74#define BUS_DEVICE_STRSIZE 10+1+10+1+10+1
76#define READER_ABSENT 0
77#define READER_PRESENT 1
78#define READER_FAILED 2
80extern bool Add_Interface_In_Name;
81extern bool Add_Serial_In_Name;
86pthread_mutex_t usbNotifierMutex;
88static pthread_t usbNotifyThread;
89static int driverSize = -1;
90static _Atomic
bool ExitHotPlug =
false;
91static int rescan_pipe[] = { -1, -1 };
92extern int HPForceReaderPolling;
95#define IFD_GENERATE_HOTPLUG 1
100static struct _driverTracker
103 unsigned int productID;
110} *driverTracker = NULL;
111#define DRIVER_TRACKER_SIZE_STEP 8
119 char bus_device[BUS_DEVICE_STRSIZE];
122struct _readerTracker *readerTracker;
123int readerTrackerNbEntries = -1;
125static LONG HPAddHotPluggable(
struct libusb_device *dev,
126 struct libusb_device_descriptor desc,
127 const char bus_device[],
128 const struct libusb_interface *idesc,
129 struct _driverTracker *driver,
130 struct _driverTracker *classdriver);
131static LONG HPRemoveHotPluggable(
int reader_index);
132static void HPCleanupHotPluggable(
int reader_index);
134static LONG HPReadBundleValues(
const char * hpDirPath)
138 struct dirent *currFP = NULL;
139 char fullPath[FILENAME_MAX];
140 char fullLibPath[FILENAME_MAX];
143 hpDir = opendir(hpDirPath);
147 Log2(PCSC_LOG_ERROR,
"Cannot open PC/SC drivers directory: %s",
149 Log1(PCSC_LOG_ERROR,
"Disabling USB support for pcscd.");
154 driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP,
sizeof(*driverTracker));
155 if (NULL == driverTracker)
157 Log1(PCSC_LOG_CRITICAL,
"Not enough memory");
160 driverSize = DRIVER_TRACKER_SIZE_STEP;
162#define GET_KEY(key, values) \
163 rv = LTPBundleFindValueWithKey(&plist, key, values); \
166 Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
171 while ((currFP = readdir(hpDir)) != 0)
173 if (strstr(currFP->d_name,
".bundle") != 0)
177 list_t *manuIDs, *productIDs, *readerNames;
186 snprintf(fullPath,
sizeof(fullPath),
"%s/%s/Contents/Info.plist",
187 hpDirPath, currFP->d_name);
188 fullPath[
sizeof(fullPath) - 1] =
'\0';
190 rv = bundleParse(fullPath, &plist);
195 GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
196 libraryPath = list_get_at(values, 0);
197 (void)snprintf(fullLibPath,
sizeof(fullLibPath),
198 "%s/%s/Contents/%s/%s",
199 hpDirPath, currFP->d_name, PCSC_ARCH,
201 fullLibPath[
sizeof(fullLibPath) - 1] =
'\0';
204 GET_KEY(PCSCLITE_HP_CPCTKEY_NAME, &values)
205 ifdCapabilities = strtol(list_get_at(values, 0), NULL, 16);
207 GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
208 GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
209 GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
212 rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME,
217 CFBundleName = list_get_at(values, 0);
220 for (alias=0; alias<list_size(manuIDs); alias++)
225 value = list_get_at(manuIDs, alias);
226 driverTracker[listCount].manuID = strtol(value, NULL, 16);
228 value = list_get_at(productIDs, alias);
229 driverTracker[listCount].productID = strtol(value, NULL, 16);
231 driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
234 driverTracker[listCount].bundleName = strdup(currFP->d_name);
235 driverTracker[listCount].libraryPath = strdup(fullLibPath);
236 driverTracker[listCount].ifdCapabilities = ifdCapabilities;
237 driverTracker[listCount].CFBundleName =
238 CFBundleName ? strdup(CFBundleName) : NULL;
241 Log2(PCSC_LOG_INFO,
"Found driver for: %s",
242 driverTracker[listCount].readerName);
245 if (listCount >= driverSize)
250 driverSize += DRIVER_TRACKER_SIZE_STEP;
253 "Increase driverTracker to %d entries", driverSize);
255 void* tmp = realloc(driverTracker,
256 driverSize *
sizeof(*driverTracker));
260 Log1(PCSC_LOG_CRITICAL,
"Not enough memory");
268 for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
270 driverTracker[i].manuID = 0;
271 driverTracker[i].productID = 0;
272 driverTracker[i].bundleName = NULL;
273 driverTracker[i].libraryPath = NULL;
274 driverTracker[i].readerName = NULL;
275 driverTracker[i].ifdCapabilities = 0;
276 driverTracker[i].CFBundleName = NULL;
280 bundleRelease(&plist);
284 driverSize = listCount;
289 Log2(PCSC_LOG_INFO,
"No bundle files in pcsc drivers directory: %s",
291 Log1(PCSC_LOG_INFO,
"Disabling USB support for pcscd");
295 Log2(PCSC_LOG_INFO,
"Found drivers for %d readers", listCount);
301static struct _driverTracker *get_driver(
unsigned int idVendor,
302 unsigned int idProduct,
struct _driverTracker **classdriver)
305 static struct _driverTracker *driver;
309 "Looking for a driver for VID: 0x%04X, PID: 0x%04X",
310 idVendor, idProduct);
316 for (i=0; i<driverSize; i++)
318 if (driverTracker[i].libraryPath != NULL &&
319 idVendor == driverTracker[i].manuID &&
320 idProduct == driverTracker[i].productID)
322 if ((driverTracker[i].CFBundleName != NULL)
323 && (0 == strcmp(driverTracker[i].CFBundleName,
"CCIDCLASSDRIVER")))
324 *classdriver = &driverTracker[i];
327 driver = &driverTracker[i];
339static void HPRescanUsbBus(
void)
342 char bus_device[BUS_DEVICE_STRSIZE];
343 libusb_device **devs, *dev;
346 for (i=0; i < readerTrackerNbEntries; i++)
348 readerTracker[i].status = READER_ABSENT;
350 cnt = libusb_get_device_list(ctx, &devs);
353 Log2(PCSC_LOG_CRITICAL,
"libusb_get_device_list() failed: %s",
354 libusb_error_name(cnt));
360 while ((dev = devs[cnt++]) != NULL)
362 struct libusb_device_descriptor desc;
363 struct libusb_config_descriptor *config_desc;
364 uint8_t bus_number = libusb_get_bus_number(dev);
365 uint8_t device_address = libusb_get_device_address(dev);
366 struct _driverTracker *driver, *classdriver;
369 int r = libusb_get_device_descriptor(dev, &desc);
373 "failed to get device descriptor for %d/%d: %s",
374 bus_number, device_address, libusb_error_name(r));
378 r = libusb_get_active_config_descriptor(dev, &config_desc);
381 Log4(PCSC_LOG_ERROR,
"failed to get device config for %d/%d: %s",
382 bus_number, device_address, libusb_error_name(r));
386 driver = get_driver(desc.idVendor, desc.idProduct, &classdriver);
391 Log3(PCSC_LOG_DEBUG,
"%d/%d is not a supported smart card reader",
392 bus_number, device_address);
394 libusb_free_config_descriptor(config_desc);
399 Log3(PCSC_LOG_DEBUG,
"Found matching USB device: %d:%d",
400 bus_number, device_address);
403 for (interface = 0;
interface < config_desc->bNumInterfaces;
409 snprintf(bus_device, BUS_DEVICE_STRSIZE,
"%d:%d:%d",
410 bus_number, device_address, interface);
411 bus_device[BUS_DEVICE_STRSIZE - 1] =
'\0';
415 for (j=0; j<readerTrackerNbEntries; j++)
417 if (strncmp(readerTracker[j].bus_device,
418 bus_device, BUS_DEVICE_STRSIZE) == 0)
421 readerTracker[j].status = READER_PRESENT;
424 Log2(PCSC_LOG_DEBUG,
"Refresh USB device: %s",
433 HPAddHotPluggable(dev, desc, bus_device,
434 &config_desc->interface[interface], driver, classdriver);
437 libusb_free_config_descriptor(config_desc);
443 for (i=0; i<readerTrackerNbEntries; i++)
445 if ((readerTracker[i].status == READER_ABSENT) &&
446 (readerTracker[i].fullName != NULL))
447 HPRemoveHotPluggable(i);
451 libusb_free_device_list(devs, 1);
454static void * HPEstablishUSBNotifications(
int pipefd[2])
460 r = libusb_init(ctx);
463 Log2(PCSC_LOG_CRITICAL,
"libusb_init failed: %s", libusb_error_name(r));
465 kill(getpid(), SIGTERM);
473 if (write(pipefd[1], &c, 1) == -1)
475 Log2(PCSC_LOG_ERROR,
"write: %s", strerror(errno));
481 for (
int i=0; i<driverSize; i++)
482 if (driverTracker[i].libraryPath)
483 if ((driverTracker[i].ifdCapabilities & IFD_GENERATE_HOTPLUG) == 0)
486 "Driver %s does not support IFD_GENERATE_HOTPLUG. Using active polling instead.",
487 driverTracker[i].bundleName);
488 if (HPForceReaderPolling < 1)
489 HPForceReaderPolling = 1;
493 if (HPForceReaderPolling)
496 "Polling forced every %d second(s)", HPForceReaderPolling);
511 while (read(rescan_pipe[0], &dummy,
sizeof(dummy)) > 0)
515 Log1(PCSC_LOG_INFO,
"Reload serial configuration");
518 RFReCheckReaderConf();
520 Log1(PCSC_LOG_INFO,
"End reload serial configuration");
526 for (
int i=0; i<readerTrackerNbEntries; i++)
528 if (readerTracker[i].fullName != NULL)
529 HPCleanupHotPluggable(i);
532 for (
int i=0; i<driverSize; i++)
535 free(driverTracker[i].bundleName);
536 free(driverTracker[i].libraryPath);
537 free(driverTracker[i].readerName);
538 free(driverTracker[i].CFBundleName);
542 close(rescan_pipe[0]);
545 Log1(PCSC_LOG_INFO,
"Hotplug stopped");
550LONG HPSearchHotPluggables(
const char * hpDirPath)
555 readerTrackerNbEntries = 2;
556 readerTracker = calloc(readerTrackerNbEntries,
sizeof(*readerTracker));
557 for (i=0; i<readerTrackerNbEntries; i++)
559 readerTracker[i].status = READER_ABSENT;
560 readerTracker[i].bus_device[0] =
'\0';
561 readerTracker[i].fullName = NULL;
564 if (HPReadBundleValues(hpDirPath) >= 0)
570 if (pipe(pipefd) == -1)
572 Log2(PCSC_LOG_ERROR,
"pipe: %s", strerror(errno));
577 if (pipe(rescan_pipe) == -1)
579 Log2(PCSC_LOG_ERROR,
"pipe: %s", strerror(errno));
583 ThreadCreate(&usbNotifyThread, 0,
584 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, pipefd);
587 if (read(pipefd[0], &c, 1) == -1)
589 Log2(PCSC_LOG_ERROR,
"read: %s", strerror(errno));
601LONG HPStopHotPluggables(
void)
606 HPReCheckSerialReaders();
608 if (rescan_pipe[1] >= 0)
610 close(rescan_pipe[1]);
614 pthread_join(usbNotifyThread, NULL);
619static LONG HPAddHotPluggable(
struct libusb_device *dev,
620 struct libusb_device_descriptor desc,
621 const char bus_device[],
622 const struct libusb_interface *idesc,
623 struct _driverTracker *driver,
624 struct _driverTracker *classdriver)
627 uint8_t iInterface = 0;
628 uint8_t iSerialNumber = 0;
631 Log2(PCSC_LOG_INFO,
"Adding USB device: %s", bus_device);
633 i = asprintf(&deviceName,
"usb:%04x/%04x:libusb-1.0:%s",
634 desc.idVendor, desc.idProduct, bus_device);
637 Log1(PCSC_LOG_ERROR,
"asprintf() failed");
641 pthread_mutex_lock(&usbNotifierMutex);
644 for (i=0; i<readerTrackerNbEntries; i++)
646 if (readerTracker[i].fullName == NULL)
650 if (i == readerTrackerNbEntries)
652 int new_size = readerTrackerNbEntries + 2;
653 Log3(PCSC_LOG_DEBUG,
"increase from %d to %d readers", readerTrackerNbEntries, new_size);
654 readerTracker = realloc(readerTracker, new_size *
sizeof(*readerTracker));
656 for (
int tmp=readerTrackerNbEntries; tmp<new_size; tmp++)
658 readerTracker[tmp].status = READER_ABSENT;
659 readerTracker[tmp].bus_device[0] =
'\0';
660 readerTracker[tmp].fullName = NULL;
663 i = readerTrackerNbEntries;
664 readerTrackerNbEntries = new_size;
667 strncpy(readerTracker[i].bus_device, bus_device,
668 sizeof(readerTracker[i].bus_device));
669 readerTracker[i].bus_device[
sizeof(readerTracker[i].bus_device) - 1] =
'\0';
670 readerTracker[i].fullName = NULL;
672 if (Add_Interface_In_Name && idesc->num_altsetting > 0)
673 iInterface = idesc->altsetting[0].iInterface;
675 if (Add_Serial_In_Name)
676 iSerialNumber = desc.iSerialNumber;
678 if (iSerialNumber != 0 || iInterface != 0)
680 libusb_device_handle *device;
683 ret = libusb_open(dev, &device);
686 Log2(PCSC_LOG_ERROR,
"libusb_open failed: %s",
687 libusb_error_name(ret));
691 unsigned char interfaceName[MAX_READERNAME];
692 unsigned char serialNumber[MAX_READERNAME];
693 char fullname[MAX_READERNAME * 3];
695 int ret_interface = 0;
700 ret_interface = libusb_get_string_descriptor_ascii(device,
701 iInterface, interfaceName,
sizeof interfaceName);
702 if (ret_interface < 0)
705 "libusb_get_string_descriptor_ascii failed: %s",
706 libusb_error_name(ret_interface));
712 ret_serial = libusb_get_string_descriptor_ascii(device,
713 iSerialNumber, serialNumber,
sizeof serialNumber);
717 "libusb_get_string_descriptor_ascii failed: %s",
718 libusb_error_name(ret_serial));
722 libusb_close(device);
724 if (ret_interface > 0 && ret_serial > 0)
726 snprintf(fullname,
sizeof(fullname),
"%s [%s] (%s)",
727 driver->readerName, interfaceName, serialNumber);
731 if (ret_interface > 0)
733 snprintf(fullname,
sizeof(fullname),
"%s [%s]",
734 driver->readerName, interfaceName);
740 snprintf(fullname,
sizeof(fullname),
"%s (%s)",
741 driver->readerName, serialNumber);
746 if (fullname[0] !=
'\0')
747 readerTracker[i].fullName = strdup(fullname);
751 if (readerTracker[i].fullName == NULL)
752 readerTracker[i].fullName = strdup(driver->readerName);
755 ret = RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
756 driver->libraryPath, deviceName);
758 readerTracker[i].status = READER_PRESENT;
761 Log2(PCSC_LOG_ERROR,
"Failed adding USB device: %s",
764 if (classdriver && driver != classdriver)
767 ret = RFAddReader(readerTracker[i].fullName,
768 PCSCLITE_HP_BASE_PORT + i,
769 classdriver->libraryPath, deviceName);
772 Log2(PCSC_LOG_ERROR,
"Failed adding USB device: %s",
774 readerTracker[i].status = READER_FAILED;
778 readerTracker[i].status = READER_FAILED;
781 if (READER_FAILED == readerTracker[i].status)
782 (void)CheckForOpenCT();
784 pthread_mutex_unlock(&usbNotifierMutex);
791static LONG HPRemoveHotPluggable(
int reader_index)
793 pthread_mutex_lock(&usbNotifierMutex);
795 Log3(PCSC_LOG_INFO,
"Removing USB device[%d]: %s", reader_index,
796 readerTracker[reader_index].bus_device);
798 RFRemoveReader(readerTracker[reader_index].fullName,
799 PCSCLITE_HP_BASE_PORT + reader_index, REMOVE_READER_FLAG_REMOVED);
800 HPCleanupHotPluggable(reader_index);
802 pthread_mutex_unlock(&usbNotifierMutex);
807static void HPCleanupHotPluggable(
int reader_index)
809 free(readerTracker[reader_index].fullName);
810 readerTracker[reader_index].status = READER_ABSENT;
811 readerTracker[reader_index].bus_device[0] =
'\0';
812 readerTracker[reader_index].fullName = NULL;
818ULONG HPRegisterForHotplugEvents(
const char * hpDirPath)
822 (void)pthread_mutex_init(&usbNotifierMutex, NULL);
826void HPReCheckSerialReaders(
void)
829 if (rescan_pipe[1] >= 0)
832 if (write(rescan_pipe[1], &dummy,
sizeof(dummy)) == -1)
833 Log2(PCSC_LOG_ERROR,
"write: %s", strerror(errno));
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
#define SCARD_S_SUCCESS
No error was encountered.
This provides a search API for hot pluggble devices.
Reads lexical config files and updates database.
This keeps track of a list of currently available reader structures.
This handles abstract system level calls.
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
This defines some structures and #defines to be used over the transport layer.
This keeps a list of Windows(R) types.