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, 90a0c61406SAlfred Perlstein "No device enumerate waiting at boot."); 91a0c61406SAlfred Perlstein 92a593f6b8SAndrew Thompson static devclass_t usb_devclass; 9302ac6454SAndrew Thompson 94a593f6b8SAndrew Thompson static device_method_t usb_methods[] = { 95a593f6b8SAndrew Thompson DEVMETHOD(device_probe, usb_probe), 96a593f6b8SAndrew Thompson DEVMETHOD(device_attach, usb_attach), 97a593f6b8SAndrew Thompson DEVMETHOD(device_detach, usb_detach), 982e141748SHans Petter Selasky DEVMETHOD(device_suspend, usb_suspend), 992e141748SHans Petter Selasky DEVMETHOD(device_resume, usb_resume), 1002e141748SHans Petter Selasky DEVMETHOD(device_shutdown, usb_shutdown), 10102ac6454SAndrew Thompson {0, 0} 10202ac6454SAndrew Thompson }; 10302ac6454SAndrew Thompson 104a593f6b8SAndrew Thompson static driver_t usb_driver = { 10502ac6454SAndrew Thompson .name = "usbus", 106a593f6b8SAndrew Thompson .methods = usb_methods, 10702ac6454SAndrew Thompson .size = 0, 10802ac6454SAndrew Thompson }; 10902ac6454SAndrew Thompson 110864bc412SHans Petter Selasky /* Host Only Drivers */ 111a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, ohci, usb_driver, usb_devclass, 0, 0); 112a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, uhci, usb_driver, usb_devclass, 0, 0); 113a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, ehci, usb_driver, usb_devclass, 0, 0); 114963169b4SHans Petter Selasky DRIVER_MODULE(usbus, xhci, usb_driver, usb_devclass, 0, 0); 115864bc412SHans Petter Selasky 116864bc412SHans Petter Selasky /* Device Only Drivers */ 117a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, at91_udp, usb_driver, usb_devclass, 0, 0); 118864bc412SHans Petter Selasky DRIVER_MODULE(usbus, musbotg, usb_driver, usb_devclass, 0, 0); 119a593f6b8SAndrew Thompson DRIVER_MODULE(usbus, uss820, usb_driver, usb_devclass, 0, 0); 12002ac6454SAndrew Thompson 12102ac6454SAndrew Thompson /*------------------------------------------------------------------------* 122a593f6b8SAndrew Thompson * usb_probe 12302ac6454SAndrew Thompson * 12402ac6454SAndrew Thompson * This function is called from "{ehci,ohci,uhci}_pci_attach()". 12502ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 12602ac6454SAndrew Thompson static int 127a593f6b8SAndrew Thompson usb_probe(device_t dev) 12802ac6454SAndrew Thompson { 12902ac6454SAndrew Thompson DPRINTF("\n"); 13002ac6454SAndrew Thompson return (0); 13102ac6454SAndrew Thompson } 13202ac6454SAndrew Thompson 1333df007ceSHans Petter Selasky static void 1343df007ceSHans Petter Selasky usb_root_mount_rel(struct usb_bus *bus) 1353df007ceSHans Petter Selasky { 1363df007ceSHans Petter Selasky if (bus->bus_roothold != NULL) { 1373df007ceSHans Petter Selasky DPRINTF("Releasing root mount hold %p\n", bus->bus_roothold); 1383df007ceSHans Petter Selasky root_mount_rel(bus->bus_roothold); 1393df007ceSHans Petter Selasky bus->bus_roothold = NULL; 1403df007ceSHans Petter Selasky } 1413df007ceSHans Petter Selasky } 1423df007ceSHans Petter Selasky 14302ac6454SAndrew Thompson /*------------------------------------------------------------------------* 144a593f6b8SAndrew Thompson * usb_attach 14502ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 14602ac6454SAndrew Thompson static int 147a593f6b8SAndrew Thompson usb_attach(device_t dev) 14802ac6454SAndrew Thompson { 149760bc48eSAndrew Thompson struct usb_bus *bus = device_get_ivars(dev); 15002ac6454SAndrew Thompson 15102ac6454SAndrew Thompson DPRINTF("\n"); 15202ac6454SAndrew Thompson 15302ac6454SAndrew Thompson if (bus == NULL) { 154767cb2e2SAndrew Thompson device_printf(dev, "USB device has no ivars\n"); 15502ac6454SAndrew Thompson return (ENXIO); 15602ac6454SAndrew Thompson } 15702ac6454SAndrew Thompson 158a0c61406SAlfred Perlstein if (usb_no_boot_wait == 0) { 15902ac6454SAndrew Thompson /* delay vfs_mountroot until the bus is explored */ 160853a10a5SAndrew Thompson bus->bus_roothold = root_mount_hold(device_get_nameunit(dev)); 161a0c61406SAlfred Perlstein } 16202ac6454SAndrew Thompson 163a593f6b8SAndrew Thompson usb_attach_sub(dev, bus); 16434b48722SAlfred Perlstein 16502ac6454SAndrew Thompson return (0); /* return success */ 16602ac6454SAndrew Thompson } 16702ac6454SAndrew Thompson 16802ac6454SAndrew Thompson /*------------------------------------------------------------------------* 169a593f6b8SAndrew Thompson * usb_detach 17002ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 17102ac6454SAndrew Thompson static int 172a593f6b8SAndrew Thompson usb_detach(device_t dev) 17302ac6454SAndrew Thompson { 174760bc48eSAndrew Thompson struct usb_bus *bus = device_get_softc(dev); 17502ac6454SAndrew Thompson 17602ac6454SAndrew Thompson DPRINTF("\n"); 17702ac6454SAndrew Thompson 17802ac6454SAndrew Thompson if (bus == NULL) { 17902ac6454SAndrew Thompson /* was never setup properly */ 18002ac6454SAndrew Thompson return (0); 18102ac6454SAndrew Thompson } 18202ac6454SAndrew Thompson /* Stop power watchdog */ 183a593f6b8SAndrew Thompson usb_callout_drain(&bus->power_wdog); 18402ac6454SAndrew Thompson 18502ac6454SAndrew Thompson /* Let the USB explore process detach all devices. */ 1863df007ceSHans Petter Selasky usb_root_mount_rel(bus); 18702ac6454SAndrew Thompson 18802ac6454SAndrew Thompson USB_BUS_LOCK(bus); 18902ac6454SAndrew Thompson 1902e141748SHans Petter Selasky /* Queue detach job */ 1912e141748SHans Petter Selasky usb_proc_msignal(&bus->explore_proc, 1922e141748SHans Petter Selasky &bus->detach_msg[0], &bus->detach_msg[1]); 1932e141748SHans Petter Selasky 1942e141748SHans Petter Selasky /* Wait for detach to complete */ 195a593f6b8SAndrew Thompson usb_proc_mwait(&bus->explore_proc, 19602ac6454SAndrew Thompson &bus->detach_msg[0], &bus->detach_msg[1]); 19702ac6454SAndrew Thompson 19802ac6454SAndrew Thompson USB_BUS_UNLOCK(bus); 19902ac6454SAndrew Thompson 20002ac6454SAndrew Thompson /* Get rid of USB callback processes */ 20102ac6454SAndrew Thompson 202a593f6b8SAndrew Thompson usb_proc_free(&bus->giant_callback_proc); 203a593f6b8SAndrew Thompson usb_proc_free(&bus->non_giant_callback_proc); 20402ac6454SAndrew Thompson 20502ac6454SAndrew Thompson /* Get rid of USB explore process */ 20602ac6454SAndrew Thompson 207a593f6b8SAndrew Thompson usb_proc_free(&bus->explore_proc); 20802ac6454SAndrew Thompson 209672c9965SAndrew Thompson /* Get rid of control transfer process */ 210672c9965SAndrew Thompson 211a593f6b8SAndrew Thompson usb_proc_free(&bus->control_xfer_proc); 212672c9965SAndrew Thompson 2138be09334SHans Petter Selasky #if USB_HAVE_PF 214fe1c24e3SWeongyo Jeong usbpf_detach(bus); 2158be09334SHans Petter Selasky #endif 21602ac6454SAndrew Thompson return (0); 21702ac6454SAndrew Thompson } 21802ac6454SAndrew Thompson 21902ac6454SAndrew Thompson /*------------------------------------------------------------------------* 2202e141748SHans Petter Selasky * usb_suspend 2212e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 2222e141748SHans Petter Selasky static int 2232e141748SHans Petter Selasky usb_suspend(device_t dev) 2242e141748SHans Petter Selasky { 2252e141748SHans Petter Selasky struct usb_bus *bus = device_get_softc(dev); 2262e141748SHans Petter Selasky 2272e141748SHans Petter Selasky DPRINTF("\n"); 2282e141748SHans Petter Selasky 2292e141748SHans Petter Selasky if (bus == NULL) { 2302e141748SHans Petter Selasky /* was never setup properly */ 2312e141748SHans Petter Selasky return (0); 2322e141748SHans Petter Selasky } 2332e141748SHans Petter Selasky 2342e141748SHans Petter Selasky USB_BUS_LOCK(bus); 2352e141748SHans Petter Selasky usb_proc_msignal(&bus->explore_proc, 2362e141748SHans Petter Selasky &bus->suspend_msg[0], &bus->suspend_msg[1]); 2372e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 2382e141748SHans Petter Selasky 2392e141748SHans Petter Selasky return (0); 2402e141748SHans Petter Selasky } 2412e141748SHans Petter Selasky 2422e141748SHans Petter Selasky /*------------------------------------------------------------------------* 2432e141748SHans Petter Selasky * usb_resume 2442e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 2452e141748SHans Petter Selasky static int 2462e141748SHans Petter Selasky usb_resume(device_t dev) 2472e141748SHans Petter Selasky { 2482e141748SHans Petter Selasky struct usb_bus *bus = device_get_softc(dev); 2492e141748SHans Petter Selasky 2502e141748SHans Petter Selasky DPRINTF("\n"); 2512e141748SHans Petter Selasky 2522e141748SHans Petter Selasky if (bus == NULL) { 2532e141748SHans Petter Selasky /* was never setup properly */ 2542e141748SHans Petter Selasky return (0); 2552e141748SHans Petter Selasky } 2562e141748SHans Petter Selasky 2572e141748SHans Petter Selasky USB_BUS_LOCK(bus); 2582e141748SHans Petter Selasky usb_proc_msignal(&bus->explore_proc, 2592e141748SHans Petter Selasky &bus->resume_msg[0], &bus->resume_msg[1]); 2602e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 2612e141748SHans Petter Selasky 2622e141748SHans Petter Selasky return (0); 2632e141748SHans Petter Selasky } 2642e141748SHans Petter Selasky 2652e141748SHans Petter Selasky /*------------------------------------------------------------------------* 2662e141748SHans Petter Selasky * usb_shutdown 2672e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 2682e141748SHans Petter Selasky static int 2692e141748SHans Petter Selasky usb_shutdown(device_t dev) 2702e141748SHans Petter Selasky { 2712e141748SHans Petter Selasky struct usb_bus *bus = device_get_softc(dev); 2722e141748SHans Petter Selasky 2732e141748SHans Petter Selasky DPRINTF("\n"); 2742e141748SHans Petter Selasky 2752e141748SHans Petter Selasky if (bus == NULL) { 2762e141748SHans Petter Selasky /* was never setup properly */ 2772e141748SHans Petter Selasky return (0); 2782e141748SHans Petter Selasky } 2792e141748SHans Petter Selasky 2802e141748SHans Petter Selasky USB_BUS_LOCK(bus); 2812e141748SHans Petter Selasky usb_proc_msignal(&bus->explore_proc, 2822e141748SHans Petter Selasky &bus->shutdown_msg[0], &bus->shutdown_msg[1]); 2832e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 2842e141748SHans Petter Selasky 2852e141748SHans Petter Selasky return (0); 2862e141748SHans Petter Selasky } 2872e141748SHans Petter Selasky 2882e141748SHans Petter Selasky /*------------------------------------------------------------------------* 289a593f6b8SAndrew Thompson * usb_bus_explore 29002ac6454SAndrew Thompson * 29102ac6454SAndrew Thompson * This function is used to explore the device tree from the root. 29202ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 29302ac6454SAndrew Thompson static void 294a593f6b8SAndrew Thompson usb_bus_explore(struct usb_proc_msg *pm) 29502ac6454SAndrew Thompson { 296760bc48eSAndrew Thompson struct usb_bus *bus; 297760bc48eSAndrew Thompson struct usb_device *udev; 29802ac6454SAndrew Thompson 299760bc48eSAndrew Thompson bus = ((struct usb_bus_msg *)pm)->bus; 30002ac6454SAndrew Thompson udev = bus->devices[USB_ROOT_HUB_ADDR]; 30102ac6454SAndrew Thompson 3022e141748SHans Petter Selasky if (bus->no_explore != 0) 3032e141748SHans Petter Selasky return; 3042e141748SHans Petter Selasky 30502ac6454SAndrew Thompson if (udev && udev->hub) { 30602ac6454SAndrew Thompson 30702ac6454SAndrew Thompson if (bus->do_probe) { 30802ac6454SAndrew Thompson bus->do_probe = 0; 30902ac6454SAndrew Thompson bus->driver_added_refcount++; 31002ac6454SAndrew Thompson } 31102ac6454SAndrew Thompson if (bus->driver_added_refcount == 0) { 31202ac6454SAndrew Thompson /* avoid zero, hence that is memory default */ 31302ac6454SAndrew Thompson bus->driver_added_refcount = 1; 31402ac6454SAndrew Thompson } 31502ac6454SAndrew Thompson 316f0c078e6SAndrew Thompson #ifdef DDB 31734b48722SAlfred Perlstein /* 31834b48722SAlfred Perlstein * The following three lines of code are only here to 31934b48722SAlfred Perlstein * recover from DDB: 32034b48722SAlfred Perlstein */ 32134b48722SAlfred Perlstein usb_proc_rewakeup(&bus->control_xfer_proc); 32234b48722SAlfred Perlstein usb_proc_rewakeup(&bus->giant_callback_proc); 32334b48722SAlfred Perlstein usb_proc_rewakeup(&bus->non_giant_callback_proc); 324f0c078e6SAndrew Thompson #endif 32534b48722SAlfred Perlstein 32634b48722SAlfred Perlstein USB_BUS_UNLOCK(bus); 327a56fe095SJohn Baldwin 328e727a16cSAndrew Thompson #if USB_HAVE_POWERD 32902ac6454SAndrew Thompson /* 33002ac6454SAndrew Thompson * First update the USB power state! 33102ac6454SAndrew Thompson */ 332a593f6b8SAndrew Thompson usb_bus_powerd(bus); 333e727a16cSAndrew Thompson #endif 33434b48722SAlfred Perlstein /* Explore the Root USB HUB. */ 33502ac6454SAndrew Thompson (udev->hub->explore) (udev); 33602ac6454SAndrew Thompson USB_BUS_LOCK(bus); 33702ac6454SAndrew Thompson } 3383df007ceSHans Petter Selasky usb_root_mount_rel(bus); 33902ac6454SAndrew Thompson } 34002ac6454SAndrew Thompson 34102ac6454SAndrew Thompson /*------------------------------------------------------------------------* 342a593f6b8SAndrew Thompson * usb_bus_detach 34302ac6454SAndrew Thompson * 34402ac6454SAndrew Thompson * This function is used to detach the device tree from the root. 34502ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 34602ac6454SAndrew Thompson static void 347a593f6b8SAndrew Thompson usb_bus_detach(struct usb_proc_msg *pm) 34802ac6454SAndrew Thompson { 349760bc48eSAndrew Thompson struct usb_bus *bus; 350760bc48eSAndrew Thompson struct usb_device *udev; 35102ac6454SAndrew Thompson device_t dev; 35202ac6454SAndrew Thompson 353760bc48eSAndrew Thompson bus = ((struct usb_bus_msg *)pm)->bus; 35402ac6454SAndrew Thompson udev = bus->devices[USB_ROOT_HUB_ADDR]; 35502ac6454SAndrew Thompson dev = bus->bdev; 35602ac6454SAndrew Thompson /* clear the softc */ 35702ac6454SAndrew Thompson device_set_softc(dev, NULL); 35802ac6454SAndrew Thompson USB_BUS_UNLOCK(bus); 35902ac6454SAndrew Thompson 36002ac6454SAndrew Thompson /* detach children first */ 36134b48722SAlfred Perlstein mtx_lock(&Giant); 36202ac6454SAndrew Thompson bus_generic_detach(dev); 36334b48722SAlfred Perlstein mtx_unlock(&Giant); 36402ac6454SAndrew Thompson 36502ac6454SAndrew Thompson /* 366d88688c7SAndrew Thompson * Free USB device and all subdevices, if any. 36702ac6454SAndrew Thompson */ 368d88688c7SAndrew Thompson usb_free_device(udev, 0); 36902ac6454SAndrew Thompson 37002ac6454SAndrew Thompson USB_BUS_LOCK(bus); 37102ac6454SAndrew Thompson /* clear bdev variable last */ 37202ac6454SAndrew Thompson bus->bdev = NULL; 37302ac6454SAndrew Thompson } 37402ac6454SAndrew Thompson 3752e141748SHans Petter Selasky /*------------------------------------------------------------------------* 3762e141748SHans Petter Selasky * usb_bus_suspend 3772e141748SHans Petter Selasky * 3782e141748SHans Petter Selasky * This function is used to suspend the USB contoller. 3792e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 3802e141748SHans Petter Selasky static void 3812e141748SHans Petter Selasky usb_bus_suspend(struct usb_proc_msg *pm) 3822e141748SHans Petter Selasky { 3832e141748SHans Petter Selasky struct usb_bus *bus; 3842e141748SHans Petter Selasky struct usb_device *udev; 3852e141748SHans Petter Selasky usb_error_t err; 3862e141748SHans Petter Selasky 3872e141748SHans Petter Selasky bus = ((struct usb_bus_msg *)pm)->bus; 3882e141748SHans Petter Selasky udev = bus->devices[USB_ROOT_HUB_ADDR]; 3892e141748SHans Petter Selasky 3902e141748SHans Petter Selasky if (udev == NULL || bus->bdev == NULL) 3912e141748SHans Petter Selasky return; 3922e141748SHans Petter Selasky 393*6bd3e535SHans Petter Selasky USB_BUS_UNLOCK(bus); 394*6bd3e535SHans Petter Selasky 3952e141748SHans Petter Selasky bus_generic_shutdown(bus->bdev); 3962e141748SHans Petter Selasky 3972e141748SHans Petter Selasky usbd_enum_lock(udev); 3982e141748SHans Petter Selasky 3992e141748SHans Petter Selasky err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX); 4002e141748SHans Petter Selasky if (err) 4012e141748SHans Petter Selasky device_printf(bus->bdev, "Could not unconfigure root HUB\n"); 4022e141748SHans Petter Selasky 4032e141748SHans Petter Selasky USB_BUS_LOCK(bus); 4042e141748SHans Petter Selasky bus->hw_power_state = 0; 4052e141748SHans Petter Selasky bus->no_explore = 1; 4062e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 4072e141748SHans Petter Selasky 4082e141748SHans Petter Selasky if (bus->methods->set_hw_power != NULL) 4092e141748SHans Petter Selasky (bus->methods->set_hw_power) (bus); 4102e141748SHans Petter Selasky 4112e141748SHans Petter Selasky if (bus->methods->set_hw_power_sleep != NULL) 4122e141748SHans Petter Selasky (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SUSPEND); 4132e141748SHans Petter Selasky 4142e141748SHans Petter Selasky usbd_enum_unlock(udev); 415*6bd3e535SHans Petter Selasky 416*6bd3e535SHans Petter Selasky USB_BUS_LOCK(bus); 4172e141748SHans Petter Selasky } 4182e141748SHans Petter Selasky 4192e141748SHans Petter Selasky /*------------------------------------------------------------------------* 4202e141748SHans Petter Selasky * usb_bus_resume 4212e141748SHans Petter Selasky * 4222e141748SHans Petter Selasky * This function is used to resume the USB contoller. 4232e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 4242e141748SHans Petter Selasky static void 4252e141748SHans Petter Selasky usb_bus_resume(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; 4302e141748SHans Petter Selasky 4312e141748SHans Petter Selasky bus = ((struct usb_bus_msg *)pm)->bus; 4322e141748SHans Petter Selasky udev = bus->devices[USB_ROOT_HUB_ADDR]; 4332e141748SHans Petter Selasky 4342e141748SHans Petter Selasky if (udev == NULL || bus->bdev == NULL) 4352e141748SHans Petter Selasky return; 4362e141748SHans Petter Selasky 437*6bd3e535SHans Petter Selasky USB_BUS_UNLOCK(bus); 438*6bd3e535SHans Petter Selasky 4392e141748SHans Petter Selasky usbd_enum_lock(udev); 4402e141748SHans Petter Selasky #if 0 4412e141748SHans Petter Selasky DEVMETHOD(usb_take_controller, NULL); /* dummy */ 4422e141748SHans Petter Selasky #endif 4432e141748SHans Petter Selasky USB_TAKE_CONTROLLER(device_get_parent(bus->bdev)); 4442e141748SHans Petter Selasky 4452e141748SHans Petter Selasky USB_BUS_LOCK(bus); 4462e141748SHans Petter Selasky bus->hw_power_state = 4472e141748SHans Petter Selasky USB_HW_POWER_CONTROL | 4482e141748SHans Petter Selasky USB_HW_POWER_BULK | 4492e141748SHans Petter Selasky USB_HW_POWER_INTERRUPT | 4502e141748SHans Petter Selasky USB_HW_POWER_ISOC | 4512e141748SHans Petter Selasky USB_HW_POWER_NON_ROOT_HUB; 4522e141748SHans Petter Selasky bus->no_explore = 0; 4532e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 4542e141748SHans Petter Selasky 4552e141748SHans Petter Selasky if (bus->methods->set_hw_power_sleep != NULL) 4562e141748SHans Petter Selasky (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_RESUME); 4572e141748SHans Petter Selasky 4582e141748SHans Petter Selasky if (bus->methods->set_hw_power != NULL) 4592e141748SHans Petter Selasky (bus->methods->set_hw_power) (bus); 4602e141748SHans Petter Selasky 4612e141748SHans Petter Selasky err = usbd_set_config_index(udev, 0); 4622e141748SHans Petter Selasky if (err) 4632e141748SHans Petter Selasky device_printf(bus->bdev, "Could not configure root HUB\n"); 4642e141748SHans Petter Selasky 4652e141748SHans Petter Selasky usbd_enum_unlock(udev); 466*6bd3e535SHans Petter Selasky 467*6bd3e535SHans Petter Selasky USB_BUS_LOCK(bus); 4682e141748SHans Petter Selasky } 4692e141748SHans Petter Selasky 4702e141748SHans Petter Selasky /*------------------------------------------------------------------------* 4712e141748SHans Petter Selasky * usb_bus_shutdown 4722e141748SHans Petter Selasky * 4732e141748SHans Petter Selasky * This function is used to shutdown the USB contoller. 4742e141748SHans Petter Selasky *------------------------------------------------------------------------*/ 4752e141748SHans Petter Selasky static void 4762e141748SHans Petter Selasky usb_bus_shutdown(struct usb_proc_msg *pm) 4772e141748SHans Petter Selasky { 4782e141748SHans Petter Selasky struct usb_bus *bus; 4792e141748SHans Petter Selasky struct usb_device *udev; 4802e141748SHans Petter Selasky usb_error_t err; 4812e141748SHans Petter Selasky 4822e141748SHans Petter Selasky bus = ((struct usb_bus_msg *)pm)->bus; 4832e141748SHans Petter Selasky udev = bus->devices[USB_ROOT_HUB_ADDR]; 4842e141748SHans Petter Selasky 4852e141748SHans Petter Selasky if (udev == NULL || bus->bdev == NULL) 4862e141748SHans Petter Selasky return; 4872e141748SHans Petter Selasky 488*6bd3e535SHans Petter Selasky USB_BUS_UNLOCK(bus); 489*6bd3e535SHans Petter Selasky 4902e141748SHans Petter Selasky bus_generic_shutdown(bus->bdev); 4912e141748SHans Petter Selasky 4922e141748SHans Petter Selasky usbd_enum_lock(udev); 4932e141748SHans Petter Selasky 4942e141748SHans Petter Selasky err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX); 4952e141748SHans Petter Selasky if (err) 4962e141748SHans Petter Selasky device_printf(bus->bdev, "Could not unconfigure root HUB\n"); 4972e141748SHans Petter Selasky 4982e141748SHans Petter Selasky USB_BUS_LOCK(bus); 4992e141748SHans Petter Selasky bus->hw_power_state = 0; 5002e141748SHans Petter Selasky bus->no_explore = 1; 5012e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 5022e141748SHans Petter Selasky 5032e141748SHans Petter Selasky if (bus->methods->set_hw_power != NULL) 5042e141748SHans Petter Selasky (bus->methods->set_hw_power) (bus); 5052e141748SHans Petter Selasky 5062e141748SHans Petter Selasky if (bus->methods->set_hw_power_sleep != NULL) 5072e141748SHans Petter Selasky (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SHUTDOWN); 5082e141748SHans Petter Selasky 5092e141748SHans Petter Selasky usbd_enum_unlock(udev); 510*6bd3e535SHans Petter Selasky 511*6bd3e535SHans Petter Selasky USB_BUS_LOCK(bus); 5122e141748SHans Petter Selasky } 5132e141748SHans Petter Selasky 51402ac6454SAndrew Thompson static void 515a593f6b8SAndrew Thompson usb_power_wdog(void *arg) 51602ac6454SAndrew Thompson { 517760bc48eSAndrew Thompson struct usb_bus *bus = arg; 51802ac6454SAndrew Thompson 51902ac6454SAndrew Thompson USB_BUS_LOCK_ASSERT(bus, MA_OWNED); 52002ac6454SAndrew Thompson 521a593f6b8SAndrew Thompson usb_callout_reset(&bus->power_wdog, 522a593f6b8SAndrew Thompson 4 * hz, usb_power_wdog, arg); 52302ac6454SAndrew Thompson 524f0c078e6SAndrew Thompson #ifdef DDB 52534b48722SAlfred Perlstein /* 52634b48722SAlfred Perlstein * The following line of code is only here to recover from 52734b48722SAlfred Perlstein * DDB: 52834b48722SAlfred Perlstein */ 52934b48722SAlfred Perlstein usb_proc_rewakeup(&bus->explore_proc); /* recover from DDB */ 530f0c078e6SAndrew Thompson #endif 53134b48722SAlfred Perlstein 532e727a16cSAndrew Thompson #if USB_HAVE_POWERD 53302ac6454SAndrew Thompson USB_BUS_UNLOCK(bus); 53402ac6454SAndrew Thompson 535a593f6b8SAndrew Thompson usb_bus_power_update(bus); 53602ac6454SAndrew Thompson 537684e3f22SAndrew Thompson USB_BUS_LOCK(bus); 538e727a16cSAndrew Thompson #endif 53902ac6454SAndrew Thompson } 54002ac6454SAndrew Thompson 54102ac6454SAndrew Thompson /*------------------------------------------------------------------------* 542a593f6b8SAndrew Thompson * usb_bus_attach 54302ac6454SAndrew Thompson * 54402ac6454SAndrew Thompson * This function attaches USB in context of the explore thread. 54502ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 54602ac6454SAndrew Thompson static void 547a593f6b8SAndrew Thompson usb_bus_attach(struct usb_proc_msg *pm) 54802ac6454SAndrew Thompson { 549760bc48eSAndrew Thompson struct usb_bus *bus; 550760bc48eSAndrew Thompson struct usb_device *child; 55102ac6454SAndrew Thompson device_t dev; 552e0a69b51SAndrew Thompson usb_error_t err; 5538d2dd5ddSAndrew Thompson enum usb_dev_speed speed; 55402ac6454SAndrew Thompson 555760bc48eSAndrew Thompson bus = ((struct usb_bus_msg *)pm)->bus; 55602ac6454SAndrew Thompson dev = bus->bdev; 55702ac6454SAndrew Thompson 55802ac6454SAndrew Thompson DPRINTF("\n"); 55902ac6454SAndrew Thompson 56002ac6454SAndrew Thompson switch (bus->usbrev) { 56102ac6454SAndrew Thompson case USB_REV_1_0: 56202ac6454SAndrew Thompson speed = USB_SPEED_FULL; 56302ac6454SAndrew Thompson device_printf(bus->bdev, "12Mbps Full Speed USB v1.0\n"); 56402ac6454SAndrew Thompson break; 56502ac6454SAndrew Thompson 56602ac6454SAndrew Thompson case USB_REV_1_1: 56702ac6454SAndrew Thompson speed = USB_SPEED_FULL; 56802ac6454SAndrew Thompson device_printf(bus->bdev, "12Mbps Full Speed USB v1.1\n"); 56902ac6454SAndrew Thompson break; 57002ac6454SAndrew Thompson 57102ac6454SAndrew Thompson case USB_REV_2_0: 57202ac6454SAndrew Thompson speed = USB_SPEED_HIGH; 57302ac6454SAndrew Thompson device_printf(bus->bdev, "480Mbps High Speed USB v2.0\n"); 57402ac6454SAndrew Thompson break; 57502ac6454SAndrew Thompson 57602ac6454SAndrew Thompson case USB_REV_2_5: 57702ac6454SAndrew Thompson speed = USB_SPEED_VARIABLE; 57802ac6454SAndrew Thompson device_printf(bus->bdev, "480Mbps Wireless USB v2.5\n"); 57902ac6454SAndrew Thompson break; 58002ac6454SAndrew Thompson 581963169b4SHans Petter Selasky case USB_REV_3_0: 582963169b4SHans Petter Selasky speed = USB_SPEED_SUPER; 583ccac019aSHans Petter Selasky device_printf(bus->bdev, "5.0Gbps Super Speed USB v3.0\n"); 584963169b4SHans Petter Selasky break; 585963169b4SHans Petter Selasky 58602ac6454SAndrew Thompson default: 587767cb2e2SAndrew Thompson device_printf(bus->bdev, "Unsupported USB revision\n"); 5883df007ceSHans Petter Selasky usb_root_mount_rel(bus); 58902ac6454SAndrew Thompson return; 59002ac6454SAndrew Thompson } 59102ac6454SAndrew Thompson 5924eae601eSAndrew Thompson /* default power_mask value */ 5934eae601eSAndrew Thompson bus->hw_power_state = 5944eae601eSAndrew Thompson USB_HW_POWER_CONTROL | 5954eae601eSAndrew Thompson USB_HW_POWER_BULK | 5964eae601eSAndrew Thompson USB_HW_POWER_INTERRUPT | 5974eae601eSAndrew Thompson USB_HW_POWER_ISOC | 5984eae601eSAndrew Thompson USB_HW_POWER_NON_ROOT_HUB; 5994eae601eSAndrew Thompson 6002e141748SHans Petter Selasky USB_BUS_UNLOCK(bus); 6012e141748SHans Petter Selasky 6024eae601eSAndrew Thompson /* make sure power is set at least once */ 6034eae601eSAndrew Thompson 6044eae601eSAndrew Thompson if (bus->methods->set_hw_power != NULL) { 6054eae601eSAndrew Thompson (bus->methods->set_hw_power) (bus); 6064eae601eSAndrew Thompson } 6074eae601eSAndrew Thompson 6082e141748SHans Petter Selasky /* allocate the Root USB device */ 60902ac6454SAndrew Thompson 610a593f6b8SAndrew Thompson child = usb_alloc_device(bus->bdev, bus, NULL, 0, 0, 1, 61102ac6454SAndrew Thompson speed, USB_MODE_HOST); 61202ac6454SAndrew Thompson if (child) { 613a593f6b8SAndrew Thompson err = usb_probe_and_attach(child, 61402ac6454SAndrew Thompson USB_IFACE_INDEX_ANY); 61502ac6454SAndrew Thompson if (!err) { 6161be5bf51SAndrew Thompson if ((bus->devices[USB_ROOT_HUB_ADDR] == NULL) || 6171be5bf51SAndrew Thompson (bus->devices[USB_ROOT_HUB_ADDR]->hub == NULL)) { 61802ac6454SAndrew Thompson err = USB_ERR_NO_ROOT_HUB; 61902ac6454SAndrew Thompson } 62002ac6454SAndrew Thompson } 62102ac6454SAndrew Thompson } else { 62202ac6454SAndrew Thompson err = USB_ERR_NOMEM; 62302ac6454SAndrew Thompson } 62402ac6454SAndrew Thompson 62502ac6454SAndrew Thompson USB_BUS_LOCK(bus); 62602ac6454SAndrew Thompson 62702ac6454SAndrew Thompson if (err) { 62802ac6454SAndrew Thompson device_printf(bus->bdev, "Root HUB problem, error=%s\n", 629a593f6b8SAndrew Thompson usbd_errstr(err)); 6303df007ceSHans Petter Selasky usb_root_mount_rel(bus); 63102ac6454SAndrew Thompson } 63202ac6454SAndrew Thompson 63302ac6454SAndrew Thompson /* set softc - we are ready */ 63402ac6454SAndrew Thompson device_set_softc(dev, bus); 63502ac6454SAndrew Thompson 636684e3f22SAndrew Thompson /* start watchdog */ 637a593f6b8SAndrew Thompson usb_power_wdog(bus); 63802ac6454SAndrew Thompson } 63902ac6454SAndrew Thompson 64002ac6454SAndrew Thompson /*------------------------------------------------------------------------* 641a593f6b8SAndrew Thompson * usb_attach_sub 64202ac6454SAndrew Thompson * 64334b48722SAlfred Perlstein * This function creates a thread which runs the USB attach code. 64402ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 64502ac6454SAndrew Thompson static void 646a593f6b8SAndrew Thompson usb_attach_sub(device_t dev, struct usb_bus *bus) 64702ac6454SAndrew Thompson { 64802ac6454SAndrew Thompson const char *pname = device_get_nameunit(dev); 64902ac6454SAndrew Thompson 65034b48722SAlfred Perlstein mtx_lock(&Giant); 65134b48722SAlfred Perlstein if (usb_devclass_ptr == NULL) 65234b48722SAlfred Perlstein usb_devclass_ptr = devclass_find("usbus"); 65334b48722SAlfred Perlstein mtx_unlock(&Giant); 65434b48722SAlfred Perlstein 6558be09334SHans Petter Selasky #if USB_HAVE_PF 656fe1c24e3SWeongyo Jeong usbpf_attach(bus); 6578be09334SHans Petter Selasky #endif 65802ac6454SAndrew Thompson /* Initialise USB process messages */ 659a593f6b8SAndrew Thompson bus->explore_msg[0].hdr.pm_callback = &usb_bus_explore; 66002ac6454SAndrew Thompson bus->explore_msg[0].bus = bus; 661a593f6b8SAndrew Thompson bus->explore_msg[1].hdr.pm_callback = &usb_bus_explore; 66202ac6454SAndrew Thompson bus->explore_msg[1].bus = bus; 66302ac6454SAndrew Thompson 664a593f6b8SAndrew Thompson bus->detach_msg[0].hdr.pm_callback = &usb_bus_detach; 66502ac6454SAndrew Thompson bus->detach_msg[0].bus = bus; 666a593f6b8SAndrew Thompson bus->detach_msg[1].hdr.pm_callback = &usb_bus_detach; 66702ac6454SAndrew Thompson bus->detach_msg[1].bus = bus; 66802ac6454SAndrew Thompson 669a593f6b8SAndrew Thompson bus->attach_msg[0].hdr.pm_callback = &usb_bus_attach; 67002ac6454SAndrew Thompson bus->attach_msg[0].bus = bus; 671a593f6b8SAndrew Thompson bus->attach_msg[1].hdr.pm_callback = &usb_bus_attach; 67202ac6454SAndrew Thompson bus->attach_msg[1].bus = bus; 67302ac6454SAndrew Thompson 6742e141748SHans Petter Selasky bus->suspend_msg[0].hdr.pm_callback = &usb_bus_suspend; 6752e141748SHans Petter Selasky bus->suspend_msg[0].bus = bus; 6762e141748SHans Petter Selasky bus->suspend_msg[1].hdr.pm_callback = &usb_bus_suspend; 6772e141748SHans Petter Selasky bus->suspend_msg[1].bus = bus; 6782e141748SHans Petter Selasky 6792e141748SHans Petter Selasky bus->resume_msg[0].hdr.pm_callback = &usb_bus_resume; 6802e141748SHans Petter Selasky bus->resume_msg[0].bus = bus; 6812e141748SHans Petter Selasky bus->resume_msg[1].hdr.pm_callback = &usb_bus_resume; 6822e141748SHans Petter Selasky bus->resume_msg[1].bus = bus; 6832e141748SHans Petter Selasky 6842e141748SHans Petter Selasky bus->shutdown_msg[0].hdr.pm_callback = &usb_bus_shutdown; 6852e141748SHans Petter Selasky bus->shutdown_msg[0].bus = bus; 6862e141748SHans Petter Selasky bus->shutdown_msg[1].hdr.pm_callback = &usb_bus_shutdown; 6872e141748SHans Petter Selasky bus->shutdown_msg[1].bus = bus; 6882e141748SHans Petter Selasky 68939307315SAndrew Thompson /* Create USB explore and callback processes */ 69002ac6454SAndrew Thompson 691a593f6b8SAndrew Thompson if (usb_proc_create(&bus->giant_callback_proc, 69202ac6454SAndrew Thompson &bus->bus_mtx, pname, USB_PRI_MED)) { 69388334428SHans Petter Selasky device_printf(dev, "WARNING: Creation of USB Giant " 69402ac6454SAndrew Thompson "callback process failed.\n"); 695a593f6b8SAndrew Thompson } else if (usb_proc_create(&bus->non_giant_callback_proc, 69602ac6454SAndrew Thompson &bus->bus_mtx, pname, USB_PRI_HIGH)) { 69788334428SHans Petter Selasky device_printf(dev, "WARNING: Creation of USB non-Giant " 69802ac6454SAndrew Thompson "callback process failed.\n"); 699a593f6b8SAndrew Thompson } else if (usb_proc_create(&bus->explore_proc, 70002ac6454SAndrew Thompson &bus->bus_mtx, pname, USB_PRI_MED)) { 70188334428SHans Petter Selasky device_printf(dev, "WARNING: Creation of USB explore " 70202ac6454SAndrew Thompson "process failed.\n"); 703a593f6b8SAndrew Thompson } else if (usb_proc_create(&bus->control_xfer_proc, 704672c9965SAndrew Thompson &bus->bus_mtx, pname, USB_PRI_MED)) { 70588334428SHans Petter Selasky device_printf(dev, "WARNING: Creation of USB control transfer " 706672c9965SAndrew Thompson "process failed.\n"); 70702ac6454SAndrew Thompson } else { 70802ac6454SAndrew Thompson /* Get final attach going */ 70902ac6454SAndrew Thompson USB_BUS_LOCK(bus); 7102e141748SHans Petter Selasky usb_proc_msignal(&bus->explore_proc, 7112e141748SHans Petter Selasky &bus->attach_msg[0], &bus->attach_msg[1]); 71202ac6454SAndrew Thompson USB_BUS_UNLOCK(bus); 71334b48722SAlfred Perlstein 71434b48722SAlfred Perlstein /* Do initial explore */ 71534b48722SAlfred Perlstein usb_needs_explore(bus, 1); 71602ac6454SAndrew Thompson } 71702ac6454SAndrew Thompson } 71802ac6454SAndrew Thompson 719a593f6b8SAndrew Thompson SYSUNINIT(usb_bus_unload, SI_SUB_KLD, SI_ORDER_ANY, usb_bus_unload, NULL); 72002ac6454SAndrew Thompson 72102ac6454SAndrew Thompson /*------------------------------------------------------------------------* 722a593f6b8SAndrew Thompson * usb_bus_mem_flush_all_cb 72302ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 724bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 72502ac6454SAndrew Thompson static void 726a593f6b8SAndrew Thompson usb_bus_mem_flush_all_cb(struct usb_bus *bus, struct usb_page_cache *pc, 727f9cb546cSAndrew Thompson struct usb_page *pg, usb_size_t size, usb_size_t align) 72802ac6454SAndrew Thompson { 729a593f6b8SAndrew Thompson usb_pc_cpu_flush(pc); 73002ac6454SAndrew Thompson } 731bdc081c6SAndrew Thompson #endif 73202ac6454SAndrew Thompson 73302ac6454SAndrew Thompson /*------------------------------------------------------------------------* 734a593f6b8SAndrew Thompson * usb_bus_mem_flush_all - factored out code 73502ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 736bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 73702ac6454SAndrew Thompson void 738a593f6b8SAndrew Thompson usb_bus_mem_flush_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb) 73902ac6454SAndrew Thompson { 74002ac6454SAndrew Thompson if (cb) { 741a593f6b8SAndrew Thompson cb(bus, &usb_bus_mem_flush_all_cb); 74202ac6454SAndrew Thompson } 74302ac6454SAndrew Thompson } 744bdc081c6SAndrew Thompson #endif 74502ac6454SAndrew Thompson 74602ac6454SAndrew Thompson /*------------------------------------------------------------------------* 747a593f6b8SAndrew Thompson * usb_bus_mem_alloc_all_cb 74802ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 749bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 75002ac6454SAndrew Thompson static void 751a593f6b8SAndrew Thompson usb_bus_mem_alloc_all_cb(struct usb_bus *bus, struct usb_page_cache *pc, 752f9cb546cSAndrew Thompson struct usb_page *pg, usb_size_t size, usb_size_t align) 75302ac6454SAndrew Thompson { 75402ac6454SAndrew Thompson /* need to initialize the page cache */ 75502ac6454SAndrew Thompson pc->tag_parent = bus->dma_parent_tag; 75602ac6454SAndrew Thompson 757a593f6b8SAndrew Thompson if (usb_pc_alloc_mem(pc, pg, size, align)) { 75802ac6454SAndrew Thompson bus->alloc_failed = 1; 75902ac6454SAndrew Thompson } 76002ac6454SAndrew Thompson } 761bdc081c6SAndrew Thompson #endif 76202ac6454SAndrew Thompson 76302ac6454SAndrew Thompson /*------------------------------------------------------------------------* 764a593f6b8SAndrew Thompson * usb_bus_mem_alloc_all - factored out code 76502ac6454SAndrew Thompson * 76602ac6454SAndrew Thompson * Returns: 76702ac6454SAndrew Thompson * 0: Success 76802ac6454SAndrew Thompson * Else: Failure 76902ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 77002ac6454SAndrew Thompson uint8_t 771a593f6b8SAndrew Thompson usb_bus_mem_alloc_all(struct usb_bus *bus, bus_dma_tag_t dmat, 772e0a69b51SAndrew Thompson usb_bus_mem_cb_t *cb) 77302ac6454SAndrew Thompson { 77402ac6454SAndrew Thompson bus->alloc_failed = 0; 77502ac6454SAndrew Thompson 77602ac6454SAndrew Thompson mtx_init(&bus->bus_mtx, device_get_nameunit(bus->parent), 77702ac6454SAndrew Thompson NULL, MTX_DEF | MTX_RECURSE); 77802ac6454SAndrew Thompson 779a593f6b8SAndrew Thompson usb_callout_init_mtx(&bus->power_wdog, 780684e3f22SAndrew Thompson &bus->bus_mtx, 0); 78102ac6454SAndrew Thompson 78202ac6454SAndrew Thompson TAILQ_INIT(&bus->intr_q.head); 78302ac6454SAndrew Thompson 784bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 785a593f6b8SAndrew Thompson usb_dma_tag_setup(bus->dma_parent_tag, bus->dma_tags, 786bdc081c6SAndrew Thompson dmat, &bus->bus_mtx, NULL, 32, USB_BUS_DMA_TAG_MAX); 787bdc081c6SAndrew Thompson #endif 78802ac6454SAndrew Thompson if ((bus->devices_max > USB_MAX_DEVICES) || 78902ac6454SAndrew Thompson (bus->devices_max < USB_MIN_DEVICES) || 79002ac6454SAndrew Thompson (bus->devices == NULL)) { 79102ac6454SAndrew Thompson DPRINTFN(0, "Devices field has not been " 792767cb2e2SAndrew Thompson "initialised properly\n"); 79302ac6454SAndrew Thompson bus->alloc_failed = 1; /* failure */ 79402ac6454SAndrew Thompson } 795bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 79602ac6454SAndrew Thompson if (cb) { 797a593f6b8SAndrew Thompson cb(bus, &usb_bus_mem_alloc_all_cb); 79802ac6454SAndrew Thompson } 799bdc081c6SAndrew Thompson #endif 80002ac6454SAndrew Thompson if (bus->alloc_failed) { 801a593f6b8SAndrew Thompson usb_bus_mem_free_all(bus, cb); 80202ac6454SAndrew Thompson } 80302ac6454SAndrew Thompson return (bus->alloc_failed); 80402ac6454SAndrew Thompson } 80502ac6454SAndrew Thompson 80602ac6454SAndrew Thompson /*------------------------------------------------------------------------* 807a593f6b8SAndrew Thompson * usb_bus_mem_free_all_cb 80802ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 809bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 81002ac6454SAndrew Thompson static void 811a593f6b8SAndrew Thompson usb_bus_mem_free_all_cb(struct usb_bus *bus, struct usb_page_cache *pc, 812f9cb546cSAndrew Thompson struct usb_page *pg, usb_size_t size, usb_size_t align) 81302ac6454SAndrew Thompson { 814a593f6b8SAndrew Thompson usb_pc_free_mem(pc); 81502ac6454SAndrew Thompson } 816bdc081c6SAndrew Thompson #endif 81702ac6454SAndrew Thompson 81802ac6454SAndrew Thompson /*------------------------------------------------------------------------* 819a593f6b8SAndrew Thompson * usb_bus_mem_free_all - factored out code 82002ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 82102ac6454SAndrew Thompson void 822a593f6b8SAndrew Thompson usb_bus_mem_free_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb) 82302ac6454SAndrew Thompson { 824bdc081c6SAndrew Thompson #if USB_HAVE_BUSDMA 82502ac6454SAndrew Thompson if (cb) { 826a593f6b8SAndrew Thompson cb(bus, &usb_bus_mem_free_all_cb); 82702ac6454SAndrew Thompson } 828a593f6b8SAndrew Thompson usb_dma_tag_unsetup(bus->dma_parent_tag); 829bdc081c6SAndrew Thompson #endif 83002ac6454SAndrew Thompson 83102ac6454SAndrew Thompson mtx_destroy(&bus->bus_mtx); 83202ac6454SAndrew Thompson } 833