pcsc-lite  2.5.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  *
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
15 are met:
16 
17 1. Redistributions of source code must retain the above copyright
18  notice, this list of conditions and the following disclaimer.
19 2. 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.
22 3. 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 
25 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 THIS 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  */
67 typedef 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  */
78 typedef 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  */
89 static HPDeviceList sDeviceList = NULL;
90 
91 static int HPScan(void);
92 static HPDriver *Drivers = NULL;
93 
94 /*
95  * A callback to handle the asynchronous appearance of new devices that are
96  * candidates for PCSC readers.
97  */
98 static 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  */
114 static 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  */
135 static 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  */
339 static 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  */
360 static 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  */
372 static HPDeviceList
373 HPDeviceListInsert(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  */
393 static 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  */
404 static 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  */
415 static int
416 HPDriversMatchUSBDevices(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  */
517 static int
518 HPDriversMatchPCCardDevices(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 
614 static 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 
658 static 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  */
705 static 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  */
717 LONG HPSearchHotPluggables(const char * hpDirPath)
718 {
719  Drivers = HPDriversGetFromDirectory(hpDirPath);
720 
721  if (!Drivers)
722  return 1;
723 
724  return 0;
725 }
726 
727 static 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 
805 pthread_t sHotplugWatcherThread;
806 
807 /*
808  * Sets up callbacks for device hotplug events.
809  */
810 ULONG 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 
821 LONG HPStopHotPluggables(void)
822 {
823  return 0;
824 }
825 
826 void HPReCheckSerialReaders(void)
827 {
828 }
829 
830 #endif /* __APPLE__ */
831 
Reads lexical config files and updates database.
This defines some structures and #defines to be used over the transport layer.
This keeps track of a list of currently available reader structures.
This provides a search API for hot pluggble devices.
This handles debugging.