📄 amd7930.c
字号:
(info->D.input_callback_arg, der, info->D.input_count); } }}long amd7930_xmit_idles = 0;static void transceive_Bchannel(struct amd7930_channel *channel, unsigned long reg){ /* Send the next byte of outgoing data. */ if (channel->output_ptr && channel->output_count > 0) { u8 byte; /* Send the next byte and advance buffer pointer. */ switch(channel->output_format) { case AUDIO_ENCODING_ULAW: case AUDIO_ENCODING_ALAW: byte = *(channel->output_ptr); sbus_writeb(byte, reg); break; case AUDIO_ENCODING_LINEAR8: byte = bilinear2mulaw(*(channel->output_ptr)); sbus_writeb(byte, reg); break; case AUDIO_ENCODING_LINEAR: if (channel->output_count >= 2) { u16 val = channel->output_ptr[0] << 8; val |= channel->output_ptr[1]; byte = linear2mulaw(val); sbus_writeb(byte, reg); channel->output_ptr++; channel->output_count--; }; }; channel->output_ptr++; channel->output_count--; /* Done with the buffer? Notify the midlevel driver. */ if (channel->output_count == 0) { channel->output_ptr = NULL; channel->output_count = 0; if (channel->output_callback) (*channel->output_callback) (channel->output_callback_arg,1); } } else { sbus_writeb(channel->xmit_idle_char, reg); amd7930_xmit_idles++; } /* Read the next byte of incoming data. */ if (channel->input_ptr && channel->input_count > 0) { /* Get the next byte and advance buffer pointer. */ switch(channel->input_format) { case AUDIO_ENCODING_ULAW: case AUDIO_ENCODING_ALAW: *(channel->input_ptr) = sbus_readb(reg); break; case AUDIO_ENCODING_LINEAR8: *(channel->input_ptr) = mulaw2bilinear(sbus_readb(reg)); break; case AUDIO_ENCODING_LINEAR: if (channel->input_count >= 2) { u16 val = mulaw2linear(sbus_readb(reg)); channel->input_ptr[0] = val >> 8; channel->input_ptr[1] = val & 0xff; channel->input_ptr++; channel->input_count--; } else { *(channel->input_ptr) = 0; } }; channel->input_ptr++; channel->input_count--; /* Done with the buffer? Notify the midlevel driver. */ if (channel->input_count == 0) { channel->input_ptr = NULL; channel->input_count = 0; if (channel->input_callback) (*channel->input_callback) (channel->input_callback_arg, 1, 0); } }}/* Interrupt handler (The chip takes only one byte per interrupt. Grrr!) */static void amd7930_interrupt(int irq, void *dev_id, struct pt_regs *intr_regs){ struct sparcaudio_driver *drv = (struct sparcaudio_driver *) dev_id; struct amd7930_info *info = (struct amd7930_info *) drv->private; unsigned long regs = info->regs; __u8 ir; /* Clear the interrupt. */ ir = sbus_readb(regs + IR); if (ir & AMR_IR_BBUF) { if (info->Bb.channel_status == CHANNEL_INUSE) transceive_Bchannel(&info->Bb, info->regs + BBTB); if (info->Bc.channel_status == CHANNEL_INUSE) transceive_Bchannel(&info->Bc, info->regs + BCTB); } if (ir & (AMR_IR_DRTHRSH | AMR_IR_DTTHRSH | AMR_IR_DSRI)) { debug_info(info, 'i'); debug_info(info, '0' + (ir&7)); transceive_Dchannel(info); } if (ir & AMR_IR_LSRI) { __u8 lsr; sbus_writeb(AMR_LIU_LSR, regs + CR); lsr = sbus_readb(regs + DR); info->liu_state = (lsr & 0x7) + 2; if (info->liu_callback) (*info->liu_callback)(info->liu_callback_arg); }}static int amd7930_open(struct inode * inode, struct file * file, struct sparcaudio_driver *drv){ struct amd7930_info *info = (struct amd7930_info *) drv->private; switch(MINOR(inode->i_rdev) & 0xf) { case SPARCAUDIO_AUDIO_MINOR: info->format_type = AUDIO_ENCODING_ULAW; break; case SPARCAUDIO_DSP_MINOR: info->format_type = AUDIO_ENCODING_LINEAR8; break; case SPARCAUDIO_DSP16_MINOR: info->format_type = AUDIO_ENCODING_LINEAR; break; }; MOD_INC_USE_COUNT; return 0;}static void amd7930_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv){ /* amd7930_disable_ints(drv->private); */ MOD_DEC_USE_COUNT;}static void request_Baudio(struct amd7930_info *info){ if (info->Bb.channel_status == CHANNEL_AVAILABLE) { info->Bb.channel_status = CHANNEL_INUSE; info->Baudio = &info->Bb; /* Multiplexor map - audio (Ba) to Bb */ sbus_writeb(AMR_MUX_MCR1, info->regs + CR); sbus_writeb(AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bb << 4), info->regs + DR); /* Enable B channel interrupts */ sbus_writeb(AMR_MUX_MCR4, info->regs + CR); sbus_writeb(AM_MUX_MCR4_ENABLE_INTS, info->regs + DR); } else if (info->Bc.channel_status == CHANNEL_AVAILABLE) { info->Bc.channel_status = CHANNEL_INUSE; info->Baudio = &info->Bc; /* Multiplexor map - audio (Ba) to Bc */ sbus_writeb(AMR_MUX_MCR1, info->regs + CR); sbus_writeb(AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bc << 4), info->regs + DR); /* Enable B channel interrupts */ sbus_writeb(AMR_MUX_MCR4, info->regs + CR); sbus_writeb(AM_MUX_MCR4_ENABLE_INTS, info->regs + DR); }}static void release_Baudio(struct amd7930_info *info){ if (info->Baudio) { info->Baudio->channel_status = CHANNEL_AVAILABLE; sbus_writeb(AMR_MUX_MCR1, info->regs + CR); sbus_writeb(0, info->regs + DR); info->Baudio = NULL; if (info->Bb.channel_status == CHANNEL_AVAILABLE && info->Bc.channel_status == CHANNEL_AVAILABLE) { /* Disable B channel interrupts */ sbus_writeb(AMR_MUX_MCR4, info->regs + CR); sbus_writeb(0, info->regs + DR); } }}static void amd7930_start_output(struct sparcaudio_driver *drv, __u8 * buffer, unsigned long count){ struct amd7930_info *info = (struct amd7930_info *) drv->private; if (! info->Baudio) request_Baudio(info); if (info->Baudio) { info->Baudio->output_ptr = buffer; info->Baudio->output_count = count; info->Baudio->output_format = info->format_type; info->Baudio->output_callback = (void *) &sparcaudio_output_done; info->Baudio->output_callback_arg = (void *) drv; info->Baudio->xmit_idle_char = 0; }}static void amd7930_stop_output(struct sparcaudio_driver *drv){ struct amd7930_info *info = (struct amd7930_info *) drv->private; if (info->Baudio) { info->Baudio->output_ptr = NULL; info->Baudio->output_count = 0; if (! info->Baudio->input_ptr) release_Baudio(info); }}static void amd7930_start_input(struct sparcaudio_driver *drv, __u8 * buffer, unsigned long count){ struct amd7930_info *info = (struct amd7930_info *) drv->private; if (! info->Baudio) request_Baudio(info); if (info->Baudio) { info->Baudio->input_ptr = buffer; info->Baudio->input_count = count; info->Baudio->input_format = info->format_type; info->Baudio->input_callback = (void *) &sparcaudio_input_done; info->Baudio->input_callback_arg = (void *) drv; }}static void amd7930_stop_input(struct sparcaudio_driver *drv){ struct amd7930_info *info = (struct amd7930_info *) drv->private; if (info->Baudio) { info->Baudio->input_ptr = NULL; info->Baudio->input_count = 0; if (! info->Baudio->output_ptr) release_Baudio(info); }}static void amd7930_sunaudio_getdev(struct sparcaudio_driver *drv, audio_device_t * audinfo){ strncpy(audinfo->name, "SUNW,am79c30", sizeof(audinfo->name) - 1); strncpy(audinfo->version, "a", sizeof(audinfo->version) - 1); strncpy(audinfo->config, "onboard1", sizeof(audinfo->config) - 1);}static int amd7930_sunaudio_getdev_sunos(struct sparcaudio_driver *drv){ return AUDIO_DEV_AMD;}static int amd7930_get_formats(struct sparcaudio_driver *drv){ return (AFMT_MU_LAW | AFMT_A_LAW | AFMT_U8 | AFMT_S16_BE);}static int amd7930_get_output_ports(struct sparcaudio_driver *drv){ return (AUDIO_SPEAKER | AUDIO_HEADPHONE);}static int amd7930_get_input_ports(struct sparcaudio_driver *drv){ return (AUDIO_MICROPHONE);}static int amd7930_set_output_volume(struct sparcaudio_driver *drv, int vol){ struct amd7930_info *info = (struct amd7930_info *) drv->private; info->pgain = vol; amd7930_update_map(drv); return 0;}static int amd7930_get_output_volume(struct sparcaudio_driver *drv){ struct amd7930_info *info = (struct amd7930_info *) drv->private; return info->pgain;}static int amd7930_set_input_volume(struct sparcaudio_driver *drv, int vol){ struct amd7930_info *info = (struct amd7930_info *) drv->private; info->rgain = vol; amd7930_update_map(drv); return 0;}static int amd7930_get_input_volume(struct sparcaudio_driver *drv){ struct amd7930_info *info = (struct amd7930_info *) drv->private; return info->rgain;}static int amd7930_set_monitor_volume(struct sparcaudio_driver *drv, int vol){ struct amd7930_info *info = (struct amd7930_info *) drv->private; info->mgain = vol; amd7930_update_map(drv); return 0;}static int amd7930_get_monitor_volume(struct sparcaudio_driver *drv){ struct amd7930_info *info = (struct amd7930_info *) drv->private; return info->mgain;}/* Cheats. The amd has the minimum capabilities we support */static int amd7930_get_output_balance(struct sparcaudio_driver *drv){ return AUDIO_MID_BALANCE;}static int amd7930_get_input_balance(struct sparcaudio_driver *drv){ return AUDIO_MID_BALANCE;}static int amd7930_get_output_channels(struct sparcaudio_driver *drv){ return AUDIO_MIN_PLAY_CHANNELS;}static int amd7930_set_output_channels(struct sparcaudio_driver *drv, int value){ return (value == AUDIO_MIN_PLAY_CHANNELS) ? 0 : -EINVAL;}static int amd7930_get_input_channels(struct sparcaudio_driver *drv){ return AUDIO_MIN_REC_CHANNELS;}static int amd7930_set_input_channels(struct sparcaudio_driver *drv, int value){ return (value == AUDIO_MIN_REC_CHANNELS) ? 0 : -EINVAL;}static int amd7930_get_output_precision(struct sparcaudio_driver *drv){ return AUDIO_MIN_PLAY_PRECISION;}static int amd7930_set_output_precision(struct sparcaudio_driver *drv, int value){ return (value == AUDIO_MIN_PLAY_PRECISION) ? 0 : -EINVAL;}static int amd7930_get_input_precision(struct sparcaudio_driver *drv){ return AUDIO_MIN_REC_PRECISION;}static int amd7930_set_input_precision(struct sparcaudio_driver *drv, int value){ return (value == AUDIO_MIN_REC_PRECISION) ? 0 : -EINVAL;}static int amd7930_get_output_port(struct sparcaudio_driver *drv){ struct amd7930_info *info = (struct amd7930_info *) drv->private; if (info->map.mmr2 & AM_MAP_MMR2_LS) return AUDIO_SPEAKER; return AUDIO_HEADPHONE;}static int amd7930_set_output_port(struct sparcaudio_driver *drv, int value){ struct amd7930_info *info = (struct amd7930_info *) drv->private; switch (value) { case AUDIO_HEADPHONE: info->map.mmr2 &= ~AM_MAP_MMR2_LS; break; case AUDIO_SPEAKER: info->map.mmr2 |= AM_MAP_MMR2_LS; break; default: return -EINVAL; }; amd7930_update_map(drv); return 0;}/* Only a microphone here, so no troubles */static int amd7930_get_input_port(struct sparcaudio_driver *drv){ return AUDIO_MICROPHONE;}static int amd7930_get_encoding(struct sparcaudio_driver *drv){ struct amd7930_info *info = (struct amd7930_info *) drv->private; if ((info->map.mmr1 & AM_MAP_MMR1_ALAW) && (info->format_type == AUDIO_ENCODING_ALAW)) return AUDIO_ENCODING_ALAW; return info->format_type;}static int amd7930_set_encoding(struct sparcaudio_driver *drv, int value){ struct amd7930_info *info = (struct amd7930_info *) drv->private; switch (value) { case AUDIO_ENCODING_ALAW: info->map.mmr1 |= AM_MAP_MMR1_ALAW; break; case AUDIO_ENCODING_LINEAR8: case AUDIO_ENCODING_LINEAR: case AUDIO_ENCODING_ULAW: info->map.mmr1 &= ~AM_MAP_MMR1_ALAW; break; default: return -EINVAL; }; info->format_type = value; amd7930_update_map(drv); return 0;}/* This is what you get. Take it or leave it */static int amd7930_get_output_rate(struct sparcaudio_driver *drv){ return AMD7930_RATE;}static int amd7930_set_output_rate(struct sparcaudio_driver *drv, int value){ return (value == AMD7930_RATE) ? 0 : -EINVAL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -