pcsc-lite 1.9.9
hotplug_macosx.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 2002-2004
5 * Stephen M. Webb <stephenw@cryptocard.com>
6 * Copyright (C) 2002-2011
7 * Ludovic Rousseau <ludovic.rousseau@free.fr>
8 * Copyright (C) 2002
9 * David Corcoran <corcoran@musclecard.com>
10 * Copyright (C) 2003
11 * Antti Tapaninen
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#include "misc.h"
44#include "pcscd.h"
45
46#if defined(__APPLE__) && !defined(HAVE_LIBUSB)
47#include <CoreFoundation/CoreFoundation.h>
48#include <IOKit/IOCFPlugIn.h>
49#include <IOKit/IOKitLib.h>
50#include <IOKit/usb/IOUSBLib.h>
51#include <stdlib.h>
52#include <string.h>
53
54#include "debuglog.h"
55#include "parser.h"
56#include "readerfactory.h"
57#include "winscard_msg.h"
58#include "utils.h"
59#include "hotplug.h"
60
61#undef DEBUG_HOTPLUG
62
63/*
64 * An aggregation of useful information on a driver bundle in the
65 * drop directory.
66 */
67typedef struct HPDriver
68{
69 UInt32 m_vendorId; /* unique vendor's manufacturer code */
70 UInt32 m_productId; /* manufacturer's unique product code */
71 char *m_friendlyName; /* bundle friendly name */
72 char *m_libPath; /* bundle's plugin library location */
73} HPDriver, *HPDriverVector;
74
75/*
76 * An aggregation on information on currently active reader drivers.
77 */
78typedef struct HPDevice
79{
80 HPDriver *m_driver; /* driver bundle information */
81 UInt32 m_address; /* unique system address of device */
82 struct HPDevice *m_next; /* next device in list */
83} HPDevice, *HPDeviceList;
84
85/*
86 * Pointer to a list of (currently) known hotplug reader devices (and their
87 * drivers).
88 */
89static HPDeviceList sDeviceList = NULL;
90
91static int HPScan(void);
92static HPDriver *Drivers = NULL;
93
94/*
95 * A callback to handle the asynchronous appearance of new devices that are
96 * candidates for PCSC readers.
97 */
98static void HPDeviceAppeared(void *refCon, io_iterator_t iterator)
99{
100 kern_return_t kret;
101 io_service_t obj;
102
103 (void)refCon;
104
105 while ((obj = IOIteratorNext(iterator)))
106 kret = IOObjectRelease(obj);
107
108 HPScan();
109}
110
111/*
112 * A callback to handle the asynchronous disappearance of devices that are
113 * possibly PCSC readers.
114 */
115static void HPDeviceDisappeared(void *refCon, io_iterator_t iterator)
116{
117 kern_return_t kret;
118 io_service_t obj;
119
120 (void)refCon;
121
122 while ((obj = IOIteratorNext(iterator)))
123 kret = IOObjectRelease(obj);
124
125 HPScan();
126}
127
128
129/*
130 * Creates a vector of driver bundle info structures from the hot-plug driver
131 * directory.
132 *
133 * Returns NULL on error and a pointer to an allocated HPDriver vector on
134 * success. The caller must free the HPDriver with a call to
135 * HPDriversRelease().
136 */
137static HPDriverVector HPDriversGetFromDirectory(const char *driverBundlePath)
138{
139#ifdef DEBUG_HOTPLUG
140 Log2(PCSC_LOG_DEBUG, "Entering HPDriversGetFromDirectory: %s",
141 driverBundlePath);
142#endif
143
144 int readersNumber = 0;
145 HPDriverVector bundleVector = NULL;
146 CFArrayRef bundleArray;
147 CFStringRef driverBundlePathString =
148 CFStringCreateWithCString(kCFAllocatorDefault,
149 driverBundlePath,
150 kCFStringEncodingMacRoman);
151 CFURLRef pluginUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
152 driverBundlePathString,
153 kCFURLPOSIXPathStyle, TRUE);
154
155 CFRelease(driverBundlePathString);
156 if (!pluginUrl)
157 {
158 Log1(PCSC_LOG_ERROR, "error getting plugin directory URL");
159 return NULL;
160 }
161 bundleArray = CFBundleCreateBundlesFromDirectory(kCFAllocatorDefault,
162 pluginUrl, NULL);
163 if (!bundleArray)
164 {
165 Log1(PCSC_LOG_ERROR, "error getting plugin directory bundles");
166 return NULL;
167 }
168 CFRelease(pluginUrl);
169
170 size_t bundleArraySize = CFArrayGetCount(bundleArray);
171 size_t i;
172
173 /* get the number of readers (including aliases) */
174 for (i = 0; i < bundleArraySize; i++)
175 {
176 CFBundleRef currBundle =
177 (CFBundleRef) CFArrayGetValueAtIndex(bundleArray, i);
178 CFDictionaryRef dict = CFBundleGetInfoDictionary(currBundle);
179
180 const void * blobValue = CFDictionaryGetValue(dict,
181 CFSTR(PCSCLITE_HP_MANUKEY_NAME));
182
183 if (!blobValue)
184 {
185 Log1(PCSC_LOG_ERROR, "error getting vendor ID from bundle");
186 return NULL;
187 }
188
189 if (CFGetTypeID(blobValue) == CFArrayGetTypeID())
190 {
191 /* alias found, each reader count as 1 */
192 CFArrayRef propertyArray = blobValue;
193 readersNumber += CFArrayGetCount(propertyArray);
194 }
195 else
196 /* No alias, only one reader supported */
197 readersNumber++;
198 }
199#ifdef DEBUG_HOTPLUG
200 Log2(PCSC_LOG_DEBUG, "Total of %d readers supported", readersNumber);
201#endif
202
203 /* The last entry is an end marker (m_vendorId = 0)
204 * see checks in HPDriversMatchUSBDevices:503
205 * and HPDriverVectorRelease:376 */
206 readersNumber++;
207
208 bundleVector = calloc(readersNumber, sizeof(HPDriver));
209 if (!bundleVector)
210 {
211 Log1(PCSC_LOG_ERROR, "memory allocation failure");
212 return NULL;
213 }
214
215 HPDriver *driverBundle = bundleVector;
216 for (i = 0; i < bundleArraySize; i++)
217 {
218 CFBundleRef currBundle =
219 (CFBundleRef) CFArrayGetValueAtIndex(bundleArray, i);
220 CFDictionaryRef dict = CFBundleGetInfoDictionary(currBundle);
221
222 CFURLRef bundleUrl = CFBundleCopyBundleURL(currBundle);
223 CFStringRef bundlePath = CFURLCopyPath(bundleUrl);
224
225 driverBundle->m_libPath = strdup(CFStringGetCStringPtr(bundlePath,
226 CFStringGetSystemEncoding()));
227
228 const void * blobValue = CFDictionaryGetValue(dict,
229 CFSTR(PCSCLITE_HP_MANUKEY_NAME));
230
231 if (!blobValue)
232 {
233 Log1(PCSC_LOG_ERROR, "error getting vendor ID from bundle");
234 return bundleVector;
235 }
236
237 if (CFGetTypeID(blobValue) == CFArrayGetTypeID())
238 {
239 CFArrayRef vendorArray = blobValue;
240 CFArrayRef productArray;
241 CFArrayRef friendlyNameArray;
242 char *libPath = driverBundle->m_libPath;
243
244#ifdef DEBUG_HOTPLUG
245 Log2(PCSC_LOG_DEBUG, "Driver with aliases: %s", libPath);
246#endif
247 /* get list of ProductID */
248 productArray = CFDictionaryGetValue(dict,
249 CFSTR(PCSCLITE_HP_PRODKEY_NAME));
250 if (!productArray)
251 {
252 Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
253 return bundleVector;
254 }
255
256 /* get list of FriendlyName */
257 friendlyNameArray = CFDictionaryGetValue(dict,
258 CFSTR(PCSCLITE_HP_NAMEKEY_NAME));
259 if (!friendlyNameArray)
260 {
261 Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
262 return bundleVector;
263 }
264
265 int reader_nb = CFArrayGetCount(vendorArray);
266
267 if (reader_nb != CFArrayGetCount(productArray))
268 {
269 Log3(PCSC_LOG_ERROR,
270 "Malformed Info.plist: %d vendors and %ld products",
271 reader_nb, CFArrayGetCount(productArray));
272 return bundleVector;
273 }
274
275 if (reader_nb != CFArrayGetCount(friendlyNameArray))
276 {
277 Log3(PCSC_LOG_ERROR,
278 "Malformed Info.plist: %d vendors and %ld friendlynames",
279 reader_nb, CFArrayGetCount(friendlyNameArray));
280 return bundleVector;
281 }
282
283 int j;
284 for (j=0; j<reader_nb; j++)
285 {
286 char stringBuffer[1000];
287 CFStringRef strValue = CFArrayGetValueAtIndex(vendorArray, j);
288
289 CFStringGetCString(strValue, stringBuffer, sizeof stringBuffer,
290 kCFStringEncodingUTF8);
291 driverBundle->m_vendorId = strtoul(stringBuffer, NULL, 16);
292
293 strValue = CFArrayGetValueAtIndex(productArray, j);
294 CFStringGetCString(strValue, stringBuffer, sizeof stringBuffer,
295 kCFStringEncodingUTF8);
296 driverBundle->m_productId = strtoul(stringBuffer, NULL, 16);
297
298 strValue = CFArrayGetValueAtIndex(friendlyNameArray, j);
299 CFStringGetCString(strValue, stringBuffer, sizeof stringBuffer,
300 kCFStringEncodingUTF8);
301 driverBundle->m_friendlyName = strdup(stringBuffer);
302
303 if (!driverBundle->m_libPath)
304 driverBundle->m_libPath = strdup(libPath);
305
306#ifdef DEBUG_HOTPLUG
307 Log2(PCSC_LOG_DEBUG, "VendorID: 0x%04X",
308 driverBundle->m_vendorId);
309 Log2(PCSC_LOG_DEBUG, "ProductID: 0x%04X",
310 driverBundle->m_productId);
311 Log2(PCSC_LOG_DEBUG, "Friendly name: %s",
312 driverBundle->m_friendlyName);
313 Log2(PCSC_LOG_DEBUG, "Driver: %s", driverBundle->m_libPath);
314#endif
315
316 /* go to next bundle in the vector */
317 driverBundle++;
318 }
319 }
320 else
321 {
322 Log1(PCSC_LOG_ERROR, "Non array not supported");
323 }
324 }
325 CFRelease(bundleArray);
326 return bundleVector;
327}
328
329/*
330 * Copies a driver bundle instance.
331 */
332static HPDriver *HPDriverCopy(HPDriver * rhs)
333{
334 if (!rhs)
335 return NULL;
336
337 HPDriver *newDriverBundle = calloc(1, sizeof(HPDriver));
338
339 if (!newDriverBundle)
340 return NULL;
341
342 newDriverBundle->m_vendorId = rhs->m_vendorId;
343 newDriverBundle->m_productId = rhs->m_productId;
344 newDriverBundle->m_friendlyName = strdup(rhs->m_friendlyName);
345 newDriverBundle->m_libPath = strdup(rhs->m_libPath);
346
347 return newDriverBundle;
348}
349
350/*
351 * Releases resources allocated to a driver bundle vector.
352 */
353static void HPDriverRelease(HPDriver * driverBundle)
354{
355 if (driverBundle)
356 {
357 free(driverBundle->m_friendlyName);
358 free(driverBundle->m_libPath);
359 }
360}
361
362/*
363 * Inserts a new reader device in the list.
364 */
365static HPDeviceList
366HPDeviceListInsert(HPDeviceList list, HPDriver * bundle, UInt32 address)
367{
368 HPDevice *newReader = calloc(1, sizeof(HPDevice));
369
370 if (!newReader)
371 {
372 Log1(PCSC_LOG_ERROR, "memory allocation failure");
373 return list;
374 }
375
376 newReader->m_driver = HPDriverCopy(bundle);
377 newReader->m_address = address;
378 newReader->m_next = list;
379
380 return newReader;
381}
382
383/*
384 * Frees resources allocated to a HPDeviceList.
385 */
386static void HPDeviceListRelease(HPDeviceList list)
387{
388 HPDevice *p;
389
390 for (p = list; p; p = p->m_next)
391 HPDriverRelease(p->m_driver);
392}
393
394/*
395 * Compares two driver bundle instances for equality.
396 */
397static int HPDeviceEquals(HPDevice * a, HPDevice * b)
398{
399 return (a->m_driver->m_vendorId == b->m_driver->m_vendorId)
400 && (a->m_driver->m_productId == b->m_driver->m_productId)
401 && (a->m_address == b->m_address);
402}
403
404/*
405 * Finds USB devices currently registered in the system that match any of
406 * the drivers detected in the driver bundle vector.
407 */
408static int
409HPDriversMatchUSBDevices(HPDriverVector driverBundle,
410 HPDeviceList * readerList)
411{
412 CFDictionaryRef usbMatch = IOServiceMatching("IOUSBDevice");
413
414 if (0 == usbMatch)
415 {
416 Log1(PCSC_LOG_ERROR,
417 "error getting USB match from IOServiceMatching()");
418 return 1;
419 }
420
421 io_iterator_t usbIter;
422 kern_return_t kret = IOServiceGetMatchingServices(kIOMasterPortDefault,
423 usbMatch, &usbIter);
424
425 if (kret != 0)
426 {
427 Log1(PCSC_LOG_ERROR,
428 "error getting iterator from IOServiceGetMatchingServices()");
429 return 1;
430 }
431
432 IOIteratorReset(usbIter);
433 io_object_t usbDevice = 0;
434
435 while ((usbDevice = IOIteratorNext(usbIter)))
436 {
437 char namebuf[1024];
438
439 kret = IORegistryEntryGetName(usbDevice, namebuf);
440 if (kret != 0)
441 {
442 Log1(PCSC_LOG_ERROR,
443 "error getting device name from IORegistryEntryGetName()");
444 return 1;
445 }
446
447 IOCFPlugInInterface **iodev;
448 SInt32 score;
449
450 kret = IOCreatePlugInInterfaceForService(usbDevice,
451 kIOUSBDeviceUserClientTypeID,
452 kIOCFPlugInInterfaceID, &iodev, &score);
453 if (kret != 0)
454 {
455 Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
456 return 1;
457 }
458 IOObjectRelease(usbDevice);
459
460 IOUSBDeviceInterface **usbdev;
461 HRESULT hres = (*iodev)->QueryInterface(iodev,
462 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
463 (LPVOID *) & usbdev);
464
465 (*iodev)->Release(iodev);
466 if (hres)
467 {
468 Log1(PCSC_LOG_ERROR,
469 "error querying interface in QueryInterface()");
470 return 1;
471 }
472
473 UInt16 vendorId = 0;
474 UInt16 productId = 0;
475 UInt32 usbAddress = 0;
476
477 kret = (*usbdev)->GetDeviceVendor(usbdev, &vendorId);
478 kret = (*usbdev)->GetDeviceProduct(usbdev, &productId);
479 kret = (*usbdev)->GetLocationID(usbdev, &usbAddress);
480 (*usbdev)->Release(usbdev);
481
482#ifdef DEBUG_HOTPLUG
483 Log4(PCSC_LOG_DEBUG, "Found USB device 0x%04X:0x%04X at 0x%X",
484 vendorId, productId, usbAddress);
485#endif
486 HPDriver *driver;
487 for (driver = driverBundle; driver->m_vendorId; ++driver)
488 {
489 if ((driver->m_vendorId == vendorId)
490 && (driver->m_productId == productId))
491 {
492#ifdef DEBUG_HOTPLUG
493 Log4(PCSC_LOG_DEBUG, "Adding USB device %04X:%04X at 0x%X",
494 vendorId, productId, usbAddress);
495#endif
496 *readerList =
497 HPDeviceListInsert(*readerList, driver, usbAddress);
498 }
499 }
500 }
501
502 IOObjectRelease(usbIter);
503 return 0;
504}
505
506/*
507 * Finds PC Card devices currently registered in the system that match any of
508 * the drivers detected in the driver bundle vector.
509 */
510static int
511HPDriversMatchPCCardDevices(HPDriver * driverBundle,
512 HPDeviceList * readerList)
513{
514 CFDictionaryRef pccMatch = IOServiceMatching("IOPCCard16Device");
515
516 if (pccMatch == NULL)
517 {
518 Log1(PCSC_LOG_ERROR,
519 "error getting PCCard match from IOServiceMatching()");
520 return 1;
521 }
522
523 io_iterator_t pccIter;
524 kern_return_t kret =
525 IOServiceGetMatchingServices(kIOMasterPortDefault, pccMatch,
526 &pccIter);
527 if (kret != 0)
528 {
529 Log1(PCSC_LOG_ERROR,
530 "error getting iterator from IOServiceGetMatchingServices()");
531 return 1;
532 }
533
534 IOIteratorReset(pccIter);
535 io_object_t pccDevice = 0;
536
537 while ((pccDevice = IOIteratorNext(pccIter)))
538 {
539 char namebuf[1024];
540
541 kret = IORegistryEntryGetName(pccDevice, namebuf);
542 if (kret != 0)
543 {
544 Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
545 return 1;
546 }
547 UInt32 vendorId = 0;
548 UInt32 productId = 0;
549 UInt32 pccAddress = 0;
550 CFTypeRef valueRef =
551 IORegistryEntryCreateCFProperty(pccDevice, CFSTR("VendorID"),
552 kCFAllocatorDefault, 0);
553
554 if (!valueRef)
555 {
556 Log1(PCSC_LOG_ERROR, "error getting vendor");
557 }
558 else
559 {
560 CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
561 &vendorId);
562 }
563 valueRef =
564 IORegistryEntryCreateCFProperty(pccDevice, CFSTR("DeviceID"),
565 kCFAllocatorDefault, 0);
566 if (!valueRef)
567 {
568 Log1(PCSC_LOG_ERROR, "error getting device");
569 }
570 else
571 {
572 CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
573 &productId);
574 }
575 valueRef =
576 IORegistryEntryCreateCFProperty(pccDevice, CFSTR("SocketNumber"),
577 kCFAllocatorDefault, 0);
578 if (!valueRef)
579 {
580 Log1(PCSC_LOG_ERROR, "error getting PC Card socket");
581 }
582 else
583 {
584 CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
585 &pccAddress);
586 }
587 HPDriver *driver = driverBundle;
588
589 for (; driver->m_vendorId; ++driver)
590 {
591 if ((driver->m_vendorId == vendorId)
592 && (driver->m_productId == productId))
593 {
594 *readerList =
595 HPDeviceListInsert(*readerList, driver, pccAddress);
596 }
597 }
598 }
599 IOObjectRelease(pccIter);
600 return 0;
601}
602
603
604static void HPEstablishUSBNotification(void)
605{
606 io_iterator_t deviceAddedIterator;
607 io_iterator_t deviceRemovedIterator;
608 CFMutableDictionaryRef matchingDictionary;
609 IONotificationPortRef notificationPort;
610 IOReturn kret;
611
612 notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
613 CFRunLoopAddSource(CFRunLoopGetCurrent(),
614 IONotificationPortGetRunLoopSource(notificationPort),
615 kCFRunLoopDefaultMode);
616
617 matchingDictionary = IOServiceMatching("IOUSBDevice");
618 if (!matchingDictionary)
619 {
620 Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
621 }
622 matchingDictionary =
623 (CFMutableDictionaryRef) CFRetain(matchingDictionary);
624
625 kret = IOServiceAddMatchingNotification(notificationPort,
626 kIOMatchedNotification,
627 matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
628 if (kret)
629 {
630 Log2(PCSC_LOG_ERROR,
631 "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
632 }
633 HPDeviceAppeared(NULL, deviceAddedIterator);
634
635 kret = IOServiceAddMatchingNotification(notificationPort,
636 kIOTerminatedNotification,
637 matchingDictionary,
638 HPDeviceDisappeared, NULL, &deviceRemovedIterator);
639 if (kret)
640 {
641 Log2(PCSC_LOG_ERROR,
642 "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
643 }
644 HPDeviceDisappeared(NULL, deviceRemovedIterator);
645}
646
647static void HPEstablishPCCardNotification(void)
648{
649 io_iterator_t deviceAddedIterator;
650 io_iterator_t deviceRemovedIterator;
651 CFMutableDictionaryRef matchingDictionary;
652 IONotificationPortRef notificationPort;
653 IOReturn kret;
654
655 notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
656 CFRunLoopAddSource(CFRunLoopGetCurrent(),
657 IONotificationPortGetRunLoopSource(notificationPort),
658 kCFRunLoopDefaultMode);
659
660 matchingDictionary = IOServiceMatching("IOPCCard16Device");
661 if (!matchingDictionary)
662 {
663 Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
664 }
665 matchingDictionary =
666 (CFMutableDictionaryRef) CFRetain(matchingDictionary);
667
668 kret = IOServiceAddMatchingNotification(notificationPort,
669 kIOMatchedNotification,
670 matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
671 if (kret)
672 {
673 Log2(PCSC_LOG_ERROR,
674 "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
675 }
676 HPDeviceAppeared(NULL, deviceAddedIterator);
677
678 kret = IOServiceAddMatchingNotification(notificationPort,
679 kIOTerminatedNotification,
680 matchingDictionary,
681 HPDeviceDisappeared, NULL, &deviceRemovedIterator);
682 if (kret)
683 {
684 Log2(PCSC_LOG_ERROR,
685 "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
686 }
687 HPDeviceDisappeared(NULL, deviceRemovedIterator);
688}
689
690/*
691 * Thread runner (does not return).
692 */
693static void HPDeviceNotificationThread(void)
694{
695 HPEstablishUSBNotification();
696 HPEstablishPCCardNotification();
697 CFRunLoopRun();
698}
699
700/*
701 * Scans the hotplug driver directory and looks in the system for
702 * matching devices.
703 * Adds or removes matching readers as necessary.
704 */
705LONG HPSearchHotPluggables(const char * hpDirPath)
706{
707 Drivers = HPDriversGetFromDirectory(hpDirPath);
708
709 if (!Drivers)
710 return 1;
711
712 return 0;
713}
714
715static int HPScan(void)
716{
717 HPDeviceList devices = NULL;
718
719 if (HPDriversMatchUSBDevices(Drivers, &devices))
720 return -1;
721
722 if (HPDriversMatchPCCardDevices(Drivers, &devices))
723 return -1;
724
725 HPDevice *a;
726
727 for (a = devices; a; a = a->m_next)
728 {
729 bool found = false;
730 HPDevice *b;
731
732 for (b = sDeviceList; b; b = b->m_next)
733 {
734 if (HPDeviceEquals(a, b))
735 {
736 found = true;
737 break;
738 }
739 }
740 if (!found)
741 {
742 char *deviceName;
743
744 /* the format should be "usb:%04x/%04x" but Apple uses the
745 * friendly name instead */
746 asprintf(&deviceName, "%s", a->m_driver->m_friendlyName);
747
748 RFAddReader(a->m_driver->m_friendlyName,
749 PCSCLITE_HP_BASE_PORT + a->m_address, a->m_driver->m_libPath,
750 deviceName);
751 free(deviceName);
752 }
753 }
754
755 for (a = sDeviceList; a; a = a->m_next)
756 {
757 bool found = false;
758 HPDevice *b;
759
760 for (b = devices; b; b = b->m_next)
761 {
762 if (HPDeviceEquals(a, b))
763 {
764 found = true;
765 break;
766 }
767 }
768 if (!found)
769 {
770 RFRemoveReader(a->m_driver->m_friendlyName,
771 PCSCLITE_HP_BASE_PORT + a->m_address,
772 REMOVE_READER_FLAG_REMOVED);
773 }
774 }
775
776 HPDeviceListRelease(sDeviceList);
777 sDeviceList = devices;
778
779 return 0;
780}
781
782
783pthread_t sHotplugWatcherThread;
784
785/*
786 * Sets up callbacks for device hotplug events.
787 */
788ULONG HPRegisterForHotplugEvents(const char * hpDirPath)
789{
790 ThreadCreate(&sHotplugWatcherThread,
791 THREAD_ATTR_DEFAULT,
792 (PCSCLITE_THREAD_FUNCTION( )) HPDeviceNotificationThread, NULL);
793
794 return 0;
795}
796
797LONG HPStopHotPluggables(void)
798{
799 return 0;
800}
801
802void HPReCheckSerialReaders(void)
803{
804}
805
806#endif /* __APPLE__ */
807
This handles debugging.
This provides a search API for hot pluggble devices.
Reads lexical config files and updates database.
This keeps a list of defines for pcsc-lite.
This keeps track of a list of currently available reader structures.
This defines some structures and #defines to be used over the transport layer.