#include <IOKitLib.h>
#include <IOCFPlugIn.h>
#include <USB.h>
#include <USBSpec.h>
#include <IOUSBLib.h>
#include <string.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFPlugIn.h>
#include <CoreFoundation/CFBundle.h>
#include <CoreFoundation/CFString.h>
#include <CoreFoundation/CFURL.h>
#include <stdio.h>
#include "config.h"
#include "wintypes.h"
#include "pcsclite.h"
#include "debuglog.h"
#include "readerfactory.h"
#include "thread_generic.h"
#include "sys_generic.h"
#include "winscard_msg.h"
#define PCSCLITE_HP_DROPDIR "/usr/local/pcsc/drivers/"
#define PCSCLITE_HP_MAX_IDENTICAL_READERS 16
#define PCSCLITE_HP_MAX_DRIVERS 20
LONG HPAddHotPluggable(int, unsigned long);
LONG HPRemoveHotPluggable(int, unsigned long);
LONG HPSetupHotPlugDevice();
void HPEstablishUSBNotifications();
void RawDeviceAdded(void *, io_iterator_t);
void RawDeviceRemoved(void *, io_iterator_t);
extern PCSCLITE_MUTEX usbNotifierMutex;
static io_iterator_t gRawAddedIter;
static io_iterator_t gRawRemovedIter;
static IONotificationPortRef gNotifyPort;
static struct _bundleTracker
{
int addrList[PCSCLITE_HP_MAX_IDENTICAL_READERS];
CFMutableDictionaryRef matchingDict;
}
bundleTracker[PCSCLITE_HP_MAX_DRIVERS];
static mach_port_t masterPort;
static CFURLRef pluginDirURL;
static LONG hpManu_id, hpProd_id;
static CFArrayRef bundleArray;
static int bundleArraySize;
static CFBundleRef currBundle;
static CFDictionaryRef bundleInfoDict;
static PCSCLITE_THREAD_T usbNotifyThread;
void RawDeviceAdded(void *refCon, io_iterator_t iterator)
{
kern_return_t kr;
io_service_t obj;
while (obj = IOIteratorNext(iterator))
{
if (refCon == NULL)
{
SYS_MutexLock(&usbNotifierMutex);
HPSetupHotPlugDevice();
SYS_MutexUnLock(&usbNotifierMutex);
}
kr = IOObjectRelease(obj);
}
}
void RawDeviceRemoved(void *refCon, io_iterator_t iterator)
{
kern_return_t kr;
io_service_t obj;
while (obj = IOIteratorNext(iterator))
{
if (refCon == NULL)
{
SYS_MutexLock(&usbNotifierMutex);
HPSetupHotPlugDevice();
SYS_MutexUnLock(&usbNotifierMutex);
}
kr = IOObjectRelease(obj);
}
}
void HPEstablishUSBNotifications()
{
mach_port_t tmpMasterPort;
const char *cStringValue;
CFStringRef propertyString;
kern_return_t kr;
CFRunLoopSourceRef runLoopSource;
int i;
kr = IOMasterPort(MACH_PORT_NULL, &tmpMasterPort);
if (kr || !tmpMasterPort)
{
printf("ERR: Couldn't create a master IOKit Port(%08x)\n", kr);
return;
}
for (i = 0; i < bundleArraySize; i++)
{
currBundle = (CFBundleRef) CFArrayGetValueAtIndex(bundleArray, i);
bundleInfoDict = CFBundleGetInfoDictionary(currBundle);
propertyString = CFDictionaryGetValue(bundleInfoDict,
CFSTR("ifdVendorID"));
if (propertyString == 0)
{
DebugLogA
("HPEstablishUSBNotifications: No vendor id in bundle.");
continue;
}
cStringValue = CFStringGetCStringPtr(propertyString,
CFStringGetSystemEncoding());
hpManu_id = strtoul(cStringValue, 0, 16);
propertyString = CFDictionaryGetValue(bundleInfoDict,
CFSTR("ifdProductID"));
if (propertyString == 0)
{
DebugLogA
("HPEstablishUSBNotifications: No product id in bundle.");
continue;
}
cStringValue = CFStringGetCStringPtr(propertyString,
CFStringGetSystemEncoding());
hpProd_id = strtoul(cStringValue, 0, 16);
bundleTracker[i].matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
if (!bundleTracker[i].matchingDict)
{
DebugLogA
("HPEstablishUSBNotifications: Can't make USBMatch dict.");
continue;
}
CFDictionarySetValue(bundleTracker[i].matchingDict,
CFSTR(kUSBVendorName),
CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt32Type,
&hpManu_id));
CFDictionarySetValue(bundleTracker[i].matchingDict,
CFSTR(kUSBProductName),
CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt32Type,
&hpProd_id));
gNotifyPort = IONotificationPortCreate(tmpMasterPort);
runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource,
kCFRunLoopDefaultMode);
bundleTracker[i].matchingDict =
(CFMutableDictionaryRef) CFRetain(bundleTracker[i].matchingDict);
bundleTracker[i].matchingDict =
(CFMutableDictionaryRef) CFRetain(bundleTracker[i].matchingDict);
bundleTracker[i].matchingDict =
(CFMutableDictionaryRef) CFRetain(bundleTracker[i].matchingDict);
kr = IOServiceAddMatchingNotification(gNotifyPort,
kIOFirstMatchNotification,
bundleTracker[i].matchingDict,
RawDeviceAdded, NULL,
&gRawAddedIter);
RawDeviceAdded((void *) 1, gRawAddedIter);
kr = IOServiceAddMatchingNotification(gNotifyPort,
kIOTerminatedNotification,
bundleTracker[i].matchingDict,
RawDeviceRemoved, NULL,
&gRawRemovedIter);
RawDeviceRemoved((void *) 1, gRawRemovedIter);
}
mach_port_deallocate(mach_task_self(), tmpMasterPort);
tmpMasterPort = 0;
CFRunLoopRun();
}
LONG HPSearchHotPluggables()
{
LONG rv;
IOReturn iorv;
CFStringRef pluginDirString;
int i, j;
for (i = 0; i < PCSCLITE_HP_MAX_DRIVERS; i++)
{
for (j = 0; j < PCSCLITE_HP_MAX_IDENTICAL_READERS; j++)
{
bundleTracker[i].addrList[j] = 0;
}
}
iorv = IOMasterPort(MACH_PORT_NULL, &masterPort);
if (iorv != 0)
{
printf("ERR: Couldn't create a master IOKit Port(%08x)\n", iorv);
return -1;
}
pluginDirString = CFStringCreateWithCString(NULL, PCSCLITE_HP_DROPDIR,
kCFStringEncodingMacRoman);
if (pluginDirString == NULL)
{
printf("ERR: Couldn't create pluginDirString\n");
return -1;
}
pluginDirURL = CFURLCreateWithFileSystemPath(NULL, pluginDirString,
kCFURLPOSIXPathStyle, TRUE);
CFRelease(pluginDirString);
if (pluginDirURL == NULL)
{
printf("ERR: Couldn't create pluginDirURL\n");
return -1;
}
bundleArray = CFBundleCreateBundlesFromDirectory(NULL, pluginDirURL,
NULL);
if (bundleArray == NULL)
{
printf("ERR: Couldn't create bundleArray\n");
return -1;
}
bundleArraySize = CFArrayGetCount(bundleArray);
SYS_MutexLock(&usbNotifierMutex);
HPSetupHotPlugDevice();
SYS_MutexUnLock(&usbNotifierMutex);
rv = SYS_ThreadCreate(&usbNotifyThread, NULL,
(LPVOID) HPEstablishUSBNotifications, 0);
return rv;
}
LONG HPSetupHotPlugDevice()
{
kern_return_t kr;
io_iterator_t iter = 0;
io_service_t USBDevice = 0;
UInt32 usbAddr;
CFStringRef propertyString;
CFDictionaryRef USBMatch;
const char *cStringValue;
int i, j, k, x;
UInt32 addrHolder[PCSCLITE_HP_MAX_IDENTICAL_READERS];
for (j = 0; j < PCSCLITE_HP_MAX_IDENTICAL_READERS; j++)
{
addrHolder[j] = 0;
}
USBMatch = IOServiceMatching(kIOUSBDeviceClassName);
if (!USBMatch)
{
DebugLogA("HPSearchHotPluggables: Can't make USBMatch dict.");
return -1;
}
kr = IOServiceGetMatchingServices(masterPort, USBMatch, &iter);
if (kr)
{
DebugLogB("HPSearchHotPluggables: Can't make USBSvc iter: %x.",
kr);
if (USBMatch)
CFRelease(USBMatch);
return -1;
}
for (i = 0; i < bundleArraySize; i++)
{
currBundle = (CFBundleRef) CFArrayGetValueAtIndex(bundleArray, i);
bundleInfoDict = CFBundleGetInfoDictionary(currBundle);
if (bundleInfoDict == NULL)
{
if (USBMatch)
CFRelease(USBMatch);
return SCARD_E_NO_MEMORY;
}
propertyString = CFDictionaryGetValue(bundleInfoDict,
CFSTR("ifdVendorID"));
if (propertyString == 0)
{
if (USBMatch)
CFRelease(USBMatch);
return -1;
}
cStringValue = CFStringGetCStringPtr(propertyString,
CFStringGetSystemEncoding());
hpManu_id = strtoul(cStringValue, 0, 16);
propertyString = CFDictionaryGetValue(bundleInfoDict,
CFSTR("ifdProductID"));
if (propertyString == 0)
{
if (USBMatch)
CFRelease(USBMatch);
return 0;
}
cStringValue = CFStringGetCStringPtr(propertyString,
CFStringGetSystemEncoding());
hpProd_id = strtoul(cStringValue, 0, 16);
IOIteratorReset(iter);
j = 0;
while ((USBDevice = IOIteratorNext(iter)))
{
IOCFPlugInInterface **iodev = NULL;
IOUSBDeviceInterface **dev = NULL;
HRESULT res;
SInt32 score;
UInt16 vendor;
UInt16 product;
kr = IOCreatePlugInInterfaceForService(USBDevice,
kIOUSBDeviceUserClientTypeID,
kIOCFPlugInInterfaceID,
&iodev, &score);
if (kr || !iodev)
{
DebugLogB
("HPSearchHotPluggables: Can't make plugin intface: %x.",
kr);
SYS_Sleep(1);
kr = IOCreatePlugInInterfaceForService(USBDevice,
kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID,
&iodev, &score);
if (kr || !iodev)
{
DebugLogB
("HPSearchHotPluggables: Can't make plugin intface: %x.",
kr);
IOObjectRelease(USBDevice);
continue;
}
}
IOObjectRelease(USBDevice);
res =
(*iodev)->QueryInterface(iodev,
CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
(LPVOID) &dev);
(*iodev)->Release(iodev);
if (res || !dev)
{
DebugLogB
("HPSearchHotPluggables: Can't query interface: %x.",
res);
continue;
}
kr = (*dev)->GetDeviceVendor(dev, &vendor);
kr = (*dev)->GetDeviceProduct(dev, &product);
kr = (*dev)->GetLocationID(dev, &usbAddr);
(*dev)->Release(dev);
if ((vendor == hpManu_id) && (product == hpProd_id))
{
addrHolder[j++] = usbAddr;
}
}
for (k = 0; k < j; k++)
{
for (x = 0; x < PCSCLITE_HP_MAX_IDENTICAL_READERS; x++)
{
if (addrHolder[k] == bundleTracker[i].addrList[x])
{
break;
}
}
if (x == PCSCLITE_HP_MAX_IDENTICAL_READERS)
{
HPAddHotPluggable(i, addrHolder[k]);
} else
{
DebugLogA("HPSearchHotPluggables: Warning - reader already in list.");
}
}
for (x = 0; x < PCSCLITE_HP_MAX_IDENTICAL_READERS; x++)
{
if (bundleTracker[i].addrList[x] != 0)
{
for (k = 0; k < j; k++)
{
if (bundleTracker[i].addrList[x] == addrHolder[k])
{
break;
}
}
if (k == j)
{
HPRemoveHotPluggable(i, bundleTracker[i].addrList[x]);
}
}
}
}
if (iter)
IOObjectRelease(iter);
return 0;
}
LONG HPAddHotPluggable(int i, unsigned long usbAddr)
{
int j;
LONG rv;
const char *cStringValue, *cStringLibPath;
CFURLRef bundPathURL;
CFStringRef propertyString, cfStringURL;
propertyString = CFDictionaryGetValue(bundleInfoDict,
CFSTR("ifdFriendlyName"));
if (propertyString == 0)
{
return -1;
}
bundPathURL = CFBundleCopyBundleURL(currBundle);
cfStringURL = CFURLCopyPath(bundPathURL);
cStringLibPath = strdup(CFStringGetCStringPtr(cfStringURL,
CFStringGetSystemEncoding()));
cStringValue = strdup(CFStringGetCStringPtr(propertyString,
CFStringGetSystemEncoding()));
for (j = 0; j < PCSCLITE_HP_MAX_IDENTICAL_READERS; j++)
{
if (bundleTracker[i].addrList[j] == 0)
{
bundleTracker[i].addrList[j] = usbAddr;
break;
}
}
if (j == PCSCLITE_HP_MAX_IDENTICAL_READERS)
{
rv = SCARD_E_INSUFFICIENT_BUFFER;
} else
{
rv = RFAddReader((LPSTR) cStringValue, 0x200000 + j,
(LPSTR) cStringLibPath);
}
if (rv != SCARD_S_SUCCESS)
{
bundleTracker[i].addrList[j] = 0;
}
free((LPSTR) cStringValue);
free((LPSTR) cStringLibPath);
return rv;
}
LONG HPRemoveHotPluggable(int i, unsigned long usbAddr)
{
int j;
LONG rv;
const char *cStringValue;
CFStringRef propertyString;
propertyString = CFDictionaryGetValue(bundleInfoDict,
CFSTR("ifdFriendlyName"));
if (propertyString == 0)
{
return -1;
}
cStringValue = strdup(CFStringGetCStringPtr(propertyString,
CFStringGetSystemEncoding()));
for (j = 0; j < PCSCLITE_HP_MAX_IDENTICAL_READERS; j++)
{
if (bundleTracker[i].addrList[j] == usbAddr)
{
bundleTracker[i].addrList[j] = 0;
break;
}
}
rv = RFRemoveReader((LPSTR) cStringValue, 0x200000 + j);
free((LPSTR) cStringValue);
return rv;
}