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