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