blob: 965985d1aa7eaf605110264fd57d6cf22f115554 [file] [log] [blame]
Jerry Zhang487be612016-10-24 12:10:41 -07001/*
2 * Copyright (C) 2016 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 <android-base/logging.h>
18#include <android-base/properties.h>
Jerry Zhangdf69dd32017-05-03 17:17:49 -070019#include <asyncio/AsyncIO.h>
Jerry Zhang487be612016-10-24 12:10:41 -070020#include <dirent.h>
21#include <errno.h>
22#include <fcntl.h>
23#include <linux/usb/ch9.h>
24#include <linux/usb/functionfs.h>
Jerry Zhangdf69dd32017-05-03 17:17:49 -070025#include <memory>
Jerry Zhang487be612016-10-24 12:10:41 -070026#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <sys/endian.h>
Jerry Zhangdf69dd32017-05-03 17:17:49 -070030#include <sys/eventfd.h>
Jerry Zhang487be612016-10-24 12:10:41 -070031#include <sys/ioctl.h>
Jerry Zhange9d94422017-01-18 12:03:56 -080032#include <sys/mman.h>
Jerry Zhangdf69dd32017-05-03 17:17:49 -070033#include <sys/poll.h>
Jerry Zhang487be612016-10-24 12:10:41 -070034#include <sys/stat.h>
35#include <sys/types.h>
36#include <unistd.h>
Jerry Zhang487be612016-10-24 12:10:41 -070037
Jerry Zhangdf69dd32017-05-03 17:17:49 -070038#include "PosixAsyncIO.h"
Jerry Zhang487be612016-10-24 12:10:41 -070039#include "MtpFfsHandle.h"
Jerry Zhangcc9d0fd2017-01-27 10:29:59 -080040#include "mtp.h"
Jerry Zhang487be612016-10-24 12:10:41 -070041
Jerry Zhang487be612016-10-24 12:10:41 -070042namespace {
43
44constexpr char FFS_MTP_EP_IN[] = "/dev/usb-ffs/mtp/ep1";
45constexpr char FFS_MTP_EP_OUT[] = "/dev/usb-ffs/mtp/ep2";
46constexpr char FFS_MTP_EP_INTR[] = "/dev/usb-ffs/mtp/ep3";
47
48constexpr int MAX_PACKET_SIZE_FS = 64;
49constexpr int MAX_PACKET_SIZE_HS = 512;
50constexpr int MAX_PACKET_SIZE_SS = 1024;
Jerry Zhangdf69dd32017-05-03 17:17:49 -070051constexpr int MAX_PACKET_SIZE_EV = 28;
Jerry Zhang487be612016-10-24 12:10:41 -070052
Jerry Zhangdf69dd32017-05-03 17:17:49 -070053constexpr unsigned AIO_BUFS_MAX = 128;
54constexpr unsigned AIO_BUF_LEN = 16384;
Jerry Zhang487be612016-10-24 12:10:41 -070055
Jerry Zhangdf69dd32017-05-03 17:17:49 -070056constexpr unsigned FFS_NUM_EVENTS = 5;
Jerry Zhang487be612016-10-24 12:10:41 -070057
Jerry Zhangdf69dd32017-05-03 17:17:49 -070058constexpr unsigned MAX_FILE_CHUNK_SIZE = AIO_BUFS_MAX * AIO_BUF_LEN;
Jerry Zhangb4f54262017-02-02 18:14:33 -080059
Jerry Zhangdf69dd32017-05-03 17:17:49 -070060constexpr uint32_t MAX_MTP_FILE_SIZE = 0xFFFFFFFF;
Jerry Zhang487be612016-10-24 12:10:41 -070061
Jerry Zhangdf69dd32017-05-03 17:17:49 -070062struct timespec ZERO_TIMEOUT = { 0, 0 };
Jerry Zhangb4f54262017-02-02 18:14:33 -080063
Jerry Zhang487be612016-10-24 12:10:41 -070064struct func_desc {
65 struct usb_interface_descriptor intf;
66 struct usb_endpoint_descriptor_no_audio sink;
67 struct usb_endpoint_descriptor_no_audio source;
68 struct usb_endpoint_descriptor_no_audio intr;
69} __attribute__((packed));
70
71struct ss_func_desc {
72 struct usb_interface_descriptor intf;
73 struct usb_endpoint_descriptor_no_audio sink;
74 struct usb_ss_ep_comp_descriptor sink_comp;
75 struct usb_endpoint_descriptor_no_audio source;
76 struct usb_ss_ep_comp_descriptor source_comp;
77 struct usb_endpoint_descriptor_no_audio intr;
78 struct usb_ss_ep_comp_descriptor intr_comp;
79} __attribute__((packed));
80
81struct desc_v1 {
82 struct usb_functionfs_descs_head_v1 {
83 __le32 magic;
84 __le32 length;
85 __le32 fs_count;
86 __le32 hs_count;
87 } __attribute__((packed)) header;
88 struct func_desc fs_descs, hs_descs;
89} __attribute__((packed));
90
91struct desc_v2 {
92 struct usb_functionfs_descs_head_v2 header;
93 // The rest of the structure depends on the flags in the header.
94 __le32 fs_count;
95 __le32 hs_count;
96 __le32 ss_count;
Jerry Zhang51bf9852017-08-31 11:57:45 -070097 __le32 os_count;
Jerry Zhang487be612016-10-24 12:10:41 -070098 struct func_desc fs_descs, hs_descs;
99 struct ss_func_desc ss_descs;
Jerry Zhang51bf9852017-08-31 11:57:45 -0700100 struct usb_os_desc_header os_header;
101 struct usb_ext_compat_desc os_desc;
Jerry Zhang487be612016-10-24 12:10:41 -0700102} __attribute__((packed));
103
104const struct usb_interface_descriptor mtp_interface_desc = {
105 .bLength = USB_DT_INTERFACE_SIZE,
106 .bDescriptorType = USB_DT_INTERFACE,
107 .bInterfaceNumber = 0,
108 .bNumEndpoints = 3,
109 .bInterfaceClass = USB_CLASS_STILL_IMAGE,
110 .bInterfaceSubClass = 1,
111 .bInterfaceProtocol = 1,
Jerry Zhang6a790522017-01-11 15:17:53 -0800112 .iInterface = 1,
Jerry Zhang487be612016-10-24 12:10:41 -0700113};
114
115const struct usb_interface_descriptor ptp_interface_desc = {
116 .bLength = USB_DT_INTERFACE_SIZE,
117 .bDescriptorType = USB_DT_INTERFACE,
118 .bInterfaceNumber = 0,
119 .bNumEndpoints = 3,
120 .bInterfaceClass = USB_CLASS_STILL_IMAGE,
121 .bInterfaceSubClass = 1,
122 .bInterfaceProtocol = 1,
123};
124
125const struct usb_endpoint_descriptor_no_audio fs_sink = {
126 .bLength = USB_DT_ENDPOINT_SIZE,
127 .bDescriptorType = USB_DT_ENDPOINT,
128 .bEndpointAddress = 1 | USB_DIR_IN,
129 .bmAttributes = USB_ENDPOINT_XFER_BULK,
130 .wMaxPacketSize = MAX_PACKET_SIZE_FS,
131};
132
133const struct usb_endpoint_descriptor_no_audio fs_source = {
134 .bLength = USB_DT_ENDPOINT_SIZE,
135 .bDescriptorType = USB_DT_ENDPOINT,
136 .bEndpointAddress = 2 | USB_DIR_OUT,
137 .bmAttributes = USB_ENDPOINT_XFER_BULK,
138 .wMaxPacketSize = MAX_PACKET_SIZE_FS,
139};
140
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700141const struct usb_endpoint_descriptor_no_audio intr = {
Jerry Zhang487be612016-10-24 12:10:41 -0700142 .bLength = USB_DT_ENDPOINT_SIZE,
143 .bDescriptorType = USB_DT_ENDPOINT,
144 .bEndpointAddress = 3 | USB_DIR_IN,
145 .bmAttributes = USB_ENDPOINT_XFER_INT,
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700146 .wMaxPacketSize = MAX_PACKET_SIZE_EV,
Jerry Zhang487be612016-10-24 12:10:41 -0700147 .bInterval = 6,
148};
149
150const struct usb_endpoint_descriptor_no_audio hs_sink = {
151 .bLength = USB_DT_ENDPOINT_SIZE,
152 .bDescriptorType = USB_DT_ENDPOINT,
153 .bEndpointAddress = 1 | USB_DIR_IN,
154 .bmAttributes = USB_ENDPOINT_XFER_BULK,
155 .wMaxPacketSize = MAX_PACKET_SIZE_HS,
156};
157
158const struct usb_endpoint_descriptor_no_audio hs_source = {
159 .bLength = USB_DT_ENDPOINT_SIZE,
160 .bDescriptorType = USB_DT_ENDPOINT,
161 .bEndpointAddress = 2 | USB_DIR_OUT,
162 .bmAttributes = USB_ENDPOINT_XFER_BULK,
163 .wMaxPacketSize = MAX_PACKET_SIZE_HS,
164};
165
Jerry Zhang487be612016-10-24 12:10:41 -0700166const struct usb_endpoint_descriptor_no_audio ss_sink = {
167 .bLength = USB_DT_ENDPOINT_SIZE,
168 .bDescriptorType = USB_DT_ENDPOINT,
169 .bEndpointAddress = 1 | USB_DIR_IN,
170 .bmAttributes = USB_ENDPOINT_XFER_BULK,
171 .wMaxPacketSize = MAX_PACKET_SIZE_SS,
172};
173
174const struct usb_endpoint_descriptor_no_audio ss_source = {
175 .bLength = USB_DT_ENDPOINT_SIZE,
176 .bDescriptorType = USB_DT_ENDPOINT,
177 .bEndpointAddress = 2 | USB_DIR_OUT,
178 .bmAttributes = USB_ENDPOINT_XFER_BULK,
179 .wMaxPacketSize = MAX_PACKET_SIZE_SS,
180};
181
Jerry Zhang487be612016-10-24 12:10:41 -0700182const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
183 .bLength = sizeof(ss_sink_comp),
184 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
Jerry Zhang2a141682017-02-13 14:24:13 -0800185 .bMaxBurst = 6,
Jerry Zhang487be612016-10-24 12:10:41 -0700186};
187
188const struct usb_ss_ep_comp_descriptor ss_source_comp = {
189 .bLength = sizeof(ss_source_comp),
190 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
Jerry Zhang2a141682017-02-13 14:24:13 -0800191 .bMaxBurst = 6,
Jerry Zhang487be612016-10-24 12:10:41 -0700192};
193
194const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
195 .bLength = sizeof(ss_intr_comp),
196 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
197};
198
199const struct func_desc mtp_fs_descriptors = {
200 .intf = mtp_interface_desc,
201 .sink = fs_sink,
202 .source = fs_source,
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700203 .intr = intr,
Jerry Zhang487be612016-10-24 12:10:41 -0700204};
205
206const struct func_desc mtp_hs_descriptors = {
207 .intf = mtp_interface_desc,
208 .sink = hs_sink,
209 .source = hs_source,
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700210 .intr = intr,
Jerry Zhang487be612016-10-24 12:10:41 -0700211};
212
213const struct ss_func_desc mtp_ss_descriptors = {
214 .intf = mtp_interface_desc,
215 .sink = ss_sink,
216 .sink_comp = ss_sink_comp,
217 .source = ss_source,
218 .source_comp = ss_source_comp,
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700219 .intr = intr,
Jerry Zhang487be612016-10-24 12:10:41 -0700220 .intr_comp = ss_intr_comp,
221};
222
223const struct func_desc ptp_fs_descriptors = {
224 .intf = ptp_interface_desc,
225 .sink = fs_sink,
226 .source = fs_source,
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700227 .intr = intr,
Jerry Zhang487be612016-10-24 12:10:41 -0700228};
229
230const struct func_desc ptp_hs_descriptors = {
231 .intf = ptp_interface_desc,
232 .sink = hs_sink,
233 .source = hs_source,
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700234 .intr = intr,
Jerry Zhang487be612016-10-24 12:10:41 -0700235};
236
237const struct ss_func_desc ptp_ss_descriptors = {
238 .intf = ptp_interface_desc,
239 .sink = ss_sink,
240 .sink_comp = ss_sink_comp,
241 .source = ss_source,
242 .source_comp = ss_source_comp,
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700243 .intr = intr,
Jerry Zhang487be612016-10-24 12:10:41 -0700244 .intr_comp = ss_intr_comp,
245};
246
Jerry Zhang6a790522017-01-11 15:17:53 -0800247#define STR_INTERFACE "MTP"
Jerry Zhang487be612016-10-24 12:10:41 -0700248const struct {
249 struct usb_functionfs_strings_head header;
Jerry Zhang6a790522017-01-11 15:17:53 -0800250 struct {
251 __le16 code;
252 const char str1[sizeof(STR_INTERFACE)];
253 } __attribute__((packed)) lang0;
Jerry Zhang487be612016-10-24 12:10:41 -0700254} __attribute__((packed)) strings = {
255 .header = {
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700256 .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
257 .length = htole32(sizeof(strings)),
258 .str_count = htole32(1),
259 .lang_count = htole32(1),
Jerry Zhang6a790522017-01-11 15:17:53 -0800260 },
261 .lang0 = {
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700262 .code = htole16(0x0409),
Jerry Zhang6a790522017-01-11 15:17:53 -0800263 .str1 = STR_INTERFACE,
Jerry Zhang487be612016-10-24 12:10:41 -0700264 },
265};
266
Jerry Zhang51bf9852017-08-31 11:57:45 -0700267struct usb_os_desc_header mtp_os_desc_header = {
268 .interface = htole32(1),
269 .dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
270 .bcdVersion = htole16(1),
271 .wIndex = htole16(4),
272 .bCount = htole16(1),
273 .Reserved = htole16(0),
274};
275
276struct usb_ext_compat_desc mtp_os_desc_compat = {
277 .bFirstInterfaceNumber = 0,
278 .Reserved1 = htole32(1),
279 .CompatibleID = { 'M', 'T', 'P' },
280 .SubCompatibleID = {0},
281 .Reserved2 = {0},
282};
283
284struct usb_ext_compat_desc ptp_os_desc_compat = {
285 .bFirstInterfaceNumber = 0,
286 .Reserved1 = htole32(1),
287 .CompatibleID = { 'P', 'T', 'P' },
288 .SubCompatibleID = {0},
289 .Reserved2 = {0},
290};
291
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700292struct mtp_device_status {
293 uint16_t wLength;
294 uint16_t wCode;
295};
296
Jerry Zhang487be612016-10-24 12:10:41 -0700297} // anonymous namespace
298
299namespace android {
300
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700301int MtpFfsHandle::getPacketSize(int ffs_fd) {
302 struct usb_endpoint_descriptor desc;
303 if (ioctl(ffs_fd, FUNCTIONFS_ENDPOINT_DESC, reinterpret_cast<unsigned long>(&desc))) {
304 PLOG(ERROR) << "Could not get FFS bulk-in descriptor";
305 return MAX_PACKET_SIZE_HS;
306 } else {
307 return desc.wMaxPacketSize;
308 }
309}
310
311MtpFfsHandle::MtpFfsHandle() {}
Jerry Zhang487be612016-10-24 12:10:41 -0700312
313MtpFfsHandle::~MtpFfsHandle() {}
314
315void MtpFfsHandle::closeEndpoints() {
316 mIntr.reset();
317 mBulkIn.reset();
318 mBulkOut.reset();
319}
320
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700321bool MtpFfsHandle::openEndpoints() {
322 if (mBulkIn < 0) {
323 mBulkIn.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_IN, O_RDWR)));
324 if (mBulkIn < 0) {
325 PLOG(ERROR) << FFS_MTP_EP_IN << ": cannot open bulk in ep";
326 return false;
327 }
328 }
329
330 if (mBulkOut < 0) {
331 mBulkOut.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_OUT, O_RDWR)));
332 if (mBulkOut < 0) {
333 PLOG(ERROR) << FFS_MTP_EP_OUT << ": cannot open bulk out ep";
334 return false;
335 }
336 }
337
338 if (mIntr < 0) {
339 mIntr.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_INTR, O_RDWR)));
340 if (mIntr < 0) {
341 PLOG(ERROR) << FFS_MTP_EP_INTR << ": cannot open intr ep";
342 return false;
343 }
344 }
345 return true;
346}
347
348void MtpFfsHandle::advise(int fd) {
349 for (unsigned i = 0; i < NUM_IO_BUFS; i++) {
350 if (posix_madvise(mIobuf[i].bufs.data(), MAX_FILE_CHUNK_SIZE,
351 POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED) < 0)
352 PLOG(ERROR) << "Failed to madvise";
353 }
354 if (posix_fadvise(fd, 0, 0,
355 POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE | POSIX_FADV_WILLNEED) < 0)
356 PLOG(ERROR) << "Failed to fadvise";
357}
358
Jerry Zhang487be612016-10-24 12:10:41 -0700359bool MtpFfsHandle::initFunctionfs() {
360 ssize_t ret;
361 struct desc_v1 v1_descriptor;
362 struct desc_v2 v2_descriptor;
363
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700364 v2_descriptor.header.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
365 v2_descriptor.header.length = htole32(sizeof(v2_descriptor));
Jerry Zhang487be612016-10-24 12:10:41 -0700366 v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
Jerry Zhang51bf9852017-08-31 11:57:45 -0700367 FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
Jerry Zhang487be612016-10-24 12:10:41 -0700368 v2_descriptor.fs_count = 4;
369 v2_descriptor.hs_count = 4;
370 v2_descriptor.ss_count = 7;
Jerry Zhang51bf9852017-08-31 11:57:45 -0700371 v2_descriptor.os_count = 1;
Jerry Zhang487be612016-10-24 12:10:41 -0700372 v2_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
373 v2_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
374 v2_descriptor.ss_descs = mPtp ? ptp_ss_descriptors : mtp_ss_descriptors;
Jerry Zhang51bf9852017-08-31 11:57:45 -0700375 v2_descriptor.os_header = mtp_os_desc_header;
376 v2_descriptor.os_desc = mPtp ? ptp_os_desc_compat : mtp_os_desc_compat;
Jerry Zhang487be612016-10-24 12:10:41 -0700377
378 if (mControl < 0) { // might have already done this before
379 mControl.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP0, O_RDWR)));
380 if (mControl < 0) {
381 PLOG(ERROR) << FFS_MTP_EP0 << ": cannot open control endpoint";
382 goto err;
383 }
384
385 ret = TEMP_FAILURE_RETRY(::write(mControl, &v2_descriptor, sizeof(v2_descriptor)));
386 if (ret < 0) {
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700387 v1_descriptor.header.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC);
388 v1_descriptor.header.length = htole32(sizeof(v1_descriptor));
Jerry Zhang487be612016-10-24 12:10:41 -0700389 v1_descriptor.header.fs_count = 4;
390 v1_descriptor.header.hs_count = 4;
391 v1_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
392 v1_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
393 PLOG(ERROR) << FFS_MTP_EP0 << "Switching to V1 descriptor format";
394 ret = TEMP_FAILURE_RETRY(::write(mControl, &v1_descriptor, sizeof(v1_descriptor)));
395 if (ret < 0) {
396 PLOG(ERROR) << FFS_MTP_EP0 << "Writing descriptors failed";
397 goto err;
398 }
399 }
400 ret = TEMP_FAILURE_RETRY(::write(mControl, &strings, sizeof(strings)));
401 if (ret < 0) {
402 PLOG(ERROR) << FFS_MTP_EP0 << "Writing strings failed";
403 goto err;
404 }
405 }
Jerry Zhang487be612016-10-24 12:10:41 -0700406
Jerry Zhang487be612016-10-24 12:10:41 -0700407 return true;
408
409err:
Jerry Zhang487be612016-10-24 12:10:41 -0700410 closeConfig();
411 return false;
412}
413
414void MtpFfsHandle::closeConfig() {
415 mControl.reset();
416}
417
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700418int MtpFfsHandle::doAsync(void* data, size_t len, bool read) {
419 struct io_event ioevs[1];
420 if (len > AIO_BUF_LEN) {
421 LOG(ERROR) << "Mtp read/write too large " << len;
422 errno = EINVAL;
423 return -1;
Jerry Zhang487be612016-10-24 12:10:41 -0700424 }
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700425 mIobuf[0].buf[0] = reinterpret_cast<unsigned char*>(data);
426 if (iobufSubmit(&mIobuf[0], read ? mBulkOut : mBulkIn, len, read) == -1)
427 return -1;
428 int ret = waitEvents(&mIobuf[0], 1, ioevs, nullptr);
429 mIobuf[0].buf[0] = mIobuf[0].bufs.data();
Jerry Zhang487be612016-10-24 12:10:41 -0700430 return ret;
431}
432
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700433int MtpFfsHandle::read(void* data, size_t len) {
434 return doAsync(data, len, true);
435}
436
437int MtpFfsHandle::write(const void* data, size_t len) {
438 return doAsync(const_cast<void*>(data), len, false);
439}
440
441int MtpFfsHandle::handleEvent() {
442
443 std::vector<usb_functionfs_event> events(FFS_NUM_EVENTS);
444 usb_functionfs_event *event = events.data();
445 int nbytes = TEMP_FAILURE_RETRY(::read(mControl, event,
446 events.size() * sizeof(usb_functionfs_event)));
447 if (nbytes == -1) {
448 return -1;
449 }
Jerry Zhang487be612016-10-24 12:10:41 -0700450 int ret = 0;
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700451 for (size_t n = nbytes / sizeof *event; n; --n, ++event) {
452 switch (event->type) {
453 case FUNCTIONFS_BIND:
454 case FUNCTIONFS_ENABLE:
455 case FUNCTIONFS_RESUME:
456 ret = 0;
457 errno = 0;
Jerry Zhang487be612016-10-24 12:10:41 -0700458 break;
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700459 case FUNCTIONFS_SUSPEND:
460 case FUNCTIONFS_UNBIND:
461 case FUNCTIONFS_DISABLE:
462 errno = ESHUTDOWN;
463 ret = -1;
Jerry Zhang487be612016-10-24 12:10:41 -0700464 break;
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700465 case FUNCTIONFS_SETUP:
466 if (handleControlRequest(&event->u.setup) == -1)
467 ret = -1;
468 break;
469 default:
470 LOG(ERROR) << "Mtp Event " << event->type << " (unknown)";
471 }
Jerry Zhang487be612016-10-24 12:10:41 -0700472 }
473 return ret;
474}
475
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700476int MtpFfsHandle::handleControlRequest(const struct usb_ctrlrequest *setup) {
477 uint8_t type = setup->bRequestType;
478 uint8_t code = setup->bRequest;
479 uint16_t length = setup->wLength;
480 uint16_t index = setup->wIndex;
481 uint16_t value = setup->wValue;
482 std::vector<char> buf;
483 buf.resize(length);
484 int ret = 0;
Jerry Zhang487be612016-10-24 12:10:41 -0700485
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700486 if (!(type & USB_DIR_IN)) {
487 if (::read(mControl, buf.data(), length) != length) {
488 PLOG(ERROR) << "Mtp error ctrlreq read data";
489 }
490 }
491
492 if ((type & USB_TYPE_MASK) == USB_TYPE_CLASS && index == 0 && value == 0) {
493 switch(code) {
494 case MTP_REQ_RESET:
495 case MTP_REQ_CANCEL:
496 errno = ECANCELED;
497 ret = -1;
498 break;
499 case MTP_REQ_GET_DEVICE_STATUS:
500 {
501 if (length < sizeof(struct mtp_device_status) + 4) {
502 errno = EINVAL;
503 return -1;
504 }
505 struct mtp_device_status *st = reinterpret_cast<struct mtp_device_status*>(buf.data());
506 st->wLength = htole16(sizeof(st));
507 if (mCanceled) {
508 st->wLength += 4;
509 st->wCode = MTP_RESPONSE_TRANSACTION_CANCELLED;
510 uint16_t *endpoints = reinterpret_cast<uint16_t*>(st + 1);
511 endpoints[0] = ioctl(mBulkIn, FUNCTIONFS_ENDPOINT_REVMAP);
512 endpoints[1] = ioctl(mBulkOut, FUNCTIONFS_ENDPOINT_REVMAP);
513 mCanceled = false;
514 } else {
515 st->wCode = MTP_RESPONSE_OK;
516 }
517 length = st->wLength;
518 break;
519 }
520 default:
521 LOG(ERROR) << "Unrecognized Mtp class request! " << code;
522 }
523 } else {
524 LOG(ERROR) << "Unrecognized request type " << type;
525 }
526
527 if (type & USB_DIR_IN) {
528 if (::write(mControl, buf.data(), length) != length) {
529 PLOG(ERROR) << "Mtp error ctrlreq write data";
530 }
531 }
532 return 0;
Jerry Zhang487be612016-10-24 12:10:41 -0700533}
534
535int MtpFfsHandle::start() {
536 mLock.lock();
Jerry Zhangcc9d0fd2017-01-27 10:29:59 -0800537
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700538 if (!openEndpoints())
Jerry Zhangcc9d0fd2017-01-27 10:29:59 -0800539 return -1;
Jerry Zhangcc9d0fd2017-01-27 10:29:59 -0800540
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700541 for (unsigned i = 0; i < NUM_IO_BUFS; i++) {
542 mIobuf[i].bufs.resize(MAX_FILE_CHUNK_SIZE);
543 mIobuf[i].iocb.resize(AIO_BUFS_MAX);
544 mIobuf[i].iocbs.resize(AIO_BUFS_MAX);
545 mIobuf[i].buf.resize(AIO_BUFS_MAX);
546 for (unsigned j = 0; j < AIO_BUFS_MAX; j++) {
547 mIobuf[i].buf[j] = mIobuf[i].bufs.data() + j * AIO_BUF_LEN;
548 mIobuf[i].iocb[j] = &mIobuf[i].iocbs[j];
Jerry Zhangcc9d0fd2017-01-27 10:29:59 -0800549 }
550 }
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700551
552 memset(&mCtx, 0, sizeof(mCtx));
553 if (io_setup(AIO_BUFS_MAX, &mCtx) < 0) {
554 PLOG(ERROR) << "unable to setup aio";
555 return -1;
556 }
557 mEventFd.reset(eventfd(0, EFD_NONBLOCK));
558 mPollFds[0].fd = mControl;
559 mPollFds[0].events = POLLIN;
560 mPollFds[1].fd = mEventFd;
561 mPollFds[1].events = POLLIN;
562
563 mCanceled = false;
Jerry Zhangb4f54262017-02-02 18:14:33 -0800564 return 0;
Jerry Zhang487be612016-10-24 12:10:41 -0700565}
566
567int MtpFfsHandle::configure(bool usePtp) {
568 // Wait till previous server invocation has closed
Jerry Zhang0475d912017-04-03 11:24:48 -0700569 if (!mLock.try_lock_for(std::chrono::milliseconds(1000))) {
570 LOG(ERROR) << "MtpServer was unable to get configure lock";
571 return -1;
572 }
573 int ret = 0;
Jerry Zhang487be612016-10-24 12:10:41 -0700574
575 // If ptp is changed, the configuration must be rewritten
576 if (mPtp != usePtp) {
577 closeEndpoints();
578 closeConfig();
579 }
580 mPtp = usePtp;
581
582 if (!initFunctionfs()) {
Jerry Zhang0475d912017-04-03 11:24:48 -0700583 ret = -1;
Jerry Zhang487be612016-10-24 12:10:41 -0700584 }
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700585
Jerry Zhang0475d912017-04-03 11:24:48 -0700586 mLock.unlock();
587 return ret;
Jerry Zhang487be612016-10-24 12:10:41 -0700588}
589
590void MtpFfsHandle::close() {
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700591 io_destroy(mCtx);
Jerry Zhang487be612016-10-24 12:10:41 -0700592 closeEndpoints();
593 mLock.unlock();
594}
595
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700596int MtpFfsHandle::waitEvents(struct io_buffer *buf, int min_events, struct io_event *events,
597 int *counter) {
598 int num_events = 0;
599 int ret = 0;
600 int error = 0;
Jerry Zhangc9cbf982017-04-14 15:26:53 -0700601
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700602 while (num_events < min_events) {
603 if (poll(mPollFds, 2, 0) == -1) {
604 PLOG(ERROR) << "Mtp error during poll()";
605 return -1;
606 }
607 if (mPollFds[0].revents & POLLIN) {
608 mPollFds[0].revents = 0;
609 if (handleEvent() == -1) {
610 error = errno;
611 }
612 }
613 if (mPollFds[1].revents & POLLIN) {
614 mPollFds[1].revents = 0;
615 uint64_t ev_cnt = 0;
616
617 if (::read(mEventFd, &ev_cnt, sizeof(ev_cnt)) == -1) {
618 PLOG(ERROR) << "Mtp unable to read eventfd";
619 error = errno;
620 continue;
621 }
622
623 // It's possible that io_getevents will return more events than the eventFd reported,
624 // since events may appear in the time between the calls. In this case, the eventFd will
625 // show up as readable next iteration, but there will be fewer or no events to actually
626 // wait for. Thus we never want io_getevents to block.
627 int this_events = TEMP_FAILURE_RETRY(io_getevents(mCtx, 0, AIO_BUFS_MAX, events, &ZERO_TIMEOUT));
628 if (this_events == -1) {
629 PLOG(ERROR) << "Mtp error getting events";
630 error = errno;
631 }
632 // Add up the total amount of data and find errors on the way.
633 for (unsigned j = 0; j < static_cast<unsigned>(this_events); j++) {
634 if (events[j].res < 0) {
635 errno = -events[j].res;
636 PLOG(ERROR) << "Mtp got error event at " << j << " and " << buf->actual << " total";
637 error = errno;
638 }
639 ret += events[j].res;
640 }
641 num_events += this_events;
642 if (counter)
643 *counter += this_events;
644 }
645 if (error) {
646 errno = error;
647 ret = -1;
648 break;
649 }
650 }
651 return ret;
652}
653
654void MtpFfsHandle::cancelTransaction() {
655 // Device cancels by stalling both bulk endpoints.
656 if (::read(mBulkIn, nullptr, 0) != -1 || errno != EBADMSG)
657 PLOG(ERROR) << "Mtp stall failed on bulk in";
658 if (::write(mBulkOut, nullptr, 0) != -1 || errno != EBADMSG)
659 PLOG(ERROR) << "Mtp stall failed on bulk out";
660 mCanceled = true;
661 errno = ECANCELED;
662}
663
664int MtpFfsHandle::cancelEvents(struct iocb **iocb, struct io_event *events, unsigned start,
665 unsigned end) {
666 // Some manpages for io_cancel are out of date and incorrect.
667 // io_cancel will return -EINPROGRESS on success and does
668 // not place the event in the given memory. We have to use
669 // io_getevents to wait for all the events we cancelled.
670 int ret = 0;
671 unsigned num_events = 0;
672 int save_errno = errno;
673 errno = 0;
674
675 for (unsigned j = start; j < end; j++) {
676 if (io_cancel(mCtx, iocb[j], nullptr) != -1 || errno != EINPROGRESS) {
677 PLOG(ERROR) << "Mtp couldn't cancel request " << j;
678 } else {
679 num_events++;
680 }
681 }
682 if (num_events != end - start) {
683 ret = -1;
684 errno = EIO;
685 }
686 int evs = TEMP_FAILURE_RETRY(io_getevents(mCtx, num_events, AIO_BUFS_MAX, events, nullptr));
687 if (static_cast<unsigned>(evs) != num_events) {
688 PLOG(ERROR) << "Mtp couldn't cancel all requests, got " << evs;
689 ret = -1;
Jerry Zhangc9cbf982017-04-14 15:26:53 -0700690 }
Jerry Zhang487be612016-10-24 12:10:41 -0700691
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700692 uint64_t ev_cnt = 0;
693 if (num_events && ::read(mEventFd, &ev_cnt, sizeof(ev_cnt)) == -1)
694 PLOG(ERROR) << "Mtp Unable to read event fd";
695
696 if (ret == 0) {
697 // Restore errno since it probably got overriden with EINPROGRESS.
698 errno = save_errno;
699 }
700 return ret;
701}
702
703int MtpFfsHandle::iobufSubmit(struct io_buffer *buf, int fd, unsigned length, bool read) {
704 int ret = 0;
705 buf->actual = AIO_BUFS_MAX;
706 for (unsigned j = 0; j < AIO_BUFS_MAX; j++) {
707 unsigned rq_length = std::min(AIO_BUF_LEN, length - AIO_BUF_LEN * j);
708 io_prep(buf->iocb[j], fd, buf->buf[j], rq_length, 0, read);
709 buf->iocb[j]->aio_flags |= IOCB_FLAG_RESFD;
710 buf->iocb[j]->aio_resfd = mEventFd;
711
712 // Not enough data, so table is truncated.
713 if (rq_length < AIO_BUF_LEN || length == AIO_BUF_LEN * (j + 1)) {
714 buf->actual = j + 1;
715 break;
716 }
717 }
718
719 ret = io_submit(mCtx, buf->actual, buf->iocb.data());
720 if (ret != static_cast<int>(buf->actual)) {
721 PLOG(ERROR) << "Mtp io_submit got " << ret << " expected " << buf->actual;
722 if (ret != -1) {
723 errno = EIO;
724 }
725 ret = -1;
726 }
727 return ret;
728}
729
730int MtpFfsHandle::receiveFile(mtp_file_range mfr, bool zero_packet) {
731 // When receiving files, the incoming length is given in 32 bits.
732 // A >=4G file is given as 0xFFFFFFFF
733 uint32_t file_length = mfr.length;
734 uint64_t offset = mfr.offset;
Jerry Zhang487be612016-10-24 12:10:41 -0700735
736 struct aiocb aio;
737 aio.aio_fildes = mfr.fd;
738 aio.aio_buf = nullptr;
739 struct aiocb *aiol[] = {&aio};
Jerry Zhang487be612016-10-24 12:10:41 -0700740
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700741 int ret = -1;
742 unsigned i = 0;
743 size_t length;
744 struct io_event ioevs[AIO_BUFS_MAX];
745 bool has_write = false;
746 bool error = false;
747 bool write_error = false;
748 int packet_size = getPacketSize(mBulkOut);
749 bool short_packet = false;
750 advise(mfr.fd);
Jerry Zhang487be612016-10-24 12:10:41 -0700751
752 // Break down the file into pieces that fit in buffers
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700753 while (file_length > 0 || has_write) {
754 // Queue an asynchronous read from USB.
Jerry Zhang487be612016-10-24 12:10:41 -0700755 if (file_length > 0) {
756 length = std::min(static_cast<uint32_t>(MAX_FILE_CHUNK_SIZE), file_length);
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700757 if (iobufSubmit(&mIobuf[i], mBulkOut, length, true) == -1)
758 error = true;
Jerry Zhang487be612016-10-24 12:10:41 -0700759 }
760
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700761 // Get the return status of the last write request.
762 if (has_write) {
Jerry Zhang487be612016-10-24 12:10:41 -0700763 aio_suspend(aiol, 1, nullptr);
Jerry Zhang487be612016-10-24 12:10:41 -0700764 int written = aio_return(&aio);
Jerry Zhang487be612016-10-24 12:10:41 -0700765 if (static_cast<size_t>(written) < aio.aio_nbytes) {
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700766 errno = written == -1 ? aio_error(&aio) : EIO;
767 PLOG(ERROR) << "Mtp error writing to disk";
768 write_error = true;
Jerry Zhang487be612016-10-24 12:10:41 -0700769 }
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700770 has_write = false;
Jerry Zhang487be612016-10-24 12:10:41 -0700771 }
772
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700773 if (error) {
Jerry Zhang7063c932017-04-04 15:06:10 -0700774 return -1;
775 }
776
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700777 // Get the result of the read request, and queue a write to disk.
778 if (file_length > 0) {
779 unsigned num_events = 0;
780 ret = 0;
781 unsigned short_i = mIobuf[i].actual;
782 while (num_events < short_i) {
783 // Get all events up to the short read, if there is one.
784 // We must wait for each event since data transfer could end at any time.
785 int this_events = 0;
786 int event_ret = waitEvents(&mIobuf[i], 1, ioevs, &this_events);
787 num_events += this_events;
788
789 if (event_ret == -1) {
790 cancelEvents(mIobuf[i].iocb.data(), ioevs, num_events, mIobuf[i].actual);
791 return -1;
792 }
793 ret += event_ret;
794 for (int j = 0; j < this_events; j++) {
795 // struct io_event contains a pointer to the associated struct iocb as a __u64.
796 if (static_cast<__u64>(ioevs[j].res) <
797 reinterpret_cast<struct iocb*>(ioevs[j].obj)->aio_nbytes) {
798 // We've found a short event. Store the index since
799 // events won't necessarily arrive in the order they are queued.
800 short_i = (ioevs[j].obj - reinterpret_cast<uint64_t>(mIobuf[i].iocbs.data()))
801 / sizeof(struct iocb) + 1;
802 short_packet = true;
803 }
804 }
805 }
806 if (short_packet) {
807 if (cancelEvents(mIobuf[i].iocb.data(), ioevs, short_i, mIobuf[i].actual)) {
808 write_error = true;
809 }
810 }
Jerry Zhang487be612016-10-24 12:10:41 -0700811 if (file_length == MAX_MTP_FILE_SIZE) {
812 // For larger files, receive until a short packet is received.
813 if (static_cast<size_t>(ret) < length) {
814 file_length = 0;
815 }
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700816 } else if (ret < static_cast<int>(length)) {
817 // If file is less than 4G and we get a short packet, it's an error.
818 errno = EIO;
819 LOG(ERROR) << "Mtp got unexpected short packet";
820 return -1;
Jerry Zhang487be612016-10-24 12:10:41 -0700821 } else {
822 file_length -= ret;
823 }
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700824
825 if (write_error) {
826 cancelTransaction();
827 return -1;
828 }
829
Jerry Zhangc9cbf982017-04-14 15:26:53 -0700830 // Enqueue a new write request
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700831 aio_prepare(&aio, mIobuf[i].bufs.data(), ret, offset);
Jerry Zhangc9cbf982017-04-14 15:26:53 -0700832 aio_write(&aio);
Jerry Zhang487be612016-10-24 12:10:41 -0700833
834 offset += ret;
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700835 i = (i + 1) % NUM_IO_BUFS;
836 has_write = true;
Jerry Zhang487be612016-10-24 12:10:41 -0700837 }
838 }
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700839 if ((ret % packet_size == 0 && !short_packet) || zero_packet) {
840 // Receive an empty packet if size is a multiple of the endpoint size
841 // and we didn't already get an empty packet from the header or large file.
842 if (read(mIobuf[0].bufs.data(), packet_size) != 0) {
Jerry Zhang54107562017-05-15 11:54:19 -0700843 return -1;
844 }
845 }
Jerry Zhang487be612016-10-24 12:10:41 -0700846 return 0;
847}
848
Jerry Zhang487be612016-10-24 12:10:41 -0700849int MtpFfsHandle::sendFile(mtp_file_range mfr) {
850 uint64_t file_length = mfr.length;
851 uint32_t given_length = std::min(static_cast<uint64_t>(MAX_MTP_FILE_SIZE),
852 file_length + sizeof(mtp_data_header));
Jerry Zhang44180302017-02-03 16:31:31 -0800853 uint64_t offset = mfr.offset;
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700854 int packet_size = getPacketSize(mBulkIn);
Jerry Zhang487be612016-10-24 12:10:41 -0700855
Jerry Zhang44180302017-02-03 16:31:31 -0800856 // If file_length is larger than a size_t, truncating would produce the wrong comparison.
857 // Instead, promote the left side to 64 bits, then truncate the small result.
858 int init_read_len = std::min(
859 static_cast<uint64_t>(packet_size - sizeof(mtp_data_header)), file_length);
Jerry Zhang487be612016-10-24 12:10:41 -0700860
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700861 advise(mfr.fd);
Jerry Zhange9d94422017-01-18 12:03:56 -0800862
Jerry Zhang487be612016-10-24 12:10:41 -0700863 struct aiocb aio;
864 aio.aio_fildes = mfr.fd;
865 struct aiocb *aiol[] = {&aio};
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700866 int ret = 0;
867 int length, num_read;
868 unsigned i = 0;
869 struct io_event ioevs[AIO_BUFS_MAX];
870 bool error = false;
871 bool has_write = false;
Jerry Zhang487be612016-10-24 12:10:41 -0700872
873 // Send the header data
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700874 mtp_data_header *header = reinterpret_cast<mtp_data_header*>(mIobuf[0].bufs.data());
875 header->length = htole32(given_length);
876 header->type = htole16(2); // data packet
877 header->command = htole16(mfr.command);
878 header->transaction_id = htole32(mfr.transaction_id);
Jerry Zhang487be612016-10-24 12:10:41 -0700879
880 // Some hosts don't support header/data separation even though MTP allows it
881 // Handle by filling first packet with initial file data
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700882 if (TEMP_FAILURE_RETRY(pread(mfr.fd, mIobuf[0].bufs.data() +
Jerry Zhang487be612016-10-24 12:10:41 -0700883 sizeof(mtp_data_header), init_read_len, offset))
884 != init_read_len) return -1;
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700885 if (write(mIobuf[0].bufs.data(), sizeof(mtp_data_header) + init_read_len) == -1)
886 return -1;
Jerry Zhang487be612016-10-24 12:10:41 -0700887 file_length -= init_read_len;
888 offset += init_read_len;
Jerry Zhang54107562017-05-15 11:54:19 -0700889 ret = init_read_len + sizeof(mtp_data_header);
Jerry Zhang487be612016-10-24 12:10:41 -0700890
Jerry Zhang487be612016-10-24 12:10:41 -0700891 // Break down the file into pieces that fit in buffers
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700892 while(file_length > 0 || has_write) {
893 if (file_length > 0) {
894 // Queue up a read from disk.
895 length = std::min(static_cast<uint64_t>(MAX_FILE_CHUNK_SIZE), file_length);
896 aio_prepare(&aio, mIobuf[i].bufs.data(), length, offset);
897 aio_read(&aio);
Jerry Zhang487be612016-10-24 12:10:41 -0700898 }
899
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700900 if (has_write) {
901 // Wait for usb write. Cancel unwritten portion if there's an error.
902 int num_events = 0;
903 if (waitEvents(&mIobuf[(i-1)%NUM_IO_BUFS], mIobuf[(i-1)%NUM_IO_BUFS].actual, ioevs,
904 &num_events) != ret) {
905 error = true;
906 cancelEvents(mIobuf[(i-1)%NUM_IO_BUFS].iocb.data(), ioevs, num_events,
907 mIobuf[(i-1)%NUM_IO_BUFS].actual);
908 }
909 has_write = false;
Jerry Zhang7063c932017-04-04 15:06:10 -0700910 }
911
Jerry Zhang487be612016-10-24 12:10:41 -0700912 if (file_length > 0) {
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700913 // Wait for the previous read to finish
914 aio_suspend(aiol, 1, nullptr);
915 num_read = aio_return(&aio);
916 if (static_cast<size_t>(num_read) < aio.aio_nbytes) {
917 errno = num_read == -1 ? aio_error(&aio) : EIO;
918 PLOG(ERROR) << "Mtp error reading from disk";
919 cancelTransaction();
920 return -1;
921 }
922
923 file_length -= num_read;
924 offset += num_read;
925
926 if (error) {
927 return -1;
928 }
929
930 // Queue up a write to usb.
931 if (iobufSubmit(&mIobuf[i], mBulkIn, num_read, false) == -1) {
932 return -1;
933 }
934 has_write = true;
935 ret = num_read;
Jerry Zhang487be612016-10-24 12:10:41 -0700936 }
937
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700938 i = (i + 1) % NUM_IO_BUFS;
Jerry Zhang487be612016-10-24 12:10:41 -0700939 }
940
Jerry Zhangc9cbf982017-04-14 15:26:53 -0700941 if (ret % packet_size == 0) {
Jerry Zhang487be612016-10-24 12:10:41 -0700942 // If the last packet wasn't short, send a final empty packet
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700943 if (write(mIobuf[0].bufs.data(), 0) != 0) {
Jerry Zhangc9cbf982017-04-14 15:26:53 -0700944 return -1;
945 }
Jerry Zhang487be612016-10-24 12:10:41 -0700946 }
Jerry Zhang487be612016-10-24 12:10:41 -0700947 return 0;
948}
949
950int MtpFfsHandle::sendEvent(mtp_event me) {
Jerry Zhang94ef0ea2017-07-26 11:37:23 -0700951 // Mimic the behavior of f_mtp by sending the event async.
952 // Events aren't critical to the connection, so we don't need to check the return value.
953 char *temp = new char[me.length];
954 memcpy(temp, me.data, me.length);
955 me.data = temp;
Jerry Zhang008f4df2017-08-09 17:53:50 -0700956 std::thread t([this, me]() { return this->doSendEvent(me); });
Jerry Zhang94ef0ea2017-07-26 11:37:23 -0700957 t.detach();
958 return 0;
959}
960
961void MtpFfsHandle::doSendEvent(mtp_event me) {
Jerry Zhang487be612016-10-24 12:10:41 -0700962 unsigned length = me.length;
Jerry Zhang94ef0ea2017-07-26 11:37:23 -0700963 int ret = ::write(mIntr, me.data, length);
Jerry Zhang94ef0ea2017-07-26 11:37:23 -0700964 if (static_cast<unsigned>(ret) != length)
965 PLOG(ERROR) << "Mtp error sending event thread!";
Jerry Zhang008f4df2017-08-09 17:53:50 -0700966 delete[] reinterpret_cast<char*>(me.data);
Jerry Zhang487be612016-10-24 12:10:41 -0700967}
968
969} // namespace android
970