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 27f0c078e6SAndrew Thompson #include "opt_ddb.h" 28f0c078e6SAndrew Thompson 29ed6d949aSAndrew Thompson #include <sys/stdint.h> 30ed6d949aSAndrew Thompson #include <sys/stddef.h> 31ed6d949aSAndrew Thompson #include <sys/param.h> 32ed6d949aSAndrew Thompson #include <sys/queue.h> 33ed6d949aSAndrew Thompson #include <sys/types.h> 34ed6d949aSAndrew Thompson #include <sys/systm.h> 35ed6d949aSAndrew Thompson #include <sys/kernel.h> 36ed6d949aSAndrew Thompson #include <sys/bus.h> 37ed6d949aSAndrew Thompson #include <sys/module.h> 38ed6d949aSAndrew Thompson #include <sys/lock.h> 39ed6d949aSAndrew Thompson #include <sys/mutex.h> 40ed6d949aSAndrew Thompson #include <sys/condvar.h> 41ed6d949aSAndrew Thompson #include <sys/sysctl.h> 42ed6d949aSAndrew Thompson #include <sys/sx.h> 43ed6d949aSAndrew Thompson #include <sys/unistd.h> 44ed6d949aSAndrew Thompson #include <sys/callout.h> 45ed6d949aSAndrew Thompson #include <sys/malloc.h> 46ed6d949aSAndrew Thompson #include <sys/priv.h> 47ed6d949aSAndrew Thompson 4802ac6454SAndrew Thompson #include <dev/usb/usb.h> 49ed6d949aSAndrew Thompson #include <dev/usb/usbdi.h> 5002ac6454SAndrew Thompson 51a593f6b8SAndrew Thompson #define USB_DEBUG_VAR usb_ctrl_debug 5202ac6454SAndrew Thompson 5302ac6454SAndrew Thompson #include <dev/usb/usb_core.h> 5402ac6454SAndrew Thompson #include <dev/usb/usb_debug.h> 5502ac6454SAndrew Thompson #include <dev/usb/usb_process.h> 5602ac6454SAndrew Thompson #include <dev/usb/usb_busdma.h> 5702ac6454SAndrew Thompson #include <dev/usb/usb_dynamic.h> 5802ac6454SAndrew Thompson #include <dev/usb/usb_device.h> 5902ac6454SAndrew Thompson #include <dev/usb/usb_hub.h> 6002ac6454SAndrew Thompson 6102ac6454SAndrew Thompson #include <dev/usb/usb_controller.h> 6202ac6454SAndrew Thompson #include <dev/usb/usb_bus.h> 6318ec6525SWeongyo Jeong #include <dev/usb/usb_pf.h> 642e141748SHans Petter Selasky #include "usb_if.h" 6502ac6454SAndrew Thompson 6602ac6454SAndrew Thompson /* function prototypes */ 6702ac6454SAndrew Thompson 68a593f6b8SAndrew Thompson static device_probe_t usb_probe; 69a593f6b8SAndrew Thompson static device_attach_t usb_attach; 70a593f6b8SAndrew Thompson static device_detach_t usb_detach; 712e141748SHans Petter Selasky static device_suspend_t usb_suspend; 722e141748SHans Petter Selasky static device_resume_t usb_resume; 732e141748SHans Petter Selasky static device_shutdown_t usb_shutdown; 7402ac6454SAndrew Thompson 75a593f6b8SAndrew Thompson static void usb_attach_sub(device_t, struct usb_bus *); 7602ac6454SAndrew Thompson 7702ac6454SAndrew Thompson /* static variables */ 7802ac6454SAndrew Thompson 79ed6d949aSAndrew Thompson #ifdef USB_DEBUG 80a593f6b8SAndrew Thompson static int usb_ctrl_debug = 0; 8102ac6454SAndrew Thompson 826472ac3dSEd Schouten static SYSCTL_NODE(_hw_usb, OID_AUTO, ctrl, CTLFLAG_RW, 0, "USB controller"); 83a593f6b8SAndrew Thompson SYSCTL_INT(_hw_usb_ctrl, OID_AUTO, debug, CTLFLAG_RW, &usb_ctrl_debug, 0, 8402ac6454SAndrew Thompson "Debug level"); 8502ac6454SAndrew Thompson #endif 8602ac6454SAndrew Thompson 87a0c61406SAlfred Perlstein static int usb_no_boot_wait = 0; 88a0c61406SAlfred Perlstein TUNABLE_INT("hw.usb.no_boot_wait", &usb_no_boot_wait); 89a0c61406SAlfred Perlstein SYSCTL_INT(_hw_usb, OID_AUTO, no_boot_wait, CTLFLAG_RDTUN, &usb_no_boot_wait, 0, 905ed294aeSHans Petter Selasky "No USB device enumerate waiting at boot."); 915ed294aeSHans Petter Selasky 9202f728afSHans Petter Selasky static int usb_no_suspend_wait = 0; 9302f728afSHans Petter Selasky TUNABLE_INT("hw.usb.no_suspend_wait", &usb_no_suspend_wait); 9402f728afSHans Petter Selasky SYSCTL_INT(_hw_usb, OID_AUTO, no_suspend_wait, CTLFLAG_RW|CTLFLAG_TUN, 9502f728afSHans Petter Selasky &usb_no_suspend_wait, 0, "No USB device waiting at system suspend."); 9602f728afSHans Petter Selasky 975ed294aeSHans Petter Selasky static int usb_no_shutdown_wait = 0; 985ed294aeSHans Petter Selasky TUNABLE_INT("hw.usb.no_shutdown_wait", &usb_no_shutdown_wait); 9902f728afSHans Petter Selasky SYSCTL_INT(_hw_usb, OID_AUTO, no_shutdown_wait, CTLFLAG_RW|CTLFLAG_TUN, 10002f728afSHans Petter Selasky &usb_no_shutdown_wait, 0, "No USB device waiting at system shutdown."); 101a0c61406SAlfred Perlstein 102a593f6b8SAndrew Thompson static devclass_t usb_devclass; 10302ac6454SAndrew Thompson 104a593f6b8SAndrew Thompson static device_method_t usb_methods[] = { 105a593f6b8SAndrew Thompson DEVMETHOD(device_probe, usb_probe), 106a593f6b8SAndrew Thompson DEVMETHOD(device_attach, usb_attach), 107a593f6b8SAndrew Thompson DEVMETHOD(device_detach, usb_detach), 1082e141748SHans Petter Selasky DEVMETHOD(device_suspend, usb_suspend), 1092e141748SHans Petter Selasky DEVMETHOD(device_resume, usb_resume), 1102e141748SHans Petter Selasky DEVMETHOD(device_shutdown, usb_shutdown), 11102ac6454SAndrew Thompson {0, 0} 11202ac6454SAndrew Thompson }; 11302ac6454SAndrew Thompson 114a593f6b8SAndrew Thompson static driver_t usb_driver = { 11502ac6454SAndrew Thompson .name = "usbus", 116a593f6b8SAndrew Thompson .methods = usb_methods, 11702ac6454SAndrew Thompson .size = 0, 11802ac6454SAndrew Thompson }; 11902ac6454SAndrew Thompson 120864bc412SHans Petter Selasky /* Host Only Drivers */ 121a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, ohci, usb_driver, usb_devclass, 0, 0); 122a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, uhci, usb_driver, usb_devclass, 0, 0); 123a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, ehci, usb_driver, usb_devclass, 0, 0); 124963169b4SHans Petter Selasky DRIVER_MODULE(usbus, xhci, usb_driver, usb_devclass, 0, 0); 125864bc412SHans Petter Selasky 126864bc412SHans Petter Selasky /* Device Only Drivers */ 127a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, at91_udp, usb_driver, usb_devclass, 0, 0); 128864bc412SHans Petter Selasky DRIVER_MODULE(usbus, musbotg, usb_driver, usb_devclass, 0, 0); 129a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, uss820, usb_driver, usb_devclass, 0, 0); 130d42cc946SOleksandr Tymoshenko DRIVER_MODULE(usbus, octusb, usb_driver, usb_devclass, 0, 0); 13102ac6454SAndrew Thompson 132*268ae63aSHans Petter Selasky /* Dual Mode Drivers */ 133*268ae63aSHans Petter Selasky DRIVER_MODULE(usbus, dwcotg, usb_driver, usb_devclass, 0, 0); 134*268ae63aSHans Petter Selasky 13502ac6454SAndrew Thompson /*------------------------------------------------------------------------* 136a593f6b8SAndrew Thompson * usb_probe 13702ac6454SAndrew Thompson * 13802ac6454SAndrew Thompson * This function is called from "{ehci,ohci,uhci}_pci_attach()". 13902ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 14002ac6454SAndrew Thompson static int 141a593f6b8SAndrew Thompson usb_probe(device_t dev) 14202ac6454SAndrew Thompson { 14302ac6454SAndrew Thompson DPRINTF("\n"); 14402ac6454SAndrew Thompson return (0); 14502ac6454SAndrew Thompson } 14602ac6454SAndrew Thompson 1473df007ceSHans Petter Selasky static void 1483df007ceSHans Petter Selasky usb_root_mount_rel(struct usb_bus *bus) 1493df007ceSHans Petter Selasky { 1503df007ceSHans Petter Selasky if (bus->bus_roothold != NULL) { 1513df007ceSHans Petter Selasky DPRINTF("Releasing root mount hold %p\n", bus->bus_roothold); 1523df007ceSHans Petter Selasky root_mount_rel(bus->bus_roothold); 1533df007ceSHans Petter Selasky bus->bus_roothold = NULL; 1543df007ceSHans Petter Selasky } 1553df007ceSHans Petter Selasky } 1563df007ceSHans Petter Selasky 15702ac6454SAndrew Thompson /*------------------------------------------------------------------------* 158a593f6b8SAndrew Thompson * usb_attach 15902ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 16002ac6454SAndrew Thompson static int 161a593f6b8SAndrew Thompson usb_attach(device_t dev) 16202ac6454SAndrew Thompson { 163760bc48eSAndrew Thompson struct usb_bus *bus = device_get_ivars(dev); 16402ac6454SAndrew Thompson 16502ac6454SAndrew Thompson DPRINTF("\n"); 16602ac6454SAndrew Thompson 16702ac6454SAndrew Thompson if (bus == NULL) { 168767cb2e2SAndrew Thompson device_printf(dev, "USB device has no ivars\n"); 16902ac6454SAndrew Thompson return (ENXIO); 17002ac6454SAndrew Thompson } 17102ac6454SAndrew Thompson 172a0c61406SAlfred Perlstein if (usb_no_boot_wait == 0) { 17302ac6454SAndrew Thompson /* delay vfs_mountroot until the bus is explored */ 174853a10a5SAndrew Thompson bus->bus_roothold = root_mount_hold(device_get_nameunit(dev)); 175a0c61406SAlfred Perlstein } 17602ac6454SAndrew Thompson 177a593f6b8SAndrew Thompson usb_attach_sub(dev, bus); 17834b48722SAlfred Perlstein 17902ac6454SAndrew Thompson return (0); /* return success */ 18002ac6454SAndrew Thompson } 18102ac6454SAndrew Thompson 18202ac6454SAndrew Thompson /*------------------------------------------------------------------------* 183a593f6b8SAndrew Thompson * usb_detach 18402ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 18502ac6454SAndrew Thompson static int 186a593f6b8SAndrew Thompson usb_detach(device_t dev) 18702ac6454SAndrew Thompson { 188760bc48eSAndrew Thompson struct usb_bus *bus = device_get_softc(dev); 18902ac6454SAndrew Thompson 19002ac6454SAndrew Thompson DPRINTF("\n"); 19102ac6454SAndrew Thompson 19202ac6454SAndrew Thompson if (bus == NULL) { 19302ac6454SAndrew Thompson /* was never setup properly */ 19402ac6454SAndrew Thompson return (0); 19502ac6454SAndrew Thompson } 19602ac6454SAndrew Thompson /* Stop power watchdog */ 197a593f6b8SAndrew Thompson usb_callout_drain(&bus->power_wdog); 19802ac6454SAndrew Thompson 19902ac6454SAndrew Thompson /* Let the USB explore process detach all devices. */ 2003df007ceSHans Petter Selasky usb_root_mount_rel(bus); 20102ac6454SAndrew Thompson 20202ac6454SAndrew Thompson USB_BUS_LOCK(bus); 20302ac6454SAndrew Thompson 2042e141748SHans Petter Selasky /* Queue detach job */ 2052e141748SHans Petter Selasky usb_proc_msignal(&bus->explore_proc, 2062e141748SHans Petter Selasky &bus->detach_msg[0], &bus->detach_msg[1]); 2072e141748SHans Petter Selasky 2082e141748SHans Petter Selasky /* Wait for detach to complete */ 209a593f6b8SAndrew Thompson usb_proc_mwait(&bus->explore_proc, 21002ac6454SAndrew Thompson &bus->detach_msg[0], &bus->detach_msg[1]); 21102ac6454SAndrew Thompson 21202ac6454SAndrew Thompson USB_BUS_UNLOCK(bus); 21302ac6454SAndrew Thompson 21402ac6454SAndrew Thompson /* Get rid of USB callback processes */ 21502ac6454SAndrew Thompson 216a593f6b8SAndrew Thompson usb_proc_free(&bus->giant_callback_proc); 217a593f6b8SAndrew Thompson usb_proc_free(&bus->non_giant_callback_proc); 21802ac6454SAndrew Thompson 21902ac6454SAndrew Thompson /* Get rid of USB explore process */ 22002ac6454SAndrew Thompson 221a593f6b8SAndrew Thompson usb_proc_free(&bus->explore_proc); 22202ac6454SAndrew Thompson 223672c9965SAndrew Thompson /* Get rid of control transfer process */ 224672c9965SAndrew Thompson 225a593f6b8SAndrew Thompson usb_proc_free(&bus->control_xfer_proc); 226672c9965SAndrew Thompson 2278be09334SHans Petter Selasky #if USB_HAVE_PF 228fe1c24e3SWeongyo Jeong usbpf_detach(bus); 2298be09334SHans Petter Selasky #endif 23002ac6454SAndrew Thompson return (0); 23102ac6454SAndrew Thompson } 23202ac6454SAndrew Thompson 23302ac6454SAndrew Thompson /*------------------------------------------------------------------------* 2342e141748SHans Petter Selasky * usb_suspend 2352e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 2362e141748SHans Petter Selasky static int 2372e141748SHans Petter Selasky usb_suspend(device_t dev) 2382e141748SHans Petter Selasky { 2392e141748SHans Petter Selasky struct usb_bus *bus = device_get_softc(dev); 2402e141748SHans Petter Selasky 2412e141748SHans Petter Selasky DPRINTF("\n"); 2422e141748SHans Petter Selasky 2432e141748SHans Petter Selasky if (bus == NULL) { 2442e141748SHans Petter Selasky /* was never setup properly */ 2452e141748SHans Petter Selasky return (0); 2462e141748SHans Petter Selasky } 2472e141748SHans Petter Selasky 2482e141748SHans Petter Selasky USB_BUS_LOCK(bus); 2492e141748SHans Petter Selasky usb_proc_msignal(&bus->explore_proc, 2502e141748SHans Petter Selasky &bus->suspend_msg[0], &bus->suspend_msg[1]); 25102f728afSHans Petter Selasky if (usb_no_suspend_wait == 0) { 25202f728afSHans Petter Selasky /* wait for suspend callback to be executed */ 25302f728afSHans Petter Selasky usb_proc_mwait(&bus->explore_proc, 25402f728afSHans Petter Selasky &bus->suspend_msg[0], &bus->suspend_msg[1]); 25502f728afSHans Petter Selasky } 2562e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 2572e141748SHans Petter Selasky 2582e141748SHans Petter Selasky return (0); 2592e141748SHans Petter Selasky } 2602e141748SHans Petter Selasky 2612e141748SHans Petter Selasky /*------------------------------------------------------------------------* 2622e141748SHans Petter Selasky * usb_resume 2632e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 2642e141748SHans Petter Selasky static int 2652e141748SHans Petter Selasky usb_resume(device_t dev) 2662e141748SHans Petter Selasky { 2672e141748SHans Petter Selasky struct usb_bus *bus = device_get_softc(dev); 2682e141748SHans Petter Selasky 2692e141748SHans Petter Selasky DPRINTF("\n"); 2702e141748SHans Petter Selasky 2712e141748SHans Petter Selasky if (bus == NULL) { 2722e141748SHans Petter Selasky /* was never setup properly */ 2732e141748SHans Petter Selasky return (0); 2742e141748SHans Petter Selasky } 2752e141748SHans Petter Selasky 2762e141748SHans Petter Selasky USB_BUS_LOCK(bus); 2772e141748SHans Petter Selasky usb_proc_msignal(&bus->explore_proc, 2782e141748SHans Petter Selasky &bus->resume_msg[0], &bus->resume_msg[1]); 2792e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 2802e141748SHans Petter Selasky 2812e141748SHans Petter Selasky return (0); 2822e141748SHans Petter Selasky } 2832e141748SHans Petter Selasky 2842e141748SHans Petter Selasky /*------------------------------------------------------------------------* 2852e141748SHans Petter Selasky * usb_shutdown 2862e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 2872e141748SHans Petter Selasky static int 2882e141748SHans Petter Selasky usb_shutdown(device_t dev) 2892e141748SHans Petter Selasky { 2902e141748SHans Petter Selasky struct usb_bus *bus = device_get_softc(dev); 2912e141748SHans Petter Selasky 2922e141748SHans Petter Selasky DPRINTF("\n"); 2932e141748SHans Petter Selasky 2942e141748SHans Petter Selasky if (bus == NULL) { 2952e141748SHans Petter Selasky /* was never setup properly */ 2962e141748SHans Petter Selasky return (0); 2972e141748SHans Petter Selasky } 2982e141748SHans Petter Selasky 2995ed294aeSHans Petter Selasky device_printf(bus->bdev, "Controller shutdown\n"); 3005ed294aeSHans Petter Selasky 3012e141748SHans Petter Selasky USB_BUS_LOCK(bus); 3022e141748SHans Petter Selasky usb_proc_msignal(&bus->explore_proc, 3032e141748SHans Petter Selasky &bus->shutdown_msg[0], &bus->shutdown_msg[1]); 3045ed294aeSHans Petter Selasky if (usb_no_shutdown_wait == 0) { 3055ed294aeSHans Petter Selasky /* wait for shutdown callback to be executed */ 3065ed294aeSHans Petter Selasky usb_proc_mwait(&bus->explore_proc, 3075ed294aeSHans Petter Selasky &bus->shutdown_msg[0], &bus->shutdown_msg[1]); 3085ed294aeSHans Petter Selasky } 3092e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 3102e141748SHans Petter Selasky 3115ed294aeSHans Petter Selasky device_printf(bus->bdev, "Controller shutdown complete\n"); 3125ed294aeSHans Petter Selasky 3132e141748SHans Petter Selasky return (0); 3142e141748SHans Petter Selasky } 3152e141748SHans Petter Selasky 3162e141748SHans Petter Selasky /*------------------------------------------------------------------------* 317a593f6b8SAndrew Thompson * usb_bus_explore 31802ac6454SAndrew Thompson * 31902ac6454SAndrew Thompson * This function is used to explore the device tree from the root. 32002ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 32102ac6454SAndrew Thompson static void 322a593f6b8SAndrew Thompson usb_bus_explore(struct usb_proc_msg *pm) 32302ac6454SAndrew Thompson { 324760bc48eSAndrew Thompson struct usb_bus *bus; 325760bc48eSAndrew Thompson struct usb_device *udev; 32602ac6454SAndrew Thompson 327760bc48eSAndrew Thompson bus = ((struct usb_bus_msg *)pm)->bus; 32802ac6454SAndrew Thompson udev = bus->devices[USB_ROOT_HUB_ADDR]; 32902ac6454SAndrew Thompson 3302e141748SHans Petter Selasky if (bus->no_explore != 0) 3312e141748SHans Petter Selasky return; 3322e141748SHans Petter Selasky 33302ac6454SAndrew Thompson if (udev && udev->hub) { 33402ac6454SAndrew Thompson 33502ac6454SAndrew Thompson if (bus->do_probe) { 33602ac6454SAndrew Thompson bus->do_probe = 0; 33702ac6454SAndrew Thompson bus->driver_added_refcount++; 33802ac6454SAndrew Thompson } 33902ac6454SAndrew Thompson if (bus->driver_added_refcount == 0) { 34002ac6454SAndrew Thompson /* avoid zero, hence that is memory default */ 34102ac6454SAndrew Thompson bus->driver_added_refcount = 1; 34202ac6454SAndrew Thompson } 34302ac6454SAndrew Thompson 344f0c078e6SAndrew Thompson #ifdef DDB 34534b48722SAlfred Perlstein /* 34634b48722SAlfred Perlstein * The following three lines of code are only here to 34734b48722SAlfred Perlstein * recover from DDB: 34834b48722SAlfred Perlstein */ 34934b48722SAlfred Perlstein usb_proc_rewakeup(&bus->control_xfer_proc); 35034b48722SAlfred Perlstein usb_proc_rewakeup(&bus->giant_callback_proc); 35134b48722SAlfred Perlstein usb_proc_rewakeup(&bus->non_giant_callback_proc); 352f0c078e6SAndrew Thompson #endif 35334b48722SAlfred Perlstein 35434b48722SAlfred Perlstein USB_BUS_UNLOCK(bus); 355a56fe095SJohn Baldwin 356e727a16cSAndrew Thompson #if USB_HAVE_POWERD 35702ac6454SAndrew Thompson /* 35802ac6454SAndrew Thompson * First update the USB power state! 35902ac6454SAndrew Thompson */ 360a593f6b8SAndrew Thompson usb_bus_powerd(bus); 361e727a16cSAndrew Thompson #endif 36234b48722SAlfred Perlstein /* Explore the Root USB HUB. */ 36302ac6454SAndrew Thompson (udev->hub->explore) (udev); 36402ac6454SAndrew Thompson USB_BUS_LOCK(bus); 36502ac6454SAndrew Thompson } 3663df007ceSHans Petter Selasky usb_root_mount_rel(bus); 36702ac6454SAndrew Thompson } 36802ac6454SAndrew Thompson 36902ac6454SAndrew Thompson /*------------------------------------------------------------------------* 370a593f6b8SAndrew Thompson * usb_bus_detach 37102ac6454SAndrew Thompson * 37202ac6454SAndrew Thompson * This function is used to detach the device tree from the root. 37302ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 37402ac6454SAndrew Thompson static void 375a593f6b8SAndrew Thompson usb_bus_detach(struct usb_proc_msg *pm) 37602ac6454SAndrew Thompson { 377760bc48eSAndrew Thompson struct usb_bus *bus; 378760bc48eSAndrew Thompson struct usb_device *udev; 37902ac6454SAndrew Thompson device_t dev; 38002ac6454SAndrew Thompson 381760bc48eSAndrew Thompson bus = ((struct usb_bus_msg *)pm)->bus; 38202ac6454SAndrew Thompson udev = bus->devices[USB_ROOT_HUB_ADDR]; 38302ac6454SAndrew Thompson dev = bus->bdev; 38402ac6454SAndrew Thompson /* clear the softc */ 38502ac6454SAndrew Thompson device_set_softc(dev, NULL); 38602ac6454SAndrew Thompson USB_BUS_UNLOCK(bus); 38702ac6454SAndrew Thompson 38802ac6454SAndrew Thompson /* detach children first */ 38934b48722SAlfred Perlstein mtx_lock(&Giant); 39002ac6454SAndrew Thompson bus_generic_detach(dev); 39134b48722SAlfred Perlstein mtx_unlock(&Giant); 39202ac6454SAndrew Thompson 39302ac6454SAndrew Thompson /* 394d88688c7SAndrew Thompson * Free USB device and all subdevices, if any. 39502ac6454SAndrew Thompson */ 396d88688c7SAndrew Thompson usb_free_device(udev, 0); 39702ac6454SAndrew Thompson 39802ac6454SAndrew Thompson USB_BUS_LOCK(bus); 39902ac6454SAndrew Thompson /* clear bdev variable last */ 40002ac6454SAndrew Thompson bus->bdev = NULL; 40102ac6454SAndrew Thompson } 40202ac6454SAndrew Thompson 4032e141748SHans Petter Selasky /*------------------------------------------------------------------------* 4042e141748SHans Petter Selasky * usb_bus_suspend 4052e141748SHans Petter Selasky * 4062e141748SHans Petter Selasky * This function is used to suspend the USB contoller. 4072e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 4082e141748SHans Petter Selasky static void 4092e141748SHans Petter Selasky usb_bus_suspend(struct usb_proc_msg *pm) 4102e141748SHans Petter Selasky { 4112e141748SHans Petter Selasky struct usb_bus *bus; 4122e141748SHans Petter Selasky struct usb_device *udev; 4132e141748SHans Petter Selasky usb_error_t err; 4142e141748SHans Petter Selasky 4152e141748SHans Petter Selasky bus = ((struct usb_bus_msg *)pm)->bus; 4162e141748SHans Petter Selasky udev = bus->devices[USB_ROOT_HUB_ADDR]; 4172e141748SHans Petter Selasky 4182e141748SHans Petter Selasky if (udev == NULL || bus->bdev == NULL) 4192e141748SHans Petter Selasky return; 4202e141748SHans Petter Selasky 4216bd3e535SHans Petter Selasky USB_BUS_UNLOCK(bus); 4226bd3e535SHans Petter Selasky 42302f728afSHans Petter Selasky /* 42402f728afSHans Petter Selasky * We use the shutdown event here because the suspend and 42502f728afSHans Petter Selasky * resume events are reserved for the USB port suspend and 42602f728afSHans Petter Selasky * resume. The USB system suspend is implemented like full 42702f728afSHans Petter Selasky * shutdown and all connected USB devices will be disconnected 42802f728afSHans Petter Selasky * subsequently. At resume all USB devices will be 42902f728afSHans Petter Selasky * re-connected again. 43002f728afSHans Petter Selasky */ 43102f728afSHans Petter Selasky 4322e141748SHans Petter Selasky bus_generic_shutdown(bus->bdev); 4332e141748SHans Petter Selasky 4342e141748SHans Petter Selasky usbd_enum_lock(udev); 4352e141748SHans Petter Selasky 4362e141748SHans Petter Selasky err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX); 4372e141748SHans Petter Selasky if (err) 4382e141748SHans Petter Selasky device_printf(bus->bdev, "Could not unconfigure root HUB\n"); 4392e141748SHans Petter Selasky 4402e141748SHans Petter Selasky USB_BUS_LOCK(bus); 4412e141748SHans Petter Selasky bus->hw_power_state = 0; 4422e141748SHans Petter Selasky bus->no_explore = 1; 4432e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 4442e141748SHans Petter Selasky 4452e141748SHans Petter Selasky if (bus->methods->set_hw_power != NULL) 4462e141748SHans Petter Selasky (bus->methods->set_hw_power) (bus); 4472e141748SHans Petter Selasky 4482e141748SHans Petter Selasky if (bus->methods->set_hw_power_sleep != NULL) 4492e141748SHans Petter Selasky (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SUSPEND); 4502e141748SHans Petter Selasky 4512e141748SHans Petter Selasky usbd_enum_unlock(udev); 4526bd3e535SHans Petter Selasky 4536bd3e535SHans Petter Selasky USB_BUS_LOCK(bus); 4542e141748SHans Petter Selasky } 4552e141748SHans Petter Selasky 4562e141748SHans Petter Selasky /*------------------------------------------------------------------------* 4572e141748SHans Petter Selasky * usb_bus_resume 4582e141748SHans Petter Selasky * 4592e141748SHans Petter Selasky * This function is used to resume the USB contoller. 4602e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 4612e141748SHans Petter Selasky static void 4622e141748SHans Petter Selasky usb_bus_resume(struct usb_proc_msg *pm) 4632e141748SHans Petter Selasky { 4642e141748SHans Petter Selasky struct usb_bus *bus; 4652e141748SHans Petter Selasky struct usb_device *udev; 4662e141748SHans Petter Selasky usb_error_t err; 4672e141748SHans Petter Selasky 4682e141748SHans Petter Selasky bus = ((struct usb_bus_msg *)pm)->bus; 4692e141748SHans Petter Selasky udev = bus->devices[USB_ROOT_HUB_ADDR]; 4702e141748SHans Petter Selasky 4712e141748SHans Petter Selasky if (udev == NULL || bus->bdev == NULL) 4722e141748SHans Petter Selasky return; 4732e141748SHans Petter Selasky 4746bd3e535SHans Petter Selasky USB_BUS_UNLOCK(bus); 4756bd3e535SHans Petter Selasky 4762e141748SHans Petter Selasky usbd_enum_lock(udev); 4772e141748SHans Petter Selasky #if 0 4782e141748SHans Petter Selasky DEVMETHOD(usb_take_controller, NULL); /* dummy */ 4792e141748SHans Petter Selasky #endif 4802e141748SHans Petter Selasky USB_TAKE_CONTROLLER(device_get_parent(bus->bdev)); 4812e141748SHans Petter Selasky 4822e141748SHans Petter Selasky USB_BUS_LOCK(bus); 4832e141748SHans Petter Selasky bus->hw_power_state = 4842e141748SHans Petter Selasky USB_HW_POWER_CONTROL | 4852e141748SHans Petter Selasky USB_HW_POWER_BULK | 4862e141748SHans Petter Selasky USB_HW_POWER_INTERRUPT | 4872e141748SHans Petter Selasky USB_HW_POWER_ISOC | 4882e141748SHans Petter Selasky USB_HW_POWER_NON_ROOT_HUB; 4892e141748SHans Petter Selasky bus->no_explore = 0; 4902e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 4912e141748SHans Petter Selasky 4922e141748SHans Petter Selasky if (bus->methods->set_hw_power_sleep != NULL) 4932e141748SHans Petter Selasky (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_RESUME); 4942e141748SHans Petter Selasky 4952e141748SHans Petter Selasky if (bus->methods->set_hw_power != NULL) 4962e141748SHans Petter Selasky (bus->methods->set_hw_power) (bus); 4972e141748SHans Petter Selasky 4986bbe7cdfSHans Petter Selasky /* restore USB configuration to index 0 */ 4992e141748SHans Petter Selasky err = usbd_set_config_index(udev, 0); 5002e141748SHans Petter Selasky if (err) 5012e141748SHans Petter Selasky device_printf(bus->bdev, "Could not configure root HUB\n"); 5022e141748SHans Petter Selasky 5036bbe7cdfSHans Petter Selasky /* probe and attach */ 5046bbe7cdfSHans Petter Selasky err = usb_probe_and_attach(udev, USB_IFACE_INDEX_ANY); 5056bbe7cdfSHans Petter Selasky if (err) { 5066bbe7cdfSHans Petter Selasky device_printf(bus->bdev, "Could not probe and " 5076bbe7cdfSHans Petter Selasky "attach root HUB\n"); 5086bbe7cdfSHans Petter Selasky } 5096bbe7cdfSHans Petter Selasky 5102e141748SHans Petter Selasky usbd_enum_unlock(udev); 5116bd3e535SHans Petter Selasky 5126bd3e535SHans Petter Selasky USB_BUS_LOCK(bus); 5132e141748SHans Petter Selasky } 5142e141748SHans Petter Selasky 5152e141748SHans Petter Selasky /*------------------------------------------------------------------------* 5162e141748SHans Petter Selasky * usb_bus_shutdown 5172e141748SHans Petter Selasky * 5182e141748SHans Petter Selasky * This function is used to shutdown the USB contoller. 5192e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 5202e141748SHans Petter Selasky static void 5212e141748SHans Petter Selasky usb_bus_shutdown(struct usb_proc_msg *pm) 5222e141748SHans Petter Selasky { 5232e141748SHans Petter Selasky struct usb_bus *bus; 5242e141748SHans Petter Selasky struct usb_device *udev; 5252e141748SHans Petter Selasky usb_error_t err; 5262e141748SHans Petter Selasky 5272e141748SHans Petter Selasky bus = ((struct usb_bus_msg *)pm)->bus; 5282e141748SHans Petter Selasky udev = bus->devices[USB_ROOT_HUB_ADDR]; 5292e141748SHans Petter Selasky 5302e141748SHans Petter Selasky if (udev == NULL || bus->bdev == NULL) 5312e141748SHans Petter Selasky return; 5322e141748SHans Petter Selasky 5336bd3e535SHans Petter Selasky USB_BUS_UNLOCK(bus); 5346bd3e535SHans Petter Selasky 5352e141748SHans Petter Selasky bus_generic_shutdown(bus->bdev); 5362e141748SHans Petter Selasky 5372e141748SHans Petter Selasky usbd_enum_lock(udev); 5382e141748SHans Petter Selasky 5392e141748SHans Petter Selasky err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX); 5402e141748SHans Petter Selasky if (err) 5412e141748SHans Petter Selasky device_printf(bus->bdev, "Could not unconfigure root HUB\n"); 5422e141748SHans Petter Selasky 5432e141748SHans Petter Selasky USB_BUS_LOCK(bus); 5442e141748SHans Petter Selasky bus->hw_power_state = 0; 5452e141748SHans Petter Selasky bus->no_explore = 1; 5462e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 5472e141748SHans Petter Selasky 5482e141748SHans Petter Selasky if (bus->methods->set_hw_power != NULL) 5492e141748SHans Petter Selasky (bus->methods->set_hw_power) (bus); 5502e141748SHans Petter Selasky 5512e141748SHans Petter Selasky if (bus->methods->set_hw_power_sleep != NULL) 5522e141748SHans Petter Selasky (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SHUTDOWN); 5532e141748SHans Petter Selasky 5542e141748SHans Petter Selasky usbd_enum_unlock(udev); 5556bd3e535SHans Petter Selasky 5566bd3e535SHans Petter Selasky USB_BUS_LOCK(bus); 5572e141748SHans Petter Selasky } 5582e141748SHans Petter Selasky 55902ac6454SAndrew Thompson static void 560a593f6b8SAndrew Thompson usb_power_wdog(void *arg) 56102ac6454SAndrew Thompson { 562760bc48eSAndrew Thompson struct usb_bus *bus = arg; 56302ac6454SAndrew Thompson 56402ac6454SAndrew Thompson USB_BUS_LOCK_ASSERT(bus, MA_OWNED); 56502ac6454SAndrew Thompson 566a593f6b8SAndrew Thompson usb_callout_reset(&bus->power_wdog, 567a593f6b8SAndrew Thompson 4 * hz, usb_power_wdog, arg); 56802ac6454SAndrew Thompson 569f0c078e6SAndrew Thompson #ifdef DDB 57034b48722SAlfred Perlstein /* 57134b48722SAlfred Perlstein * The following line of code is only here to recover from 57234b48722SAlfred Perlstein * DDB: 57334b48722SAlfred Perlstein */ 57434b48722SAlfred Perlstein usb_proc_rewakeup(&bus->explore_proc); /* recover from DDB */ 575f0c078e6SAndrew Thompson #endif 57634b48722SAlfred Perlstein 577e727a16cSAndrew Thompson #if USB_HAVE_POWERD 57802ac6454SAndrew Thompson USB_BUS_UNLOCK(bus); 57902ac6454SAndrew Thompson 580a593f6b8SAndrew Thompson usb_bus_power_update(bus); 58102ac6454SAndrew Thompson 582684e3f22SAndrew Thompson USB_BUS_LOCK(bus); 583e727a16cSAndrew Thompson #endif 58402ac6454SAndrew Thompson } 58502ac6454SAndrew Thompson 58602ac6454SAndrew Thompson /*------------------------------------------------------------------------* 587a593f6b8SAndrew Thompson * usb_bus_attach 58802ac6454SAndrew Thompson * 58902ac6454SAndrew Thompson * This function attaches USB in context of the explore thread. 59002ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 59102ac6454SAndrew Thompson static void 592a593f6b8SAndrew Thompson usb_bus_attach(struct usb_proc_msg *pm) 59302ac6454SAndrew Thompson { 594760bc48eSAndrew Thompson struct usb_bus *bus; 595760bc48eSAndrew Thompson struct usb_device *child; 59602ac6454SAndrew Thompson device_t dev; 597e0a69b51SAndrew Thompson usb_error_t err; 5988d2dd5ddSAndrew Thompson enum usb_dev_speed speed; 59902ac6454SAndrew Thompson 600760bc48eSAndrew Thompson bus = ((struct usb_bus_msg *)pm)->bus; 60102ac6454SAndrew Thompson dev = bus->bdev; 60202ac6454SAndrew Thompson 60302ac6454SAndrew Thompson DPRINTF("\n"); 60402ac6454SAndrew Thompson 60502ac6454SAndrew Thompson switch (bus->usbrev) { 60602ac6454SAndrew Thompson case USB_REV_1_0: 60702ac6454SAndrew Thompson speed = USB_SPEED_FULL; 60802ac6454SAndrew Thompson device_printf(bus->bdev, "12Mbps Full Speed USB v1.0\n"); 60902ac6454SAndrew Thompson break; 61002ac6454SAndrew Thompson 61102ac6454SAndrew Thompson case USB_REV_1_1: 61202ac6454SAndrew Thompson speed = USB_SPEED_FULL; 61302ac6454SAndrew Thompson device_printf(bus->bdev, "12Mbps Full Speed USB v1.1\n"); 61402ac6454SAndrew Thompson break; 61502ac6454SAndrew Thompson 61602ac6454SAndrew Thompson case USB_REV_2_0: 61702ac6454SAndrew Thompson speed = USB_SPEED_HIGH; 61802ac6454SAndrew Thompson device_printf(bus->bdev, "480Mbps High Speed USB v2.0\n"); 61902ac6454SAndrew Thompson break; 62002ac6454SAndrew Thompson 62102ac6454SAndrew Thompson case USB_REV_2_5: 62202ac6454SAndrew Thompson speed = USB_SPEED_VARIABLE; 62302ac6454SAndrew Thompson device_printf(bus->bdev, "480Mbps Wireless USB v2.5\n"); 62402ac6454SAndrew Thompson break; 62502ac6454SAndrew Thompson 626963169b4SHans Petter Selasky case USB_REV_3_0: 627963169b4SHans Petter Selasky speed = USB_SPEED_SUPER; 628ccac019aSHans Petter Selasky device_printf(bus->bdev, "5.0Gbps Super Speed USB v3.0\n"); 629963169b4SHans Petter Selasky break; 630963169b4SHans Petter Selasky 63102ac6454SAndrew Thompson default: 632767cb2e2SAndrew Thompson device_printf(bus->bdev, "Unsupported USB revision\n"); 6333df007ceSHans Petter Selasky usb_root_mount_rel(bus); 63402ac6454SAndrew Thompson return; 63502ac6454SAndrew Thompson } 63602ac6454SAndrew Thompson 6374eae601eSAndrew Thompson /* default power_mask value */ 6384eae601eSAndrew Thompson bus->hw_power_state = 6394eae601eSAndrew Thompson USB_HW_POWER_CONTROL | 6404eae601eSAndrew Thompson USB_HW_POWER_BULK | 6414eae601eSAndrew Thompson USB_HW_POWER_INTERRUPT | 6424eae601eSAndrew Thompson USB_HW_POWER_ISOC | 6434eae601eSAndrew Thompson USB_HW_POWER_NON_ROOT_HUB; 6444eae601eSAndrew Thompson 6452e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 6462e141748SHans Petter Selasky 6474eae601eSAndrew Thompson /* make sure power is set at least once */ 6484eae601eSAndrew Thompson 6494eae601eSAndrew Thompson if (bus->methods->set_hw_power != NULL) { 6504eae601eSAndrew Thompson (bus->methods->set_hw_power) (bus); 6514eae601eSAndrew Thompson } 6524eae601eSAndrew Thompson 6532e141748SHans Petter Selasky /* allocate the Root USB device */ 65402ac6454SAndrew Thompson 655a593f6b8SAndrew Thompson child = usb_alloc_device(bus->bdev, bus, NULL, 0, 0, 1, 65602ac6454SAndrew Thompson speed, USB_MODE_HOST); 65702ac6454SAndrew Thompson if (child) { 658a593f6b8SAndrew Thompson err = usb_probe_and_attach(child, 65902ac6454SAndrew Thompson USB_IFACE_INDEX_ANY); 66002ac6454SAndrew Thompson if (!err) { 6611be5bf51SAndrew Thompson if ((bus->devices[USB_ROOT_HUB_ADDR] == NULL) || 6621be5bf51SAndrew Thompson (bus->devices[USB_ROOT_HUB_ADDR]->hub == NULL)) { 66302ac6454SAndrew Thompson err = USB_ERR_NO_ROOT_HUB; 66402ac6454SAndrew Thompson } 66502ac6454SAndrew Thompson } 66602ac6454SAndrew Thompson } else { 66702ac6454SAndrew Thompson err = USB_ERR_NOMEM; 66802ac6454SAndrew Thompson } 66902ac6454SAndrew Thompson 67002ac6454SAndrew Thompson USB_BUS_LOCK(bus); 67102ac6454SAndrew Thompson 67202ac6454SAndrew Thompson if (err) { 67302ac6454SAndrew Thompson device_printf(bus->bdev, "Root HUB problem, error=%s\n", 674a593f6b8SAndrew Thompson usbd_errstr(err)); 6753df007ceSHans Petter Selasky usb_root_mount_rel(bus); 67602ac6454SAndrew Thompson } 67702ac6454SAndrew Thompson 67802ac6454SAndrew Thompson /* set softc - we are ready */ 67902ac6454SAndrew Thompson device_set_softc(dev, bus); 68002ac6454SAndrew Thompson 681684e3f22SAndrew Thompson /* start watchdog */ 682a593f6b8SAndrew Thompson usb_power_wdog(bus); 68302ac6454SAndrew Thompson } 68402ac6454SAndrew Thompson 68502ac6454SAndrew Thompson /*------------------------------------------------------------------------* 686a593f6b8SAndrew Thompson * usb_attach_sub 68702ac6454SAndrew Thompson * 68834b48722SAlfred Perlstein * This function creates a thread which runs the USB attach code. 68902ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 69002ac6454SAndrew Thompson static void 691a593f6b8SAndrew Thompson usb_attach_sub(device_t dev, struct usb_bus *bus) 69202ac6454SAndrew Thompson { 69302ac6454SAndrew Thompson const char *pname = device_get_nameunit(dev); 69402ac6454SAndrew Thompson 69534b48722SAlfred Perlstein mtx_lock(&Giant); 69634b48722SAlfred Perlstein if (usb_devclass_ptr == NULL) 69734b48722SAlfred Perlstein usb_devclass_ptr = devclass_find("usbus"); 69834b48722SAlfred Perlstein mtx_unlock(&Giant); 69934b48722SAlfred Perlstein 7008be09334SHans Petter Selasky #if USB_HAVE_PF 701fe1c24e3SWeongyo Jeong usbpf_attach(bus); 7028be09334SHans Petter Selasky #endif 70302ac6454SAndrew Thompson /* Initialise USB process messages */ 704a593f6b8SAndrew Thompson bus->explore_msg[0].hdr.pm_callback = &usb_bus_explore; 70502ac6454SAndrew Thompson bus->explore_msg[0].bus = bus; 706a593f6b8SAndrew Thompson bus->explore_msg[1].hdr.pm_callback = &usb_bus_explore; 70702ac6454SAndrew Thompson bus->explore_msg[1].bus = bus; 70802ac6454SAndrew Thompson 709a593f6b8SAndrew Thompson bus->detach_msg[0].hdr.pm_callback = &usb_bus_detach; 71002ac6454SAndrew Thompson bus->detach_msg[0].bus = bus; 711a593f6b8SAndrew Thompson bus->detach_msg[1].hdr.pm_callback = &usb_bus_detach; 71202ac6454SAndrew Thompson bus->detach_msg[1].bus = bus; 71302ac6454SAndrew Thompson 714a593f6b8SAndrew Thompson bus->attach_msg[0].hdr.pm_callback = &usb_bus_attach; 71502ac6454SAndrew Thompson bus->attach_msg[0].bus = bus; 716a593f6b8SAndrew Thompson bus->attach_msg[1].hdr.pm_callback = &usb_bus_attach; 71702ac6454SAndrew Thompson bus->attach_msg[1].bus = bus; 71802ac6454SAndrew Thompson 7192e141748SHans Petter Selasky bus->suspend_msg[0].hdr.pm_callback = &usb_bus_suspend; 7202e141748SHans Petter Selasky bus->suspend_msg[0].bus = bus; 7212e141748SHans Petter Selasky bus->suspend_msg[1].hdr.pm_callback = &usb_bus_suspend; 7222e141748SHans Petter Selasky bus->suspend_msg[1].bus = bus; 7232e141748SHans Petter Selasky 7242e141748SHans Petter Selasky bus->resume_msg[0].hdr.pm_callback = &usb_bus_resume; 7252e141748SHans Petter Selasky bus->resume_msg[0].bus = bus; 7262e141748SHans Petter Selasky bus->resume_msg[1].hdr.pm_callback = &usb_bus_resume; 7272e141748SHans Petter Selasky bus->resume_msg[1].bus = bus; 7282e141748SHans Petter Selasky 7292e141748SHans Petter Selasky bus->shutdown_msg[0].hdr.pm_callback = &usb_bus_shutdown; 7302e141748SHans Petter Selasky bus->shutdown_msg[0].bus = bus; 7312e141748SHans Petter Selasky bus->shutdown_msg[1].hdr.pm_callback = &usb_bus_shutdown; 7322e141748SHans Petter Selasky bus->shutdown_msg[1].bus = bus; 7332e141748SHans Petter Selasky 73439307315SAndrew Thompson /* Create USB explore and callback processes */ 73502ac6454SAndrew Thompson 736a593f6b8SAndrew Thompson if (usb_proc_create(&bus->giant_callback_proc, 73702ac6454SAndrew Thompson &bus->bus_mtx, pname, USB_PRI_MED)) { 73888334428SHans Petter Selasky device_printf(dev, "WARNING: Creation of USB Giant " 73902ac6454SAndrew Thompson "callback process failed.\n"); 740a593f6b8SAndrew Thompson } else if (usb_proc_create(&bus->non_giant_callback_proc, 74102ac6454SAndrew Thompson &bus->bus_mtx, pname, USB_PRI_HIGH)) { 74288334428SHans Petter Selasky device_printf(dev, "WARNING: Creation of USB non-Giant " 74302ac6454SAndrew Thompson "callback process failed.\n"); 744a593f6b8SAndrew Thompson } else if (usb_proc_create(&bus->explore_proc, 74502ac6454SAndrew Thompson &bus->bus_mtx, pname, USB_PRI_MED)) { 74688334428SHans Petter Selasky device_printf(dev, "WARNING: Creation of USB explore " 74702ac6454SAndrew Thompson "process failed.\n"); 748a593f6b8SAndrew Thompson } else if (usb_proc_create(&bus->control_xfer_proc, 749672c9965SAndrew Thompson &bus->bus_mtx, pname, USB_PRI_MED)) { 75088334428SHans Petter Selasky device_printf(dev, "WARNING: Creation of USB control transfer " 751672c9965SAndrew Thompson "process failed.\n"); 75202ac6454SAndrew Thompson } else { 75302ac6454SAndrew Thompson /* Get final attach going */ 75402ac6454SAndrew Thompson USB_BUS_LOCK(bus); 7552e141748SHans Petter Selasky usb_proc_msignal(&bus->explore_proc, 7562e141748SHans Petter Selasky &bus->attach_msg[0], &bus->attach_msg[1]); 75702ac6454SAndrew Thompson USB_BUS_UNLOCK(bus); 75834b48722SAlfred Perlstein 75934b48722SAlfred Perlstein /* Do initial explore */ 76034b48722SAlfred Perlstein usb_needs_explore(bus, 1); 76102ac6454SAndrew Thompson } 76202ac6454SAndrew Thompson } 76302ac6454SAndrew Thompson 764a593f6b8SAndrew Thompson SYSUNINIT(usb_bus_unload, SI_SUB_KLD, SI_ORDER_ANY, usb_bus_unload, NULL); 76502ac6454SAndrew Thompson 76602ac6454SAndrew Thompson /*------------------------------------------------------------------------* 767a593f6b8SAndrew Thompson * usb_bus_mem_flush_all_cb 76802ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 769bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 77002ac6454SAndrew Thompson static void 771a593f6b8SAndrew Thompson usb_bus_mem_flush_all_cb(struct usb_bus *bus, struct usb_page_cache *pc, 772f9cb546cSAndrew Thompson struct usb_page *pg, usb_size_t size, usb_size_t align) 77302ac6454SAndrew Thompson { 774a593f6b8SAndrew Thompson usb_pc_cpu_flush(pc); 77502ac6454SAndrew Thompson } 776bdc081c6SAndrew Thompson #endif 77702ac6454SAndrew Thompson 77802ac6454SAndrew Thompson /*------------------------------------------------------------------------* 779a593f6b8SAndrew Thompson * usb_bus_mem_flush_all - factored out code 78002ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 781bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 78202ac6454SAndrew Thompson void 783a593f6b8SAndrew Thompson usb_bus_mem_flush_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb) 78402ac6454SAndrew Thompson { 78502ac6454SAndrew Thompson if (cb) { 786a593f6b8SAndrew Thompson cb(bus, &usb_bus_mem_flush_all_cb); 78702ac6454SAndrew Thompson } 78802ac6454SAndrew Thompson } 789bdc081c6SAndrew Thompson #endif 79002ac6454SAndrew Thompson 79102ac6454SAndrew Thompson /*------------------------------------------------------------------------* 792a593f6b8SAndrew Thompson * usb_bus_mem_alloc_all_cb 79302ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 794bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 79502ac6454SAndrew Thompson static void 796a593f6b8SAndrew Thompson usb_bus_mem_alloc_all_cb(struct usb_bus *bus, struct usb_page_cache *pc, 797f9cb546cSAndrew Thompson struct usb_page *pg, usb_size_t size, usb_size_t align) 79802ac6454SAndrew Thompson { 79902ac6454SAndrew Thompson /* need to initialize the page cache */ 80002ac6454SAndrew Thompson pc->tag_parent = bus->dma_parent_tag; 80102ac6454SAndrew Thompson 802a593f6b8SAndrew Thompson if (usb_pc_alloc_mem(pc, pg, size, align)) { 80302ac6454SAndrew Thompson bus->alloc_failed = 1; 80402ac6454SAndrew Thompson } 80502ac6454SAndrew Thompson } 806bdc081c6SAndrew Thompson #endif 80702ac6454SAndrew Thompson 80802ac6454SAndrew Thompson /*------------------------------------------------------------------------* 809a593f6b8SAndrew Thompson * usb_bus_mem_alloc_all - factored out code 81002ac6454SAndrew Thompson * 81102ac6454SAndrew Thompson * Returns: 81202ac6454SAndrew Thompson * 0: Success 81302ac6454SAndrew Thompson * Else: Failure 81402ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 81502ac6454SAndrew Thompson uint8_t 816a593f6b8SAndrew Thompson usb_bus_mem_alloc_all(struct usb_bus *bus, bus_dma_tag_t dmat, 817e0a69b51SAndrew Thompson usb_bus_mem_cb_t *cb) 81802ac6454SAndrew Thompson { 81902ac6454SAndrew Thompson bus->alloc_failed = 0; 82002ac6454SAndrew Thompson 82102ac6454SAndrew Thompson mtx_init(&bus->bus_mtx, device_get_nameunit(bus->parent), 82202ac6454SAndrew Thompson NULL, MTX_DEF | MTX_RECURSE); 82302ac6454SAndrew Thompson 824a593f6b8SAndrew Thompson usb_callout_init_mtx(&bus->power_wdog, 825684e3f22SAndrew Thompson &bus->bus_mtx, 0); 82602ac6454SAndrew Thompson 82702ac6454SAndrew Thompson TAILQ_INIT(&bus->intr_q.head); 82802ac6454SAndrew Thompson 829bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 830a593f6b8SAndrew Thompson usb_dma_tag_setup(bus->dma_parent_tag, bus->dma_tags, 831bdc081c6SAndrew Thompson dmat, &bus->bus_mtx, NULL, 32, USB_BUS_DMA_TAG_MAX); 832bdc081c6SAndrew Thompson #endif 83302ac6454SAndrew Thompson if ((bus->devices_max > USB_MAX_DEVICES) || 83402ac6454SAndrew Thompson (bus->devices_max < USB_MIN_DEVICES) || 83502ac6454SAndrew Thompson (bus->devices == NULL)) { 83602ac6454SAndrew Thompson DPRINTFN(0, "Devices field has not been " 837767cb2e2SAndrew Thompson "initialised properly\n"); 83802ac6454SAndrew Thompson bus->alloc_failed = 1; /* failure */ 83902ac6454SAndrew Thompson } 840bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 84102ac6454SAndrew Thompson if (cb) { 842a593f6b8SAndrew Thompson cb(bus, &usb_bus_mem_alloc_all_cb); 84302ac6454SAndrew Thompson } 844bdc081c6SAndrew Thompson #endif 84502ac6454SAndrew Thompson if (bus->alloc_failed) { 846a593f6b8SAndrew Thompson usb_bus_mem_free_all(bus, cb); 84702ac6454SAndrew Thompson } 84802ac6454SAndrew Thompson return (bus->alloc_failed); 84902ac6454SAndrew Thompson } 85002ac6454SAndrew Thompson 85102ac6454SAndrew Thompson /*------------------------------------------------------------------------* 852a593f6b8SAndrew Thompson * usb_bus_mem_free_all_cb 85302ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 854bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 85502ac6454SAndrew Thompson static void 856a593f6b8SAndrew Thompson usb_bus_mem_free_all_cb(struct usb_bus *bus, struct usb_page_cache *pc, 857f9cb546cSAndrew Thompson struct usb_page *pg, usb_size_t size, usb_size_t align) 85802ac6454SAndrew Thompson { 859a593f6b8SAndrew Thompson usb_pc_free_mem(pc); 86002ac6454SAndrew Thompson } 861bdc081c6SAndrew Thompson #endif 86202ac6454SAndrew Thompson 86302ac6454SAndrew Thompson /*------------------------------------------------------------------------* 864a593f6b8SAndrew Thompson * usb_bus_mem_free_all - factored out code 86502ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 86602ac6454SAndrew Thompson void 867a593f6b8SAndrew Thompson usb_bus_mem_free_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb) 86802ac6454SAndrew Thompson { 869bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 87002ac6454SAndrew Thompson if (cb) { 871a593f6b8SAndrew Thompson cb(bus, &usb_bus_mem_free_all_cb); 87202ac6454SAndrew Thompson } 873a593f6b8SAndrew Thompson usb_dma_tag_unsetup(bus->dma_parent_tag); 874bdc081c6SAndrew Thompson #endif 87502ac6454SAndrew Thompson 87602ac6454SAndrew Thompson mtx_destroy(&bus->bus_mtx); 87702ac6454SAndrew Thompson } 878