📄 dbri.c
字号:
} if ((sdp & 0xf800) != sdp) { printk(KERN_ERR "DBRI: setup_pipe called " "with strange SDP value\n"); /* sdp &= 0xf800; */ } /* If this is a fixed receive pipe, arrange for an interrupt * every time its data changes */ if (D_SDP_MODE(sdp) == D_SDP_FIXED && !(sdp & D_SDP_TO_SER)) sdp |= D_SDP_CHANGE; sdp |= D_PIPE(pipe); dbri->pipes[pipe].sdp = sdp; dbri->pipes[pipe].desc = -1; dbri->pipes[pipe].first_desc = -1; reset_pipe(dbri, pipe);}/* * Lock must be held before calling this. */static void link_time_slot(struct snd_dbri *dbri, int pipe, int prevpipe, int nextpipe, int length, int cycle){ s32 *cmd; int val; if (pipe < 0 || pipe > DBRI_MAX_PIPE || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) { printk(KERN_ERR "DBRI: link_time_slot called with illegal pipe number\n"); return; } if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[prevpipe].sdp == 0 || dbri->pipes[nextpipe].sdp == 0) { printk(KERN_ERR "DBRI: link_time_slot called " "on uninitialized pipe\n"); return; } dbri->pipes[prevpipe].nextpipe = pipe; dbri->pipes[pipe].nextpipe = nextpipe; dbri->pipes[pipe].length = length; cmd = dbri_cmdlock(dbri, 4); if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) { /* Deal with CHI special case: * "If transmission on edges 0 or 1 is desired, then cycle n * (where n = # of bit times per frame...) must be used." * - DBRI data sheet, page 11 */ if (prevpipe == 16 && cycle == 0) cycle = dbri->chi_bpf; val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe; *(cmd++) = DBRI_CMD(D_DTS, 0, val); *(cmd++) = 0; *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); } else { val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe; *(cmd++) = DBRI_CMD(D_DTS, 0, val); *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); *(cmd++) = 0; } *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); dbri_cmdsend(dbri, cmd, 4);}#if 0/* * Lock must be held before calling this. */static void unlink_time_slot(struct snd_dbri *dbri, int pipe, enum in_or_out direction, int prevpipe, int nextpipe){ s32 *cmd; int val; if (pipe < 0 || pipe > DBRI_MAX_PIPE || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) { printk(KERN_ERR "DBRI: unlink_time_slot called with illegal pipe number\n"); return; } cmd = dbri_cmdlock(dbri, 4); if (direction == PIPEinput) { val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe; *(cmd++) = DBRI_CMD(D_DTS, 0, val); *(cmd++) = D_TS_NEXT(nextpipe); *(cmd++) = 0; } else { val = D_DTS_VO | D_DTS_DEL | D_DTS_PRVOUT(prevpipe) | pipe; *(cmd++) = DBRI_CMD(D_DTS, 0, val); *(cmd++) = 0; *(cmd++) = D_TS_NEXT(nextpipe); } *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); dbri_cmdsend(dbri, cmd, 4);}#endif/* xmit_fixed() / recv_fixed() * * Transmit/receive data on a "fixed" pipe - i.e, one whose contents are not * expected to change much, and which we don't need to buffer. * The DBRI only interrupts us when the data changes (receive pipes), * or only changes the data when this function is called (transmit pipes). * Only short pipes (numbers 16-31) can be used in fixed data mode. * * These function operate on a 32-bit field, no matter how large * the actual time slot is. The interrupt handler takes care of bit * ordering and alignment. An 8-bit time slot will always end up * in the low-order 8 bits, filled either MSB-first or LSB-first, * depending on the settings passed to setup_pipe(). * * Lock must not be held before calling it. */static void xmit_fixed(struct snd_dbri *dbri, int pipe, unsigned int data){ s32 *cmd; unsigned long flags; if (pipe < 16 || pipe > DBRI_MAX_PIPE) { printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n"); return; } if (D_SDP_MODE(dbri->pipes[pipe].sdp) == 0) { printk(KERN_ERR "DBRI: xmit_fixed: " "Uninitialized pipe %d\n", pipe); return; } if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) { printk(KERN_ERR "DBRI: xmit_fixed: Non-fixed pipe %d\n", pipe); return; } if (!(dbri->pipes[pipe].sdp & D_SDP_TO_SER)) { printk(KERN_ERR "DBRI: xmit_fixed: Called on receive pipe %d\n", pipe); return; } /* DBRI short pipes always transmit LSB first */ if (dbri->pipes[pipe].sdp & D_SDP_MSB) data = reverse_bytes(data, dbri->pipes[pipe].length); cmd = dbri_cmdlock(dbri, 3); *(cmd++) = DBRI_CMD(D_SSP, 0, pipe); *(cmd++) = data; *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); spin_lock_irqsave(&dbri->lock, flags); dbri_cmdsend(dbri, cmd, 3); spin_unlock_irqrestore(&dbri->lock, flags); dbri_cmdwait(dbri);}static void recv_fixed(struct snd_dbri *dbri, int pipe, volatile __u32 *ptr){ if (pipe < 16 || pipe > DBRI_MAX_PIPE) { printk(KERN_ERR "DBRI: recv_fixed called with " "illegal pipe number\n"); return; } if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) { printk(KERN_ERR "DBRI: recv_fixed called on " "non-fixed pipe %d\n", pipe); return; } if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) { printk(KERN_ERR "DBRI: recv_fixed called on " "transmit pipe %d\n", pipe); return; } dbri->pipes[pipe].recv_fixed_ptr = ptr;}/* setup_descs() * * Setup transmit/receive data on a "long" pipe - i.e, one associated * with a DMA buffer. * * Only pipe numbers 0-15 can be used in this mode. * * This function takes a stream number pointing to a data buffer, * and work by building chains of descriptors which identify the * data buffers. Buffers too large for a single descriptor will * be spread across multiple descriptors. * * All descriptors create a ring buffer. * * Lock must be held before calling this. */static int setup_descs(struct snd_dbri *dbri, int streamno, unsigned int period){ struct dbri_streaminfo *info = &dbri->stream_info[streamno]; __u32 dvma_buffer; int desc; int len; int first_desc = -1; int last_desc = -1; if (info->pipe < 0 || info->pipe > 15) { printk(KERN_ERR "DBRI: setup_descs: Illegal pipe number\n"); return -2; } if (dbri->pipes[info->pipe].sdp == 0) { printk(KERN_ERR "DBRI: setup_descs: Uninitialized pipe %d\n", info->pipe); return -2; } dvma_buffer = info->dvma_buffer; len = info->size; if (streamno == DBRI_PLAY) { if (!(dbri->pipes[info->pipe].sdp & D_SDP_TO_SER)) { printk(KERN_ERR "DBRI: setup_descs: " "Called on receive pipe %d\n", info->pipe); return -2; } } else { if (dbri->pipes[info->pipe].sdp & D_SDP_TO_SER) { printk(KERN_ERR "DBRI: setup_descs: Called on transmit pipe %d\n", info->pipe); return -2; } /* Should be able to queue multiple buffers * to receive on a pipe */ if (pipe_active(dbri, info->pipe)) { printk(KERN_ERR "DBRI: recv_on_pipe: " "Called on active pipe %d\n", info->pipe); return -2; } /* Make sure buffer size is multiple of four */ len &= ~3; } /* Free descriptors if pipe has any */ desc = dbri->pipes[info->pipe].first_desc; if (desc >= 0) do { dbri->dma->desc[desc].ba = 0; dbri->dma->desc[desc].nda = 0; desc = dbri->next_desc[desc]; } while (desc != -1 && desc != dbri->pipes[info->pipe].first_desc); dbri->pipes[info->pipe].desc = -1; dbri->pipes[info->pipe].first_desc = -1; desc = 0; while (len > 0) { int mylen; for (; desc < DBRI_NO_DESCS; desc++) { if (!dbri->dma->desc[desc].ba) break; } if (desc == DBRI_NO_DESCS) { printk(KERN_ERR "DBRI: setup_descs: No descriptors\n"); return -1; } if (len > DBRI_TD_MAXCNT) mylen = DBRI_TD_MAXCNT; /* 8KB - 4 */ else mylen = len; if (mylen > period) mylen = period; dbri->next_desc[desc] = -1; dbri->dma->desc[desc].ba = dvma_buffer; dbri->dma->desc[desc].nda = 0; if (streamno == DBRI_PLAY) { dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen); dbri->dma->desc[desc].word4 = 0; dbri->dma->desc[desc].word1 |= DBRI_TD_F | DBRI_TD_B; } else { dbri->dma->desc[desc].word1 = 0; dbri->dma->desc[desc].word4 = DBRI_RD_B | DBRI_RD_BCNT(mylen); } if (first_desc == -1) first_desc = desc; else { dbri->next_desc[last_desc] = desc; dbri->dma->desc[last_desc].nda = dbri->dma_dvma + dbri_dma_off(desc, desc); } last_desc = desc; dvma_buffer += mylen; len -= mylen; } if (first_desc == -1 || last_desc == -1) { printk(KERN_ERR "DBRI: setup_descs: " " Not enough descriptors available\n"); return -1; } dbri->dma->desc[last_desc].nda = dbri->dma_dvma + dbri_dma_off(desc, first_desc); dbri->next_desc[last_desc] = first_desc; dbri->pipes[info->pipe].first_desc = first_desc; dbri->pipes[info->pipe].desc = first_desc;#ifdef DBRI_DEBUG for (desc = first_desc; desc != -1;) { dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n", desc, dbri->dma->desc[desc].word1, dbri->dma->desc[desc].ba, dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4); desc = dbri->next_desc[desc]; if (desc == first_desc) break; }#endif return 0;}/******************************************************************************************************* DBRI - CHI interface ********************************************************************************************************The CHI is a four-wire (clock, frame sync, data in, data out) time-divisionmultiplexed serial interface which the DBRI can operate in either master(give clock/frame sync) or slave (take clock/frame sync) mode.*/enum master_or_slave { CHImaster, CHIslave };/* * Lock must not be held before calling it. */static void reset_chi(struct snd_dbri *dbri, enum master_or_slave master_or_slave, int bits_per_frame){ s32 *cmd; int val; /* Set CHI Anchor: Pipe 16 */ cmd = dbri_cmdlock(dbri, 4); val = D_DTS_VO | D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(16) | D_PIPE(16) | D_DTS_PRVOUT(16); *(cmd++) = DBRI_CMD(D_DTS, 0, val); *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); dbri_cmdsend(dbri, cmd, 4); dbri->pipes[16].sdp = 1; dbri->pipes[16].nextpipe = 16; cmd = dbri_cmdlock(dbri, 4); if (master_or_slave == CHIslave) { /* Setup DBRI for CHI Slave - receive clock, frame sync (FS) * * CHICM = 0 (slave mode, 8 kHz frame rate) * IR = give immediate CHI status interrupt * EN = give CHI status interrupt upon change */ *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0)); } else { /* Setup DBRI for CHI Master - generate clock, FS * * BPF = bits per 8 kHz frame * 12.288 MHz / CHICM_divisor = clock rate * FD = 1 - drive CHIFS on rising edge of CHICK */ int clockrate = bits_per_frame * 8; int divisor = 12288 / clockrate; if (divisor > 255 || divisor * clockrate != 12288) printk(KERN_ERR "DBRI: illegal bits_per_frame " "in setup_chi\n"); *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD | D_CHI_BPF(bits_per_frame)); } dbri->chi_bpf = bits_per_frame; /* CHI Data Mode * * RCE = 0 - receive on falling edge of CHICK * XCE = 1 - transmit on rising edge of CHICK * XEN = 1 - enable transmitter
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -