patch-2.1.6 linux/drivers/sound/ad1848.c
Next file: linux/drivers/sound/ad1848_mixer.h
Previous file: linux/drivers/sound/Readme.linux
Back to the patch index
Back to the overall index
- Lines: 1228
- Date:
Tue Oct 29 09:31:24 1996
- Orig file:
v2.1.5/linux/drivers/sound/ad1848.c
- Orig date:
Sun Aug 18 10:46:48 1996
diff -u --recursive --new-file v2.1.5/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
@@ -17,7 +17,7 @@
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free 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.
*/
@@ -36,6 +36,7 @@
{
int base;
int irq;
+ int dma1, dma2;
int dual_dma; /* 1, when two DMA channels allocated */
unsigned char MCE_bit;
unsigned char saved_regs[16];
@@ -46,6 +47,7 @@
int channels;
int audio_format;
unsigned char format_bits;
+ int audio_flags;
int xfer_count;
int audio_mode;
@@ -63,14 +65,15 @@
/* Mixer parameters */
int recmask;
- int supported_devices;
- int supported_rec_devices;
- unsigned short levels[32];
+ int supported_devices, orig_devices;
+ int supported_rec_devices, orig_rec_devices;
+ int *levels;
+ short mixer_reroute[32];
int dev_no;
volatile unsigned long timer_ticks;
int timer_running;
int irq_ok;
- int *osp;
+ mixer_ents *mix_devices;
}
ad1848_info;
@@ -86,12 +89,12 @@
{
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 | AFMT_S16_BE | AFMT_IMA_ADPCM,
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | 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
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM
};
static ad1848_info dev_info[MAX_AUDIO_DEV];
@@ -128,7 +131,7 @@
save_flags (flags);
cli ();
- outb ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
+ outb (((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr (devc));
x = inb (io_Indexed_Data (devc));
/* printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */
restore_flags (flags);
@@ -148,8 +151,8 @@
save_flags (flags);
cli ();
- outb ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
- outb ((unsigned char) (data & 0xff), io_Indexed_Data (devc));
+ outb (((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr (devc));
+ outb (((unsigned char) (data & 0xff)), io_Indexed_Data (devc));
/* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */
restore_flags (flags);
}
@@ -204,6 +207,7 @@
/*
* Let's have some delay
*/
+
for (i = 0; i < 1000; i++)
inb (devc->base);
}
@@ -220,7 +224,7 @@
inb (devc->base);
/*
- * Restore back old volume registers (unmute)
+ * Restore back old volume registers (unmute)
*/
for (i = 6; i < 8; i++)
{
@@ -249,7 +253,7 @@
return;
}
- outb (devc->MCE_bit, io_Index_Addr (devc));
+ outb ((devc->MCE_bit), io_Index_Addr (devc));
restore_flags (flags);
}
@@ -268,7 +272,7 @@
devc->MCE_bit = 0x00;
prev = inb (io_Index_Addr (devc));
- outb (0x00, io_Index_Addr (devc)); /* Clear the MCE bit */
+ outb ((0x00), io_Index_Addr (devc)); /* Clear the MCE bit */
if ((prev & 0x40) == 0) /* Not in MCE mode */
{
@@ -276,7 +280,7 @@
return;
}
- outb (0x00, io_Index_Addr (devc)); /* Clear the MCE bit */
+ outb ((0x00), io_Index_Addr (devc)); /* Clear the MCE bit */
wait_for_calibration (devc);
restore_flags (flags);
}
@@ -290,6 +294,15 @@
mask &= devc->supported_rec_devices;
+ /* Rename the mixer bits if necessary */
+ for (i = 0; i < 32; i++)
+ if (devc->mixer_reroute[i] != i)
+ if (mask & (1 << i))
+ {
+ mask &= ~(1 << i);
+ mask |= (1 << devc->mixer_reroute[i]);
+ }
+
n = 0;
for (i = 0; i < 32; i++) /* Count selected device bits */
if (mask & (1 << i))
@@ -339,21 +352,30 @@
ad_write (devc, 0, (ad_read (devc, 0) & 0x3f) | recdev);
ad_write (devc, 1, (ad_read (devc, 1) & 0x3f) | recdev);
+ /* Rename the mixer bits back if necessary */
+ for (i = 0; i < 32; i++)
+ if (devc->mixer_reroute[i] != i)
+ if (mask & (1 << devc->mixer_reroute[i]))
+ {
+ mask &= ~(1 << devc->mixer_reroute[i]);
+ mask |= (1 << i);
+ }
+
devc->recmask = mask;
return mask;
}
static void
-change_bits (unsigned char *regval, int dev, int chn, int newval)
+change_bits (ad1848_info * devc, unsigned char *regval, int dev, int chn, int newval)
{
unsigned char mask;
int shift;
- if (mix_devices[dev][chn].polarity == 1) /* Reverse */
+ if (devc->mix_devices[dev][chn].polarity == 1) /* Reverse */
newval = 100 - newval;
- mask = (1 << mix_devices[dev][chn].nbits) - 1;
- shift = mix_devices[dev][chn].bitpos;
+ mask = (1 << devc->mix_devices[dev][chn].nbits) - 1;
+ shift = devc->mix_devices[dev][chn].bitpos;
newval = (int) ((newval * mask) + 50) / 100; /* Scale it */
*regval &= ~(mask << shift); /* Clear bits */
@@ -364,7 +386,9 @@
ad1848_mixer_get (ad1848_info * devc, int dev)
{
if (!((1 << dev) & devc->supported_devices))
- return -(EINVAL);
+ return -EINVAL;
+
+ dev = devc->mixer_reroute[dev];
return devc->levels[dev];
}
@@ -379,12 +403,20 @@
int regoffs;
unsigned char val;
+ if (dev > 31)
+ return -EINVAL;
+
+ if (!(devc->supported_devices & (1 << dev)))
+ return -EINVAL;
+
+ dev = devc->mixer_reroute[dev];
+
if (left > 100)
left = 100;
if (right > 100)
right = 100;
- if (mix_devices[dev][RIGHT_CHN].nbits == 0) /* Mono control */
+ if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) /* Mono control */
right = left;
retvol = left | (right << 8);
@@ -397,14 +429,8 @@
left = mix_cvt[left];
right = mix_cvt[right];
- if (dev > 31)
- return -(EINVAL);
-
- if (!(devc->supported_devices & (1 << dev)))
- return -(EINVAL);
-
- if (mix_devices[dev][LEFT_CHN].nbits == 0)
- return -(EINVAL);
+ if (devc->mix_devices[dev][LEFT_CHN].nbits == 0)
+ return -EINVAL;
devc->levels[dev] = retvol;
@@ -412,9 +438,9 @@
* Set the left channel
*/
- regoffs = mix_devices[dev][LEFT_CHN].regno;
+ regoffs = devc->mix_devices[dev][LEFT_CHN].regno;
val = ad_read (devc, regoffs);
- change_bits (&val, dev, LEFT_CHN, left);
+ change_bits (devc, &val, dev, LEFT_CHN, left);
ad_write (devc, regoffs, val);
devc->saved_regs[regoffs] = val;
@@ -422,12 +448,12 @@
* Set the right channel
*/
- if (mix_devices[dev][RIGHT_CHN].nbits == 0)
+ if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0)
return retvol; /* Was just a mono channel */
- regoffs = mix_devices[dev][RIGHT_CHN].regno;
+ regoffs = devc->mix_devices[dev][RIGHT_CHN].regno;
val = ad_read (devc, regoffs);
- change_bits (&val, dev, RIGHT_CHN, right);
+ change_bits (devc, &val, dev, RIGHT_CHN, right);
ad_write (devc, regoffs, val);
devc->saved_regs[regoffs] = val;
@@ -438,17 +464,33 @@
ad1848_mixer_reset (ad1848_info * devc)
{
int i;
+ char name[32];
+
+ devc->mix_devices = &(ad1848_mix_devices[0]);
+
+ sprintf (name, "%s_%d", devc->chip_name, nr_ad1848_devs);
+
+ for (i = 0; i < 32; i++)
+ devc->mixer_reroute[i] = i;
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;
+ case MD_C930:
+ devc->supported_devices = C930_MIXER_DEVICES;
+ devc->mix_devices = &(c930_mix_devices[0]);
+ break;
+
+ case MD_IWAVE:
+ devc->supported_devices = MODE3_MIXER_DEVICES;
+ devc->mix_devices = &(iwave_mix_devices[0]);
+ break;
+
case MD_4232:
devc->supported_devices = MODE3_MIXER_DEVICES;
break;
@@ -458,10 +500,14 @@
}
devc->supported_rec_devices = MODE1_REC_DEVICES;
+ devc->orig_devices = devc->supported_devices;
+ devc->orig_rec_devices = devc->supported_rec_devices;
+
+ devc->levels = load_mixer_volumes (name, default_mixer_levels, 1);
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
if (devc->supported_devices & (1 << i))
- ad1848_mixer_set (devc, i, default_mixer_levels[i]);
+ ad1848_mixer_set (devc, i, devc->levels[i]);
ad1848_set_recmask (devc, SOUND_MASK_MIC);
}
@@ -472,16 +518,19 @@
if (((cmd >> 8) & 0xff) == 'M')
{
+ int val;
if (_IOC_DIR (cmd) & _IOC_WRITE)
switch (cmd & 0xff)
{
case SOUND_MIXER_RECSRC:
- return snd_ioctl_return ((int *) arg, ad1848_set_recmask (devc, get_user ((int *) arg)));
+ get_user (val, (int *) arg);
+ return ioctl_out (arg, ad1848_set_recmask (devc, val));
break;
default:
- return snd_ioctl_return ((int *) arg, ad1848_mixer_set (devc, cmd & 0xff, get_user ((int *) arg)));
+ get_user (val, (int *) arg);
+ return ioctl_out (arg, ad1848_mixer_set (devc, cmd & 0xff, val));
}
else
switch (cmd & 0xff) /*
@@ -490,31 +539,34 @@
{
case SOUND_MIXER_RECSRC:
- return snd_ioctl_return ((int *) arg, devc->recmask);
+ return ioctl_out (arg, devc->recmask);
break;
case SOUND_MIXER_DEVMASK:
- return snd_ioctl_return ((int *) arg, devc->supported_devices);
+ return ioctl_out (arg, devc->supported_devices);
break;
case SOUND_MIXER_STEREODEVS:
- return snd_ioctl_return ((int *) arg, devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX));
+ if (devc->model == MD_C930)
+ return ioctl_out (arg, devc->supported_devices);
+ else
+ return ioctl_out (arg, devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX));
break;
case SOUND_MIXER_RECMASK:
- return snd_ioctl_return ((int *) arg, devc->supported_rec_devices);
+ return ioctl_out (arg, devc->supported_rec_devices);
break;
case SOUND_MIXER_CAPS:
- return snd_ioctl_return ((int *) arg, SOUND_CAP_EXCL_INPUT);
+ return ioctl_out (arg, SOUND_CAP_EXCL_INPUT);
break;
default:
- return snd_ioctl_return ((int *) arg, ad1848_mixer_get (devc, cmd & 0xff));
+ return ioctl_out (arg, ad1848_mixer_get (devc, cmd & 0xff));
}
}
else
- return -(EINVAL);
+ return -EINVAL;
}
static int
@@ -560,7 +612,7 @@
n = sizeof (speed_table) / sizeof (speed_struct);
- if (arg == 0)
+ if (arg <= 0)
return devc->speed;
if (devc->model == MD_1845) /* AD1845 has different timer than others */
@@ -730,7 +782,7 @@
unsigned long flags;
if (dev < 0 || dev >= num_audiodevs)
- return -(ENXIO);
+ return -ENXIO;
devc = (ad1848_info *) audio_devs[dev]->devc;
@@ -740,7 +792,7 @@
if (devc->opened)
{
restore_flags (flags);
- return -(EBUSY);
+ return -EBUSY;
}
devc->dual_dma = 0;
@@ -788,7 +840,7 @@
static int
ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
{
- return -(EINVAL);
+ return -EINVAL;
}
static void
@@ -828,8 +880,7 @@
save_flags (flags);
cli ();
- /* ad_write (devc, 9, ad_read (devc, 9) & ~ 0x01); / * Playback disable */
- ad1848_halt (dev);
+ ad1848_halt_output (dev);
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
ad_write (devc, 15, (unsigned char) (cnt & 0xff));
@@ -880,8 +931,7 @@
if (dma_restart)
{
- /* ad1848_halt (dev); */
- ad_write (devc, 9, ad_read (devc, 9) & ~0x02); /* Capture disable */
+ ad1848_halt_input (dev);
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
}
@@ -911,6 +961,25 @@
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
ad_mute (devc);
+ {
+/*
+ * This code fragment ensures that the playback FIFO is empty before
+ * setting the codec for playback. Enabling playback for a moment should
+ * be enough to do that.
+ */
+ int tmout;
+
+ ad_write (devc, 9, ad_read (devc, 9) | 0x01); /* Enable playback */
+ disable_dma (audio_devs[dev]->dmachan1);
+ for (tmout = 0; tmout < 1000000; tmout++)
+ if (ad_read (devc, 11) & 0x10) /* DRQ active */
+ if (tmout > 10000)
+ break;
+ ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */
+
+ enable_dma (audio_devs[dev]->dmachan1);
+ devc->audio_mode &= ~PCM_ENABLE_OUTPUT;
+ }
return ad1848_prepare_for_IO (dev, bsize, bcount);
}
@@ -943,13 +1012,6 @@
old_fs = ad_read (devc, 8);
- if (devc->model != MD_4232)
- if (fs == old_fs) /* No change */
- {
- restore_flags (flags);
- devc->xfer_count = 0;
- return 0;
- }
ad_enter_MCE (devc); /* Enables changes to the format select reg */
@@ -963,9 +1025,12 @@
/*
* Write to I8 starts resynchronization. Wait until it completes.
*/
- timeout = 10000;
- while (timeout > 0 && inb (devc->base) == 0x80)
- timeout--;
+ timeout = 0;
+ while (timeout < 100 && inb (devc->base) != 0x80)
+ timeout++;
+ timeout = 0;
+ while (timeout < 10000 && inb (devc->base) == 0x80)
+ timeout++;
/*
* If mode >= 2 (CS4231), set I28 also. It's the capture format register.
@@ -975,12 +1040,15 @@
ad_write (devc, 28, fs);
/*
- * Write to I28 starts resynchronization. Wait until it completes.
+ * Write to I28 starts resynchronization. Wait until it completes.
*/
- timeout = 10000;
- while (timeout > 0 && inb (devc->base) == 0x80)
- timeout--;
-
+ timeout = 0;
+ while (timeout < 100 && inb (devc->base) != 0x80)
+ timeout++;
+
+ timeout = 0;
+ while (timeout < 10000 && inb (devc->base) == 0x80)
+ timeout++;
}
if (devc->model == MD_4232)
@@ -1020,6 +1088,7 @@
if (bits & 0x02)
ad1848_halt_input (dev);
+ devc->audio_mode = 0;
}
static void
@@ -1028,31 +1097,31 @@
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
unsigned long flags;
+ if (!(ad_read (devc, 9) & 0x02))
+ return; /* Capture not enabled */
+
save_flags (flags);
cli ();
ad_mute (devc);
- if (devc->model == MD_4232) /* Use applied black magic */
- {
- int tmout;
+ {
+ int tmout;
- disable_dma (audio_devs[dev]->dmachan1);
+ disable_dma (audio_devs[dev]->dmachan1);
- for (tmout = 0; tmout < 100000; tmout++)
- if (ad_read (devc, 11) & 0x10)
- break;
- ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */
+ for (tmout = 0; tmout < 100000; tmout++)
+ if (ad_read (devc, 11) & 0x10)
+ break;
+ ad_write (devc, 9, ad_read (devc, 9) & ~0x02); /* Stop capture */
- enable_dma (audio_devs[dev]->dmachan1);
- restore_flags (flags);
- return;
- }
- ad_write (devc, 9, ad_read (devc, 9) & ~0x02); /* Stop capture */
+ enable_dma (audio_devs[dev]->dmachan1);
+ devc->audio_mode &= ~PCM_ENABLE_INPUT;
+ }
- outb (0, io_Status (devc)); /* Clear interrupt status */
- outb (0, io_Status (devc)); /* Clear interrupt status */
+ outb ((0), io_Status (devc)); /* Clear interrupt status */
+ outb ((0), io_Status (devc)); /* Clear interrupt status */
devc->audio_mode &= ~PCM_ENABLE_INPUT;
@@ -1065,30 +1134,30 @@
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
unsigned long flags;
+ if (!(ad_read (devc, 9) & 0x01))
+ return; /* Playback not enabled */
+
save_flags (flags);
cli ();
ad_mute (devc);
- if (devc->model == MD_4232) /* Use applied black magic */
- {
- int tmout;
+ {
+ int tmout;
- disable_dma (audio_devs[dev]->dmachan1);
+ disable_dma (audio_devs[dev]->dmachan1);
- for (tmout = 0; tmout < 100000; tmout++)
- if (ad_read (devc, 11) & 0x10)
- break;
- ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */
+ for (tmout = 0; tmout < 100000; tmout++)
+ if (ad_read (devc, 11) & 0x10)
+ break;
+ ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */
- enable_dma (audio_devs[dev]->dmachan1);
- restore_flags (flags);
- return;
- }
- ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */
+ enable_dma (audio_devs[dev]->dmachan1);
+ devc->audio_mode &= ~PCM_ENABLE_OUTPUT;
+ }
- outb (0, io_Status (devc)); /* Clear interrupt status */
- outb (0, io_Status (devc)); /* Clear interrupt status */
+ outb ((0), io_Status (devc)); /* Clear interrupt status */
+ outb ((0), io_Status (devc)); /* Clear interrupt status */
devc->audio_mode &= ~PCM_ENABLE_OUTPUT;
@@ -1112,20 +1181,20 @@
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)
+void
+ad1848_init_hw (ad1848_info * devc)
{
+ int i;
+
/*
* Initial values for the indirect registers of CS4248/AD1848.
*/
@@ -1139,6 +1208,64 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+
+ 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]);
+
+ }
+
+ if (devc->model > MD_1848)
+ {
+ if (devc->audio_flags & DMA_DUPLEX)
+ ad_write (devc, 9, ad_read (devc, 9) & ~0x04); /* Dual DMA mode */
+ else
+ ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */
+
+ 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 specific initialization */
+ ad_write (devc, 12, 0x6c); /* Select codec mode 3 */
+ ad_write (devc, 17, 0xc2); /* Alternate feature enable */
+ }
+ }
+ else
+ {
+ devc->audio_flags &= ~DMA_DUPLEX;
+ ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */
+ }
+
+ outb ((0), io_Status (devc)); /* Clear pending interrupts */
+
+ /*
+ * Toggle the MCE bit. It completes the initialization phase.
+ */
+
+ ad_enter_MCE (devc); /* In case the bit was off */
+ ad_leave_MCE (devc);
+
+ ad1848_mixer_reset (devc);
+}
+
+int
+ad1848_detect (int io_base, int *ad_flags, int *osp)
+{
+
unsigned char tmp;
ad1848_info *devc = &dev_info[nr_ad1848_devs];
unsigned char tmp1 = 0xff, tmp2 = 0xff;
@@ -1153,8 +1280,10 @@
if (ad_flags)
{
if (*ad_flags == 0x12345678)
- interwave = 1;
- *ad_flags = 0;
+ {
+ interwave = 1;
+ *ad_flags = 0;
+ }
}
if (nr_ad1848_devs >= MAX_AUDIO_DEV)
@@ -1176,7 +1305,7 @@
devc->opened = 0;
devc->chip_name = "AD1848";
devc->model = MD_1848; /* AD1848 or CS4248 */
- devc->osp = osp;
+ devc->levels = NULL;
devc->debug_flag = 0;
/*
@@ -1190,6 +1319,20 @@
*/
DDB (printk ("ad1848_detect() - step A\n"));
+
+/*
+ * Wait for the device to stop initialization
+ */
+ /* outb(( 0x0b), devc->base); */
+
+ for (i = 0; i < 10000000; i++)
+ {
+ unsigned char x = inb (devc->base);
+
+ if (x == 0xff || !(x & 0x80))
+ break;
+ }
+
if ((inb (devc->base) & 0x80) != 0x00) /* Not a AD1848 */
{
DDB (printk ("ad1848 detect error - step A (%02x)\n",
@@ -1284,7 +1427,14 @@
*/
DDB (printk ("ad1848_detect() - step G\n"));
- ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */
+
+ if (ad_flags && *ad_flags == 400)
+ *ad_flags = 0;
+ else
+ ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */
+
+ if (ad_flags)
+ *ad_flags = 0;
tmp1 = ad_read (devc, 12);
if (tmp1 & 0x80)
@@ -1419,22 +1569,6 @@
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;
}
@@ -1454,7 +1588,6 @@
ad1848_info *devc = &dev_info[nr_ad1848_devs];
- int audio_flags = DMA_AUTOMODE;
request_region (devc->base, 4, devc->chip_name);
@@ -1462,37 +1595,9 @@
devc->irq = (irq > 0) ? irq : 0;
devc->opened = 0;
devc->timer_ticks = 0;
- devc->osp = osp;
-
- 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 */
- audio_flags &= ~DMA_DUPLEX;
- }
- else
- {
- ad_write (devc, 9, ad_read (devc, 9) & ~0x04); /* Dual DMA mode */
- audio_flags |= DMA_DUPLEX;
- }
-
- 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 specific initialization */
- ad_write (devc, 12, 0x6c); /* Select codec mode 3 */
- ad_write (devc, 17, 0xc2); /* Alternate feature enable */
- }
- }
- else
- {
- audio_flags &= ~DMA_DUPLEX;
- ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */
- }
-
- outb (0, io_Status (devc)); /* Clear pending interrupts */
+ devc->dma1 = dma_playback;
+ devc->dma2 = dma_capture;
+ devc->audio_flags = DMA_AUTOMODE;
if (name != NULL && name[0] != 0)
sprintf (dev_name,
@@ -1504,14 +1609,22 @@
conf_printf2 (dev_name,
devc->base, devc->irq, dma_playback, dma_capture);
- if (devc->model == MD_1848)
- audio_flags |= DMA_HARDSTOP;
+ if (devc->model == MD_1848 || devc->model == MD_C930)
+ devc->audio_flags |= DMA_HARDSTOP;
+
+ if (devc->model > MD_1848)
+ {
+ if (devc->dma1 == devc->dma2 || devc->dma2 == -1 || devc->dma1 == -1)
+ devc->audio_flags &= ~DMA_DUPLEX;
+ else
+ devc->audio_flags |= DMA_DUPLEX;
+ }
if ((my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION,
dev_name,
&ad1848_audio_driver,
sizeof (struct audio_driver),
- audio_flags,
+ devc->audio_flags,
ad_format_mask[devc->model],
devc,
dma_playback,
@@ -1520,17 +1633,21 @@
return;
}
+ nr_ad1848_devs++;
+
+ ad1848_init_hw (devc);
+
if (irq > 0)
{
irq2dev[irq] = devc->dev_no = my_dev;
if (snd_set_irq_handler (devc->irq, ad1848_interrupt,
"SoundPort",
- devc->osp) < 0)
+ NULL) < 0)
{
printk ("ad1848: IRQ in use\n");
}
- if (devc->model != MD_1848)
+ if (devc->model != MD_1848 && devc->model != MD_C930)
{
int x;
unsigned char tmp = ad_read (devc, 16);
@@ -1547,17 +1664,20 @@
if (devc->timer_ticks == 0)
printk ("ad1848: Interrupt test failed (IRQ%d)\n", devc->irq);
else
- devc->irq_ok = 1;
+ {
+ DDB (printk ("Interrupt test OK\n"));
+ devc->irq_ok = 1;
+ }
}
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->model != MD_1848 && devc->model != MD_1845 && devc->irq_ok)
+ if (devc->model != MD_1848 &&
+ devc->model != MD_C930 && devc->irq_ok)
ad1848_tmr_install (my_dev);
#endif
@@ -1571,14 +1691,6 @@
printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture);
}
- /*
- * Toggle the MCE bit. It completes the initialization phase.
- */
-
- 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,
@@ -1590,6 +1702,59 @@
}
void
+ad1848_control (int cmd, int arg)
+{
+ ad1848_info *devc;
+
+ if (nr_ad1848_devs < 1)
+ return;
+
+ devc = &dev_info[nr_ad1848_devs - 1];
+
+ switch (cmd)
+ {
+ case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */
+ if (devc->model != MD_1845)
+ return;
+ ad_enter_MCE (devc);
+ ad_write (devc, 29, (ad_read (devc, 29) & 0x1f) | (arg << 5));
+ ad_leave_MCE (devc);
+ break;
+
+ case AD1848_MIXER_REROUTE:
+ {
+ int o = (arg >> 8) & 0xff;
+ int n = arg & 0xff;
+
+ if (n == SOUND_MIXER_NONE)
+ { /* Just hide this control */
+ ad1848_mixer_set (devc, o, 0); /* Shut up it */
+ devc->supported_devices &= ~(1 << o);
+ devc->supported_rec_devices &= ~(1 << o);
+ return;
+ }
+
+ /* Make the mixer control identified by o to appear as n */
+
+ if (o < 0 || o > SOUND_MIXER_NRDEVICES)
+ return;
+ if (n < 0 || n > SOUND_MIXER_NRDEVICES)
+ return;
+ if (!(devc->supported_devices & (1 << o)))
+ return; /* Not supported */
+
+ devc->mixer_reroute[n] = o; /* Rename the control */
+ devc->supported_devices &= ~(1 << o);
+ devc->supported_devices |= (1 << n);
+ if (devc->supported_rec_devices & (1 << o))
+ devc->supported_rec_devices |= (1 << n);
+ devc->supported_rec_devices &= ~(1 << o);
+ }
+ break;
+ }
+}
+
+void
ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int share_dma)
{
int i, dev = 0;
@@ -1629,6 +1794,7 @@
ad1848_info *devc;
int dev;
int alt_stat = 0xff;
+ unsigned char c930_stat = 0;
if (irq < 0 || irq > 15)
{
@@ -1655,6 +1821,8 @@
else
devc = (ad1848_info *) audio_devs[dev]->devc;
+interrupt_again: /* Jump back here if int status doesn't reset */
+
status = inb (io_Status (devc));
if (status == 0x80)
@@ -1662,8 +1830,25 @@
if (status & 0x01)
{
-
- if (devc->model != MD_1848)
+ if (devc->model == MD_C930)
+ { /* 82C930 has interrupt status register in MAD16 register MC11 */
+ unsigned long flags;
+
+ save_flags (flags);
+ cli ();
+
+ alt_stat = 0;
+
+ outb ((11), 0xe0e);
+ c930_stat = inb (0xe0f);
+
+ if (c930_stat & 0x04)
+ alt_stat |= 0x10; /* Playback intr */
+ if (c930_stat & 0x08)
+ alt_stat |= 0x20; /* Playback intr */
+ restore_flags (flags);
+ }
+ else if (devc->model != MD_1848)
alt_stat = ad_read (devc, 24);
if (devc->opened && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20)
@@ -1687,10 +1872,30 @@
}
}
- if (devc->model != MD_1848)
+ if (devc->model == MD_C930)
+ { /* 82C930 has interrupt status register in MAD16 register MC11 */
+ unsigned long flags;
+
+ save_flags (flags);
+ cli ();
+
+ outb ((11), 0xe0e);
+ outb ((~c930_stat), 0xe0f);
+ restore_flags (flags);
+ }
+ else 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 */
+ outb ((0), io_Status (devc)); /* Clear interrupt status */
+
+/*
+ * Sometimes playback or capture interrupts occur while a timer interrupt
+ * is being handled. The interrupt will not be retriggered if we don't
+ * handle it now. Check if an interrupt is still pending and restart
+ * the handler in this case.
+ */
+ if (inb (io_Status (devc)) & 0x01)
+ goto interrupt_again;
}
/*
@@ -1733,7 +1938,7 @@
return 0;
}
- outb (tmp | 0x04, 0xc44); /* Select bank 1 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank 1 */
if (inb (0xc44) != 0x04)
{
DDB (printk ("init_deskpro: Invalid bank1 signature in port 0xc44\n"));
@@ -1774,9 +1979,9 @@
#ifdef DEBUGXL
/* Debug printing */
printk ("Port 0xc44 (before): ");
- outb (tmp & ~0x04, 0xc44);
+ outb ((tmp & ~0x04), 0xc44);
printk ("%02x ", inb (0xc44));
- outb (tmp | 0x04, 0xc44);
+ outb ((tmp | 0x04), 0xc44);
printk ("%02x\n", inb (0xc44));
#endif
@@ -1802,14 +2007,14 @@
hw_config->io_base));
return 0;
}
- outb (tmp & ~0x04, 0xc44); /* Write to bank=0 */
+ outb ((tmp & ~0x04), 0xc44); /* Write to bank=0 */
#ifdef DEBUGXL
/* Debug printing */
printk ("Port 0xc44 (after): ");
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc44));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
printk ("%02x\n", inb (0xc44));
#endif
@@ -1826,23 +2031,23 @@
#ifdef DEBUGXL
/* Debug printing */
printk ("Port 0xc45 (before): ");
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc45));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ 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) */
+ 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 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc45));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
printk ("%02x\n", inb (0xc45));
#endif
@@ -1857,23 +2062,23 @@
#ifdef DEBUGXL
/* Debug printing */
printk ("Port 0xc46 (before): ");
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc46));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ 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 */
+ 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 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc46));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
printk ("%02x\n", inb (0xc46));
#endif
@@ -1887,23 +2092,23 @@
#ifdef DEBUGXL
/* Debug printing */
printk ("Port 0xc47 (before): ");
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc47));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ 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 */
+ 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 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc47));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
printk ("%02x\n", inb (0xc47));
#endif
@@ -1915,7 +2120,7 @@
printk ("Port 0xc6f (before) = %02x\n", inb (0xc6f));
#endif
- outb (0x80, 0xc6f);
+ outb ((0x80), 0xc6f);
#ifdef DEBUGXL
printk ("Port 0xc6f (after) = %02x\n", inb (0xc6f));
@@ -2034,8 +2239,6 @@
int dma = hw_config->dma;
int dma2 = hw_config->dma2;
- 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 */
{
@@ -2055,9 +2258,9 @@
if (bits == -1)
return;
- outb (bits | 0x40, config_port);
+ outb ((bits | 0x40), config_port);
if ((inb (version_port) & 0x40) == 0)
- printk ("[IRQ Conflict?]");
+ printk ("[MSS: IRQ Conflict?]");
/*
* Handle the capture DMA channel
@@ -2090,7 +2293,7 @@
else
dma2 = dma;
- outb (bits | dma_bits[dma] | dma2_bit, config_port); /* Write IRQ+DMA setup */
+ 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,
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov