pcsc-lite  2.5.0
hotplug_libusb.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3  *
4  * Copyright (C) 2001-2004
5  * David Corcoran <corcoran@musclecard.com>
6  * Copyright (C) 2003-2026
7  * Ludovic Rousseau <ludovic.rousseau@free.fr>
8  * Copyright (C) 2003
9  * Toni Andjelkovic <toni@soth.at>
10  * Copyright (C) 2003-2004
11  * Damien Sauveron <damien.sauveron@labri.fr>
12  *
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
15 are met:
16 
17 1. Redistributions of source code must retain the above copyright
18  notice, this list of conditions and the following disclaimer.
19 2. Redistributions in binary form must reproduce the above copyright
20  notice, this list of conditions and the following disclaimer in the
21  documentation and/or other materials provided with the distribution.
22 3. The name of the author may not be used to endorse or promote products
23  derived from this software without specific prior written permission.
24 
25 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
42 #include "config.h"
43 #ifdef HAVE_LIBUSB
44 
45 #define _GNU_SOURCE /* for asprintf(3) */
46 #include <string.h>
47 #include <sys/types.h>
48 #include <stdio.h>
49 #include <dirent.h>
50 #include <fcntl.h>
51 #include <time.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <errno.h>
55 #include <libusb.h>
56 #include <pthread.h>
57 #include <signal.h>
58 #include <stdbool.h>
59 
60 #include "misc.h"
61 #include "wintypes.h"
62 #include "pcscd.h"
63 #include "debuglog.h"
64 #include "parser.h"
65 #include "readerfactory.h"
66 #include "winscard_msg.h"
67 #include "sys_generic.h"
68 #include "hotplug.h"
69 #include "utils.h"
70 
71 #undef DEBUG_HOTPLUG
72 
73 /* format is "%d:%d:%d", bus_number, device_address, interface */
74 #define BUS_DEVICE_STRSIZE 10+1+10+1+10+1
75 
76 #define READER_ABSENT 0
77 #define READER_PRESENT 1
78 #define READER_FAILED 2
79 
80 extern bool Add_Interface_In_Name;
81 extern bool Add_Serial_In_Name;
82 
83 /* we use the default libusb context */
84 #define ctx NULL
85 
86 pthread_mutex_t usbNotifierMutex;
87 
88 static pthread_t usbNotifyThread;
89 static int driverSize = -1;
90 static _Atomic bool ExitHotPlug = false;
91 static int rescan_pipe[] = { -1, -1 };
92 extern int HPForceReaderPolling;
93 
94 /* values of ifdCapabilities bits */
95 #define IFD_GENERATE_HOTPLUG 1
96 
100 static struct _driverTracker
101 {
102  unsigned int manuID;
103  unsigned int productID;
104 
105  char *bundleName;
106  char *libraryPath;
107  char *readerName;
108  int ifdCapabilities;
109  char *CFBundleName;
110 } *driverTracker = NULL;
111 #define DRIVER_TRACKER_SIZE_STEP 8
112 
116 struct _readerTracker
117 {
118  char status;
119  char bus_device[BUS_DEVICE_STRSIZE];
120  char *fullName;
121 };
122 struct _readerTracker *readerTracker;
123 int readerTrackerNbEntries = -1;
124 
125 static 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);
131 static LONG HPRemoveHotPluggable(int reader_index);
132 static void HPCleanupHotPluggable(int reader_index);
133 
134 static LONG HPReadBundleValues(const char * hpDirPath)
135 {
136  LONG rv;
137  DIR *hpDir;
138  struct dirent *currFP = NULL;
139  char fullPath[FILENAME_MAX];
140  char fullLibPath[FILENAME_MAX];
141  int listCount = 0;
142 
143  hpDir = opendir(hpDirPath);
144 
145  if (hpDir == NULL)
146  {
147  Log2(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: %s",
148  hpDirPath);
149  Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
150  return 0;
151  }
152 
153  /* allocate a first array */
154  driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker));
155  if (NULL == driverTracker)
156  {
157  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
158  return -1;
159  }
160  driverSize = DRIVER_TRACKER_SIZE_STEP;
161 
162 #define GET_KEY(key, values) \
163  rv = LTPBundleFindValueWithKey(&plist, key, values); \
164  if (rv) \
165  { \
166  Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
167  fullPath); \
168  continue; \
169  }
170 
171  while ((currFP = readdir(hpDir)) != 0)
172  {
173  if (strstr(currFP->d_name, ".bundle") != 0)
174  {
175  unsigned int alias;
176  list_t plist, *values;
177  list_t *manuIDs, *productIDs, *readerNames;
178  char *libraryPath;
179  int ifdCapabilities;
180  char *CFBundleName;
181 
182  /*
183  * The bundle exists - let's form a full path name and get the
184  * vendor and product ID's for this particular bundle
185  */
186  snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
187  hpDirPath, currFP->d_name);
188  fullPath[sizeof(fullPath) - 1] = '\0';
189 
190  rv = bundleParse(fullPath, &plist);
191  if (rv)
192  continue;
193 
194  /* get CFBundleExecutable */
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,
200  libraryPath);
201  fullLibPath[sizeof(fullLibPath) - 1] = '\0';
202 
203  /* Get ifdCapabilities */
204  GET_KEY(PCSCLITE_HP_CPCTKEY_NAME, &values)
205  ifdCapabilities = strtol(list_get_at(values, 0), NULL, 16);
206 
207  GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
208  GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
209  GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
210 
211  /* Get CFBundleName */
212  rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME,
213  &values);
214  if (rv)
215  CFBundleName = NULL;
216  else
217  CFBundleName = list_get_at(values, 0);
218 
219  /* while we find a nth ifdVendorID in Info.plist */
220  for (alias=0; alias<list_size(manuIDs); alias++)
221  {
222  char *value;
223 
224  /* variables entries */
225  value = list_get_at(manuIDs, alias);
226  driverTracker[listCount].manuID = strtol(value, NULL, 16);
227 
228  value = list_get_at(productIDs, alias);
229  driverTracker[listCount].productID = strtol(value, NULL, 16);
230 
231  driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
232 
233  /* constant entries for a same driver */
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;
239 
240 #ifdef DEBUG_HOTPLUG
241  Log2(PCSC_LOG_INFO, "Found driver for: %s",
242  driverTracker[listCount].readerName);
243 #endif
244  listCount++;
245  if (listCount >= driverSize)
246  {
247  int i;
248 
249  /* increase the array size */
250  driverSize += DRIVER_TRACKER_SIZE_STEP;
251 #ifdef DEBUG_HOTPLUG
252  Log2(PCSC_LOG_INFO,
253  "Increase driverTracker to %d entries", driverSize);
254 #endif
255  void* tmp = realloc(driverTracker,
256  driverSize * sizeof(*driverTracker));
257  if (NULL == tmp)
258  {
259  free(driverTracker);
260  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
261  driverSize = -1;
262  closedir(hpDir);
263  return -1;
264  }
265  driverTracker = tmp;
266 
267  /* clean the newly allocated entries */
268  for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
269  {
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;
277  }
278  }
279  }
280  bundleRelease(&plist);
281  }
282  }
283 
284  driverSize = listCount;
285  closedir(hpDir);
286 
287  if (driverSize == 0)
288  {
289  Log2(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: %s",
290  hpDirPath);
291  Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
292  }
293 #ifdef DEBUG_HOTPLUG
294  else
295  Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
296 #endif
297 
298  return driverSize;
299 }
300 
301 static struct _driverTracker *get_driver(unsigned int idVendor,
302  unsigned int idProduct, struct _driverTracker **classdriver)
303 {
304  int i;
305  static struct _driverTracker *driver;
306 
307 #ifdef DEBUG_HOTPLUG
308  Log3(PCSC_LOG_DEBUG,
309  "Looking for a driver for VID: 0x%04X, PID: 0x%04X",
310  idVendor, idProduct);
311 #endif
312 
313  *classdriver = NULL;
314  driver = NULL;
315  /* check if the device is supported by one driver */
316  for (i=0; i<driverSize; i++)
317  {
318  if (driverTracker[i].libraryPath != NULL &&
319  idVendor == driverTracker[i].manuID &&
320  idProduct == driverTracker[i].productID)
321  {
322  if ((driverTracker[i].CFBundleName != NULL)
323  && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
324  *classdriver = &driverTracker[i];
325  else
326  /* it is not a CCID Class driver */
327  driver = &driverTracker[i];
328  }
329  }
330 
331  /* if we found a specific driver */
332  if (driver)
333  return driver;
334 
335  /* else return the Class driver (if any) */
336  return *classdriver;
337 }
338 
339 static void HPRescanUsbBus(void)
340 {
341  int i, j;
342  char bus_device[BUS_DEVICE_STRSIZE];
343  libusb_device **devs, *dev;
344  ssize_t cnt;
345 
346  for (i=0; i < readerTrackerNbEntries; i++)
347  /* clear roll call */
348  readerTracker[i].status = READER_ABSENT;
349 
350  cnt = libusb_get_device_list(ctx, &devs);
351  if (cnt < 0)
352  {
353  Log2(PCSC_LOG_CRITICAL, "libusb_get_device_list() failed: %s",
354  libusb_error_name(cnt));
355  return;
356  }
357 
358  /* For each USB device */
359  cnt = 0;
360  while ((dev = devs[cnt++]) != NULL)
361  {
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;
367  int interface;
368 
369  int r = libusb_get_device_descriptor(dev, &desc);
370  if (r < 0)
371  {
372  Log4(PCSC_LOG_ERROR,
373  "failed to get device descriptor for %d/%d: %s",
374  bus_number, device_address, libusb_error_name(r));
375  continue;
376  }
377 
378  r = libusb_get_active_config_descriptor(dev, &config_desc);
379  if (r < 0)
380  {
381  Log4(PCSC_LOG_ERROR, "failed to get device config for %d/%d: %s",
382  bus_number, device_address, libusb_error_name(r));
383  continue;
384  }
385 
386  driver = get_driver(desc.idVendor, desc.idProduct, &classdriver);
387  if (NULL == driver)
388  {
389  /* not a smart card reader */
390 #ifdef DEBUG_HOTPLUG
391  Log3(PCSC_LOG_DEBUG, "%d/%d is not a supported smart card reader",
392  bus_number, device_address);
393 #endif
394  libusb_free_config_descriptor(config_desc);
395  continue;
396  }
397 
398 #ifdef DEBUG_HOTPLUG
399  Log3(PCSC_LOG_DEBUG, "Found matching USB device: %d:%d",
400  bus_number, device_address);
401 #endif
402 
403  for (interface = 0; interface < config_desc->bNumInterfaces;
404  interface++)
405  {
406  bool newreader;
407 
408  /* A known device has been found */
409  snprintf(bus_device, BUS_DEVICE_STRSIZE, "%d:%d:%d",
410  bus_number, device_address, interface);
411  bus_device[BUS_DEVICE_STRSIZE - 1] = '\0';
412  newreader = true;
413 
414  /* Check if the reader is a new one */
415  for (j=0; j<readerTrackerNbEntries; j++)
416  {
417  if (strncmp(readerTracker[j].bus_device,
418  bus_device, BUS_DEVICE_STRSIZE) == 0)
419  {
420  /* The reader is already known */
421  readerTracker[j].status = READER_PRESENT;
422  newreader = false;
423 #ifdef DEBUG_HOTPLUG
424  Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s",
425  bus_device);
426 #endif
427  break;
428  }
429  }
430 
431  /* New reader found */
432  if (newreader)
433  HPAddHotPluggable(dev, desc, bus_device,
434  &config_desc->interface[interface], driver, classdriver);
435  }
436 
437  libusb_free_config_descriptor(config_desc);
438  }
439 
440  /*
441  * check if all the previously found readers are still present
442  */
443  for (i=0; i<readerTrackerNbEntries; i++)
444  {
445  if ((readerTracker[i].status == READER_ABSENT) &&
446  (readerTracker[i].fullName != NULL))
447  HPRemoveHotPluggable(i);
448  }
449 
450  /* free the libusb allocated list & devices */
451  libusb_free_device_list(devs, 1);
452 }
453 
454 static void * HPEstablishUSBNotifications(int pipefd[2])
455 {
456  bool do_polling;
457  int r;
458  char c = 42; /* magic value */
459 
460  r = libusb_init(ctx);
461  if (r < 0)
462  {
463  Log2(PCSC_LOG_CRITICAL, "libusb_init failed: %s", libusb_error_name(r));
464  /* emergency exit */
465  kill(getpid(), SIGTERM);
466  return NULL;
467  }
468 
469  /* scan the USB bus for devices at startup */
470  HPRescanUsbBus();
471 
472  /* signal that the initially connected readers are now visible */
473  if (write(pipefd[1], &c, 1) == -1)
474  {
475  Log2(PCSC_LOG_ERROR, "write: %s", strerror(errno));
476  return NULL;
477  }
478 
479  /* if at least one driver do not have IFD_GENERATE_HOTPLUG */
480  do_polling = false;
481  for (int i=0; i<driverSize; i++)
482  if (driverTracker[i].libraryPath)
483  if ((driverTracker[i].ifdCapabilities & IFD_GENERATE_HOTPLUG) == 0)
484  {
485  Log2(PCSC_LOG_INFO,
486  "Driver %s does not support IFD_GENERATE_HOTPLUG. Using active polling instead.",
487  driverTracker[i].bundleName);
488  if (HPForceReaderPolling < 1)
489  HPForceReaderPolling = 1;
490  break;
491  }
492 
493  if (HPForceReaderPolling)
494  {
495  Log2(PCSC_LOG_INFO,
496  "Polling forced every %d second(s)", HPForceReaderPolling);
497  do_polling = true;
498  }
499 
500  if (do_polling)
501  {
502  while (!ExitHotPlug)
503  {
504  SYS_Sleep(HPForceReaderPolling);
505  HPRescanUsbBus();
506  }
507  }
508  else
509  {
510  char dummy;
511  while (read(rescan_pipe[0], &dummy, sizeof(dummy)) > 0)
512  {
513  if (ExitHotPlug)
514  break;
515  Log1(PCSC_LOG_INFO, "Reload serial configuration");
516  HPRescanUsbBus();
517 #ifdef USE_SERIAL
518  RFReCheckReaderConf();
519 #endif
520  Log1(PCSC_LOG_INFO, "End reload serial configuration");
521  }
522  }
523 
524  libusb_exit(ctx);
525 
526  for (int i=0; i<readerTrackerNbEntries; i++)
527  {
528  if (readerTracker[i].fullName != NULL)
529  HPCleanupHotPluggable(i);
530  }
531 
532  for (int i=0; i<driverSize; i++)
533  {
534  /* free strings allocated by strdup() */
535  free(driverTracker[i].bundleName);
536  free(driverTracker[i].libraryPath);
537  free(driverTracker[i].readerName);
538  free(driverTracker[i].CFBundleName);
539  }
540  free(driverTracker);
541 
542  close(rescan_pipe[0]);
543  rescan_pipe[0] = -1;
544 
545  Log1(PCSC_LOG_INFO, "Hotplug stopped");
546 
547  return NULL;
548 }
549 
550 LONG HPSearchHotPluggables(const char * hpDirPath)
551 {
552  int i;
553 
554  ExitHotPlug = false;
555  readerTrackerNbEntries = 2;
556  readerTracker = calloc(readerTrackerNbEntries, sizeof(*readerTracker));
557  for (i=0; i<readerTrackerNbEntries; i++)
558  {
559  readerTracker[i].status = READER_ABSENT;
560  readerTracker[i].bus_device[0] = '\0';
561  readerTracker[i].fullName = NULL;
562  }
563 
564  if (HPReadBundleValues(hpDirPath) >= 0)
565  {
566  /* used for waiting for the initialization completion */
567  int pipefd[2];
568  char c;
569 
570  if (pipe(pipefd) == -1)
571  {
572  Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno));
573  return -1;
574  }
575 
576  /* used for rescan events */
577  if (pipe(rescan_pipe) == -1)
578  {
579  Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno));
580  return -1;
581  }
582 
583  ThreadCreate(&usbNotifyThread, 0,
584  (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, pipefd);
585 
586  /* Wait for initial readers to setup */
587  if (read(pipefd[0], &c, 1) == -1)
588  {
589  Log2(PCSC_LOG_ERROR, "read: %s", strerror(errno));
590  return -1;
591  }
592 
593  /* cleanup pipe fd */
594  close(pipefd[0]);
595  close(pipefd[1]);
596  }
597 
598  return 0;
599 }
600 
601 LONG HPStopHotPluggables(void)
602 {
603  /* tell the rescan thread to shut down; it checks the ExitHotPlug flag, but it
604  * might also need to be awaken from reading the rescan pipe */
605  ExitHotPlug = true;
606  HPReCheckSerialReaders();
607 
608  if (rescan_pipe[1] >= 0)
609  {
610  close(rescan_pipe[1]);
611  rescan_pipe[1] = -1;
612  }
613  /* wait for the rescan thread to complete its cleanup */
614  pthread_join(usbNotifyThread, NULL);
615 
616  return 0;
617 }
618 
619 static 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)
625 {
626  int i;
627  uint8_t iInterface = 0;
628  uint8_t iSerialNumber = 0;
629  char *deviceName;
630 
631  Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device);
632 
633  i = asprintf(&deviceName, "usb:%04x/%04x:libusb-1.0:%s",
634  desc.idVendor, desc.idProduct, bus_device);
635  if (-1 == i)
636  {
637  Log1(PCSC_LOG_ERROR, "asprintf() failed");
638  return 0;
639  }
640 
641  pthread_mutex_lock(&usbNotifierMutex);
642 
643  /* find a free entry */
644  for (i=0; i<readerTrackerNbEntries; i++)
645  {
646  if (readerTracker[i].fullName == NULL)
647  break;
648  }
649 
650  if (i == readerTrackerNbEntries)
651  {
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));
655 
656  for (int tmp=readerTrackerNbEntries; tmp<new_size; tmp++)
657  {
658  readerTracker[tmp].status = READER_ABSENT;
659  readerTracker[tmp].bus_device[0] = '\0';
660  readerTracker[tmp].fullName = NULL;
661  }
662 
663  i = readerTrackerNbEntries; /* new free index */
664  readerTrackerNbEntries = new_size;
665  }
666 
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;
671 
672  if (Add_Interface_In_Name && idesc->num_altsetting > 0)
673  iInterface = idesc->altsetting[0].iInterface;
674 
675  if (Add_Serial_In_Name)
676  iSerialNumber = desc.iSerialNumber;
677 
678  if (iSerialNumber != 0 || iInterface != 0)
679  {
680  libusb_device_handle *device;
681  int ret;
682 
683  ret = libusb_open(dev, &device);
684  if (ret < 0)
685  {
686  Log2(PCSC_LOG_ERROR, "libusb_open failed: %s",
687  libusb_error_name(ret));
688  }
689  else
690  {
691  unsigned char interfaceName[MAX_READERNAME];
692  unsigned char serialNumber[MAX_READERNAME];
693  char fullname[MAX_READERNAME * 3];
694  fullname[0] = '\0';
695  int ret_interface = 0;
696  int ret_serial = 0;
697 
698  if (iInterface)
699  {
700  ret_interface = libusb_get_string_descriptor_ascii(device,
701  iInterface, interfaceName, sizeof interfaceName);
702  if (ret_interface < 0)
703  {
704  Log2(PCSC_LOG_ERROR,
705  "libusb_get_string_descriptor_ascii failed: %s",
706  libusb_error_name(ret_interface));
707  }
708  }
709 
710  if (iSerialNumber)
711  {
712  ret_serial = libusb_get_string_descriptor_ascii(device,
713  iSerialNumber, serialNumber, sizeof serialNumber);
714  if (ret_serial < 0)
715  {
716  Log2(PCSC_LOG_ERROR,
717  "libusb_get_string_descriptor_ascii failed: %s",
718  libusb_error_name(ret_serial));
719  }
720  }
721 
722  libusb_close(device);
723 
724  if (ret_interface > 0 && ret_serial > 0)
725  {
726  snprintf(fullname, sizeof(fullname), "%s [%s] (%s)",
727  driver->readerName, interfaceName, serialNumber);
728  }
729  else
730  {
731  if (ret_interface > 0)
732  {
733  snprintf(fullname, sizeof(fullname), "%s [%s]",
734  driver->readerName, interfaceName);
735  }
736  else
737  {
738  if (ret_serial > 0)
739  {
740  snprintf(fullname, sizeof(fullname), "%s (%s)",
741  driver->readerName, serialNumber);
742  }
743  }
744  }
745 
746  if (fullname[0] != '\0')
747  readerTracker[i].fullName = strdup(fullname);
748  }
749  }
750 
751  if (readerTracker[i].fullName == NULL)
752  readerTracker[i].fullName = strdup(driver->readerName);
753 
754  LONG ret;
755  ret = RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
756  driver->libraryPath, deviceName);
757  /* success by default */
758  readerTracker[i].status = READER_PRESENT;
759  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
760  {
761  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
762  driver->readerName);
763 
764  if (classdriver && driver != classdriver)
765  {
766  /* the reader can also be used by the a class driver */
767  ret = RFAddReader(readerTracker[i].fullName,
768  PCSCLITE_HP_BASE_PORT + i,
769  classdriver->libraryPath, deviceName);
770  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
771  {
772  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
773  driver->readerName);
774  readerTracker[i].status = READER_FAILED;
775  }
776  }
777  else
778  readerTracker[i].status = READER_FAILED;
779  }
780 
781  if (READER_FAILED == readerTracker[i].status)
782  (void)CheckForOpenCT();
783 
784  pthread_mutex_unlock(&usbNotifierMutex);
785 
786  free(deviceName);
787 
788  return 1;
789 } /* End of function */
790 
791 static LONG HPRemoveHotPluggable(int reader_index)
792 {
793  pthread_mutex_lock(&usbNotifierMutex);
794 
795  Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", reader_index,
796  readerTracker[reader_index].bus_device);
797 
798  RFRemoveReader(readerTracker[reader_index].fullName,
799  PCSCLITE_HP_BASE_PORT + reader_index, REMOVE_READER_FLAG_REMOVED);
800  HPCleanupHotPluggable(reader_index);
801 
802  pthread_mutex_unlock(&usbNotifierMutex);
803 
804  return 1;
805 } /* End of function */
806 
807 static void HPCleanupHotPluggable(int reader_index)
808 {
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;
813 } /* End of function */
814 
818 ULONG HPRegisterForHotplugEvents(const char * hpDirPath)
819 {
820  (void)hpDirPath;
821 
822  (void)pthread_mutex_init(&usbNotifierMutex, NULL);
823  return 0;
824 }
825 
826 void HPReCheckSerialReaders(void)
827 {
828  Log0(PCSC_LOG_INFO);
829  if (rescan_pipe[1] >= 0)
830  {
831  char dummy = 0;
832  if (write(rescan_pipe[1], &dummy, sizeof(dummy)) == -1)
833  Log2(PCSC_LOG_ERROR, "write: %s", strerror(errno));
834  }
835 }
836 
837 #endif
838 
list object
Definition: simclist.h:181
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
This handles abstract system level calls.
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
Definition: sys_unix.c:62
Reads lexical config files and updates database.
This defines some structures and #defines to be used over the transport layer.
This keeps a list of Windows(R) types.
This keeps track of a list of currently available reader structures.
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:125
This provides a search API for hot pluggble devices.
This handles debugging.