pcsc-lite  2.2.3
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-2023
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  CFRelease(pluginUrl);
164  if (!bundleArray)
165  {
166  Log1(PCSC_LOG_ERROR, "error getting plugin directory bundles");
167  return NULL;
168  }
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  CFRelease(bundleArray);
187  return NULL;
188  }
189 
190  if (CFGetTypeID(blobValue) == CFArrayGetTypeID())
191  {
192  /* alias found, each reader count as 1 */
193  CFArrayRef propertyArray = blobValue;
194  readersNumber += CFArrayGetCount(propertyArray);
195  }
196  else
197  /* No alias, only one reader supported */
198  readersNumber++;
199  }
200 #ifdef DEBUG_HOTPLUG
201  Log2(PCSC_LOG_DEBUG, "Total of %d readers supported", readersNumber);
202 #endif
203 
204  /* The last entry is an end marker (m_vendorId = 0)
205  * see checks in HPDriversMatchUSBDevices:503
206  * and HPDriverVectorRelease:376 */
207  readersNumber++;
208 
209  bundleVector = calloc(readersNumber, sizeof(HPDriver));
210  if (!bundleVector)
211  {
212  Log1(PCSC_LOG_ERROR, "memory allocation failure");
213  CFRelease(bundleArray);
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  CFRelease(bundleUrl);
227 
228  driverBundle->m_libPath = strdup(CFStringGetCStringPtr(bundlePath,
229  CFStringGetSystemEncoding()));
230  CFRelease(bundlePath);
231 
232  const void * blobValue = CFDictionaryGetValue(dict,
233  CFSTR(PCSCLITE_HP_MANUKEY_NAME));
234 
235  if (!blobValue)
236  {
237  Log1(PCSC_LOG_ERROR, "error getting vendor ID from bundle");
238  CFRelease(bundleArray);
239  return bundleVector;
240  }
241 
242  if (CFGetTypeID(blobValue) == CFArrayGetTypeID())
243  {
244  CFArrayRef vendorArray = blobValue;
245  CFArrayRef productArray;
246  CFArrayRef friendlyNameArray;
247  char *libPath = driverBundle->m_libPath;
248 
249 #ifdef DEBUG_HOTPLUG
250  Log2(PCSC_LOG_DEBUG, "Driver with aliases: %s", libPath);
251 #endif
252  /* get list of ProductID */
253  productArray = CFDictionaryGetValue(dict,
254  CFSTR(PCSCLITE_HP_PRODKEY_NAME));
255  if (!productArray)
256  {
257  Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
258  CFRelease(bundleArray);
259  return bundleVector;
260  }
261 
262  /* get list of FriendlyName */
263  friendlyNameArray = CFDictionaryGetValue(dict,
264  CFSTR(PCSCLITE_HP_NAMEKEY_NAME));
265  if (!friendlyNameArray)
266  {
267  Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
268  CFRelease(bundleArray);
269  return bundleVector;
270  }
271 
272  long reader_nb = CFArrayGetCount(vendorArray);
273 
274  if (reader_nb != CFArrayGetCount(productArray))
275  {
276  Log3(PCSC_LOG_ERROR,
277  "Malformed Info.plist: %ld vendors and %ld products",
278  reader_nb, CFArrayGetCount(productArray));
279  CFRelease(bundleArray);
280  return bundleVector;
281  }
282 
283  if (reader_nb != CFArrayGetCount(friendlyNameArray))
284  {
285  Log3(PCSC_LOG_ERROR,
286  "Malformed Info.plist: %ld vendors and %ld friendlynames",
287  reader_nb, CFArrayGetCount(friendlyNameArray));
288  CFRelease(bundleArray);
289  return bundleVector;
290  }
291 
292  int j;
293  for (j=0; j<reader_nb; j++)
294  {
295  char stringBuffer[1000];
296  CFStringRef strValue = CFArrayGetValueAtIndex(vendorArray, j);
297 
298  CFStringGetCString(strValue, stringBuffer, sizeof stringBuffer,
299  kCFStringEncodingUTF8);
300  driverBundle->m_vendorId = (unsigned int)strtoul(stringBuffer, NULL, 16);
301 
302  strValue = CFArrayGetValueAtIndex(productArray, j);
303  CFStringGetCString(strValue, stringBuffer, sizeof stringBuffer,
304  kCFStringEncodingUTF8);
305  driverBundle->m_productId = (unsigned int)strtoul(stringBuffer, NULL, 16);
306 
307  strValue = CFArrayGetValueAtIndex(friendlyNameArray, j);
308  CFStringGetCString(strValue, stringBuffer, sizeof stringBuffer,
309  kCFStringEncodingUTF8);
310  driverBundle->m_friendlyName = strdup(stringBuffer);
311 
312  if (!driverBundle->m_libPath)
313  driverBundle->m_libPath = strdup(libPath);
314 
315 #ifdef DEBUG_HOTPLUG
316  Log2(PCSC_LOG_DEBUG, "VendorID: 0x%04X",
317  driverBundle->m_vendorId);
318  Log2(PCSC_LOG_DEBUG, "ProductID: 0x%04X",
319  driverBundle->m_productId);
320  Log2(PCSC_LOG_DEBUG, "Friendly name: %s",
321  driverBundle->m_friendlyName);
322  Log2(PCSC_LOG_DEBUG, "Driver: %s", driverBundle->m_libPath);
323 #endif
324 
325  /* go to next bundle in the vector */
326  driverBundle++;
327  }
328  }
329  else
330  {
331  Log1(PCSC_LOG_ERROR, "Non array not supported");
332  }
333  }
334  CFRelease(bundleArray);
335  return bundleVector;
336 }
337 
338 /*
339  * Copies a driver bundle instance.
340  */
341 static HPDriver *HPDriverCopy(HPDriver * rhs)
342 {
343  if (!rhs)
344  return NULL;
345 
346  HPDriver *newDriverBundle = calloc(1, sizeof(HPDriver));
347 
348  if (!newDriverBundle)
349  return NULL;
350 
351  newDriverBundle->m_vendorId = rhs->m_vendorId;
352  newDriverBundle->m_productId = rhs->m_productId;
353  newDriverBundle->m_friendlyName = strdup(rhs->m_friendlyName);
354  newDriverBundle->m_libPath = strdup(rhs->m_libPath);
355 
356  return newDriverBundle;
357 }
358 
359 /*
360  * Releases resources allocated to a driver bundle vector.
361  */
362 static void HPDriverRelease(HPDriver * driverBundle)
363 {
364  if (driverBundle)
365  {
366  free(driverBundle->m_friendlyName);
367  free(driverBundle->m_libPath);
368  }
369 }
370 
371 /*
372  * Inserts a new reader device in the list.
373  */
374 static HPDeviceList
375 HPDeviceListInsert(HPDeviceList list, HPDriver * bundle, UInt32 address)
376 {
377  HPDevice *newReader = calloc(1, sizeof(HPDevice));
378 
379  if (!newReader)
380  {
381  Log1(PCSC_LOG_ERROR, "memory allocation failure");
382  return list;
383  }
384 
385  newReader->m_driver = HPDriverCopy(bundle);
386  newReader->m_address = address;
387  newReader->m_next = list;
388 
389  return newReader;
390 }
391 
392 /*
393  * Frees resources allocated to a HPDeviceList.
394  */
395 static void HPDeviceListRelease(HPDeviceList list)
396 {
397  HPDevice *p;
398 
399  for (p = list; p; p = p->m_next)
400  HPDriverRelease(p->m_driver);
401 }
402 
403 /*
404  * Compares two driver bundle instances for equality.
405  */
406 static int HPDeviceEquals(HPDevice * a, HPDevice * b)
407 {
408  return (a->m_driver->m_vendorId == b->m_driver->m_vendorId)
409  && (a->m_driver->m_productId == b->m_driver->m_productId)
410  && (a->m_address == b->m_address);
411 }
412 
413 /*
414  * Finds USB devices currently registered in the system that match any of
415  * the drivers detected in the driver bundle vector.
416  */
417 static int
418 HPDriversMatchUSBDevices(HPDriverVector driverBundle,
419  HPDeviceList * readerList)
420 {
421  CFDictionaryRef usbMatch = IOServiceMatching("IOUSBDevice");
422 
423  if (0 == usbMatch)
424  {
425  Log1(PCSC_LOG_ERROR,
426  "error getting USB match from IOServiceMatching()");
427  return 1;
428  }
429 
430  io_iterator_t usbIter;
431  kern_return_t kret = IOServiceGetMatchingServices(kIOMainPortDefault,
432  usbMatch, &usbIter);
433 
434  if (kret != 0)
435  {
436  Log1(PCSC_LOG_ERROR,
437  "error getting iterator from IOServiceGetMatchingServices()");
438  return 1;
439  }
440 
441  IOIteratorReset(usbIter);
442  io_object_t usbDevice = 0;
443 
444  while ((usbDevice = IOIteratorNext(usbIter)))
445  {
446  char namebuf[1024];
447 
448  kret = IORegistryEntryGetName(usbDevice, namebuf);
449  if (kret != 0)
450  {
451  Log1(PCSC_LOG_ERROR,
452  "error getting device name from IORegistryEntryGetName()");
453  return 1;
454  }
455 
456  IOCFPlugInInterface **iodev;
457  SInt32 score;
458 
459  kret = IOCreatePlugInInterfaceForService(usbDevice,
460  kIOUSBDeviceUserClientTypeID,
461  kIOCFPlugInInterfaceID, &iodev, &score);
462  if (kret != 0)
463  {
464  Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
465  return 1;
466  }
467  IOObjectRelease(usbDevice);
468 
469  IOUSBDeviceInterface **usbdev;
470  HRESULT hres = (*iodev)->QueryInterface(iodev,
471  CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
472  (LPVOID *) & usbdev);
473 
474  (*iodev)->Release(iodev);
475  if (hres)
476  {
477  Log1(PCSC_LOG_ERROR,
478  "error querying interface in QueryInterface()");
479  return 1;
480  }
481 
482  UInt16 vendorId = 0;
483  UInt16 productId = 0;
484  UInt32 usbAddress = 0;
485 
486  kret = (*usbdev)->GetDeviceVendor(usbdev, &vendorId);
487  kret = (*usbdev)->GetDeviceProduct(usbdev, &productId);
488  kret = (*usbdev)->GetLocationID(usbdev, &usbAddress);
489  (*usbdev)->Release(usbdev);
490 
491 #ifdef DEBUG_HOTPLUG
492  Log4(PCSC_LOG_DEBUG, "Found USB device 0x%04X:0x%04X at 0x%X",
493  vendorId, productId, usbAddress);
494 #endif
495  HPDriver *driver;
496  for (driver = driverBundle; driver->m_vendorId; ++driver)
497  {
498  if ((driver->m_vendorId == vendorId)
499  && (driver->m_productId == productId))
500  {
501 #ifdef DEBUG_HOTPLUG
502  Log4(PCSC_LOG_DEBUG, "Adding USB device %04X:%04X at 0x%X",
503  vendorId, productId, usbAddress);
504 #endif
505  *readerList =
506  HPDeviceListInsert(*readerList, driver, usbAddress);
507  }
508  }
509  }
510 
511  IOObjectRelease(usbIter);
512  return 0;
513 }
514 
515 /*
516  * Finds PC Card devices currently registered in the system that match any of
517  * the drivers detected in the driver bundle vector.
518  */
519 static int
520 HPDriversMatchPCCardDevices(HPDriver * driverBundle,
521  HPDeviceList * readerList)
522 {
523  CFDictionaryRef pccMatch = IOServiceMatching("IOPCCard16Device");
524 
525  if (pccMatch == NULL)
526  {
527  Log1(PCSC_LOG_ERROR,
528  "error getting PCCard match from IOServiceMatching()");
529  return 1;
530  }
531 
532  io_iterator_t pccIter;
533  kern_return_t kret =
534  IOServiceGetMatchingServices(kIOMainPortDefault, pccMatch,
535  &pccIter);
536  if (kret != 0)
537  {
538  Log1(PCSC_LOG_ERROR,
539  "error getting iterator from IOServiceGetMatchingServices()");
540  return 1;
541  }
542 
543  IOIteratorReset(pccIter);
544  io_object_t pccDevice = 0;
545 
546  while ((pccDevice = IOIteratorNext(pccIter)))
547  {
548  char namebuf[1024];
549 
550  kret = IORegistryEntryGetName(pccDevice, namebuf);
551  if (kret != 0)
552  {
553  Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
554  return 1;
555  }
556  UInt32 vendorId = 0;
557  UInt32 productId = 0;
558  UInt32 pccAddress = 0;
559  CFTypeRef valueRef =
560  IORegistryEntryCreateCFProperty(pccDevice, CFSTR("VendorID"),
561  kCFAllocatorDefault, 0);
562 
563  if (!valueRef)
564  {
565  Log1(PCSC_LOG_ERROR, "error getting vendor");
566  }
567  else
568  {
569  CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
570  &vendorId);
571  CFRelease(valueRef);
572  }
573  valueRef =
574  IORegistryEntryCreateCFProperty(pccDevice, CFSTR("DeviceID"),
575  kCFAllocatorDefault, 0);
576  if (!valueRef)
577  {
578  Log1(PCSC_LOG_ERROR, "error getting device");
579  }
580  else
581  {
582  CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
583  &productId);
584  CFRelease(valueRef);
585  }
586  valueRef =
587  IORegistryEntryCreateCFProperty(pccDevice, CFSTR("SocketNumber"),
588  kCFAllocatorDefault, 0);
589  if (!valueRef)
590  {
591  Log1(PCSC_LOG_ERROR, "error getting PC Card socket");
592  }
593  else
594  {
595  CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
596  &pccAddress);
597  CFRelease(valueRef);
598  }
599  HPDriver *driver = driverBundle;
600 
601  for (; driver->m_vendorId; ++driver)
602  {
603  if ((driver->m_vendorId == vendorId)
604  && (driver->m_productId == productId))
605  {
606  *readerList =
607  HPDeviceListInsert(*readerList, driver, pccAddress);
608  }
609  }
610  }
611  IOObjectRelease(pccIter);
612  return 0;
613 }
614 
615 
616 static void HPEstablishUSBNotification(void)
617 {
618  io_iterator_t deviceAddedIterator;
619  io_iterator_t deviceRemovedIterator;
620  CFMutableDictionaryRef matchingDictionary;
621  IONotificationPortRef notificationPort;
622  IOReturn kret;
623 
624  notificationPort = IONotificationPortCreate(kIOMainPortDefault);
625  CFRunLoopAddSource(CFRunLoopGetCurrent(),
626  IONotificationPortGetRunLoopSource(notificationPort),
627  kCFRunLoopDefaultMode);
628 
629  matchingDictionary = IOServiceMatching("IOUSBDevice");
630  if (!matchingDictionary)
631  {
632  Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
633  return;
634  }
635  matchingDictionary =
636  (CFMutableDictionaryRef) CFRetain(matchingDictionary);
637 
638  kret = IOServiceAddMatchingNotification(notificationPort,
639  kIOMatchedNotification,
640  matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
641  if (kret)
642  {
643  Log2(PCSC_LOG_ERROR,
644  "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
645  }
646  HPDeviceAppeared(NULL, deviceAddedIterator);
647 
648  kret = IOServiceAddMatchingNotification(notificationPort,
649  kIOTerminatedNotification,
650  matchingDictionary,
651  HPDeviceDisappeared, NULL, &deviceRemovedIterator);
652  if (kret)
653  {
654  Log2(PCSC_LOG_ERROR,
655  "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
656  }
657  HPDeviceDisappeared(NULL, deviceRemovedIterator);
658 }
659 
660 static void HPEstablishPCCardNotification(void)
661 {
662  io_iterator_t deviceAddedIterator;
663  io_iterator_t deviceRemovedIterator;
664  CFMutableDictionaryRef matchingDictionary;
665  IONotificationPortRef notificationPort;
666  IOReturn kret;
667 
668  notificationPort = IONotificationPortCreate(kIOMainPortDefault);
669  CFRunLoopAddSource(CFRunLoopGetCurrent(),
670  IONotificationPortGetRunLoopSource(notificationPort),
671  kCFRunLoopDefaultMode);
672 
673  matchingDictionary = IOServiceMatching("IOPCCard16Device");
674  if (!matchingDictionary)
675  {
676  Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
677  return;
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 /*
705  * Thread runner (does not return).
706  */
707 static void HPDeviceNotificationThread(void)
708 {
709  HPEstablishUSBNotification();
710  HPEstablishPCCardNotification();
711  CFRunLoopRun();
712 }
713 
714 /*
715  * Scans the hotplug driver directory and looks in the system for
716  * matching devices.
717  * Adds or removes matching readers as necessary.
718  */
719 LONG HPSearchHotPluggables(const char * hpDirPath)
720 {
721  Drivers = HPDriversGetFromDirectory(hpDirPath);
722 
723  if (!Drivers)
724  return 1;
725 
726  return 0;
727 }
728 
729 static int HPScan(void)
730 {
731  HPDeviceList devices = NULL;
732 
733  if (HPDriversMatchUSBDevices(Drivers, &devices))
734  {
735  if (devices)
736  free(devices);
737 
738  return -1;
739  }
740 
741  if (HPDriversMatchPCCardDevices(Drivers, &devices))
742  {
743  if (devices)
744  free(devices);
745 
746  return -1;
747  }
748 
749  HPDevice *a;
750 
751  for (a = devices; a; a = a->m_next)
752  {
753  bool found = false;
754  HPDevice *b;
755 
756  for (b = sDeviceList; b; b = b->m_next)
757  {
758  if (HPDeviceEquals(a, b))
759  {
760  found = true;
761  break;
762  }
763  }
764  if (!found)
765  {
766  char *deviceName;
767 
768  /* the format should be "usb:%04x/%04x" but Apple uses the
769  * friendly name instead */
770  asprintf(&deviceName, "%s", a->m_driver->m_friendlyName);
771 
772  RFAddReader(a->m_driver->m_friendlyName,
773  PCSCLITE_HP_BASE_PORT + a->m_address, a->m_driver->m_libPath,
774  deviceName);
775  free(deviceName);
776  }
777  }
778 
779  for (a = sDeviceList; a; a = a->m_next)
780  {
781  bool found = false;
782  HPDevice *b;
783 
784  for (b = devices; b; b = b->m_next)
785  {
786  if (HPDeviceEquals(a, b))
787  {
788  found = true;
789  break;
790  }
791  }
792  if (!found)
793  {
794  RFRemoveReader(a->m_driver->m_friendlyName,
795  PCSCLITE_HP_BASE_PORT + a->m_address,
796  REMOVE_READER_FLAG_REMOVED);
797  }
798  }
799 
800  HPDeviceListRelease(sDeviceList);
801  sDeviceList = devices;
802 
803  return 0;
804 }
805 
806 
807 pthread_t sHotplugWatcherThread;
808 
809 /*
810  * Sets up callbacks for device hotplug events.
811  */
812 ULONG HPRegisterForHotplugEvents(const char * hpDirPath)
813 {
814  (void)hpDirPath;
815 
816  ThreadCreate(&sHotplugWatcherThread,
817  THREAD_ATTR_DEFAULT,
818  (PCSCLITE_THREAD_FUNCTION( )) HPDeviceNotificationThread, NULL);
819 
820  return 0;
821 }
822 
823 LONG HPStopHotPluggables(void)
824 {
825  return 0;
826 }
827 
828 void HPReCheckSerialReaders(void)
829 {
830 }
831 
832 #endif /* __APPLE__ */
833 
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.
parser.h
Reads lexical config files and updates database.
hotplug.h
This provides a search API for hot pluggble devices.