102ac6454SAndrew Thompson /* $FreeBSD$ */ 202ac6454SAndrew Thompson /*- 3718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 4718cf2ccSPedro F. Giffuni * 5*8758aabbSHans Petter Selasky * Copyright (c) 2008-2022 Hans Petter Selasky 602ac6454SAndrew Thompson * 702ac6454SAndrew Thompson * Redistribution and use in source and binary forms, with or without 802ac6454SAndrew Thompson * modification, are permitted provided that the following conditions 902ac6454SAndrew Thompson * are met: 1002ac6454SAndrew Thompson * 1. Redistributions of source code must retain the above copyright 1102ac6454SAndrew Thompson * notice, this list of conditions and the following disclaimer. 1202ac6454SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 1302ac6454SAndrew Thompson * notice, this list of conditions and the following disclaimer in the 1402ac6454SAndrew Thompson * documentation and/or other materials provided with the distribution. 1502ac6454SAndrew Thompson * 1602ac6454SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1702ac6454SAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1802ac6454SAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1902ac6454SAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2002ac6454SAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2102ac6454SAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2202ac6454SAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2302ac6454SAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2402ac6454SAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2502ac6454SAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2602ac6454SAndrew Thompson * SUCH DAMAGE. 2702ac6454SAndrew Thompson */ 2802ac6454SAndrew Thompson 29d2b99310SHans Petter Selasky #ifdef USB_GLOBAL_INCLUDE_FILE 30d2b99310SHans Petter Selasky #include USB_GLOBAL_INCLUDE_FILE 31d2b99310SHans Petter Selasky #else 32ed6d949aSAndrew Thompson #include <sys/stdint.h> 33ed6d949aSAndrew Thompson #include <sys/stddef.h> 34ed6d949aSAndrew Thompson #include <sys/param.h> 35ed6d949aSAndrew Thompson #include <sys/queue.h> 36ed6d949aSAndrew Thompson #include <sys/types.h> 37ed6d949aSAndrew Thompson #include <sys/systm.h> 38ed6d949aSAndrew Thompson #include <sys/kernel.h> 39ed6d949aSAndrew Thompson #include <sys/bus.h> 40ed6d949aSAndrew Thompson #include <sys/module.h> 41ed6d949aSAndrew Thompson #include <sys/lock.h> 42ed6d949aSAndrew Thompson #include <sys/mutex.h> 43ed6d949aSAndrew Thompson #include <sys/condvar.h> 44ed6d949aSAndrew Thompson #include <sys/sysctl.h> 45ed6d949aSAndrew Thompson #include <sys/sx.h> 46ed6d949aSAndrew Thompson #include <sys/unistd.h> 47ed6d949aSAndrew Thompson #include <sys/callout.h> 48ed6d949aSAndrew Thompson #include <sys/malloc.h> 49ed6d949aSAndrew Thompson #include <sys/priv.h> 50ed6d949aSAndrew Thompson 5102ac6454SAndrew Thompson #include <dev/usb/usb.h> 52ed6d949aSAndrew Thompson #include <dev/usb/usbdi.h> 5302ac6454SAndrew Thompson 5402ac6454SAndrew Thompson #include <dev/usb/usb_core.h> 5502ac6454SAndrew Thompson #include <dev/usb/usb_debug.h> 5602ac6454SAndrew Thompson #include <dev/usb/usb_process.h> 5702ac6454SAndrew Thompson #include <dev/usb/usb_device.h> 5802ac6454SAndrew Thompson #include <dev/usb/usb_busdma.h> 5902ac6454SAndrew Thompson #include <dev/usb/usb_transfer.h> 6002ac6454SAndrew Thompson 61ed6d949aSAndrew Thompson #include <ddb/ddb.h> 62ed6d949aSAndrew Thompson #include <ddb/db_sym.h> 63d2b99310SHans Petter Selasky #endif /* USB_GLOBAL_INCLUDE_FILE */ 64ed6d949aSAndrew Thompson 6502ac6454SAndrew Thompson /* 6602ac6454SAndrew Thompson * Define this unconditionally in case a kernel module is loaded that 6702ac6454SAndrew Thompson * has been compiled with debugging options. 6802ac6454SAndrew Thompson */ 69a593f6b8SAndrew Thompson int usb_debug = 0; 7002ac6454SAndrew Thompson 71f8d2b1f3SPawel Biernacki SYSCTL_NODE(_hw, OID_AUTO, usb, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 72f8d2b1f3SPawel Biernacki "USB debugging"); 73af3b2549SHans Petter Selasky SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RWTUN, 74a593f6b8SAndrew Thompson &usb_debug, 0, "Debug level"); 75c13fd8d4SAndrew Thompson 7637506412SHans Petter Selasky #ifdef USB_DEBUG 7737506412SHans Petter Selasky /* 7837506412SHans Petter Selasky * Sysctls to modify timings/delays 7937506412SHans Petter Selasky */ 80f8d2b1f3SPawel Biernacki static SYSCTL_NODE(_hw_usb, OID_AUTO, timings, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 81f8d2b1f3SPawel Biernacki "Timings"); 8237506412SHans Petter Selasky static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS); 8337506412SHans Petter Selasky 84f8d2b1f3SPawel Biernacki SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_reset_delay, 85f8d2b1f3SPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &usb_port_reset_delay, 86f8d2b1f3SPawel Biernacki sizeof(usb_port_reset_delay), usb_timings_sysctl_handler, "IU", 87f8d2b1f3SPawel Biernacki "Port Reset Delay"); 88f8d2b1f3SPawel Biernacki SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_root_reset_delay, 89f8d2b1f3SPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 9037506412SHans Petter Selasky &usb_port_root_reset_delay, sizeof(usb_port_root_reset_delay), 91f8d2b1f3SPawel Biernacki usb_timings_sysctl_handler, "IU", 92f8d2b1f3SPawel Biernacki "Root Port Reset Delay"); 93f8d2b1f3SPawel Biernacki SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_reset_recovery, 94f8d2b1f3SPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 9537506412SHans Petter Selasky &usb_port_reset_recovery, sizeof(usb_port_reset_recovery), 96f8d2b1f3SPawel Biernacki usb_timings_sysctl_handler, "IU", 97f8d2b1f3SPawel Biernacki "Port Reset Recovery"); 98f8d2b1f3SPawel Biernacki SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_powerup_delay, 99f8d2b1f3SPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &usb_port_powerup_delay, 100f8d2b1f3SPawel Biernacki sizeof(usb_port_powerup_delay), usb_timings_sysctl_handler, "IU", 101f8d2b1f3SPawel Biernacki "Port PowerUp Delay"); 102f8d2b1f3SPawel Biernacki SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_resume_delay, 103f8d2b1f3SPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &usb_port_resume_delay, 104f8d2b1f3SPawel Biernacki sizeof(usb_port_resume_delay), usb_timings_sysctl_handler, "IU", 105f8d2b1f3SPawel Biernacki "Port Resume Delay"); 106f8d2b1f3SPawel Biernacki SYSCTL_PROC(_hw_usb_timings, OID_AUTO, set_address_settle, 107f8d2b1f3SPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &usb_set_address_settle, 108f8d2b1f3SPawel Biernacki sizeof(usb_set_address_settle), usb_timings_sysctl_handler, "IU", 109f8d2b1f3SPawel Biernacki "Set Address Settle"); 110f8d2b1f3SPawel Biernacki SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_delay, 111f8d2b1f3SPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &usb_resume_delay, 112f8d2b1f3SPawel Biernacki sizeof(usb_resume_delay), usb_timings_sysctl_handler, "IU", 113f8d2b1f3SPawel Biernacki "Resume Delay"); 114f8d2b1f3SPawel Biernacki SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_wait, 115f8d2b1f3SPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &usb_resume_wait, 116f8d2b1f3SPawel Biernacki sizeof(usb_resume_wait), usb_timings_sysctl_handler, "IU", 117f8d2b1f3SPawel Biernacki "Resume Wait"); 118f8d2b1f3SPawel Biernacki SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_recovery, 119f8d2b1f3SPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &usb_resume_recovery, 120f8d2b1f3SPawel Biernacki sizeof(usb_resume_recovery), usb_timings_sysctl_handler, "IU", 121f8d2b1f3SPawel Biernacki "Resume Recovery"); 122f8d2b1f3SPawel Biernacki SYSCTL_PROC(_hw_usb_timings, OID_AUTO, extra_power_up_time, 123f8d2b1f3SPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &usb_extra_power_up_time, 124f8d2b1f3SPawel Biernacki sizeof(usb_extra_power_up_time), usb_timings_sysctl_handler, "IU", 125f8d2b1f3SPawel Biernacki "Extra PowerUp Time"); 126*8758aabbSHans Petter Selasky SYSCTL_PROC(_hw_usb_timings, OID_AUTO, enum_nice_time, 127*8758aabbSHans Petter Selasky CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &usb_enum_nice_time, 128*8758aabbSHans Petter Selasky sizeof(usb_enum_nice_time), usb_timings_sysctl_handler, "IU", 129*8758aabbSHans Petter Selasky "Enumeration thread nice time"); 13037506412SHans Petter Selasky #endif 13137506412SHans Petter Selasky 13202ac6454SAndrew Thompson /*------------------------------------------------------------------------* 133a593f6b8SAndrew Thompson * usb_dump_iface 13402ac6454SAndrew Thompson * 13502ac6454SAndrew Thompson * This function dumps information about an USB interface. 13602ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 13702ac6454SAndrew Thompson void 138a593f6b8SAndrew Thompson usb_dump_iface(struct usb_interface *iface) 13902ac6454SAndrew Thompson { 140a593f6b8SAndrew Thompson printf("usb_dump_iface: iface=%p\n", iface); 14102ac6454SAndrew Thompson if (iface == NULL) { 14202ac6454SAndrew Thompson return; 14302ac6454SAndrew Thompson } 14402ac6454SAndrew Thompson printf(" iface=%p idesc=%p altindex=%d\n", 14502ac6454SAndrew Thompson iface, iface->idesc, iface->alt_index); 14602ac6454SAndrew Thompson } 14702ac6454SAndrew Thompson 14802ac6454SAndrew Thompson /*------------------------------------------------------------------------* 149a593f6b8SAndrew Thompson * usb_dump_device 15002ac6454SAndrew Thompson * 15102ac6454SAndrew Thompson * This function dumps information about an USB device. 15202ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 15302ac6454SAndrew Thompson void 154a593f6b8SAndrew Thompson usb_dump_device(struct usb_device *udev) 15502ac6454SAndrew Thompson { 156a593f6b8SAndrew Thompson printf("usb_dump_device: dev=%p\n", udev); 15702ac6454SAndrew Thompson if (udev == NULL) { 15802ac6454SAndrew Thompson return; 15902ac6454SAndrew Thompson } 16002ac6454SAndrew Thompson printf(" bus=%p \n" 16102ac6454SAndrew Thompson " address=%d config=%d depth=%d speed=%d self_powered=%d\n" 16202ac6454SAndrew Thompson " power=%d langid=%d\n", 16302ac6454SAndrew Thompson udev->bus, 16402ac6454SAndrew Thompson udev->address, udev->curr_config_no, udev->depth, udev->speed, 16502ac6454SAndrew Thompson udev->flags.self_powered, udev->power, udev->langid); 16602ac6454SAndrew Thompson } 16702ac6454SAndrew Thompson 16802ac6454SAndrew Thompson /*------------------------------------------------------------------------* 169a593f6b8SAndrew Thompson * usb_dump_queue 17002ac6454SAndrew Thompson * 171ae60fdfbSAndrew Thompson * This function dumps the USB transfer that are queued up on an USB endpoint. 17202ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 17302ac6454SAndrew Thompson void 174a593f6b8SAndrew Thompson usb_dump_queue(struct usb_endpoint *ep) 17502ac6454SAndrew Thompson { 176760bc48eSAndrew Thompson struct usb_xfer *xfer; 177a5cf1aaaSHans Petter Selasky usb_stream_t x; 17802ac6454SAndrew Thompson 179a593f6b8SAndrew Thompson printf("usb_dump_queue: endpoint=%p xfer: ", ep); 180a5cf1aaaSHans Petter Selasky for (x = 0; x != USB_MAX_EP_STREAMS; x++) { 181a5cf1aaaSHans Petter Selasky TAILQ_FOREACH(xfer, &ep->endpoint_q[x].head, wait_entry) 18202ac6454SAndrew Thompson printf(" %p", xfer); 18302ac6454SAndrew Thompson } 18402ac6454SAndrew Thompson printf("\n"); 18502ac6454SAndrew Thompson } 18602ac6454SAndrew Thompson 18702ac6454SAndrew Thompson /*------------------------------------------------------------------------* 188a593f6b8SAndrew Thompson * usb_dump_endpoint 18902ac6454SAndrew Thompson * 190ae60fdfbSAndrew Thompson * This function dumps information about an USB endpoint. 19102ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 19202ac6454SAndrew Thompson void 193a593f6b8SAndrew Thompson usb_dump_endpoint(struct usb_endpoint *ep) 19402ac6454SAndrew Thompson { 195ae60fdfbSAndrew Thompson if (ep) { 196a593f6b8SAndrew Thompson printf("usb_dump_endpoint: endpoint=%p", ep); 19702ac6454SAndrew Thompson 19802ac6454SAndrew Thompson printf(" edesc=%p isoc_next=%d toggle_next=%d", 199ae60fdfbSAndrew Thompson ep->edesc, ep->isoc_next, ep->toggle_next); 20002ac6454SAndrew Thompson 201ae60fdfbSAndrew Thompson if (ep->edesc) { 20202ac6454SAndrew Thompson printf(" bEndpointAddress=0x%02x", 203ae60fdfbSAndrew Thompson ep->edesc->bEndpointAddress); 20402ac6454SAndrew Thompson } 20502ac6454SAndrew Thompson printf("\n"); 206a593f6b8SAndrew Thompson usb_dump_queue(ep); 20702ac6454SAndrew Thompson } else { 208a593f6b8SAndrew Thompson printf("usb_dump_endpoint: endpoint=NULL\n"); 20902ac6454SAndrew Thompson } 21002ac6454SAndrew Thompson } 21102ac6454SAndrew Thompson 21202ac6454SAndrew Thompson /*------------------------------------------------------------------------* 213a593f6b8SAndrew Thompson * usb_dump_xfer 21402ac6454SAndrew Thompson * 21502ac6454SAndrew Thompson * This function dumps information about an USB transfer. 21602ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 21702ac6454SAndrew Thompson void 218a593f6b8SAndrew Thompson usb_dump_xfer(struct usb_xfer *xfer) 21902ac6454SAndrew Thompson { 220760bc48eSAndrew Thompson struct usb_device *udev; 221a593f6b8SAndrew Thompson printf("usb_dump_xfer: xfer=%p\n", xfer); 22202ac6454SAndrew Thompson if (xfer == NULL) { 22302ac6454SAndrew Thompson return; 22402ac6454SAndrew Thompson } 225ae60fdfbSAndrew Thompson if (xfer->endpoint == NULL) { 226ae60fdfbSAndrew Thompson printf("xfer %p: endpoint=NULL\n", 22702ac6454SAndrew Thompson xfer); 22802ac6454SAndrew Thompson return; 22902ac6454SAndrew Thompson } 23002ac6454SAndrew Thompson udev = xfer->xroot->udev; 23102ac6454SAndrew Thompson printf("xfer %p: udev=%p vid=0x%04x pid=0x%04x addr=%d " 232ae60fdfbSAndrew Thompson "endpoint=%p ep=0x%02x attr=0x%02x\n", 23302ac6454SAndrew Thompson xfer, udev, 23402ac6454SAndrew Thompson UGETW(udev->ddesc.idVendor), 23502ac6454SAndrew Thompson UGETW(udev->ddesc.idProduct), 236ae60fdfbSAndrew Thompson udev->address, xfer->endpoint, 237ae60fdfbSAndrew Thompson xfer->endpoint->edesc->bEndpointAddress, 238ae60fdfbSAndrew Thompson xfer->endpoint->edesc->bmAttributes); 23902ac6454SAndrew Thompson } 24037506412SHans Petter Selasky 24137506412SHans Petter Selasky #ifdef USB_DEBUG 24237506412SHans Petter Selasky unsigned int usb_port_reset_delay = USB_PORT_RESET_DELAY; 24337506412SHans Petter Selasky unsigned int usb_port_root_reset_delay = USB_PORT_ROOT_RESET_DELAY; 24437506412SHans Petter Selasky unsigned int usb_port_reset_recovery = USB_PORT_RESET_RECOVERY; 24537506412SHans Petter Selasky unsigned int usb_port_powerup_delay = USB_PORT_POWERUP_DELAY; 24637506412SHans Petter Selasky unsigned int usb_port_resume_delay = USB_PORT_RESUME_DELAY; 24737506412SHans Petter Selasky unsigned int usb_set_address_settle = USB_SET_ADDRESS_SETTLE; 24837506412SHans Petter Selasky unsigned int usb_resume_delay = USB_RESUME_DELAY; 24937506412SHans Petter Selasky unsigned int usb_resume_wait = USB_RESUME_WAIT; 25037506412SHans Petter Selasky unsigned int usb_resume_recovery = USB_RESUME_RECOVERY; 25137506412SHans Petter Selasky unsigned int usb_extra_power_up_time = USB_EXTRA_POWER_UP_TIME; 252*8758aabbSHans Petter Selasky unsigned int usb_enum_nice_time = USB_ENUM_NICE_TIME; 25337506412SHans Petter Selasky 25437506412SHans Petter Selasky /*------------------------------------------------------------------------* 25537506412SHans Petter Selasky * usb_timings_sysctl_handler 25637506412SHans Petter Selasky * 25700e501d7SHans Petter Selasky * This function is used to update USB timing variables. 25837506412SHans Petter Selasky *------------------------------------------------------------------------*/ 25937506412SHans Petter Selasky static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS) 26037506412SHans Petter Selasky { 26137506412SHans Petter Selasky int error = 0; 26200e501d7SHans Petter Selasky unsigned val; 26337506412SHans Petter Selasky 26437506412SHans Petter Selasky /* 26537506412SHans Petter Selasky * Attempt to get a coherent snapshot by making a copy of the data. 26637506412SHans Petter Selasky */ 26737506412SHans Petter Selasky if (arg1) 26800e501d7SHans Petter Selasky val = *(unsigned *)arg1; 26937506412SHans Petter Selasky else 27037506412SHans Petter Selasky val = arg2; 27100e501d7SHans Petter Selasky error = SYSCTL_OUT(req, &val, sizeof(unsigned)); 27237506412SHans Petter Selasky if (error || !req->newptr) 27337506412SHans Petter Selasky return (error); 27437506412SHans Petter Selasky 27537506412SHans Petter Selasky if (!arg1) 27600e501d7SHans Petter Selasky return (EPERM); 27737506412SHans Petter Selasky 27800e501d7SHans Petter Selasky error = SYSCTL_IN(req, &val, sizeof(unsigned)); 27937506412SHans Petter Selasky if (error) 28037506412SHans Petter Selasky return (error); 28137506412SHans Petter Selasky 28237506412SHans Petter Selasky /* 28300e501d7SHans Petter Selasky * Make sure the specified value is not too big. Accept any 28400e501d7SHans Petter Selasky * value from 0 milliseconds to 2 seconds inclusivly for all 28500e501d7SHans Petter Selasky * parameters. 28637506412SHans Petter Selasky */ 28700e501d7SHans Petter Selasky if (val > 2000) 28837506412SHans Petter Selasky return (EINVAL); 28937506412SHans Petter Selasky 29000e501d7SHans Petter Selasky *(unsigned *)arg1 = val; 29100e501d7SHans Petter Selasky return (0); 29237506412SHans Petter Selasky } 29337506412SHans Petter Selasky #endif 294