📄 dbri.c
字号:
cmd = dbri_cmdlock(dbri); *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P | D_SDP_C | D_SDP_2SAME); *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, td); dbri_cmdsend(dbri, cmd); } if (code == D_INTR_FXDT) { /* FXDT - Fixed data change */ if (dbri->pipes[channel].sdp & D_SDP_MSB) val = reverse_bytes(val, dbri->pipes[channel].length); if (dbri->pipes[channel].recv_fixed_ptr) *(dbri->pipes[channel].recv_fixed_ptr) = val; }}/* dbri_process_interrupt_buffer advances through the DBRI's interrupt * buffer until it finds a zero word (indicating nothing more to do * right now). Non-zero words require processing and are handed off * to dbri_process_one_interrupt AFTER advancing the pointer. This * order is important since we might recurse back into this function * and need to make sure the pointer has been advanced first. */static void dbri_process_interrupt_buffer(struct dbri *dbri){ s32 x; while ((x = dbri->dma->intr[dbri->dbri_irqp]) != 0) { dbri->dma->intr[dbri->dbri_irqp] = 0; dbri->dbri_irqp++; if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK)) dbri->dbri_irqp = 1; else if ((dbri->dbri_irqp & (DBRI_INT_BLK-1)) == 0) dbri->dbri_irqp++; tprintk(("dbri->dbri_irqp == %d\n", dbri->dbri_irqp)); dbri_process_one_interrupt(dbri, x); }}static void dbri_intr(int irq, void *opaque, struct pt_regs *regs){ struct dbri *dbri = (struct dbri *) opaque; int x; /* * Read it, so the interrupt goes away. */ x = sbus_readl(dbri->regs + REG1); dprintk(D_INT, ("DBRI: Interrupt! (reg1=0x%08x)\n", x)); if (x & (D_MRR|D_MLE|D_LBG|D_MBE)) { u32 tmp; if(x & D_MRR) printk("DBRI: Multiple Error Ack on SBus\n"); if(x & D_MLE) printk("DBRI: Multiple Late Error on SBus\n"); if(x & D_LBG) printk("DBRI: Lost Bus Grant on SBus\n"); if(x & D_MBE) printk("DBRI: Burst Error on SBus\n"); /* Some of these SBus errors cause the chip's SBus circuitry * to be disabled, so just re-enable and try to keep going. * * The only one I've seen is MRR, which will be triggered * if you let a transmit pipe underrun, then try to CDP it. * * If these things persist, we should probably reset * and re-init the chip. */ tmp = sbus_readl(dbri->regs + REG0); tmp &= ~(D_D); sbus_writel(tmp, dbri->regs + REG0); }#if 0 if (!(x & D_IR)) /* Not for us */ return;#endif dbri_process_interrupt_buffer(dbri);}/******************************************************************************************************* DBRI data pipe management ***************************************************************************************************While DBRI control functions use the command and interrupt buffers, themain data path takes the form of data pipes, which can be short (commandand interrupt driven), or long (attached to DMA buffers). These functionsprovide a rudimentary means of setting up and managing the DBRI's pipes,but the calling functions have to make sure they respect the pipes' linkedlist ordering, among other things. The transmit and receive functionshere interface closely with the transmit and receive interrupt code.*/static int pipe_active(struct dbri *dbri, int pipe){ return (dbri->pipes[pipe].desc != -1);}/* reset_pipe(dbri, pipe) * * Called on an in-use pipe to clear anything being transmitted or received */static void reset_pipe(struct dbri *dbri, int pipe){ int sdp; int desc; volatile int *cmd; if (pipe < 0 || pipe > 31) { printk("DBRI: reset_pipe called with illegal pipe number\n"); return; } sdp = dbri->pipes[pipe].sdp; if (sdp == 0) { printk("DBRI: reset_pipe called on uninitialized pipe\n"); return; } cmd = dbri_cmdlock(dbri); *(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P); *(cmd++) = 0; dbri_cmdsend(dbri, cmd); desc = dbri->pipes[pipe].desc; while (desc != -1) { void *buffer = dbri->descs[desc].buffer; void (*output_callback) (void *, int) = dbri->descs[desc].output_callback; void *output_callback_arg = dbri->descs[desc].output_callback_arg; void (*input_callback) (void *, int, unsigned int) = dbri->descs[desc].input_callback; void *input_callback_arg = dbri->descs[desc].input_callback_arg; if (buffer) sbus_unmap_single(dbri->sdev, dbri->descs[desc].buffer_dvma, dbri->descs[desc].len, output_callback != NULL ? SBUS_DMA_TODEVICE : SBUS_DMA_FROMDEVICE); dbri->descs[desc].inuse = 0; desc = dbri->descs[desc].next; if (output_callback) output_callback(output_callback_arg, -1); if (input_callback) input_callback(input_callback_arg, -1, 0); } dbri->pipes[pipe].desc = -1;}static void setup_pipe(struct dbri *dbri, int pipe, int sdp){ if (pipe < 0 || pipe > 31) { printk("DBRI: setup_pipe called with illegal pipe number\n"); return; } if ((sdp & 0xf800) != sdp) { printk("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; reset_pipe(dbri, pipe);}static void link_time_slot(struct dbri *dbri, int pipe, enum in_or_out direction, int basepipe, int length, int cycle){ volatile s32 *cmd; int val; int prevpipe; int nextpipe; if (pipe < 0 || pipe > 31 || basepipe < 0 || basepipe > 31) { printk("DBRI: link_time_slot called with illegal pipe number\n"); return; } if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[basepipe].sdp == 0) { printk("DBRI: link_time_slot called on uninitialized pipe\n"); return; } /* 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 (basepipe == 16 && direction == PIPEoutput && cycle == 0) cycle = dbri->chi_bpf; if (basepipe == pipe) { prevpipe = pipe; nextpipe = pipe; } else { /* We're not initializing a new linked list (basepipe != pipe), * so run through the linked list and find where this pipe * should be sloted in, based on its cycle. CHI confuses * things a bit, since it has a single anchor for both its * transmit and receive lists. */ if (basepipe == 16) { if (direction == PIPEinput) { prevpipe = dbri->chi_in_pipe; } else { prevpipe = dbri->chi_out_pipe; } } else { prevpipe = basepipe; } nextpipe = dbri->pipes[prevpipe].nextpipe; while (dbri->pipes[nextpipe].cycle < cycle && dbri->pipes[nextpipe].nextpipe != basepipe) { prevpipe = nextpipe; nextpipe = dbri->pipes[nextpipe].nextpipe; } } if (prevpipe == 16) { if (direction == PIPEinput) { dbri->chi_in_pipe = pipe; } else { dbri->chi_out_pipe = pipe; } } else { dbri->pipes[prevpipe].nextpipe = pipe; } dbri->pipes[pipe].nextpipe = nextpipe; dbri->pipes[pipe].cycle = cycle; dbri->pipes[pipe].length = length; cmd = dbri_cmdlock(dbri); if (direction == PIPEinput) { 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; } else { 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); } dbri_cmdsend(dbri, cmd);}/* I don't use this function, so it's basically untested. */static void unlink_time_slot(struct dbri *dbri, int pipe, enum in_or_out direction, int prevpipe, int nextpipe){ volatile s32 *cmd; int val; if (pipe < 0 || pipe > 31 || prevpipe < 0 || prevpipe > 31) { printk("DBRI: unlink_time_slot called with illegal pipe number\n"); return; } cmd = dbri_cmdlock(dbri); 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); } dbri_cmdsend(dbri, cmd);}/* 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() */static void xmit_fixed(struct dbri *dbri, int pipe, unsigned int data){ volatile s32 *cmd; if (pipe < 16 || pipe > 31) { printk("DBRI: xmit_fixed: Illegal pipe number\n"); return; } if (D_SDP_MODE(dbri->pipes[pipe].sdp) == 0) { printk("DBRI: xmit_fixed: Uninitialized pipe %d\n", pipe); return; } if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) { printk("DBRI: xmit_fixed: Non-fixed pipe %d\n", pipe); return; } if (! (dbri->pipes[pipe].sdp & D_SDP_TO_SER)) { printk("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); *(cmd++) = DBRI_CMD(D_SSP, 0, pipe); *(cmd++) = data; dbri_cmdsend(dbri, cmd);}static void recv_fixed(struct dbri *dbri, int pipe, volatile __u32 *ptr){ if (pipe < 16 || pipe > 31) { printk("DBRI: recv_fixed called with illegal pipe number\n"); return; } if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) { printk("DBRI: recv_fixed called on non-fixed pipe %d\n", pipe); return; } if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) { printk("DBRI: recv_fixed called on transmit pipe %d\n", pipe); return; } dbri->pipes[pipe].recv_fixed_ptr = ptr;}/* xmit_on_pipe() / recv_on_pipe() * * 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. * * Both functions take pointer/len arguments pointing to a data buffer, * and both provide callback functions (may be NULL) to notify higher * level code when transmission/reception is complete. * * Both work by building chains of descriptors which identify the * data buffers. Buffers too large for a single descriptor will * be spread across multiple descriptors. */static void xmit_on_pipe(struct dbri *dbri, int pipe, void * buffer, unsigned int len, void (*callback)(void *, int), void * callback_arg){ volatile s32 *cmd; unsigned long flags; int td = 0; int first_td = -1; int last_td = -1; __u32 dvma_buffer, dvma_buffer_base; if (pipe < 0 || pipe > 15) { printk("DBRI: xmit_on_pipe: Illegal pipe number\n"); return; } if (dbri->pipes[pipe].sdp == 0) { printk("DBRI: xmit_on_pipe: Uninitialized pipe %d\n", pipe); return; } if (! (dbri->pipes[pipe].sdp & D_SDP_TO_SER)) { printk("DBRI: xmit_on_pipe: Called on receive pipe %d\n", pipe); return; } dvma_buffer_base = dvma_buffer = sbus_map_single(dbri->sdev, buffer, len, SBUS_DMA_TODEVICE); while (len > 0) { int mylen; for (; td < DBRI_NO_DESCS; td ++) { if (! dbri->descs[td].inuse) break; } if (td == DBRI_NO_DESCS) { printk("DBRI: xmit_on_pipe: No descriptors\n"); break; } if (len > ((1 << 13) - 1)) { mylen = (1 << 13) - 1; } else { mylen = len; } dbri->descs[td].inuse = 1; dbri->descs[td].next = -1; dbri->descs[td].buffer = NULL; dbri->descs[td].output_callback = NULL; dbri->descs[td].input_callback = NULL; dbri->dma->desc[td].word1 = DBRI_TD_CNT(mylen); dbri->dma->desc[td].ba = dvma_buffer; dbri->dma->desc[td].nda = 0; dbri->dma->desc[td].word4 = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -