patch-2.1.118 linux/drivers/sound/lowlevel/aci.c
Next file: linux/drivers/sound/lowlevel/aedsp16.c
Previous file: linux/drivers/sound/lowlevel/README.aedsp16
Back to the patch index
Back to the overall index
- Lines: 246
- Date:
Sun Aug 23 13:32:25 1998
- Orig file:
v2.1.117/linux/drivers/sound/lowlevel/aci.c
- Orig date:
Thu Aug 20 17:05:16 1998
diff -u --recursive --new-file v2.1.117/linux/drivers/sound/lowlevel/aci.c linux/drivers/sound/lowlevel/aci.c
@@ -4,17 +4,21 @@
* ACI is a protocol used to communicate with the microcontroller on
* some sound cards produced by miro, e.g. the miroSOUND PCM12 and
* PCM20. The ACI has been developed for miro by Norberto Pellicci
- * <pellicci@ix.netcom.com>. Special thanks to both him and miro for
+ * <pellicci@home.com>. Special thanks to both him and miro for
* providing the ACI specification.
*
* The main function of the ACI is to control the mixer and to get a
* product identification. On the PCM20, ACI also controls the radio
- * tuner on this card, however this is not yet supported in this
- * software.
+ * tuner on this card, this is supported in the Video for Linux
+ * radio-miropcm20 driver.
*
* This Voxware ACI driver currently only supports the ACI functions
- * on the miroSOUND PCM12 card. Support for miro sound cards with
- * additional ACI functions can easily be added later.
+ * on the miroSOUND PCM12 and PCM20 card. Support for miro sound cards
+ * with additional ACI functions can easily be added later.
+ *
+ * / NOTE / When compiling as a module, make sure to load the module
+ * after loading the mad16 module. The initialisation code expects the
+ * MAD16 default mixer to be already available.
*
* / NOTE / When compiling as a module, make sure to load the module
* after loading the mad16 module. The initialisation code expects the
@@ -31,8 +35,9 @@
* 1996-05-28 Markus Kuhn
* Initialize CS4231A mixer, make ACI first mixer,
* use new private mixer API for solo mode.
- * 1998-08-04 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
- * Small modification to complete modularisation.
+ * 1998-08-18 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
+ * Small modification to export ACI functions and
+ * complete modularisation.
*/
/*
@@ -84,7 +89,7 @@
#ifdef MODULE /* Whether the aci mixer is to be reset. */
int aci_reset = 0; /* Default: don't reset if the driver is a */
MODULE_PARM(aci_reset,"i");
-#else /* module; use "insmod sound.o aci_reset=1" */
+#else /* module; use "insmod aci.o aci_reset=1" */
int aci_reset = 1; /* to override. */
#endif
@@ -150,12 +155,12 @@
* If a problem occurred, they return -1.
*/
-static int implied_cmd(unsigned char opcode)
+int aci_implied_cmd(unsigned char opcode)
{
unsigned long flags;
#ifdef DEBUG
- printk("ACI: implied_cmd(0x%02x)\n", opcode);
+ printk("ACI: aci_implied_cmd(0x%02x)\n", opcode);
#endif
save_flags(flags);
@@ -172,13 +177,13 @@
}
-static int write_cmd(unsigned char opcode, unsigned char parameter)
+int aci_write_cmd(unsigned char opcode, unsigned char parameter)
{
unsigned long flags;
int status;
#ifdef DEBUG
- printk("ACI: write_cmd(0x%02x, 0x%02x)\n", opcode, parameter);
+ printk("ACI: aci_write_cmd(0x%02x, 0x%02x)\n", opcode, parameter);
#endif
save_flags(flags);
@@ -209,8 +214,53 @@
return 0;
}
+/*
+ * This write command send 2 parameters instead of one.
+ * Only used in PCM20 radio frequency tuning control
+ */
+
+int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2)
+{
+ unsigned long flags;
+ int status;
+
+#ifdef DEBUG
+ printk("ACI: aci_write_cmd_d(0x%02x, 0x%02x)\n", opcode, parameter, parameter2);
+#endif
+
+ save_flags(flags);
+ cli();
+
+ if (read_general_status() < 0 || busy_wait()) {
+ restore_flags(flags);
+ return -1;
+ }
+ outb_p(opcode, COMMAND_REGISTER);
+ if (busy_wait()) { restore_flags(flags); return -1; }
+ outb_p(parameter, COMMAND_REGISTER);
+ if (busy_wait()) { restore_flags(flags); return -1; }
+ outb_p(parameter2, COMMAND_REGISTER);
+
+ if ((status = read_general_status()) < 0) {
+ restore_flags(flags);
+ return -1;
+ }
+ /* polarity of the INVALID flag depends on ACI version */
+ if ((aci_version < 0xb0 && (status & 0x40) != 0) ||
+ (aci_version >= 0xb0 && (status & 0x40) == 0)) {
+ restore_flags(flags);
+#if 0 /* Frequency tuning works, but the INVALID flag is set ??? */
+ printk("ACI: invalid write (double) command 0x%02x, 0x%02x, 0x%02x.\n",
+ opcode, parameter, parameter2);
+#endif
+ return -1;
+ }
+
+ restore_flags(flags);
+ return 0;
+}
-static int read_cmd(unsigned char opcode, int length, unsigned char *parameter)
+int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter)
{
unsigned long flags;
int i = 0;
@@ -226,10 +276,10 @@
parameter[i++] = inb_p(STATUS_REGISTER);
#ifdef DEBUG
if (i == 1)
- printk("ACI: read_cmd(0x%02x, %d) = 0x%02x\n", opcode, length,
+ printk("ACI: aci_read_cmd(0x%02x, %d) = 0x%02x\n", opcode, length,
parameter[i-1]);
else
- printk("ACI: read_cmd cont.: 0x%02x\n", parameter[i-1]);
+ printk("ACI: aci_read_cmd cont.: 0x%02x\n", parameter[i-1]);
#endif
}
@@ -238,7 +288,7 @@
}
-static int indexed_cmd(unsigned char opcode, unsigned char index,
+int aci_indexed_cmd(unsigned char opcode, unsigned char index,
unsigned char *parameter)
{
unsigned long flags;
@@ -256,7 +306,7 @@
if (busy_wait()) { restore_flags(flags); return -1; }
*parameter = inb_p(STATUS_REGISTER);
#ifdef DEBUG
- printk("ACI: indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index,
+ printk("ACI: aci_indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index,
*parameter);
#endif
@@ -292,10 +342,10 @@
unsigned char buf;
/* left channel */
- if (indexed_cmd(0xf0, left_index, &buf)) return -EIO;
+ if (aci_indexed_cmd(0xf0, left_index, &buf)) return -EIO;
vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
/* right channel */
- if (indexed_cmd(0xf0, right_index, &buf)) return -EIO;
+ if (aci_indexed_cmd(0xf0, right_index, &buf)) return -EIO;
vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
return (*(int *) arg = vol);
@@ -311,13 +361,13 @@
vol = *(int *)arg & 0xff;
if (vol > 100) vol = 100;
vol = SCALE(100, 0x20, vol);
- if (write_cmd(left_index, 0x20 - vol)) return -EIO;
+ if (aci_write_cmd(left_index, 0x20 - vol)) return -EIO;
ret = SCALE(0x20, 100, vol);
/* right channel */
vol = (*(int *)arg >> 8) & 0xff;
if (vol > 100) vol = 100;
vol = SCALE(100, 0x20, vol);
- if (write_cmd(right_index, 0x20 - vol)) return -EIO;
+ if (aci_write_cmd(right_index, 0x20 - vol)) return -EIO;
ret |= SCALE(0x20, 100, vol) << 8;
return (*(int *) arg = ret);
@@ -334,7 +384,7 @@
if (cmd == SOUND_MIXER_PRIVATE1) {
if (*(int *) arg >= 0) {
aci_solo = !!*(int *) arg;
- if (write_cmd(0xd2, aci_solo)) return -EIO;
+ if (aci_write_cmd(0xd2, aci_solo)) return -EIO;
} else if (aci_version >= 0xb0) {
if ((status = read_general_status()) < 0) return -EIO;
return (*(int *) arg = (status & 0x20) == 0);
@@ -366,7 +416,7 @@
vol = *(int *) arg & 0xff;
if (vol > 100) vol = 100;
vol = SCALE(100, 3, vol);
- if (write_cmd(0x03, vol)) return -EIO;
+ if (aci_write_cmd(0x03, vol)) return -EIO;
vol = SCALE(3, 100, vol);
return (*(int *) arg = vol | (vol << 8));
case SOUND_MIXER_RECSRC:
@@ -421,7 +471,7 @@
case SOUND_MIXER_LINE2: /* AUX2 */
return getvolume(arg, 0x13, 0x12);
case SOUND_MIXER_IGAIN: /* MIC pre-amp */
- if (indexed_cmd(0xf0, 0x21, &buf)) return -EIO;
+ if (aci_indexed_cmd(0xf0, 0x21, &buf)) return -EIO;
vol = SCALE(3, 100, buf <= 3 ? buf : 3);
vol |= vol << 8;
return (*(int *) arg = vol);
@@ -485,13 +535,13 @@
return 0;
}
- if (read_cmd(0xf2, 2, aci_idcode)) {
+ if (aci_read_cmd(0xf2, 2, aci_idcode)) {
#ifdef DEBUG
printk("ACI: Failed to read idcode.\n");
#endif
return 0;
}
- if (read_cmd(0xf1, 1, &aci_version)) {
+ if (aci_read_cmd(0xf1, 1, &aci_version)) {
#ifdef DEBUG
printk("ACI: Failed to read version.\n");
#endif
@@ -523,7 +573,7 @@
if (aci_reset) {
/* initialize ACI mixer */
- implied_cmd(0xff);
+ aci_implied_cmd(0xff);
aci_solo = 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov