/* * MUSCLE SmartCard Development ( http://www.linuxnet.com ) * * Copyright (C) 2001-2004 * David Corcoran * Copyright (C) 2003-2011 * Ludovic Rousseau * Copyright (C) 2003 * Toni Andjelkovic * Copyright (C) 2003-2004 * Damien Sauveron * * $Id: hotplug_libusb.c 5711 2011-05-05 09:02:08Z 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 #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" #include "utils.h" #undef DEBUG_HOTPLUG #define ADD_SERIAL_NUMBER /* format is "%d:%d:%d", bus_number, device_address, interface */ #define BUS_DEVICE_STRSIZE 10+1+10+1+10+1 #define READER_ABSENT 0 #define READER_PRESENT 1 #define READER_FAILED 2 #define FALSE 0 #define TRUE 1 /* we use the default libusb context */ #define ctx NULL pthread_mutex_t usbNotifierMutex; static pthread_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 { unsigned int manuID; unsigned int 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]; static LONG HPAddHotPluggable(struct libusb_device *dev, struct libusb_device_descriptor desc, const char bus_device[], int interface, struct _driverTracker *driver); static LONG HPRemoveHotPluggable(int reader_index); static LONG HPReadBundleValues(void) { LONG rv; DIR *hpDir; struct dirent *currFP = NULL; char fullPath[FILENAME_MAX]; char fullLibPath[FILENAME_MAX]; 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; #define GET_KEY(key, values) \ rv = LTPBundleFindValueWithKey(&plist, key, values); \ if (rv) \ { \ Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \ fullPath); \ continue; \ } while ((currFP = readdir(hpDir)) != 0) { if (strstr(currFP->d_name, ".bundle") != 0) { unsigned int alias; list_t plist, *values; list_t *manuIDs, *productIDs, *readerNames; char *libraryPath; int ifdCapabilities; /* * 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'; rv = bundleParse(fullPath, &plist); if (rv) continue; /* get CFBundleExecutable */ GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values) libraryPath = list_get_at(values, 0); (void)snprintf(fullLibPath, sizeof(fullLibPath), "%s/%s/Contents/%s/%s", PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH, libraryPath); fullLibPath[sizeof(fullLibPath) - 1] = '\0'; /* Get ifdCapabilities */ GET_KEY(PCSCLITE_HP_CPCTKEY_NAME, &values) ifdCapabilities = strtol(list_get_at(values, 0), NULL, 16); GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs) GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs) GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames) /* while we find a nth ifdVendorID in Info.plist */ for (alias=0; aliasd_name); driverTracker[listCount].libraryPath = strdup(fullLibPath); driverTracker[listCount].ifdCapabilities = ifdCapabilities; #ifdef DEBUG_HOTPLUG Log2(PCSC_LOG_INFO, "Found driver for: %s", driverTracker[listCount].readerName); #endif 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; ibNumInterfaces; interface++) { int newreader; /* A known device has been found */ snprintf(bus_device, BUS_DEVICE_STRSIZE, "%d:%d:%d", bus_number, device_address, interface); bus_device[BUS_DEVICE_STRSIZE - 1] = '\0'; newreader = TRUE; /* Check if the reader is a new one */ for (j=0; jbNumInterfaces > 1) HPAddHotPluggable(dev, desc, bus_device, interface, &driverTracker[i]); else HPAddHotPluggable(dev, desc, bus_device, -1, &driverTracker[i]); } } } } libusb_free_config_descriptor(config_desc); } /* * check if all the previously found readers are still present */ for (i=0; i 0) { Log1(PCSC_LOG_INFO, "Reload serial configuration"); HPRescanUsbBus(); #ifdef USE_SERIAL RFReCheckReaderConf(); #endif 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; } static LONG HPAddHotPluggable(struct libusb_device *dev, struct libusb_device_descriptor desc, const char bus_device[], int interface, struct _driverTracker *driver) { int i; char deviceName[MAX_DEVICENAME]; Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device); if (interface >= 0) snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libhal:/org/freedesktop/Hal/devices/usb_device_%04x_%04x_serialnotneeded_if%d", desc.idVendor, desc.idProduct, desc.idVendor, desc.idProduct, interface); else snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libusb-1.0:%s", desc.idVendor, desc.idProduct, bus_device); deviceName[sizeof(deviceName) -1] = '\0'; pthread_mutex_lock(&usbNotifierMutex); /* find a free entry */ for (i=0; ireaderName); } else { 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; (void)CheckForOpenCT(); } pthread_mutex_unlock(&usbNotifierMutex); return 1; } /* End of function */ static LONG HPRemoveHotPluggable(int reader_index) { pthread_mutex_lock(&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; pthread_mutex_unlock(&usbNotifierMutex); return 1; } /* End of function */ /** * Sets up callbacks for device hotplug events. */ ULONG HPRegisterForHotplugEvents(void) { (void)pthread_mutex_init(&usbNotifierMutex, NULL); return 0; } void HPReCheckSerialReaders(void) { if (rescan_pipe[1] >= 0) { char dummy = 0; write(rescan_pipe[1], &dummy, sizeof(dummy)); } } #endif