pcsc-lite 2.3.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-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
377 /* The device pointed to by dev contains information about
378 the interface. In order to get information about the USB
379 device, get the parent device with the subsystem/devtype pair
380 of "usb"/"usb_device". This will be several levels up the
381 tree, but the function will find it.*/
382 parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
383 "usb_device");
384 if (!parent)
385 return;
386
387 devpath = udev_device_get_devnode(parent);
388 if (!devpath)
389 {
390 /* the device disappeared? */
391 Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
392 return;
393 }
394
395 driver = get_driver(parent, devpath, &classdriver);
396 if (NULL == driver)
397 {
398 /* not a smart card reader */
399#ifdef DEBUG_HOTPLUG
400 Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
401 devpath);
402#endif
403 return;
404 }
405
406 sysname = udev_device_get_sysname(dev);
407 if (!sysname)
408 {
409 Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
410 return;
411 }
412
413 /* check for duplicated add */
414 for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
415 {
416 if (readerTracker[index].fullName && !strcmp(sysname, readerTracker[index].sysname))
417 return;
418 }
419
420 Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
421
422 sInterfaceNumber = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
423 if (sInterfaceNumber)
424 bInterfaceNumber = atoi(sInterfaceNumber);
425 else
426 bInterfaceNumber = 0;
427
428 a = asprintf(&deviceName, "usb:%04x/%04x:libudev:%d:%s",
429 driver->manuID, driver->productID, bInterfaceNumber, devpath);
430 if (-1 == a)
431 {
432 Log1(PCSC_LOG_ERROR, "asprintf() failed");
433 return;
434 }
435
436 /* find a free entry */
437 for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
438 {
439 if (NULL == readerTracker[index].fullName)
440 break;
441 }
442
444 {
445 Log2(PCSC_LOG_ERROR,
446 "Not enough reader entries. Already found %d readers", index);
447 goto exit;
448 }
449
450 if (Add_Interface_In_Name)
451 sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
452
453 if (Add_Serial_In_Name)
454 sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
455
456 /* name from the Info.plist file */
457 fullname = strdup(driver->readerName);
458
459 /* interface name from the device (if any) */
460 if (sInterfaceName)
461 {
462 char *result;
463
464 char *tmpInterfaceName = strdup(sInterfaceName);
465
466 /* check the interface name contains only valid ASCII codes */
467 for (size_t i=0; i<strlen(tmpInterfaceName); i++)
468 {
469 if (! isascii(tmpInterfaceName[i]))
470 tmpInterfaceName[i] = '.';
471 }
472
473 /* create a new name */
474 a = asprintf(&result, "%s [%s]", fullname, tmpInterfaceName);
475 if (-1 == a)
476 {
477 Log1(PCSC_LOG_ERROR, "asprintf() failed");
478 free(tmpInterfaceName);
479 goto exit;
480 }
481
482 free(fullname);
483 free(tmpInterfaceName);
484 fullname = result;
485 }
486
487 /* serial number from the device (if any) */
488 if (sSerialNumber)
489 {
490 /* only add the serial number if it is not already present in the
491 * interface name */
492 if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
493 {
494 char *result;
495
496 /* create a new name */
497 a = asprintf(&result, "%s (%s)", fullname, sSerialNumber);
498 if (-1 == a)
499 {
500 Log1(PCSC_LOG_ERROR, "asprintf() failed");
501 goto exit;
502 }
503
504 free(fullname);
505 fullname = result;
506 }
507 }
508
509 readerTracker[index].fullName = strdup(fullname);
510 readerTracker[index].devpath = strdup(devpath);
511 readerTracker[index].sysname = strdup(sysname);
512
513 ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
514 driver->libraryPath, deviceName);
515 if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
516 {
517 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
518 driver->readerName);
519
520 if (classdriver && driver != classdriver)
521 {
522 /* the reader can also be used by the a class driver */
523 ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
524 classdriver->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 (void)CheckForOpenCT();
530 }
531 }
532 else
533 {
534 (void)CheckForOpenCT();
535 }
536 }
537
538 if (SCARD_S_SUCCESS != ret)
539 {
540 /* adding the reader failed */
541 free(readerTracker[index].devpath);
542 readerTracker[index].devpath = NULL;
543 free(readerTracker[index].fullName);
544 readerTracker[index].fullName = NULL;
545 free(readerTracker[index].sysname);
546 readerTracker[index].sysname = NULL;
547 }
548
549exit:
550 free(fullname);
551 free(deviceName);
552} /* HPAddDevice */
553
554
555static void HPScanUSB(struct udev *udev)
556{
557 struct udev_enumerate *enumerate;
558 struct udev_list_entry *devices, *dev_list_entry;
559
560 /* Create a list of the devices in the 'usb' subsystem. */
561 enumerate = udev_enumerate_new(udev);
562 udev_enumerate_add_match_subsystem(enumerate, "usb");
563 udev_enumerate_scan_devices(enumerate);
564 devices = udev_enumerate_get_list_entry(enumerate);
565
566 /* For each item enumerated */
567 udev_list_entry_foreach(dev_list_entry, devices)
568 {
569 struct udev_device *dev;
570 const char *devpath;
571
572 /* Get the filename of the /sys entry for the device
573 and create a udev_device object (dev) representing it */
574 devpath = udev_list_entry_get_name(dev_list_entry);
575 dev = udev_device_new_from_syspath(udev, devpath);
576
577#ifdef DEBUG_HOTPLUG
578 Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
579#endif
580 HPAddDevice(dev);
581
582 /* free device */
583 udev_device_unref(dev);
584 }
585
586 /* Free the enumerator object */
587 udev_enumerate_unref(enumerate);
588}
589
590
591static void * HPEstablishUSBNotifications(void *arg)
592{
593 struct udev_monitor *udev_monitor = arg;
594 int r;
595 int fd;
596 struct pollfd pfd;
597
598 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
599 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
600
601 /* udev monitor file descriptor */
602 fd = udev_monitor_get_fd(udev_monitor);
603 if (fd < 0)
604 {
605 Log2(PCSC_LOG_ERROR, "udev_monitor_get_fd() error: %d", fd);
606 pthread_exit(NULL);
607 }
608
609 pfd.fd = fd;
610 pfd.events = POLLIN;
611
612 for (;;)
613 {
614 struct udev_device *dev;
615
616#ifdef DEBUG_HOTPLUG
617 Log0(PCSC_LOG_INFO);
618#endif
619 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
620
621 /* wait for a udev event */
622 r = TEMP_FAILURE_RETRY(poll(&pfd, 1, -1));
623 if (r < 0)
624 {
625 Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
626 pthread_exit(NULL);
627 }
628
629 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
630
631 dev = udev_monitor_receive_device(udev_monitor);
632 if (dev)
633 {
634 const char *action = udev_device_get_action(dev);
635
636 if (action)
637 {
638 if (!strcmp("remove", action))
639 {
640 Log1(PCSC_LOG_INFO, "USB Device removed");
641 HPRemoveDevice(dev);
642 }
643 else
644 if (!strcmp("add", action))
645 {
646 Log1(PCSC_LOG_INFO, "USB Device add");
647 HPAddDevice(dev);
648 }
649 }
650
651 /* free device */
652 udev_device_unref(dev);
653 }
654 }
655
656 pthread_exit(NULL);
657} /* HPEstablishUSBNotifications */
658
659
660/***
661 * Start a thread waiting for hotplug events
662 */
663LONG HPSearchHotPluggables(const char * hpDirPath)
664{
665 int i;
666
667 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
668 {
669 readerTracker[i].devpath = NULL;
670 readerTracker[i].fullName = NULL;
671 readerTracker[i].sysname = NULL;
672 }
673
674 return HPReadBundleValues(hpDirPath);
675} /* HPSearchHotPluggables */
676
677
681LONG HPStopHotPluggables(void)
682{
683 int i;
684
685 if (driverSize <= 0)
686 return 0;
687
688 if (!Udev)
689 return 0;
690
691 pthread_cancel(usbNotifyThread);
692 pthread_join(usbNotifyThread, NULL);
693
694 for (i=0; i<driverSize; i++)
695 {
696 /* free strings allocated by strdup() */
697 free(driverTracker[i].bundleName);
698 free(driverTracker[i].libraryPath);
699 free(driverTracker[i].readerName);
700 free(driverTracker[i].CFBundleName);
701 }
702 free(driverTracker);
703
704 udev_unref(Udev);
705 udev_monitor_unref(Udev_monitor);
706
707 Udev = NULL;
708 driverSize = -1;
709
710 Log1(PCSC_LOG_INFO, "Hotplug stopped");
711 return 0;
712} /* HPStopHotPluggables */
713
714
718ULONG HPRegisterForHotplugEvents(const char * hpDirPath)
719{
720 int r;
721
722 if (driverSize <= 0)
723 {
724 (void)hpDirPath;
725 Log2(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: %s",
726 hpDirPath);
727 Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
728 return 0;
729 }
730
731 /* Create the udev object */
732 Udev = udev_new();
733 if (!Udev)
734 {
735 Log1(PCSC_LOG_ERROR, "udev_new() failed");
737 }
738
739 Udev_monitor = udev_monitor_new_from_netlink(Udev, "udev");
740 if (NULL == Udev_monitor)
741 {
742 Log1(PCSC_LOG_ERROR, "udev_monitor_new_from_netlink() error");
743 pthread_exit(NULL);
744 }
745
746 /* filter only the interfaces */
747 r = udev_monitor_filter_add_match_subsystem_devtype(Udev_monitor, "usb",
748 "usb_interface");
749 if (r)
750 {
751 Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
752 pthread_exit(NULL);
753 }
754
755 r = udev_monitor_enable_receiving(Udev_monitor);
756 if (r)
757 {
758 Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
759 pthread_exit(NULL);
760 }
761
762 /* scan the USB bus at least once before accepting client connections */
763 HPScanUSB(Udev);
764
765 if (ThreadCreate(&usbNotifyThread, 0,
766 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, Udev_monitor))
767 {
768 Log1(PCSC_LOG_ERROR, "ThreadCreate() failed");
770 }
771
772 return 0;
773} /* HPRegisterForHotplugEvents */
774
775
776void HPReCheckSerialReaders(void)
777{
778 /* nothing to do here */
779#ifdef DEBUG_HOTPLUG
780 Log0(PCSC_LOG_ERROR);
781#endif
782} /* HPReCheckSerialReaders */
783
784#endif
785
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:285
This keeps track of a list of currently available reader structures.
list object
Definition simclist.h:181
This handles abstract system level calls.