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