/* * MUSCLE SmartCard Development ( http://www.linuxnet.com ) * * Copyright (C) 2001-2004 * David Corcoran * Ludovic Rousseau * Toni Andjelkovic * Damien Sauveron * * $Id: hotplug_libusb.c 2611 2007-08-08 14:35:57Z rousseau $ */ /** * @file * @brief This provides a search API for hot pluggble devices. */ #include "config.h" #ifdef HAVE_LIBUSB #include #include #include #include #include #include #include #include #include #include #include "misc.h" #include "wintypes.h" #include "pcscd.h" #include "debuglog.h" #include "parser.h" #include "readerfactory.h" #include "winscard_msg.h" #include "sys_generic.h" #include "hotplug.h" #undef DEBUG_HOTPLUG #define ADD_SERIAL_NUMBER #define BUS_DEVICE_STRSIZE 256 #define READER_ABSENT 0 #define READER_PRESENT 1 #define READER_FAILED 2 #define FALSE 0 #define TRUE 1 extern PCSCLITE_MUTEX usbNotifierMutex; static PCSCLITE_THREAD_T usbNotifyThread; static int driverSize = -1; static char AraKiriHotPlug = FALSE; static int rescan_pipe[] = { -1, -1 }; extern int HPForceReaderPolling; /* values of ifdCapabilities bits */ #define IFD_GENERATE_HOTPLUG 1 /* * keep track of drivers in a dynamically allocated array */ static struct _driverTracker { long manuID; long productID; char *bundleName; char *libraryPath; char *readerName; int ifdCapabilities; } *driverTracker = NULL; #define DRIVER_TRACKER_SIZE_STEP 8 /* * keep track of PCSCLITE_MAX_READERS_CONTEXTS simultaneous readers */ static struct _readerTracker { char status; char bus_device[BUS_DEVICE_STRSIZE]; /* device name */ char *fullName; /* full reader name (including serial number) */ } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS]; LONG HPReadBundleValues(void); LONG HPAddHotPluggable(struct usb_device *dev, const char bus_device[], struct _driverTracker *driver); LONG HPRemoveHotPluggable(int reader_index); static void HPRescanUsbBus(void); static void HPEstablishUSBNotifications(void); LONG HPReadBundleValues(void) { LONG rv; DIR *hpDir; struct dirent *currFP = NULL; char fullPath[FILENAME_MAX]; char fullLibPath[FILENAME_MAX]; char keyValue[TOKEN_MAX_VALUE_SIZE]; int listCount = 0; hpDir = opendir(PCSCLITE_HP_DROPDIR); if (hpDir == NULL) { Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR); Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd."); return -1; } /* allocate a first array */ driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker)); if (NULL == driverTracker) { Log1(PCSC_LOG_CRITICAL, "Not enough memory"); return -1; } driverSize = DRIVER_TRACKER_SIZE_STEP; while ((currFP = readdir(hpDir)) != 0) { if (strstr(currFP->d_name, ".bundle") != 0) { int alias = 0; /* * The bundle exists - let's form a full path name and get the * vendor and product ID's for this particular bundle */ snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist", PCSCLITE_HP_DROPDIR, currFP->d_name); fullPath[sizeof(fullPath) - 1] = '\0'; /* while we find a nth ifdVendorID in Info.plist */ while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME, keyValue, alias) == 0) { driverTracker[listCount].bundleName = strdup(currFP->d_name); /* Get ifdVendorID */ rv = LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME, keyValue, alias); if (rv == 0) driverTracker[listCount].manuID = strtol(keyValue, NULL, 16); /* get ifdProductID */ rv = LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_PRODKEY_NAME, keyValue, alias); if (rv == 0) driverTracker[listCount].productID = strtol(keyValue, NULL, 16); /* get ifdFriendlyName */ rv = LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_NAMEKEY_NAME, keyValue, alias); if (rv == 0) driverTracker[listCount].readerName = strdup(keyValue); /* get CFBundleExecutable */ rv = LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_LIBRKEY_NAME, keyValue, 0); if (rv == 0) { snprintf(fullLibPath, sizeof(fullLibPath), "%s/%s/Contents/%s/%s", PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH, keyValue); fullLibPath[sizeof(fullLibPath) - 1] = '\0'; driverTracker[listCount].libraryPath = strdup(fullLibPath); } /* Get ifdCapabilities */ rv = LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_CPCTKEY_NAME, keyValue, 0); if (rv == 0) driverTracker[listCount].ifdCapabilities = strtol(keyValue, NULL, 16); #ifdef DEBUG_HOTPLUG Log2(PCSC_LOG_INFO, "Found driver for: %s", driverTracker[listCount].readerName); #endif alias++; if (NULL == driverTracker[listCount].readerName) continue; listCount++; if (listCount >= driverSize) { int i; /* increase the array size */ driverSize += DRIVER_TRACKER_SIZE_STEP; #ifdef DEBUG_HOTPLUG Log2(PCSC_LOG_INFO, "Increase driverTracker to %d entries", driverSize); #endif driverTracker = realloc(driverTracker, driverSize * sizeof(*driverTracker)); if (NULL == driverTracker) { Log1(PCSC_LOG_CRITICAL, "Not enough memory"); driverSize = -1; return -1; } /* clean the newly allocated entries */ for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; inext) { /* For each USB device */ for (dev = bus->devices; dev; dev = dev->next) { /* check if the device is supported by one driver */ for (i=0; idescriptor.idVendor == driverTracker[i].manuID && dev->descriptor.idProduct == driverTracker[i].productID) { int newreader; /* A known device has been found */ snprintf(bus_device, BUS_DEVICE_STRSIZE, "%s:%s", bus->dirname, dev->filename); bus_device[BUS_DEVICE_STRSIZE - 1] = '\0'; #ifdef DEBUG_HOTPLUG Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", bus_device); #endif newreader = TRUE; /* Check if the reader is a new one */ for (j=0; j 0) { Log1(PCSC_LOG_INFO, "Reload serial configuration"); HPRescanUsbBus(); RFReCheckReaderConf(); Log1(PCSC_LOG_INFO, "End reload serial configuration"); } close(rescan_pipe[0]); rescan_pipe[0] = -1; } } LONG HPSearchHotPluggables(void) { int i; for (i=0; i= 0) { close(rescan_pipe[1]); rescan_pipe[1] = -1; } return 0; } LONG HPAddHotPluggable(struct usb_device *dev, const char bus_device[], struct _driverTracker *driver) { int i; char deviceName[MAX_DEVICENAME]; SYS_MutexLock(&usbNotifierMutex); Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device); snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libusb:%s", dev->descriptor.idVendor, dev->descriptor.idProduct, bus_device); deviceName[sizeof(deviceName) -1] = '\0'; /* find a free entry */ for (i=0; idescriptor.iSerialNumber) { usb_dev_handle *device; char serialNumber[MAX_READERNAME]; char fullname[MAX_READERNAME]; device = usb_open(dev); usb_get_string_simple(device, dev->descriptor.iSerialNumber, serialNumber, MAX_READERNAME); usb_close(device); snprintf(fullname, sizeof(fullname), "%s (%s)", driver->readerName, serialNumber); readerTracker[i].fullName = strdup(fullname); } else #endif readerTracker[i].fullName = strdup(driver->readerName); if (RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i, driver->libraryPath, deviceName) == SCARD_S_SUCCESS) readerTracker[i].status = READER_PRESENT; else readerTracker[i].status = READER_FAILED; SYS_MutexUnLock(&usbNotifierMutex); return 1; } /* End of function */ LONG HPRemoveHotPluggable(int reader_index) { SYS_MutexLock(&usbNotifierMutex); Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", reader_index, readerTracker[reader_index].bus_device); RFRemoveReader(readerTracker[reader_index].fullName, PCSCLITE_HP_BASE_PORT + reader_index); free(readerTracker[reader_index].fullName); readerTracker[reader_index].status = READER_ABSENT; readerTracker[reader_index].bus_device[0] = '\0'; readerTracker[reader_index].fullName = NULL; SYS_MutexUnLock(&usbNotifierMutex); return 1; } /* End of function */ /* * Sets up callbacks for device hotplug events. */ ULONG HPRegisterForHotplugEvents(void) { return 0; } void HPReCheckSerialReaders(void) { if (rescan_pipe[1] >= 0) { char dummy = 0; write(rescan_pipe[1], &dummy, sizeof(dummy)); } } #endif