patch-2.2.0-pre1 linux/drivers/sound/sb_mixer.c
Next file: linux/drivers/sound/sb_mixer.h
Previous file: linux/drivers/sound/sb_common.c
Back to the patch index
Back to the overall index
- Lines: 284
- Date:
Mon Dec 28 11:06:11 1998
- Orig file:
v2.1.132/linux/drivers/sound/sb_mixer.c
- Orig date:
Fri Oct 23 22:01:22 1998
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c
@@ -13,6 +13,24 @@
*
*
* Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
+ * Rolf Fokkens : ES188x recording level support
+ */
+
+/*
+ * About ES188x support:
+ *
+ * The standard ES1688 support doesn't take care of the ES188x recording
+ * levels very well. Whenever a device is selected (recmask) for recording
+ * it's recording level is loud, and it cannot be changed.
+ *
+ * The ES188x has separate registers to control the recording levels. The
+ * ES188x specific software makes these level the same as their corresponding
+ * playback levels, unless recmask says they aren't recorded. In the latter
+ * case the recording volumes are 0.
+ *
+ * Now recording levels of inputs can be controlled, by changing the playback
+ * levels. Futhermore several devices can be recorded together (which is not
+ * possible with the ES1688.
*/
#include <linux/config.h>
@@ -78,22 +96,62 @@
sb_mixer_reset(devc);
}
-static int smw_mixer_set(sb_devc * devc, int dev, int value)
+static int common_mixer_set(sb_devc * devc, int dev, int left, int right)
{
- int left = value & 0x000000ff;
- int right = (value & 0x0000ff00) >> 8;
- int reg, val;
+ int regoffs;
+ unsigned char val;
- if (left > 100)
- left = 100;
- if (right > 100)
- right = 100;
+ regoffs = (*devc->iomap)[dev][LEFT_CHN].regno;
- if (dev > 31)
+ if (regoffs == 0)
return -EINVAL;
- if (!(devc->supported_devices & (1 << dev))) /* Not supported */
- return -EINVAL;
+ val = sb_getmixer(devc, regoffs);
+ change_bits(devc, &val, dev, LEFT_CHN, left);
+
+ devc->levels[dev] = left | (left << 8);
+
+ if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /*
+ * Change register
+ */
+ {
+ sb_setmixer(devc, regoffs, val); /*
+ * Save the old one
+ */
+ regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno;
+
+ if (regoffs == 0)
+ return left | (left << 8); /*
+ * Just left channel present
+ */
+
+ val = sb_getmixer(devc, regoffs); /*
+ * Read the new one
+ */
+ }
+ change_bits(devc, &val, dev, RIGHT_CHN, right);
+
+ sb_setmixer(devc, regoffs, val);
+
+ devc->levels[dev] = left | (right << 8);
+ return left | (right << 8);
+}
+
+/*
+ * Changing playback levels at ES188x means having to take care of recording
+ * levels of recorded inputs (devc->recmask) too!
+ */
+static int es188x_mixer_set(sb_devc * devc, int dev, int left, int right)
+{
+ if (devc->recmask & (1 << dev)) {
+ common_mixer_set(devc, dev + ES188X_MIXER_RECDIFF, left, right);
+ }
+ return common_mixer_set(devc, dev, left, right);
+}
+
+static int smw_mixer_set(sb_devc * devc, int dev, int left, int right)
+{
+ int reg, val;
switch (dev)
{
@@ -134,12 +192,6 @@
int left = value & 0x000000ff;
int right = (value & 0x0000ff00) >> 8;
- int regoffs;
- unsigned char val;
-
- if (devc->model == MDL_SMW)
- return smw_mixer_set(devc, dev, value);
-
if (left > 100)
left = 100;
if (right > 100)
@@ -153,47 +205,60 @@
*/
return -EINVAL;
- regoffs = (*devc->iomap)[dev][LEFT_CHN].regno;
-
- if (regoffs == 0)
- return -EINVAL;
-
- val = sb_getmixer(devc, regoffs);
- change_bits(devc, &val, dev, LEFT_CHN, left);
-
- devc->levels[dev] = left | (left << 8);
-
- if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /*
- * Change register
- */
- {
- sb_setmixer(devc, regoffs, val); /*
- * Save the old one
- */
- regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno;
-
- if (regoffs == 0)
- return left | (left << 8); /*
- * Just left channel present
- */
-
- val = sb_getmixer(devc, regoffs); /*
- * Read the new one
- */
+ /* Differentiate dependong on the chipsets */
+ switch (devc->model) {
+ case MDL_SMW:
+ return smw_mixer_set(devc, dev, left, right);
+ break;
+ case MDL_ESS:
+ if (devc->submodel == SUBMDL_ES188X) {
+ return es188x_mixer_set(devc, dev, left, right);
+ }
+ break;
}
- change_bits(devc, &val, dev, RIGHT_CHN, right);
- sb_setmixer(devc, regoffs, val);
-
- devc->levels[dev] = left | (right << 8);
- return left | (right << 8);
+ return common_mixer_set(devc, dev, left, right);
}
+/*
+ * set_recsrc doesn't apply to ES188x
+ */
static void set_recsrc(sb_devc * devc, int src)
{
sb_setmixer(devc, RECORD_SRC, (sb_getmixer(devc, RECORD_SRC) & ~7) | (src & 0x7));
}
+/*
+ * Changing the recmask on a ES188x means:
+ * (1) Find the differences
+ * (2) For "turned-on" inputs: make the recording level the playback level
+ * (3) For "turned-off" inputs: make the recording level zero
+ */
+static int es188x_set_recmask(sb_devc * devc, int mask)
+{
+ int i, i_mask, cur_mask, diff_mask;
+ int value, left, right;
+
+ cur_mask = devc->recmask;
+ diff_mask = (cur_mask ^ mask);
+
+ for (i = 0; i < 32; i++) {
+ i_mask = (1 << i);
+ if (diff_mask & i_mask) { /* Difference? (1) */
+ if (mask & i_mask) { /* Turn it on (2) */
+ value = devc->levels[i];
+ left = value & 0x000000ff;
+ right = (value & 0x0000ff00) >> 8;
+ } else { /* Turn it off (3) */
+ left = 0;
+ right = 0;
+ }
+ common_mixer_set(devc, i + ES188X_MIXER_RECDIFF, left, right);
+ }
+ }
+ return mask;
+}
+
static int set_recmask(sb_devc * devc, int mask)
{
int devmask, i;
@@ -207,6 +272,14 @@
case MDL_ESS:
case MDL_JAZZ:
case MDL_SMW:
+ if (devc->model == MDL_ESS &&
+ devc->submodel == SUBMDL_ES188X) {
+ /*
+ * ES188x needs a separate approach
+ */
+ devmask = es188x_set_recmask(devc, devmask);
+ break;
+ };
if (devmask != SOUND_MASK_MIC &&
devmask != SOUND_MASK_LINE &&
@@ -423,7 +496,7 @@
static void sb_mixer_reset(sb_devc * devc)
{
char name[32];
- int i;
+ int i, regval;
extern int sm_games;
sprintf(name, "SB_%d", devc->sbmixnum);
@@ -435,6 +508,24 @@
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
sb_mixer_set(devc, i, devc->levels[i]);
+
+ /*
+ * Separate actions for ES188x:
+ * Change registers 7a and 1c to make the record mixer the
+ * actual recording source.
+ * Then call set_recmask twice to do extra ES188x initializations
+ */
+ if (devc->model == MDL_ESS && devc->submodel == SUBMDL_ES188X) {
+ regval = sb_getmixer(devc, 0x7a);
+ regval = (regval & 0xe7) | 0x08;
+ sb_setmixer(devc, 0x7a, regval);
+ regval = sb_getmixer(devc, 0x1c);
+ regval = (regval & 0xf8) | 0x07;
+ sb_setmixer(devc, 0x1c, regval);
+
+ set_recmask(devc, ES188X_RECORDING_DEVICES);
+ set_recmask(devc, 0);
+ }
set_recmask(devc, SOUND_MASK_MIC);
}
@@ -464,9 +555,26 @@
case MDL_ESS:
devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
- devc->supported_devices = ES688_MIXER_DEVICES;
- devc->supported_rec_devices = ES688_RECORDING_DEVICES;
- devc->iomap = &es688_mix;
+
+ /*
+ * Take care of ES188x specifics...
+ */
+ switch (devc->submodel) {
+ case SUBMDL_ES188X:
+ devc->supported_devices
+ = ES188X_MIXER_DEVICES;
+ devc->supported_rec_devices
+ = ES188X_RECORDING_DEVICES;
+ devc->iomap = &es188x_mix;
+ break;
+ default:
+ devc->supported_devices
+ = ES688_MIXER_DEVICES;
+ devc->supported_rec_devices
+ = ES688_RECORDING_DEVICES;
+ devc->iomap = &es688_mix;
+ }
+
break;
case MDL_SMW:
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov