static 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 */
static LONG HPRemoveHotPluggable(int i, unsigned long usbAddr) { RFRemoveReader(bundleTracker[i].readerName, PCSCLITE_HP_BASE_PORT + usbAddr); return 1; } /* End of function */
static void HPRescanUsbBus(struct udev *udev) { int i, j; struct udev_enumerate *enumerate; struct udev_list_entry *devices, *dev_list_entry; /* all reader are marked absent */ for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) readerTracker[i].status = READER_ABSENT; /* Create a list of the devices in the 'usb' subsystem. */ enumerate = udev_enumerate_new(udev); udev_enumerate_add_match_subsystem(enumerate, "usb"); udev_enumerate_scan_devices(enumerate); devices = udev_enumerate_get_list_entry(enumerate); /* For each item enumerated */ udev_list_entry_foreach(dev_list_entry, devices) { const char *devpath; struct udev_device *dev, *parent; struct _driverTracker *driver, *classdriver; int newreader; int bInterfaceNumber; const char *interface; /* Get the filename of the /sys entry for the device and create a udev_device object (dev) representing it */ devpath = udev_list_entry_get_name(dev_list_entry); dev = udev_device_new_from_syspath(udev, devpath); /* The device pointed to by dev contains information about the interface. In order to get information about the USB device, get the parent device with the subsystem/devtype pair of "usb"/"usb_device". This will be several levels up the tree, but the function will find it.*/ parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device"); if (!parent) continue; devpath = udev_device_get_devnode(parent); if (!devpath) { /* the device disapeared? */ Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed"); continue; } driver = get_driver(parent, devpath, &classdriver); if (NULL == driver) /* no driver known for this device */ continue; #ifdef DEBUG_HOTPLUG Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath); #endif newreader = TRUE; bInterfaceNumber = 0; interface = udev_device_get_sysattr_value(dev, "bInterfaceNumber"); if (interface) bInterfaceNumber = atoi(interface); /* Check if the reader is a new one */ for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++) { if (readerTracker[j].devpath && (strcmp(readerTracker[j].devpath, devpath) == 0) && (bInterfaceNumber == readerTracker[j].bInterfaceNumber)) { /* The reader is already known */ readerTracker[j].status = READER_PRESENT; newreader = FALSE; #ifdef DEBUG_HOTPLUG Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s", devpath); #endif break; } } /* New reader found */ if (newreader) HPAddDevice(dev, parent, devpath); /* free device */ udev_device_unref(dev); } /* Free the enumerator object */ udev_enumerate_unref(enumerate); /* check if all the previously found readers are still present */ for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++) { if ((READER_ABSENT == readerTracker[i].status) && (readerTracker[i].fullName != NULL)) { pthread_mutex_lock(&usbNotifierMutex); Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", i, readerTracker[i].devpath); RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i); readerTracker[i].status = READER_ABSENT; free(readerTracker[i].devpath); readerTracker[i].devpath = NULL; free(readerTracker[i].fullName); readerTracker[i].fullName = NULL; pthread_mutex_unlock(&usbNotifierMutex); } } }
LONG RFAddReader(const char *readerNameLong, int port, const char *library, const char *device) { DWORD dwContext = 0, dwGetSize; UCHAR ucGetData[1], ucThread[1]; LONG rv, parentNode; int i, j; int lrv = 0; char *readerName = NULL; if ((readerNameLong == NULL) || (library == NULL) || (device == NULL)) return SCARD_E_INVALID_VALUE; #ifdef FILTER_NAMES const char *ro_filter = getenv("PCSCLITE_FILTER_IGNORE_READER_NAMES"); if (ro_filter) { char *filter, *next; /* get a RW copy of the env string */ filter = alloca(strlen(ro_filter)+1); strcpy(filter, ro_filter); while (filter) { /* ':' is the separator */ next = strchr(filter, ':'); if (next) { /* NUL terminate the current pattern */ *next = '\0'; } /* if filter is non empty and found in the reader name */ if (*filter && strstr(readerNameLong, filter)) { Log3(PCSC_LOG_ERROR, "Reader name \"%s\" contains \"%s\": ignored", readerNameLong, filter); return SCARD_E_READER_UNAVAILABLE; } if (next) /* next pattern */ filter = next+1; else /* end */ filter = NULL; } } #endif /* allocate memory that is automatically freed */ readerName = alloca(strlen(readerNameLong)+1); strcpy(readerName, readerNameLong); /* Reader name too long? also count " 00 00"*/ if (strlen(readerName) > MAX_READERNAME - sizeof(" 00 00")) { Log3(PCSC_LOG_ERROR, "Reader name too long: %zd chars instead of max %zd. Truncating!", strlen(readerName), MAX_READERNAME - sizeof(" 00 00")); readerName[MAX_READERNAME - sizeof(" 00 00")] = '\0'; } /* Same name, same port, same device - duplicate reader cannot be used */ if (dwNumReadersContexts != 0) { for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) { if (sReadersContexts[i]->vHandle != 0) { char lpcStripReader[MAX_READERNAME]; int tmplen; /* get the reader name without the reader and slot numbers */ strncpy(lpcStripReader, sReadersContexts[i]->readerState->readerName, sizeof(lpcStripReader)); tmplen = strlen(lpcStripReader); lpcStripReader[tmplen - 6] = 0; if ((strcmp(readerName, lpcStripReader) == 0) && (port == sReadersContexts[i]->port) && (strcmp(device, sReadersContexts[i]->device) == 0)) { Log1(PCSC_LOG_ERROR, "Duplicate reader found."); return SCARD_E_DUPLICATE_READER; } } } } /* We must find an empty slot to put the reader structure */ for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) { if (sReadersContexts[i]->vHandle == 0) { dwContext = i; break; } } if (i == PCSCLITE_MAX_READERS_CONTEXTS) { /* No more spots left return */ return SCARD_E_NO_MEMORY; } /* Check and set the readername to see if it must be enumerated */ parentNode = RFSetReaderName(sReadersContexts[dwContext], readerName, library, port); if (parentNode < -1) return SCARD_E_NO_MEMORY; sReadersContexts[dwContext]->library = strdup(library); sReadersContexts[dwContext]->device = strdup(device); sReadersContexts[dwContext]->version = 0; sReadersContexts[dwContext]->port = port; sReadersContexts[dwContext]->mMutex = NULL; sReadersContexts[dwContext]->contexts = 0; sReadersContexts[dwContext]->pthThread = 0; sReadersContexts[dwContext]->hLockId = 0; sReadersContexts[dwContext]->LockCount = 0; sReadersContexts[dwContext]->vHandle = NULL; sReadersContexts[dwContext]->pFeeds = NULL; sReadersContexts[dwContext]->pMutex = NULL; sReadersContexts[dwContext]->pthCardEvent = NULL; lrv = list_init(&sReadersContexts[dwContext]->handlesList); if (lrv < 0) { Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv); return SCARD_E_NO_MEMORY; } lrv = list_attributes_seeker(&sReadersContexts[dwContext]->handlesList, RDR_CLIHANDLES_seeker); if (lrv < 0) { Log2(PCSC_LOG_CRITICAL, "list_attributes_seeker failed with return value: %d", lrv); return SCARD_E_NO_MEMORY; } (void)pthread_mutex_init(&sReadersContexts[dwContext]->handlesList_lock, NULL); (void)pthread_mutex_init(&sReadersContexts[dwContext]->powerState_lock, NULL); sReadersContexts[dwContext]->powerState = POWER_STATE_UNPOWERED; /* reference count */ (void)pthread_mutex_init(&sReadersContexts[dwContext]->reference_lock, NULL); sReadersContexts[dwContext]->reference = 1; /* If a clone to this reader exists take some values from that clone */ if (parentNode >= 0 && parentNode < PCSCLITE_MAX_READERS_CONTEXTS) { sReadersContexts[dwContext]->pFeeds = sReadersContexts[parentNode]->pFeeds; *(sReadersContexts[dwContext])->pFeeds += 1; sReadersContexts[dwContext]->vHandle = sReadersContexts[parentNode]->vHandle; sReadersContexts[dwContext]->mMutex = sReadersContexts[parentNode]->mMutex; sReadersContexts[dwContext]->pMutex = sReadersContexts[parentNode]->pMutex; /* Call on the parent driver to see if it is thread safe */ dwGetSize = sizeof(ucThread); rv = IFDGetCapabilities(sReadersContexts[parentNode], TAG_IFD_THREAD_SAFE, &dwGetSize, ucThread); if (rv == IFD_SUCCESS && dwGetSize == 1 && ucThread[0] == 1) { Log1(PCSC_LOG_INFO, "Driver is thread safe"); sReadersContexts[dwContext]->mMutex = NULL; sReadersContexts[dwContext]->pMutex = NULL; } else *(sReadersContexts[dwContext])->pMutex += 1; } if (sReadersContexts[dwContext]->pFeeds == NULL) { sReadersContexts[dwContext]->pFeeds = malloc(sizeof(int)); /* Initialize pFeeds to 1, otherwise multiple cloned readers will cause pcscd to crash when RFUnloadReader unloads the driver library and there are still devices attached using it --mikeg*/ *(sReadersContexts[dwContext])->pFeeds = 1; } if (sReadersContexts[dwContext]->mMutex == 0) { sReadersContexts[dwContext]->mMutex = malloc(sizeof(pthread_mutex_t)); (void)pthread_mutex_init(sReadersContexts[dwContext]->mMutex, NULL); } if (sReadersContexts[dwContext]->pMutex == NULL) { sReadersContexts[dwContext]->pMutex = malloc(sizeof(int)); *(sReadersContexts[dwContext])->pMutex = 1; } dwNumReadersContexts += 1; rv = RFInitializeReader(sReadersContexts[dwContext]); if (rv != SCARD_S_SUCCESS) { /* Cannot connect to reader. Exit gracefully */ Log2(PCSC_LOG_ERROR, "%s init failed.", readerName); (void)RFRemoveReader(readerName, port); return rv; } /* asynchronous card movement? */ { RESPONSECODE (*fct)(DWORD, int) = NULL; dwGetSize = sizeof(fct); rv = IFDGetCapabilities(sReadersContexts[dwContext], TAG_IFD_POLLING_THREAD_WITH_TIMEOUT, &dwGetSize, (PUCHAR)&fct); if ((rv != SCARD_S_SUCCESS) || (dwGetSize != sizeof(fct))) { Log1(PCSC_LOG_INFO, "Using the pcscd polling thread"); } else { sReadersContexts[dwContext]->pthCardEvent = fct; Log1(PCSC_LOG_INFO, "Using the reader polling thread"); } rv = EHSpawnEventHandler(sReadersContexts[dwContext]); if (rv != SCARD_S_SUCCESS) { Log2(PCSC_LOG_ERROR, "%s init failed.", readerName); (void)RFRemoveReader(readerName, port); return rv; } } /* Call on the driver to see if there are multiple slots */ dwGetSize = sizeof(ucGetData); rv = IFDGetCapabilities((sReadersContexts[dwContext]), TAG_IFD_SLOTS_NUMBER, &dwGetSize, ucGetData); int nbSlots = ucGetData[0]; if (rv != IFD_SUCCESS || dwGetSize != 1 || nbSlots == 0) /* Reader does not have this defined. Must be a single slot * reader so we can just return SCARD_S_SUCCESS. */ return SCARD_S_SUCCESS; if (1 == nbSlots) /* Reader has only one slot */ return SCARD_S_SUCCESS; /* * Check the number of slots and create a different * structure for each one accordingly */ /* Initialize the rest of the slots */ for (j = 1; j < nbSlots; j++) { char *tmpReader = NULL; DWORD dwContextB = 0; RESPONSECODE (*fct)(DWORD, int) = NULL; /* We must find an empty spot to put the reader structure */ for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) { if (sReadersContexts[i]->vHandle == 0) { dwContextB = i; break; } } if (i == PCSCLITE_MAX_READERS_CONTEXTS) { /* No more slot left return */ RFRemoveReader(readerName, port); return SCARD_E_NO_MEMORY; } /* Copy the previous reader name and increment the slot number */ tmpReader = sReadersContexts[dwContextB]->readerState->readerName; memcpy(tmpReader, sReadersContexts[dwContext]->readerState->readerName, sizeof(sReadersContexts[dwContextB]->readerState->readerName)); snprintf(tmpReader + strlen(tmpReader) - 2, 3, "%02X", j); sReadersContexts[dwContextB]->library = sReadersContexts[dwContext]->library; sReadersContexts[dwContextB]->device = sReadersContexts[dwContext]->device; sReadersContexts[dwContextB]->version = sReadersContexts[dwContext]->version; sReadersContexts[dwContextB]->port = sReadersContexts[dwContext]->port; sReadersContexts[dwContextB]->vHandle = sReadersContexts[dwContext]->vHandle; sReadersContexts[dwContextB]->mMutex = sReadersContexts[dwContext]->mMutex; sReadersContexts[dwContextB]->pMutex = sReadersContexts[dwContext]->pMutex; sReadersContexts[dwContextB]->slot = sReadersContexts[dwContext]->slot + j; sReadersContexts[dwContextB]->pthCardEvent = NULL; /* * Added by Dave - slots did not have a pFeeds * parameter so it was by luck they were working */ sReadersContexts[dwContextB]->pFeeds = sReadersContexts[dwContext]->pFeeds; /* Added by Dave for multiple slots */ *(sReadersContexts[dwContextB])->pFeeds += 1; sReadersContexts[dwContextB]->contexts = 0; sReadersContexts[dwContextB]->hLockId = 0; sReadersContexts[dwContextB]->LockCount = 0; lrv = list_init(&sReadersContexts[dwContextB]->handlesList); if (lrv < 0) { Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv); return SCARD_E_NO_MEMORY; } lrv = list_attributes_seeker(&sReadersContexts[dwContextB]->handlesList, RDR_CLIHANDLES_seeker); if (lrv < 0) { Log2(PCSC_LOG_CRITICAL, "list_attributes_seeker failed with return value: %d", lrv); return SCARD_E_NO_MEMORY; } (void)pthread_mutex_init(&sReadersContexts[dwContextB]->handlesList_lock, NULL); (void)pthread_mutex_init(&sReadersContexts[dwContextB]->powerState_lock, NULL); sReadersContexts[dwContextB]->powerState = POWER_STATE_UNPOWERED; /* reference count */ (void)pthread_mutex_init(&sReadersContexts[dwContextB]->reference_lock, NULL); sReadersContexts[dwContextB]->reference = 1; /* Call on the parent driver to see if the slots are thread safe */ dwGetSize = sizeof(ucThread); rv = IFDGetCapabilities((sReadersContexts[dwContext]), TAG_IFD_SLOT_THREAD_SAFE, &dwGetSize, ucThread); if (rv == IFD_SUCCESS && dwGetSize == 1 && ucThread[0] == 1) { Log1(PCSC_LOG_INFO, "Driver is slot thread safe"); sReadersContexts[dwContextB]->library = strdup(sReadersContexts[dwContext]->library); sReadersContexts[dwContextB]->device = strdup(sReadersContexts[dwContext]->device); sReadersContexts[dwContextB]->mMutex = malloc(sizeof(pthread_mutex_t)); (void)pthread_mutex_init(sReadersContexts[dwContextB]->mMutex, NULL); sReadersContexts[dwContextB]->pMutex = malloc(sizeof(int)); *(sReadersContexts[dwContextB])->pMutex = 1; } else *(sReadersContexts[dwContextB])->pMutex += 1; dwNumReadersContexts += 1; rv = RFInitializeReader(sReadersContexts[dwContextB]); if (rv != SCARD_S_SUCCESS) { /* Cannot connect to slot. Exit gracefully */ (void)RFRemoveReader(readerName, port); return rv; } /* asynchronous card movement? */ dwGetSize = sizeof(fct); rv = IFDGetCapabilities((sReadersContexts[dwContextB]), TAG_IFD_POLLING_THREAD_WITH_TIMEOUT, &dwGetSize, (PUCHAR)&fct); if ((rv != SCARD_S_SUCCESS) || (dwGetSize != sizeof(fct))) { Log1(PCSC_LOG_INFO, "Using the pcscd polling thread"); } else { sReadersContexts[dwContextB]->pthCardEvent = fct; Log1(PCSC_LOG_INFO, "Using the reader polling thread"); } rv = EHSpawnEventHandler(sReadersContexts[dwContextB]); if (rv != SCARD_S_SUCCESS) { Log2(PCSC_LOG_ERROR, "%s init failed.", readerName); (void)RFRemoveReader(readerName, port); return rv; } } return SCARD_S_SUCCESS; }
/* * Scans the hotplug driver directory and looks in the system for * matching devices. * Adds or removes matching readers as necessary. */ LONG HPSearchHotPluggables(void) { HPDriver *drivers = HPDriversGetFromDirectory(PCSCLITE_HP_DROPDIR); if (!drivers) return 1; HPDeviceList devices = NULL; if (HPDriversMatchUSBDevices(drivers, &devices)) return -1; if (HPDriversMatchPCCardDevices(drivers, &devices)) return -1; HPDevice *a; for (a = devices; a; a = a->m_next) { int found = FALSE; HPDevice *b; for (b = sDeviceList; b; b = b->m_next) { if (HPDeviceEquals(a, b)) { found = TRUE; break; } } if (!found) { char deviceName[MAX_DEVICENAME]; /* the format should be "usb:%04x/%04x" but Apple uses the * friendly name instead */ snprintf(deviceName, sizeof(deviceName), "%s", a->m_driver->m_friendlyName); deviceName[sizeof(deviceName)-1] = '\0'; RFAddReader(a->m_driver->m_friendlyName, PCSCLITE_HP_BASE_PORT + a->m_address, a->m_driver->m_libPath, deviceName); } } for (a = sDeviceList; a; a = a->m_next) { int found = FALSE; HPDevice *b; for (b = devices; b; b = b->m_next) { if (HPDeviceEquals(a, b)) { found = TRUE; break; } } if (!found) { RFRemoveReader(a->m_driver->m_friendlyName, PCSCLITE_HP_BASE_PORT + a->m_address); } } HPDeviceListRelease(sDeviceList); sDeviceList = devices; HPDriverVectorRelease(drivers); return 0; }
/* * Scans the hotplug driver directory and looks in the system for * matching devices. * Adds or removes matching readers as necessary. */ LONG HPSearchHotPluggables(void) { HPDriver *drivers = HPDriversGetFromDirectory(PCSCLITE_HP_DROPDIR); if (!drivers) return 1; HPDeviceList devices = NULL; if (HPDriversMatchUSBDevices(drivers, &devices)) return -1; if (HPDriversMatchPCCardDevices(drivers, &devices)) return -1; HPDevice *a; for (a = devices; a; a = a->m_next) { int found = FALSE; HPDevice *b; for (b = sDeviceList; b; b = b->m_next) { if (HPDeviceEquals(a, b)) { found = TRUE; break; } } if (!found) { char deviceName[MAX_DEVICENAME]; /* the format should be "usb:%04x/%04x:libusb:%s" but we do not * know the libusb string. So it is not possible to differentiate * two identical readers :-( */ snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x", (unsigned int)a->m_driver->m_vendorId, (unsigned int)a->m_driver->m_productId); deviceName[sizeof(deviceName)-1] = '\0'; RFAddReader(a->m_driver->m_friendlyName, PCSCLITE_HP_BASE_PORT + a->m_address, a->m_driver->m_libPath, deviceName); } } for (a = sDeviceList; a; a = a->m_next) { int found = FALSE; HPDevice *b; for (b = devices; b; b = b->m_next) { if (HPDeviceEquals(a, b)) { found = TRUE; break; } } if (!found) { RFRemoveReader(a->m_driver->m_friendlyName, PCSCLITE_HP_BASE_PORT + a->m_address); } } HPDeviceListRelease(sDeviceList); sDeviceList = devices; HPDriverVectorRelease(drivers); return 0; }