diff options
author | hselasky <hselasky@FreeBSD.org> | 2014-10-27 09:07:30 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2014-10-27 09:07:30 +0000 |
commit | 14fa4d63cd31d3abf0793390e0bbd0f0e5eb9ab0 (patch) | |
tree | 0efd108762b6b939b04123c0e318baaa796ebb50 | |
parent | 9fbf4aa76f6bfe680ff2708112548494826c6d14 (diff) | |
download | FreeBSD-src-14fa4d63cd31d3abf0793390e0bbd0f0e5eb9ab0.zip FreeBSD-src-14fa4d63cd31d3abf0793390e0bbd0f0e5eb9ab0.tar.gz |
MFC r272733, r272807 and r272822:
Add support for disabling USB enumeration or USB port power
in general or on selected USB HUBs.
-rw-r--r-- | sys/dev/usb/usb_freebsd.h | 1 | ||||
-rw-r--r-- | sys/dev/usb/usb_freebsd_loader.h | 1 | ||||
-rw-r--r-- | sys/dev/usb/usb_hub.c | 92 |
3 files changed, 83 insertions, 11 deletions
diff --git a/sys/dev/usb/usb_freebsd.h b/sys/dev/usb/usb_freebsd.h index 0c483e5..7ae5c9b 100644 --- a/sys/dev/usb/usb_freebsd.h +++ b/sys/dev/usb/usb_freebsd.h @@ -49,6 +49,7 @@ #define USB_HAVE_FIXED_IFACE 0 #define USB_HAVE_FIXED_CONFIG 0 #define USB_HAVE_FIXED_PORT 0 +#define USB_HAVE_DISABLE_ENUM 1 /* define zero ticks callout value */ #define USB_CALLOUT_ZERO_TICKS 1 diff --git a/sys/dev/usb/usb_freebsd_loader.h b/sys/dev/usb/usb_freebsd_loader.h index 68343d2..7d8281a 100644 --- a/sys/dev/usb/usb_freebsd_loader.h +++ b/sys/dev/usb/usb_freebsd_loader.h @@ -49,6 +49,7 @@ #define USB_HAVE_FIXED_IFACE 0 #define USB_HAVE_FIXED_CONFIG 0 #define USB_HAVE_FIXED_PORT 0 +#define USB_HAVE_DISABLE_ENUM 0 #define USB_CALLOUT_ZERO_TICKS 1 diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c index 2b2cee7..a590453 100644 --- a/sys/dev/usb/usb_hub.c +++ b/sys/dev/usb/usb_hub.c @@ -98,6 +98,18 @@ SYSCTL_INT(_hw_usb, OID_AUTO, power_timeout, CTLFLAG_RW, &usb_power_timeout, 0, "USB power timeout"); #endif +#if USB_HAVE_DISABLE_ENUM +static int usb_disable_enumeration = 0; +SYSCTL_INT(_hw_usb, OID_AUTO, disable_enumeration, CTLFLAG_RWTUN, + &usb_disable_enumeration, 0, "Set to disable all USB device enumeration."); +TUNABLE_INT("hw.usb.disable_enumeration", &usb_disable_enumeration); + +static int usb_disable_port_power = 0; +SYSCTL_INT(_hw_usb, OID_AUTO, disable_port_power, CTLFLAG_RWTUN, + &usb_disable_port_power, 0, "Set to disable all USB port power."); +TUNABLE_INT("hw.usb.disable_port_power", &usb_disable_port_power); +#endif + struct uhub_current_state { uint16_t port_change; uint16_t port_status; @@ -112,6 +124,10 @@ struct uhub_softc { struct mtx sc_mtx; /* our mutex */ struct usb_device *sc_udev; /* USB device */ struct usb_xfer *sc_xfer[UHUB_N_TRANSFER]; /* interrupt xfer */ +#if USB_HAVE_DISABLE_ENUM + int sc_disable_enumeration; + int sc_disable_port_power; +#endif uint8_t sc_flags; #define UHUB_FLAG_DID_EXPLORE 0x01 }; @@ -619,9 +635,9 @@ repeat: err = usbd_req_clear_port_feature(udev, NULL, portno, UHF_C_PORT_CONNECTION); - if (err) { + if (err) goto error; - } + /* check if there is a child */ if (child != NULL) { @@ -634,14 +650,22 @@ repeat: /* get fresh status */ err = uhub_read_port_status(sc, portno); - if (err) { + if (err) + goto error; + +#if USB_HAVE_DISABLE_ENUM + /* check if we should skip enumeration from this USB HUB */ + if (usb_disable_enumeration != 0 || + sc->sc_disable_enumeration != 0) { + DPRINTF("Enumeration is disabled!\n"); goto error; } +#endif /* check if nothing is connected to the port */ - if (!(sc->sc_st.port_status & UPS_CURRENT_CONNECT_STATUS)) { + if (!(sc->sc_st.port_status & UPS_CURRENT_CONNECT_STATUS)) goto error; - } + /* check if there is no power on the port and print a warning */ switch (udev->speed) { @@ -1189,6 +1213,10 @@ uhub_attach(device_t dev) struct usb_hub *hub; struct usb_hub_descriptor hubdesc20; struct usb_hub_ss_descriptor hubdesc30; +#if USB_HAVE_DISABLE_ENUM + struct sysctl_ctx_list *sysctl_ctx; + struct sysctl_oid *sysctl_tree; +#endif uint16_t pwrdly; uint16_t nports; uint8_t x; @@ -1386,6 +1414,34 @@ uhub_attach(device_t dev) /* wait with power off for a while */ usb_pause_mtx(NULL, USB_MS_TO_TICKS(USB_POWER_DOWN_TIME)); +#if USB_HAVE_DISABLE_ENUM + /* Add device sysctls */ + + sysctl_ctx = device_get_sysctl_ctx(dev); + sysctl_tree = device_get_sysctl_tree(dev); + + if (sysctl_ctx != NULL && sysctl_tree != NULL) { + char path[128]; + + snprintf(path, sizeof(path), "dev.uhub.%d.disable_enumeration", + device_get_unit(dev)); + TUNABLE_INT_FETCH(path, &sc->sc_disable_enumeration); + + (void) SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "disable_enumeration", CTLFLAG_RWTUN, + &sc->sc_disable_enumeration, 0, + "Set to disable enumeration on this USB HUB."); + + snprintf(path, sizeof(path), "dev.uhub.%d.disable_port_power", + device_get_unit(dev)); + TUNABLE_INT_FETCH(path, &sc->sc_disable_port_power); + + (void) SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "disable_port_power", CTLFLAG_RWTUN, + &sc->sc_disable_port_power, 0, + "Set to disable USB port power on this USB HUB."); + } +#endif /* * To have the best chance of success we do things in the exact same * order as Windoze98. This should not be necessary, but some @@ -1440,13 +1496,27 @@ uhub_attach(device_t dev) removable++; break; } - if (!err) { - /* turn the power on */ - err = usbd_req_set_port_feature(udev, NULL, - portno, UHF_PORT_POWER); + if (err == 0) { +#if USB_HAVE_DISABLE_ENUM + /* check if we should disable USB port power or not */ + if (usb_disable_port_power != 0 || + sc->sc_disable_port_power != 0) { + /* turn the power off */ + DPRINTFN(0, "Turning port %d power off\n", portno); + err = usbd_req_clear_port_feature(udev, NULL, + portno, UHF_PORT_POWER); + } else { +#endif + /* turn the power on */ + DPRINTFN(0, "Turning port %d power on\n", portno); + err = usbd_req_set_port_feature(udev, NULL, + portno, UHF_PORT_POWER); +#if USB_HAVE_DISABLE_ENUM + } +#endif } - if (err) { - DPRINTFN(0, "port %d power on failed, %s\n", + if (err != 0) { + DPRINTFN(0, "port %d power on or off failed, %s\n", portno, usbd_errstr(err)); } DPRINTF("turn on port %d power\n", |