11c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao/* 21c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao * Copyright (C) 2016 The Android Open Source Project 31c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao * 41c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao * Licensed under the Apache License, Version 2.0 (the "License"); 51c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao * you may not use this file except in compliance with the License. 61c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao * You may obtain a copy of the License at 71c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao * 81c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao * http://www.apache.org/licenses/LICENSE-2.0 91c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao * 101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao * Unless required by applicable law or agreed to in writing, software 111c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao * distributed under the License is distributed on an "AS IS" BASIS, 121c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao * See the License for the specific language governing permissions and 141c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao * limitations under the License. 151c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao */ 161c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 171c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include "usb.h" 181c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 191c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include "sysdeps.h" 201c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <stdint.h> 22d51c6df1ef98f2b57916ddefc80afda5f1eecb59Josh Gao#include <stdlib.h> 231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <atomic> 251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <chrono> 2650ecaca744cbc881f48f5d1bf53c7216a0a1ecacMike Frysinger#include <condition_variable> 271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <memory> 281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <mutex> 291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <string> 301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <thread> 311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <unordered_map> 321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 331c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <libusb/libusb.h> 341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 351c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <android-base/file.h> 361c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <android-base/logging.h> 371c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <android-base/stringprintf.h> 381c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <android-base/strings.h> 391c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 401c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include "adb.h" 410b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao#include "adb_utils.h" 421c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include "transport.h" 431c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include "usb.h" 441c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 451c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaousing android::base::StringPrintf; 461c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 471c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao// RAII wrappers for libusb. 481c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostruct ConfigDescriptorDeleter { 491c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao void operator()(libusb_config_descriptor* desc) { 501c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_free_config_descriptor(desc); 511c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 521c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}; 531c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 541c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaousing unique_config_descriptor = std::unique_ptr<libusb_config_descriptor, ConfigDescriptorDeleter>; 551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostruct DeviceHandleDeleter { 571c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao void operator()(libusb_device_handle* h) { 581c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_close(h); 591c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 601c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}; 611c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaousing unique_device_handle = std::unique_ptr<libusb_device_handle, DeviceHandleDeleter>; 631c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 641c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostruct transfer_info { 65b5e11415d9fdb929321c66889063dac50fb737afYabin Cui transfer_info(const char* name, uint16_t zero_mask, bool is_bulk_out) 66b5e11415d9fdb929321c66889063dac50fb737afYabin Cui : name(name), 67b5e11415d9fdb929321c66889063dac50fb737afYabin Cui transfer(libusb_alloc_transfer(0)), 68b5e11415d9fdb929321c66889063dac50fb737afYabin Cui is_bulk_out(is_bulk_out), 69b5e11415d9fdb929321c66889063dac50fb737afYabin Cui zero_mask(zero_mask) {} 701c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 711c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao ~transfer_info() { 721c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_free_transfer(transfer); 731c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 741c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 751c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao const char* name; 761c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_transfer* transfer; 77b5e11415d9fdb929321c66889063dac50fb737afYabin Cui bool is_bulk_out; 781c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao bool transfer_complete; 791c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::condition_variable cv; 801c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::mutex mutex; 811c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao uint16_t zero_mask; 821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao void Notify() { 841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "notifying " << name << " transfer complete"; 851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_complete = true; 861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao cv.notify_one(); 871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}; 891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaonamespace libusb { 911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostruct usb_handle : public ::usb_handle { 921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao usb_handle(const std::string& device_address, const std::string& serial, 931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao unique_device_handle&& device_handle, uint8_t interface, uint8_t bulk_in, 94ef3d343254405cc360b4df843c6e4a843c335012Josh Gao uint8_t bulk_out, size_t zero_mask, size_t max_packet_size) 951c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao : device_address(device_address), 961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao serial(serial), 971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao closing(false), 981c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_handle(device_handle.release()), 99b5e11415d9fdb929321c66889063dac50fb737afYabin Cui read("read", zero_mask, false), 100b5e11415d9fdb929321c66889063dac50fb737afYabin Cui write("write", zero_mask, true), 1011c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao interface(interface), 1021c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao bulk_in(bulk_in), 103ef3d343254405cc360b4df843c6e4a843c335012Josh Gao bulk_out(bulk_out), 104ef3d343254405cc360b4df843c6e4a843c335012Josh Gao max_packet_size(max_packet_size) {} 1051c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1061c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao ~usb_handle() { 1071c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao Close(); 1081c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 1091c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao void Close() { 1111c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(device_handle_mutex); 1121c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Cancelling transfers will trigger more Closes, so make sure this only happens once. 1131c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (closing) { 1141c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return; 1151c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 1161c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao closing = true; 1171c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1181c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Make sure that no new transfers come in. 1191c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_device_handle* handle = device_handle; 1201c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (!handle) { 1211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return; 1221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 1231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_handle = nullptr; 1251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1261c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Cancel already dispatched transfers. 1271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_cancel_transfer(read.transfer); 1281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_cancel_transfer(write.transfer); 1291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_release_interface(handle, interface); 1311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_close(handle); 1321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 1331c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::string device_address; 1351c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::string serial; 1361c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1371c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::atomic<bool> closing; 1381c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::mutex device_handle_mutex; 1391c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_device_handle* device_handle; 1401c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1411c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info read; 1421c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info write; 1431c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1441c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao uint8_t interface; 1451c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao uint8_t bulk_in; 1461c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao uint8_t bulk_out; 147ef3d343254405cc360b4df843c6e4a843c335012Josh Gao 148ef3d343254405cc360b4df843c6e4a843c335012Josh Gao size_t max_packet_size; 1491c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}; 1501c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1511c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic auto& usb_handles = *new std::unordered_map<std::string, std::unique_ptr<usb_handle>>(); 1521c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic auto& usb_handles_mutex = *new std::mutex(); 1531c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1546da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gaostatic libusb_hotplug_callback_handle hotplug_handle; 1551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic std::string get_device_address(libusb_device* device) { 1571c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return StringPrintf("usb:%d:%d", libusb_get_bus_number(device), 1581c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_get_device_address(device)); 1591c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 1601c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1614acb36020bfa3cb63ed81358754758e76fc5787dElliott Hughes#if defined(__linux__) 162cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughesstatic std::string get_device_serial_path(libusb_device* device) { 163cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes uint8_t ports[7]; 164cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes int port_count = libusb_get_port_numbers(device, ports, 7); 165cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes if (port_count < 0) return ""; 166cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes 167cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes std::string path = 168cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes StringPrintf("/sys/bus/usb/devices/%d-%d", libusb_get_bus_number(device), ports[0]); 169cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes for (int port = 1; port < port_count; ++port) { 170cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes path += StringPrintf(".%d", ports[port]); 171cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes } 172cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes path += "/serial"; 173cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes return path; 174cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes} 1753f60a968e35b051943249fb9ac70e349323a0590Josh Gao 1763f60a968e35b051943249fb9ac70e349323a0590Josh Gaostatic std::string get_device_dev_path(libusb_device* device) { 1773f60a968e35b051943249fb9ac70e349323a0590Josh Gao uint8_t ports[7]; 1783f60a968e35b051943249fb9ac70e349323a0590Josh Gao int port_count = libusb_get_port_numbers(device, ports, 7); 1793f60a968e35b051943249fb9ac70e349323a0590Josh Gao if (port_count < 0) return ""; 1803f60a968e35b051943249fb9ac70e349323a0590Josh Gao return StringPrintf("/dev/bus/usb/%03u/%03u", libusb_get_bus_number(device), ports[0]); 1813f60a968e35b051943249fb9ac70e349323a0590Josh Gao} 1824acb36020bfa3cb63ed81358754758e76fc5787dElliott Hughes#endif 183cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes 1841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic bool endpoint_is_output(uint8_t endpoint) { 1851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return (endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT; 1861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 1871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic bool should_perform_zero_transfer(uint8_t endpoint, size_t write_length, uint16_t zero_mask) { 1891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return endpoint_is_output(endpoint) && write_length != 0 && zero_mask != 0 && 1901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao (write_length & zero_mask) == 0; 1911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 1921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1938bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gaostatic void process_device(libusb_device* device) { 1948bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::string device_address = get_device_address(device); 1958bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::string device_serial; 1961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1978bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // Figure out if we want to open the device. 1988bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao libusb_device_descriptor device_desc; 1998bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao int rc = libusb_get_device_descriptor(device, &device_desc); 2008bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc != 0) { 2018bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to get device descriptor for device at " << device_address << ": " 2028bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << libusb_error_name(rc); 2038bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2048bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2051c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2068bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (device_desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) { 2078bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // Assume that all Android devices have the device class set to per interface. 2088bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // TODO: Is this assumption valid? 2098bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "skipping device with incorrect class at " << device_address; 2108bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2118bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2121c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2138bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao libusb_config_descriptor* config_raw; 2148bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_get_active_config_descriptor(device, &config_raw); 2158bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc != 0) { 2168bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to get active config descriptor for device at " << device_address 2178bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << ": " << libusb_error_name(rc); 2188bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2198bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2208bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const unique_config_descriptor config(config_raw); 2211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2228bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // Use size_t for interface_num so <iostream>s don't mangle it. 2238bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao size_t interface_num; 2249425996b4521eae0571b4af30056c44bb0482598Josh Gao uint16_t zero_mask = 0; 2258bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao uint8_t bulk_in = 0, bulk_out = 0; 2268bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao size_t packet_size = 0; 2278bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bool found_adb = false; 2288bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2298bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao for (interface_num = 0; interface_num < config->bNumInterfaces; ++interface_num) { 2308bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const libusb_interface& interface = config->interface[interface_num]; 2318bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (interface.num_altsetting != 1) { 2328bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // Assume that interfaces with alternate settings aren't adb interfaces. 2338bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // TODO: Is this assumption valid? 2348bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at " << device_address 2358bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << " (interface " << interface_num << ")"; 236425aefdcf0f1b2068f56ca091047af5f02ae3f3dJosh Gao continue; 2378bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2381c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2398bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const libusb_interface_descriptor& interface_desc = interface.altsetting[0]; 2408bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (!is_adb_interface(interface_desc.bInterfaceClass, interface_desc.bInterfaceSubClass, 2418bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao interface_desc.bInterfaceProtocol)) { 2428bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "skipping non-adb interface at " << device_address << " (interface " 2438bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << interface_num << ")"; 244425aefdcf0f1b2068f56ca091047af5f02ae3f3dJosh Gao continue; 2458bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2468bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2478bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "found potential adb interface at " << device_address << " (interface " 2488bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << interface_num << ")"; 2498bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2508bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bool found_in = false; 2518bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bool found_out = false; 2528bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao for (size_t endpoint_num = 0; endpoint_num < interface_desc.bNumEndpoints; ++endpoint_num) { 2538bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const auto& endpoint_desc = interface_desc.endpoint[endpoint_num]; 2548bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const uint8_t endpoint_addr = endpoint_desc.bEndpointAddress; 2558bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const uint8_t endpoint_attr = endpoint_desc.bmAttributes; 2561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2578bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK; 2588bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2598bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) { 260425aefdcf0f1b2068f56ca091047af5f02ae3f3dJosh Gao continue; 2611c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2638bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (endpoint_is_output(endpoint_addr) && !found_out) { 2648bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao found_out = true; 2658bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bulk_out = endpoint_addr; 2668bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao zero_mask = endpoint_desc.wMaxPacketSize - 1; 2678bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } else if (!endpoint_is_output(endpoint_addr) && !found_in) { 2688bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao found_in = true; 2698bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bulk_in = endpoint_addr; 2701c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2711c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2728bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao size_t endpoint_packet_size = endpoint_desc.wMaxPacketSize; 2738bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao CHECK(endpoint_packet_size != 0); 2748bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (packet_size == 0) { 2758bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao packet_size = endpoint_packet_size; 276cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes } else { 2778bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao CHECK(packet_size == endpoint_packet_size); 2788bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2798bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2808bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2818bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (found_in && found_out) { 2828bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao found_adb = true; 2838bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao break; 2848bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } else { 2858bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "rejecting potential adb interface at " << device_address 2868bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << "(interface " << interface_num << "): missing bulk endpoints " 2878bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << "(found_in = " << found_in << ", found_out = " << found_out << ")"; 2888bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2898bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2908bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2918bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (!found_adb) { 2928bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "skipping device with no adb interfaces at " << device_address; 2938bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2948bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2958bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2968bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao { 2978bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 2988bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (usb_handles.find(device_address) != usb_handles.end()) { 2998bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "device at " << device_address 3008bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << " has already been registered, skipping"; 3018bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3028bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3038bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3048bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3058bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bool writable = true; 3068bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao libusb_device_handle* handle_raw = nullptr; 3078bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_open(device, &handle_raw); 3088bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao unique_device_handle handle(handle_raw); 3098bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc == 0) { 3108bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(DEBUG) << "successfully opened adb device at " << device_address << ", " 3118bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << StringPrintf("bulk_in = %#x, bulk_out = %#x", bulk_in, bulk_out); 3128bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3138bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial.resize(255); 3148bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_get_string_descriptor_ascii(handle_raw, device_desc.iSerialNumber, 3158bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao reinterpret_cast<unsigned char*>(&device_serial[0]), 3168bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial.length()); 3178bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc == 0) { 3188bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "received empty serial from device at " << device_address; 3198bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3208bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } else if (rc < 0) { 3218bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to get serial from device at " << device_address 3228bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << libusb_error_name(rc); 3238bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3248bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3258bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial.resize(rc); 3268bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3278bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // WARNING: this isn't released via RAII. 3288bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_claim_interface(handle.get(), interface_num); 3298bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc != 0) { 3308bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to claim adb interface for device '" << device_serial << "'" 3318bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << libusb_error_name(rc); 3328bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3338bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3348bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3354b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao rc = libusb_set_interface_alt_setting(handle.get(), interface_num, 0); 3364b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao if (rc != 0) { 3374b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao LOG(WARNING) << "failed to set interface alt setting for device '" << device_serial 3384b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao << "'" << libusb_error_name(rc); 3394b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao return; 3404b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao } 3414b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao 3428bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao for (uint8_t endpoint : {bulk_in, bulk_out}) { 3438bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_clear_halt(handle.get(), endpoint); 3448bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc != 0) { 3458bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to clear halt on device '" << device_serial 3468bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << "' endpoint 0x" << std::hex << endpoint << ": " 347cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes << libusb_error_name(rc); 3488bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao libusb_release_interface(handle.get(), interface_num); 3498bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3508bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3518bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3528bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } else { 3538bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to open usb device at " << device_address << ": " 3548bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << libusb_error_name(rc); 3558bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao writable = false; 356cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes 357cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes#if defined(__linux__) 3588bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // libusb doesn't think we should be messing around with devices we don't have 3598bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // write access to, but Linux at least lets us get the serial number anyway. 3608bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (!android::base::ReadFileToString(get_device_serial_path(device), &device_serial)) { 3618bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // We don't actually want to treat an unknown serial as an error because 3628bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // devices aren't able to communicate a serial number in early bringup. 3638bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // http://b/20883914 3648bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial = "unknown"; 3658bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3668bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial = android::base::Trim(device_serial); 367cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes#else 3688bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // On Mac OS and Windows, we're screwed. But I don't think this situation actually 3698bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // happens on those OSes. 3708bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 371cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes#endif 3728bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3731c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3749425996b4521eae0571b4af30056c44bb0482598Josh Gao std::unique_ptr<usb_handle> result(new usb_handle(device_address, device_serial, 3759425996b4521eae0571b4af30056c44bb0482598Josh Gao std::move(handle), interface_num, bulk_in, 3769425996b4521eae0571b4af30056c44bb0482598Josh Gao bulk_out, zero_mask, packet_size)); 3778bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao usb_handle* usb_handle_raw = result.get(); 3781c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3798bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao { 3808bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 3818bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao usb_handles[device_address] = std::move(result); 3828bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3837dd382ded948aa5adae3618f99d00c14c3703d05Josh Gao register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), 3847dd382ded948aa5adae3618f99d00c14c3703d05Josh Gao writable); 3857dd382ded948aa5adae3618f99d00c14c3703d05Josh Gao } 3868bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(INFO) << "registered new usb device '" << device_serial << "'"; 3878bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao} 3888bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3893f60a968e35b051943249fb9ac70e349323a0590Josh Gaostatic std::atomic<int> connecting_devices(0); 3903f60a968e35b051943249fb9ac70e349323a0590Josh Gao 3913f60a968e35b051943249fb9ac70e349323a0590Josh Gaostatic void device_connected(libusb_device* device) { 3923f60a968e35b051943249fb9ac70e349323a0590Josh Gao#if defined(__linux__) 3933f60a968e35b051943249fb9ac70e349323a0590Josh Gao // Android's host linux libusb uses netlink instead of udev for device hotplug notification, 3945b8b10e078ef12f21144cdb5fbc932dda47be212Josh Gao // which means we can get hotplug notifications before udev has updated ownership/perms on the 3955b8b10e078ef12f21144cdb5fbc932dda47be212Josh Gao // device. Since we're not going to be able to link against the system's libudev any time soon, 3965b8b10e078ef12f21144cdb5fbc932dda47be212Josh Gao // hack around this by inserting a sleep. 3973f60a968e35b051943249fb9ac70e349323a0590Josh Gao auto thread = std::thread([device]() { 3983f60a968e35b051943249fb9ac70e349323a0590Josh Gao std::string device_path = get_device_dev_path(device); 3999425996b4521eae0571b4af30056c44bb0482598Josh Gao std::this_thread::sleep_for(std::chrono::seconds(1)); 4003f60a968e35b051943249fb9ac70e349323a0590Josh Gao 4013f60a968e35b051943249fb9ac70e349323a0590Josh Gao process_device(device); 4020b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao if (--connecting_devices == 0) { 4030b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao adb_notify_device_scan_complete(); 4040b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao } 4053f60a968e35b051943249fb9ac70e349323a0590Josh Gao }); 4063f60a968e35b051943249fb9ac70e349323a0590Josh Gao thread.detach(); 4073f60a968e35b051943249fb9ac70e349323a0590Josh Gao#else 4083f60a968e35b051943249fb9ac70e349323a0590Josh Gao process_device(device); 4093f60a968e35b051943249fb9ac70e349323a0590Josh Gao#endif 4103f60a968e35b051943249fb9ac70e349323a0590Josh Gao} 4113f60a968e35b051943249fb9ac70e349323a0590Josh Gao 4123f60a968e35b051943249fb9ac70e349323a0590Josh Gaostatic void device_disconnected(libusb_device* device) { 4136da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao std::string device_address = get_device_address(device); 4141c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4156da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao LOG(INFO) << "device disconnected: " << device_address; 4166da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 4176da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao auto it = usb_handles.find(device_address); 4186da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao if (it != usb_handles.end()) { 4196da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao if (!it->second->device_handle) { 4206da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao // If the handle is null, we were never able to open the device. 421e48ecce671a2ab6647cc26a3cb11163aec0b712cJosh Gao 422e48ecce671a2ab6647cc26a3cb11163aec0b712cJosh Gao // Temporarily release the usb handles mutex to avoid deadlock. 423e48ecce671a2ab6647cc26a3cb11163aec0b712cJosh Gao std::unique_ptr<usb_handle> handle = std::move(it->second); 42460b8c26520922f296a36efb17b8914b6f1e115eaJosh Gao usb_handles.erase(it); 425e48ecce671a2ab6647cc26a3cb11163aec0b712cJosh Gao lock.unlock(); 426e48ecce671a2ab6647cc26a3cb11163aec0b712cJosh Gao unregister_usb_transport(handle.get()); 427e48ecce671a2ab6647cc26a3cb11163aec0b712cJosh Gao lock.lock(); 42860b8c26520922f296a36efb17b8914b6f1e115eaJosh Gao } else { 42960b8c26520922f296a36efb17b8914b6f1e115eaJosh Gao // Closure of the transport will erase the usb_handle. 4301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4316da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao } 4326da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao} 4338bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 4340b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gaostatic auto& hotplug_queue = *new BlockingQueue<std::pair<libusb_hotplug_event, libusb_device*>>(); 4350b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gaostatic void hotplug_thread() { 4360b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao adb_thread_setname("libusb hotplug"); 4370b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao while (true) { 4380b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao hotplug_queue.PopAll([](std::pair<libusb_hotplug_event, libusb_device*> pair) { 4390b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao libusb_hotplug_event event = pair.first; 4400b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao libusb_device* device = pair.second; 4410b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { 4420b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao device_connected(device); 4430b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { 4440b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao device_disconnected(device); 4450b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao } 4460b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao }); 4470b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao } 4480b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao} 4490b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao 4509425996b4521eae0571b4af30056c44bb0482598Josh Gaostatic LIBUSB_CALL int hotplug_callback(libusb_context*, libusb_device* device, 4519425996b4521eae0571b4af30056c44bb0482598Josh Gao libusb_hotplug_event event, void*) { 4520b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao // We're called with the libusb lock taken. Call these on a separate thread outside of this 453d1a3e8f1ab653831a3cc4c2a90fb0f8b7a2a95acJosh Gao // function so that the usb_handle mutex is always taken before the libusb mutex. 4540b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao static std::once_flag once; 4550b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao std::call_once(once, []() { std::thread(hotplug_thread).detach(); }); 4560b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao 4570b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { 4580b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao ++connecting_devices; 4590b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao } 4600b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao hotplug_queue.Push({event, device}); 4616da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao return 0; 4621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 4631c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4641c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaovoid usb_init() { 4651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "initializing libusb..."; 4661c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_init(nullptr); 4671c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 4681c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(FATAL) << "failed to initialize libusb: " << libusb_error_name(rc); 4691c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4701c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4716da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao // Register the hotplug callback. 4726da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao rc = libusb_hotplug_register_callback( 4736da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao nullptr, static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | 4746da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), 4756da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, 4766da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao LIBUSB_CLASS_PER_INTERFACE, hotplug_callback, nullptr, &hotplug_handle); 4776da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao 4786da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao if (rc != LIBUSB_SUCCESS) { 4796da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao LOG(FATAL) << "failed to register libusb hotplug callback"; 4806da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao } 4816da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao 4821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Spawn a thread for libusb_handle_events. 4831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::thread([]() { 4841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao adb_thread_setname("libusb"); 4851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao while (true) { 4861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_handle_events(nullptr); 4871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao }).detach(); 48901b7bc43e90b951675cabe88313b96f57b2da712Josh Gao} 49001b7bc43e90b951675cabe88313b96f57b2da712Josh Gao 49101b7bc43e90b951675cabe88313b96f57b2da712Josh Gaovoid usb_cleanup() { 4926da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao libusb_hotplug_deregister_callback(nullptr, hotplug_handle); 4931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 4941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4959425996b4521eae0571b4af30056c44bb0482598Josh Gaostatic LIBUSB_CALL void transfer_callback(libusb_transfer* transfer) { 4969425996b4521eae0571b4af30056c44bb0482598Josh Gao transfer_info* info = static_cast<transfer_info*>(transfer->user_data); 4971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4989425996b4521eae0571b4af30056c44bb0482598Josh Gao LOG(DEBUG) << info->name << " transfer callback entered"; 4991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5009425996b4521eae0571b4af30056c44bb0482598Josh Gao // Make sure that the original submitter has made it to the condition_variable wait. 5019425996b4521eae0571b4af30056c44bb0482598Josh Gao std::unique_lock<std::mutex> lock(info->mutex); 5021c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5039425996b4521eae0571b4af30056c44bb0482598Josh Gao LOG(DEBUG) << info->name << " callback successfully acquired lock"; 5041c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5059425996b4521eae0571b4af30056c44bb0482598Josh Gao if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { 5069425996b4521eae0571b4af30056c44bb0482598Josh Gao LOG(WARNING) << info->name << " transfer failed: " << libusb_error_name(transfer->status); 5079425996b4521eae0571b4af30056c44bb0482598Josh Gao info->Notify(); 5089425996b4521eae0571b4af30056c44bb0482598Josh Gao return; 5099425996b4521eae0571b4af30056c44bb0482598Josh Gao } 5101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5119425996b4521eae0571b4af30056c44bb0482598Josh Gao // usb_read() can return when receiving some data. 5129425996b4521eae0571b4af30056c44bb0482598Josh Gao if (info->is_bulk_out && transfer->actual_length != transfer->length) { 5139425996b4521eae0571b4af30056c44bb0482598Josh Gao LOG(DEBUG) << info->name << " transfer incomplete, resubmitting"; 5149425996b4521eae0571b4af30056c44bb0482598Josh Gao transfer->length -= transfer->actual_length; 5159425996b4521eae0571b4af30056c44bb0482598Josh Gao transfer->buffer += transfer->actual_length; 5169425996b4521eae0571b4af30056c44bb0482598Josh Gao int rc = libusb_submit_transfer(transfer); 5179425996b4521eae0571b4af30056c44bb0482598Josh Gao if (rc != 0) { 5189425996b4521eae0571b4af30056c44bb0482598Josh Gao LOG(WARNING) << "failed to submit " << info->name 5199425996b4521eae0571b4af30056c44bb0482598Josh Gao << " transfer: " << libusb_error_name(rc); 5209425996b4521eae0571b4af30056c44bb0482598Josh Gao transfer->status = LIBUSB_TRANSFER_ERROR; 5211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->Notify(); 5221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5239425996b4521eae0571b4af30056c44bb0482598Josh Gao return; 5249425996b4521eae0571b4af30056c44bb0482598Josh Gao } 5251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5269425996b4521eae0571b4af30056c44bb0482598Josh Gao if (should_perform_zero_transfer(transfer->endpoint, transfer->length, info->zero_mask)) { 5279425996b4521eae0571b4af30056c44bb0482598Josh Gao LOG(DEBUG) << "submitting zero-length write"; 5289425996b4521eae0571b4af30056c44bb0482598Josh Gao transfer->length = 0; 5299425996b4521eae0571b4af30056c44bb0482598Josh Gao int rc = libusb_submit_transfer(transfer); 5309425996b4521eae0571b4af30056c44bb0482598Josh Gao if (rc != 0) { 5319425996b4521eae0571b4af30056c44bb0482598Josh Gao LOG(WARNING) << "failed to submit zero-length write: " << libusb_error_name(rc); 5329425996b4521eae0571b4af30056c44bb0482598Josh Gao transfer->status = LIBUSB_TRANSFER_ERROR; 5339425996b4521eae0571b4af30056c44bb0482598Josh Gao info->Notify(); 5341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5359425996b4521eae0571b4af30056c44bb0482598Josh Gao return; 5369425996b4521eae0571b4af30056c44bb0482598Josh Gao } 5371c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5389425996b4521eae0571b4af30056c44bb0482598Josh Gao LOG(VERBOSE) << info->name << "transfer fully complete"; 5399425996b4521eae0571b4af30056c44bb0482598Josh Gao info->Notify(); 5409425996b4521eae0571b4af30056c44bb0482598Josh Gao} 5411c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5429425996b4521eae0571b4af30056c44bb0482598Josh Gao// Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result. 5439425996b4521eae0571b4af30056c44bb0482598Josh Gaostatic int perform_usb_transfer(usb_handle* h, transfer_info* info, 5449425996b4521eae0571b4af30056c44bb0482598Josh Gao std::unique_lock<std::mutex> device_lock) { 5459425996b4521eae0571b4af30056c44bb0482598Josh Gao libusb_transfer* transfer = info->transfer; 5469425996b4521eae0571b4af30056c44bb0482598Josh Gao 5479425996b4521eae0571b4af30056c44bb0482598Josh Gao transfer->user_data = info; 5489425996b4521eae0571b4af30056c44bb0482598Josh Gao transfer->callback = transfer_callback; 5491c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5501c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "locking " << info->name << " transfer_info mutex"; 5511c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(info->mutex); 5521c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer_complete = false; 5531c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "submitting " << info->name << " transfer"; 5541c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_submit_transfer(transfer); 5551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 5561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to submit " << info->name << " transfer: " << libusb_error_name(rc); 5571c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 5581c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 5591c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5601c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5611c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << info->name << " transfer successfully submitted"; 5621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_lock.unlock(); 5631c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->cv.wait(lock, [info]() { return info->transfer_complete; }); 5641c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (transfer->status != 0) { 5651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 5661c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 5671c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5681c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5691c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return 0; 5701c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 5711c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5721c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_write(usb_handle* h, const void* d, int len) { 5731c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "usb_write of length " << len; 5741c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5751c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(h->device_handle_mutex); 5761c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (!h->device_handle) { 5771c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 5781c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 5791c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5801c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5811c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info* info = &h->write; 5821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->dev_handle = h->device_handle; 5831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->flags = 0; 5841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->endpoint = h->bulk_out; 5851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK; 5861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->length = len; 5871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->buffer = reinterpret_cast<unsigned char*>(const_cast<void*>(d)); 5881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->num_iso_packets = 0; 5891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = perform_usb_transfer(h, info, std::move(lock)); 5911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "usb_write(" << len << ") = " << rc; 5921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return rc; 5931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 5941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5951c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_read(usb_handle* h, void* d, int len) { 5961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "usb_read of length " << len; 5971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5981c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(h->device_handle_mutex); 5991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (!h->device_handle) { 6001c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 6011c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 6021c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 6031c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 6041c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info* info = &h->read; 6051c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->dev_handle = h->device_handle; 6061c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->flags = 0; 6071c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->endpoint = h->bulk_in; 6081c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK; 6091c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->length = len; 6101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->buffer = reinterpret_cast<unsigned char*>(d); 6111c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->num_iso_packets = 0; 6121c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 6131c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = perform_usb_transfer(h, info, std::move(lock)); 614b5e11415d9fdb929321c66889063dac50fb737afYabin Cui LOG(DEBUG) << "usb_read(" << len << ") = " << rc << ", actual_length " 615b5e11415d9fdb929321c66889063dac50fb737afYabin Cui << info->transfer->actual_length; 616b5e11415d9fdb929321c66889063dac50fb737afYabin Cui if (rc < 0) { 617b5e11415d9fdb929321c66889063dac50fb737afYabin Cui return rc; 618b5e11415d9fdb929321c66889063dac50fb737afYabin Cui } 619b5e11415d9fdb929321c66889063dac50fb737afYabin Cui return info->transfer->actual_length; 6201c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 6211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 6221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_close(usb_handle* h) { 6231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 6241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao auto it = usb_handles.find(h->device_address); 6251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (it == usb_handles.end()) { 6261c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(FATAL) << "attempted to close unregistered usb_handle for '" << h->serial << "'"; 6271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 6281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao usb_handles.erase(h->device_address); 6291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return 0; 6301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 6311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 6321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaovoid usb_kick(usb_handle* h) { 6331c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao h->Close(); 6341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 635ef3d343254405cc360b4df843c6e4a843c335012Josh Gao 636ef3d343254405cc360b4df843c6e4a843c335012Josh Gaosize_t usb_get_max_packet_size(usb_handle* h) { 637ef3d343254405cc360b4df843c6e4a843c335012Josh Gao CHECK(h->max_packet_size != 0); 638ef3d343254405cc360b4df843c6e4a843c335012Josh Gao return h->max_packet_size; 639ef3d343254405cc360b4df843c6e4a843c335012Josh Gao} 640ef3d343254405cc360b4df843c6e4a843c335012Josh Gao 6411c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} // namespace libusb 642