diff options
Diffstat (limited to 'freebsd/sys/dev/usb/usb_generic.c')
-rw-r--r-- | freebsd/sys/dev/usb/usb_generic.c | 84 |
1 files changed, 56 insertions, 28 deletions
diff --git a/freebsd/sys/dev/usb/usb_generic.c b/freebsd/sys/dev/usb/usb_generic.c index a0b7f007..e1fc141f 100644 --- a/freebsd/sys/dev/usb/usb_generic.c +++ b/freebsd/sys/dev/usb/usb_generic.c @@ -612,24 +612,17 @@ ugen_set_config(struct usb_fifo *f, uint8_t index) /* not possible in device side mode */ return (ENOTTY); } - if (f->udev->curr_config_index == index) { - /* no change needed */ - return (0); - } + /* make sure all FIFO's are gone */ /* else there can be a deadlock */ if (ugen_fs_uninit(f)) { /* ignore any errors */ DPRINTFN(6, "no FIFOs\n"); } - /* change setting - will free generic FIFOs, if any */ - if (usbd_set_config_index(f->udev, index)) { - return (EIO); - } - /* probe and attach */ - if (usb_probe_and_attach(f->udev, USB_IFACE_INDEX_ANY)) { + + if (usbd_start_set_config(f->udev, index) != 0) return (EIO); - } + return (0); } @@ -963,11 +956,6 @@ ugen_re_enumerate(struct usb_fifo *f) DPRINTFN(6, "device mode\n"); return (ENOTTY); } - if (udev->parent_hub == NULL) { - /* the root HUB cannot be re-enumerated */ - DPRINTFN(6, "cannot reset root HUB\n"); - return (EINVAL); - } /* make sure all FIFO's are gone */ /* else there can be a deadlock */ if (ugen_fs_uninit(f)) { @@ -1751,16 +1739,11 @@ ugen_set_power_mode(struct usb_fifo *f, int mode) switch (mode) { case USB_POWER_MODE_OFF: - /* get the device unconfigured */ - err = ugen_set_config(f, USB_UNCONFIG_INDEX); - if (err) { - DPRINTFN(0, "Could not unconfigure " - "device (ignored)\n"); + if (udev->flags.usb_mode == USB_MODE_HOST && + udev->re_enumerate_wait == USB_RE_ENUM_DONE) { + udev->re_enumerate_wait = USB_RE_ENUM_PWR_OFF; } - - /* clear port enable */ - err = usbd_req_clear_port_feature(udev->parent_hub, - NULL, udev->port_no, UHF_PORT_ENABLE); + /* set power mode will wake up the explore thread */ break; case USB_POWER_MODE_ON: @@ -1808,9 +1791,9 @@ ugen_set_power_mode(struct usb_fifo *f, int mode) /* if we are powered off we need to re-enumerate first */ if (old_mode == USB_POWER_MODE_OFF) { - if (udev->flags.usb_mode == USB_MODE_HOST) { - if (udev->re_enumerate_wait == 0) - udev->re_enumerate_wait = 1; + if (udev->flags.usb_mode == USB_MODE_HOST && + udev->re_enumerate_wait == USB_RE_ENUM_DONE) { + udev->re_enumerate_wait = USB_RE_ENUM_START; } /* set power mode will wake up the explore thread */ } @@ -1833,6 +1816,46 @@ ugen_get_power_mode(struct usb_fifo *f) } static int +ugen_get_port_path(struct usb_fifo *f, struct usb_device_port_path *dpp) +{ + struct usb_device *udev = f->udev; + struct usb_device *next; + unsigned int nlevel = 0; + + if (udev == NULL) + goto error; + + dpp->udp_bus = device_get_unit(udev->bus->bdev); + dpp->udp_index = udev->device_index; + + /* count port levels */ + next = udev; + while (next->parent_hub != NULL) { + nlevel++; + next = next->parent_hub; + } + + /* check if too many levels */ + if (nlevel > USB_DEVICE_PORT_PATH_MAX) + goto error; + + /* store port index array */ + next = udev; + while (next->parent_hub != NULL) { + nlevel--; + + dpp->udp_port_no[nlevel] = next->port_no; + dpp->udp_port_level = nlevel; + + next = next->parent_hub; + } + return (0); /* success */ + +error: + return (EINVAL); /* failure */ +} + +static int ugen_get_power_usage(struct usb_fifo *f) { struct usb_device *udev = f->udev; @@ -2033,6 +2056,7 @@ ugen_ioctl_post(struct usb_fifo *f, u_long cmd, void *addr, int fflags) struct usb_device_stats *stat; struct usb_fs_init *pinit; struct usb_fs_uninit *puninit; + struct usb_device_port_path *dpp; uint32_t *ptime; void *addr; int *pint; @@ -2205,6 +2229,10 @@ ugen_ioctl_post(struct usb_fifo *f, u_long cmd, void *addr, int fflags) *u.pint = ugen_get_power_mode(f); break; + case USB_GET_DEV_PORT_PATH: + error = ugen_get_port_path(f, u.dpp); + break; + case USB_GET_POWER_USAGE: *u.pint = ugen_get_power_usage(f); break; |