usb_libusb.cpp revision 8bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7
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" 401c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include "transport.h" 411c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include "usb.h" 421c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 431c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaousing namespace std::literals; 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 1541c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic std::thread* device_poll_thread = nullptr; 1551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic std::atomic<bool> terminate_device_poll_thread(false); 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} 1764acb36020bfa3cb63ed81358754758e76fc5787dElliott Hughes#endif 177cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes 1781c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic bool endpoint_is_output(uint8_t endpoint) { 1791c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return (endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT; 1801c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 1811c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic bool should_perform_zero_transfer(uint8_t endpoint, size_t write_length, uint16_t zero_mask) { 1831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return endpoint_is_output(endpoint) && write_length != 0 && zero_mask != 0 && 1841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao (write_length & zero_mask) == 0; 1851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 1861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1878bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gaostatic void process_device(libusb_device* device) { 1888bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::string device_address = get_device_address(device); 1898bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::string device_serial; 1901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1918bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // Figure out if we want to open the device. 1928bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao libusb_device_descriptor device_desc; 1938bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao int rc = libusb_get_device_descriptor(device, &device_desc); 1948bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc != 0) { 1958bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to get device descriptor for device at " << device_address << ": " 1968bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << libusb_error_name(rc); 1978bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 1988bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 1991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2008bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (device_desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) { 2018bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // Assume that all Android devices have the device class set to per interface. 2028bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // TODO: Is this assumption valid? 2038bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "skipping device with incorrect class at " << device_address; 2048bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2058bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2061c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2078bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao libusb_config_descriptor* config_raw; 2088bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_get_active_config_descriptor(device, &config_raw); 2098bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc != 0) { 2108bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to get active config descriptor for device at " << device_address 2118bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << ": " << libusb_error_name(rc); 2128bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2138bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2148bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const unique_config_descriptor config(config_raw); 2151c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2168bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // Use size_t for interface_num so <iostream>s don't mangle it. 2178bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao size_t interface_num; 2188bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao uint16_t zero_mask; 2198bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao uint8_t bulk_in = 0, bulk_out = 0; 2208bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao size_t packet_size = 0; 2218bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bool found_adb = false; 2228bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2238bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao for (interface_num = 0; interface_num < config->bNumInterfaces; ++interface_num) { 2248bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const libusb_interface& interface = config->interface[interface_num]; 2258bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (interface.num_altsetting != 1) { 2268bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // Assume that interfaces with alternate settings aren't adb interfaces. 2278bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // TODO: Is this assumption valid? 2288bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at " << device_address 2298bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << " (interface " << interface_num << ")"; 2308bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2318bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2338bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const libusb_interface_descriptor& interface_desc = interface.altsetting[0]; 2348bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (!is_adb_interface(interface_desc.bInterfaceClass, interface_desc.bInterfaceSubClass, 2358bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao interface_desc.bInterfaceProtocol)) { 2368bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "skipping non-adb interface at " << device_address << " (interface " 2378bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << interface_num << ")"; 2388bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2398bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2408bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2418bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "found potential adb interface at " << device_address << " (interface " 2428bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << interface_num << ")"; 2438bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2448bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bool found_in = false; 2458bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bool found_out = false; 2468bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao for (size_t endpoint_num = 0; endpoint_num < interface_desc.bNumEndpoints; ++endpoint_num) { 2478bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const auto& endpoint_desc = interface_desc.endpoint[endpoint_num]; 2488bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const uint8_t endpoint_addr = endpoint_desc.bEndpointAddress; 2498bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const uint8_t endpoint_attr = endpoint_desc.bmAttributes; 2501c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2518bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK; 2528bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2538bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) { 2548bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2578bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (endpoint_is_output(endpoint_addr) && !found_out) { 2588bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao found_out = true; 2598bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bulk_out = endpoint_addr; 2608bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao zero_mask = endpoint_desc.wMaxPacketSize - 1; 2618bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } else if (!endpoint_is_output(endpoint_addr) && !found_in) { 2628bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao found_in = true; 2638bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bulk_in = endpoint_addr; 2641c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2668bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao size_t endpoint_packet_size = endpoint_desc.wMaxPacketSize; 2678bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao CHECK(endpoint_packet_size != 0); 2688bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (packet_size == 0) { 2698bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao packet_size = endpoint_packet_size; 270cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes } else { 2718bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao CHECK(packet_size == endpoint_packet_size); 2728bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2738bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2748bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2758bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (found_in && found_out) { 2768bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao found_adb = true; 2778bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao break; 2788bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } else { 2798bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "rejecting potential adb interface at " << device_address 2808bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << "(interface " << interface_num << "): missing bulk endpoints " 2818bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << "(found_in = " << found_in << ", found_out = " << found_out << ")"; 2828bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2838bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2848bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2858bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (!found_adb) { 2868bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "skipping device with no adb interfaces at " << device_address; 2878bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2888bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2898bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2908bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao { 2918bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 2928bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (usb_handles.find(device_address) != usb_handles.end()) { 2938bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "device at " << device_address 2948bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << " has already been registered, skipping"; 2958bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 2968bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2978bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 2988bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 2998bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao bool writable = true; 3008bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao libusb_device_handle* handle_raw = nullptr; 3018bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_open(device, &handle_raw); 3028bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao unique_device_handle handle(handle_raw); 3038bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc == 0) { 3048bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(DEBUG) << "successfully opened adb device at " << device_address << ", " 3058bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << StringPrintf("bulk_in = %#x, bulk_out = %#x", bulk_in, bulk_out); 3068bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3078bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial.resize(255); 3088bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_get_string_descriptor_ascii(handle_raw, device_desc.iSerialNumber, 3098bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao reinterpret_cast<unsigned char*>(&device_serial[0]), 3108bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial.length()); 3118bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc == 0) { 3128bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "received empty serial from device at " << device_address; 3138bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3148bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } else if (rc < 0) { 3158bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to get serial from device at " << device_address 3168bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << libusb_error_name(rc); 3178bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3188bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3198bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial.resize(rc); 3208bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3218bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // WARNING: this isn't released via RAII. 3228bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_claim_interface(handle.get(), interface_num); 3238bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc != 0) { 3248bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to claim adb interface for device '" << device_serial << "'" 3258bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << libusb_error_name(rc); 3268bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3278bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3288bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3298bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao for (uint8_t endpoint : {bulk_in, bulk_out}) { 3308bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao rc = libusb_clear_halt(handle.get(), endpoint); 3318bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (rc != 0) { 3328bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to clear halt on device '" << device_serial 3338bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << "' endpoint 0x" << std::hex << endpoint << ": " 334cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes << libusb_error_name(rc); 3358bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao libusb_release_interface(handle.get(), interface_num); 3368bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 3378bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3388bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3398bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } else { 3408bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(WARNING) << "failed to open usb device at " << device_address << ": " 3418bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao << libusb_error_name(rc); 3428bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao writable = false; 343cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes 344cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes#if defined(__linux__) 3458bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // libusb doesn't think we should be messing around with devices we don't have 3468bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // write access to, but Linux at least lets us get the serial number anyway. 3478bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao if (!android::base::ReadFileToString(get_device_serial_path(device), &device_serial)) { 3488bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // We don't actually want to treat an unknown serial as an error because 3498bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // devices aren't able to communicate a serial number in early bringup. 3508bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // http://b/20883914 3518bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial = "unknown"; 3528bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3538bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao device_serial = android::base::Trim(device_serial); 354cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes#else 3558bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // On Mac OS and Windows, we're screwed. But I don't think this situation actually 3568bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao // happens on those OSes. 3578bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao return; 358cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes#endif 3598bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3601c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3618bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao auto result = 3628bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::make_unique<usb_handle>(device_address, device_serial, std::move(handle), 3638bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao interface_num, bulk_in, bulk_out, zero_mask, packet_size); 3648bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao usb_handle* usb_handle_raw = result.get(); 3651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3668bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao { 3678bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 3688bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao usb_handles[device_address] = std::move(result); 3698bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao } 3708bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3718bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), writable); 3728bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3738bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(INFO) << "registered new usb device '" << device_serial << "'"; 3748bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao} 3758bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3768bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gaostatic void poll_for_devices() { 3778bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao libusb_device** list; 3788bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao adb_thread_setname("device poll"); 3798bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao while (!terminate_device_poll_thread) { 3808bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao const ssize_t device_count = libusb_get_device_list(nullptr, &list); 3811c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3828bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao LOG(VERBOSE) << "found " << device_count << " attached devices"; 3831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3848bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao for (ssize_t i = 0; i < device_count; ++i) { 3858bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao process_device(list[i]); 3861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 3878bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao 3881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_free_device_list(list, 1); 3891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 390fd713e53e890f5b3bf26a1c5a980137cc4378c3aJosh Gao adb_notify_device_scan_complete(); 391fd713e53e890f5b3bf26a1c5a980137cc4378c3aJosh Gao 3921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::this_thread::sleep_for(500ms); 3931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 3941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 3951c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaovoid usb_init() { 3971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "initializing libusb..."; 3981c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_init(nullptr); 3991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 4001c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(FATAL) << "failed to initialize libusb: " << libusb_error_name(rc); 4011c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4021c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4031c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Spawn a thread for libusb_handle_events. 4041c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::thread([]() { 4051c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao adb_thread_setname("libusb"); 4061c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao while (true) { 4071c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_handle_events(nullptr); 4081c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4091c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao }).detach(); 4101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4111c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Spawn a thread to do device enumeration. 4121c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // TODO: Use libusb_hotplug_* instead? 4131c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_poll_thread = new std::thread(poll_for_devices); 4141c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao android::base::at_quick_exit([]() { 4151c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao terminate_device_poll_thread = true; 4161c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_poll_thread->join(); 4171c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao }); 4181c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 4191c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4201c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao// Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result. 4211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic int perform_usb_transfer(usb_handle* h, transfer_info* info, 4221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> device_lock) { 4231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_transfer* transfer = info->transfer; 4241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->user_data = info; 4261c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->callback = [](libusb_transfer* transfer) { 4271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info* info = static_cast<transfer_info*>(transfer->user_data); 4281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << info->name << " transfer callback entered"; 4301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Make sure that the original submitter has made it to the condition_variable wait. 4321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(info->mutex); 4331c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << info->name << " callback successfully acquired lock"; 4351c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4361c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { 4371c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << info->name 4381c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << " transfer failed: " << libusb_error_name(transfer->status); 4391c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->Notify(); 4401c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return; 4411c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4421c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 443b5e11415d9fdb929321c66889063dac50fb737afYabin Cui // usb_read() can return when receiving some data. 444b5e11415d9fdb929321c66889063dac50fb737afYabin Cui if (info->is_bulk_out && transfer->actual_length != transfer->length) { 4451c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << info->name << " transfer incomplete, resubmitting"; 4461c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->length -= transfer->actual_length; 4471c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->buffer += transfer->actual_length; 4481c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_submit_transfer(transfer); 4491c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 4501c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to submit " << info->name 4511c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << " transfer: " << libusb_error_name(rc); 4521c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->status = LIBUSB_TRANSFER_ERROR; 4531c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->Notify(); 4541c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return; 4561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4571c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4581c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (should_perform_zero_transfer(transfer->endpoint, transfer->length, info->zero_mask)) { 4591c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "submitting zero-length write"; 4601c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->length = 0; 4611c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_submit_transfer(transfer); 4621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 4631c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to submit zero-length write: " << libusb_error_name(rc); 4641c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->status = LIBUSB_TRANSFER_ERROR; 4651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->Notify(); 4661c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4671c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return; 4681c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4691c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4701c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(VERBOSE) << info->name << "transfer fully complete"; 4711c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->Notify(); 4721c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao }; 4731c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4741c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "locking " << info->name << " transfer_info mutex"; 4751c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(info->mutex); 4761c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer_complete = false; 4771c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "submitting " << info->name << " transfer"; 4781c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_submit_transfer(transfer); 4791c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 4801c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to submit " << info->name << " transfer: " << libusb_error_name(rc); 4811c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 4821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 4831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << info->name << " transfer successfully submitted"; 4861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_lock.unlock(); 4871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->cv.wait(lock, [info]() { return info->transfer_complete; }); 4881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (transfer->status != 0) { 4891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 4901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 4911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return 0; 4941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 4951c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_write(usb_handle* h, const void* d, int len) { 4971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "usb_write of length " << len; 4981c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(h->device_handle_mutex); 5001c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (!h->device_handle) { 5011c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 5021c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 5031c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5041c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5051c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info* info = &h->write; 5061c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->dev_handle = h->device_handle; 5071c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->flags = 0; 5081c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->endpoint = h->bulk_out; 5091c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK; 5101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->length = len; 5111c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->buffer = reinterpret_cast<unsigned char*>(const_cast<void*>(d)); 5121c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->num_iso_packets = 0; 5131c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5141c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = perform_usb_transfer(h, info, std::move(lock)); 5151c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "usb_write(" << len << ") = " << rc; 5161c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return rc; 5171c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 5181c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5191c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_read(usb_handle* h, void* d, int len) { 5201c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "usb_read of length " << len; 5211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(h->device_handle_mutex); 5231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (!h->device_handle) { 5241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 5251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 5261c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info* info = &h->read; 5291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->dev_handle = h->device_handle; 5301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->flags = 0; 5311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->endpoint = h->bulk_in; 5321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK; 5331c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->length = len; 5341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->buffer = reinterpret_cast<unsigned char*>(d); 5351c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->num_iso_packets = 0; 5361c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5371c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = perform_usb_transfer(h, info, std::move(lock)); 538b5e11415d9fdb929321c66889063dac50fb737afYabin Cui LOG(DEBUG) << "usb_read(" << len << ") = " << rc << ", actual_length " 539b5e11415d9fdb929321c66889063dac50fb737afYabin Cui << info->transfer->actual_length; 540b5e11415d9fdb929321c66889063dac50fb737afYabin Cui if (rc < 0) { 541b5e11415d9fdb929321c66889063dac50fb737afYabin Cui return rc; 542b5e11415d9fdb929321c66889063dac50fb737afYabin Cui } 543b5e11415d9fdb929321c66889063dac50fb737afYabin Cui return info->transfer->actual_length; 5441c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 5451c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5461c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_close(usb_handle* h) { 5471c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 5481c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao auto it = usb_handles.find(h->device_address); 5491c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (it == usb_handles.end()) { 5501c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(FATAL) << "attempted to close unregistered usb_handle for '" << h->serial << "'"; 5511c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5521c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao usb_handles.erase(h->device_address); 5531c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return 0; 5541c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 5551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaovoid usb_kick(usb_handle* h) { 5571c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao h->Close(); 5581c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 559ef3d343254405cc360b4df843c6e4a843c335012Josh Gao 560ef3d343254405cc360b4df843c6e4a843c335012Josh Gaosize_t usb_get_max_packet_size(usb_handle* h) { 561ef3d343254405cc360b4df843c6e4a843c335012Josh Gao CHECK(h->max_packet_size != 0); 562ef3d343254405cc360b4df843c6e4a843c335012Josh Gao return h->max_packet_size; 563ef3d343254405cc360b4df843c6e4a843c335012Josh Gao} 564ef3d343254405cc360b4df843c6e4a843c335012Josh Gao 5651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} // namespace libusb 566