summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/isa/mss.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/sound/isa/mss.c')
-rw-r--r--sys/dev/sound/isa/mss.c129
1 files changed, 99 insertions, 30 deletions
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);
OpenPOWER on IntegriCloud