/* * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define mach_test(expr, msg) do { \ kern_return_t err = (expr); \ if (KERN_SUCCESS != err) { \ fprintf(stderr, "%s: %s - %s(%x,%d)\n", cmdName, \ msg, mach_error_string(err), \ err, err & 0xffffff); \ fflush(stderr); \ *((char *) 0) = 0; \ } \ } while(0) #define plain_test(expr, msg) do { \ if (expr) { \ fprintf(stderr, "%s: %s\n", cmdName, msg); \ fflush(stderr); \ *((char *) 0) = 0; \ } \ } while(0) static const char *cmdName; static Boolean runAsync = 0; static volatile void usage(void) { fprintf(stderr, "Usage: %s [-a]", cmdName); fprintf(stderr, " where -a indicates async run"); exit(EX_USAGE); } static void init(int argc, const char *argv[]) { char c; // Get the command name and strip the leading dirpath if (cmdName = strrchr(argv[0], '/')) cmdName++; else cmdName = argv[0]; while ((c = getopt(argc, argv, "a")) != -1) { switch(c) { case 'a': runAsync = 1; break; case '?': default: usage(); } } } static void showDeviceInfo(IOUSBDeviceInterface **dev) { UInt8 devClass; UInt8 devSubClass; UInt8 devProtocol; UInt16 devVendor; UInt16 devProduct; UInt16 devRelNum; IOReturn kr; kr = (*dev)->GetDeviceClass(dev, &devClass); mach_test(kr, "Couldn't get class"); kr = (*dev)->GetDeviceSubClass(dev, &devSubClass); mach_test(kr, "Couldn't get subclass"); kr = (*dev)->GetDeviceProtocol(dev, &devProtocol); mach_test(kr, "Couldn't get protocol"); kr = (*dev)->GetDeviceVendor(dev, &devVendor); mach_test(kr, "Couldn't get vendor"); kr = (*dev)->GetDeviceProduct(dev, &devProduct); mach_test(kr, "Couldn't get product"); kr = (*dev)->GetDeviceReleaseNumber(dev, &devRelNum); mach_test(kr, "Couldn't get relnum"); printf("----------------------------\n"); printf("USB device\n"); printf("----------------------------\n"); printf("\tclass: %d\n", devClass); printf("\tsubclass: %d\n", devSubClass); printf("\tprotocol: %d\n", devProtocol); printf("\tVendor: %04x\n", devVendor); printf("\tProduct: %04x\n", devProduct); printf("\tRelease: %04x\n", devRelNum); } static void dosomethingtodevice(io_service_t USBDevice); static void showInterfaceInfo(IOUSBInterfaceInterface **intf) { UInt8 intfClass; UInt8 intfSubClass; UInt8 intfProtocol; UInt16 devVendor; UInt16 devProduct; UInt16 devRelNum; UInt8 configValue; UInt8 intfNumber; io_service_t USBdevice = 0; IOReturn kr; kr = (*intf)->GetInterfaceClass(intf, &intfClass); mach_test(kr, "Couldn't get class"); kr = (*intf)->GetInterfaceSubClass(intf, &intfSubClass); mach_test(kr, "Couldn't get subclass"); kr = (*intf)->GetInterfaceProtocol(intf, &intfProtocol); mach_test(kr, "Couldn't get protocol"); kr = (*intf)->GetDeviceVendor(intf, &devVendor); mach_test(kr, "Couldn't get vendor"); kr = (*intf)->GetDeviceProduct(intf, &devProduct); mach_test(kr, "Couldn't get product"); kr = (*intf)->GetDeviceReleaseNumber(intf, &devRelNum); mach_test(kr, "Couldn't get relnum"); kr = (*intf)->GetConfigurationValue(intf, &configValue); mach_test(kr, "Couldn't get configvalue"); kr = (*intf)->GetInterfaceNumber(intf, &intfNumber); mach_test(kr, "Couldn't get interface number"); kr = (*intf)->GetDevice(intf, &USBdevice); mach_test(kr, "Couldn't get device"); printf("----------------------------\n"); printf("USB interface\n"); printf("----------------------------\n"); printf("\tclass: %d\n", intfClass); printf("\tsubclass: %d\n", intfSubClass); printf("\tprotocol: %d\n", intfProtocol); printf("\tVendor: %04x\n", devVendor); printf("\tProduct: %04x\n", devProduct); printf("\tRelease: %04x\n", devRelNum); printf("\tConfigValue: %d\n", configValue); printf("\tInterfaceNumber: %d\n", intfNumber); dosomethingtodevice(USBdevice); } #if 0 static void printinquirydata(USBInquiry *d, UInt32 s) { char vendorName[sizeof(d->vendorName)+1]; char productName[sizeof(d->productName)+1]; char productRevision[sizeof(d->productRevision)+1]; char vendorSpecific[sizeof(d->vendorSpecific)+1]; int i, size; vendorName[sizeof(d->vendorName)] = '\0'; strncpy(vendorName, d->vendorName, sizeof(d->vendorName)); productName[sizeof(d->productName)] = '\0'; strncpy(productName, d->productName, sizeof(d->productName)); productRevision[sizeof(d->productRevision)] = '\0'; strncpy(productRevision, d->productRevision, sizeof(d->productRevision)); vendorSpecific[sizeof(d->vendorSpecific)] = '\0'; strncpy(vendorSpecific, d->vendorSpecific, sizeof(d->vendorSpecific)); printf("%s: Got inquiry results size = %ld\n", cmdName, s); printf(" devType = 0x%x\n", d->devType); printf(" devTypeMod = 0x%x\n", d->devTypeMod); printf(" version = 0x%x\n", d->version); printf(" format = 0x%x\n", d->format); printf(" length = 0x%x\n", d->length); printf(" reserved5 = 0x%x\n", d->reserved5); printf(" reserved6 = 0x%x\n", d->reserved6); printf(" flags = 0x%x\n", d->flags); printf(" vendorName = \"%s\"\n", vendorName); printf(" productName = \"%s\"\n", productName); printf(" productRevision = \"%s\"\n", productRevision); printf(" vendorSpecific = \"%s\"\n", vendorSpecific); size = s - ((char *) &d->moreReserved - (char *) d); if (size > 0) { printf(" moreReserved(%d) = ", size); for (i = 0; i < size; i++) { if ( !(i & 0xf) ) printf("\n"); printf("%02x ", ((UInt8 *) d->moreReserved)[i]); } printf("\n"); } } // assumes device is open static IOCDBCommandInterface ** allocCommand(IOUSBDeviceInterface **dev) { HRESULT res; IOCDBCommandInterface **cmd; printf("%s: opened device\n", cmdName); res = (*dev)->QueryInterface(dev, CFUUIDGetUUIDBytes(kIOCDBCommandInterfaceID), (LPVOID) &cmd); plain_test(res != S_OK, "Couldn't create a CDB Command"); return cmd; } // assumes device is open static void executeSyncInquiry(IOCDBCommandInterface **cmd) { UInt8 data[255]; IOVirtualRange range[1]; CDBInfo cdb; USBResults results; UInt32 seqNumber; IOReturn kr; bzero(data, sizeof(data)); range[0].address = (IOVirtualAddress) data; range[0].length = sizeof(data); bzero(&cdb, sizeof(cdb)); cdb.cdbLength = 6; cdb.cdb[0] = kUSBCmdInquiry; cdb.cdb[4] = sizeof(data); kr = (*cmd)->setAndExecuteCommand(cmd, &cdb, sizeof(data), range, sizeof(range)/sizeof(range[0]), /* isWrite */ 0, /* timeoutMS */ 0, /* target */ 0, /* callback */ 0, /* refcon */ 0, &seqNumber); if (kr == kIOReturnUnderrun) printf("%s: Command Underrun\n", cmdName); else mach_test(kr, "Couldn't execute a CDB Command"); kr = (*cmd)->getResults(cmd, &results); if (kr == kIOReturnUnderrun) printf("%s: getResults Underrun\n", cmdName); else mach_test(kr, "Couldn't get results of a command"); printinquirydata((USBInquiry *) data, results.bytesTransferred); } #endif static void dosomethingtodevice(io_service_t USBDevice) { io_name_t className; IOCFPlugInInterface **iodev; IOUSBDeviceInterface **dev; HRESULT res; kern_return_t kr; SInt32 score; printf("Doing something to device: %d (%08x)\n", USBDevice, USBDevice); mach_test(IOObjectGetClass(USBDevice, className), "Failed to get class name"); printf("%s: found device type %s\n", cmdName, className); kr = IOCreatePlugInInterfaceForService(USBDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score); //mach_test(kr, "Couldn't create a plug in"); if (kr) printf("--unable to create plugin\n"); else printf("!!PLUGIN SUCCESS\n"); res = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev); plain_test(res != S_OK, "Couldn't create USB Device interface"); (*iodev)->Release(iodev); showDeviceInfo(dev); #if 0 kr = (*dev)->open(dev); if (kIOReturnSuccess != kr) printf("%s: failed to open 0x%08x\n", cmdName, kr); else { IOCDBCommandInterface **cmd = allocCommand(dev); if (cmd) { executeSyncInquiry(cmd); (*cmd)->Release(cmd); } (*dev)->close(dev); } (*dev)->Release(dev); #endif IOObjectRelease(USBDevice); } static void dosomethingtointerface(io_service_t USBInterface) { io_name_t className; IOCFPlugInInterface **iodev; IOUSBInterfaceInterface **intf; HRESULT res; kern_return_t kr; SInt32 score; printf("Doing something to interface: %d (%08x)\n", USBInterface, USBInterface); mach_test(IOObjectGetClass(USBInterface, className), "Failed to get class name"); printf("%s: found device type %s\n", cmdName, className); kr = IOCreatePlugInInterfaceForService(USBInterface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score); //mach_test(kr, "Couldn't create a plug in"); if (kr) { printf("--unable to create plugin\n"); return; } else printf("!!PLUGIN SUCCESS\n"); res = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID) &intf); plain_test(res != S_OK, "Couldn't create USB Interface interface"); (*iodev)->Release(iodev); showInterfaceInfo(intf); #if 0 kr = (*dev)->open(dev); if (kIOReturnSuccess != kr) printf("%s: failed to open 0x%08x\n", cmdName, kr); else { IOCDBCommandInterface **cmd = allocCommand(dev); if (cmd) { executeSyncInquiry(cmd); (*cmd)->Release(cmd); } (*dev)->close(dev); } (*dev)->Release(dev); #endif IOObjectRelease(USBInterface); } static void findUSBDevices(void) { // this function will interate through all IOUSBDevice nubs and spit out information about them mach_port_t masterPort = 0; CFDictionaryRef USBMatch = 0; io_iterator_t iter = 0; io_service_t USBDevice = 0; mach_test(IOMasterPort(bootstrap_port, &masterPort), "Couldn't create a master IOKit Port"); USBMatch = IOServiceMatching(kIOUSBDeviceClassName); plain_test(!USBMatch, "Can't create a USB matching dictionary"); mach_test(IOServiceGetMatchingServices(masterPort, USBMatch, &iter), "Can't create a USB Service iterator"); USBMatch = 0; // Finish hand off of USBMatch dictionary while ( (USBDevice = IOIteratorNext(iter)) ) dosomethingtodevice(USBDevice); if (iter) { IOObjectRelease(iter); iter = 0; } if (USBMatch) { CFRelease(USBMatch); USBMatch = 0; } if (masterPort) { mach_port_deallocate(mach_task_self(), masterPort); masterPort = 0; } } static void findUSBInterfaces(void) { mach_port_t masterPort = 0; CFDictionaryRef USBMatch = 0; io_iterator_t iter = 0; io_service_t USBInterface = 0; // this function will iterate through all IOUSBInterface nubs and spit out information // about them mach_test(IOMasterPort(bootstrap_port, &masterPort), "Couldn't create a master IOKit Port"); USBMatch = IOServiceMatching(kIOUSBInterfaceClassName); plain_test(!USBMatch, "Can't create a USB matching dictionary"); mach_test(IOServiceGetMatchingServices(masterPort, USBMatch, &iter), "Can't create a USB Service iterator"); USBMatch = 0; // Finish hand off of USBMatch dictionary while ( (USBInterface = IOIteratorNext(iter)) ) dosomethingtointerface(USBInterface); if (iter) { IOObjectRelease(iter); iter = 0; } if (USBMatch) { CFRelease(USBMatch); USBMatch = 0; } if (masterPort) { mach_port_deallocate(mach_task_self(), masterPort); masterPort = 0; } } static unsigned char desc[1024]; CFRunLoopSourceRef cfSource; void MyCallBackFunction(IOUSBConfigurationDescriptorPtr desc, IOReturn result, void *arg0) { printf("MyCallbackfunction: %d, %d, %d\n", (int)desc, (int)result, (int)arg0); CFRunLoopStop(CFRunLoopGetCurrent()); } static void findUnconfiguredDevices(void) { // this function will interate through all IOUSBDevice nubs and spit out information about them mach_port_t masterPort = 0; CFDictionaryRef USBMatch = 0; io_iterator_t iter = 0; io_service_t USBDevice = 0; kern_return_t kr; // first create a master_port for my task kr = IOMasterPort(bootstrap_port, &masterPort); if (kr || !masterPort) { printf("ERR: Couldn't create a master IOKit Port(%08x)\n", kr); return; } USBMatch = IOServiceMatching(kIOUSBDeviceClassName); if (!USBMatch) { printf("Can't create a USB matching dictionary\n"); mach_port_deallocate(mach_task_self(), masterPort); return; } // create an iterator over all matching IOService nubs kr = IOServiceGetMatchingServices(masterPort, USBMatch, &iter); if (kr) { printf("Can't create a USB Service iterator(%08x)\n", kr); CFRelease(USBMatch); mach_port_deallocate(mach_task_self(), masterPort); return; } while ( (USBDevice = IOIteratorNext(iter)) ) { IOCFPlugInInterface **iodev; IOUSBDeviceInterface **dev; HRESULT res; SInt32 score; UInt8 numConf; UInt8 curConf = 0; UInt8 devClass = 0, devSubClass = 0; int i; IOUSBConfigurationDescriptorPtr confDesc; kr = IOCreatePlugInInterfaceForService(USBDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score); IOObjectRelease(USBDevice); // done with the device object now that I have the plugin if (kr || !iodev) { printf("unable to create a plugin (%08x)\n", kr); continue; } // i have the device plugin. I need the device interface res = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&dev); (*iodev)->Release(iodev); // done with this if (res || !dev) { printf("couldn't create a device interface (%08x)\n", (int)res); continue; } // technically should check these kr values kr = (*dev)->GetConfiguration(dev, &curConf); kr = (*dev)->GetDeviceClass(dev, &devClass); kr = (*dev)->GetDeviceSubClass(dev, &devSubClass); if (curConf != 0) { printf("found configured device (class = %d, subclass = %d)\n", devClass, devSubClass); (*dev)->Release(dev); continue; } printf("found UNCONFIGURED device (class = %d, subclass = %d)\n", devClass, devSubClass); // need to open the device in order to change its state kr = (*dev)->USBDeviceOpen(dev); if (kr) { printf("unable to open device: %08x\n", kr); continue; } kr = (*dev)->GetNumberOfConfigurations(dev, &numConf); printf("\tfound %d configurations\n", numConf); for (i=0; iGetConfigurationDescriptorPtr(dev, i, &confDesc); if (kr) { printf("\tunable to get config descriptor for index %d\n", i); continue; } printf("\t--------------------------------\n"); printf("\tConfig Descriptor index #%d\n", i); printf("\t--------------------------------\n"); printf("\tTotal Length: %d\n", USBToHostWord(confDesc->wTotalLength)); printf("\tConfig Value: %d\n", confDesc->bConfigurationValue); printf("\t--------------------------------\n"); if (i==0) { printf("\tsetting the config to %d\n", confDesc->bConfigurationValue); kr = (*dev)->SetConfiguration(dev, confDesc->bConfigurationValue); kr = (*dev)->GetConfiguration(dev, &curConf); if (curConf != confDesc->bConfigurationValue) printf("\t\tSET CONFIG FAILED!\n"); } } printf("Trying to do a device request\n"); { IOUSBDevRequest request; // create a run loop to catch the async notifications kr = (*dev)->CreateDeviceAsyncEventSource(dev, &cfSource); CFRunLoopAddSource(CFRunLoopGetCurrent(), cfSource, kCFRunLoopDefaultMode); desc[0]='H'; desc[1]='i'; request.bmRequestType = (kUSBIn << kUSBRqDirnShift) | (kUSBStandard << kUSBRqTypeShift) | kUSBDevice; request.bRequest = kUSBRqGetDescriptor; request.wValue = (kUSBConfDesc << 8) + 0; request.wIndex = 0; request.wLength = USBToHostWord(confDesc->wTotalLength); request.pData = desc; kr = (*dev)->DeviceRequestAsync(dev, &request, (IOAsyncCallback1)MyCallBackFunction, (void*)desc); if (kr) printf("device request failed\n"); else { printf("about to call RunLoopRun\n"); CFRunLoopRun(); printf("RunLoopRun returned\n"); } CFRunLoopRemoveSource(CFRunLoopGetCurrent(), cfSource, kCFRunLoopDefaultMode); } kr = (*dev)->USBDeviceClose(dev); kr = (*dev)->Release(dev); } if (iter) { IOObjectRelease(iter); iter = 0; } if (USBMatch) { CFRelease(USBMatch); USBMatch = 0; } if (masterPort) { mach_port_deallocate(mach_task_self(), masterPort); masterPort = 0; } } static void findVendorSpecificInterfaces(void) { // this function will interate through all IOUSBDevice nubs and spit out information about them mach_port_t masterPort = 0; CFDictionaryRef USBMatch = 0; io_iterator_t iter = 0; io_service_t USBInterface = 0; kern_return_t kr; // first create a master_port for my task kr = IOMasterPort(bootstrap_port, &masterPort); if (kr || !masterPort) { printf("ERR: Couldn't create a master IOKit Port(%08x)\n", kr); return; } USBMatch = IOServiceMatching(kIOUSBInterfaceClassName); if (!USBMatch) { printf("Can't create a USB matching dictionary\n"); mach_port_deallocate(mach_task_self(), masterPort); return; } // create an iterator over all matching IOService nubs kr = IOServiceGetMatchingServices(masterPort, USBMatch, &iter); if (kr) { printf("Can't create a USB Service iterator(%08x)\n", kr); CFRelease(USBMatch); mach_port_deallocate(mach_task_self(), masterPort); return; } while ( (USBInterface = IOIteratorNext(iter)) ) { IOCFPlugInInterface **iodev=NULL; IOUSBInterfaceInterface **intf=NULL; HRESULT res; SInt32 score; int i; UInt16 vendor; UInt16 product; UInt8 numPipes; kr = IOCreatePlugInInterfaceForService(USBInterface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score); IOObjectRelease(USBInterface); // done with the device object now that I have the plugin if (kr || !iodev) { printf("unable to create a plugin (%08x)\n", kr); continue; } // i have the device plugin. I need the device interface res = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)&intf); (*iodev)->Release(iodev); // done with this if (res || !intf) { printf("couldn't create a device interface (%08x)\n", (int)res); continue; } // technically should check these kr values kr = (*intf)->GetDeviceVendor(intf, &vendor); kr = (*intf)->GetDeviceProduct(intf, &product); if ((vendor != 1215) || (product != 275)) { printf("found interface i didn't want (vendor = %d, product = %d)\n", vendor, product); (*intf)->Release(intf); continue; } printf("found my interface (vendor = %d, product = %d)\n", vendor, product); // need to open the interface in order to change its state kr = (*intf)->USBInterfaceOpen(intf); if (kr) { printf("unable to open interface: %08x\n", kr); continue; } kr = (*intf)->GetNumEndpoints(intf, &numPipes); printf("\tfound %d pipes\n", numPipes); for (i=1; i<=numPipes; i++) { UInt8 number, direction, transferType, interval; UInt16 mps; kr = (*intf)->GetPipeProperties(intf, i, &direction, &number, &transferType, &mps, &interval); printf("pipe %d: dir=%d, num=%d, tt=%d, mps=%d, interval=%d\n", i, direction, number, transferType, mps, interval); } kr = (*intf)->USBInterfaceClose(intf); kr = (*intf)->Release(intf); } if (iter) { IOObjectRelease(iter); iter = 0; } if (USBMatch) { CFRelease(USBMatch); USBMatch = 0; } if (masterPort) { mach_port_deallocate(mach_task_self(), masterPort); masterPort = 0; } } __private_extern__ int main(int argc, const char *argv[]) { init(argc, argv); findUSBDevices(); // findUSBInterfaces(); //findUnconfiguredDevices(); //findVendorSpecificInterfaces(); exit(EX_OK); }