📄 cx88-video.c
字号:
}static int get_ressource(struct cx8800_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 cx8800_dev *h,*dev = NULL; struct cx88_core *core; struct cx8800_fh *fh; enum v4l2_buf_type type = 0; int radio = 0; lock_kernel(); list_for_each_entry(h, &cx8800_devlist, devlist) { if (h->video_dev->minor == minor) { dev = h; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; } if (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; } core = dev->core; 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, &cx8800_video_qops, &dev->pci->dev, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct cx88_buffer), fh); videobuf_queue_sg_init(&fh->vbiq, &cx8800_vbi_qops, &dev->pci->dev, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, sizeof(struct cx88_buffer), fh); if (fh->radio) { dprintk(1,"video_open: setting radio device\n"); cx_write(MO_GP3_IO, core->board.radio.gpio3); cx_write(MO_GP0_IO, core->board.radio.gpio0); cx_write(MO_GP1_IO, core->board.radio.gpio1); cx_write(MO_GP2_IO, core->board.radio.gpio2); if (core->board.radio.audioroute) { if(core->board.audio_chip && core->board.audio_chip == V4L2_IDENT_WM8775) { struct v4l2_routing route; route.input = core->board.radio.audioroute; cx88_call_i2c_clients(core, VIDIOC_INT_S_AUDIO_ROUTING, &route); } /* "I2S ADC mode" */ core->tvaudio = WW_I2SADC; cx88_set_tvaudio(core); } else { /* FM Mode */ core->tvaudio = WW_FM; cx88_set_tvaudio(core); cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); } cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL); } unlock_kernel(); atomic_inc(&core->users); return 0;}static ssize_tvideo_read(struct file *file, char __user *data, size_t count, loff_t *ppos){ struct cx8800_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 intvideo_poll(struct file *file, struct poll_table_struct *wait){ struct cx8800_fh *fh = file->private_data; struct cx88_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 cx88_buffer,vb.stream); } else { /* read() capture */ buf = (struct cx88_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 cx8800_fh *fh = file->private_data; struct cx8800_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); } /* stop vbi capture */ if (res_check(fh, RESOURCE_VBI)) { videobuf_stop(&fh->vbiq); res_free(dev,fh,RESOURCE_VBI); } videobuf_mmap_free(&fh->vidq); videobuf_mmap_free(&fh->vbiq); file->private_data = NULL; kfree(fh); if(atomic_dec_and_test(&dev->core->users)) cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); return 0;}static intvideo_mmap(struct file *file, struct vm_area_struct * vma){ struct cx8800_fh *fh = file->private_data; return videobuf_mmap_mapper(get_queue(fh), vma);}/* ------------------------------------------------------------------ *//* VIDEO CTRL IOCTLS */int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl){ struct cx88_ctrl *c = NULL; u32 value; int i; for (i = 0; i < CX8800_CTLS; i++) if (cx8800_ctls[i].v.id == ctl->id) c = &cx8800_ctls[i]; if (unlikely(NULL == c)) return -EINVAL; value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg); switch (ctl->id) { case V4L2_CID_AUDIO_BALANCE: ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40) : (0x7f - (value & 0x7f)); break; case V4L2_CID_AUDIO_VOLUME: ctl->value = 0x3f - (value & 0x3f); break; default: ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift; break; } dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", ctl->id, c->v.name, ctl->value, c->reg, value,c->mask, c->sreg ? " [shadowed]" : ""); return 0;}EXPORT_SYMBOL(cx88_get_control);int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl){ struct cx88_ctrl *c = NULL; u32 value,mask; int i; for (i = 0; i < CX8800_CTLS; i++) { if (cx8800_ctls[i].v.id == ctl->id) { c = &cx8800_ctls[i]; } } if (unlikely(NULL == c)) return -EINVAL; if (ctl->value < c->v.minimum)#if 0 return -ERANGE;#else ctl->value = c->v.minimum;#endif if (ctl->value > c->v.maximum)#if 0 return -ERANGE;#else ctl->value = c->v.maximum;#endif mask=c->mask; switch (ctl->id) { case V4L2_CID_AUDIO_BALANCE: value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40); break; case V4L2_CID_AUDIO_VOLUME: value = 0x3f - (ctl->value & 0x3f); break; case V4L2_CID_SATURATION: /* special v_sat handling */ value = ((ctl->value - c->off) << c->shift) & c->mask; if (core->tvnorm & V4L2_STD_SECAM) { /* For SECAM, both U and V sat should be equal */ value=value<<8|value; } else { /* Keeps U Saturation proportional to V Sat */ value=(value*0x5a)/0x7f<<8|value; } mask=0xffff; break; case V4L2_CID_CHROMA_AGC: /* Do not allow chroma AGC to be enabled for SECAM */ value = ((ctl->value - c->off) << c->shift) & c->mask; if (core->tvnorm & V4L2_STD_SECAM && value) return -EINVAL; break; default: value = ((ctl->value - c->off) << c->shift) & c->mask; break; } dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", ctl->id, c->v.name, ctl->value, c->reg, value, mask, c->sreg ? " [shadowed]" : ""); if (c->sreg) { cx_sandor(c->sreg, c->reg, mask, value); } else { cx_andor(c->reg, mask, value); } return 0;}EXPORT_SYMBOL(cx88_set_control);static void init_controls(struct cx88_core *core){ struct v4l2_control ctrl; int i; for (i = 0; i < CX8800_CTLS; i++) { ctrl.id=cx8800_ctls[i].v.id; ctrl.value=cx8800_ctls[i].v.default_value; cx88_set_control(core, &ctrl); }}/* ------------------------------------------------------------------ *//* VIDEO IOCTLS */static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f){ struct cx8800_fh *fh = priv; f->fmt.pix.width = fh->width; f->fmt.pix.height = fh->height; f->fmt.pix.field = fh->vidq.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;}static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f){ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; struct cx8800_fmt *fmt; enum v4l2_field field; unsigned int maxw, maxh; fmt = format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) return -EINVAL; field = f->fmt.pix.field; maxw = norm_maxw(core->tvnorm); maxh = norm_maxh(core->tvnorm); if (V4L2_FIELD_ANY == field) { field = (f->fmt.pix.height > maxh/2) ? V4L2_FIELD_INTERLACED : V4L2_FIELD_BOTTOM; } switch (field) { case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: maxh = maxh / 2; break; case V4L2_FIELD_INTERLACED: break; default: return -EINVAL; } f->fmt.pix.field = field; if (f->fmt.pix.height < 32) f->fmt.pix.height = 32; if (f->fmt.pix.height > maxh) f->fmt.pix.height = maxh; if (f->fmt.pix.width < 48) f->fmt.pix.width = 48; if (f->fmt.pix.width > maxw) f->fmt.pix.width = maxw; f->fmt.pix.width &= ~0x03; f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; return 0;}static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f){ struct cx8800_fh *fh = priv; int err = vidioc_try_fmt_vid_cap (file,priv,f); if (0 != err) return err; fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); fh->width = f->fmt.pix.width; fh->height = f->fmt.pix.height; fh->vidq.field = f->fmt.pix.field; return 0;}static int vidioc_querycap (struct file *file, void *priv, struct v4l2_capability *cap){ struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; struct cx88_core *core = dev->core; strcpy(cap->driver, "cx8800"); strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities =#if 0 V4L2_CAP_VIDEO_OVERLAY |#endif V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE; if (UNSET != core->board.tuner_type) cap->capabilities |= V4L2_CAP_TUNER; return 0;}static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, struct v4l2_fmtdesc *f){ if (unlikely(f->index >= ARRAY_SIZE(formats))) return -EINVAL; strlcpy(f->description,formats[f->index].name,sizeof(f->description)); f->pixelformat = formats[f->index].fourcc; return 0;}#ifdef CONFIG_VIDEO_V4L1_COMPATstatic int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf){ struct cx8800_fh *fh = priv; return videobuf_cgmbuf (get_queue(fh), mbuf, 8);}#endifstatic int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p){ struct cx8800_fh *fh = priv; return (videobuf_reqbufs(get_queue(fh), p));}static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p){ struct cx8800_fh *fh = priv; return (videobuf_querybuf(get_queue(fh), p));}static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p){ struct cx8800_fh *fh = priv; return (videobuf_qbuf(get_queue(fh), p));}static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p){ struct cx8800_fh *fh = priv; return (videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK));}static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i){ struct cx8800_fh *fh = priv; struct cx8800_dev *dev = fh->dev;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -