summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/usb_debug.c
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2012-10-24 07:23:29 +0000
committerhselasky <hselasky@FreeBSD.org>2012-10-24 07:23:29 +0000
commitddc1ceecb37fd6540ef54cf3194f65a36fd330e0 (patch)
treeb2f5dc26223f979365eae70ebbdf09f90d4c8dbd /sys/dev/usb/usb_debug.c
parent63a4ea167200b31a05ebe40e5f607b26ec0a7c78 (diff)
downloadFreeBSD-src-ddc1ceecb37fd6540ef54cf3194f65a36fd330e0.zip
FreeBSD-src-ddc1ceecb37fd6540ef54cf3194f65a36fd330e0.tar.gz
Make several timing parameters of the USB enumeration sequence tuneable.
Also update the port reset time from 250ms to 50ms. Some USB devices have a hard limit in hardware at 222ms for the port reset time and will not enumerate unless this delay is closer to the usb.org defined value. This patch can fix enumeration with some USB devices. Tested by: Guido van Rooij Submitted by: Nick Hibma MFC after: 1 week
Diffstat (limited to 'sys/dev/usb/usb_debug.c')
-rw-r--r--sys/dev/usb/usb_debug.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/sys/dev/usb/usb_debug.c b/sys/dev/usb/usb_debug.c
index ae0db7f..1e43063 100644
--- a/sys/dev/usb/usb_debug.c
+++ b/sys/dev/usb/usb_debug.c
@@ -68,6 +68,55 @@ SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW,
TUNABLE_INT("hw.usb.debug", &usb_debug);
+#ifdef USB_DEBUG
+/*
+ * Sysctls to modify timings/delays
+ */
+static SYSCTL_NODE(_hw_usb, OID_AUTO, timings, CTLFLAG_RW, 0, "Timings");
+static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS);
+
+TUNABLE_INT("hw.usb.timings.port_reset_delay", (int *)&usb_port_reset_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_reset_delay, CTLTYPE_UINT | CTLFLAG_RW,
+ &usb_port_reset_delay, sizeof(usb_port_reset_delay),
+ usb_timings_sysctl_handler, "IU", "Port Reset Delay");
+TUNABLE_INT("hw.usb.timings.port_root_reset_delay", (int *)&usb_port_root_reset_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_root_reset_delay, CTLTYPE_UINT | CTLFLAG_RW,
+ &usb_port_root_reset_delay, sizeof(usb_port_root_reset_delay),
+ usb_timings_sysctl_handler, "IU", "Root Port Reset Delay");
+TUNABLE_INT("hw.usb.timings.port_reset_recovery", (int *)&usb_port_reset_recovery);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_reset_recovery, CTLTYPE_UINT | CTLFLAG_RW,
+ &usb_port_reset_recovery, sizeof(usb_port_reset_recovery),
+ usb_timings_sysctl_handler, "IU", "Port Reset Recovery");
+TUNABLE_INT("hw.usb.timings.port_powerup_delay", (int *)&usb_port_powerup_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_powerup_delay, CTLTYPE_UINT | CTLFLAG_RW,
+ &usb_port_powerup_delay, sizeof(usb_port_powerup_delay),
+ usb_timings_sysctl_handler, "IU", "Port PowerUp Delay");
+TUNABLE_INT("hw.usb.timings.port_resume_delay", (int *)&usb_port_resume_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_resume_delay, CTLTYPE_UINT | CTLFLAG_RW,
+ &usb_port_resume_delay, sizeof(usb_port_resume_delay),
+ usb_timings_sysctl_handler, "IU", "Port Resume Delay");
+TUNABLE_INT("hw.usb.timings.set_address_settle", (int *)&usb_set_address_settle);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, set_address_settle, CTLTYPE_UINT | CTLFLAG_RW,
+ &usb_set_address_settle, sizeof(usb_set_address_settle),
+ usb_timings_sysctl_handler, "IU", "Set Address Settle");
+TUNABLE_INT("hw.usb.timings.resume_delay", (int *)&usb_resume_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_delay, CTLTYPE_UINT | CTLFLAG_RW,
+ &usb_resume_delay, sizeof(usb_resume_delay),
+ usb_timings_sysctl_handler, "IU", "Resume Delay");
+TUNABLE_INT("hw.usb.timings.resume_wait", (int *)&usb_resume_wait);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_wait, CTLTYPE_UINT | CTLFLAG_RW,
+ &usb_resume_wait, sizeof(usb_resume_wait),
+ usb_timings_sysctl_handler, "IU", "Resume Wait");
+TUNABLE_INT("hw.usb.timings.resume_recovery", (int *)&usb_resume_recovery);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_recovery, CTLTYPE_UINT | CTLFLAG_RW,
+ &usb_resume_recovery, sizeof(usb_resume_recovery),
+ usb_timings_sysctl_handler, "IU", "Resume Recovery");
+TUNABLE_INT("hw.usb.timings.extra_power_up_time", (int *)&usb_extra_power_up_time);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, extra_power_up_time, CTLTYPE_UINT | CTLFLAG_RW,
+ &usb_extra_power_up_time, sizeof(usb_extra_power_up_time),
+ usb_timings_sysctl_handler, "IU", "Extra PowerUp Time");
+#endif
+
/*------------------------------------------------------------------------*
* usb_dump_iface
*
@@ -176,3 +225,87 @@ usb_dump_xfer(struct usb_xfer *xfer)
xfer->endpoint->edesc->bEndpointAddress,
xfer->endpoint->edesc->bmAttributes);
}
+
+#ifdef USB_DEBUG
+unsigned int usb_port_reset_delay = USB_PORT_RESET_DELAY;
+unsigned int usb_port_root_reset_delay = USB_PORT_ROOT_RESET_DELAY;
+unsigned int usb_port_reset_recovery = USB_PORT_RESET_RECOVERY;
+unsigned int usb_port_powerup_delay = USB_PORT_POWERUP_DELAY;
+unsigned int usb_port_resume_delay = USB_PORT_RESUME_DELAY;
+unsigned int usb_set_address_settle = USB_SET_ADDRESS_SETTLE;
+unsigned int usb_resume_delay = USB_RESUME_DELAY;
+unsigned int usb_resume_wait = USB_RESUME_WAIT;
+unsigned int usb_resume_recovery = USB_RESUME_RECOVERY;
+unsigned int usb_extra_power_up_time = USB_EXTRA_POWER_UP_TIME;
+
+/*------------------------------------------------------------------------*
+ * usb_timings_sysctl_handler
+ *
+ * This function updates timings variables, adjusting them where necessary.
+ *------------------------------------------------------------------------*/
+static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS)
+{
+ int error = 0;
+ unsigned int val;
+
+ /*
+ * Attempt to get a coherent snapshot by making a copy of the data.
+ */
+ if (arg1)
+ val = *(unsigned int *)arg1;
+ else
+ val = arg2;
+ error = SYSCTL_OUT(req, &val, sizeof(int));
+ if (error || !req->newptr)
+ return (error);
+
+ if (!arg1)
+ return EPERM;
+
+ error = SYSCTL_IN(req, &val, sizeof(unsigned int));
+ if (error)
+ return (error);
+
+ /*
+ * Now make sure the values are decent, and certainly no lower than
+ * what the USB spec prescribes.
+ */
+ unsigned int *p = (unsigned int *)arg1;
+ if (p == &usb_port_reset_delay) {
+ if (val < USB_PORT_RESET_DELAY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_port_root_reset_delay) {
+ if (val < USB_PORT_ROOT_RESET_DELAY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_port_reset_recovery) {
+ if (val < USB_PORT_RESET_RECOVERY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_port_powerup_delay) {
+ if (val < USB_PORT_POWERUP_DELAY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_port_resume_delay) {
+ if (val < USB_PORT_RESUME_DELAY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_set_address_settle) {
+ if (val < USB_SET_ADDRESS_SETTLE_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_resume_delay) {
+ if (val < USB_RESUME_DELAY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_resume_wait) {
+ if (val < USB_RESUME_WAIT_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_resume_recovery) {
+ if (val < USB_RESUME_RECOVERY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_extra_power_up_time) {
+ if (val < USB_EXTRA_POWER_UP_TIME_SPEC)
+ return (EINVAL);
+ } else {
+ /* noop */
+ }
+
+ *p = val;
+ return 0;
+}
+#endif
OpenPOWER on IntegriCloud