Allow opening of USB device by physical bus path

In case there are multiple devices with identical VID/PID, the
existing open_vid_pid mechanism is insufficient.
This commit is contained in:
Harald Welte 2020-02-29 20:36:10 +01:00
parent 49858b1a66
commit 4c742e931a
5 changed files with 109 additions and 1 deletions

View File

@ -18,8 +18,12 @@ type record USB_Device_Match_vidpid {
HEX4n vid,
HEX4n pid
};
type record USB_Device_Match_path {
charstring path
};
type union USB_Device_Match {
USB_Device_Match_vidpid vid_pid
USB_Device_Match_vidpid vid_pid,
USB_Device_Match_path path
};
function f_usb_init_vid_pid(HEX4n vendor_id, HEX4n product_id) runs on USB_CT {
@ -41,10 +45,35 @@ function f_usb_init_vid_pid(HEX4n vendor_id, HEX4n product_id) runs on USB_CT {
g_USB_Tguard.stop;
}
function f_usb_init_path(charstring path) runs on USB_CT {
map(self:USB, system:USB);
var USB_result res;
var integer req_hdl := f_usb_get_req_hdl();
USB.send(ts_USB_open_path(path, device_hdl := g_dev_hdl, req_hdl := req_hdl));
g_USB_Tguard.start;
alt {
[] USB.receive(tr_USB_result(req_hdl := req_hdl, device_hdl := g_dev_hdl)) -> value res {
log("Received ", res);
}
[] USB.receive {
testcase.stop("Couldn't open requested USB device");
}
}
g_USB_Tguard.stop;
}
private altstep as_Tguard() runs on USB_CT {
[] g_USB_Tguard.timeout {
testcase.stop("Timeout of global USB guard timer");
}
}
function f_usb_init(USB_Device_Match udm) runs on USB_CT {
activate(as_Tguard());
if (ischosen(udm.vid_pid)) {
f_usb_init_vid_pid(udm.vid_pid.vid, udm.vid_pid.pid);
} else if (ischosen(udm.path)) {
f_usb_init_path(udm.path.path);
} else {
testcase.stop("Unsupported USB_Device_Match");
}

View File

@ -343,6 +343,67 @@ void USB__PT_PROVIDER::outgoing_send(const USB__open__vid__pid& send_par)
incoming_message(USB__result(send_par.req__hdl(), send_par.device__hdl(), rc));
}
static void stringify_usb_path(char *out, uint8_t bus_num, const uint8_t *ports, size_t num_ports)
{
int length = 0;
int i;
length += sprintf(out, "%u-%u", bus_num, ports[0]);
for (i = 1; i < num_ports; i++)
length += sprintf(out+length, ".%u", ports[i]);
}
void USB__PT_PROVIDER::outgoing_send(const USB__open__path& send_par)
{
unsigned int device_hdl = send_par.device__hdl();
const CHARSTRING &in_path_char = send_par.path();
const char *in_path = (const char *) in_path_char;
libusb_device_handle *dh = NULL;
libusb_device **list;
int rc, i;
rc = libusb_get_device_list(mCtx, &list);
if (rc < 0) {
log("Error getting USB device list: %s\n",
libusb_strerror((enum libusb_error) rc));
rc = -1;
goto out;
}
for (i = 0; list[i] != NULL; i++) {
uint8_t ports[8];
char path[256];
libusb_device *dev = list[i];
rc = libusb_get_port_numbers(dev, ports, sizeof(ports));
stringify_usb_path(path, libusb_get_bus_number(dev), ports, rc);
log("Found USB Device at path %s", path);
if (!strcmp(in_path, path)) {
rc = libusb_open(dev, &dh);
if (rc < 0) {
log("Error opening USB device %s: %s", path,
libusb_strerror((enum libusb_error) rc));
rc = -1;
} else {
USB_Device *udev = new USB_Device(this, dh, device_hdl);
mDevices.insert(std::make_pair(device_hdl, udev));
log("Successfully opened USB device at path %s", path);
rc = 0;
}
break;
}
}
if (!dh) {
log("No matching USB device for %s", in_path);
rc = -1;
}
libusb_free_device_list(list, 1);
out:
incoming_message(USB__result(send_par.req__hdl(), send_par.device__hdl(), rc));
}
void USB__PT_PROVIDER::outgoing_send(const USB__set__configuration& send_par)
{
USB_Device *dev = usbdev_by_hdl(send_par.device__hdl());

View File

@ -94,6 +94,7 @@ protected:
void user_stop();
void outgoing_send(const USB__open__vid__pid& send_par);
void outgoing_send(const USB__open__path& send_par);
void outgoing_send(const USB__transfer& send_par);
void outgoing_send(const USB__set__configuration& send_par);
void outgoing_send(const USB__claim__interface& send_par);

View File

@ -3,6 +3,7 @@ import from USB_PortTypes all;
type port USB_PT message {
out USB_open_vid_pid;
out USB_open_path;
out USB_set_configuration;
out USB_claim_interface;
out USB_release_interface;

View File

@ -60,6 +60,14 @@ module USB_PortTypes {
};
/* Response: USB_result */
type record USB_open_path {
integer req_hdl,
integer device_hdl,
charstring path
};
/* Response: USB_result */
type record USB_set_configuration {
integer req_hdl,
integer device_hdl,
@ -132,6 +140,14 @@ ts_USB_open_vid_pid(USB_vendor_id vid, USB_product_id pid, integer device_hdl :=
product_id := pid
}
template (value) USB_open_path
ts_USB_open_path(charstring path, integer device_hdl := -1, integer req_hdl := -1) := {
req_hdl := req_hdl,
device_hdl := device_hdl,
path := path
}
template USB_result tr_USB_result(template integer req_hdl := ?, template integer device_hdl := ?,
template integer result_code := ?) := {
req_hdl := req_hdl,