📄 ac97.c
字号:
{ unsigned long flags; flags = spin_lock_irqsave(); q->id[q->count] = id; q->count ++; spin_unlock_irqrestore(flags);}static inline int elements_in_queue(struct buffer_queue_s *q){ int r; unsigned long flags; flags=spin_lock_irqsave(); r = q->count; spin_unlock_irqrestore(flags); return r;}/**************************************************************************** * Architecture related routines ****************************************************************************/static void jz_ac97_record_dma_irq (unsigned int arg){ int dma = AUDIO_READ_DMA; int id1, id2; dma_stop(dma); if (__dmac_channel_address_error_detected(dma)) { printf("%s: DMAC address error.\n", __FUNCTION__); __dmac_channel_clear_address_error(dma); } if (__dmac_channel_transmit_end_detected(dma)) { __dmac_channel_clear_transmit_end(dma); id1 = get_buffer_id(&in_busy_queue); put_buffer_id(&in_full_queue, id1);// __dcache_invalidate_all(); OSSemPost(rx_sem); if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { put_buffer_id(&in_busy_queue, id2); in_dma_buf_data_count[id2] = in_dma_buf_data_count[id1]; dma_start(dma, PHYADDR(AIC_DR), in_dma_pbuf[id2], in_dma_buf_data_count[id2]); } else in_busy_queue.count = 0; }}static void jz_ac97_replay_dma_irq (unsigned int arg){ int dma = AUDIO_WRITE_DMA; int id; dma_stop(dma); if (__dmac_channel_address_error_detected(dma)) { printf("%s: DMAC address error.\n", __FUNCTION__); __dmac_channel_clear_address_error(dma); } if (__dmac_channel_transmit_end_detected(dma)) { __dmac_channel_clear_transmit_end(dma); if ((id = get_buffer_id(&out_busy_queue)) < 0) printf("Strange DMA finish interrupt for AC97 module\n"); put_buffer_id(&out_empty_queue, id); if ((id = get_buffer_id(&out_full_queue)) >= 0) { put_buffer_id(&out_busy_queue, id); dma_start(dma, out_dma_pbuf[id], PHYADDR(AIC_DR), out_dma_buf_data_count[id]); } else out_busy_queue.count = 0; if (elements_in_queue(&out_empty_queue) > 0) OSSemPost(tx_sem); }}/* * Initialize the onchip AC97 controller */static void jz_ac97_initHw(void){ __ac97_disable(); __ac97_reset(); __ac97_enable(); __ac97_cold_reset_codec(); /* wait for a long time to let ac97 controller reset completely, * otherwise, registers except ACFR will be clear by reset, can't be * set correctly. */ udelay(160); __ac97_disable_record(); __ac97_disable_replay(); __ac97_disable_loopback(); /* Set FIFO data size. Which shows valid data bits. */ __ac97_set_oass(8); __ac97_set_iass(8); __ac97_set_xs_stereo(); __ac97_set_rs_stereo();}static int jz_audio_set_speed(int rate){ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ u32 dacp; if (rate > 48000) rate = 48000; if (rate < 8000) rate = 8000; /* Power down the DAC */ dacp=ac97_codec_read(AC97_POWER_CONTROL); ac97_codec_write(AC97_POWER_CONTROL, dacp|0x0200); ac97_codec_write(AC97_PCM_FRONT_DAC_RATE, 48000); /* Power it back up */ ac97_codec_write(AC97_POWER_CONTROL, dacp); jz_audio_rate = rate; jz_audio_k = STANDARD_SPEED / rate; if (rate * jz_audio_k != STANDARD_SPEED) jz_audio_q = rate / ((STANDARD_SPEED / jz_audio_k) - rate ); else jz_audio_q = 0x1fffffff; /* a very big value, don't compensate */ switch (rate) { case 8000: f_scale_count = f_scale_counts[0]; f_scale_array = k_8000; f_scale_reload = reload_8000; break; case 11025: f_scale_count = f_scale_counts[1]; f_scale_array = k_11025; f_scale_reload = reload_11025; break; case 16000: f_scale_count = f_scale_counts[2]; f_scale_array = k_16000; f_scale_reload = reload_16000; break; case 22050: f_scale_count = f_scale_counts[3]; f_scale_array = k_22050; f_scale_reload = reload_22050; break; case 24000: f_scale_count = f_scale_counts[4]; f_scale_array = k_24000; f_scale_reload = reload_24000; break; case 32000: f_scale_count = f_scale_counts[5]; f_scale_array = k_32000; f_scale_reload = reload_32000; break; case 44100: f_scale_count = f_scale_counts[6]; f_scale_array = k_44100; f_scale_reload = reload_44100; break; case 48000: f_scale_count = f_scale_counts[7]; f_scale_array = k_48000; f_scale_reload = reload_48000; break; } f_scale_idx = 0; return jz_audio_rate;}static int record_fill_1x8_u(unsigned long dst_start, int count, int id){ int cnt = 0; unsigned char data; volatile unsigned char *s = (unsigned char *)(in_dma_buf[id]); volatile unsigned char *dp = (unsigned char *)dst_start; while (count > 0) { count -= 2; /* count in dword */ if ((jz_audio_count++ % jz_audio_k) == 0) { cnt++; data = *s++; *dp++ = data + 0x80; s++; /* skip the other channel */ } else s += 2; /* skip the redundancy */ if (jz_audio_count - last_jz_audio_count >= jz_audio_q) { jz_audio_count++; last_jz_audio_count = jz_audio_count; count -= 2; s += 2; } } return cnt;}static int record_fill_2x8_u(unsigned long dst_start, int count, int id){ int cnt = 0; unsigned char d1, d2; volatile unsigned char *s = (unsigned char *)(in_dma_buf[id]); volatile unsigned char *dp = (unsigned char *)dst_start; while (count > 0) { count -= 2; if ((jz_audio_count++ % jz_audio_k) == 0) { cnt += 2; d1 = *s++; *dp++ = d1 + 0x80; d2 = *s++; *dp++ = d2 + 0x80; } else s += 2; /* skip the redundancy */ if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 2) { jz_audio_count += 2; last_jz_audio_count = jz_audio_count; count -= 2; s += 2; } } return cnt;}static int record_fill_1x16_s(unsigned long dst_start, int count, int id){ int cnt = 0; unsigned short d1; unsigned short *s = (unsigned short *)(in_dma_buf[id]); unsigned short *dp = (unsigned short *)dst_start; while (count > 0) { count -= 2; /* count in dword */ if ((jz_audio_count++ % jz_audio_k) == 0) { cnt += 2; /* count in byte */ d1 = *s++; *dp++ = d1; s++; /* skip the other channel */ } else s += 2; /* skip the redundancy */ if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 2) { jz_audio_count += 2; last_jz_audio_count = jz_audio_count; count -= 2; s += 2; } } return cnt;}static int record_fill_2x16_s(unsigned long dst_start, int count, int id){ int cnt = 0; unsigned short d1, d2; unsigned short *s = (unsigned short *)(in_dma_buf[id]); unsigned short *dp = (unsigned short *)dst_start; while (count > 0) { count -= 2; /* count in dword */ if ((jz_audio_count++ % jz_audio_k) == 0) { cnt += 4; /* count in byte */ d1 = *s++; *dp++ = d1; d2 = *s++; *dp++ = d2; } else s += 2; /* skip the redundancy */ if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 4) { jz_audio_count += 4; last_jz_audio_count = jz_audio_count; count -= 2; s += 2; } } return cnt;}static void replay_fill_1x8_u(unsigned long src_start, int count, int id){ int i, cnt = 0; unsigned char data; unsigned char *s = (unsigned char *)src_start; unsigned char *dp = (unsigned char *)(out_dma_buf[id]); while (count > 0) { count--; jz_audio_count++; cnt += jz_audio_k; data = *s++ - 0x80; for (i=0;i<jz_audio_k;i++) { *dp++ = data; *dp++ = data; } } cnt = cnt * 2; out_dma_buf_data_count[id] = cnt;}static void replay_fill_2x8_u(unsigned long src_start, int count, int id){ int i, cnt = 0; unsigned char d1, d2; unsigned char *s = (unsigned char *)src_start; unsigned char *dp = (unsigned char*)(out_dma_buf[id]); while (count > 0) { count -= 2; jz_audio_count += 2; cnt += 2 * jz_audio_k; d1 = *s++ - 0x80; d2 = *s++ - 0x80; for (i=0;i<jz_audio_k;i++) { *dp++ = d1; *dp++ = d2; } if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 2) { cnt += 2 * jz_audio_k; last_jz_audio_count = jz_audio_count; for (i=0;i<jz_audio_k;i++) { *dp++ = d1; *dp++ = d2; } } } out_dma_buf_data_count[id] = cnt;}static void replay_fill_1x16_s(unsigned long src_start, int count, int id){ int i, cnt = 0; static short d1, d2, d; short *s = (short *)src_start; short *dp = (short *)(out_dma_buf[id]); d2 = *s++; count -= 2; while (count >= 0) { if (f_scale_reload[f_scale_idx]) { d1 = d2; d2 = *s++; if (!count) break; count -= 2; } d = d1 + (((d2 - d1) * f_scale_array[f_scale_idx]) >> 8); *dp++ = d; *dp++ = d; cnt += 4; f_scale_idx ++; if (f_scale_idx >= f_scale_count) f_scale_idx = 0; } out_dma_buf_data_count[id] = cnt;}static void replay_fill_2x16_s(unsigned long src_start, int count, int id){ int i, cnt = 0; static short d11, d12, d21, d22, d1, d2; short *s = (short *)src_start; short *dp = (short *)(out_dma_buf[id]); d12 = *s++; d22 = *s++; count -= 4; while (count >= 0) { register unsigned int kvalue; kvalue = f_scale_array[f_scale_idx]; if (f_scale_reload[f_scale_idx]) { d11 = d12; d12 = *s++; d21 = d22; d22 = *s++; if (!count) break; count -= 4; } d1 = d11 + (((d12 - d11)*kvalue) >> 8); d2 = d21 + (((d22 - d21)*kvalue) >> 8); *dp++ = d1; *dp++ = d2; cnt += 4; f_scale_idx ++; if (f_scale_idx >= f_scale_count) f_scale_idx = 0; } out_dma_buf_data_count[id] = cnt;}static unsigned int jz_audio_set_format(unsigned int fmt){ switch (fmt) { case AFMT_U8: case AFMT_S16_LE: jz_audio_format = fmt; jz_update_filler(fmt, jz_audio_channels); break; } return jz_audio_format;}static short jz_audio_set_channels(short channels){ switch (channels) { case 1: __ac97_set_xs_stereo(); // always stereo when playing __ac97_set_rs_stereo(); // always stereo when recording jz_audio_channels = channels; jz_update_filler(jz_audio_format, jz_audio_channels); break; case 2: __ac97_set_xs_stereo(); __ac97_set_rs_stereo(); jz_audio_channels = channels; jz_update_filler(jz_audio_format, jz_audio_channels); break; case 0: break; } return jz_audio_channels;}static void jz_audio_reset(void){ int i; __ac97_disable_replay(); __ac97_disable_receive_dma(); __ac97_disable_record(); __ac97_disable_transmit_dma(); in_empty_queue.count = QUEUE_MAX; out_empty_queue.count = QUEUE_MAX; for (i=0;i<QUEUE_MAX;i++) { in_empty_queue.id[i] = i; out_empty_queue.id[i] = i; } in_busy_queue.count = 0; in_full_queue.count = 0; out_busy_queue.count = 0; out_full_queue.count = 0;}/* Read / Write AC97 codec registers */static inline int jz_out_command_ready(void){ int t2 = 1000; int done = 0; while (! done && t2-- > 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -