diff options
author | cg <cg@FreeBSD.org> | 2001-03-24 23:10:29 +0000 |
---|---|---|
committer | cg <cg@FreeBSD.org> | 2001-03-24 23:10:29 +0000 |
commit | 11442775804b9679c2c761846072b171d2507840 (patch) | |
tree | 2c8e61a99c9323312c5656a92269f975ac6b0c12 /sys/dev/sound | |
parent | fb291ae7e5515cf63d4544d3eeff0a4c791e3cad (diff) | |
download | FreeBSD-src-11442775804b9679c2c761846072b171d2507840.zip FreeBSD-src-11442775804b9679c2c761846072b171d2507840.tar.gz |
mega-commit.
this introduces a new buffering mechanism which results in dramatic
simplification of the channel manager.
as several structures have changed, we take the opportunity to move their
definitions into the source files where they are used, make them private and
de-typedef them.
the sound drivers are updated to use snd_setup_intr instead of
bus_setup_intr, and to comply with the de-typedefed structures.
the ac97, mixer and channel layers have been updated with finegrained
locking, as have some drivers- not all though. the rest will follow soon.
Diffstat (limited to 'sys/dev/sound')
44 files changed, 2201 insertions, 1892 deletions
diff --git a/sys/dev/sound/isa/ad1816.c b/sys/dev/sound/isa/ad1816.c index f83aafb..8e6e6c8 100644 --- a/sys/dev/sound/isa/ad1816.c +++ b/sys/dev/sound/isa/ad1816.c @@ -37,8 +37,8 @@ struct ad1816_info; struct ad1816_chinfo { struct ad1816_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; + struct pcm_channel *channel; + struct snd_dbuf *buffer; int dir, blksz; }; @@ -53,6 +53,7 @@ struct ad1816_info { int drq2_rid; void *ih; bus_dma_tag_t parent_dmat; + void *lock; struct ad1816_chinfo pch, rch; }; @@ -80,10 +81,22 @@ static u_int32_t ad1816_fmt[] = { 0 }; -static pcmchan_caps ad1816_caps = {4000, 55200, ad1816_fmt, 0}; +static struct pcmchan_caps ad1816_caps = {4000, 55200, ad1816_fmt, 0}; #define AD1816_MUTE 31 /* value for mute */ +static void +ad1816_lock(struct ad1816_info *ad1816) +{ + snd_mtxlock(ad1816); +} + +static void +ad1816_unlock(struct ad1816_info *ad1816) +{ + snd_mtxunlock(ad1816); +} + static int port_rd(struct resource *port, int off) { @@ -122,6 +135,7 @@ ad1816_intr(void *arg) struct ad1816_info *ad1816 = (struct ad1816_info *)arg; unsigned char c, served = 0; + ad1816_lock(ad1816); /* get interupt status */ c = io_rd(ad1816, AD1816_INT); @@ -149,6 +163,7 @@ ad1816_intr(void *arg) io_wr(ad1816, AD1816_INT, c); c = io_rd(ad1816, AD1816_INT); if (c != 0) printf("pcm: int clear failed (%x)\n", c); + ad1816_unlock(ad1816); } static int @@ -166,37 +181,29 @@ ad1816_wait_init(struct ad1816_info *ad1816, int x) static unsigned short ad1816_read(struct ad1816_info *ad1816, unsigned int reg) { - int flags; u_short x = 0; - /* we don't want to be blocked here */ - flags = spltty(); if (ad1816_wait_init(ad1816, 100) == -1) return 0; io_wr(ad1816, AD1816_ALE, 0); io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK)); if (ad1816_wait_init(ad1816, 100) == -1) return 0; x = (io_rd(ad1816, AD1816_HIGH) << 8) | io_rd(ad1816, AD1816_LOW); - splx(flags); return x; } static void ad1816_write(struct ad1816_info *ad1816, unsigned int reg, unsigned short data) { - int flags; - - flags = spltty(); if (ad1816_wait_init(ad1816, 100) == -1) return; io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK)); io_wr(ad1816, AD1816_LOW, (data & 0x000000ff)); io_wr(ad1816, AD1816_HIGH, (data & 0x0000ff00) >> 8); - splx(flags); } /* -------------------------------------------------------------------- */ static int -ad1816mix_init(snd_mixer *m) +ad1816mix_init(struct snd_mixer *m) { mix_setdevs(m, AD1816_MIXER_DEVICES); mix_setrecdevs(m, AD1816_REC_DEVICES); @@ -204,7 +211,7 @@ ad1816mix_init(snd_mixer *m) } static int -ad1816mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) +ad1816mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct ad1816_info *ad1816 = mix_getdevinfo(m); u_short reg = 0; @@ -219,6 +226,7 @@ ad1816mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) if (left == AD1816_MUTE) reg |= 0x8000; if (right == AD1816_MUTE) reg |= 0x0080; + ad1816_lock(ad1816); switch (dev) { case SOUND_MIXER_VOLUME: /* Register 14 master volume */ ad1816_write(ad1816, 14, reg); @@ -257,6 +265,7 @@ ad1816mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) printf("ad1816_mixer_set(): unknown device.\n"); break; } + ad1816_unlock(ad1816); left = ((AD1816_MUTE - left) * 100) / AD1816_MUTE; right = ((AD1816_MUTE - right) * 100) / AD1816_MUTE; @@ -265,7 +274,7 @@ ad1816mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) } static int -ad1816mix_setrecsrc(snd_mixer *m, u_int32_t src) +ad1816mix_setrecsrc(struct snd_mixer *m, u_int32_t src) { struct ad1816_info *ad1816 = mix_getdevinfo(m); int dev; @@ -288,7 +297,9 @@ ad1816mix_setrecsrc(snd_mixer *m, u_int32_t src) } dev |= dev << 8; + ad1816_lock(ad1816); ad1816_write(ad1816, 20, (ad1816_read(ad1816, 20) & ~0x7070) | dev); + ad1816_unlock(ad1816); return src; } @@ -303,7 +314,7 @@ MIXER_DECLARE(ad1816mixer); /* -------------------------------------------------------------------- */ /* channel interface */ static void * -ad1816chan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +ad1816chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct ad1816_info *ad1816 = devinfo; struct ad1816_chinfo *ch = (dir == PCMDIR_PLAY)? &ad1816->pch : &ad1816->rch; @@ -331,8 +342,9 @@ ad1816chan_setformat(kobj_t obj, void *data, u_int32_t format) { struct ad1816_chinfo *ch = data; struct ad1816_info *ad1816 = ch->parent; - int fmt = AD1816_U8, reg; + + ad1816_lock(ad1816); if (ch->dir == PCMDIR_PLAY) { reg = AD1816_PLAY; ad1816_write(ad1816, 8, 0x0000); /* reset base and current counter */ @@ -365,6 +377,7 @@ ad1816chan_setformat(kobj_t obj, void *data, u_int32_t format) } if (format & AFMT_STEREO) fmt |= AD1816_STEREO; io_wr(ad1816, reg, fmt); + ad1816_unlock(ad1816); return format; } @@ -375,7 +388,9 @@ ad1816chan_setspeed(kobj_t obj, void *data, u_int32_t speed) struct ad1816_info *ad1816 = ch->parent; RANGE(speed, 4000, 55200); + ad1816_lock(ad1816); ad1816_write(ad1816, (ch->dir == PCMDIR_PLAY)? 2 : 3, speed); + ad1816_unlock(ad1816); return speed; } @@ -401,6 +416,7 @@ ad1816chan_trigger(kobj_t obj, void *data, int go) sndbuf_isadma(ch->buffer, go); wr = (ch->dir == PCMDIR_PLAY); reg = wr? AD1816_PLAY : AD1816_CAPT; + ad1816_lock(ad1816); switch (go) { case PCMTRIG_START: /* start only if not already running */ @@ -435,6 +451,7 @@ ad1816chan_trigger(kobj_t obj, void *data, int go) } break; } + ad1816_unlock(ad1816); return 0; } @@ -445,7 +462,7 @@ ad1816chan_getptr(kobj_t obj, void *data) return sndbuf_isadmaptr(ch->buffer); } -static pcmchan_caps * +static struct pcmchan_caps * ad1816chan_getcaps(kobj_t obj, void *data) { return &ad1816_caps; @@ -495,6 +512,7 @@ ad1816_release_resources(struct ad1816_info *ad1816, device_t dev) bus_dma_tag_destroy(ad1816->parent_dmat); ad1816->parent_dmat = 0; } + if (ad1816->lock) snd_mtxfree(ad1816->lock); free(ad1816, M_DEVBUF); } @@ -577,6 +595,7 @@ ad1816_attach(device_t dev) if (!ad1816) return ENXIO; bzero(ad1816, sizeof *ad1816); + ad1816->lock = snd_mtxcreate(device_get_nameunit(dev)); ad1816->io_rid = 2; ad1816->irq_rid = 0; ad1816->drq1_rid = 0; @@ -586,7 +605,7 @@ ad1816_attach(device_t dev) ad1816_init(ad1816, dev); if (mixer_init(dev, &ad1816mixer_class, ad1816)) goto no; - bus_setup_intr(dev, ad1816->irq, INTR_TYPE_TTY, ad1816_intr, ad1816, &ad1816->ih); + snd_setup_intr(dev, ad1816->irq, INTR_MPSAFE, ad1816_intr, ad1816, &ad1816->ih); if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, /*highaddr*/BUS_SPACE_MAXADDR, @@ -613,6 +632,7 @@ ad1816_attach(device_t dev) return 0; no: ad1816_release_resources(ad1816, dev); + return ENXIO; } @@ -644,7 +664,7 @@ static device_method_t ad1816_methods[] = { static driver_t ad1816_driver = { "pcm", ad1816_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; DRIVER_MODULE(snd_ad1816, isa, ad1816_driver, pcm_devclass, 0, 0); diff --git a/sys/dev/sound/isa/ess.c b/sys/dev/sound/isa/ess.c index ca7ef58..77d102e 100644 --- a/sys/dev/sound/isa/ess.c +++ b/sys/dev/sound/isa/ess.c @@ -59,7 +59,7 @@ static u_int32_t ess_pfmt[] = { 0 }; -static pcmchan_caps ess_playcaps = {5000, 49000, ess_pfmt, 0}; +static struct pcmchan_caps ess_playcaps = {5000, 49000, ess_pfmt, 0}; static u_int32_t ess_rfmt[] = { AFMT_U8, @@ -73,19 +73,20 @@ static u_int32_t ess_rfmt[] = { 0 }; -static pcmchan_caps ess_reccaps = {5000, 49000, ess_rfmt, 0}; +static struct pcmchan_caps ess_reccaps = {5000, 49000, ess_rfmt, 0}; struct ess_info; struct ess_chinfo { struct ess_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; + struct pcm_channel *channel; + struct snd_dbuf *buffer; int dir, hwch, stopping, run; u_int32_t fmt, spd, blksz; }; struct ess_info { + device_t parent_dev; struct resource *io_base; /* I/O address for the board */ struct resource *irq; struct resource *drq1; @@ -130,6 +131,18 @@ static devclass_t pcm_devclass; * ess_read access ext. regs via ess_cmd(0xc0, reg) followed by ess_get_byte */ +static void +ess_lock(struct ess_info *sc) { + + sbc_lock(device_get_softc(sc->parent_dev)); +} + +static void +ess_unlock(struct ess_info *sc) { + + sbc_unlock(device_get_softc(sc->parent_dev)); +} + static int port_rd(struct resource *port, int off) { @@ -203,29 +216,21 @@ ess_cmd1(struct ess_info *sc, u_char cmd, int val) static void ess_setmixer(struct ess_info *sc, u_int port, u_int value) { - u_long flags; - DEB(printf("ess_setmixer: reg=%x, val=%x\n", port, value);) - flags = spltty(); ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ DELAY(10); ess_wr(sc, SB_MIX_DATA, (u_char) (value & 0xff)); DELAY(10); - splx(flags); } static int ess_getmixer(struct ess_info *sc, u_int port) { int val; - u_long flags; - - flags = spltty(); ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ DELAY(10); val = ess_rd(sc, SB_MIX_DATA); DELAY(10); - splx(flags); return val; } @@ -344,6 +349,7 @@ ess_intr(void *arg) struct ess_info *sc = (struct ess_info *)arg; int src, pirq, rirq; + ess_lock(sc); src = 0; if (ess_getmixer(sc, 0x7a) & 0x80) src |= 2; @@ -383,6 +389,7 @@ ess_intr(void *arg) ess_setmixer(sc, 0x7a, ess_getmixer(sc, 0x7a) & ~0x80); if (src & 1) ess_rd(sc, DSP_DATA_AVAIL); + ess_unlock(sc); } /* utility functions for ESS */ @@ -497,8 +504,8 @@ ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int le /* filter cutoff */ ess_setmixer(sc, 0x72, ess_calcfilter(spd)); } - } + return 0; } static int @@ -507,6 +514,7 @@ ess_start(struct ess_chinfo *ch) struct ess_info *sc = ch->parent; int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; + ess_lock(sc); ess_setupch(sc, ch->hwch, ch->dir, ch->spd, ch->fmt, ch->blksz); ch->stopping = 0; if (ch->hwch == 1) @@ -515,6 +523,7 @@ ess_start(struct ess_chinfo *ch) ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) | 0x03); if (play) ess_cmd(sc, DSP_CMD_SPKON); + ess_unlock(sc); return 0; } @@ -524,6 +533,7 @@ ess_stop(struct ess_chinfo *ch) struct ess_info *sc = ch->parent; int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; + ess_lock(sc); ch->stopping = 1; if (ch->hwch == 1) ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x04); @@ -531,13 +541,14 @@ ess_stop(struct ess_chinfo *ch) ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x10); if (play) ess_cmd(sc, DSP_CMD_SPKOFF); + ess_unlock(sc); return 0; } /* -------------------------------------------------------------------- */ /* channel interface for ESS18xx */ static void * -esschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +esschan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct ess_info *sc = devinfo; struct ess_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch; @@ -619,7 +630,7 @@ esschan_getptr(kobj_t obj, void *data) return sndbuf_isadmaptr(ch->buffer); } -static pcmchan_caps * +static struct pcmchan_caps * esschan_getcaps(kobj_t obj, void *data) { struct ess_chinfo *ch = data; @@ -642,7 +653,7 @@ CHANNEL_DECLARE(esschan); /************************************************************/ static int -essmix_init(snd_mixer *m) +essmix_init(struct snd_mixer *m) { struct ess_info *sc = mix_getdevinfo(m); @@ -659,7 +670,7 @@ essmix_init(snd_mixer *m) } static int -essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) +essmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct ess_info *sc = mix_getdevinfo(m); int preg = 0, rreg = 0, l, r; @@ -723,7 +734,7 @@ essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) } static int -essmix_setrecsrc(snd_mixer *m, u_int32_t src) +essmix_setrecsrc(struct snd_mixer *m, u_int32_t src) { struct ess_info *sc = mix_getdevinfo(m); u_char recdev; @@ -795,6 +806,7 @@ ess_attach(device_t dev) return ENXIO; bzero(sc, sizeof *sc); + sc->parent_dev = device_get_parent(dev); if (ess_alloc_resources(sc, dev)) goto no; if (ess_reset_dsp(sc)) @@ -828,7 +840,7 @@ ess_attach(device_t dev) if (sc->newspeed) ess_setmixer(sc, 0x71, 0x22); - bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ess_intr, sc, &sc->ih); + snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ess_intr, sc, &sc->ih); if (!sc->duplex) pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); @@ -890,11 +902,12 @@ static device_method_t ess_methods[] = { static driver_t ess_driver = { "pcm", ess_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; DRIVER_MODULE(snd_ess, sbc, ess_driver, pcm_devclass, 0, 0); MODULE_DEPEND(snd_ess, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); +MODULE_DEPEND(snd_ess, snd_sbc, 1, 1, 1); MODULE_VERSION(snd_ess, 1); /************************************************************/ @@ -961,7 +974,7 @@ static device_method_t esscontrol_methods[] = { static driver_t esscontrol_driver = { "esscontrol", esscontrol_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; DRIVER_MODULE(esscontrol, isa, esscontrol_driver, esscontrol_devclass, 0, 0); diff --git a/sys/dev/sound/isa/mss.c b/sys/dev/sound/isa/mss.c index cc9ad6b..7f94dc3 100644 --- a/sys/dev/sound/isa/mss.c +++ b/sys/dev/sound/isa/mss.c @@ -46,8 +46,8 @@ struct mss_info; struct mss_chinfo { struct mss_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; + struct pcm_channel *channel; + struct snd_dbuf *buffer; int dir; u_int32_t fmt, blksz; }; @@ -65,6 +65,7 @@ struct mss_info { int drq2_rid; void *ih; bus_dma_tag_t parent_dmat; + void *lock; char mss_indexed_regs[MSS_INDEXED_REGS]; char opl_indexed_regs[OPL_INDEXED_REGS]; @@ -132,7 +133,7 @@ static u_int32_t mss_fmt[] = { AFMT_STEREO | AFMT_A_LAW, 0 }; -static pcmchan_caps mss_caps = {4000, 48000, mss_fmt, 0}; +static struct pcmchan_caps mss_caps = {4000, 48000, mss_fmt, 0}; static u_int32_t guspnp_fmt[] = { AFMT_U8, @@ -143,7 +144,7 @@ static u_int32_t guspnp_fmt[] = { AFMT_STEREO | AFMT_A_LAW, 0 }; -static pcmchan_caps guspnp_caps = {4000, 48000, guspnp_fmt, 0}; +static struct pcmchan_caps guspnp_caps = {4000, 48000, guspnp_fmt, 0}; static u_int32_t opti931_fmt[] = { AFMT_U8, @@ -152,7 +153,7 @@ static u_int32_t opti931_fmt[] = { AFMT_STEREO | AFMT_S16_LE, 0 }; -static pcmchan_caps opti931_caps = {4000, 48000, opti931_fmt, 0}; +static struct pcmchan_caps opti931_caps = {4000, 48000, opti931_fmt, 0}; #define MD_AD1848 0x91 #define MD_AD1845 0x92 @@ -170,6 +171,18 @@ static pcmchan_caps opti931_caps = {4000, 48000, opti931_fmt, 0}; #define FULL_DUPLEX(x) ((x)->bd_flags & BD_F_DUPLEX) +static void +mss_lock(struct mss_info *mss) +{ + snd_mtxlock(mss); +} + +static void +mss_unlock(struct mss_info *mss) +{ + snd_mtxunlock(mss); +} + static int port_rd(struct resource *port, int off) { @@ -280,6 +293,8 @@ mss_release_resources(struct mss_info *mss, device_t dev) bus_dma_tag_destroy(mss->parent_dmat); mss->parent_dmat = 0; } + if (mss->lock) snd_mtxfree(mss->lock); + free(mss, M_DEVBUF); } @@ -322,6 +337,37 @@ mss_alloc_resources(struct mss_info *mss, device_t dev) return ok; } +/* + * The various mixers use a variety of bitmasks etc. The Voxware + * driver had a very nice technique to describe a mixer and interface + * to it. A table defines, for each channel, which register, bits, + * offset, polarity to use. This procedure creates the new value + * using the table and the old value. + */ + +static void +change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval) +{ + u_char mask; + int shift; + + DEB(printf("ch_bits dev %d ch %d val %d old 0x%02x " + "r %d p %d bit %d off %d\n", + dev, chn, newval, *regval, + (*t)[dev][chn].regno, (*t)[dev][chn].polarity, + (*t)[dev][chn].nbits, (*t)[dev][chn].bitoffs ) ); + + if ( (*t)[dev][chn].polarity == 1) /* reverse */ + newval = 100 - newval ; + + mask = (1 << (*t)[dev][chn].nbits) - 1; + newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ + shift = (*t)[dev][chn].bitoffs /*- (*t)[dev][LEFT_CHN].nbits + 1*/; + + *regval &= ~(mask << shift); /* Filter out the previous value */ + *regval |= (newval & mask) << shift; /* Set the new value */ +} + /* -------------------------------------------------------------------- */ /* only one source can be set... */ static int @@ -409,7 +455,7 @@ mss_mixer_set(struct mss_info *mss, int dev, int left, int right) /* -------------------------------------------------------------------- */ static int -mssmix_init(snd_mixer *m) +mssmix_init(struct snd_mixer *m) { struct mss_info *mss = mix_getdevinfo(m); @@ -422,8 +468,10 @@ mssmix_init(snd_mixer *m) case MD_OPTI931: mix_setdevs(m, OPTI931_MIXER_DEVICES); + mss_lock(mss); ad_write(mss, 20, 0x88); ad_write(mss, 21, 0x88); + mss_unlock(mss); break; case MD_AD1848: @@ -433,29 +481,35 @@ mssmix_init(snd_mixer *m) case MD_GUSPNP: case MD_GUSMAX: /* this is only necessary in mode 3 ... */ + mss_lock(mss); ad_write(mss, 22, 0x88); ad_write(mss, 23, 0x88); + mss_unlock(mss); break; } return 0; } static int -mssmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) +mssmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct mss_info *mss = mix_getdevinfo(m); + mss_lock(mss); mss_mixer_set(mss, dev, left, right); + mss_unlock(mss); return left | (right << 8); } static int -mssmix_setrecsrc(snd_mixer *m, u_int32_t src) +mssmix_setrecsrc(struct snd_mixer *m, u_int32_t src) { struct mss_info *mss = mix_getdevinfo(m); + mss_lock(mss); src = mss_set_recsrc(mss, src); + mss_unlock(mss); return src; } @@ -470,7 +524,7 @@ MIXER_DECLARE(mssmix_mixer); /* -------------------------------------------------------------------- */ static int -ymmix_init(snd_mixer *m) +ymmix_init(struct snd_mixer *m) { struct mss_info *mss = mix_getdevinfo(m); @@ -478,18 +532,21 @@ ymmix_init(snd_mixer *m) mix_setdevs(m, mix_getdevs(m) | SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_BASS | SOUND_MASK_TREBLE); /* Set master volume */ + mss_lock(mss); conf_wr(mss, OPL3SAx_VOLUMEL, 7); conf_wr(mss, OPL3SAx_VOLUMER, 7); + mss_unlock(mss); return 0; } static int -ymmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) +ymmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct mss_info *mss = mix_getdevinfo(m); int t, l, r; + mss_lock(mss); switch (dev) { case SOUND_MIXER_VOLUME: if (left) t = 15 - (left * 15) / 100; @@ -524,15 +581,18 @@ ymmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) default: mss_mixer_set(mss, dev, left, right); } + mss_unlock(mss); return left | (right << 8); } static int -ymmix_setrecsrc(snd_mixer *m, u_int32_t src) +ymmix_setrecsrc(struct snd_mixer *m, u_int32_t src) { struct mss_info *mss = mix_getdevinfo(m); + mss_lock(mss); src = mss_set_recsrc(mss, src); + mss_unlock(mss); return src; } @@ -711,6 +771,7 @@ mss_intr(void *arg) int i; DEB(printf("mss_intr\n")); + mss_lock(mss); ad_read(mss, 11); /* fake read of status bits */ /* loop until there are interrupts, but no more than 10 times. */ @@ -740,6 +801,7 @@ mss_intr(void *arg) */ io_wr(mss, MSS_STATUS, 0); /* Clear interrupt status */ } + mss_unlock(mss); } /* @@ -751,7 +813,7 @@ ad_wait_init(struct mss_info *mss, int x) { int arg = x, n = 0; /* to shut up the compiler... */ for (; x > 0; x--) - if ((n = io_rd(mss, MSS_INDEX)) & MSS_IDXBUSY) DELAY(10); + if ((n = io_rd(mss, MSS_INDEX)) & MSS_IDXBUSY) DELAY(10000); else return n; printf("AD_WAIT_INIT FAILED %d 0x%02x\n", arg, n); return n; @@ -760,15 +822,12 @@ ad_wait_init(struct mss_info *mss, int x) static int ad_read(struct mss_info *mss, int reg) { - u_long flags; int x; - flags = spltty(); ad_wait_init(mss, 201000); x = io_rd(mss, MSS_INDEX) & ~MSS_IDXMASK; io_wr(mss, MSS_INDEX, (u_char)(reg & MSS_IDXMASK) | x); x = io_rd(mss, MSS_IDATA); - splx(flags); /* printf("ad_read %d, %x\n", reg, x); */ return x; } @@ -776,16 +835,13 @@ ad_read(struct mss_info *mss, int reg) static void ad_write(struct mss_info *mss, int reg, u_char data) { - u_long flags; - int x; + /* printf("ad_write %d, %x\n", reg, data); */ - flags = spltty(); ad_wait_init(mss, 1002000); x = io_rd(mss, MSS_INDEX) & ~MSS_IDXMASK; io_wr(mss, MSS_INDEX, (u_char)(reg & MSS_IDXMASK) | x); io_wr(mss, MSS_IDATA, data); - splx(flags); } static void @@ -849,7 +905,6 @@ ad_enter_MCE(struct mss_info *mss) static void ad_leave_MCE(struct mss_info *mss) { - u_long flags; u_char prev; if ((mss->bd_flags & BD_F_MCE_BIT) == 0) { @@ -859,14 +914,12 @@ ad_leave_MCE(struct mss_info *mss) ad_wait_init(mss, 1000000); - flags = spltty(); mss->bd_flags &= ~BD_F_MCE_BIT; prev = io_rd(mss, MSS_INDEX); prev &= ~MSS_TRD; io_wr(mss, MSS_INDEX, prev & ~MSS_MCE); /* Clear the MCE bit */ wait_for_calibration(mss); - splx(flags); } static int @@ -1011,6 +1064,7 @@ opti931_intr(void *arg) return; } #endif + mss_lock(mss); i11 = ad_read(mss, 11); /* XXX what's for ? */ again: @@ -1039,6 +1093,7 @@ opti931_intr(void *arg) else DDB(printf("intr, but mc11 not set\n");) } if (loops == 0) BVDDB(printf("intr, nothing in mcir11 0x%02x\n", mc11)); + mss_unlock(mss); return; } @@ -1046,13 +1101,14 @@ opti931_intr(void *arg) if (sndbuf_runsz(mss->pch.buffer) && (mc11 & 4)) chn_intr(mss->pch.channel); opti_wr(mss, 11, ~mc11); /* ack */ if (--loops) goto again; + mss_unlock(mss); DEB(printf("xxx too many loops\n");) } /* -------------------------------------------------------------------- */ /* channel interface */ static void * -msschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +msschan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct mss_info *mss = devinfo; struct mss_chinfo *ch = (dir == PCMDIR_PLAY)? &mss->pch : &mss->rch; @@ -1070,8 +1126,11 @@ static int msschan_setformat(kobj_t obj, void *data, u_int32_t format) { struct mss_chinfo *ch = data; + struct mss_info *mss = ch->parent; + mss_lock(mss); mss_format(ch, format); + mss_unlock(mss); return 0; } @@ -1079,8 +1138,14 @@ static int msschan_setspeed(kobj_t obj, void *data, u_int32_t speed) { struct mss_chinfo *ch = data; + struct mss_info *mss = ch->parent; + int r; + + mss_lock(mss); + r = mss_speed(ch, speed); + mss_unlock(mss); - return mss_speed(ch, speed); + return r; } static int @@ -1096,12 +1161,15 @@ static int msschan_trigger(kobj_t obj, void *data, int go) { struct mss_chinfo *ch = data; + struct mss_info *mss = ch->parent; if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) return 0; sndbuf_isadma(ch->buffer, go); + mss_lock(mss); mss_trigger(ch, go); + mss_unlock(mss); return 0; } @@ -1112,7 +1180,7 @@ msschan_getptr(kobj_t obj, void *data) return sndbuf_isadmaptr(ch->buffer); } -static pcmchan_caps * +static struct pcmchan_caps * msschan_getcaps(kobj_t obj, void *data) { struct mss_chinfo *ch = data; @@ -1581,6 +1649,7 @@ mss_doattach(device_t dev, struct mss_info *mss) int pdma, rdma, flags = device_get_flags(dev); char status[SND_STATUSLEN]; + mss->lock = snd_mtxcreate(device_get_nameunit(dev)); if (!mss_alloc_resources(mss, dev)) goto no; mss_init(mss, dev); pdma = rman_get_start(mss->drq1); @@ -1620,10 +1689,10 @@ mss_doattach(device_t dev, struct mss_info *mss) mixer_init(dev, (mss->bd_id == MD_YM0020)? &ymmix_mixer_class : &mssmix_mixer_class, mss); switch (mss->bd_id) { case MD_OPTI931: - bus_setup_intr(dev, mss->irq, INTR_TYPE_TTY, opti931_intr, mss, &mss->ih); + snd_setup_intr(dev, mss->irq, INTR_MPSAFE, opti931_intr, mss, &mss->ih); break; default: - bus_setup_intr(dev, mss->irq, INTR_TYPE_TTY, mss_intr, mss, &mss->ih); + snd_setup_intr(dev, mss->irq, INTR_MPSAFE, mss_intr, mss, &mss->ih); } if (pdma == rdma) pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); @@ -1775,7 +1844,7 @@ static device_method_t mss_methods[] = { static driver_t mss_driver = { "pcm", mss_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; DRIVER_MODULE(snd_mss, isa, mss_driver, pcm_devclass, 0, 0); @@ -2049,7 +2118,7 @@ static device_method_t pnpmss_methods[] = { static driver_t pnpmss_driver = { "pcm", pnpmss_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; DRIVER_MODULE(snd_pnpmss, isa, pnpmss_driver, pcm_devclass, 0, 0); @@ -2134,7 +2203,7 @@ static device_method_t guspcm_methods[] = { static driver_t guspcm_driver = { "pcm", guspcm_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; DRIVER_MODULE(snd_guspcm, gusc, guspcm_driver, pcm_devclass, 0, 0); diff --git a/sys/dev/sound/isa/mss.h b/sys/dev/sound/isa/mss.h index b3a2f1c..ffdb809 100644 --- a/sys/dev/sound/isa/mss.h +++ b/sys/dev/sound/isa/mss.h @@ -23,6 +23,23 @@ ahead. * */ +struct mixer_def { + u_int regno:7; + u_int polarity:1; /* 1 means reversed */ + u_int bitoffs:4; + u_int nbits:4; +}; +typedef struct mixer_def mixer_ent; +typedef struct mixer_def mixer_tab[32][2]; + +#define MIX_ENT(name, reg_l, pol_l, pos_l, len_l, reg_r, pol_r, pos_r, len_r) \ + {{reg_l, pol_l, pos_l, len_l}, {reg_r, pol_r, pos_r, len_r}} + +#define PMIX_ENT(name, reg_l, pos_l, len_l, reg_r, pos_r, len_r) \ + {{reg_l, 0, pos_l, len_l}, {reg_r, 0, pos_r, len_r}} + +#define MIX_NONE(name) MIX_ENT(name, 0,0,0,0, 0,0,0,0) + /* * The four visible registers of the MSS : * diff --git a/sys/dev/sound/isa/sb.h b/sys/dev/sound/isa/sb.h index 8b2a2f6..ff09ef2 100644 --- a/sys/dev/sound/isa/sb.h +++ b/sys/dev/sound/isa/sb.h @@ -3,6 +3,13 @@ * $FreeBSD$ */ +#ifndef SB_H +#define SB_H + +struct sbc_softc; +void sbc_lock(struct sbc_softc *); +void sbc_unlock(struct sbc_softc *); + /* * sound blaster registers */ @@ -182,6 +189,4 @@ #define SB16_IMASK_L 0x3d #define SB16_IMASK_R 0x3e #define SB16_OMASK 0x3c - - - +#endif diff --git a/sys/dev/sound/isa/sb16.c b/sys/dev/sound/isa/sb16.c index a7e5580..398c3a1 100644 --- a/sys/dev/sound/isa/sb16.c +++ b/sys/dev/sound/isa/sb16.c @@ -36,6 +36,8 @@ #include <dev/sound/isa/sb.h> #include <dev/sound/chip.h> +#include <sys/mutex.h> + #include "mixer_if.h" #define SB16_BUFFSIZE 4096 @@ -46,14 +48,14 @@ static u_int32_t sb16_fmt8[] = { AFMT_STEREO | AFMT_U8, 0 }; -static pcmchan_caps sb16_caps8 = {5000, 45000, sb16_fmt8, 0}; +static struct pcmchan_caps sb16_caps8 = {5000, 45000, sb16_fmt8, 0}; static u_int32_t sb16_fmt16[] = { AFMT_S16_LE, AFMT_STEREO | AFMT_S16_LE, 0 }; -static pcmchan_caps sb16_caps16 = {5000, 45000, sb16_fmt16, 0}; +static struct pcmchan_caps sb16_caps16 = {5000, 45000, sb16_fmt16, 0}; static u_int32_t sb16x_fmt[] = { AFMT_U8, @@ -62,14 +64,14 @@ static u_int32_t sb16x_fmt[] = { AFMT_STEREO | AFMT_S16_LE, 0 }; -static pcmchan_caps sb16x_caps = {5000, 49000, sb16x_fmt, 0}; +static struct pcmchan_caps sb16x_caps = {5000, 49000, sb16x_fmt, 0}; struct sb_info; struct sb_chinfo { struct sb_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; + struct pcm_channel *channel; + struct snd_dbuf *buffer; int dir, run, dch; u_int32_t fmt, spd, blksz; }; @@ -86,8 +88,11 @@ struct sb_info { u_long bd_flags; /* board-specific flags */ int prio, prio16; struct sb_chinfo pch, rch; + device_t parent_dev; }; +static void sb_lock(struct sb_info *sb); +static void sb_unlock(struct sb_info *sb); static int sb_rd(struct sb_info *sb, int reg); static void sb_wr(struct sb_info *sb, int reg, u_int8_t val); static int sb_cmd(struct sb_info *sb, u_char val); @@ -148,6 +153,7 @@ sb_dspwr(struct sb_info *sb, u_char val) return 1; } } + if (curproc->p_intr_nesting_level == 0) printf("sb_dspwr(0x%02x) timed out.\n", val); return 0; } @@ -193,28 +199,25 @@ sb_cmd2(struct sb_info *sb, u_char cmd, int val) static void sb_setmixer(struct sb_info *sb, u_int port, u_int value) { - u_long flags; - - flags = spltty(); + sb_lock(sb); sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ DELAY(10); sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff)); DELAY(10); - splx(flags); + sb_unlock(sb); } static int sb_getmixer(struct sb_info *sb, u_int port) { int val; - u_long flags; - flags = spltty(); + sb_lock(sb); sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ DELAY(10); val = sb_rd(sb, SB_MIX_DATA); DELAY(10); - splx(flags); + sb_unlock(sb); return val; } @@ -236,10 +239,15 @@ sb_get_byte(struct sb_info *sb) static int sb_reset_dsp(struct sb_info *sb) { + u_char b; + + sb_lock(sb); sb_wr(sb, SBDSP_RST, 3); DELAY(100); sb_wr(sb, SBDSP_RST, 0); - if (sb_get_byte(sb) != 0xAA) { + b = sb_get_byte(sb); + sb_unlock(sb); + if (b != 0xAA) { DEB(printf("sb_reset_dsp 0x%lx failed\n", rman_get_start(d->io_base))); return ENXIO; /* Sorry */ @@ -271,7 +279,7 @@ static const struct sb16_mixent sb16_mixtab[32] = { }; static int -sb16mix_init(snd_mixer *m) +sb16mix_init(struct snd_mixer *m) { struct sb_info *sb = mix_getdevinfo(m); @@ -292,7 +300,7 @@ sb16mix_init(snd_mixer *m) } static int -sb16mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) +sb16mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct sb_info *sb = mix_getdevinfo(m); const struct sb16_mixent *e; @@ -317,7 +325,7 @@ sb16mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) } static int -sb16mix_setrecsrc(snd_mixer *m, u_int32_t src) +sb16mix_setrecsrc(struct snd_mixer *m, u_int32_t src) { struct sb_info *sb = mix_getdevinfo(m); u_char recdev; @@ -429,6 +437,7 @@ sb16_alloc_resources(struct sb_info *sb, device_t dev) } else return ENXIO; } +/* sbc does locking for us */ static void sb_intr(void *arg) { @@ -441,7 +450,14 @@ sb_intr(void *arg) */ reason = 0; + sb_lock(sb); c = sb_getmixer(sb, IRQ_STAT); + if (c & 1) + sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */ + + if (c & 2) + sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */ + sb_unlock(sb); /* * this tells us if the source is 8-bit or 16-bit dma. We @@ -483,12 +499,6 @@ sb_intr(void *arg) if ((reason & 2) && (sb->rch.run)) chn_intr(sb->rch.channel); - - if (c & 1) - sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */ - - if (c & 2) - sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */ } static int @@ -498,6 +508,7 @@ sb_setup(struct sb_info *sb) u_int8_t v; int l, pprio; + sb_lock(sb); if (sb->bd_flags & BD_F_DMARUN) sndbuf_isadma(sb->pch.buffer, PCMTRIG_STOP); if (sb->bd_flags & BD_F_DMARUN2) @@ -591,13 +602,14 @@ sb_setup(struct sb_info *sb) sndbuf_isadma(ch->buffer, PCMTRIG_START); sb->bd_flags |= BD_F_DMARUN2; } + sb_unlock(sb); return 0; } /* channel interface */ static void * -sb16chan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +sb16chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sb_info *sb = devinfo; struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch; @@ -671,7 +683,7 @@ sb16chan_getptr(kobj_t obj, void *data) return sndbuf_isadmaptr(ch->buffer); } -static pcmchan_caps * +static struct pcmchan_caps * sb16chan_getcaps(kobj_t obj, void *data) { struct sb_chinfo *ch = data; @@ -745,7 +757,8 @@ sb16_attach(device_t dev) return ENXIO; bzero(sb, sizeof *sb); - BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); + sb->parent_dev = device_get_parent(dev); + BUS_READ_IVAR(sb->parent_dev, dev, 1, &ver); sb->bd_id = ver & 0x0000ffff; sb->bd_flags = (ver & 0xffff0000) >> 16; @@ -755,7 +768,7 @@ sb16_attach(device_t dev) goto no; if (mixer_init(dev, &sb16mix_mixer_class, sb)) goto no; - if (bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &sb->ih)) + if (snd_setup_intr(dev, sb->irq, INTR_MPSAFE, sb_intr, sb, &sb->ih)) goto no; if (sb->bd_flags & BD_F_SB16X) @@ -810,6 +823,18 @@ sb16_detach(device_t dev) return 0; } +static void +sb_lock(struct sb_info *sb) { + + sbc_lock(device_get_softc(sb->parent_dev)); +} + +static void +sb_unlock(struct sb_info *sb) { + + sbc_unlock(device_get_softc(sb->parent_dev)); +} + static device_method_t sb16_methods[] = { /* Device interface */ DEVMETHOD(device_probe, sb16_probe), @@ -822,13 +847,10 @@ static device_method_t sb16_methods[] = { static driver_t sb16_driver = { "pcm", sb16_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; DRIVER_MODULE(snd_sb16, sbc, sb16_driver, pcm_devclass, 0, 0); MODULE_DEPEND(snd_sb16, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); +MODULE_DEPEND(snd_sb16, snd_sbc, 1, 1, 1); MODULE_VERSION(snd_sb16, 1); - - - - diff --git a/sys/dev/sound/isa/sb8.c b/sys/dev/sound/isa/sb8.c index 39a8f95..390bbdc 100644 --- a/sys/dev/sound/isa/sb8.c +++ b/sys/dev/sound/isa/sb8.c @@ -44,30 +44,31 @@ static u_int32_t sb_fmt[] = { AFMT_U8, 0 }; -static pcmchan_caps sb200_playcaps = {4000, 23000, sb_fmt, 0}; -static pcmchan_caps sb200_reccaps = {4000, 13000, sb_fmt, 0}; -static pcmchan_caps sb201_playcaps = {4000, 44100, sb_fmt, 0}; -static pcmchan_caps sb201_reccaps = {4000, 15000, sb_fmt, 0}; +static struct pcmchan_caps sb200_playcaps = {4000, 23000, sb_fmt, 0}; +static struct pcmchan_caps sb200_reccaps = {4000, 13000, sb_fmt, 0}; +static struct pcmchan_caps sb201_playcaps = {4000, 44100, sb_fmt, 0}; +static struct pcmchan_caps sb201_reccaps = {4000, 15000, sb_fmt, 0}; static u_int32_t sbpro_fmt[] = { AFMT_U8, AFMT_STEREO | AFMT_U8, 0 }; -static pcmchan_caps sbpro_playcaps = {4000, 44100, sbpro_fmt, 0}; -static pcmchan_caps sbpro_reccaps = {4000, 44100, sbpro_fmt, 0}; +static struct pcmchan_caps sbpro_playcaps = {4000, 44100, sbpro_fmt, 0}; +static struct pcmchan_caps sbpro_reccaps = {4000, 44100, sbpro_fmt, 0}; struct sb_info; struct sb_chinfo { struct sb_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; + struct pcm_channel *channel; + struct snd_dbuf *buffer; int dir; u_int32_t fmt, spd, blksz; }; struct sb_info { + device_t parent_dev; struct resource *io_base; /* I/O address for the board */ struct resource *irq; struct resource *drq; @@ -106,6 +107,18 @@ static devclass_t pcm_devclass; * sb_get_byte returns a single byte from the DSP data port */ +static void +sb_lock(struct sb_info *sb) { + + sbc_lock(device_get_softc(sb->parent_dev)); +} + +static void +sb_unlock(struct sb_info *sb) { + + sbc_unlock(device_get_softc(sb->parent_dev)); +} + static int port_rd(struct resource *port, int off) { @@ -187,32 +200,27 @@ sb_cmd2(struct sb_info *sb, u_char cmd, int val) /* * in the SB, there is a set of indirect "mixer" registers with * address at offset 4, data at offset 5 + * + * we don't need to interlock these, the mixer lock will suffice. */ static void sb_setmixer(struct sb_info *sb, u_int port, u_int value) { - u_long flags; - - flags = spltty(); sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ DELAY(10); sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff)); DELAY(10); - splx(flags); } static int sb_getmixer(struct sb_info *sb, u_int port) { int val; - u_long flags; - flags = spltty(); sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ DELAY(10); val = sb_rd(sb, SB_MIX_DATA); DELAY(10); - splx(flags); return val; } @@ -297,7 +305,7 @@ sb_alloc_resources(struct sb_info *sb, device_t dev) /************************************************************/ static int -sbpromix_init(snd_mixer *m) +sbpromix_init(struct snd_mixer *m) { struct sb_info *sb = mix_getdevinfo(m); @@ -312,7 +320,7 @@ sbpromix_init(snd_mixer *m) } static int -sbpromix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) +sbpromix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct sb_info *sb = mix_getdevinfo(m); int reg, max; @@ -362,7 +370,7 @@ sbpromix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) } static int -sbpromix_setrecsrc(snd_mixer *m, u_int32_t src) +sbpromix_setrecsrc(struct snd_mixer *m, u_int32_t src) { struct sb_info *sb = mix_getdevinfo(m); u_char recdev; @@ -391,7 +399,7 @@ MIXER_DECLARE(sbpromix_mixer); /************************************************************/ static int -sbmix_init(snd_mixer *m) +sbmix_init(struct snd_mixer *m) { struct sb_info *sb = mix_getdevinfo(m); @@ -405,7 +413,7 @@ sbmix_init(snd_mixer *m) } static int -sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) +sbmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct sb_info *sb = mix_getdevinfo(m); int reg, max; @@ -443,7 +451,7 @@ sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) } static int -sbmix_setrecsrc(snd_mixer *m, u_int32_t src) +sbmix_setrecsrc(struct snd_mixer *m, u_int32_t src) { return 0; } @@ -463,6 +471,7 @@ sb_intr(void *arg) { struct sb_info *sb = (struct sb_info *)arg; + sb_lock(sb); if (sndbuf_runsz(sb->pch.buffer) > 0) chn_intr(sb->pch.channel); @@ -470,6 +479,7 @@ sb_intr(void *arg) chn_intr(sb->rch.channel); sb_rd(sb, DSP_DATA_AVAIL); /* int ack */ + sb_unlock(sb); } static int @@ -496,6 +506,7 @@ sb_speed(struct sb_chinfo *ch) if (speed > max) speed = max; + sb_lock(sb); sb->bd_flags &= ~BD_F_HISPEED; if (speed > thresh) sb->bd_flags |= BD_F_HISPEED; @@ -508,6 +519,7 @@ sb_speed(struct sb_chinfo *ch) speed = (256000000 / (65536 - tmp)) >> stereo; ch->spd = speed; + sb_unlock(sb); return speed; } @@ -522,6 +534,7 @@ sb_start(struct sb_chinfo *ch) l--; + sb_lock(sb); if (play) sb_cmd(sb, DSP_CMD_SPKON); @@ -535,6 +548,7 @@ sb_start(struct sb_chinfo *ch) sb_cmd(sb, i); sb->bd_flags |= BD_F_DMARUN; + sb_unlock(sb); return 0; } @@ -544,6 +558,7 @@ sb_stop(struct sb_chinfo *ch) struct sb_info *sb = ch->parent; int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; + sb_lock(sb); if (sb->bd_flags & BD_F_HISPEED) sb_reset_dsp(sb); else @@ -551,13 +566,14 @@ sb_stop(struct sb_chinfo *ch) if (play) sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */ + sb_unlock(sb); sb->bd_flags &= ~BD_F_DMARUN; return 0; } /* channel interface */ static void * -sbchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +sbchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sb_info *sb = devinfo; struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch; @@ -623,7 +639,7 @@ sbchan_getptr(kobj_t obj, void *data) return sndbuf_isadmaptr(ch->buffer); } -static pcmchan_caps * +static struct pcmchan_caps * sbchan_getcaps(kobj_t obj, void *data) { struct sb_chinfo *ch = data; @@ -687,6 +703,7 @@ sb_attach(device_t dev) return ENXIO; bzero(sb, sizeof *sb); + sb->parent_dev = device_get_parent(dev); BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); sb->bd_id = ver & 0x0000ffff; sb->bd_flags = (ver & 0xffff0000) >> 16; @@ -697,7 +714,7 @@ sb_attach(device_t dev) goto no; if (mixer_init(dev, (sb->bd_id < 0x300)? &sbmix_mixer_class : &sbpromix_mixer_class, sb)) goto no; - if (bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &sb->ih)) + if (snd_setup_intr(dev, sb->irq, INTR_MPSAFE, sb_intr, sb, &sb->ih)) goto no; pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); @@ -757,11 +774,12 @@ static device_method_t sb_methods[] = { static driver_t sb_driver = { "pcm", sb_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; DRIVER_MODULE(snd_sb8, sbc, sb_driver, pcm_devclass, 0, 0); MODULE_DEPEND(snd_sb8, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); +MODULE_DEPEND(snd_sb8, snd_sbc, 1, 1, 1); MODULE_VERSION(snd_sb8, 1); diff --git a/sys/dev/sound/isa/sbc.c b/sys/dev/sound/isa/sbc.c index 8629554..2129161 100644 --- a/sys/dev/sound/isa/sbc.c +++ b/sys/dev/sound/isa/sbc.c @@ -35,9 +35,12 @@ #define DRQ_MAX 2 #define INTR_MAX 2 +struct sbc_softc; + struct sbc_ihl { driver_intr_t *intr[INTR_MAX]; void *intr_arg[INTR_MAX]; + struct sbc_softc *parent; }; /* Here is the parameter structure per a device. */ @@ -61,6 +64,8 @@ struct sbc_softc { void *ih[IRQ_MAX]; + void *lock; + u_int32_t bd_ver; }; @@ -106,6 +111,30 @@ static int sb_cmd(struct resource *io, u_char val); static u_int sb_get_byte(struct resource *io); static void sb_setmixer(struct resource *io, u_int port, u_int value); +static void +sbc_lockinit(struct sbc_softc *scp) +{ + scp->lock = snd_mtxcreate(device_get_nameunit(scp->dev)); +} + +static void +sbc_lockdestroy(struct sbc_softc *scp) +{ + snd_mtxfree(scp->lock); +} + +void +sbc_lock(struct sbc_softc *scp) +{ + snd_mtxlock(scp->lock); +} + +void +sbc_unlock(struct sbc_softc *scp) +{ + snd_mtxunlock(scp->lock); +} + static int sb_rd(struct resource *io, int reg) { @@ -311,6 +340,7 @@ sbc_attach(device_t dev) scp = device_get_softc(dev); bzero(scp, sizeof(*scp)); scp->dev = dev; + sbc_lockinit(scp); err = "alloc_resource"; if (alloc_resource(scp)) goto bad; @@ -396,7 +426,8 @@ sbc_attach(device_t dev) err = "setup_intr"; for (i = 0; i < IRQ_MAX; i++) { - if (bus_setup_intr(dev, scp->irq[i], INTR_TYPE_TTY, sbc_intr, &scp->ihl[i], &scp->ih[i])) + scp->ihl[i].parent = scp; + if (snd_setup_intr(dev, scp->irq[i], INTR_MPSAFE, sbc_intr, &scp->ihl[i], &scp->ih[i])) goto bad; } @@ -439,10 +470,12 @@ sbc_detach(device_t dev) { struct sbc_softc *scp = device_get_softc(dev); + sbc_lock(scp); device_delete_child(dev, scp->child_midi2); device_delete_child(dev, scp->child_midi1); device_delete_child(dev, scp->child_pcm); release_resource(scp); + sbc_lockdestroy(scp); return bus_generic_detach(dev); } @@ -452,11 +485,13 @@ sbc_intr(void *p) struct sbc_ihl *ihl = p; int i; + /* sbc_lock(ihl->parent); */ i = 0; while (i < INTR_MAX) { if (ihl->intr[i] != NULL) ihl->intr[i](ihl->intr_arg[i]); i++; } + /* sbc_unlock(ihl->parent); */ } static int @@ -466,24 +501,27 @@ sbc_setup_intr(device_t dev, device_t child, struct resource *irq, { struct sbc_softc *scp = device_get_softc(dev); struct sbc_ihl *ihl = NULL; - int i; + int i, ret; + sbc_lock(scp); i = 0; while (i < IRQ_MAX) { if (irq == scp->irq[i]) ihl = &scp->ihl[i]; i++; } - if (ihl == NULL) return (EINVAL); + ret = 0; + if (ihl == NULL) ret = EINVAL; i = 0; - while (i < INTR_MAX) { + while ((ret == 0) && (i < INTR_MAX)) { if (ihl->intr[i] == NULL) { ihl->intr[i] = intr; ihl->intr_arg[i] = arg; *cookiep = &ihl->intr[i]; - return 0; + ret = -1; } else i++; } - return (EINVAL); + sbc_unlock(scp); + return (ret > 0)? EINVAL : 0; } static int @@ -492,23 +530,26 @@ sbc_teardown_intr(device_t dev, device_t child, struct resource *irq, { struct sbc_softc *scp = device_get_softc(dev); struct sbc_ihl *ihl = NULL; - int i; + int i, ret; + sbc_lock(scp); i = 0; while (i < IRQ_MAX) { if (irq == scp->irq[i]) ihl = &scp->ihl[i]; i++; } - if (ihl == NULL) return (EINVAL); + ret = 0; + if (ihl == NULL) ret = EINVAL; i = 0; - while (i < INTR_MAX) { + while ((ret == 0) && (i < INTR_MAX)) { if (cookie == &ihl->intr[i]) { ihl->intr[i] = NULL; ihl->intr_arg[i] = NULL; return 0; } else i++; } - return (EINVAL); + sbc_unlock(scp); + return (ret > 0)? EINVAL : 0; } static struct resource * diff --git a/sys/dev/sound/pci/aureal.c b/sys/dev/sound/pci/aureal.c index 09ead9f..419eb98 100644 --- a/sys/dev/sound/pci/aureal.c +++ b/sys/dev/sound/pci/aureal.c @@ -44,7 +44,7 @@ static u_int32_t au_playfmt[] = { AFMT_STEREO | AFMT_S16_LE, 0 }; -static pcmchan_caps au_playcaps = {4000, 48000, au_playfmt, 0}; +static struct pcmchan_caps au_playcaps = {4000, 48000, au_playfmt, 0}; static u_int32_t au_recfmt[] = { AFMT_U8, @@ -53,7 +53,7 @@ static u_int32_t au_recfmt[] = { AFMT_STEREO | AFMT_S16_LE, 0 }; -static pcmchan_caps au_reccaps = {4000, 48000, au_recfmt, 0}; +static struct pcmchan_caps au_reccaps = {4000, 48000, au_recfmt, 0}; /* -------------------------------------------------------------------- */ @@ -61,8 +61,8 @@ struct au_info; struct au_chinfo { struct au_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; + struct pcm_channel *channel; + struct snd_dbuf *buffer; int dir; }; @@ -73,6 +73,7 @@ struct au_info { bus_space_handle_t sh[3]; bus_dma_tag_t parent_dmat; + void *lock; u_int32_t x[32], y[128]; char z[128]; @@ -293,7 +294,7 @@ au_prepareoutput(struct au_chinfo *ch, u_int32_t format) /* -------------------------------------------------------------------- */ /* channel interface */ static void * -auchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +auchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct au_info *au = devinfo; struct au_chinfo *ch = (dir == PCMDIR_PLAY)? &au->pch : NULL; @@ -365,7 +366,7 @@ auchan_getptr(kobj_t obj, void *data) } } -static pcmchan_caps * +static struct pcmchan_caps * auchan_getcaps(kobj_t obj, void *data) { struct au_chinfo *ch = data; @@ -620,8 +621,7 @@ au_pci_attach(device_t dev) irqid = 0; irq = bus_alloc_resource(dev, SYS_RES_IRQ, &irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); - if (!irq - || bus_setup_intr(dev, irq, INTR_TYPE_TTY, au_intr, au, &ih)) { + if (!irq || snd_setup_intr(dev, irq, 0, au_intr, au, &ih)) { device_printf(dev, "unable to map interrupt\n"); goto bad; } @@ -678,7 +678,7 @@ static device_method_t au_methods[] = { static driver_t au_driver = { "pcm", au_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pci/cmi.c b/sys/dev/sound/pci/cmi.c index 27489a2..bb48b70 100644 --- a/sys/dev/sound/pci/cmi.c +++ b/sys/dev/sound/pci/cmi.c @@ -83,8 +83,8 @@ struct cmi_info; struct cmi_chinfo { struct cmi_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; + struct pcm_channel *channel; + struct snd_dbuf *buffer; int dir; int bps; /* bytes per sample */ u_int32_t fmt, spd, phys_buf; @@ -115,7 +115,7 @@ static u_int32_t cmi_fmt[] = { 0 }; -static pcmchan_caps cmi_caps = {5512, 48000, cmi_fmt, 0}; +static struct pcmchan_caps cmi_caps = {5512, 48000, cmi_fmt, 0}; /* ------------------------------------------------------------------------- */ /* Register Utilities */ @@ -328,7 +328,7 @@ cmi_spdif_speed(struct cmi_info *cmi, int speed) { /* Channel Interface implementation */ static void * -cmichan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +cmichan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct cmi_info *cmi = devinfo; struct cmi_chinfo *ch = (dir == PCMDIR_PLAY) ? &cmi->pch : &cmi->rch; @@ -541,7 +541,7 @@ cmi_intr(void *data) return; } -static pcmchan_caps * +static struct pcmchan_caps * cmichan_getcaps(kobj_t obj, void *data) { return &cmi_caps; @@ -610,7 +610,7 @@ struct sb16props { #define MIXER_GAIN_REG_RTOL(r) (r - 1) static int -cmimix_init(snd_mixer *m) +cmimix_init(struct snd_mixer *m) { struct cmi_info *cmi = mix_getdevinfo(m); u_int32_t i,v; @@ -635,7 +635,7 @@ cmimix_init(snd_mixer *m) } static int -cmimix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) +cmimix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct cmi_info *cmi = mix_getdevinfo(m); u_int32_t r, l, max; @@ -683,7 +683,7 @@ cmimix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) } static int -cmimix_setrecsrc(snd_mixer *m, u_int32_t src) +cmimix_setrecsrc(struct snd_mixer *m, u_int32_t src) { struct cmi_info *cmi = mix_getdevinfo(m); u_int32_t i, ml, sl; @@ -760,7 +760,7 @@ cmi_probe(device_t dev) static int cmi_attach(device_t dev) { - snddev_info *d; + struct snddev_info *d; struct cmi_info *cmi; u_int32_t data; char status[SND_STATUSLEN]; @@ -793,7 +793,7 @@ cmi_attach(device_t dev) cmi->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &cmi->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); if (!cmi->irq || - bus_setup_intr(dev, cmi->irq, INTR_TYPE_TTY, cmi_intr, cmi, &cmi->ih)){ + snd_setup_intr(dev, cmi->irq, 0, cmi_intr, cmi, &cmi->ih)) { device_printf(dev, "cmi_attach: Unable to map interrupt\n"); goto bad; } @@ -877,7 +877,7 @@ static device_method_t cmi_methods[] = { static driver_t cmi_driver = { "pcm", cmi_methods, - sizeof(snddev_info) + sizeof(struct snddev_info) }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pci/cs4281.c b/sys/dev/sound/pci/cs4281.c index 2f5f633..506a58a 100644 --- a/sys/dev/sound/pci/cs4281.c +++ b/sys/dev/sound/pci/cs4281.c @@ -68,8 +68,8 @@ struct sc_info; struct sc_chinfo { struct sc_info *parent; - snd_dbuf *buffer; - pcm_channel *channel; + struct snd_dbuf *buffer; + struct pcm_channel *channel; u_int32_t spd, fmt, bps, blksz; @@ -134,7 +134,7 @@ static u_int32_t cs4281_fmts[] = { 0 }; -static pcmchan_caps cs4281_caps = {6024, 48000, cs4281_fmts, 0}; +static struct pcmchan_caps cs4281_caps = {6024, 48000, cs4281_fmts, 0}; /* -------------------------------------------------------------------- */ /* Hardware */ @@ -310,7 +310,7 @@ AC97_DECLARE(cs4281_ac97); /* shared rec/play channel interface */ static void * -cs4281chan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +cs4281chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sc_info *sc = devinfo; struct sc_chinfo *ch = (dir == PCMDIR_PLAY) ? &sc->pch : &sc->rch; @@ -437,7 +437,7 @@ cs4281chan_trigger(kobj_t obj, void *data, int go) return 0; } -static pcmchan_caps * +static struct pcmchan_caps * cs4281chan_getcaps(kobj_t obj, void *data) { return &cs4281_caps; @@ -810,7 +810,7 @@ cs4281_pci_attach(device_t dev) goto bad; } - if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, cs4281_intr, sc, &sc->ih)) { + if (snd_setup_intr(dev, sc->irq, 0, cs4281_intr, sc, &sc->ih)) { device_printf(dev, "unable to setup interrupt\n"); goto bad; } @@ -962,7 +962,7 @@ static device_method_t cs4281_methods[] = { static driver_t cs4281_driver = { "pcm", cs4281_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pci/csa.c b/sys/dev/sound/pci/csa.c index 8cfc179..9dad2f2 100644 --- a/sys/dev/sound/pci/csa.c +++ b/sys/dev/sound/pci/csa.c @@ -155,7 +155,7 @@ csa_attach(device_t dev) } /* Enable interrupt. */ - if (bus_setup_intr(dev, resp->irq, INTR_TYPE_TTY, csa_intr, scp, &scp->ih)) { + if (snd_setup_intr(dev, resp->irq, 0, csa_intr, scp, &scp->ih)) { bus_release_resource(dev, SYS_RES_MEMORY, resp->io_rid, resp->io); bus_release_resource(dev, SYS_RES_MEMORY, resp->mem_rid, resp->mem); bus_release_resource(dev, SYS_RES_IRQ, resp->irq_rid, resp->irq); diff --git a/sys/dev/sound/pci/csapcm.c b/sys/dev/sound/pci/csapcm.c index 8bad7b5..399ac15 100644 --- a/sys/dev/sound/pci/csapcm.c +++ b/sys/dev/sound/pci/csapcm.c @@ -45,8 +45,8 @@ struct csa_info; struct csa_chinfo { struct csa_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; + struct pcm_channel *channel; + struct snd_dbuf *buffer; int dir; u_int32_t fmt; int dma; @@ -93,14 +93,14 @@ static u_int32_t csa_playfmt[] = { AFMT_STEREO | AFMT_S16_BE, 0 }; -static pcmchan_caps csa_playcaps = {8000, 48000, csa_playfmt, 0}; +static struct pcmchan_caps csa_playcaps = {8000, 48000, csa_playfmt, 0}; static u_int32_t csa_recfmt[] = { AFMT_S16_LE, AFMT_STEREO | AFMT_S16_LE, 0 }; -static pcmchan_caps csa_reccaps = {11025, 48000, csa_recfmt, 0}; +static struct pcmchan_caps csa_reccaps = {11025, 48000, csa_recfmt, 0}; /* -------------------------------------------------------------------- */ /* ac97 codec */ @@ -515,7 +515,7 @@ csa_startdsp(csa_res *resp) /* channel interface */ static void * -csachan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +csachan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct csa_info *csa = devinfo; struct csa_chinfo *ch = (dir == PCMDIR_PLAY)? &csa->pch : &csa->rch; @@ -654,7 +654,7 @@ csachan_getptr(kobj_t obj, void *data) return (ptr); } -static pcmchan_caps * +static struct pcmchan_caps * csachan_getcaps(kobj_t obj, void *data) { struct csa_chinfo *ch = data; @@ -854,7 +854,7 @@ pcmcsa_attach(device_t dev) snprintf(status, SND_STATUSLEN, "at irq %ld", rman_get_start(resp->irq)); /* Enable interrupt. */ - if (bus_setup_intr(dev, resp->irq, INTR_TYPE_TTY, csa_intr, csa, &csa->ih)) { + if (snd_setup_intr(dev, resp->irq, 0, csa_intr, csa, &csa->ih)) { ac97_destroy(codec); csa_releaseres(csa, dev); return (ENXIO); @@ -902,7 +902,7 @@ static device_method_t pcmcsa_methods[] = { static driver_t pcmcsa_driver = { "pcm", pcmcsa_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pci/ds1.c b/sys/dev/sound/pci/ds1.c index 64db2b7..1870917 100644 --- a/sys/dev/sound/pci/ds1.c +++ b/sys/dev/sound/pci/ds1.c @@ -87,8 +87,8 @@ struct sc_info; /* channel registers */ struct sc_pchinfo { int run, spd, dir, fmt; - snd_dbuf *buffer; - pcm_channel *channel; + struct snd_dbuf *buffer; + struct pcm_channel *channel; volatile struct pbank *lslot, *rslot; int lsnum, rsnum; struct sc_info *parent; @@ -96,8 +96,8 @@ struct sc_pchinfo { struct sc_rchinfo { int run, spd, dir, fmt, num; - snd_dbuf *buffer; - pcm_channel *channel; + struct snd_dbuf *buffer; + struct pcm_channel *channel; volatile struct rbank *slot; struct sc_info *parent; }; @@ -116,6 +116,7 @@ struct sc_info { struct resource *reg, *irq; int regid, irqid; void *ih; + void *lock; void *regbase; u_int32_t *pbase, pbankbase, pbanksize; @@ -175,7 +176,7 @@ static u_int32_t ds_recfmt[] = { AFMT_STEREO | AFMT_U16_LE, 0 }; -static pcmchan_caps ds_reccaps = {4000, 48000, ds_recfmt, 0}; +static struct pcmchan_caps ds_reccaps = {4000, 48000, ds_recfmt, 0}; static u_int32_t ds_playfmt[] = { AFMT_U8, @@ -184,7 +185,7 @@ static u_int32_t ds_playfmt[] = { AFMT_STEREO | AFMT_S16_LE, 0 }; -static pcmchan_caps ds_playcaps = {4000, 96000, ds_playfmt, 0}; +static struct pcmchan_caps ds_playcaps = {4000, 96000, ds_playfmt, 0}; /* -------------------------------------------------------------------- */ /* Hardware */ @@ -473,7 +474,7 @@ ds_setuprch(struct sc_rchinfo *ch) /* -------------------------------------------------------------------- */ /* play channel interface */ static void * -ds1pchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +ds1pchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sc_info *sc = devinfo; struct sc_pchinfo *ch; @@ -550,7 +551,9 @@ ds1pchan_trigger(kobj_t obj, void *data, int go) ds_setuppch(ch); ds_enapslot(sc, ch->lsnum, 1); ds_enapslot(sc, ch->rsnum, stereo); + snd_mtxlock(sc->lock); ds_wr(sc, YDSXGR_MODE, 0x00000003, 4); + snd_mtxunlock(sc->lock); } else { ch->run = 0; /* ds_setuppch(ch); */ @@ -580,7 +583,7 @@ ds1pchan_getptr(kobj_t obj, void *data) return ptr; } -static pcmchan_caps * +static struct pcmchan_caps * ds1pchan_getcaps(kobj_t obj, void *data) { return &ds_playcaps; @@ -601,7 +604,7 @@ CHANNEL_DECLARE(ds1pchan); /* -------------------------------------------------------------------- */ /* record channel interface */ static void * -ds1rchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +ds1rchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sc_info *sc = devinfo; struct sc_rchinfo *ch; @@ -672,15 +675,19 @@ ds1rchan_trigger(kobj_t obj, void *data, int go) if (go == PCMTRIG_START) { ch->run = 1; ds_setuprch(ch); + snd_mtxlock(sc->lock); x = ds_rd(sc, YDSXGR_MAPOFREC, 4); x |= (ch->num == DS1_RECPRIMARY)? 0x02 : 0x01; ds_wr(sc, YDSXGR_MAPOFREC, x, 4); ds_wr(sc, YDSXGR_MODE, 0x00000003, 4); + snd_mtxunlock(sc->lock); } else { ch->run = 0; + snd_mtxlock(sc->lock); x = ds_rd(sc, YDSXGR_MAPOFREC, 4); x &= ~((ch->num == DS1_RECPRIMARY)? 0x02 : 0x01); ds_wr(sc, YDSXGR_MAPOFREC, x, 4); + snd_mtxunlock(sc->lock); } return 0; @@ -695,7 +702,7 @@ ds1rchan_getptr(kobj_t obj, void *data) return ch->slot[sc->currbank].PgStart; } -static pcmchan_caps * +static struct pcmchan_caps * ds1rchan_getcaps(kobj_t obj, void *data) { return &ds_reccaps; @@ -721,6 +728,7 @@ ds_intr(void *p) struct sc_info *sc = (struct sc_info *)p; u_int32_t i, x; + snd_mtxlock(sc->lock); i = ds_rd(sc, YDSXGR_STATUS, 4); if (i & 0x00008000) device_printf(sc->dev, "timeout irq\n"); @@ -746,6 +754,7 @@ ds_intr(void *p) ds_wr(sc, YDSXGR_MODE, i | 0x00000002, 4); } + snd_mtxunlock(sc->lock); } /* -------------------------------------------------------------------- */ @@ -922,12 +931,12 @@ ds_pci_attach(device_t dev) struct ac97_info *codec = NULL; char status[SND_STATUSLEN]; - if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT)) == NULL) { + if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO)) == NULL) { device_printf(dev, "cannot allocate softc\n"); return ENXIO; } - bzero(sc, sizeof(*sc)); + sc->lock = snd_mtxcreate(device_get_nameunit(dev)); sc->dev = dev; subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev); sc->type = ds_finddev(pci_get_devid(dev), subdev); @@ -973,8 +982,7 @@ ds_pci_attach(device_t dev) sc->irqid = 0; sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); - if (!sc->irq || - bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ds_intr, sc, &sc->ih)) { + if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ds_intr, sc, &sc->ih)) { device_printf(dev, "unable to map interrupt\n"); goto bad; } @@ -1003,6 +1011,8 @@ bad: bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); if (sc->parent_dmat) bus_dma_tag_destroy(sc->parent_dmat); + if (sc->lock) + snd_mtxfree(sc->lock); free(sc, M_DEVBUF); return ENXIO; } @@ -1041,6 +1051,7 @@ ds_pci_detach(device_t dev) bus_teardown_intr(dev, sc->irq, sc->ih); bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); bus_dma_tag_destroy(sc->parent_dmat); + snd_mtxfree(sc->lock); free(sc, M_DEVBUF); return 0; } @@ -1057,7 +1068,7 @@ static device_method_t ds1_methods[] = { static driver_t ds1_driver = { "pcm", ds1_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pci/emu10k1.c b/sys/dev/sound/pci/emu10k1.c index e816572..388a8e7 100644 --- a/sys/dev/sound/pci/emu10k1.c +++ b/sys/dev/sound/pci/emu10k1.c @@ -61,7 +61,7 @@ struct emu_voice { int start, end, vol; u_int32_t buf; struct emu_voice *slave; - pcm_channel *channel; + struct pcm_channel *channel; }; struct sc_info; @@ -70,16 +70,16 @@ struct sc_info; struct sc_pchinfo { int spd, fmt, blksz, run; struct emu_voice *master, *slave; - snd_dbuf *buffer; - pcm_channel *channel; + struct snd_dbuf *buffer; + struct pcm_channel *channel; struct sc_info *parent; }; struct sc_rchinfo { int spd, fmt, run, blksz, num; u_int32_t idxreg, basereg, sizereg, setupreg, irqmask; - snd_dbuf *buffer; - pcm_channel *channel; + struct snd_dbuf *buffer; + struct pcm_channel *channel; struct sc_info *parent; }; @@ -96,6 +96,7 @@ struct sc_info { struct resource *reg, *irq; int regtype, regid, irqid; void *ih; + void *lock; int timer, timerinterval; int pnum, rnum; @@ -144,7 +145,7 @@ static u_int32_t emu_rfmt_efx[] = { 0 }; -static pcmchan_caps emu_reccaps[3] = { +static struct pcmchan_caps emu_reccaps[3] = { {8000, 48000, emu_rfmt_ac97, 0}, {8000, 8000, emu_rfmt_mic, 0}, {48000, 48000, emu_rfmt_efx, 0}, @@ -158,7 +159,7 @@ static u_int32_t emu_pfmt[] = { 0 }; -static pcmchan_caps emu_playcaps = {4000, 48000, emu_pfmt, 0}; +static struct pcmchan_caps emu_playcaps = {4000, 48000, emu_pfmt, 0}; static int adcspeed[8] = {48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000}; @@ -239,6 +240,7 @@ emu_wrefx(struct sc_info *sc, unsigned int pc, unsigned int data) /* -------------------------------------------------------------------- */ /* ac97 codec */ +/* no locking needed */ static int emu_rdcd(kobj_t obj, void *devinfo, int regno) @@ -267,40 +269,6 @@ static kobj_method_t emu_ac97_methods[] = { AC97_DECLARE(emu_ac97); /* -------------------------------------------------------------------- */ - -#if 0 -/* playback channel interrupts */ -static u_int32_t -emu_testint(struct sc_info *sc, char channel) -{ - int reg = (channel & 0x20)? CLIPH : CLIPL; - channel &= 0x1f; - reg |= 1 << 24; - reg |= channel << 16; - return emu_rdptr(sc, 0, reg); -} - -static void -emu_clrint(struct sc_info *sc, char channel) -{ - int reg = (channel & 0x20)? CLIPH : CLIPL; - channel &= 0x1f; - reg |= 1 << 24; - reg |= channel << 16; - emu_wrptr(sc, 0, reg, 1); -} - -static void -emu_enaint(struct sc_info *sc, char channel, int enable) -{ - int reg = (channel & 0x20)? CLIEH : CLIEL; - channel &= 0x1f; - reg |= 1 << 24; - reg |= channel << 16; - emu_wrptr(sc, 0, reg, enable); -} -#endif - /* stuff */ static int emu_settimer(struct sc_info *sc) @@ -450,15 +418,15 @@ emu_valloc(struct sc_info *sc) static int emu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s, - u_int32_t sz, pcm_channel *c) + u_int32_t sz, struct snd_dbuf *b) { void *buf; buf = emu_memalloc(sc, sz); if (buf == NULL) return -1; - if (c != NULL) - sndbuf_setup(&c->buffer, buf, sz); + if (b != NULL) + sndbuf_setup(b, buf, sz); m->start = emu_memstart(sc, buf) * EMUPAGESIZE; m->end = m->start + sz; m->channel = NULL; @@ -646,10 +614,11 @@ emu_vdump(struct sc_info *sc, struct emu_voice *v) /* channel interface */ static void * -emupchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +emupchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sc_info *sc = devinfo; struct sc_pchinfo *ch; + void *r; KASSERT(dir == PCMDIR_PLAY, ("emupchan_init: bad direction")); ch = &sc->pch[sc->pnum++]; @@ -659,12 +628,13 @@ emupchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) ch->blksz = EMU_BUFFSIZE / 2; ch->fmt = AFMT_U8; ch->spd = 8000; + snd_mtxlock(sc->lock); ch->master = emu_valloc(sc); ch->slave = emu_valloc(sc); - if (emu_vinit(sc, ch->master, ch->slave, EMU_BUFFSIZE, ch->channel)) - return NULL; - else - return ch; + r = (emu_vinit(sc, ch->master, ch->slave, EMU_BUFFSIZE, ch->buffer))? NULL : ch; + snd_mtxunlock(sc->lock); + + return r; } static int @@ -672,8 +642,13 @@ emupchan_free(kobj_t obj, void *data) { struct sc_pchinfo *ch = data; struct sc_info *sc = ch->parent; + int r; + + snd_mtxlock(sc->lock); + r = emu_memfree(sc, sndbuf_getbuf(ch->buffer)); + snd_mtxunlock(sc->lock); - return emu_memfree(sc, sndbuf_getbuf(ch->buffer)); + return r; } static int @@ -702,8 +677,10 @@ emupchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) int irqrate, blksz; ch->blksz = blocksize; + snd_mtxlock(sc->lock); emu_settimer(sc); irqrate = 48000 / sc->timerinterval; + snd_mtxunlock(sc->lock); blksz = (ch->spd * sndbuf_getbps(ch->buffer)) / irqrate; return blocksize; } @@ -717,6 +694,7 @@ emupchan_trigger(kobj_t obj, void *data, int go) if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) return 0; + snd_mtxlock(sc->lock); if (go == PCMTRIG_START) { emu_vsetup(ch); emu_vwrite(sc, ch->master); @@ -733,6 +711,7 @@ emupchan_trigger(kobj_t obj, void *data, int go) } ch->run = (go == PCMTRIG_START)? 1 : 0; emu_vtrigger(sc, ch->master, ch->run); + snd_mtxunlock(sc->lock); return 0; } @@ -741,11 +720,16 @@ emupchan_getptr(kobj_t obj, void *data) { struct sc_pchinfo *ch = data; struct sc_info *sc = ch->parent; + int r; + + snd_mtxlock(sc->lock); + r = emu_vpos(sc, ch->master); + snd_mtxunlock(sc->lock); - return emu_vpos(sc, ch->master); + return r; } -static pcmchan_caps * +static struct pcmchan_caps * emupchan_getcaps(kobj_t obj, void *data) { return &emu_playcaps; @@ -766,7 +750,7 @@ CHANNEL_DECLARE(emupchan); /* channel interface */ static void * -emurchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +emurchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sc_info *sc = devinfo; struct sc_rchinfo *ch; @@ -809,8 +793,10 @@ emurchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) if (sndbuf_alloc(ch->buffer, sc->parent_dmat, EMU_BUFFSIZE) == -1) return NULL; else { + snd_mtxlock(sc->lock); emu_wrptr(sc, 0, ch->basereg, vtophys(sndbuf_getbuf(ch->buffer))); emu_wrptr(sc, 0, ch->sizereg, 0); /* off */ + snd_mtxunlock(sc->lock); return ch; } } @@ -847,8 +833,10 @@ emurchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) int irqrate, blksz; ch->blksz = blocksize; + snd_mtxlock(sc->lock); emu_settimer(sc); irqrate = 48000 / sc->timerinterval; + snd_mtxunlock(sc->lock); blksz = (ch->spd * sndbuf_getbps(ch->buffer)) / irqrate; return blocksize; } @@ -861,6 +849,7 @@ emurchan_trigger(kobj_t obj, void *data, int go) struct sc_info *sc = ch->parent; u_int32_t val; + snd_mtxlock(sc->lock); switch(go) { case PCMTRIG_START: ch->run = 1; @@ -893,6 +882,7 @@ emurchan_trigger(kobj_t obj, void *data, int go) default: break; } + snd_mtxunlock(sc->lock); return 0; } @@ -902,11 +892,16 @@ emurchan_getptr(kobj_t obj, void *data) { struct sc_rchinfo *ch = data; struct sc_info *sc = ch->parent; + int r; + + snd_mtxlock(sc->lock); + r = emu_rdptr(sc, 0, ch->idxreg) & 0x0000ffff; + snd_mtxunlock(sc->lock); - return emu_rdptr(sc, 0, ch->idxreg) & 0x0000ffff; + return r; } -static pcmchan_caps * +static struct pcmchan_caps * emurchan_getcaps(kobj_t obj, void *data) { struct sc_rchinfo *ch = data; @@ -1421,12 +1416,12 @@ emu_pci_attach(device_t dev) int i, mapped; char status[SND_STATUSLEN]; - if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT)) == NULL) { + if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO)) == NULL) { device_printf(dev, "cannot allocate softc\n"); return ENXIO; } - bzero(sc, sizeof(*sc)); + sc->lock = snd_mtxcreate(device_get_nameunit(dev)); sc->dev = dev; sc->type = pci_get_devid(dev); sc->rev = pci_get_revid(dev); @@ -1482,8 +1477,7 @@ emu_pci_attach(device_t dev) sc->irqid = 0; sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); - if (!sc->irq || - bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, emu_intr, sc, &sc->ih)) { + if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, emu_intr, sc, &sc->ih)) { device_printf(dev, "unable to map interrupt\n"); goto bad; } @@ -1508,6 +1502,7 @@ bad: if (sc->ih) bus_teardown_intr(dev, sc->irq, sc->ih); if (sc->irq) bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); if (sc->parent_dmat) bus_dma_tag_destroy(sc->parent_dmat); + if (sc->lock) snd_mtxfree(sc->lock); free(sc, M_DEVBUF); return ENXIO; } @@ -1530,6 +1525,7 @@ emu_pci_detach(device_t dev) bus_teardown_intr(dev, sc->irq, sc->ih); bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); bus_dma_tag_destroy(sc->parent_dmat); + snd_mtxfree(sc->lock); free(sc, M_DEVBUF); return 0; @@ -1548,7 +1544,7 @@ static device_method_t emu_methods[] = { static driver_t emu_driver = { "pcm", emu_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pci/es137x.c b/sys/dev/sound/pci/es137x.c index 6ea6507..116a0ff 100644 --- a/sys/dev/sound/pci/es137x.c +++ b/sys/dev/sound/pci/es137x.c @@ -79,8 +79,8 @@ struct es_info; struct es_chinfo { struct es_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; + struct pcm_channel *channel; + struct snd_dbuf *buffer; int dir, num; u_int32_t fmt, blksz, bufsz; }; @@ -122,7 +122,7 @@ static u_int32_t es_playfmt[] = { AFMT_STEREO | AFMT_S16_LE, 0 }; -static pcmchan_caps es_playcaps = {4000, 48000, es_playfmt, 0}; +static struct pcmchan_caps es_playcaps = {4000, 48000, es_playfmt, 0}; static u_int32_t es_recfmt[] = { AFMT_U8, @@ -131,7 +131,7 @@ static u_int32_t es_recfmt[] = { AFMT_STEREO | AFMT_S16_LE, 0 }; -static pcmchan_caps es_reccaps = {4000, 48000, es_recfmt, 0}; +static struct pcmchan_caps es_reccaps = {4000, 48000, es_recfmt, 0}; static const struct { unsigned volidx:4; @@ -157,7 +157,7 @@ static const struct { /* The es1370 mixer interface */ static int -es1370_mixinit(snd_mixer *m) +es1370_mixinit(struct snd_mixer *m) { int i; u_int32_t v; @@ -174,7 +174,7 @@ es1370_mixinit(snd_mixer *m) } static int -es1370_mixset(snd_mixer *m, unsigned dev, unsigned left, unsigned right) +es1370_mixset(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { int l, r, rl, rr; @@ -195,7 +195,7 @@ es1370_mixset(snd_mixer *m, unsigned dev, unsigned left, unsigned right) } static int -es1370_mixsetrecsrc(snd_mixer *m, u_int32_t src) +es1370_mixsetrecsrc(struct snd_mixer *m, u_int32_t src) { int i, j = 0; @@ -245,7 +245,7 @@ es1370_wrcodec(struct es_info *es, u_char i, u_char data) /* channel interface */ static void * -eschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +eschan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct es_info *es = devinfo; struct es_chinfo *ch = (dir == PCMDIR_PLAY)? &es->pch : &es->rch; @@ -394,7 +394,7 @@ eschan_getptr(kobj_t obj, void *data) return cnt << 2; } -static pcmchan_caps * +static struct pcmchan_caps * eschan_getcaps(kobj_t obj, void *data) { struct es_chinfo *ch = data; @@ -818,8 +818,7 @@ es_pci_attach(device_t dev) es->irqid = 0; es->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &es->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); - if (!es->irq - || bus_setup_intr(dev, es->irq, INTR_TYPE_TTY, es_intr, es, &es->ih)) { + if (!es->irq || snd_setup_intr(dev, es->irq, 0, es_intr, es, &es->ih)) { device_printf(dev, "unable to map interrupt\n"); goto bad; } @@ -887,7 +886,7 @@ static device_method_t es_methods[] = { static driver_t es_driver = { "pcm", es_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pci/fm801.c b/sys/dev/sound/pci/fm801.c index 48b9940..0584c01 100644 --- a/sys/dev/sound/pci/fm801.c +++ b/sys/dev/sound/pci/fm801.c @@ -102,7 +102,7 @@ #define DPRINT if(0) printf /* -static int fm801ch_setup(pcm_channel *c); +static int fm801ch_setup(struct pcm_channel *c); */ static u_int32_t fmts[] = { @@ -113,7 +113,7 @@ static u_int32_t fmts[] = { 0 }; -static pcmchan_caps fm801ch_caps = { +static struct pcmchan_caps fm801ch_caps = { 4000, 48000, fmts, 0 }; @@ -122,8 +122,8 @@ struct fm801_info; struct fm801_chinfo { struct fm801_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; + struct pcm_channel *channel; + struct snd_dbuf *buffer; u_int32_t spd, dir, fmt; /* speed, direction, format */ u_int32_t shift; }; @@ -318,7 +318,7 @@ fm801_intr(void *p) /* -------------------------------------------------------------------- */ /* channel interface */ static void * -fm801ch_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +fm801ch_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct fm801_info *fm801 = (struct fm801_info *)devinfo; struct fm801_chinfo *ch = (dir == PCMDIR_PLAY)? &fm801->pch : &fm801->rch; @@ -504,7 +504,7 @@ fm801ch_getptr(kobj_t obj, void *data) return result; } -static pcmchan_caps * +static struct pcmchan_caps * fm801ch_getcaps(kobj_t obj, void *data) { return &fm801ch_caps; @@ -615,9 +615,7 @@ fm801_pci_attach(device_t dev) fm801->irqid = 0; fm801->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &fm801->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); - if (!fm801->irq || - bus_setup_intr(dev, fm801->irq, INTR_TYPE_TTY, - fm801_intr, fm801, &fm801->ih)) { + if (!fm801->irq || snd_setup_intr(dev, fm801->irq, 0, fm801_intr, fm801, &fm801->ih)) { device_printf(dev, "unable to map interrupt\n"); goto oops; } @@ -703,7 +701,7 @@ static device_method_t fm801_methods[] = { static driver_t fm801_driver = { "pcm", fm801_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pci/maestro.c b/sys/dev/sound/pci/maestro.c index e35e547..2042eaf 100644 --- a/sys/dev/sound/pci/maestro.c +++ b/sys/dev/sound/pci/maestro.c @@ -81,8 +81,8 @@ */ struct agg_chinfo { struct agg_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; + struct pcm_channel *channel; + struct snd_dbuf *buffer; bus_addr_t offset; u_int32_t blocksize; u_int32_t speed; @@ -109,6 +109,7 @@ struct agg_info { bus_addr_t baseaddr; struct ac97_info *codec; + void *lock; u_int playchns, active; struct agg_chinfo pch[AGG_MAXPLAYCH]; @@ -637,7 +638,7 @@ set_timer(struct agg_info *ess) */ static void * -aggch_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +aggch_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct agg_info *ess = devinfo; struct agg_chinfo *ch; @@ -661,8 +662,7 @@ aggch_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) if (physaddr < ess->baseaddr || ch->offset > WPWA_MAXADDR) { device_printf(ess->dev, "offset %#x exceeds limit. ", ch->offset); - dma_free(ess, b->buf); - b->buf = NULL; + dma_free(ess, sndbuf_getbuf(b)); return NULL; } @@ -786,7 +786,7 @@ aggch_getplayptr(kobj_t obj, void *data) return cp; } -static pcmchan_caps * +static struct pcmchan_caps * aggch_getcaps(kobj_t obj, void *data) { static u_int32_t playfmt[] = { @@ -798,7 +798,7 @@ aggch_getcaps(kobj_t obj, void *data) AFMT_STEREO | AFMT_S16_LE, 0 }; - static pcmchan_caps playcaps = {2000, 96000, playfmt, 0}; + static struct pcmchan_caps playcaps = {2000, 96000, playfmt, 0}; static u_int32_t recfmt[] = { AFMT_S8, @@ -807,7 +807,7 @@ aggch_getcaps(kobj_t obj, void *data) AFMT_STEREO | AFMT_S16_LE, 0 }; - static pcmchan_caps reccaps = {4000, 48000, recfmt, 0}; + static struct pcmchan_caps reccaps = {4000, 48000, recfmt, 0}; return (((struct agg_chinfo*)data)->dir == PCMDIR_PLAY)? &playcaps : &reccaps; @@ -1020,8 +1020,7 @@ agg_attach(device_t dev) irq = bus_alloc_resource(dev, SYS_RES_IRQ, &irqid, 0, BUS_SPACE_UNRESTRICTED, 1, RF_ACTIVE | RF_SHAREABLE); - if (irq == NULL - || bus_setup_intr(dev, irq, INTR_TYPE_TTY, agg_intr, ess, &ih)) { + if (irq == NULL || snd_setup_intr(dev, irq, 0, agg_intr, ess, &ih)) { device_printf(dev, "unable to map interrupt\n"); goto bad; } @@ -1183,7 +1182,7 @@ static device_method_t agg_methods[] = { static driver_t agg_driver = { "pcm", agg_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pci/maestro3.c b/sys/dev/sound/pci/maestro3.c index 9551dee..375fa31 100644 --- a/sys/dev/sound/pci/maestro3.c +++ b/sys/dev/sound/pci/maestro3.c @@ -95,8 +95,8 @@ struct sc_info; struct sc_pchinfo { u_int32_t spd; u_int32_t fmt; - snd_dbuf *buffer; - pcm_channel *channel; + struct snd_dbuf *buffer; + struct pcm_channel *channel; struct sc_info *parent; u_int32_t bufsize; u_int32_t dac_data; @@ -107,8 +107,8 @@ struct sc_pchinfo { struct sc_rchinfo { u_int32_t spd; u_int32_t fmt; - snd_dbuf *buffer; - pcm_channel *channel; + struct snd_dbuf *buffer; + struct pcm_channel *channel; struct sc_info *parent; u_int32_t bufsize; u_int32_t adc_data; @@ -145,24 +145,24 @@ struct sc_info { /* -------------------------------------------------------------------- */ /* play channel interface */ -static void *m3_pchan_init(kobj_t, void *, snd_dbuf *, pcm_channel *, int); +static void *m3_pchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int); static int m3_pchan_free(kobj_t, void *); static int m3_pchan_setformat(kobj_t, void *, u_int32_t); static int m3_pchan_setspeed(kobj_t, void *, u_int32_t); static int m3_pchan_setblocksize(kobj_t, void *, u_int32_t); static int m3_pchan_trigger(kobj_t, void *, int); static int m3_pchan_getptr(kobj_t, void *); -static pcmchan_caps *m3_pchan_getcaps(kobj_t, void *); +static struct pcmchan_caps *m3_pchan_getcaps(kobj_t, void *); /* record channel interface */ -static void *m3_rchan_init(kobj_t, void *, snd_dbuf *, pcm_channel *, int); +static void *m3_rchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int); static int m3_rchan_free(kobj_t, void *); static int m3_rchan_setformat(kobj_t, void *, u_int32_t); static int m3_rchan_setspeed(kobj_t, void *, u_int32_t); static int m3_rchan_setblocksize(kobj_t, void *, u_int32_t); static int m3_rchan_trigger(kobj_t, void *, int); static int m3_rchan_getptr(kobj_t, void *); -static pcmchan_caps *m3_rchan_getcaps(kobj_t, void *); +static struct pcmchan_caps *m3_rchan_getcaps(kobj_t, void *); /* talk to the codec - called from ac97.c */ static int m3_initcd(kobj_t, void *); @@ -200,7 +200,7 @@ static u_int32_t m3_playfmt[] = { AFMT_STEREO | AFMT_S16_LE, 0 }; -static pcmchan_caps m3_playcaps = {8000, 48000, m3_playfmt, 0}; +static struct pcmchan_caps m3_playcaps = {8000, 48000, m3_playfmt, 0}; static kobj_method_t m3_pch_methods[] = { KOBJMETHOD(channel_init, m3_pchan_init), @@ -222,7 +222,7 @@ static u_int32_t m3_recfmt[] = { AFMT_STEREO | AFMT_S16_LE, 0 }; -static pcmchan_caps m3_reccaps = {8000, 48000, m3_recfmt, 0}; +static struct pcmchan_caps m3_reccaps = {8000, 48000, m3_recfmt, 0}; static kobj_method_t m3_rch_methods[] = { KOBJMETHOD(channel_init, m3_rchan_init), @@ -314,7 +314,7 @@ m3_rdcd(kobj_t kobj, void *devinfo, int regno) return -1; } m3_wr_1(sc, CODEC_COMMAND, (regno & 0x7f) | 0x80); - DELAY(21); /* ac97 cycle = 20.8 usec */ + DELAY(50); /* ac97 cycle = 20.8 usec */ if (m3_wait(sc)) { device_printf(sc->dev, "m3_rdcd timed out.\n"); return -1; @@ -333,6 +333,7 @@ m3_wrcd(kobj_t kobj, void *devinfo, int regno, u_int32_t data) } m3_wr_2(sc, CODEC_DATA, data); m3_wr_1(sc, CODEC_COMMAND, regno & 0x7f); + DELAY(50); /* ac97 cycle = 20.8 usec */ return 0; } @@ -343,7 +344,7 @@ m3_wrcd(kobj_t kobj, void *devinfo, int regno, u_int32_t data) #define HI(x) (((x) & 0xffff0000) >> 16) static void * -m3_pchan_init(kobj_t kobj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +m3_pchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sc_info *sc = devinfo; struct sc_pchinfo *ch; @@ -609,7 +610,7 @@ m3_pchan_getptr(kobj_t kobj, void *chdata) return (bus_crnt - bus_base); /* current byte offset of channel */ } -static pcmchan_caps * +static struct pcmchan_caps * m3_pchan_getcaps(kobj_t kobj, void *chdata) { struct sc_pchinfo *ch = chdata; @@ -623,7 +624,7 @@ m3_pchan_getcaps(kobj_t kobj, void *chdata) /* rec channel interface */ static void * -m3_rchan_init(kobj_t kobj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +m3_rchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sc_info *sc = devinfo; struct sc_rchinfo *ch; @@ -879,7 +880,7 @@ m3_rchan_getptr(kobj_t kobj, void *chdata) return (bus_crnt - bus_base); /* current byte offset of channel */ } -static pcmchan_caps * +static struct pcmchan_caps * m3_rchan_getcaps(kobj_t kobj, void *chdata) { struct sc_rchinfo *ch = chdata; @@ -1133,8 +1134,7 @@ m3_pci_attach(device_t dev) goto bad; } - if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, m3_intr, sc, - &sc->ih)) { + if (snd_setup_intr(dev, sc->irq, 0, m3_intr, sc, &sc->ih)) { device_printf(dev, "unable to setup interrupt\n"); goto bad; } @@ -1192,6 +1192,7 @@ m3_pci_attach(device_t dev) device_printf(dev, "attach: pcm_setstatus error\n"); goto bad; } + mixer_hwvol_init(dev); /* Create the buffer for saving the card state during suspend */ len = sizeof(u_int16_t) * (REV_B_CODE_MEMORY_LENGTH + @@ -1491,7 +1492,7 @@ static device_method_t m3_methods[] = { static driver_t m3_driver = { "pcm", m3_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pci/neomagic.c b/sys/dev/sound/pci/neomagic.c index 5a6ca8c..8771136 100644 --- a/sys/dev/sound/pci/neomagic.c +++ b/sys/dev/sound/pci/neomagic.c @@ -48,8 +48,8 @@ struct sc_info; /* channel registers */ struct sc_chinfo { int spd, dir, fmt; - snd_dbuf *buffer; - pcm_channel *channel; + struct snd_dbuf *buffer; + struct pcm_channel *channel; struct sc_info *parent; }; @@ -117,7 +117,7 @@ static u_int32_t nm_fmt[] = { AFMT_STEREO | AFMT_S16_LE, 0 }; -static pcmchan_caps nm_caps = {4000, 48000, nm_fmt, 0}; +static struct pcmchan_caps nm_caps = {4000, 48000, nm_fmt, 0}; /* -------------------------------------------------------------------- */ @@ -329,7 +329,7 @@ nm_setch(struct sc_chinfo *ch) /* channel interface */ static void * -nmchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +nmchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sc_info *sc = devinfo; struct sc_chinfo *ch; @@ -341,7 +341,7 @@ nmchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) sndbuf_setup(ch->buffer, (u_int8_t *)rman_get_virtual(sc->buf) + chnbuf, NM_BUFFSIZE); if (bootverbose) device_printf(sc->dev, "%s buf %p\n", (dir == PCMDIR_PLAY)? - "play" : "rec", ch->buffer->buf); + "play" : "rec", sndbuf_getbuf(ch->buffer)); ch->parent = sc; ch->channel = c; ch->dir = dir; @@ -432,7 +432,7 @@ nmchan_getptr(kobj_t obj, void *data) return nm_rd(sc, NM_RBUFFER_CURRP, 4) - sc->rbuf; } -static pcmchan_caps * +static struct pcmchan_caps * nmchan_getcaps(kobj_t obj, void *data) { return &nm_caps; @@ -623,8 +623,7 @@ nm_pci_attach(device_t dev) sc->irqid = 0; sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); - if (!sc->irq || - bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, nm_intr, sc, &sc->ih)) { + if (!sc->irq || snd_setup_intr(dev, sc->irq, 0, nm_intr, sc, &sc->ih)) { device_printf(dev, "unable to map interrupt\n"); goto bad; } @@ -702,7 +701,7 @@ static device_method_t nm_methods[] = { static driver_t nm_driver = { "pcm", nm_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pci/solo.c b/sys/dev/sound/pci/solo.c index 71a00f1..d6d7c71 100644 --- a/sys/dev/sound/pci/solo.c +++ b/sys/dev/sound/pci/solo.c @@ -55,7 +55,7 @@ static u_int32_t ess_playfmt[] = { AFMT_STEREO | AFMT_U16_LE, 0 }; -static pcmchan_caps ess_playcaps = {5000, 49000, ess_playfmt, 0}; +static struct pcmchan_caps ess_playcaps = {5000, 49000, ess_playfmt, 0}; /* * Recording output is byte-swapped @@ -71,14 +71,14 @@ static u_int32_t ess_recfmt[] = { AFMT_STEREO | AFMT_U16_BE, 0 }; -static pcmchan_caps ess_reccaps = {5000, 49000, ess_recfmt, 0}; +static struct pcmchan_caps ess_reccaps = {5000, 49000, ess_recfmt, 0}; struct ess_info; struct ess_chinfo { struct ess_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; + struct pcm_channel *channel; + struct snd_dbuf *buffer; int dir, hwch, stopping; u_int32_t fmt, spd, blksz; }; @@ -510,7 +510,7 @@ ess_stop(struct ess_chinfo *ch) /* -------------------------------------------------------------------- */ /* channel interface for ESS18xx */ static void * -esschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +esschan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct ess_info *sc = devinfo; struct ess_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch; @@ -595,7 +595,7 @@ esschan_getptr(kobj_t obj, void *data) return ess_dmapos(sc, ch->hwch); } -static pcmchan_caps * +static struct pcmchan_caps * esschan_getcaps(kobj_t obj, void *data) { struct ess_chinfo *ch = data; @@ -618,7 +618,7 @@ CHANNEL_DECLARE(esschan); /************************************************************/ static int -essmix_init(snd_mixer *m) +essmix_init(struct snd_mixer *m) { struct ess_info *sc = mix_getdevinfo(m); @@ -635,7 +635,7 @@ essmix_init(snd_mixer *m) } static int -essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) +essmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct ess_info *sc = mix_getdevinfo(m); int preg = 0, rreg = 0, l, r; @@ -695,7 +695,7 @@ essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) } static int -essmix_setrecsrc(snd_mixer *m, u_int32_t src) +essmix_setrecsrc(struct snd_mixer *m, u_int32_t src) { struct ess_info *sc = mix_getdevinfo(m); u_char recdev; @@ -944,7 +944,7 @@ ess_attach(device_t dev) if (sc->newspeed) ess_setmixer(sc, 0x71, 0x2a); - bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ess_intr, sc, &sc->ih); + snd_setup_intr(dev, sc->irq, 0, ess_intr, sc, &sc->ih); if (!sc->duplex) pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); @@ -1005,7 +1005,7 @@ static device_method_t ess_methods[] = { static driver_t ess_driver = { "pcm", ess_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; DRIVER_MODULE(snd_solo, pci, ess_driver, pcm_devclass, 0, 0); diff --git a/sys/dev/sound/pci/t4dwave.c b/sys/dev/sound/pci/t4dwave.c index b1a3c44..76254cc 100644 --- a/sys/dev/sound/pci/t4dwave.c +++ b/sys/dev/sound/pci/t4dwave.c @@ -52,15 +52,15 @@ struct tr_chinfo { u_int32_t rvol, cvol; u_int32_t gvsel, pan, vol, ctrl; int index, bufhalf; - snd_dbuf *buffer; - pcm_channel *channel; + struct snd_dbuf *buffer; + struct pcm_channel *channel; struct tr_info *parent; }; struct tr_rchinfo { u_int32_t delta; - snd_dbuf *buffer; - pcm_channel *channel; + struct snd_dbuf *buffer; + struct pcm_channel *channel; struct tr_info *parent; }; @@ -76,6 +76,8 @@ struct tr_info { int regtype, regid, irqid; void *ih; + void *lock; + u_int32_t playchns; struct tr_chinfo chinfo[TR_MAXPLAYCH]; struct tr_rchinfo recchinfo; @@ -94,7 +96,7 @@ static u_int32_t tr_recfmt[] = { AFMT_STEREO | AFMT_U16_LE, 0 }; -static pcmchan_caps tr_reccaps = {4000, 48000, tr_recfmt, 0}; +static struct pcmchan_caps tr_reccaps = {4000, 48000, tr_recfmt, 0}; static u_int32_t tr_playfmt[] = { AFMT_U8, @@ -107,7 +109,7 @@ static u_int32_t tr_playfmt[] = { AFMT_STEREO | AFMT_U16_LE, 0 }; -static pcmchan_caps tr_playcaps = {4000, 48000, tr_playfmt, 0}; +static struct pcmchan_caps tr_playcaps = {4000, 48000, tr_playfmt, 0}; /* -------------------------------------------------------------------- */ @@ -168,9 +170,11 @@ tr_rdcd(kobj_t obj, void *devinfo, int regno) } regno &= 0x7f; + snd_mtxlock(tr->lock); tr_wr(tr, treg, regno | trw, 4); j=trw; for (i=TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) j=tr_rd(tr, treg, 4); + snd_mtxunlock(tr->lock); if (i == 0) printf("codec timeout during read of register %x\n", regno); return (j >> TR_CDC_DATA) & 0xffff; } @@ -200,11 +204,13 @@ tr_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) printf("tr_wrcd: reg %x was %x", regno, tr_rdcd(devinfo, regno)); #endif j=trw; + snd_mtxlock(tr->lock); for (i=TR_TIMEOUT_CDC; (i>0) && (j & trw); i--) j=tr_rd(tr, treg, 4); tr_wr(tr, treg, (data << TR_CDC_DATA) | regno | trw, 4); #if 0 printf(" - wrote %x, now %x\n", data, tr_rdcd(devinfo, regno)); #endif + snd_mtxunlock(tr->lock); if (i==0) printf("codec timeout writing %x, data %x\n", regno, data); return (i > 0)? 0 : -1; } @@ -250,6 +256,7 @@ tr_enaint(struct tr_chinfo *ch, int enable) u_int32_t i, reg; int bank, chan; + snd_mtxlock(tr->lock); bank = (ch->index & 0x20) ? 1 : 0; chan = ch->index & 0x1f; reg = bank? TR_REG_INTENB : TR_REG_INTENA; @@ -260,6 +267,7 @@ tr_enaint(struct tr_chinfo *ch, int enable) tr_clrint(ch); tr_wr(tr, reg, i, 4); + snd_mtxunlock(tr->lock); } /* playback channels */ @@ -336,9 +344,11 @@ tr_wrch(struct tr_chinfo *ch) cr[3]|=(ch->alpha<<20) | (ch->fms<<16) | (ch->fmc<<14); break; } + snd_mtxlock(tr->lock); tr_selch(ch); for (i=0; i<TR_CHN_REGS; i++) tr_wr(tr, TR_REG_CHNBASE+(i<<2), cr[i], 4); + snd_mtxunlock(tr->lock); } static void @@ -347,9 +357,11 @@ tr_rdch(struct tr_chinfo *ch) struct tr_info *tr = ch->parent; u_int32_t cr[5], i; + snd_mtxlock(tr->lock); tr_selch(ch); for (i=0; i<5; i++) cr[i]=tr_rd(tr, TR_REG_CHNBASE+(i<<2), 4); + snd_mtxunlock(tr->lock); ch->lba= (cr[1] & 0x3fffffff); @@ -396,7 +408,7 @@ tr_fmttobits(u_int32_t fmt) /* channel interface */ static void * -trpchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +trpchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct tr_info *tr = devinfo; struct tr_chinfo *ch; @@ -480,7 +492,7 @@ trpchan_getptr(kobj_t obj, void *data) return ch->cso * sndbuf_getbps(ch->buffer); } -static pcmchan_caps * +static struct pcmchan_caps * trpchan_getcaps(kobj_t obj, void *data) { return &tr_playcaps; @@ -502,7 +514,7 @@ CHANNEL_DECLARE(trpchan); /* rec channel interface */ static void * -trrchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +trrchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct tr_info *tr = devinfo; struct tr_rchinfo *ch; @@ -600,7 +612,7 @@ trrchan_getptr(kobj_t obj, void *data) return tr_rd(tr, TR_REG_DMAR0, 4) - vtophys(sndbuf_getbuf(ch->buffer)); } -static pcmchan_caps * +static struct pcmchan_caps * trrchan_getcaps(kobj_t obj, void *data) { return &tr_reccaps; @@ -646,9 +658,7 @@ tr_intr(void *p) if (ch->bufhalf != tmp) { chn_intr(ch->channel); ch->bufhalf = tmp; - } else - printf("same bufhalf\n"); - + } } } chnum++; @@ -716,6 +726,7 @@ tr_pci_attach(device_t dev) bzero(tr, sizeof(*tr)); tr->type = pci_get_devid(dev); + tr->lock = snd_mtxcreate(device_get_nameunit(dev)); data = pci_read_config(dev, PCIR_COMMAND, 2); data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); @@ -745,8 +756,7 @@ tr_pci_attach(device_t dev) tr->irqid = 0; tr->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &tr->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); - if (!tr->irq || - bus_setup_intr(dev, tr->irq, INTR_TYPE_TTY, tr_intr, tr, &tr->ih)) { + if (!tr->irq || snd_setup_intr(dev, tr->irq, INTR_MPSAFE, tr_intr, tr, &tr->ih)) { device_printf(dev, "unable to map interrupt\n"); goto bad; } @@ -778,6 +788,7 @@ bad: if (tr->ih) bus_teardown_intr(dev, tr->irq, tr->ih); if (tr->irq) bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); if (tr->parent_dmat) bus_dma_tag_destroy(tr->parent_dmat); + if (tr->lock) snd_mtxfree(tr->lock); free(tr, M_DEVBUF); return ENXIO; } @@ -797,6 +808,7 @@ tr_pci_detach(device_t dev) bus_teardown_intr(dev, tr->irq, tr->ih); bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); bus_dma_tag_destroy(tr->parent_dmat); + snd_mtxfree(tr->lock); free(tr, M_DEVBUF); return 0; @@ -814,7 +826,7 @@ static device_method_t tr_methods[] = { static driver_t tr_driver = { "pcm", tr_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pci/via82c686.c b/sys/dev/sound/pci/via82c686.c index 5f5a2b1..7450e2a 100644 --- a/sys/dev/sound/pci/via82c686.c +++ b/sys/dev/sound/pci/via82c686.c @@ -36,12 +36,12 @@ #include <dev/sound/pci/via82c686.h> #define VIA_PCI_ID 0x30581106 -#define NSEGS 16 /* Number of segments in SGD table */ +#define NSEGS 4 /* Number of segments in SGD table */ #define SEGS_PER_CHAN (NSEGS/2) #define TIMEOUT 50 -#define VIA_BUFFSIZE 0x4000 +#define VIA_BUFFSIZE 0x1000 #undef DEB #define DEB(x) @@ -60,9 +60,11 @@ struct via_info; struct via_chinfo { struct via_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; - int dir; + struct pcm_channel *channel; + struct snd_dbuf *buffer; + struct via_dma_op *sgd_table; + int dir, blksz; + int base, count, mode, ctrl; }; struct via_info { @@ -70,39 +72,27 @@ struct via_info { bus_space_handle_t sh; bus_dma_tag_t parent_dmat; bus_dma_tag_t sgd_dmat; + bus_dmamap_t sgd_dmamap; struct resource *reg, *irq; int regid, irqid; void *ih; + struct ac97_info *codec; struct via_chinfo pch, rch; struct via_dma_op *sgd_table; u_int16_t codec_caps; }; -static u_int32_t via_rd(struct via_info *via, int regno, int size); -static void via_wr(struct via_info *, int regno, u_int32_t data, int size); - -static void via_intr(void *); -bus_dmamap_callback_t dma_cb; - -static u_int32_t via_playfmt[] = { - AFMT_U8, - AFMT_STEREO | AFMT_U8, - AFMT_S16_LE, - AFMT_STEREO | AFMT_S16_LE, - 0 -}; -static pcmchan_caps via_playcaps = {4000, 48000, via_playfmt, 0}; - -static u_int32_t via_recfmt[] = { +static u_int32_t via_fmt[] = { AFMT_U8, AFMT_STEREO | AFMT_U8, AFMT_S16_LE, AFMT_STEREO | AFMT_S16_LE, 0 }; -static pcmchan_caps via_reccaps = {4000, 48000, via_recfmt, 0}; +static struct pcmchan_caps via_vracaps = {4000, 48000, via_fmt, 0}; +static struct pcmchan_caps via_caps = {48000, 48000, via_fmt, 0}; static u_int32_t via_rd(struct via_info *via, int regno, int size) @@ -184,8 +174,7 @@ via_write_codec(kobj_t obj, void *addr, int reg, u_int32_t val) if (via_waitready_codec(via)) return -1; - via_wr(via, VIA_CODEC_CTL, - VIA_CODEC_PRIVALID | VIA_CODEC_INDEX(reg) | val, 4); + via_wr(via, VIA_CODEC_CTL, VIA_CODEC_PRIVALID | VIA_CODEC_INDEX(reg) | val, 4); return 0; } @@ -197,16 +186,15 @@ via_read_codec(kobj_t obj, void *addr, int reg) struct via_info *via = addr; if (via_waitready_codec(via)) - return 1; + return -1; - via_wr(via, VIA_CODEC_CTL, - VIA_CODEC_PRIVALID | VIA_CODEC_READ | VIA_CODEC_INDEX(reg),4); + via_wr(via, VIA_CODEC_CTL, VIA_CODEC_PRIVALID | VIA_CODEC_READ | VIA_CODEC_INDEX(reg),4); if (via_waitready_codec(via)) - return 1; + return -1; if (via_waitvalid_codec(via)) - return 1; + return -1; return via_rd(via, VIA_CODEC_CTL, 2); } @@ -220,58 +208,60 @@ AC97_DECLARE(via_ac97); /* -------------------------------------------------------------------- */ -/* channel interface */ -static void * -viachan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) -{ - struct via_info *via = devinfo; - struct via_chinfo *ch = (dir == PCMDIR_PLAY) ? &via->pch : &via->rch; - - ch->parent = via; - ch->channel = c; - ch->buffer = b; - - if (sndbuf_alloc(ch->buffer, via->parent_dmat, VIA_BUFFSIZE) == -1) return NULL; - return ch; -} - static int -viachan_setdir(kobj_t obj, void *data, int dir) +via_buildsgdt(struct via_chinfo *ch) { - struct via_chinfo *ch = data; - struct via_info *via = ch->parent; - struct via_dma_op *ado; - int i, chunk_size; - int phys_addr, flag; + u_int32_t phys_addr, flag; + int i, segs, seg_size; - ch->dir = dir; /* * Build the scatter/gather DMA (SGD) table. * There are four slots in the table: two for play, two for record. * This creates two half-buffers, one of which is playing; the other * is feeding. */ - ado = via->sgd_table; - chunk_size = sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN; + seg_size = ch->blksz; + segs = sndbuf_getsize(ch->buffer) / seg_size; + phys_addr = vtophys(sndbuf_getbuf(ch->buffer)); - if (dir == PCMDIR_REC) { - ado += SEGS_PER_CHAN; + for (i = 0; i < segs; i++) { + flag = (i == segs - 1)? VIA_DMAOP_EOL : VIA_DMAOP_FLAG; + ch->sgd_table[i].ptr = phys_addr + (i * seg_size); + ch->sgd_table[i].flags = flag | seg_size; } - DEB(printf("SGD table located at va %p\n", ado)); - phys_addr = vtophys(sndbuf_getbuf(ch->buffer)); - for (i = 0; i < SEGS_PER_CHAN; i++) { - ado->ptr = phys_addr; - flag = (i == SEGS_PER_CHAN-1) ? - VIA_DMAOP_EOL : VIA_DMAOP_FLAG; - ado->flags = flag | chunk_size; - DEB(printf("ado->ptr/flags = %x/%x\n", phys_addr, flag)); - phys_addr += chunk_size; - ado++; - } return 0; } +/* channel interface */ +static void * +viachan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) +{ + struct via_info *via = devinfo; + struct via_chinfo *ch = (dir == PCMDIR_PLAY)? &via->pch : &via->rch; + + ch->parent = via; + ch->channel = c; + ch->buffer = b; + ch->dir = dir; + ch->sgd_table = &via->sgd_table[(dir == PCMDIR_PLAY)? 0 : SEGS_PER_CHAN]; + if (ch->dir == PCMDIR_PLAY) { + ch->base = VIA_PLAY_DMAOPS_BASE; + ch->count = VIA_PLAY_DMAOPS_COUNT; + ch->ctrl = VIA_RECORD_CONTROL; + ch->mode = VIA_PLAY_MODE; + } else { + ch->base = VIA_RECORD_DMAOPS_BASE; + ch->count = VIA_RECORD_DMAOPS_COUNT; + ch->ctrl = VIA_PLAY_CONTROL; + ch->mode = VIA_RECORD_MODE; + } + + if (sndbuf_alloc(ch->buffer, via->parent_dmat, VIA_BUFFSIZE) == -1) + return NULL; + return ch; +} + static int viachan_setformat(kobj_t obj, void *data, u_int32_t format) { @@ -285,21 +275,11 @@ viachan_setformat(kobj_t obj, void *data, u_int32_t format) if (format & AFMT_S16_LE) mode_set |= VIA_RPMODE_16BIT; - /* Set up for output format */ - if (ch->dir == PCMDIR_PLAY) { - DEB(printf("set play format: %x\n", format)); - mode = via_rd(via, VIA_PLAY_MODE, 1); - mode &= ~(VIA_RPMODE_16BIT | VIA_RPMODE_STEREO); - mode |= mode_set; - via_wr(via, VIA_PLAY_MODE, mode, 1); - } - else { - DEB(printf("set record format: %x\n", format)); - mode = via_rd(via, VIA_RECORD_MODE, 1); + DEB(printf("set format: dir = %d, format=%x\n", ch->dir, format)); + mode = via_rd(via, ch->mode, 1); mode &= ~(VIA_RPMODE_16BIT | VIA_RPMODE_STEREO); mode |= mode_set; - via_wr(via, VIA_RECORD_MODE, mode, 1); - } + via_wr(via, ch->mode, mode, 1); return 0; } @@ -309,6 +289,7 @@ viachan_setspeed(kobj_t obj, void *data, u_int32_t speed) { struct via_chinfo *ch = data; struct via_info *via = ch->parent; + int reg; /* * Basic AC'97 defines a 48 kHz sample rate only. For other rates, @@ -319,31 +300,11 @@ viachan_setspeed(kobj_t obj, void *data, u_int32_t speed) * itself), then negotiate the rate with the codec. Otherwise, * return 48 kHz cuz that's all you got. */ - if (ch->dir == PCMDIR_PLAY) { - DEB(printf("requested play speed: %d\n", speed)); - if (via->codec_caps & AC97_CODEC_DOES_VRA) { - via_write_codec(NULL, via, AC97_REG_EXT_DAC_RATE, speed); - speed = via_read_codec(NULL, via, AC97_REG_EXT_DAC_RATE); - } - else { - DEB(printf("VRA not supported!\n")); - speed = 48000; - } - DEB(printf("obtained play speed: %d\n", speed)); - } - else { - DEB(printf("requested record speed: %d\n", speed)); - if (via->codec_caps & AC97_CODEC_DOES_VRA) { - via_write_codec(NULL, via, AC97_REG_EXT_ADC_RATE, speed); - speed = via_read_codec(NULL, via, AC97_REG_EXT_ADC_RATE); - } - else { - DEB(printf("VRA not supported!\n")); - speed = 48000; - } - DEB(printf("obtained record speed: %d\n", speed)); - } - return speed; + if (via->codec_caps & AC97_EXTCAP_VRA) { + reg = (ch->dir == PCMDIR_PLAY)? AC97_REGEXT_FDACRATE : AC97_REGEXT_LADCRATE; + return ac97_setrate(via->codec, reg, speed); + } else + return 48000; } static int @@ -351,7 +312,10 @@ viachan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) { struct via_chinfo *ch = data; - return sndbuf_getsize(ch->buffer) / 2; + ch->blksz = blocksize; + sndbuf_resize(ch->buffer, SEGS_PER_CHAN, ch->blksz); + + return ch->blksz; } static int @@ -361,37 +325,20 @@ viachan_trigger(kobj_t obj, void *data, int go) struct via_info *via = ch->parent; struct via_dma_op *ado; - if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) return 0; - if (ch->dir == PCMDIR_PLAY) { - if (go == PCMTRIG_START) { - ado = &via->sgd_table[0]; + if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) + return 0; + + ado = ch->sgd_table; DEB(printf("ado located at va=%p pa=%x\n", ado, vtophys(ado))); - via_wr(via, VIA_PLAY_DMAOPS_BASE, vtophys(ado),4); - via_wr(via, VIA_PLAY_CONTROL, - VIA_RPCTRL_START, 1); - } - else { - /* Stop DMA */ - via_wr(via, VIA_PLAY_CONTROL, - VIA_RPCTRL_TERMINATE, 1); - } - } else { + if (go == PCMTRIG_START) { - ado = &via->sgd_table[SEGS_PER_CHAN]; - DEB(printf("ado located at va=%p pa=%x\n", ado, vtophys(ado))); - via_wr(via, VIA_RECORD_DMAOPS_BASE, - vtophys(ado),4); - via_wr(via, VIA_RECORD_CONTROL, - VIA_RPCTRL_START, 1); - } - else { - /* Stop DMA */ - via_wr(via, VIA_RECORD_CONTROL, - VIA_RPCTRL_TERMINATE, 1); - } - } + via_buildsgdt(ch); + via_wr(via, ch->base, vtophys(ado), 4); + via_wr(via, ch->ctrl, VIA_RPCTRL_START, 1); + } else + via_wr(via, ch->ctrl, VIA_RPCTRL_TERMINATE, 1); -DEB(printf("viachan_trigger: go=%d\n", go)); + DEB(printf("viachan_trigger: go=%d\n", go)); return 0; } @@ -401,68 +348,47 @@ viachan_getptr(kobj_t obj, void *data) struct via_chinfo *ch = data; struct via_info *via = ch->parent; struct via_dma_op *ado; - int ptr, base, len, seg; - int base1; + int ptr, base, base1, len, seg; - if (ch->dir == PCMDIR_PLAY) { - ado = &via->sgd_table[0]; - base1 = via_rd(via, VIA_PLAY_DMAOPS_BASE, 4); - len = via_rd(via, VIA_PLAY_DMAOPS_COUNT, 4); - base = via_rd(via, VIA_PLAY_DMAOPS_BASE, 4); - if (base != base1) { /* Avoid race hazzard */ - len = via_rd(via, VIA_PLAY_DMAOPS_COUNT, 4); - } - DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base)); - - /* Base points to SGD segment to do, one past current */ - - /* Determine how many segments have been done */ - seg = (base - vtophys(ado)) / sizeof(struct via_dma_op); - if (seg == 0) seg = SEGS_PER_CHAN; + ado = ch->sgd_table; + base1 = via_rd(via, ch->base, 4); + len = via_rd(via, ch->count, 4); + base = via_rd(via, ch->base, 4); + if (base != base1) /* Avoid race hazard */ + len = via_rd(via, ch->count, 4); - /* Now work out offset: seg less count */ - ptr = seg * sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN - len; - DEB(printf("return ptr=%d\n", ptr)); - return ptr; - } - else { - base1 = via_rd(via, VIA_RECORD_DMAOPS_BASE, 4); - ado = &via->sgd_table[SEGS_PER_CHAN]; - len = via_rd(via, VIA_RECORD_DMAOPS_COUNT, 4); - base = via_rd(via, VIA_RECORD_DMAOPS_BASE, 4); - if (base != base1) { /* Avoid race hazzard */ - len = via_rd(via, VIA_RECORD_DMAOPS_COUNT, 4); - } DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base)); - /* Base points to next block to do, one past current */ + /* Base points to SGD segment to do, one past current */ /* Determine how many segments have been done */ seg = (base - vtophys(ado)) / sizeof(struct via_dma_op); - if (seg == 0) seg = SEGS_PER_CHAN; + if (seg == 0) + seg = SEGS_PER_CHAN; /* Now work out offset: seg less count */ - ptr = seg * sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN - len; - + ptr = (seg * sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN) - len; + if (ch->dir == PCMDIR_REC) { /* DMA appears to operate on memory 'lines' of 32 bytes */ /* so don't return any part line - it isn't in RAM yet */ ptr = ptr & ~0x1f; + } + DEB(printf("return ptr=%d\n", ptr)); return ptr; - } - return 0; } -static pcmchan_caps * +static struct pcmchan_caps * viachan_getcaps(kobj_t obj, void *data) { struct via_chinfo *ch = data; - return (ch->dir == PCMDIR_PLAY) ? &via_playcaps : &via_reccaps; + struct via_info *via = ch->parent; + + return (via->codec_caps & AC97_EXTCAP_VRA)? &via_vracaps : &via_caps; } static kobj_method_t viachan_methods[] = { KOBJMETHOD(channel_init, viachan_init), - KOBJMETHOD(channel_setdir, viachan_setdir), KOBJMETHOD(channel_setformat, viachan_setformat), KOBJMETHOD(channel_setspeed, viachan_setspeed), KOBJMETHOD(channel_setblocksize, viachan_setblocksize), @@ -511,7 +437,8 @@ via_probe(device_t dev) } -void dma_cb(void *p, bus_dma_segment_t *bds, int a, int b) +static void +dma_cb(void *p, bus_dma_segment_t *bds, int a, int b) { } @@ -520,14 +447,9 @@ static int via_attach(device_t dev) { struct via_info *via = 0; - struct ac97_info *codec = 0; char status[SND_STATUSLEN]; - u_int32_t data; - u_int16_t v; - bus_dmamap_t sgd_dma_map; - if ((via = malloc(sizeof *via, M_DEVBUF, M_NOWAIT)) == NULL) { device_printf(dev, "cannot allocate softc\n"); return ENXIO; @@ -541,12 +463,10 @@ via_attach(device_t dev) data = pci_read_config(dev, PCIR_COMMAND, 2); pci_write_config(dev, VIA_PCICONF_MISC, - VIA_PCICONF_ACLINKENAB | VIA_PCICONF_ACSGD | - VIA_PCICONF_ACNOTRST | VIA_PCICONF_ACVSR, 1); + VIA_PCICONF_ACLINKENAB | VIA_PCICONF_ACSGD | VIA_PCICONF_ACNOTRST | VIA_PCICONF_ACVSR, 1); via->regid = PCIR_MAPS; - via->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &via->regid, - 0, ~0, 1, RF_ACTIVE); + via->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &via->regid, 0, ~0, 1, RF_ACTIVE); if (!via->reg) { device_printf(dev, "cannot allocate bus resource."); goto bad; @@ -555,44 +475,24 @@ via_attach(device_t dev) via->sh = rman_get_bushandle(via->reg); via->irqid = 0; - via->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &via->irqid, - 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); - if (!via->irq - || bus_setup_intr(dev, via->irq, INTR_TYPE_TTY, via_intr, via, &via->ih)){ + via->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &via->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); + if (!via->irq || snd_setup_intr(dev, via->irq, 0, via_intr, via, &via->ih)) { device_printf(dev, "unable to map interrupt\n"); goto bad; } - via_wr(via, VIA_PLAY_MODE, - VIA_RPMODE_AUTOSTART | - VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1); - via_wr(via, VIA_RECORD_MODE, - VIA_RPMODE_AUTOSTART | - VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1); + via_wr(via, VIA_PLAY_MODE, VIA_RPMODE_AUTOSTART | VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1); + via_wr(via, VIA_RECORD_MODE, VIA_RPMODE_AUTOSTART | VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1); - codec = AC97_CREATE(dev, via, via_ac97); - if (!codec) goto bad; + via->codec = AC97_CREATE(dev, via, via_ac97); + if (!via->codec) + goto bad; - mixer_init(dev, ac97_getmixerclass(), codec); + mixer_init(dev, ac97_getmixerclass(), via->codec); - /* - * The mixer init resets the codec. So enabling VRA must be done - * afterwards. - */ - v = via_read_codec(NULL, via, AC97_REG_EXT_AUDIO_ID); - v &= (AC97_ENAB_VRA | AC97_ENAB_MICVRA); - via_write_codec(NULL, via, AC97_REG_EXT_AUDIO_STAT, v); - via->codec_caps = v; - { - v = via_read_codec(NULL, via, AC97_REG_EXT_AUDIO_STAT); - DEB(printf("init: codec stat: %d\n", v)); - } - - if (!(v & AC97_CODEC_DOES_VRA)) { - /* no VRA => can do only 48 kbps */ - via_playcaps.minspeed = 48000; - via_reccaps.minspeed = 48000; - } + via->codec_caps = ac97_getextcaps(via->codec); + if (via->codec_caps & AC97_EXTCAP_VRA) + ac97_setextmode(via->codec, AC97_EXTCAP_VRA | AC97_EXTCAP_VRM); /* DMA tag for buffers */ if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, @@ -621,13 +521,12 @@ via_attach(device_t dev) goto bad; } - if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table, - BUS_DMA_NOWAIT, &sgd_dma_map) == -1) goto bad; - if (bus_dmamap_load(via->sgd_dmat, sgd_dma_map, via->sgd_table, - NSEGS * sizeof(struct via_dma_op), dma_cb, 0, 0)) goto bad; + if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table, BUS_DMA_NOWAIT, &via->sgd_dmamap) == -1) + goto bad; + if (bus_dmamap_load(via->sgd_dmat, via->sgd_dmamap, via->sgd_table, NSEGS * sizeof(struct via_dma_op), dma_cb, 0, 0)) + goto bad; - snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld", - rman_get_start(via->reg), rman_get_start(via->irq)); + snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld", rman_get_start(via->reg), rman_get_start(via->irq)); /* Register */ if (pcm_register(dev, via, 1, 1)) goto bad; @@ -636,11 +535,12 @@ via_attach(device_t dev) pcm_setstatus(dev, status); return 0; bad: - if (codec) ac97_destroy(codec); + if (via->codec) ac97_destroy(via->codec); if (via->reg) bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg); if (via->ih) bus_teardown_intr(dev, via->irq, via->ih); if (via->irq) bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq); if (via->parent_dmat) bus_dma_tag_destroy(via->parent_dmat); + if (via->sgd_dmamap) bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap); if (via->sgd_dmat) bus_dma_tag_destroy(via->sgd_dmat); if (via) free(via, M_DEVBUF); return ENXIO; @@ -661,6 +561,7 @@ via_detach(device_t dev) bus_teardown_intr(dev, via->irq, via->ih); bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq); bus_dma_tag_destroy(via->parent_dmat); + bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap); bus_dma_tag_destroy(via->sgd_dmat); free(via, M_DEVBUF); return 0; @@ -677,7 +578,7 @@ static device_method_t via_methods[] = { static driver_t via_driver = { "pcm", via_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pci/vibes.c b/sys/dev/sound/pci/vibes.c index 28ce36f..228b281 100644 --- a/sys/dev/sound/pci/vibes.c +++ b/sys/dev/sound/pci/vibes.c @@ -56,8 +56,8 @@ struct sc_info; struct sc_chinfo { struct sc_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; + struct pcm_channel *channel; + struct snd_dbuf *buffer; u_int32_t fmt, spd; int dir; int dma_active, dma_was_active; @@ -100,7 +100,7 @@ static u_int32_t sc_fmt[] = { 0 }; -static pcmchan_caps sc_caps = {8000, 48000, sc_fmt, 0}; +static struct pcmchan_caps sc_caps = {8000, 48000, sc_fmt, 0}; /* ------------------------------------------------------------------------- */ /* Register Manipulations */ @@ -178,7 +178,7 @@ sv_dma_get_count(bus_space_tag_t st, bus_space_handle_t sh) /* Play / Record Common Interface */ static void * -svchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +svchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sc_info *sc = devinfo; struct sc_chinfo *ch; @@ -200,7 +200,7 @@ svchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) return ch; } -static pcmchan_caps * +static struct pcmchan_caps * svchan_getcaps(kobj_t obj, void *data) { return &sc_caps; @@ -505,7 +505,7 @@ sv_mix_mute_all(struct sc_info *sc) } static int -sv_mix_init(snd_mixer *m) +sv_mix_init(struct snd_mixer *m) { u_int32_t i, v; @@ -523,14 +523,14 @@ sv_mix_init(snd_mixer *m) } static int -sv_mix_set(snd_mixer *m, u_int32_t dev, u_int32_t left, u_int32_t right) +sv_mix_set(struct snd_mixer *m, u_int32_t dev, u_int32_t left, u_int32_t right) { struct sc_info *sc = mix_getdevinfo(m); return sv_gain(sc, dev, left, right); } static int -sv_mix_setrecsrc(snd_mixer *m, u_int32_t mask) +sv_mix_setrecsrc(struct snd_mixer *m, u_int32_t mask) { struct sc_info *sc = mix_getdevinfo(m); u_int32_t i, v; @@ -706,7 +706,7 @@ sv_probe(device_t dev) static int sv_attach(device_t dev) { - snddev_info *d; + struct snddev_info *d; struct sc_info *sc; u_int32_t data; char status[SND_STATUSLEN]; @@ -920,7 +920,7 @@ static device_method_t sc_methods[] = { static driver_t sonicvibes_driver = { "pcm", sc_methods, - sizeof(snddev_info) + sizeof(struct snddev_info) }; static devclass_t pcm_devclass; diff --git a/sys/dev/sound/pcm/ac97.c b/sys/dev/sound/pcm/ac97.c index b8e47e5..72214e6 100644 --- a/sys/dev/sound/pcm/ac97.c +++ b/sys/dev/sound/pcm/ac97.c @@ -33,6 +33,19 @@ MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec"); +#define AC97_NAMELEN 16 +struct ac97_info { + kobj_t methods; + device_t dev; + void *devinfo; + char *id; + char rev; + unsigned count, caps, se, extcaps, extid, extstat, noext:1; + struct ac97mixtable_entry mix[32]; + char name[AC97_NAMELEN]; + void *lock; +}; + struct ac97_codecid { u_int32_t id, noext:1; char *name; @@ -192,6 +205,7 @@ ac97_setrate(struct ac97_info *codec, int which, int rate) return -1; } + snd_mtxlock(codec->lock); if (rate != 0) { v = rate; if (codec->extstat & AC97_EXTCAP_DRA) @@ -201,6 +215,7 @@ ac97_setrate(struct ac97_info *codec, int which, int rate) v = rdcd(codec, which); if (codec->extstat & AC97_EXTCAP_DRA) v <<= 1; + snd_mtxunlock(codec->lock); return v; } @@ -210,8 +225,10 @@ ac97_setextmode(struct ac97_info *codec, u_int16_t mode) mode &= AC97_EXTCAPS; if ((mode & ~codec->extcaps) != 0) return -1; + snd_mtxlock(codec->lock); wrcd(codec, AC97_REGEXT_STAT, mode); codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; + snd_mtxunlock(codec->lock); return (mode == codec->extstat)? 0 : -1; } @@ -235,7 +252,9 @@ ac97_setrecsrc(struct ac97_info *codec, int channel) if (e->recidx > 0) { int val = e->recidx - 1; val |= val << 8; + snd_mtxlock(codec->lock); wrcd(codec, AC97_REG_RECSEL, val); + snd_mtxunlock(codec->lock); return 0; } else return -1; @@ -280,7 +299,9 @@ ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned } if (left == 0 && right == 0 && e->mute == 1) val = AC97_MUTE; + snd_mtxlock(codec->lock); wrcd(codec, reg, val); + snd_mtxunlock(codec->lock); return left | (right << 8); } else { /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */ @@ -318,12 +339,14 @@ ac97_initmixer(struct ac97_info *codec) unsigned i, j, k, old; u_int32_t id; + snd_mtxlock(codec->lock); for (i = 0; i < 32; i++) codec->mix[i] = ac97mixtable_default[i]; codec->count = AC97_INIT(codec->methods, codec->devinfo); if (codec->count == 0) { device_printf(codec->dev, "ac97 codec init failed\n"); + snd_mtxunlock(codec->lock); return ENODEV; } @@ -340,14 +363,15 @@ ac97_initmixer(struct ac97_info *codec) codec->rev = id & 0x000000ff; if (id == 0 || id == 0xffffffff) { device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id); + snd_mtxunlock(codec->lock); return ENODEV; } codec->noext = 0; - codec->name = NULL; + codec->id = NULL; for (i = 0; ac97codecid[i].id; i++) { if (ac97codecid[i].id == id) { - codec->name = ac97codecid[i].name; + codec->id = ac97codecid[i].name; codec->noext = ac97codecid[i].noext; } } @@ -380,8 +404,8 @@ ac97_initmixer(struct ac97_info *codec) if (bootverbose) { device_printf(codec->dev, "ac97 codec id 0x%08x", id); - if (codec->name) - printf(" (%s)", codec->name); + if (codec->id) + printf(" (%s)", codec->id); printf("\n"); device_printf(codec->dev, "ac97 codec features "); for (i = j = 0; i < 10; i++) @@ -404,6 +428,7 @@ ac97_initmixer(struct ac97_info *codec) if ((rdcd(codec, AC97_REG_POWER) & 2) == 0) device_printf(codec->dev, "ac97 codec reports dac not ready\n"); + snd_mtxunlock(codec->lock); return 0; } @@ -412,9 +437,11 @@ ac97_reinitmixer(struct ac97_info *codec) { unsigned i; + snd_mtxlock(codec->lock); codec->count = AC97_INIT(codec->methods, codec->devinfo); if (codec->count == 0) { device_printf(codec->dev, "ac97 codec init failed\n"); + snd_mtxunlock(codec->lock); return ENODEV; } @@ -432,6 +459,7 @@ ac97_reinitmixer(struct ac97_info *codec) if ((rdcd(codec, AC97_REG_POWER) & 2) == 0) device_printf(codec->dev, "ac97 codec reports dac not ready\n"); + snd_mtxunlock(codec->lock); return 0; } @@ -444,8 +472,12 @@ ac97_create(device_t dev, void *devinfo, kobj_class_t cls) if (codec == NULL) return NULL; + snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev)); + codec->lock = snd_mtxcreate(codec->name); codec->methods = kobj_create(cls, M_AC97, M_WAITOK); if (codec->methods == NULL) { + snd_mtxlock(codec->lock); + snd_mtxfree(codec->lock); free(codec, M_AC97); return NULL; } @@ -458,15 +490,17 @@ ac97_create(device_t dev, void *devinfo, kobj_class_t cls) void ac97_destroy(struct ac97_info *codec) { + snd_mtxlock(codec->lock); if (codec->methods != NULL) kobj_delete(codec->methods, M_AC97); + snd_mtxfree(codec->lock); free(codec, M_AC97); } /* -------------------------------------------------------------------- */ static int -ac97mix_init(snd_mixer *m) +ac97mix_init(struct snd_mixer *m) { struct ac97_info *codec = mix_getdevinfo(m); u_int32_t i, mask; @@ -490,7 +524,7 @@ ac97mix_init(snd_mixer *m) } static int -ac97mix_uninit(snd_mixer *m) +ac97mix_uninit(struct snd_mixer *m) { struct ac97_info *codec = mix_getdevinfo(m); @@ -505,7 +539,7 @@ ac97mix_uninit(snd_mixer *m) } static int -ac97mix_reinit(snd_mixer *m) +ac97mix_reinit(struct snd_mixer *m) { struct ac97_info *codec = mix_getdevinfo(m); @@ -515,7 +549,7 @@ ac97mix_reinit(snd_mixer *m) } static int -ac97mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) +ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct ac97_info *codec = mix_getdevinfo(m); @@ -525,7 +559,7 @@ ac97mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) } static int -ac97mix_setrecsrc(snd_mixer *m, u_int32_t src) +ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src) { int i; struct ac97_info *codec = mix_getdevinfo(m); diff --git a/sys/dev/sound/pcm/ac97.h b/sys/dev/sound/pcm/ac97.h index 6f36761..b9159e1 100644 --- a/sys/dev/sound/pcm/ac97.h +++ b/sys/dev/sound/pcm/ac97.h @@ -77,15 +77,7 @@ struct ac97mixtable_entry { #define AC97_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, sizeof(struct kobj)) #define AC97_CREATE(dev, devinfo, cls) ac97_create(dev, devinfo, &cls ## _class) -struct ac97_info { - kobj_t methods; - device_t dev; - void *devinfo; - char *name; - char rev; - unsigned count, caps, se, extcaps, extid, extstat, noext:1; - struct ac97mixtable_entry mix[32]; -}; +struct ac97_info; #include "ac97_if.h" diff --git a/sys/dev/sound/pcm/buffer.c b/sys/dev/sound/pcm/buffer.c index 9a28054..e141774e 100644 --- a/sys/dev/sound/pcm/buffer.c +++ b/sys/dev/sound/pcm/buffer.c @@ -28,10 +28,50 @@ #include <dev/sound/pcm/sound.h> +#include "feeder_if.h" + +#define MIN(x, y) (((x) < (y))? (x) : (y)) + +#define SNDBUF_NAMELEN 48 +struct snd_dbuf { + u_int8_t *buf, *tmpbuf; + unsigned int bufsize, maxsize; + volatile int dl; /* transfer size */ + volatile int rp; /* pointers to the ready area */ + volatile int rl; /* length of ready area */ + volatile int hp; + volatile u_int32_t total, prev_total; + int isadmachan, dir; /* dma channel */ + u_int32_t fmt, spd, bps; + unsigned int blksz, blkcnt; + int xrun; + u_int32_t flags; + bus_dmamap_t dmamap; + bus_dma_tag_t dmatag; + struct selinfo sel; + char name[SNDBUF_NAMELEN]; +}; + +struct snd_dbuf * +sndbuf_create(char *drv, char *desc) +{ + struct snd_dbuf *b; + + b = malloc(sizeof(*b), M_DEVBUF, M_WAITOK | M_ZERO); + snprintf(b->name, SNDBUF_NAMELEN, "%s:%s", drv, desc); + return b; +} + +void +sndbuf_destroy(struct snd_dbuf *b) +{ + free(b, M_DEVBUF); +} + static void sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) { - snd_dbuf *b = (snd_dbuf *)arg; + struct snd_dbuf *b = (struct snd_dbuf *)arg; if (bootverbose) { printf("pcm: setmap %lx, %lx; ", (unsigned long)segs->ds_addr, @@ -41,11 +81,11 @@ sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) } /* - * Allocate memory for DMA buffer. If the device do not perform DMA transfer, - * the driver can call malloc(9) by its own. + * Allocate memory for DMA buffer. If the device does not use DMA transfers, + * the driver can call malloc(9) and sndbuf_setup() itself. */ int -sndbuf_alloc(snd_dbuf *b, bus_dma_tag_t dmatag, int size) +sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, unsigned int size) { b->dmatag = dmatag; b->maxsize = size; @@ -58,7 +98,7 @@ sndbuf_alloc(snd_dbuf *b, bus_dma_tag_t dmatag, int size) } int -sndbuf_setup(snd_dbuf *b, void *buf, int size) +sndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size) { bzero(b, sizeof(*b)); b->buf = buf; @@ -68,15 +108,24 @@ sndbuf_setup(snd_dbuf *b, void *buf, int size) } void -sndbuf_free(snd_dbuf *b) +sndbuf_free(struct snd_dbuf *b) { + if (b->tmpbuf) + free(b->tmpbuf, M_DEVBUF); + b->tmpbuf = NULL; + + if (b->dmamap) bus_dmamap_unload(b->dmatag, b->dmamap); + + if (b->dmamap && b->buf) bus_dmamem_free(b->dmatag, b->buf, b->dmamap); } int -sndbuf_resize(snd_dbuf *b, int blkcnt, int blksz) +sndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) { + if (b->maxsize == 0) + return 0; if (blkcnt == 0) blkcnt = b->blkcnt; if (blksz == 0) @@ -86,12 +135,43 @@ sndbuf_resize(snd_dbuf *b, int blkcnt, int blksz) b->blkcnt = blkcnt; b->blksz = blksz; b->bufsize = blkcnt * blksz; + if (b->tmpbuf) + free(b->tmpbuf, M_DEVBUF); + b->tmpbuf = malloc(b->bufsize, M_DEVBUF, M_WAITOK); + sndbuf_reset(b); + return 0; +} + +int +sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) +{ + if (blkcnt < 2 || blksz < 16) + return EINVAL; + + b->blkcnt = blkcnt; + b->blksz = blksz; + + b->maxsize = blkcnt * blksz; + b->bufsize = b->maxsize; + + if (b->buf) + free(b->buf, M_DEVBUF); + b->buf = malloc(b->bufsize, M_DEVBUF, M_WAITOK); + if (b->buf == NULL) + return ENOMEM; + + if (b->tmpbuf) + free(b->tmpbuf, M_DEVBUF); + b->tmpbuf = malloc(b->bufsize, M_DEVBUF, M_WAITOK); + if (b->tmpbuf == NULL) + return ENOMEM; + sndbuf_reset(b); return 0; } void -sndbuf_clear(snd_dbuf *b, int length) +sndbuf_clear(struct snd_dbuf *b, unsigned int length) { int i; u_char data, *p; @@ -106,8 +186,13 @@ sndbuf_clear(snd_dbuf *b, int length) else data = 0x80; - i = b->fp; - p = b->buf; + if (b->fmt & AFMT_16BIT) + data <<= 8; + else + data |= data << 8; + + i = sndbuf_getfreeptr(b); + p = sndbuf_getbuf(b); while (length > 0) { p[i] = data; length--; @@ -118,20 +203,27 @@ sndbuf_clear(snd_dbuf *b, int length) } void -sndbuf_reset(snd_dbuf *b) -{ - b->rp = b->fp = 0; - b->dl = b->rl = 0; - b->fl = b->bufsize; - b->prev_total = b->total = 0; - b->prev_int_count = b->int_count = 0; - b->underflow = 0; +sndbuf_reset(struct snd_dbuf *b) +{ + b->hp = 0; + b->rp = 0; + b->rl = 0; + b->dl = 0; + b->prev_total = 0; + b->total = 0; + b->xrun = 0; if (b->buf && b->bufsize > 0) sndbuf_clear(b, b->bufsize); } +u_int32_t +sndbuf_getfmt(struct snd_dbuf *b) +{ + return b->fmt; +} + int -sndbuf_setfmt(snd_dbuf *b, u_int32_t fmt) +sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt) { b->fmt = fmt; b->bps = 1; @@ -141,67 +233,368 @@ sndbuf_setfmt(snd_dbuf *b, u_int32_t fmt) return 0; } -int -sndbuf_getbps(snd_dbuf *b) +unsigned int +sndbuf_getspd(struct snd_dbuf *b) +{ + return b->spd; +} + +void +sndbuf_setspd(struct snd_dbuf *b, unsigned int spd) +{ + b->spd = spd; +} + +unsigned int +sndbuf_getalign(struct snd_dbuf *b) +{ + static int align[] = {0, 1, 1, 2, 2, 2, 2, 3}; + + return align[b->bps - 1]; +} + +unsigned int +sndbuf_getblkcnt(struct snd_dbuf *b) +{ + return b->blkcnt; +} + +void +sndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt) +{ + b->blkcnt = blkcnt; +} + +unsigned int +sndbuf_getblksz(struct snd_dbuf *b) +{ + return b->blksz; +} + +void +sndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz) +{ + b->blksz = blksz; +} + +unsigned int +sndbuf_getbps(struct snd_dbuf *b) { return b->bps; } void * -sndbuf_getbuf(snd_dbuf *b) +sndbuf_getbuf(struct snd_dbuf *b) { return b->buf; } -int -sndbuf_getsize(snd_dbuf *b) +void * +sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs) +{ + KASSERT((ofs >= 0) && (ofs <= b->bufsize), ("%s: ofs invalid %d", __FUNCTION__, ofs)); + + return b->buf + ofs; +} + +unsigned int +sndbuf_getsize(struct snd_dbuf *b) { return b->bufsize; } -int -sndbuf_runsz(snd_dbuf *b) +unsigned int +sndbuf_getmaxsize(struct snd_dbuf *b) +{ + return b->maxsize; +} + +unsigned int +sndbuf_runsz(struct snd_dbuf *b) { return b->dl; } +void +sndbuf_setrun(struct snd_dbuf *b, int go) +{ + b->dl = go? b->blksz : 0; +} + +struct selinfo * +sndbuf_getsel(struct snd_dbuf *b) +{ + return &b->sel; +} + +/************************************************************/ +unsigned int +sndbuf_getxrun(struct snd_dbuf *b) +{ + SNDBUF_LOCKASSERT(b); + + return b->xrun; +} + +void +sndbuf_setxrun(struct snd_dbuf *b, unsigned int cnt) +{ + SNDBUF_LOCKASSERT(b); + + b->xrun = cnt; +} + +unsigned int +sndbuf_gethwptr(struct snd_dbuf *b) +{ + SNDBUF_LOCKASSERT(b); + + return b->hp; +} + +void +sndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr) +{ + SNDBUF_LOCKASSERT(b); + + b->hp = ptr; +} + +unsigned int +sndbuf_getready(struct snd_dbuf *b) +{ + SNDBUF_LOCKASSERT(b); + KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __FUNCTION__, b->rl)); + + return b->rl; +} + +unsigned int +sndbuf_getreadyptr(struct snd_dbuf *b) +{ + SNDBUF_LOCKASSERT(b); + KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __FUNCTION__, b->rp)); + + return b->rp; +} + +unsigned int +sndbuf_getfree(struct snd_dbuf *b) +{ + SNDBUF_LOCKASSERT(b); + KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __FUNCTION__, b->rl)); + + return b->bufsize - b->rl; +} + +unsigned int +sndbuf_getfreeptr(struct snd_dbuf *b) +{ + SNDBUF_LOCKASSERT(b); + KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __FUNCTION__, b->rp)); + KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __FUNCTION__, b->rl)); + + return (b->rp + b->rl) % b->bufsize; +} + +unsigned int +sndbuf_getblocks(struct snd_dbuf *b) +{ + SNDBUF_LOCKASSERT(b); + + return b->total / b->blksz; +} + +unsigned int +sndbuf_getprevblocks(struct snd_dbuf *b) +{ + SNDBUF_LOCKASSERT(b); + + return b->prev_total / b->blksz; +} + +unsigned int +sndbuf_gettotal(struct snd_dbuf *b) +{ + SNDBUF_LOCKASSERT(b); + + return b->total; +} + +void +sndbuf_updateprevtotal(struct snd_dbuf *b) +{ + SNDBUF_LOCKASSERT(b); + + b->prev_total = b->total; +} + +/************************************************************/ + int -sndbuf_isadmasetup(snd_dbuf *b, struct resource *drq) +sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count) +{ + int l; + + KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __FUNCTION__, count, sndbuf_getfree(b))); + KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __FUNCTION__, b->rl)); + b->total += count; + if (from != NULL) { + while (count > 0) { + l = MIN(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b)); + bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l); + from += l; + b->rl += l; + count -= l; + } + } else + b->rl += count; + KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __FUNCTION__, b->rl, count)); + + return 0; +} + +int +sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count) +{ + int l; + + KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __FUNCTION__, count, sndbuf_getready(b))); + KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __FUNCTION__, b->rl)); + if (to != NULL) { + while (count > 0) { + l = MIN(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b)); + bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l); + to += l; + b->rl -= l; + b->rp = (b->rp + l) % b->bufsize; + count -= l; + } + } else { + b->rl -= count; + b->rp = (b->rp + count) % b->bufsize; + } + KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __FUNCTION__, b->rl, count)); + + return 0; +} + +int +sndbuf_uiomove(struct snd_dbuf *b, struct uio *uio, unsigned int count) +{ + int x, c, p, rd, err; + + err = 0; + rd = (uio->uio_rw == UIO_READ)? 1 : 0; + if (count > uio->uio_resid) + return EINVAL; + + if (count > (rd? sndbuf_getready(b) : sndbuf_getfree(b))) { + return EINVAL; + } + + while (err == 0 && count > 0) { + p = rd? sndbuf_getreadyptr(b) : sndbuf_getfreeptr(b); + c = MIN(count, sndbuf_getsize(b) - p); + x = uio->uio_resid; + err = uiomove(sndbuf_getbufofs(b, p), c, uio); + x -= uio->uio_resid; + count -= x; + x = rd? sndbuf_dispose(b, NULL, x) : sndbuf_acquire(b, NULL, x); + } + + return 0; +} + +/* count is number of bytes we want added to destination buffer */ +int +sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count) +{ + if (sndbuf_getfree(to) < count) + return EINVAL; + + count = FEEDER_FEED(feeder, channel, to->tmpbuf, count, from); + sndbuf_acquire(to, to->tmpbuf, count); + /* the root feeder has called sndbuf_dispose(from, , bytes fetched) */ + + return 0; +} + +/************************************************************/ + +void +sndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what) +{ + printf("%s: [", s); + if (what & 0x01) + printf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize); + if (what & 0x02) + printf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp); + if (what & 0x04) + printf(" total: %d, prev_total: %d, xrun: %d", b->total, b->prev_total, b->xrun); + if (what & 0x08) + printf(" fmt: 0x%x, spd: %d", b->fmt, b->spd); + if (what & 0x10) + printf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags); + printf(" ]\n"); +} + +/************************************************************/ +u_int32_t +sndbuf_getflags(struct snd_dbuf *b) +{ + return b->flags; +} + +void +sndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on) +{ + b->flags &= ~flags; + if (on) + b->flags |= flags; +} + +/************************************************************/ + +int +sndbuf_isadmasetup(struct snd_dbuf *b, struct resource *drq) { /* should do isa_dma_acquire/isa_dma_release here */ if (drq == NULL) { - b->flags &= ~SNDBUF_F_ISADMA; - b->chan = -1; + b->isadmachan = -1; } else { - b->flags &= ~SNDBUF_F_ISADMA; - b->chan = rman_get_start(drq); + sndbuf_setflags(b, SNDBUF_F_ISADMA, 1); + b->isadmachan = rman_get_start(drq); } return 0; } int -sndbuf_isadmasetdir(snd_dbuf *b, int dir) +sndbuf_isadmasetdir(struct snd_dbuf *b, int dir) { + KASSERT(b, ("sndbuf_isadmasetdir called with b == NULL")); + KASSERT(sndbuf_getflags(b) & SNDBUF_F_ISADMA, ("sndbuf_isadmasetdir called on non-ISA buffer")); + b->dir = (dir == PCMDIR_PLAY)? ISADMA_WRITE : ISADMA_READ; return 0; } void -sndbuf_isadma(snd_dbuf *b, int go) +sndbuf_isadma(struct snd_dbuf *b, int go) { KASSERT(b, ("sndbuf_isadma called with b == NULL")); - KASSERT(ISA_DMA(b), ("sndbuf_isadma called on non-ISA channel")); + KASSERT(sndbuf_getflags(b) & SNDBUF_F_ISADMA, ("sndbuf_isadma called on non-ISA buffer")); switch (go) { case PCMTRIG_START: /* isa_dmainit(b->chan, size); */ - isa_dmastart(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->chan); + isa_dmastart(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->isadmachan); break; case PCMTRIG_STOP: case PCMTRIG_ABORT: - isa_dmastop(b->chan); - isa_dmadone(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->chan); + isa_dmastop(b->isadmachan); + isa_dmadone(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->isadmachan); break; } @@ -212,23 +605,26 @@ sndbuf_isadma(snd_dbuf *b, int go) } int -sndbuf_isadmaptr(snd_dbuf *b) +sndbuf_isadmaptr(struct snd_dbuf *b) { - if (ISA_DMA(b)) { - int i = b->dl? isa_dmastatus(b->chan) : b->bufsize; - if (i < 0) - i = 0; + int i; + + KASSERT(b, ("sndbuf_isadmaptr called with b == NULL")); + KASSERT(sndbuf_getflags(b) & SNDBUF_F_ISADMA, ("sndbuf_isadmaptr called on non-ISA buffer")); + + if (!sndbuf_runsz(b)) + return 0; + i = isa_dmastatus(b->isadmachan); + KASSERT(i >= 0, ("isa_dmastatus returned %d", i)); return b->bufsize - i; - } else KASSERT(1, ("sndbuf_isadmaptr called on invalid channel")); - return -1; } void -sndbuf_isadmabounce(snd_dbuf *b) +sndbuf_isadmabounce(struct snd_dbuf *b) { - if (ISA_DMA(b)) { + KASSERT(b, ("sndbuf_isadmabounce called with b == NULL")); + KASSERT(sndbuf_getflags(b) & SNDBUF_F_ISADMA, ("sndbuf_isadmabounce called on non-ISA buffer")); + /* tell isa_dma to bounce data in/out */ - } else - KASSERT(1, ("chn_isadmabounce called on invalid channel")); } diff --git a/sys/dev/sound/pcm/buffer.h b/sys/dev/sound/pcm/buffer.h index 62058ce..53ac279 100644 --- a/sys/dev/sound/pcm/buffer.h +++ b/sys/dev/sound/pcm/buffer.h @@ -26,24 +26,70 @@ * $FreeBSD$ */ -#define ISA_DMA(b) (((b)->chan >= 0 && (b)->chan != 4 && (b)->chan < 8)) - -int sndbuf_alloc(snd_dbuf *b, bus_dma_tag_t dmatag, int size); -int sndbuf_setup(snd_dbuf *b, void *buf, int size); -void sndbuf_free(snd_dbuf *b); -int sndbuf_resize(snd_dbuf *b, int blkcnt, int blksz); -void sndbuf_reset(snd_dbuf *b); -void sndbuf_clear(snd_dbuf *b, int length); -int sndbuf_setfmt(snd_dbuf *b, u_int32_t fmt); -int sndbuf_getbps(snd_dbuf *b); -void *sndbuf_getbuf(snd_dbuf *b); -int sndbuf_getsize(snd_dbuf *b); -int sndbuf_runsz(snd_dbuf *b); - -int sndbuf_isadmasetup(snd_dbuf *b, struct resource *drq); -int sndbuf_isadmasetdir(snd_dbuf *b, int dir); -void sndbuf_isadma(snd_dbuf *b, int go); -int sndbuf_isadmaptr(snd_dbuf *b); -void sndbuf_isadmabounce(snd_dbuf *b); +#define ISA_DMA(b) (sndbuf_getflags((b)) & SNDBUF_F_ISADMA) +#define SNDBUF_LOCKASSERT(b) + +#define SNDBUF_F_ISADMA 0x00000001 +#define SNDBUF_F_XRUN 0x00000002 +#define SNDBUF_F_RUNNING 0x00000004 + +struct snd_dbuf *sndbuf_create(char *drv, char *desc); +void sndbuf_destroy(struct snd_dbuf *b); + +void sndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what); + +int sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, unsigned int size); +int sndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size); +void sndbuf_free(struct snd_dbuf *b); +int sndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz); +int sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz); +void sndbuf_reset(struct snd_dbuf *b); +void sndbuf_clear(struct snd_dbuf *b, unsigned int length); + +u_int32_t sndbuf_getfmt(struct snd_dbuf *b); +int sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt); +unsigned int sndbuf_getspd(struct snd_dbuf *b); +void sndbuf_setspd(struct snd_dbuf *b, unsigned int spd); +unsigned int sndbuf_getbps(struct snd_dbuf *b); + +void *sndbuf_getbuf(struct snd_dbuf *b); +void *sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs); +unsigned int sndbuf_getsize(struct snd_dbuf *b); +unsigned int sndbuf_getmaxsize(struct snd_dbuf *b); +unsigned int sndbuf_getalign(struct snd_dbuf *b); +unsigned int sndbuf_getblkcnt(struct snd_dbuf *b); +void sndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt); +unsigned int sndbuf_getblksz(struct snd_dbuf *b); +void sndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz); +unsigned int sndbuf_runsz(struct snd_dbuf *b); +void sndbuf_setrun(struct snd_dbuf *b, int go); +struct selinfo *sndbuf_getsel(struct snd_dbuf *b); + +unsigned int sndbuf_getxrun(struct snd_dbuf *b); +void sndbuf_setxrun(struct snd_dbuf *b, unsigned int cnt); +unsigned int sndbuf_gethwptr(struct snd_dbuf *b); +void sndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr); +unsigned int sndbuf_getfree(struct snd_dbuf *b); +unsigned int sndbuf_getfreeptr(struct snd_dbuf *b); +unsigned int sndbuf_getready(struct snd_dbuf *b); +unsigned int sndbuf_getreadyptr(struct snd_dbuf *b); +unsigned int sndbuf_getblocks(struct snd_dbuf *b); +unsigned int sndbuf_getprevblocks(struct snd_dbuf *b); +unsigned int sndbuf_gettotal(struct snd_dbuf *b); +void sndbuf_updateprevtotal(struct snd_dbuf *b); + +int sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count); +int sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count); +int sndbuf_uiomove(struct snd_dbuf *b, struct uio *uio, unsigned int count); +int sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count); + +u_int32_t sndbuf_getflags(struct snd_dbuf *b); +void sndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on); + +int sndbuf_isadmasetup(struct snd_dbuf *b, struct resource *drq); +int sndbuf_isadmasetdir(struct snd_dbuf *b, int dir); +void sndbuf_isadma(struct snd_dbuf *b, int go); +int sndbuf_isadmaptr(struct snd_dbuf *b); +void sndbuf_isadmabounce(struct snd_dbuf *b); diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c index 412e17f..3dcb735 100644 --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -31,816 +31,415 @@ #include "feeder_if.h" -MALLOC_DEFINE(M_CHANNEL, "channel", "pcm channel"); #define MIN_CHUNK_SIZE 256 /* for uiomove etc. */ #define DMA_ALIGN_THRESHOLD 4 #define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1)) -#define CANCHANGE(c) (!(c)->buffer.dl) -#define ROUND(x) ((x) & DMA_ALIGN_MASK) +#define MIN(x, y) (((x) < (y))? (x) : (y)) +#define CANCHANGE(c) (!(c->flags & CHN_F_TRIGGERED)) /* #define DEB(x) x */ -static void chn_dmaupdate(pcm_channel *c); -static void chn_wrintr(pcm_channel *c); -static void chn_rdintr(pcm_channel *c); -static int chn_buildfeeder(pcm_channel *c); -/* - * SOUND OUTPUT - -We use a circular buffer to store samples directed to the DAC. -The buffer is split into two variable-size regions, each identified -by an offset in the buffer (rp,fp) and a length (rl,fl): - - 0 rp,rl fp,fl bufsize - |__________>____________>________| - FREE d READY w FREE - - READY: data written from the process and ready to be sent to the DAC; - FREE: free part of the buffer. - -Both regions can wrap around the end of the buffer. At initialization, -READY is empty, FREE takes all the available space, and dma is -idle. dl contains the length of the current DMA transfer, dl=0 -means that the dma is idle. - -The two boundaries (rp,fp) in the buffers are advanced by DMA [d] -and write() [w] operations. The first portion of the READY region -is used for DMA transfers. The transfer is started at rp and with -chunks of length dl. During DMA operations, dsp_wr_dmaupdate() -updates rp, rl and fl tracking the ISA DMA engine as the transfer -makes progress. -When a new block is written, fp advances and rl,fl are updated -accordingly. - -The code works as follows: the user write routine dsp_write_body() -fills up the READY region with new data (reclaiming space from the -FREE region) and starts the write DMA engine if inactive. When a -DMA transfer is complete, an interrupt causes dsp_wrintr() to be -called which extends the FREE region and possibly starts the next -transfer. - -In some cases, the code tries to track the current status of DMA -operations by calling dsp_wr_dmaupdate() which changes rp, rl and fl. +static int chn_buildfeeder(struct pcm_channel *c); -The system tries to make all DMA transfers use the same size, -play_blocksize or rec_blocksize. The size is either selected by -the user, or computed by the system to correspond to about .25s of -audio. The blocksize must be within a range which is currently: - - min(5ms, 40 bytes) ... 1/2 buffer size. - -When there aren't enough data (write) or space (read), a transfer -is started with a reduced size. - -To reduce problems in case of overruns, the routine which fills up -the buffer should initialize (e.g. by repeating the last value) a -reasonably long area after the last block so that no noise is -produced on overruns. - - * - */ +static void +chn_lockinit(struct pcm_channel *c) +{ + c->lock = snd_mtxcreate(c->name); +} +static void +chn_lockdestroy(struct pcm_channel *c) +{ + snd_mtxfree(c->lock); +} -/* XXX this is broken: in the event a bounce buffer is used, data never - * gets copied in or out of the real buffer. fix requires mods to isa_dma.c - * and possibly fixes to other autodma mode clients - */ static int -chn_polltrigger(pcm_channel *c) +chn_polltrigger(struct pcm_channel *c) { - snd_dbuf *bs = &c->buffer2nd; - unsigned lim = (c->flags & CHN_F_HAS_SIZE)? bs->blksz : 0; - int trig = 0; + struct snd_dbuf *bs = c->bufsoft; + unsigned amt, lim; - if (c->flags & CHN_F_MAPPED) - trig = ((bs->int_count > bs->prev_int_count) || bs->prev_int_count == 0); + CHN_LOCKASSERT(c); + if (c->flags & CHN_F_MAPPED) { + if (sndbuf_getprevblocks(bs) == 0) + return 1; else - trig = (((c->direction == PCMDIR_PLAY)? bs->fl : bs->rl) > lim); - return trig; + return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0; + } else { + amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs); + lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1; + lim = 1; + return (amt >= lim)? 1 : 0; + } + return 0; } static int -chn_pollreset(pcm_channel *c) +chn_pollreset(struct pcm_channel *c) { - snd_dbuf *bs = &c->buffer2nd; + struct snd_dbuf *bs = c->bufsoft; - if (c->flags & CHN_F_MAPPED) - bs->prev_int_count = bs->int_count; + CHN_LOCKASSERT(c); + sndbuf_updateprevtotal(bs); return 1; } -/* - * chn_dmadone() updates pointers and wakes up any process waiting - * on a select(). Must be called at spltty(). - */ static void -chn_dmadone(pcm_channel *c) +chn_wakeup(struct pcm_channel *c) { - snd_dbuf *b = &c->buffer; + struct snd_dbuf *bs = c->bufsoft; - if (c->direction == PCMDIR_PLAY) - chn_checkunderflow(c); - else - chn_dmaupdate(c); - if (ISA_DMA(b)) - sndbuf_isadmabounce(b); /* sync bounce buffer */ - b->int_count++; + CHN_LOCKASSERT(c); + if (sndbuf_getsel(bs)->si_pid && chn_polltrigger(c)) + selwakeup(sndbuf_getsel(bs)); + wakeup(bs); } -/* - * chn_dmawakeup() wakes up any process sleeping. Separated from - * chn_dmadone() so that wakeup occurs only when feed from a - * secondary buffer to a DMA buffer takes place. Must be called - * at spltty(). - */ -static void -chn_dmawakeup(pcm_channel *c) +static int +chn_sleep(struct pcm_channel *c, char *str, int timeout) { - snd_dbuf *b = &c->buffer; + struct snd_dbuf *bs = c->bufsoft; + int ret; + + CHN_LOCKASSERT(c); + ret = msleep(bs, c->lock, PRIBIO | PCATCH, str, timeout); - wakeup(b); + return ret; } /* * chn_dmaupdate() tracks the status of a dma transfer, * updating pointers. It must be called at spltty(). - * - * NOTE: when we are using auto dma in the device, rl might become - * negative. */ -DEB (static int chn_updatecount=0); -static void -chn_dmaupdate(pcm_channel *c) +static unsigned int +chn_dmaupdate(struct pcm_channel *c) { - snd_dbuf *b = &c->buffer; - int delta, hwptr; - DEB (int b_rl=b->rl; int b_fl=b->fl; int b_rp=b->rp; int b_fp=b->fp); + struct snd_dbuf *b = c->bufhard; + unsigned int delta, old, hwptr, amt; + CHN_LOCKASSERT(c); + old = sndbuf_gethwptr(b); hwptr = chn_getptr(c); - delta = (b->bufsize + hwptr - b->hp) % b->bufsize; + delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b); + sndbuf_sethwptr(b, hwptr); + DEB( - if (delta >= ((b->bufsize * 15) / 16)) { + if (delta >= ((sndbuf_getsize(b) * 15) / 16)) { if (!(c->flags & (CHN_F_CLOSING | CHN_F_ABORTING))) - device_printf(c->parent->dev, "hwptr went backwards %d -> %d\n", b->hp, hwptr); + device_printf(c->parent->dev, "hwptr went backwards %d -> %d\n", old, hwptr); } - ) - if (c->direction == PCMDIR_PLAY) { - delta = (b->bufsize + hwptr - b->rp) % b->bufsize; - b->rp = hwptr; - b->rl -= delta; - b->fl += delta; + ); - if (b->rl < 0) { - DEB(printf("OUCH!(%d) rl %d(%d) delta %d bufsize %d hwptr %d rp %d(%d)\n", chn_updatecount++, b->rl, b_rl, delta, b->bufsize, hwptr, b->rp, b_rp)); - } + if (c->direction == PCMDIR_PLAY) { + amt = MIN(delta, sndbuf_getready(b)); + if (amt > 0) + sndbuf_dispose(b, NULL, amt); } else { - delta = (b->bufsize + hwptr - b->fp) % b->bufsize; - b->fp = hwptr; - b->rl += delta; - b->fl -= delta; - if (b->fl < 0) { - DEB(printf("OUCH!(%d) fl %d(%d) delta %d bufsize %d hwptr %d fp %d(%d)\n", chn_updatecount++, b->fl, b_fl, delta, b->bufsize, hwptr, b->fp, b_fp)); - } + amt = MIN(delta, sndbuf_getfree(b)); + if (amt > 0) + sndbuf_acquire(b, NULL, amt); } - b->hp = hwptr; - b->total += delta; + + return delta; } -/* - * Check channel for underflow occured. Reset DMA buffer in case of - * underflow, so that new data can go into the buffer. It must be - * called at spltty(). - */ void -chn_checkunderflow(pcm_channel *c) +chn_wrupdate(struct pcm_channel *c) { - snd_dbuf *b = &c->buffer; - - if (b->underflow) { - DEB(printf("Clear underflow condition\n")); - /* - * The DMA keeps running even after underflow occurs. - * Hence the value returned by chn_getptr() here soon - * gets a lag when we get back to chn_write(). Although - * there are no easy and precise methods to figure out - * the lag, a quarter of b->bufsize would be a fair - * choice, provided that a DMA interrupt generates upon - * each transfer of a half b->bufsize. - */ - b->rp = chn_getptr(c); - b->fp = (b->rp + b->bufsize / 4) % b->bufsize; - b->rl = b->bufsize / 4; - b->fl = b->bufsize - b->rl; - b->underflow = 0; - } else { - chn_dmaupdate(c); - } -} + int ret; -/* - * Feeds new data to the write dma buffer. Can be called in the bottom half. - * Hence must be called at spltty. - */ -int -chn_wrfeed(pcm_channel *c) -{ - snd_dbuf *b = &c->buffer; - snd_dbuf *bs = &c->buffer2nd; - int a, l, lacc; - - /* ensure we always have a whole number of samples */ - a = (1 << c->align) - 1; - lacc = 0; - if (c->flags & CHN_F_MAPPED) { - bs->rl = min(b->blksz, b->fl); - bs->fl = 0; - a = 0; - } - DEB(if (c->flags & CHN_F_CLOSING) - printf("b: [rl: %d, rp %d, fl %d, fp %d]; bs: [rl: %d, rp %d, fl %d, fp %d]\n", - b->rl, b->rp, b->fl, b->fp, bs->rl, bs->rp, bs->fl, bs->fp)); - /* Don't allow write unaligned data */ - while (bs->rl > a && b->fl > a) { - /* ensure we always have a whole number of samples */ - l = min(min(bs->rl, bs->bufsize - bs->rp), min(b->fl, b->bufsize - b->fp)) & ~a; - if (l == 0) - return lacc; - /* Move the samples, update the markers and pointers. */ - bcopy(bs->buf + bs->rp, b->buf + b->fp, l); - bs->fl += l; - bs->rl -= l; - bs->rp = (bs->rp + l) % bs->bufsize; - b->rl += l; - b->fl -= l; - b->fp = (b->fp + l) % b->bufsize; - /* Clear the new space in the secondary buffer. */ - sndbuf_clear(bs, l); - /* Accumulate the total bytes of the moved samples. */ - lacc += l; - /* A feed to the DMA buffer is equivalent to an interrupt. */ - bs->total += l; - if (c->flags & CHN_F_MAPPED) { - if (bs->total - bs->prev_total >= bs->blksz) { - bs->prev_total = bs->total; - bs->int_count++; - c->blocks++; - } - } else - bs->int_count++; - if (bs->sel.si_pid && chn_polltrigger(c)) - selwakeup(&bs->sel); - } + CHN_LOCKASSERT(c); + KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel")); + + if ((c->flags & CHN_F_MAPPED) || !(c->flags & CHN_F_TRIGGERED)) + return; + chn_dmaupdate(c); + ret = chn_wrfeed(c); + /* tell the driver we've updated the primary buffer */ + chn_trigger(c, PCMTRIG_EMLDMAWR); + DEB(if (ret) + printf("chn_wrupdate: chn_wrfeed returned %d\n", ret);) - return lacc; } -/* Feeds new data to the secondary write buffer. */ -static int -chn_wrfeed2nd(pcm_channel *c, struct uio *buf) -{ - snd_dbuf *bs = &c->buffer2nd; - int l, w, wacc, hl; - u_int8_t hackbuf[64]; - - /* The DMA buffer may have some space. */ - while (chn_wrfeed(c) > 0); - - /* ensure we always have a whole number of samples */ - wacc = 0; - hl = 0; - while (buf->uio_resid > 0 && bs->fl > 64) { - /* - * The size of the data to move here does not have to be - * aligned. We take care of it upon moving the data to a - * DMA buffer. - */ - l = min(bs->fl, bs->bufsize - bs->fp); - /* Move the samples, update the markers and pointers. */ - if (l < 64) { - w = FEEDER_FEED(c->feeder, c, hackbuf, 64, buf); - l = min(w, bs->bufsize - bs->fp); - bcopy(hackbuf, bs->buf + bs->fp, l); - if (w > l) - bcopy(hackbuf + l, bs->buf, w - l); - } else - w = FEEDER_FEED(c->feeder, c, bs->buf + bs->fp, l, buf); - if (w == 0) - panic("no feed"); - bs->rl += w; - bs->fl -= w; - bs->fp = (bs->fp + w) % bs->bufsize; - /* Accumulate the total bytes of the moved samples. */ - wacc += w; - - /* If any pcm data gets moved, push it to the DMA buffer. */ - if (w > 0) - while (chn_wrfeed(c) > 0); - } +static int irqc = 0; - return wacc; +int +chn_wrfeed(struct pcm_channel *c) +{ + struct snd_dbuf *b = c->bufhard; + struct snd_dbuf *bs = c->bufsoft; + unsigned int ret, amt; + + CHN_LOCKASSERT(c); + DEB( + if (c->flags & CHN_F_CLOSING) { + sndbuf_dump(b, "b", 0x02); + sndbuf_dump(bs, "bs", 0x02); + }) + + amt = sndbuf_getfree(b); + ret = (amt > 0)? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC; + if (ret == 0) + chn_wakeup(c); +/* + if (!(irqc & 63) || (ret != 0)) + sndbuf_dump(b, "b:wrfeed", 0x03); +*/ + return ret; } -/* - * Write interrupt routine. Can be called from other places (e.g. - * to start a paused transfer), but with interrupts disabled. - */ static void -chn_wrintr(pcm_channel *c) +chn_wrintr(struct pcm_channel *c) { - snd_dbuf *b = &c->buffer; - - if (b->underflow && !(c->flags & CHN_F_MAPPED)) { -/* printf("underflow return\n"); -*/ return; /* nothing new happened */ - } - if (b->dl) - chn_dmadone(c); - - /* - * start another dma operation only if have ready data in the buffer, - * there is no pending abort, have a full-duplex device, or have a - * half duplex device and there is no pending op on the other side. - * - * Force transfers to be aligned to a boundary of 4, which is - * needed when doing stereo and 16-bit. - */ - - /* Check underflow and update the pointers. */ - chn_checkunderflow(c); + int ret; - /* - * Fill up the DMA buffer, followed by waking up the top half. - * If some of the pcm data in uio are still left, the top half - * goes to sleep by itself. - */ - if (c->flags & CHN_F_MAPPED) - chn_wrfeed(c); - else { - while (chn_wrfeed(c) > 0); - sndbuf_clear(b, b->fl); - } - chn_dmawakeup(c); - if (c->flags & CHN_F_TRIGGERED) { + CHN_LOCKASSERT(c); + irqc++; + /* update pointers in primary buffer */ chn_dmaupdate(c); - /* - * check if we need to reprogram the DMA on the sound card. - * This happens if the size has changed from zero - */ - if (b->dl == 0) { - /* Start DMA operation */ - b->dl = b->blksz; /* record new transfer size */ - chn_trigger(c, PCMTRIG_START); - } - /* - * Emulate writing by DMA, i.e. transfer the pcm data from - * the emulated-DMA buffer to the device itself. - */ + /* ...and feed from secondary to primary */ + ret = chn_wrfeed(c); + /* tell the driver we've updated the primary buffer */ chn_trigger(c, PCMTRIG_EMLDMAWR); - if (b->rl < b->dl) { - DEB(printf("near underflow (%d < %d), %d\n", b->rl, b->dl, b->fl)); - /* - * we are near to underflow condition, so to prevent - * audio 'clicks' clear next b->fl bytes - */ - sndbuf_clear(b, b->fl); - if (b->rl < DMA_ALIGN_THRESHOLD) - b->underflow = 1; - } - } else { - /* cannot start a new dma transfer */ - DEB(printf("underflow, flags 0x%08x rp %d rl %d\n", c->flags, b->rp, b->rl)); - if (b->dl) { /* DMA was active */ - b->underflow = 1; /* set underflow flag */ - sndbuf_clear(b, b->bufsize); - } - } + DEB(if (ret) + printf("chn_wrintr: chn_wrfeed returned %d\n", ret);) } /* - * user write routine + * user write routine - uiomove data into secondary bufhard, trigger if necessary + * if blocking, sleep, rinse and repeat. * - * advance the boundary between READY and FREE, fill the space with - * uiomove(), and possibly start DMA. Do the above until the transfer - * is complete. - * - * To minimize latency in case a pending DMA transfer is about to end, - * we do the transfer in pieces of increasing sizes, extending the - * READY area at every checkpoint. In the (necessary) assumption that - * memory bandwidth is larger than the rate at which the dma consumes - * data, we reduce the latency to something proportional to the length - * of the first piece, while keeping the overhead low and being able - * to feed the DMA with large blocks. + * called externally, so must handle locking */ int -chn_write(pcm_channel *c, struct uio *buf) +chn_write(struct pcm_channel *c, struct uio *buf) { - int ret = 0, timeout, res, newsize, count; - long s; - snd_dbuf *b = &c->buffer; - snd_dbuf *bs = &c->buffer2nd; - - if (c->flags & CHN_F_WRITING) { - /* This shouldn't happen and is actually silly - * - will never wake up, just timeout; why not sleep on b? - */ - tsleep(&s, PZERO, "pcmwrW", hz); - return EBUSY; - } - c->flags |= CHN_F_WRITING; - c->flags &= ~CHN_F_ABORTING; - s = spltty(); + int ret, timeout, newsize, count, sz; + struct snd_dbuf *bs = c->bufsoft; + CHN_LOCKASSERT(c); /* * XXX Certain applications attempt to write larger size * of pcm data than c->blocksize2nd without blocking, * resulting partial write. Expand the block size so that * the write operation avoids blocking. */ - if ((c->flags & CHN_F_NBIO) && buf->uio_resid > bs->blksz) { - DEB(printf("pcm warning: broken app, nbio and tried to write %d bytes with fragsz %d\n", - buf->uio_resid, bs->blksz)); + if ((c->flags & CHN_F_NBIO) && buf->uio_resid > sndbuf_getblksz(bs)) { + DEB(device_printf(c->parent->dev, "broken app, nbio and tried to write %d bytes with fragsz %d\n", + buf->uio_resid, sndbuf_getblksz(bs))); newsize = 16; while (newsize < min(buf->uio_resid, CHN_2NDBUFMAXSIZE / 2)) newsize <<= 1; - chn_setblocksize(c, bs->blkcnt, newsize); - DEB(printf("pcm warning: frags reset to %d x %d\n", bs->blkcnt, bs->blksz)); + chn_setblocksize(c, sndbuf_getblkcnt(bs), newsize); + DEB(device_printf(c->parent->dev, "frags reset to %d x %d\n", sndbuf_getblkcnt(bs), sndbuf_getblksz(bs))); } - /* - * Fill up the secondary and DMA buffer. - * chn_wrfeed*() takes care of the alignment. - */ - - /* Check for underflow before writing into the buffers. */ - chn_checkunderflow(c); - while (chn_wrfeed2nd(c, buf) > 0); - if ((c->flags & CHN_F_NBIO) && (buf->uio_resid > 0)) - ret = EAGAIN; - - /* Start playing if not yet. */ - if (!b->dl) - chn_start(c, 0); - - if (ret == 0) { + ret = 0; count = hz; - /* Wait until all samples are played in blocking mode. */ - while ((buf->uio_resid > 0) && (count > 0)) { - /* Check for underflow before writing into the buffers. */ - chn_checkunderflow(c); - /* Fill up the buffers with new pcm data. */ - res = buf->uio_resid; - while (chn_wrfeed2nd(c, buf) > 0); - if (buf->uio_resid < res) + while (!ret && (buf->uio_resid > 0) && (count > 0)) { + sz = sndbuf_getfree(bs); + if (sz == 0) { + if (c->flags & CHN_F_NBIO) + ret = EWOULDBLOCK; + else { + timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs)); + if (timeout < 1) + timeout = 1; + ret = chn_sleep(c, "pcmwr", timeout); + if (ret == EWOULDBLOCK) { + count -= timeout; + ret = 0; + } else if (ret == 0) count = hz; - else - count--; - - /* Have we finished to feed the secondary buffer? */ - if (buf->uio_resid == 0) - break; - - /* Wait for new free space to write new pcm samples. */ - /* splx(s); */ - timeout = 1; /*(buf->uio_resid >= b->dl)? hz / 20 : 1; */ - ret = tsleep(b, PRIBIO | PCATCH, "pcmwr", timeout); - /* s = spltty(); */ - /* if (ret == EINTR) chn_abort(c); */ - if (ret == EINTR || ret == ERESTART) - break; } - if (count == 0) { + } else { + sz = MIN(sz, buf->uio_resid); + KASSERT(sz > 0, ("confusion in chn_write")); + /* printf("sz: %d\n", sz); */ + ret = sndbuf_uiomove(bs, buf, sz); + if (ret == 0 && !(c->flags & CHN_F_TRIGGERED)) + chn_start(c, 0); + } + } + /* printf("ret: %d left: %d\n", ret, buf->uio_resid); */ + + if (count <= 0) { c->flags |= CHN_F_DEAD; device_printf(c->parent->dev, "play interrupt timeout, channel dead\n"); } - } else - ret = 0; - c->flags &= ~CHN_F_WRITING; - splx(s); + return ret; } -/* - * SOUND INPUT - * - -The input part is similar to the output one, with a circular buffer -split in two regions, and boundaries advancing because of read() calls -[r] or dma operation [d]. At initialization, as for the write -routine, READY is empty, and FREE takes all the space. - - 0 rp,rl fp,fl bufsize - |__________>____________>________| - FREE r READY d FREE - -Operation is as follows: upon user read (dsp_read_body()) a DMA read -is started if not already active (marked by b->dl > 0), -then as soon as data are available in the READY region they are -transferred to the user buffer, thus advancing the boundary between FREE -and READY. Upon interrupts, caused by a completion of a DMA transfer, -the READY region is extended and possibly a new transfer is started. - -When necessary, dsp_rd_dmaupdate() is called to advance fp (and update -rl,fl accordingly). Upon user reads, rp is advanced and rl,fl are -updated accordingly. - -The rules to choose the size of the new DMA area are similar to -the other case, with a preferred constant transfer size equal to -rec_blocksize, and fallback to smaller sizes if no space is available. - - */ - static int -chn_rddump(pcm_channel *c, int cnt) +chn_rddump(struct pcm_channel *c, unsigned int cnt) { - snd_dbuf *b = &c->buffer; - int maxover, ss; - - ss = 1; - ss <<= (b->fmt & AFMT_STEREO)? 1 : 0; - ss <<= (b->fmt & AFMT_16BIT)? 1 : 0; - maxover = c->speed * ss; - - b->overrun += cnt; - if (b->overrun > maxover) { - device_printf(c->parent->dev, "record overrun, dumping %d bytes\n", - b->overrun); - b->overrun = 0; - } - b->rl -= cnt; - b->fl += cnt; - b->rp = (b->rp + cnt) % b->bufsize; - return cnt; + struct snd_dbuf *b = c->bufhard; + + CHN_LOCKASSERT(c); + sndbuf_setxrun(b, sndbuf_getxrun(b) + cnt); + return sndbuf_dispose(b, NULL, cnt); } /* - * Feed new data from the read buffer. Can be called in the bottom half. + * Feed new data from the read bufhard. Can be called in the bottom half. * Hence must be called at spltty. */ int -chn_rdfeed(pcm_channel *c) +chn_rdfeed(struct pcm_channel *c) { - snd_dbuf *b = &c->buffer; - snd_dbuf *bs = &c->buffer2nd; - int l, lacc; + struct snd_dbuf *b = c->bufhard; + struct snd_dbuf *bs = c->bufsoft; + int ret; - /* - printf("b: [rl: %d, rp %d, fl %d, fp %d]; bs: [rl: %d, rp %d, fl %d, fp %d]\n", - b->rl, b->rp, b->fl, b->fp, bs->rl, bs->rp, bs->fl, bs->fp); - */ - /* ensure we always have a whole number of samples */ - lacc = 0; - while (bs->fl >= DMA_ALIGN_THRESHOLD && b->rl >= DMA_ALIGN_THRESHOLD) { - l = min(min(bs->fl, bs->bufsize - bs->fp), min(b->rl, b->bufsize - b->rp)) & DMA_ALIGN_MASK; - /* Move the samples, update the markers and pointers. */ - bcopy(b->buf + b->rp, bs->buf + bs->fp, l); - bs->fl -= l; - bs->rl += l; - bs->fp = (bs->fp + l) % bs->bufsize; - b->rl -= l; - b->fl += l; - b->rp = (b->rp + l) % b->bufsize; - /* Accumulate the total bytes of the moved samples. */ - lacc += l; - /* A feed from the DMA buffer is equivalent to an interrupt. */ - bs->int_count++; - if (bs->sel.si_pid && chn_polltrigger(c)) - selwakeup(&bs->sel); - } + CHN_LOCKASSERT(c); + DEB( + if (c->flags & CHN_F_CLOSING) { + sndbuf_dump(b, "b", 0x02); + sndbuf_dump(bs, "bs", 0x02); + }) - return lacc; -} + ret = sndbuf_feed(b, bs, c, c->feeder, sndbuf_getblksz(b)); -/* Feeds new data from the secondary read buffer. */ -static int -chn_rdfeed2nd(pcm_channel *c, struct uio *buf) -{ - snd_dbuf *bs = &c->buffer2nd; - int l, w, wacc; - - /* ensure we always have a whole number of samples */ - wacc = 0; - while ((buf->uio_resid > 0) && (bs->rl > 0)) { - /* The DMA buffer may have pcm data. */ - /* while (chn_rdfeed(c) > 0); */ - /* - * The size of the data to move here does not have to be - * aligned. We take care of it upon moving the data to a - * DMA buffer. - */ - l = min(bs->rl, bs->bufsize - bs->rp); - /* Move the samples, update the markers and pointers. */ - w = FEEDER_FEED(c->feeder, c, bs->buf + bs->rp, l, buf); - if (w == 0) - panic("no feed"); - bs->fl += w; - bs->rl -= w; - bs->rp = (bs->rp + w) % bs->bufsize; - /* Clear the new space in the secondary buffer. */ - sndbuf_clear(bs, l); - /* Accumulate the total bytes of the moved samples. */ - bs->total += w; - wacc += w; - } + if (ret == 0) + chn_wakeup(c); - return wacc; + return ret; } -/* read interrupt routine. Must be called with interrupts blocked. */ -static void -chn_rdintr(pcm_channel *c) +void +chn_rdupdate(struct pcm_channel *c) { - snd_dbuf *b = &c->buffer; - - if (b->dl) chn_dmadone(c); + int ret; - DEB(printf("rdintr: start dl %d, rp:rl %d:%d, fp:fl %d:%d\n", - b->dl, b->rp, b->rl, b->fp, b->fl)); + CHN_LOCKASSERT(c); + KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel")); - /* Update the pointers. */ + if ((c->flags & CHN_F_MAPPED) || !(c->flags & CHN_F_TRIGGERED)) + return; + chn_trigger(c, PCMTRIG_EMLDMARD); chn_dmaupdate(c); + ret = chn_rdfeed(c); + if (ret) + printf("chn_rdfeed: %d\n", ret); - /* - * Suck up the DMA buffer, followed by waking up the top half. - * If some of the pcm data in the secondary buffer are still left, - * the top half goes to sleep by itself. - */ - while(chn_rdfeed(c) > 0); - chn_dmawakeup(c); +} - if (b->fl < b->dl) { - DEB(printf("near overflow (%d < %d), %d\n", b->fl, b->dl, b->rl)); - chn_rddump(c, b->blksz - b->fl); - } +/* read interrupt routine. Must be called with interrupts blocked. */ +static void +chn_rdintr(struct pcm_channel *c) +{ + struct snd_dbuf *b = c->bufhard; + int ret; - if (c->flags & CHN_F_TRIGGERED) { - /* - * check if we need to reprogram the DMA on the sound card. - * This happens if the size has changed from zero - */ - if (b->dl == 0) { - /* Start DMA operation */ - b->dl = b->blksz; /* record new transfer size */ - chn_trigger(c, PCMTRIG_START); - } - /* - * Emulate writing by DMA, i.e. transfer the pcm data from - * the emulated-DMA buffer to the device itself. - */ + CHN_LOCKASSERT(c); + /* tell the driver to update the primary bufhard if non-dma */ chn_trigger(c, PCMTRIG_EMLDMARD); - } else { - if (b->dl) { /* was active */ - b->dl = 0; - chn_trigger(c, PCMTRIG_STOP); + /* update pointers in primary bufhard */ chn_dmaupdate(c); - } - } + /* ...and feed from primary to secondary */ + ret = chn_rdfeed(c); + if (ret) + chn_rddump(c, sndbuf_getblksz(b)); } /* - * body of user-read routine - * - * Start DMA if not active; wait for READY not empty. - * Transfer data from READY region using uiomove(), advance boundary - * between FREE and READY. Repeat until transfer is complete. + * user read routine - trigger if necessary, uiomove data from secondary bufhard + * if blocking, sleep, rinse and repeat. * - * To avoid excessive latency in freeing up space for the DMA - * engine, transfers are done in blocks of increasing size, so that - * the latency is proportional to the size of the smallest block, but - * we have a low overhead and are able to feed the dma engine with - * large blocks. - * - * NOTE: in the current version, read will not return more than - * blocksize bytes at once (unless more are already available), to - * avoid that requests using very large buffers block for too long. + * called externally, so must handle locking */ int -chn_read(pcm_channel *c, struct uio *buf) +chn_read(struct pcm_channel *c, struct uio *buf) { - int ret = 0, timeout, limit, res, count; - long s; - snd_dbuf *b = &c->buffer; - snd_dbuf *bs = &c->buffer2nd; - - if (c->flags & CHN_F_READING) { - /* This shouldn't happen and is actually silly */ - tsleep(&s, PZERO, "pcmrdR", hz); - return (EBUSY); - } - - s = spltty(); - - /* Store the initial size in the uio. */ - res = buf->uio_resid; - - c->flags |= CHN_F_READING; - c->flags &= ~CHN_F_ABORTING; - - /* suck up the DMA and secondary buffers. */ - while (chn_rdfeed2nd(c, buf) > 0); - - if (buf->uio_resid == 0) - goto skip; - - limit = res - b->blksz; - if (limit < 0) - limit = 0; + int ret, timeout, sz, count; + struct snd_dbuf *bs = c->bufsoft; - /* Start capturing if not yet. */ - if ((!bs->rl || !b->rl) && !b->dl) + CHN_LOCKASSERT(c); + if (!(c->flags & CHN_F_TRIGGERED)) chn_start(c, 0); - if (!(c->flags & CHN_F_NBIO)) { - count = hz; - /* Wait until all samples are captured. */ - while ((buf->uio_resid > 0) && (count > 0)) { - /* Suck up the DMA and secondary buffers. */ - chn_dmaupdate(c); - res = buf->uio_resid; - while (chn_rdfeed(c) > 0); - while (chn_rdfeed2nd(c, buf) > 0); - if (buf->uio_resid < res) + ret = 0; count = hz; - else - count--; + while (!ret && (buf->uio_resid > 0) && (count > 0)) { + sz = MIN(buf->uio_resid, sndbuf_getblksz(bs)); - /* Have we finished to feed the uio? */ - if (buf->uio_resid == 0) - break; - - /* Wait for new pcm samples. */ - /* splx(s); */ - timeout = (buf->uio_resid - limit >= b->dl)? hz / 20 : 1; - ret = tsleep(b, PRIBIO | PCATCH, "pcmrd", 1); - /* s = spltty(); */ - /* if (ret == EINTR) chn_abort(c); */ - if (ret == EINTR || ret == ERESTART) - break; + if (sz <= sndbuf_getready(bs)) { + ret = sndbuf_uiomove(bs, buf, sz); + } else { + if (c->flags & CHN_F_NBIO) + ret = EWOULDBLOCK; + else { + timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs)); + if (timeout < 1) + timeout = 1; + CHN_UNLOCK(c); + ret = chn_sleep(c, "pcmrd", timeout); + CHN_LOCK(c); + if (ret == EWOULDBLOCK) { + count -= timeout; + ret = 0; + } + } } - if (count == 0) { + } + + if (count <= 0) { c->flags |= CHN_F_DEAD; device_printf(c->parent->dev, "record interrupt timeout, channel dead\n"); } - } else { - /* If no pcm data was read on nonblocking, return EAGAIN. */ - if (buf->uio_resid == res) - ret = EAGAIN; - } -skip: - c->flags &= ~CHN_F_READING; - splx(s); return ret; } void -chn_intr(pcm_channel *c) +chn_intr(struct pcm_channel *c) { - if (c->flags & CHN_F_INIT) - chn_reinit(c); + CHN_LOCK(c); if (c->direction == PCMDIR_PLAY) chn_wrintr(c); else chn_rdintr(c); + CHN_UNLOCK(c); } u_int32_t -chn_start(pcm_channel *c, int force) +chn_start(struct pcm_channel *c, int force) { - u_int32_t r, s; - snd_dbuf *b = &c->buffer; - - r = 0; - s = spltty(); - if (b->dl == 0 && !(c->flags & CHN_F_NOTRIGGER)) { - if (c->direction == PCMDIR_PLAY) { - if (!(c->flags & CHN_F_MAPPED)) - while (chn_wrfeed(c) > 0); /* Fill up the DMA buffer. */ - if (force || (b->rl >= b->blksz)) - r = CHN_F_TRIGGERED; - } else { - if (!(c->flags & CHN_F_MAPPED)) - while (chn_rdfeed(c) > 0); /* Suck up the DMA buffer. */ - if (force || (b->fl >= b->blksz)) - r = CHN_F_TRIGGERED; - } - c->flags |= r; - chn_intr(c); + u_int32_t i; + struct snd_dbuf *b = c->bufhard; + struct snd_dbuf *bs = c->bufsoft; + + CHN_LOCKASSERT(c); + /* if we're running, or if we're prevented from triggering, bail */ + if ((c->flags & CHN_F_TRIGGERED) || (c->flags & CHN_F_NOTRIGGER)) + return EINVAL; + + i = (c->direction == PCMDIR_PLAY)? sndbuf_getready(bs) : sndbuf_getfree(bs); + if (force || (i >= sndbuf_getblksz(b))) { + c->flags |= CHN_F_TRIGGERED; + if (c->direction == PCMDIR_PLAY) + chn_wrfeed(c); + sndbuf_setrun(b, 1); + chn_trigger(c, PCMTRIG_START); + return 0; } - splx(s); - return r; + + return 0; } void -chn_resetbuf(pcm_channel *c) +chn_resetbuf(struct pcm_channel *c) { - snd_dbuf *b = &c->buffer; - snd_dbuf *bs = &c->buffer2nd; + struct snd_dbuf *b = c->bufhard; + struct snd_dbuf *bs = c->bufsoft; c->blocks = 0; sndbuf_reset(b); @@ -853,133 +452,128 @@ chn_resetbuf(pcm_channel *c) * Assume that the condition can become true, do not check here... */ int -chn_sync(pcm_channel *c, int threshold) +chn_sync(struct pcm_channel *c, int threshold) { - u_long s, rdy; + u_long rdy; int ret; - snd_dbuf *b = &c->buffer; - snd_dbuf *bs = &c->buffer2nd; + struct snd_dbuf *bs = c->bufsoft; + CHN_LOCKASSERT(c); for (;;) { - s = spltty(); - chn_checkunderflow(c); - while (chn_wrfeed(c) > 0); - rdy = (c->direction == PCMDIR_PLAY)? bs->fl : bs->rl; + chn_wrupdate(c); + rdy = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs); if (rdy <= threshold) { - ret = tsleep((caddr_t)b, PRIBIO | PCATCH, "pcmsyn", 1); - splx(s); + ret = chn_sleep(c, "pcmsyn", 1); if (ret == ERESTART || ret == EINTR) { DEB(printf("chn_sync: tsleep returns %d\n", ret)); return -1; } - } else break; + } else + break; } - splx(s); return 0; } +/* called externally, handle locking */ int -chn_poll(pcm_channel *c, int ev, struct proc *p) +chn_poll(struct pcm_channel *c, int ev, struct proc *p) { - snd_dbuf *b = &c->buffer; - snd_dbuf *bs = &c->buffer2nd; - u_long s; + struct snd_dbuf *bs = c->bufsoft; int ret; - s = spltty(); - if (!(c->flags & CHN_F_MAPPED)) { - if (c->direction == PCMDIR_PLAY) { - /* Fill up the DMA buffer. */ - chn_checkunderflow(c); - while (chn_wrfeed(c) > 0); - } else { - /* Suck up the DMA buffer. */ - chn_dmaupdate(c); - while (chn_rdfeed(c) > 0); - } - if (!b->dl) + CHN_LOCK(c); + if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED)) chn_start(c, 1); - } ret = 0; if (chn_polltrigger(c) && chn_pollreset(c)) ret = ev; else - selrecord(p, &bs->sel); - splx(s); + selrecord(p, sndbuf_getsel(bs)); + CHN_UNLOCK(c); return ret; } /* - * chn_abort is a non-blocking function which aborts a pending - * DMA transfer and flushes the buffers. - * It returns the number of bytes that have not been transferred. + * chn_abort terminates a running dma transfer. it may sleep up to 200ms. + * it returns the number of bytes that have not been transferred. + * + * called from: dsp_close, dsp_ioctl, with both bufhards locked */ int -chn_abort(pcm_channel *c) +chn_abort(struct pcm_channel *c) { int missing = 0, cnt = 0; - snd_dbuf *b = &c->buffer; - snd_dbuf *bs = &c->buffer2nd; + struct snd_dbuf *b = c->bufhard; + struct snd_dbuf *bs = c->bufsoft; - if (!b->dl) + CHN_LOCKASSERT(c); + if (!(c->flags & CHN_F_TRIGGERED)) return 0; c->flags |= CHN_F_ABORTING; - c->flags &= ~CHN_F_TRIGGERED; + + /* wait up to 200ms for the secondary bufhard to empty */ cnt = 10; - while (!b->underflow && (cnt-- > 0)) - tsleep((caddr_t)b, PRIBIO | PCATCH, "pcmabr", hz / 50); + while ((sndbuf_getready(bs) > 0) && (cnt-- > 0)) { + chn_sleep(c, "pcmabr", hz / 50); + } + + c->flags &= ~CHN_F_TRIGGERED; + /* kill the channel */ chn_trigger(c, PCMTRIG_ABORT); - b->dl = 0; + sndbuf_setrun(b, 0); chn_dmaupdate(c); - missing = bs->rl + b->rl; + missing = sndbuf_getready(bs) + sndbuf_getready(b); + + c->flags &= ~CHN_F_ABORTING; return missing; } /* * this routine tries to flush the dma transfer. It is called * on a close. We immediately abort any read DMA - * operation, and then wait for the play buffer to drain. + * operation, and then wait for the play bufhard to drain. + * + * called from: dsp_close */ int -chn_flush(pcm_channel *c) +chn_flush(struct pcm_channel *c) { - int ret, count, s, resid, resid_p; - snd_dbuf *b = &c->buffer; - snd_dbuf *bs = &c->buffer2nd; + int ret, count, resid, resid_p; + struct snd_dbuf *b = c->bufhard; + struct snd_dbuf *bs = c->bufsoft; + CHN_LOCKASSERT(c); + KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel")); DEB(printf("chn_flush c->flags 0x%08x\n", c->flags)); - if (!b->dl) + if (!(c->flags & CHN_F_TRIGGERED)) return 0; c->flags |= CHN_F_CLOSING; - if (c->direction == PCMDIR_REC) - chn_abort(c); - else { - resid = b->rl + bs->rl; + resid = sndbuf_getready(bs) + sndbuf_getready(b); resid_p = resid; count = 10; - while ((count > 0) && (resid > 0) && !b->underflow) { + ret = 0; + while ((count > 0) && (resid > sndbuf_getsize(b)) && (ret == 0)) { /* still pending output data. */ - ret = tsleep((caddr_t)b, PRIBIO | PCATCH, "pcmflu", hz / 10); - if (ret == EINTR || ret == ERESTART) { - DEB(printf("chn_flush: tsleep returns %d\n", ret)); - return ret; - } - s = spltty(); - chn_dmaupdate(c); - splx(s); - DEB(printf("chn_flush: now rl = %d, fl = %d, resid = %d\n", b->rl, b->fl, resid)); - resid = b->rl + bs->rl; + ret = chn_sleep(c, "pcmflu", hz / 10); + if (ret == EWOULDBLOCK) + ret = 0; + if (ret == 0) { + resid = sndbuf_getready(bs) + sndbuf_getready(b); if (resid >= resid_p) count--; resid_p = resid; } - if (count == 0) - DEB(printf("chn_flush: timeout flushing dbuf_out, cnt 0x%x flags 0x%x\n", b->rl, c->flags)); - if (b->dl) - chn_abort(c); } + if (count == 0) + DEB(printf("chn_flush: timeout\n")); + + c->flags &= ~CHN_F_TRIGGERED; + /* kill the channel */ + chn_trigger(c, PCMTRIG_ABORT); + sndbuf_setrun(b, 0); + c->flags &= ~CHN_F_CLOSING; return 0; } @@ -996,11 +590,11 @@ fmtvalid(u_int32_t fmt, u_int32_t *fmtlist) } int -chn_reset(pcm_channel *c, u_int32_t fmt) +chn_reset(struct pcm_channel *c, u_int32_t fmt) { int hwspd, r = 0; - chn_abort(c); + CHN_LOCKASSERT(c); c->flags &= CHN_F_RESET; CHANNEL_RESET(c->methods, c->devinfo); if (fmt) { @@ -1015,35 +609,22 @@ chn_reset(pcm_channel *c, u_int32_t fmt) r = chn_setvolume(c, 100, 100); } r = chn_setblocksize(c, 0, 0); - if (r) - return r; + if (r == 0) { chn_resetbuf(c); CHANNEL_RESETDONE(c->methods, c->devinfo); - /* c->flags |= CHN_F_INIT; */ - return 0; -} - -int -chn_reinit(pcm_channel *c) -{ - if ((c->flags & CHN_F_INIT) && CANCHANGE(c)) { - chn_setformat(c, c->format); - chn_setspeed(c, c->speed); - chn_setvolume(c, (c->volume >> 8) & 0xff, c->volume & 0xff); - c->flags &= ~CHN_F_INIT; - return 1; } - return 0; + return r; } int -chn_init(pcm_channel *c, void *devinfo, int dir) +chn_init(struct pcm_channel *c, void *devinfo, int dir) { struct feeder_class *fc; - snd_dbuf *b = &c->buffer; - snd_dbuf *bs = &c->buffer2nd; + struct snd_dbuf *b, *bs; - /* Initialize the hardware and DMA buffer first. */ + chn_lockinit(c); + CHN_LOCK(c); + /* Initialize the hardware and DMA bufhard first. */ c->feeder = NULL; fc = feeder_getclass(NULL); if (fc == NULL) @@ -1051,82 +632,104 @@ chn_init(pcm_channel *c, void *devinfo, int dir) if (chn_addfeeder(c, fc, NULL)) return EINVAL; + b = sndbuf_create(c->name, "primary"); + if (b == NULL) + return ENOMEM; + bs = sndbuf_create(c->name, "secondary"); + if (bs == NULL) { + sndbuf_destroy(b); + return ENOMEM; + } + sndbuf_setup(bs, NULL, 0); + c->bufhard = b; + c->bufsoft = bs; c->flags = 0; c->feederflags = 0; - c->buffer.chan = -1; - c->devinfo = CHANNEL_INIT(c->methods, devinfo, &c->buffer, c, dir); - if (c->devinfo == NULL) + c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, dir); + if (c->devinfo == NULL) { + sndbuf_destroy(bs); + sndbuf_destroy(b); return ENODEV; - if (c->buffer.bufsize == 0) + } + if (sndbuf_getsize(b) == 0) { + sndbuf_destroy(bs); + sndbuf_destroy(b); return ENOMEM; + } chn_setdir(c, dir); - /* And the secondary buffer. */ - bs->buf = NULL; + /* And the secondary bufhard. */ sndbuf_setfmt(b, AFMT_U8); sndbuf_setfmt(bs, AFMT_U8); - bs->bufsize = 0; + CHN_UNLOCK(c); return 0; } int -chn_kill(pcm_channel *c) +chn_kill(struct pcm_channel *c) { + struct snd_dbuf *b = c->bufhard; + struct snd_dbuf *bs = c->bufsoft; + + CHN_LOCK(c); if (c->flags & CHN_F_TRIGGERED) chn_trigger(c, PCMTRIG_ABORT); while (chn_removefeeder(c) == 0); if (CHANNEL_FREE(c->methods, c->devinfo)) - sndbuf_free(&c->buffer); + sndbuf_free(c->bufhard); c->flags |= CHN_F_DEAD; + sndbuf_destroy(bs); + sndbuf_destroy(b); + chn_lockdestroy(c); return 0; } int -chn_setdir(pcm_channel *c, int dir) +chn_setdir(struct pcm_channel *c, int dir) { + struct snd_dbuf *b = c->bufhard; int r; + CHN_LOCKASSERT(c); c->direction = dir; r = CHANNEL_SETDIR(c->methods, c->devinfo, c->direction); - if (!r && ISA_DMA(&c->buffer)) - c->buffer.dir = (dir == PCMDIR_PLAY)? ISADMA_WRITE : ISADMA_READ; + if (!r && ISA_DMA(b)) + sndbuf_isadmasetdir(b, c->direction); return r; } int -chn_setvolume(pcm_channel *c, int left, int right) +chn_setvolume(struct pcm_channel *c, int left, int right) { + CHN_LOCKASSERT(c); /* could add a feeder for volume changing if channel returns -1 */ - if (CANCHANGE(c)) { c->volume = (left << 8) | right; return 0; - } - c->volume = (left << 8) | right; - c->flags |= CHN_F_INIT; - return 0; } static int -chn_tryspeed(pcm_channel *c, int speed) +chn_tryspeed(struct pcm_channel *c, int speed) { - pcm_feeder *f; - snd_dbuf *b = &c->buffer; - snd_dbuf *bs = &c->buffer2nd; + struct pcm_feeder *f; + struct snd_dbuf *b = c->bufhard; + struct snd_dbuf *bs = c->bufsoft; int r, delta; + CHN_LOCKASSERT(c); DEB(printf("want speed %d, ", speed)); if (speed <= 0) return EINVAL; if (CANCHANGE(c)) { + r = 0; c->speed = speed; - b->spd = speed; - bs->spd = speed; - RANGE(b->spd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); - DEB(printf("try speed %d, ", b->spd)); - b->spd = CHANNEL_SETSPEED(c->methods, c->devinfo, b->spd); - DEB(printf("got speed %d, ", b->spd)); - - delta = b->spd - bs->spd; + sndbuf_setspd(bs, speed); + RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); + sndbuf_setspd(b, speed); + DEB(printf("try speed %d, ", sndbuf_getspd(b))); + sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, sndbuf_getspd(b))); + DEB(printf("got speed %d, ", sndbuf_getspd(b))); + + delta = sndbuf_getspd(b) - sndbuf_getspd(bs); if (delta < 0) delta = -delta; @@ -1134,44 +737,41 @@ chn_tryspeed(pcm_channel *c, int speed) if (delta > 500) c->feederflags |= 1 << FEEDER_RATE; else - bs->spd = b->spd; + sndbuf_setspd(bs, sndbuf_getspd(b)); r = chn_buildfeeder(c); DEB(printf("r = %d\n", r)); if (r) - return r; + goto out; r = chn_setblocksize(c, 0, 0); if (r) - return r; + goto out; if (!(c->feederflags & (1 << FEEDER_RATE))) - return 0; + goto out; + r = EINVAL; f = chn_findfeeder(c, FEEDER_RATE); DEB(printf("feedrate = %p\n", f)); if (f == NULL) - return EINVAL; + goto out; - r = FEEDER_SET(f, FEEDRATE_SRC, bs->spd); - DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", bs->spd, r)); + r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(bs)); + DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(bs), r)); if (r) - return r; + goto out; - r = FEEDER_SET(f, FEEDRATE_DST, b->spd); - DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", b->spd, r)); - if (r) + r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(b)); + DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(b), r)); +out: return r; - - return 0; - } - c->speed = speed; - c->flags |= CHN_F_INIT; - return 0; + } else + return EINVAL; } int -chn_setspeed(pcm_channel *c, int speed) +chn_setspeed(struct pcm_channel *c, int speed) { int r, oldspeed = c->speed; @@ -1184,13 +784,14 @@ chn_setspeed(pcm_channel *c, int speed) } static int -chn_tryformat(pcm_channel *c, u_int32_t fmt) +chn_tryformat(struct pcm_channel *c, u_int32_t fmt) { - snd_dbuf *b = &c->buffer; - snd_dbuf *bs = &c->buffer2nd; + struct snd_dbuf *b = c->bufhard; + struct snd_dbuf *bs = c->bufsoft; int r; u_int32_t hwfmt; + CHN_LOCKASSERT(c); if (CANCHANGE(c)) { DEB(printf("want format %d\n", fmt)); c->format = fmt; @@ -1199,22 +800,21 @@ chn_tryformat(pcm_channel *c, u_int32_t fmt) if (!fmtvalid(hwfmt, chn_getcaps(c)->fmtlist)) c->feederflags |= 1 << FEEDER_FMT; r = chn_buildfeeder(c); - if (r) - return r; + if (r == 0) { hwfmt = c->feeder->desc->out; sndbuf_setfmt(b, hwfmt); - sndbuf_setfmt(bs, hwfmt); + sndbuf_setfmt(bs, fmt); chn_resetbuf(c); CHANNEL_SETFORMAT(c->methods, c->devinfo, hwfmt); - return chn_setspeed(c, c->speed); + r = chn_tryspeed(c, c->speed); } - c->format = fmt; - c->flags |= CHN_F_INIT; - return 0; + return r; + } else + return EINVAL; } int -chn_setformat(pcm_channel *c, u_int32_t fmt) +chn_setformat(struct pcm_channel *c, u_int32_t fmt) { u_int32_t oldfmt = c->format; int r; @@ -1228,20 +828,23 @@ chn_setformat(pcm_channel *c, u_int32_t fmt) } int -chn_setblocksize(pcm_channel *c, int blkcnt, int blksz) +chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz) { - snd_dbuf *b = &c->buffer; - snd_dbuf *bs = &c->buffer2nd; - int s, bufsz, irqhz, tmp; + struct snd_dbuf *b = c->bufhard; + struct snd_dbuf *bs = c->bufsoft; + int bufsz, irqhz, tmp, ret; + CHN_LOCKASSERT(c); if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED)) return EINVAL; + ret = 0; + DEB(printf("%s(%d, %d)\n", __FUNCTION__, blkcnt, blksz)); if (blksz == 0 || blksz == -1) { if (blksz == -1) c->flags &= ~CHN_F_HAS_SIZE; if (!(c->flags & CHN_F_HAS_SIZE)) { - blksz = (bs->bps * bs->spd) / CHN_DEFAULT_HZ; + blksz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / CHN_DEFAULT_HZ; tmp = 32; while (tmp <= blksz) tmp <<= 1; @@ -1251,84 +854,93 @@ chn_setblocksize(pcm_channel *c, int blkcnt, int blksz) RANGE(blksz, 16, CHN_2NDBUFMAXSIZE / 2); RANGE(blkcnt, 2, CHN_2NDBUFMAXSIZE / blksz); + DEB(printf("%s: defaulting to (%d, %d)\n", __FUNCTION__, blkcnt, blksz)); } else { - blksz = bs->blksz; - blkcnt = bs->blkcnt; + blkcnt = sndbuf_getblkcnt(bs); + blksz = sndbuf_getblksz(bs); + DEB(printf("%s: updating (%d, %d)\n", __FUNCTION__, blkcnt, blksz)); } } else { + ret = EINVAL; if ((blksz < 16) || (blkcnt < 2) || (blkcnt * blksz > CHN_2NDBUFMAXSIZE)) - return EINVAL; + goto out; + ret = 0; c->flags |= CHN_F_HAS_SIZE; } bufsz = blkcnt * blksz; - s = spltty(); - - if (bs->buf != NULL) - free(bs->buf, M_DEVBUF); - bs->buf = malloc(bufsz, M_DEVBUF, M_WAITOK); - if (bs->buf == NULL) { - splx(s); - DEB(printf("chn_setblocksize: out of memory\n")); - return ENOSPC; - } - - bs->bufsize = bufsz; - bs->blkcnt = blkcnt; - bs->blksz = blksz; + ret = ENOMEM; + if (sndbuf_remalloc(bs, blkcnt, blksz)) + goto out; + ret = 0; /* adjust for different hw format/speed */ - irqhz = (bs->bps * bs->spd) / bs->blksz; + irqhz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / sndbuf_getblksz(bs); + DEB(printf("%s: soft bps %d, spd %d, irqhz == %d\n", __FUNCTION__, sndbuf_getbps(bs), sndbuf_getspd(bs), irqhz)); RANGE(irqhz, 16, 512); - b->blksz = (b->bps * b->spd) / irqhz; + sndbuf_setblksz(b, (sndbuf_getbps(b) * sndbuf_getspd(b)) / irqhz); /* round down to 2^x */ blksz = 32; - while (blksz <= b->blksz) + while (blksz <= sndbuf_getblksz(b)) blksz <<= 1; blksz >>= 1; - /* round down to fit hw buffer size */ - RANGE(blksz, 16, b->maxsize / 2); + /* round down to fit hw bufhard size */ + RANGE(blksz, 16, sndbuf_getmaxsize(b) / 2); + DEB(printf("%s: hard blksz requested %d (maxsize %d), ", __FUNCTION__, blksz, sndbuf_getmaxsize(b))); - b->blksz = CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo, blksz); + sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo, blksz)); - chn_resetbuf(c); - splx(s); + irqhz = (sndbuf_getbps(b) * sndbuf_getspd(b)) / sndbuf_getblksz(b); + DEB(printf("got %d, irqhz == %d\n", sndbuf_getblksz(b), irqhz)); - return 0; + chn_resetbuf(c); +out: + return ret; } int -chn_trigger(pcm_channel *c, int go) +chn_trigger(struct pcm_channel *c, int go) { - return CHANNEL_TRIGGER(c->methods, c->devinfo, go); + struct snd_dbuf *b = c->bufhard; + int ret; + + CHN_LOCKASSERT(c); + if (ISA_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)) + sndbuf_isadmabounce(b); + ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go); + + return ret; } int -chn_getptr(pcm_channel *c) +chn_getptr(struct pcm_channel *c) { int hwptr; int a = (1 << c->align) - 1; - snd_dbuf *b = &c->buffer; - hwptr = b->dl? CHANNEL_GETPTR(c->methods, c->devinfo) : 0; + CHN_LOCKASSERT(c); + hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0; /* don't allow unaligned values in the hwa ptr */ +#if 1 hwptr &= ~a ; /* Apply channel align mask */ +#endif hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */ return hwptr; } -pcmchan_caps * -chn_getcaps(pcm_channel *c) +struct pcmchan_caps * +chn_getcaps(struct pcm_channel *c) { + CHN_LOCKASSERT(c); return CHANNEL_GETCAPS(c->methods, c->devinfo); } u_int32_t -chn_getformats(pcm_channel *c) +chn_getformats(struct pcm_channel *c) { u_int32_t *fmtlist, fmts; int i; @@ -1342,15 +954,16 @@ chn_getformats(pcm_channel *c) } static int -chn_buildfeeder(pcm_channel *c) +chn_buildfeeder(struct pcm_channel *c) { struct feeder_class *fc; struct pcm_feederdesc desc; u_int32_t tmp[2], src, dst, type, flags; + CHN_LOCKASSERT(c); while (chn_removefeeder(c) == 0); KASSERT((c->feeder == NULL), ("feeder chain not empty")); - c->align = 0; + c->align = sndbuf_getalign(c->bufsoft); fc = feeder_getclass(NULL); if (fc == NULL) return EINVAL; @@ -1399,3 +1012,6 @@ chn_buildfeeder(pcm_channel *c) } return 0; } + + + diff --git a/sys/dev/sound/pcm/channel.h b/sys/dev/sound/pcm/channel.h index 73c1b8c..2b4bfba 100644 --- a/sys/dev/sound/pcm/channel.h +++ b/sys/dev/sound/pcm/channel.h @@ -26,35 +26,69 @@ * $FreeBSD$ */ +struct pcmchan_caps { + u_int32_t minspeed, maxspeed; + u_int32_t *fmtlist; + u_int32_t caps; +}; + +#define CHN_NAMELEN 32 +struct pcm_channel { + kobj_t methods; + + struct pcm_feeder *feeder; + u_int32_t align; + + int volume; + u_int32_t speed; + u_int32_t format; + u_int32_t flags; + u_int32_t feederflags; + u_int32_t blocks; + + int direction; + struct snd_dbuf *bufhard, *bufsoft; + struct snddev_info *parent; + void *devinfo; + char name[CHN_NAMELEN]; + void *lock; +}; + #include "channel_if.h" -int chn_reinit(pcm_channel *c); -int chn_write(pcm_channel *c, struct uio *buf); -int chn_read(pcm_channel *c, struct uio *buf); -u_int32_t chn_start(pcm_channel *c, int force); -int chn_sync(pcm_channel *c, int threshold); -int chn_flush(pcm_channel *c); -int chn_poll(pcm_channel *c, int ev, struct proc *p); - -int chn_init(pcm_channel *c, void *devinfo, int dir); -int chn_kill(pcm_channel *c); -int chn_setdir(pcm_channel *c, int dir); -int chn_reset(pcm_channel *c, u_int32_t fmt); -int chn_setvolume(pcm_channel *c, int left, int right); -int chn_setspeed(pcm_channel *c, int speed); -int chn_setformat(pcm_channel *c, u_int32_t fmt); -int chn_setblocksize(pcm_channel *c, int blkcnt, int blksz); -int chn_trigger(pcm_channel *c, int go); -int chn_getptr(pcm_channel *c); -pcmchan_caps *chn_getcaps(pcm_channel *c); -u_int32_t chn_getformats(pcm_channel *c); - -void chn_resetbuf(pcm_channel *c); -void chn_intr(pcm_channel *c); -void chn_checkunderflow(pcm_channel *c); -int chn_wrfeed(pcm_channel *c); -int chn_rdfeed(pcm_channel *c); -int chn_abort(pcm_channel *c); +int chn_reinit(struct pcm_channel *c); +int chn_write(struct pcm_channel *c, struct uio *buf); +int chn_read(struct pcm_channel *c, struct uio *buf); +u_int32_t chn_start(struct pcm_channel *c, int force); +int chn_sync(struct pcm_channel *c, int threshold); +int chn_flush(struct pcm_channel *c); +int chn_poll(struct pcm_channel *c, int ev, struct proc *p); + +int chn_init(struct pcm_channel *c, void *devinfo, int dir); +int chn_kill(struct pcm_channel *c); +int chn_setdir(struct pcm_channel *c, int dir); +int chn_reset(struct pcm_channel *c, u_int32_t fmt); +int chn_setvolume(struct pcm_channel *c, int left, int right); +int chn_setspeed(struct pcm_channel *c, int speed); +int chn_setformat(struct pcm_channel *c, u_int32_t fmt); +int chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz); +int chn_trigger(struct pcm_channel *c, int go); +int chn_getptr(struct pcm_channel *c); +struct pcmchan_caps *chn_getcaps(struct pcm_channel *c); +u_int32_t chn_getformats(struct pcm_channel *c); + +void chn_resetbuf(struct pcm_channel *c); +void chn_intr(struct pcm_channel *c); +int chn_wrfeed(struct pcm_channel *c); +int chn_rdfeed(struct pcm_channel *c); +int chn_abort(struct pcm_channel *c); + +void chn_wrupdate(struct pcm_channel *c); +void chn_rdupdate(struct pcm_channel *c); + +#define CHN_LOCK(c) mtx_lock((struct mtx *)((c)->lock)) +#define CHN_UNLOCK(c) mtx_unlock((struct mtx *)((c)->lock)) +#define CHN_LOCKASSERT(c) int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist); @@ -67,11 +101,8 @@ int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist); #define PCMTRIG_STOP 0 #define PCMTRIG_ABORT -1 -#define CHN_F_READING 0x00000001 /* have a pending read */ -#define CHN_F_WRITING 0x00000002 /* have a pending write */ #define CHN_F_CLOSING 0x00000004 /* a pending close */ #define CHN_F_ABORTING 0x00000008 /* a pending abort */ -#define CHN_F_PENDING_IO (CHN_F_READING | CHN_F_WRITING) #define CHN_F_RUNNING 0x00000010 /* dma is running */ #define CHN_F_TRIGGERED 0x00000020 #define CHN_F_NOTRIGGER 0x00000040 @@ -79,7 +110,6 @@ int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist); #define CHN_F_BUSY 0x00001000 /* has been opened */ #define CHN_F_HAS_SIZE 0x00002000 /* user set block size */ #define CHN_F_NBIO 0x00004000 /* do non-blocking i/o */ -#define CHN_F_INIT 0x00008000 /* changed parameters. need init */ #define CHN_F_MAPPED 0x00010000 /* has been mmap()ed */ #define CHN_F_DEAD 0x00020000 #define CHN_F_BADSETTING 0x00040000 @@ -92,9 +122,9 @@ int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist); * (which is usually 48kHz * 16bit * stereo = 192000 bytes/sec) */ #define CHN_2NDBUFBLKSIZE (2 * 1024) -/* The total number of blocks per secondary buffer. */ +/* The total number of blocks per secondary bufhard. */ #define CHN_2NDBUFBLKNUM (32) -/* The size of a whole secondary buffer. */ +/* The size of a whole secondary bufhard. */ #define CHN_2NDBUFMAXSIZE (131072) #define CHN_DEFAULT_HZ 50 diff --git a/sys/dev/sound/pcm/channel_if.m b/sys/dev/sound/pcm/channel_if.m index d921f77..c5675da 100644 --- a/sys/dev/sound/pcm/channel_if.m +++ b/sys/dev/sound/pcm/channel_if.m @@ -62,8 +62,8 @@ CODE { METHOD void* init { kobj_t obj; void *devinfo; - snd_dbuf *b; - pcm_channel *c; + struct snd_dbuf *b; + struct pcm_channel *c; int dir; }; @@ -117,7 +117,7 @@ METHOD u_int32_t getptr { void *data; }; -METHOD pcmchan_caps* getcaps { +METHOD struct pcmchan_caps* getcaps { kobj_t obj; void *data; }; diff --git a/sys/dev/sound/pcm/datatypes.h b/sys/dev/sound/pcm/datatypes.h index 304a886..4ab5af3 100644 --- a/sys/dev/sound/pcm/datatypes.h +++ b/sys/dev/sound/pcm/datatypes.h @@ -118,7 +118,7 @@ struct _pcm_channel { u_int32_t blocks; int direction; - snd_dbuf buffer, buffer2nd; + snd_dbuf buffer, bufsoft; snddev_info *parent; void *devinfo; }; diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c index a80910b..0954442 100644 --- a/sys/dev/sound/pcm/dsp.c +++ b/sys/dev/sound/pcm/dsp.c @@ -33,12 +33,12 @@ #define OLDPCM_IOCTL -static int getchns(snddev_info *d, int chan, pcm_channel **rdch, pcm_channel **wrch); +static int getchns(struct snddev_info *d, int chan, struct pcm_channel **rdch, struct pcm_channel **wrch); -static pcm_channel * -allocchn(snddev_info *d, int direction) +static struct pcm_channel * +allocchn(struct snddev_info *d, int direction) { - pcm_channel *chns = (direction == PCMDIR_PLAY)? d->play : d->rec; + struct pcm_channel *chns = (direction == PCMDIR_PLAY)? d->play : d->rec; int i, cnt = (direction == PCMDIR_PLAY)? d->playcount : d->reccount; for (i = 0; i < cnt; i++) { if (!(chns[i].flags & (CHN_F_BUSY | CHN_F_DEAD))) { @@ -50,15 +50,15 @@ allocchn(snddev_info *d, int direction) } static int -getchns(snddev_info *d, int chan, pcm_channel **rdch, pcm_channel **wrch) +getchns(struct snddev_info *d, int chan, struct pcm_channel **rdch, struct pcm_channel **wrch) { KASSERT((d->flags & SD_F_PRIO_SET) != SD_F_PRIO_SET, \ ("getchns: read and write both prioritised")); if ((d->flags & SD_F_SIMPLEX) && (d->flags & SD_F_PRIO_SET)) { - *rdch = (d->flags & SD_F_PRIO_RD)? d->arec[chan] : &d->fakechan; - *wrch = (d->flags & SD_F_PRIO_WR)? d->aplay[chan] : &d->fakechan; - d->fakechan.flags |= CHN_F_BUSY; + *rdch = (d->flags & SD_F_PRIO_RD)? d->arec[chan] : d->fakechan; + *wrch = (d->flags & SD_F_PRIO_WR)? d->aplay[chan] : d->fakechan; + d->fakechan->flags |= CHN_F_BUSY; } else { *rdch = d->arec[chan]; *wrch = d->aplay[chan]; @@ -67,7 +67,7 @@ getchns(snddev_info *d, int chan, pcm_channel **rdch, pcm_channel **wrch) } static void -setchns(snddev_info *d, int chan) +setchns(struct snddev_info *d, int chan) { KASSERT((d->flags & SD_F_PRIO_SET) != SD_F_PRIO_SET, \ ("getchns: read and write both prioritised")); @@ -75,14 +75,13 @@ setchns(snddev_info *d, int chan) } int -dsp_open(snddev_info *d, int chan, int oflags, int devtype) +dsp_open(struct snddev_info *d, int chan, int oflags, int devtype) { - pcm_channel *rdch, *wrch; + struct pcm_channel *rdch, *wrch; u_int32_t fmt; if (chan >= d->chancount) return ENODEV; if ((d->flags & SD_F_SIMPLEX) && (d->ref[chan] > 0)) return EBUSY; - if (d->atype[chan] != 0 && d->atype[chan] != devtype) return EBUSY; rdch = d->arec[chan]; wrch = d->aplay[chan]; @@ -102,7 +101,6 @@ dsp_open(snddev_info *d, int chan, int oflags, int devtype) } } else return EBUSY; } - d->atype[chan] = devtype; d->aplay[chan] = wrch; d->arec[chan] = rdch; d->ref[chan]++; @@ -126,6 +124,10 @@ dsp_open(snddev_info *d, int chan, int oflags, int devtype) default: return ENXIO; } + if (rdch) + CHN_LOCK(rdch); + if (wrch) + CHN_LOCK(wrch); if (rdch && (oflags & FREAD)) { chn_reset(rdch, fmt); @@ -135,77 +137,101 @@ dsp_open(snddev_info *d, int chan, int oflags, int devtype) chn_reset(wrch, fmt); if (oflags & O_NONBLOCK) wrch->flags |= CHN_F_NBIO; } + if (wrch) + CHN_UNLOCK(wrch); + if (rdch) + CHN_UNLOCK(rdch); return 0; } int -dsp_close(snddev_info *d, int chan, int devtype) +dsp_close(struct snddev_info *d, int chan, int devtype) { - pcm_channel *rdch, *wrch; + struct pcm_channel *rdch, *wrch; - d->ref[chan] = 0; -#if 0 - /* enable this if/when every close() is propagated here */ + d->ref[chan]--; if (d->ref[chan]) return 0; -#endif d->flags &= ~SD_F_TRANSIENT; rdch = d->arec[chan]; wrch = d->aplay[chan]; if (rdch) { + CHN_LOCK(rdch); chn_abort(rdch); rdch->flags &= ~(CHN_F_BUSY | CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD); chn_reset(rdch, 0); + CHN_UNLOCK(rdch); } if (wrch) { + CHN_LOCK(wrch); chn_flush(wrch); wrch->flags &= ~(CHN_F_BUSY | CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD); chn_reset(wrch, 0); + CHN_UNLOCK(wrch); } d->aplay[chan] = NULL; d->arec[chan] = NULL; - d->atype[chan] = 0; return 0; } int -dsp_read(snddev_info *d, int chan, struct uio *buf, int flag) +dsp_read(struct snddev_info *d, int chan, struct uio *buf, int flag) { - pcm_channel *rdch, *wrch; + struct pcm_channel *rdch, *wrch; + int ret; if (!(d->flags & SD_F_PRIO_SET)) d->flags |= SD_F_PRIO_RD; if (!(d->flags & SD_F_DIR_SET)) setchns(d, chan); + getchns(d, chan, &rdch, &wrch); + CHN_LOCK(rdch); KASSERT(rdch, ("dsp_read: nonexistant channel")); KASSERT(rdch->flags & CHN_F_BUSY, ("dsp_read: nonbusy channel")); - if (rdch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) return EINVAL; + + if (rdch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) { + CHN_UNLOCK(rdch); + return EINVAL; + } if (!(rdch->flags & CHN_F_RUNNING)) rdch->flags |= CHN_F_RUNNING; - return chn_read(rdch, buf); + ret = chn_read(rdch, buf); + CHN_UNLOCK(rdch); + + return ret; } int -dsp_write(snddev_info *d, int chan, struct uio *buf, int flag) +dsp_write(struct snddev_info *d, int chan, struct uio *buf, int flag) { - pcm_channel *rdch, *wrch; + struct pcm_channel *rdch, *wrch; + int ret; if (!(d->flags & SD_F_PRIO_SET)) d->flags |= SD_F_PRIO_WR; if (!(d->flags & SD_F_DIR_SET)) setchns(d, chan); + getchns(d, chan, &rdch, &wrch); + CHN_LOCK(wrch); KASSERT(wrch, ("dsp_write: nonexistant channel")); KASSERT(wrch->flags & CHN_F_BUSY, ("dsp_write: nonbusy channel")); - if (wrch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) return EINVAL; + + if (wrch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) { + CHN_UNLOCK(wrch); + return EINVAL; + } if (!(wrch->flags & CHN_F_RUNNING)) wrch->flags |= CHN_F_RUNNING; - return chn_write(wrch, buf); + ret = chn_write(wrch, buf); + CHN_UNLOCK(wrch); + + return ret; } int -dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) +dsp_ioctl(struct snddev_info *d, int chan, u_long cmd, caddr_t arg) { int ret = 0, *arg_i = (int *)arg; u_long s; - pcm_channel *wrch = NULL, *rdch = NULL; + struct pcm_channel *wrch = NULL, *rdch = NULL; rdch = d->arec[chan]; wrch = d->aplay[chan]; @@ -216,6 +242,11 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) wrch = NULL; if (!(rdch || wrch)) return EINVAL; + + if (wrch) + CHN_LOCK(wrch); + if (rdch) + CHN_LOCK(rdch); /* * all routines are called with int. blocked. Make sure that * ints are re-enabled when calling slow or blocking functions! @@ -227,9 +258,11 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) * we start with the new ioctl interface. */ case AIONWRITE: /* how many bytes can write ? */ - if (wrch && wrch->buffer.dl) - while (chn_wrfeed(wrch) > 0); - *arg_i = wrch? wrch->buffer2nd.fl : 0; +/* + if (wrch && wrch->bufhard.dl) + while (chn_wrfeed(wrch) == 0); +*/ + *arg_i = wrch? sndbuf_getfree(wrch->bufsoft) : 0; break; case AIOSSIZE: /* set the current blocksize */ @@ -245,9 +278,9 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) { struct snd_size *p = (struct snd_size *)arg; if (wrch) - p->play_size = wrch->buffer2nd.blksz; + p->play_size = sndbuf_getblksz(wrch->bufsoft); if (rdch) - p->rec_size = rdch->buffer2nd.blksz; + p->rec_size = sndbuf_getblksz(rdch->bufsoft); } break; @@ -278,15 +311,15 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) case AIOGCAP: /* get capabilities */ { snd_capabilities *p = (snd_capabilities *)arg; - pcmchan_caps *pcaps = NULL, *rcaps = NULL; + struct pcmchan_caps *pcaps = NULL, *rcaps = NULL; if (rdch) rcaps = chn_getcaps(rdch); if (wrch) pcaps = chn_getcaps(wrch); p->rate_min = max(rcaps? rcaps->minspeed : 0, pcaps? pcaps->minspeed : 0); p->rate_max = min(rcaps? rcaps->maxspeed : 1000000, pcaps? pcaps->maxspeed : 1000000); - p->bufsize = min(rdch? rdch->buffer2nd.bufsize : 1000000, - wrch? wrch->buffer2nd.bufsize : 1000000); + p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000, + wrch? sndbuf_getsize(wrch->bufsoft) : 1000000); /* XXX bad on sb16 */ p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) & (wrch? chn_getformats(wrch) : 0xffffffff); @@ -318,9 +351,9 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) * here follow the standard ioctls (filio.h etc.) */ case FIONREAD: /* get # bytes to read */ - if (rdch && rdch->buffer.dl) - while (chn_rdfeed(rdch) > 0); - *arg_i = rdch? rdch->buffer2nd.rl : 0; +/* if (rdch && rdch->bufhard.dl) + while (chn_rdfeed(rdch) == 0); +*/ *arg_i = rdch? sndbuf_getready(rdch->bufsoft) : 0; break; case FIOASYNC: /*set/clear async i/o */ @@ -344,9 +377,9 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) case THE_REAL_SNDCTL_DSP_GETBLKSIZE: case SNDCTL_DSP_GETBLKSIZE: if (wrch) - *arg_i = wrch->buffer2nd.blksz; + *arg_i = sndbuf_getblksz(wrch->bufsoft); else if (rdch) - *arg_i = rdch->buffer2nd.blksz; + *arg_i = sndbuf_getblksz(rdch->bufsoft); else *arg_i = 0; break ; @@ -359,19 +392,18 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) case SNDCTL_DSP_RESET: DEB(printf("dsp reset\n")); - splx(s); - if (wrch) chn_abort(wrch); - if (rdch) chn_abort(rdch); + if (wrch) + chn_abort(wrch); + if (rdch) + chn_abort(rdch); break; case SNDCTL_DSP_SYNC: DEB(printf("dsp sync\n")); - splx(s); - if (wrch) chn_sync(wrch, wrch->buffer2nd.bufsize - 4); + if (wrch) chn_sync(wrch, sndbuf_getsize(wrch->bufsoft) - 4); break; case SNDCTL_DSP_SPEED: - splx(s); if (wrch) ret = chn_setspeed(wrch, *arg_i); if (rdch && ret == 0) @@ -383,7 +415,6 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) break; case SNDCTL_DSP_STEREO: - splx(s); if (wrch) ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | ((*arg_i)? AFMT_STEREO : 0)); @@ -395,7 +426,6 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) case SOUND_PCM_WRITE_CHANNELS: /* case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */ - splx(s); if (*arg_i == 1 || *arg_i == 2) { if (wrch) ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | @@ -427,15 +457,10 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) *arg_i = (wrch? wrch->format : rdch->format) & ~AFMT_STEREO; break; - case SNDCTL_DSP_SUBDIVIDE: - /* XXX watch out, this is RW! */ - printf("SNDCTL_DSP_SUBDIVIDE unimplemented\n"); - break; - case SNDCTL_DSP_SETFRAGMENT: DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg)); { - pcm_channel *c = wrch? wrch : rdch; + struct pcm_channel *c = wrch? wrch : rdch; u_int32_t fragln = (*arg_i) & 0x0000ffff; u_int32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16; u_int32_t fragsz; @@ -458,13 +483,13 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) if (wrch && ret == 0) ret = chn_setblocksize(wrch, maxfrags, fragsz); - fragsz = c->buffer2nd.blksz; + fragsz = sndbuf_getblksz(c->bufsoft); fragln = 0; while (fragsz > 1) { fragln++; fragsz >>= 1; } - *arg_i = (c->buffer2nd.blkcnt << 16) | fragln; + *arg_i = (sndbuf_getblkcnt(c->bufsoft) << 16) | fragln; } break; @@ -473,18 +498,13 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) { audio_buf_info *a = (audio_buf_info *)arg; if (rdch) { - snd_dbuf *b = &rdch->buffer; - snd_dbuf *bs = &rdch->buffer2nd; - if (b->dl && !(rdch->flags & CHN_F_MAPPED)) - /* - * Suck up the secondary and DMA buffer. - * chn_rdfeed*() takes care of the alignment. - */ - while (chn_rdfeed(rdch) > 0); - a->bytes = bs->rl; - a->fragments = a->bytes / rdch->buffer2nd.blksz; - a->fragstotal = rdch->buffer2nd.blkcnt; - a->fragsize = rdch->buffer2nd.blksz; + struct snd_dbuf *bs = rdch->bufsoft; + + chn_rdupdate(rdch); + a->bytes = sndbuf_getfree(bs); + a->fragments = a->bytes / sndbuf_getblksz(bs); + a->fragstotal = sndbuf_getblkcnt(bs); + a->fragsize = sndbuf_getblksz(bs); } } break; @@ -494,21 +514,13 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) { audio_buf_info *a = (audio_buf_info *)arg; if (wrch) { - snd_dbuf *b = &wrch->buffer; - snd_dbuf *bs = &wrch->buffer2nd; - if (b->dl && !(wrch->flags & CHN_F_MAPPED)) { - /* - * Fill up the secondary and DMA buffer. - * chn_wrfeed*() takes care of the alignment. - * Check for underflow before writing into the buffers. - */ - chn_checkunderflow(wrch); - while (chn_wrfeed(wrch) > 0); - } - a->bytes = bs->fl; - a->fragments = a->bytes / wrch->buffer2nd.blksz; - a->fragstotal = wrch->buffer2nd.blkcnt; - a->fragsize = wrch->buffer2nd.blksz; + struct snd_dbuf *bs = wrch->bufsoft; + + chn_wrupdate(wrch); + a->bytes = sndbuf_getfree(bs); + a->fragments = a->bytes / sndbuf_getblksz(bs); + a->fragstotal = sndbuf_getblkcnt(bs); + a->fragsize = sndbuf_getblksz(bs); } } break; @@ -517,18 +529,13 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) { count_info *a = (count_info *)arg; if (rdch) { - snd_dbuf *b = &rdch->buffer; - snd_dbuf *bs = &rdch->buffer2nd; - if (b->dl && !(rdch->flags & CHN_F_MAPPED)) - /* - * Suck up the secondary and DMA buffer. - * chn_rdfeed*() takes care of the alignment. - */ - while (chn_rdfeed(rdch) > 0); - a->bytes = bs->total; - a->blocks = rdch->blocks; - a->ptr = bs->rp; - rdch->blocks = 0; + struct snd_dbuf *bs = rdch->bufsoft; + + chn_rdupdate(rdch); + a->bytes = sndbuf_gettotal(bs); + a->blocks = sndbuf_getblocks(bs) - rdch->blocks; + a->ptr = sndbuf_getreadyptr(bs); + rdch->blocks = sndbuf_getblocks(bs); } else ret = EINVAL; } break; @@ -537,21 +544,13 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) { count_info *a = (count_info *)arg; if (wrch) { - snd_dbuf *b = &wrch->buffer; - snd_dbuf *bs = &wrch->buffer2nd; - if (b->dl && !(wrch->flags & CHN_F_MAPPED)) { - /* - * Fill up the secondary and DMA buffer. - * chn_wrfeed*() takes care of the alignment. - * Check for underflow before writing into the buffers. - */ - chn_checkunderflow(wrch); - while (chn_wrfeed(wrch) > 0); - } - a->bytes = bs->total; - a->blocks = wrch->blocks; - a->ptr = bs->rp; - wrch->blocks = 0; + struct snd_dbuf *bs = wrch->bufsoft; + + chn_wrupdate(wrch); + a->bytes = sndbuf_gettotal(bs); + a->blocks = sndbuf_getblocks(bs) - wrch->blocks; + a->ptr = sndbuf_getreadyptr(bs); + wrch->blocks = sndbuf_getblocks(bs); } else ret = EINVAL; } break; @@ -569,19 +568,19 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) case SNDCTL_DSP_SETTRIGGER: if (rdch) { rdch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER); - if (*arg_i & PCM_ENABLE_INPUT) + if (*arg_i & PCM_ENABLE_INPUT) { rdch->flags |= CHN_F_TRIGGERED; - else + chn_start(rdch, 1); + } else rdch->flags |= CHN_F_NOTRIGGER; - chn_intr(rdch); } if (wrch) { wrch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER); - if (*arg_i & PCM_ENABLE_OUTPUT) + if (*arg_i & PCM_ENABLE_OUTPUT) { wrch->flags |= CHN_F_TRIGGERED; - else + chn_start(wrch, 1); + } else wrch->flags |= CHN_F_NOTRIGGER; - chn_intr(wrch); } break; @@ -595,14 +594,11 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) case SNDCTL_DSP_GETODELAY: if (wrch) { - snd_dbuf *b = &wrch->buffer; - snd_dbuf *bs = &wrch->buffer2nd; - if (b->dl) { - chn_checkunderflow(wrch); - if (!(wrch->flags & CHN_F_MAPPED)) - while (chn_wrfeed(wrch) > 0); - } - *arg_i = b->rl + bs->rl; + struct snd_dbuf *b = wrch->bufhard; + struct snd_dbuf *bs = wrch->bufsoft; + + chn_wrupdate(wrch); + *arg_i = sndbuf_getready(b) + sndbuf_getready(bs); } else ret = EINVAL; break; @@ -619,6 +615,7 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) case SNDCTL_DSP_SETSYNCRO: /* undocumented */ + case SNDCTL_DSP_SUBDIVIDE: case SOUND_PCM_WRITE_FILTER: case SOUND_PCM_READ_FILTER: /* dunno what these do, don't sound important */ @@ -627,39 +624,57 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) ret = EINVAL; break; } - splx(s); + if (rdch) + CHN_UNLOCK(rdch); + if (wrch) + CHN_UNLOCK(wrch); return ret; } int -dsp_poll(snddev_info *d, int chan, int events, struct proc *p) +dsp_poll(struct snddev_info *d, int chan, int events, struct proc *p) { int ret = 0, e; - pcm_channel *wrch = NULL, *rdch = NULL; + struct pcm_channel *wrch = NULL, *rdch = NULL; getchns(d, chan, &rdch, &wrch); + e = events & (POLLOUT | POLLWRNORM); if (wrch && e) ret |= chn_poll(wrch, e, p); + e = events & (POLLIN | POLLRDNORM); if (rdch && e) ret |= chn_poll(rdch, e, p); + return ret; } int -dsp_mmap(snddev_info *d, int chan, vm_offset_t offset, int nprot) +dsp_mmap(struct snddev_info *d, int chan, vm_offset_t offset, int nprot) { - pcm_channel *wrch = NULL, *rdch = NULL, *c = NULL; + struct pcm_channel *wrch = NULL, *rdch = NULL, *c = NULL; + int ret; getchns(d, chan, &rdch, &wrch); - /* XXX this is broken by line 204 of vm/device_pager.c, so force write buffer */ +#if 0 + /* + * XXX the linux api uses the nprot to select read/write bufhard + * our vm system doesn't allow this, so force write bufhard + */ + if (1 || (wrch && (nprot & PROT_WRITE))) c = wrch; else if (rdch && (nprot & PROT_READ)) c = rdch; - if (c && (c->format == c->buffer.fmt)) { - c->flags |= CHN_F_MAPPED; - return atop(vtophys(c->buffer2nd.buf + offset)); - } else +#else + c = wrch; +#endif + + if (c == NULL) return -1; + CHN_LOCK(c); + c->flags |= CHN_F_MAPPED; + ret = atop(vtophys(((char *)sndbuf_getbuf(c->bufsoft)) + offset)); + CHN_UNLOCK(c); + return ret; } diff --git a/sys/dev/sound/pcm/dsp.h b/sys/dev/sound/pcm/dsp.h index c1ce073..89d0624 100644 --- a/sys/dev/sound/pcm/dsp.h +++ b/sys/dev/sound/pcm/dsp.h @@ -26,12 +26,12 @@ * $FreeBSD$ */ -int dsp_open(snddev_info *d, int chan, int oflags, int devtype); -int dsp_close(snddev_info *d, int chan, int devtype); -int dsp_read(snddev_info *d, int chan, struct uio *buf, int flag); -int dsp_write(snddev_info *d, int chan, struct uio *buf, int flag); -int dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg); -int dsp_poll(snddev_info *d, int chan, int events, struct proc *p); -int dsp_mmap(snddev_info *d, int chan, vm_offset_t offset, int nprot); +int dsp_open(struct snddev_info *d, int chan, int oflags, int devtype); +int dsp_close(struct snddev_info *d, int chan, int devtype); +int dsp_read(struct snddev_info *d, int chan, struct uio *buf, int flag); +int dsp_write(struct snddev_info *d, int chan, struct uio *buf, int flag); +int dsp_ioctl(struct snddev_info *d, int chan, u_long cmd, caddr_t arg); +int dsp_poll(struct snddev_info *d, int chan, int events, struct proc *p); +int dsp_mmap(struct snddev_info *d, int chan, vm_offset_t offset, int nprot); diff --git a/sys/dev/sound/pcm/fake.c b/sys/dev/sound/pcm/fake.c index e73fb6d..9001653 100644 --- a/sys/dev/sound/pcm/fake.c +++ b/sys/dev/sound/pcm/fake.c @@ -43,14 +43,16 @@ static u_int32_t fk_fmt[] = { AFMT_STEREO | AFMT_U16_BE, 0 }; -static pcmchan_caps fk_caps = {0, 1000000, fk_fmt, 0}; +static struct pcmchan_caps fk_caps = {0, 1000000, fk_fmt, 0}; + +#define FKBUFSZ 4096 +static char fakebuf[FKBUFSZ]; /* channel interface */ static void * -fkchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +fkchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { - b->bufsize = 16384; - b->buf = malloc(b->bufsize, M_DEVBUF, M_NOWAIT); + sndbuf_setup(b, fakebuf, FKBUFSZ); return (void *)0xbabef00d; } @@ -90,7 +92,7 @@ fkchan_getptr(kobj_t obj, void *data) return 0; } -static pcmchan_caps * +static struct pcmchan_caps * fkchan_getcaps(kobj_t obj, void *data) { return &fk_caps; @@ -109,18 +111,26 @@ static kobj_method_t fkchan_methods[] = { }; CHANNEL_DECLARE(fkchan); -int -fkchan_setup(pcm_channel *c) +struct pcm_channel * +fkchan_setup(device_t dev) { + struct snddev_info *d = device_get_softc(dev); + struct pcm_channel *c; + + c = malloc(sizeof(*c), M_DEVBUF, M_WAITOK); c->methods = kobj_create(&fkchan_class, M_DEVBUF, M_WAITOK); - return 0; + c->parent = d; + snprintf(c->name, CHN_NAMELEN, "%s:fake", device_get_nameunit(dev)); + + return c; } int -fkchan_kill(pcm_channel *c) +fkchan_kill(struct pcm_channel *c) { kobj_delete(c->methods, M_DEVBUF); c->methods = NULL; + free(c, M_DEVBUF); return 0; } diff --git a/sys/dev/sound/pcm/feeder.c b/sys/dev/sound/pcm/feeder.c index 1d7af27..bfa9aba 100644 --- a/sys/dev/sound/pcm/feeder.c +++ b/sys/dev/sound/pcm/feeder.c @@ -105,20 +105,20 @@ cmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m) } static void -feeder_destroy(pcm_feeder *f) +feeder_destroy(struct pcm_feeder *f) { FEEDER_FREE(f); free(f->desc, M_FEEDER); kobj_delete((kobj_t)f, M_FEEDER); } -static pcm_feeder * +static struct pcm_feeder * feeder_create(struct feeder_class *fc, struct pcm_feederdesc *desc) { - pcm_feeder *f; + struct pcm_feeder *f; int err; - f = (pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_WAITOK | M_ZERO); + f = (struct pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_WAITOK | M_ZERO); f->align = fc->align; f->desc = malloc(sizeof(*(f->desc)), M_FEEDER, M_WAITOK | M_ZERO); if (desc) @@ -155,9 +155,9 @@ feeder_getclass(struct pcm_feederdesc *desc) } int -chn_addfeeder(pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc) +chn_addfeeder(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc) { - pcm_feeder *nf; + struct pcm_feeder *nf; nf = feeder_create(fc, desc); if (nf == NULL) @@ -176,9 +176,9 @@ chn_addfeeder(pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *de } int -chn_removefeeder(pcm_channel *c) +chn_removefeeder(struct pcm_channel *c) { - pcm_feeder *f; + struct pcm_feeder *f; if (c->feeder == NULL) return -1; @@ -188,10 +188,10 @@ chn_removefeeder(pcm_channel *c) return 0; } -pcm_feeder * -chn_findfeeder(pcm_channel *c, u_int32_t type) +struct pcm_feeder * +chn_findfeeder(struct pcm_channel *c, u_int32_t type) { - pcm_feeder *f; + struct pcm_feeder *f; f = c->feeder; while (f != NULL) { @@ -203,7 +203,7 @@ chn_findfeeder(pcm_channel *c, u_int32_t type) } static int -chainok(pcm_feeder *test, pcm_feeder *stop) +chainok(struct pcm_feeder *test, struct pcm_feeder *stop) { u_int32_t visited[MAXFEEDERS / 32]; u_int32_t idx, mask; @@ -225,11 +225,11 @@ chainok(pcm_feeder *test, pcm_feeder *stop) return 1; } -static pcm_feeder * -feeder_fmtchain(u_int32_t *to, pcm_feeder *source, pcm_feeder *stop, int maxdepth) +static struct pcm_feeder * +feeder_fmtchain(u_int32_t *to, struct pcm_feeder *source, struct pcm_feeder *stop, int maxdepth) { struct feedertab_entry *fte; - pcm_feeder *try, *ret; + struct pcm_feeder *try, *ret; struct pcm_feederdesc trydesc; /* printf("trying %s...\n", source->name); */ @@ -266,9 +266,9 @@ feeder_fmtchain(u_int32_t *to, pcm_feeder *source, pcm_feeder *stop, int maxdept } u_int32_t -chn_fmtchain(pcm_channel *c, u_int32_t *to) +chn_fmtchain(struct pcm_channel *c, u_int32_t *to) { - pcm_feeder *try, *stop; + struct pcm_feeder *try, *stop; int max; stop = c->feeder; @@ -306,21 +306,27 @@ chn_fmtchain(pcm_channel *c, u_int32_t *to) /*****************************************************************************/ static int -feed_root(pcm_feeder *feeder, pcm_channel *ch, u_int8_t *buffer, u_int32_t count, struct uio *stream) +feed_root(struct pcm_feeder *feeder, struct pcm_channel *ch, u_int8_t *buffer, u_int32_t count, void *source) { - int ret, s; + struct snd_dbuf *src = source; + int l; + u_int8_t x; - KASSERT(count, ("feed_root: count == 0")); - count &= ~((1 << ch->align) - 1); - KASSERT(count, ("feed_root: aligned count == 0 (align = %d)", ch->align)); + KASSERT(count > 0, ("feed_root: count == 0")); + /* count &= ~((1 << ch->align) - 1); */ + KASSERT(count > 0, ("feed_root: aligned count == 0 (align = %d)", ch->align)); - s = spltty(); - count = min(count, stream->uio_resid); - if (count) { - ret = uiomove(buffer, count, stream); - KASSERT(ret == 0, ("feed_root: uiomove failed (%d)", ret)); - } - splx(s); + l = min(count, sndbuf_getready(src)); + sndbuf_dispose(src, buffer, l); + +/* + if (l < count) + printf("appending %d bytes\n", count - l); +*/ + + x = (sndbuf_getfmt(src) & AFMT_SIGNED)? 0 : 0x80; + while (l < count) + buffer[l++] = x; return count; } @@ -332,7 +338,7 @@ static kobj_method_t feeder_root_methods[] = { static struct feeder_class feeder_root_class = { name: "feeder_root", methods: feeder_root_methods, - size: sizeof(pcm_feeder), + size: sizeof(struct pcm_feeder), align: 0, desc: NULL, data: NULL, diff --git a/sys/dev/sound/pcm/feeder.h b/sys/dev/sound/pcm/feeder.h index bde1218..c3910e5 100644 --- a/sys/dev/sound/pcm/feeder.h +++ b/sys/dev/sound/pcm/feeder.h @@ -26,6 +26,21 @@ * $FreeBSD$ */ +struct pcm_feederdesc { + u_int32_t type; + u_int32_t in, out; + u_int32_t flags; + int idx; +}; + +struct pcm_feeder { + KOBJ_FIELDS; + int align; + struct pcm_feederdesc *desc; + void *data; + struct pcm_feeder *source; +}; + struct feeder_class { KOBJ_CLASS_FIELDS; int align; @@ -36,16 +51,16 @@ struct feeder_class { void feeder_register(void *p); struct feeder_class *feeder_getclass(struct pcm_feederdesc *desc); -u_int32_t chn_fmtchain(pcm_channel *c, u_int32_t *to); -int chn_addfeeder(pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc); -int chn_removefeeder(pcm_channel *c); -pcm_feeder *chn_findfeeder(pcm_channel *c, u_int32_t type); +u_int32_t chn_fmtchain(struct pcm_channel *c, u_int32_t *to); +int chn_addfeeder(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc); +int chn_removefeeder(struct pcm_channel *c); +struct pcm_feeder *chn_findfeeder(struct pcm_channel *c, u_int32_t type); #define FEEDER_DECLARE(feeder, palign, pdata) \ static struct feeder_class feeder ## _class = { \ name: #feeder, \ methods: feeder ## _methods, \ - size: sizeof(pcm_feeder), \ + size: sizeof(struct pcm_feeder), \ align: palign, \ desc: feeder ## _desc, \ data: pdata, \ diff --git a/sys/dev/sound/pcm/feeder_fmt.c b/sys/dev/sound/pcm/feeder_fmt.c index 3246489..49602e8 100644 --- a/sys/dev/sound/pcm/feeder_fmt.c +++ b/sys/dev/sound/pcm/feeder_fmt.c @@ -177,11 +177,11 @@ static unsigned char ulaw_to_alaw[] = { /*****************************************************************************/ static int -feed_8to16le(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_8to16le(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source) { int i, j, k; - k = FEEDER_FEED(f->source, c, b, count / 2, stream); + k = FEEDER_FEED(f->source, c, b, count / 2, source); j = k - 1; i = j * 2 + 1; while (i > 0 && j >= 0) { @@ -207,14 +207,14 @@ FEEDER_DECLARE(feeder_8to16le, 0, NULL); /*****************************************************************************/ static int -feed_16to8_init(pcm_feeder *f) +feed_16to8_init(struct pcm_feeder *f) { f->data = malloc(FEEDBUFSZ, M_FMTFEEDER, M_WAITOK | M_ZERO); return (f->data == NULL)? 0 : ENOMEM; } static int -feed_16to8_free(pcm_feeder *f) +feed_16to8_free(struct pcm_feeder *f) { if (f->data) free(f->data, M_FMTFEEDER); @@ -223,12 +223,12 @@ feed_16to8_free(pcm_feeder *f) } static int -feed_16leto8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_16leto8(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source) { u_int32_t i = 0, toget = count * 2; int j = 1, k; - k = FEEDER_FEED(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); + k = FEEDER_FEED(f->source, c, f->data, min(toget, FEEDBUFSZ), source); while (j < k) { b[i++] = ((u_int8_t *)f->data)[j]; j += 2; @@ -254,9 +254,9 @@ FEEDER_DECLARE(feeder_16leto8, 1, NULL); /*****************************************************************************/ static int -feed_monotostereo8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_monotostereo8(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source) { - int i, j, k = FEEDER_FEED(f->source, c, b, count / 2, stream); + int i, j, k = FEEDER_FEED(f->source, c, b, count / 2, source); j = k - 1; i = j * 2 + 1; @@ -282,9 +282,9 @@ FEEDER_DECLARE(feeder_monotostereo8, 0, NULL); /*****************************************************************************/ static int -feed_monotostereo16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_monotostereo16(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source) { - int i, j, k = FEEDER_FEED(f->source, c, b, count / 2, stream); + int i, j, k = FEEDER_FEED(f->source, c, b, count / 2, source); u_int8_t x, y; j = k - 1; @@ -316,14 +316,14 @@ FEEDER_DECLARE(feeder_monotostereo16, 0, NULL); /*****************************************************************************/ static int -feed_stereotomono8_init(pcm_feeder *f) +feed_stereotomono8_init(struct pcm_feeder *f) { f->data = malloc(FEEDBUFSZ, M_FMTFEEDER, M_WAITOK | M_ZERO); return (f->data == NULL)? 0 : ENOMEM; } static int -feed_stereotomono8_free(pcm_feeder *f) +feed_stereotomono8_free(struct pcm_feeder *f) { if (f->data) free(f->data, M_FMTFEEDER); @@ -332,12 +332,12 @@ feed_stereotomono8_free(pcm_feeder *f) } static int -feed_stereotomono8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_stereotomono8(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source) { u_int32_t i = 0, toget = count * 2; int j = 0, k; - k = FEEDER_FEED(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); + k = FEEDER_FEED(f->source, c, f->data, min(toget, FEEDBUFSZ), source); while (j < k) { b[i++] = ((u_int8_t *)f->data)[j]; j += 2; @@ -361,14 +361,14 @@ FEEDER_DECLARE(feeder_stereotomono8, 1, NULL); /*****************************************************************************/ static int -feed_stereotomono16_init(pcm_feeder *f) +feed_stereotomono16_init(struct pcm_feeder *f) { f->data = malloc(FEEDBUFSZ, M_FMTFEEDER, M_WAITOK | M_ZERO); return (f->data == NULL)? 0 : ENOMEM; } static int -feed_stereotomono16_free(pcm_feeder *f) +feed_stereotomono16_free(struct pcm_feeder *f) { if (f->data) free(f->data, M_FMTFEEDER); @@ -377,12 +377,12 @@ feed_stereotomono16_free(pcm_feeder *f) } static int -feed_stereotomono16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_stereotomono16(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source) { u_int32_t i = 0, toget = count * 2; int j = 0, k; - k = FEEDER_FEED(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); + k = FEEDER_FEED(f->source, c, f->data, min(toget, FEEDBUFSZ), source); while (j < k) { b[i++] = ((u_int8_t *)f->data)[j]; b[i++] = ((u_int8_t *)f->data)[j + 1]; @@ -409,10 +409,10 @@ FEEDER_DECLARE(feeder_stereotomono16, 1, NULL); /*****************************************************************************/ static int -feed_endian(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_endian(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source) { u_int8_t t; - int i = 0, j = FEEDER_FEED(f->source, c, b, count, stream); + int i = 0, j = FEEDER_FEED(f->source, c, b, count, source); while (i < j) { t = b[i]; @@ -443,9 +443,9 @@ FEEDER_DECLARE(feeder_endian, 0, NULL); /*****************************************************************************/ static int -feed_sign(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_sign(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source) { - int i = 0, j = FEEDER_FEED(f->source, c, b, count, stream); + int i = 0, j = FEEDER_FEED(f->source, c, b, count, source); int ssz = (int)f->data, ofs = ssz - 1; while (i < j) { @@ -484,9 +484,9 @@ FEEDER_DECLARE(feeder_sign16le, -1, (void *)2); /*****************************************************************************/ static int -feed_table(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_table(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source) { - int i = 0, j = FEEDER_FEED(f->source, c, b, count, stream); + int i = 0, j = FEEDER_FEED(f->source, c, b, count, source); while (i < j) { b[i] = ((u_int8_t *)f->data)[b[i]]; diff --git a/sys/dev/sound/pcm/feeder_if.m b/sys/dev/sound/pcm/feeder_if.m index cf78986..3205b09 100644 --- a/sys/dev/sound/pcm/feeder_if.m +++ b/sys/dev/sound/pcm/feeder_if.m @@ -34,13 +34,13 @@ INTERFACE feeder; CODE {
static int
- feeder_noinit(pcm_feeder* feeder)
+ feeder_noinit(struct pcm_feeder* feeder)
{
return 0;
}
static int
- feeder_nofree(pcm_feeder* feeder)
+ feeder_nofree(struct pcm_feeder* feeder)
{
return 0;
}
@@ -48,25 +48,25 @@ CODE { };
METHOD int init {
- pcm_feeder* feeder;
+ struct pcm_feeder* feeder;
} DEFAULT feeder_noinit;
METHOD int free {
- pcm_feeder* feeder;
+ struct pcm_feeder* feeder;
} DEFAULT feeder_nofree;
METHOD int set {
- pcm_feeder* feeder;
+ struct pcm_feeder* feeder;
int what;
int value;
};
METHOD int feed {
- pcm_feeder* feeder;
- pcm_channel* c;
+ struct pcm_feeder* feeder;
+ struct pcm_channel* c;
u_int8_t* buffer;
u_int32_t count;
- struct uio* stream;
+ void* source;
};
diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c index dd710ef..5b1f7a3 100644 --- a/sys/dev/sound/pcm/mixer.c +++ b/sys/dev/sound/pcm/mixer.c @@ -32,6 +32,24 @@ MALLOC_DEFINE(M_MIXER, "mixer", "mixer"); +#define MIXER_NAMELEN 16 +struct snd_mixer { + KOBJ_FIELDS; + const char *type; + void *devinfo; + int busy; + int hwvol_muted; + int hwvol_mixer; + int hwvol_step; + u_int32_t hwvol_mute_level; + u_int32_t devs; + u_int32_t recdevs; + u_int32_t recsrc; + u_int16_t level[32]; + char name[MIXER_NAMELEN]; + void *lock; +}; + static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = { [SOUND_MIXER_VOLUME] = 75, [SOUND_MIXER_BASS] = 50, @@ -65,7 +83,7 @@ mixer_lookup(char *devname) #endif static int -mixer_set(snd_mixer *mixer, unsigned dev, unsigned lev) +mixer_set(struct snd_mixer *mixer, unsigned dev, unsigned lev) { unsigned l, r; int v; @@ -85,7 +103,7 @@ mixer_set(snd_mixer *mixer, unsigned dev, unsigned lev) } static int -mixer_get(snd_mixer *mixer, int dev) +mixer_get(struct snd_mixer *mixer, int dev) { if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) return mixer->level[dev]; @@ -93,7 +111,7 @@ mixer_get(snd_mixer *mixer, int dev) } static int -mixer_setrecsrc(snd_mixer *mixer, u_int32_t src) +mixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src) { src &= mixer->recdevs; if (src == 0) @@ -103,50 +121,50 @@ mixer_setrecsrc(snd_mixer *mixer, u_int32_t src) } static int -mixer_getrecsrc(snd_mixer *mixer) +mixer_getrecsrc(struct snd_mixer *mixer) { return mixer->recsrc; } void -mix_setdevs(snd_mixer *m, u_int32_t v) +mix_setdevs(struct snd_mixer *m, u_int32_t v) { m->devs = v; } void -mix_setrecdevs(snd_mixer *m, u_int32_t v) +mix_setrecdevs(struct snd_mixer *m, u_int32_t v) { m->recdevs = v; } u_int32_t -mix_getdevs(snd_mixer *m) +mix_getdevs(struct snd_mixer *m) { return m->devs; } u_int32_t -mix_getrecdevs(snd_mixer *m) +mix_getrecdevs(struct snd_mixer *m) { return m->recdevs; } void * -mix_getdevinfo(snd_mixer *m) +mix_getdevinfo(struct snd_mixer *m) { return m->devinfo; } int -mixer_busy(snd_mixer *m, int busy) +mixer_busy(struct snd_mixer *m, int busy) { m->busy = busy; return 0; } int -mixer_isbusy(snd_mixer *m) +mixer_isbusy(struct snd_mixer *m) { return m->busy; } @@ -154,15 +172,15 @@ mixer_isbusy(snd_mixer *m) int mixer_init(device_t dev, kobj_class_t cls, void *devinfo) { - snddev_info *d; - snd_mixer *m; + struct snddev_info *d; + struct snd_mixer *m; u_int16_t v; int i; - d = device_get_softc(dev); - m = (snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO); - - m->name = cls->name; + m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO); + snprintf(m->name, MIXER_NAMELEN, "%s:mixer", device_get_nameunit(dev)); + m->lock = snd_mtxcreate(m->name); + m->type = cls->name; m->devinfo = devinfo; if (MIXER_INIT(m)) @@ -175,11 +193,15 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo) mixer_setrecsrc(m, SOUND_MASK_MIC); + d = device_get_softc(dev); d->mixer = m; return 0; -bad: kobj_delete((kobj_t)m, M_MIXER); +bad: + snd_mtxlock(m->lock); + snd_mtxfree(m->lock); + kobj_delete((kobj_t)m, M_MIXER); return -1; } @@ -187,11 +209,12 @@ int mixer_uninit(device_t dev) { int i; - snddev_info *d; - snd_mixer *m; + struct snddev_info *d; + struct snd_mixer *m; d = device_get_softc(dev); m = d->mixer; + snd_mtxlock(m->lock); for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) mixer_set(m, i, 0); @@ -200,6 +223,7 @@ mixer_uninit(device_t dev) MIXER_UNINIT(m); + snd_mtxfree(m->lock); kobj_delete((kobj_t)m, M_MIXER); d->mixer = NULL; @@ -210,38 +234,44 @@ int mixer_reinit(device_t dev) { int i; - snddev_info *d; - snd_mixer *m; + struct snddev_info *d; + struct snd_mixer *m; d = device_get_softc(dev); m = d->mixer; + snd_mtxlock(m->lock); i = MIXER_REINIT(m); - if (i) + if (i) { + snd_mtxunlock(m->lock); return i; + } for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) mixer_set(m, i, m->level[i]); mixer_setrecsrc(m, m->recsrc); + snd_mtxunlock(m->lock); return 0; } int -mixer_ioctl(snddev_info *d, u_long cmd, caddr_t arg) +mixer_ioctl(struct snddev_info *d, u_long cmd, caddr_t arg) { int ret, *arg_i = (int *)arg; int v = -1, j = cmd & 0xff; - snd_mixer *m; + struct snd_mixer *m; m = d->mixer; + snd_mtxlock(m->lock); if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) { if (j == SOUND_MIXER_RECSRC) ret = mixer_setrecsrc(m, *arg_i); else ret = mixer_set(m, j, *arg_i); + snd_mtxunlock(m->lock); return (ret == 0)? 0 : ENXIO; } @@ -265,8 +295,10 @@ mixer_ioctl(snddev_info *d, u_long cmd, caddr_t arg) v = mixer_get(m, j); } *arg_i = v; + snd_mtxunlock(m->lock); return (v != -1)? 0 : ENXIO; } + snd_mtxunlock(m->lock); return ENXIO; } @@ -276,20 +308,24 @@ sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS) { char devname[32]; int error, dev; - snd_mixer *m; + struct snd_mixer *m; m = oidp->oid_arg1; + snd_mtxlock(m->lock); strncpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname)); error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req); if (error == 0 && req->newptr != NULL) { dev = mixer_lookup(devname); - if (dev == -1) + if (dev == -1) { + snd_mtxunlock(m->lock); return EINVAL; + } else if (dev != m->hwvol_mixer) { m->hwvol_mixer = dev; m->hwvol_muted = 0; } } + snd_mtxunlock(m->lock); return error; } #endif @@ -297,11 +333,12 @@ sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS) int mixer_hwvol_init(device_t dev) { - snddev_info *d; - snd_mixer *m; + struct snddev_info *d; + struct snd_mixer *m; d = device_get_softc(dev); m = d->mixer; + snd_mtxlock(m->lock); m->hwvol_mixer = SOUND_MIXER_VOLUME; m->hwvol_step = 5; #ifdef SND_DYNSYSCTL @@ -311,17 +348,19 @@ mixer_hwvol_init(device_t dev) OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0, sysctl_hw_snd_hwvol_mixer, "A", "") #endif + snd_mtxunlock(m->lock); return 0; } void mixer_hwvol_mute(device_t dev) { - snddev_info *d; - snd_mixer *m; + struct snddev_info *d; + struct snd_mixer *m; d = device_get_softc(dev); m = d->mixer; + snd_mtxlock(m->lock); if (m->hwvol_muted) { m->hwvol_muted = 0; mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level); @@ -330,17 +369,19 @@ mixer_hwvol_mute(device_t dev) m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer); mixer_set(m, m->hwvol_mixer, 0); } + snd_mtxunlock(m->lock); } void mixer_hwvol_step(device_t dev, int left_step, int right_step) { - snddev_info *d; - snd_mixer *m; + struct snddev_info *d; + struct snd_mixer *m; int level, left, right; d = device_get_softc(dev); m = d->mixer; + snd_mtxlock(m->lock); if (m->hwvol_muted) { m->hwvol_muted = 0; level = m->hwvol_mute_level; @@ -357,36 +398,7 @@ mixer_hwvol_step(device_t dev, int left_step, int right_step) right = 0; mixer_set(m, m->hwvol_mixer, left | right << 8); } + snd_mtxunlock(m->lock); } -/* - * The various mixers use a variety of bitmasks etc. The Voxware - * driver had a very nice technique to describe a mixer and interface - * to it. A table defines, for each channel, which register, bits, - * offset, polarity to use. This procedure creates the new value - * using the table and the old value. - */ - -void -change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval) -{ - u_char mask; - int shift; - - DEB(printf("ch_bits dev %d ch %d val %d old 0x%02x " - "r %d p %d bit %d off %d\n", - dev, chn, newval, *regval, - (*t)[dev][chn].regno, (*t)[dev][chn].polarity, - (*t)[dev][chn].nbits, (*t)[dev][chn].bitoffs ) ); - - if ( (*t)[dev][chn].polarity == 1) /* reverse */ - newval = 100 - newval ; - - mask = (1 << (*t)[dev][chn].nbits) - 1; - newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ - shift = (*t)[dev][chn].bitoffs /*- (*t)[dev][LEFT_CHN].nbits + 1*/; - - *regval &= ~(mask << shift); /* Filter out the previous value */ - *regval |= (newval & mask) << shift; /* Set the new value */ -} diff --git a/sys/dev/sound/pcm/mixer.h b/sys/dev/sound/pcm/mixer.h index eeed211..b20b366 100644 --- a/sys/dev/sound/pcm/mixer.h +++ b/sys/dev/sound/pcm/mixer.h @@ -26,23 +26,27 @@ * $FreeBSD$ */ -extern int mixer_init(device_t dev, kobj_class_t cls, void *devinfo); -extern int mixer_uninit(device_t dev); -extern int mixer_reinit(device_t dev); -extern int mixer_ioctl(snddev_info *d, u_long cmd, caddr_t arg); -extern int mixer_busy(snd_mixer *m, int busy); -extern int mixer_isbusy(snd_mixer *m); +int mixer_init(device_t dev, kobj_class_t cls, void *devinfo); +int mixer_uninit(device_t dev); +int mixer_reinit(device_t dev); +int mixer_ioctl(struct snddev_info *d, u_long cmd, caddr_t arg); +int mixer_busy(struct snd_mixer *m, int busy); +int mixer_isbusy(struct snd_mixer *m); int mixer_hwvol_init(device_t dev); void mixer_hwvol_mute(device_t dev); void mixer_hwvol_step(device_t dev, int left_step, int right_step); -extern void change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval); +void mix_setdevs(struct snd_mixer *m, u_int32_t v); +void mix_setrecdevs(struct snd_mixer *m, u_int32_t v); +u_int32_t mix_getdevs(struct snd_mixer *m); +u_int32_t mix_getrecdevs(struct snd_mixer *m); +void *mix_getdevinfo(struct snd_mixer *m); -void mix_setdevs(snd_mixer *m, u_int32_t v); -void mix_setrecdevs(snd_mixer *m, u_int32_t v); -u_int32_t mix_getdevs(snd_mixer *m); -u_int32_t mix_getrecdevs(snd_mixer *m); -void *mix_getdevinfo(snd_mixer *m); +/* + * this is a kludge to allow hiding of the struct snd_mixer definition + * 512 should be enough for all architectures + */ +#define MIXER_SIZE (512 + sizeof(struct kobj)) -#define MIXER_DECLARE(name) DEFINE_CLASS(name, name ## _methods, sizeof(snd_mixer)) +#define MIXER_DECLARE(name) DEFINE_CLASS(name, name ## _methods, MIXER_SIZE) diff --git a/sys/dev/sound/pcm/mixer_if.m b/sys/dev/sound/pcm/mixer_if.m index 45bfe1a..8cfac14 100644 --- a/sys/dev/sound/pcm/mixer_if.m +++ b/sys/dev/sound/pcm/mixer_if.m @@ -34,7 +34,7 @@ INTERFACE mixer; CODE { static int - mixer_noreinit(snd_mixer *m) + mixer_noreinit(struct snd_mixer *m) { return 0; } @@ -42,26 +42,26 @@ CODE { }; METHOD int init { - snd_mixer *m; + struct snd_mixer *m; }; METHOD int reinit { - snd_mixer *m; + struct snd_mixer *m; } DEFAULT mixer_noreinit; METHOD int uninit { - snd_mixer *m; + struct snd_mixer *m; }; METHOD int set { - snd_mixer *m; + struct snd_mixer *m; unsigned dev; unsigned left; unsigned right; }; METHOD u_int32_t setrecsrc { - snd_mixer *m; + struct snd_mixer *m; u_int32_t src }; diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c index 95e7762..0cf266f 100644 --- a/sys/dev/sound/pcm/sound.c +++ b/sys/dev/sound/pcm/sound.c @@ -57,7 +57,7 @@ static struct cdevsw snd_cdevsw = { /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, - /* flags */ 0, + /* flags */ D_TRACKCLOSE, /* bmaj */ -1 }; @@ -229,8 +229,8 @@ int pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) { int unit = device_get_unit(dev), idx; - snddev_info *d = device_get_softc(dev); - pcm_channel *chns, *ch; + struct snddev_info *d = device_get_softc(dev); + struct pcm_channel *chns, *ch; char *dirs; int err; @@ -245,6 +245,7 @@ pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) ch = &chns[idx]; ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK); ch->parent = d; + snprintf(ch->name, 32, "%s:%s:%d", device_get_nameunit(dev), dirs, idx); err = chn_init(ch, devinfo, dir); if (err) { device_printf(dev, "chn_init() for (%s:%d) failed: err = %d\n", dirs, idx, err); @@ -269,8 +270,8 @@ static int pcm_killchan(device_t dev, int dir) { int unit = device_get_unit(dev), idx; - snddev_info *d = device_get_softc(dev); - pcm_channel *chns, *ch; + struct snddev_info *d = device_get_softc(dev); + struct pcm_channel *chns, *ch; char *dirs; dev_t pdev; @@ -302,7 +303,7 @@ pcm_killchan(device_t dev, int dir) int pcm_setstatus(device_t dev, char *str) { - snddev_info *d = device_get_softc(dev); + struct snddev_info *d = device_get_softc(dev); strncpy(d->status, str, SND_STATUSLEN); return 0; } @@ -310,21 +311,21 @@ pcm_setstatus(device_t dev, char *str) u_int32_t pcm_getflags(device_t dev) { - snddev_info *d = device_get_softc(dev); + struct snddev_info *d = device_get_softc(dev); return d->flags; } void pcm_setflags(device_t dev, u_int32_t val) { - snddev_info *d = device_get_softc(dev); + struct snddev_info *d = device_get_softc(dev); d->flags = val; } void * pcm_getdevinfo(device_t dev) { - snddev_info *d = device_get_softc(dev); + struct snddev_info *d = device_get_softc(dev); return d->devinfo; } @@ -333,7 +334,7 @@ int pcm_register(device_t dev, void *devinfo, int numplay, int numrec) { int sz, unit = device_get_unit(dev); - snddev_info *d = device_get_softc(dev); + struct snddev_info *d = device_get_softc(dev); if (!pcm_devclass) { pcm_devclass = device_get_devclass(dev); @@ -346,14 +347,14 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec) d->devinfo = devinfo; d->chancount = d->playcount = d->reccount = 0; d->maxchans = numplay + numrec; - sz = (numplay + numrec) * sizeof(pcm_channel *); + sz = (numplay + numrec) * sizeof(struct pcm_channel *); if (sz > 0) { - d->aplay = (pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT); + d->aplay = (struct pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT); if (!d->aplay) goto no; bzero(d->aplay, sz); - d->arec = (pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT); + d->arec = (struct pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT); if (!d->arec) goto no; bzero(d->arec, sz); @@ -361,25 +362,21 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec) d->ref = (int *)malloc(sz, M_DEVBUF, M_NOWAIT); if (!d->ref) goto no; bzero(d->ref, sz); - - d->atype = (int *)malloc(sz, M_DEVBUF, M_NOWAIT); - if (!d->atype) goto no; - bzero(d->atype, sz); } if (numplay > 0) { - d->play = (pcm_channel *)malloc(numplay * sizeof(pcm_channel), + d->play = (struct pcm_channel *)malloc(numplay * sizeof(struct pcm_channel), M_DEVBUF, M_NOWAIT); if (!d->play) goto no; - bzero(d->play, numplay * sizeof(pcm_channel)); + bzero(d->play, numplay * sizeof(struct pcm_channel)); } else d->play = NULL; if (numrec > 0) { - d->rec = (pcm_channel *)malloc(numrec * sizeof(pcm_channel), + d->rec = (struct pcm_channel *)malloc(numrec * sizeof(struct pcm_channel), M_DEVBUF, M_NOWAIT); if (!d->rec) goto no; - bzero(d->rec, numrec * sizeof(pcm_channel)); + bzero(d->rec, numrec * sizeof(struct pcm_channel)); } else d->rec = NULL; @@ -397,9 +394,8 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec) if (numplay == 0 || numrec == 0) d->flags |= SD_F_SIMPLEX; - fkchan_setup(&d->fakechan); - chn_init(&d->fakechan, NULL, 0); - d->magic = MAGIC(unit); /* debugging... */ + d->fakechan = fkchan_setup(dev); + chn_init(d->fakechan, NULL, 0); return 0; no: @@ -408,7 +404,6 @@ no: if (d->arec) free(d->arec, M_DEVBUF); if (d->rec) free(d->rec, M_DEVBUF); if (d->ref) free(d->ref, M_DEVBUF); - if (d->atype) free(d->atype, M_DEVBUF); return ENXIO; } @@ -416,15 +411,9 @@ int pcm_unregister(device_t dev) { int r, i, unit = device_get_unit(dev); - snddev_info *d = device_get_softc(dev); + struct snddev_info *d = device_get_softc(dev); dev_t pdev; -#ifdef SND_DYNSYSCTL - sysctl_remove_oid(d->sysctl_tree_top, 1, 1); - d->sysctl_tree_top = NULL; - sysctl_ctx_free(&d->sysctl_tree); -#endif - r = 0; for (i = 0; i < d->chancount; i++) if (d->ref[i]) r = EBUSY; @@ -437,6 +426,11 @@ pcm_unregister(device_t dev) return EBUSY; } +#ifdef SND_DYNSYSCTL + d->sysctl_tree_top = NULL; + sysctl_ctx_free(&d->sysctl_tree); +#endif + pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_CTL, 0)); destroy_dev(pdev); mixer_uninit(dev); @@ -445,17 +439,15 @@ pcm_unregister(device_t dev) pcm_killchan(dev, PCMDIR_PLAY); while (d->reccount > 0) pcm_killchan(dev, PCMDIR_REC); - d->magic = 0; if (d->aplay) free(d->aplay, M_DEVBUF); if (d->play) free(d->play, M_DEVBUF); if (d->arec) free(d->arec, M_DEVBUF); if (d->rec) free(d->rec, M_DEVBUF); if (d->ref) free(d->ref, M_DEVBUF); - if (d->atype) free(d->atype, M_DEVBUF); - chn_kill(&d->fakechan); - fkchan_kill(&d->fakechan); + chn_kill(d->fakechan); + fkchan_kill(d->fakechan); #ifdef USING_DEVFS pcm_makelinks(NULL); @@ -465,13 +457,13 @@ pcm_unregister(device_t dev) /* * a small utility function which, given a device number, returns - * a pointer to the associated snddev_info struct, and sets the unit + * a pointer to the associated struct snddev_info struct, and sets the unit * number. */ -static snddev_info * +static struct snddev_info * get_snddev_info(dev_t i_dev, int *unit, int *dev, int *chan) { - snddev_info *sc; + struct snddev_info *sc; int u, d, c; u = PCMUNIT(i_dev); @@ -484,7 +476,7 @@ get_snddev_info(dev_t i_dev, int *unit, int *dev, int *chan) if (u < 0) return NULL; sc = devclass_get_softc(pcm_devclass, u); - if (sc == NULL || sc->magic == 0) return NULL; + if (sc == NULL) return NULL; switch(d) { case SND_DEV_CTL: /* /dev/mixer handled by pcm */ @@ -508,7 +500,7 @@ static int sndopen(dev_t i_dev, int flags, int mode, struct proc *p) { int dev, unit, chan; - snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); + struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); DEB(printf("open snd%d subdev %d flags 0x%08x mode 0x%08x\n", unit, dev, flags, mode)); @@ -537,7 +529,7 @@ static int sndclose(dev_t i_dev, int flags, int mode, struct proc *p) { int dev, unit, chan; - snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); + struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); DEB(printf("close snd%d subdev %d\n", unit, dev)); @@ -564,7 +556,7 @@ static int sndread(dev_t i_dev, struct uio *buf, int flag) { int dev, unit, chan; - snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); + struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); DEB(printf("read snd%d subdev %d flag 0x%08x\n", unit, dev, flag)); switch(dev) { @@ -585,7 +577,7 @@ static int sndwrite(dev_t i_dev, struct uio *buf, int flag) { int dev, unit, chan; - snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); + struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); DEB(printf("write snd%d subdev %d flag 0x%08x\n", unit, dev & 0xf, flag)); @@ -604,7 +596,7 @@ static int sndioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) { int dev, chan; - snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan); + struct snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan); if (d == NULL) return ENXIO; @@ -629,7 +621,7 @@ static int sndpoll(dev_t i_dev, int events, struct proc *p) { int dev, chan; - snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan); + struct snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan); DEB(printf("sndpoll d 0x%p dev 0x%04x events 0x%08x\n", d, dev, events)); @@ -665,7 +657,7 @@ static int sndmmap(dev_t i_dev, vm_offset_t offset, int nprot) { int unit, dev, chan; - snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); + struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); DEB(printf("sndmmap d 0x%p dev 0x%04x ofs 0x%08x nprot 0x%08x\n", d, dev, offset, nprot)); @@ -688,7 +680,7 @@ status_init(char *buf, int size) { int i; device_t dev; - snddev_info *d; + struct snddev_info *d; snprintf(buf, size, "FreeBSD Audio Driver (newpcm) %s %s\n" "Installed devices:\n", __DATE__, __TIME__); diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h index d09a370..007285b 100644 --- a/sys/dev/sound/pcm/sound.h +++ b/sys/dev/sound/pcm/sound.h @@ -87,13 +87,33 @@ struct isa_device { int dummy; }; #endif /* _OS_H_ */ -#include <dev/sound/pcm/datatypes.h> -#include <dev/sound/pcm/channel.h> +struct pcm_channel; +struct pcm_feeder; +struct snd_dbuf; +struct snd_mixer; + #include <dev/sound/pcm/buffer.h> +#include <dev/sound/pcm/channel.h> #include <dev/sound/pcm/feeder.h> #include <dev/sound/pcm/mixer.h> #include <dev/sound/pcm/dsp.h> +#define SND_STATUSLEN 64 +/* descriptor of audio device */ +struct snddev_info { + struct pcm_channel *play, *rec, **aplay, **arec, *fakechan; + int *ref; + unsigned playcount, reccount, chancount, maxchans; + struct snd_mixer *mixer; + unsigned flags; + void *devinfo; + device_t dev; + char status[SND_STATUSLEN]; + struct sysctl_ctx_list sysctl_tree; + struct sysctl_oid *sysctl_tree_top; + struct mtx mutex; +}; + #ifndef ISADMA_WRITE #define ISADMA_WRITE B_WRITE #define ISADMA_READ B_READ @@ -127,8 +147,8 @@ struct isa_device { int dummy; }; #define AFMT_SIGNED (AFMT_S16_LE | AFMT_S16_BE | AFMT_S8) #define AFMT_BIGENDIAN (AFMT_S16_BE | AFMT_U16_BE) -int fkchan_setup(pcm_channel *c); -int fkchan_kill(pcm_channel *c); +struct pcm_channel *fkchan_setup(device_t dev); +int fkchan_kill(struct pcm_channel *c); /* * Minor numbers for the sound driver. |