AI 149490: Add support for 3rd party USB Vendor.
  BUG=1890147

Automated import of CL 149490
diff --git a/adb/Android.mk b/adb/Android.mk
index 2296610..ed8b501 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -54,6 +54,7 @@
 	$(USB_SRCS) \
 	shlist.c \
 	utils.c \
+	usb_vendors.c \
 
 
 ifneq ($(USE_SYSDEPS_WIN32),)
diff --git a/adb/adb.c b/adb/adb.c
index 12a36f5..36130cd 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -29,6 +29,8 @@
 
 #if !ADB_HOST
 #include <private/android_filesystem_config.h>
+#else
+#include "usb_vendors.h"
 #endif
 
 
@@ -846,6 +848,7 @@
 
 #if ADB_HOST
     HOST = 1;
+    usb_vendors_init();
     usb_init();
     local_init();
 
diff --git a/adb/adb.h b/adb/adb.h
index a17c8dd..6c5fc7c 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -357,18 +357,9 @@
 #define ADB_PORT 5037
 #define ADB_LOCAL_TRANSPORT_PORT 5555
 
-// 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
+#define ADB_CLASS              0xff
+#define ADB_SUBCLASS           0x42
+#define ADB_PROTOCOL           0x1
 
 void local_init();
 int  local_connect(int  port);
@@ -382,7 +373,9 @@
 void usb_kick(usb_handle *h);
 
 /* used for USB device detection */
+#if ADB_HOST
 int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
+#endif
 
 unsigned host_to_le32(unsigned n);
 int adb_commandline(int argc, char **argv);
diff --git a/adb/adb_client.c b/adb/adb_client.c
index 5868744..243f0fa 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -213,7 +213,7 @@
             fprintf(stdout,"* daemon started successfully *\n");
         }
         /* give the server some time to start properly and detect devices */
-        adb_sleep_ms(2000);
+        adb_sleep_ms(3000);
         // fall through to _adb_connect
     } else {
         // if server was running, check its version to make sure it is not out of date
diff --git a/adb/transport_usb.c b/adb/transport_usb.c
index 01c4a7e..3737c5c 100644
--- a/adb/transport_usb.c
+++ b/adb/transport_usb.c
@@ -23,6 +23,10 @@
 #define  TRACE_TAG  TRACE_TRANSPORT
 #include "adb.h"
 
+#if ADB_HOST
+#include "usb_vendors.h"
+#endif
+
 /* XXX better define? */
 #ifdef __ppc__
 #define H4(x)	(((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
@@ -125,23 +129,21 @@
 #endif
 }
 
+#if ADB_HOST
 int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
 {
-    if (vid == VENDOR_ID_GOOGLE) {
-            /* might support adb */
-    } else if (vid == VENDOR_ID_HTC) {
-            /* might support adb */
-    } else {
-            /* not supported */
-        return 0;
-    }
+    unsigned i;
+    for (i = 0; i < vendorIdCount; i++) {
+        if (vid == vendorIds[i]) {
+            if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS &&
+                    usb_protocol == ADB_PROTOCOL) {
+                return 1;
+            }
 
-        /* class:vendor (0xff) subclass:android (0x42) proto:adb (0x01) */
-    if(usb_class == 0xff) {
-        if((usb_subclass == 0x42) && (usb_protocol == 0x01)) {
-            return 1;
+            return 0;
         }
     }
 
     return 0;
 }
+#endif
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 49e1eef..4892c38 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -28,24 +28,12 @@
 
 #define TRACE_TAG   TRACE_USB
 #include "adb.h"
+#include "usb_vendors.h"
 
 #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 },
-};
-
 static IONotificationPortRef    notificationPort = 0;
-static io_iterator_t            notificationIterators[kSupportedDeviceCount];
+static io_iterator_t*           notificationIterators;
 
 struct usb_handle
 {
@@ -61,17 +49,20 @@
 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 +72,57 @@
 
     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 < vendorIdCount; 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,
                 &notificationIterators[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 +130,66 @@
     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 +198,8 @@
             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 +210,149 @@
             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;
+        DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product,
+            serial);
 
-        //* 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);
-        }
-
+        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 interface class, subclass and protocol
-        if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
-            (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != 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));
-
-            //* 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;
-
-                kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
-                        &number, &transferType, &maxPacketSize, &interval);
-
-                if (kIOReturnSuccess == kr) {
-                    if (kUSBBulk != transferType)
-                        continue;
-
-                    if (kUSBIn == direction)
-                        handle->bulkIn = endpoint;
-
-                    if (kUSBOut == direction)
-                        handle->bulkOut = endpoint;
-
-                    if (interfaceProtocol == 0x01) {
-                        handle->zero_mask = maxPacketSize - 1;
-                    }
-
-                } else {
-                    DBG("ERR: FindDeviceInterface - could not get pipe properties\n");
-                }
-            }
-
-            handle->interface = interface;
-            break;
-        }
-
-next_interface:
-        (*interface)->USBInterfaceClose(interface);
-        (*interface)->Release(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 ||
+            (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
+            (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) {
+            DBG("ERR: Unable to get interface class, subclass and protocol\n");
+            goto err_get_interface_class;
+    }
+
+    //* 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;
+
+    handle = calloc(1, sizeof(usb_handle));
+
+    //* 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;
+
+        kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
+                &number, &transferType, &maxPacketSize, &interval);
+
+        if (kIOReturnSuccess == kr) {
+            if (kUSBBulk != transferType)
+                continue;
+
+            if (kUSBIn == direction)
+                handle->bulkIn = endpoint;
+
+            if (kUSBOut == direction)
+                handle->bulkOut = endpoint;
+
+            handle->zero_mask = maxPacketSize - 1;
+        } else {
+            DBG("ERR: FindDeviceInterface - could not get pipe properties\n");
+            goto err_get_pipe_props;
+        }
+    }
+
+    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 +366,7 @@
     CFRunLoopRun();
     currentRunLoop = 0;
 
-    for (i = 0; i < kSupportedDeviceCount; i++) {
+    for (i = 0; i < vendorIdCount; i++) {
         IOObjectRelease(notificationIterators[i]);
     }
     IONotificationPortDestroy(notificationPort);
@@ -417,6 +383,9 @@
     {
         adb_thread_t    tid;
 
+        notificationIterators = (io_iterator_t*)malloc(
+            vendorIdCount * sizeof(io_iterator_t));
+
         adb_mutex_init(&start_lock, NULL);
         adb_cond_init(&start_cond, NULL);
 
@@ -441,6 +410,11 @@
     close_usb_devices();
     if (currentRunLoop)
         CFRunLoopStop(currentRunLoop);
+
+    if (notificationIterators != NULL) {
+        free(notificationIterators);
+        notificationIterators = NULL;
+    }
 }
 
 int usb_write(usb_handle *handle, const void *buf, int len)
@@ -527,6 +501,9 @@
 void usb_kick(usb_handle *handle)
 {
     /* release the interface */
+    if (!handle)
+        return;
+
     if (handle->interface)
     {
         (*handle->interface)->USBInterfaceClose(handle->interface);
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
new file mode 100644
index 0000000..9a15146
--- /dev/null
+++ b/adb/usb_vendors.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "usb_vendors.h"
+
+#include <stdio.h>
+
+#ifdef _WIN32
+#  define WIN32_LEAN_AND_MEAN
+#  include "windows.h"
+#  include "shlobj.h"
+#else
+#  include <unistd.h>
+#  include <sys/stat.h>
+#endif
+
+#include "sysdeps.h"
+#include "adb.h"
+
+#define ANDROID_PATH            ".android"
+#define ANDROID_ADB_INI         "adb_usb.ini"
+
+#define TRACE_TAG               TRACE_USB
+
+// Google's USB Vendor ID
+#define VENDOR_ID_GOOGLE        0x18d1
+// HTC's USB Vendor ID
+#define VENDOR_ID_HTC           0x0bb4
+
+/** built-in vendor list */
+int builtInVendorIds[] = {
+    VENDOR_ID_GOOGLE,
+    VENDOR_ID_HTC,
+};
+
+#define BUILT_IN_VENDOR_COUNT    (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
+
+/* max number of supported vendor ids (built-in + 3rd party). increase as needed */
+#define VENDOR_COUNT_MAX         128
+
+int vendorIds[VENDOR_COUNT_MAX];
+unsigned vendorIdCount = 0;
+
+int get_adb_usb_ini(char* buff, size_t len);
+
+void usb_vendors_init(void)
+{
+    if (VENDOR_COUNT_MAX < BUILT_IN_VENDOR_COUNT) {
+        fprintf(stderr, "VENDOR_COUNT_MAX not big enough for built-in vendor list.\n");
+        exit(2);
+    }
+
+    /* add the built-in vendors at the beginning of the array */
+    memcpy(vendorIds, builtInVendorIds, sizeof(builtInVendorIds));
+
+    /* default array size is the number of built-in vendors */
+    vendorIdCount = BUILT_IN_VENDOR_COUNT;
+
+    if (VENDOR_COUNT_MAX == BUILT_IN_VENDOR_COUNT)
+        return;
+
+    char temp[PATH_MAX];
+    if (get_adb_usb_ini(temp, sizeof(temp)) == 0) {
+        FILE * f = fopen(temp, "rt");
+
+        if (f != NULL) {
+            /* The vendor id file is pretty basic. 1 vendor id per line.
+               Lines starting with # are comments */
+            while (fgets(temp, sizeof(temp), f) != NULL) {
+                if (temp[0] == '#')
+                    continue;
+
+                long value = strtol(temp, NULL, 0);
+                if (errno == EINVAL || errno == ERANGE || value > INT_MAX || value < 0) {
+                    fprintf(stderr, "Invalid content in %s. Quitting.\n", ANDROID_ADB_INI);
+                    exit(2);
+                }
+
+                vendorIds[vendorIdCount++] = (int)value;
+
+                /* make sure we don't go beyond the array */
+                if (vendorIdCount == VENDOR_COUNT_MAX) {
+                    break;
+                }
+            }
+        }
+    }
+}
+
+/* Utils methods */
+
+/* builds the path to the adb vendor id file. returns 0 if success */
+int build_path(char* buff, size_t len, const char* format, const char* home)
+{
+    if (snprintf(buff, len, format, home, ANDROID_PATH, ANDROID_ADB_INI) >= len) {
+        return 1;
+    }
+
+    return 0;
+}
+
+/* fills buff with the path to the adb vendor id file. returns 0 if success */
+int get_adb_usb_ini(char* buff, size_t len)
+{
+#ifdef _WIN32
+    const char* home = getenv("ANDROID_SDK_HOME");
+    if (home != NULL) {
+        return build_path(buff, len, "%s\\%s\\%s", home);
+    } else {
+        char path[MAX_PATH];
+        SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, path);
+        return build_path(buff, len, "%s\\%s\\%s", path);
+    }
+#else
+    const char* home = getenv("HOME");
+    if (home == NULL)
+        home = "/tmp";
+
+    return build_path(buff, len, "%s/%s/%s", home);
+#endif
+}
diff --git a/adb/usb_vendors.h b/adb/usb_vendors.h
new file mode 100644
index 0000000..43790b9
--- /dev/null
+++ b/adb/usb_vendors.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __USB_VENDORS_H
+#define __USB_VENDORS_H
+
+extern int vendorIds[];
+extern unsigned  vendorIdCount;
+
+void usb_vendors_init(void);
+
+#endif
\ No newline at end of file