summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2014-10-27 09:07:30 +0000
committerhselasky <hselasky@FreeBSD.org>2014-10-27 09:07:30 +0000
commit14fa4d63cd31d3abf0793390e0bbd0f0e5eb9ab0 (patch)
tree0efd108762b6b939b04123c0e318baaa796ebb50
parent9fbf4aa76f6bfe680ff2708112548494826c6d14 (diff)
downloadFreeBSD-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.h1
-rw-r--r--sys/dev/usb/usb_freebsd_loader.h1
-rw-r--r--sys/dev/usb/usb_hub.c92
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",
OpenPOWER on IntegriCloud