pcsc-lite  1.9.9
hotplug_libudev.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
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 
38 #include "config.h"
39 #if defined(HAVE_LIBUDEV) && defined(USE_USB)
40 
41 #define _GNU_SOURCE /* for asprintf(3) */
42 #include <string.h>
43 #include <stdio.h>
44 #include <dirent.h>
45 #include <stdlib.h>
46 #include <pthread.h>
47 #include <libudev.h>
48 #include <poll.h>
49 #include <ctype.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 
58 #ifndef TEMP_FAILURE_RETRY
59 #define TEMP_FAILURE_RETRY(expression) \
60  (__extension__ \
61  ({ long int __result; \
62  do __result = (long int) (expression); \
63  while (__result == -1L && errno == EINTR); \
64  __result; }))
65 #endif
66 
67 #undef DEBUG_HOTPLUG
68 
69 #define FALSE 0
70 #define TRUE 1
71 
72 extern char Add_Interface_In_Name;
73 extern char Add_Serial_In_Name;
74 
75 static pthread_t usbNotifyThread;
76 static int driverSize = -1;
77 static struct udev *Udev;
78 
79 
83 static struct _driverTracker
84 {
85  unsigned int manuID;
86  unsigned int productID;
87 
88  char *bundleName;
89  char *libraryPath;
90  char *readerName;
91  char *CFBundleName;
92 } *driverTracker = NULL;
93 #define DRIVER_TRACKER_SIZE_STEP 10
94 
95 /* The CCID driver already supports 176 readers.
96  * We start with a big array size to avoid reallocation. */
97 #define DRIVER_TRACKER_INITIAL_SIZE 200
98 
102 static struct _readerTracker
103 {
104  char *devpath;
105  char *fullName;
106  char *sysname;
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 
233  void* tmp = realloc(driverTracker,
234  driverSize * sizeof(*driverTracker));
235 
236  if (NULL == tmp)
237  {
238  free(driverTracker);
239  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
240  driverSize = -1;
241  (void)closedir(hpDir);
242  return -1;
243  }
244  driverTracker = tmp;
245 
246  /* clean the newly allocated entries */
247  for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
248  {
249  driverTracker[i].manuID = 0;
250  driverTracker[i].productID = 0;
251  driverTracker[i].bundleName = NULL;
252  driverTracker[i].libraryPath = NULL;
253  driverTracker[i].readerName = NULL;
254  driverTracker[i].CFBundleName = NULL;
255  }
256  }
257  }
258  bundleRelease(&plist);
259  }
260  }
261 
262  driverSize = listCount;
263  (void)closedir(hpDir);
264 
265 #ifdef DEBUG_HOTPLUG
266  Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
267 #endif
268 
269  return 0;
270 } /* HPReadBundleValues */
271 
272 
273 /*@null@*/ static struct _driverTracker *get_driver(struct udev_device *dev,
274  const char *devpath, struct _driverTracker **classdriver)
275 {
276  int i;
277  unsigned int idVendor, idProduct;
278  static struct _driverTracker *driver;
279  const char *str;
280 
281  str = udev_device_get_sysattr_value(dev, "idVendor");
282  if (!str)
283  {
284  Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
285  return NULL;
286  }
287  idVendor = strtol(str, NULL, 16);
288 
289  str = udev_device_get_sysattr_value(dev, "idProduct");
290  if (!str)
291  {
292  Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
293  return NULL;
294  }
295  idProduct = strtol(str, NULL, 16);
296 
297 #ifdef NO_LOG
298  (void)devpath;
299 #endif
300  Log4(PCSC_LOG_DEBUG,
301  "Looking for a driver for VID: 0x%04X, PID: 0x%04X, path: %s",
302  idVendor, idProduct, devpath);
303 
304  *classdriver = NULL;
305  driver = NULL;
306  /* check if the device is supported by one driver */
307  for (i=0; i<driverSize; i++)
308  {
309  if (driverTracker[i].libraryPath != NULL &&
310  idVendor == driverTracker[i].manuID &&
311  idProduct == driverTracker[i].productID)
312  {
313  if ((driverTracker[i].CFBundleName != NULL)
314  && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
315  *classdriver = &driverTracker[i];
316  else
317  /* it is not a CCID Class driver */
318  driver = &driverTracker[i];
319  }
320  }
321 
322  /* if we found a specific driver */
323  if (driver)
324  return driver;
325 
326  /* else return the Class driver (if any) */
327  return *classdriver;
328 }
329 
330 
331 static void HPRemoveDevice(struct udev_device *dev)
332 {
333  int i;
334  const char *sysname;
335 
336  sysname = udev_device_get_sysname(dev);
337  if (!sysname)
338  {
339  Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
340  return;
341  }
342 
343  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
344  {
345  if (readerTracker[i].fullName && !strcmp(sysname, readerTracker[i].sysname))
346  {
347  Log4(PCSC_LOG_INFO, "Removing USB device[%d]: %s at %s", i,
348  readerTracker[i].fullName, readerTracker[i].devpath);
349 
350  RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i, REMOVE_READER_FLAG_REMOVED);
351 
352  free(readerTracker[i].devpath);
353  readerTracker[i].devpath = NULL;
354  free(readerTracker[i].fullName);
355  readerTracker[i].fullName = NULL;
356  free(readerTracker[i].sysname);
357  readerTracker[i].sysname = NULL;
358  break;
359  }
360  }
361 }
362 
363 
364 static void HPAddDevice(struct udev_device *dev)
365 {
366  int index, a;
367  char *deviceName = NULL;
368  char *fullname = NULL;
369  struct _driverTracker *driver, *classdriver;
370  const char *sSerialNumber = NULL, *sInterfaceName = NULL;
371  const char *sInterfaceNumber;
372  LONG ret;
373  int bInterfaceNumber;
374  const char *devpath;
375  struct udev_device *parent;
376  const char *sysname;
377 
378  /* The device pointed to by dev contains information about
379  the interface. In order to get information about the USB
380  device, get the parent device with the subsystem/devtype pair
381  of "usb"/"usb_device". This will be several levels up the
382  tree, but the function will find it.*/
383  parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
384  "usb_device");
385  if (!parent)
386  return;
387 
388  devpath = udev_device_get_devnode(parent);
389  if (!devpath)
390  {
391  /* the device disapeared? */
392  Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
393  return;
394  }
395 
396  driver = get_driver(parent, devpath, &classdriver);
397  if (NULL == driver)
398  {
399  /* not a smart card reader */
400 #ifdef DEBUG_HOTPLUG
401  Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
402  devpath);
403 #endif
404  return;
405  }
406 
407  sysname = udev_device_get_sysname(dev);
408  if (!sysname)
409  {
410  Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
411  return;
412  }
413 
414  /* check for duplicated add */
415  for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
416  {
417  if (readerTracker[index].fullName && !strcmp(sysname, readerTracker[index].sysname))
418  return;
419  }
420 
421  Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
422 
423  sInterfaceNumber = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
424  if (sInterfaceNumber)
425  bInterfaceNumber = atoi(sInterfaceNumber);
426  else
427  bInterfaceNumber = 0;
428 
429  a = asprintf(&deviceName, "usb:%04x/%04x:libudev:%d:%s",
430  driver->manuID, driver->productID, bInterfaceNumber, devpath);
431  if (-1 == a)
432  {
433  Log1(PCSC_LOG_ERROR, "asprintf() failed");
434  return;
435  }
436 
437  /* find a free entry */
438  for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
439  {
440  if (NULL == readerTracker[index].fullName)
441  break;
442  }
443 
444  if (PCSCLITE_MAX_READERS_CONTEXTS == index)
445  {
446  Log2(PCSC_LOG_ERROR,
447  "Not enough reader entries. Already found %d readers", index);
448  goto exit;
449  }
450 
451  if (Add_Interface_In_Name)
452  sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
453 
454  if (Add_Serial_In_Name)
455  sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
456 
457  /* name from the Info.plist file */
458  fullname = strdup(driver->readerName);
459 
460  /* interface name from the device (if any) */
461  if (sInterfaceName)
462  {
463  char *result;
464 
465  char *tmpInterfaceName = strdup(sInterfaceName);
466 
467  /* check the interface name contains only valid ASCII codes */
468  for (size_t i=0; i<strlen(tmpInterfaceName); i++)
469  {
470  if (! isascii(tmpInterfaceName[i]))
471  tmpInterfaceName[i] = '.';
472  }
473 
474  /* create a new name */
475  a = asprintf(&result, "%s [%s]", fullname, tmpInterfaceName);
476  if (-1 == a)
477  {
478  Log1(PCSC_LOG_ERROR, "asprintf() failed");
479  free(tmpInterfaceName);
480  goto exit;
481  }
482 
483  free(fullname);
484  free(tmpInterfaceName);
485  fullname = result;
486  }
487 
488  /* serial number from the device (if any) */
489  if (sSerialNumber)
490  {
491  /* only add the serial number if it is not already present in the
492  * interface name */
493  if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
494  {
495  char *result;
496 
497  /* create a new name */
498  a = asprintf(&result, "%s (%s)", fullname, sSerialNumber);
499  if (-1 == a)
500  {
501  Log1(PCSC_LOG_ERROR, "asprintf() failed");
502  goto exit;
503  }
504 
505  free(fullname);
506  fullname = result;
507  }
508  }
509 
510  readerTracker[index].fullName = strdup(fullname);
511  readerTracker[index].devpath = strdup(devpath);
512  readerTracker[index].sysname = strdup(sysname);
513 
514  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
515  driver->libraryPath, deviceName);
516  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
517  {
518  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
519  driver->readerName);
520 
521  if (classdriver && driver != classdriver)
522  {
523  /* the reader can also be used by the a class driver */
524  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
525  classdriver->libraryPath, deviceName);
526  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
527  {
528  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
529  driver->readerName);
530  (void)CheckForOpenCT();
531  }
532  }
533  else
534  {
535  (void)CheckForOpenCT();
536  }
537  }
538 
539  if (SCARD_S_SUCCESS != ret)
540  {
541  /* adding the reader failed */
542  free(readerTracker[index].devpath);
543  readerTracker[index].devpath = NULL;
544  free(readerTracker[index].fullName);
545  readerTracker[index].fullName = NULL;
546  free(readerTracker[index].sysname);
547  readerTracker[index].sysname = NULL;
548  }
549 
550 exit:
551  free(fullname);
552  free(deviceName);
553 } /* HPAddDevice */
554 
555 
556 static void HPScanUSB(struct udev *udev)
557 {
558  struct udev_enumerate *enumerate;
559  struct udev_list_entry *devices, *dev_list_entry;
560 
561  /* Create a list of the devices in the 'usb' subsystem. */
562  enumerate = udev_enumerate_new(udev);
563  udev_enumerate_add_match_subsystem(enumerate, "usb");
564  udev_enumerate_scan_devices(enumerate);
565  devices = udev_enumerate_get_list_entry(enumerate);
566 
567  /* For each item enumerated */
568  udev_list_entry_foreach(dev_list_entry, devices)
569  {
570  struct udev_device *dev;
571  const char *devpath;
572 
573  /* Get the filename of the /sys entry for the device
574  and create a udev_device object (dev) representing it */
575  devpath = udev_list_entry_get_name(dev_list_entry);
576  dev = udev_device_new_from_syspath(udev, devpath);
577 
578 #ifdef DEBUG_HOTPLUG
579  Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
580 #endif
581  HPAddDevice(dev);
582 
583  /* free device */
584  udev_device_unref(dev);
585  }
586 
587  /* Free the enumerator object */
588  udev_enumerate_unref(enumerate);
589 }
590 
591 
592 static void * HPEstablishUSBNotifications(void *arg)
593 {
594  struct udev_monitor *udev_monitor = arg;
595  int r;
596  int fd;
597  struct pollfd pfd;
598 
599  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
600  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
601 
602  /* udev monitor file descriptor */
603  fd = udev_monitor_get_fd(udev_monitor);
604  if (fd < 0)
605  {
606  Log2(PCSC_LOG_ERROR, "udev_monitor_get_fd() error: %d", fd);
607  pthread_exit(NULL);
608  }
609 
610  pfd.fd = fd;
611  pfd.events = POLLIN;
612 
613  for (;;)
614  {
615  struct udev_device *dev;
616 
617 #ifdef DEBUG_HOTPLUG
618  Log0(PCSC_LOG_INFO);
619 #endif
620  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
621 
622  /* wait for a udev event */
623  r = TEMP_FAILURE_RETRY(poll(&pfd, 1, -1));
624  if (r < 0)
625  {
626  Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
627  pthread_exit(NULL);
628  }
629 
630  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
631 
632  dev = udev_monitor_receive_device(udev_monitor);
633  if (dev)
634  {
635  const char *action = udev_device_get_action(dev);
636 
637  if (action)
638  {
639  if (!strcmp("remove", action))
640  {
641  Log1(PCSC_LOG_INFO, "USB Device removed");
642  HPRemoveDevice(dev);
643  }
644  else
645  if (!strcmp("add", action))
646  {
647  Log1(PCSC_LOG_INFO, "USB Device add");
648  HPAddDevice(dev);
649  }
650  }
651 
652  /* free device */
653  udev_device_unref(dev);
654  }
655  }
656 
657  pthread_exit(NULL);
658 } /* HPEstablishUSBNotifications */
659 
660 
661 /***
662  * Start a thread waiting for hotplug events
663  */
664 LONG HPSearchHotPluggables(void)
665 {
666  int i;
667 
668  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
669  {
670  readerTracker[i].devpath = NULL;
671  readerTracker[i].fullName = NULL;
672  readerTracker[i].sysname = NULL;
673  }
674 
675  return HPReadBundleValues();
676 } /* HPSearchHotPluggables */
677 
678 
682 LONG HPStopHotPluggables(void)
683 {
684  int i;
685 
686  if (driverSize <= 0)
687  return 0;
688 
689  if (!Udev)
690  return 0;
691 
692  pthread_cancel(usbNotifyThread);
693  pthread_join(usbNotifyThread, NULL);
694 
695  for (i=0; i<driverSize; i++)
696  {
697  /* free strings allocated by strdup() */
698  free(driverTracker[i].bundleName);
699  free(driverTracker[i].libraryPath);
700  free(driverTracker[i].readerName);
701  }
702  free(driverTracker);
703 
704  udev_unref(Udev);
705 
706  Udev = NULL;
707  driverSize = -1;
708 
709  Log1(PCSC_LOG_INFO, "Hotplug stopped");
710  return 0;
711 } /* HPStopHotPluggables */
712 
713 
717 ULONG HPRegisterForHotplugEvents(void)
718 {
719  struct udev_monitor *udev_monitor;
720  int r;
721 
722  if (driverSize <= 0)
723  {
724  Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: "
725  PCSCLITE_HP_DROPDIR);
726  Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
727  return 0;
728  }
729 
730  /* Create the udev object */
731  Udev = udev_new();
732  if (!Udev)
733  {
734  Log1(PCSC_LOG_ERROR, "udev_new() failed");
735  return SCARD_F_INTERNAL_ERROR;
736  }
737 
738  udev_monitor = udev_monitor_new_from_netlink(Udev, "udev");
739  if (NULL == udev_monitor)
740  {
741  Log1(PCSC_LOG_ERROR, "udev_monitor_new_from_netlink() error");
742  pthread_exit(NULL);
743  }
744 
745  /* filter only the interfaces */
746  r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb",
747  "usb_interface");
748  if (r)
749  {
750  Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
751  pthread_exit(NULL);
752  }
753 
754  r = udev_monitor_enable_receiving(udev_monitor);
755  if (r)
756  {
757  Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
758  pthread_exit(NULL);
759  }
760 
761  /* scan the USB bus at least once before accepting client connections */
762  HPScanUSB(Udev);
763 
764  if (ThreadCreate(&usbNotifyThread, 0,
765  (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, udev_monitor))
766  {
767  Log1(PCSC_LOG_ERROR, "ThreadCreate() failed");
768  return SCARD_F_INTERNAL_ERROR;
769  }
770 
771  return 0;
772 } /* HPRegisterForHotplugEvents */
773 
774 
775 void HPReCheckSerialReaders(void)
776 {
777  /* nothing to do here */
778 #ifdef DEBUG_HOTPLUG
779  Log0(PCSC_LOG_ERROR);
780 #endif
781 } /* HPReCheckSerialReaders */
782 
783 #endif
784 
This handles debugging.
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:109
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:125
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
This provides a search API for hot pluggble devices.
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:284
This keeps track of a list of currently available reader structures.
list object
Definition: simclist.h:181
This handles abstract system level calls.