112bd3c8bSSascha Wildner /* $FreeBSD$ */ 212bd3c8bSSascha Wildner /*- 312bd3c8bSSascha Wildner * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 412bd3c8bSSascha Wildner * 512bd3c8bSSascha Wildner * Redistribution and use in source and binary forms, with or without 612bd3c8bSSascha Wildner * modification, are permitted provided that the following conditions 712bd3c8bSSascha Wildner * are met: 812bd3c8bSSascha Wildner * 1. Redistributions of source code must retain the above copyright 912bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer. 1012bd3c8bSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 1112bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer in the 1212bd3c8bSSascha Wildner * documentation and/or other materials provided with the distribution. 1312bd3c8bSSascha Wildner * 1412bd3c8bSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1512bd3c8bSSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1612bd3c8bSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1712bd3c8bSSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1812bd3c8bSSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1912bd3c8bSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2012bd3c8bSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2112bd3c8bSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2212bd3c8bSSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2312bd3c8bSSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2412bd3c8bSSascha Wildner * SUCH DAMAGE. 2512bd3c8bSSascha Wildner */ 2612bd3c8bSSascha Wildner 2712bd3c8bSSascha Wildner #include "opt_ddb.h" 2812bd3c8bSSascha Wildner 2912bd3c8bSSascha Wildner #include <sys/stdint.h> 3012bd3c8bSSascha Wildner #include <sys/param.h> 3112bd3c8bSSascha Wildner #include <sys/queue.h> 3212bd3c8bSSascha Wildner #include <sys/types.h> 3312bd3c8bSSascha Wildner #include <sys/systm.h> 3412bd3c8bSSascha Wildner #include <sys/kernel.h> 3512bd3c8bSSascha Wildner #include <sys/bus.h> 3612bd3c8bSSascha Wildner #include <sys/module.h> 3712bd3c8bSSascha Wildner #include <sys/lock.h> 3812bd3c8bSSascha Wildner #include <sys/condvar.h> 3912bd3c8bSSascha Wildner #include <sys/sysctl.h> 4012bd3c8bSSascha Wildner #include <sys/unistd.h> 4112bd3c8bSSascha Wildner #include <sys/callout.h> 4212bd3c8bSSascha Wildner #include <sys/malloc.h> 4312bd3c8bSSascha Wildner #include <sys/priv.h> 4412bd3c8bSSascha Wildner 45722d05c3SSascha Wildner #include <bus/u4b/usb.h> 46722d05c3SSascha Wildner #include <bus/u4b/usbdi.h> 4712bd3c8bSSascha Wildner 4812bd3c8bSSascha Wildner #define USB_DEBUG_VAR usb_ctrl_debug 4912bd3c8bSSascha Wildner 50722d05c3SSascha Wildner #include <bus/u4b/usb_core.h> 51722d05c3SSascha Wildner #include <bus/u4b/usb_debug.h> 52722d05c3SSascha Wildner #include <bus/u4b/usb_process.h> 53722d05c3SSascha Wildner #include <bus/u4b/usb_busdma.h> 54722d05c3SSascha Wildner #include <bus/u4b/usb_dynamic.h> 55722d05c3SSascha Wildner #include <bus/u4b/usb_device.h> 56722d05c3SSascha Wildner #include <bus/u4b/usb_hub.h> 5712bd3c8bSSascha Wildner 58722d05c3SSascha Wildner #include <bus/u4b/usb_controller.h> 59722d05c3SSascha Wildner #include <bus/u4b/usb_bus.h> 60722d05c3SSascha Wildner #include <bus/u4b/usb_pf.h> 6112bd3c8bSSascha Wildner #include "usb_if.h" 6212bd3c8bSSascha Wildner 6312bd3c8bSSascha Wildner /* function prototypes */ 6412bd3c8bSSascha Wildner 6512bd3c8bSSascha Wildner static device_probe_t usb_probe; 6612bd3c8bSSascha Wildner static device_attach_t usb_attach; 6712bd3c8bSSascha Wildner static device_detach_t usb_detach; 6812bd3c8bSSascha Wildner static device_suspend_t usb_suspend; 6912bd3c8bSSascha Wildner static device_resume_t usb_resume; 7012bd3c8bSSascha Wildner static device_shutdown_t usb_shutdown; 7112bd3c8bSSascha Wildner 7212bd3c8bSSascha Wildner static void usb_attach_sub(device_t, struct usb_bus *); 7312bd3c8bSSascha Wildner 7412bd3c8bSSascha Wildner /* static variables */ 7512bd3c8bSSascha Wildner 7612bd3c8bSSascha Wildner #ifdef USB_DEBUG 7712bd3c8bSSascha Wildner static int usb_ctrl_debug = 0; 7812bd3c8bSSascha Wildner 7912bd3c8bSSascha Wildner static SYSCTL_NODE(_hw_usb, OID_AUTO, ctrl, CTLFLAG_RW, 0, "USB controller"); 8012bd3c8bSSascha Wildner SYSCTL_INT(_hw_usb_ctrl, OID_AUTO, debug, CTLFLAG_RW, &usb_ctrl_debug, 0, 8112bd3c8bSSascha Wildner "Debug level"); 8212bd3c8bSSascha Wildner #endif 8312bd3c8bSSascha Wildner 8412bd3c8bSSascha Wildner static int usb_no_boot_wait = 0; 8512bd3c8bSSascha Wildner TUNABLE_INT("hw.usb.no_boot_wait", &usb_no_boot_wait); 86722d05c3SSascha Wildner /* XXX freebsd uses CTLFLAG_RDTUN here */ 87722d05c3SSascha Wildner SYSCTL_INT(_hw_usb, OID_AUTO, no_boot_wait, CTLFLAG_RW, &usb_no_boot_wait, 0, 8812bd3c8bSSascha Wildner "No USB device enumerate waiting at boot."); 8912bd3c8bSSascha Wildner 9012bd3c8bSSascha Wildner static int usb_no_shutdown_wait = 0; 9112bd3c8bSSascha Wildner TUNABLE_INT("hw.usb.no_shutdown_wait", &usb_no_shutdown_wait); 92722d05c3SSascha Wildner SYSCTL_INT(_hw_usb, OID_AUTO, no_shutdown_wait, CTLFLAG_RW, &usb_no_shutdown_wait, 0, 9312bd3c8bSSascha Wildner "No USB device waiting at system shutdown."); 9412bd3c8bSSascha Wildner 9512bd3c8bSSascha Wildner static devclass_t usb_devclass; 9612bd3c8bSSascha Wildner 9712bd3c8bSSascha Wildner static device_method_t usb_methods[] = { 9812bd3c8bSSascha Wildner DEVMETHOD(device_probe, usb_probe), 9912bd3c8bSSascha Wildner DEVMETHOD(device_attach, usb_attach), 10012bd3c8bSSascha Wildner DEVMETHOD(device_detach, usb_detach), 10112bd3c8bSSascha Wildner DEVMETHOD(device_suspend, usb_suspend), 10212bd3c8bSSascha Wildner DEVMETHOD(device_resume, usb_resume), 10312bd3c8bSSascha Wildner DEVMETHOD(device_shutdown, usb_shutdown), 10412bd3c8bSSascha Wildner {0, 0} 10512bd3c8bSSascha Wildner }; 10612bd3c8bSSascha Wildner 10712bd3c8bSSascha Wildner static driver_t usb_driver = { 10812bd3c8bSSascha Wildner .name = "usbus", 10912bd3c8bSSascha Wildner .methods = usb_methods, 11012bd3c8bSSascha Wildner .size = 0, 11112bd3c8bSSascha Wildner }; 11212bd3c8bSSascha Wildner 11312bd3c8bSSascha Wildner /* Host Only Drivers */ 11412bd3c8bSSascha Wildner DRIVER_MODULE(usbus, ohci, usb_driver, usb_devclass, 0, 0); 11512bd3c8bSSascha Wildner DRIVER_MODULE(usbus, uhci, usb_driver, usb_devclass, 0, 0); 11612bd3c8bSSascha Wildner DRIVER_MODULE(usbus, ehci, usb_driver, usb_devclass, 0, 0); 11712bd3c8bSSascha Wildner DRIVER_MODULE(usbus, xhci, usb_driver, usb_devclass, 0, 0); 11812bd3c8bSSascha Wildner 11912bd3c8bSSascha Wildner /* Device Only Drivers */ 12012bd3c8bSSascha Wildner DRIVER_MODULE(usbus, at91_udp, usb_driver, usb_devclass, 0, 0); 12112bd3c8bSSascha Wildner DRIVER_MODULE(usbus, musbotg, usb_driver, usb_devclass, 0, 0); 12212bd3c8bSSascha Wildner DRIVER_MODULE(usbus, uss820, usb_driver, usb_devclass, 0, 0); 12312bd3c8bSSascha Wildner DRIVER_MODULE(usbus, octusb, usb_driver, usb_devclass, 0, 0); 12412bd3c8bSSascha Wildner 12512bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 12612bd3c8bSSascha Wildner * usb_probe 12712bd3c8bSSascha Wildner * 12812bd3c8bSSascha Wildner * This function is called from "{ehci,ohci,uhci}_pci_attach()". 12912bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 13012bd3c8bSSascha Wildner static int 13112bd3c8bSSascha Wildner usb_probe(device_t dev) 13212bd3c8bSSascha Wildner { 13312bd3c8bSSascha Wildner DPRINTF("\n"); 13412bd3c8bSSascha Wildner return (0); 13512bd3c8bSSascha Wildner } 13612bd3c8bSSascha Wildner 13712bd3c8bSSascha Wildner static void 13812bd3c8bSSascha Wildner usb_root_mount_rel(struct usb_bus *bus) 13912bd3c8bSSascha Wildner { 14012bd3c8bSSascha Wildner if (bus->bus_roothold != NULL) { 14112bd3c8bSSascha Wildner DPRINTF("Releasing root mount hold %p\n", bus->bus_roothold); 142*63da4a34SSascha Wildner #if 0 /* XXX Dragonflybsd seems to not have this? */ 143*63da4a34SSascha Wildner root_mount_rel(bus->bus_roothold); 144*63da4a34SSascha Wildner #endif 14512bd3c8bSSascha Wildner bus->bus_roothold = NULL; 14612bd3c8bSSascha Wildner } 14712bd3c8bSSascha Wildner } 14812bd3c8bSSascha Wildner 14912bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 15012bd3c8bSSascha Wildner * usb_attach 15112bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 15212bd3c8bSSascha Wildner static int 15312bd3c8bSSascha Wildner usb_attach(device_t dev) 15412bd3c8bSSascha Wildner { 15512bd3c8bSSascha Wildner struct usb_bus *bus = device_get_ivars(dev); 15612bd3c8bSSascha Wildner 15712bd3c8bSSascha Wildner DPRINTF("\n"); 15812bd3c8bSSascha Wildner 15912bd3c8bSSascha Wildner if (bus == NULL) { 16012bd3c8bSSascha Wildner device_printf(dev, "USB device has no ivars\n"); 16112bd3c8bSSascha Wildner return (ENXIO); 16212bd3c8bSSascha Wildner } 16312bd3c8bSSascha Wildner 164*63da4a34SSascha Wildner #if 0 /* XXX: Dragonfly does not seem to have this mechanism? */ 16512bd3c8bSSascha Wildner if (usb_no_boot_wait == 0) { 16612bd3c8bSSascha Wildner /* delay vfs_mountroot until the bus is explored */ 16712bd3c8bSSascha Wildner bus->bus_roothold = root_mount_hold(device_get_nameunit(dev)); 16812bd3c8bSSascha Wildner } 169*63da4a34SSascha Wildner #endif 17012bd3c8bSSascha Wildner 17112bd3c8bSSascha Wildner usb_attach_sub(dev, bus); 17212bd3c8bSSascha Wildner 17312bd3c8bSSascha Wildner return (0); /* return success */ 17412bd3c8bSSascha Wildner } 17512bd3c8bSSascha Wildner 17612bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 17712bd3c8bSSascha Wildner * usb_detach 17812bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 17912bd3c8bSSascha Wildner static int 18012bd3c8bSSascha Wildner usb_detach(device_t dev) 18112bd3c8bSSascha Wildner { 18212bd3c8bSSascha Wildner struct usb_bus *bus = device_get_softc(dev); 18312bd3c8bSSascha Wildner 18412bd3c8bSSascha Wildner DPRINTF("\n"); 18512bd3c8bSSascha Wildner 18612bd3c8bSSascha Wildner if (bus == NULL) { 18712bd3c8bSSascha Wildner /* was never setup properly */ 18812bd3c8bSSascha Wildner return (0); 18912bd3c8bSSascha Wildner } 19012bd3c8bSSascha Wildner /* Stop power watchdog */ 19112bd3c8bSSascha Wildner usb_callout_drain(&bus->power_wdog); 19212bd3c8bSSascha Wildner 19312bd3c8bSSascha Wildner /* Let the USB explore process detach all devices. */ 19412bd3c8bSSascha Wildner usb_root_mount_rel(bus); 19512bd3c8bSSascha Wildner 19612bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 19712bd3c8bSSascha Wildner 19812bd3c8bSSascha Wildner /* Queue detach job */ 19912bd3c8bSSascha Wildner usb_proc_msignal(&bus->explore_proc, 20012bd3c8bSSascha Wildner &bus->detach_msg[0], &bus->detach_msg[1]); 20112bd3c8bSSascha Wildner 20212bd3c8bSSascha Wildner /* Wait for detach to complete */ 20312bd3c8bSSascha Wildner usb_proc_mwait(&bus->explore_proc, 20412bd3c8bSSascha Wildner &bus->detach_msg[0], &bus->detach_msg[1]); 20512bd3c8bSSascha Wildner 20612bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 20712bd3c8bSSascha Wildner 20812bd3c8bSSascha Wildner /* Get rid of USB callback processes */ 20912bd3c8bSSascha Wildner 21012bd3c8bSSascha Wildner usb_proc_free(&bus->giant_callback_proc); 21112bd3c8bSSascha Wildner usb_proc_free(&bus->non_giant_callback_proc); 21212bd3c8bSSascha Wildner 21312bd3c8bSSascha Wildner /* Get rid of USB explore process */ 21412bd3c8bSSascha Wildner 21512bd3c8bSSascha Wildner usb_proc_free(&bus->explore_proc); 21612bd3c8bSSascha Wildner 21712bd3c8bSSascha Wildner /* Get rid of control transfer process */ 21812bd3c8bSSascha Wildner 21912bd3c8bSSascha Wildner usb_proc_free(&bus->control_xfer_proc); 22012bd3c8bSSascha Wildner 22112bd3c8bSSascha Wildner #if USB_HAVE_PF 22212bd3c8bSSascha Wildner usbpf_detach(bus); 22312bd3c8bSSascha Wildner #endif 22412bd3c8bSSascha Wildner return (0); 22512bd3c8bSSascha Wildner } 22612bd3c8bSSascha Wildner 22712bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 22812bd3c8bSSascha Wildner * usb_suspend 22912bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 23012bd3c8bSSascha Wildner static int 23112bd3c8bSSascha Wildner usb_suspend(device_t dev) 23212bd3c8bSSascha Wildner { 23312bd3c8bSSascha Wildner struct usb_bus *bus = device_get_softc(dev); 23412bd3c8bSSascha Wildner 23512bd3c8bSSascha Wildner DPRINTF("\n"); 23612bd3c8bSSascha Wildner 23712bd3c8bSSascha Wildner if (bus == NULL) { 23812bd3c8bSSascha Wildner /* was never setup properly */ 23912bd3c8bSSascha Wildner return (0); 24012bd3c8bSSascha Wildner } 24112bd3c8bSSascha Wildner 24212bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 24312bd3c8bSSascha Wildner usb_proc_msignal(&bus->explore_proc, 24412bd3c8bSSascha Wildner &bus->suspend_msg[0], &bus->suspend_msg[1]); 24512bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 24612bd3c8bSSascha Wildner 24712bd3c8bSSascha Wildner return (0); 24812bd3c8bSSascha Wildner } 24912bd3c8bSSascha Wildner 25012bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 25112bd3c8bSSascha Wildner * usb_resume 25212bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 25312bd3c8bSSascha Wildner static int 25412bd3c8bSSascha Wildner usb_resume(device_t dev) 25512bd3c8bSSascha Wildner { 25612bd3c8bSSascha Wildner struct usb_bus *bus = device_get_softc(dev); 25712bd3c8bSSascha Wildner 25812bd3c8bSSascha Wildner DPRINTF("\n"); 25912bd3c8bSSascha Wildner 26012bd3c8bSSascha Wildner if (bus == NULL) { 26112bd3c8bSSascha Wildner /* was never setup properly */ 26212bd3c8bSSascha Wildner return (0); 26312bd3c8bSSascha Wildner } 26412bd3c8bSSascha Wildner 26512bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 26612bd3c8bSSascha Wildner usb_proc_msignal(&bus->explore_proc, 26712bd3c8bSSascha Wildner &bus->resume_msg[0], &bus->resume_msg[1]); 26812bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 26912bd3c8bSSascha Wildner 27012bd3c8bSSascha Wildner return (0); 27112bd3c8bSSascha Wildner } 27212bd3c8bSSascha Wildner 27312bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 27412bd3c8bSSascha Wildner * usb_shutdown 27512bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 27612bd3c8bSSascha Wildner static int 27712bd3c8bSSascha Wildner usb_shutdown(device_t dev) 27812bd3c8bSSascha Wildner { 27912bd3c8bSSascha Wildner struct usb_bus *bus = device_get_softc(dev); 28012bd3c8bSSascha Wildner 28112bd3c8bSSascha Wildner DPRINTF("\n"); 28212bd3c8bSSascha Wildner 28312bd3c8bSSascha Wildner if (bus == NULL) { 28412bd3c8bSSascha Wildner /* was never setup properly */ 28512bd3c8bSSascha Wildner return (0); 28612bd3c8bSSascha Wildner } 28712bd3c8bSSascha Wildner 28812bd3c8bSSascha Wildner device_printf(bus->bdev, "Controller shutdown\n"); 28912bd3c8bSSascha Wildner 29012bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 29112bd3c8bSSascha Wildner usb_proc_msignal(&bus->explore_proc, 29212bd3c8bSSascha Wildner &bus->shutdown_msg[0], &bus->shutdown_msg[1]); 29312bd3c8bSSascha Wildner if (usb_no_shutdown_wait == 0) { 29412bd3c8bSSascha Wildner /* wait for shutdown callback to be executed */ 29512bd3c8bSSascha Wildner usb_proc_mwait(&bus->explore_proc, 29612bd3c8bSSascha Wildner &bus->shutdown_msg[0], &bus->shutdown_msg[1]); 29712bd3c8bSSascha Wildner } 29812bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 29912bd3c8bSSascha Wildner 30012bd3c8bSSascha Wildner device_printf(bus->bdev, "Controller shutdown complete\n"); 30112bd3c8bSSascha Wildner 30212bd3c8bSSascha Wildner return (0); 30312bd3c8bSSascha Wildner } 30412bd3c8bSSascha Wildner 30512bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 30612bd3c8bSSascha Wildner * usb_bus_explore 30712bd3c8bSSascha Wildner * 30812bd3c8bSSascha Wildner * This function is used to explore the device tree from the root. 30912bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 31012bd3c8bSSascha Wildner static void 31112bd3c8bSSascha Wildner usb_bus_explore(struct usb_proc_msg *pm) 31212bd3c8bSSascha Wildner { 31312bd3c8bSSascha Wildner struct usb_bus *bus; 31412bd3c8bSSascha Wildner struct usb_device *udev; 31512bd3c8bSSascha Wildner 31612bd3c8bSSascha Wildner bus = ((struct usb_bus_msg *)pm)->bus; 31712bd3c8bSSascha Wildner udev = bus->devices[USB_ROOT_HUB_ADDR]; 31812bd3c8bSSascha Wildner 31912bd3c8bSSascha Wildner if (bus->no_explore != 0) 32012bd3c8bSSascha Wildner return; 32112bd3c8bSSascha Wildner 32212bd3c8bSSascha Wildner if (udev && udev->hub) { 32312bd3c8bSSascha Wildner 32412bd3c8bSSascha Wildner if (bus->do_probe) { 32512bd3c8bSSascha Wildner bus->do_probe = 0; 32612bd3c8bSSascha Wildner bus->driver_added_refcount++; 32712bd3c8bSSascha Wildner } 32812bd3c8bSSascha Wildner if (bus->driver_added_refcount == 0) { 32912bd3c8bSSascha Wildner /* avoid zero, hence that is memory default */ 33012bd3c8bSSascha Wildner bus->driver_added_refcount = 1; 33112bd3c8bSSascha Wildner } 33212bd3c8bSSascha Wildner 33312bd3c8bSSascha Wildner #ifdef DDB 33412bd3c8bSSascha Wildner /* 33512bd3c8bSSascha Wildner * The following three lines of code are only here to 33612bd3c8bSSascha Wildner * recover from DDB: 33712bd3c8bSSascha Wildner */ 33812bd3c8bSSascha Wildner usb_proc_rewakeup(&bus->control_xfer_proc); 33912bd3c8bSSascha Wildner usb_proc_rewakeup(&bus->giant_callback_proc); 34012bd3c8bSSascha Wildner usb_proc_rewakeup(&bus->non_giant_callback_proc); 34112bd3c8bSSascha Wildner #endif 34212bd3c8bSSascha Wildner 34312bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 34412bd3c8bSSascha Wildner 34512bd3c8bSSascha Wildner #if USB_HAVE_POWERD 34612bd3c8bSSascha Wildner /* 34712bd3c8bSSascha Wildner * First update the USB power state! 34812bd3c8bSSascha Wildner */ 34912bd3c8bSSascha Wildner usb_bus_powerd(bus); 35012bd3c8bSSascha Wildner #endif 35112bd3c8bSSascha Wildner /* Explore the Root USB HUB. */ 35212bd3c8bSSascha Wildner (udev->hub->explore) (udev); 35312bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 35412bd3c8bSSascha Wildner } 35512bd3c8bSSascha Wildner usb_root_mount_rel(bus); 35612bd3c8bSSascha Wildner } 35712bd3c8bSSascha Wildner 35812bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 35912bd3c8bSSascha Wildner * usb_bus_detach 36012bd3c8bSSascha Wildner * 36112bd3c8bSSascha Wildner * This function is used to detach the device tree from the root. 36212bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 36312bd3c8bSSascha Wildner static void 36412bd3c8bSSascha Wildner usb_bus_detach(struct usb_proc_msg *pm) 36512bd3c8bSSascha Wildner { 36612bd3c8bSSascha Wildner struct usb_bus *bus; 36712bd3c8bSSascha Wildner struct usb_device *udev; 36812bd3c8bSSascha Wildner device_t dev; 36912bd3c8bSSascha Wildner 37012bd3c8bSSascha Wildner bus = ((struct usb_bus_msg *)pm)->bus; 37112bd3c8bSSascha Wildner udev = bus->devices[USB_ROOT_HUB_ADDR]; 37212bd3c8bSSascha Wildner dev = bus->bdev; 37312bd3c8bSSascha Wildner /* clear the softc */ 37412bd3c8bSSascha Wildner device_set_softc(dev, NULL); 37512bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 37612bd3c8bSSascha Wildner 37712bd3c8bSSascha Wildner /* detach children first */ 37812bd3c8bSSascha Wildner bus_generic_detach(dev); 37912bd3c8bSSascha Wildner 38012bd3c8bSSascha Wildner /* 38112bd3c8bSSascha Wildner * Free USB device and all subdevices, if any. 38212bd3c8bSSascha Wildner */ 38312bd3c8bSSascha Wildner usb_free_device(udev, 0); 38412bd3c8bSSascha Wildner 38512bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 38612bd3c8bSSascha Wildner /* clear bdev variable last */ 38712bd3c8bSSascha Wildner bus->bdev = NULL; 38812bd3c8bSSascha Wildner } 38912bd3c8bSSascha Wildner 39012bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 39112bd3c8bSSascha Wildner * usb_bus_suspend 39212bd3c8bSSascha Wildner * 39312bd3c8bSSascha Wildner * This function is used to suspend the USB contoller. 39412bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 39512bd3c8bSSascha Wildner static void 39612bd3c8bSSascha Wildner usb_bus_suspend(struct usb_proc_msg *pm) 39712bd3c8bSSascha Wildner { 39812bd3c8bSSascha Wildner struct usb_bus *bus; 39912bd3c8bSSascha Wildner struct usb_device *udev; 40012bd3c8bSSascha Wildner usb_error_t err; 40112bd3c8bSSascha Wildner 40212bd3c8bSSascha Wildner bus = ((struct usb_bus_msg *)pm)->bus; 40312bd3c8bSSascha Wildner udev = bus->devices[USB_ROOT_HUB_ADDR]; 40412bd3c8bSSascha Wildner 40512bd3c8bSSascha Wildner if (udev == NULL || bus->bdev == NULL) 40612bd3c8bSSascha Wildner return; 40712bd3c8bSSascha Wildner 40812bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 40912bd3c8bSSascha Wildner 41012bd3c8bSSascha Wildner bus_generic_shutdown(bus->bdev); 41112bd3c8bSSascha Wildner 41212bd3c8bSSascha Wildner usbd_enum_lock(udev); 41312bd3c8bSSascha Wildner 41412bd3c8bSSascha Wildner err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX); 41512bd3c8bSSascha Wildner if (err) 41612bd3c8bSSascha Wildner device_printf(bus->bdev, "Could not unconfigure root HUB\n"); 41712bd3c8bSSascha Wildner 41812bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 41912bd3c8bSSascha Wildner bus->hw_power_state = 0; 42012bd3c8bSSascha Wildner bus->no_explore = 1; 42112bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 42212bd3c8bSSascha Wildner 42312bd3c8bSSascha Wildner if (bus->methods->set_hw_power != NULL) 42412bd3c8bSSascha Wildner (bus->methods->set_hw_power) (bus); 42512bd3c8bSSascha Wildner 42612bd3c8bSSascha Wildner if (bus->methods->set_hw_power_sleep != NULL) 42712bd3c8bSSascha Wildner (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SUSPEND); 42812bd3c8bSSascha Wildner 42912bd3c8bSSascha Wildner usbd_enum_unlock(udev); 43012bd3c8bSSascha Wildner 43112bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 43212bd3c8bSSascha Wildner } 43312bd3c8bSSascha Wildner 43412bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 43512bd3c8bSSascha Wildner * usb_bus_resume 43612bd3c8bSSascha Wildner * 43712bd3c8bSSascha Wildner * This function is used to resume the USB contoller. 43812bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 43912bd3c8bSSascha Wildner static void 44012bd3c8bSSascha Wildner usb_bus_resume(struct usb_proc_msg *pm) 44112bd3c8bSSascha Wildner { 44212bd3c8bSSascha Wildner struct usb_bus *bus; 44312bd3c8bSSascha Wildner struct usb_device *udev; 44412bd3c8bSSascha Wildner usb_error_t err; 44512bd3c8bSSascha Wildner 44612bd3c8bSSascha Wildner bus = ((struct usb_bus_msg *)pm)->bus; 44712bd3c8bSSascha Wildner udev = bus->devices[USB_ROOT_HUB_ADDR]; 44812bd3c8bSSascha Wildner 44912bd3c8bSSascha Wildner if (udev == NULL || bus->bdev == NULL) 45012bd3c8bSSascha Wildner return; 45112bd3c8bSSascha Wildner 45212bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 45312bd3c8bSSascha Wildner 45412bd3c8bSSascha Wildner usbd_enum_lock(udev); 45512bd3c8bSSascha Wildner #if 0 45612bd3c8bSSascha Wildner DEVMETHOD(usb_take_controller, NULL); /* dummy */ 45712bd3c8bSSascha Wildner #endif 45812bd3c8bSSascha Wildner USB_TAKE_CONTROLLER(device_get_parent(bus->bdev)); 45912bd3c8bSSascha Wildner 46012bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 46112bd3c8bSSascha Wildner bus->hw_power_state = 46212bd3c8bSSascha Wildner USB_HW_POWER_CONTROL | 46312bd3c8bSSascha Wildner USB_HW_POWER_BULK | 46412bd3c8bSSascha Wildner USB_HW_POWER_INTERRUPT | 46512bd3c8bSSascha Wildner USB_HW_POWER_ISOC | 46612bd3c8bSSascha Wildner USB_HW_POWER_NON_ROOT_HUB; 46712bd3c8bSSascha Wildner bus->no_explore = 0; 46812bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 46912bd3c8bSSascha Wildner 47012bd3c8bSSascha Wildner if (bus->methods->set_hw_power_sleep != NULL) 47112bd3c8bSSascha Wildner (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_RESUME); 47212bd3c8bSSascha Wildner 47312bd3c8bSSascha Wildner if (bus->methods->set_hw_power != NULL) 47412bd3c8bSSascha Wildner (bus->methods->set_hw_power) (bus); 47512bd3c8bSSascha Wildner 47612bd3c8bSSascha Wildner /* restore USB configuration to index 0 */ 47712bd3c8bSSascha Wildner err = usbd_set_config_index(udev, 0); 47812bd3c8bSSascha Wildner if (err) 47912bd3c8bSSascha Wildner device_printf(bus->bdev, "Could not configure root HUB\n"); 48012bd3c8bSSascha Wildner 48112bd3c8bSSascha Wildner /* probe and attach */ 48212bd3c8bSSascha Wildner err = usb_probe_and_attach(udev, USB_IFACE_INDEX_ANY); 48312bd3c8bSSascha Wildner if (err) { 48412bd3c8bSSascha Wildner device_printf(bus->bdev, "Could not probe and " 48512bd3c8bSSascha Wildner "attach root HUB\n"); 48612bd3c8bSSascha Wildner } 48712bd3c8bSSascha Wildner 48812bd3c8bSSascha Wildner usbd_enum_unlock(udev); 48912bd3c8bSSascha Wildner 49012bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 49112bd3c8bSSascha Wildner } 49212bd3c8bSSascha Wildner 49312bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 49412bd3c8bSSascha Wildner * usb_bus_shutdown 49512bd3c8bSSascha Wildner * 49612bd3c8bSSascha Wildner * This function is used to shutdown the USB contoller. 49712bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 49812bd3c8bSSascha Wildner static void 49912bd3c8bSSascha Wildner usb_bus_shutdown(struct usb_proc_msg *pm) 50012bd3c8bSSascha Wildner { 50112bd3c8bSSascha Wildner struct usb_bus *bus; 50212bd3c8bSSascha Wildner struct usb_device *udev; 50312bd3c8bSSascha Wildner usb_error_t err; 50412bd3c8bSSascha Wildner 50512bd3c8bSSascha Wildner bus = ((struct usb_bus_msg *)pm)->bus; 50612bd3c8bSSascha Wildner udev = bus->devices[USB_ROOT_HUB_ADDR]; 50712bd3c8bSSascha Wildner 50812bd3c8bSSascha Wildner if (udev == NULL || bus->bdev == NULL) 50912bd3c8bSSascha Wildner return; 51012bd3c8bSSascha Wildner 51112bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 51212bd3c8bSSascha Wildner 51312bd3c8bSSascha Wildner bus_generic_shutdown(bus->bdev); 51412bd3c8bSSascha Wildner 51512bd3c8bSSascha Wildner usbd_enum_lock(udev); 51612bd3c8bSSascha Wildner 51712bd3c8bSSascha Wildner err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX); 51812bd3c8bSSascha Wildner if (err) 51912bd3c8bSSascha Wildner device_printf(bus->bdev, "Could not unconfigure root HUB\n"); 52012bd3c8bSSascha Wildner 52112bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 52212bd3c8bSSascha Wildner bus->hw_power_state = 0; 52312bd3c8bSSascha Wildner bus->no_explore = 1; 52412bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 52512bd3c8bSSascha Wildner 52612bd3c8bSSascha Wildner if (bus->methods->set_hw_power != NULL) 52712bd3c8bSSascha Wildner (bus->methods->set_hw_power) (bus); 52812bd3c8bSSascha Wildner 52912bd3c8bSSascha Wildner if (bus->methods->set_hw_power_sleep != NULL) 53012bd3c8bSSascha Wildner (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SHUTDOWN); 53112bd3c8bSSascha Wildner 53212bd3c8bSSascha Wildner usbd_enum_unlock(udev); 53312bd3c8bSSascha Wildner 53412bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 53512bd3c8bSSascha Wildner } 53612bd3c8bSSascha Wildner 53712bd3c8bSSascha Wildner static void 53812bd3c8bSSascha Wildner usb_power_wdog(void *arg) 53912bd3c8bSSascha Wildner { 54012bd3c8bSSascha Wildner struct usb_bus *bus = arg; 541722d05c3SSascha Wildner USB_BUS_LOCK_ASSERT(bus); 54212bd3c8bSSascha Wildner 54312bd3c8bSSascha Wildner usb_callout_reset(&bus->power_wdog, 54412bd3c8bSSascha Wildner 4 * hz, usb_power_wdog, arg); 54512bd3c8bSSascha Wildner 54612bd3c8bSSascha Wildner #ifdef DDB 54712bd3c8bSSascha Wildner /* 54812bd3c8bSSascha Wildner * The following line of code is only here to recover from 54912bd3c8bSSascha Wildner * DDB: 55012bd3c8bSSascha Wildner */ 55112bd3c8bSSascha Wildner usb_proc_rewakeup(&bus->explore_proc); /* recover from DDB */ 55212bd3c8bSSascha Wildner #endif 55312bd3c8bSSascha Wildner 55412bd3c8bSSascha Wildner #if USB_HAVE_POWERD 55512bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 55612bd3c8bSSascha Wildner 55712bd3c8bSSascha Wildner usb_bus_power_update(bus); 55812bd3c8bSSascha Wildner 55912bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 56012bd3c8bSSascha Wildner #endif 56112bd3c8bSSascha Wildner } 56212bd3c8bSSascha Wildner 56312bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 56412bd3c8bSSascha Wildner * usb_bus_attach 56512bd3c8bSSascha Wildner * 56612bd3c8bSSascha Wildner * This function attaches USB in context of the explore thread. 56712bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 56812bd3c8bSSascha Wildner static void 56912bd3c8bSSascha Wildner usb_bus_attach(struct usb_proc_msg *pm) 57012bd3c8bSSascha Wildner { 57112bd3c8bSSascha Wildner struct usb_bus *bus; 57212bd3c8bSSascha Wildner struct usb_device *child; 57312bd3c8bSSascha Wildner device_t dev; 57412bd3c8bSSascha Wildner usb_error_t err; 57512bd3c8bSSascha Wildner enum usb_dev_speed speed; 57612bd3c8bSSascha Wildner 57712bd3c8bSSascha Wildner bus = ((struct usb_bus_msg *)pm)->bus; 57812bd3c8bSSascha Wildner dev = bus->bdev; 57912bd3c8bSSascha Wildner 58012bd3c8bSSascha Wildner DPRINTF("\n"); 58112bd3c8bSSascha Wildner 58212bd3c8bSSascha Wildner switch (bus->usbrev) { 58312bd3c8bSSascha Wildner case USB_REV_1_0: 58412bd3c8bSSascha Wildner speed = USB_SPEED_FULL; 58512bd3c8bSSascha Wildner device_printf(bus->bdev, "12Mbps Full Speed USB v1.0\n"); 58612bd3c8bSSascha Wildner break; 58712bd3c8bSSascha Wildner 58812bd3c8bSSascha Wildner case USB_REV_1_1: 58912bd3c8bSSascha Wildner speed = USB_SPEED_FULL; 59012bd3c8bSSascha Wildner device_printf(bus->bdev, "12Mbps Full Speed USB v1.1\n"); 59112bd3c8bSSascha Wildner break; 59212bd3c8bSSascha Wildner 59312bd3c8bSSascha Wildner case USB_REV_2_0: 59412bd3c8bSSascha Wildner speed = USB_SPEED_HIGH; 59512bd3c8bSSascha Wildner device_printf(bus->bdev, "480Mbps High Speed USB v2.0\n"); 59612bd3c8bSSascha Wildner break; 59712bd3c8bSSascha Wildner 59812bd3c8bSSascha Wildner case USB_REV_2_5: 59912bd3c8bSSascha Wildner speed = USB_SPEED_VARIABLE; 60012bd3c8bSSascha Wildner device_printf(bus->bdev, "480Mbps Wireless USB v2.5\n"); 60112bd3c8bSSascha Wildner break; 60212bd3c8bSSascha Wildner 60312bd3c8bSSascha Wildner case USB_REV_3_0: 60412bd3c8bSSascha Wildner speed = USB_SPEED_SUPER; 60512bd3c8bSSascha Wildner device_printf(bus->bdev, "5.0Gbps Super Speed USB v3.0\n"); 60612bd3c8bSSascha Wildner break; 60712bd3c8bSSascha Wildner 60812bd3c8bSSascha Wildner default: 60912bd3c8bSSascha Wildner device_printf(bus->bdev, "Unsupported USB revision\n"); 61012bd3c8bSSascha Wildner usb_root_mount_rel(bus); 61112bd3c8bSSascha Wildner return; 61212bd3c8bSSascha Wildner } 61312bd3c8bSSascha Wildner 61412bd3c8bSSascha Wildner /* default power_mask value */ 61512bd3c8bSSascha Wildner bus->hw_power_state = 61612bd3c8bSSascha Wildner USB_HW_POWER_CONTROL | 61712bd3c8bSSascha Wildner USB_HW_POWER_BULK | 61812bd3c8bSSascha Wildner USB_HW_POWER_INTERRUPT | 61912bd3c8bSSascha Wildner USB_HW_POWER_ISOC | 62012bd3c8bSSascha Wildner USB_HW_POWER_NON_ROOT_HUB; 62112bd3c8bSSascha Wildner 62212bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 62312bd3c8bSSascha Wildner 62412bd3c8bSSascha Wildner /* make sure power is set at least once */ 62512bd3c8bSSascha Wildner 62612bd3c8bSSascha Wildner if (bus->methods->set_hw_power != NULL) { 62712bd3c8bSSascha Wildner (bus->methods->set_hw_power) (bus); 62812bd3c8bSSascha Wildner } 62912bd3c8bSSascha Wildner 63012bd3c8bSSascha Wildner /* allocate the Root USB device */ 63112bd3c8bSSascha Wildner 63212bd3c8bSSascha Wildner child = usb_alloc_device(bus->bdev, bus, NULL, 0, 0, 1, 63312bd3c8bSSascha Wildner speed, USB_MODE_HOST); 63412bd3c8bSSascha Wildner if (child) { 63512bd3c8bSSascha Wildner err = usb_probe_and_attach(child, 63612bd3c8bSSascha Wildner USB_IFACE_INDEX_ANY); 63712bd3c8bSSascha Wildner if (!err) { 63812bd3c8bSSascha Wildner if ((bus->devices[USB_ROOT_HUB_ADDR] == NULL) || 63912bd3c8bSSascha Wildner (bus->devices[USB_ROOT_HUB_ADDR]->hub == NULL)) { 64012bd3c8bSSascha Wildner err = USB_ERR_NO_ROOT_HUB; 64112bd3c8bSSascha Wildner } 64212bd3c8bSSascha Wildner } 64312bd3c8bSSascha Wildner } else { 64412bd3c8bSSascha Wildner err = USB_ERR_NOMEM; 64512bd3c8bSSascha Wildner } 64612bd3c8bSSascha Wildner 64712bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 64812bd3c8bSSascha Wildner 64912bd3c8bSSascha Wildner if (err) { 65012bd3c8bSSascha Wildner device_printf(bus->bdev, "Root HUB problem, error=%s\n", 65112bd3c8bSSascha Wildner usbd_errstr(err)); 65212bd3c8bSSascha Wildner usb_root_mount_rel(bus); 65312bd3c8bSSascha Wildner } 65412bd3c8bSSascha Wildner 65512bd3c8bSSascha Wildner /* set softc - we are ready */ 65612bd3c8bSSascha Wildner device_set_softc(dev, bus); 65712bd3c8bSSascha Wildner 65812bd3c8bSSascha Wildner /* start watchdog */ 65912bd3c8bSSascha Wildner usb_power_wdog(bus); 66012bd3c8bSSascha Wildner } 66112bd3c8bSSascha Wildner 66212bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 66312bd3c8bSSascha Wildner * usb_attach_sub 66412bd3c8bSSascha Wildner * 66512bd3c8bSSascha Wildner * This function creates a thread which runs the USB attach code. 66612bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 66712bd3c8bSSascha Wildner static void 66812bd3c8bSSascha Wildner usb_attach_sub(device_t dev, struct usb_bus *bus) 66912bd3c8bSSascha Wildner { 67012bd3c8bSSascha Wildner const char *pname = device_get_nameunit(dev); 67112bd3c8bSSascha Wildner 67212bd3c8bSSascha Wildner if (usb_devclass_ptr == NULL) 67312bd3c8bSSascha Wildner usb_devclass_ptr = devclass_find("usbus"); 67412bd3c8bSSascha Wildner 67512bd3c8bSSascha Wildner #if USB_HAVE_PF 67612bd3c8bSSascha Wildner usbpf_attach(bus); 67712bd3c8bSSascha Wildner #endif 67812bd3c8bSSascha Wildner /* Initialise USB process messages */ 67912bd3c8bSSascha Wildner bus->explore_msg[0].hdr.pm_callback = &usb_bus_explore; 68012bd3c8bSSascha Wildner bus->explore_msg[0].bus = bus; 68112bd3c8bSSascha Wildner bus->explore_msg[1].hdr.pm_callback = &usb_bus_explore; 68212bd3c8bSSascha Wildner bus->explore_msg[1].bus = bus; 68312bd3c8bSSascha Wildner 68412bd3c8bSSascha Wildner bus->detach_msg[0].hdr.pm_callback = &usb_bus_detach; 68512bd3c8bSSascha Wildner bus->detach_msg[0].bus = bus; 68612bd3c8bSSascha Wildner bus->detach_msg[1].hdr.pm_callback = &usb_bus_detach; 68712bd3c8bSSascha Wildner bus->detach_msg[1].bus = bus; 68812bd3c8bSSascha Wildner 68912bd3c8bSSascha Wildner bus->attach_msg[0].hdr.pm_callback = &usb_bus_attach; 69012bd3c8bSSascha Wildner bus->attach_msg[0].bus = bus; 69112bd3c8bSSascha Wildner bus->attach_msg[1].hdr.pm_callback = &usb_bus_attach; 69212bd3c8bSSascha Wildner bus->attach_msg[1].bus = bus; 69312bd3c8bSSascha Wildner 69412bd3c8bSSascha Wildner bus->suspend_msg[0].hdr.pm_callback = &usb_bus_suspend; 69512bd3c8bSSascha Wildner bus->suspend_msg[0].bus = bus; 69612bd3c8bSSascha Wildner bus->suspend_msg[1].hdr.pm_callback = &usb_bus_suspend; 69712bd3c8bSSascha Wildner bus->suspend_msg[1].bus = bus; 69812bd3c8bSSascha Wildner 69912bd3c8bSSascha Wildner bus->resume_msg[0].hdr.pm_callback = &usb_bus_resume; 70012bd3c8bSSascha Wildner bus->resume_msg[0].bus = bus; 70112bd3c8bSSascha Wildner bus->resume_msg[1].hdr.pm_callback = &usb_bus_resume; 70212bd3c8bSSascha Wildner bus->resume_msg[1].bus = bus; 70312bd3c8bSSascha Wildner 70412bd3c8bSSascha Wildner bus->shutdown_msg[0].hdr.pm_callback = &usb_bus_shutdown; 70512bd3c8bSSascha Wildner bus->shutdown_msg[0].bus = bus; 70612bd3c8bSSascha Wildner bus->shutdown_msg[1].hdr.pm_callback = &usb_bus_shutdown; 70712bd3c8bSSascha Wildner bus->shutdown_msg[1].bus = bus; 70812bd3c8bSSascha Wildner 70912bd3c8bSSascha Wildner /* Create USB explore and callback processes */ 71012bd3c8bSSascha Wildner 71112bd3c8bSSascha Wildner if (usb_proc_create(&bus->giant_callback_proc, 712722d05c3SSascha Wildner &bus->bus_lock, pname, USB_PRI_MED)) { 71312bd3c8bSSascha Wildner device_printf(dev, "WARNING: Creation of USB Giant " 71412bd3c8bSSascha Wildner "callback process failed.\n"); 71512bd3c8bSSascha Wildner } else if (usb_proc_create(&bus->non_giant_callback_proc, 716722d05c3SSascha Wildner &bus->bus_lock, pname, USB_PRI_HIGH)) { 71712bd3c8bSSascha Wildner device_printf(dev, "WARNING: Creation of USB non-Giant " 71812bd3c8bSSascha Wildner "callback process failed.\n"); 71912bd3c8bSSascha Wildner } else if (usb_proc_create(&bus->explore_proc, 720722d05c3SSascha Wildner &bus->bus_lock, pname, USB_PRI_MED)) { 72112bd3c8bSSascha Wildner device_printf(dev, "WARNING: Creation of USB explore " 72212bd3c8bSSascha Wildner "process failed.\n"); 72312bd3c8bSSascha Wildner } else if (usb_proc_create(&bus->control_xfer_proc, 724722d05c3SSascha Wildner &bus->bus_lock, pname, USB_PRI_MED)) { 72512bd3c8bSSascha Wildner device_printf(dev, "WARNING: Creation of USB control transfer " 72612bd3c8bSSascha Wildner "process failed.\n"); 72712bd3c8bSSascha Wildner } else { 72812bd3c8bSSascha Wildner /* Get final attach going */ 72912bd3c8bSSascha Wildner USB_BUS_LOCK(bus); 73012bd3c8bSSascha Wildner usb_proc_msignal(&bus->explore_proc, 73112bd3c8bSSascha Wildner &bus->attach_msg[0], &bus->attach_msg[1]); 73212bd3c8bSSascha Wildner USB_BUS_UNLOCK(bus); 73312bd3c8bSSascha Wildner 73412bd3c8bSSascha Wildner /* Do initial explore */ 73512bd3c8bSSascha Wildner usb_needs_explore(bus, 1); 73612bd3c8bSSascha Wildner } 73712bd3c8bSSascha Wildner } 73812bd3c8bSSascha Wildner 739722d05c3SSascha Wildner SYSUNINIT(usb_bus_unload, SI_SUB_CONFIGURE, SI_ORDER_ANY, usb_bus_unload, NULL); 74012bd3c8bSSascha Wildner 74112bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 74212bd3c8bSSascha Wildner * usb_bus_mem_flush_all_cb 74312bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 74412bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA 74512bd3c8bSSascha Wildner static void 74612bd3c8bSSascha Wildner usb_bus_mem_flush_all_cb(struct usb_bus *bus, struct usb_page_cache *pc, 74712bd3c8bSSascha Wildner struct usb_page *pg, usb_size_t size, usb_size_t align) 74812bd3c8bSSascha Wildner { 74912bd3c8bSSascha Wildner usb_pc_cpu_flush(pc); 75012bd3c8bSSascha Wildner } 75112bd3c8bSSascha Wildner #endif 75212bd3c8bSSascha Wildner 75312bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 75412bd3c8bSSascha Wildner * usb_bus_mem_flush_all - factored out code 75512bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 75612bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA 75712bd3c8bSSascha Wildner void 75812bd3c8bSSascha Wildner usb_bus_mem_flush_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb) 75912bd3c8bSSascha Wildner { 76012bd3c8bSSascha Wildner if (cb) { 76112bd3c8bSSascha Wildner cb(bus, &usb_bus_mem_flush_all_cb); 76212bd3c8bSSascha Wildner } 76312bd3c8bSSascha Wildner } 76412bd3c8bSSascha Wildner #endif 76512bd3c8bSSascha Wildner 76612bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 76712bd3c8bSSascha Wildner * usb_bus_mem_alloc_all_cb 76812bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 76912bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA 77012bd3c8bSSascha Wildner static void 77112bd3c8bSSascha Wildner usb_bus_mem_alloc_all_cb(struct usb_bus *bus, struct usb_page_cache *pc, 77212bd3c8bSSascha Wildner struct usb_page *pg, usb_size_t size, usb_size_t align) 77312bd3c8bSSascha Wildner { 77412bd3c8bSSascha Wildner /* need to initialize the page cache */ 77512bd3c8bSSascha Wildner pc->tag_parent = bus->dma_parent_tag; 77612bd3c8bSSascha Wildner 77712bd3c8bSSascha Wildner if (usb_pc_alloc_mem(pc, pg, size, align)) { 77812bd3c8bSSascha Wildner bus->alloc_failed = 1; 77912bd3c8bSSascha Wildner } 78012bd3c8bSSascha Wildner } 78112bd3c8bSSascha Wildner #endif 78212bd3c8bSSascha Wildner 78312bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 78412bd3c8bSSascha Wildner * usb_bus_mem_alloc_all - factored out code 78512bd3c8bSSascha Wildner * 78612bd3c8bSSascha Wildner * Returns: 78712bd3c8bSSascha Wildner * 0: Success 78812bd3c8bSSascha Wildner * Else: Failure 78912bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 79012bd3c8bSSascha Wildner uint8_t 79112bd3c8bSSascha Wildner usb_bus_mem_alloc_all(struct usb_bus *bus, bus_dma_tag_t dmat, 79212bd3c8bSSascha Wildner usb_bus_mem_cb_t *cb) 79312bd3c8bSSascha Wildner { 79412bd3c8bSSascha Wildner bus->alloc_failed = 0; 795*63da4a34SSascha Wildner 796722d05c3SSascha Wildner lockinit(&bus->bus_lock, "USB bus mem", 0, LK_CANRECURSE); 79712bd3c8bSSascha Wildner 79812bd3c8bSSascha Wildner usb_callout_init_mtx(&bus->power_wdog, 799722d05c3SSascha Wildner &bus->bus_lock, 0); 80012bd3c8bSSascha Wildner 80112bd3c8bSSascha Wildner TAILQ_INIT(&bus->intr_q.head); 80212bd3c8bSSascha Wildner 80312bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA 80412bd3c8bSSascha Wildner usb_dma_tag_setup(bus->dma_parent_tag, bus->dma_tags, 805722d05c3SSascha Wildner dmat, &bus->bus_lock, NULL, 32, USB_BUS_DMA_TAG_MAX); 80612bd3c8bSSascha Wildner #endif 80712bd3c8bSSascha Wildner if ((bus->devices_max > USB_MAX_DEVICES) || 80812bd3c8bSSascha Wildner (bus->devices_max < USB_MIN_DEVICES) || 80912bd3c8bSSascha Wildner (bus->devices == NULL)) { 81012bd3c8bSSascha Wildner DPRINTFN(0, "Devices field has not been " 81112bd3c8bSSascha Wildner "initialised properly\n"); 81212bd3c8bSSascha Wildner bus->alloc_failed = 1; /* failure */ 81312bd3c8bSSascha Wildner } 81412bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA 81512bd3c8bSSascha Wildner if (cb) { 81612bd3c8bSSascha Wildner cb(bus, &usb_bus_mem_alloc_all_cb); 81712bd3c8bSSascha Wildner } 81812bd3c8bSSascha Wildner #endif 81912bd3c8bSSascha Wildner if (bus->alloc_failed) { 82012bd3c8bSSascha Wildner usb_bus_mem_free_all(bus, cb); 82112bd3c8bSSascha Wildner } 82212bd3c8bSSascha Wildner return (bus->alloc_failed); 82312bd3c8bSSascha Wildner } 82412bd3c8bSSascha Wildner 82512bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 82612bd3c8bSSascha Wildner * usb_bus_mem_free_all_cb 82712bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 82812bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA 82912bd3c8bSSascha Wildner static void 83012bd3c8bSSascha Wildner usb_bus_mem_free_all_cb(struct usb_bus *bus, struct usb_page_cache *pc, 83112bd3c8bSSascha Wildner struct usb_page *pg, usb_size_t size, usb_size_t align) 83212bd3c8bSSascha Wildner { 83312bd3c8bSSascha Wildner usb_pc_free_mem(pc); 83412bd3c8bSSascha Wildner } 83512bd3c8bSSascha Wildner #endif 83612bd3c8bSSascha Wildner 83712bd3c8bSSascha Wildner /*------------------------------------------------------------------------* 83812bd3c8bSSascha Wildner * usb_bus_mem_free_all - factored out code 83912bd3c8bSSascha Wildner *------------------------------------------------------------------------*/ 84012bd3c8bSSascha Wildner void 84112bd3c8bSSascha Wildner usb_bus_mem_free_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb) 84212bd3c8bSSascha Wildner { 84312bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA 84412bd3c8bSSascha Wildner if (cb) { 84512bd3c8bSSascha Wildner cb(bus, &usb_bus_mem_free_all_cb); 84612bd3c8bSSascha Wildner } 84712bd3c8bSSascha Wildner usb_dma_tag_unsetup(bus->dma_parent_tag); 84812bd3c8bSSascha Wildner #endif 84912bd3c8bSSascha Wildner 850722d05c3SSascha Wildner lockuninit(&bus->bus_lock); 85112bd3c8bSSascha Wildner } 852