blob: b15d28a272589d5681d90f444a9a65d9d0a337e3 [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>
Josh Gao04a82182017-05-04 15:58:01 -070041#include <android-base/thread_annotations.h>
Siva Velusamy743883b2015-08-18 17:53:16 -070042
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080043#include "adb.h"
Dan Albertdc0f8ec2015-02-25 10:26:17 -080044#include "transport.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080045
Elliott Hughesdbe91ee2016-11-15 12:37:32 -080046using namespace std::chrono_literals;
47
Josh Gao06766a82017-01-26 14:01:02 -080048namespace native {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080049struct usb_handle
50{
Siva Velusamyd8b48a62015-08-13 08:48:06 -070051 UInt8 bulkIn;
52 UInt8 bulkOut;
53 IOUSBInterfaceInterface190** interface;
Siva Velusamyd8b48a62015-08-13 08:48:06 -070054 unsigned int zero_mask;
Josh Gaoef3d3432017-05-02 15:01:09 -070055 size_t max_packet_size;
Yabin Cui48d4c0c2016-03-25 13:55:07 -070056
57 // For garbage collecting disconnected devices.
58 bool mark;
59 std::string devpath;
60 std::atomic<bool> dead;
61
Josh Gaoef3d3432017-05-02 15:01:09 -070062 usb_handle()
63 : bulkIn(0),
64 bulkOut(0),
65 interface(nullptr),
66 zero_mask(0),
67 max_packet_size(0),
68 mark(false),
69 dead(false) {}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080070};
71
Yabin Cui48d4c0c2016-03-25 13:55:07 -070072static std::atomic<bool> usb_inited_flag;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080073
Yabin Cui48d4c0c2016-03-25 13:55:07 -070074static auto& g_usb_handles_mutex = *new std::mutex();
75static auto& g_usb_handles = *new std::vector<std::unique_ptr<usb_handle>>();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080076
Yabin Cui48d4c0c2016-03-25 13:55:07 -070077static bool IsKnownDevice(const std::string& devpath) {
78 std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
79 for (auto& usb : g_usb_handles) {
80 if (usb->devpath == devpath) {
81 // Set mark flag to indicate this device is still alive.
82 usb->mark = true;
83 return true;
84 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080085 }
Yabin Cui48d4c0c2016-03-25 13:55:07 -070086 return false;
87}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080088
Yabin Cui48d4c0c2016-03-25 13:55:07 -070089static void usb_kick_locked(usb_handle* handle);
Al Sutton8e01cc62014-11-21 12:21:12 +000090
Yabin Cui48d4c0c2016-03-25 13:55:07 -070091static void KickDisconnectedDevices() {
92 std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
93 for (auto& usb : g_usb_handles) {
94 if (!usb->mark) {
95 usb_kick_locked(usb.get());
96 } else {
97 usb->mark = false;
98 }
99 }
100}
Al Sutton8e01cc62014-11-21 12:21:12 +0000101
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700102static void AddDevice(std::unique_ptr<usb_handle> handle) {
103 handle->mark = true;
104 std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
105 g_usb_handles.push_back(std::move(handle));
106}
107
108static void AndroidInterfaceAdded(io_iterator_t iterator);
109static std::unique_ptr<usb_handle> CheckInterface(IOUSBInterfaceInterface190 **iface,
110 UInt16 vendor, UInt16 product);
111
112static bool FindUSBDevices() {
113 // Create the matching dictionary to find the Android device's adb interface.
114 CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
115 if (!matchingDict) {
116 LOG(ERROR) << "couldn't create USB matching dictionary";
117 return false;
118 }
119 // Create an iterator for all I/O Registry objects that match the dictionary.
120 io_iterator_t iter = 0;
121 kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
122 if (kr != KERN_SUCCESS) {
123 LOG(ERROR) << "failed to get matching services";
124 return false;
125 }
126 // Iterate over all matching objects.
127 AndroidInterfaceAdded(iter);
128 IOObjectRelease(iter);
129 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800130}
131
132static void
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700133AndroidInterfaceAdded(io_iterator_t iterator)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800134{
135 kern_return_t kr;
136 io_service_t usbDevice;
Dima Zavin3fd82b82009-05-08 18:25:58 -0700137 io_service_t usbInterface;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800138 IOCFPlugInInterface **plugInInterface = NULL;
Dima Zavin3fd82b82009-05-08 18:25:58 -0700139 IOUSBInterfaceInterface220 **iface = NULL;
140 IOUSBDeviceInterface197 **dev = NULL;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800141 HRESULT result;
142 SInt32 score;
Elliott Hughes62077d32015-08-25 17:48:12 -0700143 uint32_t locationId;
Dan Albert7447dd02015-04-16 19:20:40 -0700144 UInt8 if_class, subclass, protocol;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800145 UInt16 vendor;
146 UInt16 product;
147 UInt8 serialIndex;
148 char serial[256];
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700149 std::string devpath;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800150
Dima Zavin3fd82b82009-05-08 18:25:58 -0700151 while ((usbInterface = IOIteratorNext(iterator))) {
152 //* Create an intermediate interface plugin
153 kr = IOCreatePlugInInterfaceForService(usbInterface,
154 kIOUSBInterfaceUserClientTypeID,
155 kIOCFPlugInInterfaceID,
156 &plugInInterface, &score);
157 IOObjectRelease(usbInterface);
158 if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700159 LOG(ERROR) << "Unable to create an interface plug-in (" << std::hex << kr << ")";
Dima Zavin3fd82b82009-05-08 18:25:58 -0700160 continue;
161 }
162
163 //* This gets us the interface object
Dan Albert7447dd02015-04-16 19:20:40 -0700164 result = (*plugInInterface)->QueryInterface(
165 plugInInterface,
166 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID*)&iface);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700167 //* We only needed the plugin to get the interface, so discard it
168 (*plugInInterface)->Release(plugInInterface);
169 if (result || !iface) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700170 LOG(ERROR) << "Couldn't query the interface (" << std::hex << result << ")";
Dima Zavin3fd82b82009-05-08 18:25:58 -0700171 continue;
172 }
173
Dan Albert7447dd02015-04-16 19:20:40 -0700174 kr = (*iface)->GetInterfaceClass(iface, &if_class);
Al Sutton8e01cc62014-11-21 12:21:12 +0000175 kr = (*iface)->GetInterfaceSubClass(iface, &subclass);
176 kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
Mark Salyzyn8f3b8872017-10-04 15:05:40 -0700177 if (!is_adb_interface(if_class, subclass, protocol)) {
Al Sutton8e01cc62014-11-21 12:21:12 +0000178 // Ignore non-ADB devices.
Siva Velusamy743883b2015-08-18 17:53:16 -0700179 LOG(DEBUG) << "Ignoring interface with incorrect class/subclass/protocol - " << if_class
180 << ", " << subclass << ", " << protocol;
Al Sutton8e01cc62014-11-21 12:21:12 +0000181 (*iface)->Release(iface);
182 continue;
183 }
184
Dima Zavin3fd82b82009-05-08 18:25:58 -0700185 //* this gets us an ioservice, with which we will find the actual
186 //* device; after getting a plugin, and querying the interface, of
187 //* course.
188 //* Gotta love OS X
189 kr = (*iface)->GetDevice(iface, &usbDevice);
190 if (kIOReturnSuccess != kr || !usbDevice) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700191 LOG(ERROR) << "Couldn't grab device from interface (" << std::hex << kr << ")";
Josh Gaob6a2f592016-09-27 12:35:55 -0700192 (*iface)->Release(iface);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700193 continue;
194 }
195
196 plugInInterface = NULL;
197 score = 0;
198 //* create an intermediate device plugin
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800199 kr = IOCreatePlugInInterfaceForService(usbDevice,
200 kIOUSBDeviceUserClientTypeID,
201 kIOCFPlugInInterfaceID,
202 &plugInInterface, &score);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700203 //* only needed this to find the plugin
204 (void)IOObjectRelease(usbDevice);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800205 if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700206 LOG(ERROR) << "Unable to create a device plug-in (" << std::hex << kr << ")";
Josh Gaob6a2f592016-09-27 12:35:55 -0700207 (*iface)->Release(iface);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700208 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800209 }
210
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800211 result = (*plugInInterface)->QueryInterface(plugInInterface,
Dan Albert7447dd02015-04-16 19:20:40 -0700212 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*)&dev);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700213 //* only needed this to query the plugin
214 (*plugInInterface)->Release(plugInInterface);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800215 if (result || !dev) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700216 LOG(ERROR) << "Couldn't create a device interface (" << std::hex << result << ")";
Josh Gaob6a2f592016-09-27 12:35:55 -0700217 (*iface)->Release(iface);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700218 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800219 }
220
Dima Zavin3fd82b82009-05-08 18:25:58 -0700221 //* Now after all that, we actually have a ref to the device and
222 //* the interface that matched our criteria
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800223 kr = (*dev)->GetDeviceVendor(dev, &vendor);
224 kr = (*dev)->GetDeviceProduct(dev, &product);
Scott Andersone109d262012-04-20 11:21:14 -0700225 kr = (*dev)->GetLocationID(dev, &locationId);
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700226 if (kr == KERN_SUCCESS) {
227 devpath = android::base::StringPrintf("usb:%" PRIu32 "X", locationId);
228 if (IsKnownDevice(devpath)) {
Josh Gaob6a2f592016-09-27 12:35:55 -0700229 (*dev)->Release(dev);
230 (*iface)->Release(iface);
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700231 continue;
232 }
Scott Andersone109d262012-04-20 11:21:14 -0700233 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800234 kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
235
Siva Velusamy743883b2015-08-18 17:53:16 -0700236 if (serialIndex > 0) {
237 IOUSBDevRequest req;
238 UInt16 buffer[256];
239 UInt16 languages[128];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800240
Siva Velusamy743883b2015-08-18 17:53:16 -0700241 memset(languages, 0, sizeof(languages));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800242
Siva Velusamy743883b2015-08-18 17:53:16 -0700243 req.bmRequestType =
244 USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
245 req.bRequest = kUSBRqGetDescriptor;
246 req.wValue = (kUSBStringDesc << 8) | 0;
247 req.wIndex = 0;
248 req.pData = languages;
249 req.wLength = sizeof(languages);
250 kr = (*dev)->DeviceRequest(dev, &req);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800251
Siva Velusamy743883b2015-08-18 17:53:16 -0700252 if (kr == kIOReturnSuccess && req.wLenDone > 0) {
Guang Zhu1a1f8182009-08-06 17:21:52 -0700253
Siva Velusamy743883b2015-08-18 17:53:16 -0700254 int langCount = (req.wLenDone - 2) / 2, lang;
Guang Zhu1a1f8182009-08-06 17:21:52 -0700255
Siva Velusamy743883b2015-08-18 17:53:16 -0700256 for (lang = 1; lang <= langCount; lang++) {
Guang Zhu1a1f8182009-08-06 17:21:52 -0700257
Siva Velusamy743883b2015-08-18 17:53:16 -0700258 memset(buffer, 0, sizeof(buffer));
259 memset(&req, 0, sizeof(req));
Guang Zhu1a1f8182009-08-06 17:21:52 -0700260
Siva Velusamy743883b2015-08-18 17:53:16 -0700261 req.bmRequestType =
262 USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
263 req.bRequest = kUSBRqGetDescriptor;
264 req.wValue = (kUSBStringDesc << 8) | serialIndex;
265 req.wIndex = languages[lang];
266 req.pData = buffer;
267 req.wLength = sizeof(buffer);
268 kr = (*dev)->DeviceRequest(dev, &req);
Guang Zhu1a1f8182009-08-06 17:21:52 -0700269
Siva Velusamy743883b2015-08-18 17:53:16 -0700270 if (kr == kIOReturnSuccess && req.wLenDone > 0) {
271 int i, count;
Guang Zhu1a1f8182009-08-06 17:21:52 -0700272
Siva Velusamy743883b2015-08-18 17:53:16 -0700273 // skip first word, and copy the rest to the serial string,
274 // changing shorts to bytes.
275 count = (req.wLenDone - 1) / 2;
276 for (i = 0; i < count; i++)
277 serial[i] = buffer[i + 1];
278 serial[i] = 0;
279 break;
280 }
281 }
282 }
283 }
284
Dima Zavin3fd82b82009-05-08 18:25:58 -0700285 (*dev)->Release(dev);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800286
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700287 VLOG(USB) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n",
Siva Velusamy743883b2015-08-18 17:53:16 -0700288 vendor, product, serial);
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700289 if (devpath.empty()) {
290 devpath = serial;
291 }
292 if (IsKnownDevice(devpath)) {
293 (*iface)->USBInterfaceClose(iface);
Dima Zavin3fd82b82009-05-08 18:25:58 -0700294 (*iface)->Release(iface);
295 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800296 }
297
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700298 std::unique_ptr<usb_handle> handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
299 vendor, product);
300 if (handle == nullptr) {
301 LOG(ERROR) << "Could not find device interface";
302 (*iface)->Release(iface);
303 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800304 }
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700305 handle->devpath = devpath;
306 usb_handle* handle_p = handle.get();
307 VLOG(USB) << "Add usb device " << serial;
Josh Gao801048c2017-12-06 15:06:14 -0800308 LOG(INFO) << "reported max packet size for " << serial << " is " << handle->max_packet_size;
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700309 AddDevice(std::move(handle));
Josh Gao06766a82017-01-26 14:01:02 -0800310 register_usb_transport(reinterpret_cast<::usb_handle*>(handle_p), serial, devpath.c_str(),
311 1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800312 }
313}
314
Siva Velusamyd8b48a62015-08-13 08:48:06 -0700315// Used to clear both the endpoints before starting.
316// When adb quits, we might clear the host endpoint but not the device.
317// So we make sure both sides are clear before starting up.
318static bool ClearPipeStallBothEnds(IOUSBInterfaceInterface190** interface, UInt8 bulkEp) {
319 IOReturn rc = (*interface)->ClearPipeStallBothEnds(interface, bulkEp);
320 if (rc != kIOReturnSuccess) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700321 LOG(ERROR) << "Could not clear pipe stall both ends: " << std::hex << rc;
Siva Velusamyd8b48a62015-08-13 08:48:06 -0700322 return false;
323 }
324 return true;
325}
326
Dima Zavin3fd82b82009-05-08 18:25:58 -0700327//* TODO: simplify this further since we only register to get ADB interface
328//* subclass+protocol events
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700329static std::unique_ptr<usb_handle>
Siva Velusamyd8b48a62015-08-13 08:48:06 -0700330CheckInterface(IOUSBInterfaceInterface190 **interface, UInt16 vendor, UInt16 product)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800331{
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700332 std::unique_ptr<usb_handle> handle;
Elliott Hughes2d4f8522015-08-13 15:01:18 -0700333 IOReturn kr;
334 UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
335 UInt8 endpoint;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800336
Dima Zavin3fd82b82009-05-08 18:25:58 -0700337 //* Now open the interface. This will cause the pipes associated with
338 //* the endpoints in the interface descriptor to be instantiated
339 kr = (*interface)->USBInterfaceOpen(interface);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800340 if (kr != kIOReturnSuccess) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700341 LOG(ERROR) << "Could not open interface: " << std::hex << kr;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800342 return NULL;
343 }
344
Dima Zavin3fd82b82009-05-08 18:25:58 -0700345 //* Get the number of endpoints associated with this interface
346 kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
347 if (kr != kIOReturnSuccess) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700348 LOG(ERROR) << "Unable to get number of endpoints: " << std::hex << kr;
Dima Zavin3fd82b82009-05-08 18:25:58 -0700349 goto err_get_num_ep;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800350 }
351
Dima Zavin3fd82b82009-05-08 18:25:58 -0700352 //* Get interface class, subclass and protocol
353 if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
354 (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
355 (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700356 LOG(ERROR) << "Unable to get interface class, subclass and protocol";
Dima Zavin3fd82b82009-05-08 18:25:58 -0700357 goto err_get_interface_class;
358 }
359
360 //* check to make sure interface class, subclass and protocol match ADB
361 //* avoid opening mass storage endpoints
Josh Gao30186df2016-09-26 21:18:58 -0700362 if (!is_adb_interface(interfaceClass, interfaceSubClass, interfaceProtocol)) {
Dima Zavin3fd82b82009-05-08 18:25:58 -0700363 goto err_bad_adb_interface;
Siva Velusamyd8b48a62015-08-13 08:48:06 -0700364 }
Dima Zavin3fd82b82009-05-08 18:25:58 -0700365
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700366 handle.reset(new usb_handle);
367 if (handle == nullptr) {
368 goto err_bad_adb_interface;
369 }
Dima Zavin3fd82b82009-05-08 18:25:58 -0700370
371 //* Iterate over the endpoints for this interface and find the first
372 //* bulk in/out pipes available. These will be our read/write pipes.
Elliott Hughes2d4f8522015-08-13 15:01:18 -0700373 for (endpoint = 1; endpoint <= interfaceNumEndpoints; endpoint++) {
Dima Zavin3fd82b82009-05-08 18:25:58 -0700374 UInt8 transferType;
375 UInt16 maxPacketSize;
376 UInt8 interval;
377 UInt8 number;
378 UInt8 direction;
379
380 kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
381 &number, &transferType, &maxPacketSize, &interval);
Siva Velusamyd8b48a62015-08-13 08:48:06 -0700382 if (kr != kIOReturnSuccess) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700383 LOG(ERROR) << "FindDeviceInterface - could not get pipe properties: "
384 << std::hex << kr;
Dima Zavin3fd82b82009-05-08 18:25:58 -0700385 goto err_get_pipe_props;
386 }
Siva Velusamyd8b48a62015-08-13 08:48:06 -0700387
388 if (kUSBBulk != transferType) continue;
389
390 if (kUSBIn == direction) {
391 handle->bulkIn = endpoint;
392 if (!ClearPipeStallBothEnds(interface, handle->bulkIn)) goto err_get_pipe_props;
393 }
394
395 if (kUSBOut == direction) {
396 handle->bulkOut = endpoint;
397 if (!ClearPipeStallBothEnds(interface, handle->bulkOut)) goto err_get_pipe_props;
398 }
399
400 handle->zero_mask = maxPacketSize - 1;
Josh Gaoef3d3432017-05-02 15:01:09 -0700401 handle->max_packet_size = maxPacketSize;
Dima Zavin3fd82b82009-05-08 18:25:58 -0700402 }
403
404 handle->interface = interface;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800405 return handle;
Dima Zavin3fd82b82009-05-08 18:25:58 -0700406
407err_get_pipe_props:
Dima Zavin3fd82b82009-05-08 18:25:58 -0700408err_bad_adb_interface:
409err_get_interface_class:
410err_get_num_ep:
411 (*interface)->USBInterfaceClose(interface);
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700412 return nullptr;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800413}
414
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700415std::mutex& operate_device_lock = *new std::mutex();
416
Josh Gaoe1dacfc2017-04-12 17:00:49 -0700417static void RunLoopThread() {
Siva Velusamy49ee7cf2015-08-28 16:37:29 -0700418 adb_thread_setname("RunLoop");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800419
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700420 VLOG(USB) << "RunLoopThread started";
421 while (true) {
422 {
423 std::lock_guard<std::mutex> lock_guard(operate_device_lock);
424 FindUSBDevices();
425 KickDisconnectedDevices();
426 }
427 // Signal the parent that we are running
428 usb_inited_flag = true;
Elliott Hughesdbe91ee2016-11-15 12:37:32 -0800429 std::this_thread::sleep_for(1s);
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700430 }
431 VLOG(USB) << "RunLoopThread done";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800432}
433
Josh Gao362b4042017-05-10 13:51:36 -0700434void usb_cleanup() NO_THREAD_SAFETY_ANALYSIS {
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700435 VLOG(USB) << "usb_cleanup";
436 // Wait until usb operations in RunLoopThread finish, and prevent further operations.
437 operate_device_lock.lock();
Dan Albertc89e0cc2015-05-08 16:13:53 -0700438 close_usb_devices();
Dan Albertc89e0cc2015-05-08 16:13:53 -0700439}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800440
Elliott Hughes9b0f3542015-05-05 13:41:21 -0700441void usb_init() {
Dan Albertc89e0cc2015-05-08 16:13:53 -0700442 static bool initialized = false;
443 if (!initialized) {
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700444 usb_inited_flag = false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800445
Josh Gaoe1dacfc2017-04-12 17:00:49 -0700446 std::thread(RunLoopThread).detach();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800447
448 // Wait for initialization to finish
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700449 while (!usb_inited_flag) {
Elliott Hughesdbe91ee2016-11-15 12:37:32 -0800450 std::this_thread::sleep_for(100ms);
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700451 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800452
Dan Albertc89e0cc2015-05-08 16:13:53 -0700453 initialized = true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800454 }
455}
456
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800457int usb_write(usb_handle *handle, const void *buf, int len)
458{
459 IOReturn result;
460
461 if (!len)
462 return 0;
463
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700464 if (!handle || handle->dead)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800465 return -1;
466
467 if (NULL == handle->interface) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700468 LOG(ERROR) << "usb_write interface was null";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800469 return -1;
470 }
471
472 if (0 == handle->bulkOut) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700473 LOG(ERROR) << "bulkOut endpoint not assigned";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800474 return -1;
475 }
476
477 result =
Siva Velusamy743883b2015-08-18 17:53:16 -0700478 (*handle->interface)->WritePipe(handle->interface, handle->bulkOut, (void *)buf, len);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800479
480 if ((result == 0) && (handle->zero_mask)) {
481 /* we need 0-markers and our transfer */
482 if(!(len & handle->zero_mask)) {
483 result =
484 (*handle->interface)->WritePipe(
485 handle->interface, handle->bulkOut, (void *)buf, 0);
486 }
487 }
488
489 if (0 == result)
490 return 0;
491
Siva Velusamy743883b2015-08-18 17:53:16 -0700492 LOG(ERROR) << "usb_write failed with status: " << std::hex << result;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800493 return -1;
494}
495
496int usb_read(usb_handle *handle, void *buf, int len)
497{
498 IOReturn result;
499 UInt32 numBytes = len;
500
501 if (!len) {
502 return 0;
503 }
504
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700505 if (!handle || handle->dead) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800506 return -1;
507 }
508
509 if (NULL == handle->interface) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700510 LOG(ERROR) << "usb_read interface was null";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800511 return -1;
512 }
513
514 if (0 == handle->bulkIn) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700515 LOG(ERROR) << "bulkIn endpoint not assigned";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800516 return -1;
517 }
518
Esteban de la Canal9dd83dc2014-09-11 11:02:17 -0700519 result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800520
Esteban de la Canal9dd83dc2014-09-11 11:02:17 -0700521 if (kIOUSBPipeStalled == result) {
Siva Velusamy743883b2015-08-18 17:53:16 -0700522 LOG(ERROR) << "Pipe stalled, clearing stall.\n";
Esteban de la Canal9dd83dc2014-09-11 11:02:17 -0700523 (*handle->interface)->ClearPipeStall(handle->interface, handle->bulkIn);
524 result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
525 }
526
527 if (kIOReturnSuccess == result)
Yabin Cuib5e11412017-03-10 16:01:01 -0800528 return numBytes;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800529 else {
Siva Velusamy743883b2015-08-18 17:53:16 -0700530 LOG(ERROR) << "usb_read failed with status: " << std::hex << result;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800531 }
532
533 return -1;
534}
535
536int usb_close(usb_handle *handle)
537{
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700538 std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
539 for (auto it = g_usb_handles.begin(); it != g_usb_handles.end(); ++it) {
540 if ((*it).get() == handle) {
541 g_usb_handles.erase(it);
542 break;
543 }
544 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800545 return 0;
546}
547
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700548static void usb_kick_locked(usb_handle *handle)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800549{
Siva Velusamy743883b2015-08-18 17:53:16 -0700550 LOG(INFO) << "Kicking handle";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800551 /* release the interface */
Dima Zavin3fd82b82009-05-08 18:25:58 -0700552 if (!handle)
553 return;
554
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700555 if (!handle->dead)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800556 {
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700557 handle->dead = true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800558 (*handle->interface)->USBInterfaceClose(handle->interface);
559 (*handle->interface)->Release(handle->interface);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800560 }
561}
Yabin Cui48d4c0c2016-03-25 13:55:07 -0700562
563void usb_kick(usb_handle *handle) {
564 // Use the lock to avoid multiple thread kicking the device at the same time.
565 std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
566 usb_kick_locked(handle);
567}
Josh Gaoef3d3432017-05-02 15:01:09 -0700568
569size_t usb_get_max_packet_size(usb_handle* handle) {
570 return handle->max_packet_size;
571}
572
Josh Gao06766a82017-01-26 14:01:02 -0800573} // namespace native