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