patch-2.4.0-test7 linux/drivers/sound/emu10k1/mixer.c
Next file: linux/drivers/sound/emu10k1/osutils.c
Previous file: linux/drivers/sound/emu10k1/midi.c
Back to the patch index
Back to the overall index
- Lines: 782
- Date:
Mon Aug 14 08:32:48 2000
- Orig file:
v2.4.0-test6/linux/drivers/sound/emu10k1/mixer.c
- Orig date:
Fri Jun 23 21:55:10 2000
diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/mixer.c linux/drivers/sound/emu10k1/mixer.c
@@ -1,4 +1,3 @@
-
/*
**********************************************************************
* mixer.c - /dev/mixer interface for emu10k1 driver
@@ -36,9 +35,13 @@
#define __NO_VERSION__ /* Kernel version only defined once */
#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/bitops.h>
#include <asm/uaccess.h>
#include "hwaccess.h"
+#include "8010.h"
+#include "recmgr.h"
#define AC97_PESSIMISTIC
#undef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -49,31 +52,13 @@
#define vol_to_sw_5(hwvol) (((31 - (hwvol)) * 100) / 31)
#define vol_to_sw_4(hwvol) (((15 - (hwvol)) * 100) / 15)
+#define DM_MUTE 0x80000000
+
#ifdef PRIVATE_PCM_VOLUME
struct sblive_pcm_volume_rec sblive_pcm_volume[MAX_PCM_CHANNELS];
+u16 pcm_last_mixer = 0x6464;
#endif
-/* --------------------------------------------------------------------- */
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#ifdef hweight32
-#undef hweight32
-#endif
-
-extern __inline__ unsigned int hweight32(unsigned int w)
-{
- unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
-
- res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
- res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
- res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
- return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
-}
-
/* Mapping arrays */
static const unsigned int recsrc[] = {
SOUND_MASK_MIC,
@@ -84,10 +69,10 @@
SOUND_MASK_VOLUME,
SOUND_MASK_OGAIN, /* Used to be PHONEOUT */
SOUND_MASK_PHONEIN,
+#ifdef TONE_CONTROL
SOUND_MASK_TREBLE,
SOUND_MASK_BASS,
- SOUND_MASK_MONITOR,
- SOUND_MASK_PCM,
+#endif
};
static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = {
@@ -115,7 +100,7 @@
/* 4 bit mono */
[SOUND_MIXER_IGAIN] = AC97_RECORDGAINMIC,
/* test code */
- [SOUND_MIXER_BASS] = AC97_GENERALPUPOSE,
+ [SOUND_MIXER_BASS] = AC97_GENERALPURPOSE,
[SOUND_MIXER_TREBLE] = AC97_MASTERTONE,
[SOUND_MIXER_LINE2] = AC97_PCMOUTVOLUME,
[SOUND_MIXER_DIGITAL2] = AC97_MASTERVOLUME
@@ -134,12 +119,25 @@
int nL, nR;
switch (ch) {
+ case SOUND_MIXER_PCM:
+ case SOUND_MIXER_VOLUME:
+#ifdef TONE_CONTROL
+ case SOUND_MIXER_TREBLE:
+ case SOUND_MIXER_BASS:
+#endif
+ return put_user(0x0000, (int *) arg);
+ default:
+ break;
+ }
+
+ if(card->isaps)
+ return -EINVAL;
+
+ switch (ch) {
case SOUND_MIXER_LINE:
case SOUND_MIXER_CD:
case SOUND_MIXER_VIDEO:
case SOUND_MIXER_LINE1:
- case SOUND_MIXER_PCM:
- case SOUND_MIXER_VOLUME:
sblive_readac97(card, volreg[ch], ®);
nL = ((~(reg >> 8) & 0x1f) * 100) / 32;
nR = (~(reg & 0x1f) * 100) / 32;
@@ -165,9 +163,6 @@
nR = (~(reg & 0x1f) * 100) / 16;
return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg);
- case SOUND_MIXER_TREBLE:
- case SOUND_MIXER_BASS:
- return put_user(0x0000, (int *) arg);
default:
return -EINVAL;
}
@@ -204,7 +199,9 @@
[SOUND_MIXER_DIGITAL2] = 19
};
-u32 bass_table[41][5] = {
+#ifdef TONE_CONTROL
+
+static const u32 bass_table[41][5] = {
{ 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
{ 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
{ 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
@@ -248,7 +245,7 @@
{ 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
};
-u32 treble_table[41][5] = {
+static const u32 treble_table[41][5] = {
{ 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
{ 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
{ 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
@@ -299,8 +296,8 @@
l = (l * 40 + 50) / 100;
r = (r * 40 + 50) / 100;
for (i = 0; i < 5; i++) {
- sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2), 0, bass_table[l][i]);
- sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2) + 1, 0, bass_table[r][i]);
+ sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2), 0, bass_table[l][i]);
+ sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2) + 1, 0, bass_table[r][i]);
}
}
@@ -311,12 +308,14 @@
l = (l * 40 + 50) / 100;
r = (r * 40 + 50) / 100;
for (i = 0; i < 5; i++) {
- sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2), 0, treble_table[l][i]);
- sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2) + 1, 0, treble_table[r][i]);
+ sblive_writeptr(card, FXGPREGBASE + 0x90 + (i * 2), 0, treble_table[l][i]);
+ sblive_writeptr(card, FXGPREGBASE + 0x90 + (i * 2) + 1, 0, treble_table[r][i]);
}
}
-u32 db_table[101] = {
+#endif
+
+static const u32 db_table[101] = {
0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
@@ -340,6 +339,29 @@
0x7fffffff,
};
+static void aps_update_digital(struct emu10k1_card *card)
+{
+ int i, l1, r1, l2, r2;
+
+ i = card->arrwVol[volidx[SOUND_MIXER_VOLUME]];
+ l1 = (i & 0xff);
+ r1 = ((i >> 8) & 0xff);
+
+ i = card->arrwVol[volidx[SOUND_MIXER_PCM]];
+ l2 = (i & 0xff);
+ r2 = ((i >> 8) & 0xff);
+
+ for (i = 0; i < 108; i++) {
+ if (card->digmix[i] != DM_MUTE) {
+ if ((i % 18 >= 0) && (i % 18 < 4))
+ card->digmix[i] = ((i & 1) ? ((u64) db_table[r1] * (u64) db_table[r2]) : ((u64) db_table[l1] * (u64) db_table[l2])) >> 31;
+ else
+ card->digmix[i] = (i & 1) ? db_table[r1] : db_table[l1];
+ sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]);
+ }
+ }
+}
+
static void update_digital(struct emu10k1_card *card)
{
int i, k, l1, r1, l2, r2, l3, r3, l4, r4;
@@ -376,11 +398,11 @@
l1 = i;
}
- for (i = 0; i < 16; i++) {
- if (card->digmix[i] != 0x80000000) {
- if ((i >= 0) && (i < 4))
+ for (i = 0; i < 36; i++) {
+ if (card->digmix[i] != DM_MUTE) {
+ if (((i >= 0) && (i < 4)) || ((i >= 18) && (i < 22)))
j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r3]) : ((u64) db_table[l1] * (u64) db_table[l3]);
- else if ((i == 6) || (i == 7))
+ else if ((i == 6) || (i == 7) || (i == 24) || (i == 25))
j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r4]) : ((u64) db_table[l1] * (u64) db_table[l4]);
else
j = ((i & 1) ? db_table[r1] : db_table[l1]) << 31;
@@ -389,11 +411,11 @@
}
}
- for (i = 64; i < 80; i++) {
- if (card->digmix[i] != 0x80000000) {
- if ((i >= 64) && (i < 68))
+ for (i = 72; i < 90; i++) {
+ if (card->digmix[i] != DM_MUTE) {
+ if ((i >= 72) && (i < 76))
j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r3]) : ((u64) db_table[l2] * (u64) db_table[l3]);
- else if ((i == 70) || (i == 71))
+ else if ((i == 78) || (i == 79))
j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r4]) : ((u64) db_table[l2] * (u64) db_table[l4]);
else
j = ((i & 1) ? db_table[r2] : db_table[l2]) << 31;
@@ -402,18 +424,18 @@
}
}
- for (i = 16; i <= 80; i += 16) {
- if (i != 64) {
+ for (i = 36; i <= 90; i += 18) {
+ if (i != 72) {
for (k = 0; k < 4; k++)
- if (card->digmix[i + k] != 0x80000000) {
+ if (card->digmix[i + k] != DM_MUTE) {
card->digmix[i + k] = db_table[l3];
sblive_writeptr(card, FXGPREGBASE + 0x10 + i + k, 0, card->digmix[i + k]);
}
- if (card->digmix[i + 6] != 0x80000000) {
+ if (card->digmix[i + 6] != DM_MUTE) {
card->digmix[i + 6] = db_table[l4];
sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 6, 0, card->digmix[i + 6]);
}
- if (card->digmix[i + 7] != 0x80000000) {
+ if (card->digmix[i + 7] != DM_MUTE) {
card->digmix[i + 7] = db_table[r4];
sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 7, 0, card->digmix[i + 7]);
}
@@ -428,9 +450,9 @@
static int set_pcm_attn(struct emu10k1_card *card, int ch, int l)
{
#ifndef PCMLEVEL
-#define PCMLEVEL 140 // almost silence
+#define PCMLEVEL 110 /* almost silence */
#endif
- int vol = IFATN_ATTENUATION_MASK; // silence
+ int vol = IFATN_ATTENUATION_MASK; /* silence */
if (l > 0)
vol = (PCMLEVEL - (l * PCMLEVEL + 50) / 100);
@@ -454,29 +476,29 @@
for (i = 0; i < MAX_PCM_CHANNELS; i++) {
if (sblive_pcm_volume[i].files == current->files) {
- sblive_pcm_volume[i].mixer = mixer;
+ sblive_pcm_volume[i].mixer = pcm_last_mixer = mixer;
if (sblive_pcm_volume[i].opened) {
if (sblive_pcm_volume[i].channel_r < NUM_G) {
+ sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1);
if (sblive_pcm_volume[i].channel_l < NUM_G)
sblive_pcm_volume[i].attn_l = set_pcm_attn(card, sblive_pcm_volume[i].channel_l, l1);
- sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1);
} else {
- // mono voice
+ /* mono voice */
if (sblive_pcm_volume[i].channel_l < NUM_G)
sblive_pcm_volume[i].attn_l =
set_pcm_attn(card, sblive_pcm_volume[i].channel_l, (l1 >= r1) ? l1 : r1);
- // to correctly handle mono voice here we would need
- // to go into stereo mode and move the voice to the right & left
- // looks a bit overcomlicated...
+ /* to correctly handle mono voice here we would need
+ to go into stereo mode and move the voice to the right & left
+ looks a bit overcomplicated... */
}
-
}
+
return 1;
+
}
}
- if (i == MAX_PCM_CHANNELS)
- card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer;
+ card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer;
return 0;
}
#endif
@@ -505,10 +527,11 @@
switch (ch) {
case SOUND_MIXER_VOLUME:
- case SOUND_MIXER_DIGITAL1:
- case SOUND_MIXER_LINE3:
- DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_VOLUME) ? "VOLUME" : (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3");
- update_digital(card);
+ DPF(4, "SOUND_MIXER_VOLUME:\n");
+ if (card->isaps)
+ aps_update_digital(card);
+ else
+ update_digital(card);
return 0;
case SOUND_MIXER_PCM:
DPF(4, "SOUND_MIXER_PCM\n");
@@ -516,6 +539,34 @@
if (update_pcm_attn(card, l1, r1))
return 0;
#endif
+ if (card->isaps)
+ aps_update_digital(card);
+ else
+ update_digital(card);
+ return 0;
+#ifdef TONE_CONTROL
+ case SOUND_MIXER_TREBLE:
+ DPF(4, "SOUND_MIXER_TREBLE:\n");
+ set_treble(card, l1, r1);
+ return 0;
+
+ case SOUND_MIXER_BASS:
+ DPF(4, "SOUND_MIXER_BASS:\n");
+ set_bass(card, l1, r1);
+ return 0;
+#endif
+ default:
+ break;
+ }
+
+
+ if (card->isaps)
+ return -EINVAL;
+
+ switch (ch) {
+ case SOUND_MIXER_DIGITAL1:
+ case SOUND_MIXER_LINE3:
+ DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3");
update_digital(card);
return 0;
case SOUND_MIXER_DIGITAL2:
@@ -549,7 +600,7 @@
DPF(4, "SOUND_MIXER_MIC:\n");
i = 0;
if (l1 >= 30)
- // 20dB / (34.5dB + 12dB + 20dB) * 100 = 30
+ /* 20dB / (34.5dB + 12dB + 20dB) * 100 = 30 */
{
l1 -= 30;
i = 0x40;
@@ -572,16 +623,6 @@
sblive_writeac97(card, volreg[ch], wval);
return 0;
- case SOUND_MIXER_TREBLE:
- DPF(4, "SOUND_MIXER_TREBLE:\n");
- set_treble(card, l1, r1);
- return 0;
-
- case SOUND_MIXER_BASS:
- DPF(4, "SOUND_MIXER_BASS:\n");
- set_bass(card, l1, r1);
- return 0;
-
default:
DPF(2, "Got unknown SOUND_MIXER ioctl\n");
return -EINVAL;
@@ -597,6 +638,10 @@
/* Mixer file operations */
/* FIXME: Do we need spinlocks in here? */
+/* WARNING! not all the ioctl's are supported by the emu-APS
+ (anything AC97 related). As a general rule keep the AC97 related ioctls
+ separate from the rest. This will make it easier to rewrite the mixer
+ using the kernel AC97 interface. */
static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
static const char id[] = "SBLive";
@@ -658,10 +703,201 @@
return -EFAULT;
for (i = 0; i < sizeof(card->digmix) / sizeof(card->digmix[0]); i++)
- sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & 0x80000000) ? 0 : card->digmix[i]);
+ sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & DM_MUTE) ? 0 : card->digmix[i]);
return 0;
break;
+ case SOUND_MIXER_PRIVATE3: {
+ struct mixer_private_ioctl ctl;
+
+ if (copy_from_user(&ctl, (void *) arg, sizeof(struct mixer_private_ioctl)))
+ return -EFAULT;
+
+ switch (ctl.cmd) {
+#ifdef EMU10K1_DEBUG
+ case CMD_WRITEFN0:
+ emu10k1_writefn0(card, ctl.val[0], ctl.val[1]);
+ return 0;
+ break;
+
+ case CMD_WRITEPTR:
+ if(ctl.val[1] >= 0x40)
+ return -EINVAL;
+
+ if(ctl.val[0] > 0xff)
+ return -EINVAL;
+
+ if((ctl.val[0] & 0x7ff) > 0x3f)
+ ctl.val[1] = 0x00;
+
+ sblive_writeptr(card, ctl.val[0], ctl.val[1], ctl.val[2]);
+
+ return 0;
+ break;
+#endif
+ case CMD_READFN0:
+ ctl.val[2] = emu10k1_readfn0(card, ctl.val[0]);
+
+ if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl)))
+ return -EFAULT;
+
+ return 0;
+ break;
+
+ case CMD_READPTR:
+ if(ctl.val[1] >= 0x40)
+ return -EINVAL;
+
+ if((ctl.val[0] & 0x7ff) > 0xff)
+ return -EINVAL;
+
+ if((ctl.val[0] & 0x7ff) > 0x3f)
+ ctl.val[1] = 0x00;
+
+ ctl.val[2] = sblive_readptr(card, ctl.val[0], ctl.val[1]);
+
+ if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl)))
+ return -EFAULT;
+
+ return 0;
+ break;
+
+ case CMD_SETRECSRC:
+ switch(ctl.val[0]){
+ case WAVERECORD_AC97:
+ if(card->isaps)
+ return -EINVAL;
+ card->wavein.recsrc = WAVERECORD_AC97;
+ break;
+ case WAVERECORD_MIC:
+ card->wavein.recsrc = WAVERECORD_MIC;
+ break;
+ case WAVERECORD_FX:
+ card->wavein.recsrc = WAVERECORD_FX;
+ card->wavein.fxwc = ctl.val[1] & 0xffff;
+ if(!card->wavein.fxwc)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ break;
+
+ case CMD_GETRECSRC:
+ ctl.val[0] = card->wavein.recsrc;
+ ctl.val[1] = card->wavein.fxwc;
+ if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl)))
+ return -EFAULT;
+
+ return 0;
+ break;
+
+ case CMD_GETVOICEPARAM:
+
+ ctl.val[0] = card->waveout.send_routing[0];
+ ctl.val[1] = card->waveout.send_a[0] | card->waveout.send_b[0] << 8 |
+ card->waveout.send_c[0] << 16 | card->waveout.send_d[0] << 24;
+
+ ctl.val[2] = card->waveout.send_routing[1];
+ ctl.val[3] = card->waveout.send_a[1] | card->waveout.send_b[1] << 8 |
+ card->waveout.send_c[1] << 16 | card->waveout.send_d[1] << 24;
+
+ ctl.val[4] = card->waveout.send_routing[2];
+ ctl.val[5] = card->waveout.send_a[2] | card->waveout.send_b[2] << 8 |
+ card->waveout.send_c[2] << 16 | card->waveout.send_d[2] << 24;
+
+ if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl)))
+ return -EFAULT;
+
+ return 0;
+ break;
+
+ case CMD_SETVOICEPARAM:
+ card->waveout.send_routing[0] = ctl.val[0] & 0xffff;
+ card->waveout.send_a[0] = ctl.val[1] & 0xff;
+ card->waveout.send_b[0] = (ctl.val[1] >> 8) & 0xff;
+ card->waveout.send_c[0] = (ctl.val[1] >> 16) & 0xff;
+ card->waveout.send_d[0] = (ctl.val[1] >> 24) & 0xff;
+
+ card->waveout.send_routing[1] = ctl.val[2] & 0xffff;
+ card->waveout.send_a[1] = ctl.val[3] & 0xff;
+ card->waveout.send_b[1] = (ctl.val[3] >> 8) & 0xff;
+ card->waveout.send_c[1] = (ctl.val[3] >> 16) & 0xff;
+ card->waveout.send_d[1] = (ctl.val[3] >> 24) & 0xff;
+
+ card->waveout.send_routing[2] = ctl.val[4] & 0xffff;
+ card->waveout.send_a[2] = ctl.val[5] & 0xff;
+ card->waveout.send_b[2] = (ctl.val[5] >> 8) & 0xff;
+ card->waveout.send_c[2] = (ctl.val[5] >> 16) & 0xff;
+ card->waveout.send_d[2] = (ctl.val[5] >> 24) & 0xff;
+
+ return 0;
+ break;
+
+ default:
+ return -EINVAL;
+ break;
+ }
+ }
+ break;
+
+ case SOUND_MIXER_PRIVATE4:{
+ u32 size;
+ int size_reg = 0;
+
+ if (copy_from_user(&size, (void *) arg, sizeof(size)))
+ return -EFAULT;
+
+ DPD(2,"External tram size 0x%x\n", size);
+
+ if(size > 0x1fffff)
+ return -EINVAL;
+
+ if (size != 0) {
+ size = (size - 1) >> 14;
+
+ while (size) {
+ size >>= 1;
+ size_reg++;
+ }
+
+ size = 0x4000 << size_reg;
+ }
+
+ DPD(2,"External tram size 0x%x 0x%x\n", size, size_reg);
+
+ if (size != card->tankmem.size) {
+ if (card->tankmem.size > 0) {
+ emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 1);
+
+ sblive_writeptr_tag(card, 0, TCB, 0,
+ TCBS, 0,
+ TAGLIST_END);
+
+ pci_free_consistent(card->pci_dev, card->tankmem.size,
+ card->tankmem.addr, card->tankmem.dma_handle);
+
+ card->tankmem.size = 0;
+ }
+
+ if (size != 0) {
+ if ((card->tankmem.addr = pci_alloc_consistent(card->pci_dev, size,
+ &card->tankmem.dma_handle)) == NULL)
+ return -ENOMEM;
+
+ card->tankmem.size = size;
+
+ sblive_writeptr_tag(card, 0, TCB, card->tankmem.dma_handle,
+ TCBS, size_reg,
+ TAGLIST_END);
+
+ emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0);
+ }
+ }
+ return 0;
+ }
+ break;
default:
break;
@@ -672,57 +908,107 @@
if (_IOC_DIR(cmd) == _IOC_READ) {
switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- DPF(2, "SOUND_MIXER_READ_RECSRC\n");
- sblive_readac97(card, AC97_RECORDSELECT, ®);
- return put_user(recsrc[reg & 7], (int *) arg);
-
- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
- DPF(4, "SOUND_MIXER_READ_DEVMASK\n");
+ case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
+ DPF(4, "SOUND_MIXER_READ_DEVMASK\n");
+ if (card->isaps)
+#ifdef TONE_CONTROL
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+ SOUND_MASK_BASS | SOUND_MASK_TREBLE,
+ (int *) arg);
+#else
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME,
+ (int *) arg);
+#endif
+
+#ifdef TONE_CONTROL
return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
+ SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
+ SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+ SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
+ SOUND_MASK_BASS | SOUND_MASK_TREBLE |
+ SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
+ SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 |
+ SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg);
+#else
+ return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
+ SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
+ SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+ SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
+ SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
+ SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 |
+ SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg);
+#endif
+
+ case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+ DPF(2, "SOUND_MIXER_READ_RECMASK\n");
+ if (card->isaps)
+ return put_user(0, (int *) arg);
+
+ return put_user(SOUND_MASK_MIC | SOUND_MASK_CD |
+ SOUND_MASK_LINE1 | SOUND_MASK_LINE |
+ SOUND_MASK_VOLUME | SOUND_MASK_OGAIN |
+ SOUND_MASK_PHONEIN, (int *) arg);
+
+ case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+ DPF(2, "SOUND_MIXER_READ_STEREODEVS\n");
+
+ if (card->isaps)
+#ifdef TONE_CONTROL
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+ SOUND_MASK_BASS | SOUND_MASK_TREBLE,
+ (int *) arg);
+#else
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME,
+ (int *) arg);
+#endif
+
+#ifdef TONE_CONTROL
+ return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
SOUND_MASK_PCM | SOUND_MASK_VOLUME |
- SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
SOUND_MASK_BASS | SOUND_MASK_TREBLE |
- SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
- SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 |
- SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg);
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- DPF(2, "SOUND_MIXER_READ_RECMASK\n");
- return put_user(SOUND_MASK_MIC | SOUND_MASK_CD |
- SOUND_MASK_LINE1 | SOUND_MASK_LINE |
- SOUND_MASK_VOLUME | SOUND_MASK_OGAIN |
- SOUND_MASK_PHONEIN | SOUND_MASK_MONITOR |
- SOUND_MASK_PCM, (int *) arg);
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- DPF(2, "SOUND_MIXER_READ_STEREODEVS\n");
- return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
+ SOUND_MASK_RECLEV | SOUND_MASK_LINE3 |
+ SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 |
+ SOUND_MASK_LINE2, (int *) arg);
+#else
+ return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
SOUND_MASK_PCM | SOUND_MASK_VOLUME |
- SOUND_MASK_BASS | SOUND_MASK_TREBLE |
SOUND_MASK_RECLEV | SOUND_MASK_LINE3 |
- SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 |
+ SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 |
SOUND_MASK_LINE2, (int *) arg);
+#endif
- case SOUND_MIXER_CAPS:
- DPF(2, "SOUND_MIXER_READ_CAPS\n");
- return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg);
-
+ case SOUND_MIXER_CAPS:
+ DPF(2, "SOUND_MIXER_READ_CAPS\n");
+ return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg);
#ifdef PRIVATE_PCM_VOLUME
- case SOUND_MIXER_PCM:
- // needs to be before default: !!
- {
- int i;
-
- for (i = 0; i < MAX_PCM_CHANNELS; i++) {
- if (sblive_pcm_volume[i].files == current->files) {
- return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg);
- }
- }
- }
+ case SOUND_MIXER_PCM:
+ /* needs to be before default: !!*/
+ {
+ int i;
+
+ for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+ if (sblive_pcm_volume[i].files == current->files) {
+ return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg);
+ }
+ }
+ }
#endif
default:
+ break;
+ }
+
+ switch (_IOC_NR(cmd)) {
+ case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+ DPF(2, "SOUND_MIXER_READ_RECSRC\n");
+ if (card->isaps)
+ return put_user(0, (int *) arg);
+
+ sblive_readac97(card, AC97_RECORDSELECT, ®);
+ return put_user(recsrc[reg & 7], (int *) arg);
+
+ default:
i = _IOC_NR(cmd);
DPD(4, "SOUND_MIXER_READ(%d)\n", i);
if (i >= SOUND_MIXER_NRDEVICES)
@@ -737,6 +1023,7 @@
#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
}
}
+
/* End of _IOC_READ */
if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE))
return -EINVAL;
@@ -748,10 +1035,13 @@
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
DPF(2, "SOUND_MIXER_WRITE_RECSRC\n");
+ if (card->isaps)
+ return -EINVAL;
+
get_user_ret(val, (int *) arg, -EFAULT);
i = hweight32(val);
if (i == 0)
- return 0; /*val = mixer_recmask(s); */
+ return 0; /* val = mixer_recmask(s); */
else if (i > 1) {
sblive_readac97(card, AC97_RECORDSELECT, ®);
val &= ~recsrc[reg & 7];
@@ -809,14 +1099,14 @@
static int emu10k1_mixer_release(struct inode *inode, struct file *file)
{
- DPF(3, "emu10k1_mixer_release()\n");
+ DPF(4, "emu10k1_mixer_release()\n");
return 0;
}
struct file_operations emu10k1_mixer_fops = {
- owner:THIS_MODULE,
- llseek:emu10k1_mixer_llseek,
- ioctl:emu10k1_mixer_ioctl,
- open:emu10k1_mixer_open,
- release:emu10k1_mixer_release,
+ owner: THIS_MODULE,
+ llseek: emu10k1_mixer_llseek,
+ ioctl: emu10k1_mixer_ioctl,
+ open: emu10k1_mixer_open,
+ release: emu10k1_mixer_release,
};
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)