blob: e541f6eccd63047d4d0e1da470dfaa5ec1086911 [file] [log] [blame]
The Android Open Source Project9ca14dc2009-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 Cui19bec5b2015-09-22 15:52:57 -070017#define TRACE_TAG USB
Dan Albertdb6fe642015-03-19 15:21:08 -070018
19#include "sysdeps.h"
20
The Android Open Source Project9ca14dc2009-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 Albert25896062015-04-16 19:20:40 -070029#include <inttypes.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080030#include <stdio.h>
31
Yabin Cui234a02a2016-03-25 13:55:07 -070032#include <atomic>
Elliott Hughes73925982016-11-15 12:37:32 -080033#include <chrono>
Yabin Cui234a02a2016-03-25 13:55:07 -070034#include <memory>
35#include <mutex>
Elliott Hughes73925982016-11-15 12:37:32 -080036#include <thread>
Yabin Cui234a02a2016-03-25 13:55:07 -070037#include <vector>
38
Elliott Hughesf55ead92015-12-04 22:00:26 -080039#include <android-base/logging.h>
40#include <android-base/stringprintf.h>
Siva Velusamy878e36b2015-08-18 17:53:16 -070041
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080042#include "adb.h"
Dan Albertbd3d4482015-02-25 10:26:17 -080043#include "transport.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080044
Elliott Hughes73925982016-11-15 12:37:32 -080045using namespace std::chrono_literals;
46
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080047struct usb_handle
48{
Siva Velusamy3ce46072015-08-13 08:48:06 -070049 UInt8 bulkIn;
50 UInt8 bulkOut;
51 IOUSBInterfaceInterface190** interface;
Siva Velusamy3ce46072015-08-13 08:48:06 -070052 unsigned int zero_mask;
Yabin Cui234a02a2016-03-25 13:55:07 -070053
54 // For garbage collecting disconnected devices.
55 bool mark;
56 std::string devpath;
57 std::atomic<bool> dead;
58
59 usb_handle() : bulkIn(0), bulkOut(0), interface(nullptr),
60 zero_mask(0), mark(false), dead(false) {
61 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080062};
63
Yabin Cui234a02a2016-03-25 13:55:07 -070064static std::atomic<bool> usb_inited_flag;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080065
Yabin Cui234a02a2016-03-25 13:55:07 -070066static auto& g_usb_handles_mutex = *new std::mutex();
67static auto& g_usb_handles = *new std::vector<std::unique_ptr<usb_handle>>();
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080068
Yabin Cui234a02a2016-03-25 13:55:07 -070069static bool IsKnownDevice(const std::string& devpath) {
70 std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
71 for (auto& usb : g_usb_handles) {
72 if (usb->devpath == devpath) {
73 // Set mark flag to indicate this device is still alive.
74 usb->mark = true;
75 return true;
76 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080077 }
Yabin Cui234a02a2016-03-25 13:55:07 -070078 return false;
79}
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080080
Yabin Cui234a02a2016-03-25 13:55:07 -070081static void usb_kick_locked(usb_handle* handle);
Al Sutton178bae82014-11-21 12:21:12 +000082
Yabin Cui234a02a2016-03-25 13:55:07 -070083static void KickDisconnectedDevices() {
84 std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
85 for (auto& usb : g_usb_handles) {
86 if (!usb->mark) {
87 usb_kick_locked(usb.get());
88 } else {
89 usb->mark = false;
90 }
91 }
92}
Al Sutton178bae82014-11-21 12:21:12 +000093
Yabin Cui234a02a2016-03-25 13:55:07 -070094static void AddDevice(std::unique_ptr<usb_handle> handle) {
95 handle->mark = true;
96 std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
97 g_usb_handles.push_back(std::move(handle));
98}
99
100static void AndroidInterfaceAdded(io_iterator_t iterator);
101static std::unique_ptr<usb_handle> CheckInterface(IOUSBInterfaceInterface190 **iface,
102 UInt16 vendor, UInt16 product);
103
104static bool FindUSBDevices() {
105 // Create the matching dictionary to find the Android device's adb interface.
106 CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
107 if (!matchingDict) {
108 LOG(ERROR) << "couldn't create USB matching dictionary";
109 return false;
110 }
111 // Create an iterator for all I/O Registry objects that match the dictionary.
112 io_iterator_t iter = 0;
113 kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
114 if (kr != KERN_SUCCESS) {
115 LOG(ERROR) << "failed to get matching services";
116 return false;
117 }
118 // Iterate over all matching objects.
119 AndroidInterfaceAdded(iter);
120 IOObjectRelease(iter);
121 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800122}
123
124static void
Yabin Cui234a02a2016-03-25 13:55:07 -0700125AndroidInterfaceAdded(io_iterator_t iterator)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800126{
127 kern_return_t kr;
128 io_service_t usbDevice;
Dima Zavin3e824912009-05-08 18:25:58 -0700129 io_service_t usbInterface;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800130 IOCFPlugInInterface **plugInInterface = NULL;
Dima Zavin3e824912009-05-08 18:25:58 -0700131 IOUSBInterfaceInterface220 **iface = NULL;
132 IOUSBDeviceInterface197 **dev = NULL;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800133 HRESULT result;
134 SInt32 score;
Elliott Hughes8dc9c862015-08-25 17:48:12 -0700135 uint32_t locationId;
Dan Albert25896062015-04-16 19:20:40 -0700136 UInt8 if_class, subclass, protocol;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800137 UInt16 vendor;
138 UInt16 product;
139 UInt8 serialIndex;
140 char serial[256];
Yabin Cui234a02a2016-03-25 13:55:07 -0700141 std::string devpath;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800142
Dima Zavin3e824912009-05-08 18:25:58 -0700143 while ((usbInterface = IOIteratorNext(iterator))) {
144 //* Create an intermediate interface plugin
145 kr = IOCreatePlugInInterfaceForService(usbInterface,
146 kIOUSBInterfaceUserClientTypeID,
147 kIOCFPlugInInterfaceID,
148 &plugInInterface, &score);
149 IOObjectRelease(usbInterface);
150 if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700151 LOG(ERROR) << "Unable to create an interface plug-in (" << std::hex << kr << ")";
Dima Zavin3e824912009-05-08 18:25:58 -0700152 continue;
153 }
154
155 //* This gets us the interface object
Dan Albert25896062015-04-16 19:20:40 -0700156 result = (*plugInInterface)->QueryInterface(
157 plugInInterface,
158 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID*)&iface);
Dima Zavin3e824912009-05-08 18:25:58 -0700159 //* We only needed the plugin to get the interface, so discard it
160 (*plugInInterface)->Release(plugInInterface);
161 if (result || !iface) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700162 LOG(ERROR) << "Couldn't query the interface (" << std::hex << result << ")";
Dima Zavin3e824912009-05-08 18:25:58 -0700163 continue;
164 }
165
Dan Albert25896062015-04-16 19:20:40 -0700166 kr = (*iface)->GetInterfaceClass(iface, &if_class);
Al Sutton178bae82014-11-21 12:21:12 +0000167 kr = (*iface)->GetInterfaceSubClass(iface, &subclass);
168 kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
Dan Albert25896062015-04-16 19:20:40 -0700169 if(if_class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
Al Sutton178bae82014-11-21 12:21:12 +0000170 // Ignore non-ADB devices.
Siva Velusamy878e36b2015-08-18 17:53:16 -0700171 LOG(DEBUG) << "Ignoring interface with incorrect class/subclass/protocol - " << if_class
172 << ", " << subclass << ", " << protocol;
Al Sutton178bae82014-11-21 12:21:12 +0000173 (*iface)->Release(iface);
174 continue;
175 }
176
Dima Zavin3e824912009-05-08 18:25:58 -0700177 //* this gets us an ioservice, with which we will find the actual
178 //* device; after getting a plugin, and querying the interface, of
179 //* course.
180 //* Gotta love OS X
181 kr = (*iface)->GetDevice(iface, &usbDevice);
182 if (kIOReturnSuccess != kr || !usbDevice) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700183 LOG(ERROR) << "Couldn't grab device from interface (" << std::hex << kr << ")";
Josh Gao37df9e72016-09-27 12:35:55 -0700184 (*iface)->Release(iface);
Dima Zavin3e824912009-05-08 18:25:58 -0700185 continue;
186 }
187
188 plugInInterface = NULL;
189 score = 0;
190 //* create an intermediate device plugin
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800191 kr = IOCreatePlugInInterfaceForService(usbDevice,
192 kIOUSBDeviceUserClientTypeID,
193 kIOCFPlugInInterfaceID,
194 &plugInInterface, &score);
Dima Zavin3e824912009-05-08 18:25:58 -0700195 //* only needed this to find the plugin
196 (void)IOObjectRelease(usbDevice);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800197 if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700198 LOG(ERROR) << "Unable to create a device plug-in (" << std::hex << kr << ")";
Josh Gao37df9e72016-09-27 12:35:55 -0700199 (*iface)->Release(iface);
Dima Zavin3e824912009-05-08 18:25:58 -0700200 continue;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800201 }
202
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800203 result = (*plugInInterface)->QueryInterface(plugInInterface,
Dan Albert25896062015-04-16 19:20:40 -0700204 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*)&dev);
Dima Zavin3e824912009-05-08 18:25:58 -0700205 //* only needed this to query the plugin
206 (*plugInInterface)->Release(plugInInterface);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800207 if (result || !dev) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700208 LOG(ERROR) << "Couldn't create a device interface (" << std::hex << result << ")";
Josh Gao37df9e72016-09-27 12:35:55 -0700209 (*iface)->Release(iface);
Dima Zavin3e824912009-05-08 18:25:58 -0700210 continue;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800211 }
212
Dima Zavin3e824912009-05-08 18:25:58 -0700213 //* Now after all that, we actually have a ref to the device and
214 //* the interface that matched our criteria
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800215 kr = (*dev)->GetDeviceVendor(dev, &vendor);
216 kr = (*dev)->GetDeviceProduct(dev, &product);
Scott Anderson6dfaf4b2012-04-20 11:21:14 -0700217 kr = (*dev)->GetLocationID(dev, &locationId);
Yabin Cui234a02a2016-03-25 13:55:07 -0700218 if (kr == KERN_SUCCESS) {
219 devpath = android::base::StringPrintf("usb:%" PRIu32 "X", locationId);
220 if (IsKnownDevice(devpath)) {
Josh Gao37df9e72016-09-27 12:35:55 -0700221 (*dev)->Release(dev);
222 (*iface)->Release(iface);
Yabin Cui234a02a2016-03-25 13:55:07 -0700223 continue;
224 }
Scott Anderson6dfaf4b2012-04-20 11:21:14 -0700225 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800226 kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
227
Siva Velusamy878e36b2015-08-18 17:53:16 -0700228 if (serialIndex > 0) {
229 IOUSBDevRequest req;
230 UInt16 buffer[256];
231 UInt16 languages[128];
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800232
Siva Velusamy878e36b2015-08-18 17:53:16 -0700233 memset(languages, 0, sizeof(languages));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800234
Siva Velusamy878e36b2015-08-18 17:53:16 -0700235 req.bmRequestType =
236 USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
237 req.bRequest = kUSBRqGetDescriptor;
238 req.wValue = (kUSBStringDesc << 8) | 0;
239 req.wIndex = 0;
240 req.pData = languages;
241 req.wLength = sizeof(languages);
242 kr = (*dev)->DeviceRequest(dev, &req);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800243
Siva Velusamy878e36b2015-08-18 17:53:16 -0700244 if (kr == kIOReturnSuccess && req.wLenDone > 0) {
Guang Zhu84b5bd22009-08-06 17:21:52 -0700245
Siva Velusamy878e36b2015-08-18 17:53:16 -0700246 int langCount = (req.wLenDone - 2) / 2, lang;
Guang Zhu84b5bd22009-08-06 17:21:52 -0700247
Siva Velusamy878e36b2015-08-18 17:53:16 -0700248 for (lang = 1; lang <= langCount; lang++) {
Guang Zhu84b5bd22009-08-06 17:21:52 -0700249
Siva Velusamy878e36b2015-08-18 17:53:16 -0700250 memset(buffer, 0, sizeof(buffer));
251 memset(&req, 0, sizeof(req));
Guang Zhu84b5bd22009-08-06 17:21:52 -0700252
Siva Velusamy878e36b2015-08-18 17:53:16 -0700253 req.bmRequestType =
254 USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
255 req.bRequest = kUSBRqGetDescriptor;
256 req.wValue = (kUSBStringDesc << 8) | serialIndex;
257 req.wIndex = languages[lang];
258 req.pData = buffer;
259 req.wLength = sizeof(buffer);
260 kr = (*dev)->DeviceRequest(dev, &req);
Guang Zhu84b5bd22009-08-06 17:21:52 -0700261
Siva Velusamy878e36b2015-08-18 17:53:16 -0700262 if (kr == kIOReturnSuccess && req.wLenDone > 0) {
263 int i, count;
Guang Zhu84b5bd22009-08-06 17:21:52 -0700264
Siva Velusamy878e36b2015-08-18 17:53:16 -0700265 // skip first word, and copy the rest to the serial string,
266 // changing shorts to bytes.
267 count = (req.wLenDone - 1) / 2;
268 for (i = 0; i < count; i++)
269 serial[i] = buffer[i + 1];
270 serial[i] = 0;
271 break;
272 }
273 }
274 }
275 }
276
Dima Zavin3e824912009-05-08 18:25:58 -0700277 (*dev)->Release(dev);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800278
Yabin Cui234a02a2016-03-25 13:55:07 -0700279 VLOG(USB) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n",
Siva Velusamy878e36b2015-08-18 17:53:16 -0700280 vendor, product, serial);
Yabin Cui234a02a2016-03-25 13:55:07 -0700281 if (devpath.empty()) {
282 devpath = serial;
283 }
284 if (IsKnownDevice(devpath)) {
285 (*iface)->USBInterfaceClose(iface);
Dima Zavin3e824912009-05-08 18:25:58 -0700286 (*iface)->Release(iface);
287 continue;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800288 }
289
Yabin Cui234a02a2016-03-25 13:55:07 -0700290 std::unique_ptr<usb_handle> handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
291 vendor, product);
292 if (handle == nullptr) {
293 LOG(ERROR) << "Could not find device interface";
294 (*iface)->Release(iface);
295 continue;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800296 }
Yabin Cui234a02a2016-03-25 13:55:07 -0700297 handle->devpath = devpath;
298 usb_handle* handle_p = handle.get();
299 VLOG(USB) << "Add usb device " << serial;
300 AddDevice(std::move(handle));
301 register_usb_transport(handle_p, serial, devpath.c_str(), 1);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800302 }
303}
304
Siva Velusamy3ce46072015-08-13 08:48:06 -0700305// Used to clear both the endpoints before starting.
306// When adb quits, we might clear the host endpoint but not the device.
307// So we make sure both sides are clear before starting up.
308static bool ClearPipeStallBothEnds(IOUSBInterfaceInterface190** interface, UInt8 bulkEp) {
309 IOReturn rc = (*interface)->ClearPipeStallBothEnds(interface, bulkEp);
310 if (rc != kIOReturnSuccess) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700311 LOG(ERROR) << "Could not clear pipe stall both ends: " << std::hex << rc;
Siva Velusamy3ce46072015-08-13 08:48:06 -0700312 return false;
313 }
314 return true;
315}
316
Dima Zavin3e824912009-05-08 18:25:58 -0700317//* TODO: simplify this further since we only register to get ADB interface
318//* subclass+protocol events
Yabin Cui234a02a2016-03-25 13:55:07 -0700319static std::unique_ptr<usb_handle>
Siva Velusamy3ce46072015-08-13 08:48:06 -0700320CheckInterface(IOUSBInterfaceInterface190 **interface, UInt16 vendor, UInt16 product)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800321{
Yabin Cui234a02a2016-03-25 13:55:07 -0700322 std::unique_ptr<usb_handle> handle;
Elliott Hughes6d6cb542015-08-13 15:01:18 -0700323 IOReturn kr;
324 UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
325 UInt8 endpoint;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800326
Dima Zavin3e824912009-05-08 18:25:58 -0700327 //* Now open the interface. This will cause the pipes associated with
328 //* the endpoints in the interface descriptor to be instantiated
329 kr = (*interface)->USBInterfaceOpen(interface);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800330 if (kr != kIOReturnSuccess) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700331 LOG(ERROR) << "Could not open interface: " << std::hex << kr;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800332 return NULL;
333 }
334
Dima Zavin3e824912009-05-08 18:25:58 -0700335 //* Get the number of endpoints associated with this interface
336 kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
337 if (kr != kIOReturnSuccess) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700338 LOG(ERROR) << "Unable to get number of endpoints: " << std::hex << kr;
Dima Zavin3e824912009-05-08 18:25:58 -0700339 goto err_get_num_ep;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800340 }
341
Dima Zavin3e824912009-05-08 18:25:58 -0700342 //* Get interface class, subclass and protocol
343 if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
344 (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
345 (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700346 LOG(ERROR) << "Unable to get interface class, subclass and protocol";
Dima Zavin3e824912009-05-08 18:25:58 -0700347 goto err_get_interface_class;
348 }
349
350 //* check to make sure interface class, subclass and protocol match ADB
351 //* avoid opening mass storage endpoints
Josh Gao08dda212016-09-26 21:18:58 -0700352 if (!is_adb_interface(interfaceClass, interfaceSubClass, interfaceProtocol)) {
Dima Zavin3e824912009-05-08 18:25:58 -0700353 goto err_bad_adb_interface;
Siva Velusamy3ce46072015-08-13 08:48:06 -0700354 }
Dima Zavin3e824912009-05-08 18:25:58 -0700355
Yabin Cui234a02a2016-03-25 13:55:07 -0700356 handle.reset(new usb_handle);
357 if (handle == nullptr) {
358 goto err_bad_adb_interface;
359 }
Dima Zavin3e824912009-05-08 18:25:58 -0700360
361 //* Iterate over the endpoints for this interface and find the first
362 //* bulk in/out pipes available. These will be our read/write pipes.
Elliott Hughes6d6cb542015-08-13 15:01:18 -0700363 for (endpoint = 1; endpoint <= interfaceNumEndpoints; endpoint++) {
Dima Zavin3e824912009-05-08 18:25:58 -0700364 UInt8 transferType;
365 UInt16 maxPacketSize;
366 UInt8 interval;
367 UInt8 number;
368 UInt8 direction;
369
370 kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
371 &number, &transferType, &maxPacketSize, &interval);
Siva Velusamy3ce46072015-08-13 08:48:06 -0700372 if (kr != kIOReturnSuccess) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700373 LOG(ERROR) << "FindDeviceInterface - could not get pipe properties: "
374 << std::hex << kr;
Dima Zavin3e824912009-05-08 18:25:58 -0700375 goto err_get_pipe_props;
376 }
Siva Velusamy3ce46072015-08-13 08:48:06 -0700377
378 if (kUSBBulk != transferType) continue;
379
380 if (kUSBIn == direction) {
381 handle->bulkIn = endpoint;
382 if (!ClearPipeStallBothEnds(interface, handle->bulkIn)) goto err_get_pipe_props;
383 }
384
385 if (kUSBOut == direction) {
386 handle->bulkOut = endpoint;
387 if (!ClearPipeStallBothEnds(interface, handle->bulkOut)) goto err_get_pipe_props;
388 }
389
390 handle->zero_mask = maxPacketSize - 1;
Dima Zavin3e824912009-05-08 18:25:58 -0700391 }
392
393 handle->interface = interface;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800394 return handle;
Dima Zavin3e824912009-05-08 18:25:58 -0700395
396err_get_pipe_props:
Dima Zavin3e824912009-05-08 18:25:58 -0700397err_bad_adb_interface:
398err_get_interface_class:
399err_get_num_ep:
400 (*interface)->USBInterfaceClose(interface);
Yabin Cui234a02a2016-03-25 13:55:07 -0700401 return nullptr;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800402}
403
Yabin Cui234a02a2016-03-25 13:55:07 -0700404std::mutex& operate_device_lock = *new std::mutex();
405
Josh Gao7d405252016-02-12 14:31:15 -0800406static void RunLoopThread(void* unused) {
Siva Velusamy2669cf92015-08-28 16:37:29 -0700407 adb_thread_setname("RunLoop");
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800408
Yabin Cui234a02a2016-03-25 13:55:07 -0700409 VLOG(USB) << "RunLoopThread started";
410 while (true) {
411 {
412 std::lock_guard<std::mutex> lock_guard(operate_device_lock);
413 FindUSBDevices();
414 KickDisconnectedDevices();
415 }
416 // Signal the parent that we are running
417 usb_inited_flag = true;
Elliott Hughes73925982016-11-15 12:37:32 -0800418 std::this_thread::sleep_for(1s);
Yabin Cui234a02a2016-03-25 13:55:07 -0700419 }
420 VLOG(USB) << "RunLoopThread done";
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800421}
422
Dan Albert53a37442015-05-08 16:13:53 -0700423static void usb_cleanup() {
Yabin Cui234a02a2016-03-25 13:55:07 -0700424 VLOG(USB) << "usb_cleanup";
425 // Wait until usb operations in RunLoopThread finish, and prevent further operations.
426 operate_device_lock.lock();
Dan Albert53a37442015-05-08 16:13:53 -0700427 close_usb_devices();
Dan Albert53a37442015-05-08 16:13:53 -0700428}
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800429
Elliott Hughesf2517142015-05-05 13:41:21 -0700430void usb_init() {
Dan Albert53a37442015-05-08 16:13:53 -0700431 static bool initialized = false;
432 if (!initialized) {
433 atexit(usb_cleanup);
434
Yabin Cui234a02a2016-03-25 13:55:07 -0700435 usb_inited_flag = false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800436
Elliott Hughesf2517142015-05-05 13:41:21 -0700437 if (!adb_thread_create(RunLoopThread, nullptr)) {
Yabin Cui4e222292015-08-31 11:50:24 -0700438 fatal_errno("cannot create RunLoop thread");
Elliott Hughesf2517142015-05-05 13:41:21 -0700439 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800440
441 // Wait for initialization to finish
Yabin Cui234a02a2016-03-25 13:55:07 -0700442 while (!usb_inited_flag) {
Elliott Hughes73925982016-11-15 12:37:32 -0800443 std::this_thread::sleep_for(100ms);
Yabin Cui234a02a2016-03-25 13:55:07 -0700444 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800445
Dan Albert53a37442015-05-08 16:13:53 -0700446 initialized = true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800447 }
448}
449
The Android Open Source Project9ca14dc2009-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 Cui234a02a2016-03-25 13:55:07 -0700457 if (!handle || handle->dead)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800458 return -1;
459
460 if (NULL == handle->interface) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700461 LOG(ERROR) << "usb_write interface was null";
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800462 return -1;
463 }
464
465 if (0 == handle->bulkOut) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700466 LOG(ERROR) << "bulkOut endpoint not assigned";
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800467 return -1;
468 }
469
470 result =
Siva Velusamy878e36b2015-08-18 17:53:16 -0700471 (*handle->interface)->WritePipe(handle->interface, handle->bulkOut, (void *)buf, len);
The Android Open Source Project9ca14dc2009-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 Velusamy878e36b2015-08-18 17:53:16 -0700485 LOG(ERROR) << "usb_write failed with status: " << std::hex << result;
The Android Open Source Project9ca14dc2009-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 Cui234a02a2016-03-25 13:55:07 -0700498 if (!handle || handle->dead) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800499 return -1;
500 }
501
502 if (NULL == handle->interface) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700503 LOG(ERROR) << "usb_read interface was null";
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800504 return -1;
505 }
506
507 if (0 == handle->bulkIn) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700508 LOG(ERROR) << "bulkIn endpoint not assigned";
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800509 return -1;
510 }
511
Esteban de la Canal647231a2014-09-11 11:02:17 -0700512 result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800513
Esteban de la Canal647231a2014-09-11 11:02:17 -0700514 if (kIOUSBPipeStalled == result) {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700515 LOG(ERROR) << "Pipe stalled, clearing stall.\n";
Esteban de la Canal647231a2014-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)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800521 return 0;
522 else {
Siva Velusamy878e36b2015-08-18 17:53:16 -0700523 LOG(ERROR) << "usb_read failed with status: " << std::hex << result;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800524 }
525
526 return -1;
527}
528
529int usb_close(usb_handle *handle)
530{
Yabin Cui234a02a2016-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 Project9ca14dc2009-03-03 19:32:55 -0800538 return 0;
539}
540
Yabin Cui234a02a2016-03-25 13:55:07 -0700541static void usb_kick_locked(usb_handle *handle)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800542{
Siva Velusamy878e36b2015-08-18 17:53:16 -0700543 LOG(INFO) << "Kicking handle";
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800544 /* release the interface */
Dima Zavin3e824912009-05-08 18:25:58 -0700545 if (!handle)
546 return;
547
Yabin Cui234a02a2016-03-25 13:55:07 -0700548 if (!handle->dead)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800549 {
Yabin Cui234a02a2016-03-25 13:55:07 -0700550 handle->dead = true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800551 (*handle->interface)->USBInterfaceClose(handle->interface);
552 (*handle->interface)->Release(handle->interface);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800553 }
554}
Yabin Cui234a02a2016-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}