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