#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/syslog.h>
#include <sys/device.h>
#include <sys/buf.h>
#include <machine/cpu.h>
#include <machine/intr.h>
#include <machine/bus.h>
#include <dev/audio_if.h>
#include <dev/midi_if.h>
#include <dev/isa/isavar.h>
#include <dev/ic/mpuvar.h>
#ifdef AUDIO_DEBUG
#define DPRINTF(x) if (mpu401debug) printf x
#define DPRINTFN(n,x) if (mpu401debug >= (n)) printf x
int mpu401debug = 0;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
#endif
#define MPU_GETSTATUS(iot, ioh) (bus_space_read_1(iot, ioh, MPU_STATUS))
int mpu_reset(struct mpu_softc *);
static __inline int mpu_waitready(struct mpu_softc *);
void mpu_readinput(struct mpu_softc *);
struct cfdriver mpu_cd = {
NULL, "mpu", DV_DULL
};
const struct midi_hw_if mpu_midi_hw_if = {
mpu_open,
mpu_close,
mpu_output,
0,
mpu_getinfo,
0,
};
int
mpu_find(void *v)
{
struct mpu_softc *sc = v;
if (MPU_GETSTATUS(sc->iot, sc->ioh) == 0xff) {
DPRINTF(("mpu_find: No status\n"));
goto bad;
}
sc->open = 0;
sc->intr = 0;
if (mpu_reset(sc) == 0)
return 1;
bad:
return 0;
}
static __inline int
mpu_waitready(struct mpu_softc *sc)
{
int i;
for(i = 0; i < MPU_MAXWAIT; i++) {
if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY))
return 0;
delay(10);
}
return 1;
}
int
mpu_reset(struct mpu_softc *sc)
{
bus_space_tag_t iot = sc->iot;
bus_space_handle_t ioh = sc->ioh;
int i;
if (mpu_waitready(sc)) {
DPRINTF(("mpu_reset: not ready\n"));
return EIO;
}
mtx_enter(&audio_lock);
bus_space_write_1(iot, ioh, MPU_COMMAND, MPU_RESET);
for(i = 0; i < 2*MPU_MAXWAIT; i++) {
if (!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY) &&
bus_space_read_1(iot, ioh, MPU_DATA) == MPU_ACK) {
mtx_leave(&audio_lock);
return 0;
}
}
mtx_leave(&audio_lock);
DPRINTF(("mpu_reset: No ACK\n"));
return EIO;
}
int
mpu_open(void *v, int flags, void (*iintr)(void *, int), void (*ointr)(void *),
void *arg)
{
struct mpu_softc *sc = v;
DPRINTF(("mpu_open: sc=%p\n", sc));
if (sc->open)
return EBUSY;
if (mpu_reset(sc) != 0)
return EIO;
bus_space_write_1(sc->iot, sc->ioh, MPU_COMMAND, MPU_UART_MODE);
sc->open = 1;
sc->intr = iintr;
sc->arg = arg;
return 0;
}
void
mpu_close(void *v)
{
struct mpu_softc *sc = v;
DPRINTF(("mpu_close: sc=%p\n", sc));
sc->open = 0;
sc->intr = 0;
mpu_reset(sc);
}
void
mpu_readinput(struct mpu_softc *sc)
{
bus_space_tag_t iot = sc->iot;
bus_space_handle_t ioh = sc->ioh;
int data;
while(!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY)) {
data = bus_space_read_1(iot, ioh, MPU_DATA);
DPRINTFN(3, ("mpu_rea: sc=%p 0x%02x\n", sc, data));
if (sc->intr)
sc->intr(sc->arg, data);
}
}
int
mpu_output(void *v, int d)
{
struct mpu_softc *sc = v;
DPRINTFN(3, ("mpu_output: sc=%p 0x%02x\n", sc, d));
if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY)) {
mpu_readinput(sc);
}
if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY)
delay(10);
if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY)
return 0;
bus_space_write_1(sc->iot, sc->ioh, MPU_DATA, d);
return 1;
}
void
mpu_getinfo(void *addr, struct midi_info *mi)
{
mi->name = "MPU-401 MIDI UART";
mi->props = 0;
}
int
mpu_intr(void *v)
{
struct mpu_softc *sc = v;
mtx_enter(&audio_lock);
if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY) {
mtx_leave(&audio_lock);
DPRINTF(("mpu_intr: no data\n"));
return 0;
}
mpu_readinput(sc);
mtx_leave(&audio_lock);
return 1;
}