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