📄 cx23885-video.c
字号:
unsigned int height, enum v4l2_field field){ dprintk(1, "%s()\n", __func__); return 0;}static int cx23885_start_video_dma(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, struct cx23885_buffer *buf){ dprintk(1, "%s()\n", __func__); /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], buf->bpl, buf->risc.dma); cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); /* reset counter */ cx_write(VID_A_GPCNT_CTL, 3); q->count = 1; /* enable irq */ cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01); cx_set(VID_A_INT_MSK, 0x000011); /* start dma */ cx_set(DEV_CNTRL2, (1<<5)); cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */ return 0;}#if 0#ifdef CONFIG_PMstatic int cx23885_stop_video_dma(struct cx23885_dev *dev){ dprintk(1, "%s()\n", __func__); /* stop dma */ cx_clear(VID_A_DMA_CTL, 0x11); /* disable irqs */ cx_clear(PCI_INT_MSK, 0x000001); cx_clear(VID_A_INT_MSK, 0x000011); return 0;}#endif#endifstatic int cx23885_restart_video_queue(struct cx23885_dev *dev, struct cx23885_dmaqueue *q){ struct cx23885_buffer *buf, *prev; struct list_head *item; dprintk(1, "%s()\n", __func__); if (!list_empty(&q->active)) { 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_video_dma(dev, q, buf); list_for_each(item, &q->active) { buf = list_entry(item, struct cx23885_buffer, 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 cx23885_buffer, vb.queue); if (NULL == prev) { list_move_tail(&buf->vb.queue, &q->active); cx23885_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); prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ dprintk(2, "[%p/%d] restart_queue - move to active\n", buf, buf->vb.i); } else { return 0; } prev = buf; }}static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size){ struct cx23885_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 int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field){ struct cx23885_fh *fh = q->priv_data; struct cx23885_dev *dev = fh->dev; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); int rc, init_buffer = 0; u32 line0_offset, line1_offset; struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); BUG_ON(NULL == fh->fmt); if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || fh->height < 32 || fh->height > norm_maxh(dev->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; rc = videobuf_iolock(q, &buf->vb, NULL); if (0 != rc) goto fail; } if (init_buffer) { buf->bpl = buf->vb.width * buf->fmt->depth >> 3; switch (buf->vb.field) { case V4L2_FIELD_TOP: cx23885_risc_buffer(dev->pci, &buf->risc, dma->sglist, 0, UNSET, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_BOTTOM: cx23885_risc_buffer(dev->pci, &buf->risc, dma->sglist, UNSET, 0, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_INTERLACED: if (dev->tvnorm & V4L2_STD_NTSC) { /* cx25840 transmits NTSC bottom field first */ dprintk(1, "%s() Creating NTSC risc\n", __func__); line0_offset = buf->bpl; line1_offset = 0; } else { /* All other formats are top field first */ dprintk(1, "%s() Creating PAL/SECAM risc\n", __func__); line0_offset = 0; line1_offset = buf->bpl; } cx23885_risc_buffer(dev->pci, &buf->risc, dma->sglist, line0_offset, line1_offset, buf->bpl, buf->bpl, buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_TB: cx23885_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: cx23885_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_prep - %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: cx23885_free_buffer(q, buf); return rc;}static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb){ struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); struct cx23885_buffer *prev; struct cx23885_fh *fh = vq->priv_data; struct cx23885_dev *dev = fh->dev; struct cx23885_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); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ 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); cx23885_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 cx23885_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); /* 64 bit bits 63-32 */ prev->risc.jmp[2] = cpu_to_le32(0); 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 cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); cx23885_free_buffer(q, buf);}static struct videobuf_queue_ops cx23885_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, .buf_release = buffer_release,};static struct videobuf_queue *get_queue(struct cx23885_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; }}static int get_resource(struct cx23885_fh *fh){ switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: return RESOURCE_VIDEO; case V4L2_BUF_TYPE_VBI_CAPTURE: return RESOURCE_VBI; default: BUG(); return 0; }}static int video_open(struct inode *inode, struct file *file){ int minor = iminor(inode); struct cx23885_dev *h, *dev = NULL; struct cx23885_fh *fh; struct list_head *list; enum v4l2_buf_type type = 0; int radio = 0; lock_kernel(); list_for_each(list, &cx23885_devlist) { h = list_entry(list, struct cx23885_dev, devlist); if (h->video_dev->minor == minor) { dev = h; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; } if (h->vbi_dev && h->vbi_dev->minor == minor) { dev = h; type = V4L2_BUF_TYPE_VBI_CAPTURE; } if (h->radio_dev && h->radio_dev->minor == minor) { radio = 1; dev = h; } } if (NULL == dev) { unlock_kernel(); return -ENODEV; } dprintk(1, "open minor=%d radio=%d type=%s\n", minor, radio, v4l2_type_names[type]); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (NULL == fh) { unlock_kernel(); return -ENOMEM; } file->private_data = fh; fh->dev = dev; fh->radio = radio; fh->type = type; fh->width = 320; fh->height = 240; fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, &dev->pci->dev, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct cx23885_buffer), fh); dprintk(1, "post videobuf_queue_init()\n");#if 0 if (fh->radio) { int board = dev->board; dprintk(1, "video_open: setting radio device\n"); cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3); cx_write(MO_GP0_IO, cx88_boards[board].radio.gpio0); cx_write(MO_GP1_IO, cx88_boards[board].radio.gpio1); cx_write(MO_GP2_IO, cx88_boards[board].radio.gpio2); dev->tvaudio = WW_FM; cx23885_set_tvaudio(dev); cx23885_set_stereo(dev, V4L2_TUNER_MODE_STEREO, 1); cx23885_call_i2c_clients(&dev->i2c_bus[1], AUDC_SET_RADIO, NULL); }#endif unlock_kernel(); return 0;}static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos){ struct cx23885_fh *fh = file->private_data; switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: if (res_locked(fh->dev, RESOURCE_VIDEO)) return -EBUSY; return videobuf_read_one(&fh->vidq, data, count, ppos, file->f_flags & O_NONBLOCK); case V4L2_BUF_TYPE_VBI_CAPTURE: if (!res_get(fh->dev, fh, RESOURCE_VBI)) return -EBUSY; return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, file->f_flags & O_NONBLOCK); default: BUG(); return 0; }}static unsigned int video_poll(struct file *file, struct poll_table_struct *wait){ struct cx23885_fh *fh = file->private_data; struct cx23885_buffer *buf; if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { if (!res_get(fh->dev, fh, RESOURCE_VBI)) return POLLERR; return videobuf_poll_stream(file, &fh->vbiq, wait); } if (res_check(fh, RESOURCE_VIDEO)) { /* streaming capture */ if (list_empty(&fh->vidq.stream)) return POLLERR; buf = list_entry(fh->vidq.stream.next, struct cx23885_buffer, vb.stream); } else { /* read() capture */ buf = (struct cx23885_buffer *)fh->vidq.read_buf; if (NULL == buf) return POLLERR; } poll_wait(file, &buf->vb.done, wait); if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) return POLLIN|POLLRDNORM; return 0;}static int video_release(struct inode *inode, struct file *file){ struct cx23885_fh *fh = file->private_data; struct cx23885_dev *dev = fh->dev; /* turn off overlay */ if (res_check(fh, RESOURCE_OVERLAY)) { /* FIXME */ res_free(dev, fh, RESOURCE_OVERLAY); } /* stop video capture */ if (res_check(fh, RESOURCE_VIDEO)) { videobuf_queue_cancel(&fh->vidq); res_free(dev, fh, RESOURCE_VIDEO); } if (fh->vidq.read_buf) { buffer_release(&fh->vidq, fh->vidq.read_buf); kfree(fh->vidq.read_buf); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -