pcsc-lite 1.5.5
|
00001 /* 00002 * MUSCLE SmartCard Development ( http://www.linuxnet.com ) 00003 * 00004 * Copyright (C) 2001-2004 00005 * David Corcoran <corcoran@linuxnet.com> 00006 * Ludovic Rousseau <ludovic.rousseau@free.fr> 00007 * Toni Andjelkovic <toni@soth.at> 00008 * Damien Sauveron <damien.sauveron@labri.fr> 00009 * 00010 * $Id: hotplug_libusb.c 3197 2008-11-10 09:18:27Z rousseau $ 00011 */ 00012 00018 #include "config.h" 00019 #ifdef HAVE_LIBUSB 00020 00021 #include <string.h> 00022 #include <sys/types.h> 00023 #include <stdio.h> 00024 #include <dirent.h> 00025 #include <fcntl.h> 00026 #include <time.h> 00027 #include <stdlib.h> 00028 #include <unistd.h> 00029 #include <errno.h> 00030 #include <usb.h> 00031 00032 #include "misc.h" 00033 #include "wintypes.h" 00034 #include "pcscd.h" 00035 #include "debuglog.h" 00036 #include "parser.h" 00037 #include "readerfactory.h" 00038 #include "winscard_msg.h" 00039 #include "sys_generic.h" 00040 #include "hotplug.h" 00041 #include "utils.h" 00042 00043 #undef DEBUG_HOTPLUG 00044 #define ADD_SERIAL_NUMBER 00045 00046 #define BUS_DEVICE_STRSIZE 256 00047 00048 #define READER_ABSENT 0 00049 #define READER_PRESENT 1 00050 #define READER_FAILED 2 00051 00052 #define FALSE 0 00053 #define TRUE 1 00054 00055 extern PCSCLITE_MUTEX usbNotifierMutex; 00056 00057 static PCSCLITE_THREAD_T usbNotifyThread; 00058 static int driverSize = -1; 00059 static char AraKiriHotPlug = FALSE; 00060 static int rescan_pipe[] = { -1, -1 }; 00061 extern int HPForceReaderPolling; 00062 00063 /* values of ifdCapabilities bits */ 00064 #define IFD_GENERATE_HOTPLUG 1 00065 00069 static struct _driverTracker 00070 { 00071 long manuID; 00072 long productID; 00073 00074 char *bundleName; 00075 char *libraryPath; 00076 char *readerName; 00077 int ifdCapabilities; 00078 } *driverTracker = NULL; 00079 #define DRIVER_TRACKER_SIZE_STEP 8 00080 00084 static struct _readerTracker 00085 { 00086 char status; 00087 char bus_device[BUS_DEVICE_STRSIZE]; 00088 char *fullName; 00089 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS]; 00090 00091 static LONG HPReadBundleValues(void); 00092 static LONG HPAddHotPluggable(struct usb_device *dev, const char bus_device[], 00093 struct _driverTracker *driver); 00094 static LONG HPRemoveHotPluggable(int reader_index); 00095 static void HPRescanUsbBus(void); 00096 static void HPEstablishUSBNotifications(void); 00097 00098 static LONG HPReadBundleValues(void) 00099 { 00100 LONG rv; 00101 DIR *hpDir; 00102 struct dirent *currFP = NULL; 00103 char fullPath[FILENAME_MAX]; 00104 char fullLibPath[FILENAME_MAX]; 00105 char keyValue[TOKEN_MAX_VALUE_SIZE]; 00106 int listCount = 0; 00107 00108 hpDir = opendir(PCSCLITE_HP_DROPDIR); 00109 00110 if (hpDir == NULL) 00111 { 00112 Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR); 00113 Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd."); 00114 return -1; 00115 } 00116 00117 /* allocate a first array */ 00118 driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker)); 00119 if (NULL == driverTracker) 00120 { 00121 Log1(PCSC_LOG_CRITICAL, "Not enough memory"); 00122 return -1; 00123 } 00124 driverSize = DRIVER_TRACKER_SIZE_STEP; 00125 00126 while ((currFP = readdir(hpDir)) != 0) 00127 { 00128 if (strstr(currFP->d_name, ".bundle") != 0) 00129 { 00130 int alias = 0; 00131 00132 /* 00133 * The bundle exists - let's form a full path name and get the 00134 * vendor and product ID's for this particular bundle 00135 */ 00136 snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist", 00137 PCSCLITE_HP_DROPDIR, currFP->d_name); 00138 fullPath[sizeof(fullPath) - 1] = '\0'; 00139 00140 /* while we find a nth ifdVendorID in Info.plist */ 00141 while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME, 00142 keyValue, alias) == 0) 00143 { 00144 driverTracker[listCount].bundleName = strdup(currFP->d_name); 00145 00146 /* Get ifdVendorID */ 00147 rv = LTPBundleFindValueWithKey(fullPath, 00148 PCSCLITE_HP_MANUKEY_NAME, keyValue, alias); 00149 if (rv == 0) 00150 driverTracker[listCount].manuID = strtol(keyValue, NULL, 16); 00151 00152 /* get ifdProductID */ 00153 rv = LTPBundleFindValueWithKey(fullPath, 00154 PCSCLITE_HP_PRODKEY_NAME, keyValue, alias); 00155 if (rv == 0) 00156 driverTracker[listCount].productID = 00157 strtol(keyValue, NULL, 16); 00158 00159 /* get ifdFriendlyName */ 00160 rv = LTPBundleFindValueWithKey(fullPath, 00161 PCSCLITE_HP_NAMEKEY_NAME, keyValue, alias); 00162 if (rv == 0) 00163 driverTracker[listCount].readerName = strdup(keyValue); 00164 00165 /* get CFBundleExecutable */ 00166 rv = LTPBundleFindValueWithKey(fullPath, 00167 PCSCLITE_HP_LIBRKEY_NAME, keyValue, 0); 00168 if (rv == 0) 00169 { 00170 snprintf(fullLibPath, sizeof(fullLibPath), 00171 "%s/%s/Contents/%s/%s", 00172 PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH, 00173 keyValue); 00174 fullLibPath[sizeof(fullLibPath) - 1] = '\0'; 00175 driverTracker[listCount].libraryPath = strdup(fullLibPath); 00176 } 00177 00178 /* Get ifdCapabilities */ 00179 rv = LTPBundleFindValueWithKey(fullPath, 00180 PCSCLITE_HP_CPCTKEY_NAME, keyValue, 0); 00181 if (rv == 0) 00182 driverTracker[listCount].ifdCapabilities = strtol(keyValue, 00183 NULL, 16); 00184 00185 #ifdef DEBUG_HOTPLUG 00186 Log2(PCSC_LOG_INFO, "Found driver for: %s", 00187 driverTracker[listCount].readerName); 00188 #endif 00189 alias++; 00190 00191 if (NULL == driverTracker[listCount].readerName) 00192 continue; 00193 00194 listCount++; 00195 if (listCount >= driverSize) 00196 { 00197 int i; 00198 00199 /* increase the array size */ 00200 driverSize += DRIVER_TRACKER_SIZE_STEP; 00201 #ifdef DEBUG_HOTPLUG 00202 Log2(PCSC_LOG_INFO, 00203 "Increase driverTracker to %d entries", driverSize); 00204 #endif 00205 driverTracker = realloc(driverTracker, 00206 driverSize * sizeof(*driverTracker)); 00207 if (NULL == driverTracker) 00208 { 00209 Log1(PCSC_LOG_CRITICAL, "Not enough memory"); 00210 driverSize = -1; 00211 return -1; 00212 } 00213 00214 /* clean the newly allocated entries */ 00215 for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++) 00216 { 00217 driverTracker[i].manuID = 0; 00218 driverTracker[i].productID = 0; 00219 driverTracker[i].bundleName = NULL; 00220 driverTracker[i].libraryPath = NULL; 00221 driverTracker[i].readerName = NULL; 00222 driverTracker[i].ifdCapabilities = 0; 00223 } 00224 } 00225 } 00226 } 00227 } 00228 00229 driverSize = listCount; 00230 closedir(hpDir); 00231 00232 rv = TRUE; 00233 if (driverSize == 0) 00234 { 00235 Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR); 00236 Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd"); 00237 rv = FALSE; 00238 } 00239 #ifdef DEBUG_HOTPLUG 00240 else 00241 Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount); 00242 #endif 00243 00244 return rv; 00245 } 00246 00247 static void HPRescanUsbBus(void) 00248 { 00249 int i, j; 00250 struct usb_bus *bus; 00251 struct usb_device *dev; 00252 char bus_device[BUS_DEVICE_STRSIZE]; 00253 00254 usb_find_busses(); 00255 usb_find_devices(); 00256 00257 for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 00258 /* clear rollcall */ 00259 readerTracker[i].status = READER_ABSENT; 00260 00261 /* For each USB bus */ 00262 for (bus = usb_get_busses(); bus; bus = bus->next) 00263 { 00264 /* For each USB device */ 00265 for (dev = bus->devices; dev; dev = dev->next) 00266 { 00267 /* check if the device is supported by one driver */ 00268 for (i=0; i<driverSize; i++) 00269 { 00270 if (driverTracker[i].libraryPath != NULL && 00271 dev->descriptor.idVendor == driverTracker[i].manuID && 00272 dev->descriptor.idProduct == driverTracker[i].productID) 00273 { 00274 int newreader; 00275 00276 /* A known device has been found */ 00277 snprintf(bus_device, BUS_DEVICE_STRSIZE, "%s:%s", 00278 bus->dirname, dev->filename); 00279 bus_device[BUS_DEVICE_STRSIZE - 1] = '\0'; 00280 #ifdef DEBUG_HOTPLUG 00281 Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", 00282 bus_device); 00283 #endif 00284 newreader = TRUE; 00285 00286 /* Check if the reader is a new one */ 00287 for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++) 00288 { 00289 if (strncmp(readerTracker[j].bus_device, 00290 bus_device, BUS_DEVICE_STRSIZE) == 0) 00291 { 00292 /* The reader is already known */ 00293 readerTracker[j].status = READER_PRESENT; 00294 newreader = FALSE; 00295 #ifdef DEBUG_HOTPLUG 00296 Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s", 00297 bus_device); 00298 #endif 00299 break; 00300 } 00301 } 00302 00303 /* New reader found */ 00304 if (newreader) 00305 HPAddHotPluggable(dev, bus_device, &driverTracker[i]); 00306 } 00307 } 00308 } /* End of USB device for..loop */ 00309 00310 } /* End of USB bus for..loop */ 00311 00312 /* 00313 * check if all the previously found readers are still present 00314 */ 00315 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++) 00316 { 00317 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) 00318 int fd; 00319 char filename[BUS_DEVICE_STRSIZE]; 00320 00321 /* BSD workaround: 00322 * ugenopen() in sys/dev/usb/ugen.c returns EBUSY 00323 * when the character device file is already open. 00324 * Because of this, open usb devices will not be 00325 * detected by usb_find_devices(), so we have to 00326 * check for this explicitly. 00327 */ 00328 if (readerTracker[i].status == READER_PRESENT || 00329 readerTracker[i].fullName == NULL) 00330 continue; 00331 00332 sscanf(readerTracker[i].bus_device, "%*[^:]%*[:]%s", filename); 00333 fd = open(filename, O_RDONLY); 00334 if (fd == -1) 00335 { 00336 if (errno == EBUSY) 00337 { 00338 /* The device is present */ 00339 #ifdef DEBUG_HOTPLUG 00340 Log2(PCSC_LOG_DEBUG, "BSD: EBUSY on %s", filename); 00341 #endif 00342 readerTracker[i].status = READER_PRESENT; 00343 } 00344 #ifdef DEBUG_HOTPLUG 00345 else 00346 Log3(PCSC_LOG_DEBUG, "BSD: %s error: %s", filename, 00347 strerror(errno)); 00348 #endif 00349 } 00350 else 00351 { 00352 #ifdef DEBUG_HOTPLUG 00353 Log2(PCSC_LOG_DEBUG, "BSD: %s still present", filename); 00354 #endif 00355 readerTracker[i].status = READER_PRESENT; 00356 close(fd); 00357 } 00358 #endif 00359 if ((readerTracker[i].status == READER_ABSENT) && 00360 (readerTracker[i].fullName != NULL)) 00361 HPRemoveHotPluggable(i); 00362 } 00363 00364 if (AraKiriHotPlug) 00365 { 00366 int retval; 00367 00368 for (i=0; i<driverSize; i++) 00369 { 00370 /* free strings allocated by strdup() */ 00371 free(driverTracker[i].bundleName); 00372 free(driverTracker[i].libraryPath); 00373 free(driverTracker[i].readerName); 00374 } 00375 free(driverTracker); 00376 00377 Log1(PCSC_LOG_INFO, "Hotplug stopped"); 00378 pthread_exit(&retval); 00379 } 00380 } 00381 00382 static void HPEstablishUSBNotifications(void) 00383 { 00384 int i, do_polling; 00385 00386 /* libusb default is /dev/bus/usb but the devices are not yet visible there 00387 * when a hotplug is requested */ 00388 setenv("USB_DEVFS_PATH", "/proc/bus/usb", 0); 00389 00390 usb_init(); 00391 00392 /* scan the USB bus for devices at startup */ 00393 HPRescanUsbBus(); 00394 00395 /* if at least one driver do not have IFD_GENERATE_HOTPLUG */ 00396 do_polling = FALSE; 00397 for (i=0; i<driverSize; i++) 00398 if (driverTracker[i].libraryPath) 00399 if ((driverTracker[i].ifdCapabilities & IFD_GENERATE_HOTPLUG) == 0) 00400 { 00401 Log2(PCSC_LOG_INFO, 00402 "Driver %s does not support IFD_GENERATE_HOTPLUG. Using active polling instead.", 00403 driverTracker[i].bundleName); 00404 if (HPForceReaderPolling < 1) 00405 HPForceReaderPolling = 1; 00406 break; 00407 } 00408 00409 if (HPForceReaderPolling) 00410 { 00411 Log2(PCSC_LOG_INFO, 00412 "Polling forced every %d second(s)", HPForceReaderPolling); 00413 do_polling = TRUE; 00414 } 00415 00416 if (do_polling) 00417 { 00418 while (!AraKiriHotPlug) 00419 { 00420 SYS_Sleep(HPForceReaderPolling); 00421 HPRescanUsbBus(); 00422 } 00423 } 00424 else 00425 { 00426 char dummy; 00427 00428 pipe(rescan_pipe); 00429 while (read(rescan_pipe[0], &dummy, sizeof(dummy)) > 0) 00430 { 00431 Log1(PCSC_LOG_INFO, "Reload serial configuration"); 00432 HPRescanUsbBus(); 00433 RFReCheckReaderConf(); 00434 Log1(PCSC_LOG_INFO, "End reload serial configuration"); 00435 } 00436 close(rescan_pipe[0]); 00437 rescan_pipe[0] = -1; 00438 } 00439 } 00440 00441 LONG HPSearchHotPluggables(void) 00442 { 00443 int i; 00444 00445 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++) 00446 { 00447 readerTracker[i].status = READER_ABSENT; 00448 readerTracker[i].bus_device[0] = '\0'; 00449 readerTracker[i].fullName = NULL; 00450 } 00451 00452 if (HPReadBundleValues()) 00453 SYS_ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED, 00454 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, NULL); 00455 00456 return 0; 00457 } 00458 00459 LONG HPStopHotPluggables(void) 00460 { 00461 AraKiriHotPlug = TRUE; 00462 if (rescan_pipe[1] >= 0) 00463 { 00464 close(rescan_pipe[1]); 00465 rescan_pipe[1] = -1; 00466 } 00467 00468 return 0; 00469 } 00470 00471 static LONG HPAddHotPluggable(struct usb_device *dev, const char bus_device[], 00472 struct _driverTracker *driver) 00473 { 00474 int i; 00475 char deviceName[MAX_DEVICENAME]; 00476 00477 Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device); 00478 00479 snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libusb:%s", 00480 dev->descriptor.idVendor, dev->descriptor.idProduct, bus_device); 00481 deviceName[sizeof(deviceName) -1] = '\0'; 00482 00483 SYS_MutexLock(&usbNotifierMutex); 00484 00485 /* find a free entry */ 00486 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++) 00487 { 00488 if (readerTracker[i].fullName == NULL) 00489 break; 00490 } 00491 00492 if (i==PCSCLITE_MAX_READERS_CONTEXTS) 00493 { 00494 Log2(PCSC_LOG_ERROR, 00495 "Not enough reader entries. Already found %d readers", i); 00496 SYS_MutexUnLock(&usbNotifierMutex); 00497 return 0; 00498 } 00499 00500 strncpy(readerTracker[i].bus_device, bus_device, 00501 sizeof(readerTracker[i].bus_device)); 00502 readerTracker[i].bus_device[sizeof(readerTracker[i].bus_device) - 1] = '\0'; 00503 00504 #ifdef ADD_SERIAL_NUMBER 00505 if (dev->descriptor.iSerialNumber) 00506 { 00507 usb_dev_handle *device; 00508 char serialNumber[MAX_READERNAME]; 00509 char fullname[MAX_READERNAME]; 00510 int ret; 00511 00512 device = usb_open(dev); 00513 ret = usb_get_string_simple(device, dev->descriptor.iSerialNumber, 00514 serialNumber, MAX_READERNAME); 00515 usb_close(device); 00516 00517 if (ret < 0) 00518 { 00519 Log2(PCSC_LOG_ERROR, "usb_get_string_simple failed: %s", 00520 usb_strerror()); 00521 readerTracker[i].fullName = strdup(driver->readerName); 00522 } 00523 else 00524 { 00525 snprintf(fullname, sizeof(fullname), "%s (%s)", 00526 driver->readerName, serialNumber); 00527 readerTracker[i].fullName = strdup(fullname); 00528 } 00529 } 00530 else 00531 #endif 00532 readerTracker[i].fullName = strdup(driver->readerName); 00533 00534 if (RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i, 00535 driver->libraryPath, deviceName) == SCARD_S_SUCCESS) 00536 readerTracker[i].status = READER_PRESENT; 00537 else 00538 { 00539 readerTracker[i].status = READER_FAILED; 00540 00541 (void)CheckForOpenCT(); 00542 } 00543 00544 SYS_MutexUnLock(&usbNotifierMutex); 00545 00546 return 1; 00547 } /* End of function */ 00548 00549 static LONG HPRemoveHotPluggable(int reader_index) 00550 { 00551 SYS_MutexLock(&usbNotifierMutex); 00552 00553 Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", reader_index, 00554 readerTracker[reader_index].bus_device); 00555 00556 RFRemoveReader(readerTracker[reader_index].fullName, 00557 PCSCLITE_HP_BASE_PORT + reader_index); 00558 free(readerTracker[reader_index].fullName); 00559 readerTracker[reader_index].status = READER_ABSENT; 00560 readerTracker[reader_index].bus_device[0] = '\0'; 00561 readerTracker[reader_index].fullName = NULL; 00562 00563 SYS_MutexUnLock(&usbNotifierMutex); 00564 00565 return 1; 00566 } /* End of function */ 00567 00571 ULONG HPRegisterForHotplugEvents(void) 00572 { 00573 return 0; 00574 } 00575 00576 void HPReCheckSerialReaders(void) 00577 { 00578 if (rescan_pipe[1] >= 0) 00579 { 00580 char dummy = 0; 00581 write(rescan_pipe[1], &dummy, sizeof(dummy)); 00582 } 00583 } 00584 00585 #endif 00586