📄 cafe_ccic.c
字号:
static int cafe_vidioc_streamoff(struct file *filp, void *priv, enum v4l2_buf_type type){ struct cafe_camera *cam = filp->private_data; int ret = -EINVAL; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) goto out; 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_vid_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_vid_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_vid_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_vid_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_vid_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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -