>From f07da575a9ff41f152d29ac95661dc18d64bbb33 Mon Sep 17 00:00:00 2001
From: Andy Doan <andy.doan@linaro.org>
Date: Tue, 15 Jan 2013 15:16:50 +0000
Subject: [PATCH] allow adb host to ignore specific USB devices

The way adb scans for USB devices can interfere with USB power
management commands run on that device - specifically powering on/off
the device. This change allows a user to pass a list of devices
to "blacklist" via an environment variable to adb.

An example script that was affected by adb is:

  http://people.linaro.org/~doanac/sdmux/sdmux.sh

If adb was run in between the power off and power on commands, then
the device could not be powered on and mounted properly.

Change-Id: I97b24b46c3f65f56eead5ce59a49d4ab3f624657
Signed-off-by: Andy Doan <andy.doan@linaro.org>
---
 adb/adb.c       |   36 ++++++++++++++++++++++++++++++++++--
 adb/usb_linux.c |   26 ++++++++++++++++++++------
 2 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/adb/adb.c b/adb/adb.c
index 4c3364f..fd4545a 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -1164,6 +1164,36 @@ static int should_drop_privileges() {
 #endif /* ALLOW_ADBD_ROOT */
 }
 #endif /* !ADB_HOST */
+/* allows ADB to not check certain USB devices that are known to not function
+ * well with the usb find_devices logic.
+ * Returns a null-terminated array of strings
+ */
+static const char** build_usb_black_list()
+{
+    char *list = getenv("ADB_USB_BLACKLIST");
+    char *token;
+    char *search = ",";
+    int count = 0;
+    const char **retval;
+
+    if(!list)
+        return calloc(1, 1); //return 0 length array of strings
+
+    token = strtok(list, search);
+    while(token) {
+        count++;
+        token = strtok(NULL, search);
+    }
+
+    retval = calloc(sizeof(char*), count+1);
+    while(count--) {
+        retval[count] = list;
+	while(count && *list != '\0' ) list++;
+	list++;
+    }
+
+    return retval;
+}

 int adb_main(int is_daemon, int server_port)
 {
@@ -1186,8 +1216,10 @@ int adb_main(int is_daemon, int server_port)

 #if ADB_HOST
     HOST = 1;
-    usb_vendors_init();
-    usb_init();
+    if(!getenv("ADB_NOUSB")) {
+        usb_vendors_init();
+        usb_init(build_usb_black_list());
+    }
     local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
     adb_auth_init();

diff --git a/adb/usb_linux.c b/adb/usb_linux.c
index 7bf2057..c02d38a 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -99,6 +99,15 @@ static int known_device(const char *dev_name)
     return 0;
 }

+static int black_listed_device(const char *dev_name, const char **black_list)
+{
+    const char **ptr = black_list;
+    while(*ptr)
+        if(!strcmp(dev_name, *ptr++))
+	    return 1;
+    return 0;
+}
+
 static void kick_disconnected_devices()
 {
     usb_handle *usb;
@@ -128,7 +137,7 @@ static inline int badname(const char *name)
     return 0;
 }

-static void find_usb_device(const char *base,
+static void find_usb_device(const char *base, const char **black_listed_devices,
         void (*register_device_callback)
                 (const char *, const char *, unsigned char, unsigned char, int, int, unsigned))
 {
@@ -163,11 +172,15 @@ static void find_usb_device(const char *base,

             if(badname(de->d_name)) continue;
             snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
-
             if(known_device(devname)) {
                 DBGX("skipping %s\n", devname);
                 continue;
             }
+            if(black_listed_device(devname, black_listed_devices)) {
+                DBGX("black listed %s\n", devname);
+                continue;
+            }
+

 //            DBGX("[ scanning %s ]\n", devname);
             if((fd = unix_open(devname, O_RDONLY)) < 0) {
@@ -681,12 +694,13 @@ fail:
     free(usb);
 }

-void* device_poll_thread(void* unused)
+void* device_poll_thread(void *data)
 {
+    const char **black_listed_devices = (const char**)data;
     D("Created device thread\n");
     for(;;) {
             /* XXX use inotify */
-        find_usb_device("/dev/bus/usb", register_device);
+        find_usb_device("/dev/bus/usb", black_listed_devices, register_device);
         kick_disconnected_devices();
         sleep(1);
     }
@@ -698,7 +712,7 @@ static void sigalrm_handler(int signo)
     // don't need to do anything here
 }

-void usb_init()
+void usb_init(const char **black_listed_devices)
 {
     adb_thread_t tid;
     struct sigaction    actions;
@@ -709,7 +723,7 @@ void usb_init()
     actions.sa_handler = sigalrm_handler;
     sigaction(SIGALRM,& actions, NULL);

-    if(adb_thread_create(&tid, device_poll_thread, NULL)){
+    if(adb_thread_create(&tid, device_poll_thread, (void*)black_listed_devices)){
         fatal_errno("cannot create input thread");
     }
 }
--
1.7.5.4

