1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD$"); 3184610Salfred 4184610Salfred/*- 5189002Sed * Copyright (c) 2008 Hans Petter Selasky <hselasky@FreeBSD.org> 6184610Salfred * All rights reserved. 7184610Salfred * 8184610Salfred * Redistribution and use in source and binary forms, with or without 9184610Salfred * modification, are permitted provided that the following conditions 10184610Salfred * are met: 11184610Salfred * 1. Redistributions of source code must retain the above copyright 12184610Salfred * notice, this list of conditions and the following disclaimer. 13184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 14184610Salfred * notice, this list of conditions and the following disclaimer in the 15184610Salfred * documentation and/or other materials provided with the distribution. 16184610Salfred * 17184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27184610Salfred * SUCH DAMAGE. 28184610Salfred */ 29184610Salfred 30194677Sthompsa#include <sys/stdint.h> 31194677Sthompsa#include <sys/stddef.h> 32194677Sthompsa#include <sys/param.h> 33194677Sthompsa#include <sys/queue.h> 34194677Sthompsa#include <sys/types.h> 35194677Sthompsa#include <sys/systm.h> 36194677Sthompsa#include <sys/kernel.h> 37194677Sthompsa#include <sys/bus.h> 38194677Sthompsa#include <sys/module.h> 39194677Sthompsa#include <sys/lock.h> 40194677Sthompsa#include <sys/mutex.h> 41194677Sthompsa#include <sys/condvar.h> 42194677Sthompsa#include <sys/sysctl.h> 43194677Sthompsa#include <sys/sx.h> 44194677Sthompsa#include <sys/unistd.h> 45194677Sthompsa#include <sys/callout.h> 46194677Sthompsa#include <sys/malloc.h> 47194677Sthompsa#include <sys/priv.h> 48194677Sthompsa 49188942Sthompsa#include <dev/usb/usb.h> 50194677Sthompsa#include <dev/usb/usbdi.h> 51184610Salfred 52188942Sthompsa#include <dev/usb/usb_core.h> 53188942Sthompsa#include <dev/usb/usb_busdma.h> 54188942Sthompsa#include <dev/usb/usb_process.h> 55188942Sthompsa#include <dev/usb/usb_util.h> 56184610Salfred 57188942Sthompsa#include <dev/usb/usb_controller.h> 58188942Sthompsa#include <dev/usb/usb_bus.h> 59188942Sthompsa#include <dev/usb/controller/uss820dci.h> 60184610Salfred 61184610Salfred#include <sys/rman.h> 62184610Salfred 63184610Salfredstatic device_probe_t uss820_atmelarm_probe; 64184610Salfredstatic device_attach_t uss820_atmelarm_attach; 65184610Salfredstatic device_detach_t uss820_atmelarm_detach; 66184610Salfred 67184610Salfredstatic device_method_t uss820dci_methods[] = { 68184610Salfred /* Device interface */ 69184610Salfred DEVMETHOD(device_probe, uss820_atmelarm_probe), 70184610Salfred DEVMETHOD(device_attach, uss820_atmelarm_attach), 71184610Salfred DEVMETHOD(device_detach, uss820_atmelarm_detach), 72228483Shselasky DEVMETHOD(device_suspend, bus_generic_suspend), 73228483Shselasky DEVMETHOD(device_resume, bus_generic_resume), 74228483Shselasky DEVMETHOD(device_shutdown, bus_generic_shutdown), 75184610Salfred 76227843Smarius DEVMETHOD_END 77184610Salfred}; 78184610Salfred 79184610Salfredstatic driver_t uss820dci_driver = { 80184610Salfred .name = "uss820", 81184610Salfred .methods = uss820dci_methods, 82184610Salfred .size = sizeof(struct uss820dci_softc), 83184610Salfred}; 84184610Salfred 85184610Salfredstatic devclass_t uss820dci_devclass; 86184610Salfred 87184610SalfredDRIVER_MODULE(uss820, atmelarm, uss820dci_driver, uss820dci_devclass, 0, 0); 88188942SthompsaMODULE_DEPEND(uss820, usb, 1, 1, 1); 89184610Salfred 90184610Salfredstatic const char *const uss820_desc = "USS820 USB Device Controller"; 91184610Salfred 92184610Salfredstatic int 93184610Salfreduss820_atmelarm_probe(device_t dev) 94184610Salfred{ 95184610Salfred device_set_desc(dev, uss820_desc); 96184610Salfred return (0); /* success */ 97184610Salfred} 98184610Salfred 99184610Salfredstatic int 100184610Salfreduss820_atmelarm_attach(device_t dev) 101184610Salfred{ 102184610Salfred struct uss820dci_softc *sc = device_get_softc(dev); 103184610Salfred int err; 104184610Salfred int rid; 105184610Salfred 106187170Sthompsa /* initialise some bus fields */ 107186439Sthompsa sc->sc_bus.parent = dev; 108187170Sthompsa sc->sc_bus.devices = sc->sc_devices; 109187170Sthompsa sc->sc_bus.devices_max = USS820_MAX_DEVICES; 110187170Sthompsa 111187170Sthompsa /* get all DMA memory */ 112194228Sthompsa if (usb_bus_mem_alloc_all(&sc->sc_bus, 113184610Salfred USB_GET_DMA_TAG(dev), NULL)) { 114184610Salfred return (ENOMEM); 115184610Salfred } 116184610Salfred rid = 0; 117184610Salfred sc->sc_io_res = 118184610Salfred bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 119184610Salfred 120184610Salfred if (!sc->sc_io_res) { 121184610Salfred goto error; 122184610Salfred } 123184610Salfred sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 124184610Salfred sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 125184610Salfred sc->sc_io_size = rman_get_size(sc->sc_io_res); 126184610Salfred 127184610Salfred rid = 0; 128184610Salfred sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 129184610Salfred RF_SHAREABLE | RF_ACTIVE); 130184610Salfred if (sc->sc_irq_res == NULL) { 131184610Salfred goto error; 132184610Salfred } 133184610Salfred sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); 134184610Salfred if (!(sc->sc_bus.bdev)) { 135184610Salfred goto error; 136184610Salfred } 137184610Salfred device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 138184610Salfred 139184610Salfred#if (__FreeBSD_version >= 700031) 140184610Salfred err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 141190183Sthompsa NULL, (driver_intr_t *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); 142184610Salfred#else 143184610Salfred err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 144190183Sthompsa (driver_intr_t *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); 145184610Salfred#endif 146184610Salfred if (err) { 147184610Salfred sc->sc_intr_hdl = NULL; 148184610Salfred goto error; 149184610Salfred } 150184610Salfred err = uss820dci_init(sc); 151184610Salfred if (err) { 152184610Salfred device_printf(dev, "Init failed\n"); 153184610Salfred goto error; 154184610Salfred } 155184610Salfred err = device_probe_and_attach(sc->sc_bus.bdev); 156184610Salfred if (err) { 157184610Salfred device_printf(dev, "USB probe and attach failed\n"); 158184610Salfred goto error; 159184610Salfred } 160184610Salfred return (0); 161184610Salfred 162184610Salfrederror: 163184610Salfred uss820_atmelarm_detach(dev); 164184610Salfred return (ENXIO); 165184610Salfred} 166184610Salfred 167184610Salfredstatic int 168184610Salfreduss820_atmelarm_detach(device_t dev) 169184610Salfred{ 170184610Salfred struct uss820dci_softc *sc = device_get_softc(dev); 171184610Salfred device_t bdev; 172184610Salfred int err; 173184610Salfred 174184610Salfred if (sc->sc_bus.bdev) { 175184610Salfred bdev = sc->sc_bus.bdev; 176184610Salfred device_detach(bdev); 177184610Salfred device_delete_child(dev, bdev); 178184610Salfred } 179184610Salfred /* during module unload there are lots of children leftover */ 180227849Shselasky device_delete_children(dev); 181184610Salfred 182184610Salfred if (sc->sc_irq_res && sc->sc_intr_hdl) { 183184610Salfred /* 184184610Salfred * only call at91_udp_uninit() after at91_udp_init() 185184610Salfred */ 186184610Salfred uss820dci_uninit(sc); 187184610Salfred 188184610Salfred err = bus_teardown_intr(dev, sc->sc_irq_res, 189184610Salfred sc->sc_intr_hdl); 190184610Salfred sc->sc_intr_hdl = NULL; 191184610Salfred } 192184610Salfred if (sc->sc_irq_res) { 193184610Salfred bus_release_resource(dev, SYS_RES_IRQ, 0, 194184610Salfred sc->sc_irq_res); 195184610Salfred sc->sc_irq_res = NULL; 196184610Salfred } 197184610Salfred if (sc->sc_io_res) { 198184610Salfred bus_release_resource(dev, SYS_RES_IOPORT, 0, 199184610Salfred sc->sc_io_res); 200184610Salfred sc->sc_io_res = NULL; 201184610Salfred } 202194228Sthompsa usb_bus_mem_free_all(&sc->sc_bus, NULL); 203184610Salfred 204184610Salfred return (0); 205184610Salfred} 206