/*********************************************************** / Title: usbserial.c / Author: David Corcoran / Purpose: Abstracts usb API to serial like calls / License: See file COPYING / $Id: usbserial_mosx.c,v 1.15 2004/01/20 13:58:57 rousseau Exp $ ************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "Config.h" #include "pcscdefines.h" #include "GemCore.h" #include "GCdebug.h" #include "usbserial.h" #define USBMAX_READERS (PCSCLITE_MAX_READERS) // Read time out in milliseconds unsigned long ReadTimeOut = 60000; /* Change the following to uniquely match your reader. */ /*enum { kMyDeviceClass = kIOUSBAnyClass, kMyDeviceSubClass = kIOUSBAnySubClass, kMyDeviceProtocol = kIOUSBAnyProtocol }; */ static int iInitialized = FALSE; typedef struct _intFace { IOUSBInterfaceInterface182 **iface; IOUSBDeviceInterface182 **dev; UInt32 usbAddr; UInt8 inPipeRef; UInt8 outPipeRef; } intrFace, *pIntrFace; static pIntrFace intFace[USBMAX_READERS]; void FreeintFace(); void FreeintFace() { int i; for (i=0; i < USBMAX_READERS; i++) { free(intFace[i]); } } status_t OpenUSB( DWORD lun, DWORD Channel) { CFMutableDictionaryRef USBMatch = 0; io_iterator_t iter = 0; io_service_t USBDevice = 0; io_service_t USBIface = 0; kern_return_t kr; io_iterator_t iterB = 0; SInt32 score; IOUSBFindInterfaceRequest findInterface; IOCFPlugInInterface **iodev=NULL; IOCFPlugInInterface **iodevB=NULL; HRESULT res; DWORD rdrLun; SInt32 hpManu_id, hpProd_id; UInt32 usbAddr,usbAddrtest; short iFound; int i; IOUSBConfigurationDescriptorPtr confDesc; UInt8 intfNumEndpoints; UInt8 direction, number, transferType, interval; UInt16 maxPacketSize; mach_port_t masterPort; CFBundleRef myBundle; CFStringRef propertyString; CFDictionaryRef bundleInfoDict; const char *cStringValue; DEBUG_INFO(""); hpManu_id = 0; hpProd_id = 0; // Look for a bundle using its identifier if (!(myBundle = CFBundleGetBundleWithIdentifier(CFSTR("free.pcsc.GemPC430") ))) { DEBUG_CRITICAL("Bundle Identifier not found"); return STATUS_UNSUCCESSFUL; } bundleInfoDict = CFBundleGetInfoDictionary(myBundle); if (bundleInfoDict == NULL) { DEBUG_CRITICAL("Bundle InfoDic error"); return STATUS_UNSUCCESSFUL; } propertyString = CFDictionaryGetValue(bundleInfoDict, CFSTR("ifdVendorID")); if (propertyString == NULL) { DEBUG_CRITICAL("Bundle InfoDic error: ifdVendorID not found"); return STATUS_UNSUCCESSFUL; } cStringValue = CFStringGetCStringPtr(propertyString, CFStringGetSystemEncoding()); hpManu_id = strtoul(cStringValue, 0, 16); propertyString = CFDictionaryGetValue(bundleInfoDict, CFSTR("ifdProductID")); if (propertyString == 0) { DEBUG_CRITICAL("Bundle InfoDic error: ifdProductID not found"); return STATUS_UNSUCCESSFUL; } cStringValue = CFStringGetCStringPtr(propertyString, CFStringGetSystemEncoding()); hpProd_id = strtoul(cStringValue, 0, 16); propertyString = CFDictionaryGetValue(bundleInfoDict, CFSTR("ifdReadTimeOut")); if (propertyString == 0) { DEBUG_CRITICAL("Bundle InfoDic error: could find ifdReadTimeOut, keep default"); } else { cStringValue = CFStringGetCStringPtr(propertyString, CFStringGetSystemEncoding()); ReadTimeOut = strtoul(cStringValue, 0, 10); } DEBUG_CRITICAL2("Driver configured to detect Vendor ID = %04X", hpManu_id); DEBUG_CRITICAL2("Driver configured to detect Product ID = %04X", hpProd_id); iFound = FALSE; rdrLun = lun >> 16; if ( iInitialized == FALSE ) { for (i=0; i < USBMAX_READERS; i++) { intFace[i] = (pIntrFace)malloc(sizeof(intrFace)); if (!intFace[i]) { /* Malloc failed! */ DEBUG_CRITICAL("Couldn't malloc structure: "); return STATUS_UNSUCCESSFUL; } (intFace[i])->usbAddr = 0; (intFace[i])->dev = NULL; (intFace[i])->iface = NULL; (intFace[i])->inPipeRef = 0; (intFace[i])->outPipeRef = 0; } iInitialized = TRUE; } /* first create a master_port for my task */ kr = IOMasterPort(bootstrap_port, &masterPort); if (kr || !masterPort) { DEBUG_CRITICAL2("Couldn't create a master IOKit Port (0x%08X)", kr); FreeintFace(); return STATUS_UNSUCCESSFUL; } USBMatch = IOServiceMatching(kIOUSBDeviceClassName); if (!USBMatch) { DEBUG_CRITICAL("Can't create a USB matching dictionary"); mach_port_deallocate(mach_task_self(), masterPort); FreeintFace(); return STATUS_UNSUCCESSFUL; } CFDictionarySetValue(USBMatch, CFSTR(kUSBVendorName), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &hpManu_id)); CFDictionarySetValue(USBMatch, CFSTR(kUSBProductName), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &hpProd_id)); /* create an iterator over all matching IOService nubs */ kr = IOServiceGetMatchingServices(masterPort, USBMatch, &iter); if (kr) { DEBUG_CRITICAL2("Can't create a USB Service iterator (0x%08X)", kr); //? CFRelease(USBMatch); mach_port_deallocate(mach_task_self(), masterPort); return STATUS_UNSUCCESSFUL; } // masterPort not used any more mach_port_deallocate(mach_task_self(), masterPort); while ( (USBDevice = IOIteratorNext(iter)) ) { kr = IOCreatePlugInInterfaceForService(USBDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score); IOObjectRelease(USBDevice); /* done with the device object now */ if (kr || !iodev) { DEBUG_CRITICAL2("unable to create a plugin (0x%08X)", kr); continue; } /* i have the device plugin. I need the device interface */ res = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&(intFace[rdrLun])->dev); //(*iodev)->Release(iodev); if (res || !(intFace[rdrLun])->dev) { DEBUG_CRITICAL2("Couldn't create a device interface (0x%08X)", (int)res); continue; } kr = (*(intFace[rdrLun])->dev)->GetLocationID(((intFace[rdrLun])->dev), &usbAddr); for (i=0; i < USBMAX_READERS; i++) { if ( usbAddr == (intFace[i])->usbAddr ) { iFound = TRUE; break; } } if ( iFound ) { iFound = FALSE; continue; } /* We found it now lets break out of the loop */ break; } if ((intFace[rdrLun])->dev == NULL) { /* Device not found */ CFRelease(USBMatch); return STATUS_UNSUCCESSFUL; } kr = (*(intFace[rdrLun])->dev)->GetLocationID(((intFace[rdrLun])->dev), &usbAddrtest); kr = (*(intFace[rdrLun])->dev)->USBDeviceOpen(((intFace[rdrLun])->dev)); if (kr == kIOReturnExclusiveAccess) { sleep(1); // Try to re-open in case Classic is using the device if( kr = (*(intFace[rdrLun])->dev)->USBDeviceOpenSeize(((intFace[rdrLun])->dev)) ) { DEBUG_CRITICAL2("unable to open device: 0x%08X", kr); (*(intFace[rdrLun])->dev)->Release(((intFace[rdrLun])->dev)); return STATUS_UNSUCCESSFUL; } } else { if ( kr != kIOReturnSuccess) { DEBUG_CRITICAL2("unable to open device, not kIOReturnExclusiveAccess: 0x%08X", kr); (*(intFace[rdrLun])->dev)->Release(((intFace[rdrLun])->dev)); return STATUS_UNSUCCESSFUL; } } kr = (*(intFace[rdrLun])->dev)->GetConfigurationDescriptorPtr(((intFace[rdrLun])->dev), 0, &confDesc); if (kr) { DEBUG_CRITICAL("ERR: unable to get the configuration"); (*(intFace[rdrLun])->dev)->USBDeviceClose(((intFace[rdrLun])->dev)); (*(intFace[rdrLun])->dev)->Release(((intFace[rdrLun])->dev)); return STATUS_UNSUCCESSFUL; } (*(intFace[rdrLun])->dev)->ResetDevice(((intFace[rdrLun])->dev)); kr = (*(intFace[rdrLun])->dev)->SetConfiguration(((intFace[rdrLun])->dev), confDesc->bConfigurationValue); if (kr) { DEBUG_CRITICAL("ERR: unable to set the configuration"); (*(intFace[rdrLun])->dev)->USBDeviceClose(((intFace[rdrLun])->dev)); (*(intFace[rdrLun])->dev)->Release(((intFace[rdrLun])->dev)); return STATUS_UNSUCCESSFUL; } /* Time to find the first interface */ findInterface.bInterfaceClass = kIOUSBFindInterfaceDontCare; findInterface.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; findInterface.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; findInterface.bAlternateSetting = kIOUSBFindInterfaceDontCare; kr = (*(intFace[rdrLun])->dev)->CreateInterfaceIterator( ((intFace[rdrLun])->dev), &findInterface, &iterB ); USBIface = IOIteratorNext(iterB); if ( USBIface == 0 ) { DEBUG_CRITICAL("No interface found"); return STATUS_UNSUCCESSFUL; } score = 0; /* Create the plugin for the interface service */ kr = IOCreatePlugInInterfaceForService(USBIface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodevB, &score); res = (*iodev)->QueryInterface(iodevB, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)&(intFace[rdrLun])->iface); (intFace[rdrLun])->usbAddr = usbAddr; /* Open the interface to open all the pipes */ kr = (*(intFace[rdrLun])->iface)->USBInterfaceOpen((intFace[rdrLun])->iface); if (kr != kIOReturnSuccess ) { DEBUG_CRITICAL2("unable to open device: 0x%08X", kr); return STATUS_UNSUCCESSFUL; } if (iter) { IOObjectRelease(iter); iter = 0; } // Get nb of end points kr = (*(intFace[rdrLun])->iface)->GetNumEndpoints((intFace[rdrLun])->iface, &intfNumEndpoints); if (kr != kIOReturnSuccess ) { DEBUG_CRITICAL2("unable to get number of end points: 0x%08X", kr); return STATUS_UNSUCCESSFUL; } // pipes are one based, since zero is the default control pipe for (i=1; i <= intfNumEndpoints; i++) { kr = (*(intFace[rdrLun])->iface)->GetPipeProperties((intFace[rdrLun])->iface, i, &direction, &number, &transferType, &maxPacketSize, &interval); if (kr != kIOReturnSuccess ) { DEBUG_CRITICAL2("unable to get pipe properties: 0x%08X", kr); return STATUS_UNSUCCESSFUL; } if (transferType != kUSBBulk) { continue; } if ((direction == kUSBIn) && !((intFace[rdrLun])->inPipeRef)) { (intFace[rdrLun])->inPipeRef = i; } if ((direction == kUSBOut) && !((intFace[rdrLun])->outPipeRef)) { (intFace[rdrLun])->outPipeRef = i; } } if ( !((intFace[rdrLun])->outPipeRef) ) { DEBUG_CRITICAL2("unable to get outPipe: 0x%08X", kr); CloseUSB(lun); return STATUS_UNSUCCESSFUL; } if (!( (intFace[rdrLun])->inPipeRef)) { DEBUG_CRITICAL2("unable to get inPipe: 0x%08X", kr); CloseUSB(lun); return STATUS_UNSUCCESSFUL; } DEBUG_CRITICAL2("New reader found at USB address: %08X", (intFace[rdrLun])->usbAddr); return STATUS_SUCCESS; } status_t WriteUSB( DWORD lun, DWORD length, unsigned char *buffer ) { IOReturn iorv; DWORD rdrLun; rdrLun = lun >> 16; DEBUG_XXD("Attempt to write: ", buffer, length); /* Make sure the pipe is OK */ iorv = (*(intFace[rdrLun])->iface)->GetPipeStatus( (intFace[rdrLun])->iface, (intFace[rdrLun])->outPipeRef ); if ( iorv != kIOReturnSuccess ) { return STATUS_UNSUCCESSFUL; } /* Write the data */ iorv = (*(intFace[rdrLun])->iface)->WritePipe((intFace[rdrLun])->iface, (intFace[rdrLun])->outPipeRef, buffer, length); if ( iorv != kIOReturnSuccess ) { return STATUS_UNSUCCESSFUL; } return STATUS_SUCCESS; } status_t ReadUSB( DWORD lun, DWORD *length, unsigned char *buffer ) { IOReturn iorv; UInt32 recvLen; UInt32 noDataTO, completeTO; DWORD rdrLun; rdrLun = lun >> 16; DEBUG_COMM2("Attempt to read %ld bytes", *length); /* Make sure the pipe is OK */ iorv = (*(intFace[rdrLun])->iface)->GetPipeStatus( (intFace[rdrLun])->iface, (intFace[rdrLun])->inPipeRef ); if ( iorv != kIOReturnSuccess ) { return STATUS_UNSUCCESSFUL; } /* Try to read up to 256 bytes */ recvLen = 256; completeTO = ReadTimeOut; noDataTO = ReadTimeOut; iorv = (*(intFace[rdrLun])->iface)->ReadPipeTO( (intFace[rdrLun])->iface, (intFace[rdrLun])->inPipeRef, buffer, &recvLen, noDataTO, completeTO); if ( iorv != 0 ) { (*(intFace[rdrLun])->dev)->ResetDevice(((intFace[rdrLun])->dev)); return STATUS_UNSUCCESSFUL; } DEBUG_XXD("received: ", buffer, recvLen); *length = recvLen; return STATUS_SUCCESS; } status_t CloseUSB( DWORD lun ) { IOReturn iorv; DWORD rdrLun; rdrLun = lun >> 16; // Reset struct (intFace[rdrLun])->usbAddr = 0; (intFace[rdrLun])->outPipeRef = 0; (intFace[rdrLun])->inPipeRef = 0; /* Close the interface and rid the iterator */ iorv = (*(intFace[rdrLun])->iface)->USBInterfaceClose( (intFace[rdrLun])->iface ); if (iorv) { DEBUG_CRITICAL2("ERR: Couldn't close interface (%08x)", (int)iorv); } /* Release the interface */ (*(intFace[rdrLun])->iface)->Release((intFace[rdrLun])->iface); iorv = (*(intFace[rdrLun])->dev)->USBDeviceClose((intFace[rdrLun])->dev); if (iorv) { DEBUG_CRITICAL2("ERR: Couldn't close device (%08x)", (int)iorv); } (*(intFace[rdrLun])->dev)->Release((intFace[rdrLun])->dev); if ( iorv != kIOReturnSuccess ) { return STATUS_UNSUCCESSFUL; } return STATUS_SUCCESS; }