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