usb/173666: [USB, LIBUSB] usb_reset() behavior different between GNU/Linux and FreeBSD
Wojciech A. Koszek
wkoszek at FreeBSD.org
Fri Nov 16 22:50:00 UTC 2012
>Number: 173666
>Category: usb
>Synopsis: [USB, LIBUSB] usb_reset() behavior different between GNU/Linux and FreeBSD
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-usb
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Fri Nov 16 22:50:00 UTC 2012
>Closed-Date:
>Last-Modified:
>Originator: Wojciech A. Koszek
>Release: 9.0-RELEASE
>Organization:
FreeBSD
>Environment:
FreeBSD seu 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Tue Jan 3 07:15:25 UTC 2012 root at obrian.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC i386
>Description:
I have a driver written for libusb, which works fine under GNU/Linux and libusb. Device:
gen0.2: <JSB283 Relay Module J-Works,Inc> at usbus0, cfg=0 md=HOST spd=LOW (1.5Mbps) pwr=ON
(I used USB sniffer to uncover traffic based on what Windows was doing)
Under Linux usb_reset()+usb_set_configuration() calls works fine. Under FreeBSD I have to disable calling usb_reset(), otherwise usb_set_configuration() fails with I/O error.
=========== usb_relay.c ================
#include <sys/param.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libusb.h>
#include <usb.h>
static int g_debug = 0;
#define DBG(...) do { \
if (g_debug == 0) { \
break; \
} \
printf("%s(%d): ", __func__, __LINE__); \
printf(__VA_ARGS__); \
printf("\n"); \
} while (0)
enum {
CMD_QUERY,
CMD_ON,
CMD_FLASH,
CMD_OFF
};
static void
usage(void)
{
printf("./usb_relay <on|off>\n");
exit(1);
}
static struct usb_device *
usb_dev_find(uint32_t look_vid, uint32_t look_pid)
{
struct usb_bus *busses;
struct usb_bus *bus;
struct usb_device *dev;
struct usb_device_descriptor *desc;
uint32_t vid, pid;
usb_init();
usb_find_busses();
usb_find_devices();
busses = usb_get_busses();
for (bus = busses; bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
desc = &dev->descriptor;
vid = desc->idVendor;
pid = desc->idProduct;
if ((vid == look_vid) && (pid == look_pid)) {
return (dev);
}
}
}
return (NULL);
}
int
main(int argc, char **argv)
{
struct usb_device *dev;
struct usb_dev_handle *hptr;
int o, ret, state, ep, ac, cmd;
uint32_t data[2];
char **av;
int i;
while ((o = getopt(argc, argv, "dh")) != -1) {
switch (o) {
case 'd':
g_debug++;
break;
case 'h':
usage();
break;
default:
usage();
break;
}
}
ac = argc - optind;
av = argv + optind;
cmd = CMD_QUERY;
if (ac > 0) {
if (strcmp(av[0], "on") == 0) {
cmd = CMD_ON;
} else if (strcmp(av[0], "off") == 0) {
cmd = CMD_OFF;
} else if (strcmp(av[0], "flash") == 0) {
cmd = CMD_FLASH;
} else {
abort();
}
}
dev = usb_dev_find(0x07c3, 0x1283);
if (dev == NULL) {
printf("J283 not found!\n");
exit(1);
}
hptr = usb_open(dev);
DBG("usb_open returned %p", hptr);
#ifdef HAS_RESET
ret = usb_reset(hptr);
DBG("usb_reset returned %d: %s", ret, libusb_strerror(ret));
#endif
ret = usb_set_configuration(hptr, 1);
DBG("usb_reset returned %d: %s", ret, libusb_strerror(ret));
ret = usb_claim_interface(hptr, 1);
DBG("usb_reset returned %d: %s", ret, libusb_strerror(ret));
data[0] = -1;
data[1] = -1;
ret = usb_control_msg(hptr, 0xc2, 176, 0x0, 0, (char *)data, 8, 400);
DBG("usb_control_msg = %d %08x,%08x", ret, data[0], data[1]);
ret = usb_control_msg(hptr, 0xc2, 184, 0x0, 0, (char *)data, 8, 400);
DBG("usb_control_msg = %d %08x,%08x", ret, data[0], data[1]);
if (cmd == CMD_QUERY) {
state = data[0] & 1;
printf("%s\n", state ? "on" : "off");
} else if (cmd == CMD_ON) {
ret = usb_control_msg(hptr, 0xc2, 183, 0x0, 0, (char *)data,
8, 400);
} else if (cmd == CMD_OFF) {
ret = usb_control_msg(hptr, 0xc2, 182, 0x0, 0, (char *)data,
8, 400);
} else if (cmd == CMD_FLASH) {
ret = usb_control_msg(hptr, 0xc2, 177, 0x0, 0, (char *)data,
8, 400);
} else {
abort();
}
exit(0);
}
>How-To-Repeat:
seu# gcc -DHAS_RESET usb_relay.c -o usb_relay.has_reset -lusb
seu# ./usb_relay.has_reset -d off && sleep 1 && ./usb_relay.has_reset -d on
main(110): usb_open returned 0x28405480
main(113): usb_reset returned 0: Success
main(117): usb_reset returned -1: I/O error
main(119): usb_reset returned 0: Success
main(124): usb_control_msg = -1 ffffffff,ffffffff
main(126): usb_control_msg = -1 ffffffff,ffffffff
main(110): usb_open returned 0x28405480
main(113): usb_reset returned 0: Success
main(117): usb_reset returned -1: I/O error
main(119): usb_reset returned 0: Success
main(124): usb_control_msg = -1 ffffffff,ffffffff
main(126): usb_control_msg = -1 ffffffff,ffffffff
seu#
seu# gcc usb_relay.c -o usb_relay -lusb
seu# ./usb_relay -d off && sleep 1 && ./usb_relay -d on
main(110): usb_open returned 0x28405480
main(117): usb_reset returned 0: Success
main(119): usb_reset returned 0: Success
main(124): usb_control_msg = 5 01000001,ffffff00
main(126): usb_control_msg = 5 01000001,ffffff00
main(110): usb_open returned 0x28405480
main(117): usb_reset returned 0: Success
main(119): usb_reset returned 0: Success
main(124): usb_control_msg = 5 01000001,ffffff00
main(126): usb_control_msg = 5 01000000,ffffff00
>Fix:
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-usb
mailing list