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