📄 maestro3.c
字号:
static struct rec_vals { u16 addr, val;} rv[] = { {CDATA_LEFT_VOLUME, ARB_VOLUME}, {CDATA_RIGHT_VOLUME, ARB_VOLUME}, {SRC3_DIRECTION_OFFSET, 1} , /* +1, +2 are stereo/16 bit */ {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */ {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */ {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */ {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */ {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */ {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */ {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */ {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */ {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */ {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */ {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */ {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */ {SRC3_DIRECTION_OFFSET + 16, 50},/* numin */ {SRC3_DIRECTION_OFFSET + 17, 8}, /* numout */ {SRC3_DIRECTION_OFFSET + 18, 0}, /* numstage */ {SRC3_DIRECTION_OFFSET + 19, 0}, /* coef */ {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */ {SRC3_DIRECTION_OFFSET + 21, 0}, /* booster */ {SRC3_DIRECTION_OFFSET + 22, 0xff} /* skip lpf */};/* again, passed mode is alrady shifted/masked */static void m3_rec_setup(struct m3_state *s, int mode, u32 rate, void *buffer, int size){ int dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2); int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2); int dsp_in_buffer = s->adc_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2); int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1; struct dmabuf *db = &s->dma_adc; int i; DPRINTK(DPSTR, "rec_setup mode=%d rate=%d buf=%p len=%d.\n", mode, rate, buffer, size);#define LO(x) ((x) & 0xffff)#define HI(x) LO((x) >> 16) /* host dma buffer pointers */ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_HOST_SRC_ADDRL, LO(virt_to_bus(buffer))); m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_HOST_SRC_ADDRH, HI(virt_to_bus(buffer))); m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1L, LO(virt_to_bus(buffer) + size)); m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1H, HI(virt_to_bus(buffer) + size)); m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_HOST_SRC_CURRENTL, LO(virt_to_bus(buffer))); m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_HOST_SRC_CURRENTH, HI(virt_to_bus(buffer)));#undef LO#undef HI /* dsp buffers */ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_IN_BUF_BEGIN, dsp_in_buffer); m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_IN_BUF_END_PLUS_1, dsp_in_buffer + (dsp_in_size / 2)); m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_IN_BUF_HEAD, dsp_in_buffer); m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_IN_BUF_TAIL, dsp_in_buffer); m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_OUT_BUF_BEGIN, dsp_out_buffer); m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_OUT_BUF_END_PLUS_1, dsp_out_buffer + (dsp_out_size / 2)); m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_OUT_BUF_HEAD, dsp_out_buffer); m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_OUT_BUF_TAIL, dsp_out_buffer); /* * some per client initializers */ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + SRC3_DIRECTION_OFFSET + 12, s->adc_inst.data + 40 + 8); /* tell it which way dma is going? */ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + CDATA_DMA_CONTROL, DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR); /* * set an armload of static initializers */ for(i = 0 ; i < (sizeof(rv) / sizeof(rv[0])) ; i++) m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, s->adc_inst.data + rv[i].addr, rv[i].val); /* * put us in the lists if we're not already there */ if(db->in_lists == 0) { db->adc1_index = m3_add_list(s->card, &s->card->adc1_list, s->adc_inst.data >> DP_SHIFT_COUNT); db->dma_index = m3_add_list(s->card, &s->card->dma_list, s->adc_inst.data >> DP_SHIFT_COUNT); db->msrc_index = m3_add_list(s->card, &s->card->msrc_list, s->adc_inst.data >> DP_SHIFT_COUNT); db->in_lists = 1; } set_adc_rate(s,rate); start_adc(s);}/* --------------------------------------------------------------------- */static void set_dmaa(struct m3_state *s, unsigned int addr, unsigned int count){ DPRINTK(DPINT,"set_dmaa??\n");}static void set_dmac(struct m3_state *s, unsigned int addr, unsigned int count){ DPRINTK(DPINT,"set_dmac??\n");}u32 get_dma_pos(struct m3_card *card, int instance_addr){ u16 hi = 0, lo = 0; int retry = 10; /* * try and get a valid answer */ while(retry--) { hi = m3_assp_read(card, MEMTYPE_INTERNAL_DATA, instance_addr + CDATA_HOST_SRC_CURRENTH); lo = m3_assp_read(card, MEMTYPE_INTERNAL_DATA, instance_addr + CDATA_HOST_SRC_CURRENTL); if(hi == m3_assp_read(card, MEMTYPE_INTERNAL_DATA, instance_addr + CDATA_HOST_SRC_CURRENTH)) break; } return lo | (hi<<16);}u32 get_dmaa(struct m3_state *s){ u32 offset; offset = get_dma_pos(s->card, s->dac_inst.data) - virt_to_bus(s->dma_dac.rawbuf); DPRINTK(DPINT,"get_dmaa: 0x%08x\n",offset); return offset;}u32 get_dmac(struct m3_state *s){ u32 offset; offset = get_dma_pos(s->card, s->adc_inst.data) - virt_to_bus(s->dma_adc.rawbuf); DPRINTK(DPINT,"get_dmac: 0x%08x\n",offset); return offset;}static void m3_interrupt(int irq, void *dev_id, struct pt_regs *regs);static int prog_dmabuf(struct m3_state *s, unsigned rec){ struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac; unsigned rate = rec ? s->rateadc : s->ratedac; unsigned bytepersec; unsigned bufs; unsigned char fmt; unsigned long flags; spin_lock_irqsave(&s->lock, flags); fmt = s->fmt; if (rec) { stop_adc(s); fmt >>= ESS_ADC_SHIFT; } else { stop_dac(s); fmt >>= ESS_DAC_SHIFT; } fmt &= ESS_FMT_MASK; db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; bytepersec = rate << sample_shift[fmt]; bufs = PAGE_SIZE << db->buforder; if (db->ossfragshift) { if ((1000 << db->ossfragshift) < bytepersec) db->fragshift = ld2(bytepersec/1000); else db->fragshift = db->ossfragshift; } else { db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); if (db->fragshift < 3) db->fragshift = 3; } db->numfrag = bufs >> db->fragshift; while (db->numfrag < 4 && db->fragshift > 3) { db->fragshift--; db->numfrag = bufs >> db->fragshift; } db->fragsize = 1 << db->fragshift; if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) db->numfrag = db->ossmaxfrags; db->fragsamples = db->fragsize >> sample_shift[fmt]; db->dmasize = db->numfrag << db->fragshift; DPRINTK(DPSTR,"prog_dmabuf: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize); memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize); if (rec) m3_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize); else m3_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize); db->ready = 1; spin_unlock_irqrestore(&s->lock, flags); return 0;}static void clear_advance(struct m3_state *s){ unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80; unsigned char *buf = s->dma_dac.rawbuf; unsigned bsize = s->dma_dac.dmasize; unsigned bptr = s->dma_dac.swptr; unsigned len = s->dma_dac.fragsize; if (bptr + len > bsize) { unsigned x = bsize - bptr; memset(buf + bptr, c, x); /* account for wrapping? */ bptr = 0; len -= x; } memset(buf + bptr, c, len);}/* call with spinlock held! */static void m3_update_ptr(struct m3_state *s){ unsigned hwptr; int diff; /* update ADC pointer */ if (s->dma_adc.ready) { hwptr = get_dmac(s) % s->dma_adc.dmasize; diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; s->dma_adc.hwptr = hwptr; s->dma_adc.total_bytes += diff; s->dma_adc.count += diff; if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) wake_up(&s->dma_adc.wait); if (!s->dma_adc.mapped) { if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { stop_adc(s); /* brute force everyone back in sync, sigh */ s->dma_adc.count = 0; s->dma_adc.swptr = 0; s->dma_adc.hwptr = 0; s->dma_adc.error++; } } } /* update DAC pointer */ if (s->dma_dac.ready) { hwptr = get_dmaa(s) % s->dma_dac.dmasize; diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; DPRINTK(DPINT,"updating dac: hwptr: %6d diff: %6d count: %6d\n", hwptr,diff,s->dma_dac.count); s->dma_dac.hwptr = hwptr; s->dma_dac.total_bytes += diff; if (s->dma_dac.mapped) { s->dma_dac.count += diff; if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) { wake_up(&s->dma_dac.wait); } } else { s->dma_dac.count -= diff; if (s->dma_dac.count <= 0) { DPRINTK(DPCRAP,"underflow! diff: %d (0x%x) count: %d (0x%x) hw: %d (0x%x) sw: %d (0x%x)\n", diff, diff, s->dma_dac.count, s->dma_dac.count, hwptr, hwptr, s->dma_dac.swptr, s->dma_dac.swptr); stop_dac(s); /* brute force everyone back in sync, sigh */ s->dma_dac.count = 0; s->dma_dac.swptr = hwptr; s->dma_dac.error++; } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { clear_advance(s); s->dma_dac.endcleared = 1; } if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) { wake_up(&s->dma_dac.wait); DPRINTK(DPINT,"waking up DAC count: %d sw: %d hw: %d\n", s->dma_dac.count, s->dma_dac.swptr, hwptr); } } }}static void m3_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct m3_card *c = (struct m3_card *)dev_id; struct m3_state *s = &c->channels[0]; u8 status; status = inb(c->iobase+0x1A); if(status == 0xff) return; /* presumably acking the ints? */ outw(status, c->iobase+0x1A); if(c->in_suspend) return; /* * ack an assp int if its running * and has an int pending */ if( status & ASSP_INT_PENDING) { u8 ctl = inb(c->iobase + ASSP_CONTROL_B); if( !(ctl & STOP_ASSP_CLOCK)) { ctl = inb(c->iobase + ASSP_HOST_INT_STATUS ); if(ctl & DSP2HOST_REQ_TIMER) { outb( DSP2HOST_REQ_TIMER, c->iobase + ASSP_HOST_INT_STATUS); /* update adc/dac info if it was a timer int */ spin_lock(&s->lock); m3_update_ptr(s); spin_unlock(&s->lock); } } } /* XXX is this needed? */ if(status & 0x40) outb(0x40, c->iobase+0x1A);}/* --------------------------------------------------------------------- */static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value in %s\n";#define VALIDATE_MAGIC(FOO,MAG) \({ \ if (!(FOO) || (FOO)->magic != MAG) { \ printk(invalid_magic,__FUNCTION__); \ return -ENXIO; \ } \})#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,M3_STATE_MAGIC)#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,M3_CARD_MAGIC)/* --------------------------------------------------------------------- */static int drain_dac(struct m3_state *s, int nonblock){ DECLARE_WAITQUEUE(wait,current); unsigned long flags; int count; signed long tmo; if (s->dma_dac.mapped || !s->dma_dac.ready)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -