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>
22d51c6df1ef98f2b57916ddefc80afda5f1eecb59Josh Gao#include <stdlib.h>
231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <atomic>
251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <chrono>
2650ecaca744cbc881f48f5d1bf53c7216a0a1ecacMike Frysinger#include <condition_variable>
271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <memory>
281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <mutex>
291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <string>
301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <thread>
311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <unordered_map>
321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
331c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <libusb/libusb.h>
341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
351c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <android-base/file.h>
361c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <android-base/logging.h>
371c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <android-base/stringprintf.h>
381c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include <android-base/strings.h>
391c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
401c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include "adb.h"
410b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao#include "adb_utils.h"
421c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include "transport.h"
431c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao#include "usb.h"
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
1546da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gaostatic libusb_hotplug_callback_handle hotplug_handle;
1551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
1561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic std::string get_device_address(libusb_device* device) {
1571c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    return StringPrintf("usb:%d:%d", libusb_get_bus_number(device),
1581c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao                        libusb_get_device_address(device));
1591c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}
1601c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
1614acb36020bfa3cb63ed81358754758e76fc5787dElliott Hughes#if defined(__linux__)
162cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughesstatic std::string get_device_serial_path(libusb_device* device) {
163cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes    uint8_t ports[7];
164cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes    int port_count = libusb_get_port_numbers(device, ports, 7);
165cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes    if (port_count < 0) return "";
166cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes
167cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes    std::string path =
168cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes        StringPrintf("/sys/bus/usb/devices/%d-%d", libusb_get_bus_number(device), ports[0]);
169cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes    for (int port = 1; port < port_count; ++port) {
170cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes        path += StringPrintf(".%d", ports[port]);
171cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes    }
172cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes    path += "/serial";
173cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes    return path;
174cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes}
1753f60a968e35b051943249fb9ac70e349323a0590Josh Gao
1763f60a968e35b051943249fb9ac70e349323a0590Josh Gaostatic std::string get_device_dev_path(libusb_device* device) {
1773f60a968e35b051943249fb9ac70e349323a0590Josh Gao    uint8_t ports[7];
1783f60a968e35b051943249fb9ac70e349323a0590Josh Gao    int port_count = libusb_get_port_numbers(device, ports, 7);
1793f60a968e35b051943249fb9ac70e349323a0590Josh Gao    if (port_count < 0) return "";
1803f60a968e35b051943249fb9ac70e349323a0590Josh Gao    return StringPrintf("/dev/bus/usb/%03u/%03u", libusb_get_bus_number(device), ports[0]);
1813f60a968e35b051943249fb9ac70e349323a0590Josh Gao}
1824acb36020bfa3cb63ed81358754758e76fc5787dElliott Hughes#endif
183cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes
1841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic bool endpoint_is_output(uint8_t endpoint) {
1851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    return (endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT;
1861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}
1871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
1881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaostatic bool should_perform_zero_transfer(uint8_t endpoint, size_t write_length, uint16_t zero_mask) {
1891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    return endpoint_is_output(endpoint) && write_length != 0 && zero_mask != 0 &&
1901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao           (write_length & zero_mask) == 0;
1911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}
1921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
1938bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gaostatic void process_device(libusb_device* device) {
1948bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    std::string device_address = get_device_address(device);
1958bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    std::string device_serial;
1961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
1978bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    // Figure out if we want to open the device.
1988bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    libusb_device_descriptor device_desc;
1998bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    int rc = libusb_get_device_descriptor(device, &device_desc);
2008bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    if (rc != 0) {
2018bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        LOG(WARNING) << "failed to get device descriptor for device at " << device_address << ": "
2028bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                     << libusb_error_name(rc);
2038bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        return;
2048bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    }
2051c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
2068bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    if (device_desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) {
2078bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        // Assume that all Android devices have the device class set to per interface.
2088bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        // TODO: Is this assumption valid?
2098bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        LOG(VERBOSE) << "skipping device with incorrect class at " << device_address;
2108bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        return;
2118bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    }
2121c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
2138bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    libusb_config_descriptor* config_raw;
2148bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    rc = libusb_get_active_config_descriptor(device, &config_raw);
2158bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    if (rc != 0) {
2168bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        LOG(WARNING) << "failed to get active config descriptor for device at " << device_address
2178bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                     << ": " << libusb_error_name(rc);
2188bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        return;
2198bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    }
2208bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    const unique_config_descriptor config(config_raw);
2211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
2228bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    // Use size_t for interface_num so <iostream>s don't mangle it.
2238bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    size_t interface_num;
2249425996b4521eae0571b4af30056c44bb0482598Josh Gao    uint16_t zero_mask = 0;
2258bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    uint8_t bulk_in = 0, bulk_out = 0;
2268bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    size_t packet_size = 0;
2278bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    bool found_adb = false;
2288bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
2298bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    for (interface_num = 0; interface_num < config->bNumInterfaces; ++interface_num) {
2308bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        const libusb_interface& interface = config->interface[interface_num];
2318bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        if (interface.num_altsetting != 1) {
2328bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            // Assume that interfaces with alternate settings aren't adb interfaces.
2338bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            // TODO: Is this assumption valid?
2348bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at " << device_address
2358bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                         << " (interface " << interface_num << ")";
236425aefdcf0f1b2068f56ca091047af5f02ae3f3dJosh Gao            continue;
2378bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        }
2381c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
2398bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        const libusb_interface_descriptor& interface_desc = interface.altsetting[0];
2408bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        if (!is_adb_interface(interface_desc.bInterfaceClass, interface_desc.bInterfaceSubClass,
2418bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                              interface_desc.bInterfaceProtocol)) {
2428bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            LOG(VERBOSE) << "skipping non-adb interface at " << device_address << " (interface "
2438bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                         << interface_num << ")";
244425aefdcf0f1b2068f56ca091047af5f02ae3f3dJosh Gao            continue;
2458bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        }
2468bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
2478bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        LOG(VERBOSE) << "found potential adb interface at " << device_address << " (interface "
2488bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                     << interface_num << ")";
2498bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
2508bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        bool found_in = false;
2518bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        bool found_out = false;
2528bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        for (size_t endpoint_num = 0; endpoint_num < interface_desc.bNumEndpoints; ++endpoint_num) {
2538bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            const auto& endpoint_desc = interface_desc.endpoint[endpoint_num];
2548bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            const uint8_t endpoint_addr = endpoint_desc.bEndpointAddress;
2558bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            const uint8_t endpoint_attr = endpoint_desc.bmAttributes;
2561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
2578bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK;
2588bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
2598bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) {
260425aefdcf0f1b2068f56ca091047af5f02ae3f3dJosh Gao                continue;
2611c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao            }
2621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
2638bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            if (endpoint_is_output(endpoint_addr) && !found_out) {
2648bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                found_out = true;
2658bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                bulk_out = endpoint_addr;
2668bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                zero_mask = endpoint_desc.wMaxPacketSize - 1;
2678bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            } else if (!endpoint_is_output(endpoint_addr) && !found_in) {
2688bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                found_in = true;
2698bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                bulk_in = endpoint_addr;
2701c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao            }
2711c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
2728bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            size_t endpoint_packet_size = endpoint_desc.wMaxPacketSize;
2738bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            CHECK(endpoint_packet_size != 0);
2748bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            if (packet_size == 0) {
2758bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                packet_size = endpoint_packet_size;
276cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes            } else {
2778bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                CHECK(packet_size == endpoint_packet_size);
2788bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            }
2798bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        }
2808bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
2818bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        if (found_in && found_out) {
2828bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            found_adb = true;
2838bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            break;
2848bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        } else {
2858bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            LOG(VERBOSE) << "rejecting potential adb interface at " << device_address
2868bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                         << "(interface " << interface_num << "): missing bulk endpoints "
2878bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                         << "(found_in = " << found_in << ", found_out = " << found_out << ")";
2888bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        }
2898bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    }
2908bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
2918bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    if (!found_adb) {
2928bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        LOG(VERBOSE) << "skipping device with no adb interfaces at " << device_address;
2938bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        return;
2948bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    }
2958bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
2968bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    {
2978bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        std::unique_lock<std::mutex> lock(usb_handles_mutex);
2988bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        if (usb_handles.find(device_address) != usb_handles.end()) {
2998bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            LOG(VERBOSE) << "device at " << device_address
3008bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                         << " has already been registered, skipping";
3018bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            return;
3028bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        }
3038bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    }
3048bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
3058bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    bool writable = true;
3068bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    libusb_device_handle* handle_raw = nullptr;
3078bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    rc = libusb_open(device, &handle_raw);
3088bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    unique_device_handle handle(handle_raw);
3098bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    if (rc == 0) {
3108bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        LOG(DEBUG) << "successfully opened adb device at " << device_address << ", "
3118bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                   << StringPrintf("bulk_in = %#x, bulk_out = %#x", bulk_in, bulk_out);
3128bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
3138bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        device_serial.resize(255);
3148bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        rc = libusb_get_string_descriptor_ascii(handle_raw, device_desc.iSerialNumber,
3158bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                                                reinterpret_cast<unsigned char*>(&device_serial[0]),
3168bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                                                device_serial.length());
3178bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        if (rc == 0) {
3188bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            LOG(WARNING) << "received empty serial from device at " << device_address;
3198bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            return;
3208bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        } else if (rc < 0) {
3218bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            LOG(WARNING) << "failed to get serial from device at " << device_address
3228bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                         << libusb_error_name(rc);
3238bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            return;
3248bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        }
3258bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        device_serial.resize(rc);
3268bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
3278bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        // WARNING: this isn't released via RAII.
3288bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        rc = libusb_claim_interface(handle.get(), interface_num);
3298bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        if (rc != 0) {
3308bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            LOG(WARNING) << "failed to claim adb interface for device '" << device_serial << "'"
3318bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                         << libusb_error_name(rc);
3328bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            return;
3338bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        }
3348bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
3354b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao        rc = libusb_set_interface_alt_setting(handle.get(), interface_num, 0);
3364b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao        if (rc != 0) {
3374b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao            LOG(WARNING) << "failed to set interface alt setting for device '" << device_serial
3384b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao                         << "'" << libusb_error_name(rc);
3394b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao            return;
3404b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao        }
3414b5d4da6f6a863638c8100cde5af834a83ac8956Josh Gao
3428bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        for (uint8_t endpoint : {bulk_in, bulk_out}) {
3438bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            rc = libusb_clear_halt(handle.get(), endpoint);
3448bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            if (rc != 0) {
3458bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                LOG(WARNING) << "failed to clear halt on device '" << device_serial
3468bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                             << "' endpoint 0x" << std::hex << endpoint << ": "
347cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes                             << libusb_error_name(rc);
3488bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                libusb_release_interface(handle.get(), interface_num);
3498bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                return;
3508bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            }
3518bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        }
3528bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    } else {
3538bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        LOG(WARNING) << "failed to open usb device at " << device_address << ": "
3548bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao                     << libusb_error_name(rc);
3558bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        writable = false;
356cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes
357cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes#if defined(__linux__)
3588bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        // libusb doesn't think we should be messing around with devices we don't have
3598bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        // write access to, but Linux at least lets us get the serial number anyway.
3608bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        if (!android::base::ReadFileToString(get_device_serial_path(device), &device_serial)) {
3618bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            // We don't actually want to treat an unknown serial as an error because
3628bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            // devices aren't able to communicate a serial number in early bringup.
3638bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            // http://b/20883914
3648bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao            device_serial = "unknown";
3658bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        }
3668bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        device_serial = android::base::Trim(device_serial);
367cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes#else
3688bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        // On Mac OS and Windows, we're screwed. But I don't think this situation actually
3698bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        // happens on those OSes.
3708bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        return;
371cd35664cdc5097bf38fa2f12aa310855b3c123afElliott Hughes#endif
3728bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    }
3731c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
3749425996b4521eae0571b4af30056c44bb0482598Josh Gao    std::unique_ptr<usb_handle> result(new usb_handle(device_address, device_serial,
3759425996b4521eae0571b4af30056c44bb0482598Josh Gao                                                      std::move(handle), interface_num, bulk_in,
3769425996b4521eae0571b4af30056c44bb0482598Josh Gao                                                      bulk_out, zero_mask, packet_size));
3778bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    usb_handle* usb_handle_raw = result.get();
3781c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
3798bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    {
3808bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        std::unique_lock<std::mutex> lock(usb_handles_mutex);
3818bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao        usb_handles[device_address] = std::move(result);
3828bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
3837dd382ded948aa5adae3618f99d00c14c3703d05Josh Gao        register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(),
3847dd382ded948aa5adae3618f99d00c14c3703d05Josh Gao                               writable);
3857dd382ded948aa5adae3618f99d00c14c3703d05Josh Gao    }
3868bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao    LOG(INFO) << "registered new usb device '" << device_serial << "'";
3878bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao}
3888bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
3893f60a968e35b051943249fb9ac70e349323a0590Josh Gaostatic std::atomic<int> connecting_devices(0);
3903f60a968e35b051943249fb9ac70e349323a0590Josh Gao
3913f60a968e35b051943249fb9ac70e349323a0590Josh Gaostatic void device_connected(libusb_device* device) {
3923f60a968e35b051943249fb9ac70e349323a0590Josh Gao#if defined(__linux__)
3933f60a968e35b051943249fb9ac70e349323a0590Josh Gao    // Android's host linux libusb uses netlink instead of udev for device hotplug notification,
3945b8b10e078ef12f21144cdb5fbc932dda47be212Josh Gao    // which means we can get hotplug notifications before udev has updated ownership/perms on the
3955b8b10e078ef12f21144cdb5fbc932dda47be212Josh Gao    // device. Since we're not going to be able to link against the system's libudev any time soon,
3965b8b10e078ef12f21144cdb5fbc932dda47be212Josh Gao    // hack around this by inserting a sleep.
3973f60a968e35b051943249fb9ac70e349323a0590Josh Gao    auto thread = std::thread([device]() {
3983f60a968e35b051943249fb9ac70e349323a0590Josh Gao        std::string device_path = get_device_dev_path(device);
3999425996b4521eae0571b4af30056c44bb0482598Josh Gao        std::this_thread::sleep_for(std::chrono::seconds(1));
4003f60a968e35b051943249fb9ac70e349323a0590Josh Gao
4013f60a968e35b051943249fb9ac70e349323a0590Josh Gao        process_device(device);
4020b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao        if (--connecting_devices == 0) {
4030b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao            adb_notify_device_scan_complete();
4040b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao        }
4053f60a968e35b051943249fb9ac70e349323a0590Josh Gao    });
4063f60a968e35b051943249fb9ac70e349323a0590Josh Gao    thread.detach();
4073f60a968e35b051943249fb9ac70e349323a0590Josh Gao#else
4083f60a968e35b051943249fb9ac70e349323a0590Josh Gao    process_device(device);
4093f60a968e35b051943249fb9ac70e349323a0590Josh Gao#endif
4103f60a968e35b051943249fb9ac70e349323a0590Josh Gao}
4113f60a968e35b051943249fb9ac70e349323a0590Josh Gao
4123f60a968e35b051943249fb9ac70e349323a0590Josh Gaostatic void device_disconnected(libusb_device* device) {
4136da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao    std::string device_address = get_device_address(device);
4141c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
4156da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao    LOG(INFO) << "device disconnected: " << device_address;
4166da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao    std::unique_lock<std::mutex> lock(usb_handles_mutex);
4176da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao    auto it = usb_handles.find(device_address);
4186da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao    if (it != usb_handles.end()) {
4196da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao        if (!it->second->device_handle) {
4206da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao            // If the handle is null, we were never able to open the device.
421e48ecce671a2ab6647cc26a3cb11163aec0b712cJosh Gao
422e48ecce671a2ab6647cc26a3cb11163aec0b712cJosh Gao            // Temporarily release the usb handles mutex to avoid deadlock.
423e48ecce671a2ab6647cc26a3cb11163aec0b712cJosh Gao            std::unique_ptr<usb_handle> handle = std::move(it->second);
42460b8c26520922f296a36efb17b8914b6f1e115eaJosh Gao            usb_handles.erase(it);
425e48ecce671a2ab6647cc26a3cb11163aec0b712cJosh Gao            lock.unlock();
426e48ecce671a2ab6647cc26a3cb11163aec0b712cJosh Gao            unregister_usb_transport(handle.get());
427e48ecce671a2ab6647cc26a3cb11163aec0b712cJosh Gao            lock.lock();
42860b8c26520922f296a36efb17b8914b6f1e115eaJosh Gao        } else {
42960b8c26520922f296a36efb17b8914b6f1e115eaJosh Gao            // Closure of the transport will erase the usb_handle.
4301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        }
4316da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao    }
4326da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao}
4338bf37d7a4d0b8e05a5fe6500c2e3c13eef2a99e7Josh Gao
4340b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gaostatic auto& hotplug_queue = *new BlockingQueue<std::pair<libusb_hotplug_event, libusb_device*>>();
4350b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gaostatic void hotplug_thread() {
4360b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao    adb_thread_setname("libusb hotplug");
4370b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao    while (true) {
4380b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao        hotplug_queue.PopAll([](std::pair<libusb_hotplug_event, libusb_device*> pair) {
4390b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao            libusb_hotplug_event event = pair.first;
4400b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao            libusb_device* device = pair.second;
4410b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao            if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
4420b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao                device_connected(device);
4430b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao            } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) {
4440b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao                device_disconnected(device);
4450b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao            }
4460b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao        });
4470b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao    }
4480b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao}
4490b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao
4509425996b4521eae0571b4af30056c44bb0482598Josh Gaostatic LIBUSB_CALL int hotplug_callback(libusb_context*, libusb_device* device,
4519425996b4521eae0571b4af30056c44bb0482598Josh Gao                                        libusb_hotplug_event event, void*) {
4520b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao    // We're called with the libusb lock taken. Call these on a separate thread outside of this
453d1a3e8f1ab653831a3cc4c2a90fb0f8b7a2a95acJosh Gao    // function so that the usb_handle mutex is always taken before the libusb mutex.
4540b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao    static std::once_flag once;
4550b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao    std::call_once(once, []() { std::thread(hotplug_thread).detach(); });
4560b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao
4570b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao    if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
4580b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao        ++connecting_devices;
4590b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao    }
4600b13c89f7a4df0c3105ca2aa4d9406ae4964fd8bJosh Gao    hotplug_queue.Push({event, device});
4616da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao    return 0;
4621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}
4631c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
4641c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaovoid usb_init() {
4651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    LOG(DEBUG) << "initializing libusb...";
4661c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    int rc = libusb_init(nullptr);
4671c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    if (rc != 0) {
4681c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        LOG(FATAL) << "failed to initialize libusb: " << libusb_error_name(rc);
4691c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    }
4701c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
4716da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao    // Register the hotplug callback.
4726da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao    rc = libusb_hotplug_register_callback(
4736da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao        nullptr, static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
4746da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao                                                   LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
4756da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao        LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
4766da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao        LIBUSB_CLASS_PER_INTERFACE, hotplug_callback, nullptr, &hotplug_handle);
4776da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao
4786da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao    if (rc != LIBUSB_SUCCESS) {
4796da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao        LOG(FATAL) << "failed to register libusb hotplug callback";
4806da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao    }
4816da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao
4821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    // Spawn a thread for libusb_handle_events.
4831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    std::thread([]() {
4841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        adb_thread_setname("libusb");
4851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        while (true) {
4861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao            libusb_handle_events(nullptr);
4871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        }
4881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    }).detach();
48901b7bc43e90b951675cabe88313b96f57b2da712Josh Gao}
49001b7bc43e90b951675cabe88313b96f57b2da712Josh Gao
49101b7bc43e90b951675cabe88313b96f57b2da712Josh Gaovoid usb_cleanup() {
4926da1cd49b5eaeabb3febe584845de6bb3ae45873Josh Gao    libusb_hotplug_deregister_callback(nullptr, hotplug_handle);
4931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}
4941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
4959425996b4521eae0571b4af30056c44bb0482598Josh Gaostatic LIBUSB_CALL void transfer_callback(libusb_transfer* transfer) {
4969425996b4521eae0571b4af30056c44bb0482598Josh Gao    transfer_info* info = static_cast<transfer_info*>(transfer->user_data);
4971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
4989425996b4521eae0571b4af30056c44bb0482598Josh Gao    LOG(DEBUG) << info->name << " transfer callback entered";
4991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5009425996b4521eae0571b4af30056c44bb0482598Josh Gao    // Make sure that the original submitter has made it to the condition_variable wait.
5019425996b4521eae0571b4af30056c44bb0482598Josh Gao    std::unique_lock<std::mutex> lock(info->mutex);
5021c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5039425996b4521eae0571b4af30056c44bb0482598Josh Gao    LOG(DEBUG) << info->name << " callback successfully acquired lock";
5041c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5059425996b4521eae0571b4af30056c44bb0482598Josh Gao    if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
5069425996b4521eae0571b4af30056c44bb0482598Josh Gao        LOG(WARNING) << info->name << " transfer failed: " << libusb_error_name(transfer->status);
5079425996b4521eae0571b4af30056c44bb0482598Josh Gao        info->Notify();
5089425996b4521eae0571b4af30056c44bb0482598Josh Gao        return;
5099425996b4521eae0571b4af30056c44bb0482598Josh Gao    }
5101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5119425996b4521eae0571b4af30056c44bb0482598Josh Gao    // usb_read() can return when receiving some data.
5129425996b4521eae0571b4af30056c44bb0482598Josh Gao    if (info->is_bulk_out && transfer->actual_length != transfer->length) {
5139425996b4521eae0571b4af30056c44bb0482598Josh Gao        LOG(DEBUG) << info->name << " transfer incomplete, resubmitting";
5149425996b4521eae0571b4af30056c44bb0482598Josh Gao        transfer->length -= transfer->actual_length;
5159425996b4521eae0571b4af30056c44bb0482598Josh Gao        transfer->buffer += transfer->actual_length;
5169425996b4521eae0571b4af30056c44bb0482598Josh Gao        int rc = libusb_submit_transfer(transfer);
5179425996b4521eae0571b4af30056c44bb0482598Josh Gao        if (rc != 0) {
5189425996b4521eae0571b4af30056c44bb0482598Josh Gao            LOG(WARNING) << "failed to submit " << info->name
5199425996b4521eae0571b4af30056c44bb0482598Josh Gao                         << " transfer: " << libusb_error_name(rc);
5209425996b4521eae0571b4af30056c44bb0482598Josh Gao            transfer->status = LIBUSB_TRANSFER_ERROR;
5211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao            info->Notify();
5221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        }
5239425996b4521eae0571b4af30056c44bb0482598Josh Gao        return;
5249425996b4521eae0571b4af30056c44bb0482598Josh Gao    }
5251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5269425996b4521eae0571b4af30056c44bb0482598Josh Gao    if (should_perform_zero_transfer(transfer->endpoint, transfer->length, info->zero_mask)) {
5279425996b4521eae0571b4af30056c44bb0482598Josh Gao        LOG(DEBUG) << "submitting zero-length write";
5289425996b4521eae0571b4af30056c44bb0482598Josh Gao        transfer->length = 0;
5299425996b4521eae0571b4af30056c44bb0482598Josh Gao        int rc = libusb_submit_transfer(transfer);
5309425996b4521eae0571b4af30056c44bb0482598Josh Gao        if (rc != 0) {
5319425996b4521eae0571b4af30056c44bb0482598Josh Gao            LOG(WARNING) << "failed to submit zero-length write: " << libusb_error_name(rc);
5329425996b4521eae0571b4af30056c44bb0482598Josh Gao            transfer->status = LIBUSB_TRANSFER_ERROR;
5339425996b4521eae0571b4af30056c44bb0482598Josh Gao            info->Notify();
5341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        }
5359425996b4521eae0571b4af30056c44bb0482598Josh Gao        return;
5369425996b4521eae0571b4af30056c44bb0482598Josh Gao    }
5371c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5389425996b4521eae0571b4af30056c44bb0482598Josh Gao    LOG(VERBOSE) << info->name << "transfer fully complete";
5399425996b4521eae0571b4af30056c44bb0482598Josh Gao    info->Notify();
5409425996b4521eae0571b4af30056c44bb0482598Josh Gao}
5411c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5429425996b4521eae0571b4af30056c44bb0482598Josh Gao// Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result.
5439425996b4521eae0571b4af30056c44bb0482598Josh Gaostatic int perform_usb_transfer(usb_handle* h, transfer_info* info,
5449425996b4521eae0571b4af30056c44bb0482598Josh Gao                                std::unique_lock<std::mutex> device_lock) {
5459425996b4521eae0571b4af30056c44bb0482598Josh Gao    libusb_transfer* transfer = info->transfer;
5469425996b4521eae0571b4af30056c44bb0482598Josh Gao
5479425996b4521eae0571b4af30056c44bb0482598Josh Gao    transfer->user_data = info;
5489425996b4521eae0571b4af30056c44bb0482598Josh Gao    transfer->callback = transfer_callback;
5491c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5501c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    LOG(DEBUG) << "locking " << info->name << " transfer_info mutex";
5511c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    std::unique_lock<std::mutex> lock(info->mutex);
5521c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer_complete = false;
5531c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    LOG(DEBUG) << "submitting " << info->name << " transfer";
5541c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    int rc = libusb_submit_transfer(transfer);
5551c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    if (rc != 0) {
5561c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        LOG(WARNING) << "failed to submit " << info->name << " transfer: " << libusb_error_name(rc);
5571c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        errno = EIO;
5581c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        return -1;
5591c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    }
5601c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5611c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    LOG(DEBUG) << info->name << " transfer successfully submitted";
5621c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    device_lock.unlock();
5631c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->cv.wait(lock, [info]() { return info->transfer_complete; });
5641c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    if (transfer->status != 0) {
5651c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        errno = EIO;
5661c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        return -1;
5671c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    }
5681c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5691c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    return 0;
5701c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}
5711c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5721c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_write(usb_handle* h, const void* d, int len) {
5731c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    LOG(DEBUG) << "usb_write of length " << len;
5741c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5751c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    std::unique_lock<std::mutex> lock(h->device_handle_mutex);
5761c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    if (!h->device_handle) {
5771c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        errno = EIO;
5781c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        return -1;
5791c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    }
5801c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5811c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    transfer_info* info = &h->write;
5821c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->dev_handle = h->device_handle;
5831c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->flags = 0;
5841c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->endpoint = h->bulk_out;
5851c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
5861c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->length = len;
5871c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->buffer = reinterpret_cast<unsigned char*>(const_cast<void*>(d));
5881c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->num_iso_packets = 0;
5891c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5901c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    int rc = perform_usb_transfer(h, info, std::move(lock));
5911c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    LOG(DEBUG) << "usb_write(" << len << ") = " << rc;
5921c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    return rc;
5931c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}
5941c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5951c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_read(usb_handle* h, void* d, int len) {
5961c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    LOG(DEBUG) << "usb_read of length " << len;
5971c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
5981c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    std::unique_lock<std::mutex> lock(h->device_handle_mutex);
5991c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    if (!h->device_handle) {
6001c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        errno = EIO;
6011c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        return -1;
6021c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    }
6031c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
6041c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    transfer_info* info = &h->read;
6051c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->dev_handle = h->device_handle;
6061c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->flags = 0;
6071c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->endpoint = h->bulk_in;
6081c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
6091c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->length = len;
6101c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->buffer = reinterpret_cast<unsigned char*>(d);
6111c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    info->transfer->num_iso_packets = 0;
6121c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
6131c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    int rc = perform_usb_transfer(h, info, std::move(lock));
614b5e11415d9fdb929321c66889063dac50fb737afYabin Cui    LOG(DEBUG) << "usb_read(" << len << ") = " << rc << ", actual_length "
615b5e11415d9fdb929321c66889063dac50fb737afYabin Cui               << info->transfer->actual_length;
616b5e11415d9fdb929321c66889063dac50fb737afYabin Cui    if (rc < 0) {
617b5e11415d9fdb929321c66889063dac50fb737afYabin Cui        return rc;
618b5e11415d9fdb929321c66889063dac50fb737afYabin Cui    }
619b5e11415d9fdb929321c66889063dac50fb737afYabin Cui    return info->transfer->actual_length;
6201c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}
6211c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
6221c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaoint usb_close(usb_handle* h) {
6231c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    std::unique_lock<std::mutex> lock(usb_handles_mutex);
6241c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    auto it = usb_handles.find(h->device_address);
6251c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    if (it == usb_handles.end()) {
6261c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao        LOG(FATAL) << "attempted to close unregistered usb_handle for '" << h->serial << "'";
6271c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    }
6281c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    usb_handles.erase(h->device_address);
6291c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    return 0;
6301c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}
6311c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao
6321c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gaovoid usb_kick(usb_handle* h) {
6331c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao    h->Close();
6341c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao}
635ef3d343254405cc360b4df843c6e4a843c335012Josh Gao
636ef3d343254405cc360b4df843c6e4a843c335012Josh Gaosize_t usb_get_max_packet_size(usb_handle* h) {
637ef3d343254405cc360b4df843c6e4a843c335012Josh Gao    CHECK(h->max_packet_size != 0);
638ef3d343254405cc360b4df843c6e4a843c335012Josh Gao    return h->max_packet_size;
639ef3d343254405cc360b4df843c6e4a843c335012Josh Gao}
640ef3d343254405cc360b4df843c6e4a843c335012Josh Gao
6411c70e1bcbcced190b351d4fb418f32b4e428f496Josh Gao} // namespace libusb
642