blob: 7a8e46f3eff0ba04ef5f062790a2c32d2d907649 [file] [log] [blame]
Colin Crossa3d386e2013-02-06 21:03:34 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <endian.h>
18#include <fcntl.h>
19#include <pthread.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
24
25#include <sys/ioctl.h>
26#include <sys/types.h>
27
28#include <linux/usb/ch9.h>
29#include <linux/usb/functionfs.h>
30
31#include "debug.h"
32#include "transport.h"
Szymon Starzycki2a656c32013-09-05 14:26:28 -070033#include "utils.h"
Colin Crossa3d386e2013-02-06 21:03:34 -080034
35#define TRACE_TAG TRACE_USB
36
37#define MAX_PACKET_SIZE_FS 64
38#define MAX_PACKET_SIZE_HS 512
39
40#define cpu_to_le16(x) htole16(x)
41#define cpu_to_le32(x) htole32(x)
42
43#define FASTBOOT_CLASS 0xff
44#define FASTBOOT_SUBCLASS 0x42
45#define FASTBOOT_PROTOCOL 0x3
46
47#define USB_FFS_FASTBOOT_PATH "/dev/usb-ffs/adb/"
48#define USB_FFS_FASTBOOT_EP(x) USB_FFS_FASTBOOT_PATH#x
49
50#define USB_FFS_FASTBOOT_EP0 USB_FFS_FASTBOOT_EP(ep0)
51#define USB_FFS_FASTBOOT_OUT USB_FFS_FASTBOOT_EP(ep1)
52#define USB_FFS_FASTBOOT_IN USB_FFS_FASTBOOT_EP(ep2)
53
Colin Crossa3d386e2013-02-06 21:03:34 -080054#define container_of(ptr, type, member) \
55 ((type*)((char*)(ptr) - offsetof(type, member)))
56
57struct usb_transport {
58 struct transport transport;
59
60 pthread_cond_t notify;
61 pthread_mutex_t lock;
62
63 int control;
64 int bulk_out; /* "out" from the host's perspective => source for fastbootd */
65 int bulk_in; /* "in" from the host's perspective => sink for fastbootd */
66};
67
68struct usb_handle {
69 struct transport_handle handle;
70};
71
72static const struct {
73 struct usb_functionfs_descs_head header;
74 struct {
75 struct usb_interface_descriptor intf;
76 struct usb_endpoint_descriptor_no_audio source;
77 struct usb_endpoint_descriptor_no_audio sink;
78 } __attribute__((packed)) fs_descs, hs_descs;
79} __attribute__((packed)) descriptors = {
80 .header = {
81 .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
82 .length = cpu_to_le32(sizeof(descriptors)),
83 .fs_count = 3,
84 .hs_count = 3,
85 },
86 .fs_descs = {
87 .intf = {
88 .bLength = sizeof(descriptors.fs_descs.intf),
89 .bDescriptorType = USB_DT_INTERFACE,
90 .bInterfaceNumber = 0,
91 .bNumEndpoints = 2,
92 .bInterfaceClass = FASTBOOT_CLASS,
93 .bInterfaceSubClass = FASTBOOT_SUBCLASS,
94 .bInterfaceProtocol = FASTBOOT_PROTOCOL,
95 .iInterface = 1, /* first string from the provided table */
96 },
97 .source = {
98 .bLength = sizeof(descriptors.fs_descs.source),
99 .bDescriptorType = USB_DT_ENDPOINT,
100 .bEndpointAddress = 1 | USB_DIR_OUT,
101 .bmAttributes = USB_ENDPOINT_XFER_BULK,
102 .wMaxPacketSize = MAX_PACKET_SIZE_FS,
103 },
104 .sink = {
105 .bLength = sizeof(descriptors.fs_descs.sink),
106 .bDescriptorType = USB_DT_ENDPOINT,
107 .bEndpointAddress = 2 | USB_DIR_IN,
108 .bmAttributes = USB_ENDPOINT_XFER_BULK,
109 .wMaxPacketSize = MAX_PACKET_SIZE_FS,
110 },
111 },
112 .hs_descs = {
113 .intf = {
114 .bLength = sizeof(descriptors.hs_descs.intf),
115 .bDescriptorType = USB_DT_INTERFACE,
116 .bInterfaceNumber = 0,
117 .bNumEndpoints = 2,
118 .bInterfaceClass = FASTBOOT_CLASS,
119 .bInterfaceSubClass = FASTBOOT_SUBCLASS,
120 .bInterfaceProtocol = FASTBOOT_PROTOCOL,
121 .iInterface = 1, /* first string from the provided table */
122 },
123 .source = {
124 .bLength = sizeof(descriptors.hs_descs.source),
125 .bDescriptorType = USB_DT_ENDPOINT,
126 .bEndpointAddress = 1 | USB_DIR_OUT,
127 .bmAttributes = USB_ENDPOINT_XFER_BULK,
128 .wMaxPacketSize = MAX_PACKET_SIZE_HS,
129 },
130 .sink = {
131 .bLength = sizeof(descriptors.hs_descs.sink),
132 .bDescriptorType = USB_DT_ENDPOINT,
133 .bEndpointAddress = 2 | USB_DIR_IN,
134 .bmAttributes = USB_ENDPOINT_XFER_BULK,
135 .wMaxPacketSize = MAX_PACKET_SIZE_HS,
136 },
137 },
138};
139
140#define STR_INTERFACE_ "Fastboot Interface"
141
142static const struct {
143 struct usb_functionfs_strings_head header;
144 struct {
145 __le16 code;
146 const char str1[sizeof(STR_INTERFACE_)];
147 } __attribute__((packed)) lang0;
148} __attribute__((packed)) strings = {
149 .header = {
150 .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
151 .length = cpu_to_le32(sizeof(strings)),
152 .str_count = cpu_to_le32(1),
153 .lang_count = cpu_to_le32(1),
154 },
155 .lang0 = {
156 cpu_to_le16(0x0409), /* en-us */
157 STR_INTERFACE_,
158 },
159};
160
161static int init_functionfs(struct usb_transport *usb_transport)
162{
163 ssize_t ret;
164
165 D(VERBOSE, "OPENING %s", USB_FFS_FASTBOOT_EP0);
166 usb_transport->control = open(USB_FFS_FASTBOOT_EP0, O_RDWR);
167 if (usb_transport->control < 0) {
168 D(ERR, "[ %s: cannot open control endpoint: errno=%d]", USB_FFS_FASTBOOT_EP0, errno);
169 goto err;
170 }
171
172 ret = write(usb_transport->control, &descriptors, sizeof(descriptors));
173 if (ret < 0) {
174 D(ERR, "[ %s: write descriptors failed: errno=%d ]", USB_FFS_FASTBOOT_EP0, errno);
175 goto err;
176 }
177
178 ret = write(usb_transport->control, &strings, sizeof(strings));
179 if (ret < 0) {
180 D(ERR, "[ %s: writing strings failed: errno=%d]", USB_FFS_FASTBOOT_EP0, errno);
181 goto err;
182 }
183
184 usb_transport->bulk_out = open(USB_FFS_FASTBOOT_OUT, O_RDWR);
185 if (usb_transport->bulk_out < 0) {
186 D(ERR, "[ %s: cannot open bulk-out ep: errno=%d ]", USB_FFS_FASTBOOT_OUT, errno);
187 goto err;
188 }
189
190 usb_transport->bulk_in = open(USB_FFS_FASTBOOT_IN, O_RDWR);
191 if (usb_transport->bulk_in < 0) {
192 D(ERR, "[ %s: cannot open bulk-in ep: errno=%d ]", USB_FFS_FASTBOOT_IN, errno);
193 goto err;
194 }
195
196 return 0;
197
198err:
199 if (usb_transport->bulk_in > 0) {
200 close(usb_transport->bulk_in);
201 usb_transport->bulk_in = -1;
202 }
203 if (usb_transport->bulk_out > 0) {
204 close(usb_transport->bulk_out);
205 usb_transport->bulk_out = -1;
206 }
207 if (usb_transport->control > 0) {
208 close(usb_transport->control);
209 usb_transport->control = -1;
210 }
211 return -1;
212}
213
Colin Crossa3d386e2013-02-06 21:03:34 -0800214static ssize_t usb_write(struct transport_handle *thandle, const void *data, size_t len)
215{
216 ssize_t ret;
217 struct transport *t = thandle->transport;
218 struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
219
220 D(DEBUG, "about to write (fd=%d, len=%d)", usb_transport->bulk_in, len);
221 ret = bulk_write(usb_transport->bulk_in, data, len);
222 if (ret < 0) {
223 D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_in, ret);
224 return -1;
225 }
226 D(DEBUG, "[ usb_write done fd=%d ]", usb_transport->bulk_in);
227 return ret;
228}
229
Colin Crossa3d386e2013-02-06 21:03:34 -0800230ssize_t usb_read(struct transport_handle *thandle, void *data, size_t len)
231{
232 ssize_t ret;
233 struct transport *t = thandle->transport;
234 struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
235
236 D(DEBUG, "about to read (fd=%d, len=%d)", usb_transport->bulk_out, len);
237 ret = bulk_read(usb_transport->bulk_out, data, len);
238 if (ret < 0) {
239 D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_out, ret);
240 return -1;
241 }
242 D(DEBUG, "[ usb_read done fd=%d ret=%zd]", usb_transport->bulk_out, ret);
243 return ret;
244}
245
246void usb_close(struct transport_handle *thandle)
247{
248 int err;
249 struct transport *t = thandle->transport;
250 struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
251
252 err = ioctl(usb_transport->bulk_in, FUNCTIONFS_CLEAR_HALT);
253 if (err < 0)
254 D(WARN, "[ kick: source (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_in, errno);
255
256 err = ioctl(usb_transport->bulk_out, FUNCTIONFS_CLEAR_HALT);
257 if (err < 0)
258 D(WARN, "[ kick: sink (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_out, errno);
259
260 pthread_mutex_lock(&usb_transport->lock);
261 close(usb_transport->control);
262 close(usb_transport->bulk_out);
263 close(usb_transport->bulk_in);
264 usb_transport->control = usb_transport->bulk_out = usb_transport->bulk_in = -1;
265
266 pthread_cond_signal(&usb_transport->notify);
267 pthread_mutex_unlock(&usb_transport->lock);
268}
269
270struct transport_handle *usb_connect(struct transport *transport)
271{
272 int ret;
273 struct usb_handle *usb_handle = calloc(sizeof(struct usb_handle), 1);
274 struct usb_transport *usb_transport = container_of(transport, struct usb_transport, transport);
275
276 pthread_mutex_lock(&usb_transport->lock);
277 while (usb_transport->control != -1)
278 pthread_cond_wait(&usb_transport->notify, &usb_transport->lock);
279 pthread_mutex_unlock(&usb_transport->lock);
280
281 ret = init_functionfs(usb_transport);
282 if (ret < 0) {
283 D(ERR, "usb connect: failed to initialize usb transport");
284 return NULL;
285 }
286
287 D(DEBUG, "[ usb_thread - registering device ]");
288 return &usb_handle->handle;
289}
290
291void usb_init()
292{
293 struct usb_transport *usb_transport = calloc(1, sizeof(struct usb_transport));
294
295 usb_transport->transport.connect = usb_connect;
296 usb_transport->transport.close = usb_close;
297 usb_transport->transport.read = usb_read;
298 usb_transport->transport.write = usb_write;
299 usb_transport->control = -1;
300 usb_transport->bulk_out = -1;
301 usb_transport->bulk_out = -1;
302
303 pthread_cond_init(&usb_transport->notify, NULL);
304 pthread_mutex_init(&usb_transport->lock, NULL);
305
306 transport_register(&usb_transport->transport);
307}
308