pcsc-lite 1.9.4
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 CFStringRef strValue = CFArrayGetValueAtIndex(vendorArray, j);
287
288 driverBundle->m_vendorId = strtoul(CFStringGetCStringPtr(strValue,
289 CFStringGetSystemEncoding()), NULL, 16);
290
291 strValue = CFArrayGetValueAtIndex(productArray, j);
292 driverBundle->m_productId = strtoul(CFStringGetCStringPtr(strValue,
293 CFStringGetSystemEncoding()), NULL, 16);
294
295 strValue = CFArrayGetValueAtIndex(friendlyNameArray, j);
296 const char *cstr = CFStringGetCStringPtr(strValue,
297 CFStringGetSystemEncoding());
298 if (NULL == cstr)
299 {
300 char utf8_str[200];
301 if (CFStringGetCString(strValue, utf8_str, sizeof utf8_str,
302 kCFStringEncodingUTF8))
303 driverBundle->m_friendlyName = strdup(utf8_str);
304 else
305 continue;
306 }
307 else
308 driverBundle->m_friendlyName = strdup(cstr);
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 CFStringRef strValue = blobValue;
330
331#ifdef DEBUG_HOTPLUG
332 Log3(PCSC_LOG_DEBUG, "Driver without alias: %s %s",
333 driverBundle->m_friendlyName, driverBundle->m_libPath);
334#endif
335
336 driverBundle->m_vendorId = strtoul(CFStringGetCStringPtr(strValue,
337 CFStringGetSystemEncoding()), NULL, 16);
338
339 strValue = (CFStringRef) CFDictionaryGetValue(dict,
340 CFSTR(PCSCLITE_HP_PRODKEY_NAME));
341 if (!strValue)
342 {
343 Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
344 return bundleVector;
345 }
346 driverBundle->m_productId = strtoul(CFStringGetCStringPtr(strValue,
347 CFStringGetSystemEncoding()), NULL, 16);
348
349 strValue = (CFStringRef) CFDictionaryGetValue(dict,
350 CFSTR(PCSCLITE_HP_NAMEKEY_NAME));
351 if (!strValue)
352 {
353 Log1(PCSC_LOG_ERROR, "error getting product friendly name from bundle");
354 driverBundle->m_friendlyName = strdup("unnamed device");
355 }
356 else
357 {
358 const char *cstr = CFStringGetCStringPtr(strValue,
359 CFStringGetSystemEncoding());
360
361 driverBundle->m_friendlyName = strdup(cstr);
362 }
363#ifdef DEBUG_HOTPLUG
364 Log2(PCSC_LOG_DEBUG, "VendorID: 0x%04X", driverBundle->m_vendorId);
365 Log2(PCSC_LOG_DEBUG, "ProductID: 0x%04X", driverBundle->m_productId);
366 Log2(PCSC_LOG_DEBUG, "Friendly name: %s", driverBundle->m_friendlyName);
367 Log2(PCSC_LOG_DEBUG, "Driver: %s", driverBundle->m_libPath);
368#endif
369
370 /* go to next bundle in the vector */
371 driverBundle++;
372 }
373 }
374 CFRelease(bundleArray);
375 return bundleVector;
376}
377
378/*
379 * Copies a driver bundle instance.
380 */
381static HPDriver *HPDriverCopy(HPDriver * rhs)
382{
383 if (!rhs)
384 return NULL;
385
386 HPDriver *newDriverBundle = calloc(1, sizeof(HPDriver));
387
388 if (!newDriverBundle)
389 return NULL;
390
391 newDriverBundle->m_vendorId = rhs->m_vendorId;
392 newDriverBundle->m_productId = rhs->m_productId;
393 newDriverBundle->m_friendlyName = strdup(rhs->m_friendlyName);
394 newDriverBundle->m_libPath = strdup(rhs->m_libPath);
395
396 return newDriverBundle;
397}
398
399/*
400 * Releases resources allocated to a driver bundle vector.
401 */
402static void HPDriverRelease(HPDriver * driverBundle)
403{
404 if (driverBundle)
405 {
406 free(driverBundle->m_friendlyName);
407 free(driverBundle->m_libPath);
408 }
409}
410
411/*
412 * Inserts a new reader device in the list.
413 */
414static HPDeviceList
415HPDeviceListInsert(HPDeviceList list, HPDriver * bundle, UInt32 address)
416{
417 HPDevice *newReader = calloc(1, sizeof(HPDevice));
418
419 if (!newReader)
420 {
421 Log1(PCSC_LOG_ERROR, "memory allocation failure");
422 return list;
423 }
424
425 newReader->m_driver = HPDriverCopy(bundle);
426 newReader->m_address = address;
427 newReader->m_next = list;
428
429 return newReader;
430}
431
432/*
433 * Frees resources allocated to a HPDeviceList.
434 */
435static void HPDeviceListRelease(HPDeviceList list)
436{
437 HPDevice *p;
438
439 for (p = list; p; p = p->m_next)
440 HPDriverRelease(p->m_driver);
441}
442
443/*
444 * Compares two driver bundle instances for equality.
445 */
446static int HPDeviceEquals(HPDevice * a, HPDevice * b)
447{
448 return (a->m_driver->m_vendorId == b->m_driver->m_vendorId)
449 && (a->m_driver->m_productId == b->m_driver->m_productId)
450 && (a->m_address == b->m_address);
451}
452
453/*
454 * Finds USB devices currently registered in the system that match any of
455 * the drivers detected in the driver bundle vector.
456 */
457static int
458HPDriversMatchUSBDevices(HPDriverVector driverBundle,
459 HPDeviceList * readerList)
460{
461 CFDictionaryRef usbMatch = IOServiceMatching("IOUSBDevice");
462
463 if (0 == usbMatch)
464 {
465 Log1(PCSC_LOG_ERROR,
466 "error getting USB match from IOServiceMatching()");
467 return 1;
468 }
469
470 io_iterator_t usbIter;
471 kern_return_t kret = IOServiceGetMatchingServices(kIOMasterPortDefault,
472 usbMatch, &usbIter);
473
474 if (kret != 0)
475 {
476 Log1(PCSC_LOG_ERROR,
477 "error getting iterator from IOServiceGetMatchingServices()");
478 return 1;
479 }
480
481 IOIteratorReset(usbIter);
482 io_object_t usbDevice = 0;
483
484 while ((usbDevice = IOIteratorNext(usbIter)))
485 {
486 char namebuf[1024];
487
488 kret = IORegistryEntryGetName(usbDevice, namebuf);
489 if (kret != 0)
490 {
491 Log1(PCSC_LOG_ERROR,
492 "error getting device name from IORegistryEntryGetName()");
493 return 1;
494 }
495
496 IOCFPlugInInterface **iodev;
497 SInt32 score;
498
499 kret = IOCreatePlugInInterfaceForService(usbDevice,
500 kIOUSBDeviceUserClientTypeID,
501 kIOCFPlugInInterfaceID, &iodev, &score);
502 if (kret != 0)
503 {
504 Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
505 return 1;
506 }
507 IOObjectRelease(usbDevice);
508
509 IOUSBDeviceInterface **usbdev;
510 HRESULT hres = (*iodev)->QueryInterface(iodev,
511 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
512 (LPVOID *) & usbdev);
513
514 (*iodev)->Release(iodev);
515 if (hres)
516 {
517 Log1(PCSC_LOG_ERROR,
518 "error querying interface in QueryInterface()");
519 return 1;
520 }
521
522 UInt16 vendorId = 0;
523 UInt16 productId = 0;
524 UInt32 usbAddress = 0;
525
526 kret = (*usbdev)->GetDeviceVendor(usbdev, &vendorId);
527 kret = (*usbdev)->GetDeviceProduct(usbdev, &productId);
528 kret = (*usbdev)->GetLocationID(usbdev, &usbAddress);
529 (*usbdev)->Release(usbdev);
530
531#ifdef DEBUG_HOTPLUG
532 Log4(PCSC_LOG_DEBUG, "Found USB device 0x%04X:0x%04X at 0x%X",
533 vendorId, productId, usbAddress);
534#endif
535 HPDriver *driver;
536 for (driver = driverBundle; driver->m_vendorId; ++driver)
537 {
538 if ((driver->m_vendorId == vendorId)
539 && (driver->m_productId == productId))
540 {
541#ifdef DEBUG_HOTPLUG
542 Log4(PCSC_LOG_DEBUG, "Adding USB device %04X:%04X at 0x%X",
543 vendorId, productId, usbAddress);
544#endif
545 *readerList =
546 HPDeviceListInsert(*readerList, driver, usbAddress);
547 }
548 }
549 }
550
551 IOObjectRelease(usbIter);
552 return 0;
553}
554
555/*
556 * Finds PC Card devices currently registered in the system that match any of
557 * the drivers detected in the driver bundle vector.
558 */
559static int
560HPDriversMatchPCCardDevices(HPDriver * driverBundle,
561 HPDeviceList * readerList)
562{
563 CFDictionaryRef pccMatch = IOServiceMatching("IOPCCard16Device");
564
565 if (pccMatch == NULL)
566 {
567 Log1(PCSC_LOG_ERROR,
568 "error getting PCCard match from IOServiceMatching()");
569 return 1;
570 }
571
572 io_iterator_t pccIter;
573 kern_return_t kret =
574 IOServiceGetMatchingServices(kIOMasterPortDefault, pccMatch,
575 &pccIter);
576 if (kret != 0)
577 {
578 Log1(PCSC_LOG_ERROR,
579 "error getting iterator from IOServiceGetMatchingServices()");
580 return 1;
581 }
582
583 IOIteratorReset(pccIter);
584 io_object_t pccDevice = 0;
585
586 while ((pccDevice = IOIteratorNext(pccIter)))
587 {
588 char namebuf[1024];
589
590 kret = IORegistryEntryGetName(pccDevice, namebuf);
591 if (kret != 0)
592 {
593 Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
594 return 1;
595 }
596 UInt32 vendorId = 0;
597 UInt32 productId = 0;
598 UInt32 pccAddress = 0;
599 CFTypeRef valueRef =
600 IORegistryEntryCreateCFProperty(pccDevice, CFSTR("VendorID"),
601 kCFAllocatorDefault, 0);
602
603 if (!valueRef)
604 {
605 Log1(PCSC_LOG_ERROR, "error getting vendor");
606 }
607 else
608 {
609 CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
610 &vendorId);
611 }
612 valueRef =
613 IORegistryEntryCreateCFProperty(pccDevice, CFSTR("DeviceID"),
614 kCFAllocatorDefault, 0);
615 if (!valueRef)
616 {
617 Log1(PCSC_LOG_ERROR, "error getting device");
618 }
619 else
620 {
621 CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
622 &productId);
623 }
624 valueRef =
625 IORegistryEntryCreateCFProperty(pccDevice, CFSTR("SocketNumber"),
626 kCFAllocatorDefault, 0);
627 if (!valueRef)
628 {
629 Log1(PCSC_LOG_ERROR, "error getting PC Card socket");
630 }
631 else
632 {
633 CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
634 &pccAddress);
635 }
636 HPDriver *driver = driverBundle;
637
638 for (; driver->m_vendorId; ++driver)
639 {
640 if ((driver->m_vendorId == vendorId)
641 && (driver->m_productId == productId))
642 {
643 *readerList =
644 HPDeviceListInsert(*readerList, driver, pccAddress);
645 }
646 }
647 }
648 IOObjectRelease(pccIter);
649 return 0;
650}
651
652
653static void HPEstablishUSBNotification(void)
654{
655 io_iterator_t deviceAddedIterator;
656 io_iterator_t deviceRemovedIterator;
657 CFMutableDictionaryRef matchingDictionary;
658 IONotificationPortRef notificationPort;
659 IOReturn kret;
660
661 notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
662 CFRunLoopAddSource(CFRunLoopGetCurrent(),
663 IONotificationPortGetRunLoopSource(notificationPort),
664 kCFRunLoopDefaultMode);
665
666 matchingDictionary = IOServiceMatching("IOUSBDevice");
667 if (!matchingDictionary)
668 {
669 Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
670 }
671 matchingDictionary =
672 (CFMutableDictionaryRef) CFRetain(matchingDictionary);
673
674 kret = IOServiceAddMatchingNotification(notificationPort,
675 kIOMatchedNotification,
676 matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
677 if (kret)
678 {
679 Log2(PCSC_LOG_ERROR,
680 "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
681 }
682 HPDeviceAppeared(NULL, deviceAddedIterator);
683
684 kret = IOServiceAddMatchingNotification(notificationPort,
685 kIOTerminatedNotification,
686 matchingDictionary,
687 HPDeviceDisappeared, NULL, &deviceRemovedIterator);
688 if (kret)
689 {
690 Log2(PCSC_LOG_ERROR,
691 "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
692 }
693 HPDeviceDisappeared(NULL, deviceRemovedIterator);
694}
695
696static void HPEstablishPCCardNotification(void)
697{
698 io_iterator_t deviceAddedIterator;
699 io_iterator_t deviceRemovedIterator;
700 CFMutableDictionaryRef matchingDictionary;
701 IONotificationPortRef notificationPort;
702 IOReturn kret;
703
704 notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
705 CFRunLoopAddSource(CFRunLoopGetCurrent(),
706 IONotificationPortGetRunLoopSource(notificationPort),
707 kCFRunLoopDefaultMode);
708
709 matchingDictionary = IOServiceMatching("IOPCCard16Device");
710 if (!matchingDictionary)
711 {
712 Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
713 }
714 matchingDictionary =
715 (CFMutableDictionaryRef) CFRetain(matchingDictionary);
716
717 kret = IOServiceAddMatchingNotification(notificationPort,
718 kIOMatchedNotification,
719 matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
720 if (kret)
721 {
722 Log2(PCSC_LOG_ERROR,
723 "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
724 }
725 HPDeviceAppeared(NULL, deviceAddedIterator);
726
727 kret = IOServiceAddMatchingNotification(notificationPort,
728 kIOTerminatedNotification,
729 matchingDictionary,
730 HPDeviceDisappeared, NULL, &deviceRemovedIterator);
731 if (kret)
732 {
733 Log2(PCSC_LOG_ERROR,
734 "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
735 }
736 HPDeviceDisappeared(NULL, deviceRemovedIterator);
737}
738
739/*
740 * Thread runner (does not return).
741 */
742static void HPDeviceNotificationThread(void)
743{
744 HPEstablishUSBNotification();
745 HPEstablishPCCardNotification();
746 CFRunLoopRun();
747}
748
749/*
750 * Scans the hotplug driver directory and looks in the system for
751 * matching devices.
752 * Adds or removes matching readers as necessary.
753 */
754LONG HPSearchHotPluggables(void)
755{
756 Drivers = HPDriversGetFromDirectory(PCSCLITE_HP_DROPDIR);
757
758 if (!Drivers)
759 return 1;
760
761 return 0;
762}
763
764static int HPScan(void)
765{
766 HPDeviceList devices = NULL;
767
768 if (HPDriversMatchUSBDevices(Drivers, &devices))
769 return -1;
770
771 if (HPDriversMatchPCCardDevices(Drivers, &devices))
772 return -1;
773
774 HPDevice *a;
775
776 for (a = devices; a; a = a->m_next)
777 {
778 int found = FALSE;
779 HPDevice *b;
780
781 for (b = sDeviceList; b; b = b->m_next)
782 {
783 if (HPDeviceEquals(a, b))
784 {
785 found = TRUE;
786 break;
787 }
788 }
789 if (!found)
790 {
791 char deviceName[MAX_DEVICENAME];
792
793 /* the format should be "usb:%04x/%04x" but Apple uses the
794 * friendly name instead */
795 snprintf(deviceName, sizeof(deviceName),
796 "%s", a->m_driver->m_friendlyName);
797 deviceName[sizeof(deviceName)-1] = '\0';
798
799 RFAddReader(a->m_driver->m_friendlyName,
800 PCSCLITE_HP_BASE_PORT + a->m_address, a->m_driver->m_libPath,
801 deviceName);
802 }
803 }
804
805 for (a = sDeviceList; a; a = a->m_next)
806 {
807 int found = FALSE;
808 HPDevice *b;
809
810 for (b = devices; b; b = b->m_next)
811 {
812 if (HPDeviceEquals(a, b))
813 {
814 found = TRUE;
815 break;
816 }
817 }
818 if (!found)
819 {
820 RFRemoveReader(a->m_driver->m_friendlyName,
821 PCSCLITE_HP_BASE_PORT + a->m_address);
822 }
823 }
824
825 HPDeviceListRelease(sDeviceList);
826 sDeviceList = devices;
827
828 return 0;
829}
830
831
832pthread_t sHotplugWatcherThread;
833
834/*
835 * Sets up callbacks for device hotplug events.
836 */
837ULONG HPRegisterForHotplugEvents(void)
838{
839 ThreadCreate(&sHotplugWatcherThread,
840 THREAD_ATTR_DEFAULT,
841 (PCSCLITE_THREAD_FUNCTION( )) HPDeviceNotificationThread, NULL);
842
843 return 0;
844}
845
846LONG HPStopHotPluggables(void)
847{
848 return 0;
849}
850
851void HPReCheckSerialReaders(void)
852{
853}
854
855#endif /* __APPLE__ */
856
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.