Hi,
Here is one of the possible ways to reproduce the issue. I am using the following environment:
Product: MCUXpresso IDE
Version: MCUXpresso IDE v11.1.0 [Build 3209] [2019-12-12]
LPCOpen:
lpcopen_3_02_lpcxpresso_link2_4370.zip
You will need to build and deploy 'usbd_rom_libusb' sample project to 'LPC-Link 2' board with the following modifications of the main():
int main(void)
{
/* Initialize board and chip */
SystemCoreClockUpdate();
Board_Init();
/* Init USB subsystem and LibUSBDevice */
libusbdev_init(USB_STACK_MEM_BASE, USB_STACK_MEM_SIZE);
while (1) {
/* wait until host is connected */
while (libusbdev_Connected() == 0) {
/* Sleep until next IRQ happens */
__WFI();
}
while (libusbdev_Connected()) {
if (libusbdev_QueueReadDone() != -1 && libusbdev_QueueSendDone() == 0) {
/* read data */
libusbdev_QueueReadReq(g_rxBuff, 1);
/* send data */
libusbdev_QueueSendReq(g_rxBuff, PACKET_BUFFER_SIZE);
}
}
}
}
You will need Ubuntu environment to build and run the following 'test.cpp' sample code for testing USB bulk data transmission:
#include <iostream>
#include <libusb-1.0/libusb.h>
#define VENDOR_ID (0x1fc9)
#define PRODUCT_ID (0x8A)
#define BULK_EP_OUT 0x01
#define BULK_EP_IN 0x81
#define BUFF_SIZE 4096
using namespace std;
int main() {
libusb_device_handle *dev_handle;
libusb_context *ctx = NULL;
int r;
int actual;
r = libusb_init(&ctx);
if(r < 0) {
cout << "Could not initialize USB library, error code: " << r << endl;
return 1;
}
dev_handle = libusb_open_device_with_vid_pid(ctx, VENDOR_ID, PRODUCT_ID);
if(dev_handle == NULL) {
cout << "Could not open usb device" << endl;
return 1;
}
cout << "Device was open successfully" << endl;
unsigned char *data = new unsigned char[BUFF_SIZE];
if(libusb_kernel_driver_active(dev_handle, 0) == 1) {
cout << "There is a kernel driver attached to the device" << endl;
if(libusb_detach_kernel_driver(dev_handle, 0) == 0)
cout << "Kernel driver detached successfully" << endl;
}
r = libusb_claim_interface(dev_handle, 0);
if(r < 0) {
cout << "Could not claim the interface" << endl;
return 1;
}
cout << "Interface claimed successfully" << endl;
cout << "Clearing device sending buffer ..." << endl;
r = libusb_bulk_transfer(dev_handle, BULK_EP_IN, data, BUFF_SIZE, &actual, 200);
cout << "Sending data to usb device ..." << endl;
r = libusb_bulk_transfer(dev_handle, BULK_EP_OUT, data, 1, &actual, 200);
if(r == 0 && actual == 1) {
cout << "Data sent successfully to usb device" << endl;
} else {
cout << "Could not send data to usb device, error: " << r << " actual bytes sent: " << actual << endl;
}
cout << "Receiving data from usb device ..." << endl;
r = libusb_bulk_transfer(dev_handle, BULK_EP_IN, data, BUFF_SIZE, &actual, 200);
if(r == 0 && actual == BUFF_SIZE) {
cout << "Received successfully " << actual << " bytes" << endl;
} else {
cout << "Could not receive data from usb device, error: " << r << " actual bytes received: " << actual << endl;
}
r = libusb_release_interface(dev_handle, 0);
if( r != 0) {
cout << "Could not release interface, error: " << r << endl;
return 1;
}
cout << "Interface released successfully" << endl;
libusb_close(dev_handle);
cout << "device closed successfully" << endl;
libusb_exit(ctx);
return 0;
}
To build the 'test.cpp' you will need libusb library that on Ubuntu can be installed with the following command:
sudo apt install libusb-1.0
To build 'test.cpp' sample program:
cc test.cpp -o test -lusb-1.0 -O2 -lstdc++
Plug the LPC-Link 2 board into USB port and run the 'test' program on the host:
sudo ./test
When successfully executed, 'test' program should log the following:
Device was open successfully
Interface claimed successfully
Clearing device sending buffer ...
Sending data to usb device ...
Data sent successfully to usb device
Receiving data from usb device ...
Received successfully 4096 bytes
Interface released successfully
device closed successfully
On a single host machine, with no VMs running, the 'test' program will run successfully every time you kick it off.
To reproduce the issue, install a VM software like VBox on Ubuntu host machine and spin up a guest Ubuntu OS.
When running the guest OS, repeatedly assign the USB device 'LPC18xx GENERIC USB' between Host Ubuntu machine and the guest Ubuntu instance and run 'test' program on the machine that the device is assigned to.
Eventually the 'test' program will throw an error -7 when sending data which indicates a bulk transfer time out, like in the output shown below:
Device was open successfully
Interface claimed successfully
Clearing device sending buffer ...
Sending data to usb device ...
Could not send data to usb device, error: -7 actual bytes sent: 0
Receiving data from usb device ...
Could not receive data from usb device, error: -7 actual bytes received: 0
Interface released successfully
device closed successfully
I could not find a software solution for the timeout error (-7) shown. The only way to get rid of the timeout is to unplug the device from the USB port and plug it back in.
It seems like there is a race condition with the libusbdev.c example or with the USB ROM (LPC4370) when switching device ownership between host and guest machines (I suspect it is related to USB connection re-initialization). I can also reproduce the same issue on CentOS or when running guest machines using VMWare.
Any comments appreciated.
thanks,
A.B.