Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 15 Aug 2006 14:52:17 GMT
From:      Naoyuki Tai <ntai@smartfruit.com>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   usb/102096: /usr/sbin/usbd does not handle multiple devices in one event
Message-ID:  <200608151452.k7FEqH3d050636@www.freebsd.org>
Resent-Message-ID: <200608151500.k7FF0WuM031310@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         102096
>Category:       usb
>Synopsis:       /usr/sbin/usbd does not handle multiple devices in one event
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-usb
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Aug 15 15:00:31 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Naoyuki Tai
>Release:        FreeBSD 5.5
>Organization:
>Environment:
FreeBSD nile.smartfruit.com 5.5-RELEASE FreeBSD 5.5-RELEASE #0: Sun Aug 13 04:03:03 EDT 2006     root@nile.smartfruit.com:/usr/obj/usr/src/sys/NILE  i386

>Description:
/usr/sbin/usbd does not handle an event with multiple devices. This happens when a hub or KVM switch with multiple devices (such as keyboard and mouse) is connected to a USB port.
The problem has been around since the beginning of usbd, and reported the problem years ago. One time, the patch I reported has been applied, and fixed. FreeBSD 5.5's usbd.c regressed, unfortunately.
The problem is that, the USB event may report more than one device in it but the usbd.c only handles the first device and ignores the rest.

>How-To-Repeat:
Connect a USB based KVM to a FreeBSD computer.
Similary, you can connect a mouse and keyboard to a hub, then connect the hub to a computer.

>Fix:
--- usbd.c.orig Tue Aug 15 10:23:07 2006
+++ usbd.c      Tue Aug 15 10:25:02 2006
@@ -843,84 +843,105 @@
 void
 process_event_queue(int fd)
 {
-       struct usb_event event;
+       struct usb_event events;
        int error;
        int len;
        action_match_t action_match;
+       int i;
+       struct usb_event the_event;
+       struct usb_device_info* devinfo;
+       struct usb_device_info* the_devinfo;

        for (;;) {
-               len = read(fd, &event, sizeof(event));
+               len = read(fd, &events, sizeof(events));
                if (len == -1) {
                        if (errno == EWOULDBLOCK) {
                                /* no more events */
                                break;
                        } else {
                                fprintf(stderr,"%s: Could not read event, %s\n",
-                                       __progname, strerror(errno));
+                                               __progname, strerror(errno));
                                exit(1);
                        }
                }
                if (len == 0)
                        break;
-               if (len != sizeof(event)) {
+               if (len != sizeof(events)) {
                        fprintf(stderr, "partial read on %s\n", USBDEV);
                        exit(1);
                }

                /* we seem to have gotten a valid event */

-               if (verbose)
-                       print_event(&event);
+               devinfo = &events.u.ue_device;
+               for (i = 0; i < USB_MAX_DEVNAMES; i++) {
+                       if (devinfo->udi_devnames[i][0] == '\0')
+                               break;
+
+                       memcpy(&the_event, &events, sizeof(the_event));
+                       the_devinfo = &the_event.u.ue_device;
+
+                       if (i > 0)
+                               memcpy(the_devinfo->udi_devnames[0], the_devinfo->udi_devnames[i], USB_MAX_DEVNAMELEN);
+                       the_devinfo->udi_devnames[1][0] = '\0';

-               /* handle the event appropriately */
-               switch (event.ue_type) {
-               case USB_EVENT_CTRLR_ATTACH:
-                       if (verbose)
-                               printf("USB_EVENT_CTRLR_ATTACH\n");
-                       break;
-               case USB_EVENT_CTRLR_DETACH:
                        if (verbose)
-                               printf("USB_EVENT_CTRLR_DETACH\n");
-                       break;
-               case USB_EVENT_DEVICE_ATTACH:
-               case USB_EVENT_DEVICE_DETACH:
-                       if (find_action(&event.u.ue_device, &action_match) == 0)
-                               /* nothing found */
-                               break;
+                               print_event(&the_event);

-                       if (verbose >= 2)
-                               print_action(action_match.action, 0);
+                       if (verbose >=2) {
+                               printf("  === match attempt: %s\n", the_devinfo->udi_devnames[0]);
+                       }
+
+                       /* handle the event appropriately */
+                       switch (the_event.ue_type) {
+                       case USB_EVENT_CTRLR_ATTACH:
+                               if (verbose)
+                                       printf("USB_EVENT_CTRLR_ATTACH\n");
+                               break;
+                       case USB_EVENT_CTRLR_DETACH:
+                               if (verbose)
+                                       printf("USB_EVENT_CTRLR_DETACH\n");
+                               break;
+                       case USB_EVENT_DEVICE_ATTACH:
+                       case USB_EVENT_DEVICE_DETACH:
+                               if (find_action(&the_event.u.ue_device, &action_match) == 0)
+                                       /* nothing found */
+                                       break;

-                       if (action_match.devname) {
                                if (verbose >= 2)
-                                       printf("%s: Setting DEVNAME='%s'\n",
-                                               __progname, action_match.devname);
+                                       print_action(action_match.action, 0);

-                               error = setenv("DEVNAME", action_match.devname, 1);
-                               if (error)
-                                       fprintf(stderr, "%s: setenv(\"DEVNAME\", \"%s\",1) failed, %s\n",
-                                               __progname, action_match.devname, strerror(errno));
+                               if (action_match.devname) {
+                                       if (verbose >= 2)
+                                               printf("%s: Setting DEVNAME='%s'\n",
+                                                          __progname, action_match.devname);
+
+                                       error = setenv("DEVNAME", action_match.devname, 1);
+                                       if (error)
+                                               fprintf(stderr, "%s: setenv(\"DEVNAME\", \"%s\",1) failed, %s\n",
+                                                               __progname, action_match.devname, strerror(errno));
+                               }
+
+                               if (USB_EVENT_IS_ATTACH(the_event.ue_type) &&
+                                       action_match.action->attach)
+                                       execute_command(action_match.action->attach);
+                               if (USB_EVENT_IS_DETACH(the_event.ue_type) &&
+                                       action_match.action->detach)
+                                       execute_command(action_match.action->detach);
+                               break;
+                       case USB_EVENT_DRIVER_ATTACH:
+                               if (verbose)
+                                       printf("USB_EVENT_DRIVER_ATTACH\n");
+                               break;
+                       case USB_EVENT_DRIVER_DETACH:
+                               if (verbose)
+                                       printf("USB_EVENT_DRIVER_DETACH\n");
+                               break;
+                       default:
+                               printf("Unknown USB event %d\n", the_event.ue_type);
                        }
-
-                       if (USB_EVENT_IS_ATTACH(event.ue_type) &&
-                           action_match.action->attach)
-                               execute_command(action_match.action->attach);
-                       if (USB_EVENT_IS_DETACH(event.ue_type) &&
-                           action_match.action->detach)
-                               execute_command(action_match.action->detach);
-                       break;
-               case USB_EVENT_DRIVER_ATTACH:
-                       if (verbose)
-                               printf("USB_EVENT_DRIVER_ATTACH\n");
-                       break;
-               case USB_EVENT_DRIVER_DETACH:
-                       if (verbose)
-                               printf("USB_EVENT_DRIVER_DETACH\n");
-                       break;
-               default:
-                       printf("Unknown USB event %d\n", event.ue_type);
                }
-       }
+       }
 }


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200608151452.k7FEqH3d050636>