diff options
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. |