pcsc-lite 2.3.3
hotplug_libudev.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 2011-2023
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
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
101static struct _readerTracker
102{
103 char *devpath;
104 char *fullName;
105 char *sysname;
106} readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
107
108
109static LONG HPReadBundleValues(const char * hpDirPath)
110{
111 LONG rv;
112 DIR *hpDir;
113 struct dirent *currFP = NULL;
114 char fullPath[FILENAME_MAX];
115 char fullLibPath[FILENAME_MAX];
116 int listCount = 0;
117
118 hpDir = opendir(hpDirPath);
119
120 if (NULL == hpDir)
121 {
122 Log2(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: %s", hpDirPath);
123 Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
124 return -1;
125 }
126
127 /* allocate a first array */
128 driverSize = DRIVER_TRACKER_INITIAL_SIZE;
129 driverTracker = calloc(driverSize, sizeof(*driverTracker));
130 if (NULL == driverTracker)
131 {
132 Log1(PCSC_LOG_CRITICAL, "Not enough memory");
133 (void)closedir(hpDir);
134 return -1;
135 }
136
137#define GET_KEY(key, values) \
138 rv = LTPBundleFindValueWithKey(&plist, key, values); \
139 if (rv) \
140 { \
141 Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
142 fullPath); \
143 continue; \
144 }
145
146 while ((currFP = readdir(hpDir)) != 0)
147 {
148 if (strstr(currFP->d_name, ".bundle") != 0)
149 {
150 unsigned int alias;
151 list_t plist, *values;
152 list_t *manuIDs, *productIDs, *readerNames;
153 char *CFBundleName;
154 char *libraryPath;
155
156 /*
157 * The bundle exists - let's form a full path name and get the
158 * vendor and product ID's for this particular bundle
159 */
160 (void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
161 hpDirPath, currFP->d_name);
162 fullPath[sizeof(fullPath) - 1] = '\0';
163
164 rv = bundleParse(fullPath, &plist);
165 if (rv)
166 continue;
167
168 /* get CFBundleExecutable */
169 GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
170 libraryPath = list_get_at(values, 0);
171 (void)snprintf(fullLibPath, sizeof(fullLibPath),
172 "%s/%s/Contents/%s/%s",
173 hpDirPath, currFP->d_name, PCSC_ARCH,
174 libraryPath);
175 fullLibPath[sizeof(fullLibPath) - 1] = '\0';
176
177 GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
178 GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
179 GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
180
181 if ((list_size(manuIDs) != list_size(productIDs))
182 || (list_size(manuIDs) != list_size(readerNames)))
183 {
184 Log2(PCSC_LOG_CRITICAL, "Error parsing %s", fullPath);
185 (void)closedir(hpDir);
186 return -1;
187 }
188
189 /* Get CFBundleName */
190 rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME,
191 &values);
192 if (rv)
193 CFBundleName = NULL;
194 else
195 CFBundleName = list_get_at(values, 0);
196
197 /* while we find a nth ifdVendorID in Info.plist */
198 for (alias=0; alias<list_size(manuIDs); alias++)
199 {
200 char *value;
201
202 /* variables entries */
203 value = list_get_at(manuIDs, alias);
204 driverTracker[listCount].manuID = strtol(value, NULL, 16);
205
206 value = list_get_at(productIDs, alias);
207 driverTracker[listCount].productID = strtol(value, NULL, 16);
208
209 driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
210
211 /* constant entries for a same driver */
212 driverTracker[listCount].bundleName = strdup(currFP->d_name);
213 driverTracker[listCount].libraryPath = strdup(fullLibPath);
214 driverTracker[listCount].CFBundleName = CFBundleName ? strdup(CFBundleName) : NULL;
215
216#ifdef DEBUG_HOTPLUG
217 Log2(PCSC_LOG_INFO, "Found driver for: %s",
218 driverTracker[listCount].readerName);
219#endif
220 listCount++;
221 if (listCount >= driverSize)
222 {
223 int i;
224
225 /* increase the array size */
226 driverSize += DRIVER_TRACKER_SIZE_STEP;
227#ifdef DEBUG_HOTPLUG
228 Log2(PCSC_LOG_INFO,
229 "Increase driverTracker to %d entries", driverSize);
230#endif
231
232 void* tmp = realloc(driverTracker,
233 driverSize * sizeof(*driverTracker));
234
235 if (NULL == tmp)
236 {
237 free(driverTracker);
238 Log1(PCSC_LOG_CRITICAL, "Not enough memory");
239 driverSize = -1;
240 (void)closedir(hpDir);
241 return -1;
242 }
243 driverTracker = tmp;
244
245 /* clean the newly allocated entries */
246 for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
247 {
248 driverTracker[i].manuID = 0;
249 driverTracker[i].productID = 0;
250 driverTracker[i].bundleName = NULL;
251 driverTracker[i].libraryPath = NULL;
252 driverTracker[i].readerName = NULL;
253 driverTracker[i].CFBundleName = NULL;
254 }
255 }
256 }
257 bundleRelease(&plist);
258 }
259 }
260
261 driverSize = listCount;
262 (void)closedir(hpDir);
263
264#ifdef DEBUG_HOTPLUG
265 Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
266#endif
267
268 return 0;
269} /* HPReadBundleValues */
270
271
272/*@null@*/ static struct _driverTracker *get_driver(struct udev_device *dev,
273 const char *devpath, struct _driverTracker **classdriver)
274{
275 int i;
276 unsigned int idVendor, idProduct;
277 static struct _driverTracker *driver;
278 const char *str;
279
280 str = udev_device_get_sysattr_value(dev, "idVendor");
281 if (!str)
282 {
283 Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
284 return NULL;
285 }
286 idVendor = strtol(str, NULL, 16);
287
288 str = udev_device_get_sysattr_value(dev, "idProduct");
289 if (!str)
290 {
291 Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
292 return NULL;
293 }
294 idProduct = strtol(str, NULL, 16);
295
296#ifdef NO_LOG
297 (void)devpath;
298#endif
299 Log4(PCSC_LOG_DEBUG,
300 "Looking for a driver for VID: 0x%04X, PID: 0x%04X, path: %s",
301 idVendor, idProduct, devpath);
302
303 *classdriver = NULL;
304 driver = NULL;
305 /* check if the device is supported by one driver */
306 for (i=0; i<driverSize; i++)
307 {
308 if (driverTracker[i].libraryPath != NULL &&
309 idVendor == driverTracker[i].manuID &&
310 idProduct == driverTracker[i].productID)
311 {
312 if ((driverTracker[i].CFBundleName != NULL)
313 && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
314 *classdriver = &driverTracker[i];
315 else
316 /* it is not a CCID Class driver */
317 driver = &driverTracker[i];
318 }
319 }
320
321 /* if we found a specific driver */
322 if (driver)
323 return driver;
324
325 /* else return the Class driver (if any) */
326 return *classdriver;
327}
328
329
330static void HPRemoveDevice(struct udev_device *dev)
331{
332 int i;
333 const char *sysname;
334
335 sysname = udev_device_get_sysname(dev);
336 if (!sysname)
337 {
338 Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
339 return;
340 }
341
342 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
343 {
344 if (readerTracker[i].fullName && !strcmp(sysname, readerTracker[i].sysname))
345 {
346 Log4(PCSC_LOG_INFO, "Removing USB device[%d]: %s at %s", i,
347 readerTracker[i].fullName, readerTracker[i].devpath);
348
349 RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i, REMOVE_READER_FLAG_REMOVED);
350
351 free(readerTracker[i].devpath);
352 readerTracker[i].devpath = NULL;
353 free(readerTracker[i].fullName);
354 readerTracker[i].fullName = NULL;
355 free(readerTracker[i].sysname);
356 readerTracker[i].sysname = NULL;
357 break;
358 }
359 }
360}
361
362
363static void HPAddDevice(struct udev_device *dev)
364{
365 int index, a;
366 char *deviceName = NULL;
367 char *fullname = NULL;
368 struct _driverTracker *driver, *classdriver;
369 const char *sSerialNumber = NULL, *sInterfaceName = NULL;
370 const char *sInterfaceNumber;
371 LONG ret;
372 int bInterfaceNumber;
373 const char *devpath;
374 struct udev_device *parent;
375 const char *sysname;
376 const char *ignoreprop;
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 disappeared? */
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 ignoreprop = udev_device_get_property_value(parent, "PCSCLITE_IGNORE");
415 if (ignoreprop && !strcmp(ignoreprop, "1"))
416 {
417 Log4(PCSC_LOG_ERROR,
418 "Device %s at %s (%s) has PCSCLITE_IGNORE set: ignored",
419 driver->readerName, devpath, sysname);
420 return;
421 }
422
423 /* check for duplicated add */
424 for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
425 {
426 if (readerTracker[index].fullName && !strcmp(sysname, readerTracker[index].sysname))
427 return;
428 }
429
430 Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
431
432 sInterfaceNumber = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
433 if (sInterfaceNumber)
434 bInterfaceNumber = atoi(sInterfaceNumber);
435 else
436 bInterfaceNumber = 0;
437
438 a = asprintf(&deviceName, "usb:%04x/%04x:libudev:%d:%s",
439 driver->manuID, driver->productID, bInterfaceNumber, devpath);
440 if (-1 == a)
441 {
442 Log1(PCSC_LOG_ERROR, "asprintf() failed");
443 return;
444 }
445
446 /* find a free entry */
447 for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
448 {
449 if (NULL == readerTracker[index].fullName)
450 break;
451 }
452
454 {
455 Log2(PCSC_LOG_ERROR,
456 "Not enough reader entries. Already found %d readers", index);
457 goto exit;
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 char *tmpInterfaceName = strdup(sInterfaceName);
475
476 /* check the interface name contains only valid ASCII codes */
477 for (size_t i=0; i<strlen(tmpInterfaceName); i++)
478 {
479 if (! isascii(tmpInterfaceName[i]))
480 tmpInterfaceName[i] = '.';
481 }
482
483 /* create a new name */
484 a = asprintf(&result, "%s [%s]", fullname, tmpInterfaceName);
485 if (-1 == a)
486 {
487 Log1(PCSC_LOG_ERROR, "asprintf() failed");
488 free(tmpInterfaceName);
489 goto exit;
490 }
491
492 free(fullname);
493 free(tmpInterfaceName);
494 fullname = result;
495 }
496
497 /* serial number from the device (if any) */
498 if (sSerialNumber)
499 {
500 /* only add the serial number if it is not already present in the
501 * interface name */
502 if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
503 {
504 char *result;
505
506 /* create a new name */
507 a = asprintf(&result, "%s (%s)", fullname, sSerialNumber);
508 if (-1 == a)
509 {
510 Log1(PCSC_LOG_ERROR, "asprintf() failed");
511 goto exit;
512 }
513
514 free(fullname);
515 fullname = result;
516 }
517 }
518
519 readerTracker[index].fullName = strdup(fullname);
520 readerTracker[index].devpath = strdup(devpath);
521 readerTracker[index].sysname = strdup(sysname);
522
523 ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
524 driver->libraryPath, deviceName);
525 if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
526 {
527 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
528 driver->readerName);
529
530 if (classdriver && driver != classdriver)
531 {
532 /* the reader can also be used by the a class driver */
533 ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
534 classdriver->libraryPath, deviceName);
535 if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
536 {
537 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
538 driver->readerName);
539 (void)CheckForOpenCT();
540 }
541 }
542 else
543 {
544 (void)CheckForOpenCT();
545 }
546 }
547
548 if (SCARD_S_SUCCESS != ret)
549 {
550 /* adding the reader failed */
551 free(readerTracker[index].devpath);
552 readerTracker[index].devpath = NULL;
553 free(readerTracker[index].fullName);
554 readerTracker[index].fullName = NULL;
555 free(readerTracker[index].sysname);
556 readerTracker[index].sysname = NULL;
557 }
558
559exit:
560 free(fullname);
561 free(deviceName);
562} /* HPAddDevice */
563
564
565static void HPScanUSB(struct udev *udev)
566{
567 struct udev_enumerate *enumerate;
568 struct udev_list_entry *devices, *dev_list_entry;
569
570 /* Create a list of the devices in the 'usb' subsystem. */
571 enumerate = udev_enumerate_new(udev);
572 udev_enumerate_add_match_subsystem(enumerate, "usb");
573 udev_enumerate_scan_devices(enumerate);
574 devices = udev_enumerate_get_list_entry(enumerate);
575
576 /* For each item enumerated */
577 udev_list_entry_foreach(dev_list_entry, devices)
578 {
579 struct udev_device *dev;
580 const char *devpath;
581
582 /* Get the filename of the /sys entry for the device
583 and create a udev_device object (dev) representing it */
584 devpath = udev_list_entry_get_name(dev_list_entry);
585 dev = udev_device_new_from_syspath(udev, devpath);
586
587#ifdef DEBUG_HOTPLUG
588 Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
589#endif
590 HPAddDevice(dev);
591
592 /* free device */
593 udev_device_unref(dev);
594 }
595
596 /* Free the enumerator object */
597 udev_enumerate_unref(enumerate);
598}
599
600
601static void * HPEstablishUSBNotifications(void *arg)
602{
603 struct udev_monitor *udev_monitor = arg;
604 int r;
605 int fd;
606 struct pollfd pfd;
607
608 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
609 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
610
611 /* udev monitor file descriptor */
612 fd = udev_monitor_get_fd(udev_monitor);
613 if (fd < 0)
614 {
615 Log2(PCSC_LOG_ERROR, "udev_monitor_get_fd() error: %d", fd);
616 pthread_exit(NULL);
617 }
618
619 pfd.fd = fd;
620 pfd.events = POLLIN;
621
622 for (;;)
623 {
624 struct udev_device *dev;
625
626#ifdef DEBUG_HOTPLUG
627 Log0(PCSC_LOG_INFO);
628#endif
629 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
630
631 /* wait for a udev event */
632 r = TEMP_FAILURE_RETRY(poll(&pfd, 1, -1));
633 if (r < 0)
634 {
635 Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
636 pthread_exit(NULL);
637 }
638
639 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
640
641 dev = udev_monitor_receive_device(udev_monitor);
642 if (dev)
643 {
644 const char *action = udev_device_get_action(dev);
645
646 if (action)
647 {
648 if (!strcmp("remove", action))
649 {
650 Log1(PCSC_LOG_INFO, "USB Device removed");
651 HPRemoveDevice(dev);
652 }
653 else
654 if (!strcmp("add", action))
655 {
656 Log1(PCSC_LOG_INFO, "USB Device add");
657 HPAddDevice(dev);
658 }
659 }
660
661 /* free device */
662 udev_device_unref(dev);
663 }
664 }
665
666 pthread_exit(NULL);
667} /* HPEstablishUSBNotifications */
668
669
670/***
671 * Start a thread waiting for hotplug events
672 */
673LONG HPSearchHotPluggables(const char * hpDirPath)
674{
675 int i;
676
677 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
678 {
679 readerTracker[i].devpath = NULL;
680 readerTracker[i].fullName = NULL;
681 readerTracker[i].sysname = NULL;
682 }
683
684 return HPReadBundleValues(hpDirPath);
685} /* HPSearchHotPluggables */
686
687
691LONG HPStopHotPluggables(void)
692{
693 int i;
694
695 if (driverSize <= 0)
696 return 0;
697
698 if (!Udev)
699 return 0;
700
701 pthread_cancel(usbNotifyThread);
702 pthread_join(usbNotifyThread, NULL);
703
704 for (i=0; i<driverSize; i++)
705 {
706 /* free strings allocated by strdup() */
707 free(driverTracker[i].bundleName);
708 free(driverTracker[i].libraryPath);
709 free(driverTracker[i].readerName);
710 free(driverTracker[i].CFBundleName);
711 }
712 free(driverTracker);
713
714 udev_unref(Udev);
715 udev_monitor_unref(Udev_monitor);
716
717 Udev = NULL;
718 driverSize = -1;
719
720 Log1(PCSC_LOG_INFO, "Hotplug stopped");
721 return 0;
722} /* HPStopHotPluggables */
723
724
728ULONG HPRegisterForHotplugEvents(const char * hpDirPath)
729{
730 int r;
731
732 if (driverSize <= 0)
733 {
734 (void)hpDirPath;
735 Log2(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: %s",
736 hpDirPath);
737 Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
738 return 0;
739 }
740
741 /* Create the udev object */
742 Udev = udev_new();
743 if (!Udev)
744 {
745 Log1(PCSC_LOG_ERROR, "udev_new() failed");
747 }
748
749 Udev_monitor = udev_monitor_new_from_netlink(Udev, "udev");
750 if (NULL == Udev_monitor)
751 {
752 Log1(PCSC_LOG_ERROR, "udev_monitor_new_from_netlink() error");
753 pthread_exit(NULL);
754 }
755
756 /* filter only the interfaces */
757 r = udev_monitor_filter_add_match_subsystem_devtype(Udev_monitor, "usb",
758 "usb_interface");
759 if (r)
760 {
761 Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
762 pthread_exit(NULL);
763 }
764
765 r = udev_monitor_enable_receiving(Udev_monitor);
766 if (r)
767 {
768 Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
769 pthread_exit(NULL);
770 }
771
772 /* scan the USB bus at least once before accepting client connections */
773 HPScanUSB(Udev);
774
775 if (ThreadCreate(&usbNotifyThread, 0,
776 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, Udev_monitor))
777 {
778 Log1(PCSC_LOG_ERROR, "ThreadCreate() failed");
780 }
781
782 return 0;
783} /* HPRegisterForHotplugEvents */
784
785
786void HPReCheckSerialReaders(void)
787{
788 /* nothing to do here */
789#ifdef DEBUG_HOTPLUG
790 Log0(PCSC_LOG_ERROR);
791#endif
792} /* HPReCheckSerialReaders */
793
794#endif
795
This handles debugging.
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
#define SCARD_S_SUCCESS
No error was encountered.
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.
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
list object
Definition simclist.h:181
This handles abstract system level calls.