summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/sound/isa/ad1816.c58
-rw-r--r--sys/dev/sound/isa/ess.c55
-rw-r--r--sys/dev/sound/isa/mss.c129
-rw-r--r--sys/dev/sound/isa/mss.h17
-rw-r--r--sys/dev/sound/isa/sb.h11
-rw-r--r--sys/dev/sound/isa/sb16.c84
-rw-r--r--sys/dev/sound/isa/sb8.c68
-rw-r--r--sys/dev/sound/isa/sbc.c61
-rw-r--r--sys/dev/sound/pci/aureal.c18
-rw-r--r--sys/dev/sound/pci/cmi.c22
-rw-r--r--sys/dev/sound/pci/cs4281.c14
-rw-r--r--sys/dev/sound/pci/csa.c2
-rw-r--r--sys/dev/sound/pci/csapcm.c16
-rw-r--r--sys/dev/sound/pci/ds1.c41
-rw-r--r--sys/dev/sound/pci/emu10k1.c116
-rw-r--r--sys/dev/sound/pci/es137x.c23
-rw-r--r--sys/dev/sound/pci/fm801.c18
-rw-r--r--sys/dev/sound/pci/maestro.c21
-rw-r--r--sys/dev/sound/pci/maestro3.c37
-rw-r--r--sys/dev/sound/pci/neomagic.c17
-rw-r--r--sys/dev/sound/pci/solo.c22
-rw-r--r--sys/dev/sound/pci/t4dwave.c44
-rw-r--r--sys/dev/sound/pci/via82c686.c343
-rw-r--r--sys/dev/sound/pci/vibes.c20
-rw-r--r--sys/dev/sound/pcm/ac97.c52
-rw-r--r--sys/dev/sound/pcm/ac97.h10
-rw-r--r--sys/dev/sound/pcm/buffer.c492
-rw-r--r--sys/dev/sound/pcm/buffer.h84
-rw-r--r--sys/dev/sound/pcm/channel.c1312
-rw-r--r--sys/dev/sound/pcm/channel.h96
-rw-r--r--sys/dev/sound/pcm/channel_if.m6
-rw-r--r--sys/dev/sound/pcm/datatypes.h2
-rw-r--r--sys/dev/sound/pcm/dsp.c289
-rw-r--r--sys/dev/sound/pcm/dsp.h14
-rw-r--r--sys/dev/sound/pcm/fake.c28
-rw-r--r--sys/dev/sound/pcm/feeder.c66
-rw-r--r--sys/dev/sound/pcm/feeder.h25
-rw-r--r--sys/dev/sound/pcm/feeder_fmt.c48
-rw-r--r--sys/dev/sound/pcm/feeder_if.m16
-rw-r--r--sys/dev/sound/pcm/mixer.c138
-rw-r--r--sys/dev/sound/pcm/mixer.h30
-rw-r--r--sys/dev/sound/pcm/mixer_if.m12
-rw-r--r--sys/dev/sound/pcm/sound.c88
-rw-r--r--sys/dev/sound/pcm/sound.h28
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.
OpenPOWER on IntegriCloud