diff --git a/fel.c b/fel.c index f4b2d0f7ea..b027d64c06 100644 --- a/fel.c +++ b/fel.c @@ -1069,6 +1069,17 @@ int main(int argc, char **argv) if (*argv[i] == '-') pr_fatal("Invalid option %s\n", argv[i]); + /* Check for virtual machine */ + const char *emulation = fel_check_vm(); + if (emulation) { + /* print a warning message, but otherwise try to continue normally */ + printf("Virtual machine detected! (%s)\n\n", emulation); + printf("The FEL protocol (handler in the BROM) is not very robust. Trying to use it\n" + "via emulated USB is known to be problematic on some virtual machines. If you\n" + "insist on doing this, expect spurious errors due to timing issues etc. These\n" + "do _not_ mean that sunxi-fel is at fault, and it can't do anything about it.\n\n"); + } + /* Process options that don't require a FEL device handle */ if (device_list) felusb_list_devices(); /* and exit program afterwards */ diff --git a/fel_lib.c b/fel_lib.c index d482ce8b91..3c87e5c4ef 100644 --- a/fel_lib.c +++ b/fel_lib.c @@ -820,3 +820,47 @@ feldev_list_entry *list_fel_devices(size_t *count) if (count) *count = devices; return list; } + +/* + * Check for virtual machine (USB emulation). The FEL protocol is rather + * sensitive to errors and timing issues, so such environments are known + * to NOT work well with sunxi-fel. + * + * Returns either NULL (if no virtual machine could be detected), or a string + * pointer that identifies the environment. (e.g. "VirtualBox", "VMware", ...) + */ +const char *fel_check_vm(void) { + const char *result = NULL; + + ssize_t rc; + libusb_context *ctx; + libusb_device **usb; + struct libusb_device_descriptor desc; + + libusb_init(&ctx); + rc = libusb_get_device_list(ctx, &usb); + if (rc < 0) + usb_error(rc, "libusb_get_device_list()", 1); + + // iterate over device descriptors, checking their vendor IDs + while (--rc >= 0) { + libusb_get_device_descriptor(usb[rc], &desc); + switch (desc.idVendor) { + case 0x0E0F: + result = "VMware"; + break; + case 0x15AD: + result = "VMware"; + break; + case 0x80EE: + result = "VirtualBox"; + break; + } + if (result) + break; // exit while loop + } + libusb_free_device_list(usb, true); + libusb_exit(ctx); + + return result; +} diff --git a/fel_lib.h b/fel_lib.h index 62ab8dd95f..fe95d0daff 100644 --- a/fel_lib.h +++ b/fel_lib.h @@ -81,4 +81,7 @@ void fel_clrsetbits_le32(feldev_handle *dev, bool fel_get_sid_root_key(feldev_handle *dev, uint32_t *result, bool force_workaround); +/* check for virtual machine (USB emulation) */ +const char *fel_check_vm(void); + #endif /* _SUNXI_TOOLS_FEL_LIB_H */