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