blob: e95b04936434d9aa45d1050ef0c88654964b44fa [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
David Pursell0b156632015-10-30 11:22:01 -070068class OsxUsbTransport : public Transport {
69 public:
70 OsxUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
71 ~OsxUsbTransport() override = default;
72
73 ssize_t Read(void* data, size_t len) override;
74 ssize_t Write(const void* data, size_t len) override;
75 int Close() override;
76
77 private:
78 std::unique_ptr<usb_handle> handle_;
79
80 DISALLOW_COPY_AND_ASSIGN(OsxUsbTransport);
81};
82
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080083/** Try out all the interfaces and see if there's a match. Returns 0 on
84 * success, -1 on failure. */
Jeff Brownb6406372010-05-21 13:20:47 -070085static int try_interfaces(IOUSBDeviceInterface182 **dev, usb_handle *handle) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080086 IOReturn kr;
87 IOUSBFindInterfaceRequest request;
88 io_iterator_t iterator;
89 io_service_t usbInterface;
90 IOCFPlugInInterface **plugInInterface;
91 IOUSBInterfaceInterface190 **interface = NULL;
92 HRESULT result;
93 SInt32 score;
94 UInt8 interfaceNumEndpoints;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080095
Josh Gaof806a3c2017-08-18 18:25:44 -070096 request.bInterfaceClass = 0xff;
97 request.bInterfaceSubClass = 0x42;
98 request.bInterfaceProtocol = 0x03;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080099 request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
100
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800101 // Get an iterator for the interfaces on the device
102 kr = (*dev)->CreateInterfaceIterator(dev, &request, &iterator);
103
104 if (kr != 0) {
105 ERR("Couldn't create a device interface iterator: (%08x)\n", kr);
106 return -1;
107 }
108
109 while ((usbInterface = IOIteratorNext(iterator))) {
110 // Create an intermediate plugin
111 kr = IOCreatePlugInInterfaceForService(
112 usbInterface,
113 kIOUSBInterfaceUserClientTypeID,
114 kIOCFPlugInInterfaceID,
115 &plugInInterface,
116 &score);
117
118 // No longer need the usbInterface object now that we have the plugin
119 (void) IOObjectRelease(usbInterface);
120
121 if ((kr != 0) || (!plugInInterface)) {
122 WARN("Unable to create plugin (%08x)\n", kr);
123 continue;
124 }
125
126 // Now create the interface interface for the interface
127 result = (*plugInInterface)->QueryInterface(
128 plugInInterface,
129 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
Elliott Hughesfbcb93a2015-06-24 13:28:24 -0700130 (LPVOID*) &interface);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800131
132 // No longer need the intermediate plugin
133 (*plugInInterface)->Release(plugInInterface);
134
135 if (result || !interface) {
136 ERR("Couldn't create interface interface: (%08x)\n",
137 (unsigned int) result);
138 // continue so we can try the next interface
139 continue;
140 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800141
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800142 /*
143 * Now open the interface. This will cause the pipes
144 * associated with the endpoints in the interface descriptor
145 * to be instantiated.
146 */
147
148 /*
149 * TODO: Earlier comments here indicated that it was a bad
150 * idea to just open any interface, because opening "mass
151 * storage endpoints" is bad. However, the only way to find
152 * out if an interface does bulk in or out is to open it, and
153 * the framework in this application wants to be told about
154 * bulk in / out before deciding whether it actually wants to
155 * use the interface. Maybe something needs to be done about
156 * this situation.
157 */
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800158
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800159 kr = (*interface)->USBInterfaceOpen(interface);
160
161 if (kr != 0) {
162 WARN("Could not open interface: (%08x)\n", kr);
163 (void) (*interface)->Release(interface);
164 // continue so we can try the next interface
165 continue;
166 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800167
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800168 // Get the number of endpoints associated with this interface.
169 kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
170
171 if (kr != 0) {
172 ERR("Unable to get number of endpoints: (%08x)\n", kr);
173 goto next_interface;
174 }
175
176 // Get interface class, subclass and protocol
177 if ((*interface)->GetInterfaceClass(interface, &handle->info.ifc_class) != 0 ||
178 (*interface)->GetInterfaceSubClass(interface, &handle->info.ifc_subclass) != 0 ||
179 (*interface)->GetInterfaceProtocol(interface, &handle->info.ifc_protocol) != 0)
180 {
181 ERR("Unable to get interface class, subclass and protocol\n");
182 goto next_interface;
183 }
184
185 handle->info.has_bulk_in = 0;
186 handle->info.has_bulk_out = 0;
187
188 // Iterate over the endpoints for this interface and see if there
189 // are any that do bulk in/out.
Elliott Hughes2d4f8522015-08-13 15:01:18 -0700190 for (UInt8 endpoint = 1; endpoint <= interfaceNumEndpoints; endpoint++) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800191 UInt8 transferType;
192 UInt16 maxPacketSize;
193 UInt8 interval;
194 UInt8 number;
195 UInt8 direction;
196
197 kr = (*interface)->GetPipeProperties(interface, endpoint,
198 &direction,
199 &number, &transferType, &maxPacketSize, &interval);
200
201 if (kr == 0) {
202 if (transferType != kUSBBulk) {
203 continue;
204 }
205
206 if (direction == kUSBIn) {
207 handle->info.has_bulk_in = 1;
208 handle->bulkIn = endpoint;
209 } else if (direction == kUSBOut) {
210 handle->info.has_bulk_out = 1;
211 handle->bulkOut = endpoint;
212 }
213
214 if (handle->info.ifc_protocol == 0x01) {
215 handle->zero_mask = maxPacketSize - 1;
216 }
217 } else {
Elliott Hughes2ae8d2e2015-08-07 10:49:36 -0700218 ERR("could not get pipe properties for endpoint %u (%08x)\n", endpoint, kr);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800219 }
220
221 if (handle->info.has_bulk_in && handle->info.has_bulk_out) {
222 break;
223 }
224 }
225
226 if (handle->callback(&handle->info) == 0) {
227 handle->interface = interface;
228 handle->success = 1;
229
230 /*
231 * Clear both the endpoints, because it has been observed
232 * that the Mac may otherwise (incorrectly) start out with
233 * them in bad state.
234 */
235
236 if (handle->info.has_bulk_in) {
237 kr = (*interface)->ClearPipeStallBothEnds(interface,
238 handle->bulkIn);
239 if (kr != 0) {
Nick Pelly286d50f2010-07-22 10:59:55 -0700240 ERR("could not clear input pipe; result %x, ignoring...\n", kr);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800241 }
242 }
243
244 if (handle->info.has_bulk_out) {
245 kr = (*interface)->ClearPipeStallBothEnds(interface,
246 handle->bulkOut);
247 if (kr != 0) {
Nick Pelly286d50f2010-07-22 10:59:55 -0700248 ERR("could not clear output pipe; result %x, ignoring....\n", kr);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800249 }
250 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800251
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800252 return 0;
253 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800254
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800255next_interface:
256 (*interface)->USBInterfaceClose(interface);
257 (*interface)->Release(interface);
258 }
259
260 return 0;
261}
262
263/** Try out the given device and see if there's a match. Returns 0 on
264 * success, -1 on failure.
265 */
266static int try_device(io_service_t device, usb_handle *handle) {
267 kern_return_t kr;
268 IOCFPlugInInterface **plugin = NULL;
269 IOUSBDeviceInterface182 **dev = NULL;
270 SInt32 score;
271 HRESULT result;
272 UInt8 serialIndex;
Scott Anderson13081c62012-04-06 12:39:30 -0700273 UInt32 locationId;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800274
275 // Create an intermediate plugin.
276 kr = IOCreatePlugInInterfaceForService(device,
277 kIOUSBDeviceUserClientTypeID,
278 kIOCFPlugInInterfaceID,
279 &plugin, &score);
280
281 if ((kr != 0) || (plugin == NULL)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800282 goto error;
283 }
284
285 // Now create the device interface.
286 result = (*plugin)->QueryInterface(plugin,
Elliott Hughesfbcb93a2015-06-24 13:28:24 -0700287 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*) &dev);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800288 if ((result != 0) || (dev == NULL)) {
289 ERR("Couldn't create a device interface (%08x)\n", (int) result);
290 goto error;
291 }
292
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800293 /*
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800294 * We don't need the intermediate interface after the device interface
295 * is created.
296 */
297 IODestroyPlugInInterface(plugin);
298
299 // So, we have a device, finally. Grab its vitals.
300
301 kr = (*dev)->GetDeviceVendor(dev, &handle->info.dev_vendor);
302 if (kr != 0) {
303 ERR("GetDeviceVendor");
304 goto error;
305 }
306
307 kr = (*dev)->GetDeviceProduct(dev, &handle->info.dev_product);
308 if (kr != 0) {
309 ERR("GetDeviceProduct");
310 goto error;
311 }
312
313 kr = (*dev)->GetDeviceClass(dev, &handle->info.dev_class);
314 if (kr != 0) {
315 ERR("GetDeviceClass");
316 goto error;
317 }
318
319 kr = (*dev)->GetDeviceSubClass(dev, &handle->info.dev_subclass);
320 if (kr != 0) {
321 ERR("GetDeviceSubClass");
322 goto error;
323 }
324
325 kr = (*dev)->GetDeviceProtocol(dev, &handle->info.dev_protocol);
326 if (kr != 0) {
327 ERR("GetDeviceProtocol");
328 goto error;
329 }
330
Scott Anderson13081c62012-04-06 12:39:30 -0700331 kr = (*dev)->GetLocationID(dev, &locationId);
332 if (kr != 0) {
333 ERR("GetLocationId");
334 goto error;
335 }
Ying Wang42a809b2014-08-14 15:50:13 -0700336 snprintf(handle->info.device_path, sizeof(handle->info.device_path),
337 "usb:%" PRIu32 "X", (unsigned int)locationId);
Scott Anderson13081c62012-04-06 12:39:30 -0700338
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800339 kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
340
341 if (serialIndex > 0) {
342 IOUSBDevRequest req;
343 UInt16 buffer[256];
344
345 req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
346 req.bRequest = kUSBRqGetDescriptor;
347 req.wValue = (kUSBStringDesc << 8) | serialIndex;
mgrossc8406532011-07-07 17:08:10 -0700348 //language ID (en-us) for serial number string
349 req.wIndex = 0x0409;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800350 req.pData = buffer;
351 req.wLength = sizeof(buffer);
352 kr = (*dev)->DeviceRequest(dev, &req);
353
354 if (kr == kIOReturnSuccess && req.wLenDone > 0) {
355 int i, count;
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800356
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800357 // skip first word, and copy the rest to the serial string, changing shorts to bytes.
358 count = (req.wLenDone - 1) / 2;
359 for (i = 0; i < count; i++)
360 handle->info.serial_number[i] = buffer[i + 1];
361 handle->info.serial_number[i] = 0;
362 }
363 } else {
364 // device has no serial number
365 handle->info.serial_number[0] = 0;
366 }
Elliott Hughesb4add9b2009-10-06 18:07:49 -0700367 handle->info.writable = 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800368
369 if (try_interfaces(dev, handle)) {
370 goto error;
371 }
372
373 (*dev)->Release(dev);
374 return 0;
375
376 error:
377
378 if (dev != NULL) {
379 (*dev)->Release(dev);
380 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800381
382 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800383}
384
385
386/** Initializes the USB system. Returns 0 on success, -1 on error. */
David Pursell0b156632015-10-30 11:22:01 -0700387static int init_usb(ifc_match_func callback, std::unique_ptr<usb_handle>* handle) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800388 int ret = -1;
389 CFMutableDictionaryRef matchingDict;
390 kern_return_t result;
391 io_iterator_t iterator;
392 usb_handle h;
393
394 h.success = 0;
395 h.callback = callback;
396
397 /*
398 * Create our matching dictionary to find appropriate devices.
399 * IOServiceAddMatchingNotification consumes the reference, so we
400 * do not need to release it.
401 */
402 matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
403
404 if (matchingDict == NULL) {
405 ERR("Couldn't create USB matching dictionary.\n");
406 return -1;
407 }
408
409 result = IOServiceGetMatchingServices(
410 kIOMasterPortDefault, matchingDict, &iterator);
411
412 if (result != 0) {
413 ERR("Could not create iterator.");
414 return -1;
415 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800416
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800417 for (;;) {
418 if (! IOIteratorIsValid(iterator)) {
419 /*
420 * Apple documentation advises resetting the iterator if
421 * it should become invalid during iteration.
422 */
423 IOIteratorReset(iterator);
424 continue;
425 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800426
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800427 io_service_t device = IOIteratorNext(iterator);
428
429 if (device == 0) {
430 break;
431 }
432
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800433 if (try_device(device, &h) != 0) {
434 IOObjectRelease(device);
Josh Gaof806a3c2017-08-18 18:25:44 -0700435 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800436 }
437
438 if (h.success) {
David Pursell0b156632015-10-30 11:22:01 -0700439 handle->reset(new usb_handle);
440 memcpy(handle->get(), &h, sizeof(usb_handle));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800441 ret = 0;
442 break;
443 }
444
445 IOObjectRelease(device);
446 }
447
448 IOObjectRelease(iterator);
449
450 return ret;
451}
452
453
454
455/*
456 * Definitions of this file's public functions.
457 */
458
David Pursell0b156632015-10-30 11:22:01 -0700459Transport* usb_open(ifc_match_func callback) {
460 std::unique_ptr<usb_handle> handle;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800461
462 if (init_usb(callback, &handle) < 0) {
463 /* Something went wrong initializing USB. */
David Pursell0b156632015-10-30 11:22:01 -0700464 return nullptr;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800465 }
466
David Pursell0b156632015-10-30 11:22:01 -0700467 return new OsxUsbTransport(std::move(handle));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800468}
469
David Pursell0b156632015-10-30 11:22:01 -0700470int OsxUsbTransport::Close() {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800471 /* TODO: Something better here? */
472 return 0;
473}
474
David Pursell0b156632015-10-30 11:22:01 -0700475ssize_t OsxUsbTransport::Read(void* data, size_t len) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800476 IOReturn result;
477 UInt32 numBytes = len;
478
479 if (len == 0) {
480 return 0;
481 }
482
David Pursell0b156632015-10-30 11:22:01 -0700483 if (handle_ == nullptr) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800484 return -1;
485 }
486
David Pursell0b156632015-10-30 11:22:01 -0700487 if (handle_->interface == nullptr) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800488 ERR("usb_read interface was null\n");
489 return -1;
490 }
491
David Pursell0b156632015-10-30 11:22:01 -0700492 if (handle_->bulkIn == 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800493 ERR("bulkIn endpoint not assigned\n");
494 return -1;
495 }
496
David Pursell0b156632015-10-30 11:22:01 -0700497 result = (*handle_->interface)->ReadPipe(handle_->interface, handle_->bulkIn, data, &numBytes);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800498
499 if (result == 0) {
500 return (int) numBytes;
501 } else {
502 ERR("usb_read failed with status %x\n", result);
503 }
504
505 return -1;
506}
507
David Pursell0b156632015-10-30 11:22:01 -0700508ssize_t OsxUsbTransport::Write(const void* data, size_t len) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800509 IOReturn result;
510
511 if (len == 0) {
512 return 0;
513 }
514
David Pursell0b156632015-10-30 11:22:01 -0700515 if (handle_ == NULL) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800516 return -1;
517 }
518
David Pursell0b156632015-10-30 11:22:01 -0700519 if (handle_->interface == NULL) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800520 ERR("usb_write interface was null\n");
521 return -1;
522 }
523
David Pursell0b156632015-10-30 11:22:01 -0700524 if (handle_->bulkOut == 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800525 ERR("bulkOut endpoint not assigned\n");
526 return -1;
527 }
528
Jeff Brownb6406372010-05-21 13:20:47 -0700529#if 0
David Pursell0b156632015-10-30 11:22:01 -0700530 result = (*handle_->interface)->WritePipe(
531 handle_->interface, handle_->bulkOut, (void *)data, len);
Jeff Brownb6406372010-05-21 13:20:47 -0700532#else
533 /* Attempt to work around crashes in the USB driver that may be caused
534 * by trying to write too much data at once. The kernel IOCopyMapper
535 * panics if a single iovmAlloc needs more than half of its mapper pages.
536 */
537 const int maxLenToSend = 1048576; // 1 MiB
538 int lenRemaining = len;
539 result = 0;
540 while (lenRemaining > 0) {
541 int lenToSend = lenRemaining > maxLenToSend
542 ? maxLenToSend : lenRemaining;
543
David Pursell0b156632015-10-30 11:22:01 -0700544 result = (*handle_->interface)->WritePipe(
545 handle_->interface, handle_->bulkOut, (void *)data, lenToSend);
Jeff Brownb6406372010-05-21 13:20:47 -0700546 if (result != 0) break;
547
548 lenRemaining -= lenToSend;
549 data = (const char*)data + lenToSend;
550 }
551#endif
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800552
553 #if 0
David Pursell0b156632015-10-30 11:22:01 -0700554 if ((result == 0) && (handle_->zero_mask)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800555 /* we need 0-markers and our transfer */
David Pursell0b156632015-10-30 11:22:01 -0700556 if(!(len & handle_->zero_mask)) {
557 result = (*handle_->interface)->WritePipe(
558 handle_->interface, handle_->bulkOut, (void *)data, 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800559 }
560 }
561 #endif
562
563 if (result != 0) {
564 ERR("usb_write failed with status %x\n", result);
565 return -1;
566 }
567
568 return len;
569}