pcsc-lite 2.3.0
hotplug_libusb.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 2001-2004
5 * David Corcoran <corcoran@musclecard.com>
6 * Copyright (C) 2003-2024
7 * Ludovic Rousseau <ludovic.rousseau@free.fr>
8 * Copyright (C) 2003
9 * Toni Andjelkovic <toni@soth.at>
10 * Copyright (C) 2003-2004
11 * Damien Sauveron <damien.sauveron@labri.fr>
12 *
13Redistribution and use in source and binary forms, with or without
14modification, are permitted provided that the following conditions
15are met:
16
171. Redistributions of source code must retain the above copyright
18 notice, this list of conditions and the following disclaimer.
192. Redistributions in binary form must reproduce the above copyright
20 notice, this list of conditions and the following disclaimer in the
21 documentation and/or other materials provided with the distribution.
223. The name of the author may not be used to endorse or promote products
23 derived from this software without specific prior written permission.
24
25THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
42#include "config.h"
43#ifdef HAVE_LIBUSB
44
45#define _GNU_SOURCE /* for asprintf(3) */
46#include <string.h>
47#include <sys/types.h>
48#include <stdio.h>
49#include <dirent.h>
50#include <fcntl.h>
51#include <time.h>
52#include <stdlib.h>
53#include <unistd.h>
54#include <errno.h>
55#include <libusb.h>
56#include <pthread.h>
57#include <signal.h>
58#include <stdbool.h>
59
60#include "misc.h"
61#include "wintypes.h"
62#include "pcscd.h"
63#include "debuglog.h"
64#include "parser.h"
65#include "readerfactory.h"
66#include "winscard_msg.h"
67#include "sys_generic.h"
68#include "hotplug.h"
69#include "utils.h"
70
71#undef DEBUG_HOTPLUG
72
73/* format is "%d:%d:%d", bus_number, device_address, interface */
74#define BUS_DEVICE_STRSIZE 10+1+10+1+10+1
75
76#define READER_ABSENT 0
77#define READER_PRESENT 1
78#define READER_FAILED 2
79
80extern bool Add_Interface_In_Name;
81extern bool Add_Serial_In_Name;
82
83/* we use the default libusb context */
84#define ctx NULL
85
86pthread_mutex_t usbNotifierMutex;
87
88static pthread_t usbNotifyThread;
89static int driverSize = -1;
90static bool AraKiriHotPlug = false;
91static int rescan_pipe[] = { -1, -1 };
92extern int HPForceReaderPolling;
93
94/* values of ifdCapabilities bits */
95#define IFD_GENERATE_HOTPLUG 1
96
100static struct _driverTracker
101{
102 unsigned int manuID;
103 unsigned int productID;
104
105 char *bundleName;
106 char *libraryPath;
107 char *readerName;
108 int ifdCapabilities;
109 char *CFBundleName;
110} *driverTracker = NULL;
111#define DRIVER_TRACKER_SIZE_STEP 8
112
116static struct _readerTracker
117{
118 char status;
119 char bus_device[BUS_DEVICE_STRSIZE];
120 char *fullName;
121} readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
122
123static LONG HPAddHotPluggable(struct libusb_device *dev,
124 struct libusb_device_descriptor desc,
125 const char bus_device[],
126 const struct libusb_interface *idesc,
127 struct _driverTracker *driver,
128 struct _driverTracker *classdriver);
129static LONG HPRemoveHotPluggable(int reader_index);
130static void HPCleanupHotPluggable(int reader_index);
131
132static LONG HPReadBundleValues(const char * hpDirPath)
133{
134 LONG rv;
135 DIR *hpDir;
136 struct dirent *currFP = NULL;
137 char fullPath[FILENAME_MAX];
138 char fullLibPath[FILENAME_MAX];
139 int listCount = 0;
140
141 hpDir = opendir(hpDirPath);
142
143 if (hpDir == NULL)
144 {
145 Log2(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: %s",
146 hpDirPath);
147 Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
148 return -1;
149 }
150
151 /* allocate a first array */
152 driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker));
153 if (NULL == driverTracker)
154 {
155 Log1(PCSC_LOG_CRITICAL, "Not enough memory");
156 return -1;
157 }
158 driverSize = DRIVER_TRACKER_SIZE_STEP;
159
160#define GET_KEY(key, values) \
161 rv = LTPBundleFindValueWithKey(&plist, key, values); \
162 if (rv) \
163 { \
164 Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
165 fullPath); \
166 continue; \
167 }
168
169 while ((currFP = readdir(hpDir)) != 0)
170 {
171 if (strstr(currFP->d_name, ".bundle") != 0)
172 {
173 unsigned int alias;
174 list_t plist, *values;
175 list_t *manuIDs, *productIDs, *readerNames;
176 char *libraryPath;
177 int ifdCapabilities;
178 char *CFBundleName;
179
180 /*
181 * The bundle exists - let's form a full path name and get the
182 * vendor and product ID's for this particular bundle
183 */
184 snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
185 hpDirPath, currFP->d_name);
186 fullPath[sizeof(fullPath) - 1] = '\0';
187
188 rv = bundleParse(fullPath, &plist);
189 if (rv)
190 continue;
191
192 /* get CFBundleExecutable */
193 GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
194 libraryPath = list_get_at(values, 0);
195 (void)snprintf(fullLibPath, sizeof(fullLibPath),
196 "%s/%s/Contents/%s/%s",
197 hpDirPath, currFP->d_name, PCSC_ARCH,
198 libraryPath);
199 fullLibPath[sizeof(fullLibPath) - 1] = '\0';
200
201 /* Get ifdCapabilities */
202 GET_KEY(PCSCLITE_HP_CPCTKEY_NAME, &values)
203 ifdCapabilities = strtol(list_get_at(values, 0), NULL, 16);
204
205 GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
206 GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
207 GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
208
209 /* Get CFBundleName */
210 rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME,
211 &values);
212 if (rv)
213 CFBundleName = NULL;
214 else
215 CFBundleName = list_get_at(values, 0);
216
217 /* while we find a nth ifdVendorID in Info.plist */
218 for (alias=0; alias<list_size(manuIDs); alias++)
219 {
220 char *value;
221
222 /* variables entries */
223 value = list_get_at(manuIDs, alias);
224 driverTracker[listCount].manuID = strtol(value, NULL, 16);
225
226 value = list_get_at(productIDs, alias);
227 driverTracker[listCount].productID = strtol(value, NULL, 16);
228
229 driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
230
231 /* constant entries for a same driver */
232 driverTracker[listCount].bundleName = strdup(currFP->d_name);
233 driverTracker[listCount].libraryPath = strdup(fullLibPath);
234 driverTracker[listCount].ifdCapabilities = ifdCapabilities;
235 driverTracker[listCount].CFBundleName =
236 CFBundleName ? strdup(CFBundleName) : NULL;
237
238#ifdef DEBUG_HOTPLUG
239 Log2(PCSC_LOG_INFO, "Found driver for: %s",
240 driverTracker[listCount].readerName);
241#endif
242 listCount++;
243 if (listCount >= driverSize)
244 {
245 int i;
246
247 /* increase the array size */
248 driverSize += DRIVER_TRACKER_SIZE_STEP;
249#ifdef DEBUG_HOTPLUG
250 Log2(PCSC_LOG_INFO,
251 "Increase driverTracker to %d entries", driverSize);
252#endif
253 void* tmp = realloc(driverTracker,
254 driverSize * sizeof(*driverTracker));
255 if (NULL == tmp)
256 {
257 free(driverTracker);
258 Log1(PCSC_LOG_CRITICAL, "Not enough memory");
259 driverSize = -1;
260 closedir(hpDir);
261 return -1;
262 }
263 driverTracker = tmp;
264
265 /* clean the newly allocated entries */
266 for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
267 {
268 driverTracker[i].manuID = 0;
269 driverTracker[i].productID = 0;
270 driverTracker[i].bundleName = NULL;
271 driverTracker[i].libraryPath = NULL;
272 driverTracker[i].readerName = NULL;
273 driverTracker[i].ifdCapabilities = 0;
274 driverTracker[i].CFBundleName = NULL;
275 }
276 }
277 }
278 bundleRelease(&plist);
279 }
280 }
281
282 driverSize = listCount;
283 closedir(hpDir);
284
285 if (driverSize == 0)
286 {
287 Log2(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: %s",
288 hpDirPath);
289 Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
290 }
291#ifdef DEBUG_HOTPLUG
292 else
293 Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
294#endif
295
296 return driverSize;
297}
298
299static struct _driverTracker *get_driver(unsigned int idVendor,
300 unsigned int idProduct, struct _driverTracker **classdriver)
301{
302 int i;
303 static struct _driverTracker *driver;
304
305#ifdef DEBUG_HOTPLUG
306 Log3(PCSC_LOG_DEBUG,
307 "Looking for a driver for VID: 0x%04X, PID: 0x%04X",
308 idVendor, idProduct);
309#endif
310
311 *classdriver = NULL;
312 driver = NULL;
313 /* check if the device is supported by one driver */
314 for (i=0; i<driverSize; i++)
315 {
316 if (driverTracker[i].libraryPath != NULL &&
317 idVendor == driverTracker[i].manuID &&
318 idProduct == driverTracker[i].productID)
319 {
320 if ((driverTracker[i].CFBundleName != NULL)
321 && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
322 *classdriver = &driverTracker[i];
323 else
324 /* it is not a CCID Class driver */
325 driver = &driverTracker[i];
326 }
327 }
328
329 /* if we found a specific driver */
330 if (driver)
331 return driver;
332
333 /* else return the Class driver (if any) */
334 return *classdriver;
335}
336
337static void HPRescanUsbBus(void)
338{
339 int i, j;
340 char bus_device[BUS_DEVICE_STRSIZE];
341 libusb_device **devs, *dev;
342 ssize_t cnt;
343
344 for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
345 /* clear roll call */
346 readerTracker[i].status = READER_ABSENT;
347
348 cnt = libusb_get_device_list(ctx, &devs);
349 if (cnt < 0)
350 {
351 Log2(PCSC_LOG_CRITICAL, "libusb_get_device_list() failed: %s",
352 libusb_error_name(cnt));
353 return;
354 }
355
356 /* For each USB device */
357 cnt = 0;
358 while ((dev = devs[cnt++]) != NULL)
359 {
360 struct libusb_device_descriptor desc;
361 struct libusb_config_descriptor *config_desc;
362 uint8_t bus_number = libusb_get_bus_number(dev);
363 uint8_t device_address = libusb_get_device_address(dev);
364 struct _driverTracker *driver, *classdriver;
365 int interface;
366
367 int r = libusb_get_device_descriptor(dev, &desc);
368 if (r < 0)
369 {
370 Log4(PCSC_LOG_ERROR,
371 "failed to get device descriptor for %d/%d: %s",
372 bus_number, device_address, libusb_error_name(r));
373 continue;
374 }
375
376 r = libusb_get_active_config_descriptor(dev, &config_desc);
377 if (r < 0)
378 {
379 Log4(PCSC_LOG_ERROR, "failed to get device config for %d/%d: %s",
380 bus_number, device_address, libusb_error_name(r));
381 continue;
382 }
383
384 driver = get_driver(desc.idVendor, desc.idProduct, &classdriver);
385 if (NULL == driver)
386 {
387 /* not a smart card reader */
388#ifdef DEBUG_HOTPLUG
389 Log3(PCSC_LOG_DEBUG, "%d/%d is not a supported smart card reader",
390 bus_number, device_address);
391#endif
392 libusb_free_config_descriptor(config_desc);
393 continue;
394 }
395
396#ifdef DEBUG_HOTPLUG
397 Log3(PCSC_LOG_DEBUG, "Found matching USB device: %d:%d",
398 bus_number, device_address);
399#endif
400
401 for (interface = 0; interface < config_desc->bNumInterfaces;
402 interface++)
403 {
404 bool newreader;
405
406 /* A known device has been found */
407 snprintf(bus_device, BUS_DEVICE_STRSIZE, "%d:%d:%d",
408 bus_number, device_address, interface);
409 bus_device[BUS_DEVICE_STRSIZE - 1] = '\0';
410 newreader = true;
411
412 /* Check if the reader is a new one */
413 for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
414 {
415 if (strncmp(readerTracker[j].bus_device,
416 bus_device, BUS_DEVICE_STRSIZE) == 0)
417 {
418 /* The reader is already known */
419 readerTracker[j].status = READER_PRESENT;
420 newreader = false;
421#ifdef DEBUG_HOTPLUG
422 Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s",
423 bus_device);
424#endif
425 break;
426 }
427 }
428
429 /* New reader found */
430 if (newreader)
431 HPAddHotPluggable(dev, desc, bus_device,
432 &config_desc->interface[interface], driver, classdriver);
433 }
434
435 libusb_free_config_descriptor(config_desc);
436 }
437
438 /*
439 * check if all the previously found readers are still present
440 */
441 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
442 {
443 if ((readerTracker[i].status == READER_ABSENT) &&
444 (readerTracker[i].fullName != NULL))
445 HPRemoveHotPluggable(i);
446 }
447
448 /* free the libusb allocated list & devices */
449 libusb_free_device_list(devs, 1);
450}
451
452static void * HPEstablishUSBNotifications(int pipefd[2])
453{
454 bool do_polling;
455 int r;
456 char c = 42; /* magic value */
457
458 r = libusb_init(ctx);
459 if (r < 0)
460 {
461 Log2(PCSC_LOG_CRITICAL, "libusb_init failed: %s", libusb_error_name(r));
462 /* emergency exit */
463 kill(getpid(), SIGTERM);
464 return NULL;
465 }
466
467 /* scan the USB bus for devices at startup */
468 HPRescanUsbBus();
469
470 /* signal that the initially connected readers are now visible */
471 if (write(pipefd[1], &c, 1) == -1)
472 {
473 Log2(PCSC_LOG_ERROR, "write: %s", strerror(errno));
474 return NULL;
475 }
476
477 /* if at least one driver do not have IFD_GENERATE_HOTPLUG */
478 do_polling = false;
479 for (int i=0; i<driverSize; i++)
480 if (driverTracker[i].libraryPath)
481 if ((driverTracker[i].ifdCapabilities & IFD_GENERATE_HOTPLUG) == 0)
482 {
483 Log2(PCSC_LOG_INFO,
484 "Driver %s does not support IFD_GENERATE_HOTPLUG. Using active polling instead.",
485 driverTracker[i].bundleName);
486 if (HPForceReaderPolling < 1)
487 HPForceReaderPolling = 1;
488 break;
489 }
490
491 if (HPForceReaderPolling)
492 {
493 Log2(PCSC_LOG_INFO,
494 "Polling forced every %d second(s)", HPForceReaderPolling);
495 do_polling = true;
496 }
497
498 if (do_polling)
499 {
500 while (!AraKiriHotPlug)
501 {
502 SYS_Sleep(HPForceReaderPolling);
503 HPRescanUsbBus();
504 }
505 }
506 else
507 {
508 char dummy;
509 while (read(rescan_pipe[0], &dummy, sizeof(dummy)) > 0)
510 {
511 if (AraKiriHotPlug)
512 break;
513 Log1(PCSC_LOG_INFO, "Reload serial configuration");
514 HPRescanUsbBus();
515#ifdef USE_SERIAL
516 RFReCheckReaderConf();
517#endif
518 Log1(PCSC_LOG_INFO, "End reload serial configuration");
519 }
520 }
521
522 libusb_exit(ctx);
523
524 for (int i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
525 {
526 if (readerTracker[i].fullName != NULL)
527 HPCleanupHotPluggable(i);
528 }
529
530 for (int i=0; i<driverSize; i++)
531 {
532 /* free strings allocated by strdup() */
533 free(driverTracker[i].bundleName);
534 free(driverTracker[i].libraryPath);
535 free(driverTracker[i].readerName);
536 free(driverTracker[i].CFBundleName);
537 }
538 free(driverTracker);
539
540 close(rescan_pipe[0]);
541 rescan_pipe[0] = -1;
542
543 Log1(PCSC_LOG_INFO, "Hotplug stopped");
544
545 return NULL;
546}
547
548LONG HPSearchHotPluggables(const char * hpDirPath)
549{
550 int i;
551
552 AraKiriHotPlug = false;
553 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
554 {
555 readerTracker[i].status = READER_ABSENT;
556 readerTracker[i].bus_device[0] = '\0';
557 readerTracker[i].fullName = NULL;
558 }
559
560 if (HPReadBundleValues(hpDirPath) > 0)
561 {
562 /* used for waiting for the initialization completion */
563 int pipefd[2];
564 char c;
565
566 if (pipe(pipefd) == -1)
567 {
568 Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno));
569 return -1;
570 }
571
572 /* used for rescan events */
573 if (pipe(rescan_pipe) == -1)
574 {
575 Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno));
576 return -1;
577 }
578
579 ThreadCreate(&usbNotifyThread, 0,
580 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, pipefd);
581
582 /* Wait for initial readers to setup */
583 if (read(pipefd[0], &c, 1) == -1)
584 {
585 Log2(PCSC_LOG_ERROR, "read: %s", strerror(errno));
586 return -1;
587 }
588
589 /* cleanup pipe fd */
590 close(pipefd[0]);
591 close(pipefd[1]);
592 }
593
594 return 0;
595}
596
597LONG HPStopHotPluggables(void)
598{
599 /* tell the rescan thread to shut down; it checks the ara kiri flag, but it
600 * might also need to be awaken from reading the rescan pipe */
601 AraKiriHotPlug = true;
602 HPReCheckSerialReaders();
603
604 if (rescan_pipe[1] >= 0)
605 {
606 close(rescan_pipe[1]);
607 rescan_pipe[1] = -1;
608 }
609 /* wait for the rescan thread to complete its cleanup */
610 pthread_join(usbNotifyThread, NULL);
611
612 return 0;
613}
614
615static LONG HPAddHotPluggable(struct libusb_device *dev,
616 struct libusb_device_descriptor desc,
617 const char bus_device[],
618 const struct libusb_interface *idesc,
619 struct _driverTracker *driver,
620 struct _driverTracker *classdriver)
621{
622 int i;
623 uint8_t iInterface = 0;
624 uint8_t iSerialNumber = 0;
625 char *deviceName;
626
627 Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device);
628
629 i = asprintf(&deviceName, "usb:%04x/%04x:libusb-1.0:%s",
630 desc.idVendor, desc.idProduct, bus_device);
631 if (-1 == i)
632 {
633 Log1(PCSC_LOG_ERROR, "asprintf() failed");
634 return 0;
635 }
636
637 pthread_mutex_lock(&usbNotifierMutex);
638
639 /* find a free entry */
640 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
641 {
642 if (readerTracker[i].fullName == NULL)
643 break;
644 }
645
647 {
648 Log2(PCSC_LOG_ERROR,
649 "Not enough reader entries. Already found %d readers", i);
650 pthread_mutex_unlock(&usbNotifierMutex);
651 return 0;
652 }
653
654 strncpy(readerTracker[i].bus_device, bus_device,
655 sizeof(readerTracker[i].bus_device));
656 readerTracker[i].bus_device[sizeof(readerTracker[i].bus_device) - 1] = '\0';
657 readerTracker[i].fullName = NULL;
658
659 if (Add_Interface_In_Name && idesc->num_altsetting > 0)
660 iInterface = idesc->altsetting[0].iInterface;
661
662 if (Add_Serial_In_Name)
663 iSerialNumber = desc.iSerialNumber;
664
665 if (iSerialNumber != 0 || iInterface != 0)
666 {
667 libusb_device_handle *device;
668 int ret;
669
670 ret = libusb_open(dev, &device);
671 if (ret < 0)
672 {
673 Log2(PCSC_LOG_ERROR, "libusb_open failed: %s",
674 libusb_error_name(ret));
675 }
676 else
677 {
678 unsigned char interfaceName[MAX_READERNAME];
679 unsigned char serialNumber[MAX_READERNAME];
680 char fullname[MAX_READERNAME * 3];
681 fullname[0] = '\0';
682 int ret_interface = 0;
683 int ret_serial = 0;
684
685 if (iInterface)
686 {
687 ret_interface = libusb_get_string_descriptor_ascii(device,
688 iInterface, interfaceName, sizeof interfaceName);
689 if (ret_interface < 0)
690 {
691 Log2(PCSC_LOG_ERROR,
692 "libusb_get_string_descriptor_ascii failed: %s",
693 libusb_error_name(ret_interface));
694 }
695 }
696
697 if (iSerialNumber)
698 {
699 ret_serial = libusb_get_string_descriptor_ascii(device,
700 iSerialNumber, serialNumber, sizeof serialNumber);
701 if (ret_serial < 0)
702 {
703 Log2(PCSC_LOG_ERROR,
704 "libusb_get_string_descriptor_ascii failed: %s",
705 libusb_error_name(ret_serial));
706 }
707 }
708
709 libusb_close(device);
710
711 if (ret_interface > 0 && ret_serial > 0)
712 {
713 snprintf(fullname, sizeof(fullname), "%s [%s] (%s)",
714 driver->readerName, interfaceName, serialNumber);
715 }
716 else
717 {
718 if (ret_interface > 0)
719 {
720 snprintf(fullname, sizeof(fullname), "%s [%s]",
721 driver->readerName, interfaceName);
722 }
723 else
724 {
725 if (ret_serial > 0)
726 {
727 snprintf(fullname, sizeof(fullname), "%s (%s)",
728 driver->readerName, serialNumber);
729 }
730 }
731 }
732
733 if (fullname[0] != '\0')
734 readerTracker[i].fullName = strdup(fullname);
735 }
736 }
737
738 if (readerTracker[i].fullName == NULL)
739 readerTracker[i].fullName = strdup(driver->readerName);
740
741 LONG ret;
742 ret = RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
743 driver->libraryPath, deviceName);
744 /* success by default */
745 readerTracker[i].status = READER_PRESENT;
746 if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
747 {
748 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
749 driver->readerName);
750
751 if (classdriver && driver != classdriver)
752 {
753 /* the reader can also be used by the a class driver */
754 ret = RFAddReader(readerTracker[i].fullName,
755 PCSCLITE_HP_BASE_PORT + i,
756 classdriver->libraryPath, deviceName);
757 if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
758 {
759 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
760 driver->readerName);
761 readerTracker[i].status = READER_FAILED;
762 }
763 }
764 else
765 readerTracker[i].status = READER_FAILED;
766 }
767
768 if (READER_FAILED == readerTracker[i].status)
769 (void)CheckForOpenCT();
770
771 pthread_mutex_unlock(&usbNotifierMutex);
772
773 free(deviceName);
774
775 return 1;
776} /* End of function */
777
778static LONG HPRemoveHotPluggable(int reader_index)
779{
780 pthread_mutex_lock(&usbNotifierMutex);
781
782 Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", reader_index,
783 readerTracker[reader_index].bus_device);
784
785 RFRemoveReader(readerTracker[reader_index].fullName,
786 PCSCLITE_HP_BASE_PORT + reader_index, REMOVE_READER_FLAG_REMOVED);
787 HPCleanupHotPluggable(reader_index);
788
789 pthread_mutex_unlock(&usbNotifierMutex);
790
791 return 1;
792} /* End of function */
793
794static void HPCleanupHotPluggable(int reader_index)
795{
796 free(readerTracker[reader_index].fullName);
797 readerTracker[reader_index].status = READER_ABSENT;
798 readerTracker[reader_index].bus_device[0] = '\0';
799 readerTracker[reader_index].fullName = NULL;
800} /* End of function */
801
805ULONG HPRegisterForHotplugEvents(const char * hpDirPath)
806{
807 (void)hpDirPath;
808
809 (void)pthread_mutex_init(&usbNotifierMutex, NULL);
810 return 0;
811}
812
813void HPReCheckSerialReaders(void)
814{
815 Log0(PCSC_LOG_INFO);
816 if (rescan_pipe[1] >= 0)
817 {
818 char dummy = 0;
819 if (write(rescan_pipe[1], &dummy, sizeof(dummy)) == -1)
820 Log2(PCSC_LOG_ERROR, "write: %s", strerror(errno));
821 }
822}
823
824#endif
825
This handles debugging.
#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.
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
Definition sys_unix.c:62
This defines some structures and #defines to be used over the transport layer.
This keeps a list of Windows(R) types.