⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 saa7134-video.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	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;#ifdef VIDIOC_G_PRIORITY	v4l2_prio_open(&dev->prio,&fh->prio);#endif	videobuf_queue_init(&fh->cap, &video_qops,			    dev->pci, &dev->slock,			    V4L2_BUF_TYPE_VIDEO_CAPTURE,			    V4L2_FIELD_INTERLACED,			    sizeof(struct saa7134_buf));	init_MUTEX(&fh->cap.lock);	saa7134_pgtable_alloc(dev->pci,&fh->pt_cap);	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));        init_MUTEX(&fh->vbi.lock);	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(file, saa7134_queue(fh),					 data, count, ppos);	case V4L2_BUF_TYPE_VBI_CAPTURE:		if (!res_get(fh->dev,fh,RESOURCE_VBI))			return -EBUSY;		return videobuf_read_stream(file, saa7134_queue(fh),					    data, count, ppos, 1);		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(file,fh->cap.read_buf,fh->cap.field)) {                                up(&fh->cap.lock);                                return POLLERR;                        }                        fh->cap.ops->buf_queue(file,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(file,&fh->cap);		res_free(dev,fh,RESOURCE_VIDEO);	}	if (fh->cap.read_buf) {		buffer_release(file,fh->cap.read_buf);		kfree(fh->cap.read_buf);	}	/* stop vbi capture */	if (res_check(fh, RESOURCE_VBI)) {		if (fh->vbi.streaming)			videobuf_streamoff(file,&fh->vbi);		if (fh->vbi.reading)			videobuf_read_stop(file,&fh->vbi);		res_free(dev,fh,RESOURCE_VBI);	}	saa7134_pgtable_free(dev->pci,&fh->pt_cap);	saa7134_pgtable_free(dev->pci,&fh->pt_vbi);#ifdef VIDIOC_G_PRIORITY	v4l2_prio_close(&dev->prio,&fh->prio);#endif	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(vma,saa7134_queue(fh));}/* ------------------------------------------------------------------ */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;	f->fmt.vbi.count[0] = norm->vbi_v_stop - norm->vbi_v_start +1;	f->fmt.vbi.start[1] = norm->video_v_stop + norm->vbi_v_start +1;	f->fmt.vbi.count[1] = f->fmt.vbi.count[0];	f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */#if 0	if (V4L2_STD_PAL == norm->id) {		/* FIXME */		f->fmt.vbi.start[0] += 3;		f->fmt.vbi.start[1] += 3*2;	}#endif}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;	}}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.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;	}}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;}/* * 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);#ifdef VIDIOC_G_PRIORITY	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;	}#endif	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_VIDEO_CAPTURE |			V4L2_CAP_VIDEO_OVERLAY |			V4L2_CAP_VBI_CAPTURE |			V4L2_CAP_TUNER |			V4L2_CAP_READWRITE | 			V4L2_CAP_STREAMING;		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)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -