1 /* $FreeBSD$ */ 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/stddef.h> 29 #include <sys/param.h> 30 #include <sys/queue.h> 31 #include <sys/types.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/bus.h> 35 #include <sys/module.h> 36 #include <sys/lock.h> 37 #include <sys/mutex.h> 38 #include <sys/condvar.h> 39 #include <sys/sysctl.h> 40 #include <sys/sx.h> 41 #include <sys/unistd.h> 42 #include <sys/callout.h> 43 #include <sys/malloc.h> 44 #include <sys/priv.h> 45 46 #include <dev/usb/usb.h> 47 #include <dev/usb/usbdi.h> 48 49 #include <dev/usb/usb_core.h> 50 #include <dev/usb/usb_debug.h> 51 #include <dev/usb/usb_process.h> 52 #include <dev/usb/usb_device.h> 53 #include <dev/usb/usb_busdma.h> 54 #include <dev/usb/usb_transfer.h> 55 56 #include <ddb/ddb.h> 57 #include <ddb/db_sym.h> 58 59 /* 60 * Define this unconditionally in case a kernel module is loaded that 61 * has been compiled with debugging options. 62 */ 63 int usb_debug = 0; 64 65 SYSCTL_NODE(_hw, OID_AUTO, usb, CTLFLAG_RW, 0, "USB debugging"); 66 SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW, 67 &usb_debug, 0, "Debug level"); 68 69 TUNABLE_INT("hw.usb.debug", &usb_debug); 70 71 #ifdef USB_DEBUG 72 /* 73 * Sysctls to modify timings/delays 74 */ 75 static SYSCTL_NODE(_hw_usb, OID_AUTO, timings, CTLFLAG_RW, 0, "Timings"); 76 static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS); 77 78 TUNABLE_INT("hw.usb.timings.port_reset_delay", (int *)&usb_port_reset_delay); 79 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_reset_delay, CTLTYPE_UINT | CTLFLAG_RW, 80 &usb_port_reset_delay, sizeof(usb_port_reset_delay), 81 usb_timings_sysctl_handler, "IU", "Port Reset Delay"); 82 TUNABLE_INT("hw.usb.timings.port_root_reset_delay", (int *)&usb_port_root_reset_delay); 83 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_root_reset_delay, CTLTYPE_UINT | CTLFLAG_RW, 84 &usb_port_root_reset_delay, sizeof(usb_port_root_reset_delay), 85 usb_timings_sysctl_handler, "IU", "Root Port Reset Delay"); 86 TUNABLE_INT("hw.usb.timings.port_reset_recovery", (int *)&usb_port_reset_recovery); 87 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_reset_recovery, CTLTYPE_UINT | CTLFLAG_RW, 88 &usb_port_reset_recovery, sizeof(usb_port_reset_recovery), 89 usb_timings_sysctl_handler, "IU", "Port Reset Recovery"); 90 TUNABLE_INT("hw.usb.timings.port_powerup_delay", (int *)&usb_port_powerup_delay); 91 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_powerup_delay, CTLTYPE_UINT | CTLFLAG_RW, 92 &usb_port_powerup_delay, sizeof(usb_port_powerup_delay), 93 usb_timings_sysctl_handler, "IU", "Port PowerUp Delay"); 94 TUNABLE_INT("hw.usb.timings.port_resume_delay", (int *)&usb_port_resume_delay); 95 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_resume_delay, CTLTYPE_UINT | CTLFLAG_RW, 96 &usb_port_resume_delay, sizeof(usb_port_resume_delay), 97 usb_timings_sysctl_handler, "IU", "Port Resume Delay"); 98 TUNABLE_INT("hw.usb.timings.set_address_settle", (int *)&usb_set_address_settle); 99 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, set_address_settle, CTLTYPE_UINT | CTLFLAG_RW, 100 &usb_set_address_settle, sizeof(usb_set_address_settle), 101 usb_timings_sysctl_handler, "IU", "Set Address Settle"); 102 TUNABLE_INT("hw.usb.timings.resume_delay", (int *)&usb_resume_delay); 103 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_delay, CTLTYPE_UINT | CTLFLAG_RW, 104 &usb_resume_delay, sizeof(usb_resume_delay), 105 usb_timings_sysctl_handler, "IU", "Resume Delay"); 106 TUNABLE_INT("hw.usb.timings.resume_wait", (int *)&usb_resume_wait); 107 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_wait, CTLTYPE_UINT | CTLFLAG_RW, 108 &usb_resume_wait, sizeof(usb_resume_wait), 109 usb_timings_sysctl_handler, "IU", "Resume Wait"); 110 TUNABLE_INT("hw.usb.timings.resume_recovery", (int *)&usb_resume_recovery); 111 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_recovery, CTLTYPE_UINT | CTLFLAG_RW, 112 &usb_resume_recovery, sizeof(usb_resume_recovery), 113 usb_timings_sysctl_handler, "IU", "Resume Recovery"); 114 TUNABLE_INT("hw.usb.timings.extra_power_up_time", (int *)&usb_extra_power_up_time); 115 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, extra_power_up_time, CTLTYPE_UINT | CTLFLAG_RW, 116 &usb_extra_power_up_time, sizeof(usb_extra_power_up_time), 117 usb_timings_sysctl_handler, "IU", "Extra PowerUp Time"); 118 #endif 119 120 /*------------------------------------------------------------------------* 121 * usb_dump_iface 122 * 123 * This function dumps information about an USB interface. 124 *------------------------------------------------------------------------*/ 125 void 126 usb_dump_iface(struct usb_interface *iface) 127 { 128 printf("usb_dump_iface: iface=%p\n", iface); 129 if (iface == NULL) { 130 return; 131 } 132 printf(" iface=%p idesc=%p altindex=%d\n", 133 iface, iface->idesc, iface->alt_index); 134 } 135 136 /*------------------------------------------------------------------------* 137 * usb_dump_device 138 * 139 * This function dumps information about an USB device. 140 *------------------------------------------------------------------------*/ 141 void 142 usb_dump_device(struct usb_device *udev) 143 { 144 printf("usb_dump_device: dev=%p\n", udev); 145 if (udev == NULL) { 146 return; 147 } 148 printf(" bus=%p \n" 149 " address=%d config=%d depth=%d speed=%d self_powered=%d\n" 150 " power=%d langid=%d\n", 151 udev->bus, 152 udev->address, udev->curr_config_no, udev->depth, udev->speed, 153 udev->flags.self_powered, udev->power, udev->langid); 154 } 155 156 /*------------------------------------------------------------------------* 157 * usb_dump_queue 158 * 159 * This function dumps the USB transfer that are queued up on an USB endpoint. 160 *------------------------------------------------------------------------*/ 161 void 162 usb_dump_queue(struct usb_endpoint *ep) 163 { 164 struct usb_xfer *xfer; 165 usb_stream_t x; 166 167 printf("usb_dump_queue: endpoint=%p xfer: ", ep); 168 for (x = 0; x != USB_MAX_EP_STREAMS; x++) { 169 TAILQ_FOREACH(xfer, &ep->endpoint_q[x].head, wait_entry) 170 printf(" %p", xfer); 171 } 172 printf("\n"); 173 } 174 175 /*------------------------------------------------------------------------* 176 * usb_dump_endpoint 177 * 178 * This function dumps information about an USB endpoint. 179 *------------------------------------------------------------------------*/ 180 void 181 usb_dump_endpoint(struct usb_endpoint *ep) 182 { 183 if (ep) { 184 printf("usb_dump_endpoint: endpoint=%p", ep); 185 186 printf(" edesc=%p isoc_next=%d toggle_next=%d", 187 ep->edesc, ep->isoc_next, ep->toggle_next); 188 189 if (ep->edesc) { 190 printf(" bEndpointAddress=0x%02x", 191 ep->edesc->bEndpointAddress); 192 } 193 printf("\n"); 194 usb_dump_queue(ep); 195 } else { 196 printf("usb_dump_endpoint: endpoint=NULL\n"); 197 } 198 } 199 200 /*------------------------------------------------------------------------* 201 * usb_dump_xfer 202 * 203 * This function dumps information about an USB transfer. 204 *------------------------------------------------------------------------*/ 205 void 206 usb_dump_xfer(struct usb_xfer *xfer) 207 { 208 struct usb_device *udev; 209 printf("usb_dump_xfer: xfer=%p\n", xfer); 210 if (xfer == NULL) { 211 return; 212 } 213 if (xfer->endpoint == NULL) { 214 printf("xfer %p: endpoint=NULL\n", 215 xfer); 216 return; 217 } 218 udev = xfer->xroot->udev; 219 printf("xfer %p: udev=%p vid=0x%04x pid=0x%04x addr=%d " 220 "endpoint=%p ep=0x%02x attr=0x%02x\n", 221 xfer, udev, 222 UGETW(udev->ddesc.idVendor), 223 UGETW(udev->ddesc.idProduct), 224 udev->address, xfer->endpoint, 225 xfer->endpoint->edesc->bEndpointAddress, 226 xfer->endpoint->edesc->bmAttributes); 227 } 228 229 #ifdef USB_DEBUG 230 unsigned int usb_port_reset_delay = USB_PORT_RESET_DELAY; 231 unsigned int usb_port_root_reset_delay = USB_PORT_ROOT_RESET_DELAY; 232 unsigned int usb_port_reset_recovery = USB_PORT_RESET_RECOVERY; 233 unsigned int usb_port_powerup_delay = USB_PORT_POWERUP_DELAY; 234 unsigned int usb_port_resume_delay = USB_PORT_RESUME_DELAY; 235 unsigned int usb_set_address_settle = USB_SET_ADDRESS_SETTLE; 236 unsigned int usb_resume_delay = USB_RESUME_DELAY; 237 unsigned int usb_resume_wait = USB_RESUME_WAIT; 238 unsigned int usb_resume_recovery = USB_RESUME_RECOVERY; 239 unsigned int usb_extra_power_up_time = USB_EXTRA_POWER_UP_TIME; 240 241 /*------------------------------------------------------------------------* 242 * usb_timings_sysctl_handler 243 * 244 * This function updates timings variables, adjusting them where necessary. 245 *------------------------------------------------------------------------*/ 246 static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS) 247 { 248 int error = 0; 249 unsigned int val; 250 251 /* 252 * Attempt to get a coherent snapshot by making a copy of the data. 253 */ 254 if (arg1) 255 val = *(unsigned int *)arg1; 256 else 257 val = arg2; 258 error = SYSCTL_OUT(req, &val, sizeof(int)); 259 if (error || !req->newptr) 260 return (error); 261 262 if (!arg1) 263 return EPERM; 264 265 error = SYSCTL_IN(req, &val, sizeof(unsigned int)); 266 if (error) 267 return (error); 268 269 /* 270 * Now make sure the values are decent, and certainly no lower than 271 * what the USB spec prescribes. 272 */ 273 unsigned int *p = (unsigned int *)arg1; 274 if (p == &usb_port_reset_delay) { 275 if (val < USB_PORT_RESET_DELAY_SPEC) 276 return (EINVAL); 277 } else if (p == &usb_port_root_reset_delay) { 278 if (val < USB_PORT_ROOT_RESET_DELAY_SPEC) 279 return (EINVAL); 280 } else if (p == &usb_port_reset_recovery) { 281 if (val < USB_PORT_RESET_RECOVERY_SPEC) 282 return (EINVAL); 283 } else if (p == &usb_port_powerup_delay) { 284 if (val < USB_PORT_POWERUP_DELAY_SPEC) 285 return (EINVAL); 286 } else if (p == &usb_port_resume_delay) { 287 if (val < USB_PORT_RESUME_DELAY_SPEC) 288 return (EINVAL); 289 } else if (p == &usb_set_address_settle) { 290 if (val < USB_SET_ADDRESS_SETTLE_SPEC) 291 return (EINVAL); 292 } else if (p == &usb_resume_delay) { 293 if (val < USB_RESUME_DELAY_SPEC) 294 return (EINVAL); 295 } else if (p == &usb_resume_wait) { 296 if (val < USB_RESUME_WAIT_SPEC) 297 return (EINVAL); 298 } else if (p == &usb_resume_recovery) { 299 if (val < USB_RESUME_RECOVERY_SPEC) 300 return (EINVAL); 301 } else if (p == &usb_extra_power_up_time) { 302 if (val < USB_EXTRA_POWER_UP_TIME_SPEC) 303 return (EINVAL); 304 } else { 305 /* noop */ 306 } 307 308 *p = val; 309 return 0; 310 } 311 #endif 312