2
* MUSCLE SmartCard Development ( http://www.linuxnet.com )
4
* Copyright (C) 2001-2004
5
* David Corcoran <corcoran@linuxnet.com>
6
* Ludovic Rousseau <ludovic.rousseau@free.fr>
7
* Toni Andjelkovic <toni@soth.at>
8
* Damien Sauveron <damien.sauveron@labri.fr>
10
* $Id: hotplug_libusb.c,v 1.3 2005-09-06 20:37:24 rousseau Exp $
15
* @brief This provides a search API for hot pluggble devices.
22
#include <sys/types.h>
35
#include "readerfactory.h"
36
#include "winscard_msg.h"
37
#include "sys_generic.h"
42
#define BUS_DEVICE_STRSIZE 256
44
#define READER_ABSENT 0
45
#define READER_PRESENT 1
46
#define READER_FAILED 2
51
extern PCSCLITE_MUTEX usbNotifierMutex;
53
static PCSCLITE_THREAD_T usbNotifyThread;
54
static int driverSize = -1;
55
static char AraKiriHotPlug = FALSE;
56
char ReCheckSerialReaders = FALSE;
59
* keep track of drivers in a dynamically allocated array
61
static struct _driverTracker
69
} *driverTracker = NULL;
70
#define DRIVER_TRACKER_SIZE_STEP 8
73
* keep track of PCSCLITE_MAX_READERS_CONTEXTS simultaneous readers
75
static struct _readerTracker
78
char bus_device[BUS_DEVICE_STRSIZE]; /* device name */
80
struct _driverTracker *driver; /* driver for this reader */
81
} readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
83
LONG HPReadBundleValues(void);
84
LONG HPAddHotPluggable(struct usb_device *dev, const char bus_device[],
85
struct _driverTracker *driver);
86
LONG HPRemoveHotPluggable(int index);
88
LONG HPReadBundleValues(void)
92
struct dirent *currFP = 0;
93
char fullPath[FILENAME_MAX];
94
char fullLibPath[FILENAME_MAX];
95
char keyValue[TOKEN_MAX_VALUE_SIZE];
98
hpDir = opendir(PCSCLITE_HP_DROPDIR);
102
Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
103
Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
107
/* allocate a first array */
108
driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker));
109
if (NULL == driverTracker)
111
Log1(PCSC_LOG_CRITICAL, "Not enough memory");
114
driverSize = DRIVER_TRACKER_SIZE_STEP;
116
while ((currFP = readdir(hpDir)) != 0)
118
if (strstr(currFP->d_name, ".bundle") != 0)
123
* The bundle exists - let's form a full path name and get the
124
* vendor and product ID's for this particular bundle
126
snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
127
PCSCLITE_HP_DROPDIR, currFP->d_name);
128
fullPath[sizeof(fullPath) - 1] = '\0';
130
/* while we find a nth ifdVendorID in Info.plist */
131
while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME,
132
keyValue, alias) == 0)
134
driverTracker[listCount].bundleName = strdup(currFP->d_name);
136
/* Get ifdVendorID */
137
rv = LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME,
140
driverTracker[listCount].manuID = strtol(keyValue, 0, 16);
142
/* get ifdProductID */
143
rv = LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_PRODKEY_NAME,
146
driverTracker[listCount].productID =
147
strtol(keyValue, 0, 16);
149
/* get ifdFriendlyName */
150
rv = LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_NAMEKEY_NAME,
153
driverTracker[listCount].readerName = strdup(keyValue);
155
/* get CFBundleExecutable */
156
rv = LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_LIBRKEY_NAME,
160
snprintf(fullLibPath, sizeof(fullLibPath),
161
"%s/%s/Contents/%s/%s",
162
PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH, keyValue);
163
fullLibPath[sizeof(fullLibPath) - 1] = '\0';
164
driverTracker[listCount].libraryPath = strdup(fullLibPath);
168
Log2(PCSC_LOG_INFO, "Found driver for: %s",
169
driverTracker[listCount].readerName);
175
if (listCount >= driverSize)
179
/* increase the array size */
180
driverSize += DRIVER_TRACKER_SIZE_STEP;
183
"Increase driverTracker to %d entries", driverSize);
185
driverTracker = realloc(driverTracker,
186
driverSize * sizeof(*driverTracker));
187
if (NULL == driverTracker)
189
Log1(PCSC_LOG_CRITICAL, "Not enough memory");
194
/* clean the newly allocated entries */
195
for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
197
driverTracker[i].manuID = 0;
198
driverTracker[i].productID = 0;
199
driverTracker[i].bundleName = NULL;
200
driverTracker[i].libraryPath = NULL;
201
driverTracker[i].readerName = NULL;
208
driverSize = listCount;
214
Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR);
215
Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
220
Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
226
void HPEstablishUSBNotifications(void)
230
struct usb_device *dev;
231
char bus_device[BUS_DEVICE_STRSIZE];
239
for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
241
readerTracker[i].status = READER_ABSENT;
243
/* For each USB bus */
244
for (bus = usb_get_busses(); bus; bus = bus->next)
246
/* For each USB device */
247
for (dev = bus->devices; dev; dev = dev->next)
249
/* check if the device is supported by one driver */
250
for (i=0; i<driverSize; i++)
252
if (driverTracker[i].libraryPath != NULL &&
253
dev->descriptor.idVendor == driverTracker[i].manuID &&
254
dev->descriptor.idProduct == driverTracker[i].productID)
258
/* A known device has been found */
259
snprintf(bus_device, BUS_DEVICE_STRSIZE, "%s:%s",
260
bus->dirname, dev->filename);
261
bus_device[BUS_DEVICE_STRSIZE - 1] = '\0';
263
Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", bus_device);
267
/* Check if the reader is a new one */
268
for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
270
if (strncmp(readerTracker[j].bus_device,
271
bus_device, BUS_DEVICE_STRSIZE) == 0)
273
/* The reader is already known */
274
readerTracker[j].status = READER_PRESENT;
277
Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s", bus_device);
283
/* New reader found */
285
HPAddHotPluggable(dev, bus_device, &driverTracker[i]);
288
} /* End of USB device for..loop */
290
} /* End of USB bus for..loop */
293
* check if all the previously found readers are still present
295
for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
297
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
299
char filename[BUS_DEVICE_STRSIZE];
302
* ugenopen() in sys/dev/usb/ugen.c returns EBUSY
303
* when the character device file is already open.
304
* Because of this, open usb devices will not be
305
* detected by usb_find_devices(), so we have to
306
* check for this explicitly.
308
if (readerTracker[i].status == READER_PRESENT ||
309
readerTracker[i].driver == NULL)
312
sscanf(readerTracker[i].bus_device, "%*[^:]%*[:]%s", filename);
313
fd = open(filename, O_RDONLY);
318
/* The device is present */
320
Log2(PCSC_LOG_DEBUG, "BSD: EBUSY on %s", filename);
322
readerTracker[i].status = READER_PRESENT;
326
Log3(PCSC_LOG_DEBUG, "BSD: %s error: %s", filename,
333
Log2(PCSC_LOG_DEBUG, "BSD: %s still present", filename);
335
readerTracker[i].status = READER_PRESENT;
339
if (readerTracker[i].status == READER_ABSENT &&
340
readerTracker[i].driver != NULL)
341
HPRemoveHotPluggable(i);
349
for (i=0; i<driverSize; i++)
351
/* free strings allocated by strdup() */
352
free(driverTracker[i].bundleName);
353
free(driverTracker[i].libraryPath);
354
free(driverTracker[i].readerName);
358
Log1(PCSC_LOG_INFO, "Hotplug stopped");
359
pthread_exit(&retval);
362
if (ReCheckSerialReaders)
364
ReCheckSerialReaders = FALSE;
365
RFReCheckReaderConf();
368
} /* End of while loop */
371
LONG HPSearchHotPluggables(void)
375
for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
377
readerTracker[i].driver = NULL;
378
readerTracker[i].status = READER_ABSENT;
379
readerTracker[i].bus_device[0] = '\0';
382
if (HPReadBundleValues())
383
SYS_ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
384
(PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, 0);
389
LONG HPStopHotPluggables(void)
391
AraKiriHotPlug = TRUE;
396
LONG HPAddHotPluggable(struct usb_device *dev, const char bus_device[],
397
struct _driverTracker *driver)
400
char deviceName[MAX_DEVICENAME];
402
SYS_MutexLock(&usbNotifierMutex);
404
Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device);
406
snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libusb:%s",
407
dev->descriptor.idVendor, dev->descriptor.idProduct, bus_device);
408
deviceName[sizeof(deviceName) -1] = '\0';
410
/* find a free entry */
411
for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
413
if (readerTracker[i].driver == NULL)
417
if (i==PCSCLITE_MAX_READERS_CONTEXTS)
420
"Not enough reader entries. Already found %d readers", i);
424
strncpy(readerTracker[i].bus_device, bus_device,
425
sizeof(readerTracker[i].bus_device));
426
readerTracker[i].bus_device[sizeof(readerTracker[i].bus_device) - 1] = '\0';
428
readerTracker[i].driver = driver;
430
if (RFAddReader(driver->readerName, PCSCLITE_HP_BASE_PORT + i,
431
driver->libraryPath, deviceName) == SCARD_S_SUCCESS)
432
readerTracker[i].status = READER_PRESENT;
434
readerTracker[i].status = READER_FAILED;
436
SYS_MutexUnLock(&usbNotifierMutex);
439
} /* End of function */
441
LONG HPRemoveHotPluggable(int index)
443
SYS_MutexLock(&usbNotifierMutex);
445
Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", index,
446
readerTracker[index].bus_device);
448
RFRemoveReader(readerTracker[index].driver->readerName,
449
PCSCLITE_HP_BASE_PORT + index);
450
readerTracker[index].status = READER_ABSENT;
451
readerTracker[index].bus_device[0] = '\0';
452
readerTracker[index].driver = NULL;
454
SYS_MutexUnLock(&usbNotifierMutex);
457
} /* End of function */
460
* Sets up callbacks for device hotplug events.
462
ULONG HPRegisterForHotplugEvents(void)
467
void HPReCheckSerialReaders(void)
469
ReCheckSerialReaders = TRUE;