pcsc-lite 2.5.0
hotplug_libudev.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 2011-2026
5 * Ludovic Rousseau <ludovic.rousseau@free.fr>
6 * Copyright (C) 2014
7 * Stefani Seibold <stefani@seibold.net>
8 *
9Redistribution and use in source and binary forms, with or without
10modification, are permitted provided that the following conditions
11are met:
12
131. Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
152. 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.
183. 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
21THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
37
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#include <stdbool.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
70extern bool Add_Interface_In_Name;
71extern bool Add_Serial_In_Name;
72
73static pthread_t usbNotifyThread;
74static int driverSize = -1;
75static struct udev *Udev;
76static struct udev_monitor *Udev_monitor;
77
78
82static struct _driverTracker
83{
84 unsigned int manuID;
85 unsigned int productID;
86
87 char *bundleName;
88 char *libraryPath;
89 char *readerName;
90 char *CFBundleName;
91} *driverTracker = NULL;
92#define DRIVER_TRACKER_SIZE_STEP 10
93
94/* The CCID driver already supports 176 readers.
95 * We start with a big array size to avoid reallocation. */
96#define DRIVER_TRACKER_INITIAL_SIZE 200
97
101struct _readerTracker
102{
103 char *devpath;
104 char *fullName;
105 char *sysname;
106};
107struct _readerTracker *readerTracker = NULL;
108int readerTrackerNbEntries = -1;
109
110
111static LONG HPReadBundleValues(const char * hpDirPath)
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(hpDirPath);
121
122 if (NULL == hpDir)
123 {
124 Log2(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: %s", hpDirPath);
125 Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
126 return 0;
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 hpDirPath, 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 hpDirPath, 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 = 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 ? strdup(CFBundleName) : NULL;
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
234 void* tmp = realloc(driverTracker,
235 driverSize * sizeof(*driverTracker));
236
237 if (NULL == tmp)
238 {
239 free(driverTracker);
240 Log1(PCSC_LOG_CRITICAL, "Not enough memory");
241 driverSize = -1;
242 (void)closedir(hpDir);
243 return -1;
244 }
245 driverTracker = tmp;
246
247 /* clean the newly allocated entries */
248 for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
249 {
250 driverTracker[i].manuID = 0;
251 driverTracker[i].productID = 0;
252 driverTracker[i].bundleName = NULL;
253 driverTracker[i].libraryPath = NULL;
254 driverTracker[i].readerName = NULL;
255 driverTracker[i].CFBundleName = NULL;
256 }
257 }
258 }
259 bundleRelease(&plist);
260 }
261 }
262
263 driverSize = listCount;
264 (void)closedir(hpDir);
265
266#ifdef DEBUG_HOTPLUG
267 Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
268#endif
269
270 return 0;
271} /* HPReadBundleValues */
272
273
274/*@null@*/ static struct _driverTracker *get_driver(struct udev_device *dev,
275 const char *devpath, struct _driverTracker **classdriver)
276{
277 int i;
278 unsigned int idVendor, idProduct;
279 static struct _driverTracker *driver;
280 const char *str;
281
282 str = udev_device_get_sysattr_value(dev, "idVendor");
283 if (!str)
284 {
285 Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
286 return NULL;
287 }
288 idVendor = strtol(str, NULL, 16);
289
290 str = udev_device_get_sysattr_value(dev, "idProduct");
291 if (!str)
292 {
293 Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
294 return NULL;
295 }
296 idProduct = strtol(str, NULL, 16);
297
298#ifdef NO_LOG
299 (void)devpath;
300#endif
301 Log4(PCSC_LOG_DEBUG,
302 "Looking for a driver for VID: 0x%04X, PID: 0x%04X, path: %s",
303 idVendor, idProduct, devpath);
304
305 *classdriver = NULL;
306 driver = NULL;
307 /* check if the device is supported by one driver */
308 for (i=0; i<driverSize; i++)
309 {
310 if (driverTracker[i].libraryPath != NULL &&
311 idVendor == driverTracker[i].manuID &&
312 idProduct == driverTracker[i].productID)
313 {
314 if ((driverTracker[i].CFBundleName != NULL)
315 && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
316 *classdriver = &driverTracker[i];
317 else
318 /* it is not a CCID Class driver */
319 driver = &driverTracker[i];
320 }
321 }
322
323 /* if we found a specific driver */
324 if (driver)
325 return driver;
326
327 /* else return the Class driver (if any) */
328 return *classdriver;
329}
330
331
332static void HPRemoveDevice(struct udev_device *dev)
333{
334 int i;
335 const char *sysname;
336
337 sysname = udev_device_get_sysname(dev);
338 if (!sysname)
339 {
340 Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
341 return;
342 }
343
344 for (i=0; i<readerTrackerNbEntries; i++)
345 {
346 if (readerTracker[i].fullName && !strcmp(sysname, readerTracker[i].sysname))
347 {
348 Log4(PCSC_LOG_INFO, "Removing USB device[%d]: %s at %s", i,
349 readerTracker[i].fullName, readerTracker[i].devpath);
350
351 RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i, REMOVE_READER_FLAG_REMOVED);
352
353 free(readerTracker[i].devpath);
354 readerTracker[i].devpath = NULL;
355 free(readerTracker[i].fullName);
356 readerTracker[i].fullName = NULL;
357 free(readerTracker[i].sysname);
358 readerTracker[i].sysname = NULL;
359 break;
360 }
361 }
362}
363
364
365static void HPAddDevice(struct udev_device *dev)
366{
367 int index, a;
368 char *deviceName = NULL;
369 char *fullname = NULL;
370 struct _driverTracker *driver, *classdriver;
371 const char *sSerialNumber = NULL, *sInterfaceName = NULL;
372 const char *sInterfaceNumber;
373 LONG ret;
374 int bInterfaceNumber;
375 const char *devpath;
376 struct udev_device *parent;
377 const char *sysname;
378 const char *ignoreprop;
379
380 /* The device pointed to by dev contains information about
381 the interface. In order to get information about the USB
382 device, get the parent device with the subsystem/devtype pair
383 of "usb"/"usb_device". This will be several levels up the
384 tree, but the function will find it.*/
385 parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
386 "usb_device");
387 if (!parent)
388 return;
389
390 devpath = udev_device_get_devnode(parent);
391 if (!devpath)
392 {
393 /* the device disappeared? */
394 Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
395 return;
396 }
397
398 driver = get_driver(parent, devpath, &classdriver);
399 if (NULL == driver)
400 {
401 /* not a smart card reader */
402#ifdef DEBUG_HOTPLUG
403 Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
404 devpath);
405#endif
406 return;
407 }
408
409 sysname = udev_device_get_sysname(dev);
410 if (!sysname)
411 {
412 Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
413 return;
414 }
415
416 ignoreprop = udev_device_get_property_value(parent, "PCSCLITE_IGNORE");
417 if (ignoreprop && !strcmp(ignoreprop, "1"))
418 {
419 Log4(PCSC_LOG_ERROR,
420 "Device %s at %s (%s) has PCSCLITE_IGNORE set: ignored",
421 driver->readerName, devpath, sysname);
422 return;
423 }
424
425 /* check for duplicated add */
426 for (index=0; index<readerTrackerNbEntries; index++)
427 {
428 if (readerTracker[index].fullName && !strcmp(sysname, readerTracker[index].sysname))
429 return;
430 }
431
432 Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
433
434 sInterfaceNumber = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
435 if (sInterfaceNumber)
436 bInterfaceNumber = atoi(sInterfaceNumber);
437 else
438 bInterfaceNumber = 0;
439
440 a = asprintf(&deviceName, "usb:%04x/%04x:libudev:%d:%s",
441 driver->manuID, driver->productID, bInterfaceNumber, devpath);
442 if (-1 == a)
443 {
444 Log1(PCSC_LOG_ERROR, "asprintf() failed");
445 return;
446 }
447
448 /* find a free entry */
449 for (index=0; index<readerTrackerNbEntries; index++)
450 {
451 if (NULL == readerTracker[index].fullName)
452 break;
453 }
454
455 /* the array is full? */
456 if (readerTrackerNbEntries == index)
457 {
458 int new_size = readerTrackerNbEntries + 2;
459 Log3(PCSC_LOG_DEBUG, "increase from %d to %d readers", readerTrackerNbEntries, new_size);
460 readerTracker = realloc(readerTracker, new_size * sizeof(*readerTracker));
461 for (int i=readerTrackerNbEntries; i<new_size; i++)
462 {
463 readerTracker[i].devpath = NULL;
464 readerTracker[i].fullName = NULL;
465 readerTracker[i].sysname = NULL;
466 }
467
468 index = readerTrackerNbEntries; /* new free index */
469 readerTrackerNbEntries = new_size;
470 }
471
472 if (Add_Interface_In_Name)
473 sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
474
475 if (Add_Serial_In_Name)
476 sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
477
478 /* name from the Info.plist file */
479 fullname = strdup(driver->readerName);
480
481 /* interface name from the device (if any) */
482 if (sInterfaceName)
483 {
484 char *result;
485
486 char *tmpInterfaceName = strdup(sInterfaceName);
487
488 /* check the interface name contains only valid ASCII codes */
489 for (size_t i=0; i<strlen(tmpInterfaceName); i++)
490 {
491 if (! isascii(tmpInterfaceName[i]))
492 tmpInterfaceName[i] = '.';
493 }
494
495 /* create a new name */
496 a = asprintf(&result, "%s [%s]", fullname, tmpInterfaceName);
497 if (-1 == a)
498 {
499 Log1(PCSC_LOG_ERROR, "asprintf() failed");
500 free(tmpInterfaceName);
501 goto exit;
502 }
503
504 free(fullname);
505 free(tmpInterfaceName);
506 fullname = result;
507 }
508
509 /* serial number from the device (if any) */
510 if (sSerialNumber)
511 {
512 /* only add the serial number if it is not already present in the
513 * interface name */
514 if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
515 {
516 char *result;
517
518 /* create a new name */
519 a = asprintf(&result, "%s (%s)", fullname, sSerialNumber);
520 if (-1 == a)
521 {
522 Log1(PCSC_LOG_ERROR, "asprintf() failed");
523 goto exit;
524 }
525
526 free(fullname);
527 fullname = result;
528 }
529 }
530
531 readerTracker[index].fullName = strdup(fullname);
532 readerTracker[index].devpath = strdup(devpath);
533 readerTracker[index].sysname = strdup(sysname);
534
535 ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
536 driver->libraryPath, deviceName);
537 if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
538 {
539 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
540 driver->readerName);
541
542 if (classdriver && driver != classdriver)
543 {
544 /* the reader can also be used by the a class driver */
545 ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
546 classdriver->libraryPath, deviceName);
547 if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
548 {
549 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
550 driver->readerName);
551 (void)CheckForOpenCT();
552 }
553 }
554 else
555 {
556 (void)CheckForOpenCT();
557 }
558 }
559
560 if (SCARD_S_SUCCESS != ret)
561 {
562 /* adding the reader failed */
563 free(readerTracker[index].devpath);
564 readerTracker[index].devpath = NULL;
565 free(readerTracker[index].fullName);
566 readerTracker[index].fullName = NULL;
567 free(readerTracker[index].sysname);
568 readerTracker[index].sysname = NULL;
569 }
570
571exit:
572 free(fullname);
573 free(deviceName);
574} /* HPAddDevice */
575
576
577static void HPScanUSB(struct udev *udev)
578{
579 struct udev_enumerate *enumerate;
580 struct udev_list_entry *devices, *dev_list_entry;
581
582 /* Create a list of the devices in the 'usb' subsystem. */
583 enumerate = udev_enumerate_new(udev);
584 udev_enumerate_add_match_subsystem(enumerate, "usb");
585 udev_enumerate_scan_devices(enumerate);
586 devices = udev_enumerate_get_list_entry(enumerate);
587
588 /* For each item enumerated */
589 udev_list_entry_foreach(dev_list_entry, devices)
590 {
591 struct udev_device *dev;
592 const char *devpath;
593
594 /* Get the filename of the /sys entry for the device
595 and create a udev_device object (dev) representing it */
596 devpath = udev_list_entry_get_name(dev_list_entry);
597 dev = udev_device_new_from_syspath(udev, devpath);
598
599#ifdef DEBUG_HOTPLUG
600 Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
601#endif
602 HPAddDevice(dev);
603
604 /* free device */
605 udev_device_unref(dev);
606 }
607
608 /* Free the enumerator object */
609 udev_enumerate_unref(enumerate);
610}
611
612
613static void * HPEstablishUSBNotifications(void *arg)
614{
615 struct udev_monitor *udev_monitor = arg;
616 int r;
617 int fd;
618 struct pollfd pfd;
619
620 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
621 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
622
623 /* udev monitor file descriptor */
624 fd = udev_monitor_get_fd(udev_monitor);
625 if (fd < 0)
626 {
627 Log2(PCSC_LOG_ERROR, "udev_monitor_get_fd() error: %d", fd);
628 pthread_exit(NULL);
629 }
630
631 pfd.fd = fd;
632 pfd.events = POLLIN;
633
634 for (;;)
635 {
636 struct udev_device *dev;
637
638#ifdef DEBUG_HOTPLUG
639 Log0(PCSC_LOG_INFO);
640#endif
641 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
642
643 /* wait for a udev event */
644 r = TEMP_FAILURE_RETRY(poll(&pfd, 1, -1));
645 if (r < 0)
646 {
647 Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
648 pthread_exit(NULL);
649 }
650
651 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
652
653 dev = udev_monitor_receive_device(udev_monitor);
654 if (dev)
655 {
656 const char *action = udev_device_get_action(dev);
657
658 if (action)
659 {
660 if (!strcmp("remove", action))
661 {
662 Log1(PCSC_LOG_INFO, "USB Device removed");
663 HPRemoveDevice(dev);
664 }
665 else
666 if (!strcmp("add", action))
667 {
668 Log1(PCSC_LOG_INFO, "USB Device add");
669 HPAddDevice(dev);
670 }
671 }
672
673 /* free device */
674 udev_device_unref(dev);
675 }
676 }
677
678 pthread_exit(NULL);
679} /* HPEstablishUSBNotifications */
680
681
682/***
683 * Start a thread waiting for hotplug events
684 */
685LONG HPSearchHotPluggables(const char * hpDirPath)
686{
687 readerTrackerNbEntries = 2;
688 readerTracker = calloc(readerTrackerNbEntries, sizeof(*readerTracker));
689
690 return HPReadBundleValues(hpDirPath);
691} /* HPSearchHotPluggables */
692
693
697LONG HPStopHotPluggables(void)
698{
699 int i;
700
701 if (driverSize <= 0)
702 return 0;
703
704 if (!Udev)
705 return 0;
706
707 pthread_cancel(usbNotifyThread);
708 pthread_join(usbNotifyThread, NULL);
709
710 for (i=0; i<driverSize; i++)
711 {
712 /* free strings allocated by strdup() */
713 free(driverTracker[i].bundleName);
714 free(driverTracker[i].libraryPath);
715 free(driverTracker[i].readerName);
716 free(driverTracker[i].CFBundleName);
717 }
718 free(driverTracker);
719
720 udev_unref(Udev);
721 udev_monitor_unref(Udev_monitor);
722
723 Udev = NULL;
724 driverSize = -1;
725
726 Log1(PCSC_LOG_INFO, "Hotplug stopped");
727 return 0;
728} /* HPStopHotPluggables */
729
730
734ULONG HPRegisterForHotplugEvents(const char * hpDirPath)
735{
736 int r;
737
738 if (driverSize <= 0)
739 {
740 (void)hpDirPath;
741 Log2(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: %s",
742 hpDirPath);
743 Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
744 return 0;
745 }
746
747 /* Create the udev object */
748 Udev = udev_new();
749 if (!Udev)
750 {
751 Log1(PCSC_LOG_ERROR, "udev_new() failed");
753 }
754
755 Udev_monitor = udev_monitor_new_from_netlink(Udev, "udev");
756 if (NULL == Udev_monitor)
757 {
758 Log1(PCSC_LOG_ERROR, "udev_monitor_new_from_netlink() error");
759 pthread_exit(NULL);
760 }
761
762 /* filter only the interfaces */
763 r = udev_monitor_filter_add_match_subsystem_devtype(Udev_monitor, "usb",
764 "usb_interface");
765 if (r)
766 {
767 Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
768 pthread_exit(NULL);
769 }
770
771 r = udev_monitor_enable_receiving(Udev_monitor);
772 if (r)
773 {
774 Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
775 pthread_exit(NULL);
776 }
777
778 /* scan the USB bus at least once before accepting client connections */
779 HPScanUSB(Udev);
780
781 if (ThreadCreate(&usbNotifyThread, 0,
782 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, Udev_monitor))
783 {
784 Log1(PCSC_LOG_ERROR, "ThreadCreate() failed");
786 }
787
788 return 0;
789} /* HPRegisterForHotplugEvents */
790
791
792void HPReCheckSerialReaders(void)
793{
794 /* nothing to do here */
795#ifdef DEBUG_HOTPLUG
796 Log0(PCSC_LOG_ERROR);
797#endif
798
799 /* re-scan the USB bus */
800 HPScanUSB(Udev);
801
802} /* HPReCheckSerialReaders */
803
804#endif
805
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.
This keeps track of a list of currently available reader structures.
list object
Definition simclist.h:181
This handles abstract system level calls.