blob: 442dea5276a847c965eee1dc2fd83002729f7afe [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
Anatol Pomazau5ae3f932012-02-28 07:21:08 -080012 * the documentation and/or other materials provided with the
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080013 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
Anatol Pomazau5ae3f932012-02-28 07:21:08 -080022 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080023 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
Elliott Hughesfbcb93a2015-06-24 13:28:24 -070029#include <inttypes.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080030#include <stdio.h>
31#include <CoreFoundation/CoreFoundation.h>
32#include <IOKit/IOKitLib.h>
33#include <IOKit/IOCFPlugIn.h>
34#include <IOKit/usb/IOUSBLib.h>
35#include <IOKit/IOMessage.h>
36#include <mach/mach_port.h>
37
David Pursell0b156632015-10-30 11:22:01 -070038#include <memory>
39
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080040#include "usb.h"
41
42
43/*
44 * Internal helper functions and associated definitions.
45 */
46
47#if TRACE_USB
48#define WARN(x...) fprintf(stderr, x)
49#else
50#define WARN(x...)
51#endif
52
53#define ERR(x...) fprintf(stderr, "ERROR: " x)
54
55/** An open usb device */
56struct usb_handle
57{
58 int success;
59 ifc_match_func callback;
60 usb_ifc_info info;
Anatol Pomazau5ae3f932012-02-28 07:21:08 -080061
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080062 UInt8 bulkIn;
63 UInt8 bulkOut;
64 IOUSBInterfaceInterface190 **interface;
65 unsigned int zero_mask;
66};
67
Aaron Wisnerceb7cbf2018-07-23 15:40:58 -050068class OsxUsbTransport : public UsbTransport {
David Pursell0b156632015-10-30 11:22:01 -070069 public:
Aaron Wisnerceb7cbf2018-07-23 15:40:58 -050070 OsxUsbTransport(std::unique_ptr<usb_handle> handle, uint32_t ms_timeout)
71 : handle_(std::move(handle)), ms_timeout_(ms_timeout) {}
David Pursell0b156632015-10-30 11:22:01 -070072 ~OsxUsbTransport() override = default;
73
74 ssize_t Read(void* data, size_t len) override;
75 ssize_t Write(const void* data, size_t len) override;
76 int Close() override;
Aaron Wisnerceb7cbf2018-07-23 15:40:58 -050077 int Reset() override;
David Pursell0b156632015-10-30 11:22:01 -070078
79 private:
80 std::unique_ptr<usb_handle> handle_;
Aaron Wisnerceb7cbf2018-07-23 15:40:58 -050081 const uint32_t ms_timeout_;
David Pursell0b156632015-10-30 11:22:01 -070082
83 DISALLOW_COPY_AND_ASSIGN(OsxUsbTransport);
84};
85
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080086/** Try out all the interfaces and see if there's a match. Returns 0 on
87 * success, -1 on failure. */
Jeff Brownb6406372010-05-21 13:20:47 -070088static int try_interfaces(IOUSBDeviceInterface182 **dev, usb_handle *handle) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080089 IOReturn kr;
90 IOUSBFindInterfaceRequest request;
91 io_iterator_t iterator;
92 io_service_t usbInterface;
93 IOCFPlugInInterface **plugInInterface;
94 IOUSBInterfaceInterface190 **interface = NULL;
95 HRESULT result;
96 SInt32 score;
97 UInt8 interfaceNumEndpoints;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080098
Josh Gaof806a3c2017-08-18 18:25:44 -070099 request.bInterfaceClass = 0xff;
100 request.bInterfaceSubClass = 0x42;
101 request.bInterfaceProtocol = 0x03;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800102 request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
103
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800104 // Get an iterator for the interfaces on the device
105 kr = (*dev)->CreateInterfaceIterator(dev, &request, &iterator);
106
107 if (kr != 0) {
108 ERR("Couldn't create a device interface iterator: (%08x)\n", kr);
109 return -1;
110 }
111
112 while ((usbInterface = IOIteratorNext(iterator))) {
113 // Create an intermediate plugin
114 kr = IOCreatePlugInInterfaceForService(
115 usbInterface,
116 kIOUSBInterfaceUserClientTypeID,
117 kIOCFPlugInInterfaceID,
118 &plugInInterface,
119 &score);
120
121 // No longer need the usbInterface object now that we have the plugin
122 (void) IOObjectRelease(usbInterface);
123
124 if ((kr != 0) || (!plugInInterface)) {
125 WARN("Unable to create plugin (%08x)\n", kr);
126 continue;
127 }
128
129 // Now create the interface interface for the interface
130 result = (*plugInInterface)->QueryInterface(
131 plugInInterface,
132 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
Elliott Hughesfbcb93a2015-06-24 13:28:24 -0700133 (LPVOID*) &interface);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800134
135 // No longer need the intermediate plugin
136 (*plugInInterface)->Release(plugInInterface);
137
138 if (result || !interface) {
139 ERR("Couldn't create interface interface: (%08x)\n",
140 (unsigned int) result);
141 // continue so we can try the next interface
142 continue;
143 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800144
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800145 /*
146 * Now open the interface. This will cause the pipes
147 * associated with the endpoints in the interface descriptor
148 * to be instantiated.
149 */
150
151 /*
152 * TODO: Earlier comments here indicated that it was a bad
153 * idea to just open any interface, because opening "mass
154 * storage endpoints" is bad. However, the only way to find
155 * out if an interface does bulk in or out is to open it, and
156 * the framework in this application wants to be told about
157 * bulk in / out before deciding whether it actually wants to
158 * use the interface. Maybe something needs to be done about
159 * this situation.
160 */
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800161
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800162 kr = (*interface)->USBInterfaceOpen(interface);
163
164 if (kr != 0) {
165 WARN("Could not open interface: (%08x)\n", kr);
166 (void) (*interface)->Release(interface);
167 // continue so we can try the next interface
168 continue;
169 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800170
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800171 // Get the number of endpoints associated with this interface.
172 kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
173
174 if (kr != 0) {
175 ERR("Unable to get number of endpoints: (%08x)\n", kr);
176 goto next_interface;
177 }
178
179 // Get interface class, subclass and protocol
180 if ((*interface)->GetInterfaceClass(interface, &handle->info.ifc_class) != 0 ||
181 (*interface)->GetInterfaceSubClass(interface, &handle->info.ifc_subclass) != 0 ||
182 (*interface)->GetInterfaceProtocol(interface, &handle->info.ifc_protocol) != 0)
183 {
184 ERR("Unable to get interface class, subclass and protocol\n");
185 goto next_interface;
186 }
187
188 handle->info.has_bulk_in = 0;
189 handle->info.has_bulk_out = 0;
190
191 // Iterate over the endpoints for this interface and see if there
192 // are any that do bulk in/out.
Elliott Hughes2d4f8522015-08-13 15:01:18 -0700193 for (UInt8 endpoint = 1; endpoint <= interfaceNumEndpoints; endpoint++) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800194 UInt8 transferType;
195 UInt16 maxPacketSize;
196 UInt8 interval;
197 UInt8 number;
198 UInt8 direction;
199
200 kr = (*interface)->GetPipeProperties(interface, endpoint,
201 &direction,
202 &number, &transferType, &maxPacketSize, &interval);
203
204 if (kr == 0) {
205 if (transferType != kUSBBulk) {
206 continue;
207 }
208
209 if (direction == kUSBIn) {
210 handle->info.has_bulk_in = 1;
211 handle->bulkIn = endpoint;
212 } else if (direction == kUSBOut) {
213 handle->info.has_bulk_out = 1;
214 handle->bulkOut = endpoint;
215 }
216
217 if (handle->info.ifc_protocol == 0x01) {
218 handle->zero_mask = maxPacketSize - 1;
219 }
220 } else {
Elliott Hughes2ae8d2e2015-08-07 10:49:36 -0700221 ERR("could not get pipe properties for endpoint %u (%08x)\n", endpoint, kr);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800222 }
223
224 if (handle->info.has_bulk_in && handle->info.has_bulk_out) {
225 break;
226 }
227 }
228
229 if (handle->callback(&handle->info) == 0) {
230 handle->interface = interface;
231 handle->success = 1;
232
233 /*
234 * Clear both the endpoints, because it has been observed
235 * that the Mac may otherwise (incorrectly) start out with
236 * them in bad state.
237 */
238
239 if (handle->info.has_bulk_in) {
240 kr = (*interface)->ClearPipeStallBothEnds(interface,
241 handle->bulkIn);
242 if (kr != 0) {
Nick Pelly286d50f2010-07-22 10:59:55 -0700243 ERR("could not clear input pipe; result %x, ignoring...\n", kr);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800244 }
245 }
246
247 if (handle->info.has_bulk_out) {
248 kr = (*interface)->ClearPipeStallBothEnds(interface,
249 handle->bulkOut);
250 if (kr != 0) {
Nick Pelly286d50f2010-07-22 10:59:55 -0700251 ERR("could not clear output pipe; result %x, ignoring....\n", kr);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800252 }
253 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800254
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800255 return 0;
256 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800257
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800258next_interface:
259 (*interface)->USBInterfaceClose(interface);
260 (*interface)->Release(interface);
261 }
262
263 return 0;
264}
265
266/** Try out the given device and see if there's a match. Returns 0 on
267 * success, -1 on failure.
268 */
269static int try_device(io_service_t device, usb_handle *handle) {
270 kern_return_t kr;
271 IOCFPlugInInterface **plugin = NULL;
272 IOUSBDeviceInterface182 **dev = NULL;
273 SInt32 score;
274 HRESULT result;
275 UInt8 serialIndex;
Scott Anderson13081c62012-04-06 12:39:30 -0700276 UInt32 locationId;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800277
278 // Create an intermediate plugin.
279 kr = IOCreatePlugInInterfaceForService(device,
280 kIOUSBDeviceUserClientTypeID,
281 kIOCFPlugInInterfaceID,
282 &plugin, &score);
283
284 if ((kr != 0) || (plugin == NULL)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800285 goto error;
286 }
287
288 // Now create the device interface.
289 result = (*plugin)->QueryInterface(plugin,
Elliott Hughesfbcb93a2015-06-24 13:28:24 -0700290 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*) &dev);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800291 if ((result != 0) || (dev == NULL)) {
292 ERR("Couldn't create a device interface (%08x)\n", (int) result);
293 goto error;
294 }
295
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800296 /*
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800297 * We don't need the intermediate interface after the device interface
298 * is created.
299 */
300 IODestroyPlugInInterface(plugin);
301
302 // So, we have a device, finally. Grab its vitals.
303
304 kr = (*dev)->GetDeviceVendor(dev, &handle->info.dev_vendor);
305 if (kr != 0) {
306 ERR("GetDeviceVendor");
307 goto error;
308 }
309
310 kr = (*dev)->GetDeviceProduct(dev, &handle->info.dev_product);
311 if (kr != 0) {
312 ERR("GetDeviceProduct");
313 goto error;
314 }
315
316 kr = (*dev)->GetDeviceClass(dev, &handle->info.dev_class);
317 if (kr != 0) {
318 ERR("GetDeviceClass");
319 goto error;
320 }
321
322 kr = (*dev)->GetDeviceSubClass(dev, &handle->info.dev_subclass);
323 if (kr != 0) {
324 ERR("GetDeviceSubClass");
325 goto error;
326 }
327
328 kr = (*dev)->GetDeviceProtocol(dev, &handle->info.dev_protocol);
329 if (kr != 0) {
330 ERR("GetDeviceProtocol");
331 goto error;
332 }
333
Scott Anderson13081c62012-04-06 12:39:30 -0700334 kr = (*dev)->GetLocationID(dev, &locationId);
335 if (kr != 0) {
336 ERR("GetLocationId");
337 goto error;
338 }
Ying Wang42a809b2014-08-14 15:50:13 -0700339 snprintf(handle->info.device_path, sizeof(handle->info.device_path),
340 "usb:%" PRIu32 "X", (unsigned int)locationId);
Scott Anderson13081c62012-04-06 12:39:30 -0700341
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800342 kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
343
344 if (serialIndex > 0) {
345 IOUSBDevRequest req;
346 UInt16 buffer[256];
347
348 req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
349 req.bRequest = kUSBRqGetDescriptor;
350 req.wValue = (kUSBStringDesc << 8) | serialIndex;
mgrossc8406532011-07-07 17:08:10 -0700351 //language ID (en-us) for serial number string
352 req.wIndex = 0x0409;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800353 req.pData = buffer;
354 req.wLength = sizeof(buffer);
355 kr = (*dev)->DeviceRequest(dev, &req);
356
357 if (kr == kIOReturnSuccess && req.wLenDone > 0) {
358 int i, count;
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800359
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800360 // skip first word, and copy the rest to the serial string, changing shorts to bytes.
361 count = (req.wLenDone - 1) / 2;
362 for (i = 0; i < count; i++)
363 handle->info.serial_number[i] = buffer[i + 1];
364 handle->info.serial_number[i] = 0;
365 }
366 } else {
367 // device has no serial number
368 handle->info.serial_number[0] = 0;
369 }
Elliott Hughesb4add9b2009-10-06 18:07:49 -0700370 handle->info.writable = 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800371
372 if (try_interfaces(dev, handle)) {
373 goto error;
374 }
375
376 (*dev)->Release(dev);
377 return 0;
378
379 error:
380
381 if (dev != NULL) {
382 (*dev)->Release(dev);
383 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800384
385 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800386}
387
388
389/** Initializes the USB system. Returns 0 on success, -1 on error. */
David Pursell0b156632015-10-30 11:22:01 -0700390static int init_usb(ifc_match_func callback, std::unique_ptr<usb_handle>* handle) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800391 int ret = -1;
392 CFMutableDictionaryRef matchingDict;
393 kern_return_t result;
394 io_iterator_t iterator;
395 usb_handle h;
396
397 h.success = 0;
398 h.callback = callback;
399
400 /*
401 * Create our matching dictionary to find appropriate devices.
402 * IOServiceAddMatchingNotification consumes the reference, so we
403 * do not need to release it.
404 */
405 matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
406
407 if (matchingDict == NULL) {
408 ERR("Couldn't create USB matching dictionary.\n");
409 return -1;
410 }
411
412 result = IOServiceGetMatchingServices(
413 kIOMasterPortDefault, matchingDict, &iterator);
414
415 if (result != 0) {
416 ERR("Could not create iterator.");
417 return -1;
418 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800419
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800420 for (;;) {
421 if (! IOIteratorIsValid(iterator)) {
422 /*
423 * Apple documentation advises resetting the iterator if
424 * it should become invalid during iteration.
425 */
426 IOIteratorReset(iterator);
427 continue;
428 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800429
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800430 io_service_t device = IOIteratorNext(iterator);
431
432 if (device == 0) {
433 break;
434 }
435
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800436 if (try_device(device, &h) != 0) {
437 IOObjectRelease(device);
Josh Gaof806a3c2017-08-18 18:25:44 -0700438 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800439 }
440
441 if (h.success) {
David Pursell0b156632015-10-30 11:22:01 -0700442 handle->reset(new usb_handle);
443 memcpy(handle->get(), &h, sizeof(usb_handle));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800444 ret = 0;
445 break;
446 }
447
448 IOObjectRelease(device);
449 }
450
451 IOObjectRelease(iterator);
452
453 return ret;
454}
455
456
457
458/*
459 * Definitions of this file's public functions.
460 */
461
Aaron Wisnerceb7cbf2018-07-23 15:40:58 -0500462UsbTransport* usb_open(ifc_match_func callback, uint32_t timeout_ms) {
David Pursell0b156632015-10-30 11:22:01 -0700463 std::unique_ptr<usb_handle> handle;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800464
465 if (init_usb(callback, &handle) < 0) {
466 /* Something went wrong initializing USB. */
David Pursell0b156632015-10-30 11:22:01 -0700467 return nullptr;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800468 }
469
Aaron Wisnerceb7cbf2018-07-23 15:40:58 -0500470 return new OsxUsbTransport(std::move(handle), timeout_ms);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800471}
472
David Pursell0b156632015-10-30 11:22:01 -0700473int OsxUsbTransport::Close() {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800474 /* TODO: Something better here? */
475 return 0;
476}
477
Aaron Wisnerceb7cbf2018-07-23 15:40:58 -0500478int OsxUsbTransport::Reset() {
479 IOReturn result = (*handle_->interface)->ResetDevice(handle_->interface);
480
481 if (result == 0) {
482 return 0;
483 } else {
484 ERR("usb_reset failed with status %x\n", result);
485 return -1;
486 }
487}
488
David Pursell0b156632015-10-30 11:22:01 -0700489ssize_t OsxUsbTransport::Read(void* data, size_t len) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800490 IOReturn result;
491 UInt32 numBytes = len;
492
493 if (len == 0) {
494 return 0;
495 }
496
David Pursell0b156632015-10-30 11:22:01 -0700497 if (handle_ == nullptr) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800498 return -1;
499 }
500
David Pursell0b156632015-10-30 11:22:01 -0700501 if (handle_->interface == nullptr) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800502 ERR("usb_read interface was null\n");
503 return -1;
504 }
505
David Pursell0b156632015-10-30 11:22:01 -0700506 if (handle_->bulkIn == 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800507 ERR("bulkIn endpoint not assigned\n");
508 return -1;
509 }
510
Aaron Wisnerceb7cbf2018-07-23 15:40:58 -0500511 result = (*handle_->interface)
512 ->ReadPipeTO(handle_->interface, handle_->bulkIn, data, &numBytes,
513 USB_TRANSACTION_TIMEOUT, USB_TRANSACTION_TIMEOUT);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800514
515 if (result == 0) {
516 return (int) numBytes;
517 } else {
518 ERR("usb_read failed with status %x\n", result);
519 }
520
521 return -1;
522}
523
David Pursell0b156632015-10-30 11:22:01 -0700524ssize_t OsxUsbTransport::Write(const void* data, size_t len) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800525 IOReturn result;
526
527 if (len == 0) {
528 return 0;
529 }
530
David Pursell0b156632015-10-30 11:22:01 -0700531 if (handle_ == NULL) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800532 return -1;
533 }
534
David Pursell0b156632015-10-30 11:22:01 -0700535 if (handle_->interface == NULL) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800536 ERR("usb_write interface was null\n");
537 return -1;
538 }
539
David Pursell0b156632015-10-30 11:22:01 -0700540 if (handle_->bulkOut == 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800541 ERR("bulkOut endpoint not assigned\n");
542 return -1;
543 }
544
Jeff Brownb6406372010-05-21 13:20:47 -0700545#if 0
David Pursell0b156632015-10-30 11:22:01 -0700546 result = (*handle_->interface)->WritePipe(
547 handle_->interface, handle_->bulkOut, (void *)data, len);
Jeff Brownb6406372010-05-21 13:20:47 -0700548#else
549 /* Attempt to work around crashes in the USB driver that may be caused
550 * by trying to write too much data at once. The kernel IOCopyMapper
551 * panics if a single iovmAlloc needs more than half of its mapper pages.
552 */
553 const int maxLenToSend = 1048576; // 1 MiB
554 int lenRemaining = len;
555 result = 0;
556 while (lenRemaining > 0) {
557 int lenToSend = lenRemaining > maxLenToSend
558 ? maxLenToSend : lenRemaining;
559
David Pursell0b156632015-10-30 11:22:01 -0700560 result = (*handle_->interface)->WritePipe(
561 handle_->interface, handle_->bulkOut, (void *)data, lenToSend);
Jeff Brownb6406372010-05-21 13:20:47 -0700562 if (result != 0) break;
563
564 lenRemaining -= lenToSend;
565 data = (const char*)data + lenToSend;
566 }
567#endif
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800568
569 #if 0
David Pursell0b156632015-10-30 11:22:01 -0700570 if ((result == 0) && (handle_->zero_mask)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800571 /* we need 0-markers and our transfer */
David Pursell0b156632015-10-30 11:22:01 -0700572 if(!(len & handle_->zero_mask)) {
573 result = (*handle_->interface)->WritePipe(
574 handle_->interface, handle_->bulkOut, (void *)data, 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800575 }
576 }
577 #endif
578
579 if (result != 0) {
580 ERR("usb_write failed with status %x\n", result);
581 return -1;
582 }
583
584 return len;
585}