📄 v4l2.c
字号:
}#endif /* MVL-CEE *//* * * M E M O R Y M A P P I N G * */static struct stream_buffer *mmap_stream_buffer_from_offset (struct capture_device *dev, unsigned long offset){ int i; offset = offset * PAGE_SIZE; for (i = 0; i < MAX_CAPTURE_BUFFERS; ++i) if (offset == dev->stream_buf[i].vidbuf.offset) return &dev->stream_buf[i]; return NULL;}static intmmap_request_buffers (struct capture_device *dev, struct v4l2_requestbuffers *req){ int i; u32 buflen; u32 type; if (dev->stream_buffers_mapped) return 0; /* can't make requests if buffers are mapped */ if (req->count < 1) req->count = 1; if (req->count > MAX_CAPTURE_BUFFERS) req->count = MAX_CAPTURE_BUFFERS; type = V4L2_BUF_TYPE_CAPTURE; dev->stream_contig_map = 0; if (req->type & V4L2_BUF_REQ_CONTIG) { dev->stream_contig_map = 1; req->type = type | V4L2_BUF_REQ_CONTIG; /* note: _REQ_CONTIG is only used in v4l2_requestbuffers */ } /* The buffer length needs to be a multiple of the page size */ buflen = (dev->clientfmt.sizeimage + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); //dbg("Granting %d buffers\n",req->count); /* Now initialize the buffer structures. Don't allocate the */ /* buffers until they're mapped. */ for (i = 0; i < req->count; ++i) { dev->stream_buf[i].requested = 1; dev->stream_buf[i].vidbuf.index = i; dev->stream_buf[i].vidbuf.type = type; /* offset must be unique for each buffer, and a multiple */ /* of PAGE_SIZE on 2.4.x */ dev->stream_buf[i].vidbuf.offset = PAGE_SIZE * (i + 1); dev->stream_buf[i].vidbuf.length = buflen; dev->stream_buf[i].vidbuf.bytesused = 0; dev->stream_buf[i].vidbuf.flags = 0; dev->stream_buf[i].vidbuf.timestamp = 0; dev->stream_buf[i].vidbuf.sequence = 0; memset (&dev->stream_buf[i].vidbuf.timecode, 0, sizeof (struct v4l2_timecode)); } for (i = req->count; i < MAX_CAPTURE_BUFFERS; ++i) dev->stream_buf[i].requested = 0; dev->stream_buffers_requested = req->count; return 1;}static voidmmap_unrequest_buffers (struct capture_device *dev){ int i; if (dev->stream_buffers_requested == 0 || dev->stream_buffers_mapped) return; for (i = 0; i < MAX_CAPTURE_BUFFERS; ++i) dev->stream_buf[i].requested = 0; dev->stream_buffers_requested = 0;}static voidmmap_vma_open (struct vm_area_struct *vma){ struct capture_device *dev = capture_device_from_file (vma->vm_file); struct stream_buffer *buf;#ifdef CONFIG_CEE /* MVL-CEE */ wait_event(dev->suspend_wq, dev->suspended == 0);#endif /* MVL-CEE */ if (dev == NULL) return; buf = mmap_stream_buffer_from_offset (dev, vma->vm_pgoff); if (dev->stream_contig_map) buf = &dev->stream_buf[0]; ++buf->vma_refcount; //dbg("vma_open called\n"); //MOD_INC_USE_COUNT;}static voidmmap_vma_close (struct vm_area_struct *vma){ struct capture_device *dev = capture_device_from_file (vma->vm_file); struct stream_buffer *buf = mmap_stream_buffer_from_offset (dev, vma->vm_pgoff); int i, n = 1;#ifdef CONFIG_CEE /* MVL-CEE */ wait_event(dev->suspend_wq, dev->suspended == 0);#endif /* MVL-CEE */ if (dev->stream_contig_map) { /* Unmap all the buffers in one stroke */ n = dev->stream_buffers_mapped; buf = &dev->stream_buf[0]; } --buf->vma_refcount; if (buf->vma_refcount > 0) return; for (i = 0; i < n; ++i) { if (dev->streaming) { //dbg("Warning- munmap() called while streaming\n"); capture_streamoff (dev, buf->vidbuf.type); } v4l2_q_yank_node (&dev->stream_q_capture, &buf->qnode); v4l2_q_yank_node (&dev->stream_q_done, &buf->qnode); if (buf->vaddress != NULL && i == 0) vfree (buf->vaddress); buf->vaddress = NULL; if (buf->dma_list) free_page ((unsigned long) buf->dma_list); buf->dma_list = NULL; buf->vidbuf.flags = 0; //dbg("Buffer %d deallocated\n",(int)vma->vm_pgoff); ++buf; if (dev->stream_buffers_mapped > 0) --dev->stream_buffers_mapped; } //MOD_DEC_USE_COUNT;}static struct page *mmap_vma_nopage (struct vm_area_struct *vma, unsigned long address, int write){ struct capture_device *dev; struct stream_buffer *buf; unsigned long offset_into_buffer; struct page *page; int n = 1; dev = capture_device_from_file (vma->vm_file); if (dev == NULL) return 0;#ifdef CONFIG_CEE /* MVL-CEE */ wait_event(dev->suspend_wq, dev->suspended == 0);#endif /* MVL-CEE */ if (dev->stream_contig_map) { buf = &dev->stream_buf[0]; n = dev->stream_buffers_requested; } else buf = mmap_stream_buffer_from_offset (dev, vma->vm_pgoff); if (buf == NULL) return 0; offset_into_buffer = address - vma->vm_start; if (offset_into_buffer >= buf->vidbuf.length * n) { err ("Attempt to read past end of mmap() buffer\n"); return 0; } page = v4l2_vmalloc_to_page (buf->vaddress + offset_into_buffer); if (page == 0) return 0; atomic_inc (&page->count); return page;}static struct vm_operations_struct capture_vma_operations = { mmap_vma_open, mmap_vma_close, mmap_vma_nopage,};/* * * V 4 L 2 I N T E R F A C E * */static intv4l2_open (struct v4l2_device *v, int flags, void **idptr){ struct capture_device *dev = (struct capture_device *) v; int i, n; int cap; int retcode;#ifdef CONFIG_CEE /* MVL-CEE */ wait_event(dev->suspend_wq, dev->suspended == 0);#endif /* MVL-CEE */ for (i = 0, n = -1, cap = 0; i < MAX_OPENS; ++i) { if (!dev->open_data[i].isopen) n = i; /* available open_data structure */ else if (!dev->open_data[i].noncapturing) cap = 1; /* another open is already capturing */ } if (n == -1) { /* No available open_data structures */ //dbg("No more opens on this device\n"); return -EBUSY; } if (flags & O_NONCAP) /* Non-capturing open */ dev->open_data[n].noncapturing = 1; else if (cap) { //dbg("No more capturing opens on this device\n"); return -EBUSY; } else { dev->open_data[n].noncapturing = 0; /* Keep track of whether there is a capturing open */ ++dev->capturing_opens; dev->perf.frames = 0; dev->perf.framesdropped = 0; dev->perf.bytesout = 0; } //MOD_INC_USE_COUNT; ++dev->open_count; dev->open_data[n].isopen = 1; dev->open_data[n].dev = dev; *idptr = &dev->open_data[n]; if (dev->open_count == 1) { if (dev->preview) { // If preview mode is on then we will refrain // from any furthur device initialization since // it isn't needed and actually will disrupt the // automatic preview operation that the driver // is in the process of doing. Recall that apps // can open() the video device, turn on preview, // and then close() it; preview continues. Sometime // later they may re-open() the device and we don't // want that disrupting the on-going preview // processing. return 0; } if ((retcode = dev->camif->open ())) { dev->open_count = 0; dev->open_data[n].isopen = 0; return retcode; } dev->ready_to_capture = 0; /* benchmark changes parameters! */ dev->capture_completed = 0; dev->capture_started = 0; v4l2_q_init (&dev->stream_q_capture); v4l2_q_init (&dev->stream_q_done); } //dbg("Open succeeded\n"); /* frame counter for test images only */ if (!dev->open_data[n].noncapturing) dev->h = dev->m = dev->s = dev->f = 0; return 0;}static voidv4l2_close (void *id){ struct device_open *o = (struct device_open *) id; struct capture_device *dev = o->dev;#ifdef CONFIG_CEE /* MVL-CEE */ wait_event(dev->suspend_wq, dev->suspended == 0);#endif /* MVL-CEE */ if (!o->noncapturing) { --dev->capturing_opens; //dbg("Close\n"); } o->isopen = 0; --dev->open_count; if (dev->preview) { // If we have been placed into preview mode then // we want to keep that going even if the app // closes the video device. We expect sometime // later the app, or some app, will open the // video device and turn off preview when it // desires. This video driver handles the // preview operation and all the app needs to // do is briefly open() us and turn on or // off the preview mode and then, if desired, // close() us. return; } // shut things down. if (dev->open_count == 0) { capture_close (dev); dev->camif->close (); } //MOD_DEC_USE_COUNT;}static longv4l2_write (void *id, const char *buf, unsigned long count, int noblock){ //dbg("Write() not handled\n"); return -EINVAL;}/* The arguments are already copied into kernel memory, so don't use copy_from_user() or copy_to_user() on arg. */static intv4l2_ioctl (void *id, unsigned int cmd, void *arg){ struct device_open *o = (struct device_open *) id; struct capture_device *dev = o->dev;#ifdef CONFIG_CEE /* MVL-CEE */ wait_event(dev->suspend_wq, dev->suspended == 0);#endif /* MVL-CEE */ switch (cmd) { case VIDIOC_QUERYCAP: { struct v4l2_capability *b = arg; strcpy (b->name, dev->v.name); b->type = V4L2_TYPE_CAPTURE; b->flags = V4L2_FLAG_READ | V4L2_FLAG_STREAMING | V4L2_FLAG_PREVIEW | V4L2_FLAG_SELECT; b->inputs = dev->videc.num_inputs; b->outputs = 0; b->audios = 0; b->maxwidth = MAX_WIDTH; b->maxheight = MAX_HEIGHT; b->minwidth = MIN_WIDTH; b->minheight = MIN_HEIGHT; b->maxframerate = 30; return 0; } case VIDIOC_ENUM_PIXFMT: { struct v4l2_fmtdesc *f = arg; if (f->index < 0 || f->index >= NUM_CAPFMT) return -EINVAL; *f = capfmt[f->index]; return 0; } case VIDIOC_G_FMT: { struct v4l2_format *fmt = arg; if (fmt->type != V4L2_BUF_TYPE_CAPTURE) { //dbg("G_FMT wrong buffer type %d\n",fmt->type); return -EINVAL; } fmt->fmt.pix = dev->clientfmt; return 0; } case VIDIOC_S_FMT: { struct v4l2_format *fmt = arg; if (o->noncapturing) { //dbg("S_FMT illegal in non-capturing open\n"); return -EPERM; } if (fmt->type != V4L2_BUF_TYPE_CAPTURE) { //dbg("S_FMT wrong buffer type %d\n",fmt->type); return -EINVAL; } dev->clientfmt = fmt->fmt.pix; capture_abort (dev); if (capture_new_format (dev)) return -EINVAL; if (dev->streaming) capture_stream_start (dev); else if (dev->preview) capture_grab_frame (dev); fmt->fmt.pix = dev->clientfmt; return 0; } case VIDIOC_G_COMP: return -EINVAL; case VIDIOC_S_COMP: return -EINVAL; case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *req = arg; if (o->noncapturing) { //dbg("REQBUFS illegal in non-capturing open\n"); return -EPERM; } if (dev->stream_buffers_mapped) { //dbg("Can't request buffers if buffers are " // "already mapped\n"); return -EPERM; } mmap_unrequest_buffers (dev); capture_begin (dev); if (!mmap_request_buffers (dev, req)) return -EINVAL; return 0; } case VIDIOC_QUERYBUF: { struct v4l2_buffer *buf = arg; int i; if (o->noncapturing) { //dbg("QUERYBUF illegal in non-capturing open\n"); return -EPERM; } i = buf->index; if (i < 0 || i >= MAX_CAPTURE_BUFFERS || !dev->stream_buf[i].requested || (buf->type & V4L2_BUF_TYPE_field) != (dev->stream_buf[i].vidbuf. type & V4L2_BUF_TYPE_field)) { //dbg("QUERYBUF bad parameter\n"); return -EINVAL; } *buf = dev->stream_buf[i].vidbuf; return 0; } case VIDIOC_QBUF: { struct v4l2_buffer *buf = arg; if (o->noncapturing) { //dbg("QBUF illegal in non-capturing open\n"); return -EPERM; } if (!dev->stream_buffers_mapped) { //dbg("QBUF no buffers are mapped\n"); return -EINVAL; } if (!capture_queuebuffer (dev, buf)) return -EINVAL; return 0; } case VIDIOC_DQBUF: { struct v4l2_buffer *buf = arg; if (o->noncapturing) { //dbg("DQBUF illegal in non-capturing open\n"); return -EPERM; } if (!capture_dequeuebuffer (dev, buf)) return -EINVAL; return 0; } case VIDIOC_STREAMON: { __u32 *type = arg; if (o->noncapturing) { //dbg("STREAMON illegal in non-capturing open\n"); return -EPERM; } if (!capture_streamon (dev, *type)) return -EINVAL; return 0; } case VIDIOC_STREAMOFF: { __u32 *type = arg; if (o->noncapturing) { //dbg("STREAMOFF illegal in non-capturing open\n"); return -EPERM; } capture_streamoff (dev, *type); return 0; } case VIDIOC_ENUM_FBUFFMT: return -EINVAL; case VIDIOC_G_FBUF: return -EINVAL; case VIDIOC_S_FBUF: return -EINVAL; case VIDIOC_G_WIN: return -EINVAL; case VIDIOC_S_WIN: return -EINVAL; case VIDIOC_PREVIEW: { int *on = (unsigned int *) arg; dbg ("VIDIOC_PREVIEW %d\n", *on); // *revisit-skranz* temp. if (!dev->preview && (*on == 1)) { // It is "off" now but we want it "on", so... /* * schedule the framebuffer info updater to run * (it has to run under keventd). */ dev->fbinfo_valid = 0; fbinfo_tsk_q_entry.routine = update_fbinfo_task; fbinfo_tsk_q_entry.data = (void *) dev; schedule_task (&fbinfo_tsk_q_entry); interruptible_sleep_on (&dev->fbinfo_wait); if (signal_pending (current)) return -ERESTARTSYS; dev->preview = 1; capture_grab_frame (dev); if (!dev->ready_to_capture) { dbg ("ioctl(..,VIDIOC_PREVIEW,...); Can't grab frames!\n"); return -EINVAL; } } else { if (dev->preview && (*on == 0)) { // It is "on" now but we want it "off", so... capture_abort (dev); dev->ready_to_capture = 0; dev->preview = 0; } } return 0; } case VIDIOC_G_PERF: { memcpy (arg, &dev->perf, sizeof (dev->perf)); return 0; } case VIDIOC_G_INPUT: { memcpy (arg, &dev->input, sizeof (dev->input)); return 0; } case VIDIOC_S_INPUT: { int input = *(int *) arg; if (input < 0 || input >= dev->videc.num_inputs) { //dbg("Input out of range %d\n", input); return -EINVAL; } if (input != dev->input) { dev->SwitchInputs = 1; dev->input = input; set_video_input (dev, input); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -