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

📄 gspca.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
{	struct gspca_dev *gspca_dev = priv;	const struct ctrl *ctrls;	int i, ret;	for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;	     i < gspca_dev->sd_desc->nctrls;	     i++, ctrls++) {		if (ctrl->id != ctrls->qctrl.id)			continue;		if (gspca_dev->ctrl_dis & (1 << i))			return -EINVAL;		if (mutex_lock_interruptible(&gspca_dev->usb_lock))			return -ERESTARTSYS;		ret = ctrls->get(gspca_dev, &ctrl->value);		mutex_unlock(&gspca_dev->usb_lock);		return ret;	}	return -EINVAL;}static int vidioc_querymenu(struct file *file, void *priv,			    struct v4l2_querymenu *qmenu){	struct gspca_dev *gspca_dev = priv;	if (!gspca_dev->sd_desc->querymenu)		return -EINVAL;	return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu);}static int vidioc_enum_input(struct file *file, void *priv,				struct v4l2_input *input){	struct gspca_dev *gspca_dev = priv;	if (input->index != 0)		return -EINVAL;	memset(input, 0, sizeof *input);	input->type = V4L2_INPUT_TYPE_CAMERA;	strncpy(input->name, gspca_dev->sd_desc->name,		sizeof input->name);	return 0;}static int vidioc_g_input(struct file *file, void *priv, unsigned int *i){	*i = 0;	return 0;}static int vidioc_s_input(struct file *file, void *priv, unsigned int i){	if (i > 0)		return -EINVAL;	return (0);}static int vidioc_reqbufs(struct file *file, void *priv,			  struct v4l2_requestbuffers *rb){	struct gspca_dev *gspca_dev = priv;	int i, ret = 0;	if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	switch (rb->memory) {	case GSPCA_MEMORY_READ:			/* (internal call) */	case V4L2_MEMORY_MMAP:	case V4L2_MEMORY_USERPTR:		break;	default:		return -EINVAL;	}	if (mutex_lock_interruptible(&gspca_dev->queue_lock))		return -ERESTARTSYS;	if (gspca_dev->memory != GSPCA_MEMORY_NO	    && gspca_dev->memory != rb->memory) {		ret = -EBUSY;		goto out;	}	/* only one file may do the capture */	if (gspca_dev->capt_file != NULL	    && gspca_dev->capt_file != file) {		ret = -EBUSY;		goto out;	}	/* if allocated, the buffers must not be mapped */	for (i = 0; i < gspca_dev->nframes; i++) {		if (gspca_dev->frame[i].vma_use_count) {			ret = -EBUSY;			goto out;		}	}	/* stop streaming */	if (gspca_dev->streaming) {		mutex_lock(&gspca_dev->usb_lock);		gspca_stream_off(gspca_dev);		mutex_unlock(&gspca_dev->usb_lock);	}	/* free the previous allocated buffers, if any */	if (gspca_dev->nframes != 0) {		frame_free(gspca_dev);		gspca_dev->capt_file = NULL;	}	if (rb->count == 0)			/* unrequest */		goto out;	gspca_dev->memory = rb->memory;	ret = frame_alloc(gspca_dev, rb->count);	if (ret == 0) {		rb->count = gspca_dev->nframes;		gspca_dev->capt_file = file;	}out:	mutex_unlock(&gspca_dev->queue_lock);	PDEBUG(D_STREAM, "reqbufs st:%d c:%d", ret, rb->count);	return ret;}static int vidioc_querybuf(struct file *file, void *priv,			   struct v4l2_buffer *v4l2_buf){	struct gspca_dev *gspca_dev = priv;	struct gspca_frame *frame;	if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE	    || v4l2_buf->index < 0	    || v4l2_buf->index >= gspca_dev->nframes)		return -EINVAL;	frame = &gspca_dev->frame[v4l2_buf->index];	memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);	return 0;}static int vidioc_streamon(struct file *file, void *priv,			   enum v4l2_buf_type buf_type){	struct gspca_dev *gspca_dev = priv;	int ret;	if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	if (mutex_lock_interruptible(&gspca_dev->queue_lock))		return -ERESTARTSYS;	if (!gspca_dev->present) {		ret = -ENODEV;		goto out;	}	if (gspca_dev->nframes == 0) {		ret = -EINVAL;		goto out;	}	if (!gspca_dev->streaming) {		ret = gspca_init_transfer(gspca_dev);		if (ret < 0)			goto out;	}#ifdef GSPCA_DEBUG	if (gspca_debug & D_STREAM) {		PDEBUG_MODE("stream on OK",			gspca_dev->pixfmt,			gspca_dev->width,			gspca_dev->height);	}#endif	ret = 0;out:	mutex_unlock(&gspca_dev->queue_lock);	return ret;}static int vidioc_streamoff(struct file *file, void *priv,				enum v4l2_buf_type buf_type){	struct gspca_dev *gspca_dev = priv;	int i, ret;	if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	if (!gspca_dev->streaming)		return 0;	if (mutex_lock_interruptible(&gspca_dev->queue_lock))		return -ERESTARTSYS;	/* stop streaming */	if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {		ret = -ERESTARTSYS;		goto out;	}	gspca_stream_off(gspca_dev);	mutex_unlock(&gspca_dev->usb_lock);	/* empty the application queues */	for (i = 0; i < gspca_dev->nframes; i++)		gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS;	gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;	gspca_dev->last_packet_type = DISCARD_PACKET;	gspca_dev->sequence = 0;	atomic_set(&gspca_dev->nevent, 0);	ret = 0;out:	mutex_unlock(&gspca_dev->queue_lock);	return ret;}static int vidioc_g_jpegcomp(struct file *file, void *priv,			struct v4l2_jpegcompression *jpegcomp){	struct gspca_dev *gspca_dev = priv;	int ret;	if (!gspca_dev->sd_desc->get_jcomp)		return -EINVAL;	if (mutex_lock_interruptible(&gspca_dev->usb_lock))		return -ERESTARTSYS;	ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);	mutex_unlock(&gspca_dev->usb_lock);	return ret;}static int vidioc_s_jpegcomp(struct file *file, void *priv,			struct v4l2_jpegcompression *jpegcomp){	struct gspca_dev *gspca_dev = priv;	int ret;	if (mutex_lock_interruptible(&gspca_dev->usb_lock))		return -ERESTARTSYS;	if (!gspca_dev->sd_desc->set_jcomp)		return -EINVAL;	ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);	mutex_unlock(&gspca_dev->usb_lock);	return ret;}static int vidioc_g_parm(struct file *filp, void *priv,			struct v4l2_streamparm *parm){	struct gspca_dev *gspca_dev = priv;	memset(parm, 0, sizeof *parm);	parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;	parm->parm.capture.readbuffers = gspca_dev->nbufread;	return 0;}static int vidioc_s_parm(struct file *filp, void *priv,			struct v4l2_streamparm *parm){	struct gspca_dev *gspca_dev = priv;	int n;	n = parm->parm.capture.readbuffers;	if (n == 0 || n > GSPCA_MAX_FRAMES)		parm->parm.capture.readbuffers = gspca_dev->nbufread;	else		gspca_dev->nbufread = n;	return 0;}static int vidioc_s_std(struct file *filp, void *priv,			v4l2_std_id *parm){	return 0;}#ifdef CONFIG_VIDEO_V4L1_COMPATstatic int vidiocgmbuf(struct file *file, void *priv,			struct video_mbuf *mbuf){	struct gspca_dev *gspca_dev = file->private_data;	int i;	PDEBUG(D_STREAM, "cgmbuf");	if (gspca_dev->nframes == 0) {		int ret;		{			struct v4l2_format fmt;			memset(&fmt, 0, sizeof fmt);			fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;			i = gspca_dev->cam.nmodes - 1;	/* highest mode */			fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;			fmt.fmt.pix.height = gspca_dev->cam.cam_mode[i].height;			fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;			ret = vidioc_s_fmt_vid_cap(file, priv, &fmt);			if (ret != 0)				return ret;		}		{			struct v4l2_requestbuffers rb;			memset(&rb, 0, sizeof rb);			rb.count = 4;			rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;			rb.memory = V4L2_MEMORY_MMAP;			ret = vidioc_reqbufs(file, priv, &rb);			if (ret != 0)				return ret;		}	}	mbuf->frames = gspca_dev->nframes;	mbuf->size = gspca_dev->frsz * gspca_dev->nframes;	for (i = 0; i < mbuf->frames; i++)		mbuf->offsets[i] = gspca_dev->frame[i].v4l2_buf.m.offset;	return 0;}#endifstatic int dev_mmap(struct file *file, struct vm_area_struct *vma){	struct gspca_dev *gspca_dev = file->private_data;	struct gspca_frame *frame;	struct page *page;	unsigned long addr, start, size;	int i, ret;	start = vma->vm_start;	size = vma->vm_end - vma->vm_start;	PDEBUG(D_STREAM, "mmap start:%08x size:%d", (int) start, (int) size);	if (mutex_lock_interruptible(&gspca_dev->queue_lock))		return -ERESTARTSYS;	if (!gspca_dev->present) {		ret = -ENODEV;		goto out;	}	if (gspca_dev->capt_file != file) {		ret = -EINVAL;		goto out;	}	frame = NULL;	for (i = 0; i < gspca_dev->nframes; ++i) {		if (gspca_dev->frame[i].v4l2_buf.memory != V4L2_MEMORY_MMAP) {			PDEBUG(D_STREAM, "mmap bad memory type");			break;		}		if ((gspca_dev->frame[i].v4l2_buf.m.offset >> PAGE_SHIFT)						== vma->vm_pgoff) {			frame = &gspca_dev->frame[i];			break;		}	}	if (frame == NULL) {		PDEBUG(D_STREAM, "mmap no frame buffer found");		ret = -EINVAL;		goto out;	}#ifdef CONFIG_VIDEO_V4L1_COMPAT	/* v4l1 maps all the buffers */	if (i != 0	    || size != frame->v4l2_buf.length * gspca_dev->nframes)#endif	    if (size != frame->v4l2_buf.length) {		PDEBUG(D_STREAM, "mmap bad size");		ret = -EINVAL;		goto out;	}	/*	 * - VM_IO marks the area as being a mmaped region for I/O to a	 *   device. It also prevents the region from being core dumped.	 */	vma->vm_flags |= VM_IO;	addr = (unsigned long) frame->data;	while (size > 0) {		page = vmalloc_to_page((void *) addr);		ret = vm_insert_page(vma, start, page);		if (ret < 0)			goto out;		start += PAGE_SIZE;		addr += PAGE_SIZE;		size -= PAGE_SIZE;	}	vma->vm_ops = &gspca_vm_ops;	vma->vm_private_data = frame;	gspca_vm_open(vma);	ret = 0;out:	mutex_unlock(&gspca_dev->queue_lock);	return ret;}/* * wait for a video frame * * If a frame is ready, its index is returned. */static int frame_wait(struct gspca_dev *gspca_dev,			int nonblock_ing){	struct gspca_frame *frame;	int i, j, ret;	/* check if a frame is ready */	i = gspca_dev->fr_o;	j = gspca_dev->fr_queue[i];	frame = &gspca_dev->frame[j];	if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) {		atomic_dec(&gspca_dev->nevent);		goto ok;	}	if (nonblock_ing)			/* no frame yet */		return -EAGAIN;	/* wait till a frame is ready */	for (;;) {		ret = wait_event_interruptible_timeout(gspca_dev->wq,					atomic_read(&gspca_dev->nevent) > 0,					msecs_to_jiffies(3000));		if (ret <= 0) {			if (ret < 0)				return ret;	/* interrupt */			return -EIO;		/* timeout */		}		atomic_dec(&gspca_dev->nevent);		if (!gspca_dev->streaming || !gspca_dev->present)			return -EIO;		i = gspca_dev->fr_o;		j = gspca_dev->fr_queue[i];		frame = &gspca_dev->frame[j];		if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE)			break;	}ok:	gspca_dev->fr_o = (i + 1) % gspca_dev->nframes;	PDEBUG(D_FRAM, "frame wait q:%d i:%d o:%d",		gspca_dev->fr_q,		gspca_dev->fr_i,		gspca_dev->fr_o);	if (gspca_dev->sd_desc->dq_callback) {		mutex_lock(&gspca_dev->usb_lock);		gspca_dev->sd_desc->dq_callback(gspca_dev);		mutex_unlock(&gspca_dev->usb_lock);	}	return j;}/* * dequeue a video buffer * * If nonblock_ing is false, block until a buffer is available. */static int vidioc_dqbuf(struct file *file, void *priv,			struct v4l2_buffer *v4l2_buf){	struct gspca_dev *gspca_dev = priv;	struct gspca_frame *frame;	int i, ret;	PDEBUG(D_FRAM, "dqbuf");	if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	if (v4l2_buf->memory != gspca_dev->memory)		return -EINVAL;	/* if not streaming, be sure the application will not loop forever */	if (!(file->f_flags & O_NONBLOCK)	    && !gspca_dev->streaming && gspca_dev->users == 1)		return -EINVAL;	/* only the capturing file may dequeue */	if (gspca_dev->capt_file != file)		return -EINVAL;	/* only one dequeue / read at a time */	if (mutex_lock_interruptible(&gspca_dev->read_lock))		return -ERESTARTSYS;	ret = frame_wait(gspca_dev, file->f_flags & O_NONBLOCK);	if (ret < 0)		goto out;	i = ret;				/* frame index */	frame = &gspca_dev->frame[i];	if (gspca_dev->memory == V4L2_MEMORY_USERPTR) {		if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr,				 frame->data,				 frame->v4l2_buf.bytesused)) {			PDEBUG(D_ERR|D_STREAM,				"dqbuf cp to user failed");			ret = -EFAULT;			goto out;		}	}	frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;	memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);	PDEBUG(D_FRAM, "dqbuf %d", i);	ret = 0;out:	mutex_unlock(&gspca_dev->read_lock);	return ret;}/* * queue a video buffer * * Attempting to queue a buffer that has already been * queued will return -EINVAL. */static int vidioc_qbuf(struct file *file, void *priv,			struct v4l2_buffer *v4l2_buf){	struct gspca_dev *gspca_dev = priv;	struct gspca_frame *frame;	int i, index, ret;

⌨️ 快捷键说明

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