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