Add support for fastboot transport timeouts and USB Reset() on linux
USB Reset() allows simulating unplugging and replugging device. Test: build and run fastboot on mac 10.13.3 Test: glinux build and run fastboot Change-Id: Id924d063e549a4cca9dda03afd8f8fe266f6d2ab
This commit is contained in:
parent
28fb130cbb
commit
acf78d462f
4 changed files with 78 additions and 20 deletions
|
@ -52,6 +52,14 @@ struct usb_ifc_info {
|
|||
char device_path[256];
|
||||
};
|
||||
|
||||
class UsbTransport : public Transport {
|
||||
// Resets the underlying transport. Returns 0 on success.
|
||||
// This effectively simulates unplugging and replugging
|
||||
public:
|
||||
virtual int Reset() = 0;
|
||||
};
|
||||
|
||||
typedef int (*ifc_match_func)(usb_ifc_info *ifc);
|
||||
|
||||
Transport* usb_open(ifc_match_func callback);
|
||||
// 0 is non blocking
|
||||
UsbTransport* usb_open(ifc_match_func callback, uint32_t timeout_ms = 0);
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#define MAX_RETRIES 5
|
||||
#define MAX_RETRIES 2
|
||||
|
||||
/* Timeout in seconds for usb_wait_for_disconnect.
|
||||
* It doesn't usually take long for a device to disconnect (almost always
|
||||
|
@ -91,18 +91,21 @@ struct usb_handle
|
|||
unsigned char ep_out;
|
||||
};
|
||||
|
||||
class LinuxUsbTransport : public Transport {
|
||||
class LinuxUsbTransport : public UsbTransport {
|
||||
public:
|
||||
explicit LinuxUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
|
||||
explicit LinuxUsbTransport(std::unique_ptr<usb_handle> handle, uint32_t ms_timeout = 0)
|
||||
: handle_(std::move(handle)), ms_timeout_(ms_timeout) {}
|
||||
~LinuxUsbTransport() override = default;
|
||||
|
||||
ssize_t Read(void* data, size_t len) override;
|
||||
ssize_t Write(const void* data, size_t len) override;
|
||||
int Close() override;
|
||||
int Reset() override;
|
||||
int WaitForDisconnect() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<usb_handle> handle_;
|
||||
const uint32_t ms_timeout_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LinuxUsbTransport);
|
||||
};
|
||||
|
@ -402,7 +405,7 @@ ssize_t LinuxUsbTransport::Write(const void* _data, size_t len)
|
|||
bulk.ep = handle_->ep_out;
|
||||
bulk.len = xfer;
|
||||
bulk.data = data;
|
||||
bulk.timeout = 0;
|
||||
bulk.timeout = ms_timeout_;
|
||||
|
||||
n = ioctl(handle_->desc, USBDEVFS_BULK, &bulk);
|
||||
if(n != xfer) {
|
||||
|
@ -436,7 +439,7 @@ ssize_t LinuxUsbTransport::Read(void* _data, size_t len)
|
|||
bulk.ep = handle_->ep_in;
|
||||
bulk.len = xfer;
|
||||
bulk.data = data;
|
||||
bulk.timeout = 0;
|
||||
bulk.timeout = ms_timeout_;
|
||||
retry = 0;
|
||||
|
||||
do {
|
||||
|
@ -447,7 +450,7 @@ ssize_t LinuxUsbTransport::Read(void* _data, size_t len)
|
|||
if (n < 0) {
|
||||
DBG1("ERROR: n = %d, errno = %d (%s)\n",n, errno, strerror(errno));
|
||||
if (++retry > MAX_RETRIES) return -1;
|
||||
std::this_thread::sleep_for(1s);
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
} while (n < 0);
|
||||
|
||||
|
@ -477,10 +480,19 @@ int LinuxUsbTransport::Close()
|
|||
return 0;
|
||||
}
|
||||
|
||||
Transport* usb_open(ifc_match_func callback)
|
||||
{
|
||||
int LinuxUsbTransport::Reset() {
|
||||
int ret = 0;
|
||||
// We reset the USB connection
|
||||
if ((ret = ioctl(handle_->desc, USBDEVFS_RESET, 0))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UsbTransport* usb_open(ifc_match_func callback, uint32_t timeout_ms) {
|
||||
std::unique_ptr<usb_handle> handle = find_usb_device("/sys/bus/usb/devices", callback);
|
||||
return handle ? new LinuxUsbTransport(std::move(handle)) : nullptr;
|
||||
return handle ? new LinuxUsbTransport(std::move(handle), timeout_ms) : nullptr;
|
||||
}
|
||||
|
||||
/* Wait for the system to notice the device is gone, so that a subsequent
|
||||
|
|
|
@ -65,17 +65,21 @@ struct usb_handle
|
|||
unsigned int zero_mask;
|
||||
};
|
||||
|
||||
class OsxUsbTransport : public Transport {
|
||||
class OsxUsbTransport : public UsbTransport {
|
||||
public:
|
||||
OsxUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
|
||||
// A timeout of 0 is blocking
|
||||
OsxUsbTransport(std::unique_ptr<usb_handle> handle, uint32_t ms_timeout = 0)
|
||||
: handle_(std::move(handle)), ms_timeout_(ms_timeout) {}
|
||||
~OsxUsbTransport() override = default;
|
||||
|
||||
ssize_t Read(void* data, size_t len) override;
|
||||
ssize_t Write(const void* data, size_t len) override;
|
||||
int Close() override;
|
||||
int Reset() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<usb_handle> handle_;
|
||||
const uint32_t ms_timeout_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(OsxUsbTransport);
|
||||
};
|
||||
|
@ -456,7 +460,7 @@ static int init_usb(ifc_match_func callback, std::unique_ptr<usb_handle>* handle
|
|||
* Definitions of this file's public functions.
|
||||
*/
|
||||
|
||||
Transport* usb_open(ifc_match_func callback) {
|
||||
UsbTransport* usb_open(ifc_match_func callback, uint32_t timeout_ms) {
|
||||
std::unique_ptr<usb_handle> handle;
|
||||
|
||||
if (init_usb(callback, &handle) < 0) {
|
||||
|
@ -464,7 +468,7 @@ Transport* usb_open(ifc_match_func callback) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return new OsxUsbTransport(std::move(handle));
|
||||
return new OsxUsbTransport(std::move(handle), timeout_ms);
|
||||
}
|
||||
|
||||
int OsxUsbTransport::Close() {
|
||||
|
@ -472,6 +476,19 @@ int OsxUsbTransport::Close() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: this SHOULD be easy to do with ResetDevice() from IOUSBDeviceInterface.
|
||||
However to perform operations that manipulate the state of the device, you must
|
||||
claim ownership of the device with USBDeviceOpenSeize(). However, this operation
|
||||
always fails with kIOReturnExclusiveAccess.
|
||||
It seems that the kext com.apple.driver.usb.AppleUSBHostCompositeDevice
|
||||
always loads and claims ownership of the device and refuses to give it up.
|
||||
*/
|
||||
int OsxUsbTransport::Reset() {
|
||||
ERR("USB reset is currently unsupported on osx\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t OsxUsbTransport::Read(void* data, size_t len) {
|
||||
IOReturn result;
|
||||
UInt32 numBytes = len;
|
||||
|
@ -494,7 +511,14 @@ ssize_t OsxUsbTransport::Read(void* data, size_t len) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
result = (*handle_->interface)->ReadPipe(handle_->interface, handle_->bulkIn, data, &numBytes);
|
||||
if (!ms_timeout_) {
|
||||
result = (*handle_->interface)
|
||||
->ReadPipe(handle_->interface, handle_->bulkIn, data, &numBytes);
|
||||
} else {
|
||||
result = (*handle_->interface)
|
||||
->ReadPipeTO(handle_->interface, handle_->bulkIn, data, &numBytes,
|
||||
ms_timeout_, ms_timeout_);
|
||||
}
|
||||
|
||||
if (result == 0) {
|
||||
return (int) numBytes;
|
||||
|
@ -541,8 +565,16 @@ ssize_t OsxUsbTransport::Write(const void* data, size_t len) {
|
|||
int lenToSend = lenRemaining > maxLenToSend
|
||||
? maxLenToSend : lenRemaining;
|
||||
|
||||
result = (*handle_->interface)->WritePipe(
|
||||
handle_->interface, handle_->bulkOut, (void *)data, lenToSend);
|
||||
if (!ms_timeout_) { // blocking
|
||||
result = (*handle_->interface)
|
||||
->WritePipe(handle_->interface, handle_->bulkOut, (void*)data,
|
||||
lenToSend);
|
||||
} else {
|
||||
result = (*handle_->interface)
|
||||
->WritePipeTO(handle_->interface, handle_->bulkOut, (void*)data,
|
||||
lenToSend, ms_timeout_, ms_timeout_);
|
||||
}
|
||||
|
||||
if (result != 0) break;
|
||||
|
||||
lenRemaining -= lenToSend;
|
||||
|
|
|
@ -66,7 +66,7 @@ struct usb_handle {
|
|||
std::string interface_name;
|
||||
};
|
||||
|
||||
class WindowsUsbTransport : public Transport {
|
||||
class WindowsUsbTransport : public UsbTransport {
|
||||
public:
|
||||
WindowsUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
|
||||
~WindowsUsbTransport() override = default;
|
||||
|
@ -74,6 +74,7 @@ class WindowsUsbTransport : public Transport {
|
|||
ssize_t Read(void* data, size_t len) override;
|
||||
ssize_t Write(const void* data, size_t len) override;
|
||||
int Close() override;
|
||||
int Reset() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<usb_handle> handle_;
|
||||
|
@ -261,6 +262,12 @@ int WindowsUsbTransport::Close() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int WindowsUsbTransport::Reset() {
|
||||
DBG("usb_reset currently unsupported\n\n");
|
||||
// TODO, this is a bit complicated since it is using ADB
|
||||
return -1;
|
||||
}
|
||||
|
||||
int recognized_device(usb_handle* handle, ifc_match_func callback) {
|
||||
struct usb_ifc_info info;
|
||||
USB_DEVICE_DESCRIPTOR device_desc;
|
||||
|
@ -366,8 +373,7 @@ static std::unique_ptr<usb_handle> find_usb_device(ifc_match_func callback) {
|
|||
return handle;
|
||||
}
|
||||
|
||||
Transport* usb_open(ifc_match_func callback)
|
||||
{
|
||||
UsbTransport* usb_open(ifc_match_func callback, uint32_t) {
|
||||
std::unique_ptr<usb_handle> handle = find_usb_device(callback);
|
||||
return handle ? new WindowsUsbTransport(std::move(handle)) : nullptr;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue