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