📄 saa7134-video.c
字号:
}static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_format *f){ int err; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { struct saa7134_format *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 = min(dev->crop_current.width*4, dev->crop_bounds.width); maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); 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.width < 48) f->fmt.pix.width = 48; if (f->fmt.pix.height < 32) f->fmt.pix.height = 32; if (f->fmt.pix.width > maxw) f->fmt.pix.width = maxw; if (f->fmt.pix.height > maxh) f->fmt.pix.height = maxh; 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_VIDEO_OVERLAY: err = verify_preview(dev,&f->fmt.win); if (0 != err) return err; return 0; case V4L2_BUF_TYPE_VBI_CAPTURE: saa7134_vbi_fmt(dev,f); return 0; default: return -EINVAL; }}static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_format *f){ unsigned long flags; int err; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: err = saa7134_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->cap.field = f->fmt.pix.field; return 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: err = verify_preview(dev,&f->fmt.win); if (0 != err) return err; down(&dev->lock); fh->win = f->fmt.win; fh->nclips = f->fmt.win.clipcount; if (fh->nclips > 8) fh->nclips = 8; if (copy_from_user(fh->clips,f->fmt.win.clips, sizeof(struct v4l2_clip)*fh->nclips)) { up(&dev->lock); return -EFAULT; } if (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); } up(&dev->lock); return 0; case V4L2_BUF_TYPE_VBI_CAPTURE: saa7134_vbi_fmt(dev,f); return 0; default: return -EINVAL; }}int saa7134_common_ioctl(struct saa7134_dev *dev, unsigned int cmd, void *arg){ int err; switch (cmd) { case VIDIOC_QUERYCTRL: { const struct v4l2_queryctrl *ctrl; struct v4l2_queryctrl *c = arg; if ((c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) && (c->id < V4L2_CID_PRIVATE_BASE || c->id >= V4L2_CID_PRIVATE_LASTP1)) return -EINVAL; ctrl = ctrl_by_id(c->id); *c = (NULL != ctrl) ? *ctrl : no_ctrl; return 0; } case VIDIOC_G_CTRL: return get_control(dev,arg); case VIDIOC_S_CTRL: { down(&dev->lock); err = set_control(dev,NULL,arg); up(&dev->lock); return err; } /* --- input switching --------------------------------------- */ case VIDIOC_ENUMINPUT: { struct v4l2_input *i = arg; unsigned int n; n = i->index; if (n >= SAA7134_INPUT_MAX) return -EINVAL; if (NULL == card_in(dev,i->index).name) return -EINVAL; memset(i,0,sizeof(*i)); i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; strcpy(i->name,card_in(dev,n).name); if (card_in(dev,n).tv) i->type = V4L2_INPUT_TYPE_TUNER; i->audioset = 1; if (n == dev->ctl_input) { int v1 = saa_readb(SAA7134_STATUS_VIDEO1); int v2 = saa_readb(SAA7134_STATUS_VIDEO2); if (0 != (v1 & 0x40)) i->status |= V4L2_IN_ST_NO_H_LOCK; if (0 != (v2 & 0x40)) i->status |= V4L2_IN_ST_NO_SYNC; if (0 != (v2 & 0x0e)) i->status |= V4L2_IN_ST_MACROVISION; } for (n = 0; n < TVNORMS; n++) i->std |= tvnorms[n].id; return 0; } case VIDIOC_G_INPUT: { int *i = arg; *i = dev->ctl_input; return 0; } case VIDIOC_S_INPUT: { int *i = arg; if (*i < 0 || *i >= SAA7134_INPUT_MAX) return -EINVAL; if (NULL == card_in(dev,*i).name) return -EINVAL; down(&dev->lock); video_mux(dev,*i); up(&dev->lock); return 0; } } return 0;}EXPORT_SYMBOL(saa7134_common_ioctl);/* * 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 saa7134_fh *fh = file->private_data; struct saa7134_dev *dev = fh->dev; unsigned long flags; int err; if (video_debug > 1) saa7134_print_ioctl(dev->name,cmd); switch (cmd) { case VIDIOC_S_CTRL: case VIDIOC_S_STD: case VIDIOC_S_INPUT: case VIDIOC_S_TUNER: case VIDIOC_S_FREQUENCY: err = v4l2_prio_check(&dev->prio,&fh->prio); if (0 != err) return err; } switch (cmd) { case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; unsigned int tuner_type = dev->tuner_type; memset(cap,0,sizeof(*cap)); strcpy(cap->driver, "saa7134"); strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); cap->version = SAA7134_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_TUNER; if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) cap->capabilities &= ~V4L2_CAP_TUNER; return 0; } /* --- tv standards ------------------------------------------ */ case VIDIOC_ENUMSTD: { struct v4l2_standard *e = arg; unsigned int i; i = e->index; if (i >= 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 = dev->tvnorm->id; return 0; } case VIDIOC_S_STD: { v4l2_std_id *id = arg; unsigned int i; for (i = 0; i < TVNORMS; i++) if (*id == tvnorms[i].id) break; if (i == TVNORMS) for (i = 0; i < TVNORMS; i++) if (*id & tvnorms[i].id) break; if (i == TVNORMS) return -EINVAL; down(&dev->lock); if (res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); stop_preview(dev,fh); set_tvnorm(dev,&tvnorms[i]); start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); } else set_tvnorm(dev,&tvnorms[i]); saa7134_tvaudio_do_scan(dev); up(&dev->lock); return 0; } case VIDIOC_CROPCAP: { struct v4l2_cropcap *cap = arg; if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) return -EINVAL; cap->bounds = dev->crop_bounds; cap->defrect = dev->crop_defrect; cap->pixelaspect.numerator = 1; cap->pixelaspect.denominator = 1; if (dev->tvnorm->id & V4L2_STD_525_60) { cap->pixelaspect.numerator = 11; cap->pixelaspect.denominator = 10; } if (dev->tvnorm->id & V4L2_STD_625_50) { cap->pixelaspect.numerator = 54; cap->pixelaspect.denominator = 59; } return 0; } case VIDIOC_G_CROP: { struct v4l2_crop * crop = arg; if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) return -EINVAL; crop->c = dev->crop_current; return 0; } case VIDIOC_S_CROP: { struct v4l2_crop *crop = arg; struct v4l2_rect *b = &dev->crop_bounds; if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) return -EINVAL; if (crop->c.height < 0) return -EINVAL; if (crop->c.width < 0) return -EINVAL; if (res_locked(fh->dev,RESOURCE_OVERLAY)) return -EBUSY; if (res_locked(fh->dev,RESOURCE_VIDEO)) return -EBUSY; if (crop->c.top < b->top) crop->c.top = b->top; if (crop->c.top > b->top + b->height) crop->c.top = b->top + b->height; if (crop->c.height > b->top - crop->c.top + b->height) crop->c.height = b->top - crop->c.top + b->height; if (crop->c.left < b->left) crop->c.left = b->left; if (crop->c.left > b->left + b->width) crop->c.left = b->left + b->width; if (crop->c.width > b->left - crop->c.left + b->width) crop->c.width = b->left - crop->c.left + b->width; dev->crop_current = crop->c; return 0; } /* --- tuner ioctls ------------------------------------------ */ case VIDIOC_G_TUNER: { struct v4l2_tuner *t = arg; int n; if (0 != t->index) return -EINVAL; memset(t,0,sizeof(*t)); for (n = 0; n < SAA7134_INPUT_MAX; n++) if (card_in(dev,n).tv) break; if (NULL != card_in(dev,n).name) { strcpy(t->name, "Television"); t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; t->rangehigh = 0xffffffffUL; t->rxsubchans = saa7134_tvaudio_getstereo(dev); t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans); } if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)) t->signal = 0xffff; return 0; } case VIDIOC_S_TUNER: { struct v4l2_tuner *t = arg; int rx,mode; mode = dev->thread.mode; if (UNSET == mode) { rx = saa7134_tvaudio_getstereo(dev); mode = saa7134_tvaudio_rx2mode(t->rxsubchans); } if (mode != t->audmode) { dev->thread.mode = t->audmode; } return 0; } case VIDIOC_G_FREQUENCY: { struct v4l2_frequency *f = arg; memset(f,0,sizeof(*f)); f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = dev->ctl_freq; return 0; } case VIDIOC_S_FREQUENCY: { struct v4l2_frequency *f = arg; if (0 != f->tuner) return -EINVAL; if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) return -EINVAL; if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) return -EINVAL; down(&dev->lock); dev->ctl_freq = f->frequency; saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f); saa7134_tvaudio_do_scan(dev); up(&dev->lock); return 0; } /* --- control ioctls ---------------------------------------- */ case VIDIOC_ENUMINPUT: case VIDIOC_G_INPUT: case VIDIOC_S_INPUT: case VIDIOC_QUERYCTRL: case VIDIOC_G_CTRL: case VIDIOC_S_CTRL: return saa7134_common_ioctl(dev, cmd, arg); case VIDIOC_G_AUDIO: { struct v4l2_audio *a = arg; memset(a,0,sizeof(*a)); strcpy(a->name,"audio"); return 0; } case VIDIOC_S_AUDIO: return 0; case VIDIOC_G_PARM: { struct v4l2_captureparm *parm = arg; memset(parm,0,sizeof(*parm)); return 0; } case VIDIOC_G_PRIORITY: { enum v4l2_priority *p = arg; *p = v4l2_prio_max(&dev->prio); return 0; } case VIDIOC_S_PRIORITY: { enum v4l2_priority *prio = arg; return v4l2_prio_change(&dev->prio, &fh->prio, *prio); } /* --- preview ioctls ---------------------------------------- */ case VIDIOC_ENUM_FMT: {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -