1dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/*
2dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
4dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * you may not use this file except in compliance with the License.
6dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * You may obtain a copy of the License at
7dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
8dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
10dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * See the License for the specific language governing permissions and
14dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * limitations under the License.
15dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
16dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
17dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdio.h>
18dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdlib.h>
19dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <unistd.h>
20dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <string.h>
21dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
22fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz#include <linux/usb/ch9.h>
23fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz#include <linux/usb/functionfs.h>
24dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/ioctl.h>
25dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/types.h>
26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <dirent.h>
27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <errno.h>
28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "sysdeps.h"
30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
31dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define   TRACE_TAG  TRACE_USB
32dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "adb.h"
33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
34fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz#define MAX_PACKET_SIZE_FS	64
35fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz#define MAX_PACKET_SIZE_HS	512
36fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
37fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz#define cpu_to_le16(x)  htole16(x)
38fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz#define cpu_to_le32(x)  htole32(x)
39dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
40dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstruct usb_handle
41dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
42dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    adb_cond_t notify;
43dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    adb_mutex_t lock;
44fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
45fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    int (*write)(usb_handle *h, const void *data, int len);
46fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    int (*read)(usb_handle *h, void *data, int len);
47fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    void (*kick)(usb_handle *h);
48fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
49fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    // Legacy f_adb
50fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    int fd;
51fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
52fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    // FunctionFS
53fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    int control;
54fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    int bulk_out; /* "out" from the host's perspective => source for adbd */
55fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    int bulk_in;  /* "in" from the host's perspective => sink for adbd */
56fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz};
57fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
58fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewiczstatic const struct {
59fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    struct usb_functionfs_descs_head header;
60fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    struct {
61fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        struct usb_interface_descriptor intf;
62fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        struct usb_endpoint_descriptor_no_audio source;
63fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        struct usb_endpoint_descriptor_no_audio sink;
64fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    } __attribute__((packed)) fs_descs, hs_descs;
65fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz} __attribute__((packed)) descriptors = {
66fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    .header = {
67fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
68fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .length = cpu_to_le32(sizeof(descriptors)),
69fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .fs_count = 3,
70fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .hs_count = 3,
71fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    },
72fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    .fs_descs = {
73fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .intf = {
74fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bLength = sizeof(descriptors.fs_descs.intf),
75fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bDescriptorType = USB_DT_INTERFACE,
76fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bInterfaceNumber = 0,
77fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bNumEndpoints = 2,
78fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bInterfaceClass = ADB_CLASS,
79fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bInterfaceSubClass = ADB_SUBCLASS,
80fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bInterfaceProtocol = ADB_PROTOCOL,
81fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .iInterface = 1, /* first string from the provided table */
82fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        },
83fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .source = {
84fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bLength = sizeof(descriptors.fs_descs.source),
85fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bDescriptorType = USB_DT_ENDPOINT,
86fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bEndpointAddress = 1 | USB_DIR_OUT,
87fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bmAttributes = USB_ENDPOINT_XFER_BULK,
88fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
89fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        },
90fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .sink = {
91fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bLength = sizeof(descriptors.fs_descs.sink),
92fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bDescriptorType = USB_DT_ENDPOINT,
93fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bEndpointAddress = 2 | USB_DIR_IN,
94fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bmAttributes = USB_ENDPOINT_XFER_BULK,
95fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
96fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        },
97fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    },
98fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    .hs_descs = {
99fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .intf = {
100fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bLength = sizeof(descriptors.hs_descs.intf),
101fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bDescriptorType = USB_DT_INTERFACE,
102fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bInterfaceNumber = 0,
103fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bNumEndpoints = 2,
104fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bInterfaceClass = ADB_CLASS,
105fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bInterfaceSubClass = ADB_SUBCLASS,
106fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bInterfaceProtocol = ADB_PROTOCOL,
107fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .iInterface = 1, /* first string from the provided table */
108fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        },
109fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .source = {
110fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bLength = sizeof(descriptors.hs_descs.source),
111fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bDescriptorType = USB_DT_ENDPOINT,
112fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bEndpointAddress = 1 | USB_DIR_OUT,
113fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bmAttributes = USB_ENDPOINT_XFER_BULK,
114fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
115fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        },
116fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .sink = {
117fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bLength = sizeof(descriptors.hs_descs.sink),
118fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bDescriptorType = USB_DT_ENDPOINT,
119fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bEndpointAddress = 2 | USB_DIR_IN,
120fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .bmAttributes = USB_ENDPOINT_XFER_BULK,
121fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
122fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        },
123fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    },
124fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz};
125fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
126fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz#define STR_INTERFACE_ "ADB Interface"
127fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
128fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewiczstatic const struct {
129fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    struct usb_functionfs_strings_head header;
130fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    struct {
131fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        __le16 code;
132fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        const char str1[sizeof(STR_INTERFACE_)];
133fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    } __attribute__((packed)) lang0;
134fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz} __attribute__((packed)) strings = {
135fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    .header = {
136fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
137fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .length = cpu_to_le32(sizeof(strings)),
138fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .str_count = cpu_to_le32(1),
139fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        .lang_count = cpu_to_le32(1),
140fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    },
141fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    .lang0 = {
142fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        cpu_to_le16(0x0409), /* en-us */
143fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        STR_INTERFACE_,
144fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    },
145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project};
146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
148fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
149fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewiczstatic void *usb_adb_open_thread(void *x)
150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct usb_handle *usb = (struct usb_handle *)x;
152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int fd;
153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (1) {
155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // wait until the USB device needs opening
156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        adb_mutex_lock(&usb->lock);
157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        while (usb->fd != -1)
158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            adb_cond_wait(&usb->notify, &usb->lock);
159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        adb_mutex_unlock(&usb->lock);
160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        D("[ usb_thread - opening device ]\n");
162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        do {
163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            /* XXX use inotify? */
164dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            fd = unix_open("/dev/android_adb", O_RDWR);
165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (fd < 0) {
166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                // to support older kernels
167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                fd = unix_open("/dev/android", O_RDWR);
168dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (fd < 0) {
170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                adb_sleep_ms(1000);
171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
172dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } while (fd < 0);
173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        D("[ opening device succeeded ]\n");
174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        close_on_exec(fd);
176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        usb->fd = fd;
177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        D("[ usb_thread - registering device ]\n");
179e109d266c12c5f537d429ca4b892f2719e02c2daScott Anderson        register_usb_transport(usb, 0, 0, 1);
180dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
182dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // never gets here
183dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
184dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
185dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
186fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewiczstatic int usb_adb_write(usb_handle *h, const void *data, int len)
187dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
188dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int n;
189dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
190408fa57864c01113deaa213e5c1848a9c594ae92JP Abgrall    D("about to write (fd=%d, len=%d)\n", h->fd, len);
191dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    n = adb_write(h->fd, data, len);
192dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if(n != len) {
193408fa57864c01113deaa213e5c1848a9c594ae92JP Abgrall        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
194408fa57864c01113deaa213e5c1848a9c594ae92JP Abgrall            h->fd, n, errno, strerror(errno));
195dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
196dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
197408fa57864c01113deaa213e5c1848a9c594ae92JP Abgrall    D("[ done fd=%d ]\n", h->fd);
198dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
199dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
200dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
201fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewiczstatic int usb_adb_read(usb_handle *h, void *data, int len)
202dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
203dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int n;
204dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
205408fa57864c01113deaa213e5c1848a9c594ae92JP Abgrall    D("about to read (fd=%d, len=%d)\n", h->fd, len);
206dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    n = adb_read(h->fd, data, len);
207dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if(n != len) {
208408fa57864c01113deaa213e5c1848a9c594ae92JP Abgrall        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
209408fa57864c01113deaa213e5c1848a9c594ae92JP Abgrall            h->fd, n, errno, strerror(errno));
210dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
211dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
212408fa57864c01113deaa213e5c1848a9c594ae92JP Abgrall    D("[ done fd=%d ]\n", h->fd);
213dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
214dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
215dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
216fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewiczstatic void usb_adb_kick(usb_handle *h)
217fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz{
218fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    D("usb_kick\n");
219fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    adb_mutex_lock(&h->lock);
220fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    adb_close(h->fd);
221fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    h->fd = -1;
222fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
223fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    // notify usb_adb_open_thread that we are disconnected
224fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    adb_cond_signal(&h->notify);
225fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    adb_mutex_unlock(&h->lock);
226fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz}
227fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
228fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewiczstatic void usb_adb_init()
229dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
230dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    usb_handle *h;
231dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    adb_thread_t tid;
232dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int fd;
233dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
234dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    h = calloc(1, sizeof(usb_handle));
235fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
236fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    h->write = usb_adb_write;
237fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    h->read = usb_adb_read;
238fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    h->kick = usb_adb_kick;
239dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    h->fd = -1;
240fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
241dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    adb_cond_init(&h->notify, 0);
242dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    adb_mutex_init(&h->lock, 0);
243dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
244dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Open the file /dev/android_adb_enable to trigger
245dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // the enabling of the adb USB function in the kernel.
246dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // We never touch this file again - just leave it open
247dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // indefinitely so the kernel will know when we are running
248dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // and when we are not.
249dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    fd = unix_open("/dev/android_adb_enable", O_RDWR);
250dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (fd < 0) {
251dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project       D("failed to open /dev/android_adb_enable\n");
252dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
253dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        close_on_exec(fd);
254dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
255dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
256dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    D("[ usb_init - starting thread ]\n");
257fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    if(adb_thread_create(&tid, usb_adb_open_thread, h)){
258dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fatal_errno("cannot create usb thread");
259dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
260dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
261dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
262fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
263fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewiczstatic void init_functionfs(struct usb_handle *h)
264dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
265fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    ssize_t ret;
266fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
267fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    D("OPENING %s\n", USB_FFS_ADB_EP0);
268fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR);
269fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    if (h->control < 0) {
270fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        D("[ %s: cannot open control endpoint: errno=%d]\n", USB_FFS_ADB_EP0, errno);
271fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        goto err;
272fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    }
273fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
274fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    ret = adb_write(h->control, &descriptors, sizeof(descriptors));
275fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    if (ret < 0) {
276fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno);
277fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        goto err;
278fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    }
279fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
280fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    ret = adb_write(h->control, &strings, sizeof(strings));
281fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    if (ret < 0) {
282fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        D("[ %s: writing strings failed: errno=%d]\n", USB_FFS_ADB_EP0, errno);
283fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        goto err;
284fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    }
285fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
286fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR);
287fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    if (h->bulk_out < 0) {
288fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        D("[ %s: cannot open bulk-out ep: errno=%d ]\n", USB_FFS_ADB_OUT, errno);
289fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        goto err;
290fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    }
291fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
292fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    h->bulk_in = adb_open(USB_FFS_ADB_IN, O_RDWR);
293fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    if (h->bulk_in < 0) {
294fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        D("[ %s: cannot open bulk-in ep: errno=%d ]\n", USB_FFS_ADB_IN, errno);
295fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        goto err;
296fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    }
297fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
298fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    return;
299fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
300fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewiczerr:
301fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    if (h->bulk_in > 0) {
302fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        adb_close(h->bulk_in);
303fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        h->bulk_in = -1;
304fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    }
305fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    if (h->bulk_out > 0) {
306fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        adb_close(h->bulk_out);
307fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        h->bulk_out = -1;
308fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    }
309fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    if (h->control > 0) {
310fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        adb_close(h->control);
311fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        h->control = -1;
312fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    }
313fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    return;
314fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz}
315fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
316fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewiczstatic void *usb_ffs_open_thread(void *x)
317fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz{
318fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    struct usb_handle *usb = (struct usb_handle *)x;
319fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
320fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    while (1) {
321fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        // wait until the USB device needs opening
322fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        adb_mutex_lock(&usb->lock);
323fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        while (usb->control != -1)
324fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            adb_cond_wait(&usb->notify, &usb->lock);
325fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        adb_mutex_unlock(&usb->lock);
326fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
327fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        while (1) {
328fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            init_functionfs(usb);
329fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
330fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            if (usb->control >= 0)
331fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz                break;
332fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
333fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            adb_sleep_ms(1000);
334fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        }
335fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
336fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        D("[ usb_thread - registering device ]\n");
337fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        register_usb_transport(usb, 0, 0, 1);
338fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    }
339fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
340fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    // never gets here
341fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    return 0;
342fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz}
343fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
344fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewiczstatic int bulk_write(int bulk_in, const char *buf, size_t length)
345fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz{
346fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    size_t count = 0;
347fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    int ret;
348fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
349fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    do {
350fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        ret = adb_write(bulk_in, buf + count, length - count);
351fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        if (ret < 0) {
352fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            if (errno != EINTR)
353fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz                return ret;
354fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        } else {
355fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            count += ret;
356fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        }
357fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    } while (count < length);
358fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
359fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    D("[ bulk_write done fd=%d ]\n", bulk_in);
360fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    return count;
361fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz}
362fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
363fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewiczstatic int usb_ffs_write(usb_handle *h, const void *data, int len)
364fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz{
365fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    int n;
366fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
367fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    D("about to write (fd=%d, len=%d)\n", h->bulk_in, len);
368fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    n = bulk_write(h->bulk_in, data, len);
369fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    if (n != len) {
370fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
371fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            h->bulk_in, n, errno, strerror(errno));
372fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        return -1;
373fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    }
374fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    D("[ done fd=%d ]\n", h->bulk_in);
375fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    return 0;
376fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz}
377fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
378fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewiczstatic int bulk_read(int bulk_out, char *buf, size_t length)
379fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz{
380fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    size_t count = 0;
381fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    int ret;
382fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
383fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    do {
384fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        ret = adb_read(bulk_out, buf + count, length - count);
385fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        if (ret < 0) {
386fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            if (errno != EINTR) {
387fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz                D("[ bulk_read failed fd=%d length=%d count=%d ]\n",
388fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz                                           bulk_out, length, count);
389fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz                return ret;
390fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            }
391fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        } else {
392fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz            count += ret;
393fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz        }
394fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    } while (count < length);
395fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
396fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz    return count;
397fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz}
398fd96db17b7f07eb6615af01fd1908b74383bf04bAndrzej Pietrasiewicz
399