uss820dci_atmelarm.c revision 308402
1169689Skan#include <sys/cdefs.h> 2169689Skan__FBSDID("$FreeBSD: stable/10/sys/dev/usb/controller/uss820dci_atmelarm.c 308402 2016-11-07 09:19:04Z hselasky $"); 3169689Skan 4169689Skan/*- 5169689Skan * Copyright (c) 2008 Hans Petter Selasky <hselasky@FreeBSD.org> 6169689Skan * All rights reserved. 7169689Skan * 8169689Skan * Redistribution and use in source and binary forms, with or without 9169689Skan * modification, are permitted provided that the following conditions 10169689Skan * are met: 11169689Skan * 1. Redistributions of source code must retain the above copyright 12169689Skan * notice, this list of conditions and the following disclaimer. 13169689Skan * 2. Redistributions in binary form must reproduce the above copyright 14169689Skan * notice, this list of conditions and the following disclaimer in the 15169689Skan * documentation and/or other materials provided with the distribution. 16169689Skan * 17169689Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20169689Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27169689Skan * SUCH DAMAGE. 28169689Skan */ 29169689Skan 30169689Skan#include <sys/stdint.h> 31169689Skan#include <sys/stddef.h> 32169689Skan#include <sys/param.h> 33169689Skan#include <sys/queue.h> 34169689Skan#include <sys/types.h> 35169689Skan#include <sys/systm.h> 36169689Skan#include <sys/kernel.h> 37169689Skan#include <sys/bus.h> 38169689Skan#include <sys/module.h> 39169689Skan#include <sys/lock.h> 40169689Skan#include <sys/mutex.h> 41169689Skan#include <sys/condvar.h> 42169689Skan#include <sys/sysctl.h> 43169689Skan#include <sys/sx.h> 44169689Skan#include <sys/unistd.h> 45169689Skan#include <sys/callout.h> 46169689Skan#include <sys/malloc.h> 47169689Skan#include <sys/priv.h> 48169689Skan 49169689Skan#include <dev/usb/usb.h> 50169689Skan#include <dev/usb/usbdi.h> 51169689Skan 52169689Skan#include <dev/usb/usb_core.h> 53169689Skan#include <dev/usb/usb_busdma.h> 54169689Skan#include <dev/usb/usb_process.h> 55169689Skan#include <dev/usb/usb_util.h> 56169689Skan 57169689Skan#include <dev/usb/usb_controller.h> 58169689Skan#include <dev/usb/usb_bus.h> 59169689Skan#include <dev/usb/controller/uss820dci.h> 60169689Skan 61169689Skan#include <sys/rman.h> 62169689Skan 63169689Skanstatic device_probe_t uss820_atmelarm_probe; 64169689Skanstatic device_attach_t uss820_atmelarm_attach; 65169689Skanstatic device_detach_t uss820_atmelarm_detach; 66169689Skan 67169689Skanstatic device_method_t uss820dci_methods[] = { 68169689Skan /* Device interface */ 69169689Skan DEVMETHOD(device_probe, uss820_atmelarm_probe), 70169689Skan DEVMETHOD(device_attach, uss820_atmelarm_attach), 71169689Skan DEVMETHOD(device_detach, uss820_atmelarm_detach), 72169689Skan DEVMETHOD(device_suspend, bus_generic_suspend), 73169689Skan DEVMETHOD(device_resume, bus_generic_resume), 74169689Skan DEVMETHOD(device_shutdown, bus_generic_shutdown), 75169689Skan 76169689Skan DEVMETHOD_END 77169689Skan}; 78169689Skan 79169689Skanstatic driver_t uss820dci_driver = { 80169689Skan .name = "uss820dci", 81169689Skan .methods = uss820dci_methods, 82169689Skan .size = sizeof(struct uss820dci_softc), 83169689Skan}; 84169689Skan 85169689Skanstatic devclass_t uss820dci_devclass; 86169689Skan 87169689SkanDRIVER_MODULE(uss820dci, atmelarm, uss820dci_driver, uss820dci_devclass, 0, 0); 88169689SkanMODULE_DEPEND(uss820dci, usb, 1, 1, 1); 89169689Skan 90169689Skanstatic const char *const uss820_desc = "USS820 USB Device Controller"; 91169689Skan 92169689Skanstatic int 93169689Skanuss820_atmelarm_probe(device_t dev) 94169689Skan{ 95169689Skan device_set_desc(dev, uss820_desc); 96169689Skan return (0); /* success */ 97169689Skan} 98169689Skan 99169689Skanstatic int 100169689Skanuss820_atmelarm_attach(device_t dev) 101169689Skan{ 102169689Skan struct uss820dci_softc *sc = device_get_softc(dev); 103169689Skan int err; 104169689Skan int rid; 105169689Skan 106169689Skan /* initialise some bus fields */ 107169689Skan sc->sc_bus.parent = dev; 108169689Skan sc->sc_bus.devices = sc->sc_devices; 109169689Skan sc->sc_bus.devices_max = USS820_MAX_DEVICES; 110169689Skan sc->sc_bus.dma_bits = 32; 111169689Skan 112169689Skan /* get all DMA memory */ 113169689Skan if (usb_bus_mem_alloc_all(&sc->sc_bus, 114169689Skan USB_GET_DMA_TAG(dev), NULL)) { 115169689Skan return (ENOMEM); 116169689Skan } 117169689Skan rid = 0; 118169689Skan sc->sc_io_res = 119169689Skan bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 120169689Skan 121169689Skan if (!sc->sc_io_res) { 122169689Skan goto error; 123169689Skan } 124169689Skan sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 125169689Skan sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 126169689Skan sc->sc_io_size = rman_get_size(sc->sc_io_res); 127169689Skan 128169689Skan rid = 0; 129169689Skan sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 130169689Skan RF_SHAREABLE | RF_ACTIVE); 131169689Skan if (sc->sc_irq_res == NULL) { 132169689Skan goto error; 133169689Skan } 134169689Skan sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); 135169689Skan if (!(sc->sc_bus.bdev)) { 136169689Skan goto error; 137169689Skan } 138169689Skan device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 139169689Skan 140169689Skan#if (__FreeBSD_version >= 700031) 141169689Skan err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 142169689Skan NULL, (driver_intr_t *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); 143169689Skan#else 144169689Skan err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 145169689Skan (driver_intr_t *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); 146169689Skan#endif 147169689Skan if (err) { 148169689Skan sc->sc_intr_hdl = NULL; 149169689Skan goto error; 150169689Skan } 151169689Skan err = uss820dci_init(sc); 152169689Skan if (err) { 153169689Skan device_printf(dev, "Init failed\n"); 154169689Skan goto error; 155169689Skan } 156169689Skan err = device_probe_and_attach(sc->sc_bus.bdev); 157169689Skan if (err) { 158169689Skan device_printf(dev, "USB probe and attach failed\n"); 159169689Skan goto error; 160169689Skan } 161169689Skan return (0); 162169689Skan 163169689Skanerror: 164169689Skan uss820_atmelarm_detach(dev); 165169689Skan return (ENXIO); 166169689Skan} 167169689Skan 168169689Skanstatic int 169169689Skanuss820_atmelarm_detach(device_t dev) 170169689Skan{ 171169689Skan struct uss820dci_softc *sc = device_get_softc(dev); 172169689Skan int err; 173169689Skan 174169689Skan /* during module unload there are lots of children leftover */ 175169689Skan device_delete_children(dev); 176169689Skan 177169689Skan if (sc->sc_irq_res && sc->sc_intr_hdl) { 178169689Skan /* 179169689Skan * only call at91_udp_uninit() after at91_udp_init() 180169689Skan */ 181169689Skan uss820dci_uninit(sc); 182169689Skan 183169689Skan err = bus_teardown_intr(dev, sc->sc_irq_res, 184169689Skan sc->sc_intr_hdl); 185169689Skan sc->sc_intr_hdl = NULL; 186169689Skan } 187169689Skan if (sc->sc_irq_res) { 188169689Skan bus_release_resource(dev, SYS_RES_IRQ, 0, 189169689Skan sc->sc_irq_res); 190169689Skan sc->sc_irq_res = NULL; 191169689Skan } 192169689Skan if (sc->sc_io_res) { 193169689Skan bus_release_resource(dev, SYS_RES_IOPORT, 0, 194169689Skan sc->sc_io_res); 195169689Skan sc->sc_io_res = NULL; 196169689Skan } 197169689Skan usb_bus_mem_free_all(&sc->sc_bus, NULL); 198169689Skan 199169689Skan return (0); 200169689Skan} 201169689Skan