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