📄 dmasound_awacs.c
字号:
static voidawacs_burgundy_wcw(unsigned addr, unsigned val){ out_le32(&awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff)); awacs_burgundy_busy_wait(); out_le32(&awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff)); awacs_burgundy_busy_wait(); out_le32(&awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff)); awacs_burgundy_busy_wait(); out_le32(&awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff)); awacs_burgundy_busy_wait();}static unsignedawacs_burgundy_rcw(unsigned addr){ unsigned val = 0; unsigned long flags; /* should have timeouts here */ save_flags(flags); cli(); out_le32(&awacs->codec_ctrl, addr + 0x100000); awacs_burgundy_busy_wait(); awacs_burgundy_extend_wait(); val += (in_le32(&awacs->codec_stat) >> 4) & 0xff; out_le32(&awacs->codec_ctrl, addr + 0x100100); awacs_burgundy_busy_wait(); awacs_burgundy_extend_wait(); val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<8; out_le32(&awacs->codec_ctrl, addr + 0x100200); awacs_burgundy_busy_wait(); awacs_burgundy_extend_wait(); val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<16; out_le32(&awacs->codec_ctrl, addr + 0x100300); awacs_burgundy_busy_wait(); awacs_burgundy_extend_wait(); val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<24; restore_flags(flags); return val;}static voidawacs_burgundy_wcb(unsigned addr, unsigned val){ out_le32(&awacs->codec_ctrl, addr + 0x300000 + (val & 0xff)); awacs_burgundy_busy_wait();}static unsignedawacs_burgundy_rcb(unsigned addr){ unsigned val = 0; unsigned long flags; /* should have timeouts here */ save_flags(flags); cli(); out_le32(&awacs->codec_ctrl, addr + 0x100000); awacs_burgundy_busy_wait(); awacs_burgundy_extend_wait(); val += (in_le32(&awacs->codec_stat) >> 4) & 0xff; restore_flags(flags); return val;}static intawacs_burgundy_check(void){ /* Checks to see the chip is alive and kicking */ int error = in_le32(&awacs->codec_ctrl) & MASK_ERRCODE; return error == 0xf0000;}static intawacs_burgundy_init(void){ if (awacs_burgundy_check()) { printk(KERN_WARNING "dmasound_pmac: burgundy not working :-(\n"); return 1; } awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_OUTPUTENABLES, DEF_BURGUNDY_OUTPUTENABLES); awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, DEF_BURGUNDY_MORE_OUTPUTENABLES); awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_OUTPUTSELECTS, DEF_BURGUNDY_OUTPUTSELECTS); awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL21, DEF_BURGUNDY_INPSEL21); awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL3, DEF_BURGUNDY_INPSEL3); awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINCD, DEF_BURGUNDY_GAINCD); awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINLINE, DEF_BURGUNDY_GAINLINE); awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMIC, DEF_BURGUNDY_GAINMIC); awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMODEM, DEF_BURGUNDY_GAINMODEM); awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, DEF_BURGUNDY_ATTENSPEAKER); awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENLINEOUT, DEF_BURGUNDY_ATTENLINEOUT); awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENHP, DEF_BURGUNDY_ATTENHP); awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_MASTER_VOLUME, DEF_BURGUNDY_MASTER_VOLUME); awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLCD, DEF_BURGUNDY_VOLCD); awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLLINE, DEF_BURGUNDY_VOLLINE); awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLMIC, DEF_BURGUNDY_VOLMIC); return 0;}static voidawacs_burgundy_write_volume(unsigned address, int volume){ int hardvolume,lvolume,rvolume; lvolume = (volume & 0xff) ? (volume & 0xff) + 155 : 0; rvolume = ((volume >>8)&0xff) ? ((volume >> 8)&0xff ) + 155 : 0; hardvolume = lvolume + (rvolume << 16); awacs_burgundy_wcw(address, hardvolume);}static intawacs_burgundy_read_volume(unsigned address){ int softvolume,wvolume; wvolume = awacs_burgundy_rcw(address); softvolume = (wvolume & 0xff) - 155; softvolume += (((wvolume >> 16) & 0xff) - 155)<<8; return softvolume > 0 ? softvolume : 0;}static intawacs_burgundy_read_mvolume(unsigned address){ int lvolume,rvolume,wvolume; wvolume = awacs_burgundy_rcw(address); wvolume &= 0xffff; rvolume = (wvolume & 0xff) - 155; lvolume = ((wvolume & 0xff00)>>8) - 155; return lvolume + (rvolume << 8);}static voidawacs_burgundy_write_mvolume(unsigned address, int volume){ int lvolume,rvolume,hardvolume; lvolume = (volume &0xff) ? (volume & 0xff) + 155 :0; rvolume = ((volume >>8) & 0xff) ? (volume >> 8) + 155 :0; hardvolume = lvolume + (rvolume << 8); hardvolume += (hardvolume << 16); awacs_burgundy_wcw(address, hardvolume);}/* End burgundy functions *//* Set up output volumes on machines with the 'perch/whisper' extension card. * this has an SGS i2c chip (7433) which is accessed using the cuda. * * TODO: split this out and make use of the other parts of the SGS chip to * do Bass, Treble etc. */static voidawacs_enable_amp(int spkr_vol){#ifdef CONFIG_ADB_CUDA struct adb_request req; awacs_spkr_vol = spkr_vol; if (sys_ctrler != SYS_CTRLER_CUDA) return; /* turn on headphones */ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, 4, 0); while (!req.complete) cuda_poll(); cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, 6, 0); while (!req.complete) cuda_poll(); /* turn on speaker */ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100); while (!req.complete) cuda_poll(); cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100); while (!req.complete) cuda_poll(); cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, 1, 0x29); while (!req.complete) cuda_poll();#endif /* CONFIG_ADB_CUDA */}/*** Mid level stuff *********************************************************//* * /dev/mixer abstraction */static void do_line_lev(int data){ line_lev = data ; awacs_reg[0] &= ~MASK_MUX_AUDIN; if ((data & 0xff) >= 50) awacs_reg[0] |= MASK_MUX_AUDIN; awacs_write(MASK_ADDR0 | awacs_reg[0]);}static void do_ip_gain(int data){ ip_gain = data ; data &= 0xff; awacs_reg[0] &= ~MASK_GAINLINE; if (awacs_revision == AWACS_SCREAMER) { awacs_reg[6] &= ~MASK_MIC_BOOST ; if (data >= 33) { awacs_reg[0] |= MASK_GAINLINE; if( data >= 66) awacs_reg[6] |= MASK_MIC_BOOST ; } awacs_write(MASK_ADDR6 | awacs_reg[6]) ; } else { if (data >= 50) awacs_reg[0] |= MASK_GAINLINE; } awacs_write(MASK_ADDR0 | awacs_reg[0]);}static void do_mic_lev(int data){ mic_lev = data ; data &= 0xff; awacs_reg[0] &= ~MASK_MUX_MIC; if (data >= 50) awacs_reg[0] |= MASK_MUX_MIC; awacs_write(MASK_ADDR0 | awacs_reg[0]);}static void do_cd_lev(int data){ cd_lev = data ; awacs_reg[0] &= ~MASK_MUX_CD; if ((data & 0xff) >= 50) awacs_reg[0] |= MASK_MUX_CD; awacs_write(MASK_ADDR0 | awacs_reg[0]);}static void do_rec_lev(int data){ int left, right ; rec_lev = data ; /* need to fudge this to use the volume setter routine */ left = 100 - (data & 0xff) ; if( left < 0 ) left = 0 ; right = 100 - ((data >> 8) & 0xff) ; if( right < 0 ) right = 0 ; left |= (right << 8 ); left = awacs_volume_setter(left, 0, 0, 4);}static void do_passthru_vol(int data){ passthru_vol = data ; awacs_reg[1] &= ~MASK_LOOPTHRU; if (awacs_revision == AWACS_SCREAMER) { if( data ) { /* switch it on for non-zero */ awacs_reg[1] |= MASK_LOOPTHRU; awacs_write(MASK_ADDR1 | awacs_reg[1]); } data = awacs_volume_setter(data, 5, 0, 6) ; } else { if ((data & 0xff) >= 50) awacs_reg[1] |= MASK_LOOPTHRU; awacs_write(MASK_ADDR1 | awacs_reg[1]); data = (awacs_reg[1] & MASK_LOOPTHRU)? 100: 0; }}static int awacs_mixer_ioctl(u_int cmd, u_long arg){ int data; int rc; switch (cmd) { case SOUND_MIXER_READ_CAPS: /* say we will allow multiple inputs? prob. wrong so I'm switching it to single */ return IOCTL_OUT(arg, 1); case SOUND_MIXER_READ_DEVMASK: data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_IGAIN | SOUND_MASK_RECLEV | SOUND_MASK_ALTPCM | SOUND_MASK_MONITOR; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_RECMASK: data = SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_RECSRC: data = 0; if (awacs_reg[0] & MASK_MUX_AUDIN) data |= SOUND_MASK_LINE; if (awacs_reg[0] & MASK_MUX_MIC) data |= SOUND_MASK_MIC; if (awacs_reg[0] & MASK_MUX_CD) data |= SOUND_MASK_CD; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_RECSRC: IOCTL_IN(arg, data); data &= (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD); awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC | MASK_MUX_AUDIN); if (data & SOUND_MASK_LINE) awacs_reg[0] |= MASK_MUX_AUDIN; if (data & SOUND_MASK_MIC) awacs_reg[0] |= MASK_MUX_MIC; if (data & SOUND_MASK_CD) awacs_reg[0] |= MASK_MUX_CD; awacs_write(awacs_reg[0] | MASK_ADDR0); rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_STEREODEVS: data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER| SOUND_MASK_RECLEV ; if (awacs_revision == AWACS_SCREAMER) data |= SOUND_MASK_MONITOR ; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_VOLUME: IOCTL_IN(arg, data); line_vol = data ; awacs_volume_setter(data, 2, 0, 6); /* fall through */ case SOUND_MIXER_READ_VOLUME: rc = IOCTL_OUT(arg, line_vol); break; case SOUND_MIXER_WRITE_SPEAKER: IOCTL_IN(arg, data); spk_vol = data ; if (has_perch) awacs_enable_amp(data); else (void)awacs_volume_setter(data, 4, MASK_CMUTE, 6); /* fall though */ case SOUND_MIXER_READ_SPEAKER: rc = IOCTL_OUT(arg, spk_vol); break; case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ IOCTL_IN(arg, data); beep_vol = data & 0xff; /* fall through */ case SOUND_MIXER_READ_ALTPCM: rc = IOCTL_OUT(arg, beep_vol); break; case SOUND_MIXER_WRITE_LINE: IOCTL_IN(arg, data); do_line_lev(data) ; /* fall through */ case SOUND_MIXER_READ_LINE: rc = IOCTL_OUT(arg, line_lev); break; case SOUND_MIXER_WRITE_IGAIN: IOCTL_IN(arg, data); do_ip_gain(data) ; /* fall through */ case SOUND_MIXER_READ_IGAIN: rc = IOCTL_OUT(arg, ip_gain); break; case SOUND_MIXER_WRITE_MIC: IOCTL_IN(arg, data); do_mic_lev(data); /* fall through */ case SOUND_MIXER_READ_MIC: rc = IOCTL_OUT(arg, mic_lev); break; case SOUND_MIXER_WRITE_CD: IOCTL_IN(arg, data); do_cd_lev(data); /* fall through */ case SOUND_MIXER_READ_CD: rc = IOCTL_OUT(arg, cd_lev); break; case SOUND_MIXER_WRITE_RECLEV: IOCTL_IN(arg, data); do_rec_lev(data) ; /* fall through */ case SOUND_MIXER_READ_RECLEV: rc = IOCTL_OUT(arg, rec_lev); break; case MIXER_WRITE(SOUND_MIXER_MONITOR): IOCTL_IN(arg, data); do_passthru_vol(data) ; /* fall through */ case MIXER_READ(SOUND_MIXER_MONITOR): rc = IOCTL_OUT(arg, passthru_vol); break; default: rc = -EINVAL; } return rc;}static void awacs_mixer_init(void){ awacs_volume_setter(line_vol, 2, 0, 6); if (has_perch) awacs_enable_amp(spk_vol); else (void)awacs_volume_setter(spk_vol, 4, MASK_CMUTE, 6); do_line_lev(line_lev) ; do_ip_gain(ip_gain) ; do_mic_lev(mic_lev) ; do_cd_lev(cd_lev) ; do_rec_lev(rec_lev) ; do_passthru_vol(passthru_vol) ;}static int burgundy_mixer_ioctl(u_int cmd, u_long arg){ int data; int rc; /* We are, we are, we are... Burgundy or better */ switch(cmd) { case SOUND_MIXER_READ_DEVMASK: data = SOUND_MASK_VOLUME | SOUND_MASK_CD | SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_RECMASK: data = SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD; rc = IOCTL_OUT(arg, data); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -