usb_libusb.cpp revision 60b8c26520922f296a36efb17b8914b6f1e115ea
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> 221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <atomic> 241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <chrono> 251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <memory> 261c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <mutex> 271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <string> 281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <thread> 291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <unordered_map> 301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <libusb/libusb.h> 321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 331c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <android-base/file.h> 341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <android-base/logging.h> 351c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <android-base/quick_exit.h> 361c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <android-base/stringprintf.h> 371c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <android-base/strings.h> 381c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 391c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include "adb.h" 400b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao#include "adb_utils.h" 411c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include "transport.h" 421c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include "usb.h" 431c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 441c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaousing namespace std::literals; 451c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 461c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaousing android::base::StringPrintf; 471c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 481c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao// RAII wrappers for libusb. 491c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostruct ConfigDescriptorDeleter { 501c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao void operator()(libusb_config_descriptor* desc) { 511c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_free_config_descriptor(desc); 521c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 531c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}; 541c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaousing unique_config_descriptor = std::unique_ptr<libusb_config_descriptor, ConfigDescriptorDeleter>; 561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 571c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostruct DeviceHandleDeleter { 581c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao void operator()(libusb_device_handle* h) { 591c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_close(h); 601c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 611c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}; 621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 631c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaousing unique_device_handle = std::unique_ptr<libusb_device_handle, DeviceHandleDeleter>; 641c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostruct transfer_info { 66b5e11415d9fdb929321c66889063dac50fb737afYabin Cui transfer_info(const char* name, uint16_t zero_mask, bool is_bulk_out) 67b5e11415d9fdb929321c66889063dac50fb737afYabin Cui : name(name), 68b5e11415d9fdb929321c66889063dac50fb737afYabin Cui transfer(libusb_alloc_transfer(0)), 69b5e11415d9fdb929321c66889063dac50fb737afYabin Cui is_bulk_out(is_bulk_out), 70b5e11415d9fdb929321c66889063dac50fb737afYabin Cui zero_mask(zero_mask) {} 711c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 721c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao ~transfer_info() { 731c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_free_transfer(transfer); 741c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 751c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 761c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao const char* name; 771c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_transfer* transfer; 78b5e11415d9fdb929321c66889063dac50fb737afYabin Cui bool is_bulk_out; 791c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao bool transfer_complete; 801c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::condition_variable cv; 811c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::mutex mutex; 821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao uint16_t zero_mask; 831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao void Notify() { 851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "notifying " << name << " transfer complete"; 861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_complete = true; 871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao cv.notify_one(); 881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}; 901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaonamespace libusb { 921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostruct usb_handle : public ::usb_handle { 931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao usb_handle(const std::string& device_address, const std::string& serial, 941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao unique_device_handle&& device_handle, uint8_t interface, uint8_t bulk_in, 95ef3d343254405cc360b4df843c6e4a843c335012Josh Gao uint8_t bulk_out, size_t zero_mask, size_t max_packet_size) 961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao : device_address(device_address), 971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao serial(serial), 981c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao closing(false), 991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_handle(device_handle.release()), 100b5e11415d9fdb929321c66889063dac50fb737afYabin Cui read("read", zero_mask, false), 101b5e11415d9fdb929321c66889063dac50fb737afYabin Cui write("write", zero_mask, true), 1021c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao interface(interface), 1031c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao bulk_in(bulk_in), 104ef3d343254405cc360b4df843c6e4a843c335012Josh Gao bulk_out(bulk_out), 105ef3d343254405cc360b4df843c6e4a843c335012Josh Gao max_packet_size(max_packet_size) {} 1061c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1071c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao ~usb_handle() { 1081c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao Close(); 1091c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 1101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1111c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao void Close() { 1121c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(device_handle_mutex); 1131c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Cancelling transfers will trigger more Closes, so make sure this only happens once. 1141c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (closing) { 1151c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return; 1161c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 1171c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao closing = true; 1181c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1191c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Make sure that no new transfers come in. 1201c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_device_handle* handle = device_handle; 1211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (!handle) { 1221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return; 1231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 1241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_handle = nullptr; 1261c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Cancel already dispatched transfers. 1281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_cancel_transfer(read.transfer); 1291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_cancel_transfer(write.transfer); 1301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_release_interface(handle, interface); 1321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_close(handle); 1331c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 1341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1351c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::string device_address; 1361c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::string serial; 1371c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1381c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::atomic<bool> closing; 1391c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::mutex device_handle_mutex; 1401c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_device_handle* device_handle; 1411c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1421c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info read; 1431c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info write; 1441c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1451c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao uint8_t interface; 1461c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao uint8_t bulk_in; 1471c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao uint8_t bulk_out; 148ef3d343254405cc360b4df843c6e4a843c335012Josh Gao 149ef3d343254405cc360b4df843c6e4a843c335012Josh Gao size_t max_packet_size; 1501c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}; 1511c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1521c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic auto& usb_handles = *new std::unordered_map<std::string, std::unique_ptr<usb_handle>>(); 1531c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic auto& usb_handles_mutex = *new std::mutex(); 1541c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1556da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gaostatic libusb_hotplug_callback_handle hotplug_handle; 1561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1571c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic std::string get_device_address(libusb_device* device) { 1581c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return StringPrintf("usb:%d:%d", libusb_get_bus_number(device), 1591c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_get_device_address(device)); 1601c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 1611c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1624acb36020bfa3cb63ed81358754758e76fc5787dElliott Hughes#if defined(__linux__) 163cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughesstatic std::string get_device_serial_path(libusb_device* device) { 164cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes uint8_t ports[7]; 165cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes int port_count = libusb_get_port_numbers(device, ports, 7); 166cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes if (port_count < 0) return ""; 167cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes 168cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes std::string path = 169cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes StringPrintf("/sys/bus/usb/devices/%d-%d", libusb_get_bus_number(device), ports[0]); 170cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes for (int port = 1; port < port_count; ++port) { 171cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes path += StringPrintf(".%d", ports[port]); 172cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes } 173cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes path += "/serial"; 174cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes return path; 175cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes} 1763f60a968e35b051943249fb9ac70e349323a0590Josh Gao 1773f60a968e35b051943249fb9ac70e349323a0590Josh Gaostatic std::string get_device_dev_path(libusb_device* device) { 1783f60a968e35b051943249fb9ac70e349323a0590Josh Gao uint8_t ports[7]; 1793f60a968e35b051943249fb9ac70e349323a0590Josh Gao int port_count = libusb_get_port_numbers(device, ports, 7); 1803f60a968e35b051943249fb9ac70e349323a0590Josh Gao if (port_count < 0) return ""; 1813f60a968e35b051943249fb9ac70e349323a0590Josh Gao return StringPrintf("/dev/bus/usb/%03u/%03u", libusb_get_bus_number(device), ports[0]); 1823f60a968e35b051943249fb9ac70e349323a0590Josh Gao} 1833f60a968e35b051943249fb9ac70e349323a0590Josh Gao 1843f60a968e35b051943249fb9ac70e349323a0590Josh Gaostatic bool is_device_accessible(libusb_device* device) { 1853f60a968e35b051943249fb9ac70e349323a0590Josh Gao return access(get_device_dev_path(device).c_str(), R_OK | W_OK) == 0; 1863f60a968e35b051943249fb9ac70e349323a0590Josh Gao} 1874acb36020bfa3cb63ed81358754758e76fc5787dElliott Hughes#endif 188cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes 1891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic bool endpoint_is_output(uint8_t endpoint) { 1901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return (endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT; 1911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 1921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic bool should_perform_zero_transfer(uint8_t endpoint, size_t write_length, uint16_t zero_mask) { 1941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return endpoint_is_output(endpoint) && write_length != 0 && zero_mask != 0 && 1951c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao (write_length & zero_mask) == 0; 1961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 1971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1988bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gaostatic void process_device(libusb_device* device) { 1998bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::string device_address = get_device_address(device); 2008bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::string device_serial; 2011c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2028bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // Figure out if we want to open the device. 2038bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao libusb_device_descriptor device_desc; 2048bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao int rc = libusb_get_device_descriptor(device, &device_desc); 2058bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc != 0) { 2068bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to get device descriptor for device at " << device_address << ": " 2078bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << libusb_error_name(rc); 2088bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2098bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2118bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (device_desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) { 2128bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // Assume that all Android devices have the device class set to per interface. 2138bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // TODO: Is this assumption valid? 2148bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "skipping device with incorrect class at " << device_address; 2158bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2168bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2171c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2188bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao libusb_config_descriptor* config_raw; 2198bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_get_active_config_descriptor(device, &config_raw); 2208bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc != 0) { 2218bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to get active config descriptor for device at " << device_address 2228bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << ": " << libusb_error_name(rc); 2238bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2248bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2258bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const unique_config_descriptor config(config_raw); 2261c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2278bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // Use size_t for interface_num so <iostream>s don't mangle it. 2288bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao size_t interface_num; 2298bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao uint16_t zero_mask; 2308bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao uint8_t bulk_in = 0, bulk_out = 0; 2318bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao size_t packet_size = 0; 2328bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bool found_adb = false; 2338bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2348bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao for (interface_num = 0; interface_num < config->bNumInterfaces; ++interface_num) { 2358bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const libusb_interface& interface = config->interface[interface_num]; 2368bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (interface.num_altsetting != 1) { 2378bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // Assume that interfaces with alternate settings aren't adb interfaces. 2388bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // TODO: Is this assumption valid? 2398bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at " << device_address 2408bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << " (interface " << interface_num << ")"; 241425aefdcf0f1b2068f56ca091047af5f02ae3f3dJosh Gao continue; 2428bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2431c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2448bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const libusb_interface_descriptor& interface_desc = interface.altsetting[0]; 2458bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (!is_adb_interface(interface_desc.bInterfaceClass, interface_desc.bInterfaceSubClass, 2468bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao interface_desc.bInterfaceProtocol)) { 2478bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "skipping non-adb interface at " << device_address << " (interface " 2488bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << interface_num << ")"; 249425aefdcf0f1b2068f56ca091047af5f02ae3f3dJosh Gao continue; 2508bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2518bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2528bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "found potential adb interface at " << device_address << " (interface " 2538bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << interface_num << ")"; 2548bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2558bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bool found_in = false; 2568bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bool found_out = false; 2578bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao for (size_t endpoint_num = 0; endpoint_num < interface_desc.bNumEndpoints; ++endpoint_num) { 2588bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const auto& endpoint_desc = interface_desc.endpoint[endpoint_num]; 2598bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const uint8_t endpoint_addr = endpoint_desc.bEndpointAddress; 2608bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const uint8_t endpoint_attr = endpoint_desc.bmAttributes; 2611c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2628bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK; 2638bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2648bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) { 265425aefdcf0f1b2068f56ca091047af5f02ae3f3dJosh Gao continue; 2661c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2671c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2688bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (endpoint_is_output(endpoint_addr) && !found_out) { 2698bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao found_out = true; 2708bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bulk_out = endpoint_addr; 2718bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao zero_mask = endpoint_desc.wMaxPacketSize - 1; 2728bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } else if (!endpoint_is_output(endpoint_addr) && !found_in) { 2738bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao found_in = true; 2748bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bulk_in = endpoint_addr; 2751c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2761c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2778bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao size_t endpoint_packet_size = endpoint_desc.wMaxPacketSize; 2788bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao CHECK(endpoint_packet_size != 0); 2798bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (packet_size == 0) { 2808bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao packet_size = endpoint_packet_size; 281cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes } else { 2828bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao CHECK(packet_size == endpoint_packet_size); 2838bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2848bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2858bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2868bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (found_in && found_out) { 2878bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao found_adb = true; 2888bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao break; 2898bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } else { 2908bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "rejecting potential adb interface at " << device_address 2918bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << "(interface " << interface_num << "): missing bulk endpoints " 2928bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << "(found_in = " << found_in << ", found_out = " << found_out << ")"; 2938bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2948bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2958bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2968bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (!found_adb) { 2978bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "skipping device with no adb interfaces at " << device_address; 2988bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2998bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3008bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3018bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao { 3028bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 3038bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (usb_handles.find(device_address) != usb_handles.end()) { 3048bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "device at " << device_address 3058bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << " has already been registered, skipping"; 3068bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3078bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3088bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3098bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3108bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bool writable = true; 3118bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao libusb_device_handle* handle_raw = nullptr; 3128bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_open(device, &handle_raw); 3138bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao unique_device_handle handle(handle_raw); 3148bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc == 0) { 3158bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(DEBUG) << "successfully opened adb device at " << device_address << ", " 3168bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << StringPrintf("bulk_in = %#x, bulk_out = %#x", bulk_in, bulk_out); 3178bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3188bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial.resize(255); 3198bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_get_string_descriptor_ascii(handle_raw, device_desc.iSerialNumber, 3208bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao reinterpret_cast<unsigned char*>(&device_serial[0]), 3218bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial.length()); 3228bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc == 0) { 3238bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "received empty serial from device at " << device_address; 3248bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3258bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } else if (rc < 0) { 3268bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to get serial from device at " << device_address 3278bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << libusb_error_name(rc); 3288bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3298bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3308bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial.resize(rc); 3318bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3328bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // WARNING: this isn't released via RAII. 3338bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_claim_interface(handle.get(), interface_num); 3348bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc != 0) { 3358bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to claim adb interface for device '" << device_serial << "'" 3368bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << libusb_error_name(rc); 3378bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3388bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3398bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3408bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao for (uint8_t endpoint : {bulk_in, bulk_out}) { 3418bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_clear_halt(handle.get(), endpoint); 3428bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc != 0) { 3438bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to clear halt on device '" << device_serial 3448bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << "' endpoint 0x" << std::hex << endpoint << ": " 345cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes << libusb_error_name(rc); 3468bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao libusb_release_interface(handle.get(), interface_num); 3478bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3488bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3498bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3508bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } else { 3518bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to open usb device at " << device_address << ": " 3528bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << libusb_error_name(rc); 3538bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao writable = false; 354cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes 355cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes#if defined(__linux__) 3568bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // libusb doesn't think we should be messing around with devices we don't have 3578bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // write access to, but Linux at least lets us get the serial number anyway. 3588bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (!android::base::ReadFileToString(get_device_serial_path(device), &device_serial)) { 3598bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // We don't actually want to treat an unknown serial as an error because 3608bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // devices aren't able to communicate a serial number in early bringup. 3618bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // http://b/20883914 3628bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial = "unknown"; 3638bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3648bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial = android::base::Trim(device_serial); 365cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes#else 3668bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // On Mac OS and Windows, we're screwed. But I don't think this situation actually 3678bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // happens on those OSes. 3688bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 369cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes#endif 3708bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3711c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3728bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao auto result = 3738bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::make_unique<usb_handle>(device_address, device_serial, std::move(handle), 3748bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao interface_num, bulk_in, bulk_out, zero_mask, packet_size); 3758bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao usb_handle* usb_handle_raw = result.get(); 3761c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3778bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao { 3788bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 3798bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao usb_handles[device_address] = std::move(result); 3808bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3818bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3828bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), writable); 3838bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(INFO) << "registered new usb device '" << device_serial << "'"; 3848bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao} 3858bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3863f60a968e35b051943249fb9ac70e349323a0590Josh Gaostatic std::atomic<int> connecting_devices(0); 3873f60a968e35b051943249fb9ac70e349323a0590Josh Gao 3883f60a968e35b051943249fb9ac70e349323a0590Josh Gaostatic void device_connected(libusb_device* device) { 3893f60a968e35b051943249fb9ac70e349323a0590Josh Gao#if defined(__linux__) 3903f60a968e35b051943249fb9ac70e349323a0590Josh Gao // Android's host linux libusb uses netlink instead of udev for device hotplug notification, 3910b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao // which means we can get hotplug notifications before udev has updated ownership/perms on 3920b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao // the device. Since we're not going to be able to link against the system's libudev any 3930b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao // time soon, hack around this by checking for accessibility in a loop. 3943f60a968e35b051943249fb9ac70e349323a0590Josh Gao auto thread = std::thread([device]() { 3953f60a968e35b051943249fb9ac70e349323a0590Josh Gao std::string device_path = get_device_dev_path(device); 3963f60a968e35b051943249fb9ac70e349323a0590Josh Gao auto start = std::chrono::steady_clock::now(); 3973f60a968e35b051943249fb9ac70e349323a0590Josh Gao while (std::chrono::steady_clock::now() - start < 500ms) { 3983f60a968e35b051943249fb9ac70e349323a0590Josh Gao if (is_device_accessible(device)) { 3993f60a968e35b051943249fb9ac70e349323a0590Josh Gao break; 4003f60a968e35b051943249fb9ac70e349323a0590Josh Gao } 4013f60a968e35b051943249fb9ac70e349323a0590Josh Gao std::this_thread::sleep_for(10ms); 4023f60a968e35b051943249fb9ac70e349323a0590Josh Gao } 4033f60a968e35b051943249fb9ac70e349323a0590Josh Gao 4043f60a968e35b051943249fb9ac70e349323a0590Josh Gao process_device(device); 4050b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao if (--connecting_devices == 0) { 4060b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao adb_notify_device_scan_complete(); 4070b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao } 4083f60a968e35b051943249fb9ac70e349323a0590Josh Gao }); 4093f60a968e35b051943249fb9ac70e349323a0590Josh Gao thread.detach(); 4103f60a968e35b051943249fb9ac70e349323a0590Josh Gao#else 4113f60a968e35b051943249fb9ac70e349323a0590Josh Gao process_device(device); 4123f60a968e35b051943249fb9ac70e349323a0590Josh Gao#endif 4133f60a968e35b051943249fb9ac70e349323a0590Josh Gao} 4143f60a968e35b051943249fb9ac70e349323a0590Josh Gao 4153f60a968e35b051943249fb9ac70e349323a0590Josh Gaostatic void device_disconnected(libusb_device* device) { 4166da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao std::string device_address = get_device_address(device); 4171c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4186da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao LOG(INFO) << "device disconnected: " << device_address; 4196da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 4206da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao auto it = usb_handles.find(device_address); 4216da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao if (it != usb_handles.end()) { 4226da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao if (!it->second->device_handle) { 4236da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao // If the handle is null, we were never able to open the device. 4246da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao unregister_usb_transport(it->second.get()); 42560b8c26520922f296a36efb17b8914b6f1e115eaJosh Gao usb_handles.erase(it); 42660b8c26520922f296a36efb17b8914b6f1e115eaJosh Gao } else { 42760b8c26520922f296a36efb17b8914b6f1e115eaJosh Gao // Closure of the transport will erase the usb_handle. 4281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4296da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao } 4306da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao} 4318bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 4320b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gaostatic auto& hotplug_queue = *new BlockingQueue<std::pair<libusb_hotplug_event, libusb_device*>>(); 4330b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gaostatic void hotplug_thread() { 4340b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao adb_thread_setname("libusb hotplug"); 4350b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao while (true) { 4360b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao hotplug_queue.PopAll([](std::pair<libusb_hotplug_event, libusb_device*> pair) { 4370b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao libusb_hotplug_event event = pair.first; 4380b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao libusb_device* device = pair.second; 4390b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { 4400b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao device_connected(device); 4410b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { 4420b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao device_disconnected(device); 4430b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao } 4440b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao }); 4450b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao } 4460b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao} 4470b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao 4486da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gaostatic int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event, 4496da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao void*) { 4500b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao // We're called with the libusb lock taken. Call these on a separate thread outside of this 451d1a3e8f1ab653831a3cc4c2a90fb0f8b7a2a95acJosh Gao // function so that the usb_handle mutex is always taken before the libusb mutex. 4520b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao static std::once_flag once; 4530b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao std::call_once(once, []() { std::thread(hotplug_thread).detach(); }); 4540b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao 4550b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { 4560b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao ++connecting_devices; 4570b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao } 4580b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao hotplug_queue.Push({event, device}); 4596da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao return 0; 4601c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 4611c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaovoid usb_init() { 4631c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "initializing libusb..."; 4641c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_init(nullptr); 4651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 4661c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(FATAL) << "failed to initialize libusb: " << libusb_error_name(rc); 4671c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4681c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4696da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao // Register the hotplug callback. 4706da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao rc = libusb_hotplug_register_callback( 4716da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao nullptr, static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | 4726da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), 4736da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, 4746da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao LIBUSB_CLASS_PER_INTERFACE, hotplug_callback, nullptr, &hotplug_handle); 4756da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao 4766da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao if (rc != LIBUSB_SUCCESS) { 4776da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao LOG(FATAL) << "failed to register libusb hotplug callback"; 4786da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao } 4796da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao 4801c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Spawn a thread for libusb_handle_events. 4811c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::thread([]() { 4821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao adb_thread_setname("libusb"); 4831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao while (true) { 4841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_handle_events(nullptr); 4851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao }).detach(); 48701b7bc43e90b951675cabe88313b96f57b2da712Josh Gao} 48801b7bc43e90b951675cabe88313b96f57b2da712Josh Gao 48901b7bc43e90b951675cabe88313b96f57b2da712Josh Gaovoid usb_cleanup() { 4906da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao libusb_hotplug_deregister_callback(nullptr, hotplug_handle); 4911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 4921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao// Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result. 4941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic int perform_usb_transfer(usb_handle* h, transfer_info* info, 4951c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> device_lock) { 4961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_transfer* transfer = info->transfer; 4971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4981c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->user_data = info; 4991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->callback = [](libusb_transfer* transfer) { 5001c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info* info = static_cast<transfer_info*>(transfer->user_data); 5011c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5021c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << info->name << " transfer callback entered"; 5031c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5041c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Make sure that the original submitter has made it to the condition_variable wait. 5051c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(info->mutex); 5061c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5071c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << info->name << " callback successfully acquired lock"; 5081c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5091c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { 5101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << info->name 5111c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << " transfer failed: " << libusb_error_name(transfer->status); 5121c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->Notify(); 5131c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return; 5141c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5151c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 516b5e11415d9fdb929321c66889063dac50fb737afYabin Cui // usb_read() can return when receiving some data. 517b5e11415d9fdb929321c66889063dac50fb737afYabin Cui if (info->is_bulk_out && transfer->actual_length != transfer->length) { 5181c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << info->name << " transfer incomplete, resubmitting"; 5191c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->length -= transfer->actual_length; 5201c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->buffer += transfer->actual_length; 5211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_submit_transfer(transfer); 5221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 5231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to submit " << info->name 5241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << " transfer: " << libusb_error_name(rc); 5251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->status = LIBUSB_TRANSFER_ERROR; 5261c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->Notify(); 5271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return; 5291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (should_perform_zero_transfer(transfer->endpoint, transfer->length, info->zero_mask)) { 5321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "submitting zero-length write"; 5331c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->length = 0; 5341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_submit_transfer(transfer); 5351c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 5361c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to submit zero-length write: " << libusb_error_name(rc); 5371c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->status = LIBUSB_TRANSFER_ERROR; 5381c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->Notify(); 5391c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5401c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return; 5411c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5421c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5431c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(VERBOSE) << info->name << "transfer fully complete"; 5441c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->Notify(); 5451c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao }; 5461c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5471c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "locking " << info->name << " transfer_info mutex"; 5481c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(info->mutex); 5491c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer_complete = false; 5501c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "submitting " << info->name << " transfer"; 5511c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_submit_transfer(transfer); 5521c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 5531c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to submit " << info->name << " transfer: " << libusb_error_name(rc); 5541c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 5551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 5561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5571c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5581c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << info->name << " transfer successfully submitted"; 5591c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_lock.unlock(); 5601c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->cv.wait(lock, [info]() { return info->transfer_complete; }); 5611c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (transfer->status != 0) { 5621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 5631c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 5641c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5661c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return 0; 5671c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 5681c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5691c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_write(usb_handle* h, const void* d, int len) { 5701c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "usb_write of length " << len; 5711c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5721c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(h->device_handle_mutex); 5731c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (!h->device_handle) { 5741c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 5751c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 5761c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5771c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5781c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info* info = &h->write; 5791c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->dev_handle = h->device_handle; 5801c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->flags = 0; 5811c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->endpoint = h->bulk_out; 5821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK; 5831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->length = len; 5841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->buffer = reinterpret_cast<unsigned char*>(const_cast<void*>(d)); 5851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->num_iso_packets = 0; 5861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = perform_usb_transfer(h, info, std::move(lock)); 5881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "usb_write(" << len << ") = " << rc; 5891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return rc; 5901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 5911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_read(usb_handle* h, void* d, int len) { 5931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "usb_read of length " << len; 5941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5951c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(h->device_handle_mutex); 5961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (!h->device_handle) { 5971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 5981c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 5991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 6001c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 6011c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info* info = &h->read; 6021c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->dev_handle = h->device_handle; 6031c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->flags = 0; 6041c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->endpoint = h->bulk_in; 6051c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK; 6061c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->length = len; 6071c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->buffer = reinterpret_cast<unsigned char*>(d); 6081c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->num_iso_packets = 0; 6091c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 6101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = perform_usb_transfer(h, info, std::move(lock)); 611b5e11415d9fdb929321c66889063dac50fb737afYabin Cui LOG(DEBUG) << "usb_read(" << len << ") = " << rc << ", actual_length " 612b5e11415d9fdb929321c66889063dac50fb737afYabin Cui << info->transfer->actual_length; 613b5e11415d9fdb929321c66889063dac50fb737afYabin Cui if (rc < 0) { 614b5e11415d9fdb929321c66889063dac50fb737afYabin Cui return rc; 615b5e11415d9fdb929321c66889063dac50fb737afYabin Cui } 616b5e11415d9fdb929321c66889063dac50fb737afYabin Cui return info->transfer->actual_length; 6171c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 6181c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 6191c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_close(usb_handle* h) { 6201c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 6211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao auto it = usb_handles.find(h->device_address); 6221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (it == usb_handles.end()) { 6231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(FATAL) << "attempted to close unregistered usb_handle for '" << h->serial << "'"; 6241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 6251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao usb_handles.erase(h->device_address); 6261c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return 0; 6271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 6281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 6291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaovoid usb_kick(usb_handle* h) { 6301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao h->Close(); 6311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 632ef3d343254405cc360b4df843c6e4a843c335012Josh Gao 633ef3d343254405cc360b4df843c6e4a843c335012Josh Gaosize_t usb_get_max_packet_size(usb_handle* h) { 634ef3d343254405cc360b4df843c6e4a843c335012Josh Gao CHECK(h->max_packet_size != 0); 635ef3d343254405cc360b4df843c6e4a843c335012Josh Gao return h->max_packet_size; 636ef3d343254405cc360b4df843c6e4a843c335012Josh Gao} 637ef3d343254405cc360b4df843c6e4a843c335012Josh Gao 6381c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} // namespace libusb 639