summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authorluigi <luigi@FreeBSD.org>1999-01-04 10:40:14 +0000
committerluigi <luigi@FreeBSD.org>1999-01-04 10:40:14 +0000
commitca0883293604a732bb1f0677db1554a154639595 (patch)
tree36320751487d949cc715752b6b6c4ef6d608d038 /sys/i386
parent30ad5c00bb23aae0b44ff207fc1083fb62e5e3c4 (diff)
downloadFreeBSD-src-ca0883293604a732bb1f0677db1554a154639595.zip
FreeBSD-src-ca0883293604a732bb1f0677db1554a154639595.tar.gz
Bring in ad1816 patches from German Tischler.
Fix 'device not configured' problem that people were experiencing when only PCI devices are present.
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/isa/snd/CARDS19
-rw-r--r--sys/i386/isa/snd/ad1848.c522
-rw-r--r--sys/i386/isa/snd/mss.h55
-rw-r--r--sys/i386/isa/snd/sound.c15
-rw-r--r--sys/i386/isa/snd/sound.h1
5 files changed, 604 insertions, 8 deletions
diff --git a/sys/i386/isa/snd/CARDS b/sys/i386/isa/snd/CARDS
index 4c229d0..5757be3 100644
--- a/sys/i386/isa/snd/CARDS
+++ b/sys/i386/isa/snd/CARDS
@@ -101,6 +101,25 @@ COMMENTS:
--------------------------
CHIPSET:
+ AD1815/1816
+
+MANUFACTURER:
+ Analog Devices
+
+DOCUMENTATION:
+ http://www.analog.com
+
+COMMENTS:
+ This is a chip for ISA-PnP cards, and so should be configured
+ using the PnP interface. For full function configure port2,
+ irq0, drq0 and drq1 of ldn0.
+ The driver is contributed by German Tischler
+
+FORMATS:
+ ALAW/ULAW/8bit/16bit(le)/16bit(be),8kHz-55.2kHz,full duplex
+
+--------------------------
+CHIPSET:
OPTi931: PnP id 0x3109143e
OPTi933: PnP id 0x3109143e (yes, it's the same)
diff --git a/sys/i386/isa/snd/ad1848.c b/sys/i386/isa/snd/ad1848.c
index 660e0eb..7777e4b 100644
--- a/sys/i386/isa/snd/ad1848.c
+++ b/sys/i386/isa/snd/ad1848.c
@@ -79,6 +79,25 @@ static void ad_write(snddev_info *d, int reg, u_char data);
static void ad_write_cnt(snddev_info *d, int reg, u_short data);
static int ad_read(snddev_info *d, int reg);
+/* ad1816 prototypes */
+
+/* IO primitives */
+static int ad1816_wait_init(snddev_info * d, int x);
+static unsigned short ad1816_read(snddev_info * d, unsigned int reg);
+static void ad1816_write(snddev_info * d, unsigned int reg, unsigned short data);
+/* intr and callback functions */
+static irq_proc_t ad1816_intr;
+static snd_callback_t ad1816_callback;
+/* device specific ioctl calls */
+static d_ioctl_t ad1816_ioctl;
+/* parameter set functions */
+static void ad1816_reinit(snddev_info * d);
+static int ad1816_mixer_set(snddev_info * d, int dev, int value);
+static int ad1816_set_recsrc(snddev_info * d, int mask);
+static void ad1816_mixer_reset(snddev_info * d);
+
+/* ad1816 prototypes end */
+
/*
* device descriptors for the boards supported by this module.
*/
@@ -183,6 +202,31 @@ mss_probe_end:
return mss_detect(dev) ? 8 : 0 ; /* mss uses 8 regs */
}
+static int
+ad1816_attach(struct isa_device *dev)
+{
+ snddev_info *d = &(pcm_info[dev->id_unit]);
+
+ dev->id_alive = 16; /* number of io ports */
+
+ if (FULL_DUPLEX(d))
+ d->audio_fmt |= AFMT_FULLDUPLEX;
+
+ ad1816_write(d, 1, 0x2);/* disable interrupts */
+ ad1816_write(d, 32, 0x90F0); /* SoundSystem Mode, split format */
+
+ ad1816_write(d, 5, 0x8080); /* FM volume mute */
+ ad1816_write(d, 6, 0x8080); /* I2S1 volume mute */
+ ad1816_write(d, 7, 0x8080); /* I2S0 volume mute */
+ ad1816_write(d, 17, 0x8888); /* VID Volume mute */
+ ad1816_write(d, 20, 0x5050); /* Source select Mic & auto gain ctrl
+ * off */
+ /* adc gain is set to 0 */
+ ad1816_reinit(d);
+ ad1816_mixer_reset(d);
+ return 0 ;
+}
+
/*
* the address passed as io_base for mss_attach is also the old
* MSS base address (e.g. 0x530). The codec is four locations ahead.
@@ -199,6 +243,9 @@ mss_attach(struct isa_device *dev)
d->name, dev->id_unit,
d->io_base, d->irq, d->dbuf_out.chan, d->dbuf_in.chan, dev->id_flags);
+ if (d->bd_id == MD_AD1816)
+ return ad1816_attach(dev);
+
dev->id_alive = 8 ; /* number of io ports */
/* should be already set but just in case... */
@@ -374,7 +421,11 @@ mss_close(dev_t dev, int flags, int mode, struct proc * p)
d->flags |= SND_F_CLOSING ;
splx(s); /* is this ok here ? */
snd_flush(d);
- outb(io_Status(d), 0); /* Clear interrupt status */
+ /* Clear interrupt status */
+ if ( d->bd_id == MD_AD1816 )
+ outb(ad1816_int(d), 0);
+ else
+ outb(io_Status(d), 0);
d->flags = 0 ;
}
return 0 ;
@@ -1370,11 +1421,12 @@ mss_reinit(snddev_info *d)
#if NPNP > 0
static char * cs423x_probe(u_long csn, u_long vend_id);
-static void cs423x_attach(u_long csn, u_long vend_id, char *name,
+static void
+cs423x_attach(u_long csn, u_long vend_id, char *name,
struct isa_device *dev);
static struct pnp_device cs423x = {
- "CS423x/Yamaha",
+ "CS423x/Yamaha/AD1816",
cs423x_probe,
cs423x_attach,
&nsnd, /* use this for all sound cards */
@@ -1405,6 +1457,10 @@ cs423x_probe(u_long csn, u_long vend_id)
s = "Yamaha YMF719 OPL-SA3";
else if (vend_id == 0x8140d315)
s = "SoundscapeVIVO";
+ else if (vend_id == 0x1114b250)
+ s = "Terratec Soundsystem BASE 1";
+ else if (vend_id == 0x50719304)
+ s = "Generic AD1815";
if (s) {
struct pnp_cinfo d;
read_pnp_parms(&d, 0);
@@ -1433,7 +1489,26 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
return ;
}
snddev_last_probed = &tmp_d;
- if (d.flags & DV_PNP_SBCODEC) { /*** use sb-compatible codec ***/
+
+ /* AD1816 */
+ if (vend_id == 0x1114b250 || vend_id == 0x50719304) {
+ dev->id_alive = 16; /* number of io ports ? */
+
+ tmp_d = mss_op_desc; /* copy it */
+
+ tmp_d.ioctl = ad1816_ioctl;
+ tmp_d.isr = ad1816_intr;
+ tmp_d.callback = ad1816_callback;
+ tmp_d.audio_fmt = AFMT_STEREO | AFMT_U8 |
+ AFMT_A_LAW | AFMT_MU_LAW |
+ AFMT_S16_LE | AFMT_S16_BE;
+
+ dev->id_iobase = d.port[2];
+ tmp_d.alt_base = d.port[0]; /* soundblaster comp. but we don't
+ * use that */
+ tmp_d.bd_id = MD_AD1816;
+ strcpy(tmp_d.name, name);
+ } else if (d.flags & DV_PNP_SBCODEC) { /* use sb-compatible codec */
dev->id_alive = 16 ; /* number of io ports ? */
tmp_d = sb_op_desc ;
if (vend_id==0x2000a865 || vend_id==0x3000a865 ||
@@ -1484,12 +1559,14 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
break;
default:
- tmp_d.bd_id = MD_CS4232 ; /* to short-circuit the detect routine */
+ tmp_d.bd_id = MD_CS4232; /* to short-circuit the
+ * detect routine */
break;
}
snprintf(tmp_d.name, sizeof(tmp_d.name), "%s", name);
tmp_d.audio_fmt |= AFMT_FULLDUPLEX ;
}
+
write_pnp_parms( &d, ldn );
enable_pnp_card();
@@ -1814,5 +1891,440 @@ gus_mem_cfg(snddev_info *d)
}
#endif /* gus mem cfg... */
+static int
+ad1816_ioctl(dev_t dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
+{
+ snddev_info *d;
+ int unit;
+
+ dev = minor(dev);
+ unit = dev >> 4;
+ d = &pcm_info[unit];
+
+ if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
+ cmd &= 0xff;
+ if (cmd == SOUND_MIXER_RECSRC)
+ return ad1816_set_recsrc(d, *(int *) arg);
+ else
+ return ad1816_mixer_set(d, cmd, *(int *) arg);
+ }
+ switch (cmd) { /* driver specific ioctls other than mixer
+ * calls */
+ /* ad1816 has special features */
+ case AIOGCAP: /* get capabilities */
+ {
+ snd_capabilities *p = (snd_capabilities *) arg;
+ p->rate_min = 4000;
+ p->rate_max = 55200;
+ p->bufsize = d->bufsize;
+ p->formats = d->audio_fmt;
+ p->mixers = 1;
+ p->inputs = d->mix_devs;
+ p->left = p->right = 100;
+ return 0;
+ }
+ default:
+ {
+ return ENOSYS; /* fallback to default */
+ }
+ break;
+ }
+}
+
+static int
+ad1816_callback(snddev_info * d, int reason)
+{
+ int wr, cnt;
+
+ wr = reason & SND_CB_WR;
+ reason &= SND_CB_REASON_MASK;
+
+ switch (reason) {
+ case SND_CB_INIT:
+ ad1816_reinit(d);
+ reset_dbuf(&(d->dbuf_in), SND_CHAN_RD);
+ reset_dbuf(&(d->dbuf_out), SND_CHAN_WR);
+ return 1;
+ break;
+
+ case SND_CB_START:
+ cnt = wr ? d->dbuf_out.dl : d->dbuf_in.dl;
+
+ cnt /= 4;
+ cnt--;
+
+ /* start only if not already running */
+ if (wr && !(inb(ad1816_play(d)) & AD1816_ENABLE)) {
+ /* set dma counter */
+ ad1816_write(d, 8, cnt); /* playback count */
+ /* int enable */
+ ad1816_write(d, 1, ad1816_read(d, 1) | 0x8000);
+ /* enable playback */
+ outb(ad1816_play(d), (inb(ad1816_play(d)) | AD1816_ENABLE));
+ /* check if we succeeded */
+ if (!(inb(ad1816_play(d)) & AD1816_ENABLE)) {
+ printf("ad1816: failed to start write (playback) DMA !\n");
+ }
+ } else if (!wr && !(inb(ad1816_capt(d)) & AD1816_ENABLE)) {
+ /* same for capture */
+ ad1816_write(d, 10, cnt); /* capture count */
+ ad1816_write(d, 1, ad1816_read(d, 1) | 0x4000); /* int */
+ outb(ad1816_capt(d), (inb(ad1816_capt(d)) | AD1816_ENABLE)); /* CEN */
+ if (!(inb(ad1816_capt(d)) & AD1816_ENABLE)) { /* check */
+ printf("ad1816: failed to start read (capture) DMA !\n");
+ }
+ }
+ break;
+
+ case SND_CB_STOP:
+ case SND_CB_ABORT: /* XXX check this... */
+ /* we don't test here if it is running... */
+ if (wr) {
+ ad1816_write(d, 1, ad1816_read(d, 1) & ~0x8000);
+ /* disable int */
+ outb(ad1816_play(d), (inb(ad1816_play(d)) & ~AD1816_ENABLE));
+ /* disable playback */
+ if ((inb(ad1816_play(d)) & AD1816_ENABLE)) {
+ printf("ad1816: failed to stop write (playback) DMA !\n");
+ }
+ ad1816_write(d, 8, 0); /* reset base counter */
+ ad1816_write(d, 9, 0); /* reset cur counter */
+ } else {
+ /* same for capture */
+ ad1816_write(d, 1, ad1816_read(d, 1) & ~0x4000);
+ outb(ad1816_capt(d), (inb(ad1816_capt(d)) & ~AD1816_ENABLE));
+ if ((inb(ad1816_capt(d)) & AD1816_ENABLE)) {
+ printf("ad1816: failed to stop read (capture) DMA !\n");
+ }
+ ad1816_write(d, 10, 0);
+ ad1816_write(d, 11, 0);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static void
+ad1816_intr(int unit)
+{
+ snddev_info *d = &pcm_info[unit];
+ unsigned char c, served = 0;
+
+ /* get interupt status */
+ c = inb(ad1816_int(d));
+
+ /* check for stray interupts */
+ if (c & ~(AD1816_INTRCI | AD1816_INTRPI)) {
+ printf("ad1816: Stray interrupt 0x%x.\n", c);
+ c = c & (AD1816_INTRCI | AD1816_INTRPI);
+ outb(ad1816_int(d), c); /* ack it anyway */
+ }
+ /* check for capture interupt */
+ if (d->dbuf_in.dl && (c & AD1816_INTRCI)) {
+ outb(ad1816_int(d), c & ~AD1816_INTRCI); /* ack it */
+ if (inb(ad1816_int(d)) & AD1816_INTRCI)
+ printf("ad1816: Failed to clear cp int !!!\n");
+ dsp_rdintr(d);
+ served |= AD1816_INTRCI; /* cp served */
+ }
+ /* check for playback interupt */
+ if (d->dbuf_out.dl && (c & AD1816_INTRPI)) {
+ outb(ad1816_int(d), c & ~AD1816_INTRPI); /* ack it */
+ if (inb(ad1816_int(d)) & AD1816_INTRPI != 0)
+ printf("ad1816: Failed to clear pb int !!!\n");
+ dsp_wrintr(d);
+ served |= AD1816_INTRPI; /* pb served */
+ }
+ if (served == 0) {
+ /* this probably means this is not a (working) ad1816 chip, */
+ /* or an error in dma handling */
+ printf("ad1816: raised an interrupt without reason 0x%x.\n", c);
+ outb(ad1816_int(d), 0); /* Clear interrupt status anyway */
+ }
+}
+
+static int
+ad1816_wait_init(snddev_info * d, int x)
+{
+ int n = 0; /* to shut up the compiler... */
+
+ for (; x--;)
+ if (((n = (inb(ad1816_ale(d)) & AD1816_BUSY))) == 0)
+ DELAY(10);
+ else
+ return n;
+ printf("ad1816_wait_init failed 0x%02x.\n", inb(ad1816_ale(d)));
+ return n;
+}
+
+static unsigned short
+ad1816_read(snddev_info * d, unsigned int reg)
+{
+ int flags;
+ u_short x;
+
+ /* we don't want to be blocked here */
+ flags = spltty();
+ if (ad1816_wait_init(d, 100) == 0) {
+ printf("ad1816_read: chip timeout before read.\n");
+ return 0;
+ }
+ outb(ad1816_ale(d), (u_char) 0);
+ outb(ad1816_ale(d), (u_char) (reg & AD1816_ALEMASK));
+ if (ad1816_wait_init(d, 100) == 0) {
+ printf("ad1816_read: chip timeout during read.\n");
+ return 0;
+ }
+ x = (inb(ad1816_high(d)) << 8) | inb(ad1816_low(d));
+ splx(flags);
+ return x;
+}
+
+static void
+ad1816_write(snddev_info * d, unsigned int reg, unsigned short data)
+{
+ int flags;
+
+ flags = spltty();
+ if (ad1816_wait_init(d, 100) == 0) {
+ printf("ad1816_write: chip timeout before write.\n");
+ return;
+ }
+ outb(ad1816_ale(d), (u_char) (reg & AD1816_ALEMASK));
+ outb(ad1816_low(d), (u_char) (data & 0x000000ff));
+ outb(ad1816_high(d), (u_char) ((data & 0x0000ff00) >> 8));
+ splx(flags);
+}
+
+#if 0 /* unused right now..., and untested... */
+static void
+ad1816_mute(snddev_info * d)
+{
+ ad1816_write(d, 14, ad1816_read(d, 14) | 0x8000 | 0x80);
+}
+
+static void
+ad1816_unmute(snddev_info * d)
+{
+ ad1816_write(d, 14, ad1816_read(d, 14) & ~(0x8000 | 0x80));
+}
+#endif
+
+/* only one rec source is possible */
+
+static int
+ad1816_set_recsrc(snddev_info * d, int mask)
+{
+ mask &= d->mix_rec_devs;
+
+ switch (mask) {
+ case SOUND_MASK_LINE:
+ case SOUND_MASK_LINE3:
+ ad1816_write(d, 20, (ad1816_read(d, 20) & ~0x7070) | 0x0000);
+ break;
+
+ case SOUND_MASK_CD:
+ case SOUND_MASK_LINE1:
+ ad1816_write(d, 20, (ad1816_read(d, 20) & ~0x7070) | 0x2020);
+ break;
+
+ case SOUND_MASK_MIC:
+ default:
+ ad1816_write(d, 20, (ad1816_read(d, 20) & ~0x7070) | 0x5050);
+ }
+
+ d->mix_recsrc = mask;
+
+ return 0; /* success */
+}
+
+#define AD1816_MUTE 31 /* value for mute */
+
+static int
+ad1816_mixer_set(snddev_info * d, int dev, int value)
+{
+ u_char left = (value & 0x000000ff);
+ u_char right = (value & 0x0000ff00) >> 8;
+ u_short reg = 0;
+
+ if (dev > 31)
+ return EINVAL;
+
+ if (!(d->mix_devs & (1 << dev)))
+ return EINVAL;
+
+ if (left > 100)
+ left = 100;
+ if (right > 100)
+ right = 100;
+
+ d->mix_levels[dev] = left | (right << 8);
+
+ /* Scale volumes */
+ left = AD1816_MUTE - (AD1816_MUTE * left) / 100;
+ right = AD1816_MUTE - (AD1816_MUTE * right) / 100;
+
+ reg = (left << 8) | right;
+
+ /* do channel selective muting if volume is zero */
+ if (left == AD1816_MUTE)
+ reg |= 0x8000;
+ if (right == AD1816_MUTE)
+ reg |= 0x0080;
+
+ switch (dev) {
+ case SOUND_MIXER_VOLUME: /* Register 14 master volume */
+ ad1816_write(d, 14, reg);
+ break;
+ case SOUND_MIXER_CD: /* Register 15 cd */
+ case SOUND_MIXER_LINE1:
+ ad1816_write(d, 15, reg);
+ break;
+ case SOUND_MIXER_SYNTH: /* Register 16 synth */
+ ad1816_write(d, 16, reg);
+ break;
+ case SOUND_MIXER_PCM: /* Register 4 pcm */
+ ad1816_write(d, 4, reg);
+ break;
+ case SOUND_MIXER_LINE:
+ case SOUND_MIXER_LINE3: /* Register 18 line in */
+ ad1816_write(d, 18, reg);
+ break;
+ case SOUND_MIXER_MIC: /* Register 19 mic volume */
+ ad1816_write(d, 19, reg & ~0xff); /* mic is mono */
+ break;
+ case SOUND_MIXER_IGAIN:
+ /* and now to something completely different ... */
+ ad1816_write(d, 20, ((ad1816_read(d, 20) & ~0x0f0f)
+ | (((AD1816_MUTE - left) / 2) << 8) /* four bits of adc gain */
+ | ((AD1816_MUTE - right) / 2)));
+ break;
+ default:
+ printf("ad1816_mixer_set(): unknown device.\n");
+ break;
+ }
+
+ return 0; /* success */
+}
+
+static void
+ad1816_mixer_reset(snddev_info * d)
+{
+ int i;
+
+ d->mix_devs = AD1816_MIXER_DEVICES;
+ d->mix_rec_devs = AD1816_REC_DEVICES;
+
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ if (d->mix_devs & (1 << i))
+ ad1816_mixer_set(d, i, default_mixer_levels[i]);
+ ad1816_set_recsrc(d, SOUND_MASK_MIC);
+}
+
+/* Set the playback and capture rates. */
+
+static int
+ad1816_speed(snddev_info * d)
+{
+ RANGE(d->play_speed,4000,55200);
+ RANGE(d->rec_speed,4000,55200);
+
+ ad1816_write(d, 2, d->play_speed);
+ ad1816_write(d, 3, d->rec_speed);
+
+ return d->play_speed;
+}
+
+/*
+ * ad1816_format checks that the format is supported (or defaults to AFMT_U8)
+ * and sets the chip to the desired format.
+ */
+
+static int
+ad1816_format(snddev_info * d)
+{
+ int oldplay =inb(ad1816_play(d)) & ~AD1816_FORMASK;
+ int oldrec = inb(ad1816_capt(d)) & ~AD1816_FORMASK;
+ int play = (d->play_fmt & d->audio_fmt) ? d->play_fmt : AFMT_U8;
+ int rec = (d->rec_fmt & d->audio_fmt) ? d->rec_fmt : AFMT_U8;
+
+ /*
+ * check that arg is one of the supported formats in d->format; otherwise
+ * fallback to AFMT_U8
+ */
+
+ switch (play) {
+ case AFMT_A_LAW:
+ outb(ad1816_play(d), oldplay | AD1816_ALAW);
+ break;
+ case AFMT_MU_LAW:
+ outb(ad1816_play(d), oldplay | AD1816_MULAW);
+ break;
+ case AFMT_S16_LE:
+ outb(ad1816_play(d), oldplay | AD1816_S16LE);
+ break;
+ case AFMT_S16_BE:
+ outb(ad1816_play(d), oldplay | AD1816_S16BE);
+ break;
+ default:
+ /* unlikely to happen */
+ printf("ad1816: unknown play format. defaulting to U8.\n");
+ case AFMT_U8:
+ outb(ad1816_play(d), oldplay | AD1816_U8);
+ break;
+ }
+
+ switch (rec) {
+ case AFMT_A_LAW:
+ outb(ad1816_capt(d), oldrec | AD1816_ALAW);
+ break;
+ case AFMT_MU_LAW:
+ outb(ad1816_capt(d), oldrec | AD1816_MULAW);
+ break;
+ case AFMT_S16_LE:
+ outb(ad1816_capt(d), oldrec | AD1816_S16LE);
+ break;
+ case AFMT_S16_BE:
+ outb(ad1816_capt(d), oldrec | AD1816_S16BE);
+ break;
+ default:
+ printf("ad1816: unknown capture format. defaulting to U8.\n");
+ case AFMT_U8:
+ outb(ad1816_capt(d), oldrec | AD1816_U8);
+ break;
+ }
+
+ d->play_fmt = play;
+ d->rec_fmt = rec;
+
+ return (play);
+}
+
+/*
+ * ad1816_reinit resets codec registers
+ */
+static void
+ad1816_reinit(snddev_info * d)
+{
+ ad1816_write(d, 8, 0x0000); /* reset base and current counter */
+ ad1816_write(d, 9, 0x0000); /* for playback and capture */
+ ad1816_write(d, 10, 0x0000);
+ ad1816_write(d, 11, 0x0000);
+
+ if (d->flags & SND_F_STEREO) {
+ outb((ad1816_play(d)), AD1816_STEREO); /* set playback to stereo */
+ outb((ad1816_capt(d)), AD1816_STEREO); /* set capture to stereo */
+ } else {
+ outb((ad1816_play(d)), 0x00); /* set playback to mono */
+ outb((ad1816_capt(d)), 0x00); /* set capture to mono */
+ }
+
+ ad1816_format(d);
+ ad1816_speed(d);
+
+ snd_set_blocksize(d); /* update blocksize if user did not force it */
+}
+
#endif /* NPNP > 0 */
#endif /* NPCM > 0 */
diff --git a/sys/i386/isa/snd/mss.h b/sys/i386/isa/snd/mss.h
index 54efc3c..20ceaaf 100644
--- a/sys/i386/isa/snd/mss.h
+++ b/sys/i386/isa/snd/mss.h
@@ -105,6 +105,55 @@ ahead.
#define BD_F_IRQ_OK 0x0002
#define BD_F_TMR_RUN 0x0004
+/* AD1816 register macros */
+
+#define ad1816_ale(d) ((d)->io_base+0) /* indirect reg access */
+#define ad1816_int(d) ((d)->io_base+1) /* interupt status */
+#define ad1816_low(d) ((d)->io_base+2) /* indirect low byte */
+#define ad1816_high(d) ((d)->io_base+3) /* indirect high byte */
+/* unused */
+#define ad1816_pioD(d) ((d)->io_base+4) /* PIO debug */
+#define ad1816_pios(d) ((d)->io_base+5) /* PIO status */
+#define ad1816_piod(d) ((d)->io_base+6) /* PIO data */
+/* end of unused */
+/* values for playback/capture config:
+ bits: 0 enable/disable
+ 1 pio/dma
+ 2 stereo/mono
+ 3 companded/linearPCM
+ 4-5 format : 00 8bit linear (uncomp)
+ 00 8bit mulaw (comp)
+ 01 16bit le (uncomp)
+ 01 8bit alaw (comp)
+ 11 16bit be (uncomp)
+*/
+#define ad1816_play(d) ((d)->io_base+8) /* playback config */
+#define ad1816_capt(d) ((d)->io_base+9) /* capture config */
+
+#define AD1816_BUSY 0x80 /* chip is busy */
+#define AD1816_ALEMASK 0x3F /* mask for indirect adr. */
+/* unusud */
+#define AD1816_INTRSI 0x01 /* sb intr */
+#define AD1816_INTRGI 0x02 /* game intr */
+#define AD1816_INTRRI 0x04 /* ring intr */
+#define AD1816_INTRDI 0x08 /* dsp intr */
+#define AD1816_INTRVI 0x10 /* vol intr */
+#define AD1816_INTRTI 0x20 /* timer intr */
+/* used again */
+#define AD1816_INTRCI 0x40 /* capture intr */
+#define AD1816_INTRPI 0x80 /* playback intr */
+/* PIO stuff is not supplied here */
+/* playback / capture config */
+#define AD1816_ENABLE 0x01 /* enable pl/cp */
+#define AD1816_PIO 0x02 /* use pio */
+#define AD1816_STEREO 0x04
+#define AD1816_COMP 0x08 /* data is companded */
+#define AD1816_U8 0x00 /* 8 bit linear pcm */
+#define AD1816_MULAW 0x08 /* 8 bit mulaw */
+#define AD1816_ALAW 0x18 /* 8 bit alaw */
+#define AD1816_S16LE 0x10 /* 16 bit linear little endian */
+#define AD1816_S16BE 0x30 /* 16 bit linear big endian */
+#define AD1816_FORMASK 0x38 /* format mask */
/*
* sound/ad1848_mixer.h
@@ -225,6 +274,12 @@ MIX_NONE(SOUND_MIXER_LINE3),
SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | \
SOUND_MASK_IGAIN | SOUND_MASK_LINE1 )
+#define AD1816_REC_DEVICES \
+ (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
+
+#define AD1816_MIXER_DEVICES \
+ (SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH | \
+ SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_IGAIN)
static u_short default_mixer_levels[SOUND_MIXER_NRDEVICES] = {
0x5a5a, /* Master Volume */
diff --git a/sys/i386/isa/snd/sound.c b/sys/i386/isa/snd/sound.c
index 1cbbe8a..f8b5cfb 100644
--- a/sys/i386/isa/snd/sound.c
+++ b/sys/i386/isa/snd/sound.c
@@ -238,7 +238,6 @@ pcmattach(struct isa_device * dev)
snddev_info *d = NULL ;
struct isa_device *dvp;
int stat = 0;
- dev_t isadev;
dev->id_ointr = pcmintr;
@@ -284,8 +283,6 @@ pcmattach(struct isa_device * dev)
if (FULL_DUPLEX(d))
isa_dma_acquire(d->dbuf_in.chan);
- isadev = makedev(CDEV_MAJOR, 0);
- cdevsw_add(&isadev, &snd_cdevsw, NULL);
/*
* should try and find a suitable value for id_id, otherwise
@@ -331,6 +328,10 @@ pcminit(snddev_info *d, int unit)
#ifdef DEVFS
void *cookie;
#endif
+ dev_t isadev;
+
+ isadev = makedev(CDEV_MAJOR, 0);
+ cdevsw_add(&isadev, &snd_cdevsw, NULL);
/*
* initialize standard parameters for the device. This can be
@@ -604,6 +605,14 @@ sndread(dev_t i_dev, struct uio * buf, int flag)
return uiomove(p, l, buf) ;
}
+ /*
+ * XXX read from the ad1816 with a single DMA channel is unsupported.
+ * This is really not the place for machine-dependent functions,
+ * a proper device routine will be supplied in the future - luigi
+ */
+ if ((d->bd_id == MD_AD1816) && (!(FULL_DUPLEX(d))))
+ return EIO;
+
if (d->read) /* device-specific read */
return d->read(i_dev, buf, flag);
diff --git a/sys/i386/isa/snd/sound.h b/sys/i386/isa/snd/sound.h
index 8edd114..c404ce6 100644
--- a/sys/i386/isa/snd/sound.h
+++ b/sys/i386/isa/snd/sound.h
@@ -313,6 +313,7 @@ struct _snddev_info {
*/
#define MD_AD1848 0x91
#define MD_AD1845 0x92
+#define MD_AD1816 0x93
#define MD_CS4248 0xA1
#define MD_CS4231 0xA2
#define MD_CS4231A 0xA3
OpenPOWER on IntegriCloud