📄 v4l2.c
字号:
* 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); /* 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;#if 1 /* power management */ if (capture_pwm.suspended) return;#endif /* power management */ 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");}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;#if 1 /* power management */ if (capture_pwm.suspended) return;#endif /* power management */ 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; }}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;#if 1 /* power management */ if (capture_pwm.suspended) return 0;#endif /* power management */ 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; dbg("Trying to open\n");#if 1 /* power management */ if (capture_pwm.suspended) return -EPERM;#endif /* power management */ 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->id))) { 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; if (!o->noncapturing) { --dev->capturing_opens; dbg("Close\n"); } o->isopen = 0; --dev->open_count; MOD_DEC_USE_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.*/ /* power management considered */ if ((dev->open_count == 0) && (!capture_pwm.suspended)) { capture_close (dev); dev->camif->close (dev->id); }}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;#if 1 /* power management */ if (capture_pwm.suspended) return -EPERM;#endif /* power management */ 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[dev->id][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); } return 0; } case VIDIOC_G_PARM: { struct v4l2_streamparm *sp = arg; if (sp->type != V4L2_BUF_TYPE_CAPTURE) return -EINVAL; sp->parm.capture = dev->capture; return 0; } case VIDIOC_S_PARM: { struct v4l2_streamparm *sp = arg; struct v4l2_captureparm *vp = &sp->parm.capture; if (vp->capturemode & ~dev->capture.capability) { dbg("PARM unsupported capture capability %08X\n", vp->capturemode); return -EINVAL; } if ((dev->capture.capability & V4L2_CAP_TIMEPERFRAME) && vp->timeperframe < 10000) { dbg("PARM time per frame out of range %ld\n", vp->timeperframe); return -EINVAL; } if (vp->capturemode != dev->capture.capturemode && !o->noncapturing && dev->streaming) { dbg("S_PARM state error\n"); return -EINVAL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -