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