blob: 28300b2e1808c4820ace5f510bdedeac4b7f4f24 [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;
Eran Messeribe0ab0a2018-11-10 23:56:19 +000064 IOUSBInterfaceInterface500** interface;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080065 unsigned int zero_mask;
66};
67
Aaron Wisneracf78d42018-07-26 10:56:09 -050068class OsxUsbTransport : public UsbTransport {
David Pursell0b156632015-10-30 11:22:01 -070069 public:
Aaron Wisneracf78d42018-07-26 10:56:09 -050070 // A timeout of 0 is blocking
71 OsxUsbTransport(std::unique_ptr<usb_handle> handle, uint32_t ms_timeout = 0)
72 : handle_(std::move(handle)), ms_timeout_(ms_timeout) {}
David Anderson03de6452018-09-04 14:32:54 -070073 ~OsxUsbTransport() override;
David Pursell0b156632015-10-30 11:22:01 -070074
75 ssize_t Read(void* data, size_t len) override;
76 ssize_t Write(const void* data, size_t len) override;
77 int Close() override;
Aaron Wisneracf78d42018-07-26 10:56:09 -050078 int Reset() override;
David Pursell0b156632015-10-30 11:22:01 -070079
80 private:
81 std::unique_ptr<usb_handle> handle_;
Aaron Wisneracf78d42018-07-26 10:56:09 -050082 const uint32_t ms_timeout_;
David Pursell0b156632015-10-30 11:22:01 -070083
84 DISALLOW_COPY_AND_ASSIGN(OsxUsbTransport);
85};
86
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080087/** Try out all the interfaces and see if there's a match. Returns 0 on
88 * success, -1 on failure. */
Eran Messeribe0ab0a2018-11-10 23:56:19 +000089static int try_interfaces(IOUSBDeviceInterface500** dev, usb_handle* handle) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080090 IOReturn kr;
91 IOUSBFindInterfaceRequest request;
92 io_iterator_t iterator;
93 io_service_t usbInterface;
94 IOCFPlugInInterface **plugInInterface;
Eran Messeribe0ab0a2018-11-10 23:56:19 +000095 IOUSBInterfaceInterface500** interface = NULL;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080096 HRESULT result;
97 SInt32 score;
98 UInt8 interfaceNumEndpoints;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080099
Josh Gaof806a3c2017-08-18 18:25:44 -0700100 request.bInterfaceClass = 0xff;
101 request.bInterfaceSubClass = 0x42;
102 request.bInterfaceProtocol = 0x03;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800103 request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
104
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800105 // Get an iterator for the interfaces on the device
106 kr = (*dev)->CreateInterfaceIterator(dev, &request, &iterator);
107
108 if (kr != 0) {
Josh Gao16f992e2019-05-10 11:28:38 -0700109 WARN("Couldn't create a device interface iterator: (%08x)\n", kr);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800110 return -1;
111 }
112
113 while ((usbInterface = IOIteratorNext(iterator))) {
114 // Create an intermediate plugin
115 kr = IOCreatePlugInInterfaceForService(
116 usbInterface,
117 kIOUSBInterfaceUserClientTypeID,
118 kIOCFPlugInInterfaceID,
119 &plugInInterface,
120 &score);
121
122 // No longer need the usbInterface object now that we have the plugin
123 (void) IOObjectRelease(usbInterface);
124
125 if ((kr != 0) || (!plugInInterface)) {
126 WARN("Unable to create plugin (%08x)\n", kr);
127 continue;
128 }
129
130 // Now create the interface interface for the interface
Eran Messeribe0ab0a2018-11-10 23:56:19 +0000131 result = (*plugInInterface)
132 ->QueryInterface(plugInInterface,
133 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID500),
134 (LPVOID*)&interface);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800135
136 // No longer need the intermediate plugin
137 (*plugInInterface)->Release(plugInInterface);
138
139 if (result || !interface) {
140 ERR("Couldn't create interface interface: (%08x)\n",
141 (unsigned int) result);
142 // continue so we can try the next interface
143 continue;
144 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800145
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800146 /*
147 * Now open the interface. This will cause the pipes
148 * associated with the endpoints in the interface descriptor
149 * to be instantiated.
150 */
151
152 /*
153 * TODO: Earlier comments here indicated that it was a bad
154 * idea to just open any interface, because opening "mass
155 * storage endpoints" is bad. However, the only way to find
156 * out if an interface does bulk in or out is to open it, and
157 * the framework in this application wants to be told about
158 * bulk in / out before deciding whether it actually wants to
159 * use the interface. Maybe something needs to be done about
160 * this situation.
161 */
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800162
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800163 kr = (*interface)->USBInterfaceOpen(interface);
164
165 if (kr != 0) {
166 WARN("Could not open interface: (%08x)\n", kr);
167 (void) (*interface)->Release(interface);
168 // continue so we can try the next interface
169 continue;
170 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800171
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800172 // Get the number of endpoints associated with this interface.
173 kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
174
175 if (kr != 0) {
176 ERR("Unable to get number of endpoints: (%08x)\n", kr);
177 goto next_interface;
178 }
179
180 // Get interface class, subclass and protocol
181 if ((*interface)->GetInterfaceClass(interface, &handle->info.ifc_class) != 0 ||
182 (*interface)->GetInterfaceSubClass(interface, &handle->info.ifc_subclass) != 0 ||
183 (*interface)->GetInterfaceProtocol(interface, &handle->info.ifc_protocol) != 0)
184 {
185 ERR("Unable to get interface class, subclass and protocol\n");
186 goto next_interface;
187 }
188
189 handle->info.has_bulk_in = 0;
190 handle->info.has_bulk_out = 0;
191
192 // Iterate over the endpoints for this interface and see if there
193 // are any that do bulk in/out.
Shaju Mathewdce13712022-12-19 21:28:51 -0800194 for (UInt8 endpoint = 1; endpoint <= interfaceNumEndpoints; ++endpoint) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800195 UInt8 transferType;
Shaju Mathewdce13712022-12-19 21:28:51 -0800196 UInt16 endPointMaxPacketSize = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800197 UInt8 interval;
Shaju Mathewdce13712022-12-19 21:28:51 -0800198
199 // Attempt to retrieve the 'true' packet-size from supported interface.
200 kr = (*interface)
201 ->GetEndpointProperties(interface, 0, endpoint,
202 kUSBOut,
203 &transferType,
204 &endPointMaxPacketSize, &interval);
205 if (kr == kIOReturnSuccess && !endPointMaxPacketSize) {
206 ERR("GetEndpointProperties() returned zero len packet-size");
207 }
208
209 UInt16 pipePropMaxPacketSize;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800210 UInt8 number;
211 UInt8 direction;
212
Shaju Mathewdce13712022-12-19 21:28:51 -0800213 // Proceed with extracting the transfer direction, so we can fill in the
214 // appropriate fields (bulkIn or bulkOut).
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800215 kr = (*interface)->GetPipeProperties(interface, endpoint,
216 &direction,
Shaju Mathewdce13712022-12-19 21:28:51 -0800217 &number, &transferType, &pipePropMaxPacketSize, &interval);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800218
219 if (kr == 0) {
220 if (transferType != kUSBBulk) {
221 continue;
222 }
223
224 if (direction == kUSBIn) {
225 handle->info.has_bulk_in = 1;
226 handle->bulkIn = endpoint;
227 } else if (direction == kUSBOut) {
228 handle->info.has_bulk_out = 1;
229 handle->bulkOut = endpoint;
230 }
231
232 if (handle->info.ifc_protocol == 0x01) {
Shaju Mathewdce13712022-12-19 21:28:51 -0800233 handle->zero_mask = (endPointMaxPacketSize == 0) ?
234 pipePropMaxPacketSize - 1 : endPointMaxPacketSize - 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800235 }
236 } else {
Elliott Hughes2ae8d2e2015-08-07 10:49:36 -0700237 ERR("could not get pipe properties for endpoint %u (%08x)\n", endpoint, kr);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800238 }
239
240 if (handle->info.has_bulk_in && handle->info.has_bulk_out) {
241 break;
242 }
243 }
244
245 if (handle->callback(&handle->info) == 0) {
246 handle->interface = interface;
247 handle->success = 1;
248
249 /*
250 * Clear both the endpoints, because it has been observed
251 * that the Mac may otherwise (incorrectly) start out with
252 * them in bad state.
253 */
254
255 if (handle->info.has_bulk_in) {
256 kr = (*interface)->ClearPipeStallBothEnds(interface,
257 handle->bulkIn);
258 if (kr != 0) {
Nick Pelly286d50f2010-07-22 10:59:55 -0700259 ERR("could not clear input pipe; result %x, ignoring...\n", kr);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800260 }
261 }
262
263 if (handle->info.has_bulk_out) {
264 kr = (*interface)->ClearPipeStallBothEnds(interface,
265 handle->bulkOut);
266 if (kr != 0) {
Nick Pelly286d50f2010-07-22 10:59:55 -0700267 ERR("could not clear output pipe; result %x, ignoring....\n", kr);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800268 }
269 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800270
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800271 return 0;
272 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800273
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800274next_interface:
275 (*interface)->USBInterfaceClose(interface);
276 (*interface)->Release(interface);
277 }
278
279 return 0;
280}
281
282/** Try out the given device and see if there's a match. Returns 0 on
283 * success, -1 on failure.
284 */
285static int try_device(io_service_t device, usb_handle *handle) {
286 kern_return_t kr;
287 IOCFPlugInInterface **plugin = NULL;
Eran Messeribe0ab0a2018-11-10 23:56:19 +0000288 IOUSBDeviceInterface500** dev = NULL;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800289 SInt32 score;
290 HRESULT result;
291 UInt8 serialIndex;
Scott Anderson13081c62012-04-06 12:39:30 -0700292 UInt32 locationId;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800293
294 // Create an intermediate plugin.
295 kr = IOCreatePlugInInterfaceForService(device,
296 kIOUSBDeviceUserClientTypeID,
297 kIOCFPlugInInterfaceID,
298 &plugin, &score);
299
300 if ((kr != 0) || (plugin == NULL)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800301 goto error;
302 }
303
304 // Now create the device interface.
Eran Messeribe0ab0a2018-11-10 23:56:19 +0000305 result = (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID500),
306 (LPVOID*)&dev);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800307 if ((result != 0) || (dev == NULL)) {
308 ERR("Couldn't create a device interface (%08x)\n", (int) result);
309 goto error;
310 }
311
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800312 /*
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800313 * We don't need the intermediate interface after the device interface
314 * is created.
315 */
316 IODestroyPlugInInterface(plugin);
317
318 // So, we have a device, finally. Grab its vitals.
319
320 kr = (*dev)->GetDeviceVendor(dev, &handle->info.dev_vendor);
321 if (kr != 0) {
322 ERR("GetDeviceVendor");
323 goto error;
324 }
325
326 kr = (*dev)->GetDeviceProduct(dev, &handle->info.dev_product);
327 if (kr != 0) {
328 ERR("GetDeviceProduct");
329 goto error;
330 }
331
332 kr = (*dev)->GetDeviceClass(dev, &handle->info.dev_class);
333 if (kr != 0) {
334 ERR("GetDeviceClass");
335 goto error;
336 }
337
338 kr = (*dev)->GetDeviceSubClass(dev, &handle->info.dev_subclass);
339 if (kr != 0) {
340 ERR("GetDeviceSubClass");
341 goto error;
342 }
343
344 kr = (*dev)->GetDeviceProtocol(dev, &handle->info.dev_protocol);
345 if (kr != 0) {
346 ERR("GetDeviceProtocol");
347 goto error;
348 }
349
Scott Anderson13081c62012-04-06 12:39:30 -0700350 kr = (*dev)->GetLocationID(dev, &locationId);
351 if (kr != 0) {
352 ERR("GetLocationId");
353 goto error;
354 }
Ying Wang42a809b2014-08-14 15:50:13 -0700355 snprintf(handle->info.device_path, sizeof(handle->info.device_path),
356 "usb:%" PRIu32 "X", (unsigned int)locationId);
Scott Anderson13081c62012-04-06 12:39:30 -0700357
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800358 kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
359
360 if (serialIndex > 0) {
361 IOUSBDevRequest req;
362 UInt16 buffer[256];
363
364 req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
365 req.bRequest = kUSBRqGetDescriptor;
366 req.wValue = (kUSBStringDesc << 8) | serialIndex;
mgrossc8406532011-07-07 17:08:10 -0700367 //language ID (en-us) for serial number string
368 req.wIndex = 0x0409;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800369 req.pData = buffer;
370 req.wLength = sizeof(buffer);
371 kr = (*dev)->DeviceRequest(dev, &req);
372
373 if (kr == kIOReturnSuccess && req.wLenDone > 0) {
374 int i, count;
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800375
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800376 // skip first word, and copy the rest to the serial string, changing shorts to bytes.
377 count = (req.wLenDone - 1) / 2;
378 for (i = 0; i < count; i++)
379 handle->info.serial_number[i] = buffer[i + 1];
380 handle->info.serial_number[i] = 0;
381 }
382 } else {
383 // device has no serial number
384 handle->info.serial_number[0] = 0;
385 }
David Anderson4e058ca2020-05-28 04:39:37 +0000386 handle->info.interface[0] = 0;
Elliott Hughesb4add9b2009-10-06 18:07:49 -0700387 handle->info.writable = 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800388
389 if (try_interfaces(dev, handle)) {
390 goto error;
391 }
392
393 (*dev)->Release(dev);
394 return 0;
395
396 error:
397
398 if (dev != NULL) {
399 (*dev)->Release(dev);
400 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800401
402 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800403}
404
405
406/** Initializes the USB system. Returns 0 on success, -1 on error. */
David Pursell0b156632015-10-30 11:22:01 -0700407static int init_usb(ifc_match_func callback, std::unique_ptr<usb_handle>* handle) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800408 int ret = -1;
409 CFMutableDictionaryRef matchingDict;
410 kern_return_t result;
411 io_iterator_t iterator;
412 usb_handle h;
413
414 h.success = 0;
415 h.callback = callback;
416
417 /*
418 * Create our matching dictionary to find appropriate devices.
419 * IOServiceAddMatchingNotification consumes the reference, so we
420 * do not need to release it.
421 */
422 matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
423
424 if (matchingDict == NULL) {
425 ERR("Couldn't create USB matching dictionary.\n");
426 return -1;
427 }
428
429 result = IOServiceGetMatchingServices(
430 kIOMasterPortDefault, matchingDict, &iterator);
431
432 if (result != 0) {
433 ERR("Could not create iterator.");
434 return -1;
435 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800436
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800437 for (;;) {
438 if (! IOIteratorIsValid(iterator)) {
Roy Luod1d5f5a2023-06-20 21:44:53 +0000439 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800440 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800441
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800442 io_service_t device = IOIteratorNext(iterator);
443
444 if (device == 0) {
445 break;
446 }
447
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800448 if (try_device(device, &h) != 0) {
449 IOObjectRelease(device);
Josh Gaof806a3c2017-08-18 18:25:44 -0700450 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800451 }
452
453 if (h.success) {
Dmitrii Merkurevb5b82762023-02-15 15:21:22 +0000454 handle->reset(new usb_handle(h));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800455 ret = 0;
456 break;
457 }
458
459 IOObjectRelease(device);
460 }
461
462 IOObjectRelease(iterator);
463
464 return ret;
465}
466
467
468
469/*
470 * Definitions of this file's public functions.
471 */
Dmitrii Merkurev0b627d92023-09-03 17:30:46 +0100472std::unique_ptr<UsbTransport> usb_open(ifc_match_func callback, uint32_t timeout_ms) {
473 std::unique_ptr<UsbTransport> result;
David Pursell0b156632015-10-30 11:22:01 -0700474 std::unique_ptr<usb_handle> handle;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800475
476 if (init_usb(callback, &handle) < 0) {
477 /* Something went wrong initializing USB. */
Dmitrii Merkurev0b627d92023-09-03 17:30:46 +0100478 return result;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800479 }
480
Dmitrii Merkurev0b627d92023-09-03 17:30:46 +0100481 if (handle) {
482 result = std::make_unique<OsxUsbTransport>(std::move(handle), timeout_ms);
483 }
484
485 return result;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800486}
487
David Anderson03de6452018-09-04 14:32:54 -0700488OsxUsbTransport::~OsxUsbTransport() {
489 Close();
490}
491
David Pursell0b156632015-10-30 11:22:01 -0700492int OsxUsbTransport::Close() {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800493 /* TODO: Something better here? */
494 return 0;
495}
496
Aaron Wisneracf78d42018-07-26 10:56:09 -0500497/*
498 TODO: this SHOULD be easy to do with ResetDevice() from IOUSBDeviceInterface.
499 However to perform operations that manipulate the state of the device, you must
500 claim ownership of the device with USBDeviceOpenSeize(). However, this operation
501 always fails with kIOReturnExclusiveAccess.
502 It seems that the kext com.apple.driver.usb.AppleUSBHostCompositeDevice
503 always loads and claims ownership of the device and refuses to give it up.
504*/
505int OsxUsbTransport::Reset() {
506 ERR("USB reset is currently unsupported on osx\n");
507 return -1;
508}
509
David Pursell0b156632015-10-30 11:22:01 -0700510ssize_t OsxUsbTransport::Read(void* data, size_t len) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800511 IOReturn result;
512 UInt32 numBytes = len;
513
514 if (len == 0) {
515 return 0;
516 }
517
David Pursell0b156632015-10-30 11:22:01 -0700518 if (handle_ == nullptr) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800519 return -1;
520 }
521
David Pursell0b156632015-10-30 11:22:01 -0700522 if (handle_->interface == nullptr) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800523 ERR("usb_read interface was null\n");
524 return -1;
525 }
526
David Pursell0b156632015-10-30 11:22:01 -0700527 if (handle_->bulkIn == 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800528 ERR("bulkIn endpoint not assigned\n");
529 return -1;
530 }
531
Aaron Wisneracf78d42018-07-26 10:56:09 -0500532 if (!ms_timeout_) {
533 result = (*handle_->interface)
534 ->ReadPipe(handle_->interface, handle_->bulkIn, data, &numBytes);
535 } else {
536 result = (*handle_->interface)
537 ->ReadPipeTO(handle_->interface, handle_->bulkIn, data, &numBytes,
538 ms_timeout_, ms_timeout_);
539 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800540
541 if (result == 0) {
542 return (int) numBytes;
543 } else {
544 ERR("usb_read failed with status %x\n", result);
545 }
546
547 return -1;
548}
549
David Pursell0b156632015-10-30 11:22:01 -0700550ssize_t OsxUsbTransport::Write(const void* data, size_t len) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800551 IOReturn result;
552
553 if (len == 0) {
554 return 0;
555 }
556
David Pursell0b156632015-10-30 11:22:01 -0700557 if (handle_ == NULL) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800558 return -1;
559 }
560
David Pursell0b156632015-10-30 11:22:01 -0700561 if (handle_->interface == NULL) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800562 ERR("usb_write interface was null\n");
563 return -1;
564 }
565
David Pursell0b156632015-10-30 11:22:01 -0700566 if (handle_->bulkOut == 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800567 ERR("bulkOut endpoint not assigned\n");
568 return -1;
569 }
570
Jeff Brownb6406372010-05-21 13:20:47 -0700571#if 0
David Pursell0b156632015-10-30 11:22:01 -0700572 result = (*handle_->interface)->WritePipe(
573 handle_->interface, handle_->bulkOut, (void *)data, len);
Jeff Brownb6406372010-05-21 13:20:47 -0700574#else
575 /* Attempt to work around crashes in the USB driver that may be caused
576 * by trying to write too much data at once. The kernel IOCopyMapper
577 * panics if a single iovmAlloc needs more than half of its mapper pages.
578 */
579 const int maxLenToSend = 1048576; // 1 MiB
580 int lenRemaining = len;
581 result = 0;
582 while (lenRemaining > 0) {
583 int lenToSend = lenRemaining > maxLenToSend
584 ? maxLenToSend : lenRemaining;
585
Aaron Wisneracf78d42018-07-26 10:56:09 -0500586 if (!ms_timeout_) { // blocking
587 result = (*handle_->interface)
588 ->WritePipe(handle_->interface, handle_->bulkOut, (void*)data,
589 lenToSend);
590 } else {
591 result = (*handle_->interface)
592 ->WritePipeTO(handle_->interface, handle_->bulkOut, (void*)data,
593 lenToSend, ms_timeout_, ms_timeout_);
594 }
595
Jeff Brownb6406372010-05-21 13:20:47 -0700596 if (result != 0) break;
597
598 lenRemaining -= lenToSend;
599 data = (const char*)data + lenToSend;
600 }
601#endif
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800602
603 #if 0
David Pursell0b156632015-10-30 11:22:01 -0700604 if ((result == 0) && (handle_->zero_mask)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800605 /* we need 0-markers and our transfer */
David Pursell0b156632015-10-30 11:22:01 -0700606 if(!(len & handle_->zero_mask)) {
607 result = (*handle_->interface)->WritePipe(
608 handle_->interface, handle_->bulkOut, (void *)data, 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800609 }
610 }
611 #endif
612
613 if (result != 0) {
614 ERR("usb_write failed with status %x\n", result);
615 return -1;
616 }
617
618 return len;
619}