260 lines
8.0 KiB
Diff
260 lines
8.0 KiB
Diff
diff --git a/vendor/core/fastboot/usb_linux.cpp b/vendor/core/fastboot/usb_linux.cpp
|
|
index 964488c..995a219 100644
|
|
--- a/vendor/core/fastboot/usb_linux.cpp
|
|
+++ b/vendor/core/fastboot/usb_linux.cpp
|
|
@@ -48,6 +48,9 @@
|
|
#include <chrono>
|
|
#include <memory>
|
|
#include <thread>
|
|
+#ifdef __ANDROID__
|
|
+#include <libusb-1.0/libusb.h>
|
|
+#endif
|
|
|
|
#include "usb.h"
|
|
#include "util.h"
|
|
@@ -88,11 +91,29 @@ using namespace std::chrono_literals;
|
|
struct usb_handle
|
|
{
|
|
char fname[64];
|
|
+#ifdef __ANDROID__
|
|
+ bool is_termux_usb;
|
|
+#endif
|
|
int desc;
|
|
unsigned char ep_in;
|
|
unsigned char ep_out;
|
|
};
|
|
|
|
+#ifdef __ANDROID__
|
|
+struct context {
|
|
+ libusb_context *libusb_ctx;
|
|
+
|
|
+ context() {
|
|
+ libusb_set_option(NULL, LIBUSB_OPTION_WEAK_AUTHORITY);
|
|
+ libusb_init(&libusb_ctx);
|
|
+ }
|
|
+
|
|
+ ~context() {
|
|
+ libusb_exit(libusb_ctx);
|
|
+ }
|
|
+} ctx;
|
|
+#endif
|
|
+
|
|
class LinuxUsbTransport : public UsbTransport {
|
|
public:
|
|
explicit LinuxUsbTransport(std::unique_ptr<usb_handle> handle, uint32_t ms_timeout = 0)
|
|
@@ -104,6 +125,9 @@ class LinuxUsbTransport : public UsbTransport {
|
|
int Close() override;
|
|
int Reset() override;
|
|
int WaitForDisconnect() override;
|
|
+#ifdef __ANDROID__
|
|
+ bool NotReusable() override;
|
|
+#endif
|
|
|
|
private:
|
|
std::unique_ptr<usb_handle> handle_;
|
|
@@ -140,7 +164,18 @@ static int check(void *_desc, int len, unsigned type, int size)
|
|
return 0;
|
|
}
|
|
|
|
+#ifdef __ANDROID__
|
|
+bool ref_deleted(int fd) {
|
|
+ struct stat fd_stat;
|
|
+ fstat(fd, &fd_stat);
|
|
+ return fd_stat.st_nlink < 1;
|
|
+}
|
|
+#endif
|
|
+
|
|
static int filter_usb_device(char* sysfs_name,
|
|
+#ifdef __ANDROID__
|
|
+ bool is_termux_usb, int termux_usb_fd,
|
|
+#endif
|
|
char *ptr, int len, int writable,
|
|
ifc_match_func callback,
|
|
int *ept_in_id, int *ept_out_id, int *ifc_id)
|
|
@@ -149,6 +184,9 @@ static int filter_usb_device(char* sysfs_name,
|
|
struct usb_config_descriptor *cfg;
|
|
struct usb_interface_descriptor *ifc;
|
|
struct usb_endpoint_descriptor *ept;
|
|
+#ifdef __ANDROID__
|
|
+ libusb_device_handle *libusb_handle;
|
|
+#endif
|
|
struct usb_ifc_info info;
|
|
|
|
int in, out;
|
|
@@ -167,6 +205,11 @@ static int filter_usb_device(char* sysfs_name,
|
|
len -= cfg->bLength;
|
|
ptr += cfg->bLength;
|
|
|
|
+#ifdef __ANDROID__
|
|
+ if (is_termux_usb)
|
|
+ libusb_wrap_sys_device(ctx.libusb_ctx, termux_usb_fd, &libusb_handle);
|
|
+#endif
|
|
+
|
|
info.dev_vendor = dev->idVendor;
|
|
info.dev_product = dev->idProduct;
|
|
info.dev_class = dev->bDeviceClass;
|
|
@@ -174,6 +217,12 @@ static int filter_usb_device(char* sysfs_name,
|
|
info.dev_protocol = dev->bDeviceProtocol;
|
|
info.writable = writable;
|
|
|
|
+#ifdef __ANDROID__
|
|
+ if (is_termux_usb)
|
|
+ snprintf(info.device_path, sizeof(info.device_path),
|
|
+ "fd:%d", termux_usb_fd);
|
|
+ else
|
|
+#endif
|
|
snprintf(info.device_path, sizeof(info.device_path), "usb:%s", sysfs_name);
|
|
|
|
/* Read device serial number (if there is one).
|
|
@@ -184,6 +233,15 @@ static int filter_usb_device(char* sysfs_name,
|
|
*/
|
|
info.serial_number[0] = '\0';
|
|
if (dev->iSerialNumber) {
|
|
+#ifdef __ANDROID__
|
|
+ if (is_termux_usb) {
|
|
+ unsigned char serial_num[256];
|
|
+ libusb_get_string_descriptor_ascii(libusb_handle, dev->iSerialNumber,
|
|
+ serial_num, sizeof(serial_num));
|
|
+ snprintf(info.serial_number, sizeof(info.serial_number),
|
|
+ "%s", serial_num);
|
|
+ } else {
|
|
+#endif
|
|
char path[80];
|
|
int fd;
|
|
|
|
@@ -204,6 +262,9 @@ static int filter_usb_device(char* sysfs_name,
|
|
info.serial_number[chars_read - 1] = '\0';
|
|
}
|
|
}
|
|
+#ifdef __ANDROID__
|
|
+ }
|
|
+#endif
|
|
}
|
|
|
|
for(i = 0; i < cfg->bNumInterfaces; i++) {
|
|
@@ -265,12 +326,25 @@ static int filter_usb_device(char* sysfs_name,
|
|
info.has_bulk_in = (in != -1);
|
|
info.has_bulk_out = (out != -1);
|
|
|
|
+#ifdef __ANDROID__
|
|
+ if (is_termux_usb) {
|
|
+ if (ifc->iInterface) {
|
|
+ unsigned char interface_name[256];
|
|
+ libusb_get_string_descriptor_ascii(libusb_handle, ifc->iInterface,
|
|
+ interface_name, sizeof(interface_name));
|
|
+ snprintf(info.interface, sizeof(interface_name), "%s\n", interface_name);
|
|
+ }
|
|
+ } else {
|
|
+#endif
|
|
std::string interface;
|
|
auto path = android::base::StringPrintf("/sys/bus/usb/devices/%s/%s:1.%d/interface",
|
|
sysfs_name, sysfs_name, ifc->bInterfaceNumber);
|
|
if (android::base::ReadFileToString(path, &interface)) {
|
|
snprintf(info.interface, sizeof(info.interface), "%s", interface.c_str());
|
|
}
|
|
+#ifdef __ANDROID__
|
|
+ }
|
|
+#endif
|
|
|
|
if(callback(&info) == 0) {
|
|
*ept_in_id = in;
|
|
@@ -353,16 +427,52 @@ static std::unique_ptr<usb_handle> find_usb_device(const char* base, ifc_match_f
|
|
int fd;
|
|
int writable;
|
|
|
|
+#ifdef __ANDROID__
|
|
+ bool linux_usb = true, termux_usb = false, is_linux_usb, is_termux_usb;
|
|
+ int termux_usb_fd;
|
|
+ char* fd_str = getenv("TERMUX_USB_FD");
|
|
+ if (fd_str != nullptr) {
|
|
+ long int fd_long = strtol(fd_str, nullptr, 10);
|
|
+ if (fd_long >= INT_MIN && fd_long <= INT_MAX) {
|
|
+ termux_usb_fd = (int) fd_long;
|
|
+ if (termux_usb_fd != -1 && !ref_deleted(termux_usb_fd))
|
|
+ termux_usb = true;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
std::unique_ptr<DIR, decltype(&closedir)> busdir(opendir(base), closedir);
|
|
+#ifdef __ANDROID__
|
|
+ if (busdir == nullptr)
|
|
+ linux_usb = false;
|
|
+
|
|
+ while (((is_linux_usb = (linux_usb &&
|
|
+ (de = readdir(busdir.get())))) || termux_usb) && (usb == nullptr)) {
|
|
+ is_termux_usb = !is_linux_usb;
|
|
+
|
|
+ if (is_linux_usb && badname(de->d_name))
|
|
+ continue;
|
|
+
|
|
+ if (is_termux_usb || !convert_to_devfs_name(de->d_name,
|
|
+ devname, sizeof(devname))) {
|
|
+#else
|
|
if (busdir == 0) return 0;
|
|
|
|
while ((de = readdir(busdir.get())) && (usb == nullptr)) {
|
|
if (badname(de->d_name)) continue;
|
|
|
|
if (!convert_to_devfs_name(de->d_name, devname, sizeof(devname))) {
|
|
+#endif
|
|
|
|
// DBG("[ scanning %s ]\n", devname);
|
|
writable = 1;
|
|
+#ifdef __ANDROID__
|
|
+ if (is_termux_usb) {
|
|
+ termux_usb = false;
|
|
+ fd = termux_usb_fd;
|
|
+ lseek(fd, 0, SEEK_SET);
|
|
+ } else {
|
|
+#endif
|
|
if ((fd = open(devname, O_RDWR)) < 0) {
|
|
// Check if we have read-only access, so we can give a helpful
|
|
// diagnostic like "adb devices" does.
|
|
@@ -371,12 +481,25 @@ static std::unique_ptr<usb_handle> find_usb_device(const char* base, ifc_match_f
|
|
continue;
|
|
}
|
|
}
|
|
+#ifdef __ANDROID__
|
|
+ }
|
|
+#endif
|
|
|
|
n = read(fd, desc, sizeof(desc));
|
|
|
|
+#ifdef __ANDROID__
|
|
+ if (filter_usb_device(de->d_name, is_termux_usb, fd, desc, n,
|
|
+ writable, callback, &in, &out, &ifc) == 0) {
|
|
+#else
|
|
if (filter_usb_device(de->d_name, desc, n, writable, callback, &in, &out, &ifc) == 0) {
|
|
+#endif
|
|
usb.reset(new usb_handle());
|
|
+#ifdef __ANDROID__
|
|
+ if (is_termux_usb)
|
|
+ usb->is_termux_usb = true;
|
|
+#else
|
|
strcpy(usb->fname, devname);
|
|
+#endif
|
|
usb->ep_in = in;
|
|
usb->ep_out = out;
|
|
usb->desc = fd;
|
|
@@ -516,8 +639,19 @@ int LinuxUsbTransport::WaitForDisconnect()
|
|
{
|
|
double deadline = now() + WAIT_FOR_DISCONNECT_TIMEOUT;
|
|
while (now() < deadline) {
|
|
+#ifdef __ANDROID__
|
|
+ if (handle_->is_termux_usb)
|
|
+ { if (ref_deleted(handle_->desc)) return 0; }
|
|
+ else
|
|
+#endif
|
|
if (access(handle_->fname, F_OK)) return 0;
|
|
std::this_thread::sleep_for(50ms);
|
|
}
|
|
return -1;
|
|
}
|
|
+
|
|
+#ifdef __ANDROID__
|
|
+bool LinuxUsbTransport::NotReusable() {
|
|
+ return handle_->is_termux_usb;
|
|
+}
|
|
+#endif
|