From owner-p4-projects@FreeBSD.ORG Mon Jun 4 07:17:20 2007 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id A30F216A469; Mon, 4 Jun 2007 07:17:20 +0000 (UTC) X-Original-To: perforce@FreeBSD.org Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 7496216A421 for ; Mon, 4 Jun 2007 07:17:20 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.freebsd.org (Postfix) with ESMTP id 6561B13C487 for ; Mon, 4 Jun 2007 07:17:20 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.8/8.13.8) with ESMTP id l547HKCb044810 for ; Mon, 4 Jun 2007 07:17:20 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.8/8.13.8/Submit) id l547HKfK044801 for perforce@freebsd.org; Mon, 4 Jun 2007 07:17:20 GMT (envelope-from hselasky@FreeBSD.org) Date: Mon, 4 Jun 2007 07:17:20 GMT Message-Id: <200706040717.l547HKfK044801@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 120885 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 04 Jun 2007 07:17:21 -0000 http://perforce.freebsd.org/chv.cgi?CH=120885 Change 120885 by hselasky@hselasky_mini_itx on 2007/06/04 07:16:51 This is the start of a completely new /dev/usbX backend that can be used to access any USB device on the USB bus. "/dev/usbX" now uses the "usb_cdev" system that makes it detach safe among other things. Remove support for "usbd", "/dev/usb" hence this utility has been replaced by "devd". Affected files ... .. //depot/projects/usb/src/sys/dev/usb/usb.c#13 edit .. //depot/projects/usb/src/sys/dev/usb/usb.h#10 edit .. //depot/projects/usb/src/sys/dev/usb/usb_requests.c#5 edit .. //depot/projects/usb/src/sys/dev/usb/usb_subr.c#37 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/usb.c#13 (text+ko) ==== @@ -50,11 +50,8 @@ #include #include -#include /* UIO_XXX */ #include #include -#include /* FXXX */ -#include /* IOR()/IOW()/IORW() */ #include #include #include @@ -63,13 +60,7 @@ #include #include #include -#include - -#define DEV2UNIT(d) (minor(d)) -#define DEV2BUS(d) (*((struct usbd_bus **)&((d)->si_drv1))) -#define USB_DEV_MINOR 255 /* event queue device */ - MALLOC_DEFINE(M_USB, "USB", "USB"); MALLOC_DEFINE(M_USBDEV, "USBdev", "USB device"); MALLOC_DEFINE(M_USBHC, "USBHC", "USB host controller"); @@ -83,58 +74,82 @@ int usbdebug = 0; SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW, &usbdebug, 0, "usb debug level"); +#endif -/* - * 0 - do usual exploration - * 1 - do not use timeout exploration - * >1 - do no exploration - */ -int usb_noexplore = 0; +#if ((__FreeBSD_version >= 700001) || (__FreeBSD_version == 0) || \ + ((__FreeBSD_version >= 600034) && (__FreeBSD_version < 700000))) +#define USB_UCRED struct ucred *ucred, +#else +#define USB_UCRED #endif -#define USB_MAX_EVENTS 100 -struct usb_event_wrapper -{ - struct usb_event ue; - TAILQ_ENTRY(usb_event_wrapper) next; -}; +uint8_t usb_driver_added_refcount; -static TAILQ_HEAD(, usb_event_wrapper) usb_events = - TAILQ_HEAD_INITIALIZER(usb_events); +static uint8_t usb_post_init_called = 0; -#ifndef usb_global_lock -struct mtx usb_global_lock; -#endif - static device_probe_t usb_probe; static device_attach_t usb_attach; static device_detach_t usb_detach; -/* these variables are protected by "usb_global_lock" */ -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 int usb_dummy_open(struct cdev *dev, int oflags, int devtype, struct thread *td); +static void usb_discover(struct usbd_bus *bus); +static void usb_event_thread(struct usbd_bus *bus); +static void usb_create_event_thread(struct usbd_bus *bus); +static void __usb_attach(device_t dev, struct usbd_bus *bus); +static void usb_post_init(void *arg); +static struct usbd_clone *usb_clone_sub(struct usbd_bus *bus); +static void usb_clone_remove(struct usbd_bus *bus); +static void usb_clone(void *arg, USB_UCRED char *name, int namelen, struct cdev **dev); +static int usb_ioctl(struct usb_cdev *dev, u_long cmd, caddr_t addr, int32_t fflags, struct thread *td); +static void usb_init(void *arg); +static void usb_uninit(void *arg); + +static devclass_t usb_devclass; +static driver_t usb_driver = +{ + .name = "usb", + .methods = (device_method_t []) + { + DEVMETHOD(device_probe, usb_probe), + DEVMETHOD(device_attach, usb_attach), + DEVMETHOD(device_detach, usb_detach), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + {0,0} + }, + .size = 0, /* the softc must be set by the attacher! */ +}; + +DRIVER_MODULE(usb, ohci, usb_driver, usb_devclass, 0, 0); +DRIVER_MODULE(usb, uhci, usb_driver, usb_devclass, 0, 0); +DRIVER_MODULE(usb, ehci, usb_driver, usb_devclass, 0, 0); + +MODULE_DEPEND(usb, usb, 1, 1, 1); +MODULE_VERSION(usb, 1); + +static cdevsw_t usb_dummy_cdevsw = { + .d_version = D_VERSION, + .d_open = usb_dummy_open, + .d_name = "usb_dummy_cdev", +}; -/**/ -static const char * const usbrev_str[] = USBREV_STR; +static int +usb_dummy_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +{ + return ENODEV; +} -/* - * usb_discover - explore the device tree from the root - * - * usb_discover device nodes, kthread - */ +/*------------------------------------------------------------------------* + * usb_discover - explore the device tree from the root + *------------------------------------------------------------------------*/ static void usb_discover(struct usbd_bus *bus) { + int32_t error; + PRINTFN(2,("\n")); -#ifdef USB_DEBUG - if(usb_noexplore > 1) - { - return; - } -#endif mtx_assert(&usb_global_lock, MA_OWNED); /* check that only one thread is exploring @@ -144,8 +159,8 @@ { bus->wait_explore = 1; - mtx_sleep(&bus->wait_explore, &usb_global_lock, PWAIT, - "usb wait explore", 0); + error = mtx_sleep(&bus->wait_explore, &usb_global_lock, 0, + "usb wait explore", 0); } bus->is_exploring = 1; @@ -179,6 +194,8 @@ static void usb_event_thread(struct usbd_bus *bus) { + int32_t error; + mtx_lock(&usb_global_lock); while(1) @@ -188,20 +205,11 @@ break; } -#ifdef USB_DEBUG - if(usb_noexplore < 2) -#endif - { - usb_discover(bus); - } + usb_discover(bus); + + error = mtx_sleep(&bus->needs_explore, &usb_global_lock, + 0, "usbevt", hz * 60); -#ifdef USB_DEBUG - mtx_sleep(&bus->needs_explore, &usb_global_lock, PWAIT, - "usbevt", usb_noexplore ? 0 : hz * 60); -#else - mtx_sleep(&bus->needs_explore, &usb_global_lock, PWAIT, - "usbevt", hz * 60); -#endif PRINTFN(2,("woke up\n")); } @@ -231,8 +239,6 @@ return; } -u_int8_t usb_driver_added_refcount; - void usb_needs_probe_and_attach(void) { @@ -286,128 +292,8 @@ return; } -static int -usb_event_get_next(struct usb_event *ue) -{ - struct usb_event_wrapper *uew; - int err; - - mtx_lock(&usb_global_lock); - - uew = TAILQ_FIRST(&usb_events); - - if(uew == NULL) - { - usb_nevents = 0; - err = 0; - } - else - { - *ue = uew->ue; - - TAILQ_REMOVE(&usb_events, uew, next); - - free(uew, M_USBDEV); - - if(usb_nevents) - { - usb_nevents--; - } - err = 1; - } - mtx_unlock(&usb_global_lock); - return (err); -} - -static void -usb_event_add(int type, struct usb_event *uep) -{ - struct usb_event_wrapper *uew; - struct timeval thetime; +/* called from "{ehci,ohci,uhci}_pci_attach()" */ - uew = malloc(sizeof *uew, M_USBDEV, M_WAITOK|M_ZERO); - if(uew == NULL) - { - return; - } - uew->ue = *uep; - uew->ue.ue_type = type; - microtime(&thetime); - TIMEVAL_TO_TIMESPEC(&thetime, &uew->ue.ue_time); - - mtx_lock(&usb_global_lock); - - if(USB_EVENT_IS_DETACH(type)) - { - struct usb_event_wrapper *uewi, *uewi_next; - - for (uewi = TAILQ_FIRST(&usb_events); - uewi; - uewi = uewi_next) - { - uewi_next = TAILQ_NEXT(uewi, next); - if(uewi->ue.u.ue_driver.ue_cookie.cookie == - uep->u.ue_device.udi_cookie.cookie) - { - TAILQ_REMOVE(&usb_events, uewi, next); - free(uewi, M_USBDEV); - usb_nevents--; - uewi_next = TAILQ_FIRST(&usb_events); - } - } - } - if(usb_nevents >= USB_MAX_EVENTS) - { - /* too many queued events, drop an old one */ - PRINTF(("event dropped\n")); - - struct usb_event ue; - (void)usb_event_get_next(&ue); - } - TAILQ_INSERT_TAIL(&usb_events, uew, next); - usb_nevents++; - wakeup(&usb_events); - selwakeuppri(&usb_selevent, PZERO); - if(usb_async_proc != NULL) - { - PROC_LOCK(usb_async_proc); - psignal(usb_async_proc, SIGIO); - PROC_UNLOCK(usb_async_proc); - } - - mtx_unlock(&usb_global_lock); - return; -} - -void -usbd_add_dev_event(int type, struct usbd_device *udev) -{ - struct usb_event ue; - - bzero(&ue, sizeof(ue)); - - usbd_fill_deviceinfo(udev, &ue.u.ue_device, - USB_EVENT_IS_ATTACH(type)); - usb_event_add(type, &ue); - return; -} - -void -usbd_add_drv_event(int type, struct usbd_device *udev, device_t dev) -{ - struct usb_event ue; - - bzero(&ue, sizeof(ue)); - - ue.u.ue_driver.ue_cookie = udev->cookie; - strncpy(ue.u.ue_driver.ue_devname, device_get_nameunit(dev), - sizeof ue.u.ue_driver.ue_devname); - usb_event_add(type, &ue); - return; -} - -/* called from uhci_pci_attach */ - static int usb_probe(device_t dev) { @@ -415,15 +301,12 @@ return (UMATCH_GENERIC); } -extern cdevsw_t usb_cdevsw; - static void __usb_attach(device_t dev, struct usbd_bus *bus) { + dev_clone_fn usb_clone_ptr = &usb_clone; usbd_status err; u_int8_t speed; - struct usb_event ue; - struct cdev *cdev; PRINTF(("\n")); @@ -431,36 +314,38 @@ bus->root_port.power = USB_MAX_POWER; - device_printf(bus->bdev, "USB revision %s", - usbrev_str[bus->usbrev]); + switch (bus->usbrev) { + case USBREV_1_0: + speed = USB_SPEED_FULL; + device_printf(bus->bdev, "12MBps Full Speed USB v1.0\n"); + break; - switch (bus->usbrev) - { - case USBREV_1_0: case USBREV_1_1: speed = USB_SPEED_FULL; + device_printf(bus->bdev, "12MBps Full Speed USB v1.1\n"); break; case USBREV_2_0: speed = USB_SPEED_HIGH; + device_printf(bus->bdev, "480MBps High Speed USB v2.0\n"); + break; + + case USBREV_2_5: + speed = USB_SPEED_VARIABLE; + device_printf(bus->bdev, "Wireless USB v2.5\n"); break; default: - printf(", not supported\n"); + device_printf(bus->bdev, "Unsupported USB revision!\n"); return; } - printf("\n"); - /* make sure not to use tsleep() if we are cold booting */ if(cold) { bus->use_polling++; } - ue.u.ue_ctrlr.ue_bus = device_get_unit(bus->bdev); - usb_event_add(USB_EVENT_CTRLR_ATTACH, &ue); - err = usbd_new_device(bus->bdev, bus, 0, speed, 0, &bus->root_port); if(!err) @@ -495,20 +380,24 @@ usb_create_event_thread(bus); - /* the per controller devices (used for usb_discover) */ - /* XXX This is redundant now, but old usbd's will want it */ - cdev = make_dev(&usb_cdevsw, device_get_unit(dev), UID_ROOT, GID_OPERATOR, - 0660, "usb%d", device_get_unit(dev)); + snprintf(bus->usb_name, sizeof(bus->usb_name), "usb%u", device_get_unit(dev)); + + bus->usb_clone_tag = EVENTHANDLER_REGISTER(dev_clone, usb_clone_ptr, bus, 1000); + if (bus->usb_clone_tag == NULL) { + device_printf(dev, "Registering clone handler failed!\n"); + } + + /* create a dummy device so that we are visible */ + bus->usb_cdev = + make_dev(&usb_dummy_cdevsw, device_get_unit(dev), + UID_ROOT, GID_OPERATOR, 0660, "%s ", bus->usb_name); - if(cdev) - { - DEV2BUS(cdev) = bus; + if (bus->usb_cdev == NULL) { + device_printf(dev, "Creating dummy device failed!\n"); } return; } -static u_int8_t usb_post_init_called = 0; - static int usb_attach(device_t dev) { @@ -572,7 +461,7 @@ usb_detach(device_t dev) { struct usbd_bus *bus = device_get_softc(dev); - struct usb_event ue; + int32_t error; PRINTF(("start\n")); @@ -583,8 +472,8 @@ { bus->wait_explore = 1; - mtx_sleep(&bus->wait_explore, &usb_global_lock, PWAIT, - "usb wait explore", 0); + mtx_sleep(&bus->wait_explore, &usb_global_lock, 0, + "usb wait explore", 0); } /* detach children first */ @@ -604,19 +493,13 @@ { wakeup(&bus->needs_explore); - if(mtx_sleep(bus, &usb_global_lock, PWAIT, "usbdet", hz * 60)) - { - device_printf(bus->bdev, - "event thread didn't die\n"); - } + error = mtx_sleep(bus, &usb_global_lock, 0, "usbdet", 0); + PRINTF(("event thread dead\n")); } mtx_unlock(&usb_global_lock); - ue.u.ue_ctrlr.ue_bus = device_get_unit(bus->bdev); - usb_event_add(USB_EVENT_CTRLR_DETACH, &ue); - mtx_lock(&bus->mtx); if(bus->bdev == dev) { @@ -632,351 +515,345 @@ device_printf(dev, "unexpected bus->bdev value!\n"); } mtx_unlock(&bus->mtx); + + if (bus->usb_cdev) { + destroy_dev(bus->usb_cdev); + bus->usb_cdev = NULL; + } + + if (bus->usb_clone_tag) { + EVENTHANDLER_DEREGISTER(dev_clone, bus->usb_clone_tag); + bus->usb_clone_tag = NULL; + } + + usb_clone_remove(bus); + return (0); } -static int -usbopen(struct cdev *dev, int flag, int mode, struct thread *proc) +static struct usbd_clone * +usb_clone_sub(struct usbd_bus *bus) { - int error = 0; + struct usbd_clone *sub; + int32_t error; + const char *p_name[2]; + char n_name[64]; + + mtx_lock(&(bus->mtx)); + sub = bus->usb_clone_root; + mtx_unlock(&(bus->mtx)); + + while (sub) { + if (!usb_cdev_opened(&(sub->cdev))) { + return sub; + } + sub = sub->next; + } + + sub = malloc(sizeof(*sub), M_USBDEV, M_ZERO|M_WAITOK); + if (sub == NULL) { + return NULL; + } - mtx_lock(&usb_global_lock); + mtx_lock(&(bus->mtx)); + sub->unit = bus->usb_clone_count; + if (bus->usb_clone_count < USB_BUS_MAX_CLONES) { + bus->usb_clone_count ++; + } + mtx_unlock(&(bus->mtx)); - if(DEV2UNIT(dev) == USB_DEV_MINOR) - { - if(usb_dev_open) - { - error = EBUSY; - goto done; - } - usb_dev_open = 1; - usb_async_proc = 0; + if (sub->unit >= USB_BUS_MAX_CLONES) { + /* limit reached */ + goto error; } - else - { - struct usbd_bus *bus = DEV2BUS(dev); + + snprintf(n_name, sizeof(n_name), "%s.%02x", bus->usb_name, sub->unit); + + mtx_init(&(sub->mtx), "usb_clone", NULL, MTX_DEF|MTX_RECURSE); + + p_name[0] = n_name; + p_name[1] = NULL; + + sub->cdev.sc_ioctl = &usb_ioctl; + sub->bus = bus; - if(bus->root_port.device == NULL) - { - /* device is beeing detached */ - error = EIO; - goto done; - } + error = usb_cdev_attach(&(sub->cdev), sub, &(sub->mtx), + p_name, UID_ROOT, GID_OPERATOR, 0660, + 0, 0, 0, 0); + if (error) { + goto error; } - done: - mtx_unlock(&usb_global_lock); - return (error); + /* insert sub-device into a one-way linked list */ + + mtx_lock(&(bus->mtx)); + sub->next = bus->usb_clone_root; + bus->usb_clone_root = sub; + mtx_unlock(&(bus->mtx)); + return sub; + + error: + free(sub, M_USBDEV); + return NULL; } -static int -usbread(struct cdev *dev, struct uio *uio, int flag) +static void +usb_clone_remove(struct usbd_bus *bus) { - struct usb_event ue; - int error = 0; + struct usbd_clone *sub; + struct usbd_clone *next; + uint8_t done = 0; - if(DEV2UNIT(dev) != USB_DEV_MINOR) - { - return (ENODEV); - } + while (1) { - if(uio->uio_resid != sizeof(struct usb_event)) - { - return (EINVAL); - } + /* first prevent any further clones from + * being created: + */ + mtx_lock(&(bus->mtx)); + bus->usb_clone_count = USB_BUS_MAX_CLONES; + sub = bus->usb_clone_root; + bus->usb_clone_root = NULL; + mtx_unlock(&(bus->mtx)); - mtx_lock(&usb_global_lock); + /* XXX wait for any leftover VOP_LOOKUP() calls + * to finish. Really we should lock some lock + * here to lock that problem out! --hps + */ + usb_delay_ms(bus, 500); - for(;;) - { - if(usb_event_get_next(&ue) != 0) - { - break; + if (sub == NULL) { + if (done) { + break; + } else { + done = 1; } - if(flag & IO_NDELAY) - { - error = EWOULDBLOCK; - break; - } - error = mtx_sleep(&usb_events, &usb_global_lock, - (PZERO|PCATCH), "usbrea", 0); - if(error) - { - break; - } - } + } else { + done = 0; + } + + /* teardown all cloned devices */ + while (sub) { + + usb_cdev_detach(&(sub->cdev)); + + next = sub->next; + + mtx_destroy(&(sub->mtx)); - mtx_unlock(&usb_global_lock); + free(sub, M_USBDEV); - if(!error) - { - error = uiomove((void *)&ue, uio->uio_resid, uio); + sub = next; + } } - return (error); + return; } -static int -usbclose(struct cdev *dev, int flag, int mode, struct thread *proc) +static void +usb_clone(void *arg, USB_UCRED char *name, int namelen, struct cdev **dev) { - if(DEV2UNIT(dev) == USB_DEV_MINOR) - { - mtx_lock(&usb_global_lock); + struct usbd_bus *bus = arg; + struct usbd_clone *sub; + + if (*dev) { + return; + } - usb_async_proc = 0; - usb_dev_open = 0; + if (strcmp(name, bus->usb_name) != 0) { + return; + } - mtx_unlock(&usb_global_lock); + sub = usb_clone_sub(bus); + if (sub == NULL) { + return; } - return (0); + + *dev = sub->cdev.sc_cdev[0]; + + dev_ref(*dev); + return; } static int -usbioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *p) +usb_ioctl(struct usb_cdev *dev, u_long cmd, caddr_t addr, + int32_t fflags, struct thread *td) { + struct usbd_clone *sub = dev->sc_priv_ptr; + struct usbd_bus *bus = sub->bus; + struct usbd_device *udev = 0; int error = 0; - mtx_lock(&usb_global_lock); + usb_cdev_unlock(dev, fflags); - if(DEV2UNIT(dev) == USB_DEV_MINOR) - { - switch (cmd) - { - case FIONBIO: - /* all handled in the upper FS layer */ - break; + switch (cmd) { + /* this part should be deleted */ + case USB_DISCOVER: + break; - case FIOASYNC: - if(*(int *)data) - usb_async_proc = p->td_proc; - else - usb_async_proc = 0; - - break; - - default: - error = EINVAL; - break; - } - } - else + case USB_REQUEST: { - struct usbd_bus *bus = DEV2BUS(dev); + struct usb_ctl_request *ur = (void *)addr; + uint16_t len = UGETW(ur->ucr_request.wLength); + uint8_t isread = (ur->ucr_request.bmRequestType & UT_READ) ? 1 : 0; + void *ptr = 0; - if(bus->root_port.device == NULL) - { - /* detached */ - error = EIO; + udev = usbd_ref_device(bus, ur->ucr_addr); + if (udev == NULL) { + error = ENXIO; goto done; } - switch (cmd) - { - /* this part should be deleted */ - case USB_DISCOVER: - break; - case USB_REQUEST: - { - struct usb_ctl_request *ur = (void *)data; - int len = UGETW(ur->ucr_request.wLength); - struct iovec iov; - struct uio uio; - void *ptr = 0; - int addr = ur->ucr_addr; - usbd_status err; - int error = 0; + PRINTF(("USB_REQUEST addr=%d len=%d\n", ur->ucr_addr, len)); - PRINTF(("USB_REQUEST addr=%d len=%d\n", addr, len)); - if((len < 0) || - (len > 32768)) - { - error = EINVAL; - goto done; + if (len != 0) { + ptr = malloc(len, M_TEMP, M_WAITOK); + if (ptr == NULL) { + error = ENOMEM; + goto ret001; } - - if((addr < 0) || - (addr >= USB_MAX_DEVICES) || - (bus->devices[addr] == 0 /* might be checked by usbd_do_request_flags */)) - { - error = EINVAL; - goto done; - } - - if(len != 0) - { - iov.iov_base = (caddr_t)ur->ucr_data; - iov.iov_len = len; - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - uio.uio_resid = len; - uio.uio_offset = 0; - uio.uio_segflg = UIO_USERSPACE; - uio.uio_rw = - ur->ucr_request.bmRequestType & UT_READ ? - UIO_READ : UIO_WRITE; - uio.uio_procp = p; - ptr = malloc(len, M_TEMP, M_WAITOK); - if(uio.uio_rw == UIO_WRITE) - { - error = uiomove(ptr, len, &uio); - if(error) - { - goto ret; - } - } - } - err = usbd_do_request_flags - (bus->devices[addr], &ur->ucr_request, ptr, - ur->ucr_flags, &ur->ucr_actlen, - USBD_DEFAULT_TIMEOUT); - if(err) - { - error = EIO; - goto ret; - } - if(len != 0) - { - if(uio.uio_rw == UIO_READ) - { - error = uiomove(ptr, len, &uio); - if(error) - { - goto ret; - } + if (isread == 0) { + error = copyin(ur->ucr_data, ptr, len); + if (error) { + goto ret001; } } - ret: - if(ptr) - { - free(ptr, M_TEMP); - } - goto done; } - case USB_DEVICEINFO: - { - struct usb_device_info *di = (void *)data; - int addr = di->udi_addr; + mtx_lock(dev->sc_mtx_ptr); + error = usbd_do_request_flags_mtx + (udev, dev->sc_mtx_ptr, &ur->ucr_request, ptr, ur->ucr_flags, + &ur->ucr_actlen, USBD_DEFAULT_TIMEOUT); + mtx_unlock(dev->sc_mtx_ptr); + + if (error) { + error = EIO; + goto ret001; + } - if((addr < 1) || - (addr >= USB_MAX_DEVICES)) - { - error = EINVAL; - goto done; + if (len != 0) { + if (isread) { + error = copyout(ptr, ur->ucr_data, len); + if (error) { + goto ret001; + } } + } + ret001: + if (ptr) { + free(ptr, M_TEMP); + } + usbd_unref_device(udev); + goto done; + } - if (bus->devices[addr] == 0) - { - error = ENXIO; - goto done; - } + case USB_DEVICEINFO: + { + struct usb_device_info *di = (void *)addr; - error = usbd_fill_deviceinfo(bus->devices[addr], di, 1); - goto done; + udev = usbd_ref_device(bus, di->udi_addr); + if (udev == NULL) { + error = ENXIO; + goto done; } - case USB_DEVICESTATS: - *(struct usb_device_stats *)data = bus->stats; - break; + error = usbd_fill_deviceinfo(udev, di, 1); - default: - error = EINVAL; - break; - } + usbd_unref_device(udev); + goto done; } - done: - mtx_unlock(&usb_global_lock); - return (error); -} + case USB_DEVICESTATS: + *(struct usb_device_stats *)addr = bus->stats; + break; -static int -usbpoll(struct cdev *dev, int events, struct thread *td) -{ - int revents, mask; - int unit = DEV2UNIT(dev); + case USB_DEVICEENUMERATE: + { + struct usb_device_enumerate *ude = (void *)addr; + struct usbd_port *pp; + usb_port_status_t ps; + uint8_t old_addr; + uint8_t buf[8]; - if(unit == USB_DEV_MINOR) - { - revents = 0; - mask = POLLIN | POLLRDNORM; + udev = usbd_ref_device(bus, ude->ude_addr); + if (udev == NULL) { + error = ENXIO; + goto done; + } - mtx_lock(&usb_global_lock); + old_addr = udev->address; + pp = udev->powersrc; + if (pp == NULL) { + error = EINVAL; + goto ret002; + } - if((events & mask) && (usb_nevents > 0)) - { - revents |= events & mask; + error = usbreq_reset_port(pp->parent, pp->portno, &ps); + if (error) { + error = ENXIO; + goto ret002; } - if((revents == 0) && (events & mask)) - { - selrecord(td, &usb_selevent); + + /* After that the port has been reset + * our device should be at address + * zero: + */ + udev->address = 0; + + /* It should be allowed to read some descriptors + * from address zero: + */ + error = usbreq_get_desc(udev, UDESC_DEVICE, 0, 8, buf, 0); + if (error) { >>> TRUNCATED FOR MAIL (1000 lines) <<<