swarm_cs4297a.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,962 行 · 第 1/5 页
C
1,962 行
//****************************************************************************// "cs4297a_write_ac97()"-- writes an AC97 register//****************************************************************************static int cs4297a_write_ac97(struct cs4297a_state *s, u32 offset, u32 value){ CS_DBGOUT(CS_AC97, 1, printk(KERN_INFO "cs4297a: write reg %2x -> %04x\n", offset, value)); return (serdma_reg_access(s, (0xELL << 60) | ((u64)(offset & 0x7F) << 40) | ((value & 0xffff) << 12)));}static void stop_dac(struct cs4297a_state *s){ unsigned long flags; CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4297a: stop_dac():\n")); spin_lock_irqsave(&s->lock, flags); s->ena &= ~FMODE_WRITE;#if 0 /* XXXKW what do I really want here? My theory for now is that I just flip the "ena" bit, and the interrupt handler will stop processing the xmit channel */ out64((s->ena & FMODE_READ) ? M_SYNCSER_DMA_RX_EN : 0, SS_CSR(R_SER_DMA_ENABLE));#endif spin_unlock_irqrestore(&s->lock, flags);}static void start_dac(struct cs4297a_state *s){ unsigned long flags; CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4297a: start_dac()+\n")); spin_lock_irqsave(&s->lock, flags); if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || (s->dma_dac.count > 0 && s->dma_dac.ready))) { s->ena |= FMODE_WRITE; /* XXXKW what do I really want here? My theory for now is that I just flip the "ena" bit, and the interrupt handler will start processing the xmit channel */ CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 8, printk(KERN_INFO "cs4297a: start_dac(): start dma\n")); } spin_unlock_irqrestore(&s->lock, flags); CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4297a: start_dac()-\n"));}static void stop_adc(struct cs4297a_state *s){ unsigned long flags; CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4297a: stop_adc()+\n")); spin_lock_irqsave(&s->lock, flags); s->ena &= ~FMODE_READ; if (s->conversion == 1) { s->conversion = 0; s->prop_adc.fmt = s->prop_adc.fmt_original; } /* Nothing to do really, I need to keep the DMA going XXXKW when do I get here, and is there more I should do? */ spin_unlock_irqrestore(&s->lock, flags); CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4297a: stop_adc()-\n"));}static void start_adc(struct cs4297a_state *s){ unsigned long flags; CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4297a: start_adc()+\n")); if (!(s->ena & FMODE_READ) && (s->dma_adc.mapped || s->dma_adc.count <= (signed) (s->dma_adc.sbufsz - 2 * s->dma_adc.fragsize)) && s->dma_adc.ready) { if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) { // // now only use 16 bit capture, due to truncation issue // in the chip, noticable distortion occurs. // allocate buffer and then convert from 16 bit to // 8 bit for the user buffer. // s->prop_adc.fmt_original = s->prop_adc.fmt; if (s->prop_adc.fmt & AFMT_S8) { s->prop_adc.fmt &= ~AFMT_S8; s->prop_adc.fmt |= AFMT_S16_LE; } if (s->prop_adc.fmt & AFMT_U8) { s->prop_adc.fmt &= ~AFMT_U8; s->prop_adc.fmt |= AFMT_U16_LE; } // // prog_dmabuf_adc performs a stop_adc() but that is // ok since we really haven't started the DMA yet. // prog_codec(s, CS_TYPE_ADC); prog_dmabuf_adc(s); s->conversion = 1; } spin_lock_irqsave(&s->lock, flags); s->ena |= FMODE_READ; /* Nothing to do really, I am probably already DMAing... XXXKW when do I get here, and is there more I should do? */ spin_unlock_irqrestore(&s->lock, flags); CS_DBGOUT(CS_PARMS, 6, printk(KERN_INFO "cs4297a: start_adc(): start adc\n")); } CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4297a: start_adc()-\n"));}// call with spinlock held! static void cs4297a_update_ptr(struct cs4297a_state *s, int intflag){ int good_diff, diff, diff2; u64 *data_p, data; u32 *s_ptr; unsigned hwptr; u32 status; serdma_t *d; serdma_descr_t *descr; // update ADC pointer status = intflag ? in64(SS_CSR(R_SER_STATUS)) : 0; if ((s->ena & FMODE_READ) || (status & (M_SYNCSER_RX_EOP_COUNT))) { d = &s->dma_adc; hwptr = (unsigned) (((in64(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_RX)) & M_DMA_CURDSCR_ADDR) - d->descrtab_phys) / sizeof(serdma_descr_t)); if (s->ena & FMODE_READ) { CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4297a: upd_rcv sw->hw->hw %x/%x/%x (int-%d)n", d->swptr, d->hwptr, hwptr, intflag)); /* Number of DMA buffers available for software: */ diff2 = diff = (d->ringsz + hwptr - d->hwptr) % d->ringsz; d->hwptr = hwptr; good_diff = 0; s_ptr = (u32 *)&(d->dma_buf[d->swptr*4]); descr = &d->descrtab[d->swptr]; while (diff2--) { u64 data = *(u64 *)s_ptr; u64 descr_a; u16 left, right; descr_a = descr->descr_a; descr->descr_a &= ~M_DMA_SERRX_SOP; if ((descr_a & M_DMA_DSCRA_A_ADDR) != PHYSADDR((int)s_ptr)) { printk(KERN_ERR "cs4297a: RX Bad address (read)\n"); } if (((data & 0x9800000000000000) != 0x9800000000000000) || (!(descr_a & M_DMA_SERRX_SOP)) || (G_DMA_DSCRB_PKT_SIZE(descr->descr_b) != FRAME_BYTES)) { s->stats.rx_bad++; printk(KERN_DEBUG "cs4297a: RX Bad attributes (read)\n"); continue; } s->stats.rx_good++; if ((data >> 61) == 7) { s->read_value = (data >> 12) & 0xffff; s->read_reg = (data >> 40) & 0x7f; wake_up(&d->reg_wait); } if (d->count && (d->sb_hwptr == d->sb_swptr)) { s->stats.rx_overflow++; printk(KERN_DEBUG "cs4297a: RX overflow\n"); continue; } good_diff++; left = ((s_ptr[1] & 0xff) << 8) | ((s_ptr[2] >> 24) & 0xff); right = (s_ptr[2] >> 4) & 0xffff; *d->sb_hwptr++ = left; *d->sb_hwptr++ = right; if (d->sb_hwptr == d->sb_end) d->sb_hwptr = d->sample_buf; descr++; if (descr == d->descrtab_end) { descr = d->descrtab; s_ptr = (u32 *)s->dma_adc.dma_buf; } else { s_ptr += 8; } } d->total_bytes += good_diff * FRAME_SAMPLE_BYTES; d->count += good_diff * FRAME_SAMPLE_BYTES; if (d->count > d->sbufsz) { printk(KERN_ERR "cs4297a: bogus receive overflow!!\n"); } d->swptr = (d->swptr + diff) % d->ringsz; out64(diff, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); if (d->mapped) { if (d->count >= (signed) d->fragsize) wake_up(&d->wait); } else { if (d->count > 0) { CS_DBGOUT(CS_WAVE_READ, 4, printk(KERN_INFO "cs4297a: update count -> %d\n", d->count)); wake_up(&d->wait); } } } else { /* Receive is going even if no one is listening (for register accesses and to avoid FIFO overrun) */ diff2 = diff = (hwptr + d->ringsz - d->hwptr) % d->ringsz; if (!diff) { printk(KERN_ERR "cs4297a: RX full or empty?\n"); } descr = &d->descrtab[d->swptr]; data_p = &d->dma_buf[d->swptr*4]; /* Force this to happen at least once; I got here because of an interrupt, so there must be a buffer to process. */ do { data = *data_p; if ((descr->descr_a & M_DMA_DSCRA_A_ADDR) != PHYSADDR((int)data_p)) { printk(KERN_ERR "cs4297a: RX Bad address %d (%x %x)\n", d->swptr, (int)(descr->descr_a & M_DMA_DSCRA_A_ADDR), (int)PHYSADDR((int)data_p)); } if (!(data & (1LL << 63)) || !(descr->descr_a & M_DMA_SERRX_SOP) || (G_DMA_DSCRB_PKT_SIZE(descr->descr_b) != FRAME_BYTES)) { s->stats.rx_bad++; printk(KERN_DEBUG "cs4297a: RX Bad attributes\n"); } else { s->stats.rx_good++; if ((data >> 61) == 7) { s->read_value = (data >> 12) & 0xffff; s->read_reg = (data >> 40) & 0x7f; wake_up(&d->reg_wait); } } descr->descr_a &= ~M_DMA_SERRX_SOP; descr++; d->swptr++; data_p += 4; if (descr == d->descrtab_end) { descr = d->descrtab; d->swptr = 0; data_p = d->dma_buf; } out64(1, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); } while (--diff); d->hwptr = hwptr; CS_DBGOUT(CS_DESCR, 6, printk(KERN_INFO "cs4297a: hw/sw %x/%x\n", d->hwptr, d->swptr)); } CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO "cs4297a: cs4297a_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n", (unsigned)s, d->hwptr, d->total_bytes, d->count)); } /* XXXKW worry about s->reg_request -- there is a starvation case if s->ena has FMODE_WRITE on, but the client isn't doing writes */ // update DAC pointer // // check for end of buffer, means that we are going to wait for another interrupt // to allow silence to fill the fifos on the part, to keep pops down to a minimum. // if (s->ena & FMODE_WRITE) { serdma_t *d = &s->dma_dac; hwptr = (unsigned) (((in64(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - d->descrtab_phys) / sizeof(serdma_descr_t)); diff = (d->ringsz + hwptr - d->hwptr) % d->ringsz; CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO "cs4297a: cs4297a_update_ptr(): hw/hw/sw %x/%x/%x diff %d count %d\n", d->hwptr, hwptr, d->swptr, diff, d->count)); d->hwptr = hwptr; /* XXXKW stereo? conversion? Just assume 2 16-bit samples for now */ d->total_bytes += diff * FRAME_SAMPLE_BYTES; if (d->mapped) { d->count += diff * FRAME_SAMPLE_BYTES; if (d->count >= d->fragsize) { d->wakeup = 1; wake_up(&d->wait); if (d->count > d->sbufsz) d->count &= d->sbufsz - 1; } } else { d->count -= diff * FRAME_SAMPLE_BYTES; if (d->count <= 0) { // // fill with silence, and do not shut down the DAC. // Continue to play silence until the _release. // CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO "cs4297a: cs4297a_update_ptr(): memset %d at 0x%.8x for %d size \n", (unsigned)(s->prop_dac.fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, (unsigned)d->dma_buf, d->ringsz)); memset(d->dma_buf, 0, d->ringsz * FRAME_BYTES); if (d->count < 0) { d->underrun = 1; s->stats.tx_underrun++; d->count = 0; CS_DBGOUT(CS_ERROR, 9, printk(KERN_INFO "cs4297a: cs4297a_update_ptr(): underrun\n")); } } else if (d->count <= (signed) d->fragsize && !d->endcleared) { /* XXXKW what is this for? */ clear_advance(d->dma_buf, d->sbufsz, d->swptr, d->fragsize, 0); d->endcleared = 1; } if ( (d->count <= (signed) d->sbufsz/2) || intflag) { CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO "cs4297a: update count -> %d\n", d->count)); wake_up(&d->wait); } } CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO "cs4297a: cs4297a_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n", (unsigned) s, d->hwptr, d->total_bytes, d->count)); }}static int mixer_ioctl(struct cs4297a_state *s, unsigned int cmd, unsigned long arg){ // Index to mixer_src[] is value of AC97 Input Mux Select Reg. // Value of array member is recording source Device ID Mask. static const unsigned int mixer_src[8] = { SOUND_MASK_MIC, SOUND_MASK_CD, 0, SOUND_MASK_LINE1, SOUND_MASK_LINE, SOUND_MASK_VOLUME, 0, 0 }; // Index of mixtable1[] member is Device ID // and must be <= SOUND_MIXER_NRDEVICES. // Value of array member is index into s->mix.vol[] static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = { [SOUND_MIXER_PCM] = 1, // voice [SOUND_MIXER_LINE1] = 2, // AUX [SOUND_MIXER_CD] = 3, // CD [SOUND_MIXER_LINE] = 4, // Line [SOUND_MIXER_SYNTH] = 5, // FM [SOUND_MIXER_MIC] = 6, // Mic [SOUND_MIXER_SPEAKER] = 7, // Speaker [SOUND_MIXER_RECLEV] = 8, // Recording level [SOUND_MIXER_VOLUME] = 9 // Master Volume }; static const unsigned mixreg[] = { AC97_PCMOUT_VOL, AC97_AUX_VOL, AC97_CD_VOL, AC97_LINEIN_VOL }; unsigned char l, r, rl, rr, vidx; unsigned char attentbl[11] = { 63, 42, 26, 17, 14, 11, 8, 6, 4, 2, 0 }; unsigned temp1; int i, val; VALIDATE_STATE(s); CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs4297a: mixer_ioctl(): s=0x%.8x cmd=0x%.8x\n", (unsigned) s, cmd));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?