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

📄 em28xx-video.c

📁 linux2.6.16版本
💻 C
📖 第 1 页 / 共 4 页
字号:
	}	if (list_empty(&dev->outqueue)) {		if (filp->f_flags & O_NONBLOCK) {			up(&dev->fileop_lock);			return -EAGAIN;		}		ret = wait_event_interruptible		    (dev->wait_frame,		     (!list_empty(&dev->outqueue)) ||		     (dev->state & DEV_DISCONNECTED));		if (ret) {			up(&dev->fileop_lock);			return ret;		}		if (dev->state & DEV_DISCONNECTED) {			up(&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)) {		up(&dev->fileop_lock);		return -EFAULT;	}	*f_pos += count;	up(&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 (down_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;			up(&dev->fileop_lock);			return mask;		}	}	up(&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 (down_interruptible(&dev->fileop_lock))		return -ERESTARTSYS;	if (dev->state & DEV_DISCONNECTED) {		em28xx_videodbg("mmap: device not present\n");		up(&dev->fileop_lock);		return -ENODEV;	}	if (dev->state & DEV_MISCONFIGURED) {		em28xx_videodbg ("mmap: Device is misconfigured; close and "						"open it again\n");		up(&dev->fileop_lock);		return -EIO;	}	if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||	    size != PAGE_ALIGN(dev->frame[0].buf.length)) {		up(&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");		up(&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");			up(&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);	up(&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;	}}/*FIXME: should be moved to saa711x */static int saa711x_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl){	s32 tmp;	switch (ctrl->id) {	case V4L2_CID_BRIGHTNESS:		if ((tmp = em28xx_brightness_get(dev)) < 0)			return -EIO;		ctrl->value = (s32) ((s8) tmp);	/* FIXME: clenaer way to extend sign? */		return 0;	case V4L2_CID_CONTRAST:		if ((ctrl->value = em28xx_contrast_get(dev)) < 0)			return -EIO;		return 0;	case V4L2_CID_SATURATION:		if ((ctrl->value = em28xx_saturation_get(dev)) < 0)			return -EIO;		return 0;	case V4L2_CID_RED_BALANCE:		if ((tmp = em28xx_v_balance_get(dev)) < 0)			return -EIO;		ctrl->value = (s32) ((s8) tmp);	/* FIXME: clenaer way to extend sign? */		return 0;	case V4L2_CID_BLUE_BALANCE:		if ((tmp = em28xx_u_balance_get(dev)) < 0)			return -EIO;		ctrl->value = (s32) ((s8) tmp);	/* FIXME: clenaer way to extend sign? */		return 0;	case V4L2_CID_GAMMA:		if ((ctrl->value = em28xx_gamma_get(dev)) < 0)			return -EIO;		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;	}}/*FIXME: should be moved to saa711x */static int saa711x_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl){	switch (ctrl->id) {	case V4L2_CID_BRIGHTNESS:		return em28xx_brightness_set(dev, ctrl->value);	case V4L2_CID_CONTRAST:		return em28xx_contrast_set(dev, ctrl->value);	case V4L2_CID_SATURATION:		return em28xx_saturation_set(dev, ctrl->value);	case V4L2_CID_RED_BALANCE:		return em28xx_v_balance_set(dev, ctrl->value);	case V4L2_CID_BLUE_BALANCE:		return em28xx_u_balance_set(dev, ctrl->value);	case V4L2_CID_GAMMA:		return em28xx_gamma_set(dev, ctrl->value);	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);		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;}/* * 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:		{			struct v4l2_standard *e = arg;			unsigned int i;			i = e->index;			if (i >= TVNORMS)				return -EINVAL;			ret = v4l2_video_std_construct(e, tvnorms[e->index].id,						       tvnorms[e->index].name);			e->index = i;			if (ret < 0)				return ret;			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);			dev->tvnorm = &tvnorms[i];			em28xx_set_norm(dev, dev->width, dev->height);/*		dev->width=norm_maxw(dev);		dev->height=norm_maxh(dev);		dev->frame_size=dev->width*dev->height*2;		dev->field_size=dev->frame_size>>1;		dev->bytesperline=dev->width*2;		dev->hscale=0;		dev->vscale=0;		em28xx_resolution_set(dev);*//*		em28xx_uninit_isoc(dev);		em28xx_set_alternate(dev);		em28xx_capture_start(dev, 1);		em28xx_resolution_set(dev);		em28xx_init_isoc(dev);*/			em28xx_i2c_call_clients(dev, DECODER_SET_NORM,						&tvnorms[i].mode);			em28xx_i2c_call_clients(dev, VIDIOC_S_STD,						&dev->tvnorm->id);			up(&dev->lock);			return 0;		}		/* ------ input switching ---------- */	case VIDIOC_ENUMINPUT:		{			struct v4l2_input *i = arg;			unsigned int n;			static const char *iname[] = {				[EM28XX_VMUX_COMPOSITE1] = "Composite1",				[EM28XX_VMUX_COMPOSITE2] = "Composite2",				[EM28XX_VMUX_COMPOSITE3] = "Composite3",				[EM28XX_VMUX_COMPOSITE4] = "Composite4",				[EM28XX_VMUX_SVIDEO] = "S-Video",				[EM28XX_VMUX_TELEVISION] = "Television",				[EM28XX_VMUX_CABLE] = "Cable TV",				[EM28XX_VMUX_DVB] = "DVB",				[EM28XX_VMUX_DEBUG] = "for debug only",			};			n = i->index;			if (n >= MAX_EM28XX_INPUT)				return -EINVAL;			if (0 == INPUT(n)->type)				return -EINVAL;			memset(i, 0, sizeof(*i));			i->index = n;			i->type = V4L2_INPUT_TYPE_CAMERA;			strcpy(i->name, iname[INPUT(n)->type]);			if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||			    (EM28XX_VMUX_CABLE == INPUT(n)->type))				i->type = V4L2_INPUT_TYPE_TUNER;			for (n = 0; n < ARRAY_SIZE(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 *index = arg;			if (*index >= MAX_EM28XX_INPUT)				return -EINVAL;			if (0 == INPUT(*index)->type)				return -EINVAL;			down(&dev->lock);			video_mux(dev, *index);			up(&dev->lock);			return 0;		}	case VIDIOC_G_AUDIO:		{			struct v4l2_audio *a = arg;			unsigned int index = a->index;			if (a->index > 1)				return -EINVAL;			memset(a, 0, sizeof(*a));			index = dev->ctl_ainput;			if (index == 0) {

⌨️ 快捷键说明

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