pcsc-lite  1.8.13
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: hotplug_libudev.c 7033 2014-11-07 10:04:52Z rousseau $
33  */
34 
40 #include "config.h"
41 #if defined(HAVE_LIBUDEV) && defined(USE_USB)
42 
43 #include <string.h>
44 #include <stdio.h>
45 #include <dirent.h>
46 #include <stdlib.h>
47 #include <pthread.h>
48 #include <libudev.h>
49 #include <poll.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 #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[MAX_DEVICENAME];
382  char fullname[MAX_READERNAME];
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  (void)snprintf(deviceName, sizeof(deviceName),
444  "usb:%04x/%04x:libudev:%d:%s", driver->manuID, driver->productID,
445  bInterfaceNumber, devpath);
446  deviceName[sizeof(deviceName) -1] = '\0';
447 
448  /* find a free entry */
449  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
450  {
451  if (NULL == readerTracker[i].fullName)
452  break;
453  }
454 
455  if (PCSCLITE_MAX_READERS_CONTEXTS == i)
456  {
457  Log2(PCSC_LOG_ERROR,
458  "Not enough reader entries. Already found %d readers", i);
459  return;
460  }
461 
462  if (Add_Interface_In_Name)
463  sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
464 
465  if (Add_Serial_In_Name)
466  sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
467 
468  /* name from the Info.plist file */
469  strlcpy(fullname, driver->readerName, sizeof(fullname));
470 
471  /* interface name from the device (if any) */
472  if (sInterfaceName)
473  {
474  strlcat(fullname, " [", sizeof(fullname));
475  strlcat(fullname, sInterfaceName, sizeof(fullname));
476  strlcat(fullname, "]", sizeof(fullname));
477  }
478 
479  /* serial number from the device (if any) */
480  if (sSerialNumber)
481  {
482  /* only add the serial number if it is not already present in the
483  * interface name */
484  if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
485  {
486  strlcat(fullname, " (", sizeof(fullname));
487  strlcat(fullname, sSerialNumber, sizeof(fullname));
488  strlcat(fullname, ")", sizeof(fullname));
489  }
490  }
491 
492  readerTracker[i].fullName = strdup(fullname);
493  readerTracker[i].devpath = strdup(devpath);
494  readerTracker[i].sysname = strdup(sysname);
495 
496  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + i,
497  driver->libraryPath, deviceName);
498  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
499  {
500  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
501  driver->readerName);
502 
503  if (classdriver && driver != classdriver)
504  {
505  /* the reader can also be used by the a class driver */
506  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + i,
507  classdriver->libraryPath, deviceName);
508  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
509  {
510  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
511  driver->readerName);
512  (void)CheckForOpenCT();
513  }
514  }
515  else
516  {
517  (void)CheckForOpenCT();
518  }
519  }
520 } /* HPAddDevice */
521 
522 
523 static void HPScanUSB(struct udev *udev)
524 {
525  struct udev_enumerate *enumerate;
526  struct udev_list_entry *devices, *dev_list_entry;
527 
528  /* Create a list of the devices in the 'usb' subsystem. */
529  enumerate = udev_enumerate_new(udev);
530  udev_enumerate_add_match_subsystem(enumerate, "usb");
531  udev_enumerate_scan_devices(enumerate);
532  devices = udev_enumerate_get_list_entry(enumerate);
533 
534  /* For each item enumerated */
535  udev_list_entry_foreach(dev_list_entry, devices)
536  {
537  struct udev_device *dev;
538  const char *devpath;
539 
540  /* Get the filename of the /sys entry for the device
541  and create a udev_device object (dev) representing it */
542  devpath = udev_list_entry_get_name(dev_list_entry);
543  dev = udev_device_new_from_syspath(udev, devpath);
544 
545 #ifdef DEBUG_HOTPLUG
546  Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
547 #endif
548  HPAddDevice(dev);
549 
550  /* free device */
551  udev_device_unref(dev);
552  }
553 
554  /* Free the enumerator object */
555  udev_enumerate_unref(enumerate);
556 }
557 
558 
559 static void HPEstablishUSBNotifications(void *arg)
560 {
561  struct udev_monitor *udev_monitor = arg;
562  int r;
563  int fd;
564  struct pollfd pfd;
565 
566  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
567  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
568 
569  /* udev monitor file descriptor */
570  fd = udev_monitor_get_fd(udev_monitor);
571  if (fd < 0)
572  {
573  Log2(PCSC_LOG_ERROR, "udev_monitor_get_fd() error: %d", fd);
574  pthread_exit(NULL);
575  }
576 
577  pfd.fd = fd;
578  pfd.events = POLLIN;
579 
580  for (;;)
581  {
582  struct udev_device *dev;
583 
584 #ifdef DEBUG_HOTPLUG
585  Log0(PCSC_LOG_INFO);
586 #endif
587  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
588 
589  /* wait for a udev event */
590  r = TEMP_FAILURE_RETRY(poll(&pfd, 1, -1));
591  if (r < 0)
592  {
593  Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
594  pthread_exit(NULL);
595  }
596 
597  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
598 
599  dev = udev_monitor_receive_device(udev_monitor);
600  if (dev)
601  {
602  const char *action = udev_device_get_action(dev);
603 
604  if (action)
605  {
606  if (!strcmp("remove", action))
607  {
608  Log1(PCSC_LOG_INFO, "USB Device removed");
609  HPRemoveDevice(dev);
610  }
611  else
612  if (!strcmp("add", action))
613  {
614  Log1(PCSC_LOG_INFO, "USB Device add");
615  HPAddDevice(dev);
616  }
617  }
618 
619  /* free device */
620  udev_device_unref(dev);
621  }
622  }
623 
624  pthread_exit(NULL);
625 } /* HPEstablishUSBNotifications */
626 
627 
628 /***
629  * Start a thread waiting for hotplug events
630  */
631 LONG HPSearchHotPluggables(void)
632 {
633  int i;
634 
635  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
636  {
637  readerTracker[i].devpath = NULL;
638  readerTracker[i].fullName = NULL;
639  readerTracker[i].sysname = NULL;
640  }
641 
642  return HPReadBundleValues();
643 } /* HPSearchHotPluggables */
644 
645 
649 LONG HPStopHotPluggables(void)
650 {
651  int i;
652 
653  if (driverSize <= 0)
654  return 0;
655 
656  if (!Udev)
657  return 0;
658 
659  pthread_cancel(usbNotifyThread);
660  pthread_join(usbNotifyThread, NULL);
661 
662  for (i=0; i<driverSize; i++)
663  {
664  /* free strings allocated by strdup() */
665  free(driverTracker[i].bundleName);
666  free(driverTracker[i].libraryPath);
667  free(driverTracker[i].readerName);
668  }
669  free(driverTracker);
670 
671  udev_unref(Udev);
672 
673  Udev = NULL;
674  driverSize = -1;
675 
676  Log1(PCSC_LOG_INFO, "Hotplug stopped");
677  return 0;
678 } /* HPStopHotPluggables */
679 
680 
684 ULONG HPRegisterForHotplugEvents(void)
685 {
686  struct udev_monitor *udev_monitor;
687  int r;
688 
689  if (driverSize <= 0)
690  {
691  Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: "
692  PCSCLITE_HP_DROPDIR);
693  Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
694  return 0;
695  }
696 
697  /* Create the udev object */
698  Udev = udev_new();
699  if (!Udev)
700  {
701  Log1(PCSC_LOG_ERROR, "udev_new() failed");
702  return SCARD_F_INTERNAL_ERROR;
703  }
704 
705  udev_monitor = udev_monitor_new_from_netlink(Udev, "udev");
706  if (NULL == udev_monitor)
707  {
708  Log1(PCSC_LOG_ERROR, "udev_monitor_new_from_netlink() error");
709  pthread_exit(NULL);
710  }
711 
712  /* filter only the interfaces */
713  r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb",
714  "usb_interface");
715  if (r)
716  {
717  Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
718  pthread_exit(NULL);
719  }
720 
721  r = udev_monitor_enable_receiving(udev_monitor);
722  if (r)
723  {
724  Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
725  pthread_exit(NULL);
726  }
727 
728  /* scan the USB bus at least once before accepting client connections */
729  HPScanUSB(Udev);
730 
731  if (ThreadCreate(&usbNotifyThread, 0,
732  (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, udev_monitor))
733  {
734  Log1(PCSC_LOG_ERROR, "ThreadCreate() failed");
735  return SCARD_F_INTERNAL_ERROR;
736  }
737 
738  return 0;
739 } /* HPRegisterForHotplugEvents */
740 
741 
742 void HPReCheckSerialReaders(void)
743 {
744  /* nothing to do here */
745 #ifdef DEBUG_HOTPLUG
746  Log0(PCSC_LOG_ERROR);
747 #endif
748 } /* HPReCheckSerialReaders */
749 
750 #endif
751 
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
prototypes of strlcpy()/strlcat() imported from OpenBSD
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