pcsc-lite  1.9.0
hotplug_macosx.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3  *
4  * Copyright (C) 2002-2004
5  * Stephen M. Webb <stephenw@cryptocard.com>
6  * Copyright (C) 2002-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  CFStringRef strValue = CFArrayGetValueAtIndex(vendorArray, j);
287 
288  driverBundle->m_vendorId = strtoul(CFStringGetCStringPtr(strValue,
289  CFStringGetSystemEncoding()), NULL, 16);
290 
291  strValue = CFArrayGetValueAtIndex(productArray, j);
292  driverBundle->m_productId = strtoul(CFStringGetCStringPtr(strValue,
293  CFStringGetSystemEncoding()), NULL, 16);
294 
295  strValue = CFArrayGetValueAtIndex(friendlyNameArray, j);
296  const char *cstr = CFStringGetCStringPtr(strValue,
297  CFStringGetSystemEncoding());
298  if (NULL == cstr)
299  {
300  char utf8_str[200];
301  if (CFStringGetCString(strValue, utf8_str, sizeof utf8_str,
302  kCFStringEncodingUTF8))
303  driverBundle->m_friendlyName = strdup(utf8_str);
304  else
305  continue;
306  }
307  else
308  driverBundle->m_friendlyName = strdup(cstr);
309 
310  if (!driverBundle->m_libPath)
311  driverBundle->m_libPath = strdup(libPath);
312 
313 #ifdef DEBUG_HOTPLUG
314  Log2(PCSC_LOG_DEBUG, "VendorID: 0x%04X",
315  driverBundle->m_vendorId);
316  Log2(PCSC_LOG_DEBUG, "ProductID: 0x%04X",
317  driverBundle->m_productId);
318  Log2(PCSC_LOG_DEBUG, "Friendly name: %s",
319  driverBundle->m_friendlyName);
320  Log2(PCSC_LOG_DEBUG, "Driver: %s", driverBundle->m_libPath);
321 #endif
322 
323  /* go to next bundle in the vector */
324  driverBundle++;
325  }
326  }
327  else
328  {
329  CFStringRef strValue = blobValue;
330 
331 #ifdef DEBUG_HOTPLUG
332  Log3(PCSC_LOG_DEBUG, "Driver without alias: %s %s",
333  driverBundle->m_friendlyName, driverBundle->m_libPath);
334 #endif
335 
336  driverBundle->m_vendorId = strtoul(CFStringGetCStringPtr(strValue,
337  CFStringGetSystemEncoding()), NULL, 16);
338 
339  strValue = (CFStringRef) CFDictionaryGetValue(dict,
340  CFSTR(PCSCLITE_HP_PRODKEY_NAME));
341  if (!strValue)
342  {
343  Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
344  return bundleVector;
345  }
346  driverBundle->m_productId = strtoul(CFStringGetCStringPtr(strValue,
347  CFStringGetSystemEncoding()), NULL, 16);
348 
349  strValue = (CFStringRef) CFDictionaryGetValue(dict,
350  CFSTR(PCSCLITE_HP_NAMEKEY_NAME));
351  if (!strValue)
352  {
353  Log1(PCSC_LOG_ERROR, "error getting product friendly name from bundle");
354  driverBundle->m_friendlyName = strdup("unnamed device");
355  }
356  else
357  {
358  const char *cstr = CFStringGetCStringPtr(strValue,
359  CFStringGetSystemEncoding());
360 
361  driverBundle->m_friendlyName = strdup(cstr);
362  }
363 #ifdef DEBUG_HOTPLUG
364  Log2(PCSC_LOG_DEBUG, "VendorID: 0x%04X", driverBundle->m_vendorId);
365  Log2(PCSC_LOG_DEBUG, "ProductID: 0x%04X", driverBundle->m_productId);
366  Log2(PCSC_LOG_DEBUG, "Friendly name: %s", driverBundle->m_friendlyName);
367  Log2(PCSC_LOG_DEBUG, "Driver: %s", driverBundle->m_libPath);
368 #endif
369 
370  /* go to next bundle in the vector */
371  driverBundle++;
372  }
373  }
374  CFRelease(bundleArray);
375  return bundleVector;
376 }
377 
378 /*
379  * Copies a driver bundle instance.
380  */
381 static HPDriver *HPDriverCopy(HPDriver * rhs)
382 {
383  if (!rhs)
384  return NULL;
385 
386  HPDriver *newDriverBundle = calloc(1, sizeof(HPDriver));
387 
388  if (!newDriverBundle)
389  return NULL;
390 
391  newDriverBundle->m_vendorId = rhs->m_vendorId;
392  newDriverBundle->m_productId = rhs->m_productId;
393  newDriverBundle->m_friendlyName = strdup(rhs->m_friendlyName);
394  newDriverBundle->m_libPath = strdup(rhs->m_libPath);
395 
396  return newDriverBundle;
397 }
398 
399 /*
400  * Releases resources allocated to a driver bundle vector.
401  */
402 static void HPDriverRelease(HPDriver * driverBundle)
403 {
404  if (driverBundle)
405  {
406  free(driverBundle->m_friendlyName);
407  free(driverBundle->m_libPath);
408  }
409 }
410 
411 /*
412  * Inserts a new reader device in the list.
413  */
414 static HPDeviceList
415 HPDeviceListInsert(HPDeviceList list, HPDriver * bundle, UInt32 address)
416 {
417  HPDevice *newReader = calloc(1, sizeof(HPDevice));
418 
419  if (!newReader)
420  {
421  Log1(PCSC_LOG_ERROR, "memory allocation failure");
422  return list;
423  }
424 
425  newReader->m_driver = HPDriverCopy(bundle);
426  newReader->m_address = address;
427  newReader->m_next = list;
428 
429  return newReader;
430 }
431 
432 /*
433  * Frees resources allocated to a HPDeviceList.
434  */
435 static void HPDeviceListRelease(HPDeviceList list)
436 {
437  HPDevice *p;
438 
439  for (p = list; p; p = p->m_next)
440  HPDriverRelease(p->m_driver);
441 }
442 
443 /*
444  * Compares two driver bundle instances for equality.
445  */
446 static int HPDeviceEquals(HPDevice * a, HPDevice * b)
447 {
448  return (a->m_driver->m_vendorId == b->m_driver->m_vendorId)
449  && (a->m_driver->m_productId == b->m_driver->m_productId)
450  && (a->m_address == b->m_address);
451 }
452 
453 /*
454  * Finds USB devices currently registered in the system that match any of
455  * the drivers detected in the driver bundle vector.
456  */
457 static int
458 HPDriversMatchUSBDevices(HPDriverVector driverBundle,
459  HPDeviceList * readerList)
460 {
461  CFDictionaryRef usbMatch = IOServiceMatching("IOUSBDevice");
462 
463  if (0 == usbMatch)
464  {
465  Log1(PCSC_LOG_ERROR,
466  "error getting USB match from IOServiceMatching()");
467  return 1;
468  }
469 
470  io_iterator_t usbIter;
471  kern_return_t kret = IOServiceGetMatchingServices(kIOMasterPortDefault,
472  usbMatch, &usbIter);
473 
474  if (kret != 0)
475  {
476  Log1(PCSC_LOG_ERROR,
477  "error getting iterator from IOServiceGetMatchingServices()");
478  return 1;
479  }
480 
481  IOIteratorReset(usbIter);
482  io_object_t usbDevice = 0;
483 
484  while ((usbDevice = IOIteratorNext(usbIter)))
485  {
486  char namebuf[1024];
487 
488  kret = IORegistryEntryGetName(usbDevice, namebuf);
489  if (kret != 0)
490  {
491  Log1(PCSC_LOG_ERROR,
492  "error getting device name from IORegistryEntryGetName()");
493  return 1;
494  }
495 
496  IOCFPlugInInterface **iodev;
497  SInt32 score;
498 
499  kret = IOCreatePlugInInterfaceForService(usbDevice,
500  kIOUSBDeviceUserClientTypeID,
501  kIOCFPlugInInterfaceID, &iodev, &score);
502  if (kret != 0)
503  {
504  Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
505  return 1;
506  }
507  IOObjectRelease(usbDevice);
508 
509  IOUSBDeviceInterface **usbdev;
510  HRESULT hres = (*iodev)->QueryInterface(iodev,
511  CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
512  (LPVOID *) & usbdev);
513 
514  (*iodev)->Release(iodev);
515  if (hres)
516  {
517  Log1(PCSC_LOG_ERROR,
518  "error querying interface in QueryInterface()");
519  return 1;
520  }
521 
522  UInt16 vendorId = 0;
523  UInt16 productId = 0;
524  UInt32 usbAddress = 0;
525 
526  kret = (*usbdev)->GetDeviceVendor(usbdev, &vendorId);
527  kret = (*usbdev)->GetDeviceProduct(usbdev, &productId);
528  kret = (*usbdev)->GetLocationID(usbdev, &usbAddress);
529  (*usbdev)->Release(usbdev);
530 
531 #ifdef DEBUG_HOTPLUG
532  Log4(PCSC_LOG_DEBUG, "Found USB device 0x%04X:0x%04X at 0x%X",
533  vendorId, productId, usbAddress);
534 #endif
535  HPDriver *driver;
536  for (driver = driverBundle; driver->m_vendorId; ++driver)
537  {
538  if ((driver->m_vendorId == vendorId)
539  && (driver->m_productId == productId))
540  {
541 #ifdef DEBUG_HOTPLUG
542  Log4(PCSC_LOG_DEBUG, "Adding USB device %04X:%04X at 0x%X",
543  vendorId, productId, usbAddress);
544 #endif
545  *readerList =
546  HPDeviceListInsert(*readerList, driver, usbAddress);
547  }
548  }
549  }
550 
551  IOObjectRelease(usbIter);
552  return 0;
553 }
554 
555 /*
556  * Finds PC Card devices currently registered in the system that match any of
557  * the drivers detected in the driver bundle vector.
558  */
559 static int
560 HPDriversMatchPCCardDevices(HPDriver * driverBundle,
561  HPDeviceList * readerList)
562 {
563  CFDictionaryRef pccMatch = IOServiceMatching("IOPCCard16Device");
564 
565  if (pccMatch == NULL)
566  {
567  Log1(PCSC_LOG_ERROR,
568  "error getting PCCard match from IOServiceMatching()");
569  return 1;
570  }
571 
572  io_iterator_t pccIter;
573  kern_return_t kret =
574  IOServiceGetMatchingServices(kIOMasterPortDefault, pccMatch,
575  &pccIter);
576  if (kret != 0)
577  {
578  Log1(PCSC_LOG_ERROR,
579  "error getting iterator from IOServiceGetMatchingServices()");
580  return 1;
581  }
582 
583  IOIteratorReset(pccIter);
584  io_object_t pccDevice = 0;
585 
586  while ((pccDevice = IOIteratorNext(pccIter)))
587  {
588  char namebuf[1024];
589 
590  kret = IORegistryEntryGetName(pccDevice, namebuf);
591  if (kret != 0)
592  {
593  Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
594  return 1;
595  }
596  UInt32 vendorId = 0;
597  UInt32 productId = 0;
598  UInt32 pccAddress = 0;
599  CFTypeRef valueRef =
600  IORegistryEntryCreateCFProperty(pccDevice, CFSTR("VendorID"),
601  kCFAllocatorDefault, 0);
602 
603  if (!valueRef)
604  {
605  Log1(PCSC_LOG_ERROR, "error getting vendor");
606  }
607  else
608  {
609  CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
610  &vendorId);
611  }
612  valueRef =
613  IORegistryEntryCreateCFProperty(pccDevice, CFSTR("DeviceID"),
614  kCFAllocatorDefault, 0);
615  if (!valueRef)
616  {
617  Log1(PCSC_LOG_ERROR, "error getting device");
618  }
619  else
620  {
621  CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
622  &productId);
623  }
624  valueRef =
625  IORegistryEntryCreateCFProperty(pccDevice, CFSTR("SocketNumber"),
626  kCFAllocatorDefault, 0);
627  if (!valueRef)
628  {
629  Log1(PCSC_LOG_ERROR, "error getting PC Card socket");
630  }
631  else
632  {
633  CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
634  &pccAddress);
635  }
636  HPDriver *driver = driverBundle;
637 
638  for (; driver->m_vendorId; ++driver)
639  {
640  if ((driver->m_vendorId == vendorId)
641  && (driver->m_productId == productId))
642  {
643  *readerList =
644  HPDeviceListInsert(*readerList, driver, pccAddress);
645  }
646  }
647  }
648  IOObjectRelease(pccIter);
649  return 0;
650 }
651 
652 
653 static void HPEstablishUSBNotification(void)
654 {
655  io_iterator_t deviceAddedIterator;
656  io_iterator_t deviceRemovedIterator;
657  CFMutableDictionaryRef matchingDictionary;
658  IONotificationPortRef notificationPort;
659  IOReturn kret;
660 
661  notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
662  CFRunLoopAddSource(CFRunLoopGetCurrent(),
663  IONotificationPortGetRunLoopSource(notificationPort),
664  kCFRunLoopDefaultMode);
665 
666  matchingDictionary = IOServiceMatching("IOUSBDevice");
667  if (!matchingDictionary)
668  {
669  Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
670  }
671  matchingDictionary =
672  (CFMutableDictionaryRef) CFRetain(matchingDictionary);
673 
674  kret = IOServiceAddMatchingNotification(notificationPort,
675  kIOMatchedNotification,
676  matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
677  if (kret)
678  {
679  Log2(PCSC_LOG_ERROR,
680  "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
681  }
682  HPDeviceAppeared(NULL, deviceAddedIterator);
683 
684  kret = IOServiceAddMatchingNotification(notificationPort,
685  kIOTerminatedNotification,
686  matchingDictionary,
687  HPDeviceDisappeared, NULL, &deviceRemovedIterator);
688  if (kret)
689  {
690  Log2(PCSC_LOG_ERROR,
691  "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
692  }
693  HPDeviceDisappeared(NULL, deviceRemovedIterator);
694 }
695 
696 static void HPEstablishPCCardNotification(void)
697 {
698  io_iterator_t deviceAddedIterator;
699  io_iterator_t deviceRemovedIterator;
700  CFMutableDictionaryRef matchingDictionary;
701  IONotificationPortRef notificationPort;
702  IOReturn kret;
703 
704  notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
705  CFRunLoopAddSource(CFRunLoopGetCurrent(),
706  IONotificationPortGetRunLoopSource(notificationPort),
707  kCFRunLoopDefaultMode);
708 
709  matchingDictionary = IOServiceMatching("IOPCCard16Device");
710  if (!matchingDictionary)
711  {
712  Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
713  }
714  matchingDictionary =
715  (CFMutableDictionaryRef) CFRetain(matchingDictionary);
716 
717  kret = IOServiceAddMatchingNotification(notificationPort,
718  kIOMatchedNotification,
719  matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
720  if (kret)
721  {
722  Log2(PCSC_LOG_ERROR,
723  "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
724  }
725  HPDeviceAppeared(NULL, deviceAddedIterator);
726 
727  kret = IOServiceAddMatchingNotification(notificationPort,
728  kIOTerminatedNotification,
729  matchingDictionary,
730  HPDeviceDisappeared, NULL, &deviceRemovedIterator);
731  if (kret)
732  {
733  Log2(PCSC_LOG_ERROR,
734  "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
735  }
736  HPDeviceDisappeared(NULL, deviceRemovedIterator);
737 }
738 
739 /*
740  * Thread runner (does not return).
741  */
742 static void HPDeviceNotificationThread(void)
743 {
744  HPEstablishUSBNotification();
745  HPEstablishPCCardNotification();
746  CFRunLoopRun();
747 }
748 
749 /*
750  * Scans the hotplug driver directory and looks in the system for
751  * matching devices.
752  * Adds or removes matching readers as necessary.
753  */
754 LONG HPSearchHotPluggables(void)
755 {
756  Drivers = HPDriversGetFromDirectory(PCSCLITE_HP_DROPDIR);
757 
758  if (!Drivers)
759  return 1;
760 
761  return 0;
762 }
763 
764 static int HPScan(void)
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 
828  return 0;
829 }
830 
831 
832 pthread_t sHotplugWatcherThread;
833 
834 /*
835  * Sets up callbacks for device hotplug events.
836  */
837 ULONG HPRegisterForHotplugEvents(void)
838 {
839  ThreadCreate(&sHotplugWatcherThread,
840  THREAD_ATTR_DEFAULT,
841  (PCSCLITE_THREAD_FUNCTION( )) HPDeviceNotificationThread, NULL);
842 
843  return 0;
844 }
845 
846 LONG HPStopHotPluggables(void)
847 {
848  return 0;
849 }
850 
851 void HPReCheckSerialReaders(void)
852 {
853 }
854 
855 #endif /* __APPLE__ */
856 
debuglog.h
This handles debugging.
readerfactory.h
This keeps track of a list of currently available reader structures.
winscard_msg.h
This defines some structures and #defines to be used over the transport layer.
pcscd.h
This keeps a list of defines for pcsc-lite.
parser.h
Reads lexical config files and updates database.
hotplug.h
This provides a search API for hot pluggble devices.