pcsc-lite 2.3.0
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-2023
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 CFRelease(pluginUrl);
164 if (!bundleArray)
165 {
166 Log1(PCSC_LOG_ERROR, "error getting plugin directory bundles");
167 return NULL;
168 }
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 CFRelease(bundleArray);
187 return NULL;
188 }
189
190 if (CFGetTypeID(blobValue) == CFArrayGetTypeID())
191 {
192 /* alias found, each reader count as 1 */
193 CFArrayRef propertyArray = blobValue;
194 readersNumber += CFArrayGetCount(propertyArray);
195 }
196 else
197 /* No alias, only one reader supported */
198 readersNumber++;
199 }
200#ifdef DEBUG_HOTPLUG
201 Log2(PCSC_LOG_DEBUG, "Total of %d readers supported", readersNumber);
202#endif
203
204 /* The last entry is an end marker (m_vendorId = 0)
205 * see checks in HPDriversMatchUSBDevices:503
206 * and HPDriverVectorRelease:376 */
207 readersNumber++;
208
209 bundleVector = calloc(readersNumber, sizeof(HPDriver));
210 if (!bundleVector)
211 {
212 Log1(PCSC_LOG_ERROR, "memory allocation failure");
213 CFRelease(bundleArray);
214 return NULL;
215 }
216
217 HPDriver *driverBundle = bundleVector;
218 for (i = 0; i < bundleArraySize; i++)
219 {
220 CFBundleRef currBundle =
221 (CFBundleRef) CFArrayGetValueAtIndex(bundleArray, i);
222 CFDictionaryRef dict = CFBundleGetInfoDictionary(currBundle);
223
224 CFURLRef bundleUrl = CFBundleCopyBundleURL(currBundle);
225 CFStringRef bundlePath = CFURLCopyPath(bundleUrl);
226 CFRelease(bundleUrl);
227
228 driverBundle->m_libPath = strdup(CFStringGetCStringPtr(bundlePath,
229 CFStringGetSystemEncoding()));
230 CFRelease(bundlePath);
231
232 const void * blobValue = CFDictionaryGetValue(dict,
233 CFSTR(PCSCLITE_HP_MANUKEY_NAME));
234
235 if (!blobValue)
236 {
237 Log1(PCSC_LOG_ERROR, "error getting vendor ID from bundle");
238 CFRelease(bundleArray);
239 return bundleVector;
240 }
241
242 if (CFGetTypeID(blobValue) == CFArrayGetTypeID())
243 {
244 CFArrayRef vendorArray = blobValue;
245 CFArrayRef productArray;
246 CFArrayRef friendlyNameArray;
247 char *libPath = driverBundle->m_libPath;
248
249#ifdef DEBUG_HOTPLUG
250 Log2(PCSC_LOG_DEBUG, "Driver with aliases: %s", libPath);
251#endif
252 /* get list of ProductID */
253 productArray = CFDictionaryGetValue(dict,
254 CFSTR(PCSCLITE_HP_PRODKEY_NAME));
255 if (!productArray)
256 {
257 Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
258 CFRelease(bundleArray);
259 return bundleVector;
260 }
261
262 /* get list of FriendlyName */
263 friendlyNameArray = CFDictionaryGetValue(dict,
264 CFSTR(PCSCLITE_HP_NAMEKEY_NAME));
265 if (!friendlyNameArray)
266 {
267 Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
268 CFRelease(bundleArray);
269 return bundleVector;
270 }
271
272 long reader_nb = CFArrayGetCount(vendorArray);
273
274 if (reader_nb != CFArrayGetCount(productArray))
275 {
276 Log3(PCSC_LOG_ERROR,
277 "Malformed Info.plist: %ld vendors and %ld products",
278 reader_nb, CFArrayGetCount(productArray));
279 CFRelease(bundleArray);
280 return bundleVector;
281 }
282
283 if (reader_nb != CFArrayGetCount(friendlyNameArray))
284 {
285 Log3(PCSC_LOG_ERROR,
286 "Malformed Info.plist: %ld vendors and %ld friendlynames",
287 reader_nb, CFArrayGetCount(friendlyNameArray));
288 CFRelease(bundleArray);
289 return bundleVector;
290 }
291
292 int j;
293 for (j=0; j<reader_nb; j++)
294 {
295 char stringBuffer[1000];
296 CFStringRef strValue = CFArrayGetValueAtIndex(vendorArray, j);
297
298 CFStringGetCString(strValue, stringBuffer, sizeof stringBuffer,
299 kCFStringEncodingUTF8);
300 driverBundle->m_vendorId = (unsigned int)strtoul(stringBuffer, NULL, 16);
301
302 strValue = CFArrayGetValueAtIndex(productArray, j);
303 CFStringGetCString(strValue, stringBuffer, sizeof stringBuffer,
304 kCFStringEncodingUTF8);
305 driverBundle->m_productId = (unsigned int)strtoul(stringBuffer, NULL, 16);
306
307 strValue = CFArrayGetValueAtIndex(friendlyNameArray, j);
308 CFStringGetCString(strValue, stringBuffer, sizeof stringBuffer,
309 kCFStringEncodingUTF8);
310 driverBundle->m_friendlyName = strdup(stringBuffer);
311
312 if (!driverBundle->m_libPath)
313 driverBundle->m_libPath = strdup(libPath);
314
315#ifdef DEBUG_HOTPLUG
316 Log2(PCSC_LOG_DEBUG, "VendorID: 0x%04X",
317 driverBundle->m_vendorId);
318 Log2(PCSC_LOG_DEBUG, "ProductID: 0x%04X",
319 driverBundle->m_productId);
320 Log2(PCSC_LOG_DEBUG, "Friendly name: %s",
321 driverBundle->m_friendlyName);
322 Log2(PCSC_LOG_DEBUG, "Driver: %s", driverBundle->m_libPath);
323#endif
324
325 /* go to next bundle in the vector */
326 driverBundle++;
327 }
328 }
329 else
330 {
331 Log1(PCSC_LOG_ERROR, "Non array not supported");
332 }
333 }
334 CFRelease(bundleArray);
335 return bundleVector;
336}
337
338/*
339 * Copies a driver bundle instance.
340 */
341static HPDriver *HPDriverCopy(HPDriver * rhs)
342{
343 if (!rhs)
344 return NULL;
345
346 HPDriver *newDriverBundle = calloc(1, sizeof(HPDriver));
347
348 if (!newDriverBundle)
349 return NULL;
350
351 newDriverBundle->m_vendorId = rhs->m_vendorId;
352 newDriverBundle->m_productId = rhs->m_productId;
353 newDriverBundle->m_friendlyName = strdup(rhs->m_friendlyName);
354 newDriverBundle->m_libPath = strdup(rhs->m_libPath);
355
356 return newDriverBundle;
357}
358
359/*
360 * Releases resources allocated to a driver bundle vector.
361 */
362static void HPDriverRelease(HPDriver * driverBundle)
363{
364 if (driverBundle)
365 {
366 free(driverBundle->m_friendlyName);
367 free(driverBundle->m_libPath);
368 }
369}
370
371/*
372 * Inserts a new reader device in the list.
373 */
374static HPDeviceList
375HPDeviceListInsert(HPDeviceList list, HPDriver * bundle, UInt32 address)
376{
377 HPDevice *newReader = calloc(1, sizeof(HPDevice));
378
379 if (!newReader)
380 {
381 Log1(PCSC_LOG_ERROR, "memory allocation failure");
382 return list;
383 }
384
385 newReader->m_driver = HPDriverCopy(bundle);
386 newReader->m_address = address;
387 newReader->m_next = list;
388
389 return newReader;
390}
391
392/*
393 * Frees resources allocated to a HPDeviceList.
394 */
395static void HPDeviceListRelease(HPDeviceList list)
396{
397 HPDevice *p;
398
399 for (p = list; p; p = p->m_next)
400 HPDriverRelease(p->m_driver);
401}
402
403/*
404 * Compares two driver bundle instances for equality.
405 */
406static int HPDeviceEquals(HPDevice * a, HPDevice * b)
407{
408 return (a->m_driver->m_vendorId == b->m_driver->m_vendorId)
409 && (a->m_driver->m_productId == b->m_driver->m_productId)
410 && (a->m_address == b->m_address);
411}
412
413/*
414 * Finds USB devices currently registered in the system that match any of
415 * the drivers detected in the driver bundle vector.
416 */
417static int
418HPDriversMatchUSBDevices(HPDriverVector driverBundle,
419 HPDeviceList * readerList)
420{
421 CFDictionaryRef usbMatch = IOServiceMatching("IOUSBDevice");
422
423 if (0 == usbMatch)
424 {
425 Log1(PCSC_LOG_ERROR,
426 "error getting USB match from IOServiceMatching()");
427 return 1;
428 }
429
430 io_iterator_t usbIter;
431 kern_return_t kret = IOServiceGetMatchingServices(kIOMainPortDefault,
432 usbMatch, &usbIter);
433
434 if (kret != 0)
435 {
436 Log1(PCSC_LOG_ERROR,
437 "error getting iterator from IOServiceGetMatchingServices()");
438 return 1;
439 }
440
441 IOIteratorReset(usbIter);
442 io_object_t usbDevice = 0;
443
444 while ((usbDevice = IOIteratorNext(usbIter)))
445 {
446 char namebuf[1024];
447
448 kret = IORegistryEntryGetName(usbDevice, namebuf);
449 if (kret != 0)
450 {
451 Log1(PCSC_LOG_ERROR,
452 "error getting device name from IORegistryEntryGetName()");
453 return 1;
454 }
455
456 IOCFPlugInInterface **iodev;
457 SInt32 score;
458
459 kret = IOCreatePlugInInterfaceForService(usbDevice,
460 kIOUSBDeviceUserClientTypeID,
461 kIOCFPlugInInterfaceID, &iodev, &score);
462 if (kret != 0)
463 {
464 Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
465 return 1;
466 }
467 IOObjectRelease(usbDevice);
468
469 IOUSBDeviceInterface **usbdev;
470 HRESULT hres = (*iodev)->QueryInterface(iodev,
471 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
472 (LPVOID *) & usbdev);
473
474 (*iodev)->Release(iodev);
475 if (hres)
476 {
477 Log1(PCSC_LOG_ERROR,
478 "error querying interface in QueryInterface()");
479 return 1;
480 }
481
482 UInt16 vendorId = 0;
483 UInt16 productId = 0;
484 UInt32 usbAddress = 0;
485
486 kret = (*usbdev)->GetDeviceVendor(usbdev, &vendorId);
487 kret = (*usbdev)->GetDeviceProduct(usbdev, &productId);
488 kret = (*usbdev)->GetLocationID(usbdev, &usbAddress);
489 (*usbdev)->Release(usbdev);
490
491#ifdef DEBUG_HOTPLUG
492 Log4(PCSC_LOG_DEBUG, "Found USB device 0x%04X:0x%04X at 0x%X",
493 vendorId, productId, usbAddress);
494#endif
495 HPDriver *driver;
496 for (driver = driverBundle; driver->m_vendorId; ++driver)
497 {
498 if ((driver->m_vendorId == vendorId)
499 && (driver->m_productId == productId))
500 {
501#ifdef DEBUG_HOTPLUG
502 Log4(PCSC_LOG_DEBUG, "Adding USB device %04X:%04X at 0x%X",
503 vendorId, productId, usbAddress);
504#endif
505 *readerList =
506 HPDeviceListInsert(*readerList, driver, usbAddress);
507 }
508 }
509 }
510
511 IOObjectRelease(usbIter);
512 return 0;
513}
514
515/*
516 * Finds PC Card devices currently registered in the system that match any of
517 * the drivers detected in the driver bundle vector.
518 */
519static int
520HPDriversMatchPCCardDevices(HPDriver * driverBundle,
521 HPDeviceList * readerList)
522{
523 CFDictionaryRef pccMatch = IOServiceMatching("IOPCCard16Device");
524
525 if (pccMatch == NULL)
526 {
527 Log1(PCSC_LOG_ERROR,
528 "error getting PCCard match from IOServiceMatching()");
529 return 1;
530 }
531
532 io_iterator_t pccIter;
533 kern_return_t kret =
534 IOServiceGetMatchingServices(kIOMainPortDefault, pccMatch,
535 &pccIter);
536 if (kret != 0)
537 {
538 Log1(PCSC_LOG_ERROR,
539 "error getting iterator from IOServiceGetMatchingServices()");
540 return 1;
541 }
542
543 IOIteratorReset(pccIter);
544 io_object_t pccDevice = 0;
545
546 while ((pccDevice = IOIteratorNext(pccIter)))
547 {
548 char namebuf[1024];
549
550 kret = IORegistryEntryGetName(pccDevice, namebuf);
551 if (kret != 0)
552 {
553 Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
554 return 1;
555 }
556 UInt32 vendorId = 0;
557 UInt32 productId = 0;
558 UInt32 pccAddress = 0;
559 CFTypeRef valueRef =
560 IORegistryEntryCreateCFProperty(pccDevice, CFSTR("VendorID"),
561 kCFAllocatorDefault, 0);
562
563 if (!valueRef)
564 {
565 Log1(PCSC_LOG_ERROR, "error getting vendor");
566 }
567 else
568 {
569 CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
570 &vendorId);
571 CFRelease(valueRef);
572 }
573 valueRef =
574 IORegistryEntryCreateCFProperty(pccDevice, CFSTR("DeviceID"),
575 kCFAllocatorDefault, 0);
576 if (!valueRef)
577 {
578 Log1(PCSC_LOG_ERROR, "error getting device");
579 }
580 else
581 {
582 CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
583 &productId);
584 CFRelease(valueRef);
585 }
586 valueRef =
587 IORegistryEntryCreateCFProperty(pccDevice, CFSTR("SocketNumber"),
588 kCFAllocatorDefault, 0);
589 if (!valueRef)
590 {
591 Log1(PCSC_LOG_ERROR, "error getting PC Card socket");
592 }
593 else
594 {
595 CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
596 &pccAddress);
597 CFRelease(valueRef);
598 }
599 HPDriver *driver = driverBundle;
600
601 for (; driver->m_vendorId; ++driver)
602 {
603 if ((driver->m_vendorId == vendorId)
604 && (driver->m_productId == productId))
605 {
606 *readerList =
607 HPDeviceListInsert(*readerList, driver, pccAddress);
608 }
609 }
610 }
611 IOObjectRelease(pccIter);
612 return 0;
613}
614
615
616static void HPEstablishUSBNotification(void)
617{
618 io_iterator_t deviceAddedIterator;
619 io_iterator_t deviceRemovedIterator;
620 CFMutableDictionaryRef matchingDictionary;
621 IONotificationPortRef notificationPort;
622 IOReturn kret;
623
624 notificationPort = IONotificationPortCreate(kIOMainPortDefault);
625 CFRunLoopAddSource(CFRunLoopGetCurrent(),
626 IONotificationPortGetRunLoopSource(notificationPort),
627 kCFRunLoopDefaultMode);
628
629 matchingDictionary = IOServiceMatching("IOUSBDevice");
630 if (!matchingDictionary)
631 {
632 Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
633 return;
634 }
635 matchingDictionary =
636 (CFMutableDictionaryRef) CFRetain(matchingDictionary);
637
638 kret = IOServiceAddMatchingNotification(notificationPort,
639 kIOMatchedNotification,
640 matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
641 if (kret)
642 {
643 Log2(PCSC_LOG_ERROR,
644 "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
645 }
646 HPDeviceAppeared(NULL, deviceAddedIterator);
647
648 kret = IOServiceAddMatchingNotification(notificationPort,
649 kIOTerminatedNotification,
650 matchingDictionary,
651 HPDeviceDisappeared, NULL, &deviceRemovedIterator);
652 if (kret)
653 {
654 Log2(PCSC_LOG_ERROR,
655 "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
656 }
657 HPDeviceDisappeared(NULL, deviceRemovedIterator);
658}
659
660static void HPEstablishPCCardNotification(void)
661{
662 io_iterator_t deviceAddedIterator;
663 io_iterator_t deviceRemovedIterator;
664 CFMutableDictionaryRef matchingDictionary;
665 IONotificationPortRef notificationPort;
666 IOReturn kret;
667
668 notificationPort = IONotificationPortCreate(kIOMainPortDefault);
669 CFRunLoopAddSource(CFRunLoopGetCurrent(),
670 IONotificationPortGetRunLoopSource(notificationPort),
671 kCFRunLoopDefaultMode);
672
673 matchingDictionary = IOServiceMatching("IOPCCard16Device");
674 if (!matchingDictionary)
675 {
676 Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
677 return;
678 }
679 matchingDictionary =
680 (CFMutableDictionaryRef) CFRetain(matchingDictionary);
681
682 kret = IOServiceAddMatchingNotification(notificationPort,
683 kIOMatchedNotification,
684 matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
685 if (kret)
686 {
687 Log2(PCSC_LOG_ERROR,
688 "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
689 }
690 HPDeviceAppeared(NULL, deviceAddedIterator);
691
692 kret = IOServiceAddMatchingNotification(notificationPort,
693 kIOTerminatedNotification,
694 matchingDictionary,
695 HPDeviceDisappeared, NULL, &deviceRemovedIterator);
696 if (kret)
697 {
698 Log2(PCSC_LOG_ERROR,
699 "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
700 }
701 HPDeviceDisappeared(NULL, deviceRemovedIterator);
702}
703
704/*
705 * Thread runner (does not return).
706 */
707static void HPDeviceNotificationThread(void)
708{
709 HPEstablishUSBNotification();
710 HPEstablishPCCardNotification();
711 CFRunLoopRun();
712}
713
714/*
715 * Scans the hotplug driver directory and looks in the system for
716 * matching devices.
717 * Adds or removes matching readers as necessary.
718 */
719LONG HPSearchHotPluggables(const char * hpDirPath)
720{
721 Drivers = HPDriversGetFromDirectory(hpDirPath);
722
723 if (!Drivers)
724 return 1;
725
726 return 0;
727}
728
729static int HPScan(void)
730{
731 HPDeviceList devices = NULL;
732
733 if (HPDriversMatchUSBDevices(Drivers, &devices))
734 {
735 if (devices)
736 free(devices);
737
738 return -1;
739 }
740
741 if (HPDriversMatchPCCardDevices(Drivers, &devices))
742 {
743 if (devices)
744 free(devices);
745
746 return -1;
747 }
748
749 HPDevice *a;
750
751 for (a = devices; a; a = a->m_next)
752 {
753 bool found = false;
754 HPDevice *b;
755
756 for (b = sDeviceList; b; b = b->m_next)
757 {
758 if (HPDeviceEquals(a, b))
759 {
760 found = true;
761 break;
762 }
763 }
764 if (!found)
765 {
766 char *deviceName;
767
768 /* the format should be "usb:%04x/%04x" but Apple uses the
769 * friendly name instead */
770 asprintf(&deviceName, "%s", a->m_driver->m_friendlyName);
771
772 RFAddReader(a->m_driver->m_friendlyName,
773 PCSCLITE_HP_BASE_PORT + a->m_address, a->m_driver->m_libPath,
774 deviceName);
775 free(deviceName);
776 }
777 }
778
779 for (a = sDeviceList; a; a = a->m_next)
780 {
781 bool found = false;
782 HPDevice *b;
783
784 for (b = devices; b; b = b->m_next)
785 {
786 if (HPDeviceEquals(a, b))
787 {
788 found = true;
789 break;
790 }
791 }
792 if (!found)
793 {
794 RFRemoveReader(a->m_driver->m_friendlyName,
795 PCSCLITE_HP_BASE_PORT + a->m_address,
796 REMOVE_READER_FLAG_REMOVED);
797 }
798 }
799
800 HPDeviceListRelease(sDeviceList);
801 sDeviceList = devices;
802
803 return 0;
804}
805
806
807pthread_t sHotplugWatcherThread;
808
809/*
810 * Sets up callbacks for device hotplug events.
811 */
812ULONG HPRegisterForHotplugEvents(const char * hpDirPath)
813{
814 (void)hpDirPath;
815
816 ThreadCreate(&sHotplugWatcherThread,
817 THREAD_ATTR_DEFAULT,
818 (PCSCLITE_THREAD_FUNCTION( )) HPDeviceNotificationThread, NULL);
819
820 return 0;
821}
822
823LONG HPStopHotPluggables(void)
824{
825 return 0;
826}
827
828void HPReCheckSerialReaders(void)
829{
830}
831
832#endif /* __APPLE__ */
833
This handles debugging.
This provides a search API for hot pluggble devices.
Reads lexical config files and updates database.
This keeps track of a list of currently available reader structures.
This defines some structures and #defines to be used over the transport layer.