summaryrefslogtreecommitdiff
path: root/sys/arch/hppa/gsc/harmony.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/hppa/gsc/harmony.c')
-rw-r--r--sys/arch/hppa/gsc/harmony.c136
1 files changed, 90 insertions, 46 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
};