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