diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2003-02-05 08:47:06 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2003-02-05 08:47:06 +0000 |
commit | 000c59c5ecadeeaf9c15ee74aff432337795cc10 (patch) | |
tree | a9fcd18230431c834e6c0279f4e5392a3a7e80a2 /sys | |
parent | e6cf03899f11f3af06d27a1d205307adf5620a55 (diff) |
Get rid of the pops:
- interrupt is called when the block has been DMA'd... since LASI seems to
include a FIFO this is -not- the same as block completion which we have
to poll for. Luckily the FIFO is deep enough that polling in the
interrupt handler seems to work.
- This probably breaks capture, but I'll fix that when I get up tomorrow.
(committed to the tune of Fugazi's "Waiting Room")
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/hppa/gsc/harmony.c | 136 | ||||
-rw-r--r-- | sys/arch/hppa/gsc/harmonyreg.h | 11 | ||||
-rw-r--r-- | sys/arch/hppa/gsc/harmonyvar.h | 4 |
3 files changed, 102 insertions, 49 deletions
diff --git a/sys/arch/hppa/gsc/harmony.c b/sys/arch/hppa/gsc/harmony.c index 7d5302dcfeb..e7f245ffff0 100644 --- a/sys/arch/hppa/gsc/harmony.c +++ b/sys/arch/hppa/gsc/harmony.c @@ -1,4 +1,4 @@ -/* $OpenBSD: harmony.c,v 1.14 2003/01/30 03:34:26 mickey Exp $ */ +/* $OpenBSD: harmony.c,v 1.15 2003/02/05 08:47:05 jason Exp $ */ /* * Copyright (c) 2003 Jason L. Wright (jason@thought.net) @@ -36,6 +36,7 @@ */ #include <sys/param.h> +#include <sys/kernel.h> #include <sys/systm.h> #include <sys/errno.h> #include <sys/ioctl.h> @@ -76,9 +77,9 @@ void harmony_freem(void *, void *, int); size_t harmony_round_buffersize(void *, int, size_t); int harmony_get_props(void *); int harmony_trigger_output(void *, void *, void *, int, - void (*intr)(void *), void *arg, struct audio_params *); + void (*intr)(void *), void *, struct audio_params *); int harmony_trigger_input(void *, void *, void *, int, - void (*intr)(void *), void *arg, struct audio_params *); + void (*intr)(void *), void *, struct audio_params *); struct audio_hw_if harmony_sa_hw_if = { harmony_open, @@ -117,8 +118,10 @@ void harmony_intr_disable(struct harmony_softc *); u_int32_t harmony_speed_bits(struct harmony_softc *, u_long *); int harmony_set_gainctl(struct harmony_softc *); void harmony_reset_codec(struct harmony_softc *); -void harmony_start_pb(struct harmony_softc *); void harmony_start_cp(struct harmony_softc *); +void harmony_tick_pb(void *); +void harmony_tick_cp(void *); +void harmony_try_more(struct harmony_softc *); int harmony_match(parent, match, aux) @@ -270,11 +273,32 @@ harmony_intr(vsc) dstatus = READ_REG(sc, HARMONY_DSTATUS); if (dstatus & DSTATUS_PN) { - c = &sc->sc_playback; + struct harmony_dma *d; + bus_addr_t nextaddr; + bus_size_t togo; + r = 1; - harmony_start_pb(sc); - if (sc->sc_playing && c->c_intr != NULL) - (*c->c_intr)(c->c_intrarg); + c = &sc->sc_playback; + d = c->c_current; + togo = c->c_segsz - c->c_cnt; + if (togo == 0) { + nextaddr = d->d_map->dm_segs[0].ds_addr; + c->c_cnt = togo = c->c_blksz; + } else { + nextaddr = c->c_lastaddr; + if (togo > c->c_blksz) + togo = c->c_blksz; + c->c_cnt += togo; + } + + bus_dmamap_sync(sc->sc_dmat, d->d_map, + nextaddr - d->d_map->dm_segs[0].ds_addr, + c->c_blksz, BUS_DMASYNC_PREWRITE); + + WRITE_REG(sc, HARMONY_PNXTADD, nextaddr); + SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE); + c->c_lastaddr = nextaddr + togo; + harmony_try_more(sc); } dstatus = READ_REG(sc, HARMONY_DSTATUS); @@ -902,6 +926,8 @@ harmony_trigger_output(void *vsc, void *start, void *end, int blksize, struct harmony_softc *sc = vsc; struct harmony_channel *c = &sc->sc_playback; struct harmony_dma *d; + bus_addr_t nextaddr; + bus_size_t togo; for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next) /*EMPTY*/; @@ -920,48 +946,31 @@ harmony_trigger_output(void *vsc, void *start, void *end, int blksize, c->c_lastaddr = d->d_map->dm_segs[0].ds_addr; sc->sc_playing = 1; - harmony_start_pb(sc); - harmony_start_cp(sc); - harmony_intr_enable(sc); - return (0); -} + togo = c->c_segsz - c->c_cnt; + if (togo == 0) { + nextaddr = d->d_map->dm_segs[0].ds_addr; + c->c_cnt = togo = c->c_blksz; + } else { + nextaddr = c->c_lastaddr; + if (togo > c->c_blksz) + togo = c->c_blksz; + c->c_cnt += togo; + } -void -harmony_start_pb(struct harmony_softc *sc) -{ - struct harmony_channel *c = &sc->sc_playback; - struct harmony_dma *d; - bus_addr_t nextaddr; - bus_size_t togo; + bus_dmamap_sync(sc->sc_dmat, d->d_map, + nextaddr - d->d_map->dm_segs[0].ds_addr, + c->c_blksz, BUS_DMASYNC_PREWRITE); - if (sc->sc_playing == 0) { - WRITE_REG(sc, HARMONY_PNXTADD, - sc->sc_playback_paddrs[sc->sc_playback_empty]); - SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE); - if (++sc->sc_playback_empty == PLAYBACK_EMPTYS) - sc->sc_playback_empty = 0; - } else { - d = c->c_current; - togo = c->c_segsz - c->c_cnt; - if (togo == 0) { - nextaddr = d->d_map->dm_segs[0].ds_addr; - c->c_cnt = togo = c->c_blksz; - } else { - nextaddr = c->c_lastaddr; - if (togo > c->c_blksz) - togo = c->c_blksz; - c->c_cnt += togo; - } + WRITE_REG(sc, HARMONY_PNXTADD, nextaddr); + c->c_theaddr = nextaddr; + SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE); + c->c_lastaddr = nextaddr + togo; - bus_dmamap_sync(sc->sc_dmat, d->d_map, - nextaddr - d->d_map->dm_segs[0].ds_addr, - c->c_blksz, BUS_DMASYNC_PREWRITE); + harmony_start_cp(sc); + harmony_intr_enable(sc); - WRITE_REG(sc, HARMONY_PNXTADD, nextaddr); - SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE); - c->c_lastaddr = nextaddr + togo; - } + return (0); } void @@ -1025,7 +1034,6 @@ harmony_trigger_input(void *vsc, void *start, void *end, int blksize, c->c_lastaddr = d->d_map->dm_segs[0].ds_addr; sc->sc_capturing = 1; - harmony_start_pb(sc); harmony_start_cp(sc); harmony_intr_enable(sc); return (0); @@ -1136,6 +1144,42 @@ harmony_set_gainctl(struct harmony_softc *sc) return (0); } +void +harmony_try_more(struct harmony_softc *sc) +{ + struct harmony_channel *c = &sc->sc_playback; + struct harmony_dma *d = c->c_current; + u_int32_t cur; + int i, nsegs; + + cur = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_PCURADD); + cur &= PCURADD_BUFMASK; + nsegs = 0; + +#ifdef DIAGNOSTIC + if (cur < d->d_map->dm_segs[0].ds_addr || + cur >= (d->d_map->dm_segs[0].ds_addr + c->c_segsz)) + panic("%s: bad current %x < %x || %x > %x", sc->sc_dv.dv_xname, + cur, d->d_map->dm_segs[0].ds_addr, cur, + d->d_map->dm_segs[0].ds_addr + c->c_segsz); +#endif /* DIAGNOSTIC */ + + if (cur > c->c_theaddr) { + nsegs = (cur - c->c_theaddr) / HARMONY_BUFSIZE; + } else if (cur < c->c_theaddr) { + nsegs = (d->d_map->dm_segs[0].ds_addr + c->c_segsz - + c->c_theaddr) / HARMONY_BUFSIZE; + nsegs += (cur - d->d_map->dm_segs[0].ds_addr) / + HARMONY_BUFSIZE; + } + + if (nsegs != 0 && c->c_intr != NULL) { + for (i = 0; i < nsegs; i++) + (*c->c_intr)(c->c_intrarg); + c->c_theaddr = cur; + } +} + struct cfdriver harmony_cd = { NULL, "harmony", DV_DULL }; diff --git a/sys/arch/hppa/gsc/harmonyreg.h b/sys/arch/hppa/gsc/harmonyreg.h index 6dbc6a198f0..8e9f2d62ad5 100644 --- a/sys/arch/hppa/gsc/harmonyreg.h +++ b/sys/arch/hppa/gsc/harmonyreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: harmonyreg.h,v 1.2 2003/01/30 01:23:24 jason Exp $ */ +/* $OpenBSD: harmonyreg.h,v 1.3 2003/02/05 08:47:05 jason Exp $ */ /* * Copyright (c) 2003 Jason L. Wright (jason@thought.net) @@ -36,6 +36,9 @@ * "712 I/O Subsystem ERS", Revision 1.1, 12 February 1993 */ +/* harmony always uses a 4K buffer */ +#define HARMONY_BUFSIZE 4096 + #define HARMONY_NREGS 0x40 #define HARMONY_ID 0x00 /* identification */ @@ -122,6 +125,12 @@ #define GAINCTL_OUTPUT_RIGHT_S 0 #define GAINCTL_OUTPUT_BITS 6 +/* HARMONY_PCURADD */ +#define PCURADD_BUFMASK (~(HARMONY_BUFSIZE - 1)) + +/* HARMONY_RCURADD */ +#define PCURADD_BUFMASK (~(HARMONY_BUFSIZE - 1)) + /* HARMONY_DSTATUS */ #define DSTATUS_IE 0x80000000 /* interrupt enable */ #define DSTATUS_PN 0x00000200 /* playback next empty */ diff --git a/sys/arch/hppa/gsc/harmonyvar.h b/sys/arch/hppa/gsc/harmonyvar.h index 59085f750be..9ad811dd6ba 100644 --- a/sys/arch/hppa/gsc/harmonyvar.h +++ b/sys/arch/hppa/gsc/harmonyvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: harmonyvar.h,v 1.3 2003/01/30 03:23:19 mickey Exp $ */ +/* $OpenBSD: harmonyvar.h,v 1.4 2003/02/05 08:47:05 jason Exp $ */ /* * Copyright (c) 2003 Jason L. Wright (jason@thought.net) @@ -50,7 +50,6 @@ #define PLAYBACK_EMPTYS 3 /* playback empty buffers */ #define CAPTURE_EMPTYS 3 /* capture empty buffers */ -#define HARMONY_BUFSIZE 4096 struct harmony_volume { u_char left, right; @@ -77,6 +76,7 @@ struct harmony_channel { bus_addr_t c_lastaddr; void (*c_intr)(void *); void *c_intrarg; + bus_addr_t c_theaddr; }; struct harmony_softc { |