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