1 /* $FreeBSD: head/sys/dev/usb/usb_debug.c 267992 2014-06-28 03:56:17Z hselasky $ */ 2 /*- 3 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/stdint.h> 28 #include <sys/queue.h> 29 #include <sys/types.h> 30 #include <sys/systm.h> 31 #include <sys/kernel.h> 32 #include <sys/bus.h> 33 #include <sys/module.h> 34 #include <sys/lock.h> 35 #include <sys/condvar.h> 36 #include <sys/sysctl.h> 37 #include <sys/unistd.h> 38 #include <sys/callout.h> 39 #include <sys/malloc.h> 40 #include <sys/priv.h> 41 42 #include <bus/u4b/usb.h> 43 #include <bus/u4b/usbdi.h> 44 45 #include <bus/u4b/usb_core.h> 46 #include <bus/u4b/usb_debug.h> 47 #include <bus/u4b/usb_process.h> 48 #include <bus/u4b/usb_device.h> 49 #include <bus/u4b/usb_busdma.h> 50 #include <bus/u4b/usb_transfer.h> 51 52 #include <ddb/ddb.h> 53 #include <ddb/db_sym.h> 54 55 /* 56 * Define this unconditionally in case a kernel module is loaded that 57 * has been compiled with debugging options. 58 */ 59 int usb_debug = 0; 60 61 SYSCTL_NODE(_hw, OID_AUTO, usb, CTLFLAG_RW, 0, "USB debugging"); 62 SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW, 63 &usb_debug, 0, "Debug level"); 64 65 TUNABLE_INT("hw.usb.debug", &usb_debug); 66 67 #ifdef USB_DEBUG 68 /* 69 * Sysctls to modify timings/delays 70 */ 71 static SYSCTL_NODE(_hw_usb, OID_AUTO, timings, CTLFLAG_RW, 0, "Timings"); 72 static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS); 73 74 TUNABLE_INT("hw.usb.timings.port_reset_delay", (int *)&usb_port_reset_delay); 75 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_reset_delay, CTLTYPE_UINT | CTLFLAG_RW, 76 &usb_port_reset_delay, sizeof(usb_port_reset_delay), 77 usb_timings_sysctl_handler, "IU", "Port Reset Delay"); 78 TUNABLE_INT("hw.usb.timings.port_root_reset_delay", (int *)&usb_port_root_reset_delay); 79 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_root_reset_delay, CTLTYPE_UINT | CTLFLAG_RW, 80 &usb_port_root_reset_delay, sizeof(usb_port_root_reset_delay), 81 usb_timings_sysctl_handler, "IU", "Root Port Reset Delay"); 82 TUNABLE_INT("hw.usb.timings.port_reset_recovery", (int *)&usb_port_reset_recovery); 83 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_reset_recovery, CTLTYPE_UINT | CTLFLAG_RW, 84 &usb_port_reset_recovery, sizeof(usb_port_reset_recovery), 85 usb_timings_sysctl_handler, "IU", "Port Reset Recovery"); 86 TUNABLE_INT("hw.usb.timings.port_powerup_delay", (int *)&usb_port_powerup_delay); 87 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_powerup_delay, CTLTYPE_UINT | CTLFLAG_RW, 88 &usb_port_powerup_delay, sizeof(usb_port_powerup_delay), 89 usb_timings_sysctl_handler, "IU", "Port PowerUp Delay"); 90 TUNABLE_INT("hw.usb.timings.port_resume_delay", (int *)&usb_port_resume_delay); 91 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_resume_delay, CTLTYPE_UINT | CTLFLAG_RW, 92 &usb_port_resume_delay, sizeof(usb_port_resume_delay), 93 usb_timings_sysctl_handler, "IU", "Port Resume Delay"); 94 TUNABLE_INT("hw.usb.timings.set_address_settle", (int *)&usb_set_address_settle); 95 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, set_address_settle, CTLTYPE_UINT | CTLFLAG_RW, 96 &usb_set_address_settle, sizeof(usb_set_address_settle), 97 usb_timings_sysctl_handler, "IU", "Set Address Settle"); 98 TUNABLE_INT("hw.usb.timings.resume_delay", (int *)&usb_resume_delay); 99 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_delay, CTLTYPE_UINT | CTLFLAG_RW, 100 &usb_resume_delay, sizeof(usb_resume_delay), 101 usb_timings_sysctl_handler, "IU", "Resume Delay"); 102 TUNABLE_INT("hw.usb.timings.resume_wait", (int *)&usb_resume_wait); 103 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_wait, CTLTYPE_UINT | CTLFLAG_RW, 104 &usb_resume_wait, sizeof(usb_resume_wait), 105 usb_timings_sysctl_handler, "IU", "Resume Wait"); 106 TUNABLE_INT("hw.usb.timings.resume_recovery", (int *)&usb_resume_recovery); 107 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_recovery, CTLTYPE_UINT | CTLFLAG_RW, 108 &usb_resume_recovery, sizeof(usb_resume_recovery), 109 usb_timings_sysctl_handler, "IU", "Resume Recovery"); 110 TUNABLE_INT("hw.usb.timings.extra_power_up_time", (int *)&usb_extra_power_up_time); 111 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, extra_power_up_time, CTLTYPE_UINT | CTLFLAG_RW, 112 &usb_extra_power_up_time, sizeof(usb_extra_power_up_time), 113 usb_timings_sysctl_handler, "IU", "Extra PowerUp Time"); 114 #endif 115 116 /*------------------------------------------------------------------------* 117 * usb_dump_iface 118 * 119 * This function dumps information about an USB interface. 120 *------------------------------------------------------------------------*/ 121 void 122 usb_dump_iface(struct usb_interface *iface) 123 { 124 kprintf("usb_dump_iface: iface=%p\n", iface); 125 if (iface == NULL) { 126 return; 127 } 128 kprintf(" iface=%p idesc=%p altindex=%d\n", 129 iface, iface->idesc, iface->alt_index); 130 } 131 132 /*------------------------------------------------------------------------* 133 * usb_dump_device 134 * 135 * This function dumps information about an USB device. 136 *------------------------------------------------------------------------*/ 137 void 138 usb_dump_device(struct usb_device *udev) 139 { 140 kprintf("usb_dump_device: dev=%p\n", udev); 141 if (udev == NULL) { 142 return; 143 } 144 kprintf(" bus=%p \n" 145 " address=%d config=%d depth=%d speed=%d self_powered=%d\n" 146 " power=%d langid=%d\n", 147 udev->bus, 148 udev->address, udev->curr_config_no, udev->depth, udev->speed, 149 udev->flags.self_powered, udev->power, udev->langid); 150 } 151 152 /*------------------------------------------------------------------------* 153 * usb_dump_queue 154 * 155 * This function dumps the USB transfer that are queued up on an USB endpoint. 156 *------------------------------------------------------------------------*/ 157 void 158 usb_dump_queue(struct usb_endpoint *ep) 159 { 160 struct usb_xfer *xfer; 161 usb_stream_t x; 162 163 kprintf("usb_dump_queue: endpoint=%p xfer: ", ep); 164 for (x = 0; x != USB_MAX_EP_STREAMS; x++) { 165 TAILQ_FOREACH(xfer, &ep->endpoint_q[x].head, wait_entry) { 166 kprintf(" %p", xfer); 167 } 168 } 169 kprintf("\n"); 170 } 171 172 /*------------------------------------------------------------------------* 173 * usb_dump_endpoint 174 * 175 * This function dumps information about an USB endpoint. 176 *------------------------------------------------------------------------*/ 177 void 178 usb_dump_endpoint(struct usb_endpoint *ep) 179 { 180 if (ep) { 181 kprintf("usb_dump_endpoint: endpoint=%p", ep); 182 183 kprintf(" edesc=%p isoc_next=%d toggle_next=%d", 184 ep->edesc, ep->isoc_next, ep->toggle_next); 185 186 if (ep->edesc) { 187 kprintf(" bEndpointAddress=0x%02x", 188 ep->edesc->bEndpointAddress); 189 } 190 kprintf("\n"); 191 usb_dump_queue(ep); 192 } else { 193 kprintf("usb_dump_endpoint: endpoint=NULL\n"); 194 } 195 } 196 197 /*------------------------------------------------------------------------* 198 * usb_dump_xfer 199 * 200 * This function dumps information about an USB transfer. 201 *------------------------------------------------------------------------*/ 202 void 203 usb_dump_xfer(struct usb_xfer *xfer) 204 { 205 struct usb_device *udev; 206 kprintf("usb_dump_xfer: xfer=%p\n", xfer); 207 if (xfer == NULL) { 208 return; 209 } 210 if (xfer->endpoint == NULL) { 211 kprintf("xfer %p: endpoint=NULL\n", 212 xfer); 213 return; 214 } 215 udev = xfer->xroot->udev; 216 kprintf("xfer %p: udev=%p vid=0x%04x pid=0x%04x addr=%d " 217 "endpoint=%p ep=0x%02x attr=0x%02x\n", 218 xfer, udev, 219 UGETW(udev->ddesc.idVendor), 220 UGETW(udev->ddesc.idProduct), 221 udev->address, xfer->endpoint, 222 xfer->endpoint->edesc->bEndpointAddress, 223 xfer->endpoint->edesc->bmAttributes); 224 } 225 226 #ifdef USB_DEBUG 227 unsigned int usb_port_reset_delay = USB_PORT_RESET_DELAY; 228 unsigned int usb_port_root_reset_delay = USB_PORT_ROOT_RESET_DELAY; 229 unsigned int usb_port_reset_recovery = USB_PORT_RESET_RECOVERY; 230 unsigned int usb_port_powerup_delay = USB_PORT_POWERUP_DELAY; 231 unsigned int usb_port_resume_delay = USB_PORT_RESUME_DELAY; 232 unsigned int usb_set_address_settle = USB_SET_ADDRESS_SETTLE; 233 unsigned int usb_resume_delay = USB_RESUME_DELAY; 234 unsigned int usb_resume_wait = USB_RESUME_WAIT; 235 unsigned int usb_resume_recovery = USB_RESUME_RECOVERY; 236 unsigned int usb_extra_power_up_time = USB_EXTRA_POWER_UP_TIME; 237 238 /*------------------------------------------------------------------------* 239 * usb_timings_sysctl_handler 240 * 241 * This function updates timings variables, adjusting them where necessary. 242 *------------------------------------------------------------------------*/ 243 static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS) 244 { 245 int error = 0; 246 unsigned int val; 247 248 /* 249 * Attempt to get a coherent snapshot by making a copy of the data. 250 */ 251 if (arg1) 252 val = *(unsigned int *)arg1; 253 else 254 val = arg2; 255 error = SYSCTL_OUT(req, &val, sizeof(int)); 256 if (error || !req->newptr) 257 return (error); 258 259 if (!arg1) 260 return EPERM; 261 262 error = SYSCTL_IN(req, &val, sizeof(unsigned int)); 263 if (error) 264 return (error); 265 266 /* 267 * Now make sure the values are decent, and certainly no lower than 268 * what the USB spec prescribes. 269 */ 270 unsigned int *p = (unsigned int *)arg1; 271 if (p == &usb_port_reset_delay) { 272 if (val < USB_PORT_RESET_DELAY_SPEC) 273 return (EINVAL); 274 } else if (p == &usb_port_root_reset_delay) { 275 if (val < USB_PORT_ROOT_RESET_DELAY_SPEC) 276 return (EINVAL); 277 } else if (p == &usb_port_reset_recovery) { 278 if (val < USB_PORT_RESET_RECOVERY_SPEC) 279 return (EINVAL); 280 } else if (p == &usb_port_powerup_delay) { 281 if (val < USB_PORT_POWERUP_DELAY_SPEC) 282 return (EINVAL); 283 } else if (p == &usb_port_resume_delay) { 284 if (val < USB_PORT_RESUME_DELAY_SPEC) 285 return (EINVAL); 286 } else if (p == &usb_set_address_settle) { 287 if (val < USB_SET_ADDRESS_SETTLE_SPEC) 288 return (EINVAL); 289 } else if (p == &usb_resume_delay) { 290 if (val < USB_RESUME_DELAY_SPEC) 291 return (EINVAL); 292 } else if (p == &usb_resume_wait) { 293 if (val < USB_RESUME_WAIT_SPEC) 294 return (EINVAL); 295 } else if (p == &usb_resume_recovery) { 296 if (val < USB_RESUME_RECOVERY_SPEC) 297 return (EINVAL); 298 } else if (p == &usb_extra_power_up_time) { 299 if (val < USB_EXTRA_POWER_UP_TIME_SPEC) 300 return (EINVAL); 301 } else { 302 /* noop */ 303 } 304 305 *p = val; 306 return 0; 307 } 308 #endif 309