usb_libusb.cpp revision ef3d343254405cc360b4df843c6e4a843c335012
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 1621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic bool endpoint_is_output(uint8_t endpoint) { 1631c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return (endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT; 1641c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 1651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1661c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic bool should_perform_zero_transfer(uint8_t endpoint, size_t write_length, uint16_t zero_mask) { 1671c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return endpoint_is_output(endpoint) && write_length != 0 && zero_mask != 0 && 1681c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao (write_length & zero_mask) == 0; 1691c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 1701c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1711c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic void poll_for_devices() { 1721c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_device** list; 1731c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao adb_thread_setname("device poll"); 1741c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao while (!terminate_device_poll_thread) { 1751c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao const ssize_t device_count = libusb_get_device_list(nullptr, &list); 1761c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1771c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(VERBOSE) << "found " << device_count << " attached devices"; 1781c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1791c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao for (ssize_t i = 0; i < device_count; ++i) { 1801c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_device* device = list[i]; 1811c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::string device_address = get_device_address(device); 1821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::string device_serial; 1831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Figure out if we want to open the device. 1851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_device_descriptor device_desc; 1861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_get_device_descriptor(device, &device_desc); 1871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 1881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to get device descriptor for device at " << device_address 1891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << ": " << libusb_error_name(rc); 1901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 1911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (device_desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) { 1931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Assume that all Android devices have the device class set to per interface. 1941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // TODO: Is this assumption valid? 1951c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(VERBOSE) << "skipping device with incorrect class at " << device_address; 1961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao continue; 1971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 1981c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 1991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_config_descriptor* config_raw; 2001c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao rc = libusb_get_active_config_descriptor(device, &config_raw); 2011c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 2021c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to get active config descriptor for device at " 2031c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << device_address << ": " << libusb_error_name(rc); 2041c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao continue; 2051c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2061c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao const unique_config_descriptor config(config_raw); 2071c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2081c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Use size_t for interface_num so <iostream>s don't mangle it. 2091c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao size_t interface_num; 2101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao uint16_t zero_mask; 2111c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao uint8_t bulk_in = 0, bulk_out = 0; 212ef3d343254405cc360b4df843c6e4a843c335012Josh Gao size_t packet_size = 0; 2131c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao bool found_adb = false; 2141c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2151c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao for (interface_num = 0; interface_num < config->bNumInterfaces; ++interface_num) { 2161c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao const libusb_interface& interface = config->interface[interface_num]; 2171c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (interface.num_altsetting != 1) { 2181c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Assume that interfaces with alternate settings aren't adb interfaces. 2191c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // TODO: Is this assumption valid? 2201c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at " 2211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << device_address << " (interface " << interface_num << ")"; 2221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao continue; 2231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao const libusb_interface_descriptor& interface_desc = interface.altsetting[0]; 2261c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (!is_adb_interface(interface_desc.bInterfaceClass, 2271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao interface_desc.bInterfaceSubClass, 2281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao interface_desc.bInterfaceProtocol)) { 2291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(VERBOSE) << "skipping non-adb interface at " << device_address 2301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << " (interface " << interface_num << ")"; 2311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao continue; 2321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2331c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(VERBOSE) << "found potential adb interface at " << device_address 2351c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << " (interface " << interface_num << ")"; 2361c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2371c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao bool found_in = false; 2381c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao bool found_out = false; 2391c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao for (size_t endpoint_num = 0; endpoint_num < interface_desc.bNumEndpoints; 2401c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao ++endpoint_num) { 2411c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao const auto& endpoint_desc = interface_desc.endpoint[endpoint_num]; 2421c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao const uint8_t endpoint_addr = endpoint_desc.bEndpointAddress; 2431c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao const uint8_t endpoint_attr = endpoint_desc.bmAttributes; 2441c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2451c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK; 2461c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2471c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) { 2481c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao continue; 2491c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2501c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2511c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (endpoint_is_output(endpoint_addr) && !found_out) { 2521c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao found_out = true; 2531c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao bulk_out = endpoint_addr; 2541c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao zero_mask = endpoint_desc.wMaxPacketSize - 1; 2551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } else if (!endpoint_is_output(endpoint_addr) && !found_in) { 2561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao found_in = true; 2571c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao bulk_in = endpoint_addr; 2581c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 259ef3d343254405cc360b4df843c6e4a843c335012Josh Gao 260ef3d343254405cc360b4df843c6e4a843c335012Josh Gao size_t endpoint_packet_size = endpoint_desc.wMaxPacketSize; 261ef3d343254405cc360b4df843c6e4a843c335012Josh Gao CHECK(endpoint_packet_size != 0); 262ef3d343254405cc360b4df843c6e4a843c335012Josh Gao if (packet_size == 0) { 263ef3d343254405cc360b4df843c6e4a843c335012Josh Gao packet_size = endpoint_packet_size; 264ef3d343254405cc360b4df843c6e4a843c335012Josh Gao } else { 265ef3d343254405cc360b4df843c6e4a843c335012Josh Gao CHECK(packet_size == endpoint_packet_size); 266ef3d343254405cc360b4df843c6e4a843c335012Josh Gao } 2671c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2681c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2691c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (found_in && found_out) { 2701c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao found_adb = true; 2711c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao break; 2721c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } else { 2731c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(VERBOSE) << "rejecting potential adb interface at " << device_address 2741c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << "(interface " << interface_num << "): missing bulk endpoints " 2751c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << "(found_in = " << found_in << ", found_out = " << found_out 2761c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << ")"; 2771c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2781c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2791c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2801c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (!found_adb) { 2811c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(VERBOSE) << "skipping device with no adb interfaces at " << device_address; 2821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao continue; 2831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao { 2861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 2871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (usb_handles.find(device_address) != usb_handles.end()) { 2881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(VERBOSE) << "device at " << device_address 2891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << " has already been registered, skipping"; 2901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao continue; 2911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 2931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 2941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_device_handle* handle_raw; 295ef3d343254405cc360b4df843c6e4a843c335012Josh Gao rc = libusb_open(device, &handle_raw); 2961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 2971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to open usb device at " << device_address << ": " 2981c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << libusb_error_name(rc); 2991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao continue; 3001c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 3011c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3021c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao unique_device_handle handle(handle_raw); 3031c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "successfully opened adb device at " << device_address << ", " 3041c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << StringPrintf("bulk_in = %#x, bulk_out = %#x", bulk_in, bulk_out); 3051c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3061c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_serial.resize(255); 3071c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao rc = libusb_get_string_descriptor_ascii( 3081c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao handle_raw, device_desc.iSerialNumber, 3091c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao reinterpret_cast<unsigned char*>(&device_serial[0]), device_serial.length()); 3101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc == 0) { 3111c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "received empty serial from device at " << device_address; 3121c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao continue; 3131c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } else if (rc < 0) { 3141c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to get serial from device at " << device_address 3151c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << libusb_error_name(rc); 3161c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao continue; 3171c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 3181c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_serial.resize(rc); 3191c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3201c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // WARNING: this isn't released via RAII. 3211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao rc = libusb_claim_interface(handle.get(), interface_num); 3221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 3231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to claim adb interface for device '" << device_serial << "'" 3241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << libusb_error_name(rc); 3251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao continue; 3261c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 3271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao for (uint8_t endpoint : {bulk_in, bulk_out}) { 3291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao rc = libusb_clear_halt(handle.get(), endpoint); 3301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 3311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to clear halt on device '" << device_serial 3321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << "' endpoint 0x" << std::hex << endpoint << ": " 3331c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << libusb_error_name(rc); 3341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_release_interface(handle.get(), interface_num); 3351c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao continue; 3361c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 3371c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 3381c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 339ef3d343254405cc360b4df843c6e4a843c335012Josh Gao auto result = std::make_unique<usb_handle>(device_address, device_serial, 340ef3d343254405cc360b4df843c6e4a843c335012Josh Gao std::move(handle), interface_num, bulk_in, 341ef3d343254405cc360b4df843c6e4a843c335012Josh Gao bulk_out, zero_mask, packet_size); 3421c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao usb_handle* usb_handle_raw = result.get(); 3431c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3441c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao { 3451c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 3461c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao usb_handles[device_address] = std::move(result); 3471c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 3481c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3491c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), 1); 3501c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3511c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(INFO) << "registered new usb device '" << device_serial << "'"; 3521c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 3531c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_free_device_list(list, 1); 3541c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::this_thread::sleep_for(500ms); 3561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 3571c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 3581c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3591c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaovoid usb_init() { 3601c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "initializing libusb..."; 3611c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_init(nullptr); 3621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 3631c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(FATAL) << "failed to initialize libusb: " << libusb_error_name(rc); 3641c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 3651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3661c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Spawn a thread for libusb_handle_events. 3671c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::thread([]() { 3681c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao adb_thread_setname("libusb"); 3691c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao while (true) { 3701c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_handle_events(nullptr); 3711c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 3721c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao }).detach(); 3731c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3741c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Spawn a thread to do device enumeration. 3751c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // TODO: Use libusb_hotplug_* instead? 3761c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_poll_thread = new std::thread(poll_for_devices); 3771c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao android::base::at_quick_exit([]() { 3781c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao terminate_device_poll_thread = true; 3791c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_poll_thread->join(); 3801c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao }); 3811c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 3821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao// Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result. 3841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic int perform_usb_transfer(usb_handle* h, transfer_info* info, 3851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> device_lock) { 3861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao libusb_transfer* transfer = info->transfer; 3871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->user_data = info; 3891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->callback = [](libusb_transfer* transfer) { 3901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info* info = static_cast<transfer_info*>(transfer->user_data); 3911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << info->name << " transfer callback entered"; 3931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao // Make sure that the original submitter has made it to the condition_variable wait. 3951c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(info->mutex); 3961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << info->name << " callback successfully acquired lock"; 3981c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 3991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { 4001c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << info->name 4011c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << " transfer failed: " << libusb_error_name(transfer->status); 4021c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->Notify(); 4031c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return; 4041c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4051c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 406b5e11415d9fdb929321c66889063dac50fb737afYabin Cui // usb_read() can return when receiving some data. 407b5e11415d9fdb929321c66889063dac50fb737afYabin Cui if (info->is_bulk_out && transfer->actual_length != transfer->length) { 4081c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << info->name << " transfer incomplete, resubmitting"; 4091c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->length -= transfer->actual_length; 4101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->buffer += transfer->actual_length; 4111c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_submit_transfer(transfer); 4121c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 4131c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to submit " << info->name 4141c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao << " transfer: " << libusb_error_name(rc); 4151c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->status = LIBUSB_TRANSFER_ERROR; 4161c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->Notify(); 4171c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4181c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return; 4191c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4201c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (should_perform_zero_transfer(transfer->endpoint, transfer->length, info->zero_mask)) { 4221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "submitting zero-length write"; 4231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->length = 0; 4241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_submit_transfer(transfer); 4251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 4261c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to submit zero-length write: " << libusb_error_name(rc); 4271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer->status = LIBUSB_TRANSFER_ERROR; 4281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->Notify(); 4291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return; 4311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4331c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(VERBOSE) << info->name << "transfer fully complete"; 4341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->Notify(); 4351c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao }; 4361c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4371c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "locking " << info->name << " transfer_info mutex"; 4381c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(info->mutex); 4391c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer_complete = false; 4401c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "submitting " << info->name << " transfer"; 4411c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = libusb_submit_transfer(transfer); 4421c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (rc != 0) { 4431c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(WARNING) << "failed to submit " << info->name << " transfer: " << libusb_error_name(rc); 4441c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 4451c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 4461c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4471c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4481c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << info->name << " transfer successfully submitted"; 4491c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao device_lock.unlock(); 4501c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->cv.wait(lock, [info]() { return info->transfer_complete; }); 4511c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (transfer->status != 0) { 4521c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 4531c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 4541c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return 0; 4571c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 4581c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4591c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_write(usb_handle* h, const void* d, int len) { 4601c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "usb_write of length " << len; 4611c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(h->device_handle_mutex); 4631c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (!h->device_handle) { 4641c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 4651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 4661c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4671c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4681c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info* info = &h->write; 4691c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->dev_handle = h->device_handle; 4701c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->flags = 0; 4711c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->endpoint = h->bulk_out; 4721c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK; 4731c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->length = len; 4741c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->buffer = reinterpret_cast<unsigned char*>(const_cast<void*>(d)); 4751c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->num_iso_packets = 0; 4761c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4771c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = perform_usb_transfer(h, info, std::move(lock)); 4781c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "usb_write(" << len << ") = " << rc; 4791c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return rc; 4801c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 4811c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_read(usb_handle* h, void* d, int len) { 4831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(DEBUG) << "usb_read of length " << len; 4841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(h->device_handle_mutex); 4861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (!h->device_handle) { 4871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao errno = EIO; 4881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return -1; 4891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 4901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 4911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao transfer_info* info = &h->read; 4921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->dev_handle = h->device_handle; 4931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->flags = 0; 4941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->endpoint = h->bulk_in; 4951c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK; 4961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->length = len; 4971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->buffer = reinterpret_cast<unsigned char*>(d); 4981c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao info->transfer->num_iso_packets = 0; 4991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5001c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao int rc = perform_usb_transfer(h, info, std::move(lock)); 501b5e11415d9fdb929321c66889063dac50fb737afYabin Cui LOG(DEBUG) << "usb_read(" << len << ") = " << rc << ", actual_length " 502b5e11415d9fdb929321c66889063dac50fb737afYabin Cui << info->transfer->actual_length; 503b5e11415d9fdb929321c66889063dac50fb737afYabin Cui if (rc < 0) { 504b5e11415d9fdb929321c66889063dac50fb737afYabin Cui return rc; 505b5e11415d9fdb929321c66889063dac50fb737afYabin Cui } 506b5e11415d9fdb929321c66889063dac50fb737afYabin Cui return info->transfer->actual_length; 5071c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 5081c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5091c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_close(usb_handle* h) { 5101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao std::unique_lock<std::mutex> lock(usb_handles_mutex); 5111c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao auto it = usb_handles.find(h->device_address); 5121c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao if (it == usb_handles.end()) { 5131c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao LOG(FATAL) << "attempted to close unregistered usb_handle for '" << h->serial << "'"; 5141c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao } 5151c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao usb_handles.erase(h->device_address); 5161c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao return 0; 5171c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 5181c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao 5191c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaovoid usb_kick(usb_handle* h) { 5201c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao h->Close(); 5211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} 522ef3d343254405cc360b4df843c6e4a843c335012Josh Gao 523ef3d343254405cc360b4df843c6e4a843c335012Josh Gaosize_t usb_get_max_packet_size(usb_handle* h) { 524ef3d343254405cc360b4df843c6e4a843c335012Josh Gao CHECK(h->max_packet_size != 0); 525ef3d343254405cc360b4df843c6e4a843c335012Josh Gao return h->max_packet_size; 526ef3d343254405cc360b4df843c6e4a843c335012Josh Gao} 527ef3d343254405cc360b4df843c6e4a843c335012Josh Gao 5281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} // namespace libusb 529