📄 saa7134-video.c
字号:
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.top = b->left; if (crop->c.left > b->left + b->width) crop->c.top = 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->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 = 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 (V4L2_TUNER_ANALOG_TV != f->type) return -EINVAL; down(&dev->lock); dev->ctl_freq = f->frequency;#ifdef V4L2_I2C_CLIENTS saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);#else saa7134_i2c_call_clients(dev,VIDIOCSFREQ,&dev->ctl_freq);#endif 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; }#ifdef VIDIOC_G_PRIORITY 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); }#endif /* --- preview 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: case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (index >= FORMATS) return -EINVAL; if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY && formats[index].planar) 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; case V4L2_BUF_TYPE_VBI_CAPTURE: if (0 != index) return -EINVAL; memset(f,0,sizeof(*f)); f->index = index; f->type = type; f->pixelformat = V4L2_PIX_FMT_GREY; strcpy(f->description,"vbi data"); break; default: return -EINVAL; } return 0; } case VIDIOC_G_FBUF: { struct v4l2_framebuffer *fb = arg; *fb = dev->ovbuf; fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; return 0; } case VIDIOC_S_FBUF: { struct v4l2_framebuffer *fb = arg; struct saa7134_format *fmt; if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) return -EPERM; /* check args */ fmt = format_by_fourcc(fb->fmt.pixelformat); if (NULL == fmt) return -EINVAL; /* ok, accept it */ dev->ovbuf = *fb; dev->ovfmt = fmt; if (0 == dev->ovbuf.fmt.bytesperline) dev->ovbuf.fmt.bytesperline = dev->ovbuf.fmt.width*fmt->depth/8; return 0; } case VIDIOC_OVERLAY: { int *on = arg; if (*on) { if (!res_get(dev,fh,RESOURCE_OVERLAY)) return -EBUSY; spin_lock_irqsave(&dev->slock,flags); start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); } if (!*on) { if (!res_check(fh, RESOURCE_OVERLAY)) return -EINVAL; spin_lock_irqsave(&dev->slock,flags); stop_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); res_free(dev,fh,RESOURCE_OVERLAY); } return 0; } /* --- capture ioctls ---------------------------------------- */ case VIDIOC_G_FMT: { struct v4l2_format *f = arg; return saa7134_g_fmt(dev,fh,f); } case VIDIOC_S_FMT: { struct v4l2_format *f = arg; return saa7134_s_fmt(dev,fh,f); } case VIDIOC_TRY_FMT: { struct v4l2_format *f = arg; return saa7134_try_fmt(dev,fh,f); } case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; struct videobuf_queue *q; struct v4l2_requestbuffers req; unsigned int i; q = saa7134_queue(fh); memset(&req,0,sizeof(req)); req.type = q->type; req.count = gbuffers; req.memory = V4L2_MEMORY_MMAP; err = videobuf_reqbufs(file,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(file,saa7134_queue(fh),arg); case VIDIOC_QUERYBUF: return videobuf_querybuf(saa7134_queue(fh),arg); case VIDIOC_QBUF: return videobuf_qbuf(file,saa7134_queue(fh),arg); case VIDIOC_DQBUF: return videobuf_dqbuf(file,saa7134_queue(fh),arg); case VIDIOC_STREAMON: { int res = saa7134_resource(fh); if (!res_get(dev,fh,res)) return -EBUSY; return videobuf_streamon(file,saa7134_queue(fh)); } case VIDIOC_STREAMOFF: { int res = saa7134_resource(fh); err = videobuf_streamoff(file,saa7134_queue(fh)); if (err < 0) return err; res_free(dev,fh,res); return 0; } default: return v4l_compat_translate_ioctl(inode,file,cmd,arg, video_do_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 saa7134_fh *fh = file->private_data; struct saa7134_dev *dev = fh->dev; if (video_debug > 1) saa7134_print_ioctl(dev->name,cmd); switch (cmd) { case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; 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_TUNER; return 0; } case VIDIOC_G_TUNER: { struct v4l2_tuner *t = arg; if (0 != t->index) return -EINVAL; memset(t,0,sizeof(*t)); strcpy(t->name, "Radio"); t->rangelow = (int)(65*16); t->rangehigh = (int)(108*16);#ifdef V4L2_I2C_CLIENTS saa7134_i2c_call_clients(dev,VIDIOC_G_TUNER,t);#else { struct video_tuner vt; memset(&vt,0,sizeof(vt)); saa7134_i2c_call_clients(dev,VIDIOCGTUNER,&vt); t->signal = vt.signal; }#endif 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 VIDIOC_S_AUDIO: case VIDIOC_S_TUNER: case VIDIOC_S_INPUT: case VIDIOC_S_STD: return 0; case VIDIOC_QUERYCTRL: { const struct v4l2_queryctrl *ctrl; struct v4l2_queryctrl *c = arg; if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) return -EINVAL; if (c->id == V4L2_CID_AUDIO_MUTE) { ctrl = ctrl_by_id(c->id); *c = *ctrl; } else *c = no_ctrl; return 0; } case VIDIOC_G_CTRL: case VIDIOC_S_CTRL: case VIDIOC_G_FREQUENCY: case VIDIOC_S_FREQUENCY: return video_do_ioctl(inode,file,cmd,arg); default: return v4l_compat_translate_ioctl(inode,file,cmd,arg, radio_do_ioctl); } return 0;}static int radio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);}static struct file_operations video_fops ={ .owner = THIS_MODULE, .open = video_open, .release = video_release, .read = video_read, .poll = video_poll, .mmap = video_mmap, .ioctl = video_ioctl, .llseek = no_llseek,};static struct file_operations radio_fops ={ .owner = THIS_MODULE, .open = video_open, .release = video_release, .ioctl = radio_ioctl, .llseek = no_llseek,};/* ----------------------------------------------------------- *//* exported stuff */struct video_device saa7134_video_template ={ .name = "saa7134-video", .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY| VID_TYPE_CLIPPING|VID_TYPE_SCALES, .hardware = 0, .fops = &video_fops, .minor = -1,};struct video_device saa7134_vbi_template ={ .name = "saa7134-vbi", .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT, .hardware = 0, .fops = &video_fops, .minor = -1,};struct video_device saa7134_radio_template ={ .name = "saa7134-radio", .type = VID_TYPE_TUNER, .hardware = 0, .fops = &radio_fops, .minor = -1,};int saa7134_video_init1(struct saa7134_dev *dev){ /* sanitycheck insmod options */ if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) gbuffers = 2; if (gbufsize < 0 || gbufsize > gbufsize_max) gbufsize = gbufsize_max; gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; /* put some sensible defaults into the data structures ... */ dev->ctl_bright = ctrl_by_id(V4L2_CID_BRIGHTNESS)->default_value; dev->ctl_contrast = ctrl_by_id(V4L2_CID_CONTRAST)->default_value; dev->ctl_hue = ctrl_by_id(V4L2_CID_HUE)->default_value; dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value; dev->ctl_volume = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value; dev->ctl_invert = 0; dev->ctl_mute = 1; dev->automute = 0; INIT_LIST_HEAD(&dev->video_q.queue); init_timer(&dev->video_q.timeout); dev->video_q.timeout.function = saa7134_buffer_timeout; dev->video_q.timeout.data = (unsigned long)(&dev->video_q); dev->video_q.dev = dev; if (saa7134_boards[dev->board].video_out) { /* enable video output */ int vo = saa7134_boards[dev->board].video_out; saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_out[vo][1]); saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_out[vo][5]); saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_out[vo][6]); saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); } return 0;}int saa7134_video_init2(struct saa7134_dev *dev){ /* init video hw */ set_tvnorm(dev,&tvnorms[0]); video_mux(dev,0); saa7134_tvaudio_setmute(dev); saa7134_tvaudio_setvolume(dev,dev->ctl_volume); return 0;}int saa7134_video_fini(struct saa7134_dev *dev){ /* nothing */ return 0;}void saa7134_irq_video_intl(struct saa7134_dev *dev){ static const char *st[] = { "no signal", "found NTSC", "found PAL", "found SECAM" }; int norm; norm = saa_readb(SAA7134_STATUS_VIDEO1) & 0x03; dprintk("DCSDT: %s\n",st[norm]); if (0 != norm) { /* wake up tvaudio audio carrier scan thread */ saa7134_tvaudio_do_scan(dev); } else { /* no video signal -> mute audio */ dev->automute = 1; saa7134_tvaudio_setmute(dev); }}void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status){ enum v4l2_field field; spin_lock(&dev->slock); if (dev->video_q.curr) { dev->video_fieldcount++; field = dev->video_q.curr->vb.field; if (V4L2_FIELD_HAS_BOTH(field)) { /* make sure we have seen both fields */ if ((status & 0x10) == 0x00) { dev->video_q.curr->top_seen = 1; goto done; } if (!dev->video_q.curr->top_seen) goto done; } else if (field == V4L2_FIELD_TOP) { if ((status & 0x10) != 0x10) goto done; } else if (field == V4L2_FIELD_BOTTOM) { if ((status & 0x10) != 0x00) goto done; } dev->video_q.curr->vb.field_count = dev->video_fieldcount; saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE); } saa7134_buffer_next(dev,&dev->video_q); done: spin_unlock(&dev->slock);}/* ----------------------------------------------------------- *//* * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -