1d71896a7SEmmanuel Vadot /*- 2d3f13132SWarner Losh * Copyright (c) 2016 Emmanuel Vadot <manu@freebsd.org> All rights reserved. 3*f86e6000SWarner Losh * Copyright (c) 2006 M. Warner Losh <imp@FreeBSD.org> 4d71896a7SEmmanuel Vadot * 5d71896a7SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 6d71896a7SEmmanuel Vadot * modification, are permitted provided that the following conditions 7d71896a7SEmmanuel Vadot * are met: 8d71896a7SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 9d71896a7SEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 10d71896a7SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 11d71896a7SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 12d71896a7SEmmanuel Vadot * documentation and/or other materials provided with the distribution. 13d71896a7SEmmanuel Vadot * 14d71896a7SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15d71896a7SEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16d71896a7SEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17d71896a7SEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18d71896a7SEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19d71896a7SEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20d71896a7SEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21d71896a7SEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22d71896a7SEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23d71896a7SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24d71896a7SEmmanuel Vadot * SUCH DAMAGE. 25d71896a7SEmmanuel Vadot */ 26d71896a7SEmmanuel Vadot 27d71896a7SEmmanuel Vadot /* 28d71896a7SEmmanuel Vadot * Generic OHCI driver based on AT91 OHCI 29d71896a7SEmmanuel Vadot */ 30d71896a7SEmmanuel Vadot 31d71896a7SEmmanuel Vadot #include <sys/cdefs.h> 32d71896a7SEmmanuel Vadot __FBSDID("$FreeBSD$"); 33d71896a7SEmmanuel Vadot 34d71896a7SEmmanuel Vadot #include <sys/param.h> 35d71896a7SEmmanuel Vadot #include <sys/systm.h> 36d71896a7SEmmanuel Vadot #include <sys/bus.h> 37d71896a7SEmmanuel Vadot #include <sys/rman.h> 38d71896a7SEmmanuel Vadot #include <sys/condvar.h> 39d71896a7SEmmanuel Vadot #include <sys/kernel.h> 40d71896a7SEmmanuel Vadot #include <sys/module.h> 41d71896a7SEmmanuel Vadot 42d71896a7SEmmanuel Vadot #include <machine/bus.h> 43d71896a7SEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 44d71896a7SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 45d71896a7SEmmanuel Vadot 46d71896a7SEmmanuel Vadot #include <dev/usb/usb.h> 47d71896a7SEmmanuel Vadot #include <dev/usb/usbdi.h> 48d71896a7SEmmanuel Vadot 49d71896a7SEmmanuel Vadot #include <dev/usb/usb_core.h> 50d71896a7SEmmanuel Vadot #include <dev/usb/usb_busdma.h> 51d71896a7SEmmanuel Vadot #include <dev/usb/usb_process.h> 52d71896a7SEmmanuel Vadot #include <dev/usb/usb_util.h> 53d71896a7SEmmanuel Vadot 54d71896a7SEmmanuel Vadot #include <dev/usb/usb_controller.h> 55d71896a7SEmmanuel Vadot #include <dev/usb/usb_bus.h> 56d71896a7SEmmanuel Vadot #include <dev/usb/controller/ohci.h> 57d71896a7SEmmanuel Vadot #include <dev/usb/controller/ohcireg.h> 58d71896a7SEmmanuel Vadot 59d71896a7SEmmanuel Vadot #ifdef EXT_RESOURCES 60d71896a7SEmmanuel Vadot #include <dev/extres/clk/clk.h> 61d71896a7SEmmanuel Vadot #include <dev/extres/hwreset/hwreset.h> 62627c360fSJared McNeill #include <dev/extres/phy/phy.h> 63150c95edSEmmanuel Vadot #include <dev/extres/phy/phy_usb.h> 64d71896a7SEmmanuel Vadot #endif 65d71896a7SEmmanuel Vadot 66d71896a7SEmmanuel Vadot #include "generic_usb_if.h" 67d71896a7SEmmanuel Vadot 68d71896a7SEmmanuel Vadot #ifdef EXT_RESOURCES 69d71896a7SEmmanuel Vadot struct clk_list { 70d71896a7SEmmanuel Vadot TAILQ_ENTRY(clk_list) next; 71d71896a7SEmmanuel Vadot clk_t clk; 72d71896a7SEmmanuel Vadot }; 73150c95edSEmmanuel Vadot struct phy_list { 74150c95edSEmmanuel Vadot TAILQ_ENTRY(phy_list) next; 75150c95edSEmmanuel Vadot phy_t phy; 76150c95edSEmmanuel Vadot }; 77150c95edSEmmanuel Vadot struct hwrst_list { 78150c95edSEmmanuel Vadot TAILQ_ENTRY(hwrst_list) next; 79150c95edSEmmanuel Vadot hwreset_t rst; 80150c95edSEmmanuel Vadot }; 81d71896a7SEmmanuel Vadot #endif 82d71896a7SEmmanuel Vadot 83d71896a7SEmmanuel Vadot struct generic_ohci_softc { 84d71896a7SEmmanuel Vadot ohci_softc_t ohci_sc; 85d71896a7SEmmanuel Vadot 86d71896a7SEmmanuel Vadot #ifdef EXT_RESOURCES 87d71896a7SEmmanuel Vadot TAILQ_HEAD(, clk_list) clk_list; 88150c95edSEmmanuel Vadot TAILQ_HEAD(, phy_list) phy_list; 89150c95edSEmmanuel Vadot TAILQ_HEAD(, hwrst_list) rst_list; 90d71896a7SEmmanuel Vadot #endif 91d71896a7SEmmanuel Vadot }; 92d71896a7SEmmanuel Vadot 93d71896a7SEmmanuel Vadot static int generic_ohci_detach(device_t); 94d71896a7SEmmanuel Vadot 95d71896a7SEmmanuel Vadot static int 96d71896a7SEmmanuel Vadot generic_ohci_probe(device_t dev) 97d71896a7SEmmanuel Vadot { 98d71896a7SEmmanuel Vadot 99d71896a7SEmmanuel Vadot if (!ofw_bus_status_okay(dev)) 100d71896a7SEmmanuel Vadot return (ENXIO); 101d71896a7SEmmanuel Vadot 102d71896a7SEmmanuel Vadot if (!ofw_bus_is_compatible(dev, "generic-ohci")) 103d71896a7SEmmanuel Vadot return (ENXIO); 104d71896a7SEmmanuel Vadot 105d71896a7SEmmanuel Vadot device_set_desc(dev, "Generic OHCI Controller"); 106d71896a7SEmmanuel Vadot 107d71896a7SEmmanuel Vadot return (BUS_PROBE_DEFAULT); 108d71896a7SEmmanuel Vadot } 109d71896a7SEmmanuel Vadot 110d71896a7SEmmanuel Vadot static int 111d71896a7SEmmanuel Vadot generic_ohci_attach(device_t dev) 112d71896a7SEmmanuel Vadot { 113d71896a7SEmmanuel Vadot struct generic_ohci_softc *sc = device_get_softc(dev); 114d71896a7SEmmanuel Vadot int err, rid; 115d71896a7SEmmanuel Vadot #ifdef EXT_RESOURCES 116d71896a7SEmmanuel Vadot int off; 117d71896a7SEmmanuel Vadot struct clk_list *clkp; 118150c95edSEmmanuel Vadot struct phy_list *phyp; 119150c95edSEmmanuel Vadot struct hwrst_list *rstp; 120d71896a7SEmmanuel Vadot clk_t clk; 121150c95edSEmmanuel Vadot phy_t phy; 122150c95edSEmmanuel Vadot hwreset_t rst; 123d71896a7SEmmanuel Vadot #endif 124d71896a7SEmmanuel Vadot 125d71896a7SEmmanuel Vadot sc->ohci_sc.sc_bus.parent = dev; 126d71896a7SEmmanuel Vadot sc->ohci_sc.sc_bus.devices = sc->ohci_sc.sc_devices; 127d71896a7SEmmanuel Vadot sc->ohci_sc.sc_bus.devices_max = OHCI_MAX_DEVICES; 128d71896a7SEmmanuel Vadot sc->ohci_sc.sc_bus.dma_bits = 32; 129d71896a7SEmmanuel Vadot 130d71896a7SEmmanuel Vadot /* get all DMA memory */ 131d71896a7SEmmanuel Vadot if (usb_bus_mem_alloc_all(&sc->ohci_sc.sc_bus, 132d71896a7SEmmanuel Vadot USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) { 133d71896a7SEmmanuel Vadot return (ENOMEM); 134d71896a7SEmmanuel Vadot } 135d71896a7SEmmanuel Vadot 136d71896a7SEmmanuel Vadot rid = 0; 137d71896a7SEmmanuel Vadot sc->ohci_sc.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 138d71896a7SEmmanuel Vadot &rid, RF_ACTIVE); 139d71896a7SEmmanuel Vadot if (sc->ohci_sc.sc_io_res == 0) { 140d71896a7SEmmanuel Vadot err = ENOMEM; 141d71896a7SEmmanuel Vadot goto error; 142d71896a7SEmmanuel Vadot } 143d71896a7SEmmanuel Vadot 144d71896a7SEmmanuel Vadot sc->ohci_sc.sc_io_tag = rman_get_bustag(sc->ohci_sc.sc_io_res); 145d71896a7SEmmanuel Vadot sc->ohci_sc.sc_io_hdl = rman_get_bushandle(sc->ohci_sc.sc_io_res); 146d71896a7SEmmanuel Vadot sc->ohci_sc.sc_io_size = rman_get_size(sc->ohci_sc.sc_io_res); 147d71896a7SEmmanuel Vadot 148d71896a7SEmmanuel Vadot rid = 0; 149d71896a7SEmmanuel Vadot sc->ohci_sc.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 150d71896a7SEmmanuel Vadot RF_ACTIVE); 151d71896a7SEmmanuel Vadot if (sc->ohci_sc.sc_irq_res == 0) { 152d71896a7SEmmanuel Vadot err = ENXIO; 153d71896a7SEmmanuel Vadot goto error; 154d71896a7SEmmanuel Vadot } 155d71896a7SEmmanuel Vadot sc->ohci_sc.sc_bus.bdev = device_add_child(dev, "usbus", -1); 156d71896a7SEmmanuel Vadot if (sc->ohci_sc.sc_bus.bdev == 0) { 157d71896a7SEmmanuel Vadot err = ENXIO; 158d71896a7SEmmanuel Vadot goto error; 159d71896a7SEmmanuel Vadot } 160d71896a7SEmmanuel Vadot device_set_ivars(sc->ohci_sc.sc_bus.bdev, &sc->ohci_sc.sc_bus); 161d71896a7SEmmanuel Vadot 162d71896a7SEmmanuel Vadot strlcpy(sc->ohci_sc.sc_vendor, "Generic", 163d71896a7SEmmanuel Vadot sizeof(sc->ohci_sc.sc_vendor)); 164d71896a7SEmmanuel Vadot 165d71896a7SEmmanuel Vadot err = bus_setup_intr(dev, sc->ohci_sc.sc_irq_res, 166d71896a7SEmmanuel Vadot INTR_TYPE_BIO | INTR_MPSAFE, NULL, 167d71896a7SEmmanuel Vadot (driver_intr_t *)ohci_interrupt, sc, &sc->ohci_sc.sc_intr_hdl); 168d71896a7SEmmanuel Vadot if (err) { 169d71896a7SEmmanuel Vadot sc->ohci_sc.sc_intr_hdl = NULL; 170d71896a7SEmmanuel Vadot goto error; 171d71896a7SEmmanuel Vadot } 172d71896a7SEmmanuel Vadot 173d71896a7SEmmanuel Vadot #ifdef EXT_RESOURCES 174d71896a7SEmmanuel Vadot TAILQ_INIT(&sc->clk_list); 175d71896a7SEmmanuel Vadot /* Enable clock */ 176dac93553SMichal Meloun for (off = 0; clk_get_by_ofw_index(dev, 0, off, &clk) == 0; off++) { 177d71896a7SEmmanuel Vadot err = clk_enable(clk); 178d71896a7SEmmanuel Vadot if (err != 0) { 179d71896a7SEmmanuel Vadot device_printf(dev, "Could not enable clock %s\n", 180d71896a7SEmmanuel Vadot clk_get_name(clk)); 181d71896a7SEmmanuel Vadot goto error; 182d71896a7SEmmanuel Vadot } 1836e2392aeSHans Petter Selasky clkp = malloc(sizeof(*clkp), M_DEVBUF, M_WAITOK | M_ZERO); 184d71896a7SEmmanuel Vadot clkp->clk = clk; 185d71896a7SEmmanuel Vadot TAILQ_INSERT_TAIL(&sc->clk_list, clkp, next); 186d71896a7SEmmanuel Vadot } 187d71896a7SEmmanuel Vadot 188d71896a7SEmmanuel Vadot /* De-assert reset */ 189150c95edSEmmanuel Vadot TAILQ_INIT(&sc->rst_list); 190150c95edSEmmanuel Vadot for (off = 0; hwreset_get_by_ofw_idx(dev, 0, off, &rst) == 0; off++) { 191150c95edSEmmanuel Vadot err = hwreset_deassert(rst); 192d71896a7SEmmanuel Vadot if (err != 0) { 193150c95edSEmmanuel Vadot device_printf(dev, "Could not de-assert reset\n"); 194d71896a7SEmmanuel Vadot goto error; 195d71896a7SEmmanuel Vadot } 196150c95edSEmmanuel Vadot rstp = malloc(sizeof(*rstp), M_DEVBUF, M_WAITOK | M_ZERO); 197150c95edSEmmanuel Vadot rstp->rst = rst; 198150c95edSEmmanuel Vadot TAILQ_INSERT_TAIL(&sc->rst_list, rstp, next); 199d71896a7SEmmanuel Vadot } 200627c360fSJared McNeill 201627c360fSJared McNeill /* Enable phy */ 202150c95edSEmmanuel Vadot TAILQ_INIT(&sc->phy_list); 203150c95edSEmmanuel Vadot for (off = 0; phy_get_by_ofw_idx(dev, 0, off, &phy) == 0; off++) { 204150c95edSEmmanuel Vadot err = phy_usb_set_mode(phy, PHY_USB_MODE_HOST); 205150c95edSEmmanuel Vadot if (err != 0) { 206150c95edSEmmanuel Vadot device_printf(dev, "Could not set phy to host mode\n"); 207150c95edSEmmanuel Vadot goto error; 208150c95edSEmmanuel Vadot } 209150c95edSEmmanuel Vadot err = phy_enable(phy); 210627c360fSJared McNeill if (err != 0) { 211627c360fSJared McNeill device_printf(dev, "Could not enable phy\n"); 212627c360fSJared McNeill goto error; 213627c360fSJared McNeill } 214150c95edSEmmanuel Vadot phyp = malloc(sizeof(*phyp), M_DEVBUF, M_WAITOK | M_ZERO); 215150c95edSEmmanuel Vadot phyp->phy = phy; 216150c95edSEmmanuel Vadot TAILQ_INSERT_TAIL(&sc->phy_list, phyp, next); 217627c360fSJared McNeill } 218d71896a7SEmmanuel Vadot #endif 219d71896a7SEmmanuel Vadot 220d71896a7SEmmanuel Vadot if (GENERIC_USB_INIT(dev) != 0) { 221d71896a7SEmmanuel Vadot err = ENXIO; 222d71896a7SEmmanuel Vadot goto error; 223d71896a7SEmmanuel Vadot } 224d71896a7SEmmanuel Vadot 225d71896a7SEmmanuel Vadot err = ohci_init(&sc->ohci_sc); 226d71896a7SEmmanuel Vadot if (err == 0) 227d71896a7SEmmanuel Vadot err = device_probe_and_attach(sc->ohci_sc.sc_bus.bdev); 228d71896a7SEmmanuel Vadot if (err) 229d71896a7SEmmanuel Vadot goto error; 230d71896a7SEmmanuel Vadot 231d71896a7SEmmanuel Vadot return (0); 232d71896a7SEmmanuel Vadot error: 233d71896a7SEmmanuel Vadot generic_ohci_detach(dev); 234d71896a7SEmmanuel Vadot return (err); 235d71896a7SEmmanuel Vadot } 236d71896a7SEmmanuel Vadot 237d71896a7SEmmanuel Vadot static int 238d71896a7SEmmanuel Vadot generic_ohci_detach(device_t dev) 239d71896a7SEmmanuel Vadot { 240d71896a7SEmmanuel Vadot struct generic_ohci_softc *sc = device_get_softc(dev); 241d71896a7SEmmanuel Vadot int err; 242d71896a7SEmmanuel Vadot #ifdef EXT_RESOURCES 243d71896a7SEmmanuel Vadot struct clk_list *clk, *clk_tmp; 244150c95edSEmmanuel Vadot struct phy_list *phy, *phy_tmp; 245150c95edSEmmanuel Vadot struct hwrst_list *rst, *rst_tmp; 246d71896a7SEmmanuel Vadot #endif 247d71896a7SEmmanuel Vadot 248d71896a7SEmmanuel Vadot /* during module unload there are lots of children leftover */ 249d71896a7SEmmanuel Vadot device_delete_children(dev); 250d71896a7SEmmanuel Vadot 251d71896a7SEmmanuel Vadot /* 252d71896a7SEmmanuel Vadot * Put the controller into reset, then disable clocks and do 253d71896a7SEmmanuel Vadot * the MI tear down. We have to disable the clocks/hardware 254d71896a7SEmmanuel Vadot * after we do the rest of the teardown. We also disable the 255d71896a7SEmmanuel Vadot * clocks in the opposite order we acquire them, but that 256d71896a7SEmmanuel Vadot * doesn't seem to be absolutely necessary. We free up the 257d71896a7SEmmanuel Vadot * clocks after we disable them, so the system could, in 258d71896a7SEmmanuel Vadot * theory, reuse them. 259d71896a7SEmmanuel Vadot */ 260d71896a7SEmmanuel Vadot bus_space_write_4(sc->ohci_sc.sc_io_tag, sc->ohci_sc.sc_io_hdl, 261d71896a7SEmmanuel Vadot OHCI_CONTROL, 0); 262d71896a7SEmmanuel Vadot 263d71896a7SEmmanuel Vadot if (sc->ohci_sc.sc_irq_res && sc->ohci_sc.sc_intr_hdl) { 264d71896a7SEmmanuel Vadot /* 265d71896a7SEmmanuel Vadot * only call ohci_detach() after ohci_init() 266d71896a7SEmmanuel Vadot */ 267d71896a7SEmmanuel Vadot ohci_detach(&sc->ohci_sc); 268d71896a7SEmmanuel Vadot 269d71896a7SEmmanuel Vadot err = bus_teardown_intr(dev, sc->ohci_sc.sc_irq_res, 270d71896a7SEmmanuel Vadot sc->ohci_sc.sc_intr_hdl); 271d71896a7SEmmanuel Vadot sc->ohci_sc.sc_intr_hdl = NULL; 272d71896a7SEmmanuel Vadot } 273d71896a7SEmmanuel Vadot if (sc->ohci_sc.sc_irq_res) { 274d71896a7SEmmanuel Vadot bus_release_resource(dev, SYS_RES_IRQ, 0, 275d71896a7SEmmanuel Vadot sc->ohci_sc.sc_irq_res); 276d71896a7SEmmanuel Vadot sc->ohci_sc.sc_irq_res = NULL; 277d71896a7SEmmanuel Vadot } 278d71896a7SEmmanuel Vadot if (sc->ohci_sc.sc_io_res) { 279d71896a7SEmmanuel Vadot bus_release_resource(dev, SYS_RES_MEMORY, 0, 280d71896a7SEmmanuel Vadot sc->ohci_sc.sc_io_res); 281d71896a7SEmmanuel Vadot sc->ohci_sc.sc_io_res = NULL; 282d71896a7SEmmanuel Vadot } 283d71896a7SEmmanuel Vadot usb_bus_mem_free_all(&sc->ohci_sc.sc_bus, &ohci_iterate_hw_softc); 284d71896a7SEmmanuel Vadot 285d71896a7SEmmanuel Vadot #ifdef EXT_RESOURCES 286627c360fSJared McNeill /* Disable phy */ 287150c95edSEmmanuel Vadot TAILQ_FOREACH_SAFE(phy, &sc->phy_list, next, phy_tmp) { 288150c95edSEmmanuel Vadot err = phy_disable(phy->phy); 289627c360fSJared McNeill if (err != 0) 290627c360fSJared McNeill device_printf(dev, "Could not disable phy\n"); 291150c95edSEmmanuel Vadot phy_release(phy->phy); 292150c95edSEmmanuel Vadot TAILQ_REMOVE(&sc->phy_list, phy, next); 293150c95edSEmmanuel Vadot free(phy, M_DEVBUF); 294150c95edSEmmanuel Vadot } 295150c95edSEmmanuel Vadot 296150c95edSEmmanuel Vadot /* Assert reset */ 297150c95edSEmmanuel Vadot TAILQ_FOREACH_SAFE(rst, &sc->rst_list, next, rst_tmp) { 298150c95edSEmmanuel Vadot hwreset_assert(rst->rst); 299150c95edSEmmanuel Vadot hwreset_release(rst->rst); 300150c95edSEmmanuel Vadot TAILQ_REMOVE(&sc->rst_list, rst, next); 301150c95edSEmmanuel Vadot free(rst, M_DEVBUF); 302627c360fSJared McNeill } 303627c360fSJared McNeill 304d71896a7SEmmanuel Vadot /* Disable clock */ 305d71896a7SEmmanuel Vadot TAILQ_FOREACH_SAFE(clk, &sc->clk_list, next, clk_tmp) { 306d71896a7SEmmanuel Vadot err = clk_disable(clk->clk); 307d71896a7SEmmanuel Vadot if (err != 0) 308d71896a7SEmmanuel Vadot device_printf(dev, "Could not disable clock %s\n", 309d71896a7SEmmanuel Vadot clk_get_name(clk->clk)); 310d71896a7SEmmanuel Vadot err = clk_release(clk->clk); 311d71896a7SEmmanuel Vadot if (err != 0) 312d71896a7SEmmanuel Vadot device_printf(dev, "Could not release clock %s\n", 313d71896a7SEmmanuel Vadot clk_get_name(clk->clk)); 314d71896a7SEmmanuel Vadot TAILQ_REMOVE(&sc->clk_list, clk, next); 315d71896a7SEmmanuel Vadot free(clk, M_DEVBUF); 316d71896a7SEmmanuel Vadot } 317d71896a7SEmmanuel Vadot #endif 318d71896a7SEmmanuel Vadot 319d71896a7SEmmanuel Vadot if (GENERIC_USB_DEINIT(dev) != 0) 320d71896a7SEmmanuel Vadot return (ENXIO); 321d71896a7SEmmanuel Vadot 322d71896a7SEmmanuel Vadot return (0); 323d71896a7SEmmanuel Vadot } 324d71896a7SEmmanuel Vadot 325d71896a7SEmmanuel Vadot static device_method_t generic_ohci_methods[] = { 326d71896a7SEmmanuel Vadot /* Device interface */ 327d71896a7SEmmanuel Vadot DEVMETHOD(device_probe, generic_ohci_probe), 328d71896a7SEmmanuel Vadot DEVMETHOD(device_attach, generic_ohci_attach), 329d71896a7SEmmanuel Vadot DEVMETHOD(device_detach, generic_ohci_detach), 330d71896a7SEmmanuel Vadot 331d71896a7SEmmanuel Vadot DEVMETHOD(device_suspend, bus_generic_suspend), 332d71896a7SEmmanuel Vadot DEVMETHOD(device_resume, bus_generic_resume), 333d71896a7SEmmanuel Vadot DEVMETHOD(device_shutdown, bus_generic_shutdown), 334d71896a7SEmmanuel Vadot 335d71896a7SEmmanuel Vadot DEVMETHOD_END 336d71896a7SEmmanuel Vadot }; 337d71896a7SEmmanuel Vadot 338d71896a7SEmmanuel Vadot driver_t generic_ohci_driver = { 339d71896a7SEmmanuel Vadot .name = "ohci", 340d71896a7SEmmanuel Vadot .methods = generic_ohci_methods, 341d71896a7SEmmanuel Vadot .size = sizeof(struct generic_ohci_softc), 342d71896a7SEmmanuel Vadot }; 343d71896a7SEmmanuel Vadot 344d71896a7SEmmanuel Vadot static devclass_t generic_ohci_devclass; 345d71896a7SEmmanuel Vadot 346d71896a7SEmmanuel Vadot DRIVER_MODULE(ohci, simplebus, generic_ohci_driver, 347d71896a7SEmmanuel Vadot generic_ohci_devclass, 0, 0); 348d71896a7SEmmanuel Vadot MODULE_DEPEND(ohci, usb, 1, 1, 1); 349