pcsc-lite  1.8.3
hotplug_macosx.c
Go to the documentation of this file.
00001 /*
00002  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
00003  *
00004  * Copyright (C) 2002-2004
00005  *  Stephen M. Webb <stephenw@cryptocard.com>
00006  * Copyright (C) 2002-2011
00007  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00008  * Copyright (C) 2002
00009  *  David Corcoran <corcoran@linuxnet.com>
00010  * Copyright (C) 2003
00011  *  Antti Tapaninen
00012  *
00013  * $Id: hotplug_macosx.c 5868 2011-07-09 11:59:09Z rousseau $
00014  */
00015 
00021 #include "config.h"
00022 #include "misc.h"
00023 #include "pcscd.h"
00024 
00025 #if defined(__APPLE__) && !defined(HAVE_LIBUSB)
00026 #include <CoreFoundation/CoreFoundation.h>
00027 #include <IOKit/IOCFPlugIn.h>
00028 #include <IOKit/IOKitLib.h>
00029 #include <IOKit/usb/IOUSBLib.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 
00033 #include "debuglog.h"
00034 #include "parser.h"
00035 #include "readerfactory.h"
00036 #include "winscard_msg.h"
00037 #include "utils.h"
00038 #include "hotplug.h"
00039 
00040 #undef DEBUG_HOTPLUG
00041 
00042 /*
00043  * An aggregation of useful information on a driver bundle in the
00044  * drop directory.
00045  */
00046 typedef struct HPDriver
00047 {
00048     UInt32 m_vendorId;          /* unique vendor's manufacturer code */
00049     UInt32 m_productId;         /* manufacturer's unique product code */
00050     char *m_friendlyName;       /* bundle friendly name */
00051     char *m_libPath;            /* bundle's plugin library location */
00052 } HPDriver, *HPDriverVector;
00053 
00054 /*
00055  * An aggregation on information on currently active reader drivers.
00056  */
00057 typedef struct HPDevice
00058 {
00059     HPDriver *m_driver;         /* driver bundle information */
00060     UInt32 m_address;           /* unique system address of device */
00061     struct HPDevice *m_next;    /* next device in list */
00062 } HPDevice, *HPDeviceList;
00063 
00064 /*
00065  * Pointer to a list of (currently) known hotplug reader devices (and their
00066  * drivers).
00067  */
00068 static HPDeviceList sDeviceList = NULL;
00069 
00070 /*
00071  * A callback to handle the asynchronous appearance of new devices that are
00072  * candidates for PCSC readers.
00073  */
00074 static void HPDeviceAppeared(void *refCon, io_iterator_t iterator)
00075 {
00076     kern_return_t kret;
00077     io_service_t obj;
00078 
00079     (void)refCon;
00080 
00081     while ((obj = IOIteratorNext(iterator)))
00082         kret = IOObjectRelease(obj);
00083 
00084     HPSearchHotPluggables();
00085 }
00086 
00087 /*
00088  * A callback to handle the asynchronous disappearance of devices that are
00089  * possibly PCSC readers.
00090  */
00091 static void HPDeviceDisappeared(void *refCon, io_iterator_t iterator)
00092 {
00093     kern_return_t kret;
00094     io_service_t obj;
00095 
00096     (void)refCon;
00097 
00098     while ((obj = IOIteratorNext(iterator)))
00099         kret = IOObjectRelease(obj);
00100 
00101     HPSearchHotPluggables();
00102 }
00103 
00104 
00105 /*
00106  * Creates a vector of driver bundle info structures from the hot-plug driver
00107  * directory.
00108  *
00109  * Returns NULL on error and a pointer to an allocated HPDriver vector on
00110  * success.  The caller must free the HPDriver with a call to
00111  * HPDriversRelease().
00112  */
00113 static HPDriverVector HPDriversGetFromDirectory(const char *driverBundlePath)
00114 {
00115 #ifdef DEBUG_HOTPLUG
00116     Log2(PCSC_LOG_DEBUG, "Entering HPDriversGetFromDirectory: %s",
00117         driverBundlePath);
00118 #endif
00119 
00120     int readersNumber = 0;
00121     HPDriverVector bundleVector = NULL;
00122     CFArrayRef bundleArray;
00123     CFStringRef driverBundlePathString =
00124         CFStringCreateWithCString(kCFAllocatorDefault,
00125         driverBundlePath,
00126         kCFStringEncodingMacRoman);
00127     CFURLRef pluginUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
00128         driverBundlePathString,
00129         kCFURLPOSIXPathStyle, TRUE);
00130 
00131     CFRelease(driverBundlePathString);
00132     if (!pluginUrl)
00133     {
00134         Log1(PCSC_LOG_ERROR, "error getting plugin directory URL");
00135         return NULL;
00136     }
00137     bundleArray = CFBundleCreateBundlesFromDirectory(kCFAllocatorDefault,
00138         pluginUrl, NULL);
00139     if (!bundleArray)
00140     {
00141         Log1(PCSC_LOG_ERROR, "error getting plugin directory bundles");
00142         return NULL;
00143     }
00144     CFRelease(pluginUrl);
00145 
00146     size_t bundleArraySize = CFArrayGetCount(bundleArray);
00147     size_t i;
00148 
00149     /* get the number of readers (including aliases) */
00150     for (i = 0; i < bundleArraySize; i++)
00151     {
00152         CFBundleRef currBundle =
00153             (CFBundleRef) CFArrayGetValueAtIndex(bundleArray, i);
00154         CFDictionaryRef dict = CFBundleGetInfoDictionary(currBundle);
00155 
00156         const void * blobValue = CFDictionaryGetValue(dict,
00157             CFSTR(PCSCLITE_HP_MANUKEY_NAME));
00158 
00159         if (!blobValue)
00160         {
00161             Log1(PCSC_LOG_ERROR, "error getting vendor ID from bundle");
00162             return NULL;
00163         }
00164 
00165         if (CFGetTypeID(blobValue) == CFArrayGetTypeID())
00166         {
00167             /* alias found, each reader count as 1 */
00168             CFArrayRef propertyArray = blobValue;
00169             readersNumber += CFArrayGetCount(propertyArray);
00170         }
00171         else
00172             /* No alias, only one reader supported */
00173             readersNumber++;
00174     }
00175 #ifdef DEBUG_HOTPLUG
00176     Log2(PCSC_LOG_DEBUG, "Total of %d readers supported", readersNumber);
00177 #endif
00178 
00179     /* The last entry is an end marker (m_vendorId = 0)
00180      * see checks in HPDriversMatchUSBDevices:503
00181      *  and HPDriverVectorRelease:376 */
00182     readersNumber++;
00183 
00184     bundleVector = calloc(readersNumber, sizeof(HPDriver));
00185     if (!bundleVector)
00186     {
00187         Log1(PCSC_LOG_ERROR, "memory allocation failure");
00188         return NULL;
00189     }
00190 
00191     HPDriver *driverBundle = bundleVector;
00192     for (i = 0; i < bundleArraySize; i++)
00193     {
00194         CFBundleRef currBundle =
00195             (CFBundleRef) CFArrayGetValueAtIndex(bundleArray, i);
00196         CFDictionaryRef dict = CFBundleGetInfoDictionary(currBundle);
00197 
00198         CFURLRef bundleUrl = CFBundleCopyBundleURL(currBundle);
00199         CFStringRef bundlePath = CFURLCopyPath(bundleUrl);
00200 
00201         driverBundle->m_libPath = strdup(CFStringGetCStringPtr(bundlePath,
00202                 CFStringGetSystemEncoding()));
00203 
00204         const void * blobValue = CFDictionaryGetValue(dict,
00205             CFSTR(PCSCLITE_HP_MANUKEY_NAME));
00206 
00207         if (!blobValue)
00208         {
00209             Log1(PCSC_LOG_ERROR, "error getting vendor ID from bundle");
00210             return bundleVector;
00211         }
00212 
00213         if (CFGetTypeID(blobValue) == CFArrayGetTypeID())
00214         {
00215             CFArrayRef vendorArray = blobValue;
00216             CFArrayRef productArray;
00217             CFArrayRef friendlyNameArray;
00218             char *libPath = driverBundle->m_libPath;
00219 
00220 #ifdef DEBUG_HOTPLUG
00221             Log2(PCSC_LOG_DEBUG, "Driver with aliases: %s", libPath);
00222 #endif
00223             /* get list of ProductID */
00224             productArray = CFDictionaryGetValue(dict,
00225                  CFSTR(PCSCLITE_HP_PRODKEY_NAME));
00226             if (!productArray)
00227             {
00228                 Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
00229                 return bundleVector;
00230             }
00231 
00232             /* get list of FriendlyName */
00233             friendlyNameArray = CFDictionaryGetValue(dict,
00234                  CFSTR(PCSCLITE_HP_NAMEKEY_NAME));
00235             if (!friendlyNameArray)
00236             {
00237                 Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
00238                 return bundleVector;
00239             }
00240 
00241             int reader_nb = CFArrayGetCount(vendorArray);
00242 
00243             if (reader_nb != CFArrayGetCount(productArray))
00244             {
00245                 Log3(PCSC_LOG_ERROR,
00246                     "Malformed Info.plist: %d vendors and %ld products",
00247                     reader_nb, CFArrayGetCount(productArray));
00248                 return bundleVector;
00249             }
00250 
00251             if (reader_nb != CFArrayGetCount(friendlyNameArray))
00252             {
00253                 Log3(PCSC_LOG_ERROR,
00254                     "Malformed Info.plist: %d vendors and %ld friendlynames",
00255                     reader_nb, CFArrayGetCount(friendlyNameArray));
00256                 return bundleVector;
00257             }
00258 
00259             int j;
00260             for (j=0; j<reader_nb; j++)
00261             {
00262                 CFStringRef strValue = CFArrayGetValueAtIndex(vendorArray, j);
00263 
00264                 driverBundle->m_vendorId = strtoul(CFStringGetCStringPtr(strValue,
00265                     CFStringGetSystemEncoding()), NULL, 16);
00266 
00267                 strValue = CFArrayGetValueAtIndex(productArray, j);
00268                 driverBundle->m_productId = strtoul(CFStringGetCStringPtr(strValue,
00269                     CFStringGetSystemEncoding()), NULL, 16);
00270 
00271                 strValue = CFArrayGetValueAtIndex(friendlyNameArray, j);
00272                 const char *cstr = CFStringGetCStringPtr(strValue,
00273                     CFStringGetSystemEncoding());
00274 
00275                 driverBundle->m_friendlyName = strdup(cstr);
00276                 if (!driverBundle->m_libPath)
00277                     driverBundle->m_libPath = strdup(libPath);
00278 
00279 #ifdef DEBUG_HOTPLUG
00280                 Log2(PCSC_LOG_DEBUG, "VendorID: 0x%04X",
00281                     driverBundle->m_vendorId);
00282                 Log2(PCSC_LOG_DEBUG, "ProductID: 0x%04X",
00283                     driverBundle->m_productId);
00284                 Log2(PCSC_LOG_DEBUG, "Friendly name: %s",
00285                     driverBundle->m_friendlyName);
00286                 Log2(PCSC_LOG_DEBUG, "Driver: %s", driverBundle->m_libPath);
00287 #endif
00288 
00289                 /* go to next bundle in the vector */
00290                 driverBundle++;
00291             }
00292         }
00293         else
00294         {
00295             CFStringRef strValue = blobValue;
00296 
00297 #ifdef DEBUG_HOTPLUG
00298             Log3(PCSC_LOG_DEBUG, "Driver without alias: %s",
00299                 driverBundle, driverBundle->m_libPath);
00300 #endif
00301 
00302             driverBundle->m_vendorId = strtoul(CFStringGetCStringPtr(strValue,
00303                     CFStringGetSystemEncoding()), NULL, 16);
00304 
00305             strValue = (CFStringRef) CFDictionaryGetValue(dict,
00306                 CFSTR(PCSCLITE_HP_PRODKEY_NAME));
00307             if (!strValue)
00308             {
00309                 Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
00310                 return bundleVector;
00311             }
00312             driverBundle->m_productId = strtoul(CFStringGetCStringPtr(strValue,
00313                 CFStringGetSystemEncoding()), NULL, 16);
00314 
00315             strValue = (CFStringRef) CFDictionaryGetValue(dict,
00316                 CFSTR(PCSCLITE_HP_NAMEKEY_NAME));
00317             if (!strValue)
00318             {
00319                 Log1(PCSC_LOG_ERROR, "error getting product friendly name from bundle");
00320                 driverBundle->m_friendlyName = strdup("unnamed device");
00321             }
00322             else
00323             {
00324                 const char *cstr = CFStringGetCStringPtr(strValue,
00325                     CFStringGetSystemEncoding());
00326 
00327                 driverBundle->m_friendlyName = strdup(cstr);
00328             }
00329 #ifdef DEBUG_HOTPLUG
00330             Log2(PCSC_LOG_DEBUG, "VendorID: 0x%04X", driverBundle->m_vendorId);
00331             Log2(PCSC_LOG_DEBUG, "ProductID: 0x%04X", driverBundle->m_productId);
00332             Log2(PCSC_LOG_DEBUG, "Friendly name: %s", driverBundle->m_friendlyName);
00333             Log2(PCSC_LOG_DEBUG, "Driver: %s", driverBundle->m_libPath);
00334 #endif
00335 
00336             /* go to next bundle in the vector */
00337             driverBundle++;
00338         }
00339     }
00340     CFRelease(bundleArray);
00341     return bundleVector;
00342 }
00343 
00344 /*
00345  * Copies a driver bundle instance.
00346  */
00347 static HPDriver *HPDriverCopy(HPDriver * rhs)
00348 {
00349     if (!rhs)
00350         return NULL;
00351 
00352     HPDriver *newDriverBundle = calloc(1, sizeof(HPDriver));
00353 
00354     if (!newDriverBundle)
00355         return NULL;
00356 
00357     newDriverBundle->m_vendorId = rhs->m_vendorId;
00358     newDriverBundle->m_productId = rhs->m_productId;
00359     newDriverBundle->m_friendlyName = strdup(rhs->m_friendlyName);
00360     newDriverBundle->m_libPath = strdup(rhs->m_libPath);
00361 
00362     return newDriverBundle;
00363 }
00364 
00365 /*
00366  * Releases resources allocated to a driver bundle vector.
00367  */
00368 static void HPDriverRelease(HPDriver * driverBundle)
00369 {
00370     if (driverBundle)
00371     {
00372         free(driverBundle->m_friendlyName);
00373         free(driverBundle->m_libPath);
00374     }
00375 }
00376 
00377 /*
00378  * Releases resources allocated to a driver bundle vector.
00379  */
00380 static void HPDriverVectorRelease(HPDriverVector driverBundleVector)
00381 {
00382     if (driverBundleVector)
00383     {
00384         HPDriver *b;
00385 
00386         for (b = driverBundleVector; b->m_vendorId; ++b)
00387             HPDriverRelease(b);
00388 
00389         free(driverBundleVector);
00390     }
00391 }
00392 
00393 /*
00394  * Inserts a new reader device in the list.
00395  */
00396 static HPDeviceList
00397 HPDeviceListInsert(HPDeviceList list, HPDriver * bundle, UInt32 address)
00398 {
00399     HPDevice *newReader = calloc(1, sizeof(HPDevice));
00400 
00401     if (!newReader)
00402     {
00403         Log1(PCSC_LOG_ERROR, "memory allocation failure");
00404         return list;
00405     }
00406 
00407     newReader->m_driver = HPDriverCopy(bundle);
00408     newReader->m_address = address;
00409     newReader->m_next = list;
00410 
00411     return newReader;
00412 }
00413 
00414 /*
00415  * Frees resources allocated to a HPDeviceList.
00416  */
00417 static void HPDeviceListRelease(HPDeviceList list)
00418 {
00419     HPDevice *p;
00420 
00421     for (p = list; p; p = p->m_next)
00422         HPDriverRelease(p->m_driver);
00423 }
00424 
00425 /*
00426  * Compares two driver bundle instances for equality.
00427  */
00428 static int HPDeviceEquals(HPDevice * a, HPDevice * b)
00429 {
00430     return (a->m_driver->m_vendorId == b->m_driver->m_vendorId)
00431         && (a->m_driver->m_productId == b->m_driver->m_productId)
00432         && (a->m_address == b->m_address);
00433 }
00434 
00435 /*
00436  * Finds USB devices currently registered in the system that match any of
00437  * the drivers detected in the driver bundle vector.
00438  */
00439 static int
00440 HPDriversMatchUSBDevices(HPDriverVector driverBundle,
00441     HPDeviceList * readerList)
00442 {
00443     CFDictionaryRef usbMatch = IOServiceMatching("IOUSBDevice");
00444 
00445     if (0 == usbMatch)
00446     {
00447         Log1(PCSC_LOG_ERROR,
00448             "error getting USB match from IOServiceMatching()");
00449         return 1;
00450     }
00451 
00452     io_iterator_t usbIter;
00453     kern_return_t kret = IOServiceGetMatchingServices(kIOMasterPortDefault,
00454         usbMatch, &usbIter);
00455 
00456     if (kret != 0)
00457     {
00458         Log1(PCSC_LOG_ERROR,
00459             "error getting iterator from IOServiceGetMatchingServices()");
00460         return 1;
00461     }
00462 
00463     IOIteratorReset(usbIter);
00464     io_object_t usbDevice = 0;
00465 
00466     while ((usbDevice = IOIteratorNext(usbIter)))
00467     {
00468         char namebuf[1024];
00469 
00470         kret = IORegistryEntryGetName(usbDevice, namebuf);
00471         if (kret != 0)
00472         {
00473             Log1(PCSC_LOG_ERROR,
00474                 "error getting device name from IORegistryEntryGetName()");
00475             return 1;
00476         }
00477 
00478         IOCFPlugInInterface **iodev;
00479         SInt32 score;
00480 
00481         kret = IOCreatePlugInInterfaceForService(usbDevice,
00482             kIOUSBDeviceUserClientTypeID,
00483             kIOCFPlugInInterfaceID, &iodev, &score);
00484         if (kret != 0)
00485         {
00486             Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
00487             return 1;
00488         }
00489         IOObjectRelease(usbDevice);
00490 
00491         IOUSBDeviceInterface **usbdev;
00492         HRESULT hres = (*iodev)->QueryInterface(iodev,
00493             CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
00494             (LPVOID *) & usbdev);
00495 
00496         (*iodev)->Release(iodev);
00497         if (hres)
00498         {
00499             Log1(PCSC_LOG_ERROR,
00500                 "error querying interface in QueryInterface()");
00501             return 1;
00502         }
00503 
00504         UInt16 vendorId = 0;
00505         UInt16 productId = 0;
00506         UInt32 usbAddress = 0;
00507 
00508         kret = (*usbdev)->GetDeviceVendor(usbdev, &vendorId);
00509         kret = (*usbdev)->GetDeviceProduct(usbdev, &productId);
00510         kret = (*usbdev)->GetLocationID(usbdev, &usbAddress);
00511         (*usbdev)->Release(usbdev);
00512 
00513         HPDriver *driver;
00514         for (driver = driverBundle; driver->m_vendorId; ++driver)
00515         {
00516             if ((driver->m_vendorId == vendorId)
00517                 && (driver->m_productId == productId))
00518             {
00519                 *readerList =
00520                     HPDeviceListInsert(*readerList, driver, usbAddress);
00521             }
00522         }
00523     }
00524 
00525     IOObjectRelease(usbIter);
00526     return 0;
00527 }
00528 
00529 /*
00530  * Finds PC Card devices currently registered in the system that match any of
00531  * the drivers detected in the driver bundle vector.
00532  */
00533 static int
00534 HPDriversMatchPCCardDevices(HPDriver * driverBundle,
00535     HPDeviceList * readerList)
00536 {
00537     CFDictionaryRef pccMatch = IOServiceMatching("IOPCCard16Device");
00538 
00539     if (pccMatch == NULL)
00540     {
00541         Log1(PCSC_LOG_ERROR,
00542             "error getting PCCard match from IOServiceMatching()");
00543         return 1;
00544     }
00545 
00546     io_iterator_t pccIter;
00547     kern_return_t kret =
00548         IOServiceGetMatchingServices(kIOMasterPortDefault, pccMatch,
00549         &pccIter);
00550     if (kret != 0)
00551     {
00552         Log1(PCSC_LOG_ERROR,
00553             "error getting iterator from IOServiceGetMatchingServices()");
00554         return 1;
00555     }
00556 
00557     IOIteratorReset(pccIter);
00558     io_object_t pccDevice = 0;
00559 
00560     while ((pccDevice = IOIteratorNext(pccIter)))
00561     {
00562         char namebuf[1024];
00563 
00564         kret = IORegistryEntryGetName(pccDevice, namebuf);
00565         if (kret != 0)
00566         {
00567             Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
00568             return 1;
00569         }
00570         UInt32 vendorId = 0;
00571         UInt32 productId = 0;
00572         UInt32 pccAddress = 0;
00573         CFTypeRef valueRef =
00574             IORegistryEntryCreateCFProperty(pccDevice, CFSTR("VendorID"),
00575             kCFAllocatorDefault, 0);
00576 
00577         if (!valueRef)
00578         {
00579             Log1(PCSC_LOG_ERROR, "error getting vendor");
00580         }
00581         else
00582         {
00583             CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
00584                 &vendorId);
00585         }
00586         valueRef =
00587             IORegistryEntryCreateCFProperty(pccDevice, CFSTR("DeviceID"),
00588             kCFAllocatorDefault, 0);
00589         if (!valueRef)
00590         {
00591             Log1(PCSC_LOG_ERROR, "error getting device");
00592         }
00593         else
00594         {
00595             CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
00596                 &productId);
00597         }
00598         valueRef =
00599             IORegistryEntryCreateCFProperty(pccDevice, CFSTR("SocketNumber"),
00600             kCFAllocatorDefault, 0);
00601         if (!valueRef)
00602         {
00603             Log1(PCSC_LOG_ERROR, "error getting PC Card socket");
00604         }
00605         else
00606         {
00607             CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
00608                 &pccAddress);
00609         }
00610         HPDriver *driver = driverBundle;
00611 
00612         for (; driver->m_vendorId; ++driver)
00613         {
00614             if ((driver->m_vendorId == vendorId)
00615                 && (driver->m_productId == productId))
00616             {
00617                 *readerList =
00618                     HPDeviceListInsert(*readerList, driver, pccAddress);
00619             }
00620         }
00621     }
00622     IOObjectRelease(pccIter);
00623     return 0;
00624 }
00625 
00626 
00627 static void HPEstablishUSBNotification(void)
00628 {
00629     io_iterator_t deviceAddedIterator;
00630     io_iterator_t deviceRemovedIterator;
00631     CFMutableDictionaryRef matchingDictionary;
00632     IONotificationPortRef notificationPort;
00633     IOReturn kret;
00634 
00635     notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
00636     CFRunLoopAddSource(CFRunLoopGetCurrent(),
00637         IONotificationPortGetRunLoopSource(notificationPort),
00638         kCFRunLoopDefaultMode);
00639 
00640     matchingDictionary = IOServiceMatching("IOUSBDevice");
00641     if (!matchingDictionary)
00642     {
00643         Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
00644     }
00645     matchingDictionary =
00646         (CFMutableDictionaryRef) CFRetain(matchingDictionary);
00647 
00648     kret = IOServiceAddMatchingNotification(notificationPort,
00649         kIOMatchedNotification,
00650         matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
00651     if (kret)
00652     {
00653         Log2(PCSC_LOG_ERROR,
00654             "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
00655     }
00656     HPDeviceAppeared(NULL, deviceAddedIterator);
00657 
00658     kret = IOServiceAddMatchingNotification(notificationPort,
00659         kIOTerminatedNotification,
00660         matchingDictionary,
00661         HPDeviceDisappeared, NULL, &deviceRemovedIterator);
00662     if (kret)
00663     {
00664         Log2(PCSC_LOG_ERROR,
00665             "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
00666     }
00667     HPDeviceDisappeared(NULL, deviceRemovedIterator);
00668 }
00669 
00670 static void HPEstablishPCCardNotification(void)
00671 {
00672     io_iterator_t deviceAddedIterator;
00673     io_iterator_t deviceRemovedIterator;
00674     CFMutableDictionaryRef matchingDictionary;
00675     IONotificationPortRef notificationPort;
00676     IOReturn kret;
00677 
00678     notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
00679     CFRunLoopAddSource(CFRunLoopGetCurrent(),
00680         IONotificationPortGetRunLoopSource(notificationPort),
00681         kCFRunLoopDefaultMode);
00682 
00683     matchingDictionary = IOServiceMatching("IOPCCard16Device");
00684     if (!matchingDictionary)
00685     {
00686         Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
00687     }
00688     matchingDictionary =
00689         (CFMutableDictionaryRef) CFRetain(matchingDictionary);
00690 
00691     kret = IOServiceAddMatchingNotification(notificationPort,
00692         kIOMatchedNotification,
00693         matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
00694     if (kret)
00695     {
00696         Log2(PCSC_LOG_ERROR,
00697             "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
00698     }
00699     HPDeviceAppeared(NULL, deviceAddedIterator);
00700 
00701     kret = IOServiceAddMatchingNotification(notificationPort,
00702         kIOTerminatedNotification,
00703         matchingDictionary,
00704         HPDeviceDisappeared, NULL, &deviceRemovedIterator);
00705     if (kret)
00706     {
00707         Log2(PCSC_LOG_ERROR,
00708             "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
00709     }
00710     HPDeviceDisappeared(NULL, deviceRemovedIterator);
00711 }
00712 
00713 /*
00714  * Thread runner (does not return).
00715  */
00716 static void HPDeviceNotificationThread(void)
00717 {
00718     HPEstablishUSBNotification();
00719     HPEstablishPCCardNotification();
00720     CFRunLoopRun();
00721 }
00722 
00723 /*
00724  * Scans the hotplug driver directory and looks in the system for
00725  * matching devices.
00726  * Adds or removes matching readers as necessary.
00727  */
00728 LONG HPSearchHotPluggables(void)
00729 {
00730     HPDriver *drivers = HPDriversGetFromDirectory(PCSCLITE_HP_DROPDIR);
00731 
00732     if (!drivers)
00733         return 1;
00734 
00735     HPDeviceList devices = NULL;
00736 
00737     if (HPDriversMatchUSBDevices(drivers, &devices))
00738         return -1;
00739 
00740     if (HPDriversMatchPCCardDevices(drivers, &devices))
00741         return -1;
00742 
00743     HPDevice *a;
00744 
00745     for (a = devices; a; a = a->m_next)
00746     {
00747         int found = FALSE;
00748         HPDevice *b;
00749 
00750         for (b = sDeviceList; b; b = b->m_next)
00751         {
00752             if (HPDeviceEquals(a, b))
00753             {
00754                 found = TRUE;
00755                 break;
00756             }
00757         }
00758         if (!found)
00759         {
00760             char deviceName[MAX_DEVICENAME];
00761 
00762             /* the format should be "usb:%04x/%04x" but Apple uses the
00763              * friendly name instead */
00764             snprintf(deviceName, sizeof(deviceName),
00765                 "%s", a->m_driver->m_friendlyName);
00766             deviceName[sizeof(deviceName)-1] = '\0';
00767 
00768             RFAddReader(a->m_driver->m_friendlyName,
00769                 PCSCLITE_HP_BASE_PORT + a->m_address, a->m_driver->m_libPath,
00770                 deviceName);
00771         }
00772     }
00773 
00774     for (a = sDeviceList; a; a = a->m_next)
00775     {
00776         int found = FALSE;
00777         HPDevice *b;
00778 
00779         for (b = devices; b; b = b->m_next)
00780         {
00781             if (HPDeviceEquals(a, b))
00782             {
00783                 found = TRUE;
00784                 break;
00785             }
00786         }
00787         if (!found)
00788         {
00789             RFRemoveReader(a->m_driver->m_friendlyName,
00790                 PCSCLITE_HP_BASE_PORT + a->m_address);
00791         }
00792     }
00793 
00794     HPDeviceListRelease(sDeviceList);
00795     sDeviceList = devices;
00796     HPDriverVectorRelease(drivers);
00797 
00798     return 0;
00799 }
00800 
00801 
00802 pthread_t sHotplugWatcherThread;
00803 
00804 /*
00805  * Sets up callbacks for device hotplug events.
00806  */
00807 ULONG HPRegisterForHotplugEvents(void)
00808 {
00809     ThreadCreate(&sHotplugWatcherThread,
00810         THREAD_ATTR_DEFAULT,
00811         (PCSCLITE_THREAD_FUNCTION( )) HPDeviceNotificationThread, NULL);
00812 
00813     return 0;
00814 }
00815 
00816 LONG HPStopHotPluggables(void)
00817 {
00818     return 0;
00819 }
00820 
00821 void HPReCheckSerialReaders(void)
00822 {
00823 }
00824 
00825 #endif  /* __APPLE__ */
00826