1 /* $FreeBSD$ */ 2 /*- 3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 4 * 5 * Copyright (c) 2008-2022 Hans Petter Selasky 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 SYSCTL_PROC(_hw_usb_timings, OID_AUTO, enum_nice_time, 127 CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &usb_enum_nice_time, 128 sizeof(usb_enum_nice_time), usb_timings_sysctl_handler, "IU", 129 "Enumeration thread nice time"); 130 #endif 131 132 /*------------------------------------------------------------------------* 133 * usb_dump_iface 134 * 135 * This function dumps information about an USB interface. 136 *------------------------------------------------------------------------*/ 137 void 138 usb_dump_iface(struct usb_interface *iface) 139 { 140 printf("usb_dump_iface: iface=%p\n", iface); 141 if (iface == NULL) { 142 return; 143 } 144 printf(" iface=%p idesc=%p altindex=%d\n", 145 iface, iface->idesc, iface->alt_index); 146 } 147 148 /*------------------------------------------------------------------------* 149 * usb_dump_device 150 * 151 * This function dumps information about an USB device. 152 *------------------------------------------------------------------------*/ 153 void 154 usb_dump_device(struct usb_device *udev) 155 { 156 printf("usb_dump_device: dev=%p\n", udev); 157 if (udev == NULL) { 158 return; 159 } 160 printf(" bus=%p \n" 161 " address=%d config=%d depth=%d speed=%d self_powered=%d\n" 162 " power=%d langid=%d\n", 163 udev->bus, 164 udev->address, udev->curr_config_no, udev->depth, udev->speed, 165 udev->flags.self_powered, udev->power, udev->langid); 166 } 167 168 /*------------------------------------------------------------------------* 169 * usb_dump_queue 170 * 171 * This function dumps the USB transfer that are queued up on an USB endpoint. 172 *------------------------------------------------------------------------*/ 173 void 174 usb_dump_queue(struct usb_endpoint *ep) 175 { 176 struct usb_xfer *xfer; 177 usb_stream_t x; 178 179 printf("usb_dump_queue: endpoint=%p xfer: ", ep); 180 for (x = 0; x != USB_MAX_EP_STREAMS; x++) { 181 TAILQ_FOREACH(xfer, &ep->endpoint_q[x].head, wait_entry) 182 printf(" %p", xfer); 183 } 184 printf("\n"); 185 } 186 187 /*------------------------------------------------------------------------* 188 * usb_dump_endpoint 189 * 190 * This function dumps information about an USB endpoint. 191 *------------------------------------------------------------------------*/ 192 void 193 usb_dump_endpoint(struct usb_endpoint *ep) 194 { 195 if (ep) { 196 printf("usb_dump_endpoint: endpoint=%p", ep); 197 198 printf(" edesc=%p isoc_next=%d toggle_next=%d", 199 ep->edesc, ep->isoc_next, ep->toggle_next); 200 201 if (ep->edesc) { 202 printf(" bEndpointAddress=0x%02x", 203 ep->edesc->bEndpointAddress); 204 } 205 printf("\n"); 206 usb_dump_queue(ep); 207 } else { 208 printf("usb_dump_endpoint: endpoint=NULL\n"); 209 } 210 } 211 212 /*------------------------------------------------------------------------* 213 * usb_dump_xfer 214 * 215 * This function dumps information about an USB transfer. 216 *------------------------------------------------------------------------*/ 217 void 218 usb_dump_xfer(struct usb_xfer *xfer) 219 { 220 struct usb_device *udev; 221 printf("usb_dump_xfer: xfer=%p\n", xfer); 222 if (xfer == NULL) { 223 return; 224 } 225 if (xfer->endpoint == NULL) { 226 printf("xfer %p: endpoint=NULL\n", 227 xfer); 228 return; 229 } 230 udev = xfer->xroot->udev; 231 printf("xfer %p: udev=%p vid=0x%04x pid=0x%04x addr=%d " 232 "endpoint=%p ep=0x%02x attr=0x%02x\n", 233 xfer, udev, 234 UGETW(udev->ddesc.idVendor), 235 UGETW(udev->ddesc.idProduct), 236 udev->address, xfer->endpoint, 237 xfer->endpoint->edesc->bEndpointAddress, 238 xfer->endpoint->edesc->bmAttributes); 239 } 240 241 #ifdef USB_DEBUG 242 unsigned usb_port_reset_delay = USB_PORT_RESET_DELAY; 243 unsigned usb_port_root_reset_delay = USB_PORT_ROOT_RESET_DELAY; 244 unsigned usb_port_reset_recovery = USB_PORT_RESET_RECOVERY; 245 unsigned usb_port_powerup_delay = USB_PORT_POWERUP_DELAY; 246 unsigned usb_port_resume_delay = USB_PORT_RESUME_DELAY; 247 unsigned usb_set_address_settle = USB_SET_ADDRESS_SETTLE; 248 unsigned usb_resume_delay = USB_RESUME_DELAY; 249 unsigned usb_resume_wait = USB_RESUME_WAIT; 250 unsigned usb_resume_recovery = USB_RESUME_RECOVERY; 251 unsigned usb_extra_power_up_time = USB_EXTRA_POWER_UP_TIME; 252 unsigned usb_enum_nice_time = USB_ENUM_NICE_TIME; 253 254 /*------------------------------------------------------------------------* 255 * usb_timings_sysctl_handler 256 * 257 * This function is used to update USB timing variables. 258 *------------------------------------------------------------------------*/ 259 static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS) 260 { 261 int error = 0; 262 unsigned val; 263 264 /* 265 * Attempt to get a coherent snapshot by making a copy of the data. 266 */ 267 if (arg1) 268 val = *(unsigned *)arg1; 269 else 270 val = arg2; 271 error = SYSCTL_OUT(req, &val, sizeof(unsigned)); 272 if (error || !req->newptr) 273 return (error); 274 275 if (!arg1) 276 return (EPERM); 277 278 error = SYSCTL_IN(req, &val, sizeof(unsigned)); 279 if (error) 280 return (error); 281 282 /* 283 * Make sure the specified value is not too big. Accept any 284 * value from 0 milliseconds to 2 seconds inclusivly for all 285 * parameters. 286 */ 287 if (val > 2000) 288 return (EINVAL); 289 290 *(unsigned *)arg1 = val; 291 return (0); 292 } 293 #endif 294