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

Generated on Mon Aug 17 01:00:09 2009 for pcsc-lite by  doxygen 1.5.9