pcsc-lite  1.8.11
hotplug_libudev.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html )
3  *
4  * Copyright (C) 2011
5  * Ludovic Rousseau <ludovic.rousseau@free.fr>
6  *
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10 
11 1. Redistributions of source code must retain the above copyright
12  notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14  notice, this list of conditions and the following disclaimer in the
15  documentation and/or other materials provided with the distribution.
16 3. The name of the author may not be used to endorse or promote products
17  derived from this software without specific prior written permission.
18 
19 Changes to this license can be made only by the copyright author with
20 explicit written consent.
21 
22 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * $Id: hotplug_libudev.c 6851 2014-02-14 15:43:32Z rousseau $
34  */
35 
41 #include "config.h"
42 #if defined(HAVE_LIBUDEV) && defined(USE_USB)
43 
44 #include <string.h>
45 #include <stdio.h>
46 #include <dirent.h>
47 #include <stdlib.h>
48 #include <pthread.h>
49 #include <libudev.h>
50 
51 #include "debuglog.h"
52 #include "parser.h"
53 #include "readerfactory.h"
54 #include "sys_generic.h"
55 #include "hotplug.h"
56 #include "utils.h"
57 #include "strlcpycat.h"
58 
59 #undef DEBUG_HOTPLUG
60 
61 #define FALSE 0
62 #define TRUE 1
63 
64 extern char Add_Interface_In_Name;
65 extern char Add_Serial_In_Name;
66 
67 pthread_mutex_t usbNotifierMutex;
68 
69 static pthread_t usbNotifyThread;
70 static int driverSize = -1;
71 static char AraKiriHotPlug = FALSE;
72 
76 static struct _driverTracker
77 {
78  unsigned int manuID;
79  unsigned int productID;
80 
81  char *bundleName;
82  char *libraryPath;
83  char *readerName;
84  char *CFBundleName;
85 } *driverTracker = NULL;
86 #define DRIVER_TRACKER_SIZE_STEP 10
87 
88 /* The CCID driver already supports 176 readers.
89  * We start with a big array size to avoid reallocation. */
90 #define DRIVER_TRACKER_INITIAL_SIZE 200
91 
92 typedef enum {
93  READER_ABSENT,
94  READER_PRESENT,
95  READER_FAILED
96 } readerState_t;
97 
101 static struct _readerTracker
102 {
103  readerState_t status;
104  char bInterfaceNumber;
105  char *devpath;
106  char *fullName;
107 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
108 
109 
110 static LONG HPReadBundleValues(void)
111 {
112  LONG rv;
113  DIR *hpDir;
114  struct dirent *currFP = NULL;
115  char fullPath[FILENAME_MAX];
116  char fullLibPath[FILENAME_MAX];
117  int listCount = 0;
118 
119  hpDir = opendir(PCSCLITE_HP_DROPDIR);
120 
121  if (NULL == hpDir)
122  {
123  Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
124  Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
125  return -1;
126  }
127 
128  /* allocate a first array */
129  driverSize = DRIVER_TRACKER_INITIAL_SIZE;
130  driverTracker = calloc(driverSize, sizeof(*driverTracker));
131  if (NULL == driverTracker)
132  {
133  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
134  (void)closedir(hpDir);
135  return -1;
136  }
137 
138 #define GET_KEY(key, values) \
139  rv = LTPBundleFindValueWithKey(&plist, key, values); \
140  if (rv) \
141  { \
142  Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
143  fullPath); \
144  continue; \
145  }
146 
147  while ((currFP = readdir(hpDir)) != 0)
148  {
149  if (strstr(currFP->d_name, ".bundle") != 0)
150  {
151  unsigned int alias;
152  list_t plist, *values;
153  list_t *manuIDs, *productIDs, *readerNames;
154  char *CFBundleName;
155  char *libraryPath;
156 
157  /*
158  * The bundle exists - let's form a full path name and get the
159  * vendor and product ID's for this particular bundle
160  */
161  (void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
162  PCSCLITE_HP_DROPDIR, currFP->d_name);
163  fullPath[sizeof(fullPath) - 1] = '\0';
164 
165  rv = bundleParse(fullPath, &plist);
166  if (rv)
167  continue;
168 
169  /* get CFBundleExecutable */
170  GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
171  libraryPath = list_get_at(values, 0);
172  (void)snprintf(fullLibPath, sizeof(fullLibPath),
173  "%s/%s/Contents/%s/%s",
174  PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
175  libraryPath);
176  fullLibPath[sizeof(fullLibPath) - 1] = '\0';
177 
178  GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
179  GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
180  GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
181 
182  if ((list_size(manuIDs) != list_size(productIDs))
183  || (list_size(manuIDs) != list_size(readerNames)))
184  {
185  Log2(PCSC_LOG_CRITICAL, "Error parsing %s", fullPath);
186  (void)closedir(hpDir);
187  return -1;
188  }
189 
190  /* Get CFBundleName */
191  rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME,
192  &values);
193  if (rv)
194  CFBundleName = NULL;
195  else
196  CFBundleName = strdup(list_get_at(values, 0));
197 
198  /* while we find a nth ifdVendorID in Info.plist */
199  for (alias=0; alias<list_size(manuIDs); alias++)
200  {
201  char *value;
202 
203  /* variables entries */
204  value = list_get_at(manuIDs, alias);
205  driverTracker[listCount].manuID = strtol(value, NULL, 16);
206 
207  value = list_get_at(productIDs, alias);
208  driverTracker[listCount].productID = strtol(value, NULL, 16);
209 
210  driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
211 
212  /* constant entries for a same driver */
213  driverTracker[listCount].bundleName = strdup(currFP->d_name);
214  driverTracker[listCount].libraryPath = strdup(fullLibPath);
215  driverTracker[listCount].CFBundleName = CFBundleName;
216 
217 #ifdef DEBUG_HOTPLUG
218  Log2(PCSC_LOG_INFO, "Found driver for: %s",
219  driverTracker[listCount].readerName);
220 #endif
221  listCount++;
222  if (listCount >= driverSize)
223  {
224  int i;
225 
226  /* increase the array size */
227  driverSize += DRIVER_TRACKER_SIZE_STEP;
228 #ifdef DEBUG_HOTPLUG
229  Log2(PCSC_LOG_INFO,
230  "Increase driverTracker to %d entries", driverSize);
231 #endif
232  driverTracker = realloc(driverTracker,
233  driverSize * sizeof(*driverTracker));
234  if (NULL == driverTracker)
235  {
236  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
237  driverSize = -1;
238  (void)closedir(hpDir);
239  return -1;
240  }
241 
242  /* clean the newly allocated entries */
243  for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
244  {
245  driverTracker[i].manuID = 0;
246  driverTracker[i].productID = 0;
247  driverTracker[i].bundleName = NULL;
248  driverTracker[i].libraryPath = NULL;
249  driverTracker[i].readerName = NULL;
250  driverTracker[i].CFBundleName = NULL;
251  }
252  }
253  }
254  bundleRelease(&plist);
255  }
256  }
257 
258  driverSize = listCount;
259  (void)closedir(hpDir);
260 
261 #ifdef DEBUG_HOTPLUG
262  Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
263 #endif
264 
265  return 0;
266 } /* HPReadBundleValues */
267 
268 
269 /*@null@*/ static struct _driverTracker *get_driver(struct udev_device *dev,
270  const char *devpath, struct _driverTracker **classdriver)
271 {
272  int i;
273  unsigned int idVendor, idProduct;
274  static struct _driverTracker *driver;
275  const char *str;
276 
277  str = udev_device_get_sysattr_value(dev, "idVendor");
278  if (!str)
279  {
280  Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
281  return NULL;
282  }
283  idVendor = strtol(str, NULL, 16);
284 
285  str = udev_device_get_sysattr_value(dev, "idProduct");
286  if (!str)
287  {
288  Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
289  return NULL;
290  }
291  idProduct = strtol(str, NULL, 16);
292 
293  Log4(PCSC_LOG_DEBUG,
294  "Looking for a driver for VID: 0x%04X, PID: 0x%04X, path: %s",
295  idVendor, idProduct, devpath);
296 
297  *classdriver = NULL;
298  driver = NULL;
299  /* check if the device is supported by one driver */
300  for (i=0; i<driverSize; i++)
301  {
302  if (driverTracker[i].libraryPath != NULL &&
303  idVendor == driverTracker[i].manuID &&
304  idProduct == driverTracker[i].productID)
305  {
306  if ((driverTracker[i].CFBundleName != NULL)
307  && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
308  *classdriver = &driverTracker[i];
309  else
310  /* it is not a CCID Class driver */
311  driver = &driverTracker[i];
312  }
313  }
314 
315  /* if we found a specific driver */
316  if (driver)
317  return driver;
318 
319  /* else return the Class driver (if any) */
320  return *classdriver;
321 }
322 
323 
324 static void HPAddDevice(struct udev_device *dev, struct udev_device *parent,
325  const char *devpath)
326 {
327  int i;
328  char deviceName[MAX_DEVICENAME];
329  char fullname[MAX_READERNAME];
330  struct _driverTracker *driver, *classdriver;
331  const char *sSerialNumber = NULL, *sInterfaceName = NULL;
332  const char *sInterfaceNumber;
333  LONG ret;
334  int bInterfaceNumber;
335 
336  driver = get_driver(parent, devpath, &classdriver);
337  if (NULL == driver)
338  {
339  /* not a smart card reader */
340 #ifdef DEBUG_HOTPLUG
341  Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
342  devpath);
343 #endif
344  return;
345  }
346 
347  Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
348 
349  sInterfaceNumber = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
350  if (sInterfaceNumber)
351  bInterfaceNumber = atoi(sInterfaceNumber);
352  else
353  bInterfaceNumber = 0;
354 
355  (void)snprintf(deviceName, sizeof(deviceName),
356  "usb:%04x/%04x:libudev:%d:%s", driver->manuID, driver->productID,
357  bInterfaceNumber, devpath);
358  deviceName[sizeof(deviceName) -1] = '\0';
359 
360  (void)pthread_mutex_lock(&usbNotifierMutex);
361 
362  /* find a free entry */
363  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
364  {
365  if (NULL == readerTracker[i].fullName)
366  break;
367  }
368 
369  if (PCSCLITE_MAX_READERS_CONTEXTS == i)
370  {
371  Log2(PCSC_LOG_ERROR,
372  "Not enough reader entries. Already found %d readers", i);
373  (void)pthread_mutex_unlock(&usbNotifierMutex);
374  return;
375  }
376 
377  if (Add_Interface_In_Name)
378  sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
379 
380  if (Add_Serial_In_Name)
381  sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
382 
383  /* name from the Info.plist file */
384  strlcpy(fullname, driver->readerName, sizeof(fullname));
385 
386  /* interface name from the device (if any) */
387  if (sInterfaceName)
388  {
389  strlcat(fullname, " [", sizeof(fullname));
390  strlcat(fullname, sInterfaceName, sizeof(fullname));
391  strlcat(fullname, "]", sizeof(fullname));
392  }
393 
394  /* serial number from the device (if any) */
395  if (sSerialNumber)
396  {
397  /* only add the serial number if it is not already present in the
398  * interface name */
399  if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
400  {
401  strlcat(fullname, " (", sizeof(fullname));
402  strlcat(fullname, sSerialNumber, sizeof(fullname));
403  strlcat(fullname, ")", sizeof(fullname));
404  }
405  }
406 
407  readerTracker[i].fullName = strdup(fullname);
408  readerTracker[i].devpath = strdup(devpath);
409  readerTracker[i].status = READER_PRESENT;
410  readerTracker[i].bInterfaceNumber = bInterfaceNumber;
411 
412  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + i,
413  driver->libraryPath, deviceName);
414  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
415  {
416  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
417  driver->readerName);
418 
419  if (classdriver && driver != classdriver)
420  {
421  /* the reader can also be used by the a class driver */
422  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + i,
423  classdriver->libraryPath, deviceName);
424  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
425  {
426  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
427  driver->readerName);
428 
429  readerTracker[i].status = READER_FAILED;
430 
431  (void)CheckForOpenCT();
432  }
433  }
434  else
435  {
436  readerTracker[i].status = READER_FAILED;
437 
438  (void)CheckForOpenCT();
439  }
440  }
441 
442  (void)pthread_mutex_unlock(&usbNotifierMutex);
443 } /* HPAddDevice */
444 
445 
446 static void HPRescanUsbBus(struct udev *udev)
447 {
448  int i, j;
449  struct udev_enumerate *enumerate;
450  struct udev_list_entry *devices, *dev_list_entry;
451 
452  /* all reader are marked absent */
453  for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
454  readerTracker[i].status = READER_ABSENT;
455 
456  /* Create a list of the devices in the 'usb' subsystem. */
457  enumerate = udev_enumerate_new(udev);
458  udev_enumerate_add_match_subsystem(enumerate, "usb");
459  udev_enumerate_scan_devices(enumerate);
460  devices = udev_enumerate_get_list_entry(enumerate);
461 
462  /* For each item enumerated */
463  udev_list_entry_foreach(dev_list_entry, devices)
464  {
465  const char *devpath;
466  struct udev_device *dev, *parent;
467  struct _driverTracker *driver, *classdriver;
468  int newreader;
469  int bInterfaceNumber;
470  const char *interface;
471 
472  /* Get the filename of the /sys entry for the device
473  and create a udev_device object (dev) representing it */
474  devpath = udev_list_entry_get_name(dev_list_entry);
475  dev = udev_device_new_from_syspath(udev, devpath);
476 
477  /* The device pointed to by dev contains information about
478  the interface. In order to get information about the USB
479  device, get the parent device with the subsystem/devtype pair
480  of "usb"/"usb_device". This will be several levels up the
481  tree, but the function will find it.*/
482  parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
483  "usb_device");
484  if (!parent)
485  continue;
486 
487  devpath = udev_device_get_devnode(parent);
488  if (!devpath)
489  {
490  /* the device disapeared? */
491  Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
492  continue;
493  }
494 
495  driver = get_driver(parent, devpath, &classdriver);
496  if (NULL == driver)
497  /* no driver known for this device */
498  continue;
499 
500 #ifdef DEBUG_HOTPLUG
501  Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
502 #endif
503 
504  newreader = TRUE;
505  bInterfaceNumber = 0;
506  interface = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
507  if (interface)
508  bInterfaceNumber = atoi(interface);
509 
510  /* Check if the reader is a new one */
511  for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
512  {
513  if (readerTracker[j].devpath
514  && (strcmp(readerTracker[j].devpath, devpath) == 0)
515  && (bInterfaceNumber == readerTracker[j].bInterfaceNumber))
516  {
517  /* The reader is already known */
518  readerTracker[j].status = READER_PRESENT;
519  newreader = FALSE;
520 #ifdef DEBUG_HOTPLUG
521  Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s", devpath);
522 #endif
523  break;
524  }
525  }
526 
527  /* New reader found */
528  if (newreader)
529  HPAddDevice(dev, parent, devpath);
530 
531  /* free device */
532  udev_device_unref(dev);
533  }
534 
535  /* Free the enumerator object */
536  udev_enumerate_unref(enumerate);
537 
538  pthread_mutex_lock(&usbNotifierMutex);
539  /* check if all the previously found readers are still present */
540  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
541  {
542  if ((READER_ABSENT == readerTracker[i].status)
543  && (readerTracker[i].fullName != NULL))
544  {
545  Log4(PCSC_LOG_INFO, "Removing USB device[%d]: %s at %s", i,
546  readerTracker[i].fullName, readerTracker[i].devpath);
547 
548  RFRemoveReader(readerTracker[i].fullName,
549  PCSCLITE_HP_BASE_PORT + i);
550 
551  readerTracker[i].status = READER_ABSENT;
552  free(readerTracker[i].devpath);
553  readerTracker[i].devpath = NULL;
554  free(readerTracker[i].fullName);
555  readerTracker[i].fullName = NULL;
556 
557  }
558  }
559  pthread_mutex_unlock(&usbNotifierMutex);
560 }
561 
562 static void HPEstablishUSBNotifications(struct udev *udev)
563 {
564  struct udev_monitor *udev_monitor;
565  int r, i;
566  int fd;
567  fd_set fds;
568 
569  udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
570 
571  /* filter only the interfaces */
572  r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb",
573  "usb_interface");
574  if (r)
575  {
576  Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
577  return;
578  }
579 
580  r = udev_monitor_enable_receiving(udev_monitor);
581  if (r)
582  {
583  Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
584  return;
585  }
586 
587  /* udev monitor file descriptor */
588  fd = udev_monitor_get_fd(udev_monitor);
589 
590  while (!AraKiriHotPlug)
591  {
592  struct udev_device *dev, *parent;
593  const char *action, *devpath;
594 
595 #ifdef DEBUG_HOTPLUG
596  Log0(PCSC_LOG_INFO);
597 #endif
598 
599  FD_ZERO(&fds);
600  FD_SET(fd, &fds);
601 
602  /* wait for a udev event */
603  r = select(fd+1, &fds, NULL, NULL, NULL);
604  if (r < 0)
605  {
606  Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
607  return;
608  }
609 
610  dev = udev_monitor_receive_device(udev_monitor);
611  if (!dev)
612  {
613  Log1(PCSC_LOG_ERROR, "udev_monitor_receive_device() error\n");
614  return;
615  }
616 
617  action = udev_device_get_action(dev);
618  if (0 == strcmp("remove", action))
619  {
620  Log1(PCSC_LOG_INFO, "Device removed");
621  HPRescanUsbBus(udev);
622  continue;
623  }
624 
625  if (strcmp("add", action))
626  continue;
627 
628  parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
629  "usb_device");
630  devpath = udev_device_get_devnode(parent);
631  if (!devpath)
632  {
633  /* the device disapeared? */
634  Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
635  continue;
636  }
637 
638  HPAddDevice(dev, parent, devpath);
639 
640  /* free device */
641  udev_device_unref(dev);
642 
643  }
644 
645  for (i=0; i<driverSize; i++)
646  {
647  /* free strings allocated by strdup() */
648  free(driverTracker[i].bundleName);
649  free(driverTracker[i].libraryPath);
650  free(driverTracker[i].readerName);
651  }
652  free(driverTracker);
653 
654  Log1(PCSC_LOG_INFO, "Hotplug stopped");
655 } /* HPEstablishUSBNotifications */
656 
657 
658 /***
659  * Start a thread waiting for hotplug events
660  */
661 LONG HPSearchHotPluggables(void)
662 {
663  int i;
664 
665  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
666  {
667  readerTracker[i].status = READER_ABSENT;
668  readerTracker[i].bInterfaceNumber = 0;
669  readerTracker[i].devpath = NULL;
670  readerTracker[i].fullName = NULL;
671  }
672 
673  return HPReadBundleValues();
674 } /* HPSearchHotPluggables */
675 
676 
680 LONG HPStopHotPluggables(void)
681 {
682  AraKiriHotPlug = TRUE;
683 
684  return 0;
685 } /* HPStopHotPluggables */
686 
687 
691 ULONG HPRegisterForHotplugEvents(void)
692 {
693  struct udev *udev;
694 
695  (void)pthread_mutex_init(&usbNotifierMutex, NULL);
696 
697  if (driverSize <= 0)
698  {
699  Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: "
700  PCSCLITE_HP_DROPDIR);
701  Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
702  return 0;
703  }
704 
705  /* Create the udev object */
706  udev = udev_new();
707  if (!udev)
708  {
709  Log1(PCSC_LOG_ERROR, "udev_new() failed");
710  return 0;
711  }
712 
713  HPRescanUsbBus(udev);
714 
715  (void)ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
716  (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, udev);
717 
718  return 0;
719 } /* HPRegisterForHotplugEvents */
720 
721 
722 void HPReCheckSerialReaders(void)
723 {
724  /* nothing to do here */
725 #ifdef DEBUG_HOTPLUG
726  Log0(PCSC_LOG_ERROR);
727 #endif
728 } /* HPReCheckSerialReaders */
729 
730 #endif
731 
list object
Definition: simclist.h:181
This handles abstract system level calls.
Reads lexical config files and updates database.
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:221
prototypes of strlcpy()/strlcat() imported from OpenBSD
int LTPBundleFindValueWithKey(list_t *l, const char *key, list_t **values)
Find an optional key in a configuration file No error is logged if the key is not found...
Definition: tokenparser.c:1931
This keeps track of a list of currently available reader structures.
This provides a search API for hot pluggble devices.
int bundleParse(const char *fileName, list_t *l)
Parse a Info.plist file and file a list.
Definition: tokenparser.c:1962
void bundleRelease(list_t *l)
Free the list created by bundleParse()
Definition: tokenparser.c:2020
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:115
#define SCARD_S_SUCCESS
error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx
Definition: pcsclite.h:106
This handles debugging.