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
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
72extern char Add_Interface_In_Name;
73extern char Add_Serial_In_Name;
74
75static pthread_t usbNotifyThread;
76static int driverSize = -1;
77static struct udev *Udev;
78
79
83static 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
102static struct _readerTracker
103{
104 char *devpath;
105 char *fullName;
106 char *sysname;
107} readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
108
109
110static 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
331static 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
364static 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
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
550exit:
551 free(fullname);
552 free(deviceName);
553} /* HPAddDevice */
554
555
556static 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
592static 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 */
664LONG 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
682LONG 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
717ULONG 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");
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");
769 }
770
771 return 0;
772} /* HPRegisterForHotplugEvents */
773
774
775void 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.