uss820dci_atmelarm.c revision 184824
1#include <sys/cdefs.h> 2__FBSDID("$FreeBSD: head/sys/dev/usb2/controller/uss820dci_atmelarm.c 184824 2008-11-10 20:54:31Z thompsa $"); 3 4/*- 5 * Copyright (c) 2008 Hans Petter Selasky <hselasky@freebsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <dev/usb2/include/usb2_mfunc.h> 31#include <dev/usb2/include/usb2_defs.h> 32#include <dev/usb2/include/usb2_standard.h> 33 34#include <dev/usb2/core/usb2_core.h> 35#include <dev/usb2/core/usb2_busdma.h> 36#include <dev/usb2/core/usb2_process.h> 37#include <dev/usb2/core/usb2_config_td.h> 38#include <dev/usb2/core/usb2_sw_transfer.h> 39#include <dev/usb2/core/usb2_util.h> 40 41#include <dev/usb2/controller/usb2_controller.h> 42#include <dev/usb2/controller/usb2_bus.h> 43#include <dev/usb2/controller/uss820dci.h> 44 45#include <sys/rman.h> 46 47static device_probe_t uss820_atmelarm_probe; 48static device_attach_t uss820_atmelarm_attach; 49static device_detach_t uss820_atmelarm_detach; 50static device_suspend_t uss820_atmelarm_suspend; 51static device_resume_t uss820_atmelarm_resume; 52static device_shutdown_t uss820_atmelarm_shutdown; 53 54static device_method_t uss820dci_methods[] = { 55 /* Device interface */ 56 DEVMETHOD(device_probe, uss820_atmelarm_probe), 57 DEVMETHOD(device_attach, uss820_atmelarm_attach), 58 DEVMETHOD(device_detach, uss820_atmelarm_detach), 59 DEVMETHOD(device_suspend, uss820_atmelarm_suspend), 60 DEVMETHOD(device_resume, uss820_atmelarm_resume), 61 DEVMETHOD(device_shutdown, uss820_atmelarm_shutdown), 62 63 /* Bus interface */ 64 DEVMETHOD(bus_print_child, bus_generic_print_child), 65 66 {0, 0} 67}; 68 69static driver_t uss820dci_driver = { 70 .name = "uss820", 71 .methods = uss820dci_methods, 72 .size = sizeof(struct uss820dci_softc), 73}; 74 75static devclass_t uss820dci_devclass; 76 77DRIVER_MODULE(uss820, atmelarm, uss820dci_driver, uss820dci_devclass, 0, 0); 78MODULE_DEPEND(uss820, usb2_controller, 1, 1, 1); 79MODULE_DEPEND(uss820, usb2_core, 1, 1, 1); 80 81static const char *const uss820_desc = "USS820 USB Device Controller"; 82 83static int 84uss820_atmelarm_suspend(device_t dev) 85{ 86 struct uss820dci_softc *sc = device_get_softc(dev); 87 int err; 88 89 err = bus_generic_suspend(dev); 90 if (err == 0) { 91 uss820dci_suspend(sc); 92 } 93 return (err); 94} 95 96static int 97uss820_atmelarm_resume(device_t dev) 98{ 99 struct uss820dci_softc *sc = device_get_softc(dev); 100 int err; 101 102 uss820dci_resume(sc); 103 104 err = bus_generic_resume(dev); 105 106 return (err); 107} 108 109static int 110uss820_atmelarm_shutdown(device_t dev) 111{ 112 struct uss820dci_softc *sc = device_get_softc(dev); 113 int err; 114 115 err = bus_generic_shutdown(dev); 116 if (err) 117 return (err); 118 119 uss820dci_uninit(sc); 120 121 return (0); 122} 123 124static int 125uss820_atmelarm_probe(device_t dev) 126{ 127 device_set_desc(dev, uss820_desc); 128 return (0); /* success */ 129} 130 131static int 132uss820_atmelarm_attach(device_t dev) 133{ 134 struct uss820dci_softc *sc = device_get_softc(dev); 135 int err; 136 int rid; 137 138 if (sc == NULL) { 139 return (ENXIO); 140 } 141 /* get all DMA memory */ 142 143 if (usb2_bus_mem_alloc_all(&sc->sc_bus, 144 USB_GET_DMA_TAG(dev), NULL)) { 145 return (ENOMEM); 146 } 147 rid = 0; 148 sc->sc_io_res = 149 bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 150 151 if (!sc->sc_io_res) { 152 goto error; 153 } 154 sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 155 sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 156 sc->sc_io_size = rman_get_size(sc->sc_io_res); 157 158 /* multiply all addresses by 4 */ 159 sc->sc_reg_shift = 2; 160 161 rid = 0; 162 sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 163 RF_SHAREABLE | RF_ACTIVE); 164 if (sc->sc_irq_res == NULL) { 165 goto error; 166 } 167 sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); 168 if (!(sc->sc_bus.bdev)) { 169 goto error; 170 } 171 device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 172 173 err = usb2_config_td_setup(&sc->sc_config_td, sc, 174 &sc->sc_bus.bus_mtx, NULL, 0, 4); 175 if (err) { 176 device_printf(dev, "could not setup config thread!\n"); 177 goto error; 178 } 179#if (__FreeBSD_version >= 700031) 180 err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 181 NULL, (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); 182#else 183 err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 184 (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); 185#endif 186 if (err) { 187 sc->sc_intr_hdl = NULL; 188 goto error; 189 } 190 err = uss820dci_init(sc); 191 if (err) { 192 device_printf(dev, "Init failed\n"); 193 goto error; 194 } 195 err = device_probe_and_attach(sc->sc_bus.bdev); 196 if (err) { 197 device_printf(dev, "USB probe and attach failed\n"); 198 goto error; 199 } 200 return (0); 201 202error: 203 uss820_atmelarm_detach(dev); 204 return (ENXIO); 205} 206 207static int 208uss820_atmelarm_detach(device_t dev) 209{ 210 struct uss820dci_softc *sc = device_get_softc(dev); 211 device_t bdev; 212 int err; 213 214 if (sc->sc_bus.bdev) { 215 bdev = sc->sc_bus.bdev; 216 device_detach(bdev); 217 device_delete_child(dev, bdev); 218 } 219 /* during module unload there are lots of children leftover */ 220 device_delete_all_children(dev); 221 222 if (sc->sc_irq_res && sc->sc_intr_hdl) { 223 /* 224 * only call at91_udp_uninit() after at91_udp_init() 225 */ 226 uss820dci_uninit(sc); 227 228 err = bus_teardown_intr(dev, sc->sc_irq_res, 229 sc->sc_intr_hdl); 230 sc->sc_intr_hdl = NULL; 231 } 232 if (sc->sc_irq_res) { 233 bus_release_resource(dev, SYS_RES_IRQ, 0, 234 sc->sc_irq_res); 235 sc->sc_irq_res = NULL; 236 } 237 if (sc->sc_io_res) { 238 bus_release_resource(dev, SYS_RES_IOPORT, 0, 239 sc->sc_io_res); 240 sc->sc_io_res = NULL; 241 } 242 usb2_config_td_unsetup(&sc->sc_config_td); 243 244 usb2_bus_mem_free_all(&sc->sc_bus, NULL); 245 246 return (0); 247} 248