blob: 5066046a2d9a47b98a03962e8a098ad4c3b8b8f8 [file] [log] [blame]
Hridya Valsarajudea91b42018-07-17 11:14:01 -07001/*
2 * Copyright (C) 2018 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 "usb_client.h"
18
19#include <endian.h>
20#include <fcntl.h>
21#include <linux/usb/ch9.h>
22#include <linux/usb/functionfs.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27
28#include <android-base/logging.h>
29#include <android-base/properties.h>
30
31constexpr int kMaxPacketSizeFs = 64;
32constexpr int kMaxPacketSizeHs = 512;
33constexpr int kMaxPacketsizeSs = 1024;
34
35constexpr size_t kFbFfsNumBufs = 16;
Hridya Valsarajud747dba2019-05-21 13:03:24 -070036constexpr size_t kFbFfsBufSize = 16384;
Hridya Valsarajudea91b42018-07-17 11:14:01 -070037
38constexpr const char* kUsbFfsFastbootEp0 = "/dev/usb-ffs/fastboot/ep0";
39constexpr const char* kUsbFfsFastbootOut = "/dev/usb-ffs/fastboot/ep1";
40constexpr const char* kUsbFfsFastbootIn = "/dev/usb-ffs/fastboot/ep2";
41
42struct FuncDesc {
43 struct usb_interface_descriptor intf;
44 struct usb_endpoint_descriptor_no_audio source;
45 struct usb_endpoint_descriptor_no_audio sink;
46} __attribute__((packed));
47
48struct SsFuncDesc {
49 struct usb_interface_descriptor intf;
50 struct usb_endpoint_descriptor_no_audio source;
51 struct usb_ss_ep_comp_descriptor source_comp;
52 struct usb_endpoint_descriptor_no_audio sink;
53 struct usb_ss_ep_comp_descriptor sink_comp;
54} __attribute__((packed));
55
56struct DescV2 {
57 struct usb_functionfs_descs_head_v2 header;
58 // The rest of the structure depends on the flags in the header.
59 __le32 fs_count;
60 __le32 hs_count;
61 __le32 ss_count;
62 struct FuncDesc fs_descs, hs_descs;
63 struct SsFuncDesc ss_descs;
64} __attribute__((packed));
65
66struct usb_interface_descriptor fastboot_interface = {
67 .bLength = USB_DT_INTERFACE_SIZE,
68 .bDescriptorType = USB_DT_INTERFACE,
69 .bInterfaceNumber = 0,
70 .bNumEndpoints = 2,
71 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
72 .bInterfaceSubClass = 66,
73 .bInterfaceProtocol = 3,
74 .iInterface = 1, /* first string from the provided table */
75};
76
77static struct FuncDesc fs_descriptors = {
78 .intf = fastboot_interface,
79 .source =
80 {
81 .bLength = sizeof(fs_descriptors.source),
82 .bDescriptorType = USB_DT_ENDPOINT,
83 .bEndpointAddress = 1 | USB_DIR_OUT,
84 .bmAttributes = USB_ENDPOINT_XFER_BULK,
85 .wMaxPacketSize = kMaxPacketSizeFs,
86 },
87 .sink =
88 {
89 .bLength = sizeof(fs_descriptors.sink),
90 .bDescriptorType = USB_DT_ENDPOINT,
91 .bEndpointAddress = 1 | USB_DIR_IN,
92 .bmAttributes = USB_ENDPOINT_XFER_BULK,
93 .wMaxPacketSize = kMaxPacketSizeFs,
94 },
95};
96
97static struct FuncDesc hs_descriptors = {
98 .intf = fastboot_interface,
99 .source =
100 {
101 .bLength = sizeof(hs_descriptors.source),
102 .bDescriptorType = USB_DT_ENDPOINT,
103 .bEndpointAddress = 1 | USB_DIR_OUT,
104 .bmAttributes = USB_ENDPOINT_XFER_BULK,
105 .wMaxPacketSize = kMaxPacketSizeHs,
106 },
107 .sink =
108 {
109 .bLength = sizeof(hs_descriptors.sink),
110 .bDescriptorType = USB_DT_ENDPOINT,
111 .bEndpointAddress = 1 | USB_DIR_IN,
112 .bmAttributes = USB_ENDPOINT_XFER_BULK,
113 .wMaxPacketSize = kMaxPacketSizeHs,
114 },
115};
116
117static struct SsFuncDesc ss_descriptors = {
118 .intf = fastboot_interface,
119 .source =
120 {
121 .bLength = sizeof(ss_descriptors.source),
122 .bDescriptorType = USB_DT_ENDPOINT,
123 .bEndpointAddress = 1 | USB_DIR_OUT,
124 .bmAttributes = USB_ENDPOINT_XFER_BULK,
125 .wMaxPacketSize = kMaxPacketsizeSs,
126 },
127 .source_comp =
128 {
129 .bLength = sizeof(ss_descriptors.source_comp),
130 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
131 .bMaxBurst = 15,
132 },
133 .sink =
134 {
135 .bLength = sizeof(ss_descriptors.sink),
136 .bDescriptorType = USB_DT_ENDPOINT,
137 .bEndpointAddress = 1 | USB_DIR_IN,
138 .bmAttributes = USB_ENDPOINT_XFER_BULK,
139 .wMaxPacketSize = kMaxPacketsizeSs,
140 },
141 .sink_comp =
142 {
143 .bLength = sizeof(ss_descriptors.sink_comp),
144 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
145 .bMaxBurst = 15,
146 },
147};
148
149#define STR_INTERFACE_ "fastboot"
150
151static const struct {
152 struct usb_functionfs_strings_head header;
153 struct {
154 __le16 code;
155 const char str1[sizeof(STR_INTERFACE_)];
156 } __attribute__((packed)) lang0;
157} __attribute__((packed)) strings = {
158 .header =
159 {
160 .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
161 .length = htole32(sizeof(strings)),
162 .str_count = htole32(1),
163 .lang_count = htole32(1),
164 },
165 .lang0 =
166 {
167 htole16(0x0409), /* en-us */
168 STR_INTERFACE_,
169 },
170};
171
172static struct DescV2 v2_descriptor = {
173 .header =
174 {
175 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
176 .length = htole32(sizeof(v2_descriptor)),
177 .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
178 FUNCTIONFS_HAS_SS_DESC,
179 },
180 .fs_count = 3,
181 .hs_count = 3,
182 .ss_count = 5,
183 .fs_descs = fs_descriptors,
184 .hs_descs = hs_descriptors,
185 .ss_descs = ss_descriptors,
186};
187
188// Reimplementing since usb_ffs_close() does not close the control FD.
189static void CloseFunctionFs(usb_handle* h) {
Josh Gao860cc5a2018-08-21 15:44:49 -0700190 h->bulk_in.reset();
191 h->bulk_out.reset();
192 h->control.reset();
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700193}
194
195static bool InitFunctionFs(usb_handle* h) {
196 LOG(INFO) << "initializing functionfs";
197
198 if (h->control < 0) { // might have already done this before
199 LOG(INFO) << "opening control endpoint " << kUsbFfsFastbootEp0;
Josh Gao860cc5a2018-08-21 15:44:49 -0700200 h->control.reset(open(kUsbFfsFastbootEp0, O_RDWR));
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700201 if (h->control < 0) {
202 PLOG(ERROR) << "cannot open control endpoint " << kUsbFfsFastbootEp0;
203 goto err;
204 }
205
Josh Gao860cc5a2018-08-21 15:44:49 -0700206 auto ret = write(h->control.get(), &v2_descriptor, sizeof(v2_descriptor));
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700207 if (ret < 0) {
208 PLOG(ERROR) << "cannot write descriptors " << kUsbFfsFastbootEp0;
209 goto err;
210 }
211
Josh Gao860cc5a2018-08-21 15:44:49 -0700212 ret = write(h->control.get(), &strings, sizeof(strings));
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700213 if (ret < 0) {
214 PLOG(ERROR) << "cannot write strings " << kUsbFfsFastbootEp0;
215 goto err;
216 }
217 // Signal only when writing the descriptors to ffs
218 android::base::SetProperty("sys.usb.ffs.ready", "1");
219 }
220
Josh Gao860cc5a2018-08-21 15:44:49 -0700221 h->bulk_out.reset(open(kUsbFfsFastbootOut, O_RDONLY));
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700222 if (h->bulk_out < 0) {
223 PLOG(ERROR) << "cannot open bulk-out endpoint " << kUsbFfsFastbootOut;
224 goto err;
225 }
226
Josh Gao860cc5a2018-08-21 15:44:49 -0700227 h->bulk_in.reset(open(kUsbFfsFastbootIn, O_WRONLY));
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700228 if (h->bulk_in < 0) {
229 PLOG(ERROR) << "cannot open bulk-in endpoint " << kUsbFfsFastbootIn;
230 goto err;
231 }
232
Josh Gao860cc5a2018-08-21 15:44:49 -0700233 h->read_aiob.fd = h->bulk_out.get();
234 h->write_aiob.fd = h->bulk_in.get();
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700235 h->reads_zero_packets = false;
236 return true;
237
238err:
239 CloseFunctionFs(h);
240 return false;
241}
242
243ClientUsbTransport::ClientUsbTransport()
244 : handle_(std::unique_ptr<usb_handle>(create_usb_handle(kFbFfsNumBufs, kFbFfsBufSize))) {
245 if (!InitFunctionFs(handle_.get())) {
246 handle_.reset(nullptr);
247 }
248}
249
250ssize_t ClientUsbTransport::Read(void* data, size_t len) {
251 if (handle_ == nullptr || len > SSIZE_MAX) {
252 return -1;
253 }
254 char* char_data = static_cast<char*>(data);
255 size_t bytes_read_total = 0;
256 while (bytes_read_total < len) {
257 auto bytes_to_read = std::min(len - bytes_read_total, kFbFfsNumBufs * kFbFfsBufSize);
chihhao.chen8c544b62019-05-20 16:55:55 +0800258 auto bytes_read_now =
259 handle_->read(handle_.get(), char_data, bytes_to_read, true /* allow_partial */);
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700260 if (bytes_read_now < 0) {
Hridya Valsaraju8efadf72019-04-15 10:27:38 -0700261 return bytes_read_total == 0 ? -1 : bytes_read_total;
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700262 }
263 bytes_read_total += bytes_read_now;
264 char_data += bytes_read_now;
265 if (static_cast<size_t>(bytes_read_now) < bytes_to_read) {
266 break;
267 }
268 }
269 return bytes_read_total;
270}
271
272ssize_t ClientUsbTransport::Write(const void* data, size_t len) {
273 if (handle_ == nullptr || len > SSIZE_MAX) {
274 return -1;
275 }
276 const char* char_data = reinterpret_cast<const char*>(data);
277 size_t bytes_written_total = 0;
278 while (bytes_written_total < len) {
279 auto bytes_to_write = std::min(len - bytes_written_total, kFbFfsNumBufs * kFbFfsBufSize);
280 auto bytes_written_now = handle_->write(handle_.get(), data, bytes_to_write);
281 if (bytes_written_now < 0) {
Hridya Valsaraju8efadf72019-04-15 10:27:38 -0700282 return bytes_written_total == 0 ? -1 : bytes_written_total;
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700283 }
284 bytes_written_total += bytes_written_now;
285 char_data += bytes_written_now;
286 if (static_cast<size_t>(bytes_written_now) < bytes_to_write) {
287 break;
288 }
289 }
290 return bytes_written_total;
291}
292
293int ClientUsbTransport::Close() {
294 if (handle_ == nullptr) {
295 return -1;
296 }
297 CloseFunctionFs(handle_.get());
298 return 0;
299}