patch-2.1.41 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: 486
- Date:
Sun May 11 02:58:54 1997
- Orig file:
v2.1.40/linux/drivers/sound/ad1848.c
- Orig date:
Tue Mar 4 10:25:24 1997
diff -u --recursive --new-file v2.1.40/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
@@ -71,6 +71,7 @@
int irq_ok;
mixer_ents *mix_devices;
int mixer_output_port;
+ int c930_password_port;
}
ad1848_info;
@@ -107,7 +108,7 @@
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];
+static ad1848_info adev_info[MAX_AUDIO_DEV];
#define io_Index_Addr(d) ((d)->base)
#define io_Indexed_Data(d) ((d)->base+1)
@@ -200,7 +201,6 @@
if (ad_read (devc, 11) & 0x20)
if (devc->model != MD_1845)
printk ("ad1848: Auto calibration timed out(3).\n");
- ad_write (devc, 9, ad_read (devc, 9) & ~0x18); /* Disable autocalibration */
}
static void
@@ -215,7 +215,6 @@
for (i = 6; i < 8; i++)
{
prev = devc->saved_regs[i] = ad_read (devc, i);
- ad_write (devc, i, prev | 0x80);
}
}
@@ -223,21 +222,6 @@
static void
ad_unmute (ad1848_info * devc)
{
- int i, dummy;
-
-/*
- * Let's have some delay
- */
- for (i = 0; i < 1000; i++)
- dummy = inb (devc->base);
-
- /*
- * Restore back old volume registers (unmute)
- */
- for (i = 6; i < 8; i++)
- {
- ad_write (devc, i, devc->saved_regs[i] & ~0x80);
- }
}
static void
@@ -296,7 +280,6 @@
restore_flags (flags);
}
-
static int
ad1848_set_recmask (ad1848_info * devc, int mask)
{
@@ -381,16 +364,32 @@
{
unsigned char mask;
int shift;
+ int mute;
+ int mutemask;
+ int set_mute_bit;
+
+ set_mute_bit = (newval == 0);
if (devc->mix_devices[dev][chn].polarity == 1) /* Reverse */
newval = 100 - newval;
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 */
- *regval |= (newval & mask) << shift; /* Set new value */
+ if (devc->mix_devices[dev][chn].mutepos == 8)
+ { /* if there is no mute bit */
+ mute = 0; /* No mute bit; do nothing special */
+ mutemask = ~0; /* No mute bit; do nothing special */
+ }
+ else
+ {
+ mute = (set_mute_bit << devc->mix_devices[dev][chn].mutepos);
+ mutemask = ~(1 << devc->mix_devices[dev][chn].mutepos);
+ }
+
+ newval = (int) ((newval * mask) + 50) / 100; /* Scale it */
+ *regval &= (~(mask << shift)) & (mutemask); /* Clear bits */
+ *regval |= ((newval & mask) << shift) | mute; /* Set new value */
}
static int
@@ -969,13 +968,12 @@
save_flags (flags);
cli ();
- if (devc->model == MD_1848 || !devc->dual_dma) /* Single DMA channel mode */
+ if (devc->model == MD_1848)
{
ad_write (devc, 15, (unsigned char) (cnt & 0xff));
ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
}
else
- /* Dual DMA channel mode */
{
ad_write (devc, 31, (unsigned char) (cnt & 0xff));
ad_write (devc, 30, (unsigned char) ((cnt >> 8) & 0xff));
@@ -1007,6 +1005,8 @@
if (portc->channels > 1)
fs |= 0x10;
+ ad_enter_MCE (devc); /* Enables changes to the format select reg */
+
if (devc->model == MD_1845) /* Use alternate speed select registers */
{
fs &= 0xf0; /* Mask off the rate select bits */
@@ -1017,14 +1017,15 @@
old_fs = ad_read (devc, 8);
- ad_enter_MCE (devc); /* Enables changes to the format select reg */
-
if (devc->model == MD_4232)
{
tmp = ad_read (devc, 16);
ad_write (devc, 16, tmp | 0x30);
}
+ if (devc->model == MD_IWAVE)
+ ad_write (devc, 17, 0xc2); /* Disable variable frequency select */
+
ad_write (devc, 8, fs);
/*
* Write to I8 starts resynchronization. Wait until it completes.
@@ -1075,6 +1076,8 @@
if (portc->channels > 1)
fs |= 0x10;
+ ad_enter_MCE (devc); /* Enables changes to the format select reg */
+
if (devc->model == MD_1845) /* Use alternate speed select registers */
{
fs &= 0xf0; /* Mask off the rate select bits */
@@ -1083,32 +1086,21 @@
ad_write (devc, 23, portc->speed & 0xff); /* Speed LSB */
}
- old_fs = ad_read (devc, 8);
-
- ad_enter_MCE (devc); /* Enables changes to the format select reg */
-
if (devc->model == MD_4232)
{
tmp = ad_read (devc, 16);
ad_write (devc, 16, tmp | 0x30);
}
- ad_write (devc, 8, fs);
- /*
- * Write to I8 starts resynchronization. Wait until it completes.
- */
- timeout = 0;
- while (timeout < 100 && inb (devc->base) != 0x80)
- timeout++;
- timeout = 0;
- while (timeout < 10000 && inb (devc->base) == 0x80)
- timeout++;
+ if (devc->model == MD_IWAVE)
+ ad_write (devc, 17, 0xc2); /* Disable variable frequency select */
/*
- * If mode >= 2 (CS4231), set I28 also. It's the capture format register.
+ * If mode >= 2 (CS4231), set I28. It's the capture format register.
*/
if (devc->model != MD_1848)
{
+ old_fs = ad_read (devc, 28);
ad_write (devc, 28, fs);
/*
@@ -1121,6 +1113,43 @@
timeout = 0;
while (timeout < 10000 && inb (devc->base) == 0x80)
timeout++;
+
+ if (devc->model != MD_1848 && devc->model != MD_1845)
+ {
+ /*
+ * CS4231 compatible devices don't have separate sampling rate selection
+ * register for recording an playback. The I8 register is shared so we have to
+ * set the speed encoding bits of it too.
+ */
+ unsigned char tmp = portc->speed_bits | (ad_read (devc, 8) & 0xf0);
+
+ ad_write (devc, 8, tmp);
+ /*
+ * Write to I8 starts resynchronization. Wait until it completes.
+ */
+ timeout = 0;
+ while (timeout < 100 && inb (devc->base) != 0x80)
+ timeout++;
+
+ timeout = 0;
+ while (timeout < 10000 && inb (devc->base) == 0x80)
+ timeout++;
+ }
+ }
+ else
+ { /* For AD1848 set I8. */
+
+ old_fs = ad_read (devc, 8);
+ ad_write (devc, 8, fs);
+ /*
+ * Write to I8 starts resynchronization. Wait until it completes.
+ */
+ 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)
@@ -1176,14 +1205,14 @@
{
int tmout;
- disable_dma (audio_devs[dev]->dmap_out->dma);
+ disable_dma (audio_devs[dev]->dmap_in->dma);
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]->dmap_out->dma);
+ enable_dma (audio_devs[dev]->dmap_in->dma);
devc->audio_mode &= ~PCM_ENABLE_INPUT;
}
@@ -1306,6 +1335,9 @@
for (i = 16; i < 32; i++)
ad_write (devc, i, init_values[i]);
+ if (devc->model == MD_IWAVE)
+ ad_write (devc, 16, 0x30); /* Playback and capture counters enabled */
+
}
if (devc->model > MD_1848)
@@ -1321,6 +1353,7 @@
if (devc->model == MD_IWAVE)
{ /* Some magic Interwave specific initialization */
ad_write (devc, 12, 0x6c); /* Select codec mode 3 */
+ ad_write (devc, 16, 0x30); /* Playback and capture counters enabled */
ad_write (devc, 17, 0xc2); /* Alternate feature enable */
}
}
@@ -1347,11 +1380,12 @@
{
unsigned char tmp;
- ad1848_info *devc = &dev_info[nr_ad1848_devs];
+ ad1848_info *devc = &adev_info[nr_ad1848_devs];
unsigned char tmp1 = 0xff, tmp2 = 0xff;
int optiC930 = 0; /* OPTi 82C930 flag */
int interwave = 0;
int ad1847_flag = 0;
+ int cs4248_flag = 0;
int i;
@@ -1364,16 +1398,22 @@
interwave = 1;
*ad_flags = 0;
}
+
+ if (*ad_flags == 0x12345677)
+ {
+ cs4248_flag = 1;
+ *ad_flags = 0;
+ }
}
if (nr_ad1848_devs >= MAX_AUDIO_DEV)
{
- DDB (printk ("ad1848 detect error - step 0\n"));
+ printk ("ad1848 - Too many audio devices\n");
return 0;
}
if (check_region (io_base, 4))
{
- printk ("\n\nad1848.c: Port %x not free.\n\n", io_base);
+ printk ("ad1848.c: Port %x not free.\n", io_base);
return 0;
}
@@ -1386,6 +1426,7 @@
devc->chip_name = "AD1848";
devc->model = MD_1848; /* AD1848 or CS4248 */
devc->levels = NULL;
+ devc->c930_password_port = 0;
devc->debug_flag = 0;
/*
@@ -1413,6 +1454,9 @@
DDB (printk ("ad1848_detect() - step A\n"));
+ if (inb (devc->base) == 0x80) /* Not ready. Let's wait */
+ ad_leave_MCE (devc);
+
if ((inb (devc->base) & 0x80) != 0x00) /* Not a AD1848 */
{
DDB (printk ("ad1848 detect error - step A (%02x)\n",
@@ -1420,11 +1464,6 @@
return 0;
}
- DDB (printk ("ad1848: regs: "));
- for (i = 0; i < 32; i++)
- DDB (printk ("%02x ", ad_read (devc, i)));
- DDB (printk ("\n"));
-
/*
* Test if it's possible to change contents of the indirect registers.
* Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only
@@ -1480,6 +1519,8 @@
/*
* The original AD1848/CS4248 has just 15 indirect registers. This means
* that I0 and I16 should return the same value (etc.).
+ * However this doesn't work with CS4248. Actually it seems to be impossible
+ * to detect if the chip is a CS4231 or CS4248.
* Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails
* with CS4231.
*/
@@ -1513,6 +1554,7 @@
else
ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */
+
if (ad_flags)
*ad_flags = 0;
@@ -1630,6 +1672,15 @@
devc->chip_name = "AD1845";
devc->model = MD_1845;
}
+ else if (cs4248_flag)
+ {
+ if (ad_flags)
+ *ad_flags |= AD_F_CS4248;
+
+ devc->chip_name = "CS4248";
+ devc->model = MD_1848;
+ ad_write (devc, 12, ad_read (devc, 12) & ~0x40); /* Mode2 off */
+ }
ad_write (devc, 23, tmp); /* Restore */
}
@@ -1686,7 +1737,7 @@
int my_dev;
char dev_name[100];
- ad1848_info *devc = &dev_info[nr_ad1848_devs];
+ ad1848_info *devc = &adev_info[nr_ad1848_devs];
ad1848_port_info *portc = NULL;
@@ -1749,7 +1800,7 @@
if (irq > 0)
{
irq2dev[irq] = devc->dev_no = my_dev;
- if (snd_set_irq_handler (devc->irq, ad1848_interrupt,
+ if (snd_set_irq_handler (devc->irq, adintr,
"SoundPort",
NULL) < 0)
{
@@ -1819,7 +1870,7 @@
if (nr_ad1848_devs < 1)
return;
- devc = &dev_info[nr_ad1848_devs - 1];
+ devc = &adev_info[nr_ad1848_devs - 1];
switch (cmd)
{
@@ -1871,9 +1922,9 @@
ad1848_info *devc = NULL;
for (i = 0; devc == NULL && i < nr_ad1848_devs; i++)
- if (dev_info[i].base == io_base)
+ if (adev_info[i].base == io_base)
{
- devc = &dev_info[i];
+ devc = &adev_info[i];
dev = devc->dev_no;
}
@@ -1898,7 +1949,7 @@
}
void
-ad1848_interrupt (int irq, void *dev_id, struct pt_regs *dummy)
+adintr (int irq, void *dev_id, struct pt_regs *dummy)
{
unsigned char status;
ad1848_info *devc;
@@ -1937,7 +1988,7 @@
status = inb (io_Status (devc));
if (status == 0x80)
- printk ("ad1848_interrupt: Why?\n");
+ printk ("adintr: Why?\n");
if (devc->model == MD_1848)
outb ((0), io_Status (devc)); /* Clear interrupt status */
@@ -1952,6 +2003,8 @@
alt_stat = 0;
+ if (devc->c930_password_port)
+ outb ((0xe4), devc->c930_password_port); /* Password */
outb ((11), 0xe0e);
c930_stat = inb (0xe0f);
@@ -1972,6 +2025,8 @@
save_flags (flags);
cli ();
+ if (devc->c930_password_port)
+ outb ((0xe4), devc->c930_password_port); /* Password */
outb ((11), 0xe0e);
outb ((~c930_stat), 0xe0f);
restore_flags (flags);
@@ -2319,7 +2374,6 @@
-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
};
char bits, dma2_bit = 0;
- int ad_flags = 0;
static char dma_bits[4] =
{
@@ -2347,7 +2401,10 @@
bits = interrupt_bits[hw_config->irq];
if (bits == -1)
- return;
+ {
+ printk ("MSS: Bad IRQ %d\n", hw_config->irq);
+ return;
+ }
outb ((bits | 0x40), config_port);
if ((inb (version_port) & 0x40) == 0)
@@ -2357,7 +2414,7 @@
* Handle the capture DMA channel
*/
- if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma)
+ if (dma2 != -1 && dma2 != dma)
{
if (!((dma == 0 && dma2 == 1) ||
(dma == 1 && dma2 == 0) ||
@@ -2382,7 +2439,12 @@
}
}
else
- dma2 = dma;
+ {
+ dma2 = dma;
+ }
+
+ hw_config->dma = dma;
+ hw_config->dma2 = dma2;
outb ((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov