From fdbeee028ea2ff94cc3c9a26d368ed817637f890 Mon Sep 17 00:00:00 2001 From: "K, Gururaj" Date: Tue, 5 Jun 2018 15:05:05 +0530 Subject: [PATCH] Add Support to enable ADB over DBC This patch adds adb changes required to enable adb over debug-capability provided by xhci. ADB over DBC can be a useful feature for debug purposes especially on platforms which lack usb device mode port. Jira: None Test: None Signed-off-by: Rajaram Regupathy Signed-off-by: K, Gururaj --- adb/adb.h | 5 +- adb/client/usb_linux.cpp | 45 +++++++++++++ adb/commandline.cpp | 12 ++-- adb/daemon/main.cpp | 3 +- adb/daemon/usb.cpp | 134 ++++++++++++++++++++++++++++++++++++++- adb/transport_usb.cpp | 8 ++- 6 files changed, 198 insertions(+), 9 deletions(-) diff --git a/adb/adb.h b/adb/adb.h index 98e26046c..f0f6b3a4f 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -194,6 +194,9 @@ void put_apacket(apacket *p); #define ADB_SUBCLASS 0x42 #define ADB_PROTOCOL 0x1 +#define ADB_DBC_CLASS 0xDC +#define ADB_DBC_SUBCLASS 0x2 +#define ADB_DBC_PROTOCOL 0x1 void local_init(int port); bool local_connect(int port); @@ -210,9 +213,9 @@ extern int SHELL_EXIT_NOTIFY_FD; #define CHUNK_SIZE (64*1024) #if !ADB_HOST +#define USB_DBC_ADB_PATH "/dev/dbc_raw" #define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/" #define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x - #define USB_FFS_ADB_EP0 USB_FFS_ADB_EP(ep0) #define USB_FFS_ADB_OUT USB_FFS_ADB_EP(ep1) #define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2) diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp index a7df0ed51..dd80c3b3d 100644 --- a/adb/client/usb_linux.cpp +++ b/adb/client/usb_linux.cpp @@ -350,6 +350,9 @@ static int usb_bulk_read(usb_handle* h, void* data, int len) { urb->buffer = data; urb->buffer_length = len; + usbdevfs_ctrltransfer ufs; + unsigned short int ufsdata; + if (h->dead) { errno = EINVAL; return -1; @@ -364,13 +367,55 @@ static int usb_bulk_read(usb_handle* h, void* data, int len) { D("[ reap urb - wait ]"); h->reaper_thread = pthread_self(); int fd = h->fd; + + ufsdata = 0; + ufs.bRequestType = 0x82; + ufs.bRequest = USB_REQ_GET_STATUS; + ufs.wValue = 0x0000; + ufs.wIndex = h->ep_in; + ufs.wLength = 0x0002; + ufs.data = &ufsdata; + + if(TEMP_FAILURE_RETRY(ioctl(h->fd,USBDEVFS_CONTROL,&ufs))== -1) + { + D("clear_halt read failed");} + else + { + D("clear_halt read successful %d",ufsdata); + } + + if(ufsdata) + { + ufs.bRequestType = 0x02; + ufs.bRequest = USB_REQ_CLEAR_FEATURE; + ufs.wValue = 0x0000; + ufs.wIndex = h->ep_out; + ufs.wLength = 0x0000; + ufs.data = NULL; + + if(TEMP_FAILURE_RETRY(ioctl(h->fd,USBDEVFS_CONTROL,&ufs))== -1) + { + D("clear_halt read2 failed"); + } + else + { + D("clear_halt read2 successful "); + } + errno = ETIMEDOUT; + return -1; + } + lock.unlock(); // This ioctl must not have TEMP_FAILURE_RETRY because we send SIGALRM to break out. + usbdevfs_urb* out = nullptr; + D("before reap urb"); + int res = ioctl(fd, USBDEVFS_REAPURB, &out); int saved_errno = errno; + D("after reap urb"); lock.lock(); h->reaper_thread = 0; if (h->dead) { diff --git a/adb/commandline.cpp b/adb/commandline.cpp index 9f234737b..8e5e84145 100644 --- a/adb/commandline.cpp +++ b/adb/commandline.cpp @@ -67,6 +67,7 @@ static int install_multiple_app(int argc, const char** argv); static int uninstall_app(int argc, const char** argv); static int install_app_legacy(int argc, const char** argv); static int uninstall_app_legacy(int argc, const char** argv); +static int adb_query_command(const std::string& command); extern int gListenAll; @@ -1040,7 +1041,12 @@ static bool adb_root(const char* command) { return false; } + // Give adbd some time to kill itself and come back up. + // We can't use wait-for-device because devices (e.g. adb over network) might not come back. + std::this_thread::sleep_for(1s); + // Figure out whether we actually did anything. +/* char buf[256]; char* cur = buf; ssize_t bytes_left = sizeof(buf); @@ -1066,10 +1072,8 @@ static bool adb_root(const char* command) { if (cur != buf && strstr(buf, "restarting") == nullptr) { return true; } +*/ - // Give adbd some time to kill itself and come back up. - // We can't use wait-for-device because devices (e.g. adb over network) might not come back. - std::this_thread::sleep_for(3s); return true; } @@ -1608,7 +1612,7 @@ int adb_commandline(int argc, const char** argv) { } return adb_connect_command(command); } else if (!strcmp(argv[0], "root") || !strcmp(argv[0], "unroot")) { - return adb_root(argv[0]) ? 0 : 1; + return adb_root(argv[0]) ? adb_query_command(format_host_command("reconnect")) : 1; } else if (!strcmp(argv[0], "bugreport")) { Bugreport bugreport; return bugreport.DoIt(argc, argv); diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp index 3c2758276..083a83495 100644 --- a/adb/daemon/main.cpp +++ b/adb/daemon/main.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -177,7 +178,7 @@ int adbd_main(int server_port) { drop_privileges(server_port); bool is_usb = false; - if (access(USB_FFS_ADB_EP0, F_OK) == 0) { + if ( (access(USB_FFS_ADB_EP0, F_OK) == 0) || (access(USB_DBC_ADB_PATH,F_OK) == 0) ) { // Listen on USB. usb_init(); is_usb = true; diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp index 0f92282c4..ba622fe47 100644 --- a/adb/daemon/usb.cpp +++ b/adb/daemon/usb.cpp @@ -57,7 +57,8 @@ using namespace std::chrono_literals; // on a device kernel that has been running for a while fragmenting its // memory so we start with a larger allocation, and shrink the amount if // necessary. -#define USB_FFS_BULK_SIZE 16384 +#define USB_FFS_BULK_SIZE (64*1024) +#define USB_DBC_BULK_SIZE (64*1024) #define cpu_to_le16(x) htole16(x) #define cpu_to_le32(x) htole32(x) @@ -459,10 +460,139 @@ static void usb_ffs_init() { std::thread(usb_ffs_open_thread, h).detach(); } +bool init_dbc_raw(struct usb_handle* h) { + D("init_dbc_raw called\n"); + h->max_rw = USB_DBC_BULK_SIZE; + + h->bulk_out = adb_open(USB_DBC_ADB_PATH, O_RDWR); + if (h->bulk_out < 0) { + D("[ %s: cannot open bulk-out ep: errno=%d ]", USB_DBC_ADB_PATH, errno); + goto err; + } + + h->bulk_in = h->bulk_out; + h->control = h->bulk_out; + + return true; + +err: + h->bulk_out = -1; + h->bulk_in = -1; + h->control = -1; + return false; +} + +static void usb_dbc_open_thread(void* x) { + struct usb_handle* usb = (struct usb_handle*)x; + + adb_thread_setname("usb dbc open"); + D("dbc_open_thread called\n"); + while (true) { + // wait until the USB device needs opening + std::unique_lock lock(usb->lock); + while (!usb->open_new_connection) { + usb->notify.wait(lock); + } + usb->open_new_connection = false; + lock.unlock(); + + while (true) { + if (init_dbc_raw(usb)) { + break; + } + std::this_thread::sleep_for(1s); + } + + D("register usb transport\n"); + register_usb_transport(usb, 0, 0, 1); + } + + // never gets here + abort(); +} + +static int usb_dbc_write(usb_handle* h, const void* data, int len) { + D("about to write (fd=%d, len=%d)", h->bulk_in, len); + + const char* buf = static_cast(data); + while (len > 0) { + int write_len = std::min(h->max_rw, len); + int n = adb_write(h->bulk_in, buf, write_len); + if (n < 0) { + D("ERROR: fd = %d, n = %d: %s", h->bulk_in, n, strerror(errno)); + return -1; + } + buf += n; + len -= n; + } + + D("[ done fd=%d ]", h->bulk_in); + return 0; +} + +static int usb_dbc_read(usb_handle* h, void* data, int len) { + D("about to read (fd=%d, len=%d)", h->bulk_out, len); + + char* buf = static_cast(data); + while (len > 0) { + int read_len = std::min(h->max_rw, len); + int n = adb_read(h->bulk_out, buf, read_len); + if (n < 0) { + D("ERROR: fd = %d, n = %d: %s", h->bulk_out, n, strerror(errno)); + return -1; + } + buf += n; + len -= n; + } + D("[ done fd=%d ]", h->bulk_out); + return 0; +} + +static void usb_dbc_kick(usb_handle* h) { + int err; + D("usb_dbc_kick called\n"); + err = ioctl(h->bulk_in, FLUSH_DBC_EP); + if (err < 0) { + D("[ kick: source (fd=%d) clear halt failed (%d) ]", h->bulk_in, errno); + } + h->kicked = true; +} + +static void usb_dbc_close(usb_handle* h) { + h->kicked = false; + D("usb_dbc_close called\n"); + adb_close(h->bulk_out); + // Notify usb_adb_open_thread to open a new connection. + h->lock.lock(); + h->open_new_connection = true; + h->lock.unlock(); + h->notify.notify_one(); +} + +static void usb_dbc_init() { + D("[ usb_init - using dbc ]"); + + usb_handle* h = new usb_handle(); + + h->write = usb_dbc_write; + h->read = usb_dbc_read; + h->kick = usb_dbc_kick; + h->close = usb_dbc_close; + + D("[ usb_init - starting thread ]"); + std::thread(usb_dbc_open_thread, h).detach(); +} + + void usb_init() { dummy_fd = adb_open("/dev/null", O_WRONLY); CHECK_NE(dummy_fd, -1); - usb_ffs_init(); + + if (access(USB_DBC_ADB_PATH,F_OK) == 0) + usb_dbc_init(); + else + usb_ffs_init(); + } int usb_write(usb_handle* h, const void* data, int len) { diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp index e5845f018..658683436 100644 --- a/adb/transport_usb.cpp +++ b/adb/transport_usb.cpp @@ -177,7 +177,13 @@ void init_usb_transport(atransport* t, usb_handle* h) { int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol) { - return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL); + + if ( (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL) || + (usb_class == ADB_DBC_CLASS && usb_subclass == ADB_DBC_SUBCLASS && usb_protocol == ADB_DBC_PROTOCOL)) + return true; + else + return false; + } bool should_use_libusb() {