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