📄 cx88-video.c
字号:
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; } case V4L2_BUF_TYPE_VBI_CAPTURE: cx8800_vbi_fmt(dev, f); return 0; default: return -EINVAL; }}static int cx8800_s_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh, struct v4l2_format *f){ int err; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: err = cx8800_try_fmt(dev,fh,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; case V4L2_BUF_TYPE_VBI_CAPTURE: cx8800_vbi_fmt(dev, f); return 0; default: return -EINVAL; }}/* * This function is _not_ called directly, but from * video_generic_ioctl (and maybe others). userspace * copying is done already, arg is a kernel pointer. */static int video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg){ struct cx8800_fh *fh = file->private_data; struct cx8800_dev *dev = fh->dev; struct cx88_core *core = dev->core; int err; if (video_debug > 1) cx88_print_ioctl(core->name,cmd); switch (cmd) { /* --- capabilities ------------------------------------------ */ case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); strcpy(cap->driver, "cx8800"); strlcpy(cap->card, cx88_boards[core->board].name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | 0; if (UNSET != core->tuner_type) cap->capabilities |= V4L2_CAP_TUNER; return 0; } /* --- capture ioctls ---------------------------------------- */ case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *f = arg; enum v4l2_buf_type type; unsigned int index; index = f->index; type = f->type; switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: if (index >= ARRAY_SIZE(formats)) return -EINVAL; memset(f,0,sizeof(*f)); f->index = index; f->type = type; strlcpy(f->description,formats[index].name,sizeof(f->description)); f->pixelformat = formats[index].fourcc; break; default: return -EINVAL; } return 0; } case VIDIOC_G_FMT: { struct v4l2_format *f = arg; return cx8800_g_fmt(dev,fh,f); } case VIDIOC_S_FMT: { struct v4l2_format *f = arg; return cx8800_s_fmt(dev,fh,f); } case VIDIOC_TRY_FMT: { struct v4l2_format *f = arg; return cx8800_try_fmt(dev,fh,f); } /* --- streaming capture ------------------------------------- */ case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; struct videobuf_queue *q; struct v4l2_requestbuffers req; unsigned int i; q = get_queue(fh); memset(&req,0,sizeof(req)); req.type = q->type; req.count = 8; req.memory = V4L2_MEMORY_MMAP; err = videobuf_reqbufs(q,&req); if (err < 0) return err; memset(mbuf,0,sizeof(*mbuf)); mbuf->frames = req.count; mbuf->size = 0; for (i = 0; i < mbuf->frames; i++) { mbuf->offsets[i] = q->bufs[i]->boff; mbuf->size += q->bufs[i]->bsize; } return 0; } case VIDIOC_REQBUFS: return videobuf_reqbufs(get_queue(fh), arg); case VIDIOC_QUERYBUF: return videobuf_querybuf(get_queue(fh), arg); case VIDIOC_QBUF: return videobuf_qbuf(get_queue(fh), arg); case VIDIOC_DQBUF: return videobuf_dqbuf(get_queue(fh), arg, file->f_flags & O_NONBLOCK); case VIDIOC_STREAMON: { int res = get_ressource(fh); if (!res_get(dev,fh,res)) return -EBUSY; return videobuf_streamon(get_queue(fh)); } case VIDIOC_STREAMOFF: { int res = get_ressource(fh); err = videobuf_streamoff(get_queue(fh)); if (err < 0) return err; res_free(dev,fh,res); return 0; } default: return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl ); } return 0;}int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl){ int err; if (video_debug > 1) cx88_print_ioctl(core->name,cmd); printk( KERN_INFO "CORE IOCTL: 0x%x\n", cmd ); cx88_print_ioctl(core->name,cmd); dprintk( 1, "CORE IOCTL: 0x%x\n", cmd ); switch (cmd) { /* ---------- tv norms ---------- */ case VIDIOC_ENUMSTD: { struct v4l2_standard *e = arg; unsigned int i; i = e->index; if (i >= ARRAY_SIZE(tvnorms)) return -EINVAL; err = v4l2_video_std_construct(e, tvnorms[e->index].id, tvnorms[e->index].name); e->index = i; if (err < 0) return err; return 0; } case VIDIOC_G_STD: { v4l2_std_id *id = arg; *id = core->tvnorm->id; return 0; } case VIDIOC_S_STD: { v4l2_std_id *id = arg; unsigned int i; for(i = 0; i < ARRAY_SIZE(tvnorms); i++) if (*id & tvnorms[i].id) break; if (i == ARRAY_SIZE(tvnorms)) return -EINVAL; down(&core->lock); cx88_set_tvnorm(core,&tvnorms[i]); up(&core->lock); return 0; } /* ------ input switching ---------- */ case VIDIOC_ENUMINPUT: { static const char *iname[] = { [ CX88_VMUX_COMPOSITE1 ] = "Composite1", [ CX88_VMUX_COMPOSITE2 ] = "Composite2", [ CX88_VMUX_COMPOSITE3 ] = "Composite3", [ CX88_VMUX_COMPOSITE4 ] = "Composite4", [ CX88_VMUX_SVIDEO ] = "S-Video", [ CX88_VMUX_TELEVISION ] = "Television", [ CX88_VMUX_CABLE ] = "Cable TV", [ CX88_VMUX_DVB ] = "DVB", [ CX88_VMUX_DEBUG ] = "for debug only", }; struct v4l2_input *i = arg; unsigned int n; n = i->index; if (n >= 4) return -EINVAL; if (0 == INPUT(n)->type) return -EINVAL; memset(i,0,sizeof(*i)); i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; strcpy(i->name,iname[INPUT(n)->type]); if ((CX88_VMUX_TELEVISION == INPUT(n)->type) || (CX88_VMUX_CABLE == INPUT(n)->type)) i->type = V4L2_INPUT_TYPE_TUNER; for (n = 0; n < ARRAY_SIZE(tvnorms); n++) i->std |= tvnorms[n].id; return 0; } case VIDIOC_G_INPUT: { unsigned int *i = arg; *i = core->input; return 0; } case VIDIOC_S_INPUT: { unsigned int *i = arg; if (*i >= 4) return -EINVAL; down(&core->lock); cx88_newstation(core); video_mux(core,*i); up(&core->lock); return 0; } /* --- controls ---------------------------------------------- */ case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *c = arg; int i; if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) return -EINVAL; for (i = 0; i < CX8800_CTLS; i++) if (cx8800_ctls[i].v.id == c->id) break; if (i == CX8800_CTLS) { *c = no_ctl; return 0; } *c = cx8800_ctls[i].v; return 0; } case VIDIOC_G_CTRL: return get_control(core,arg); case VIDIOC_S_CTRL: return set_control(core,arg); /* --- tuner ioctls ------------------------------------------ */ case VIDIOC_G_TUNER: { struct v4l2_tuner *t = arg; u32 reg; if (UNSET == core->tuner_type) return -EINVAL; if (0 != t->index) return -EINVAL; memset(t,0,sizeof(*t)); strcpy(t->name, "Television"); t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM; t->rangehigh = 0xffffffffUL; cx88_get_stereo(core ,t); reg = cx_read(MO_DEVICE_STATUS); t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; return 0; } case VIDIOC_S_TUNER: { struct v4l2_tuner *t = arg; if (UNSET == core->tuner_type) return -EINVAL; if (0 != t->index) return -EINVAL; cx88_set_stereo(core, t->audmode, 1); return 0; } case VIDIOC_G_FREQUENCY: { struct v4l2_frequency *f = arg; memset(f,0,sizeof(*f)); if (UNSET == core->tuner_type) return -EINVAL; /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ f->type = radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = core->freq; cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); return 0; } case VIDIOC_S_FREQUENCY: { struct v4l2_frequency *f = arg; if (UNSET == core->tuner_type) return -EINVAL; if (f->tuner != 0) return -EINVAL; if (0 == radio && f->type != V4L2_TUNER_ANALOG_TV) return -EINVAL; if (1 == radio && f->type != V4L2_TUNER_RADIO) return -EINVAL; down(&core->lock); core->freq = f->frequency; cx88_newstation(core); cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f); /* When changing channels it is required to reset TVAUDIO */ msleep (10); cx88_set_tvaudio(core); up(&core->lock); return 0; } default: return v4l_compat_translate_ioctl(inode,file,cmd,arg, driver_ioctl); } return 0;}static int video_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return video_usercopy(inode, file, cmd, arg, video_do_ioctl);}/* ----------------------------------------------------------- */static int radio_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg){ struct cx8800_fh *fh = file->private_data; struct cx8800_dev *dev = fh->dev; struct cx88_core *core = dev->core; if (video_debug > 1) cx88_print_ioctl(core->name,cmd); switch (cmd) { case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); strcpy(cap->driver, "cx8800"); strlcpy(cap->card, cx88_boards[core->board].name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; return 0; } case VIDIOC_G_TUNER: { struct v4l2_tuner *t = arg; if (t->index > 0) return -EINVAL; memset(t,0,sizeof(*t)); strcpy(t->name, "Radio"); cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t); return 0; } case VIDIOC_ENUMINPUT: { struct v4l2_input *i = arg; if (i->index != 0) return -EINVAL; strcpy(i->name,"Radio"); i->type = V4L2_INPUT_TYPE_TUNER; return 0; } case VIDIOC_G_INPUT: { int *i = arg; *i = 0; return 0; } case VIDIOC_G_AUDIO: { struct v4l2_audio *a = arg; memset(a,0,sizeof(*a)); strcpy(a->name,"Radio"); return 0; } case VIDIOC_G_STD: { v4l2_std_id *id = arg; *id = 0; return 0; } case VIDIOCSTUNER: { struct video_tuner *v = arg; if (v->tuner) /* Only tuner 0 */ return -EINVAL; cx88_call_i2c_clients(core,VIDIOCSTUNER,v); return 0; } case VIDIOC_S_TUNER: { struct v4l2_tuner *t = arg; if (0 != t->index) return -EINVAL; cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t); return 0; } case VIDIOC_S_AUDIO: case VIDIOC_S_INPUT: case VIDIOC_S_STD: return 0; case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *c = arg; int i; if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) return -EINVAL; if (c->id == V4L2_CID_AUDIO_MUTE) { for (i = 0; i < CX8800_CTLS; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -