245 lines
5.9 KiB
C
245 lines
5.9 KiB
C
/*-
|
|
* 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 <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/module.h>
|
|
#include <sys/bus.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/rman.h>
|
|
#include <sys/reboot.h>
|
|
|
|
#include <machine/bus.h>
|
|
#include <machine/platform.h>
|
|
#include <machine/intr_machdep.h>
|
|
#include <machine/resource.h>
|
|
|
|
#include <powerpc/wii/wii_picreg.h>
|
|
|
|
#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);
|
|
}
|
|
|