📄 cx23885-core.c
字号:
cx23885_video_unregister(dev); if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) cx23885_dvb_unregister(&dev->ts1); if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) cx23885_417_unregister(dev); if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) cx23885_dvb_unregister(&dev->ts2); if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) cx23885_417_unregister(dev); cx23885_i2c_unregister(&dev->i2c_bus[2]); cx23885_i2c_unregister(&dev->i2c_bus[1]); cx23885_i2c_unregister(&dev->i2c_bus[0]); iounmap(dev->lmmio);}static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, unsigned int lines){ struct scatterlist *sg; unsigned int line, todo; /* sync instruction */ if (sync_line != NO_SYNC_LINE) *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); /* scan lines */ sg = sglist; for (line = 0; line < lines; line++) { while (offset && offset >= sg_dma_len(sg)) { offset -= sg_dma_len(sg); sg++; } if (bpl <= sg_dma_len(sg)-offset) { /* fits into current chunk */ *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ offset += bpl; } else { /* scanline needs to be split */ todo = bpl; *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL| (sg_dma_len(sg)-offset)); *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ todo -= (sg_dma_len(sg)-offset); offset = 0; sg++; while (todo > sg_dma_len(sg)) { *(rp++) = cpu_to_le32(RISC_WRITE| sg_dma_len(sg)); *(rp++) = cpu_to_le32(sg_dma_address(sg)); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ todo -= sg_dma_len(sg); sg++; } *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo); *(rp++) = cpu_to_le32(sg_dma_address(sg)); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ offset += todo; } offset += padding; } return rp;}int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines){ u32 instructions, fields; __le32 *rp; int rc; fields = 0; if (UNSET != top_offset) fields++; if (UNSET != bottom_offset) fields++; /* estimate risc mem: worst case is one write per page border + one write per scan line + syncs + jump (all 2 dwords). Padding can cause next bpl to start close to a page border. First DMA region may be smaller than PAGE_SIZE */ /* write and jump need and extra dword */ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); instructions += 2; rc = btcx_riscmem_alloc(pci, risc, instructions*12); if (rc < 0) return rc; /* write risc instructions */ rp = risc->cpu; if (UNSET != top_offset) rp = cx23885_risc_field(rp, sglist, top_offset, 0, bpl, padding, lines); if (UNSET != bottom_offset) rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, bpl, padding, lines); /* save pointer to jmp instruction address */ risc->jmp = rp; BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); return 0;}static int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, unsigned int lines){ u32 instructions; __le32 *rp; int rc; /* estimate risc mem: worst case is one write per page border + one write per scan line + syncs + jump (all 2 dwords). Here there is no padding and no sync. First DMA region may be smaller than PAGE_SIZE */ /* Jump and write need an extra dword */ instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; instructions += 1; rc = btcx_riscmem_alloc(pci, risc, instructions*12); if (rc < 0) return rc; /* write risc instructions */ rp = risc->cpu; rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines); /* save pointer to jmp instruction address */ risc->jmp = rp; BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); return 0;}int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, u32 reg, u32 mask, u32 value){ __le32 *rp; int rc; rc = btcx_riscmem_alloc(pci, risc, 4*16); if (rc < 0) return rc; /* write risc instructions */ rp = risc->cpu; *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); *(rp++) = cpu_to_le32(reg); *(rp++) = cpu_to_le32(value); *(rp++) = cpu_to_le32(mask); *(rp++) = cpu_to_le32(RISC_JUMP); *(rp++) = cpu_to_le32(risc->dma); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ return 0;}void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf){ struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb, 0, 0); videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); buf->vb.state = VIDEOBUF_NEEDS_INIT;}static void cx23885_tsport_reg_dump(struct cx23885_tsport *port){ struct cx23885_dev *dev = port->dev; dprintk(1, "%s() Register Dump\n", __func__); dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __func__, cx_read(DEV_CNTRL2)); dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __func__, cx_read(PCI_INT_MSK)); dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __func__, cx_read(AUDIO_INT_INT_MSK)); dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __func__, cx_read(AUD_INT_DMA_CTL)); dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08X\n", __func__, cx_read(AUDIO_EXT_INT_MSK)); dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08X\n", __func__, cx_read(AUD_EXT_DMA_CTL)); dprintk(1, "%s() PAD_CTRL 0x%08X\n", __func__, cx_read(PAD_CTRL)); dprintk(1, "%s() ALT_PIN_OUT_SEL 0x%08X\n", __func__, cx_read(ALT_PIN_OUT_SEL)); dprintk(1, "%s() GPIO2 0x%08X\n", __func__, cx_read(GPIO2)); dprintk(1, "%s() gpcnt(0x%08X) 0x%08X\n", __func__, port->reg_gpcnt, cx_read(port->reg_gpcnt)); dprintk(1, "%s() gpcnt_ctl(0x%08X) 0x%08x\n", __func__, port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl)); dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __func__, port->reg_dma_ctl, cx_read(port->reg_dma_ctl)); if (port->reg_src_sel) dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __func__, port->reg_src_sel, cx_read(port->reg_src_sel)); dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __func__, port->reg_lngth, cx_read(port->reg_lngth)); dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __func__, port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl)); dprintk(1, "%s() gen_ctrl(0x%08X) 0x%08x\n", __func__, port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl)); dprintk(1, "%s() bd_pkt_status(0x%08X) 0x%08x\n", __func__, port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status)); dprintk(1, "%s() sop_status(0x%08X) 0x%08x\n", __func__, port->reg_sop_status, cx_read(port->reg_sop_status)); dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __func__, port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat)); dprintk(1, "%s() vld_misc(0x%08X) 0x%08x\n", __func__, port->reg_vld_misc, cx_read(port->reg_vld_misc)); dprintk(1, "%s() ts_clk_en(0x%08X) 0x%08x\n", __func__, port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en)); dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __func__, port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));}static int cx23885_start_dma(struct cx23885_tsport *port, struct cx23885_dmaqueue *q, struct cx23885_buffer *buf){ struct cx23885_dev *dev = port->dev; u32 reg; dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__, buf->vb.width, buf->vb.height, buf->vb.field); /* Stop the fifo and risc engine for this port */ cx_clear(port->reg_dma_ctl, port->dma_ctl_val); /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[port->sram_chno], port->ts_packet_size, buf->risc.dma); if (debug > 5) { cx23885_sram_channel_dump(dev, &dev->sram_channels[port->sram_chno]); cx23885_risc_disasm(port, &buf->risc); } /* write TS length to chip */ cx_write(port->reg_lngth, buf->vb.width); if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) { printk("%s() Unsupported .portb/c (0x%08x)/(0x%08x)\n", __func__, cx23885_boards[dev->board].portb, cx23885_boards[dev->board].portc); return -EINVAL; } if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) cx23885_av_clk(dev, 0); udelay(100); /* If the port supports SRC SELECT, configure it */ if (port->reg_src_sel) cx_write(port->reg_src_sel, port->src_sel_val); cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val); cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); cx_write(port->reg_vld_misc, port->vld_misc_val); cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); udelay(100); /* NOTE: this is 2 (reserved) for portb, does it matter? */ /* reset counter to zero */ cx_write(port->reg_gpcnt_ctl, 3); q->count = 1; /* Set VIDB pins to input */ if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { reg = cx_read(PAD_CTRL); reg &= ~0x3; /* Clear TS1_OE & TS1_SOP_OE */ cx_write(PAD_CTRL, reg); } /* Set VIDC pins to input */ if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { reg = cx_read(PAD_CTRL); reg &= ~0x4; /* Clear TS2_SOP_OE */ cx_write(PAD_CTRL, reg); } if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { reg = cx_read(PAD_CTRL); reg = reg & ~0x1; /* Clear TS1_OE */ /* FIXME, bit 2 writing here is questionable */ /* set TS1_SOP_OE and TS1_OE_HI */ reg = reg | 0xa; cx_write(PAD_CTRL, reg); /* FIXME and these two registers should be documented. */ cx_write(CLK_DELAY, cx_read(CLK_DELAY) | 0x80000011); cx_write(ALT_PIN_OUT_SEL, 0x10100045); } switch (dev->bridge) { case CX23885_BRIDGE_885: case CX23885_BRIDGE_887: /* enable irqs */ dprintk(1, "%s() enabling TS int's and DMA\n", __func__); cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); cx_set(port->reg_dma_ctl, port->dma_ctl_val); cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); break; default: BUG(); } cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) cx23885_av_clk(dev, 1); if (debug > 4) cx23885_tsport_reg_dump(port); return 0;}static int cx23885_stop_dma(struct cx23885_tsport *port){ struct cx23885_dev *dev = port->dev; u32 reg; dprintk(1, "%s()\n", __func__); /* Stop interrupts and DMA */ cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val); cx_clear(port->reg_dma_ctl, port->dma_ctl_val); if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { reg = cx_read(PAD_CTRL); /* Set TS1_OE */ reg = reg | 0x1; /* clear TS1_SOP_OE and TS1_OE_HI */ reg = reg & ~0xa; cx_write(PAD_CTRL, reg);#if 0 /* * cx_write(CLK_DELAY, cx_read(CLK_DELAY) & ~0x80000011); ???? * cx_write(ALT_PIN_OUT_SEL, 0x10100045); ?? need to undo this? */#endif cx_write(port->reg_src_sel, 0); cx_write(port->reg_gen_ctrl, 8); } if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) cx23885_av_clk(dev, 0); return 0;}int cx23885_restart_queue(struct cx23885_tsport *port, struct cx23885_dmaqueue *q){ struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; dprintk(5, "%s()\n", __func__); if (list_empty(&q->active)) { struct cx23885_buffer *prev; prev = NULL; dprintk(5, "%s() queue is empty\n", __func__); for (;;) { if (list_empty(&q->queued)) return 0; buf = list_entry(q->queued.next, struct cx23885_buffer, vb.queue); if (NULL == prev) { list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue, &q->active); cx23885_start_dma(port, q, buf); buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(5, "[%p/%d] restart_queue - f/active\n", buf, buf->vb.i); } else if (prev->vb.width == buf->vb.width && prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue, &q->active); buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); /* 64 bit bits 63-32 */ prev->risc.jmp[2] = cpu_to_le32(0); dprintk(5, "[%p/%d] restart_queue - m/active\n", buf, buf->vb.i); } else { return 0; } prev = buf; } return 0; } buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); dprintk(2, "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); cx23885_start_dma(port, q, buf); list_for_each_entry(buf, &q->active, vb.queue) buf->count = q->count++; mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); return 0;}/* ------------------------------------------------------------------ */int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, struct cx23885_buffer *buf, enum v4l2_field field){ struct cx23885_dev *dev = port->dev; int size = port->ts_packet_size * port->ts_packet_count; int rc; dprintk(1, "%s: %p\n", __func__, buf); if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { buf->vb.width = port->ts_packet_size; buf->vb.height = port->ts_packet_count; buf->vb.size = size; buf->vb.field = field /*V4L2_FIELD_TOP*/; rc = videobuf_iolock(q, &buf->vb, NULL); if (0 != rc) goto fail; cx23885_risc_databuffer(dev->pci, &buf->risc, videobuf_to_dma(&buf->vb)->sglist, buf->vb.width, buf->vb.height);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -