102ac6454SAndrew Thompson /* $FreeBSD$ */ 202ac6454SAndrew Thompson /*- 302ac6454SAndrew Thompson * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 402ac6454SAndrew Thompson * 502ac6454SAndrew Thompson * Redistribution and use in source and binary forms, with or without 602ac6454SAndrew Thompson * modification, are permitted provided that the following conditions 702ac6454SAndrew Thompson * are met: 802ac6454SAndrew Thompson * 1. Redistributions of source code must retain the above copyright 902ac6454SAndrew Thompson * notice, this list of conditions and the following disclaimer. 1002ac6454SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 1102ac6454SAndrew Thompson * notice, this list of conditions and the following disclaimer in the 1202ac6454SAndrew Thompson * documentation and/or other materials provided with the distribution. 1302ac6454SAndrew Thompson * 1402ac6454SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1502ac6454SAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1602ac6454SAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1702ac6454SAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1802ac6454SAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1902ac6454SAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2002ac6454SAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2102ac6454SAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2202ac6454SAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2302ac6454SAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2402ac6454SAndrew Thompson * SUCH DAMAGE. 2502ac6454SAndrew Thompson */ 2602ac6454SAndrew Thompson 27d2b99310SHans Petter Selasky #ifdef USB_GLOBAL_INCLUDE_FILE 28d2b99310SHans Petter Selasky #include USB_GLOBAL_INCLUDE_FILE 29d2b99310SHans Petter Selasky #else 30f0c078e6SAndrew Thompson #include "opt_ddb.h" 31f0c078e6SAndrew Thompson 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 54a593f6b8SAndrew Thompson #define USB_DEBUG_VAR usb_ctrl_debug 5502ac6454SAndrew Thompson 5602ac6454SAndrew Thompson #include <dev/usb/usb_core.h> 5702ac6454SAndrew Thompson #include <dev/usb/usb_debug.h> 5802ac6454SAndrew Thompson #include <dev/usb/usb_process.h> 5902ac6454SAndrew Thompson #include <dev/usb/usb_busdma.h> 6002ac6454SAndrew Thompson #include <dev/usb/usb_dynamic.h> 6102ac6454SAndrew Thompson #include <dev/usb/usb_device.h> 6202ac6454SAndrew Thompson #include <dev/usb/usb_hub.h> 6302ac6454SAndrew Thompson 6402ac6454SAndrew Thompson #include <dev/usb/usb_controller.h> 6502ac6454SAndrew Thompson #include <dev/usb/usb_bus.h> 6618ec6525SWeongyo Jeong #include <dev/usb/usb_pf.h> 672e141748SHans Petter Selasky #include "usb_if.h" 68d2b99310SHans Petter Selasky #endif /* USB_GLOBAL_INCLUDE_FILE */ 6902ac6454SAndrew Thompson 7002ac6454SAndrew Thompson /* function prototypes */ 7102ac6454SAndrew Thompson 72a593f6b8SAndrew Thompson static device_probe_t usb_probe; 73a593f6b8SAndrew Thompson static device_attach_t usb_attach; 74a593f6b8SAndrew Thompson static device_detach_t usb_detach; 752e141748SHans Petter Selasky static device_suspend_t usb_suspend; 762e141748SHans Petter Selasky static device_resume_t usb_resume; 772e141748SHans Petter Selasky static device_shutdown_t usb_shutdown; 7802ac6454SAndrew Thompson 79a593f6b8SAndrew Thompson static void usb_attach_sub(device_t, struct usb_bus *); 8002ac6454SAndrew Thompson 8102ac6454SAndrew Thompson /* static variables */ 8202ac6454SAndrew Thompson 83ed6d949aSAndrew Thompson #ifdef USB_DEBUG 84a593f6b8SAndrew Thompson static int usb_ctrl_debug = 0; 8502ac6454SAndrew Thompson 866472ac3dSEd Schouten static SYSCTL_NODE(_hw_usb, OID_AUTO, ctrl, CTLFLAG_RW, 0, "USB controller"); 87a593f6b8SAndrew Thompson SYSCTL_INT(_hw_usb_ctrl, OID_AUTO, debug, CTLFLAG_RW, &usb_ctrl_debug, 0, 8802ac6454SAndrew Thompson "Debug level"); 8902ac6454SAndrew Thompson #endif 9002ac6454SAndrew Thompson 91d2b99310SHans Petter Selasky #if USB_HAVE_ROOT_MOUNT_HOLD 92a0c61406SAlfred Perlstein static int usb_no_boot_wait = 0; 93a0c61406SAlfred Perlstein TUNABLE_INT("hw.usb.no_boot_wait", &usb_no_boot_wait); 9483cadd7dSHans Petter Selasky SYSCTL_INT(_hw_usb, OID_AUTO, no_boot_wait, CTLFLAG_RD|CTLFLAG_TUN, &usb_no_boot_wait, 0, 955ed294aeSHans Petter Selasky "No USB device enumerate waiting at boot."); 96d2b99310SHans Petter Selasky #endif 975ed294aeSHans Petter Selasky 9802f728afSHans Petter Selasky static int usb_no_suspend_wait = 0; 9902f728afSHans Petter Selasky TUNABLE_INT("hw.usb.no_suspend_wait", &usb_no_suspend_wait); 10002f728afSHans Petter Selasky SYSCTL_INT(_hw_usb, OID_AUTO, no_suspend_wait, CTLFLAG_RW|CTLFLAG_TUN, 10102f728afSHans Petter Selasky &usb_no_suspend_wait, 0, "No USB device waiting at system suspend."); 10202f728afSHans Petter Selasky 1035ed294aeSHans Petter Selasky static int usb_no_shutdown_wait = 0; 1045ed294aeSHans Petter Selasky TUNABLE_INT("hw.usb.no_shutdown_wait", &usb_no_shutdown_wait); 10502f728afSHans Petter Selasky SYSCTL_INT(_hw_usb, OID_AUTO, no_shutdown_wait, CTLFLAG_RW|CTLFLAG_TUN, 10602f728afSHans Petter Selasky &usb_no_shutdown_wait, 0, "No USB device waiting at system shutdown."); 107a0c61406SAlfred Perlstein 108a593f6b8SAndrew Thompson static devclass_t usb_devclass; 10902ac6454SAndrew Thompson 110a593f6b8SAndrew Thompson static device_method_t usb_methods[] = { 111a593f6b8SAndrew Thompson DEVMETHOD(device_probe, usb_probe), 112a593f6b8SAndrew Thompson DEVMETHOD(device_attach, usb_attach), 113a593f6b8SAndrew Thompson DEVMETHOD(device_detach, usb_detach), 1142e141748SHans Petter Selasky DEVMETHOD(device_suspend, usb_suspend), 1152e141748SHans Petter Selasky DEVMETHOD(device_resume, usb_resume), 1162e141748SHans Petter Selasky DEVMETHOD(device_shutdown, usb_shutdown), 11761bfd867SSofian Brabez 11861bfd867SSofian Brabez DEVMETHOD_END 11902ac6454SAndrew Thompson }; 12002ac6454SAndrew Thompson 121a593f6b8SAndrew Thompson static driver_t usb_driver = { 12202ac6454SAndrew Thompson .name = "usbus", 123a593f6b8SAndrew Thompson .methods = usb_methods, 12402ac6454SAndrew Thompson .size = 0, 12502ac6454SAndrew Thompson }; 12602ac6454SAndrew Thompson 127864bc412SHans Petter Selasky /* Host Only Drivers */ 128a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, ohci, usb_driver, usb_devclass, 0, 0); 129a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, uhci, usb_driver, usb_devclass, 0, 0); 130a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, ehci, usb_driver, usb_devclass, 0, 0); 131963169b4SHans Petter Selasky DRIVER_MODULE(usbus, xhci, usb_driver, usb_devclass, 0, 0); 132864bc412SHans Petter Selasky 133864bc412SHans Petter Selasky /* Device Only Drivers */ 134a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, at91_udp, usb_driver, usb_devclass, 0, 0); 135864bc412SHans Petter Selasky DRIVER_MODULE(usbus, musbotg, usb_driver, usb_devclass, 0, 0); 136a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, uss820, usb_driver, usb_devclass, 0, 0); 137d42cc946SOleksandr Tymoshenko DRIVER_MODULE(usbus, octusb, usb_driver, usb_devclass, 0, 0); 13802ac6454SAndrew Thompson 139268ae63aSHans Petter Selasky /* Dual Mode Drivers */ 140268ae63aSHans Petter Selasky DRIVER_MODULE(usbus, dwcotg, usb_driver, usb_devclass, 0, 0); 141268ae63aSHans Petter Selasky 14202ac6454SAndrew Thompson /*------------------------------------------------------------------------* 143a593f6b8SAndrew Thompson * usb_probe 14402ac6454SAndrew Thompson * 14502ac6454SAndrew Thompson * This function is called from "{ehci,ohci,uhci}_pci_attach()". 14602ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 14702ac6454SAndrew Thompson static int 148a593f6b8SAndrew Thompson usb_probe(device_t dev) 14902ac6454SAndrew Thompson { 15002ac6454SAndrew Thompson DPRINTF("\n"); 15102ac6454SAndrew Thompson return (0); 15202ac6454SAndrew Thompson } 15302ac6454SAndrew Thompson 154d2b99310SHans Petter Selasky #if USB_HAVE_ROOT_MOUNT_HOLD 1553df007ceSHans Petter Selasky static void 1563df007ceSHans Petter Selasky usb_root_mount_rel(struct usb_bus *bus) 1573df007ceSHans Petter Selasky { 1583df007ceSHans Petter Selasky if (bus->bus_roothold != NULL) { 1593df007ceSHans Petter Selasky DPRINTF("Releasing root mount hold %p\n", bus->bus_roothold); 1603df007ceSHans Petter Selasky root_mount_rel(bus->bus_roothold); 1613df007ceSHans Petter Selasky bus->bus_roothold = NULL; 1623df007ceSHans Petter Selasky } 1633df007ceSHans Petter Selasky } 164d2b99310SHans Petter Selasky #endif 1653df007ceSHans Petter Selasky 16602ac6454SAndrew Thompson /*------------------------------------------------------------------------* 167a593f6b8SAndrew Thompson * usb_attach 16802ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 16902ac6454SAndrew Thompson static int 170a593f6b8SAndrew Thompson usb_attach(device_t dev) 17102ac6454SAndrew Thompson { 172760bc48eSAndrew Thompson struct usb_bus *bus = device_get_ivars(dev); 17302ac6454SAndrew Thompson 17402ac6454SAndrew Thompson DPRINTF("\n"); 17502ac6454SAndrew Thompson 17602ac6454SAndrew Thompson if (bus == NULL) { 177767cb2e2SAndrew Thompson device_printf(dev, "USB device has no ivars\n"); 17802ac6454SAndrew Thompson return (ENXIO); 17902ac6454SAndrew Thompson } 18002ac6454SAndrew Thompson 181d2b99310SHans Petter Selasky #if USB_HAVE_ROOT_MOUNT_HOLD 182a0c61406SAlfred Perlstein if (usb_no_boot_wait == 0) { 18302ac6454SAndrew Thompson /* delay vfs_mountroot until the bus is explored */ 184853a10a5SAndrew Thompson bus->bus_roothold = root_mount_hold(device_get_nameunit(dev)); 185a0c61406SAlfred Perlstein } 186d2b99310SHans Petter Selasky #endif 187a593f6b8SAndrew Thompson usb_attach_sub(dev, bus); 18834b48722SAlfred Perlstein 18902ac6454SAndrew Thompson return (0); /* return success */ 19002ac6454SAndrew Thompson } 19102ac6454SAndrew Thompson 19202ac6454SAndrew Thompson /*------------------------------------------------------------------------* 193a593f6b8SAndrew Thompson * usb_detach 19402ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 19502ac6454SAndrew Thompson static int 196a593f6b8SAndrew Thompson usb_detach(device_t dev) 19702ac6454SAndrew Thompson { 198760bc48eSAndrew Thompson struct usb_bus *bus = device_get_softc(dev); 19902ac6454SAndrew Thompson 20002ac6454SAndrew Thompson DPRINTF("\n"); 20102ac6454SAndrew Thompson 20202ac6454SAndrew Thompson if (bus == NULL) { 20302ac6454SAndrew Thompson /* was never setup properly */ 20402ac6454SAndrew Thompson return (0); 20502ac6454SAndrew Thompson } 20602ac6454SAndrew Thompson /* Stop power watchdog */ 207a593f6b8SAndrew Thompson usb_callout_drain(&bus->power_wdog); 20802ac6454SAndrew Thompson 209d2b99310SHans Petter Selasky #if USB_HAVE_ROOT_MOUNT_HOLD 21002ac6454SAndrew Thompson /* Let the USB explore process detach all devices. */ 2113df007ceSHans Petter Selasky usb_root_mount_rel(bus); 212d2b99310SHans Petter Selasky #endif 21302ac6454SAndrew Thompson 21402ac6454SAndrew Thompson USB_BUS_LOCK(bus); 21502ac6454SAndrew Thompson 2162e141748SHans Petter Selasky /* Queue detach job */ 2179b3a48eeSHans Petter Selasky usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus), 2182e141748SHans Petter Selasky &bus->detach_msg[0], &bus->detach_msg[1]); 2192e141748SHans Petter Selasky 2202e141748SHans Petter Selasky /* Wait for detach to complete */ 2219b3a48eeSHans Petter Selasky usb_proc_mwait(USB_BUS_EXPLORE_PROC(bus), 22202ac6454SAndrew Thompson &bus->detach_msg[0], &bus->detach_msg[1]); 22302ac6454SAndrew Thompson 22402ac6454SAndrew Thompson USB_BUS_UNLOCK(bus); 22502ac6454SAndrew Thompson 2269b3a48eeSHans Petter Selasky #if USB_HAVE_PER_BUS_PROCESS 22702ac6454SAndrew Thompson /* Get rid of USB callback processes */ 22802ac6454SAndrew Thompson 2299b3a48eeSHans Petter Selasky usb_proc_free(USB_BUS_GIANT_PROC(bus)); 2309b3a48eeSHans Petter Selasky usb_proc_free(USB_BUS_NON_GIANT_PROC(bus)); 23102ac6454SAndrew Thompson 23202ac6454SAndrew Thompson /* Get rid of USB explore process */ 23302ac6454SAndrew Thompson 2349b3a48eeSHans Petter Selasky usb_proc_free(USB_BUS_EXPLORE_PROC(bus)); 23502ac6454SAndrew Thompson 236672c9965SAndrew Thompson /* Get rid of control transfer process */ 237672c9965SAndrew Thompson 2389b3a48eeSHans Petter Selasky usb_proc_free(USB_BUS_CONTROL_XFER_PROC(bus)); 2399b3a48eeSHans Petter Selasky #endif 240672c9965SAndrew Thompson 2418be09334SHans Petter Selasky #if USB_HAVE_PF 242fe1c24e3SWeongyo Jeong usbpf_detach(bus); 2438be09334SHans Petter Selasky #endif 24402ac6454SAndrew Thompson return (0); 24502ac6454SAndrew Thompson } 24602ac6454SAndrew Thompson 24702ac6454SAndrew Thompson /*------------------------------------------------------------------------* 2482e141748SHans Petter Selasky * usb_suspend 2492e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 2502e141748SHans Petter Selasky static int 2512e141748SHans Petter Selasky usb_suspend(device_t dev) 2522e141748SHans Petter Selasky { 2532e141748SHans Petter Selasky struct usb_bus *bus = device_get_softc(dev); 2542e141748SHans Petter Selasky 2552e141748SHans Petter Selasky DPRINTF("\n"); 2562e141748SHans Petter Selasky 2572e141748SHans Petter Selasky if (bus == NULL) { 2582e141748SHans Petter Selasky /* was never setup properly */ 2592e141748SHans Petter Selasky return (0); 2602e141748SHans Petter Selasky } 2612e141748SHans Petter Selasky 2622e141748SHans Petter Selasky USB_BUS_LOCK(bus); 2639b3a48eeSHans Petter Selasky usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus), 2642e141748SHans Petter Selasky &bus->suspend_msg[0], &bus->suspend_msg[1]); 26502f728afSHans Petter Selasky if (usb_no_suspend_wait == 0) { 26602f728afSHans Petter Selasky /* wait for suspend callback to be executed */ 2679b3a48eeSHans Petter Selasky usb_proc_mwait(USB_BUS_EXPLORE_PROC(bus), 26802f728afSHans Petter Selasky &bus->suspend_msg[0], &bus->suspend_msg[1]); 26902f728afSHans Petter Selasky } 2702e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 2712e141748SHans Petter Selasky 2722e141748SHans Petter Selasky return (0); 2732e141748SHans Petter Selasky } 2742e141748SHans Petter Selasky 2752e141748SHans Petter Selasky /*------------------------------------------------------------------------* 2762e141748SHans Petter Selasky * usb_resume 2772e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 2782e141748SHans Petter Selasky static int 2792e141748SHans Petter Selasky usb_resume(device_t dev) 2802e141748SHans Petter Selasky { 2812e141748SHans Petter Selasky struct usb_bus *bus = device_get_softc(dev); 2822e141748SHans Petter Selasky 2832e141748SHans Petter Selasky DPRINTF("\n"); 2842e141748SHans Petter Selasky 2852e141748SHans Petter Selasky if (bus == NULL) { 2862e141748SHans Petter Selasky /* was never setup properly */ 2872e141748SHans Petter Selasky return (0); 2882e141748SHans Petter Selasky } 2892e141748SHans Petter Selasky 2902e141748SHans Petter Selasky USB_BUS_LOCK(bus); 2919b3a48eeSHans Petter Selasky usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus), 2922e141748SHans Petter Selasky &bus->resume_msg[0], &bus->resume_msg[1]); 2932e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 2942e141748SHans Petter Selasky 2952e141748SHans Petter Selasky return (0); 2962e141748SHans Petter Selasky } 2972e141748SHans Petter Selasky 2982e141748SHans Petter Selasky /*------------------------------------------------------------------------* 2992e141748SHans Petter Selasky * usb_shutdown 3002e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 3012e141748SHans Petter Selasky static int 3022e141748SHans Petter Selasky usb_shutdown(device_t dev) 3032e141748SHans Petter Selasky { 3042e141748SHans Petter Selasky struct usb_bus *bus = device_get_softc(dev); 3052e141748SHans Petter Selasky 3062e141748SHans Petter Selasky DPRINTF("\n"); 3072e141748SHans Petter Selasky 3082e141748SHans Petter Selasky if (bus == NULL) { 3092e141748SHans Petter Selasky /* was never setup properly */ 3102e141748SHans Petter Selasky return (0); 3112e141748SHans Petter Selasky } 3122e141748SHans Petter Selasky 3135ed294aeSHans Petter Selasky device_printf(bus->bdev, "Controller shutdown\n"); 3145ed294aeSHans Petter Selasky 3152e141748SHans Petter Selasky USB_BUS_LOCK(bus); 3169b3a48eeSHans Petter Selasky usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus), 3172e141748SHans Petter Selasky &bus->shutdown_msg[0], &bus->shutdown_msg[1]); 3185ed294aeSHans Petter Selasky if (usb_no_shutdown_wait == 0) { 3195ed294aeSHans Petter Selasky /* wait for shutdown callback to be executed */ 3209b3a48eeSHans Petter Selasky usb_proc_mwait(USB_BUS_EXPLORE_PROC(bus), 3215ed294aeSHans Petter Selasky &bus->shutdown_msg[0], &bus->shutdown_msg[1]); 3225ed294aeSHans Petter Selasky } 3232e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 3242e141748SHans Petter Selasky 3255ed294aeSHans Petter Selasky device_printf(bus->bdev, "Controller shutdown complete\n"); 3265ed294aeSHans Petter Selasky 3272e141748SHans Petter Selasky return (0); 3282e141748SHans Petter Selasky } 3292e141748SHans Petter Selasky 3302e141748SHans Petter Selasky /*------------------------------------------------------------------------* 331a593f6b8SAndrew Thompson * usb_bus_explore 33202ac6454SAndrew Thompson * 33302ac6454SAndrew Thompson * This function is used to explore the device tree from the root. 33402ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 33502ac6454SAndrew Thompson static void 336a593f6b8SAndrew Thompson usb_bus_explore(struct usb_proc_msg *pm) 33702ac6454SAndrew Thompson { 338760bc48eSAndrew Thompson struct usb_bus *bus; 339760bc48eSAndrew Thompson struct usb_device *udev; 34002ac6454SAndrew Thompson 341760bc48eSAndrew Thompson bus = ((struct usb_bus_msg *)pm)->bus; 34202ac6454SAndrew Thompson udev = bus->devices[USB_ROOT_HUB_ADDR]; 34302ac6454SAndrew Thompson 3442e141748SHans Petter Selasky if (bus->no_explore != 0) 3452e141748SHans Petter Selasky return; 3462e141748SHans Petter Selasky 34702ac6454SAndrew Thompson if (udev && udev->hub) { 34802ac6454SAndrew Thompson 34902ac6454SAndrew Thompson if (bus->do_probe) { 35002ac6454SAndrew Thompson bus->do_probe = 0; 35102ac6454SAndrew Thompson bus->driver_added_refcount++; 35202ac6454SAndrew Thompson } 35302ac6454SAndrew Thompson if (bus->driver_added_refcount == 0) { 35402ac6454SAndrew Thompson /* avoid zero, hence that is memory default */ 35502ac6454SAndrew Thompson bus->driver_added_refcount = 1; 35602ac6454SAndrew Thompson } 35702ac6454SAndrew Thompson 358f0c078e6SAndrew Thompson #ifdef DDB 35934b48722SAlfred Perlstein /* 36034b48722SAlfred Perlstein * The following three lines of code are only here to 36134b48722SAlfred Perlstein * recover from DDB: 36234b48722SAlfred Perlstein */ 3639b3a48eeSHans Petter Selasky usb_proc_rewakeup(USB_BUS_CONTROL_XFER_PROC(bus)); 3649b3a48eeSHans Petter Selasky usb_proc_rewakeup(USB_BUS_GIANT_PROC(bus)); 3659b3a48eeSHans Petter Selasky usb_proc_rewakeup(USB_BUS_NON_GIANT_PROC(bus)); 366f0c078e6SAndrew Thompson #endif 36734b48722SAlfred Perlstein 36834b48722SAlfred Perlstein USB_BUS_UNLOCK(bus); 369a56fe095SJohn Baldwin 370e727a16cSAndrew Thompson #if USB_HAVE_POWERD 37102ac6454SAndrew Thompson /* 37202ac6454SAndrew Thompson * First update the USB power state! 37302ac6454SAndrew Thompson */ 374a593f6b8SAndrew Thompson usb_bus_powerd(bus); 375e727a16cSAndrew Thompson #endif 37634b48722SAlfred Perlstein /* Explore the Root USB HUB. */ 37702ac6454SAndrew Thompson (udev->hub->explore) (udev); 37802ac6454SAndrew Thompson USB_BUS_LOCK(bus); 37902ac6454SAndrew Thompson } 380d2b99310SHans Petter Selasky #if USB_HAVE_ROOT_MOUNT_HOLD 3813df007ceSHans Petter Selasky usb_root_mount_rel(bus); 382d2b99310SHans Petter Selasky #endif 38302ac6454SAndrew Thompson } 38402ac6454SAndrew Thompson 38502ac6454SAndrew Thompson /*------------------------------------------------------------------------* 386a593f6b8SAndrew Thompson * usb_bus_detach 38702ac6454SAndrew Thompson * 38802ac6454SAndrew Thompson * This function is used to detach the device tree from the root. 38902ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 39002ac6454SAndrew Thompson static void 391a593f6b8SAndrew Thompson usb_bus_detach(struct usb_proc_msg *pm) 39202ac6454SAndrew Thompson { 393760bc48eSAndrew Thompson struct usb_bus *bus; 394760bc48eSAndrew Thompson struct usb_device *udev; 39502ac6454SAndrew Thompson device_t dev; 39602ac6454SAndrew Thompson 397760bc48eSAndrew Thompson bus = ((struct usb_bus_msg *)pm)->bus; 39802ac6454SAndrew Thompson udev = bus->devices[USB_ROOT_HUB_ADDR]; 39902ac6454SAndrew Thompson dev = bus->bdev; 40002ac6454SAndrew Thompson /* clear the softc */ 40102ac6454SAndrew Thompson device_set_softc(dev, NULL); 40202ac6454SAndrew Thompson USB_BUS_UNLOCK(bus); 40302ac6454SAndrew Thompson 40402ac6454SAndrew Thompson /* detach children first */ 40534b48722SAlfred Perlstein mtx_lock(&Giant); 40602ac6454SAndrew Thompson bus_generic_detach(dev); 40734b48722SAlfred Perlstein mtx_unlock(&Giant); 40802ac6454SAndrew Thompson 40902ac6454SAndrew Thompson /* 410d88688c7SAndrew Thompson * Free USB device and all subdevices, if any. 41102ac6454SAndrew Thompson */ 412d88688c7SAndrew Thompson usb_free_device(udev, 0); 41302ac6454SAndrew Thompson 41402ac6454SAndrew Thompson USB_BUS_LOCK(bus); 41502ac6454SAndrew Thompson /* clear bdev variable last */ 41602ac6454SAndrew Thompson bus->bdev = NULL; 41702ac6454SAndrew Thompson } 41802ac6454SAndrew Thompson 4192e141748SHans Petter Selasky /*------------------------------------------------------------------------* 4202e141748SHans Petter Selasky * usb_bus_suspend 4212e141748SHans Petter Selasky * 4222e141748SHans Petter Selasky * This function is used to suspend the USB contoller. 4232e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 4242e141748SHans Petter Selasky static void 4252e141748SHans Petter Selasky usb_bus_suspend(struct usb_proc_msg *pm) 4262e141748SHans Petter Selasky { 4272e141748SHans Petter Selasky struct usb_bus *bus; 4282e141748SHans Petter Selasky struct usb_device *udev; 4292e141748SHans Petter Selasky usb_error_t err; 430*a18a7a41SHans Petter Selasky uint8_t do_unlock; 4312e141748SHans Petter Selasky 4322e141748SHans Petter Selasky bus = ((struct usb_bus_msg *)pm)->bus; 4332e141748SHans Petter Selasky udev = bus->devices[USB_ROOT_HUB_ADDR]; 4342e141748SHans Petter Selasky 4352e141748SHans Petter Selasky if (udev == NULL || bus->bdev == NULL) 4362e141748SHans Petter Selasky return; 4372e141748SHans Petter Selasky 4386bd3e535SHans Petter Selasky USB_BUS_UNLOCK(bus); 4396bd3e535SHans Petter Selasky 44002f728afSHans Petter Selasky /* 44102f728afSHans Petter Selasky * We use the shutdown event here because the suspend and 44202f728afSHans Petter Selasky * resume events are reserved for the USB port suspend and 44302f728afSHans Petter Selasky * resume. The USB system suspend is implemented like full 44402f728afSHans Petter Selasky * shutdown and all connected USB devices will be disconnected 44502f728afSHans Petter Selasky * subsequently. At resume all USB devices will be 44602f728afSHans Petter Selasky * re-connected again. 44702f728afSHans Petter Selasky */ 44802f728afSHans Petter Selasky 4492e141748SHans Petter Selasky bus_generic_shutdown(bus->bdev); 4502e141748SHans Petter Selasky 451*a18a7a41SHans Petter Selasky do_unlock = usbd_enum_lock(udev); 4522e141748SHans Petter Selasky 4532e141748SHans Petter Selasky err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX); 4542e141748SHans Petter Selasky if (err) 4552e141748SHans Petter Selasky device_printf(bus->bdev, "Could not unconfigure root HUB\n"); 4562e141748SHans Petter Selasky 4572e141748SHans Petter Selasky USB_BUS_LOCK(bus); 4582e141748SHans Petter Selasky bus->hw_power_state = 0; 4592e141748SHans Petter Selasky bus->no_explore = 1; 4602e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 4612e141748SHans Petter Selasky 4622e141748SHans Petter Selasky if (bus->methods->set_hw_power != NULL) 4632e141748SHans Petter Selasky (bus->methods->set_hw_power) (bus); 4642e141748SHans Petter Selasky 4652e141748SHans Petter Selasky if (bus->methods->set_hw_power_sleep != NULL) 4662e141748SHans Petter Selasky (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SUSPEND); 4672e141748SHans Petter Selasky 468*a18a7a41SHans Petter Selasky if (do_unlock) 4692e141748SHans Petter Selasky usbd_enum_unlock(udev); 4706bd3e535SHans Petter Selasky 4716bd3e535SHans Petter Selasky USB_BUS_LOCK(bus); 4722e141748SHans Petter Selasky } 4732e141748SHans Petter Selasky 4742e141748SHans Petter Selasky /*------------------------------------------------------------------------* 4752e141748SHans Petter Selasky * usb_bus_resume 4762e141748SHans Petter Selasky * 4772e141748SHans Petter Selasky * This function is used to resume the USB contoller. 4782e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 4792e141748SHans Petter Selasky static void 4802e141748SHans Petter Selasky usb_bus_resume(struct usb_proc_msg *pm) 4812e141748SHans Petter Selasky { 4822e141748SHans Petter Selasky struct usb_bus *bus; 4832e141748SHans Petter Selasky struct usb_device *udev; 4842e141748SHans Petter Selasky usb_error_t err; 485*a18a7a41SHans Petter Selasky uint8_t do_unlock; 4862e141748SHans Petter Selasky 4872e141748SHans Petter Selasky bus = ((struct usb_bus_msg *)pm)->bus; 4882e141748SHans Petter Selasky udev = bus->devices[USB_ROOT_HUB_ADDR]; 4892e141748SHans Petter Selasky 4902e141748SHans Petter Selasky if (udev == NULL || bus->bdev == NULL) 4912e141748SHans Petter Selasky return; 4922e141748SHans Petter Selasky 4936bd3e535SHans Petter Selasky USB_BUS_UNLOCK(bus); 4946bd3e535SHans Petter Selasky 495*a18a7a41SHans Petter Selasky do_unlock = usbd_enum_lock(udev); 4962e141748SHans Petter Selasky #if 0 4972e141748SHans Petter Selasky DEVMETHOD(usb_take_controller, NULL); /* dummy */ 4982e141748SHans Petter Selasky #endif 4992e141748SHans Petter Selasky USB_TAKE_CONTROLLER(device_get_parent(bus->bdev)); 5002e141748SHans Petter Selasky 5012e141748SHans Petter Selasky USB_BUS_LOCK(bus); 5022e141748SHans Petter Selasky bus->hw_power_state = 5032e141748SHans Petter Selasky USB_HW_POWER_CONTROL | 5042e141748SHans Petter Selasky USB_HW_POWER_BULK | 5052e141748SHans Petter Selasky USB_HW_POWER_INTERRUPT | 5062e141748SHans Petter Selasky USB_HW_POWER_ISOC | 5072e141748SHans Petter Selasky USB_HW_POWER_NON_ROOT_HUB; 5082e141748SHans Petter Selasky bus->no_explore = 0; 5092e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 5102e141748SHans Petter Selasky 5112e141748SHans Petter Selasky if (bus->methods->set_hw_power_sleep != NULL) 5122e141748SHans Petter Selasky (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_RESUME); 5132e141748SHans Petter Selasky 5142e141748SHans Petter Selasky if (bus->methods->set_hw_power != NULL) 5152e141748SHans Petter Selasky (bus->methods->set_hw_power) (bus); 5162e141748SHans Petter Selasky 5176bbe7cdfSHans Petter Selasky /* restore USB configuration to index 0 */ 5182e141748SHans Petter Selasky err = usbd_set_config_index(udev, 0); 5192e141748SHans Petter Selasky if (err) 5202e141748SHans Petter Selasky device_printf(bus->bdev, "Could not configure root HUB\n"); 5212e141748SHans Petter Selasky 5226bbe7cdfSHans Petter Selasky /* probe and attach */ 5236bbe7cdfSHans Petter Selasky err = usb_probe_and_attach(udev, USB_IFACE_INDEX_ANY); 5246bbe7cdfSHans Petter Selasky if (err) { 5256bbe7cdfSHans Petter Selasky device_printf(bus->bdev, "Could not probe and " 5266bbe7cdfSHans Petter Selasky "attach root HUB\n"); 5276bbe7cdfSHans Petter Selasky } 5286bbe7cdfSHans Petter Selasky 529*a18a7a41SHans Petter Selasky if (do_unlock) 5302e141748SHans Petter Selasky usbd_enum_unlock(udev); 5316bd3e535SHans Petter Selasky 5326bd3e535SHans Petter Selasky USB_BUS_LOCK(bus); 5332e141748SHans Petter Selasky } 5342e141748SHans Petter Selasky 5352e141748SHans Petter Selasky /*------------------------------------------------------------------------* 5362e141748SHans Petter Selasky * usb_bus_shutdown 5372e141748SHans Petter Selasky * 5382e141748SHans Petter Selasky * This function is used to shutdown the USB contoller. 5392e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 5402e141748SHans Petter Selasky static void 5412e141748SHans Petter Selasky usb_bus_shutdown(struct usb_proc_msg *pm) 5422e141748SHans Petter Selasky { 5432e141748SHans Petter Selasky struct usb_bus *bus; 5442e141748SHans Petter Selasky struct usb_device *udev; 5452e141748SHans Petter Selasky usb_error_t err; 546*a18a7a41SHans Petter Selasky uint8_t do_unlock; 5472e141748SHans Petter Selasky 5482e141748SHans Petter Selasky bus = ((struct usb_bus_msg *)pm)->bus; 5492e141748SHans Petter Selasky udev = bus->devices[USB_ROOT_HUB_ADDR]; 5502e141748SHans Petter Selasky 5512e141748SHans Petter Selasky if (udev == NULL || bus->bdev == NULL) 5522e141748SHans Petter Selasky return; 5532e141748SHans Petter Selasky 5546bd3e535SHans Petter Selasky USB_BUS_UNLOCK(bus); 5556bd3e535SHans Petter Selasky 5562e141748SHans Petter Selasky bus_generic_shutdown(bus->bdev); 5572e141748SHans Petter Selasky 558*a18a7a41SHans Petter Selasky do_unlock = usbd_enum_lock(udev); 5592e141748SHans Petter Selasky 5602e141748SHans Petter Selasky err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX); 5612e141748SHans Petter Selasky if (err) 5622e141748SHans Petter Selasky device_printf(bus->bdev, "Could not unconfigure root HUB\n"); 5632e141748SHans Petter Selasky 5642e141748SHans Petter Selasky USB_BUS_LOCK(bus); 5652e141748SHans Petter Selasky bus->hw_power_state = 0; 5662e141748SHans Petter Selasky bus->no_explore = 1; 5672e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 5682e141748SHans Petter Selasky 5692e141748SHans Petter Selasky if (bus->methods->set_hw_power != NULL) 5702e141748SHans Petter Selasky (bus->methods->set_hw_power) (bus); 5712e141748SHans Petter Selasky 5722e141748SHans Petter Selasky if (bus->methods->set_hw_power_sleep != NULL) 5732e141748SHans Petter Selasky (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SHUTDOWN); 5742e141748SHans Petter Selasky 575*a18a7a41SHans Petter Selasky if (do_unlock) 5762e141748SHans Petter Selasky usbd_enum_unlock(udev); 5776bd3e535SHans Petter Selasky 5786bd3e535SHans Petter Selasky USB_BUS_LOCK(bus); 5792e141748SHans Petter Selasky } 5802e141748SHans Petter Selasky 58102ac6454SAndrew Thompson static void 582a593f6b8SAndrew Thompson usb_power_wdog(void *arg) 58302ac6454SAndrew Thompson { 584760bc48eSAndrew Thompson struct usb_bus *bus = arg; 58502ac6454SAndrew Thompson 58602ac6454SAndrew Thompson USB_BUS_LOCK_ASSERT(bus, MA_OWNED); 58702ac6454SAndrew Thompson 588a593f6b8SAndrew Thompson usb_callout_reset(&bus->power_wdog, 589a593f6b8SAndrew Thompson 4 * hz, usb_power_wdog, arg); 59002ac6454SAndrew Thompson 591f0c078e6SAndrew Thompson #ifdef DDB 59234b48722SAlfred Perlstein /* 59334b48722SAlfred Perlstein * The following line of code is only here to recover from 59434b48722SAlfred Perlstein * DDB: 59534b48722SAlfred Perlstein */ 5969b3a48eeSHans Petter Selasky usb_proc_rewakeup(USB_BUS_EXPLORE_PROC(bus)); /* recover from DDB */ 597f0c078e6SAndrew Thompson #endif 59834b48722SAlfred Perlstein 599e727a16cSAndrew Thompson #if USB_HAVE_POWERD 60002ac6454SAndrew Thompson USB_BUS_UNLOCK(bus); 60102ac6454SAndrew Thompson 602a593f6b8SAndrew Thompson usb_bus_power_update(bus); 60302ac6454SAndrew Thompson 604684e3f22SAndrew Thompson USB_BUS_LOCK(bus); 605e727a16cSAndrew Thompson #endif 60602ac6454SAndrew Thompson } 60702ac6454SAndrew Thompson 60802ac6454SAndrew Thompson /*------------------------------------------------------------------------* 609a593f6b8SAndrew Thompson * usb_bus_attach 61002ac6454SAndrew Thompson * 61102ac6454SAndrew Thompson * This function attaches USB in context of the explore thread. 61202ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 61302ac6454SAndrew Thompson static void 614a593f6b8SAndrew Thompson usb_bus_attach(struct usb_proc_msg *pm) 61502ac6454SAndrew Thompson { 616760bc48eSAndrew Thompson struct usb_bus *bus; 617760bc48eSAndrew Thompson struct usb_device *child; 61802ac6454SAndrew Thompson device_t dev; 619e0a69b51SAndrew Thompson usb_error_t err; 6208d2dd5ddSAndrew Thompson enum usb_dev_speed speed; 62102ac6454SAndrew Thompson 622760bc48eSAndrew Thompson bus = ((struct usb_bus_msg *)pm)->bus; 62302ac6454SAndrew Thompson dev = bus->bdev; 62402ac6454SAndrew Thompson 62502ac6454SAndrew Thompson DPRINTF("\n"); 62602ac6454SAndrew Thompson 62702ac6454SAndrew Thompson switch (bus->usbrev) { 62802ac6454SAndrew Thompson case USB_REV_1_0: 62902ac6454SAndrew Thompson speed = USB_SPEED_FULL; 63002ac6454SAndrew Thompson device_printf(bus->bdev, "12Mbps Full Speed USB v1.0\n"); 63102ac6454SAndrew Thompson break; 63202ac6454SAndrew Thompson 63302ac6454SAndrew Thompson case USB_REV_1_1: 63402ac6454SAndrew Thompson speed = USB_SPEED_FULL; 63502ac6454SAndrew Thompson device_printf(bus->bdev, "12Mbps Full Speed USB v1.1\n"); 63602ac6454SAndrew Thompson break; 63702ac6454SAndrew Thompson 63802ac6454SAndrew Thompson case USB_REV_2_0: 63902ac6454SAndrew Thompson speed = USB_SPEED_HIGH; 64002ac6454SAndrew Thompson device_printf(bus->bdev, "480Mbps High Speed USB v2.0\n"); 64102ac6454SAndrew Thompson break; 64202ac6454SAndrew Thompson 64302ac6454SAndrew Thompson case USB_REV_2_5: 64402ac6454SAndrew Thompson speed = USB_SPEED_VARIABLE; 64502ac6454SAndrew Thompson device_printf(bus->bdev, "480Mbps Wireless USB v2.5\n"); 64602ac6454SAndrew Thompson break; 64702ac6454SAndrew Thompson 648963169b4SHans Petter Selasky case USB_REV_3_0: 649963169b4SHans Petter Selasky speed = USB_SPEED_SUPER; 650ccac019aSHans Petter Selasky device_printf(bus->bdev, "5.0Gbps Super Speed USB v3.0\n"); 651963169b4SHans Petter Selasky break; 652963169b4SHans Petter Selasky 65302ac6454SAndrew Thompson default: 654767cb2e2SAndrew Thompson device_printf(bus->bdev, "Unsupported USB revision\n"); 655d2b99310SHans Petter Selasky #if USB_HAVE_ROOT_MOUNT_HOLD 6563df007ceSHans Petter Selasky usb_root_mount_rel(bus); 657d2b99310SHans Petter Selasky #endif 65802ac6454SAndrew Thompson return; 65902ac6454SAndrew Thompson } 66002ac6454SAndrew Thompson 6614eae601eSAndrew Thompson /* default power_mask value */ 6624eae601eSAndrew Thompson bus->hw_power_state = 6634eae601eSAndrew Thompson USB_HW_POWER_CONTROL | 6644eae601eSAndrew Thompson USB_HW_POWER_BULK | 6654eae601eSAndrew Thompson USB_HW_POWER_INTERRUPT | 6664eae601eSAndrew Thompson USB_HW_POWER_ISOC | 6674eae601eSAndrew Thompson USB_HW_POWER_NON_ROOT_HUB; 6684eae601eSAndrew Thompson 6692e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 6702e141748SHans Petter Selasky 6714eae601eSAndrew Thompson /* make sure power is set at least once */ 6724eae601eSAndrew Thompson 6734eae601eSAndrew Thompson if (bus->methods->set_hw_power != NULL) { 6744eae601eSAndrew Thompson (bus->methods->set_hw_power) (bus); 6754eae601eSAndrew Thompson } 6764eae601eSAndrew Thompson 6772e141748SHans Petter Selasky /* allocate the Root USB device */ 67802ac6454SAndrew Thompson 679a593f6b8SAndrew Thompson child = usb_alloc_device(bus->bdev, bus, NULL, 0, 0, 1, 68002ac6454SAndrew Thompson speed, USB_MODE_HOST); 68102ac6454SAndrew Thompson if (child) { 682a593f6b8SAndrew Thompson err = usb_probe_and_attach(child, 68302ac6454SAndrew Thompson USB_IFACE_INDEX_ANY); 68402ac6454SAndrew Thompson if (!err) { 6851be5bf51SAndrew Thompson if ((bus->devices[USB_ROOT_HUB_ADDR] == NULL) || 6861be5bf51SAndrew Thompson (bus->devices[USB_ROOT_HUB_ADDR]->hub == NULL)) { 68702ac6454SAndrew Thompson err = USB_ERR_NO_ROOT_HUB; 68802ac6454SAndrew Thompson } 68902ac6454SAndrew Thompson } 69002ac6454SAndrew Thompson } else { 69102ac6454SAndrew Thompson err = USB_ERR_NOMEM; 69202ac6454SAndrew Thompson } 69302ac6454SAndrew Thompson 69402ac6454SAndrew Thompson USB_BUS_LOCK(bus); 69502ac6454SAndrew Thompson 69602ac6454SAndrew Thompson if (err) { 69702ac6454SAndrew Thompson device_printf(bus->bdev, "Root HUB problem, error=%s\n", 698a593f6b8SAndrew Thompson usbd_errstr(err)); 699d2b99310SHans Petter Selasky #if USB_HAVE_ROOT_MOUNT_HOLD 7003df007ceSHans Petter Selasky usb_root_mount_rel(bus); 701d2b99310SHans Petter Selasky #endif 70202ac6454SAndrew Thompson } 70302ac6454SAndrew Thompson 70402ac6454SAndrew Thompson /* set softc - we are ready */ 70502ac6454SAndrew Thompson device_set_softc(dev, bus); 70602ac6454SAndrew Thompson 707684e3f22SAndrew Thompson /* start watchdog */ 708a593f6b8SAndrew Thompson usb_power_wdog(bus); 70902ac6454SAndrew Thompson } 71002ac6454SAndrew Thompson 71102ac6454SAndrew Thompson /*------------------------------------------------------------------------* 712a593f6b8SAndrew Thompson * usb_attach_sub 71302ac6454SAndrew Thompson * 71434b48722SAlfred Perlstein * This function creates a thread which runs the USB attach code. 71502ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 71602ac6454SAndrew Thompson static void 717a593f6b8SAndrew Thompson usb_attach_sub(device_t dev, struct usb_bus *bus) 71802ac6454SAndrew Thompson { 71934b48722SAlfred Perlstein mtx_lock(&Giant); 72034b48722SAlfred Perlstein if (usb_devclass_ptr == NULL) 72134b48722SAlfred Perlstein usb_devclass_ptr = devclass_find("usbus"); 72234b48722SAlfred Perlstein mtx_unlock(&Giant); 72334b48722SAlfred Perlstein 7248be09334SHans Petter Selasky #if USB_HAVE_PF 725fe1c24e3SWeongyo Jeong usbpf_attach(bus); 7268be09334SHans Petter Selasky #endif 72702ac6454SAndrew Thompson /* Initialise USB process messages */ 728a593f6b8SAndrew Thompson bus->explore_msg[0].hdr.pm_callback = &usb_bus_explore; 72902ac6454SAndrew Thompson bus->explore_msg[0].bus = bus; 730a593f6b8SAndrew Thompson bus->explore_msg[1].hdr.pm_callback = &usb_bus_explore; 73102ac6454SAndrew Thompson bus->explore_msg[1].bus = bus; 73202ac6454SAndrew Thompson 733a593f6b8SAndrew Thompson bus->detach_msg[0].hdr.pm_callback = &usb_bus_detach; 73402ac6454SAndrew Thompson bus->detach_msg[0].bus = bus; 735a593f6b8SAndrew Thompson bus->detach_msg[1].hdr.pm_callback = &usb_bus_detach; 73602ac6454SAndrew Thompson bus->detach_msg[1].bus = bus; 73702ac6454SAndrew Thompson 738a593f6b8SAndrew Thompson bus->attach_msg[0].hdr.pm_callback = &usb_bus_attach; 73902ac6454SAndrew Thompson bus->attach_msg[0].bus = bus; 740a593f6b8SAndrew Thompson bus->attach_msg[1].hdr.pm_callback = &usb_bus_attach; 74102ac6454SAndrew Thompson bus->attach_msg[1].bus = bus; 74202ac6454SAndrew Thompson 7432e141748SHans Petter Selasky bus->suspend_msg[0].hdr.pm_callback = &usb_bus_suspend; 7442e141748SHans Petter Selasky bus->suspend_msg[0].bus = bus; 7452e141748SHans Petter Selasky bus->suspend_msg[1].hdr.pm_callback = &usb_bus_suspend; 7462e141748SHans Petter Selasky bus->suspend_msg[1].bus = bus; 7472e141748SHans Petter Selasky 7482e141748SHans Petter Selasky bus->resume_msg[0].hdr.pm_callback = &usb_bus_resume; 7492e141748SHans Petter Selasky bus->resume_msg[0].bus = bus; 7502e141748SHans Petter Selasky bus->resume_msg[1].hdr.pm_callback = &usb_bus_resume; 7512e141748SHans Petter Selasky bus->resume_msg[1].bus = bus; 7522e141748SHans Petter Selasky 7532e141748SHans Petter Selasky bus->shutdown_msg[0].hdr.pm_callback = &usb_bus_shutdown; 7542e141748SHans Petter Selasky bus->shutdown_msg[0].bus = bus; 7552e141748SHans Petter Selasky bus->shutdown_msg[1].hdr.pm_callback = &usb_bus_shutdown; 7562e141748SHans Petter Selasky bus->shutdown_msg[1].bus = bus; 7572e141748SHans Petter Selasky 7589b3a48eeSHans Petter Selasky #if USB_HAVE_PER_BUS_PROCESS 75939307315SAndrew Thompson /* Create USB explore and callback processes */ 76002ac6454SAndrew Thompson 7619b3a48eeSHans Petter Selasky if (usb_proc_create(USB_BUS_GIANT_PROC(bus), 7629b3a48eeSHans Petter Selasky &bus->bus_mtx, device_get_nameunit(dev), USB_PRI_MED)) { 76388334428SHans Petter Selasky device_printf(dev, "WARNING: Creation of USB Giant " 76402ac6454SAndrew Thompson "callback process failed.\n"); 7659b3a48eeSHans Petter Selasky } else if (usb_proc_create(USB_BUS_NON_GIANT_PROC(bus), 7669b3a48eeSHans Petter Selasky &bus->bus_mtx, device_get_nameunit(dev), USB_PRI_HIGH)) { 76788334428SHans Petter Selasky device_printf(dev, "WARNING: Creation of USB non-Giant " 76802ac6454SAndrew Thompson "callback process failed.\n"); 7699b3a48eeSHans Petter Selasky } else if (usb_proc_create(USB_BUS_EXPLORE_PROC(bus), 7709b3a48eeSHans Petter Selasky &bus->bus_mtx, device_get_nameunit(dev), USB_PRI_MED)) { 77188334428SHans Petter Selasky device_printf(dev, "WARNING: Creation of USB explore " 77202ac6454SAndrew Thompson "process failed.\n"); 7739b3a48eeSHans Petter Selasky } else if (usb_proc_create(USB_BUS_CONTROL_XFER_PROC(bus), 7749b3a48eeSHans Petter Selasky &bus->bus_mtx, device_get_nameunit(dev), USB_PRI_MED)) { 77588334428SHans Petter Selasky device_printf(dev, "WARNING: Creation of USB control transfer " 776672c9965SAndrew Thompson "process failed.\n"); 7779b3a48eeSHans Petter Selasky } else 7789b3a48eeSHans Petter Selasky #endif 7799b3a48eeSHans Petter Selasky { 78002ac6454SAndrew Thompson /* Get final attach going */ 78102ac6454SAndrew Thompson USB_BUS_LOCK(bus); 7829b3a48eeSHans Petter Selasky usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus), 7832e141748SHans Petter Selasky &bus->attach_msg[0], &bus->attach_msg[1]); 78402ac6454SAndrew Thompson USB_BUS_UNLOCK(bus); 78534b48722SAlfred Perlstein 78634b48722SAlfred Perlstein /* Do initial explore */ 78734b48722SAlfred Perlstein usb_needs_explore(bus, 1); 78802ac6454SAndrew Thompson } 78902ac6454SAndrew Thompson } 790a593f6b8SAndrew Thompson SYSUNINIT(usb_bus_unload, SI_SUB_KLD, SI_ORDER_ANY, usb_bus_unload, NULL); 79102ac6454SAndrew Thompson 79202ac6454SAndrew Thompson /*------------------------------------------------------------------------* 793a593f6b8SAndrew Thompson * usb_bus_mem_flush_all_cb 79402ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 795bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 79602ac6454SAndrew Thompson static void 797a593f6b8SAndrew Thompson usb_bus_mem_flush_all_cb(struct usb_bus *bus, struct usb_page_cache *pc, 798f9cb546cSAndrew Thompson struct usb_page *pg, usb_size_t size, usb_size_t align) 79902ac6454SAndrew Thompson { 800a593f6b8SAndrew Thompson usb_pc_cpu_flush(pc); 80102ac6454SAndrew Thompson } 802bdc081c6SAndrew Thompson #endif 80302ac6454SAndrew Thompson 80402ac6454SAndrew Thompson /*------------------------------------------------------------------------* 805a593f6b8SAndrew Thompson * usb_bus_mem_flush_all - factored out code 80602ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 807bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 80802ac6454SAndrew Thompson void 809a593f6b8SAndrew Thompson usb_bus_mem_flush_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb) 81002ac6454SAndrew Thompson { 81102ac6454SAndrew Thompson if (cb) { 812a593f6b8SAndrew Thompson cb(bus, &usb_bus_mem_flush_all_cb); 81302ac6454SAndrew Thompson } 81402ac6454SAndrew Thompson } 815bdc081c6SAndrew Thompson #endif 81602ac6454SAndrew Thompson 81702ac6454SAndrew Thompson /*------------------------------------------------------------------------* 818a593f6b8SAndrew Thompson * usb_bus_mem_alloc_all_cb 81902ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 820bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 82102ac6454SAndrew Thompson static void 822a593f6b8SAndrew Thompson usb_bus_mem_alloc_all_cb(struct usb_bus *bus, struct usb_page_cache *pc, 823f9cb546cSAndrew Thompson struct usb_page *pg, usb_size_t size, usb_size_t align) 82402ac6454SAndrew Thompson { 82502ac6454SAndrew Thompson /* need to initialize the page cache */ 82602ac6454SAndrew Thompson pc->tag_parent = bus->dma_parent_tag; 82702ac6454SAndrew Thompson 828a593f6b8SAndrew Thompson if (usb_pc_alloc_mem(pc, pg, size, align)) { 82902ac6454SAndrew Thompson bus->alloc_failed = 1; 83002ac6454SAndrew Thompson } 83102ac6454SAndrew Thompson } 832bdc081c6SAndrew Thompson #endif 83302ac6454SAndrew Thompson 83402ac6454SAndrew Thompson /*------------------------------------------------------------------------* 835a593f6b8SAndrew Thompson * usb_bus_mem_alloc_all - factored out code 83602ac6454SAndrew Thompson * 83702ac6454SAndrew Thompson * Returns: 83802ac6454SAndrew Thompson * 0: Success 83902ac6454SAndrew Thompson * Else: Failure 84002ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 84102ac6454SAndrew Thompson uint8_t 842a593f6b8SAndrew Thompson usb_bus_mem_alloc_all(struct usb_bus *bus, bus_dma_tag_t dmat, 843e0a69b51SAndrew Thompson usb_bus_mem_cb_t *cb) 84402ac6454SAndrew Thompson { 84502ac6454SAndrew Thompson bus->alloc_failed = 0; 84602ac6454SAndrew Thompson 84702ac6454SAndrew Thompson mtx_init(&bus->bus_mtx, device_get_nameunit(bus->parent), 84802ac6454SAndrew Thompson NULL, MTX_DEF | MTX_RECURSE); 84902ac6454SAndrew Thompson 850a593f6b8SAndrew Thompson usb_callout_init_mtx(&bus->power_wdog, 851684e3f22SAndrew Thompson &bus->bus_mtx, 0); 85202ac6454SAndrew Thompson 85302ac6454SAndrew Thompson TAILQ_INIT(&bus->intr_q.head); 85402ac6454SAndrew Thompson 855bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 856a593f6b8SAndrew Thompson usb_dma_tag_setup(bus->dma_parent_tag, bus->dma_tags, 857bdc081c6SAndrew Thompson dmat, &bus->bus_mtx, NULL, 32, USB_BUS_DMA_TAG_MAX); 858bdc081c6SAndrew Thompson #endif 85902ac6454SAndrew Thompson if ((bus->devices_max > USB_MAX_DEVICES) || 86002ac6454SAndrew Thompson (bus->devices_max < USB_MIN_DEVICES) || 86102ac6454SAndrew Thompson (bus->devices == NULL)) { 86202ac6454SAndrew Thompson DPRINTFN(0, "Devices field has not been " 863767cb2e2SAndrew Thompson "initialised properly\n"); 86402ac6454SAndrew Thompson bus->alloc_failed = 1; /* failure */ 86502ac6454SAndrew Thompson } 866bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 86702ac6454SAndrew Thompson if (cb) { 868a593f6b8SAndrew Thompson cb(bus, &usb_bus_mem_alloc_all_cb); 86902ac6454SAndrew Thompson } 870bdc081c6SAndrew Thompson #endif 87102ac6454SAndrew Thompson if (bus->alloc_failed) { 872a593f6b8SAndrew Thompson usb_bus_mem_free_all(bus, cb); 87302ac6454SAndrew Thompson } 87402ac6454SAndrew Thompson return (bus->alloc_failed); 87502ac6454SAndrew Thompson } 87602ac6454SAndrew Thompson 87702ac6454SAndrew Thompson /*------------------------------------------------------------------------* 878a593f6b8SAndrew Thompson * usb_bus_mem_free_all_cb 87902ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 880bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 88102ac6454SAndrew Thompson static void 882a593f6b8SAndrew Thompson usb_bus_mem_free_all_cb(struct usb_bus *bus, struct usb_page_cache *pc, 883f9cb546cSAndrew Thompson struct usb_page *pg, usb_size_t size, usb_size_t align) 88402ac6454SAndrew Thompson { 885a593f6b8SAndrew Thompson usb_pc_free_mem(pc); 88602ac6454SAndrew Thompson } 887bdc081c6SAndrew Thompson #endif 88802ac6454SAndrew Thompson 88902ac6454SAndrew Thompson /*------------------------------------------------------------------------* 890a593f6b8SAndrew Thompson * usb_bus_mem_free_all - factored out code 89102ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 89202ac6454SAndrew Thompson void 893a593f6b8SAndrew Thompson usb_bus_mem_free_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb) 89402ac6454SAndrew Thompson { 895bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 89602ac6454SAndrew Thompson if (cb) { 897a593f6b8SAndrew Thompson cb(bus, &usb_bus_mem_free_all_cb); 89802ac6454SAndrew Thompson } 899a593f6b8SAndrew Thompson usb_dma_tag_unsetup(bus->dma_parent_tag); 900bdc081c6SAndrew Thompson #endif 90102ac6454SAndrew Thompson 90202ac6454SAndrew Thompson mtx_destroy(&bus->bus_mtx); 90302ac6454SAndrew Thompson } 904