📄 cx88-video.c
字号:
bits 12 to 15: BERR signal asserted for: BRDG, SRC, DST, IPB */ cx_set(MO_VID_INTMSK, 0x0f0011); /* enable capture */ cx_set(VID_CAPTURE_CONTROL,0x06); /* start dma */ cx_set(MO_DEV_CNTRL2, (1<<5)); cx_set(MO_VID_DMACNTRL, 0x11); /* Planar Y and packed FIFO and RISC enable */ return 0;}#ifdef CONFIG_PMstatic int stop_video_dma(struct cx8800_dev *dev){ struct cx88_core *core = dev->core; /* stop dma */ cx_clear(MO_VID_DMACNTRL, 0x11); /* disable capture */ cx_clear(VID_CAPTURE_CONTROL,0x06); /* disable irqs */ cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); cx_clear(MO_VID_INTMSK, 0x0f0011); return 0;}#endifstatic int restart_video_queue(struct cx8800_dev *dev, struct cx88_dmaqueue *q){ struct cx88_core *core = dev->core; struct cx88_buffer *buf, *prev; if (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); start_video_dma(dev, q, buf); list_for_each_entry(buf, &q->active, vb.queue) buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); return 0; } prev = NULL; for (;;) { if (list_empty(&q->queued)) return 0; buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); if (NULL == prev) { list_move_tail(&buf->vb.queue, &q->active); start_video_dma(dev, q, buf); buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] restart_queue - first 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_move_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); dprintk(2,"[%p/%d] restart_queue - move to active\n", buf,buf->vb.i); } else { return 0; } prev = buf; }}/* ------------------------------------------------------------------ */static intbuffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size){ struct cx8800_fh *fh = q->priv_data; *size = fh->fmt->depth*fh->width*fh->height >> 3; if (0 == *count) *count = 32; while (*size * *count > vid_limit * 1024 * 1024) (*count)--; return 0;}static intbuffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field){ struct cx8800_fh *fh = q->priv_data; struct cx8800_dev *dev = fh->dev; struct cx88_core *core = dev->core; struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); int rc, init_buffer = 0; BUG_ON(NULL == fh->fmt); if (fh->width < 48 || fh->width > norm_maxw(core->tvnorm) || fh->height < 32 || fh->height > norm_maxh(core->tvnorm)) return -EINVAL; buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) return -EINVAL; if (buf->fmt != fh->fmt || buf->vb.width != fh->width || buf->vb.height != fh->height || buf->vb.field != field) { buf->fmt = fh->fmt; buf->vb.width = fh->width; buf->vb.height = fh->height; buf->vb.field = field; init_buffer = 1; } if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { init_buffer = 1; if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) goto fail; } if (init_buffer) { buf->bpl = buf->vb.width * buf->fmt->depth >> 3; switch (buf->vb.field) { case V4L2_FIELD_TOP: cx88_risc_buffer(dev->pci, &buf->risc, dma->sglist, 0, UNSET, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_BOTTOM: cx88_risc_buffer(dev->pci, &buf->risc, dma->sglist, UNSET, 0, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_INTERLACED: cx88_risc_buffer(dev->pci, &buf->risc, dma->sglist, 0, buf->bpl, buf->bpl, buf->bpl, buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_TB: cx88_risc_buffer(dev->pci, &buf->risc, dma->sglist, 0, buf->bpl * (buf->vb.height >> 1), buf->bpl, 0, buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_BT: cx88_risc_buffer(dev->pci, &buf->risc, dma->sglist, buf->bpl * (buf->vb.height >> 1), 0, buf->bpl, 0, buf->vb.height >> 1); break; default: BUG(); } } dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", buf, buf->vb.i, fh->width, fh->height, fh->fmt->depth, fh->fmt->name, (unsigned long)buf->risc.dma); buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: cx88_free_buffer(q,buf); return rc;}static voidbuffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb){ struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); struct cx88_buffer *prev; struct cx8800_fh *fh = vq->priv_data; struct cx8800_dev *dev = fh->dev; struct cx88_core *core = dev->core; struct cx88_dmaqueue *q = &dev->vidq; /* add jump to stopper */ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); if (!list_empty(&q->queued)) { list_add_tail(&buf->vb.queue,&q->queued); buf->vb.state = VIDEOBUF_QUEUED; dprintk(2,"[%p/%d] buffer_queue - append to queued\n", buf, buf->vb.i); } else if (list_empty(&q->active)) { list_add_tail(&buf->vb.queue,&q->active); start_video_dma(dev, q, buf); buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] buffer_queue - first active\n", buf, buf->vb.i); } else { prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue); if (prev->vb.width == buf->vb.width && prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { 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); dprintk(2,"[%p/%d] buffer_queue - append to active\n", buf, buf->vb.i); } else { list_add_tail(&buf->vb.queue,&q->queued); buf->vb.state = VIDEOBUF_QUEUED; dprintk(2,"[%p/%d] buffer_queue - first queued\n", buf, buf->vb.i); } }}static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb){ struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); cx88_free_buffer(q,buf);}static struct videobuf_queue_ops cx8800_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, .buf_release = buffer_release,};/* ------------------------------------------------------------------ */#if 0 /* overlay support not finished yet */static u32* ov_risc_field(struct cx8800_dev *dev, struct cx8800_fh *fh, u32 *rp, struct btcx_skiplist *skips, u32 sync_line, int skip_even, int skip_odd){ int line,maxy,start,end,skip,nskips; u32 ri,ra; u32 addr; /* sync instruction */ *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); addr = (unsigned long)dev->fbuf.base; addr += dev->fbuf.fmt.bytesperline * fh->win.w.top; addr += (fh->fmt->depth >> 3) * fh->win.w.left; /* scan lines */ for (maxy = -1, line = 0; line < fh->win.w.height; line++, addr += dev->fbuf.fmt.bytesperline) { if ((line%2) == 0 && skip_even) continue; if ((line%2) == 1 && skip_odd) continue; /* calculate clipping */ if (line > maxy) btcx_calc_skips(line, fh->win.w.width, &maxy, skips, &nskips, fh->clips, fh->nclips); /* write out risc code */ for (start = 0, skip = 0; start < fh->win.w.width; start = end) { if (skip >= nskips) { ri = RISC_WRITE; end = fh->win.w.width; } else if (start < skips[skip].start) { ri = RISC_WRITE; end = skips[skip].start; } else { ri = RISC_SKIP; end = skips[skip].end; skip++; } if (RISC_WRITE == ri) ra = addr + (fh->fmt->depth>>3)*start; else ra = 0; if (0 == start) ri |= RISC_SOL; if (fh->win.w.width == end) ri |= RISC_EOL; ri |= (fh->fmt->depth>>3) * (end-start); *(rp++)=cpu_to_le32(ri); if (0 != ra) *(rp++)=cpu_to_le32(ra); } } kfree(skips); return rp;}static int ov_risc_frame(struct cx8800_dev *dev, struct cx8800_fh *fh, struct cx88_buffer *buf){ struct btcx_skiplist *skips; u32 instructions,fields; u32 *rp; int rc; /* skip list for window clipping */ if (NULL == (skips = kmalloc(sizeof(*skips) * fh->nclips,GFP_KERNEL))) return -ENOMEM; fields = 0; if (V4L2_FIELD_HAS_TOP(fh->win.field)) fields++; if (V4L2_FIELD_HAS_BOTTOM(fh->win.field)) fields++; /* estimate risc mem: worst case is (clip+1) * lines instructions + syncs + jump (all 2 dwords) */ instructions = (fh->nclips+1) * fh->win.w.height; instructions += 3 + 4; if ((rc = btcx_riscmem_alloc(dev->pci,&buf->risc,instructions*8)) < 0) { kfree(skips); return rc; } /* write risc instructions */ rp = buf->risc.cpu; switch (fh->win.field) { case V4L2_FIELD_TOP: rp = ov_risc_field(dev, fh, rp, skips, 0, 0, 0); break; case V4L2_FIELD_BOTTOM: rp = ov_risc_field(dev, fh, rp, skips, 0x200, 0, 0); break; case V4L2_FIELD_INTERLACED: rp = ov_risc_field(dev, fh, rp, skips, 0, 0, 1); rp = ov_risc_field(dev, fh, rp, skips, 0x200, 1, 0); break; default: BUG(); } /* save pointer to jmp instruction address */ buf->risc.jmp = rp; kfree(skips); return 0;}static int verify_window(struct cx8800_dev *dev, struct v4l2_window *win){ enum v4l2_field field; int maxw, maxh; if (NULL == dev->fbuf.base) return -EINVAL; if (win->w.width < 48 || win->w.height < 32) return -EINVAL; if (win->clipcount > 2048) return -EINVAL; field = win->field; maxw = norm_maxw(core->tvnorm); maxh = norm_maxh(core->tvnorm); if (V4L2_FIELD_ANY == field) { field = (win->w.height > maxh/2) ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; } switch (field) { case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: maxh = maxh / 2; break; case V4L2_FIELD_INTERLACED: break; default: return -EINVAL; } win->field = field; if (win->w.width > maxw) win->w.width = maxw; if (win->w.height > maxh) win->w.height = maxh; return 0;}static int setup_window(struct cx8800_dev *dev, struct cx8800_fh *fh, struct v4l2_window *win){ struct v4l2_clip *clips = NULL; int n,size,retval = 0; if (NULL == fh->fmt) return -EINVAL; retval = verify_window(dev,win); if (0 != retval) return retval; /* copy clips -- luckily v4l1 + v4l2 are binary compatible here ...*/ n = win->clipcount; size = sizeof(*clips)*(n+4); clips = kmalloc(size,GFP_KERNEL); if (NULL == clips) return -ENOMEM; if (n > 0) { if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) { kfree(clips); return -EFAULT; } } /* clip against screen */ if (NULL != dev->fbuf.base) n = btcx_screen_clips(dev->fbuf.fmt.width, dev->fbuf.fmt.height, &win->w, clips, n); btcx_sort_clips(clips,n); /* 4-byte alignments */ switch (fh->fmt->depth) { case 8: case 24: btcx_align(&win->w, clips, n, 3); break; case 16: btcx_align(&win->w, clips, n, 1); break; case 32: /* no alignment fixups needed */ break; default: BUG(); } down(&fh->vidq.lock); if (fh->clips) kfree(fh->clips); fh->clips = clips; fh->nclips = n; fh->win = *win;/* #if 0 */ fh->ov.setup_ok = 1;/* #endif */ /* update overlay if needed */ retval = 0;/* #if 0 */ if (check_btres(fh, RESOURCE_OVERLAY)) { struct bttv_buffer *new; new = videobuf_pci_alloc(sizeof(*new)); bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval = bttv_switch_overlay(btv,fh,new); }/* #endif */ up(&fh->vidq.lock); return retval;}#endif/* ------------------------------------------------------------------ */static struct videobuf_queue* get_queue(struct cx8800_fh *fh){ switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: return &fh->vidq; case V4L2_BUF_TYPE_VBI_CAPTURE: return &fh->vbiq; default: BUG(); return NULL; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -