[PATCH 3/3] adbd: introduce FunctionFS support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Modify the newly created usb access layer to support FunctionFS

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx>
Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>
---
 adb/Android.mk                |    3 +
 adb/adb.c                     |    4 +
 adb/adb.h                     |    6 +
 adb/usb_funcfs_linux_client.c |  284 ++++++++++++++++++++++++++++++++++-------
 4 files changed, 252 insertions(+), 45 deletions(-)

diff --git a/adb/Android.mk b/adb/Android.mk
index 24f088b..be75c8c 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -132,6 +132,9 @@ LOCAL_SRC_FILES := \
 
 LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
 LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
+ifeq ($(USE_USB_FUNCFS),true)
+LOCAL_CFLAGS += -DUSE_USB_FUNCFS=1
+endif
 
 # TODO: This should probably be board specific, whether or not the kernel has
 # the gadget driver; rather than relying on the architecture type.
diff --git a/adb/adb.c b/adb/adb.c
index bdeff9f..0b36499 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -947,7 +947,11 @@ int adb_main(int is_daemon, int server_port)
     if (sscanf(value, "%d", &port) == 1 && port > 0) {
         // listen on TCP port specified by service.adb.tcp.port property
         local_init(port);
+#ifndef USE_USB_FUNCFS
     } else if (access("/dev/android_adb", F_OK) == 0) {
+#else
+    } else if (access(USB_FUNCFS_ROOT, F_OK) == 0) {
+#endif
         // listen on USB
         usb_init();
     } else {
diff --git a/adb/adb.h b/adb/adb.h
index 1aadf7b..5190d47 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -440,6 +440,12 @@ extern int SHELL_EXIT_NOTIFY_FD;
 
 #define CHUNK_SIZE (64*1024)
 
+#if !ADB_HOST
+#ifdef USE_USB_FUNCFS
+#define USB_FUNCFS_ROOT "/dev/usbgadget/adb"
+#endif
+#endif
+
 int sendfailmsg(int fd, const char *reason);
 int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
 
diff --git a/adb/usb_funcfs_linux_client.c b/adb/usb_funcfs_linux_client.c
index 635fa4b..94c358b 100644
--- a/adb/usb_funcfs_linux_client.c
+++ b/adb/usb_funcfs_linux_client.c
@@ -12,6 +12,10 @@
  * 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.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co Ltd.
+ * Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx>
+ *
  */
 
 #include <stdio.h>
@@ -24,19 +28,167 @@
 #include <dirent.h>
 #include <errno.h>
 
+#include <linux/usb_ch9.h>
+#include <linux/usb_functionfs.h>
+
 #include "sysdeps.h"
 
 #define   TRACE_TAG  TRACE_USB
 #include "adb.h"
 
+#define USB_CLASS_ADB		0xff
+#define USB_SC_ADB		0x42
+#define MAX_PACKET_SIZE_FS	64
+#define MAX_PACKET_SIZE_HS	512
+
+#define cpu_to_le16(x)  htole16(x)
+#define cpu_to_le32(x)  htole32(x)
+
+static const struct {
+    struct usb_functionfs_descs_head header;
+    struct {
+        struct usb_interface_descriptor intf;
+        struct usb_endpoint_descriptor_no_audio source;
+        struct usb_endpoint_descriptor_no_audio sink;
+    } __attribute__((packed)) fs_descs, hs_descs;
+} __attribute__((packed)) descriptors = {
+    .header = {
+        .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+        .length = cpu_to_le32(sizeof descriptors),
+        .fs_count = 3,
+        .hs_count = 3,
+},
+    .fs_descs = {
+        .intf = {
+            .bLength = sizeof descriptors.fs_descs.intf,
+            .bDescriptorType = USB_DT_INTERFACE,
+            .bInterfaceNumber = 0,
+            .bNumEndpoints = 2,
+            .bInterfaceClass = USB_CLASS_ADB,
+            .bInterfaceSubClass = USB_SC_ADB,
+            .bInterfaceProtocol = 1,
+            .iInterface = 1, /* first string from the provided table */
+        },
+        .source = {
+            .bLength = sizeof descriptors.fs_descs.source,
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 1 | USB_DIR_OUT,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+	},
+        .sink = {
+            .bLength = sizeof descriptors.fs_descs.sink,
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 2 | USB_DIR_IN,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+        },
+    },
+    .hs_descs = {
+        .intf = {
+            .bLength = sizeof descriptors.hs_descs.intf,
+            .bDescriptorType = USB_DT_INTERFACE,
+            .bInterfaceNumber = 0,
+            .bNumEndpoints = 2,
+            .bInterfaceClass = USB_CLASS_ADB,
+            .bInterfaceSubClass = USB_SC_ADB,
+            .bInterfaceProtocol = 1,
+            .iInterface = 1, /* first string from the provided table */
+        },
+        .source = {
+            .bLength = sizeof descriptors.hs_descs.source,
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 1 | USB_DIR_OUT,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+        },
+        .sink = {
+            .bLength = sizeof descriptors.hs_descs.sink,
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 2 | USB_DIR_IN,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+        },
+    },
+};
+
+#define STR_INTERFACE_ "ADB Interface"
+
+static const struct {
+    struct usb_functionfs_strings_head header;
+    struct {
+        __le16 code;
+        const char str1[sizeof STR_INTERFACE_];
+    } __attribute__((packed)) lang0;
+} __attribute__((packed)) strings = {
+    .header = {
+        .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
+        .length = cpu_to_le32(sizeof strings),
+        .str_count = cpu_to_le32(1),
+        .lang_count = cpu_to_le32(1),
+    },
+    .lang0 = {
+        cpu_to_le16(0x0409), /* en-us */
+        STR_INTERFACE_,
+    },
+};
 
 struct usb_handle
 {
-    int fd;
+    char *EP0_NAME;
+    char *EP_IN_NAME;
+    char *EP_OUT_NAME;
+    int control;
+    int bulk_out; /* "out" from the host's perspective => source for adbd */
+    int bulk_in;  /* "in" from the host's perspective => sink for adbd */
     adb_cond_t notify;
     adb_mutex_t lock;
 };
 
+static void init_functionfs(struct usb_handle *h)
+{
+    ssize_t ret;
+
+    h->control = adb_open(h->EP0_NAME, O_RDWR);
+    if (h->control < 0) {
+        D("[ %s: cannot open control endpoint ]\n", h->EP0_NAME);
+        h->control = -errno;
+        return;
+    }
+
+    D("[ %s: writing descriptors ]\n", h->EP0_NAME);
+    ret = adb_write(h->control, &descriptors, sizeof descriptors);
+    if (ret < 0) {
+        D("[ %s: write: descriptors ]\n", h->EP0_NAME);
+        h->control = -errno;
+        return;
+    }
+
+    D("[ %s: writing strings ]\n", h->EP0_NAME);
+    ret = adb_write(h->control, &strings, sizeof strings);
+    if(ret < 0) {
+        D("[ %s: write: strings ]\n", h->EP0_NAME);
+        h->control = -errno;
+        return;
+    }
+
+    D("[ %s: opening ]\n", h->EP_OUT_NAME);
+    if ((h->bulk_out = adb_open(h->EP_OUT_NAME, O_RDWR)) < 0) {
+        D("[ %s: cannot open bulk-out endpoint ]\n", h->EP_OUT_NAME);
+        h->bulk_out = -errno;
+        return;
+    }
+	
+    D("[ %s: opening ]\n", h->EP_IN_NAME);
+    if ((h->bulk_in = adb_open(h->EP_IN_NAME, O_RDWR)) < 0) {
+        D("[ %s: cannot open bulk-in endpoint ]\n", h->EP_IN_NAME);
+        h->bulk_in = -errno;
+        return;
+    }
+
+    return;
+}
+
 void usb_cleanup()
 {
     // nothing to do here
@@ -45,32 +197,17 @@ void usb_cleanup()
 static void *usb_open_thread(void *x)
 {
     struct usb_handle *usb = (struct usb_handle *)x;
-    int fd;
 
     while (1) {
         // wait until the USB device needs opening
         adb_mutex_lock(&usb->lock);
-        while (usb->fd != -1)
+        while (usb->control != -1)
             adb_cond_wait(&usb->notify, &usb->lock);
         adb_mutex_unlock(&usb->lock);
 
-        D("[ usb_thread - opening device ]\n");
-        do {
-            /* XXX use inotify? */
-            fd = unix_open("/dev/android_adb", O_RDWR);
-            if (fd < 0) {
-                // to support older kernels
-                fd = unix_open("/dev/android", O_RDWR);
-            }
-            if (fd < 0) {
-                adb_sleep_ms(1000);
-            }
-        } while (fd < 0);
+        init_functionfs(usb);
         D("[ opening device succeeded ]\n");
 
-        close_on_exec(fd);
-        usb->fd = fd;
-
         D("[ usb_thread - registering device ]\n");
         register_usb_transport(usb, 0, 1);
     }
@@ -79,33 +216,82 @@ static void *usb_open_thread(void *x)
     return 0;
 }
 
+static int bulk_write(int bulk_in, const void *buf, size_t length)
+{
+    size_t count = 0;
+    int ret;
+
+    do {
+        ret = adb_write(bulk_in, buf + count, length - count);
+        if (ret < 0) {
+            if (errno != EINTR)
+                return ret;
+            } else
+                count += ret;
+    } while (count < length);
+
+    return count;
+}
+
 int usb_write(usb_handle *h, const void *data, int len)
 {
     int n;
 
-    D("about to write (fd=%d, len=%d)\n", h->fd, len);
-    n = adb_write(h->fd, data, len);
+    D("about to write (fd=%d, len=%d)\n", h->bulk_in, len);
+    n = bulk_write(h->bulk_in, data, len);
     if(n != len) {
         D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
-            h->fd, n, errno, strerror(errno));
+            h->bulk_in, n, errno, strerror(errno));
         return -1;
     }
-    D("[ done fd=%d ]\n", h->fd);
+    D("[ done fd=%d ]\n", h->bulk_in);
     return 0;
 }
 
+static int bulk_read(int bulk_in, void *buf, size_t length)
+{
+    size_t count = 0;
+    int ret;
+
+    do {
+        ret = adb_read(bulk_in, buf + count, length - count);
+        if (ret < 0) {
+            if (errno != EINTR)
+                return ret;
+            } else
+            count += ret;
+    } while (count < length);
+
+    return count;
+}
+
 int usb_read(usb_handle *h, void *data, int len)
 {
     int n;
 
-    D("about to read (fd=%d, len=%d)\n", h->fd, len);
-    n = adb_read(h->fd, data, len);
+    D("about to read (fd=%d, len=%d)\n", h->bulk_out, len);
+    n = bulk_read(h->bulk_out, data, len);
     if(n != len) {
         D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
-            h->fd, n, errno, strerror(errno));
+            h->bulk_out, n, errno, strerror(errno));
         return -1;
     }
-    D("[ done fd=%d ]\n", h->fd);
+    D("[ done fd=%d ]\n", h->bulk_out);
+    return 0;
+}
+
+static int autoconfig(struct usb_handle *h)
+{
+    struct stat statb;
+
+    if (stat(h->EP0_NAME = "ep0", &statb) == 0) {
+        h->EP_OUT_NAME = "ep1";
+        h->EP_IN_NAME = "ep2";
+    } else {
+        h->EP0_NAME = 0;
+        return -ENODEV;
+    }
+
     return 0;
 }
 
@@ -113,37 +299,44 @@ void usb_init()
 {
     usb_handle *h;
     adb_thread_t tid;
-    int fd;
+
+    D("[ usb_init - using FunctionFS ]\n");
 
     h = calloc(1, sizeof(usb_handle));
-    h->fd = -1;
+    if (chdir(USB_FUNCFS_ROOT) < 0 || autoconfig(h) < 0) {
+	fatal_errno("[ can't recognize usb FunctionFS bulk device ]\n");
+	free(h);
+        return;
+    }
+
+    h->control = h->bulk_out = h->bulk_out = -1;
+
     adb_cond_init(&h->notify, 0);
     adb_mutex_init(&h->lock, 0);
 
-    // Open the file /dev/android_adb_enable to trigger 
-    // the enabling of the adb USB function in the kernel.
-    // We never touch this file again - just leave it open
-    // indefinitely so the kernel will know when we are running
-    // and when we are not.
-    fd = unix_open("/dev/android_adb_enable", O_RDWR);
-    if (fd < 0) {
-       D("failed to open /dev/android_adb_enable\n");
-    } else {
-        close_on_exec(fd);
-    }
-
     D("[ usb_init - starting thread ]\n");
     if(adb_thread_create(&tid, usb_open_thread, h)){
-        fatal_errno("cannot create usb thread");
+        fatal_errno("[ cannot create usb thread ]\n");
     }
 }
 
 void usb_kick(usb_handle *h)
 {
-    D("usb_kick\n");
+    int err;
+
+    err = ioctl(h->bulk_in, FUNCTIONFS_CLEAR_HALT);
+    if (err < 0)
+	perror("[ reset source fd ]\n");
+
+    err = ioctl(h->bulk_out, FUNCTIONFS_CLEAR_HALT);
+    if (err < 0)
+	perror("reset sink fd");
+
     adb_mutex_lock(&h->lock);
-    adb_close(h->fd);
-    h->fd = -1;
+    adb_close(h->control);
+    adb_close(h->bulk_out);
+    adb_close(h->bulk_in);
+    h->control = h->bulk_out = h->bulk_out = -1;
 
     // notify usb_open_thread that we are disconnected
     adb_cond_signal(&h->notify);
@@ -152,6 +345,7 @@ void usb_kick(usb_handle *h)
 
 int usb_close(usb_handle *h)
 {
-    // nothing to do here
+    free(h);
+
     return 0;
 }
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux