📄 bttv-risc.c
字号:
/* risc group / risc main loop / dma management */voidbttv_set_dma(struct bttv *btv, int override){ unsigned long cmd; int capctl; btv->cap_ctl = 0; if (NULL != btv->curr.top) btv->cap_ctl |= 0x02; if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01; if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c; capctl = 0; capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */ capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */ capctl |= override; d2printk(KERN_DEBUG "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n", btv->c.nr,capctl,btv->loop_irq, btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0, btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); cmd = BT848_RISC_JUMP; if (btv->loop_irq) { cmd |= BT848_RISC_IRQ; cmd |= (btv->loop_irq & 0x0f) << 16; cmd |= (~btv->loop_irq & 0x0f) << 20; } if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) { mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT); } else { del_timer(&btv->timeout); } btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd); btaor(capctl, ~0x0f, BT848_CAP_CTL); if (capctl) { if (btv->dma_on) return; btwrite(btv->main.dma, BT848_RISC_STRT_ADD); btor(3, BT848_GPIO_DMA_CTL); btv->dma_on = 1; } else { if (!btv->dma_on) return; btand(~3, BT848_GPIO_DMA_CTL); btv->dma_on = 0; } return;}intbttv_risc_init_main(struct bttv *btv){ int rc; if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0) return rc; dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n", btv->c.nr,(unsigned long long)btv->main.dma); btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | BT848_FIFO_STATUS_VRE); btv->main.cpu[1] = cpu_to_le32(0); btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP); btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2)); /* top field */ btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP); btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2)); btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP); btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2)); btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | BT848_FIFO_STATUS_VRO); btv->main.cpu[9] = cpu_to_le32(0); /* bottom field */ btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP); btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2)); btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP); btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2)); /* jump back to top field */ btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP); btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2)); return 0;}intbttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, int irqflags){ unsigned long cmd; unsigned long next = btv->main.dma + ((slot+2) << 2); if (NULL == risc) { d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n", btv->c.nr,risc,slot); btv->main.cpu[slot+1] = cpu_to_le32(next); } else { d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n", btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags); cmd = BT848_RISC_JUMP; if (irqflags) { cmd |= BT848_RISC_IRQ; cmd |= (irqflags & 0x0f) << 16; cmd |= (~irqflags & 0x0f) << 20; } risc->jmp[0] = cpu_to_le32(cmd); risc->jmp[1] = cpu_to_le32(next); btv->main.cpu[slot+1] = cpu_to_le32(risc->dma); } return 0;}voidbttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_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(btv->c.pci,&buf->bottom); btcx_riscmem_free(btv->c.pci,&buf->top); buf->vb.state = VIDEOBUF_NEEDS_INIT;}intbttv_buffer_activate_vbi(struct bttv *btv, struct bttv_buffer *vbi){ struct btcx_riscmem *top; struct btcx_riscmem *bottom; int top_irq_flags; int bottom_irq_flags; top = NULL; bottom = NULL; top_irq_flags = 0; bottom_irq_flags = 0; if (vbi) { unsigned int crop, vdelay; vbi->vb.state = VIDEOBUF_ACTIVE; list_del(&vbi->vb.queue); /* VDELAY is start of video, end of VBI capturing. */ crop = btread(BT848_E_CROP); vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2); if (vbi->geo.vdelay > vdelay) { vdelay = vbi->geo.vdelay & 0xfe; crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0); btwrite(vdelay, BT848_E_VDELAY_LO); btwrite(crop, BT848_E_CROP); btwrite(vdelay, BT848_O_VDELAY_LO); btwrite(crop, BT848_O_CROP); } if (vbi->vbi_count[0] > 0) { top = &vbi->top; top_irq_flags = 4; } if (vbi->vbi_count[1] > 0) { top_irq_flags = 0; bottom = &vbi->bottom; bottom_irq_flags = 4; } } bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags); bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags); return 0;}intbttv_buffer_activate_video(struct bttv *btv, struct bttv_buffer_set *set){ /* video capture */ if (NULL != set->top && NULL != set->bottom) { if (set->top == set->bottom) { set->top->vb.state = VIDEOBUF_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); } else { set->top->vb.state = VIDEOBUF_ACTIVE; set->bottom->vb.state = VIDEOBUF_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); if (set->bottom->vb.queue.next) list_del(&set->bottom->vb.queue); } bttv_apply_geo(btv, &set->top->geo, 1); bttv_apply_geo(btv, &set->bottom->geo,0); bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, set->top_irq); bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, set->frame_irq); btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f), ~0xff, BT848_COLOR_FMT); btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05), ~0x0f, BT848_COLOR_CTL); } else if (NULL != set->top) { set->top->vb.state = VIDEOBUF_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); bttv_apply_geo(btv, &set->top->geo,1); bttv_apply_geo(btv, &set->top->geo,0); bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, set->frame_irq); bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT); btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); } else if (NULL != set->bottom) { set->bottom->vb.state = VIDEOBUF_ACTIVE; if (set->bottom->vb.queue.next) list_del(&set->bottom->vb.queue); bttv_apply_geo(btv, &set->bottom->geo,1); bttv_apply_geo(btv, &set->bottom->geo,0); bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, set->frame_irq); btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT); btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); } else { bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); } return 0;}/* ---------------------------------------------------------- *//* calculate geometry, build risc code */intbttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf){ const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); dprintk(KERN_DEBUG "bttv%d: buffer field: %s format: %s size: %dx%d\n", btv->c.nr, v4l2_field_names[buf->vb.field], buf->fmt->name, buf->vb.width, buf->vb.height); /* packed pixel modes */ if (buf->fmt->flags & FORMAT_FLAGS_PACKED) { int bpl = (buf->fmt->depth >> 3) * buf->vb.width; int bpf = bpl * (buf->vb.height >> 1); bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height, V4L2_FIELD_HAS_BOTH(buf->vb.field), tvnorm,&buf->crop); switch (buf->vb.field) { case V4L2_FIELD_TOP: bttv_risc_packed(btv,&buf->top,dma->sglist, /* offset */ 0,bpl, /* padding */ 0,/* skip_lines */ 0, buf->vb.height); break; case V4L2_FIELD_BOTTOM: bttv_risc_packed(btv,&buf->bottom,dma->sglist, 0,bpl,0,0,buf->vb.height); break; case V4L2_FIELD_INTERLACED: bttv_risc_packed(btv,&buf->top,dma->sglist, 0,bpl,bpl,0,buf->vb.height >> 1); bttv_risc_packed(btv,&buf->bottom,dma->sglist, bpl,bpl,bpl,0,buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_TB: bttv_risc_packed(btv,&buf->top,dma->sglist, 0,bpl,0,0,buf->vb.height >> 1); bttv_risc_packed(btv,&buf->bottom,dma->sglist, bpf,bpl,0,0,buf->vb.height >> 1); break; default: BUG(); } } /* planar modes */ if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) { int uoffset, voffset; int ypadding, cpadding, lines; /* calculate chroma offsets */ uoffset = buf->vb.width * buf->vb.height; voffset = buf->vb.width * buf->vb.height; if (buf->fmt->flags & FORMAT_FLAGS_CrCb) { /* Y-Cr-Cb plane order */ uoffset >>= buf->fmt->hshift; uoffset >>= buf->fmt->vshift; uoffset += voffset; } else { /* Y-Cb-Cr plane order */ voffset >>= buf->fmt->hshift; voffset >>= buf->fmt->vshift; voffset += uoffset; } switch (buf->vb.field) { case V4L2_FIELD_TOP: bttv_calc_geo(btv,&buf->geo,buf->vb.width, buf->vb.height,/* both_fields */ 0, tvnorm,&buf->crop); bttv_risc_planar(btv, &buf->top, dma->sglist, 0,buf->vb.width,0,buf->vb.height, uoffset,voffset,buf->fmt->hshift, buf->fmt->vshift,0); break; case V4L2_FIELD_BOTTOM: bttv_calc_geo(btv,&buf->geo,buf->vb.width, buf->vb.height,0, tvnorm,&buf->crop); bttv_risc_planar(btv, &buf->bottom, dma->sglist, 0,buf->vb.width,0,buf->vb.height, uoffset,voffset,buf->fmt->hshift, buf->fmt->vshift,0); break; case V4L2_FIELD_INTERLACED: bttv_calc_geo(btv,&buf->geo,buf->vb.width, buf->vb.height,1, tvnorm,&buf->crop); lines = buf->vb.height >> 1; ypadding = buf->vb.width; cpadding = buf->vb.width >> buf->fmt->hshift; bttv_risc_planar(btv,&buf->top, dma->sglist, 0,buf->vb.width,ypadding,lines, uoffset,voffset, buf->fmt->hshift, buf->fmt->vshift, cpadding); bttv_risc_planar(btv,&buf->bottom, dma->sglist, ypadding,buf->vb.width,ypadding,lines, uoffset+cpadding, voffset+cpadding, buf->fmt->hshift, buf->fmt->vshift, cpadding); break; case V4L2_FIELD_SEQ_TB: bttv_calc_geo(btv,&buf->geo,buf->vb.width, buf->vb.height,1, tvnorm,&buf->crop); lines = buf->vb.height >> 1; ypadding = buf->vb.width; cpadding = buf->vb.width >> buf->fmt->hshift; bttv_risc_planar(btv,&buf->top, dma->sglist, 0,buf->vb.width,0,lines, uoffset >> 1, voffset >> 1, buf->fmt->hshift, buf->fmt->vshift, 0); bttv_risc_planar(btv,&buf->bottom, dma->sglist, lines * ypadding,buf->vb.width,0,lines, lines * ypadding + (uoffset >> 1), lines * ypadding + (voffset >> 1), buf->fmt->hshift, buf->fmt->vshift, 0); break; default: BUG(); } } /* raw data */ if (buf->fmt->flags & FORMAT_FLAGS_RAW) { /* build risc code */ buf->vb.field = V4L2_FIELD_SEQ_TB; bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight, 1,tvnorm,&buf->crop); bttv_risc_packed(btv, &buf->top, dma->sglist, /* offset */ 0, RAW_BPL, /* padding */ 0, /* skip_lines */ 0, RAW_LINES); bttv_risc_packed(btv, &buf->bottom, dma->sglist, buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES); } /* copy format info */ buf->btformat = buf->fmt->btformat; buf->btswap = buf->fmt->btswap; return 0;}/* ---------------------------------------------------------- *//* calculate geometry, build risc code */intbttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, const struct bttv_format *fmt, struct bttv_buffer *buf){ /* check interleave, bottom+top fields */ dprintk(KERN_DEBUG "bttv%d: overlay fields: %s format: %s size: %dx%d\n", btv->c.nr, v4l2_field_names[buf->vb.field], fmt->name,ov->w.width,ov->w.height); /* calculate geometry */ bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height, V4L2_FIELD_HAS_BOTH(ov->field), &bttv_tvnorms[ov->tvnorm],&buf->crop); /* build risc code */ switch (ov->field) { case V4L2_FIELD_TOP: bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0); break; case V4L2_FIELD_BOTTOM: bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0); break; case V4L2_FIELD_INTERLACED:#if 0 bttv_risc_overlay(btv, &buf->top, fmt, ov, 1, 0); bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 1);#else bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1); bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);#endif break; default: BUG(); } /* copy format info */ buf->btformat = fmt->btformat; buf->btswap = fmt->btswap; buf->vb.field = ov->field; return 0;}/* * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -