/*- * Copyright (C) 2012 Margarida Gouveia * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pic_if.h" static int wiipic_probe(device_t); static int wiipic_attach(device_t); static void wiipic_dispatch(device_t, struct trapframe *); static void wiipic_enable(device_t, unsigned int, unsigned int); static void wiipic_eoi(device_t, unsigned int); static void wiipic_mask(device_t, unsigned int); static void wiipic_unmask(device_t, unsigned int); static void wiipic_intr(void *); struct wiipic_softc { device_t sc_dev; struct resource *sc_rres; bus_space_tag_t sc_bt; bus_space_handle_t sc_bh; int sc_rrid; int sc_irqid; struct resource *sc_irq; void *sc_irqctx; int sc_vector[WIIPIC_NIRQ]; }; static device_method_t wiipic_methods[] = { /* Device interface */ DEVMETHOD(device_probe, wiipic_probe), DEVMETHOD(device_attach, wiipic_attach), /* PIC interface */ DEVMETHOD(pic_dispatch, wiipic_dispatch), DEVMETHOD(pic_enable, wiipic_enable), DEVMETHOD(pic_eoi, wiipic_eoi), DEVMETHOD(pic_mask, wiipic_mask), DEVMETHOD(pic_unmask, wiipic_unmask), DEVMETHOD_END }; static driver_t wiipic_driver = { "wiipic", wiipic_methods, sizeof(struct wiipic_softc) }; static devclass_t wiipic_devclass; DRIVER_MODULE(wiipic, wiibus, wiipic_driver, wiipic_devclass, 0, 0); static __inline uint32_t wiipic_imr_read(struct wiipic_softc *sc) { return (bus_space_read_4(sc->sc_bt, sc->sc_bh, WIIPIC_IMR)); } static __inline void wiipic_imr_write(struct wiipic_softc *sc, uint32_t imr) { bus_space_write_4(sc->sc_bt, sc->sc_bh, WIIPIC_IMR, imr); } static __inline uint32_t wiipic_icr_read(struct wiipic_softc *sc) { return (bus_space_read_4(sc->sc_bt, sc->sc_bh, WIIPIC_ICR)); } static __inline void wiipic_icr_write(struct wiipic_softc *sc, uint32_t icr) { bus_space_write_4(sc->sc_bt, sc->sc_bh, WIIPIC_ICR, icr); } static int wiipic_probe(device_t dev) { device_set_desc(dev, "Nintendo Wii PIC"); return (BUS_PROBE_NOWILDCARD); } static int wiipic_attach(device_t dev) { struct wiipic_softc *sc; sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_rrid = 0; sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid, RF_ACTIVE); if (sc->sc_rres == NULL) { device_printf(dev, "could not alloc mem resource\n"); return (ENXIO); } sc->sc_bt = rman_get_bustag(sc->sc_rres); sc->sc_bh = rman_get_bushandle(sc->sc_rres); /* Turn off all interrupts */ wiipic_imr_write(sc, 0x00000000); wiipic_icr_write(sc, 0xffffffff); powerpc_register_pic(dev, 0, WIIPIC_NIRQ, 0, FALSE); /* * Setup the interrupt handler. */ sc->sc_irqid = 0; sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid, RF_ACTIVE); if (sc->sc_irq == NULL) { device_printf(dev, "could not alloc IRQ resource\n"); return (ENXIO); } bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE, NULL, wiipic_intr, sc, &sc->sc_irqctx); return (0); } static void wiipic_dispatch(device_t dev, struct trapframe *tf) { struct wiipic_softc *sc; uint32_t irq; sc = device_get_softc(dev); irq = wiipic_icr_read(sc) & wiipic_imr_read(sc); if (irq == 0) return; irq = ffs(irq) - 1; KASSERT(irq < WIIPIC_NIRQ, ("bogus irq %d", irq)); powerpc_dispatch_intr(sc->sc_vector[irq], tf); } static void wiipic_enable(device_t dev, unsigned int irq, unsigned int vector) { struct wiipic_softc *sc; KASSERT(irq < WIIPIC_NIRQ, ("bogus irq %d", irq)); sc = device_get_softc(dev); sc->sc_vector[irq] = vector; wiipic_unmask(dev, irq); } static void wiipic_eoi(device_t dev, unsigned int irq) { struct wiipic_softc *sc; uint32_t icr; sc = device_get_softc(dev); icr = wiipic_icr_read(sc); icr |= (1 << irq); wiipic_icr_write(sc, icr); } static void wiipic_mask(device_t dev, unsigned int irq) { struct wiipic_softc *sc; uint32_t imr; sc = device_get_softc(dev); imr = wiipic_imr_read(sc); imr &= ~(1 << irq); wiipic_imr_write(sc, imr); } static void wiipic_unmask(device_t dev, unsigned int irq) { struct wiipic_softc *sc; uint32_t imr; sc = device_get_softc(dev); imr = wiipic_imr_read(sc); imr |= (1 << irq); wiipic_imr_write(sc, imr); } /* * Reset button interrupt. */ static void wiipic_intr(void *xsc) { struct wiipic_softc *sc; sc = (struct wiipic_softc *)xsc; if (wiipic_icr_read(sc) & WIIPIC_RBS) shutdown_nice(RB_AUTOBOOT); }