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

📄 em28xx-video.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		     (dev->state & DEV_DISCONNECTED));		if (ret) {			mutex_unlock(&dev->fileop_lock);			return ret;		}		if (dev->state & DEV_DISCONNECTED) {			mutex_unlock(&dev->fileop_lock);			return -ENODEV;		}	}	f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);	spin_lock_irqsave(&dev->queue_lock, lock_flags);	list_for_each_entry(i, &dev->outqueue, frame)	    i->state = F_UNUSED;	INIT_LIST_HEAD(&dev->outqueue);	spin_unlock_irqrestore(&dev->queue_lock, lock_flags);	em28xx_queue_unusedframes(dev);	if (count > f->buf.length)		count = f->buf.length;	if (copy_to_user(buf, f->bufmem, count)) {		mutex_unlock(&dev->fileop_lock);		return -EFAULT;	}	*f_pos += count;	mutex_unlock(&dev->fileop_lock);	return count;}/* * em28xx_v4l2_poll() * will allocate buffers when called for the first time */static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait){	unsigned int mask = 0;	struct em28xx *dev = filp->private_data;	if (mutex_lock_interruptible(&dev->fileop_lock))		return POLLERR;	if (dev->state & DEV_DISCONNECTED) {		em28xx_videodbg("device not present\n");	} else if (dev->state & DEV_MISCONFIGURED) {		em28xx_videodbg("device is misconfigured; close and open it again\n");	} else {		if (dev->io == IO_NONE) {			if (!em28xx_request_buffers			    (dev, EM28XX_NUM_READ_FRAMES)) {				em28xx_warn				    ("poll() failed, not enough memory\n");			} else {				dev->io = IO_READ;				dev->stream = STREAM_ON;			}		}		if (dev->io == IO_READ) {			em28xx_queue_unusedframes(dev);			poll_wait(filp, &dev->wait_frame, wait);			if (!list_empty(&dev->outqueue))				mask |= POLLIN | POLLRDNORM;			mutex_unlock(&dev->fileop_lock);			return mask;		}	}	mutex_unlock(&dev->fileop_lock);	return POLLERR;}/* * em28xx_vm_open() */static void em28xx_vm_open(struct vm_area_struct *vma){	struct em28xx_frame_t *f = vma->vm_private_data;	f->vma_use_count++;}/* * em28xx_vm_close() */static void em28xx_vm_close(struct vm_area_struct *vma){	/* NOTE: buffers are not freed here */	struct em28xx_frame_t *f = vma->vm_private_data;	f->vma_use_count--;}static struct vm_operations_struct em28xx_vm_ops = {	.open = em28xx_vm_open,	.close = em28xx_vm_close,};/* * em28xx_v4l2_mmap() */static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma){	unsigned long size = vma->vm_end - vma->vm_start,	    start = vma->vm_start;	void *pos;	u32 i;	struct em28xx *dev = filp->private_data;	if (mutex_lock_interruptible(&dev->fileop_lock))		return -ERESTARTSYS;	if (dev->state & DEV_DISCONNECTED) {		em28xx_videodbg("mmap: device not present\n");		mutex_unlock(&dev->fileop_lock);		return -ENODEV;	}	if (dev->state & DEV_MISCONFIGURED) {		em28xx_videodbg ("mmap: Device is misconfigured; close and "						"open it again\n");		mutex_unlock(&dev->fileop_lock);		return -EIO;	}	if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||	    size != PAGE_ALIGN(dev->frame[0].buf.length)) {		mutex_unlock(&dev->fileop_lock);		return -EINVAL;	}	for (i = 0; i < dev->num_frames; i++) {		if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)			break;	}	if (i == dev->num_frames) {		em28xx_videodbg("mmap: user supplied mapping address is out of range\n");		mutex_unlock(&dev->fileop_lock);		return -EINVAL;	}	/* VM_IO is eventually going to replace PageReserved altogether */	vma->vm_flags |= VM_IO;	vma->vm_flags |= VM_RESERVED;	/* avoid to swap out this VMA */	pos = dev->frame[i].bufmem;	while (size > 0) {	/* size is page-aligned */		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {			em28xx_videodbg("mmap: vm_insert_page failed\n");			mutex_unlock(&dev->fileop_lock);			return -EAGAIN;		}		start += PAGE_SIZE;		pos += PAGE_SIZE;		size -= PAGE_SIZE;	}	vma->vm_ops = &em28xx_vm_ops;	vma->vm_private_data = &dev->frame[i];	em28xx_vm_open(vma);	mutex_unlock(&dev->fileop_lock);	return 0;}/* * em28xx_get_ctrl() * return the current saturation, brightness or contrast, mute state */static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl){	switch (ctrl->id) {	case V4L2_CID_AUDIO_MUTE:		ctrl->value = dev->mute;		return 0;	case V4L2_CID_AUDIO_VOLUME:		ctrl->value = dev->volume;		return 0;	default:		return -EINVAL;	}}/* * em28xx_set_ctrl() * mute or set new saturation, brightness or contrast */static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl){	switch (ctrl->id) {	case V4L2_CID_AUDIO_MUTE:		if (ctrl->value != dev->mute) {			dev->mute = ctrl->value;			em28xx_audio_usb_mute(dev, ctrl->value);			return em28xx_audio_analog_set(dev);		}		return 0;	case V4L2_CID_AUDIO_VOLUME:		dev->volume = ctrl->value;		return em28xx_audio_analog_set(dev);	default:		return -EINVAL;	}}/* * em28xx_stream_interrupt() * stops streaming */static int em28xx_stream_interrupt(struct em28xx *dev){	int ret = 0;	/* stop reading from the device */	dev->stream = STREAM_INTERRUPT;	ret = wait_event_timeout(dev->wait_stream,				 (dev->stream == STREAM_OFF) ||				 (dev->state & DEV_DISCONNECTED),				 EM28XX_URB_TIMEOUT);	if (dev->state & DEV_DISCONNECTED)		return -ENODEV;	else if (ret) {		dev->state |= DEV_MISCONFIGURED;		em28xx_videodbg("device is misconfigured; close and "			"open /dev/video%d again\n",				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);		return ret;	}	return 0;}static int em28xx_set_norm(struct em28xx *dev, int width, int height){	unsigned int hscale, vscale;	unsigned int maxh, maxw;	maxw = norm_maxw(dev);	maxh = norm_maxh(dev);	/* width must even because of the YUYV format */	/* height must be even because of interlacing */	height &= 0xfffe;	width &= 0xfffe;	if (height < 32)		height = 32;	if (height > maxh)		height = maxh;	if (width < 48)		width = 48;	if (width > maxw)		width = maxw;	if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)		hscale = 0x3fff;	width = (((unsigned long)maxw) << 12) / (hscale + 4096L);	if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)		vscale = 0x3fff;	height = (((unsigned long)maxh) << 12) / (vscale + 4096L);	/* set new image size */	dev->width = width;	dev->height = height;	dev->frame_size = dev->width * dev->height * 2;	dev->field_size = dev->frame_size >> 1;	/*both_fileds ? dev->frame_size>>1 : dev->frame_size; */	dev->bytesperline = dev->width * 2;	dev->hscale = hscale;	dev->vscale = vscale;	em28xx_resolution_set(dev);	return 0;}static int em28xx_get_fmt(struct em28xx *dev, struct v4l2_format *format){	em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",		(format->type ==V4L2_BUF_TYPE_VIDEO_CAPTURE) ?		"V4L2_BUF_TYPE_VIDEO_CAPTURE" :		(format->type ==V4L2_BUF_TYPE_VBI_CAPTURE) ?		"V4L2_BUF_TYPE_VBI_CAPTURE" :		(format->type ==V4L2_CAP_SLICED_VBI_CAPTURE) ?		"V4L2_BUF_TYPE_SLICED_VBI_CAPTURE " :		"not supported");	switch (format->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:	{		format->fmt.pix.width = dev->width;		format->fmt.pix.height = dev->height;		format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;		format->fmt.pix.bytesperline = dev->bytesperline;		format->fmt.pix.sizeimage = dev->frame_size;		format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;		format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;	/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */		em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,			dev->height);		break;	}	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:	{		format->fmt.sliced.service_set=0;		em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);		if (format->fmt.sliced.service_set==0)			return -EINVAL;		break;	}	default:		return -EINVAL;	}	return (0);}static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_format *format){	u32 i;	int ret = 0;	int width = format->fmt.pix.width;	int height = format->fmt.pix.height;	unsigned int hscale, vscale;	unsigned int maxh, maxw;	maxw = norm_maxw(dev);	maxh = norm_maxh(dev);	em28xx_videodbg("%s: type=%s\n",			cmd == VIDIOC_TRY_FMT ?			"VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",			format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?			"V4L2_BUF_TYPE_VIDEO_CAPTURE" :			format->type == V4L2_BUF_TYPE_VBI_CAPTURE ?			"V4L2_BUF_TYPE_VBI_CAPTURE " :			"not supported");	if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {		em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);		if (format->fmt.sliced.service_set==0)			return -EINVAL;		return 0;	}	if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	em28xx_videodbg("%s: requested %dx%d\n",		cmd == VIDIOC_TRY_FMT ?		"VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",		format->fmt.pix.width, format->fmt.pix.height);	/* FIXME: Move some code away from here */	/* width must even because of the YUYV format */	/* height must be even because of interlacing */	height &= 0xfffe;	width &= 0xfffe;	if (height < 32)		height = 32;	if (height > maxh)		height = maxh;	if (width < 48)		width = 48;	if (width > maxw)		width = maxw;	if(dev->is_em2800){		/* the em2800 can only scale down to 50% */		if(height % (maxh / 2))			height=maxh;		if(width % (maxw / 2))			width=maxw;		/* according to empiatech support */		/* the MaxPacketSize is to small to support */		/* framesizes larger than 640x480 @ 30 fps */		/* or 640x576 @ 25 fps. As this would cut */		/* of a part of the image we prefer */		/* 360x576 or 360x480 for now */		if(width == maxw && height == maxh)			width /= 2;	}	if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)		hscale = 0x3fff;	width = (((unsigned long)maxw) << 12) / (hscale + 4096L);	if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)		vscale = 0x3fff;	height = (((unsigned long)maxh) << 12) / (vscale + 4096L);	format->fmt.pix.width = width;	format->fmt.pix.height = height;	format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;	format->fmt.pix.bytesperline = width * 2;	format->fmt.pix.sizeimage = width * 2 * height;	format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;	format->fmt.pix.field = V4L2_FIELD_INTERLACED;	em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",		cmd == VIDIOC_TRY_FMT ?		"VIDIOC_TRY_FMT" :"VIDIOC_S_FMT",		format->fmt.pix.width, format->fmt.pix.height, hscale, vscale);	if (cmd == VIDIOC_TRY_FMT)		return 0;	for (i = 0; i < dev->num_frames; i++)		if (dev->frame[i].vma_use_count) {			em28xx_videodbg("VIDIOC_S_FMT failed. "				"Unmap the buffers first.\n");			return -EINVAL;		}	/* stop io in case it is already in progress */	if (dev->stream == STREAM_ON) {		em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n");		if ((ret = em28xx_stream_interrupt(dev)))			return ret;	}	em28xx_release_buffers(dev);	dev->io = IO_NONE;	/* set new image size */	dev->width = width;	dev->height = height;	dev->frame_size = dev->width * dev->height * 2;	dev->field_size = dev->frame_size >> 1;	dev->bytesperline = dev->width * 2;	dev->hscale = hscale;	dev->vscale = vscale;	em28xx_uninit_isoc(dev);	em28xx_set_alternate(dev);	em28xx_capture_start(dev, 1);	em28xx_resolution_set(dev);	em28xx_init_isoc(dev);	return 0;}/* * em28xx_v4l2_do_ioctl() * This function is _not_ called directly, but from * em28xx_v4l2_ioctl. Userspace * copying is done already, arg is a kernel pointer. */static int em28xx_do_ioctl(struct inode *inode, struct file *filp,			   struct em28xx *dev, unsigned int cmd, void *arg,			   v4l2_kioctl driver_ioctl){	int ret;	switch (cmd) {		/* ---------- tv norms ---------- */	case VIDIOC_ENUMSTD:	{

⌨️ 快捷键说明

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