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

📄 saa7146_video.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
static int set_control(struct saa7146_fh *fh, struct v4l2_control *c){	struct saa7146_dev *dev = fh->dev;	struct saa7146_vv *vv = dev->vv_data;	const struct v4l2_queryctrl* ctrl;	ctrl = ctrl_by_id(c->id);	if (NULL == ctrl) {		DEB_D(("unknown control %d\n",c->id));		return -EINVAL;	}	down(&dev->lock);	switch (ctrl->type) {	case V4L2_CTRL_TYPE_BOOLEAN:	case V4L2_CTRL_TYPE_MENU:	case V4L2_CTRL_TYPE_INTEGER:		if (c->value < ctrl->minimum)			c->value = ctrl->minimum;		if (c->value > ctrl->maximum)			c->value = ctrl->maximum;		break;	default:		/* nothing */;	};	switch (c->id) {	case V4L2_CID_BRIGHTNESS: {		u32 value = saa7146_read(dev, BCS_CTRL);		value &= 0x00ffffff;		value |= (c->value << 24);		saa7146_write(dev, BCS_CTRL, value);		saa7146_write(dev, MC2, MASK_22 | MASK_06 );		break;	}	case V4L2_CID_CONTRAST: {		u32 value = saa7146_read(dev, BCS_CTRL);		value &= 0xff00ffff;		value |= (c->value << 16);		saa7146_write(dev, BCS_CTRL, value);		saa7146_write(dev, MC2, MASK_22 | MASK_06 );		break;	}	case V4L2_CID_SATURATION: {		u32 value = saa7146_read(dev, BCS_CTRL);		value &= 0xffffff00;		value |= (c->value << 0);		saa7146_write(dev, BCS_CTRL, value);		saa7146_write(dev, MC2, MASK_22 | MASK_06 );		break;	}	case V4L2_CID_HFLIP:		/* fixme: we can support changing VFLIP and HFLIP here... */		if (IS_CAPTURE_ACTIVE(fh) != 0) {			DEB_D(("V4L2_CID_HFLIP while active capture.\n"));			up(&dev->lock);			return -EINVAL;		}		vv->hflip = c->value;		break;	case V4L2_CID_VFLIP:		if (IS_CAPTURE_ACTIVE(fh) != 0) {			DEB_D(("V4L2_CID_VFLIP while active capture.\n"));			up(&dev->lock);			return -EINVAL;		}		vv->vflip = c->value;		break;	default: {		return -EINVAL;	}	}	up(&dev->lock);	if (IS_OVERLAY_ACTIVE(fh) != 0) {		saa7146_stop_preview(fh);		saa7146_start_preview(fh);	}	return 0;}/********************************************************************************//* common pagetable functions */static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf){	struct pci_dev *pci = dev->pci;	struct scatterlist *list = buf->vb.dma.sglist;	int length = buf->vb.dma.sglen;	struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);	DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length));	if( 0 != IS_PLANAR(sfmt->trans)) {		struct saa7146_pgtable *pt1 = &buf->pt[0];		struct saa7146_pgtable *pt2 = &buf->pt[1];		struct saa7146_pgtable *pt3 = &buf->pt[2];		u32  *ptr1, *ptr2, *ptr3;		u32 fill;		int size = buf->fmt->width*buf->fmt->height;		int i,p,m1,m2,m3,o1,o2;		switch( sfmt->depth ) {			case 12: {				/* create some offsets inside the page table */				m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;				m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1;				m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;				o1 = size%PAGE_SIZE;				o2 = (size+(size/4))%PAGE_SIZE;				DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));				break;			}			case 16: {				/* create some offsets inside the page table */				m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;				m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;				m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1;				o1 = size%PAGE_SIZE;				o2 = (size+(size/2))%PAGE_SIZE;				DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));				break;			}			default: {				return -1;			}		}		ptr1 = pt1->cpu;		ptr2 = pt2->cpu;		ptr3 = pt3->cpu;		/* walk all pages, copy all page addresses to ptr1 */		for (i = 0; i < length; i++, list++) {			for (p = 0; p * 4096 < list->length; p++, ptr1++) {				*ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset);			}		}/*		ptr1 = pt1->cpu;		for(j=0;j<40;j++) {			printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);		}*/		/* if we have a user buffer, the first page may not be		   aligned to a page boundary. */		pt1->offset = buf->vb.dma.sglist->offset;		pt2->offset = pt1->offset+o1;		pt3->offset = pt1->offset+o2;		/* create video-dma2 page table */		ptr1 = pt1->cpu;		for(i = m1; i <= m2 ; i++, ptr2++) {			*ptr2 = ptr1[i];		}		fill = *(ptr2-1);		for(;i<1024;i++,ptr2++) {			*ptr2 = fill;		}		/* create video-dma3 page table */		ptr1 = pt1->cpu;		for(i = m2; i <= m3; i++,ptr3++) {			*ptr3 = ptr1[i];		}		fill = *(ptr3-1);		for(;i<1024;i++,ptr3++) {			*ptr3 = fill;		}		/* finally: finish up video-dma1 page table */		ptr1 = pt1->cpu+m1;		fill = pt1->cpu[m1];		for(i=m1;i<1024;i++,ptr1++) {			*ptr1 = fill;		}/*		ptr1 = pt1->cpu;		ptr2 = pt2->cpu;		ptr3 = pt3->cpu;		for(j=0;j<40;j++) {			printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);		}		for(j=0;j<40;j++) {			printk("ptr2 %d: 0x%08x\n",j,ptr2[j]);		}		for(j=0;j<40;j++) {			printk("ptr3 %d: 0x%08x\n",j,ptr3[j]);		}*/	} else {		struct saa7146_pgtable *pt = &buf->pt[0];		return saa7146_pgtable_build_single(pci, pt, list, length);	}	return 0;}/********************************************************************************//* file operations */static int video_begin(struct saa7146_fh *fh){	struct saa7146_dev *dev = fh->dev;	struct saa7146_vv *vv = dev->vv_data;	struct saa7146_format *fmt = NULL;	unsigned int resource;	int ret = 0, err = 0;	DEB_EE(("dev:%p, fh:%p\n",dev,fh));	if ((vv->video_status & STATUS_CAPTURE) != 0) {		if (vv->video_fh == fh) {			DEB_S(("already capturing.\n"));			return 0;		}		DEB_S(("already capturing in another open.\n"));		return -EBUSY;	}	if ((vv->video_status & STATUS_OVERLAY) != 0) {		DEB_S(("warning: suspending overlay video for streaming capture.\n"));		vv->ov_suspend = vv->video_fh;		err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */		if (0 != err) {			DEB_D(("suspending video failed. aborting\n"));			return err;		}	}	fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);	/* we need to have a valid format set here */	BUG_ON(NULL == fmt);	if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {		resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;	} else {		resource = RESOURCE_DMA1_HPS;	}	ret = saa7146_res_get(fh, resource);	if (0 == ret) {		DEB_S(("cannot get capture resource %d\n",resource));		if (vv->ov_suspend != NULL) {			saa7146_start_preview(vv->ov_suspend);			vv->ov_suspend = NULL;		}		return -EBUSY;	}	/* clear out beginning of streaming bit (rps register 0)*/	saa7146_write(dev, MC2, MASK_27 );	/* enable rps0 irqs */	SAA7146_IER_ENABLE(dev, MASK_27);	vv->video_fh = fh;	vv->video_status = STATUS_CAPTURE;	return 0;}static int video_end(struct saa7146_fh *fh, struct file *file){	struct saa7146_dev *dev = fh->dev;	struct saa7146_vv *vv = dev->vv_data;	struct saa7146_format *fmt = NULL;	unsigned long flags;	unsigned int resource;	u32 dmas = 0;	DEB_EE(("dev:%p, fh:%p\n",dev,fh));	if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {		DEB_S(("not capturing.\n"));		return 0;	}	if (vv->video_fh != fh) {		DEB_S(("capturing, but in another open.\n"));		return -EBUSY;	}	fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);	/* we need to have a valid format set here */	BUG_ON(NULL == fmt);	if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {		resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;		dmas = MASK_22 | MASK_21 | MASK_20;	} else {		resource = RESOURCE_DMA1_HPS;		dmas = MASK_22;	}	spin_lock_irqsave(&dev->slock,flags);	/* disable rps0  */	saa7146_write(dev, MC1, MASK_28);	/* disable rps0 irqs */	SAA7146_IER_DISABLE(dev, MASK_27);	/* shut down all used video dma transfers */	saa7146_write(dev, MC1, dmas);	spin_unlock_irqrestore(&dev->slock, flags);	vv->video_fh = NULL;	vv->video_status = 0;	saa7146_res_free(fh, resource);	if (vv->ov_suspend != NULL) {		saa7146_start_preview(vv->ov_suspend);		vv->ov_suspend = NULL;	}	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. */int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg){	struct saa7146_fh *fh  = file->private_data;	struct saa7146_dev *dev = fh->dev;	struct saa7146_vv *vv = dev->vv_data;	int err = 0, result = 0, ee = 0;	struct saa7146_use_ops *ops;	struct videobuf_queue *q;	/* check if extension handles the command */	for(ee = 0; dev->ext_vv_data->ioctls[ee].flags != 0; ee++) {		if( cmd == dev->ext_vv_data->ioctls[ee].cmd )			break;	}	if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) {		DEB_D(("extension handles ioctl exclusive.\n"));		result = dev->ext_vv_data->ioctl(fh, cmd, arg);		return result;	}	if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) {		DEB_D(("extension handles ioctl before.\n"));		result = dev->ext_vv_data->ioctl(fh, cmd, arg);		if( -EAGAIN != result ) {			return result;		}	}	/* fixme: add handle "after" case (is it still needed?) */	switch (fh->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE: {		ops = &saa7146_video_uops;		q = &fh->video_q;		break;		}	case V4L2_BUF_TYPE_VBI_CAPTURE: {		ops = &saa7146_vbi_uops;		q = &fh->vbi_q;		break;		}	default:		BUG();		return 0;	}	switch (cmd) {	case VIDIOC_QUERYCAP:	{		struct v4l2_capability *cap = arg;		memset(cap,0,sizeof(*cap));		DEB_EE(("VIDIOC_QUERYCAP\n"));		strcpy(cap->driver, "saa7146 v4l2");		strlcpy(cap->card, dev->ext->name, sizeof(cap->card));		sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));		cap->version = SAA7146_VERSION_CODE;		cap->capabilities =			V4L2_CAP_VIDEO_CAPTURE |			V4L2_CAP_VIDEO_OVERLAY |			V4L2_CAP_READWRITE |			V4L2_CAP_STREAMING;		cap->capabilities |= dev->ext_vv_data->capabilities;		return 0;	}	case VIDIOC_G_FBUF:	{		struct v4l2_framebuffer *fb = arg;		DEB_EE(("VIDIOC_G_FBUF\n"));		*fb = vv->ov_fb;		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;		return 0;	}	case VIDIOC_S_FBUF:	{		struct v4l2_framebuffer *fb = arg;		struct saa7146_format *fmt;		DEB_EE(("VIDIOC_S_FBUF\n"));		if(!capable(CAP_SYS_ADMIN) &&		   !capable(CAP_SYS_RAWIO))			return -EPERM;		/* check args */		fmt = format_by_fourcc(dev,fb->fmt.pixelformat);		if (NULL == fmt) {			return -EINVAL;		}		/* planar formats are not allowed for overlay video, clipping and video dma would clash */		if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {			DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",(char *)&fmt->pixelformat));		}		/* check if overlay is running */		if (IS_OVERLAY_ACTIVE(fh) != 0) {			if (vv->video_fh != fh) {				DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n"));				return -EBUSY;			}		}		down(&dev->lock);		/* ok, accept it */		vv->ov_fb = *fb;		vv->ov_fmt = fmt;		if (0 == vv->ov_fb.fmt.bytesperline)			vv->ov_fb.fmt.bytesperline =				vv->ov_fb.fmt.width*fmt->depth/8;		up(&dev->lock);		return 0;	}	case VIDIOC_ENUM_FMT:	{		struct v4l2_fmtdesc *f = arg;		int index;		switch (f->type) {		case V4L2_BUF_TYPE_VIDEO_CAPTURE:		case V4L2_BUF_TYPE_VIDEO_OVERLAY: {			index = f->index;			if (index < 0 || index >= NUM_FORMATS) {				return -EINVAL;			}			memset(f,0,sizeof(*f));			f->index = index;			strlcpy(f->description,formats[index].name,sizeof(f->description));			f->pixelformat = formats[index].pixelformat;			break;		}		default:			return -EINVAL;		}		DEB_EE(("VIDIOC_ENUM_FMT: type:%d, index:%d\n",f->type,f->index));		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) &&		    (c->id <  V4L2_CID_PRIVATE_BASE ||		     c->id >= V4L2_CID_PRIVATE_LASTP1))			return -EINVAL;		ctrl = ctrl_by_id(c->id);		if( NULL == ctrl ) {			return -EINVAL;/*			c->flags = V4L2_CTRL_FLAG_DISABLED;			return 0;*/		}		DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n",c->id));		*c = *ctrl;		return 0;	}	case VIDIOC_G_CTRL: {		DEB_EE(("VIDIOC_G_CTRL\n"));		return get_control(fh,arg);	}	case VIDIOC_S_CTRL:

⌨️ 快捷键说明

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