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 */ 68int usb_debug = 0; 69 70SYSCTL_NODE(_hw, OID_AUTO, usb, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 71 "USB debugging"); 72SYSCTL_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 */ 79static SYSCTL_NODE(_hw_usb, OID_AUTO, timings, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 80 "Timings"); 81static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS); 82 83SYSCTL_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"); 87SYSCTL_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"); 92SYSCTL_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"); 97SYSCTL_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"); 101SYSCTL_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"); 105SYSCTL_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"); 109SYSCTL_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"); 113SYSCTL_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"); 117SYSCTL_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"); 121SYSCTL_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"); 125SYSCTL_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 *------------------------------------------------------------------------*/ 136void 137usb_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 *------------------------------------------------------------------------*/ 152void 153usb_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 *------------------------------------------------------------------------*/ 172void 173usb_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 *------------------------------------------------------------------------*/ 191void 192usb_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 *------------------------------------------------------------------------*/ 216void 217usb_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 241unsigned usb_port_reset_delay = USB_PORT_RESET_DELAY; 242unsigned usb_port_root_reset_delay = USB_PORT_ROOT_RESET_DELAY; 243unsigned usb_port_reset_recovery = USB_PORT_RESET_RECOVERY; 244unsigned usb_port_powerup_delay = USB_PORT_POWERUP_DELAY; 245unsigned usb_port_resume_delay = USB_PORT_RESUME_DELAY; 246unsigned usb_set_address_settle = USB_SET_ADDRESS_SETTLE; 247unsigned usb_resume_delay = USB_RESUME_DELAY; 248unsigned usb_resume_wait = USB_RESUME_WAIT; 249unsigned usb_resume_recovery = USB_RESUME_RECOVERY; 250unsigned usb_extra_power_up_time = USB_EXTRA_POWER_UP_TIME; 251unsigned 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 *------------------------------------------------------------------------*/ 258static 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