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