diff --git a/share/man/man4/usb.4 b/share/man/man4/usb.4 index 0b63d965aea3..0fb22094ce56 100644 --- a/share/man/man4/usb.4 +++ b/share/man/man4/usb.4 @@ -291,11 +291,78 @@ The include file similarly contains the definitions for Human Interface Devices .Pq Tn HID . +.Sh USB EVENT INTERFACE +All +.Tn USB +events are reported via the +.Pa /dev/usb +device. This devices can be opened for reading and each +.Xr read 2 +will yield an event record (if something has happened). +The +.Xr poll 2 +system call can be used to determine if an event record is available +for reading. +.Pp +The event record has the following definition: +.Bd -literal +struct usb_event { + int ue_type; +#define USB_EVENT_CTRLR_ATTACH 1 +#define USB_EVENT_CTRLR_DETACH 2 +#define USB_EVENT_DEVICE_ATTACH 3 +#define USB_EVENT_DEVICE_DETACH 4 +#define USB_EVENT_DRIVER_ATTACH 5 +#define USB_EVENT_DRIVER_DETACH 6 + struct timespec ue_time; + union { + struct { + int ue_bus; + } ue_ctrlr; + struct usb_device_info ue_device; + struct { + usb_event_cookie_t ue_cookie; + char ue_devname[16]; + } ue_driver; + } u; +}; +.Ed +The +.Va ue_type +field identifies the type of event that is described. +The possible events are attach/detach of a host controller, +a device, or a device driver. The union contains information +pertinent to the different types of events. +.br +The +.Va ue_bus +contains the number of the +.Tn USB +bus for host controller events. +.br +The +.Va ue_device +record contains information about the device in a device event event. +.br +The +.Va ue_cookie +is an opaque value that uniquely determines which which +device a device driver has been attached to (i.e., it equals +the cookie value in the device that the driver attached to). +The +.Va ue_devname +contains the name of the device (driver) as seen in, e.g., +kernel messages. +.Pp +Note that that there is a separation between device and device +driver events. A device event is generated when a physical +USB device is attached or detached. A single USB device may +have zero, one, or many device drivers associated with it. .Sh SEE ALSO The .Tn USB specifications can be found at: -.D1 http://www.usb.org/developers/docs.htm . +.D1 http://www.usb.org/developers/docs.html .Pp .Xr usb 3 , .Xr aue 4 , diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c index 0533249aab8d..05a19729e8e2 100644 --- a/sys/dev/usb/uhub.c +++ b/sys/dev/usb/uhub.c @@ -263,6 +263,8 @@ USB_ATTACH(uhub) /* Wait with power off for a while. */ usbd_delay_ms(dev, USB_POWER_DOWN_TIME); + usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, USBDEV(sc->sc_dev)); + /* * To have the best chance of success we do things in the exact same * order as Windoze98. This should not be necessary, but some @@ -525,7 +527,8 @@ USB_DETACH(uhub) if (rup->device) usb_disconnect_port(rup, self); } - + + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, dev, USBDEV(sc->sc_dev)); free(dev->hub, M_USBDEV); dev->hub = NULL; diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c index 545d35c97ec3..0798248809df 100644 --- a/sys/dev/usb/usb.c +++ b/sys/dev/usb/usb.c @@ -1,4 +1,4 @@ -/* $NetBSD: usb.c,v 1.37 2000/01/24 18:35:51 thorpej Exp $ */ +/* $NetBSD: usb.c,v 1.38 2000/02/02 07:33:59 augustss Exp $ */ /* $FreeBSD$ */ /* @@ -163,6 +163,7 @@ Static int usb_nevents = 0; Static struct selinfo usb_selevent; Static struct proc *usb_async_proc; /* process that wants USB SIGIO */ Static int usb_dev_open = 0; +Static void usb_add_event(int, struct usb_event *); Static int usb_get_next_event(struct usb_event *); @@ -201,6 +202,7 @@ USB_ATTACH(usb) usbd_device_handle dev; usbd_status err; int usbrev; + struct usb_event ue; sc->sc_dev = self; @@ -226,6 +228,9 @@ USB_ATTACH(usb) if (cold) sc->sc_bus->use_polling++; + ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev); + usb_add_event(USB_EVENT_CTRLR_ATTACH, &ue); + err = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0, 0, 0, &sc->sc_port); if (!err) { @@ -631,18 +636,45 @@ usb_get_next_event(struct usb_event *ue) } void -usbd_add_event(int type, usbd_device_handle dev) +usbd_add_dev_event(int type, usbd_device_handle udev) +{ + struct usb_event ue; + + usbd_fill_deviceinfo(udev, &ue.u.ue_device, USB_EVENT_IS_ATTACH(type)); + usb_add_event(type, &ue); +} + +void +usbd_add_drv_event(int type, usbd_device_handle udev, device_ptr_t dev) +{ + struct usb_event ue; + + ue.u.ue_driver.ue_cookie = udev->cookie; + strncpy(ue.u.ue_driver.ue_devname, USBDEVPTRNAME(dev), + sizeof ue.u.ue_driver.ue_devname); + usb_add_event(type, &ue); +} + +void +usb_add_event(int type, struct usb_event *uep) { struct usb_event_q *ueq, *ueq_next; struct usb_event ue; struct timeval thetime; int s; + ueq = malloc(sizeof *ueq, M_USBDEV, M_WAITOK); + ueq->ue = *uep; + ueq->ue.ue_type = type; + microtime(&thetime); + TIMEVAL_TO_TIMESPEC(&thetime, &ueq->ue.ue_time); + s = splusb(); - if (type == USB_EVENT_CTRLR_DETACH) { + if (USB_EVENT_IS_DETACH(type)) { for (ueq = TAILQ_FIRST(&usb_events); ueq; ueq = ueq_next) { ueq_next = TAILQ_NEXT(ueq, next); - if (ueq->ue.u.ue_driver.ue_cookie.cookie == dev->cookie.cookie) { + if (ueq->ue.u.ue_driver.ue_cookie.cookie == + uep->u.ue_device.cookie.cookie) { TAILQ_REMOVE(&usb_events, ueq, next); free(ueq, M_USBDEV); usb_nevents--; @@ -655,18 +687,6 @@ usbd_add_event(int type, usbd_device_handle dev) DPRINTF(("usb: event dropped\n")); (void)usb_get_next_event(&ue); } - /* Don't want to wait here inside splusb() */ - ueq = malloc(sizeof *ueq, M_USBDEV, M_NOWAIT); - if (ueq == NULL) { - printf("usb: no memory, event dropped\n"); - splx(s); - return; - } - ueq->ue.ue_type = type; - ueq->ue.u.ue_driver.ue_cookie = dev->cookie; - usbd_fill_deviceinfo(dev, &ueq->ue.u.ue_device, 0); - microtime(&thetime); - TIMEVAL_TO_TIMESPEC(&thetime, &ueq->ue.ue_time); TAILQ_INSERT_TAIL(&usb_events, ueq, next); usb_nevents++; wakeup(&usb_events); @@ -713,6 +733,7 @@ int usb_detach(device_ptr_t self, int flags) { struct usb_softc *sc = (struct usb_softc *)self; + struct usb_event ue; DPRINTF(("usb_detach: start\n")); @@ -732,6 +753,10 @@ usb_detach(device_ptr_t self, int flags) } usbd_finish(); + + ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev); + usb_add_event(USB_EVENT_CTRLR_DETACH, &ue); + return (0); } #elif defined(__FreeBSD__) diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h index 21c733f33831..8d5a3da94d1e 100644 --- a/sys/dev/usb/usb.h +++ b/sys/dev/usb/usb.h @@ -627,6 +627,7 @@ struct usb_event { #define USB_EVENT_DRIVER_ATTACH 5 #define USB_EVENT_DRIVER_DETACH 6 #define USB_EVENT_IS_ATTACH(n) ((n) == USB_EVENT_CTRLR_ATTACH || (n) == USB_EVENT_DEVICE_ATTACH || (n) == USB_EVENT_DRIVER_ATTACH) +#define USB_EVENT_IS_DETACH(n) ((n) == USB_EVENT_CTRLR_DETACH || (n) == USB_EVENT_DEVICE_DETACH || (n) == USB_EVENT_DRIVER_DETACH) struct timespec ue_time; union { struct { diff --git a/sys/dev/usb/usb_port.h b/sys/dev/usb/usb_port.h index 3f7842250bc9..e2ac72f97e0e 100644 --- a/sys/dev/usb/usb_port.h +++ b/sys/dev/usb/usb_port.h @@ -70,6 +70,7 @@ typedef struct device *device_ptr_t; #define USBBASEDEVICE struct device #define USBDEV(bdev) (&(bdev)) #define USBDEVNAME(bdev) ((bdev).dv_xname) +#define USBDEVUNIT(bdev) ((bdev).dv_unit) #define USBDEVPTRNAME(bdevptr) ((bdevptr)->dv_xname) #define USBDEVUNIT(bdev) ((bdev).dv_unit) @@ -191,6 +192,7 @@ typedef struct device device_ptr_t; #define USBBASEDEVICE struct device #define USBDEV(bdev) (&(bdev)) #define USBDEVNAME(bdev) ((bdev).dv_xname) +#define USBDEVUNIT(bdev) ((bdev).dv_unit) #define USBDEVPTRNAME(bdevptr) ((bdevptr)->dv_xname) #define USBDEVUNIT(bdev) ((bdev).dv_unit) @@ -290,6 +292,7 @@ __CONCAT(dname,_detach)(self, flags) \ #define USBBASEDEVICE device_t #define USBDEV(bdev) (bdev) #define USBDEVNAME(bdev) device_get_nameunit(bdev) +#define USBDEVUNIT(bdev) device_get_unit(bdev) #define USBDEVPTRNAME(bdev) device_get_nameunit(bdev) #define USBDEVUNIT(bdev) device_get_unit(bdev) diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c index f17e5155cf03..2565c44a8e59 100644 --- a/sys/dev/usb/usb_subr.c +++ b/sys/dev/usb/usb_subr.c @@ -1031,9 +1031,9 @@ usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth, usbd_remove_device(dev, up); return (err); } - - usbd_add_event(USB_EVENT_CTRLR_ATTACH, dev); + usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev); + return (USBD_NORMAL_COMPLETION); } @@ -1158,6 +1158,7 @@ usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di, di->bus = USBDEVUNIT(dev->bus->bdev); di->addr = dev->address; + di->cookie = dev->cookie; usbd_devinfo_vp(dev, di->vendor, di->product, usedev); usbd_printBCD(di->release, UGETW(dev->ddesc.bcdDevice)); di->vendorNo = UGETW(dev->ddesc.idVendor); @@ -1281,7 +1282,7 @@ usb_disconnect_port(struct usbd_port *up, device_ptr_t parent) } } - /*usbd_add_event(USB_EVENT_DETACH, dev);*/ + /*usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev);*/ dev->bus->devices[dev->address] = NULL; up->device = NULL; usb_free_device(dev); diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index bb5bfbf7fbe3..7a184e7b87e7 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -176,7 +176,8 @@ void usbd_set_polling(usbd_interface_handle iface, int on); const char *usbd_errstr(usbd_status err); -void usbd_add_event(int, usbd_device_handle); +void usbd_add_dev_event (int, usbd_device_handle); +void usbd_add_drv_event (int, usbd_device_handle, device_ptr_t); void usbd_devinfo(usbd_device_handle, int, char *); const struct usbd_quirks *usbd_get_quirks(usbd_device_handle); diff --git a/usr.sbin/usbd/usbd.c b/usr.sbin/usbd/usbd.c index 967a80b9b1a2..ff5387d85fe4 100644 --- a/usr.sbin/usbd/usbd.c +++ b/usr.sbin/usbd/usbd.c @@ -109,8 +109,12 @@ typedef struct event_name_s { } event_name_t; event_name_t event_names[] = { - {USB_EVENT_CTRLR_ATTACH, "attach"}, - {USB_EVENT_CTRLR_DETACH, "detach"}, + {USB_EVENT_CTRLR_ATTACH, "ctrlr-attach"}, + {USB_EVENT_CTRLR_DETACH, "ctrlr-detach"}, + {USB_EVENT_DRIVER_ATTACH, "driver-attach"}, + {USB_EVENT_DRIVER_DETACH, "driver-detach"}, + {USB_EVENT_DEVICE_ATTACH, "device-attach"}, + {USB_EVENT_DEVICE_DETACH, "device-detach"}, {0, NULL} /* NULL indicates end of list, not 0 */ }; @@ -572,28 +576,42 @@ print_event(struct usb_event *event) if (event_names[i].name == NULL) printf("unknown event %d", event->ue_type); - printf(" at %ld.%09ld, %s, %s:\n", - timespec->tv_sec, timespec->tv_nsec, - devinfo->product, devinfo->vendor); + if (event->ue_type == USB_EVENT_DEVICE_ATTACH || + event->ue_type == USB_EVENT_DEVICE_DETACH) { + devinfo = &event->u.ue_device; - printf(" vndr=0x%04x prdct=0x%04x rlse=0x%04x " - "clss=0x%04x subclss=0x%04x prtcl=0x%04x\n", - devinfo->vendorNo, devinfo->productNo, devinfo->releaseNo, - devinfo->class, devinfo->subclass, devinfo->protocol); + printf(" at %ld.%09ld, %s, %s:\n", + timespec->tv_sec, timespec->tv_nsec, + devinfo->product, devinfo->vendor); - if (devinfo->devnames[0][0] != '\0') { - char c = ' '; + printf(" vndr=0x%04x prdct=0x%04x rlse=0x%04x " + "clss=0x%04x subclss=0x%04x prtcl=0x%04x\n", + devinfo->vendorNo, devinfo->productNo, + devinfo->releaseNo, + devinfo->class, devinfo->subclass, devinfo->protocol); - printf(" device names:"); - for (i = 0; i < USB_MAX_DEVNAMES; i++) { - if (devinfo->devnames[i][0] == '\0') - break; + if (devinfo->devnames[0][0] != '\0') { + char c = ' '; - printf("%c%s", c, devinfo->devnames[i]); - c = ','; + printf(" device names:"); + for (i = 0; i < USB_MAX_DEVNAMES; i++) { + if (devinfo->devnames[i][0] == '\0') + break; + + printf("%c%s", c, devinfo->devnames[i]); + c = ','; + } } - printf("\n"); + } else if (event->ue_type == USB_EVENT_CTRLR_ATTACH || + event->ue_type == USB_EVENT_CTRLR_DETACH) { + printf(" bus=%d", &event->u.ue_ctrlr.ue_bus); + } else if (event->ue_type == USB_EVENT_DRIVER_ATTACH || + event->ue_type == USB_EVENT_DRIVER_DETACH) { + printf(" cookie=%u devname=%s", + &event->u.ue_driver.ue_cookie.cookie, + &event->u.ue_driver.ue_devname); } + printf("\n"); } void @@ -854,7 +872,15 @@ process_event_queue(int fd) /* 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; @@ -873,11 +899,20 @@ process_event_queue(int fd) __progname, action_match.devname, strerror(errno)); } - if (event.ue_type == USB_EVENT_CTRLR_ATTACH && action_match.action->attach) + if (USB_EVENT_IS_ATTACH(event.ue_type) && + action_match.action->attach) execute_command(action_match.action->attach); - if (event.ue_type == USB_EVENT_CTRLR_DETACH && action_match.action->detach) + 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_DETACH\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);