blob: fcd0bc044b559598996626ecaee2fa401530fcc5 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2007 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
Yabin Cuiaed3c612015-09-22 15:52:57 -070017#define TRACE_TAG USB
Dan Albert33134262015-03-19 15:21:08 -070018
19#include "sysdeps.h"
20
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080021#include <CoreFoundation/CoreFoundation.h>
22
23#include <IOKit/IOKitLib.h>
24#include <IOKit/IOCFPlugIn.h>
25#include <IOKit/usb/IOUSBLib.h>
26#include <IOKit/IOMessage.h>
27#include <mach/mach_port.h>
28
Dan Albert7447dd02015-04-16 19:20:40 -070029#include <inttypes.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080030#include <stdio.h>
31
Yabin Cui48d4c0c2016-03-25 13:55:07 -070032#include <atomic>
Elliott Hughesdbe91ee2016-11-15 12:37:32 -080033#include <chrono>
Yabin Cui48d4c0c2016-03-25 13:55:07 -070034#include <memory>
35#include <mutex>
Elliott Hughesdbe91ee2016-11-15 12:37:32 -080036#include <thread>
Yabin Cui48d4c0c2016-03-25 13:55:07 -070037#include <vector>
38
Elliott Hughes4f713192015-12-04 22:00:26 -080039#include <android-base/logging.h>
40#include <android-base/stringprintf.h>
Siva Velusamy743883b2015-08-18 17:53:16 -070041
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080042#include "adb.h"
Dan Albertdc0f8ec2015-02-25 10:26:17 -080043#include "transport.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080044
Elliott Hughesdbe91ee2016-11-15 12:37:32 -080045using namespace std::chrono_literals;
46
Josh Gao06766a82017-01-26 14:01:02 -080047namespace native {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080048struct usb_handle
49{
Siva Velusamyd8b48a62015-08-13 08:48:06 -070050 UInt8 bulkIn;
51 UInt8 bulkOut;
52 IOUSBInterfaceInterface190** interface;
Siva Velusamyd8b48a62015-08-13 08:48:06 -070053 unsigned int zero_mask;
Yabin Cui48d4c0c2016-03-25 13:55:07 -070054
55 // For garbage collecting disconnected devices.
56 bool mark;
57 std::string devpath;
58 std::atomic<bool> dead;
59
60 usb_handle() : bulkIn(0), bulkOut(0), interface(nullptr),
61 zero_mask(0), mark(false), dead(false) {
62 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080063};
64
Yabin Cui48d4c0c2016-03-25 13:55:07 -070065static std::atomic<bool> usb_inited_flag;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080066
Yabin Cui48d4c0c2016-03-25 13:55:07 -070067static auto& g_usb_handles_mutex = *new std::mutex();
68static auto& g_usb_handles = *new std::vector<std::unique_ptr<usb_handle>>();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080069
Yabin Cui48d4c0c2016-03-25 13:55:07 -070070static bool IsKnownDevice(const std::string& devpath) {
71 std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
72 for (auto& usb : g_usb_handles) {
73 if (usb->devpath == devpath) {
74 // Set mark flag to indicate this device is still alive.
75 usb->mark = true;
76 return true;
77 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080078 }
Yabin Cui48d4c0c2016-03-25 13:55:07 -070079 return false;
80}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080081
Yabin Cui48d4c0c2016-03-25 13:55:07 -070082static void usb_kick_locked(usb_handle* handle);
Al Sutton8e01cc62014-11-21 12:21:12 +000083
Yabin Cui48d4c0c2016-03-25 13:55:07 -070084static void KickDisconnectedDevices() {
85 std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
86 for (auto& usb : g_usb_handles) {
87 if (!usb->mark) {
88 usb_kick_locked(usb.get());
89 } else {
90 usb->mark = false;
91 }
92 }
93}
Al Sutton8e01cc62014-11-21 12:21:12 +000094
Yabin Cui48d4c0c2016-03-25 13:55:07 -070095static void AddDevice(std::unique_ptr<usb_handle> handle) {
96 handle->mark = true;
97 std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
98 g_usb_handles.push_back(std::move(handle));
99}
100
101static void AndroidInterfaceAdded(io_iterator_t iterator);
102static std::unique_ptr<usb_handle> CheckInterface(IOUSBInterfaceInterface190 **iface,
103 UInt16 vendor, UInt16 product);
104
105static bool FindUSBDevices() {
106 // Create the matching dictionary to find the Android device's adb interface.
107 CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
108 if (!matchingDict) {
109 LOG(ERROR) << "couldn't create USB matching dictionary";
110 return false;
111 }
112 // Create an iterator for all I/O Registry objects that match the dictionary.
113 io_iterator_t iter = 0;
114 kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
115 if (kr != KERN_SUCCESS) {
116 LOG(ERROR) << "failed to get matching services";
117 return false;
118 }
119 // Iterate over all matching objects.
120 AndroidInterfaceAdded(iter);
121 IOObjectRelease(iter);
122 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800123}
124
125static void
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700126AndroidInterfaceAdded(io_iterator_t iterator)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800127{
128 kern_return_t kr;
129 io_service_t usbDevice;
Dima Zavin3fd82b82009-05-08 18:25:58 -0700130 io_service_t usbInterface;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800131 IOCFPlugInInterface **plugInInterface = NULL;
Dima Zavin3fd82b82009-05-08 18:25:58 -0700132 IOUSBInterfaceInterface220 **iface = NULL;
133 IOUSBDeviceInterface197 **dev = NULL;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800134 HRESULT result;
135 SInt32 score;
Elliott Hughes62077d32015-08-25 17:48:12 -0700136 uint32_t locationId;
Dan Albert7447dd02015-04-16 19:20:40 -0700137 UInt8 if_class, subclass, protocol;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800138 UInt16 vendor;
139 UInt16 product;
140 UInt8 serialIndex;
141 char serial[256];
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700142 std::string devpath;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800143
Dima Zavin3fd82b82009-05-08 18:25:58 -0700144 while ((usbInterface = IOIteratorNext(iterator))) {
145 //* Create an intermediate interface plugin
146 kr = IOCreatePlugInInterfaceForService(usbInterface,
147 kIOUSBInterfaceUserClientTypeID,
148 kIOCFPlugInInterfaceID,
149 &plugInInterface, &score);
150 IOObjectRelease(usbInterface);
151 if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700152 LOG(ERROR) << "Unable to create an interface plug-in (" << std::hex << kr << ")";
Dima Zavin3fd82b82009-05-08 18:25:58 -0700153 continue;
154 }
155
156 //* This gets us the interface object
Dan Albert7447dd02015-04-16 19:20:40 -0700157 result = (*plugInInterface)->QueryInterface(
158 plugInInterface,
159 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID*)&iface);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700160 //* We only needed the plugin to get the interface, so discard it
161 (*plugInInterface)->Release(plugInInterface);
162 if (result || !iface) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700163 LOG(ERROR) << "Couldn't query the interface (" << std::hex << result << ")";
Dima Zavin3fd82b82009-05-08 18:25:58 -0700164 continue;
165 }
166
Dan Albert7447dd02015-04-16 19:20:40 -0700167 kr = (*iface)->GetInterfaceClass(iface, &if_class);
Al Sutton8e01cc62014-11-21 12:21:12 +0000168 kr = (*iface)->GetInterfaceSubClass(iface, &subclass);
169 kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
Dan Albert7447dd02015-04-16 19:20:40 -0700170 if(if_class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
Al Sutton8e01cc62014-11-21 12:21:12 +0000171 // Ignore non-ADB devices.
Siva Velusamy743883b2015-08-18 17:53:16 -0700172 LOG(DEBUG) << "Ignoring interface with incorrect class/subclass/protocol - " << if_class
173 << ", " << subclass << ", " << protocol;
Al Sutton8e01cc62014-11-21 12:21:12 +0000174 (*iface)->Release(iface);
175 continue;
176 }
177
Dima Zavin3fd82b82009-05-08 18:25:58 -0700178 //* this gets us an ioservice, with which we will find the actual
179 //* device; after getting a plugin, and querying the interface, of
180 //* course.
181 //* Gotta love OS X
182 kr = (*iface)->GetDevice(iface, &usbDevice);
183 if (kIOReturnSuccess != kr || !usbDevice) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700184 LOG(ERROR) << "Couldn't grab device from interface (" << std::hex << kr << ")";
Josh Gaob6a2f592016-09-27 12:35:55 -0700185 (*iface)->Release(iface);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700186 continue;
187 }
188
189 plugInInterface = NULL;
190 score = 0;
191 //* create an intermediate device plugin
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800192 kr = IOCreatePlugInInterfaceForService(usbDevice,
193 kIOUSBDeviceUserClientTypeID,
194 kIOCFPlugInInterfaceID,
195 &plugInInterface, &score);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700196 //* only needed this to find the plugin
197 (void)IOObjectRelease(usbDevice);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800198 if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700199 LOG(ERROR) << "Unable to create a device plug-in (" << std::hex << kr << ")";
Josh Gaob6a2f592016-09-27 12:35:55 -0700200 (*iface)->Release(iface);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700201 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800202 }
203
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800204 result = (*plugInInterface)->QueryInterface(plugInInterface,
Dan Albert7447dd02015-04-16 19:20:40 -0700205 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*)&dev);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700206 //* only needed this to query the plugin
207 (*plugInInterface)->Release(plugInInterface);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800208 if (result || !dev) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700209 LOG(ERROR) << "Couldn't create a device interface (" << std::hex << result << ")";
Josh Gaob6a2f592016-09-27 12:35:55 -0700210 (*iface)->Release(iface);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700211 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800212 }
213
Dima Zavin3fd82b82009-05-08 18:25:58 -0700214 //* Now after all that, we actually have a ref to the device and
215 //* the interface that matched our criteria
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800216 kr = (*dev)->GetDeviceVendor(dev, &vendor);
217 kr = (*dev)->GetDeviceProduct(dev, &product);
Scott Andersone109d262012-04-20 11:21:14 -0700218 kr = (*dev)->GetLocationID(dev, &locationId);
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700219 if (kr == KERN_SUCCESS) {
220 devpath = android::base::StringPrintf("usb:%" PRIu32 "X", locationId);
221 if (IsKnownDevice(devpath)) {
Josh Gaob6a2f592016-09-27 12:35:55 -0700222 (*dev)->Release(dev);
223 (*iface)->Release(iface);
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700224 continue;
225 }
Scott Andersone109d262012-04-20 11:21:14 -0700226 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800227 kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
228
Siva Velusamy743883b2015-08-18 17:53:16 -0700229 if (serialIndex > 0) {
230 IOUSBDevRequest req;
231 UInt16 buffer[256];
232 UInt16 languages[128];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800233
Siva Velusamy743883b2015-08-18 17:53:16 -0700234 memset(languages, 0, sizeof(languages));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800235
Siva Velusamy743883b2015-08-18 17:53:16 -0700236 req.bmRequestType =
237 USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
238 req.bRequest = kUSBRqGetDescriptor;
239 req.wValue = (kUSBStringDesc << 8) | 0;
240 req.wIndex = 0;
241 req.pData = languages;
242 req.wLength = sizeof(languages);
243 kr = (*dev)->DeviceRequest(dev, &req);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800244
Siva Velusamy743883b2015-08-18 17:53:16 -0700245 if (kr == kIOReturnSuccess && req.wLenDone > 0) {
Guang Zhu1a1f8182009-08-06 17:21:52 -0700246
Siva Velusamy743883b2015-08-18 17:53:16 -0700247 int langCount = (req.wLenDone - 2) / 2, lang;
Guang Zhu1a1f8182009-08-06 17:21:52 -0700248
Siva Velusamy743883b2015-08-18 17:53:16 -0700249 for (lang = 1; lang <= langCount; lang++) {
Guang Zhu1a1f8182009-08-06 17:21:52 -0700250
Siva Velusamy743883b2015-08-18 17:53:16 -0700251 memset(buffer, 0, sizeof(buffer));
252 memset(&req, 0, sizeof(req));
Guang Zhu1a1f8182009-08-06 17:21:52 -0700253
Siva Velusamy743883b2015-08-18 17:53:16 -0700254 req.bmRequestType =
255 USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
256 req.bRequest = kUSBRqGetDescriptor;
257 req.wValue = (kUSBStringDesc << 8) | serialIndex;
258 req.wIndex = languages[lang];
259 req.pData = buffer;
260 req.wLength = sizeof(buffer);
261 kr = (*dev)->DeviceRequest(dev, &req);
Guang Zhu1a1f8182009-08-06 17:21:52 -0700262
Siva Velusamy743883b2015-08-18 17:53:16 -0700263 if (kr == kIOReturnSuccess && req.wLenDone > 0) {
264 int i, count;
Guang Zhu1a1f8182009-08-06 17:21:52 -0700265
Siva Velusamy743883b2015-08-18 17:53:16 -0700266 // skip first word, and copy the rest to the serial string,
267 // changing shorts to bytes.
268 count = (req.wLenDone - 1) / 2;
269 for (i = 0; i < count; i++)
270 serial[i] = buffer[i + 1];
271 serial[i] = 0;
272 break;
273 }
274 }
275 }
276 }
277
Dima Zavin3fd82b82009-05-08 18:25:58 -0700278 (*dev)->Release(dev);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800279
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700280 VLOG(USB) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n",
Siva Velusamy743883b2015-08-18 17:53:16 -0700281 vendor, product, serial);
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700282 if (devpath.empty()) {
283 devpath = serial;
284 }
285 if (IsKnownDevice(devpath)) {
286 (*iface)->USBInterfaceClose(iface);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700287 (*iface)->Release(iface);
288 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800289 }
290
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700291 std::unique_ptr<usb_handle> handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
292 vendor, product);
293 if (handle == nullptr) {
294 LOG(ERROR) << "Could not find device interface";
295 (*iface)->Release(iface);
296 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800297 }
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700298 handle->devpath = devpath;
299 usb_handle* handle_p = handle.get();
300 VLOG(USB) << "Add usb device " << serial;
301 AddDevice(std::move(handle));
Josh Gao06766a82017-01-26 14:01:02 -0800302 register_usb_transport(reinterpret_cast<::usb_handle*>(handle_p), serial, devpath.c_str(),
303 1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800304 }
305}
306
Siva Velusamyd8b48a62015-08-13 08:48:06 -0700307// Used to clear both the endpoints before starting.
308// When adb quits, we might clear the host endpoint but not the device.
309// So we make sure both sides are clear before starting up.
310static bool ClearPipeStallBothEnds(IOUSBInterfaceInterface190** interface, UInt8 bulkEp) {
311 IOReturn rc = (*interface)->ClearPipeStallBothEnds(interface, bulkEp);
312 if (rc != kIOReturnSuccess) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700313 LOG(ERROR) << "Could not clear pipe stall both ends: " << std::hex << rc;
Siva Velusamyd8b48a62015-08-13 08:48:06 -0700314 return false;
315 }
316 return true;
317}
318
Dima Zavin3fd82b82009-05-08 18:25:58 -0700319//* TODO: simplify this further since we only register to get ADB interface
320//* subclass+protocol events
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700321static std::unique_ptr<usb_handle>
Siva Velusamyd8b48a62015-08-13 08:48:06 -0700322CheckInterface(IOUSBInterfaceInterface190 **interface, UInt16 vendor, UInt16 product)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800323{
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700324 std::unique_ptr<usb_handle> handle;
Elliott Hughes2d4f8522015-08-13 15:01:18 -0700325 IOReturn kr;
326 UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
327 UInt8 endpoint;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800328
Dima Zavin3fd82b82009-05-08 18:25:58 -0700329 //* Now open the interface. This will cause the pipes associated with
330 //* the endpoints in the interface descriptor to be instantiated
331 kr = (*interface)->USBInterfaceOpen(interface);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800332 if (kr != kIOReturnSuccess) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700333 LOG(ERROR) << "Could not open interface: " << std::hex << kr;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800334 return NULL;
335 }
336
Dima Zavin3fd82b82009-05-08 18:25:58 -0700337 //* Get the number of endpoints associated with this interface
338 kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
339 if (kr != kIOReturnSuccess) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700340 LOG(ERROR) << "Unable to get number of endpoints: " << std::hex << kr;
Dima Zavin3fd82b82009-05-08 18:25:58 -0700341 goto err_get_num_ep;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800342 }
343
Dima Zavin3fd82b82009-05-08 18:25:58 -0700344 //* Get interface class, subclass and protocol
345 if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
346 (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
347 (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700348 LOG(ERROR) << "Unable to get interface class, subclass and protocol";
Dima Zavin3fd82b82009-05-08 18:25:58 -0700349 goto err_get_interface_class;
350 }
351
352 //* check to make sure interface class, subclass and protocol match ADB
353 //* avoid opening mass storage endpoints
Josh Gao30186df2016-09-26 21:18:58 -0700354 if (!is_adb_interface(interfaceClass, interfaceSubClass, interfaceProtocol)) {
Dima Zavin3fd82b82009-05-08 18:25:58 -0700355 goto err_bad_adb_interface;
Siva Velusamyd8b48a62015-08-13 08:48:06 -0700356 }
Dima Zavin3fd82b82009-05-08 18:25:58 -0700357
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700358 handle.reset(new usb_handle);
359 if (handle == nullptr) {
360 goto err_bad_adb_interface;
361 }
Dima Zavin3fd82b82009-05-08 18:25:58 -0700362
363 //* Iterate over the endpoints for this interface and find the first
364 //* bulk in/out pipes available. These will be our read/write pipes.
Elliott Hughes2d4f8522015-08-13 15:01:18 -0700365 for (endpoint = 1; endpoint <= interfaceNumEndpoints; endpoint++) {
Dima Zavin3fd82b82009-05-08 18:25:58 -0700366 UInt8 transferType;
367 UInt16 maxPacketSize;
368 UInt8 interval;
369 UInt8 number;
370 UInt8 direction;
371
372 kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
373 &number, &transferType, &maxPacketSize, &interval);
Siva Velusamyd8b48a62015-08-13 08:48:06 -0700374 if (kr != kIOReturnSuccess) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700375 LOG(ERROR) << "FindDeviceInterface - could not get pipe properties: "
376 << std::hex << kr;
Dima Zavin3fd82b82009-05-08 18:25:58 -0700377 goto err_get_pipe_props;
378 }
Siva Velusamyd8b48a62015-08-13 08:48:06 -0700379
380 if (kUSBBulk != transferType) continue;
381
382 if (kUSBIn == direction) {
383 handle->bulkIn = endpoint;
384 if (!ClearPipeStallBothEnds(interface, handle->bulkIn)) goto err_get_pipe_props;
385 }
386
387 if (kUSBOut == direction) {
388 handle->bulkOut = endpoint;
389 if (!ClearPipeStallBothEnds(interface, handle->bulkOut)) goto err_get_pipe_props;
390 }
391
392 handle->zero_mask = maxPacketSize - 1;
Dima Zavin3fd82b82009-05-08 18:25:58 -0700393 }
394
395 handle->interface = interface;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800396 return handle;
Dima Zavin3fd82b82009-05-08 18:25:58 -0700397
398err_get_pipe_props:
Dima Zavin3fd82b82009-05-08 18:25:58 -0700399err_bad_adb_interface:
400err_get_interface_class:
401err_get_num_ep:
402 (*interface)->USBInterfaceClose(interface);
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700403 return nullptr;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800404}
405
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700406std::mutex& operate_device_lock = *new std::mutex();
407
Josh Gaoe1dacfc2017-04-12 17:00:49 -0700408static void RunLoopThread() {
Siva Velusamy49ee7cf2015-08-28 16:37:29 -0700409 adb_thread_setname("RunLoop");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800410
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700411 VLOG(USB) << "RunLoopThread started";
412 while (true) {
413 {
414 std::lock_guard<std::mutex> lock_guard(operate_device_lock);
415 FindUSBDevices();
416 KickDisconnectedDevices();
417 }
418 // Signal the parent that we are running
419 usb_inited_flag = true;
Elliott Hughesdbe91ee2016-11-15 12:37:32 -0800420 std::this_thread::sleep_for(1s);
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700421 }
422 VLOG(USB) << "RunLoopThread done";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800423}
424
Dan Albertc89e0cc2015-05-08 16:13:53 -0700425static void usb_cleanup() {
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700426 VLOG(USB) << "usb_cleanup";
427 // Wait until usb operations in RunLoopThread finish, and prevent further operations.
428 operate_device_lock.lock();
Dan Albertc89e0cc2015-05-08 16:13:53 -0700429 close_usb_devices();
Dan Albertc89e0cc2015-05-08 16:13:53 -0700430}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800431
Elliott Hughes9b0f3542015-05-05 13:41:21 -0700432void usb_init() {
Dan Albertc89e0cc2015-05-08 16:13:53 -0700433 static bool initialized = false;
434 if (!initialized) {
435 atexit(usb_cleanup);
436
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700437 usb_inited_flag = false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800438
Josh Gaoe1dacfc2017-04-12 17:00:49 -0700439 std::thread(RunLoopThread).detach();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800440
441 // Wait for initialization to finish
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700442 while (!usb_inited_flag) {
Elliott Hughesdbe91ee2016-11-15 12:37:32 -0800443 std::this_thread::sleep_for(100ms);
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700444 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800445
Dan Albertc89e0cc2015-05-08 16:13:53 -0700446 initialized = true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800447 }
448}
449
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800450int usb_write(usb_handle *handle, const void *buf, int len)
451{
452 IOReturn result;
453
454 if (!len)
455 return 0;
456
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700457 if (!handle || handle->dead)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800458 return -1;
459
460 if (NULL == handle->interface) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700461 LOG(ERROR) << "usb_write interface was null";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800462 return -1;
463 }
464
465 if (0 == handle->bulkOut) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700466 LOG(ERROR) << "bulkOut endpoint not assigned";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800467 return -1;
468 }
469
470 result =
Siva Velusamy743883b2015-08-18 17:53:16 -0700471 (*handle->interface)->WritePipe(handle->interface, handle->bulkOut, (void *)buf, len);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800472
473 if ((result == 0) && (handle->zero_mask)) {
474 /* we need 0-markers and our transfer */
475 if(!(len & handle->zero_mask)) {
476 result =
477 (*handle->interface)->WritePipe(
478 handle->interface, handle->bulkOut, (void *)buf, 0);
479 }
480 }
481
482 if (0 == result)
483 return 0;
484
Siva Velusamy743883b2015-08-18 17:53:16 -0700485 LOG(ERROR) << "usb_write failed with status: " << std::hex << result;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800486 return -1;
487}
488
489int usb_read(usb_handle *handle, void *buf, int len)
490{
491 IOReturn result;
492 UInt32 numBytes = len;
493
494 if (!len) {
495 return 0;
496 }
497
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700498 if (!handle || handle->dead) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800499 return -1;
500 }
501
502 if (NULL == handle->interface) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700503 LOG(ERROR) << "usb_read interface was null";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800504 return -1;
505 }
506
507 if (0 == handle->bulkIn) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700508 LOG(ERROR) << "bulkIn endpoint not assigned";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800509 return -1;
510 }
511
Esteban de la Canal9dd83dc2014-09-11 11:02:17 -0700512 result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800513
Esteban de la Canal9dd83dc2014-09-11 11:02:17 -0700514 if (kIOUSBPipeStalled == result) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700515 LOG(ERROR) << "Pipe stalled, clearing stall.\n";
Esteban de la Canal9dd83dc2014-09-11 11:02:17 -0700516 (*handle->interface)->ClearPipeStall(handle->interface, handle->bulkIn);
517 result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
518 }
519
520 if (kIOReturnSuccess == result)
Yabin Cuib5e11412017-03-10 16:01:01 -0800521 return numBytes;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800522 else {
Siva Velusamy743883b2015-08-18 17:53:16 -0700523 LOG(ERROR) << "usb_read failed with status: " << std::hex << result;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800524 }
525
526 return -1;
527}
528
529int usb_close(usb_handle *handle)
530{
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700531 std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
532 for (auto it = g_usb_handles.begin(); it != g_usb_handles.end(); ++it) {
533 if ((*it).get() == handle) {
534 g_usb_handles.erase(it);
535 break;
536 }
537 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800538 return 0;
539}
540
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700541static void usb_kick_locked(usb_handle *handle)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800542{
Siva Velusamy743883b2015-08-18 17:53:16 -0700543 LOG(INFO) << "Kicking handle";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800544 /* release the interface */
Dima Zavin3fd82b82009-05-08 18:25:58 -0700545 if (!handle)
546 return;
547
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700548 if (!handle->dead)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800549 {
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700550 handle->dead = true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800551 (*handle->interface)->USBInterfaceClose(handle->interface);
552 (*handle->interface)->Release(handle->interface);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800553 }
554}
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700555
556void usb_kick(usb_handle *handle) {
557 // Use the lock to avoid multiple thread kicking the device at the same time.
558 std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
559 usb_kick_locked(handle);
560}
Josh Gao06766a82017-01-26 14:01:02 -0800561} // namespace native