📄 saa7134-video.c
字号:
return -EINVAL; size = (fh->width * fh->height * fh->fmt->depth) >> 3; if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n", vb->i,fh->width,fh->height,size,v4l2_field_names[field], fh->fmt->name); if (buf->vb.width != fh->width || buf->vb.height != fh->height || buf->vb.size != size || buf->vb.field != field || buf->fmt != fh->fmt) { saa7134_dma_free(dev,buf); } if (STATE_NEEDS_INIT == buf->vb.state) { buf->vb.width = fh->width; buf->vb.height = fh->height; buf->vb.size = size; buf->vb.field = field; buf->fmt = fh->fmt; buf->pt = &fh->pt_cap; err = videobuf_iolock(dev->pci,&buf->vb,&dev->ovbuf); if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, buf->vb.dma.sglist, buf->vb.dma.sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; } buf->vb.state = STATE_PREPARED; buf->activate = buffer_activate; return 0; oops: saa7134_dma_free(dev,buf); return err;}static intbuffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size){ struct saa7134_fh *fh = q->priv_data; *size = fh->fmt->depth * fh->width * fh->height >> 3; if (0 == *count) *count = gbuffers; *count = saa7134_buffer_count(*size,*count); return 0;}static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb){ struct saa7134_fh *fh = q->priv_data; struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf);}static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb){ struct saa7134_fh *fh = q->priv_data; struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); saa7134_dma_free(fh->dev,buf);}static struct videobuf_queue_ops video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, .buf_release = buffer_release,};/* ------------------------------------------------------------------ */static int get_control(struct saa7134_dev *dev, struct v4l2_control *c){ const struct v4l2_queryctrl* ctrl; ctrl = ctrl_by_id(c->id); if (NULL == ctrl) return -EINVAL; switch (c->id) { case V4L2_CID_BRIGHTNESS: c->value = dev->ctl_bright; break; case V4L2_CID_HUE: c->value = dev->ctl_hue; break; case V4L2_CID_CONTRAST: c->value = dev->ctl_contrast; break; case V4L2_CID_SATURATION: c->value = dev->ctl_saturation; break; case V4L2_CID_AUDIO_MUTE: c->value = dev->ctl_mute; break; case V4L2_CID_AUDIO_VOLUME: c->value = dev->ctl_volume; break; case V4L2_CID_PRIVATE_INVERT: c->value = dev->ctl_invert; break; case V4L2_CID_HFLIP: c->value = dev->ctl_mirror; break; case V4L2_CID_PRIVATE_Y_EVEN: c->value = dev->ctl_y_even; break; case V4L2_CID_PRIVATE_Y_ODD: c->value = dev->ctl_y_odd; break; case V4L2_CID_PRIVATE_AUTOMUTE: c->value = dev->ctl_automute; break; default: return -EINVAL; } return 0;}static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c){ const struct v4l2_queryctrl* ctrl; unsigned long flags; int restart_overlay = 0; ctrl = ctrl_by_id(c->id); if (NULL == ctrl) return -EINVAL; dprintk("set_control name=%s val=%d\n",ctrl->name,c->value); switch (ctrl->type) { case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_INTEGER: if (c->value < ctrl->minimum) c->value = ctrl->minimum; if (c->value > ctrl->maximum) c->value = ctrl->maximum; break; default: /* nothing */; }; switch (c->id) { case V4L2_CID_BRIGHTNESS: dev->ctl_bright = c->value; saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); break; case V4L2_CID_HUE: dev->ctl_hue = c->value; saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); break; case V4L2_CID_CONTRAST: dev->ctl_contrast = c->value; saa_writeb(SAA7134_DEC_LUMA_CONTRAST, dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); break; case V4L2_CID_SATURATION: dev->ctl_saturation = c->value; saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); break; case V4L2_CID_AUDIO_MUTE: dev->ctl_mute = c->value; saa7134_tvaudio_setmute(dev); break; case V4L2_CID_AUDIO_VOLUME: dev->ctl_volume = c->value; saa7134_tvaudio_setvolume(dev,dev->ctl_volume); break; case V4L2_CID_PRIVATE_INVERT: dev->ctl_invert = c->value; saa_writeb(SAA7134_DEC_LUMA_CONTRAST, dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); break; case V4L2_CID_HFLIP: dev->ctl_mirror = c->value; restart_overlay = 1; break; case V4L2_CID_PRIVATE_Y_EVEN: dev->ctl_y_even = c->value; restart_overlay = 1; break; case V4L2_CID_PRIVATE_Y_ODD: dev->ctl_y_odd = c->value; restart_overlay = 1; break; case V4L2_CID_PRIVATE_AUTOMUTE: dev->ctl_automute = c->value; if (dev->tda9887_conf) { if (dev->ctl_automute) dev->tda9887_conf |= TDA9887_AUTOMUTE; else dev->tda9887_conf &= ~TDA9887_AUTOMUTE; saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf); } break; default: return -EINVAL; } if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); stop_preview(dev,fh); start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); } return 0;}/* ------------------------------------------------------------------ */static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh){ struct videobuf_queue* q = NULL; switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: q = &fh->cap; break; case V4L2_BUF_TYPE_VBI_CAPTURE: q = &fh->vbi; break; default: BUG(); } return q;}static int saa7134_resource(struct saa7134_fh *fh){ int res = 0; switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: res = RESOURCE_VIDEO; break; case V4L2_BUF_TYPE_VBI_CAPTURE: res = RESOURCE_VBI; break; default: BUG(); } return res;}static int video_open(struct inode *inode, struct file *file){ int minor = iminor(inode); struct saa7134_dev *h,*dev = NULL; struct saa7134_fh *fh; struct list_head *list; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int radio = 0; list_for_each(list,&saa7134_devlist) { h = list_entry(list, struct saa7134_dev, devlist); if (h->video_dev && (h->video_dev->minor == minor)) dev = h; if (h->radio_dev && (h->radio_dev->minor == minor)) { radio = 1; dev = h; } if (h->vbi_dev && (h->vbi_dev->minor == minor)) { type = V4L2_BUF_TYPE_VBI_CAPTURE; dev = h; } } if (NULL == dev) return -ENODEV; dprintk("open minor=%d radio=%d type=%s\n",minor,radio, v4l2_type_names[type]); /* allocate + initialize per filehandle data */ fh = kmalloc(sizeof(*fh),GFP_KERNEL); if (NULL == fh) return -ENOMEM; memset(fh,0,sizeof(*fh)); file->private_data = fh; fh->dev = dev; fh->radio = radio; fh->type = type; fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); fh->width = 720; fh->height = 576; v4l2_prio_open(&dev->prio,&fh->prio); videobuf_queue_init(&fh->cap, &video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct saa7134_buf), fh); videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, sizeof(struct saa7134_buf), fh); saa7134_pgtable_alloc(dev->pci,&fh->pt_cap); saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi); if (fh->radio) { /* switch to radio mode */ saa7134_tvaudio_setinput(dev,&card(dev).radio); saa7134_i2c_call_clients(dev,AUDC_SET_RADIO, NULL); } else { /* switch to video/vbi mode */ video_mux(dev,dev->ctl_input); } return 0;}static ssize_tvideo_read(struct file *file, char __user *data, size_t count, loff_t *ppos){ struct saa7134_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(saa7134_queue(fh), 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(saa7134_queue(fh), data, count, ppos, 1, file->f_flags & O_NONBLOCK); break; default: BUG(); return 0; }}static unsigned intvideo_poll(struct file *file, struct poll_table_struct *wait){ struct saa7134_fh *fh = file->private_data; struct videobuf_buffer *buf = NULL; if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) return videobuf_poll_stream(file, &fh->vbi, wait); if (res_check(fh,RESOURCE_VIDEO)) { if (!list_empty(&fh->cap.stream)) buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream); } else { down(&fh->cap.lock); if (UNSET == fh->cap.read_off) { /* need to capture a new frame */ if (res_locked(fh->dev,RESOURCE_VIDEO)) { up(&fh->cap.lock); return POLLERR; } if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) { up(&fh->cap.lock); return POLLERR; } fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); fh->cap.read_off = 0; } up(&fh->cap.lock); buf = fh->cap.read_buf; } if (!buf) return POLLERR; poll_wait(file, &buf->done, wait); if (buf->state == STATE_DONE || buf->state == STATE_ERROR) return POLLIN|POLLRDNORM; return 0;}static int video_release(struct inode *inode, struct file *file){ struct saa7134_fh *fh = file->private_data; struct saa7134_dev *dev = fh->dev; unsigned long flags; /* turn off overlay */ if (res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); stop_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); res_free(dev,fh,RESOURCE_OVERLAY); } /* stop video capture */ if (res_check(fh, RESOURCE_VIDEO)) { videobuf_streamoff(&fh->cap); res_free(dev,fh,RESOURCE_VIDEO); } if (fh->cap.read_buf) { buffer_release(&fh->cap,fh->cap.read_buf); kfree(fh->cap.read_buf); } /* stop vbi capture */ if (res_check(fh, RESOURCE_VBI)) { if (fh->vbi.streaming) videobuf_streamoff(&fh->vbi); if (fh->vbi.reading) videobuf_read_stop(&fh->vbi); res_free(dev,fh,RESOURCE_VBI); } /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/ saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0); saa_andorb(SAA7134_OFMT_VIDEO_B, 0x1f, 0); saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); /* free stuff */ videobuf_mmap_free(&fh->cap); videobuf_mmap_free(&fh->vbi); saa7134_pgtable_free(dev->pci,&fh->pt_cap); saa7134_pgtable_free(dev->pci,&fh->pt_vbi); v4l2_prio_close(&dev->prio,&fh->prio); file->private_data = NULL; kfree(fh); return 0;}static intvideo_mmap(struct file *file, struct vm_area_struct * vma){ struct saa7134_fh *fh = file->private_data; return videobuf_mmap_mapper(saa7134_queue(fh), vma);}/* ------------------------------------------------------------------ */static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f){ struct saa7134_tvnorm *norm = dev->tvnorm; f->fmt.vbi.sampling_rate = 6750000 * 4; f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */; f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; f->fmt.vbi.offset = 64 * 4; f->fmt.vbi.start[0] = norm->vbi_v_start_0; f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1; f->fmt.vbi.start[1] = norm->vbi_v_start_1; f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */}static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_format *f){ switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); f->fmt.pix.width = fh->width; f->fmt.pix.height = fh->height; f->fmt.pix.field = fh->cap.field; f->fmt.pix.pixelformat = fh->fmt->fourcc; f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; return 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: f->fmt.win = fh->win; return 0; case V4L2_BUF_TYPE_VBI_CAPTURE: saa7134_vbi_fmt(dev,f); return 0; default: return -EINVAL; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -