diff options
author | Dima Zavin <dima@android.com> | 2009-05-08 18:25:58 -0700 |
---|---|---|
committer | Dima Zavin <dima@android.com> | 2009-05-09 12:49:54 -0700 |
commit | 3fd82b8861aa410fab7785074941b459d92220c1 (patch) | |
tree | b9b6f6507bf429cb74a506ca2d4b94ba1af4835f /adb | |
parent | b3779558dcfbe99f0b9c1ef796e3728edad25672 (diff) | |
download | system_core-3fd82b8861aa410fab7785074941b459d92220c1.zip system_core-3fd82b8861aa410fab7785074941b459d92220c1.tar.gz system_core-3fd82b8861aa410fab7785074941b459d92220c1.tar.bz2 |
adb: osx: Match devices based on interface subclass and protocol
Enumerating all vendor+product id combinations is not practical.
This modifies the matching algorithm to use the adb interface
subclass/protocol instead (0x42/0x1).
Signed-off-by: Dima Zavin <dima@android.com>
Diffstat (limited to 'adb')
-rw-r--r-- | adb/adb.h | 9 | ||||
-rw-r--r-- | adb/usb_osx.c | 373 |
2 files changed, 176 insertions, 206 deletions
@@ -359,17 +359,10 @@ typedef enum { // Google's USB Vendor ID #define VENDOR_ID_GOOGLE 0x18d1 + // HTC's USB Vendor ID #define VENDOR_ID_HTC 0x0bb4 -// products for VENDOR_ID_GOOGLE -#define PRODUCT_ID_SOONER 0xd00d // Sooner bootloader -#define PRODUCT_ID_SOONER_COMP 0xdeed // Sooner composite device - -// products for VENDOR_ID_HTC -#define PRODUCT_ID_DREAM 0x0c01 // Dream bootloader -#define PRODUCT_ID_DREAM_COMP 0x0c02 // Dream composite device - void local_init(); int local_connect(int port); diff --git a/adb/usb_osx.c b/adb/usb_osx.c index 49e1eef..2d4c1a9 100644 --- a/adb/usb_osx.c +++ b/adb/usb_osx.c @@ -31,21 +31,17 @@ #define DBG D -typedef struct { - int vid; - int pid; -} VendorProduct; - -#define kSupportedDeviceCount 4 -VendorProduct kSupportedDevices[kSupportedDeviceCount] = { - { VENDOR_ID_GOOGLE, PRODUCT_ID_SOONER }, - { VENDOR_ID_GOOGLE, PRODUCT_ID_SOONER_COMP }, - { VENDOR_ID_HTC, PRODUCT_ID_DREAM }, - { VENDOR_ID_HTC, PRODUCT_ID_DREAM_COMP }, +#define ADB_SUBCLASS 0x42 +#define ADB_PROTOCOL 0x1 + +int vendorIds[] = { + VENDOR_ID_GOOGLE, + VENDOR_ID_HTC, }; +#define NUM_VENDORS (sizeof(vendorIds)/sizeof(vendorIds[0])) static IONotificationPortRef notificationPort = 0; -static io_iterator_t notificationIterators[kSupportedDeviceCount]; +static io_iterator_t notificationIterators[NUM_VENDORS]; struct usb_handle { @@ -61,17 +57,20 @@ static pthread_mutex_t start_lock; static pthread_cond_t start_cond; -static void AndroidDeviceAdded(void *refCon, io_iterator_t iterator); -static void AndroidDeviceNotify(void *refCon, io_iterator_t iterator, natural_t messageType, void *messageArgument); -static usb_handle* FindDeviceInterface(IOUSBDeviceInterface **dev, UInt16 vendor, UInt16 product); +static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator); +static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator, + natural_t messageType, + void *messageArgument); +static usb_handle* CheckInterface(IOUSBInterfaceInterface **iface, + UInt16 vendor, UInt16 product); static int InitUSB() { CFMutableDictionaryRef matchingDict; CFRunLoopSourceRef runLoopSource; - SInt32 vendor, product; - int i; + SInt32 vendor, if_subclass, if_protocol; + unsigned i; //* To set up asynchronous notifications, create a notification port and //* add its run loop event source to the program's run loop @@ -81,51 +80,57 @@ InitUSB() memset(notificationIterators, 0, sizeof(notificationIterators)); - //* loop through all supported vendor/product pairs - for (i = 0; i < kSupportedDeviceCount; i++) { - //* Create our matching dictionary to find the Android device - //* IOServiceAddMatchingNotification consumes the reference, so we do not need to release this - matchingDict = IOServiceMatching(kIOUSBDeviceClassName); + //* loop through all supported vendors + for (i = 0; i < NUM_VENDORS; i++) { + //* Create our matching dictionary to find the Android device's + //* adb interface + //* IOServiceAddMatchingNotification consumes the reference, so we do + //* not need to release this + matchingDict = IOServiceMatching(kIOUSBInterfaceClassName); if (!matchingDict) { DBG("ERR: Couldn't create USB matching dictionary.\n"); return -1; } - //* Set up two matching dictionaries, one for each product ID we support. - //* This will cause the kernel to notify us only if the vendor and product IDs match. - vendor = kSupportedDevices[i].vid; - product = kSupportedDevices[i].pid; - CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor)); - CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product)); - - //* Now set up two notifications: one to be called when a raw device - //* is first matched by the I/O Kit and another to be called when the - //* device is terminated. - //* we need to do this with each matching dictionary. + //* Match based on vendor id, interface subclass and protocol + vendor = vendorIds[i]; + if_subclass = ADB_SUBCLASS; + if_protocol = ADB_PROTOCOL; + CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), + CFNumberCreate(kCFAllocatorDefault, + kCFNumberSInt32Type, &vendor)); + CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass), + CFNumberCreate(kCFAllocatorDefault, + kCFNumberSInt32Type, &if_subclass)); + CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol), + CFNumberCreate(kCFAllocatorDefault, + kCFNumberSInt32Type, &if_protocol)); IOServiceAddMatchingNotification( notificationPort, kIOFirstMatchNotification, matchingDict, - AndroidDeviceAdded, + AndroidInterfaceAdded, NULL, ¬ificationIterators[i]); - //* Iterate over set of matching devices to access already-present devices - //* and to arm the notification - AndroidDeviceAdded(NULL, notificationIterators[i]); + //* Iterate over set of matching interfaces to access already-present + //* devices and to arm the notification + AndroidInterfaceAdded(NULL, notificationIterators[i]); } return 0; } static void -AndroidDeviceAdded(void *refCon, io_iterator_t iterator) +AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) { kern_return_t kr; io_service_t usbDevice; + io_service_t usbInterface; IOCFPlugInInterface **plugInInterface = NULL; - IOUSBDeviceInterface182 **dev = NULL; + IOUSBInterfaceInterface220 **iface = NULL; + IOUSBDeviceInterface197 **dev = NULL; HRESULT result; SInt32 score; UInt16 vendor; @@ -133,28 +138,66 @@ AndroidDeviceAdded(void *refCon, io_iterator_t iterator) UInt8 serialIndex; char serial[256]; - while ((usbDevice = IOIteratorNext(iterator))) { - //* Create an intermediate plugin + while ((usbInterface = IOIteratorNext(iterator))) { + //* Create an intermediate interface plugin + kr = IOCreatePlugInInterfaceForService(usbInterface, + kIOUSBInterfaceUserClientTypeID, + kIOCFPlugInInterfaceID, + &plugInInterface, &score); + IOObjectRelease(usbInterface); + if ((kIOReturnSuccess != kr) || (!plugInInterface)) { + DBG("ERR: Unable to create an interface plug-in (%08x)\n", kr); + continue; + } + + //* This gets us the interface object + result = (*plugInInterface)->QueryInterface(plugInInterface, + CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID) + &iface); + //* We only needed the plugin to get the interface, so discard it + (*plugInInterface)->Release(plugInInterface); + if (result || !iface) { + DBG("ERR: Couldn't query the interface (%08x)\n", (int) result); + continue; + } + + //* this gets us an ioservice, with which we will find the actual + //* device; after getting a plugin, and querying the interface, of + //* course. + //* Gotta love OS X + kr = (*iface)->GetDevice(iface, &usbDevice); + if (kIOReturnSuccess != kr || !usbDevice) { + DBG("ERR: Couldn't grab device from interface (%08x)\n", kr); + continue; + } + + plugInInterface = NULL; + score = 0; + //* create an intermediate device plugin kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); - + //* only needed this to find the plugin + (void)IOObjectRelease(usbDevice); if ((kIOReturnSuccess != kr) || (!plugInInterface)) { - DBG("ERR: Unable to create a plug-in (%08x)\n", kr); - goto continue1; + DBG("ERR: Unable to create a device plug-in (%08x)\n", kr); + continue; } - //* Now create the device interface result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev); - + //* only needed this to query the plugin + (*plugInInterface)->Release(plugInInterface); if (result || !dev) { - DBG("ERR: Couldn't create a device interface (%08x)\n", (int) result); - goto continue2; + DBG("ERR: Couldn't create a device interface (%08x)\n", + (int) result); + continue; } - //* Check the device to see if it's ours + //* Now after all that, we actually have a ref to the device and + //* the interface that matched our criteria + kr = (*dev)->GetDeviceVendor(dev, &vendor); kr = (*dev)->GetDeviceProduct(dev, &product); kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex); @@ -163,7 +206,8 @@ AndroidDeviceAdded(void *refCon, io_iterator_t iterator) IOUSBDevRequest req; UInt16 buffer[256]; - req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); + req.bmRequestType = + USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); req.bRequest = kUSBRqGetDescriptor; req.wValue = (kUSBStringDesc << 8) | serialIndex; req.wIndex = 0; @@ -174,219 +218,149 @@ AndroidDeviceAdded(void *refCon, io_iterator_t iterator) if (kr == kIOReturnSuccess && req.wLenDone > 0) { int i, count; - // skip first word, and copy the rest to the serial string, changing shorts to bytes. + // skip first word, and copy the rest to the serial string, + // changing shorts to bytes. count = (req.wLenDone - 1) / 2; for (i = 0; i < count; i++) serial[i] = buffer[i + 1]; serial[i] = 0; } } + (*dev)->Release(dev); - usb_handle* handle = NULL; - - //* Open the device - kr = (*dev)->USBDeviceOpen(dev); - - if (kr != kIOReturnSuccess) { - DBG("ERR: Could not open device: %08x\n", kr); - goto continue3; - } else { - //* Find an interface for the device - handle = FindDeviceInterface((IOUSBDeviceInterface**)dev, vendor, product); - } + DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product, + serial); + usb_handle* handle = CheckInterface((IOUSBInterfaceInterface**)iface, + vendor, product); if (handle == NULL) { DBG("ERR: Could not find device interface: %08x\n", kr); - (*dev)->USBDeviceClose(dev); - goto continue3; + (*iface)->Release(iface); + continue; } DBG("AndroidDeviceAdded calling register_usb_transport\n"); register_usb_transport(handle, (serial[0] ? serial : NULL)); - // Register for an interest notification of this device being removed. Pass the reference to our - // private data as the refCon for the notification. + // Register for an interest notification of this device being removed. + // Pass the reference to our private data as the refCon for the + // notification. kr = IOServiceAddInterestNotification(notificationPort, - usbDevice, + usbInterface, kIOGeneralInterest, - AndroidDeviceNotify, + AndroidInterfaceNotify, handle, &handle->usbNotification); + if (kIOReturnSuccess != kr) { DBG("ERR: Unable to create interest notification (%08x)\n", kr); } - -continue3: - (void)(*dev)->Release(dev); -continue2: - IODestroyPlugInInterface(plugInInterface); -continue1: - IOObjectRelease(usbDevice); } } static void -AndroidDeviceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument) +AndroidInterfaceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument) { usb_handle *handle = (usb_handle *)refCon; if (messageType == kIOMessageServiceIsTerminated) { - DBG("AndroidDeviceNotify\n"); + if (!handle) { + DBG("ERR: NULL handle\n"); + return; + } + DBG("AndroidInterfaceNotify\n"); IOObjectRelease(handle->usbNotification); usb_kick(handle); } } +//* TODO: simplify this further since we only register to get ADB interface +//* subclass+protocol events static usb_handle* -FindDeviceInterface(IOUSBDeviceInterface **dev, UInt16 vendor, UInt16 product) +CheckInterface(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 product) { usb_handle* handle = NULL; IOReturn kr; - IOUSBFindInterfaceRequest request; - io_iterator_t iterator; - io_service_t usbInterface; - IOCFPlugInInterface **plugInInterface; - IOUSBInterfaceInterface **interface = NULL; - HRESULT result; - SInt32 score; UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol; - UInt8 endpoint, configuration; + UInt8 endpoint; - //* Placing the constant KIOUSBFindInterfaceDontCare into the following - //* fields of the IOUSBFindInterfaceRequest structure will allow us to - //* find all of the interfaces - request.bInterfaceClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; - request.bAlternateSetting = kIOUSBFindInterfaceDontCare; - - //* SetConfiguration will kill an existing UMS connection, so let's not do this if not necessary. - configuration = 0; - (*dev)->GetConfiguration(dev, &configuration); - if (configuration != 1) - (*dev)->SetConfiguration(dev, 1); - - //* Get an iterator for the interfaces on the device - kr = (*dev)->CreateInterfaceIterator(dev, &request, &iterator); + //* Now open the interface. This will cause the pipes associated with + //* the endpoints in the interface descriptor to be instantiated + kr = (*interface)->USBInterfaceOpen(interface); if (kr != kIOReturnSuccess) { - DBG("ERR: Couldn't create a device interface iterator: (%08x)\n", kr); + DBG("ERR: Could not open interface: (%08x)\n", kr); return NULL; } - while ((usbInterface = IOIteratorNext(iterator))) { - //* Create an intermediate plugin - kr = IOCreatePlugInInterfaceForService( - usbInterface, - kIOUSBInterfaceUserClientTypeID, - kIOCFPlugInInterfaceID, - &plugInInterface, - &score); - - //* No longer need the usbInterface object now that we have the plugin - (void) IOObjectRelease(usbInterface); - - if ((kr != kIOReturnSuccess) || (!plugInInterface)) { - DBG("ERR: Unable to create plugin (%08x)\n", kr); - break; - } - - //* Now create the interface interface for the interface - result = (*plugInInterface)->QueryInterface( - plugInInterface, - CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), - (LPVOID) &interface); - - //* No longer need the intermediate plugin - (*plugInInterface)->Release(plugInInterface); - - if (result || !interface) { - DBG("ERR: Couldn't create interface interface: (%08x)\n", - (unsigned int) result); - break; - } - - //* Now open the interface. This will cause the pipes associated with - //* the endpoints in the interface descriptor to be instantiated - kr = (*interface)->USBInterfaceOpen(interface); - - if (kr != kIOReturnSuccess) - { - DBG("ERR: Could not open interface: (%08x)\n", kr); - (void) (*interface)->Release(interface); - //* continue so we can try the next interface - continue; - } - - //* Get the number of endpoints associated with this interface - kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints); - - if (kr != kIOReturnSuccess) { - DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr); - goto next_interface; - } + //* Get the number of endpoints associated with this interface + kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints); + if (kr != kIOReturnSuccess) { + DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr); + goto err_get_num_ep; + } - //* Get interface class, subclass and protocol - if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess || + //* Get interface class, subclass and protocol + if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess || (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess || - (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) - { + (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) { DBG("ERR: Unable to get interface class, subclass and protocol\n"); - goto next_interface; - } - - //* check to make sure interface class, subclass and protocol match ADB - //* avoid opening mass storage endpoints - if (is_adb_interface(vendor, product, interfaceClass, interfaceSubClass, interfaceProtocol)) { - handle = calloc(1, sizeof(usb_handle)); + goto err_get_interface_class; + } - //* Iterate over the endpoints for this interface and find the first - //* bulk in/out pipes available. These will be our read/write pipes. - for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) { - UInt8 transferType; - UInt16 maxPacketSize; - UInt8 interval; - UInt8 number; - UInt8 direction; + //* check to make sure interface class, subclass and protocol match ADB + //* avoid opening mass storage endpoints + if (!is_adb_interface(vendor, product, interfaceClass, + interfaceSubClass, interfaceProtocol)) + goto err_bad_adb_interface; - kr = (*interface)->GetPipeProperties(interface, endpoint, &direction, - &number, &transferType, &maxPacketSize, &interval); + handle = calloc(1, sizeof(usb_handle)); - if (kIOReturnSuccess == kr) { - if (kUSBBulk != transferType) - continue; + //* Iterate over the endpoints for this interface and find the first + //* bulk in/out pipes available. These will be our read/write pipes. + for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) { + UInt8 transferType; + UInt16 maxPacketSize; + UInt8 interval; + UInt8 number; + UInt8 direction; - if (kUSBIn == direction) - handle->bulkIn = endpoint; + kr = (*interface)->GetPipeProperties(interface, endpoint, &direction, + &number, &transferType, &maxPacketSize, &interval); - if (kUSBOut == direction) - handle->bulkOut = endpoint; + if (kIOReturnSuccess == kr) { + if (kUSBBulk != transferType) + continue; - if (interfaceProtocol == 0x01) { - handle->zero_mask = maxPacketSize - 1; - } + if (kUSBIn == direction) + handle->bulkIn = endpoint; - } else { - DBG("ERR: FindDeviceInterface - could not get pipe properties\n"); - } - } + if (kUSBOut == direction) + handle->bulkOut = endpoint; - handle->interface = interface; - break; + handle->zero_mask = maxPacketSize - 1; + } else { + DBG("ERR: FindDeviceInterface - could not get pipe properties\n"); + goto err_get_pipe_props; } - -next_interface: - (*interface)->USBInterfaceClose(interface); - (*interface)->Release(interface); } + handle->interface = interface; return handle; + +err_get_pipe_props: + free(handle); +err_bad_adb_interface: +err_get_interface_class: +err_get_num_ep: + (*interface)->USBInterfaceClose(interface); + return NULL; } void* RunLoopThread(void* unused) { - int i; + unsigned i; InitUSB(); @@ -400,7 +374,7 @@ void* RunLoopThread(void* unused) CFRunLoopRun(); currentRunLoop = 0; - for (i = 0; i < kSupportedDeviceCount; i++) { + for (i = 0; i < NUM_VENDORS; i++) { IOObjectRelease(notificationIterators[i]); } IONotificationPortDestroy(notificationPort); @@ -527,6 +501,9 @@ int usb_close(usb_handle *handle) void usb_kick(usb_handle *handle) { /* release the interface */ + if (!handle) + return; + if (handle->interface) { (*handle->interface)->USBInterfaceClose(handle->interface); |