patch-2.0.1 linux/drivers/sound/ad1848.c
Next file: linux/drivers/sound/ad1848_mixer.h
Previous file: linux/drivers/sound/Readme.v30
Back to the patch index
Back to the overall index
- Lines: 1656
- Date:
Sun Jun 30 11:43:48 1996
- Orig file:
v2.0.0/linux/drivers/sound/ad1848.c
- Orig date:
Tue May 7 16:22:34 1996
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
@@ -15,27 +15,11 @@
*/
/*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
*/
#include <linux/config.h>
@@ -64,16 +48,18 @@
unsigned char format_bits;
int xfer_count;
- int irq_mode;
+ int audio_mode;
int intr_active;
int opened;
char *chip_name;
- int mode;
+ int model;
#define MD_1848 1
#define MD_4231 2
#define MD_4231A 3
#define MD_1845 4
#define MD_4232 5
+#define MD_C930 6
+#define MD_IWAVE 7
/* Mixer parameters */
int recmask;
@@ -96,16 +82,15 @@
static int timer_installed = -1;
-static char mixer2codec[MAX_MIXER_DEV] =
-{0};
-
-static int ad_format_mask[6 /*devc->mode */ ] =
+static int ad_format_mask[8 /*devc->model */ ] =
{
0,
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM,
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM,
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, /* AD1845 */
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM,
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM,
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM
};
@@ -121,6 +106,7 @@
static int ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local);
static void ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
static void ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
+static int ad1848_prepare_for_output (int dev, int bsize, int bcount);
static int ad1848_prepare_for_IO (int dev, int bsize, int bcount);
static void ad1848_reset (int dev);
static void ad1848_halt (int dev);
@@ -196,7 +182,8 @@
while (timeout > 0 && ad_read (devc, 11) & 0x20)
timeout--;
if (ad_read (devc, 11) & 0x20)
- printk ("ad1848: Auto calibration timed out(3).\n");
+ if (devc->model != MD_1845)
+ printk ("ad1848: Auto calibration timed out(3).\n");
}
static void
@@ -205,8 +192,6 @@
int i;
unsigned char prev;
- if (devc->mode != MD_1848)
- return;
/*
* Save old register settings and mute output channels
*/
@@ -215,6 +200,12 @@
prev = devc->saved_regs[i] = ad_read (devc, i);
ad_write (devc, i, prev | 0x80);
}
+
+/*
+ * Let's have some delay
+ */
+ for (i = 0; i < 1000; i++)
+ inb (devc->base);
}
static void
@@ -222,6 +213,12 @@
{
int i;
+/*
+ * Let's have some delay
+ */
+ for (i = 0; i < 1000; i++)
+ inb (devc->base);
+
/*
* Restore back old volume registers (unmute)
*/
@@ -367,7 +364,7 @@
ad1848_mixer_get (ad1848_info * devc, int dev)
{
if (!((1 << dev) & devc->supported_devices))
- return -EINVAL;
+ return -(EINVAL);
return devc->levels[dev];
}
@@ -401,13 +398,13 @@
right = mix_cvt[right];
if (dev > 31)
- return -EINVAL;
+ return -(EINVAL);
if (!(devc->supported_devices & (1 << dev)))
- return -EINVAL;
+ return -(EINVAL);
if (mix_devices[dev][LEFT_CHN].nbits == 0)
- return -EINVAL;
+ return -(EINVAL);
devc->levels[dev] = retvol;
@@ -442,10 +439,12 @@
{
int i;
- switch (devc->mode)
+ switch (devc->model)
{
case MD_4231:
case MD_4231A:
+ case MD_C930:
+ case MD_IWAVE:
case MD_1845:
devc->supported_devices = MODE2_MIXER_DEVICES;
break;
@@ -469,16 +468,7 @@
static int
ad1848_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
{
- ad1848_info *devc;
-
- int codec_dev = mixer2codec[dev];
-
- if (!codec_dev)
- return -ENXIO;
-
- codec_dev--;
-
- devc = (ad1848_info *) audio_devs[codec_dev]->devc;
+ ad1848_info *devc = mixer_devs[dev]->devc;
if (((cmd >> 8) & 0xff) == 'M')
{
@@ -524,107 +514,16 @@
}
}
else
- return -EINVAL;
+ return -(EINVAL);
}
-static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] =
-{
- {
- "Generic AD1848 codec",
- DMA_AUTOMODE,
- AFMT_U8, /* Will be set later */
- NULL,
- ad1848_open,
- ad1848_close,
- ad1848_output_block,
- ad1848_start_input,
- ad1848_ioctl,
- ad1848_prepare_for_IO,
- ad1848_prepare_for_IO,
- ad1848_reset,
- ad1848_halt,
- NULL,
- NULL,
- ad1848_halt_input,
- ad1848_halt_output,
- ad1848_trigger
- }};
-
-static struct mixer_operations ad1848_mixer_operations =
-{
- "AD1848/CS4248/CS4231",
- ad1848_mixer_ioctl
-};
-
static int
-ad1848_open (int dev, int mode)
+ad1848_set_speed (int dev, int arg)
{
- ad1848_info *devc = NULL;
- unsigned long flags;
-
- if (dev < 0 || dev >= num_audiodevs)
- return -ENXIO;
-
- devc = (ad1848_info *) audio_devs[dev]->devc;
-
-
- save_flags (flags);
- cli ();
- if (devc->opened)
- {
- restore_flags (flags);
- printk ("ad1848: Already opened\n");
- return -EBUSY;
- }
-
-
- devc->dual_dma = 0;
-
- if (audio_devs[dev]->flags & DMA_DUPLEX)
- {
- devc->dual_dma = 1;
- }
-
- devc->intr_active = 0;
- devc->opened = 1;
- devc->irq_mode = 0;
- ad1848_trigger (dev, 0);
- restore_flags (flags);
-/*
- * Mute output until the playback really starts. This decreases clicking (hope so).
- */
- ad_mute (devc);
-
- return 0;
-}
-
-static void
-ad1848_close (int dev)
-{
- unsigned long flags;
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
- DEB (printk ("ad1848_close(void)\n"));
-
- save_flags (flags);
- cli ();
-
- devc->intr_active = 0;
- ad1848_reset (dev);
-
-
- devc->opened = 0;
- devc->irq_mode = 0;
-
- ad_unmute (devc);
- restore_flags (flags);
-}
-
-static int
-set_speed (ad1848_info * devc, int arg)
-{
/*
- * The sampling speed is encoded in the least significant nibble of I8. The
+ * The sampling speed is encoded in the least significant nible of I8. The
* LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other
* three bits select the divisor (indirectly):
*
@@ -632,10 +531,10 @@
* the increasing order.
*/
typedef struct
- {
- int speed;
- unsigned char bits;
- }
+ {
+ int speed;
+ unsigned char bits;
+ }
speed_struct;
static speed_struct speed_table[] =
@@ -661,7 +560,10 @@
n = sizeof (speed_table) / sizeof (speed_struct);
- if (devc->mode == MD_1845) /* AD1845 has different timer than others */
+ if (arg == 0)
+ return devc->speed;
+
+ if (devc->model == MD_1845) /* AD1845 has different timer than others */
{
if (arg < 4000)
arg = 4000;
@@ -705,9 +607,11 @@
return devc->speed;
}
-static int
-set_channels (ad1848_info * devc, int arg)
+static short
+ad1848_set_channels (int dev, short arg)
{
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+
if (arg != 1 && arg != 2)
return devc->channels;
@@ -715,15 +619,16 @@
return arg;
}
-static int
-set_format (ad1848_info * devc, int arg)
+static unsigned int
+ad1848_set_bits (int dev, unsigned int arg)
{
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
static struct format_tbl
- {
- int format;
- unsigned char bits;
- }
+ {
+ int format;
+ unsigned char bits;
+ }
format2bits[] =
{
{
@@ -768,7 +673,10 @@
};
int i, n = sizeof (format2bits) / sizeof (struct format_tbl);
- if (!(arg & ad_format_mask[devc->mode]))
+ if (arg == 0)
+ return devc->audio_format;
+
+ if (!(arg & ad_format_mask[devc->model]))
arg = AFMT_U8;
devc->audio_format = arg;
@@ -787,51 +695,100 @@
return devc->audio_format = AFMT_U8;
}
+static struct audio_driver ad1848_audio_driver =
+{
+ ad1848_open,
+ ad1848_close,
+ ad1848_output_block,
+ ad1848_start_input,
+ ad1848_ioctl,
+ ad1848_prepare_for_IO,
+ ad1848_prepare_for_output,
+ ad1848_reset,
+ ad1848_halt,
+ NULL,
+ NULL,
+ ad1848_halt_input,
+ ad1848_halt_output,
+ ad1848_trigger,
+ ad1848_set_speed,
+ ad1848_set_bits,
+ ad1848_set_channels
+};
+
+static struct mixer_operations ad1848_mixer_operations =
+{
+ "SOUNDPORT",
+ "AD1848/CS4248/CS4231",
+ ad1848_mixer_ioctl
+};
+
static int
-ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
+ad1848_open (int dev, int mode)
{
- ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ ad1848_info *devc = NULL;
+ unsigned long flags;
+
+ if (dev < 0 || dev >= num_audiodevs)
+ return -(ENXIO);
+
+ devc = (ad1848_info *) audio_devs[dev]->devc;
+
- switch (cmd)
+ save_flags (flags);
+ cli ();
+ if (devc->opened)
{
- case SOUND_PCM_WRITE_RATE:
- if (local)
- return set_speed (devc, (int) arg);
- return snd_ioctl_return ((int *) arg, set_speed (devc, get_fs_long ((long *) arg)));
-
- case SOUND_PCM_READ_RATE:
- if (local)
- return devc->speed;
- return snd_ioctl_return ((int *) arg, devc->speed);
-
- case SNDCTL_DSP_STEREO:
- if (local)
- return set_channels (devc, (int) arg + 1) - 1;
- return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg) + 1) - 1);
-
- case SOUND_PCM_WRITE_CHANNELS:
- if (local)
- return set_channels (devc, (int) arg);
- return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg)));
-
- case SOUND_PCM_READ_CHANNELS:
- if (local)
- return devc->channels;
- return snd_ioctl_return ((int *) arg, devc->channels);
-
- case SNDCTL_DSP_SAMPLESIZE:
- if (local)
- return set_format (devc, (int) arg);
- return snd_ioctl_return ((int *) arg, set_format (devc, get_fs_long ((long *) arg)));
-
- case SOUND_PCM_READ_BITS:
- if (local)
- return devc->audio_format;
- return snd_ioctl_return ((int *) arg, devc->audio_format);
+ restore_flags (flags);
+ return -(EBUSY);
+ }
- default:;
+ devc->dual_dma = 0;
+
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ {
+ devc->dual_dma = 1;
}
- return -EINVAL;
+
+ devc->intr_active = 0;
+ devc->opened = 1;
+ devc->audio_mode = 0;
+ ad1848_trigger (dev, 0);
+ restore_flags (flags);
+/*
+ * Mute output until the playback really starts. This decreases clicking (hope so).
+ */
+ ad_mute (devc);
+
+ return 0;
+}
+
+static void
+ad1848_close (int dev)
+{
+ unsigned long flags;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+ DEB (printk ("ad1848_close(void)\n"));
+
+ save_flags (flags);
+ cli ();
+
+ devc->intr_active = 0;
+ ad1848_reset (dev);
+
+
+ devc->opened = 0;
+ devc->audio_mode = 0;
+
+ ad_unmute (devc);
+ restore_flags (flags);
+}
+
+static int
+ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
+{
+ return -(EINVAL);
}
static void
@@ -840,6 +797,9 @@
unsigned long flags, cnt;
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ if (!dma_restart)
+ return;
+
cnt = count;
if (devc->audio_format == AFMT_IMA_ADPCM)
@@ -855,11 +815,11 @@
cnt >>= 1;
cnt--;
- if (devc->irq_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE &&
+ if (devc->audio_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE &&
intrflag &&
cnt == devc->xfer_count)
{
- devc->irq_mode |= PCM_ENABLE_OUTPUT;
+ devc->audio_mode |= PCM_ENABLE_OUTPUT;
devc->intr_active = 1;
return; /*
* Auto DMA mode on. No need to react
@@ -868,20 +828,16 @@
save_flags (flags);
cli ();
- if (dma_restart)
- {
- ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Playback disable */
- /* ad1848_halt (dev); */
- DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
- }
+ /* ad_write (devc, 9, ad_read (devc, 9) & ~ 0x01); / * Playback disable */
+ ad1848_halt (dev);
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
ad_write (devc, 15, (unsigned char) (cnt & 0xff));
ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
- ad_unmute (devc);
devc->xfer_count = cnt;
- devc->irq_mode |= PCM_ENABLE_OUTPUT;
+ devc->audio_mode |= PCM_ENABLE_OUTPUT;
devc->intr_active = 1;
restore_flags (flags);
}
@@ -892,6 +848,9 @@
unsigned long flags, cnt;
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ if (!dma_restart)
+ return;
+
cnt = count;
if (devc->audio_format == AFMT_IMA_ADPCM)
{
@@ -906,11 +865,11 @@
cnt >>= 1;
cnt--;
- if (devc->irq_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE &&
+ if (devc->audio_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE &&
intrflag &&
cnt == devc->xfer_count)
{
- devc->irq_mode |= PCM_ENABLE_INPUT;
+ devc->audio_mode |= PCM_ENABLE_INPUT;
devc->intr_active = 1;
return; /*
* Auto DMA mode on. No need to react
@@ -926,7 +885,7 @@
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
}
- if (devc->mode == MD_1848 || !devc->dual_dma) /* Single DMA channel mode */
+ if (devc->model == MD_1848 || !devc->dual_dma) /* Single DMA channel mode */
{
ad_write (devc, 15, (unsigned char) (cnt & 0xff));
ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
@@ -941,12 +900,22 @@
ad_unmute (devc);
devc->xfer_count = cnt;
- devc->irq_mode |= PCM_ENABLE_INPUT;
+ devc->audio_mode |= PCM_ENABLE_INPUT;
devc->intr_active = 1;
restore_flags (flags);
}
static int
+ad1848_prepare_for_output (int dev, int bsize, int bcount)
+{
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+ ad_mute (devc);
+
+ return ad1848_prepare_for_IO (dev, bsize, bcount);
+}
+
+static int
ad1848_prepare_for_IO (int dev, int bsize, int bcount)
{
int timeout;
@@ -954,7 +923,7 @@
unsigned long flags;
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
- if (devc->irq_mode)
+ if (devc->audio_mode)
return 0;
save_flags (flags);
@@ -964,7 +933,7 @@
if (devc->channels > 1)
fs |= 0x10;
- if (devc->mode == MD_1845) /* Use alternate speed select registers */
+ if (devc->model == MD_1845) /* Use alternate speed select registers */
{
fs &= 0xf0; /* Mask off the rate select bits */
@@ -974,7 +943,7 @@
old_fs = ad_read (devc, 8);
- if (devc->mode != MD_4232)
+ if (devc->model != MD_4232)
if (fs == old_fs) /* No change */
{
restore_flags (flags);
@@ -984,7 +953,7 @@
ad_enter_MCE (devc); /* Enables changes to the format select reg */
- if (devc->mode == MD_4232)
+ if (devc->model == MD_4232)
{
tmp = ad_read (devc, 16);
ad_write (devc, 16, tmp | 0x30);
@@ -992,21 +961,21 @@
ad_write (devc, 8, fs);
/*
- * Write to I8 starts resynchronization. Wait until it completes.
+ * Write to I8 starts resyncronization. Wait until it completes.
*/
timeout = 10000;
while (timeout > 0 && inb (devc->base) == 0x80)
timeout--;
/*
- * If mode == 2 (CS4231), set I28 also. It's the capture format register.
+ * If mode >= 2 (CS4231), set I28 also. It's the capture format register.
*/
- if (devc->mode != MD_1848)
+ if (devc->model != MD_1848)
{
ad_write (devc, 28, fs);
/*
- * Write to I28 starts resynchronization. Wait until it completes.
+ * Write to I28 starts resyncronization. Wait until it completes.
*/
timeout = 10000;
while (timeout > 0 && inb (devc->base) == 0x80)
@@ -1014,7 +983,7 @@
}
- if (devc->mode == MD_4232)
+ if (devc->model == MD_4232)
ad_write (devc, 16, tmp & ~0x30);
ad_leave_MCE (devc); /*
@@ -1064,7 +1033,7 @@
ad_mute (devc);
- if (devc->mode == MD_4232) /* Use applied black magic */
+ if (devc->model == MD_4232) /* Use applied black magic */
{
int tmout;
@@ -1085,7 +1054,7 @@
outb (0, io_Status (devc)); /* Clear interrupt status */
outb (0, io_Status (devc)); /* Clear interrupt status */
- devc->irq_mode &= ~PCM_ENABLE_INPUT;
+ devc->audio_mode &= ~PCM_ENABLE_INPUT;
restore_flags (flags);
}
@@ -1100,7 +1069,7 @@
cli ();
ad_mute (devc);
- if (devc->mode == MD_4232) /* Use applied black magic */
+ if (devc->model == MD_4232) /* Use applied black magic */
{
int tmout;
@@ -1121,7 +1090,7 @@
outb (0, io_Status (devc)); /* Clear interrupt status */
outb (0, io_Status (devc)); /* Clear interrupt status */
- devc->irq_mode &= ~PCM_ENABLE_OUTPUT;
+ devc->audio_mode &= ~PCM_ENABLE_OUTPUT;
restore_flags (flags);
}
@@ -1131,35 +1100,62 @@
{
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
unsigned long flags;
- unsigned char tmp;
+ unsigned char tmp, old;
save_flags (flags);
cli ();
- state &= devc->irq_mode;
+ state &= devc->audio_mode;
- tmp = ad_read (devc, 9) & ~0x03;
+ tmp = (old = ad_read (devc, 9)) & ~0x03;
if (state & PCM_ENABLE_INPUT)
tmp |= 0x02;
if (state & PCM_ENABLE_OUTPUT)
tmp |= 0x01;
+
+ if (!(state & PCM_ENABLE_OUTPUT) && old & 0x01);
+ ad_mute (devc);
+
ad_write (devc, 9, tmp);
+ if (state & PCM_ENABLE_OUTPUT && !(old & 0x01));
+ ad_unmute (devc);
+
restore_flags (flags);
}
int
ad1848_detect (int io_base, int *ad_flags, int *osp)
{
+ /*
+ * Initial values for the indirect registers of CS4248/AD1848.
+ */
+ static int init_values[] =
+ {
+ 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00,
+
+ /* Positions 16 to 31 just for CS4231/2 and ad1845 */
+ 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
unsigned char tmp;
ad1848_info *devc = &dev_info[nr_ad1848_devs];
unsigned char tmp1 = 0xff, tmp2 = 0xff;
+ int optiC930 = 0; /* OPTi 82C930 flag */
+ int interwave = 0;
+ int ad1847_flag = 0;
+
int i;
DDB (printk ("ad1848_detect(%x)\n", io_base));
if (ad_flags)
- *ad_flags = 0;
+ {
+ if (*ad_flags == 0x12345678)
+ interwave = 1;
+ *ad_flags = 0;
+ }
if (nr_ad1848_devs >= MAX_AUDIO_DEV)
{
@@ -1179,7 +1175,7 @@
devc->irq = 0;
devc->opened = 0;
devc->chip_name = "AD1848";
- devc->mode = MD_1848; /* AD1848 or CS4248 */
+ devc->model = MD_1848; /* AD1848 or CS4248 */
devc->osp = osp;
devc->debug_flag = 0;
@@ -1187,7 +1183,7 @@
* Check that the I/O address is in use.
*
* The bit 0x80 of the base I/O port is known to be 0 after the
- * chip has performed its power-on initialization. Just assume
+ * chip has performed it's power on initialization. Just assume
* this has happened before the OS is starting.
*
* If the I/O address is unused, it typically returns 0xff.
@@ -1217,23 +1213,29 @@
ad_write (devc, 1, 0x45); /* 0x55 with bit 0x10 clear */
if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45)
- {
- DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2));
- return 0;
- }
+ if (tmp2 == 0x65) /* AD1847 has couple of bits hardcoded to 1 */
+ ad1847_flag = 1;
+ else
+ {
+ DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2));
+ return 0;
+ }
DDB (printk ("ad1848_detect() - step C\n"));
ad_write (devc, 0, 0x45);
ad_write (devc, 1, 0xaa);
if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa)
- {
- DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2));
- return 0;
- }
+ if (tmp2 == 0x8a) /* AD1847 has few bits hardcoded to 1 */
+ ad1847_flag = 1;
+ else
+ {
+ DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2));
+ return 0;
+ }
/*
- * The indirect register I12 has some read only bits. Let's
+ * The indirect register I12 has some read only bits. Lets
* try to change them.
*/
@@ -1259,6 +1261,22 @@
* with CS4231.
*/
+/*
+ * OPTi 82C930 has mode2 control bit in another place. This test will fail
+ * with it. Accept this situation as a possible indication of this chip.
+ */
+
+ DDB (printk ("ad1848_detect() - step F\n"));
+ ad_write (devc, 12, 0); /* Mode2=disabled */
+
+ for (i = 0; i < 16; i++)
+ if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16)))
+ {
+ DDB (printk ("ad1848 detect step F(%d/%x/%x) - OPTi chip?\n", i, tmp1, tmp2));
+ if (!ad1847_flag)
+ optiC930 = 1;
+ break;
+ }
/*
* Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40).
@@ -1277,7 +1295,7 @@
devc->chip_name = "CS4248"; /* Our best knowledge just now */
}
- if ((tmp1 & 0xc0) == (0x80 | 0x40))
+ if (optiC930 || (tmp1 & 0xc0) == (0x80 | 0x40))
{
/*
* CS4231 detected - is it?
@@ -1314,7 +1332,7 @@
*/
devc->chip_name = "CS4231";
- devc->mode = MD_4231;
+ devc->model = MD_4231;
/*
* It could be an AD1845 or CS4231A as well.
@@ -1330,17 +1348,17 @@
case 0xa0:
devc->chip_name = "CS4231A";
- devc->mode = MD_4231A;
+ devc->model = MD_4231A;
break;
case 0xa2:
devc->chip_name = "CS4232";
- devc->mode = MD_4232;
+ devc->model = MD_4232;
break;
case 0xb2:
devc->chip_name = "CS4232A";
- devc->mode = MD_4232;
+ devc->model = MD_4232;
break;
case 0x80:
@@ -1358,15 +1376,28 @@
if (ad_read (devc, 23) != tmp) /* AD1845 ? */
{
devc->chip_name = "AD1845";
- devc->mode = MD_1845;
+ devc->model = MD_1845;
+ }
+ else if (interwave)
+ {
+ devc->model = MD_IWAVE;
+ devc->chip_name = "IWave";
}
ad_write (devc, 23, tmp); /* Restore */
}
break;
- default: /* Assume CS4231 */
- devc->mode = MD_4231;
+ default: /* Assume CS4231 or OPTi 82C930 */
+ if (optiC930)
+ {
+ devc->chip_name = "82C930";
+ devc->model = MD_C930;
+ }
+ else
+ {
+ devc->model = MD_4231;
+ }
}
}
@@ -1379,11 +1410,32 @@
DDB (printk ("ad1848_detect() - step L\n"));
if (ad_flags)
{
- if (devc->mode != MD_1848)
+ if (devc->model != MD_1848)
*ad_flags |= AD_F_CS4231;
}
DDB (printk ("ad1848_detect() - Detected OK\n"));
+
+ if (devc->model == MD_1848 && ad1847_flag)
+ devc->chip_name = "AD1847";
+
+ for (i = 0; i < 16; i++)
+ ad_write (devc, i, init_values[i]);
+
+ ad_mute (devc); /* Initialize some variables */
+ ad_unmute (devc); /* Leave it unmuted now */
+
+ if (devc->model > MD_1848)
+ {
+ ad_write (devc, 12, ad_read (devc, 12) | 0x40); /* Mode2 = enabled */
+
+ if (devc->model == MD_IWAVE)
+ ad_write (devc, 12, 0x6c); /* Select codec mode 3 */
+
+ for (i = 16; i < 32; i++)
+ ad_write (devc, i, init_values[i]);
+ }
+
return 1;
}
@@ -1396,24 +1448,14 @@
* The actually used IRQ is ABS(irq).
*/
- /*
- * Initial values for the indirect registers of CS4248/AD1848.
- */
- static int init_values[] =
- {
- 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
- 0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00,
- /* Positions 16 to 31 just for CS4231 */
- 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
- int i, my_dev;
+ int my_dev;
+ char dev_name[100];
ad1848_info *devc = &dev_info[nr_ad1848_devs];
- if (!ad1848_detect (io_base, NULL, osp))
- return;
+ int audio_flags = DMA_AUTOMODE;
+
request_region (devc->base, 4, devc->chip_name);
@@ -1422,141 +1464,129 @@
devc->timer_ticks = 0;
devc->osp = osp;
- if (nr_ad1848_devs != 0)
- {
- memcpy ((char *) &ad1848_pcm_operations[nr_ad1848_devs],
- (char *) &ad1848_pcm_operations[0],
- sizeof (struct audio_operations));
- }
-
- for (i = 0; i < 16; i++)
- ad_write (devc, i, init_values[i]);
-
- ad_mute (devc); /* Initialize some variables */
- ad_unmute (devc); /* Leave it unmuted now */
-
- if (devc->mode > MD_1848)
+ if (devc->model > MD_1848)
{
if (dma_capture == dma_playback || dma_capture == -1 || dma_playback == -1)
{
ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */
- ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX;
+ audio_flags &= ~DMA_DUPLEX;
}
else
{
ad_write (devc, 9, ad_read (devc, 9) & ~0x04); /* Dual DMA mode */
- ad1848_pcm_operations[nr_ad1848_devs].flags |= DMA_DUPLEX;
+ audio_flags |= DMA_DUPLEX;
}
- ad_write (devc, 12, ad_read (devc, 12) | 0x40); /* Mode2 = enabled */
- for (i = 16; i < 32; i++)
- ad_write (devc, i, init_values[i]);
-
-
- if (devc->mode == MD_1845)
+ if (devc->model == MD_1845)
ad_write (devc, 27, ad_read (devc, 27) | 0x08); /* Alternate freq select enabled */
+
+ if (devc->model == MD_IWAVE)
+ { /* Some magic Interwave spesific initialization */
+ ad_write (devc, 12, 0x6c); /* Select codec mode 3 */
+ ad_write (devc, 17, 0xc2); /* Alternate feature enable */
+ }
}
else
{
- ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX;
+ audio_flags &= ~DMA_DUPLEX;
ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */
}
outb (0, io_Status (devc)); /* Clear pending interrupts */
if (name != NULL && name[0] != 0)
- sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
+ sprintf (dev_name,
"%s (%s)", name, devc->chip_name);
else
- sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
+ sprintf (dev_name,
"Generic audio codec (%s)", devc->chip_name);
- conf_printf2 (ad1848_pcm_operations[nr_ad1848_devs].name,
+ conf_printf2 (dev_name,
devc->base, devc->irq, dma_playback, dma_capture);
- if (num_audiodevs < MAX_AUDIO_DEV)
+ if (devc->model == MD_1848)
+ audio_flags |= DMA_HARDSTOP;
+
+ if ((my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION,
+ dev_name,
+ &ad1848_audio_driver,
+ sizeof (struct audio_driver),
+ audio_flags,
+ ad_format_mask[devc->model],
+ devc,
+ dma_playback,
+ dma_capture)) < 0)
+ {
+ return;
+ }
+
+ if (irq > 0)
{
- audio_devs[my_dev = num_audiodevs++] = &ad1848_pcm_operations[nr_ad1848_devs];
- if (irq > 0)
+ irq2dev[irq] = devc->dev_no = my_dev;
+ if (snd_set_irq_handler (devc->irq, ad1848_interrupt,
+ "SoundPort",
+ devc->osp) < 0)
{
- audio_devs[my_dev]->devc = devc;
- irq2dev[irq] = devc->dev_no = my_dev;
- if (snd_set_irq_handler (devc->irq, ad1848_interrupt,
- audio_devs[my_dev]->name,
- devc->osp) < 0)
- {
- printk ("ad1848: IRQ in use\n");
- }
+ printk ("ad1848: IRQ in use\n");
+ }
-#ifdef NO_IRQ_TEST
- if (devc->mode != MD_1848)
- {
- int x;
- unsigned char tmp = ad_read (devc, 16);
+ if (devc->model != MD_1848)
+ {
+ int x;
+ unsigned char tmp = ad_read (devc, 16);
- devc->timer_ticks = 0;
+ devc->timer_ticks = 0;
- ad_write (devc, 21, 0x00); /* Timer msb */
- ad_write (devc, 20, 0x10); /* Timer lsb */
+ ad_write (devc, 21, 0x00); /* Timer msb */
+ ad_write (devc, 20, 0x10); /* Timer lsb */
- ad_write (devc, 16, tmp | 0x40); /* Enable timer */
- for (x = 0; x < 100000 && devc->timer_ticks == 0; x++);
- ad_write (devc, 16, tmp & ~0x40); /* Disable timer */
-
- if (devc->timer_ticks == 0)
- printk ("[IRQ conflict???]");
- else
- devc->irq_ok = 1;
+ ad_write (devc, 16, tmp | 0x40); /* Enable timer */
+ for (x = 0; x < 100000 && devc->timer_ticks == 0; x++);
+ ad_write (devc, 16, tmp & ~0x40); /* Disable timer */
- }
+ if (devc->timer_ticks == 0)
+ printk ("ad1848: Interrupt test failed (IRQ%d)\n", devc->irq);
else
- devc->irq_ok = 1; /* Couldn't test. assume it's OK */
-#else
- devc->irq_ok = 1;
-#endif
+ devc->irq_ok = 1;
}
- else if (irq < 0)
- irq2dev[-irq] = devc->dev_no = my_dev;
-
- audio_devs[my_dev]->dmachan1 = dma_playback;
- audio_devs[my_dev]->dmachan2 = dma_capture;
- audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
- audio_devs[my_dev]->devc = devc;
- audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode];
- nr_ad1848_devs++;
+ else
+ devc->irq_ok = 1; /* Couldn't test. assume it's OK */
+ }
+ else if (irq < 0)
+ irq2dev[-irq] = devc->dev_no = my_dev;
+ nr_ad1848_devs++;
#ifdef CONFIG_SEQUENCER
- if (devc->mode != MD_1848 && devc->mode != MD_1845 && devc->irq_ok)
- ad1848_tmr_install (my_dev);
+ if (devc->model != MD_1848 && devc->model != MD_1845 && devc->irq_ok)
+ ad1848_tmr_install (my_dev);
#endif
- if (!share_dma)
- {
- if (sound_alloc_dma (dma_playback, "Sound System"))
- printk ("ad1848.c: Can't allocate DMA%d\n", dma_playback);
-
- if (dma_capture != dma_playback)
- if (sound_alloc_dma (dma_capture, "Sound System (capture)"))
- printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture);
- }
+ if (!share_dma)
+ {
+ if (sound_alloc_dma (dma_playback, "Sound System"))
+ printk ("ad1848.c: Can't allocate DMA%d\n", dma_playback);
- /*
- * Toggle the MCE bit. It completes the initialization phase.
- */
+ if (dma_capture != dma_playback)
+ if (sound_alloc_dma (dma_capture, "Sound System (capture)"))
+ printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture);
+ }
- ad_enter_MCE (devc); /* In case the bit was off */
- ad_leave_MCE (devc);
+ /*
+ * Toggle the MCE bit. It completes the initialization phase.
+ */
- if (num_mixers < MAX_MIXER_DEV)
- {
- mixer2codec[num_mixers] = my_dev + 1;
- audio_devs[my_dev]->mixer_dev = num_mixers;
- mixer_devs[num_mixers++] = &ad1848_mixer_operations;
- ad1848_mixer_reset (devc);
- }
+ ad_enter_MCE (devc); /* In case the bit was off */
+ ad_leave_MCE (devc);
+ ad1848_mixer_reset (devc);
+
+ if (sound_install_mixer (MIXER_DRIVER_VERSION,
+ dev_name,
+ &ad1848_mixer_operations,
+ sizeof (struct mixer_operations),
+ devc) >= 0)
+ {
+ audio_devs[my_dev]->mixer_dev = num_mixers - 1;
}
- else
- printk ("AD1848: Too many PCM devices available\n");
}
void
@@ -1588,7 +1618,7 @@
}
}
else
- printk ("ad1848: Can't find device to be unloaded. Base=%x\n",
+ printk ("ad1848: Can't find device to be undoaded. Base=%x\n",
io_base);
}
@@ -1633,21 +1663,21 @@
if (status & 0x01)
{
- if (devc->mode != MD_1848)
+ if (devc->model != MD_1848)
alt_stat = ad_read (devc, 24);
- if (devc->opened && devc->irq_mode & PCM_ENABLE_INPUT && alt_stat & 0x20)
+ if (devc->opened && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20)
{
DMAbuf_inputintr (dev);
}
- if (devc->opened && devc->irq_mode & PCM_ENABLE_OUTPUT &&
+ if (devc->opened && devc->audio_mode & PCM_ENABLE_OUTPUT &&
alt_stat & 0x10)
{
DMAbuf_outputintr (dev, 1);
}
- if (devc->mode != MD_1848 && alt_stat & 0x40) /* Timer interrupt */
+ if (devc->model != MD_1848 && alt_stat & 0x40) /* Timer interrupt */
{
devc->timer_ticks++;
#ifdef CONFIG_SEQUENCER
@@ -1657,7 +1687,7 @@
}
}
- if (devc->mode != MD_1848)
+ if (devc->model != MD_1848)
ad_write (devc, 24, ad_read (devc, 24) & ~alt_stat); /* Selective ack */
else
outb (0, io_Status (devc)); /* Clear interrupt status */
@@ -1681,11 +1711,220 @@
if (!opl3_detect (base, hw_config->osp))
return;
- opl3_init (0, base, hw_config->osp);
+ opl3_init (base, hw_config->osp);
request_region (base, 4, "OPL3/OPL2");
#endif
}
+#ifdef DESKPROXL
+/*
+ * Very experimental initialization sequence for the integrated sound system
+ * of Compaq Deskpro XL. Will be moved somewhere else in future.
+ */
+
+static int
+init_deskpro (struct address_info *hw_config)
+{
+ unsigned char tmp;
+
+ if ((tmp = inb (0xc44)) == 0xff)
+ {
+ DDB (printk ("init_deskpro: Dead port 0xc44\n"));
+ return 0;
+ }
+
+ outb (tmp | 0x04, 0xc44); /* Select bank 1 */
+ if (inb (0xc44) != 0x04)
+ {
+ DDB (printk ("init_deskpro: Invalid bank1 signature in port 0xc44\n"));
+ return 0;
+ }
+
+/*
+ * OK. It looks like a Deskpro so let's proceed.
+ */
+
+/*
+ * I/O port 0xc44 Audio configuration register.
+ *
+ * bits 0xc0: Audio revision bits
+ * 0x00 = Compaq Business Audio
+ * 0x40 = MS Sound System Compatible (reset default)
+ * 0x80 = Reserved
+ * 0xc0 = Reserved
+ * bit 0x20: No Wait State Enable
+ * 0x00 = Disabled (reset default, DMA mode)
+ * 0x20 = Enabled (programmed I/O mode)
+ * bit 0x10: MS Sound System Decode Enable
+ * 0x00 = Decoding disabled (reset default)
+ * 0x10 = Decoding enabled
+ * bit 0x08: FM Synthesis Decode Enable
+ * 0x00 = Decoding Disabled (reset default)
+ * 0x08 = Decoding enabled
+ * bit 0x04 Bank select
+ * 0x00 = Bank 0
+ * 0x04 = Bank 1
+ * bits 0x03 MSS Base address
+ * 0x00 = 0x530 (reset default)
+ * 0x01 = 0x604
+ * 0x02 = 0xf40
+ * 0x03 = 0xe80
+ */
+
+#ifdef DEBUGXL
+ /* Debug printing */
+ printk ("Port 0xc44 (before): ");
+ outb (tmp & ~0x04, 0xc44);
+ printk ("%02x ", inb (0xc44));
+ outb (tmp | 0x04, 0xc44);
+ printk ("%02x\n", inb (0xc44));
+#endif
+
+ /* Set bank 1 of the register */
+ tmp = 0x58; /* MSS Mode, MSS&FM decode enabled */
+
+ switch (hw_config->io_base)
+ {
+ case 0x530:
+ tmp |= 0x00;
+ break;
+ case 0x604:
+ tmp |= 0x01;
+ break;
+ case 0xf40:
+ tmp |= 0x02;
+ break;
+ case 0xe80:
+ tmp |= 0x03;
+ break;
+ default:
+ DDB (printk ("init_deskpro: Invalid MSS port %x\n",
+ hw_config->io_base));
+ return 0;
+ }
+ outb (tmp & ~0x04, 0xc44); /* Write to bank=0 */
+
+#ifdef DEBUGXL
+ /* Debug printing */
+ printk ("Port 0xc44 (after): ");
+ outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ printk ("%02x ", inb (0xc44));
+ outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ printk ("%02x\n", inb (0xc44));
+#endif
+
+/*
+ * I/O port 0xc45 FM Address Decode/MSS ID Register.
+ *
+ * bank=0, bits 0xfe: FM synthesis Decode Comare bits 7:1 (default=0x88)
+ * bank=0, bit 0x01: SBIC Power Control Bit
+ * 0x00 = Powered up
+ * 0x01 = Powered down
+ * bank=1, bits 0xfc: MSS ID (default=0x40)
+ */
+
+#ifdef DEBUGXL
+ /* Debug printing */
+ printk ("Port 0xc45 (before): ");
+ outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ printk ("%02x ", inb (0xc45));
+ outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ printk ("%02x\n", inb (0xc45));
+#endif
+
+ outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb (0x88, 0xc45); /* FM base 7:0 = 0x88 */
+ outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb (0x10, 0xc45); /* MSS ID = 0x10 (MSS port returns 0x04) */
+
+#ifdef DEBUGXL
+ /* Debug printing */
+ printk ("Port 0xc45 (after): ");
+ outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ printk ("%02x ", inb (0xc45));
+ outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ printk ("%02x\n", inb (0xc45));
+#endif
+
+
+/*
+ * I/O port 0xc46 FM Address Decode/Address ASIC Revision Register.
+ *
+ * bank=0, bits 0xff: FM synthesis Decode Compare bits 15:8 (default=0x03)
+ * bank=1, bits 0xff: Audio addressing ASIC id
+ */
+
+#ifdef DEBUGXL
+ /* Debug printing */
+ printk ("Port 0xc46 (before): ");
+ outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ printk ("%02x ", inb (0xc46));
+ outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ printk ("%02x\n", inb (0xc46));
+#endif
+
+ outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb (0x03, 0xc46); /* FM base 15:8 = 0x03 */
+ outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb (0x11, 0xc46); /* ASIC ID = 0x11 */
+
+#ifdef DEBUGXL
+ /* Debug printing */
+ printk ("Port 0xc46 (after): ");
+ outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ printk ("%02x ", inb (0xc46));
+ outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ printk ("%02x\n", inb (0xc46));
+#endif
+
+/*
+ * I/O port 0xc47 FM Address Decode Register.
+ *
+ * bank=0, bits 0xff: Decode enble selection for various FM address bits
+ * bank=1, bits 0xff: Reserved
+ */
+
+#ifdef DEBUGXL
+ /* Debug printing */
+ printk ("Port 0xc47 (before): ");
+ outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ printk ("%02x ", inb (0xc47));
+ outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ printk ("%02x\n", inb (0xc47));
+#endif
+
+ outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb (0x7c, 0xc47); /* FM decode enable bits = 0x7c */
+ outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb (0x00, 0xc47); /* Reserved bank1 = 0x00 */
+
+#ifdef DEBUGXL
+ /* Debug printing */
+ printk ("Port 0xc47 (after): ");
+ outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ printk ("%02x ", inb (0xc47));
+ outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ printk ("%02x\n", inb (0xc47));
+#endif
+
+/*
+ * I/O port 0xc6f = Audio Disable Function Register
+ */
+
+#ifdef DEBUGXL
+ printk ("Port 0xc6f (before) = %02x\n", inb (0xc6f));
+#endif
+
+ outb (0x80, 0xc6f);
+
+#ifdef DEBUGXL
+ printk ("Port 0xc6f (after) = %02x\n", inb (0xc6f));
+#endif
+
+ return 1;
+}
+#endif
+
int
probe_ms_sound (struct address_info *hw_config)
{
@@ -1705,9 +1944,17 @@
return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp);
}
+#ifdef DESKPROXL
+ if (hw_config->card_subtype == 2) /* Compaq Deskpro XL */
+ {
+ if (!init_deskpro (hw_config))
+ return 0;
+ }
+#endif
+
/*
* Check if the IO port returns valid signature. The original MS Sound
- * system returns 0x04 while some cards (AudioTriX Pro for example)
+ * system returns 0x04 while some cards (AudioTrix Pro for example)
* return 0x00 or 0x0f.
*/
@@ -1720,6 +1967,7 @@
return 0;
return 1;
}
+ DDB (printk ("MSS signature = %x\n", tmp & 0x3f));
if ((tmp & 0x3f) != 0x04 &&
(tmp & 0x3f) != 0x0f &&
(tmp & 0x3f) != 0x00)
@@ -1766,14 +2014,15 @@
return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp);
}
-long
-attach_ms_sound (long mem_start, struct address_info *hw_config)
+void
+attach_ms_sound (struct address_info *hw_config)
{
static char interrupt_bits[12] =
{
-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
};
- char bits;
+ char bits, dma2_bit = 0;
+ int ad_flags = 0;
static char dma_bits[4] =
{
@@ -1782,9 +2031,11 @@
int config_port = hw_config->io_base + 0;
int version_port = hw_config->io_base + 3;
+ int dma = hw_config->dma;
+ int dma2 = hw_config->dma2;
- if (!ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp))
- return mem_start;
+ if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, hw_config->osp))
+ return;
if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */
{
@@ -1793,7 +2044,7 @@
hw_config->dma,
hw_config->dma2, 0, hw_config->osp);
request_region (hw_config->io_base, 4, "WSS config");
- return mem_start;
+ return;
}
/*
@@ -1802,20 +2053,51 @@
bits = interrupt_bits[hw_config->irq];
if (bits == -1)
- return mem_start;
+ return;
outb (bits | 0x40, config_port);
if ((inb (version_port) & 0x40) == 0)
printk ("[IRQ Conflict?]");
- outb (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */
+/*
+ * Handle the capture DMA channel
+ */
+
+ if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma)
+ {
+ if (!((dma == 0 && dma2 == 1) ||
+ (dma == 1 && dma2 == 0) ||
+ (dma == 3 && dma2 == 0)))
+ { /* Unsupported combination. Try to swap channels */
+ int tmp = dma;
+
+ dma = dma2;
+ dma2 = tmp;
+ }
+
+ if ((dma == 0 && dma2 == 1) ||
+ (dma == 1 && dma2 == 0) ||
+ (dma == 3 && dma2 == 0))
+ {
+ dma2_bit = 0x04; /* Enable capture DMA */
+ }
+ else
+ {
+ printk ("MSS: Invalid capture DMA\n");
+ dma2 = dma;
+ }
+ }
+ else
+ dma2 = dma;
- ad1848_init ("MS Sound System", hw_config->io_base + 4,
+ outb (bits | dma_bits[dma] | dma2_bit, config_port); /* Write IRQ+DMA setup */
+
+ ad1848_init ("MSS audio codec", hw_config->io_base + 4,
hw_config->irq,
- hw_config->dma,
- hw_config->dma, 0, hw_config->osp);
+ dma,
+ dma2, 0,
+ hw_config->osp);
request_region (hw_config->io_base, 4, "WSS config");
- return mem_start;
}
void
@@ -1838,15 +2120,14 @@
return ad1848_detect (hw_config->io_base, NULL, hw_config->osp);
}
-long
-attach_pnp_ad1848 (long mem_start, struct address_info *hw_config)
+void
+attach_pnp_ad1848 (struct address_info *hw_config)
{
ad1848_init (hw_config->name, hw_config->io_base,
hw_config->irq,
hw_config->dma,
hw_config->dma2, 0, hw_config->osp);
- return mem_start;
}
void
@@ -1871,7 +2152,7 @@
{
unsigned long flags;
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
- unsigned long xtal_nsecs; /* nanoseconds per xtal oscillator tick */
+ unsigned long xtal_nsecs; /* nanoseconds per xtal oscillaror tick */
unsigned long divider;
save_flags (flags);
@@ -1888,7 +2169,7 @@
* the timer divider.
*/
- if (devc->mode == MD_1845)
+ if (devc->model == MD_1845)
xtal_nsecs = 10050;
else if (ad_read (devc, 8) & 0x01)
xtal_nsecs = 9920;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov