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

📄 cafe_ccic.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	mutex_lock(&cam->s_mutex);	if (cam->state != S_STREAMING)		goto out_unlock;	cafe_ctlr_stop_dma(cam);	ret = 0;  out_unlock:	mutex_unlock(&cam->s_mutex);  out:	return ret;}static int cafe_setup_siobuf(struct cafe_camera *cam, int index){	struct cafe_sio_buffer *buf = cam->sb_bufs + index;	INIT_LIST_HEAD(&buf->list);	buf->v4lbuf.length = PAGE_ALIGN(cam->pix_format.sizeimage);	buf->buffer = vmalloc_user(buf->v4lbuf.length);	if (buf->buffer == NULL)		return -ENOMEM;	buf->mapcount = 0;	buf->cam = cam;	buf->v4lbuf.index = index;	buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;	buf->v4lbuf.field = V4L2_FIELD_NONE;	buf->v4lbuf.memory = V4L2_MEMORY_MMAP;	/*	 * Offset: must be 32-bit even on a 64-bit system.  videobuf-dma-sg	 * just uses the length times the index, but the spec warns	 * against doing just that - vma merging problems.  So we	 * leave a gap between each pair of buffers.	 */	buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;	return 0;}static int cafe_free_sio_buffers(struct cafe_camera *cam){	int i;	/*	 * If any buffers are mapped, we cannot free them at all.	 */	for (i = 0; i < cam->n_sbufs; i++)		if (cam->sb_bufs[i].mapcount > 0)			return -EBUSY;	/*	 * OK, let's do it.	 */	for (i = 0; i < cam->n_sbufs; i++)		vfree(cam->sb_bufs[i].buffer);	cam->n_sbufs = 0;	kfree(cam->sb_bufs);	cam->sb_bufs = NULL;	INIT_LIST_HEAD(&cam->sb_avail);	INIT_LIST_HEAD(&cam->sb_full);	return 0;}static int cafe_vidioc_reqbufs(struct file *filp, void *priv,		struct v4l2_requestbuffers *req){	struct cafe_camera *cam = filp->private_data;	int ret = 0;  /* Silence warning */	/*	 * Make sure it's something we can do.  User pointers could be	 * implemented without great pain, but that's not been done yet.	 */	if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	if (req->memory != V4L2_MEMORY_MMAP)		return -EINVAL;	/*	 * If they ask for zero buffers, they really want us to stop streaming	 * (if it's happening) and free everything.  Should we check owner?	 */	mutex_lock(&cam->s_mutex);	if (req->count == 0) {		if (cam->state == S_STREAMING)			cafe_ctlr_stop_dma(cam);		ret = cafe_free_sio_buffers (cam);		goto out;	}	/*	 * Device needs to be idle and working.  We *could* try to do the	 * right thing in S_SPECREAD by shutting things down, but it	 * probably doesn't matter.	 */	if (cam->state != S_IDLE || (cam->owner && cam->owner != filp)) {		ret = -EBUSY;		goto out;	}	cam->owner = filp;	if (req->count < min_buffers)		req->count = min_buffers;	else if (req->count > max_buffers)		req->count = max_buffers;	if (cam->n_sbufs > 0) {		ret = cafe_free_sio_buffers(cam);		if (ret)			goto out;	}	cam->sb_bufs = kzalloc(req->count*sizeof(struct cafe_sio_buffer),			GFP_KERNEL);	if (cam->sb_bufs == NULL) {		ret = -ENOMEM;		goto out;	}	for (cam->n_sbufs = 0; cam->n_sbufs < req->count; (cam->n_sbufs++)) {		ret = cafe_setup_siobuf(cam, cam->n_sbufs);		if (ret)			break;	}	if (cam->n_sbufs == 0)  /* no luck at all - ret already set */		kfree(cam->sb_bufs);	req->count = cam->n_sbufs;  /* In case of partial success */  out:	mutex_unlock(&cam->s_mutex);	return ret;}static int cafe_vidioc_querybuf(struct file *filp, void *priv,		struct v4l2_buffer *buf){	struct cafe_camera *cam = filp->private_data;	int ret = -EINVAL;	mutex_lock(&cam->s_mutex);	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		goto out;	if (buf->index < 0 || buf->index >= cam->n_sbufs)		goto out;	*buf = cam->sb_bufs[buf->index].v4lbuf;	ret = 0;  out:	mutex_unlock(&cam->s_mutex);	return ret;}static int cafe_vidioc_qbuf(struct file *filp, void *priv,		struct v4l2_buffer *buf){	struct cafe_camera *cam = filp->private_data;	struct cafe_sio_buffer *sbuf;	int ret = -EINVAL;	unsigned long flags;	mutex_lock(&cam->s_mutex);	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		goto out;	if (buf->index < 0 || buf->index >= cam->n_sbufs)		goto out;	sbuf = cam->sb_bufs + buf->index;	if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) {		ret = 0; /* Already queued?? */		goto out;	}	if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_DONE) {		/* Spec doesn't say anything, seems appropriate tho */		ret = -EBUSY;		goto out;	}	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;	spin_lock_irqsave(&cam->dev_lock, flags);	list_add(&sbuf->list, &cam->sb_avail);	spin_unlock_irqrestore(&cam->dev_lock, flags);	ret = 0;  out:	mutex_unlock(&cam->s_mutex);	return ret;}static int cafe_vidioc_dqbuf(struct file *filp, void *priv,		struct v4l2_buffer *buf){	struct cafe_camera *cam = filp->private_data;	struct cafe_sio_buffer *sbuf;	int ret = -EINVAL;	unsigned long flags;	mutex_lock(&cam->s_mutex);	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		goto out_unlock;	if (cam->state != S_STREAMING)		goto out_unlock;	if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) {		ret = -EAGAIN;		goto out_unlock;	}	while (list_empty(&cam->sb_full) && cam->state == S_STREAMING) {		mutex_unlock(&cam->s_mutex);		if (wait_event_interruptible(cam->iowait,						!list_empty(&cam->sb_full))) {			ret = -ERESTARTSYS;			goto out;		}		mutex_lock(&cam->s_mutex);	}	if (cam->state != S_STREAMING)		ret = -EINTR;	else {		spin_lock_irqsave(&cam->dev_lock, flags);		/* Should probably recheck !list_empty() here */		sbuf = list_entry(cam->sb_full.next,				struct cafe_sio_buffer, list);		list_del_init(&sbuf->list);		spin_unlock_irqrestore(&cam->dev_lock, flags);		sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;		*buf = sbuf->v4lbuf;		ret = 0;	}  out_unlock:	mutex_unlock(&cam->s_mutex);  out:	return ret;}static void cafe_v4l_vm_open(struct vm_area_struct *vma){	struct cafe_sio_buffer *sbuf = vma->vm_private_data;	/*	 * Locking: done under mmap_sem, so we don't need to	 * go back to the camera lock here.	 */	sbuf->mapcount++;}static void cafe_v4l_vm_close(struct vm_area_struct *vma){	struct cafe_sio_buffer *sbuf = vma->vm_private_data;	mutex_lock(&sbuf->cam->s_mutex);	sbuf->mapcount--;	/* Docs say we should stop I/O too... */	if (sbuf->mapcount == 0)		sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;	mutex_unlock(&sbuf->cam->s_mutex);}static struct vm_operations_struct cafe_v4l_vm_ops = {	.open = cafe_v4l_vm_open,	.close = cafe_v4l_vm_close};static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma){	struct cafe_camera *cam = filp->private_data;	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;	int ret = -EINVAL;	int i;	struct cafe_sio_buffer *sbuf = NULL;	if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED))		return -EINVAL;	/*	 * Find the buffer they are looking for.	 */	mutex_lock(&cam->s_mutex);	for (i = 0; i < cam->n_sbufs; i++)		if (cam->sb_bufs[i].v4lbuf.m.offset == offset) {			sbuf = cam->sb_bufs + i;			break;		}	if (sbuf == NULL)		goto out;	ret = remap_vmalloc_range(vma, sbuf->buffer, 0);	if (ret)		goto out;	vma->vm_flags |= VM_DONTEXPAND;	vma->vm_private_data = sbuf;	vma->vm_ops = &cafe_v4l_vm_ops;	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED;	cafe_v4l_vm_open(vma);	ret = 0;  out:	mutex_unlock(&cam->s_mutex);	return ret;}static int cafe_v4l_open(struct inode *inode, struct file *filp){	struct cafe_camera *cam;	cam = cafe_find_dev(iminor(inode));	if (cam == NULL)		return -ENODEV;	filp->private_data = cam;	mutex_lock(&cam->s_mutex);	if (cam->users == 0) {		cafe_ctlr_power_up(cam);		__cafe_cam_reset(cam);		cafe_set_config_needed(cam, 1);	/* FIXME make sure this is complete */	}	(cam->users)++;	mutex_unlock(&cam->s_mutex);	return 0;}static int cafe_v4l_release(struct inode *inode, struct file *filp){	struct cafe_camera *cam = filp->private_data;	mutex_lock(&cam->s_mutex);	(cam->users)--;	if (filp == cam->owner) {		cafe_ctlr_stop_dma(cam);		cafe_free_sio_buffers(cam);		cam->owner = NULL;	}	if (cam->users == 0) {		cafe_ctlr_power_down(cam);		if (alloc_bufs_at_read)			cafe_free_dma_bufs(cam);	}	mutex_unlock(&cam->s_mutex);	return 0;}static unsigned int cafe_v4l_poll(struct file *filp,		struct poll_table_struct *pt){	struct cafe_camera *cam = filp->private_data;	poll_wait(filp, &cam->iowait, pt);	if (cam->next_buf >= 0)		return POLLIN | POLLRDNORM;	return 0;}static int cafe_vidioc_queryctrl(struct file *filp, void *priv,		struct v4l2_queryctrl *qc){	struct cafe_camera *cam = filp->private_data;	int ret;	mutex_lock(&cam->s_mutex);	ret = __cafe_cam_cmd(cam, VIDIOC_QUERYCTRL, qc);	mutex_unlock(&cam->s_mutex);	return ret;}static int cafe_vidioc_g_ctrl(struct file *filp, void *priv,		struct v4l2_control *ctrl){	struct cafe_camera *cam = filp->private_data;	int ret;	mutex_lock(&cam->s_mutex);	ret = __cafe_cam_cmd(cam, VIDIOC_G_CTRL, ctrl);	mutex_unlock(&cam->s_mutex);	return ret;}static int cafe_vidioc_s_ctrl(struct file *filp, void *priv,		struct v4l2_control *ctrl){	struct cafe_camera *cam = filp->private_data;	int ret;	mutex_lock(&cam->s_mutex);	ret = __cafe_cam_cmd(cam, VIDIOC_S_CTRL, ctrl);	mutex_unlock(&cam->s_mutex);	return ret;}static int cafe_vidioc_querycap(struct file *file, void *priv,		struct v4l2_capability *cap){	strcpy(cap->driver, "cafe_ccic");	strcpy(cap->card, "cafe_ccic");	cap->version = CAFE_VERSION;	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |		V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;	return 0;}/* * The default format we use until somebody says otherwise. */static struct v4l2_pix_format cafe_def_pix_format = {	.width		= VGA_WIDTH,	.height		= VGA_HEIGHT,	.pixelformat	= V4L2_PIX_FMT_YUYV,	.field		= V4L2_FIELD_NONE,	.bytesperline	= VGA_WIDTH*2,	.sizeimage	= VGA_WIDTH*VGA_HEIGHT*2,};static int cafe_vidioc_enum_fmt_cap(struct file *filp,		void *priv, struct v4l2_fmtdesc *fmt){	struct cafe_camera *cam = priv;	int ret;	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	mutex_lock(&cam->s_mutex);	ret = __cafe_cam_cmd(cam, VIDIOC_ENUM_FMT, fmt);	mutex_unlock(&cam->s_mutex);	return ret;}static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv,		struct v4l2_format *fmt){	struct cafe_camera *cam = priv;	int ret;	mutex_lock(&cam->s_mutex);	ret = __cafe_cam_cmd(cam, VIDIOC_TRY_FMT, fmt);	mutex_unlock(&cam->s_mutex);	return ret;}static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,		struct v4l2_format *fmt){	struct cafe_camera *cam = priv;	int ret;	/*	 * Can't do anything if the device is not idle	 * Also can't if there are streaming buffers in place.	 */	if (cam->state != S_IDLE || cam->n_sbufs > 0)		return -EBUSY;	/*	 * See if the formatting works in principle.	 */	ret = cafe_vidioc_try_fmt_cap(filp, priv, fmt);	if (ret)		return ret;	/*	 * Now we start to change things for real, so let's do it	 * under lock.	 */	mutex_lock(&cam->s_mutex);	cam->pix_format = fmt->fmt.pix;	/*	 * Make sure we have appropriate DMA buffers.	 */	ret = -ENOMEM;	if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage)		cafe_free_dma_bufs(cam);	if (cam->nbufs == 0) {		if (cafe_alloc_dma_bufs(cam, 0))			goto out;	}	/*	 * It looks like this might work, so let's program the sensor.	 */	ret = cafe_cam_configure(cam);	if (! ret)		ret = cafe_ctlr_configure(cam);  out:	mutex_unlock(&cam->s_mutex);	return ret;}/* * Return our stored notion of how the camera is/should be configured. * The V4l2 spec wants us to be smarter, and actually get this from * the camera (and not mess with it at open time).  Someday. */static int cafe_vidioc_g_fmt_cap(struct file *filp, void *priv,		struct v4l2_format *f){	struct cafe_camera *cam = priv;	f->fmt.pix = cam->pix_format;	return 0;}/* * We only have one input - the sensor - so minimize the nonsense here. */static int cafe_vidioc_enum_input(struct file *filp, void *priv,		struct v4l2_input *input){	if (input->index != 0)		return -EINVAL;	input->type = V4L2_INPUT_TYPE_CAMERA;	input->std = V4L2_STD_ALL; /* Not sure what should go here */	strcpy(input->name, "Camera");	return 0;}static int cafe_vidioc_g_input(struct file *filp, void *priv, unsigned int *i){	*i = 0;	return 0;}static int cafe_vidioc_s_input(struct file *filp, void *priv, unsigned int i){	if (i != 0)		return -EINVAL;	return 0;}/* from vivi.c */static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a){	return 0;}/* * G/S_PARM.  Most of this is done by the sensor, but we are * the level which controls the number of read buffers. */static int cafe_vidioc_g_parm(struct file *filp, void *priv,		struct v4l2_streamparm *parms){	struct cafe_camera *cam = priv;	int ret;	mutex_lock(&cam->s_mutex);	ret = __cafe_cam_cmd(cam, VIDIOC_G_PARM, parms);	mutex_unlock(&cam->s_mutex);	parms->parm.capture.readbuffers = n_dma_bufs;	return ret;}static int cafe_vidioc_s_parm(struct file *filp, void *priv,		struct v4l2_streamparm *parms){	struct cafe_camera *cam = priv;	int ret;	mutex_lock(&cam->s_mutex);	ret = __cafe_cam_cmd(cam, VIDIOC_S_PARM, parms);	mutex_unlock(&cam->s_mutex);	parms->parm.capture.readbuffers = n_dma_bufs;	return ret;}static void cafe_v4l_dev_release(struct video_device *vd){	struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev);	kfree(cam);}/*

⌨️ 快捷键说明

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