欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

sn9c102_core.c

优龙2410linux2.6.8内核源代码
C
第 1 页 / 共 4 页
字号:
	kfree(cam->control_buffer);}/*****************************************************************************/static int sn9c102_open(struct inode* inode, struct file* filp){	struct sn9c102_device* cam;	int err = 0;	/* This the only safe way to prevent race conditions with disconnect */	if (!down_read_trylock(&sn9c102_disconnect))		return -ERESTARTSYS;	cam = video_get_drvdata(video_devdata(filp));	if (down_interruptible(&cam->dev_sem)) {		up_read(&sn9c102_disconnect);		return -ERESTARTSYS;	}	if (cam->users) {		DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor)		if ((filp->f_flags & O_NONBLOCK) ||		    (filp->f_flags & O_NDELAY)) {			err = -EWOULDBLOCK;			goto out;		}		up(&cam->dev_sem);		err = wait_event_interruptible_exclusive(cam->open,		                                  cam->state & DEV_DISCONNECTED		                                         || !cam->users);		if (err) {			up_read(&sn9c102_disconnect);			return err;		}		if (cam->state & DEV_DISCONNECTED) {			up_read(&sn9c102_disconnect);			return -ENODEV;		}		down(&cam->dev_sem);	}	if (cam->state & DEV_MISCONFIGURED) {		err = sn9c102_init(cam);		if (err) {			DBG(1, "Initialization failed again. "			       "I will retry on next open().")			goto out;		}		cam->state &= ~DEV_MISCONFIGURED;	}	if ((err = sn9c102_start_transfer(cam)))		goto out;	filp->private_data = cam;	cam->users++;	cam->io = IO_NONE;	cam->stream = STREAM_OFF;	cam->nbuffers = 0;	cam->frame_count = 0;	sn9c102_empty_framequeues(cam);	DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor)out:	up(&cam->dev_sem);	up_read(&sn9c102_disconnect);	return err;}static int sn9c102_release(struct inode* inode, struct file* filp){	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));	down(&cam->dev_sem); /* prevent disconnect() to be called */	sn9c102_stop_transfer(cam);	sn9c102_release_buffers(cam);	if (cam->state & DEV_DISCONNECTED) {		sn9c102_release_resources(cam);		up(&cam->dev_sem);		kfree(cam);		return 0;	}	cam->users--;	wake_up_interruptible_nr(&cam->open, 1);	DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor)	up(&cam->dev_sem);	return 0;}static ssize_tsn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos){	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));	struct sn9c102_frame_t* f, * i;	unsigned long lock_flags;	int err = 0;	if (down_interruptible(&cam->fileop_sem))		return -ERESTARTSYS;	if (cam->state & DEV_DISCONNECTED) {		DBG(1, "Device not present")		up(&cam->fileop_sem);		return -ENODEV;	}	if (cam->state & DEV_MISCONFIGURED) {		DBG(1, "The camera is misconfigured. Close and open it again.")		up(&cam->fileop_sem);		return -EIO;	}	if (cam->io == IO_MMAP) {		DBG(3, "Close and open the device again to choose "		       "the read method")		up(&cam->fileop_sem);		return -EINVAL;	}	if (cam->io == IO_NONE) {		if (!sn9c102_request_buffers(cam, 2)) {			DBG(1, "read() failed, not enough memory")			up(&cam->fileop_sem);			return -ENOMEM;		}		cam->io = IO_READ;		cam->stream = STREAM_ON;		sn9c102_queue_unusedframes(cam);	}	if (!count) {		up(&cam->fileop_sem);		return 0;	}	if (list_empty(&cam->outqueue)) {		if (filp->f_flags & O_NONBLOCK) {			up(&cam->fileop_sem);			return -EAGAIN;		}		err = wait_event_interruptible		      ( cam->wait_frame, 		        (!list_empty(&cam->outqueue)) ||		        (cam->state & DEV_DISCONNECTED) );		if (err) {			up(&cam->fileop_sem);			return err;		}		if (cam->state & DEV_DISCONNECTED) {			up(&cam->fileop_sem);			return -ENODEV;		}	}	f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame);	spin_lock_irqsave(&cam->queue_lock, lock_flags);	list_for_each_entry(i, &cam->outqueue, frame)		i->state = F_UNUSED;	INIT_LIST_HEAD(&cam->outqueue);	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);	sn9c102_queue_unusedframes(cam);	if (count > f->buf.length)		count = f->buf.length;	if (copy_to_user(buf, f->bufmem, count)) {		up(&cam->fileop_sem);		return -EFAULT;	}	*f_pos += count;	PDBGG("Frame #%lu, bytes read: %zu", (unsigned long)f->buf.index,count)	up(&cam->fileop_sem);	return count;}static unsigned int sn9c102_poll(struct file *filp, poll_table *wait){	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));	unsigned int mask = 0;	if (down_interruptible(&cam->fileop_sem))		return POLLERR;	if (cam->state & DEV_DISCONNECTED) {		DBG(1, "Device not present")		goto error;	}	if (cam->state & DEV_MISCONFIGURED) {		DBG(1, "The camera is misconfigured. Close and open it again.")		goto error;	}	if (cam->io == IO_NONE) {		if (!sn9c102_request_buffers(cam, 2)) {			DBG(1, "poll() failed, not enough memory")			goto error;		}		cam->io = IO_READ;		cam->stream = STREAM_ON;	}	if (cam->io == IO_READ)		sn9c102_queue_unusedframes(cam);	poll_wait(filp, &cam->wait_frame, wait);	if (!list_empty(&cam->outqueue))		mask |= POLLIN | POLLRDNORM;	up(&cam->fileop_sem);	return mask;error:	up(&cam->fileop_sem);	return POLLERR;}static void sn9c102_vm_open(struct vm_area_struct* vma){	struct sn9c102_frame_t* f = vma->vm_private_data;	f->vma_use_count++;}static void sn9c102_vm_close(struct vm_area_struct* vma){	/* NOTE: buffers are not freed here */	struct sn9c102_frame_t* f = vma->vm_private_data;	f->vma_use_count--;}static struct vm_operations_struct sn9c102_vm_ops = {	.open = sn9c102_vm_open,	.close = sn9c102_vm_close,};static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma){	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));	unsigned long size = vma->vm_end - vma->vm_start,	              start = vma->vm_start,	              pos,	              page;	u32 i;	if (down_interruptible(&cam->fileop_sem))		return -ERESTARTSYS;	if (cam->state & DEV_DISCONNECTED) {		DBG(1, "Device not present")		up(&cam->fileop_sem);		return -ENODEV;	}	if (cam->state & DEV_MISCONFIGURED) {		DBG(1, "The camera is misconfigured. Close and open it again.")		up(&cam->fileop_sem);		return -EIO;	}	if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||	    size != PAGE_ALIGN(cam->frame[0].buf.length)) {		up(&cam->fileop_sem);		return -EINVAL;	}	for (i = 0; i < cam->nbuffers; i++) {		if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)			break;	}	if (i == cam->nbuffers) {		up(&cam->fileop_sem);		return -EINVAL;	}	pos = (unsigned long)cam->frame[i].bufmem;	while (size > 0) { /* size is page-aligned */		page = kvirt_to_pa(pos);		if (remap_page_range(vma, start, page, PAGE_SIZE, 		                     vma->vm_page_prot)) {			up(&cam->fileop_sem);			return -EAGAIN;		}		start += PAGE_SIZE;		pos += PAGE_SIZE;		size -= PAGE_SIZE;	}	vma->vm_ops = &sn9c102_vm_ops;	vma->vm_flags &= ~VM_IO; /* not I/O memory */	vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */	vma->vm_private_data = &cam->frame[i];	sn9c102_vm_open(vma);	up(&cam->fileop_sem);	return 0;}static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,                              unsigned int cmd, void __user * arg){	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));	switch (cmd) {	case VIDIOC_QUERYCAP:	{		struct v4l2_capability cap = {			.driver = "sn9c102",			.version = SN9C102_MODULE_VERSION_CODE,			.capabilities = V4L2_CAP_VIDEO_CAPTURE | 			                V4L2_CAP_READWRITE |		 	                V4L2_CAP_STREAMING,		};		strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));		strlcpy(cap.bus_info, cam->dev.bus_id, sizeof(cap.bus_info));		if (copy_to_user(arg, &cap, sizeof(cap)))			return -EFAULT;		return 0;	}	case VIDIOC_ENUMINPUT:	{		struct v4l2_input i;		if (copy_from_user(&i, arg, sizeof(i)))			return -EFAULT;		if (i.index)			return -EINVAL;		memset(&i, 0, sizeof(i));		strcpy(i.name, "USB");		if (copy_to_user(arg, &i, sizeof(i)))			return -EFAULT;		return 0;	}	case VIDIOC_G_INPUT:	case VIDIOC_S_INPUT:	{		int index;		if (copy_from_user(&index, arg, sizeof(index)))			return -EFAULT;		if (index != 0)			return -EINVAL;		return 0;	}	case VIDIOC_QUERYCTRL:	{		struct sn9c102_sensor* s = cam->sensor;		struct v4l2_queryctrl qc;		u8 i, n;		if (copy_from_user(&qc, arg, sizeof(qc)))			return -EFAULT;		n = sizeof(s->qctrl) / sizeof(s->qctrl[0]);		for (i = 0; i < n; i++)			if (qc.id && qc.id == s->qctrl[i].id) {				memcpy(&qc, &(s->qctrl[i]), sizeof(qc));				if (copy_to_user(arg, &qc, sizeof(qc)))					return -EFAULT;				return 0;			}		return -EINVAL;	}	case VIDIOC_G_CTRL:	{		struct sn9c102_sensor* s = cam->sensor;		struct v4l2_control ctrl;		int err = 0;		if (!s->get_ctrl)			return -EINVAL;		if (copy_from_user(&ctrl, arg, sizeof(ctrl)))			return -EFAULT;		err = s->get_ctrl(cam, &ctrl);		if (copy_to_user(arg, &ctrl, sizeof(ctrl)))			return -EFAULT;		return err;	}	case VIDIOC_S_CTRL:	{		struct sn9c102_sensor* s = cam->sensor;		struct v4l2_control ctrl;		u8 i, n;		int err = 0;		if (!s->set_ctrl)			return -EINVAL;		if (copy_from_user(&ctrl, arg, sizeof(ctrl)))			return -EFAULT;		if ((err = s->set_ctrl(cam, &ctrl)))			return err;		n = sizeof(s->qctrl) / sizeof(s->qctrl[0]);		for (i = 0; i < n; i++)			if (ctrl.id == s->qctrl[i].id) {				s->_qctrl[i].default_value = ctrl.value;				break;			}		return 0;	}	case VIDIOC_CROPCAP:	{		struct v4l2_cropcap* cc = &(cam->sensor->cropcap);		cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;		cc->pixelaspect.numerator = 1;		cc->pixelaspect.denominator = 1;		if (copy_to_user(arg, cc, sizeof(*cc)))			return -EFAULT;		return 0;	}	case VIDIOC_G_CROP:	{		struct sn9c102_sensor* s = cam->sensor;		struct v4l2_crop crop = {			.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,		};		memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));		if (copy_to_user(arg, &crop, sizeof(crop)))			return -EFAULT;		return 0;	}	case VIDIOC_S_CROP:	{		struct sn9c102_sensor* s = cam->sensor;		struct v4l2_crop crop;		struct v4l2_rect* rect;		struct v4l2_rect* bounds = &(s->cropcap.bounds);		struct v4l2_pix_format* pix_format = &(s->pix_format);		u8 scale;		const enum sn9c102_stream_state stream = cam->stream;		const u32 nbuffers = cam->nbuffers;		u32 i;		int err = 0;		if (copy_from_user(&crop, arg, sizeof(crop)))			return -EFAULT;		rect = &(crop.c);		if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)			return -EINVAL;		for (i = 0; i < cam->nbuffers; i++)			if (cam->frame[i].vma_use_count) {				DBG(3, "VIDIOC_S_CROP failed. "				       "Unmap the buffers first.")				return -EINVAL;			}		if (rect->width < 16)			rect->width = 16;		if (rect->height < 16)			rect->height = 16;		if (rect->width > bounds->width)			rect->width = bounds->width;		if (rect->height > bounds->height)			rect->height = bounds->height;		if (rect->left < bounds->left)			rect->left = bounds->left;		if (rect->top < bounds->top)			rect->top = bounds->top;		if (rect->left + rect->width > bounds->left + bounds->width)			rect->left = bounds->left+bounds->width - rect->width;		if (rect->top + rect->height > bounds->top + bounds->height)			rect->top = bounds->top+bounds->height - rect->height;		rect->width &= ~15L;		rect->height &= ~15L;		{ /* calculate the scaling factor */			u32 a, b;			a = rect->width * rect->height;			b = pix_format->width * pix_format->height;			scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 :			            ((a / b) > 4 ? 4 : (a / b)))) : 1;		}		if (cam->stream == STREAM_ON) {			cam->stream = STREAM_INTERRUPT;			err = wait_event_interruptible			      ( cam->wait_stream, 			        (cam->stream == STREAM_OFF) ||			        (cam->state & DEV_DISCONNECTED) );			if (err) {				cam->state |= DEV_MISCONFIGURED;				DBG(1, "The camera is misconfigured. To use "				       "it, close and open /dev/video%d "				       "again.", cam->v4ldev->minor)				return err;			}			if (cam->state & DEV_DISCONNECTED)				return -ENODEV;		}		if (copy_to_user(arg, &crop, sizeof(crop))) {			cam->stream = stream;			return -EFAULT;		}		sn9c102_release_buffers(cam);		err = sn9c102_set_crop(cam, rect);		if (s->set_crop)			err += s->set_crop(cam, rect);		err += sn9c102_set_scale(cam, scale);		if (err) { /* atomic, no rollback in ioctl() */			cam->state |= DEV_MISCONFIGURED;			DBG(1, "VIDIOC_S_CROP failed because of hardware "			       "problems. To use the camera, close and open "			       "/dev/video%d again.", cam->v4ldev->minor)			return err;		}		s->pix_format.width = rect->width/scale;		s->pix_format.height = rect->height/scale;		memcpy(&(s->_rect), rect, sizeof(*rect));		if (nbuffers != sn9c102_request_buffers(cam, nbuffers)) {			cam->state |= DEV_MISCONFIGURED;			DBG(1, "VIDIOC_S_CROP failed because of not enough "			       "memory. To use the camera, close and open "			       "/dev/video%d again.", cam->v4ldev->minor)			return -ENOMEM;		}		cam->stream = stream;		return 0;	}	case VIDIOC_ENUM_FMT:	{		struct sn9c102_sensor* s = cam->sensor;		struct v4l2_fmtdesc fmtd;		if (copy_from_user(&fmtd, arg, sizeof(fmtd)))			return -EFAULT;		if (fmtd.index != 0)			return -EINVAL;		memset(&fmtd, 0, sizeof(fmtd));		fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;		strcpy(fmtd.description, "bayer rgb");		fmtd.pixelformat = s->pix_format.pixelformat;		if (copy_to_user(arg, &fmtd, sizeof(fmtd)))			return -EFAULT;

⌨️ 快捷键说明

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