ar71xx_ohci.c revision 191086
1188884Sgonzo/*- 2188884Sgonzo * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 3188884Sgonzo * All rights reserved. 4188884Sgonzo * 5188884Sgonzo * Redistribution and use in source and binary forms, with or without 6188884Sgonzo * modification, are permitted provided that the following conditions 7188884Sgonzo * are met: 8188884Sgonzo * 1. Redistributions of source code must retain the above copyright 9188884Sgonzo * notice unmodified, this list of conditions, and the following 10188884Sgonzo * disclaimer. 11188884Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 12188884Sgonzo * notice, this list of conditions and the following disclaimer in the 13188884Sgonzo * documentation and/or other materials provided with the distribution. 14188884Sgonzo * 15188884Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16188884Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17188884Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18188884Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19188884Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20188884Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21188884Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22188884Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23188884Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24188884Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25188884Sgonzo * SUCH DAMAGE. 26188884Sgonzo */ 27188884Sgonzo 28188884Sgonzo#include <sys/cdefs.h> 29188884Sgonzo__FBSDID("$FreeBSD$"); 30188884Sgonzo 31191086Sgonzo#include <dev/usb/usb_mfunc.h> 32188884Sgonzo#include <dev/usb/usb.h> 33188884Sgonzo 34191086Sgonzo#include <dev/usb/usb_core.h> 35191086Sgonzo#include <dev/usb/usb_busdma.h> 36191086Sgonzo#include <dev/usb/usb_process.h> 37191086Sgonzo#include <dev/usb/usb_util.h> 38188884Sgonzo 39191086Sgonzo#include <dev/usb/usb_controller.h> 40191086Sgonzo#include <dev/usb/usb_bus.h> 41191086Sgonzo#include <dev/usb/controller/ohci.h> 42191086Sgonzo 43191086Sgonzo#include <sys/rman.h> 44191086Sgonzo 45188884Sgonzostatic int ar71xx_ohci_attach(device_t dev); 46188884Sgonzostatic int ar71xx_ohci_detach(device_t dev); 47188884Sgonzostatic int ar71xx_ohci_probe(device_t dev); 48188884Sgonzo 49188884Sgonzostruct ar71xx_ohci_softc 50188884Sgonzo{ 51188884Sgonzo struct ohci_softc sc_ohci; 52188884Sgonzo}; 53188884Sgonzo 54188884Sgonzostatic int 55188884Sgonzoar71xx_ohci_probe(device_t dev) 56188884Sgonzo{ 57188884Sgonzo device_set_desc(dev, "AR71XX integrated OHCI controller"); 58188884Sgonzo return (BUS_PROBE_DEFAULT); 59188884Sgonzo} 60188884Sgonzo 61188884Sgonzostatic int 62188884Sgonzoar71xx_ohci_attach(device_t dev) 63188884Sgonzo{ 64188884Sgonzo struct ar71xx_ohci_softc *sc = device_get_softc(dev); 65188884Sgonzo int err; 66188884Sgonzo int rid; 67188884Sgonzo 68188884Sgonzo rid = 0; 69191086Sgonzo sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 70188884Sgonzo RF_ACTIVE); 71191086Sgonzo if (sc->sc_ohci.sc_io_res == NULL) { 72188884Sgonzo err = ENOMEM; 73188884Sgonzo goto error; 74188884Sgonzo } 75191086Sgonzo sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res); 76191086Sgonzo sc->sc_ohci.sc_io_hdl = rman_get_bushandle(sc->sc_ohci.sc_io_res); 77191086Sgonzo sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res); 78188884Sgonzo 79188884Sgonzo rid = 0; 80191086Sgonzo sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 81188884Sgonzo RF_ACTIVE); 82191086Sgonzo if (sc->sc_ohci.sc_irq_res == NULL) { 83188884Sgonzo err = ENOMEM; 84188884Sgonzo goto error; 85188884Sgonzo } 86188884Sgonzo sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usb", -1); 87188884Sgonzo if (sc->sc_ohci.sc_bus.bdev == NULL) { 88188884Sgonzo err = ENOMEM; 89188884Sgonzo goto error; 90188884Sgonzo } 91188884Sgonzo device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus); 92188884Sgonzo 93191086Sgonzo err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, 94191086Sgonzo INTR_TYPE_BIO | INTR_MPSAFE, NULL, 95191086Sgonzo (driver_intr_t *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); 96188884Sgonzo if (err) { 97188884Sgonzo err = ENXIO; 98188884Sgonzo goto error; 99188884Sgonzo } 100188884Sgonzo 101191086Sgonzo strlcpy(sc->sc_ohci.sc_vendor, "Atheros", sizeof(sc->sc_ohci.sc_vendor)); 102188884Sgonzo 103191086Sgonzo bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, OHCI_CONTROL, 0); 104188884Sgonzo 105188884Sgonzo err = ohci_init(&sc->sc_ohci); 106188884Sgonzo if (!err) { 107188884Sgonzo err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev); 108188884Sgonzo } 109188884Sgonzo 110188884Sgonzoerror: 111188884Sgonzo if (err) { 112188884Sgonzo ar71xx_ohci_detach(dev); 113188884Sgonzo return (err); 114188884Sgonzo } 115188884Sgonzo return (err); 116188884Sgonzo} 117188884Sgonzo 118188884Sgonzostatic int 119188884Sgonzoar71xx_ohci_detach(device_t dev) 120188884Sgonzo{ 121188884Sgonzo struct ar71xx_ohci_softc *sc = device_get_softc(dev); 122188884Sgonzo 123191086Sgonzo if (sc->sc_ohci.sc_intr_hdl) { 124191086Sgonzo bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, sc->sc_ohci.sc_intr_hdl); 125191086Sgonzo sc->sc_ohci.sc_intr_hdl = NULL; 126188884Sgonzo } 127188884Sgonzo if (sc->sc_ohci.sc_bus.bdev) { 128188884Sgonzo device_delete_child(dev, sc->sc_ohci.sc_bus.bdev); 129188884Sgonzo sc->sc_ohci.sc_bus.bdev = NULL; 130188884Sgonzo } 131191086Sgonzo if (sc->sc_ohci.sc_irq_res) { 132191086Sgonzo bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res); 133191086Sgonzo sc->sc_ohci.sc_irq_res = NULL; 134188884Sgonzo } 135191086Sgonzo if (sc->sc_ohci.sc_io_res) { 136191086Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_ohci.sc_io_res); 137191086Sgonzo sc->sc_ohci.sc_io_res = NULL; 138191086Sgonzo sc->sc_ohci.sc_io_tag = 0; 139191086Sgonzo sc->sc_ohci.sc_io_hdl = 0; 140188884Sgonzo } 141188884Sgonzo return (0); 142188884Sgonzo} 143188884Sgonzo 144188884Sgonzostatic device_method_t ohci_methods[] = { 145188884Sgonzo /* Device interface */ 146188884Sgonzo DEVMETHOD(device_probe, ar71xx_ohci_probe), 147188884Sgonzo DEVMETHOD(device_attach, ar71xx_ohci_attach), 148188884Sgonzo DEVMETHOD(device_detach, ar71xx_ohci_detach), 149188884Sgonzo DEVMETHOD(device_shutdown, bus_generic_shutdown), 150188884Sgonzo 151188884Sgonzo /* Bus interface */ 152188884Sgonzo DEVMETHOD(bus_print_child, bus_generic_print_child), 153188884Sgonzo 154188884Sgonzo {0, 0} 155188884Sgonzo}; 156188884Sgonzo 157188884Sgonzostatic driver_t ohci_driver = { 158188884Sgonzo "ohci", 159188884Sgonzo ohci_methods, 160188884Sgonzo sizeof(struct ar71xx_ohci_softc), 161188884Sgonzo}; 162188884Sgonzo 163188884Sgonzostatic devclass_t ohci_devclass; 164188884Sgonzo 165188884SgonzoDRIVER_MODULE(ohci, apb, ohci_driver, ohci_devclass, 0, 0); 166