Logo Search packages:      
Sourcecode: pcsc-lite version File versions  Download package

hotplug_macosx.c
Go to the documentation of this file.
/*
 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
 *
 * Copyright (C) 2002-2004
 *  Stephen M. Webb <stephenw@cryptocard.com>
 * Copyright (C) 2002-2011
 *  Ludovic Rousseau <ludovic.rousseau@free.fr>
 * Copyright (C) 2002
 *  David Corcoran <corcoran@linuxnet.com>
 * Copyright (C) 2003
 *  Antti Tapaninen
 *
 * $Id: hotplug_macosx.c 5868 2011-07-09 11:59:09Z rousseau $
 */

/**
 * @file
 * @brief This provides a search API for hot pluggble devices.
 */

#include "config.h"
#include "misc.h"
#include "pcscd.h"

#if defined(__APPLE__) && !defined(HAVE_LIBUSB)
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/usb/IOUSBLib.h>
#include <stdlib.h>
#include <string.h>

#include "debuglog.h"
#include "parser.h"
#include "readerfactory.h"
#include "winscard_msg.h"
#include "utils.h"
#include "hotplug.h"

#undef DEBUG_HOTPLUG

/*
 * An aggregation of useful information on a driver bundle in the
 * drop directory.
 */
typedef struct HPDriver
{
      UInt32 m_vendorId;                  /* unique vendor's manufacturer code */
      UInt32 m_productId;                 /* manufacturer's unique product code */
      char *m_friendlyName;         /* bundle friendly name */
      char *m_libPath;              /* bundle's plugin library location */
} HPDriver, *HPDriverVector;

/*
 * An aggregation on information on currently active reader drivers.
 */
typedef struct HPDevice
{
      HPDriver *m_driver;                 /* driver bundle information */
      UInt32 m_address;             /* unique system address of device */
      struct HPDevice *m_next;      /* next device in list */
} HPDevice, *HPDeviceList;

/*
 * Pointer to a list of (currently) known hotplug reader devices (and their
 * drivers).
 */
static HPDeviceList sDeviceList = NULL;

/*
 * A callback to handle the asynchronous appearance of new devices that are
 * candidates for PCSC readers.
 */
static void HPDeviceAppeared(void *refCon, io_iterator_t iterator)
{
      kern_return_t kret;
      io_service_t obj;

      (void)refCon;

      while ((obj = IOIteratorNext(iterator)))
            kret = IOObjectRelease(obj);

      HPSearchHotPluggables();
}

/*
 * A callback to handle the asynchronous disappearance of devices that are
 * possibly PCSC readers.
 */
static void HPDeviceDisappeared(void *refCon, io_iterator_t iterator)
{
      kern_return_t kret;
      io_service_t obj;

      (void)refCon;

      while ((obj = IOIteratorNext(iterator)))
            kret = IOObjectRelease(obj);

      HPSearchHotPluggables();
}


/*
 * Creates a vector of driver bundle info structures from the hot-plug driver
 * directory.
 *
 * Returns NULL on error and a pointer to an allocated HPDriver vector on
 * success.  The caller must free the HPDriver with a call to
 * HPDriversRelease().
 */
static HPDriverVector HPDriversGetFromDirectory(const char *driverBundlePath)
{
#ifdef DEBUG_HOTPLUG
      Log2(PCSC_LOG_DEBUG, "Entering HPDriversGetFromDirectory: %s",
            driverBundlePath);
#endif

      int readersNumber = 0;
      HPDriverVector bundleVector = NULL;
      CFArrayRef bundleArray;
      CFStringRef driverBundlePathString =
            CFStringCreateWithCString(kCFAllocatorDefault,
            driverBundlePath,
            kCFStringEncodingMacRoman);
      CFURLRef pluginUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
            driverBundlePathString,
            kCFURLPOSIXPathStyle, TRUE);

      CFRelease(driverBundlePathString);
      if (!pluginUrl)
      {
            Log1(PCSC_LOG_ERROR, "error getting plugin directory URL");
            return NULL;
      }
      bundleArray = CFBundleCreateBundlesFromDirectory(kCFAllocatorDefault,
            pluginUrl, NULL);
      if (!bundleArray)
      {
            Log1(PCSC_LOG_ERROR, "error getting plugin directory bundles");
            return NULL;
      }
      CFRelease(pluginUrl);

      size_t bundleArraySize = CFArrayGetCount(bundleArray);
      size_t i;

      /* get the number of readers (including aliases) */
      for (i = 0; i < bundleArraySize; i++)
      {
            CFBundleRef currBundle =
                  (CFBundleRef) CFArrayGetValueAtIndex(bundleArray, i);
            CFDictionaryRef dict = CFBundleGetInfoDictionary(currBundle);

            const void * blobValue = CFDictionaryGetValue(dict,
                  CFSTR(PCSCLITE_HP_MANUKEY_NAME));

            if (!blobValue)
            {
                  Log1(PCSC_LOG_ERROR, "error getting vendor ID from bundle");
                  return NULL;
            }

            if (CFGetTypeID(blobValue) == CFArrayGetTypeID())
            {
                  /* alias found, each reader count as 1 */
                  CFArrayRef propertyArray = blobValue;
                  readersNumber += CFArrayGetCount(propertyArray);
            }
            else
                  /* No alias, only one reader supported */
                  readersNumber++;
      }
#ifdef DEBUG_HOTPLUG
      Log2(PCSC_LOG_DEBUG, "Total of %d readers supported", readersNumber);
#endif

      /* The last entry is an end marker (m_vendorId = 0)
       * see checks in HPDriversMatchUSBDevices:503
       *  and HPDriverVectorRelease:376 */
      readersNumber++;

      bundleVector = calloc(readersNumber, sizeof(HPDriver));
      if (!bundleVector)
      {
            Log1(PCSC_LOG_ERROR, "memory allocation failure");
            return NULL;
      }

      HPDriver *driverBundle = bundleVector;
      for (i = 0; i < bundleArraySize; i++)
      {
            CFBundleRef currBundle =
                  (CFBundleRef) CFArrayGetValueAtIndex(bundleArray, i);
            CFDictionaryRef dict = CFBundleGetInfoDictionary(currBundle);

            CFURLRef bundleUrl = CFBundleCopyBundleURL(currBundle);
            CFStringRef bundlePath = CFURLCopyPath(bundleUrl);

            driverBundle->m_libPath = strdup(CFStringGetCStringPtr(bundlePath,
                        CFStringGetSystemEncoding()));

            const void * blobValue = CFDictionaryGetValue(dict,
                  CFSTR(PCSCLITE_HP_MANUKEY_NAME));

            if (!blobValue)
            {
                  Log1(PCSC_LOG_ERROR, "error getting vendor ID from bundle");
                  return bundleVector;
            }

            if (CFGetTypeID(blobValue) == CFArrayGetTypeID())
            {
                  CFArrayRef vendorArray = blobValue;
                  CFArrayRef productArray;
                  CFArrayRef friendlyNameArray;
                  char *libPath = driverBundle->m_libPath;

#ifdef DEBUG_HOTPLUG
                  Log2(PCSC_LOG_DEBUG, "Driver with aliases: %s", libPath);
#endif
                  /* get list of ProductID */
                  productArray = CFDictionaryGetValue(dict,
                         CFSTR(PCSCLITE_HP_PRODKEY_NAME));
                  if (!productArray)
                  {
                        Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
                        return bundleVector;
                  }

                  /* get list of FriendlyName */
                  friendlyNameArray = CFDictionaryGetValue(dict,
                         CFSTR(PCSCLITE_HP_NAMEKEY_NAME));
                  if (!friendlyNameArray)
                  {
                        Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
                        return bundleVector;
                  }

                  int reader_nb = CFArrayGetCount(vendorArray);

                  if (reader_nb != CFArrayGetCount(productArray))
                  {
                        Log3(PCSC_LOG_ERROR,
                              "Malformed Info.plist: %d vendors and %ld products",
                              reader_nb, CFArrayGetCount(productArray));
                        return bundleVector;
                  }

                  if (reader_nb != CFArrayGetCount(friendlyNameArray))
                  {
                        Log3(PCSC_LOG_ERROR,
                              "Malformed Info.plist: %d vendors and %ld friendlynames",
                              reader_nb, CFArrayGetCount(friendlyNameArray));
                        return bundleVector;
                  }

                  int j;
                  for (j=0; j<reader_nb; j++)
                  {
                        CFStringRef strValue = CFArrayGetValueAtIndex(vendorArray, j);

                        driverBundle->m_vendorId = strtoul(CFStringGetCStringPtr(strValue,
                              CFStringGetSystemEncoding()), NULL, 16);

                        strValue = CFArrayGetValueAtIndex(productArray, j);
                        driverBundle->m_productId = strtoul(CFStringGetCStringPtr(strValue,
                              CFStringGetSystemEncoding()), NULL, 16);

                        strValue = CFArrayGetValueAtIndex(friendlyNameArray, j);
                        const char *cstr = CFStringGetCStringPtr(strValue,
                              CFStringGetSystemEncoding());

                        driverBundle->m_friendlyName = strdup(cstr);
                        if (!driverBundle->m_libPath)
                              driverBundle->m_libPath = strdup(libPath);

#ifdef DEBUG_HOTPLUG
                        Log2(PCSC_LOG_DEBUG, "VendorID: 0x%04X",
                              driverBundle->m_vendorId);
                        Log2(PCSC_LOG_DEBUG, "ProductID: 0x%04X",
                              driverBundle->m_productId);
                        Log2(PCSC_LOG_DEBUG, "Friendly name: %s",
                              driverBundle->m_friendlyName);
                        Log2(PCSC_LOG_DEBUG, "Driver: %s", driverBundle->m_libPath);
#endif

                        /* go to next bundle in the vector */
                        driverBundle++;
                  }
            }
            else
            {
                  CFStringRef strValue = blobValue;

#ifdef DEBUG_HOTPLUG
                  Log3(PCSC_LOG_DEBUG, "Driver without alias: %s",
                        driverBundle, driverBundle->m_libPath);
#endif

                  driverBundle->m_vendorId = strtoul(CFStringGetCStringPtr(strValue,
                              CFStringGetSystemEncoding()), NULL, 16);

                  strValue = (CFStringRef) CFDictionaryGetValue(dict,
                        CFSTR(PCSCLITE_HP_PRODKEY_NAME));
                  if (!strValue)
                  {
                        Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
                        return bundleVector;
                  }
                  driverBundle->m_productId = strtoul(CFStringGetCStringPtr(strValue,
                        CFStringGetSystemEncoding()), NULL, 16);

                  strValue = (CFStringRef) CFDictionaryGetValue(dict,
                        CFSTR(PCSCLITE_HP_NAMEKEY_NAME));
                  if (!strValue)
                  {
                        Log1(PCSC_LOG_ERROR, "error getting product friendly name from bundle");
                        driverBundle->m_friendlyName = strdup("unnamed device");
                  }
                  else
                  {
                        const char *cstr = CFStringGetCStringPtr(strValue,
                              CFStringGetSystemEncoding());

                        driverBundle->m_friendlyName = strdup(cstr);
                  }
#ifdef DEBUG_HOTPLUG
                  Log2(PCSC_LOG_DEBUG, "VendorID: 0x%04X", driverBundle->m_vendorId);
                  Log2(PCSC_LOG_DEBUG, "ProductID: 0x%04X", driverBundle->m_productId);
                  Log2(PCSC_LOG_DEBUG, "Friendly name: %s", driverBundle->m_friendlyName);
                  Log2(PCSC_LOG_DEBUG, "Driver: %s", driverBundle->m_libPath);
#endif

                  /* go to next bundle in the vector */
                  driverBundle++;
            }
      }
      CFRelease(bundleArray);
      return bundleVector;
}

/*
 * Copies a driver bundle instance.
 */
static HPDriver *HPDriverCopy(HPDriver * rhs)
{
      if (!rhs)
            return NULL;

      HPDriver *newDriverBundle = calloc(1, sizeof(HPDriver));

      if (!newDriverBundle)
            return NULL;

      newDriverBundle->m_vendorId = rhs->m_vendorId;
      newDriverBundle->m_productId = rhs->m_productId;
      newDriverBundle->m_friendlyName = strdup(rhs->m_friendlyName);
      newDriverBundle->m_libPath = strdup(rhs->m_libPath);

      return newDriverBundle;
}

/*
 * Releases resources allocated to a driver bundle vector.
 */
static void HPDriverRelease(HPDriver * driverBundle)
{
      if (driverBundle)
      {
            free(driverBundle->m_friendlyName);
            free(driverBundle->m_libPath);
      }
}

/*
 * Releases resources allocated to a driver bundle vector.
 */
static void HPDriverVectorRelease(HPDriverVector driverBundleVector)
{
      if (driverBundleVector)
      {
            HPDriver *b;

            for (b = driverBundleVector; b->m_vendorId; ++b)
                  HPDriverRelease(b);

            free(driverBundleVector);
      }
}

/*
 * Inserts a new reader device in the list.
 */
static HPDeviceList
HPDeviceListInsert(HPDeviceList list, HPDriver * bundle, UInt32 address)
{
      HPDevice *newReader = calloc(1, sizeof(HPDevice));

      if (!newReader)
      {
            Log1(PCSC_LOG_ERROR, "memory allocation failure");
            return list;
      }

      newReader->m_driver = HPDriverCopy(bundle);
      newReader->m_address = address;
      newReader->m_next = list;

      return newReader;
}

/*
 * Frees resources allocated to a HPDeviceList.
 */
static void HPDeviceListRelease(HPDeviceList list)
{
      HPDevice *p;

      for (p = list; p; p = p->m_next)
            HPDriverRelease(p->m_driver);
}

/*
 * Compares two driver bundle instances for equality.
 */
static int HPDeviceEquals(HPDevice * a, HPDevice * b)
{
      return (a->m_driver->m_vendorId == b->m_driver->m_vendorId)
            && (a->m_driver->m_productId == b->m_driver->m_productId)
            && (a->m_address == b->m_address);
}

/*
 * Finds USB devices currently registered in the system that match any of
 * the drivers detected in the driver bundle vector.
 */
static int
HPDriversMatchUSBDevices(HPDriverVector driverBundle,
      HPDeviceList * readerList)
{
      CFDictionaryRef usbMatch = IOServiceMatching("IOUSBDevice");

      if (0 == usbMatch)
      {
            Log1(PCSC_LOG_ERROR,
                  "error getting USB match from IOServiceMatching()");
            return 1;
      }

      io_iterator_t usbIter;
      kern_return_t kret = IOServiceGetMatchingServices(kIOMasterPortDefault,
            usbMatch, &usbIter);

      if (kret != 0)
      {
            Log1(PCSC_LOG_ERROR,
                  "error getting iterator from IOServiceGetMatchingServices()");
            return 1;
      }

      IOIteratorReset(usbIter);
      io_object_t usbDevice = 0;

      while ((usbDevice = IOIteratorNext(usbIter)))
      {
            char namebuf[1024];

            kret = IORegistryEntryGetName(usbDevice, namebuf);
            if (kret != 0)
            {
                  Log1(PCSC_LOG_ERROR,
                        "error getting device name from IORegistryEntryGetName()");
                  return 1;
            }

            IOCFPlugInInterface **iodev;
            SInt32 score;

            kret = IOCreatePlugInInterfaceForService(usbDevice,
                  kIOUSBDeviceUserClientTypeID,
                  kIOCFPlugInInterfaceID, &iodev, &score);
            if (kret != 0)
            {
                  Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
                  return 1;
            }
            IOObjectRelease(usbDevice);

            IOUSBDeviceInterface **usbdev;
            HRESULT hres = (*iodev)->QueryInterface(iodev,
                  CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
                  (LPVOID *) & usbdev);

            (*iodev)->Release(iodev);
            if (hres)
            {
                  Log1(PCSC_LOG_ERROR,
                        "error querying interface in QueryInterface()");
                  return 1;
            }

            UInt16 vendorId = 0;
            UInt16 productId = 0;
            UInt32 usbAddress = 0;

            kret = (*usbdev)->GetDeviceVendor(usbdev, &vendorId);
            kret = (*usbdev)->GetDeviceProduct(usbdev, &productId);
            kret = (*usbdev)->GetLocationID(usbdev, &usbAddress);
            (*usbdev)->Release(usbdev);

            HPDriver *driver;
            for (driver = driverBundle; driver->m_vendorId; ++driver)
            {
                  if ((driver->m_vendorId == vendorId)
                        && (driver->m_productId == productId))
                  {
                        *readerList =
                              HPDeviceListInsert(*readerList, driver, usbAddress);
                  }
            }
      }

      IOObjectRelease(usbIter);
      return 0;
}

/*
 * Finds PC Card devices currently registered in the system that match any of
 * the drivers detected in the driver bundle vector.
 */
static int
HPDriversMatchPCCardDevices(HPDriver * driverBundle,
      HPDeviceList * readerList)
{
      CFDictionaryRef pccMatch = IOServiceMatching("IOPCCard16Device");

      if (pccMatch == NULL)
      {
            Log1(PCSC_LOG_ERROR,
                  "error getting PCCard match from IOServiceMatching()");
            return 1;
      }

      io_iterator_t pccIter;
      kern_return_t kret =
            IOServiceGetMatchingServices(kIOMasterPortDefault, pccMatch,
            &pccIter);
      if (kret != 0)
      {
            Log1(PCSC_LOG_ERROR,
                  "error getting iterator from IOServiceGetMatchingServices()");
            return 1;
      }

      IOIteratorReset(pccIter);
      io_object_t pccDevice = 0;

      while ((pccDevice = IOIteratorNext(pccIter)))
      {
            char namebuf[1024];

            kret = IORegistryEntryGetName(pccDevice, namebuf);
            if (kret != 0)
            {
                  Log1(PCSC_LOG_ERROR, "error getting plugin interface from IOCreatePlugInInterfaceForService()");
                  return 1;
            }
            UInt32 vendorId = 0;
            UInt32 productId = 0;
            UInt32 pccAddress = 0;
            CFTypeRef valueRef =
                  IORegistryEntryCreateCFProperty(pccDevice, CFSTR("VendorID"),
                  kCFAllocatorDefault, 0);

            if (!valueRef)
            {
                  Log1(PCSC_LOG_ERROR, "error getting vendor");
            }
            else
            {
                  CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
                        &vendorId);
            }
            valueRef =
                  IORegistryEntryCreateCFProperty(pccDevice, CFSTR("DeviceID"),
                  kCFAllocatorDefault, 0);
            if (!valueRef)
            {
                  Log1(PCSC_LOG_ERROR, "error getting device");
            }
            else
            {
                  CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
                        &productId);
            }
            valueRef =
                  IORegistryEntryCreateCFProperty(pccDevice, CFSTR("SocketNumber"),
                  kCFAllocatorDefault, 0);
            if (!valueRef)
            {
                  Log1(PCSC_LOG_ERROR, "error getting PC Card socket");
            }
            else
            {
                  CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type,
                        &pccAddress);
            }
            HPDriver *driver = driverBundle;

            for (; driver->m_vendorId; ++driver)
            {
                  if ((driver->m_vendorId == vendorId)
                        && (driver->m_productId == productId))
                  {
                        *readerList =
                              HPDeviceListInsert(*readerList, driver, pccAddress);
                  }
            }
      }
      IOObjectRelease(pccIter);
      return 0;
}


static void HPEstablishUSBNotification(void)
{
      io_iterator_t deviceAddedIterator;
      io_iterator_t deviceRemovedIterator;
      CFMutableDictionaryRef matchingDictionary;
      IONotificationPortRef notificationPort;
      IOReturn kret;

      notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
      CFRunLoopAddSource(CFRunLoopGetCurrent(),
            IONotificationPortGetRunLoopSource(notificationPort),
            kCFRunLoopDefaultMode);

      matchingDictionary = IOServiceMatching("IOUSBDevice");
      if (!matchingDictionary)
      {
            Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
      }
      matchingDictionary =
            (CFMutableDictionaryRef) CFRetain(matchingDictionary);

      kret = IOServiceAddMatchingNotification(notificationPort,
            kIOMatchedNotification,
            matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
      if (kret)
      {
            Log2(PCSC_LOG_ERROR,
                  "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
      }
      HPDeviceAppeared(NULL, deviceAddedIterator);

      kret = IOServiceAddMatchingNotification(notificationPort,
            kIOTerminatedNotification,
            matchingDictionary,
            HPDeviceDisappeared, NULL, &deviceRemovedIterator);
      if (kret)
      {
            Log2(PCSC_LOG_ERROR,
                  "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
      }
      HPDeviceDisappeared(NULL, deviceRemovedIterator);
}

static void HPEstablishPCCardNotification(void)
{
      io_iterator_t deviceAddedIterator;
      io_iterator_t deviceRemovedIterator;
      CFMutableDictionaryRef matchingDictionary;
      IONotificationPortRef notificationPort;
      IOReturn kret;

      notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
      CFRunLoopAddSource(CFRunLoopGetCurrent(),
            IONotificationPortGetRunLoopSource(notificationPort),
            kCFRunLoopDefaultMode);

      matchingDictionary = IOServiceMatching("IOPCCard16Device");
      if (!matchingDictionary)
      {
            Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed");
      }
      matchingDictionary =
            (CFMutableDictionaryRef) CFRetain(matchingDictionary);

      kret = IOServiceAddMatchingNotification(notificationPort,
            kIOMatchedNotification,
            matchingDictionary, HPDeviceAppeared, NULL, &deviceAddedIterator);
      if (kret)
      {
            Log2(PCSC_LOG_ERROR,
                  "IOServiceAddMatchingNotification()-1 failed with code %d", kret);
      }
      HPDeviceAppeared(NULL, deviceAddedIterator);

      kret = IOServiceAddMatchingNotification(notificationPort,
            kIOTerminatedNotification,
            matchingDictionary,
            HPDeviceDisappeared, NULL, &deviceRemovedIterator);
      if (kret)
      {
            Log2(PCSC_LOG_ERROR,
                  "IOServiceAddMatchingNotification()-2 failed with code %d", kret);
      }
      HPDeviceDisappeared(NULL, deviceRemovedIterator);
}

/*
 * Thread runner (does not return).
 */
static void HPDeviceNotificationThread(void)
{
      HPEstablishUSBNotification();
      HPEstablishPCCardNotification();
      CFRunLoopRun();
}

/*
 * Scans the hotplug driver directory and looks in the system for
 * matching devices.
 * Adds or removes matching readers as necessary.
 */
LONG HPSearchHotPluggables(void)
{
      HPDriver *drivers = HPDriversGetFromDirectory(PCSCLITE_HP_DROPDIR);

      if (!drivers)
            return 1;

      HPDeviceList devices = NULL;

      if (HPDriversMatchUSBDevices(drivers, &devices))
            return -1;

      if (HPDriversMatchPCCardDevices(drivers, &devices))
            return -1;

      HPDevice *a;

      for (a = devices; a; a = a->m_next)
      {
            int found = FALSE;
            HPDevice *b;

            for (b = sDeviceList; b; b = b->m_next)
            {
                  if (HPDeviceEquals(a, b))
                  {
                        found = TRUE;
                        break;
                  }
            }
            if (!found)
            {
                  char deviceName[MAX_DEVICENAME];

                  /* the format should be "usb:%04x/%04x" but Apple uses the
                   * friendly name instead */
                  snprintf(deviceName, sizeof(deviceName),
                        "%s", a->m_driver->m_friendlyName);
                  deviceName[sizeof(deviceName)-1] = '\0';

                  RFAddReader(a->m_driver->m_friendlyName,
                        PCSCLITE_HP_BASE_PORT + a->m_address, a->m_driver->m_libPath,
                        deviceName);
            }
      }

      for (a = sDeviceList; a; a = a->m_next)
      {
            int found = FALSE;
            HPDevice *b;

            for (b = devices; b; b = b->m_next)
            {
                  if (HPDeviceEquals(a, b))
                  {
                        found = TRUE;
                        break;
                  }
            }
            if (!found)
            {
                  RFRemoveReader(a->m_driver->m_friendlyName,
                        PCSCLITE_HP_BASE_PORT + a->m_address);
            }
      }

      HPDeviceListRelease(sDeviceList);
      sDeviceList = devices;
      HPDriverVectorRelease(drivers);

      return 0;
}


pthread_t sHotplugWatcherThread;

/*
 * Sets up callbacks for device hotplug events.
 */
ULONG HPRegisterForHotplugEvents(void)
{
      ThreadCreate(&sHotplugWatcherThread,
            THREAD_ATTR_DEFAULT,
            (PCSCLITE_THREAD_FUNCTION( )) HPDeviceNotificationThread, NULL);

      return 0;
}

LONG HPStopHotPluggables(void)
{
      return 0;
}

void HPReCheckSerialReaders(void)
{
}

#endif      /* __APPLE__ */


Generated by  Doxygen 1.6.0   Back to index