summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/usb/usb_generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/dev/usb/usb_generic.c')
-rw-r--r--freebsd/sys/dev/usb/usb_generic.c84
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;