?? mixer.c
字號(hào):
l2 = i & 0xff; r2 = (i >> 8) & 0xff; i = card->arrwVol[volidx[SOUND_MIXER_PCM]]; l3 = i & 0xff; r3 = (i >> 8) & 0xff; i = card->arrwVol[volidx[SOUND_MIXER_DIGITAL1]]; l4 = i & 0xff; r4 = (i >> 8) & 0xff; i = (r1 * r2) / 50; if (r2 > 50) r2 = 2 * r1 - i; else { r2 = r1; r1 = i; } i = (l1 * l2) / 50; if (l2 > 50) l2 = 2 * l1 - i; else { l2 = l1; l1 = i; } 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) || (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; card->digmix[i] = j >> 31; sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]); } } 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 == 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; card->digmix[i] = j >> 31; sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]); } } for (i = 36; i <= 90; i += 18) { if (i != 72) { for (k = 0; k < 4; k++) 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] != 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] != DM_MUTE) { card->digmix[i + 7] = db_table[r4]; sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 7, 0, card->digmix[i + 7]); } } }}#ifdef PRIVATE_PCM_VOLUME/* calc & set attenuation factor for given channel */static int set_pcm_attn(struct emu10k1_card *card, int ch, int l){#ifndef PCMLEVEL#define PCMLEVEL 110 /* almost silence */#endif int vol = IFATN_ATTENUATION_MASK; /* silence */ if (l > 0) vol = (PCMLEVEL - (l * PCMLEVEL + 50) / 100); sblive_writeptr(card, IFATN, ch, IFATN_FILTERCUTOFF_MASK | vol); DPD(2, "SOUND_MIXER_PCM: channel:%d level:%d attn:%d\n", ch, l, vol); return vol;#undef PCMLEVEL}/* update value of local PCM volume level (using channel attenuation) * * return 1: in case its local change * 0: if the current process doesn't have entry in table * (it means this process have not opened audio (mixer usually) */static int update_pcm_attn(struct emu10k1_card *card, unsigned l1, unsigned r1){ int i; int mixer = (r1 << 8) | l1; for (i = 0; i < MAX_PCM_CHANNELS; i++) { if (sblive_pcm_volume[i].files == current->files) { 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); } else { /* 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 overcomplicated... */ } } return 1; } } card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer; return 0;}#endifint emu10k1_mixer_wrch(struct emu10k1_card *card, unsigned int ch, int val){ int i; unsigned l1, r1; u16 wval; l1 = val & 0xff; r1 = (val >> 8) & 0xff; if (l1 > 100) l1 = 100; if (r1 > 100) r1 = 100; DPD(4, "emu10k1_mixer_wrch() called: ch=%u, l1=%u, r1=%u\n", ch, l1, r1); if (!volidx[ch]) return -EINVAL;#ifdef PRIVATE_PCM_VOLUME if (ch != SOUND_MIXER_PCM)#endif card->arrwVol[volidx[ch]] = (r1 << 8) | l1; switch (ch) { case SOUND_MIXER_VOLUME: 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");#ifdef PRIVATE_PCM_VOLUME 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: case SOUND_MIXER_LINE2: case SOUND_MIXER_LINE1: case SOUND_MIXER_LINE: case SOUND_MIXER_CD: DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_LINE1) ? "LINE1" : (ch == SOUND_MIXER_LINE2) ? "LINE2" : (ch == SOUND_MIXER_LINE) ? "LINE" : (ch == SOUND_MIXER_DIGITAL2) ? "DIGITAL2" : "CD"); wval = ((((100 - l1) * 32 + 50) / 100) << 8) | (((100 - r1) * 32 + 50) / 100); if (wval == 0x2020) wval = 0x8000; else wval -= ((wval & 0x2020) / 0x20); sblive_writeac97(card, volreg[ch], wval); return 0; case SOUND_MIXER_OGAIN: case SOUND_MIXER_PHONEIN: DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_PHONEIN) ? "PHONEIN" : "OGAIN"); sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((100 - l1) * 32 + 50) / 100); return 0; case SOUND_MIXER_SPEAKER: DPF(4, "SOUND_MIXER_SPEAKER:\n"); sblive_writeac97(card, volreg[ch], (l1 < 4) ? 0x8000 : (((100 - l1) * 16 + 50) / 100) << 1); return 0; case SOUND_MIXER_MIC: DPF(4, "SOUND_MIXER_MIC:\n"); i = 0; if (l1 >= 30) /* 20dB / (34.5dB + 12dB + 20dB) * 100 = 30 */ { l1 -= 30; i = 0x40; } sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((((70 - l1) * 0x20 + 35) / 70) | i)); return 0; case SOUND_MIXER_RECLEV: DPF(4, "SOUND_MIXER_RECLEV:\n"); wval = (((l1 * 16 + 50) / 100) << 8) | ((r1 * 16 + 50) / 100); if (wval == 0) wval = 0x8000; else { if (wval & 0xff) wval--; if (wval & 0xff00) wval -= 0x0100; } sblive_writeac97(card, volreg[ch], wval); return 0; default: DPF(2, "Got unknown SOUND_MIXER ioctl\n"); return -EINVAL; }}static loff_t emu10k1_mixer_llseek(struct file *file, loff_t offset, int origin){ DPF(2, "sblive_mixer_llseek() called\n"); return -ESPIPE;}/* 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"; static const char name[] = "Creative SBLive"; int i, val; struct emu10k1_card *card = (struct emu10k1_card *) file->private_data; u16 reg; switch (cmd) { case SOUND_MIXER_INFO:{ mixer_info info; DPF(4, "SOUND_MIXER_INFO\n"); strncpy(info.id, id, sizeof(info.id)); strncpy(info.name, name, sizeof(info.name)); info.modify_counter = card->modcnt; if (copy_to_user((void *) arg, &info, sizeof(info))) return -EFAULT; return 0; } break; case SOUND_OLD_MIXER_INFO:{ _old_mixer_info info; DPF(4, "SOUND_OLD_MIXER_INFO\n"); strncpy(info.id, id, sizeof(info.id)); strncpy(info.name, name, sizeof(info.name)); if (copy_to_user((void *) arg, &info, sizeof(info))) return -EFAULT; return 0; } break; case OSS_GETVERSION: DPF(4, "OSS_GETVERSION\n"); return put_user(SOUND_VERSION, (int *) arg); break; case SOUND_MIXER_PRIVATE1: DPF(4, "SOUND_MIXER_PRIVATE1"); if (copy_to_user((void *) arg, card->digmix, sizeof(card->digmix))) return -EFAULT; return 0; break; case SOUND_MIXER_PRIVATE2: DPF(4, "SOUND_MIXER_PRIVATE2"); if (copy_from_user(card->digmix, (void *) arg, sizeof(card->digmix))) return -EFAULT; for (i = 0; i < sizeof(card->digmix) / sizeof(card->digmix[0]); 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;
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -