pcsc-lite  1.8.8
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 5868 2011-07-09 11:59:09Z 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",
299  driverBundle, 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  HPDriver *driver;
514  for (driver = driverBundle; driver->m_vendorId; ++driver)
515  {
516  if ((driver->m_vendorId == vendorId)
517  && (driver->m_productId == productId))
518  {
519  *readerList =
520  HPDeviceListInsert(*readerList, driver, usbAddress);
521  }
522  }
523  }
524 
525  IOObjectRelease(usbIter);
526  return 0;
527 }
528 
529 /*
530  * Finds PC Card devices currently registered in the system that match any of
531  * the drivers detected in the driver bundle vector.
532  */
533 static int
534 HPDriversMatchPCCardDevices(HPDriver * driverBundle,
535  HPDeviceList * readerList)
536 {
537  CFDictionaryRef pccMatch = IOServiceMatching("IOPCCard16Device");
538 
539  if (pccMatch == NULL)
540  {
541  Log1(PCSC_LOG_ERROR,
542  "error getting PCCard match from IOServiceMatching()");
543  return 1;
544  }
545 
546  io_iterator_t pccIter;
547  kern_return_t kret =
548  IOServiceGetMatchingServices(kIOMasterPortDefault, pccMatch,
549  &pccIter);
550  if (kret != 0)
551  {
552  Log1(PCSC_LOG_ERROR,
553  "error getting iterator from IOServiceGetMatchingServices()");
554  return 1;
555  }
556 
557  IOIteratorReset(pccIter);
558  io_object_t pccDevice = 0;
559 
560  while ((pccDevice = IOIteratorNext(pccIter)))
561  {
562  char namebuf[1024];
563 
564  kret = IORegistryEntryGetName(pccDevice, namebuf);
565  if (kret != 0)
566  {
567  Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
568  return 1;
569  }
570  UInt32 vendorId = 0;
571  UInt32 productId = 0;
572  UInt32 pccAddress = 0;
573  CFTypeRef valueRef =
574  IORegistryEntryCreateCFProperty(pccDevice, CFSTR("VendorID"),
575  kCFAllocatorDefault, 0);
576 
577  if (!valueRef)
578  {
579  Log1(PCSC_LOG_ERROR, "error getting vendor");
580  }
581  else
582  {
583  CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
584  &vendorId);
585  }
586  valueRef =
587  IORegistryEntryCreateCFProperty(pccDevice, CFSTR("DeviceID"),
588  kCFAllocatorDefault, 0);
589  if (!valueRef)
590  {
591  Log1(PCSC_LOG_ERROR, "error getting device");
592  }
593  else
594  {
595  CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
596  &productId);
597  }
598  valueRef =
599  IORegistryEntryCreateCFProperty(pccDevice, CFSTR("SocketNumber"),
600  kCFAllocatorDefault, 0);
601  if (!valueRef)
602  {
603  Log1(PCSC_LOG_ERROR, "error getting PC Card socket");
604  }
605  else
606  {
607  CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
608  &pccAddress);
609  }
610  HPDriver *driver = driverBundle;
611 
612  for (; driver->m_vendorId; ++driver)
613  {
614  if ((driver->m_vendorId == vendorId)
615  && (driver->m_productId == productId))
616  {
617  *readerList =
618  HPDeviceListInsert(*readerList, driver, pccAddress);
619  }
620  }
621  }
622  IOObjectRelease(pccIter);
623  return 0;
624 }
625 
626 
627 static void HPEstablishUSBNotification(void)
628 {
629  io_iterator_t deviceAddedIterator;
630  io_iterator_t deviceRemovedIterator;
631  CFMutableDictionaryRef matchingDictionary;
632  IONotificationPortRef notificationPort;
633  IOReturn kret;
634 
635  notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
636  CFRunLoopAddSource(CFRunLoopGetCurrent(),
637  IONotificationPortGetRunLoopSource(notificationPort),
638  kCFRunLoopDefaultMode);
639 
640  matchingDictionary = IOServiceMatching("IOUSBDevice");
641  if (!matchingDictionary)
642  {
643  Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
644  }
645  matchingDictionary =
646  (CFMutableDictionaryRef) CFRetain(matchingDictionary);
647 
648  kret = IOServiceAddMatchingNotification(notificationPort,
649  kIOMatchedNotification,
650  matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
651  if (kret)
652  {
653  Log2(PCSC_LOG_ERROR,
654  "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
655  }
656  HPDeviceAppeared(NULL, deviceAddedIterator);
657 
658  kret = IOServiceAddMatchingNotification(notificationPort,
659  kIOTerminatedNotification,
660  matchingDictionary,
661  HPDeviceDisappeared, NULL, &deviceRemovedIterator);
662  if (kret)
663  {
664  Log2(PCSC_LOG_ERROR,
665  "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
666  }
667  HPDeviceDisappeared(NULL, deviceRemovedIterator);
668 }
669 
670 static void HPEstablishPCCardNotification(void)
671 {
672  io_iterator_t deviceAddedIterator;
673  io_iterator_t deviceRemovedIterator;
674  CFMutableDictionaryRef matchingDictionary;
675  IONotificationPortRef notificationPort;
676  IOReturn kret;
677 
678  notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
679  CFRunLoopAddSource(CFRunLoopGetCurrent(),
680  IONotificationPortGetRunLoopSource(notificationPort),
681  kCFRunLoopDefaultMode);
682 
683  matchingDictionary = IOServiceMatching("IOPCCard16Device");
684  if (!matchingDictionary)
685  {
686  Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
687  }
688  matchingDictionary =
689  (CFMutableDictionaryRef) CFRetain(matchingDictionary);
690 
691  kret = IOServiceAddMatchingNotification(notificationPort,
692  kIOMatchedNotification,
693  matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
694  if (kret)
695  {
696  Log2(PCSC_LOG_ERROR,
697  "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
698  }
699  HPDeviceAppeared(NULL, deviceAddedIterator);
700 
701  kret = IOServiceAddMatchingNotification(notificationPort,
702  kIOTerminatedNotification,
703  matchingDictionary,
704  HPDeviceDisappeared, NULL, &deviceRemovedIterator);
705  if (kret)
706  {
707  Log2(PCSC_LOG_ERROR,
708  "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
709  }
710  HPDeviceDisappeared(NULL, deviceRemovedIterator);
711 }
712 
713 /*
714  * Thread runner (does not return).
715  */
716 static void HPDeviceNotificationThread(void)
717 {
718  HPEstablishUSBNotification();
719  HPEstablishPCCardNotification();
720  CFRunLoopRun();
721 }
722 
723 /*
724  * Scans the hotplug driver directory and looks in the system for
725  * matching devices.
726  * Adds or removes matching readers as necessary.
727  */
728 LONG HPSearchHotPluggables(void)
729 {
730  HPDriver *drivers = HPDriversGetFromDirectory(PCSCLITE_HP_DROPDIR);
731 
732  if (!drivers)
733  return 1;
734 
735  HPDeviceList devices = NULL;
736 
737  if (HPDriversMatchUSBDevices(drivers, &devices))
738  return -1;
739 
740  if (HPDriversMatchPCCardDevices(drivers, &devices))
741  return -1;
742 
743  HPDevice *a;
744 
745  for (a = devices; a; a = a->m_next)
746  {
747  int found = FALSE;
748  HPDevice *b;
749 
750  for (b = sDeviceList; b; b = b->m_next)
751  {
752  if (HPDeviceEquals(a, b))
753  {
754  found = TRUE;
755  break;
756  }
757  }
758  if (!found)
759  {
760  char deviceName[MAX_DEVICENAME];
761 
762  /* the format should be "usb:%04x/%04x" but Apple uses the
763  * friendly name instead */
764  snprintf(deviceName, sizeof(deviceName),
765  "%s", a->m_driver->m_friendlyName);
766  deviceName[sizeof(deviceName)-1] = '\0';
767 
768  RFAddReader(a->m_driver->m_friendlyName,
769  PCSCLITE_HP_BASE_PORT + a->m_address, a->m_driver->m_libPath,
770  deviceName);
771  }
772  }
773 
774  for (a = sDeviceList; a; a = a->m_next)
775  {
776  int found = FALSE;
777  HPDevice *b;
778 
779  for (b = devices; b; b = b->m_next)
780  {
781  if (HPDeviceEquals(a, b))
782  {
783  found = TRUE;
784  break;
785  }
786  }
787  if (!found)
788  {
789  RFRemoveReader(a->m_driver->m_friendlyName,
790  PCSCLITE_HP_BASE_PORT + a->m_address);
791  }
792  }
793 
794  HPDeviceListRelease(sDeviceList);
795  sDeviceList = devices;
796  HPDriverVectorRelease(drivers);
797 
798  return 0;
799 }
800 
801 
802 pthread_t sHotplugWatcherThread;
803 
804 /*
805  * Sets up callbacks for device hotplug events.
806  */
807 ULONG HPRegisterForHotplugEvents(void)
808 {
809  ThreadCreate(&sHotplugWatcherThread,
810  THREAD_ATTR_DEFAULT,
811  (PCSCLITE_THREAD_FUNCTION( )) HPDeviceNotificationThread, NULL);
812 
813  return 0;
814 }
815 
816 LONG HPStopHotPluggables(void)
817 {
818  return 0;
819 }
820 
821 void HPReCheckSerialReaders(void)
822 {
823 }
824 
825 #endif /* __APPLE__ */
826 
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.