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