📄 v4l2.c
字号:
if (dev->camif->snapshot (dev->id, dev->capture_buffer_phys, dev->capture_size) == 0) { dev->capture_started = 1; dev->capture_completed = 0; } } else { dev->capture_started = 1; dev->capture_completed = 0; }}/* Start an image stream */static voidcapture_stream_start (struct capture_device *dev){ capture_begin (dev); if (!dev->ready_to_capture) return; /* Set up stream_capture_buffer to point to the buffer to */ /* capture the next frame into */ dev->stream_capture_buffer = dev->capture_buffer; if (dev->camera && dev->input == 0) { /* Start the camera h/w. It will call us back on image completion.*/ if (dev->camif->start_streaming (dev->id, dev->capture_buffer_phys, dev->capture_size) == 0) { dev->capture_started = 1; dev->capture_completed = 0; } } else { dev->capture_started = 1; dev->capture_completed = 0; }}/* * STREAMING CAPTURE *//* 1 = success; 0 = failed */static intcapture_queuebuffer (struct capture_device *dev, struct v4l2_buffer *vidbuf){ int i = vidbuf->index; struct stream_buffer *buf = NULL; if (!dev->stream_buffers_mapped) { dbg("QBUF no buffers mapped\n"); return 0; } if (vidbuf->type != V4L2_BUF_TYPE_CAPTURE) { dbg("QBUF wrong type\n"); return 0; } if (i < 0 || i >= MAX_CAPTURE_BUFFERS || !dev->stream_buf[i].requested) { dbg("QBUF buffer index %d is out of range\n", i); return 0; } buf = &dev->stream_buf[i]; if (!(buf->vidbuf.flags & V4L2_BUF_FLAG_MAPPED)) { dbg("QBUF buffer %d is not mapped\n", i); return 0; } if ((buf->vidbuf.flags & V4L2_BUF_FLAG_QUEUED)) { dbg("QBUF buffer %d is already queued\n", i); return 0; } buf->vidbuf.flags &= ~V4L2_BUF_FLAG_DONE; v4l2_q_add_tail (&dev->stream_q_capture, &buf->qnode); buf->vidbuf.flags |= V4L2_BUF_FLAG_QUEUED; return 1;}static int /* 1 = got a buffer; 0 = no buffers */capture_dequeuebuffer (struct capture_device *dev, struct v4l2_buffer *buf){ struct stream_buffer *newbuf; if (buf->type != V4L2_BUF_TYPE_CAPTURE) { dbg("DQBUF wrong buffer type\n"); return 0; } newbuf = v4l2_q_del_head (&dev->stream_q_done); if (newbuf == NULL) { dbg("DQBUF nothing on done queue\n"); return 0; } newbuf->vidbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; *buf = newbuf->vidbuf; return 1;}static intcapture_streamon (struct capture_device *dev, __u32 type){ struct stream_buffer *buf; ENTRY (); if (type != V4L2_BUF_TYPE_CAPTURE) { dbg("STREAMON wrong buffer type\n"); EXIT(); return 0; } if (dev->streaming) { EXIT(); return 1; } capture_abort (dev); /* cancel any capture that might be in progress */ /* -2 is a magic number that triggers start-of-stream logic in */ /* capture_interrupt() */ dev->stream_last_frame = -2; dev->perf.frames = 0; dev->perf.framesdropped = 0; dev->perf.bytesout = 0; /* Can't capture frames faster than the video input */ if (dev->capture.timeperframe < dev->videc.frame_period) dev->capture.timeperframe = dev->videc.frame_period; /* Move any leftover DONE buffers to the free pool */ while ((buf = v4l2_q_del_head (&dev->stream_q_done))) buf->vidbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; /* Kick off the machine in continuous capture mode */ dev->streaming = 1; capture_stream_start (dev); EXIT(); return 1;}static voidcapture_streamoff (struct capture_device *dev, __u32 type){ ENTRY(); if (!dev->streaming) { EXIT(); return; } if (type != V4L2_BUF_TYPE_CAPTURE) { err("STREAMOFF wrong buffer type\n"); EXIT(); return; } capture_abort (dev); dev->streaming = 0; /* Note: should really delay this till next capture */ dev->perf.frames = 0; dev->perf.framesdropped = 0; dev->perf.bytesout = 0; EXIT();}/* * Convert raw camera image directly into framebuffer (used by * preview mode). Returns length of data or negative for error. */static intcapture_display_image (struct capture_device *dev, __u8 * capture_buffer){ if (!dev->capture_started) { /* If we get here is probably because the PREVIEW mode was turned off just prior to the interrupt routines completing the last image. We don't want anymore images. Just return.*/ dbg ("capture not started??\n"); return 0; } if (dev->camera) { int dest_stride; if (!dev->fbinfo_valid) { err ("preview set but no valid fb info\n"); return -EINVAL; } dest_stride = (dev->fbvar.xres_virtual * dev->fbvar.bits_per_pixel) / 8; dev->camif->convert_image (dev->id, (u8 *) capture_buffer, (u8 *) phys_to_virt (dev->fbfix. smem_start), 0, dest_stride, &dev->clientfmt); } ++dev->perf.frames; dev->perf.bytesout += dev->clientfmt.sizeimage; return dev->clientfmt.sizeimage;}/* * Convert the next frame. * Returns length of data or negative for error. */static intcapture_convert_image (struct capture_device *dev, __u8 * capture_buffer, __u8 * output_buffer, int output_is_user){ if (!dev->capture_started) { /* If we get here is probably because the PREVIEW mode was turned off just prior to the interrupt routines completing the last image. We don't want anymore images. Just return.*/ dbg ("capture not started??\n"); return 0; } if (dev->camera) { int dest_stride; dest_stride = (dev->clientfmt.width * dev->clientfmt.depth) / 8; dev->camif->convert_image (dev->id, (u8 *) capture_buffer, (void *) output_buffer, output_is_user, dest_stride, &dev->clientfmt); } ++dev->perf.frames; dev->perf.bytesout += dev->clientfmt.sizeimage; return dev->clientfmt.sizeimage;}/* The hardware has issued the interrupt signal, do any post-capture * processing that may be necessary. * [This function is called indirectly through the immediate task queue; * it executes at elevated IRQL, but it is interruptible. (It's a b.h.)] */static voidcapture_interrupt (void *v){ struct capture_device *dev = (struct capture_device *) v; struct stream_buffer *buf; int len; stamp_t timestamp_rough; unsigned long raw_frame_num; unsigned long next_raw_frame_to_keep; unsigned long stream_frame_num; stamp_t temp64; if (!dev->capture_started || dev->capture_completed) return; if (!dev->streaming) dev->capture_completed = 1; if (dev->capture_buffer == NULL) { err ("Can't process the interrupt\n"); return; } if (!dev->streaming) { dev->time_acquired = current_time_ms (); if (dev->preview) { capture_display_image (dev, dev->capture_buffer); dev->capture_started = 0; capture_grab_frame (dev); /* Start another capture.*/ } wake_up_interruptible (&dev->new_video_frame); return; } /* Only get here in streaming mode */ if (dev->stream_last_frame == -2) { /* First frame of the stream */ v4l2_masterclock_gettime (&dev->stream_begin); dev->stream_last_frame = -1; } if (dev->stream_capture_buffer == NULL) { dbg ("stream_capture_buffer is NULL!\n"); return; } buf = v4l2_q_peek_head (&dev->stream_q_capture); if (buf == NULL) { /* * No available buffers. Skip this frame. This is not an * error, it's a normal way to throttle the capture rate */ return; } /* Compute current stream time */ v4l2_masterclock_gettime (×tamp_rough); /* We do computations on a relative timestamp (since beginning */ /* of stream), then add 'dev->stream_begin' back in later */ timestamp_rough -= dev->stream_begin; /* Capture rate control */ if (dev->videc.frame_period == 0) { /* Sanity check to avoid divide-by-zero */ err ("videc.frame_period == 0 -- divide by 0\n"); dev->videc.frame_period = 333667; dev->capture.timeperframe= 333667; } raw_frame_num = v4l2_timestamp_divide (timestamp_rough, dev->videc.frame_period); temp64 = (stamp_t) dev->capture.timeperframe * (dev->stream_last_frame + 1) + (dev->videc.frame_period >> 1); next_raw_frame_to_keep = v4l2_math_div6432 ((u64) temp64, dev->videc.frame_period, NULL); if (raw_frame_num < next_raw_frame_to_keep) { /* Not time yet, don't keep this frame */ return; } /* Want this frame */ len = capture_convert_image (dev, dev->stream_capture_buffer, buf->vaddress, 0); if (len <= 0) { /* Frame no good, skip it. */ dbg ("frame no good\n"); return; } /* Fill in the buffer information fields */ buf->vidbuf.bytesused = len; buf->vidbuf.flags |= V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_KEYFRAME; stream_frame_num = v4l2_timestamp_correct (×tamp_rough, dev->capture.timeperframe); /* Returned timestamp should be absolute system time */ buf->vidbuf.timestamp = timestamp_rough + dev->stream_begin; buf->vidbuf.sequence = stream_frame_num; if (stream_frame_num > dev->stream_last_frame + 1) { /* We have missed one or more frames */ dev->perf.framesdropped += (stream_frame_num - (dev->stream_last_frame + 1)); } dev->stream_last_frame = stream_frame_num; /* Move buffer to done queue */ buf = v4l2_q_del_head (&dev->stream_q_capture); v4l2_q_add_tail (&dev->stream_q_done, &buf->qnode); /* A new frame is ready! */ wake_up_interruptible (&dev->new_video_frame);}/* * This is the callback from the Camera Interface, when * a new image has been captured by the camif h/w. This * is called at interrupt time, so just mark a bh and do * nothing more. */static voidcamif_capture_callback (void *data){ struct capture_device *dev = (struct capture_device *) data; dev->tqnode_dpc.routine = capture_interrupt; dev->tqnode_dpc.data = dev; queue_task (&dev->tqnode_dpc, &tq_immediate); mark_bh (IMMEDIATE_BH);}/* Read captured data into a user buffer. * Return: negative = error * 0 = keep waiting * positive = count of bytes read successfully */static longcapture_read (struct capture_device *dev, __u8 * user_buffer, int user_buffer_size){ int len = user_buffer_size; unsigned long now; if (!dev->capture_completed) { /* No interrupt has occurred yet, or DMA didn't finish. */ dbg("No data ready.\n"); if (!dev->capture_started) { capture_grab_frame (dev); } return 0; /* caller should keep waiting */ } now = current_time_ms (); if (now - dev->time_acquired > MAX_FRAME_AGE) { /* Frame in buffer is stale, get a new one */ dbg("Stale frame, re-acquiring.\n"); dev->capture_started = 0; capture_grab_frame (dev); return 0; /* caller should keep waiting */ } len = capture_convert_image (dev, dev->capture_buffer, user_buffer, 1); dev->capture_started = 0; capture_grab_frame (dev); return len;}/* Stop capturing and free all resources used for capture. */static voidcapture_close (struct capture_device *dev){ ENTRY(); if (dev->streaming) capture_streamoff (dev, V4L2_BUF_TYPE_CAPTURE); capture_abort (dev); dev->ready_to_capture = 0; if (dev->capture_dma_list) free_page ((unsigned long) dev->capture_dma_list); dev->capture_dma_list = 0; DeallocateBuffer (dev); dev->capture_buffer = NULL; dev->capture_buffer_size = 0; EXIT();}/* * * P O W E R M A N A G E M E N T * */#if 1 /* power management */static voidmx2ads_camera_suspend(void){ int i; capture_pwm.suspended = 1; for (i = 0; i < CAMIF_CHANNELS_NUM; i++) { if (capture[i].open_count || capture[i].preview) { capture_close (&capture[i]); capture[i].camif->close (i); } }}static voidmx2ads_camera_resume(void){ /* * Resume is getting called in an interrupt context and * resume requires waiting on queues etc. to power * up the camera. So we can't resume here. So we have to * use a kernel thread for resume requests (PITA). */ up(&capture_pwm.resume_wait);}#ifdef CONFIG_PMstatic struct pm_dev *mx2ads_image_pmdev;static intmx2ads_image_pm_callback(struct pm_dev *pmdev, pm_request_t rqst, void *data){ switch (rqst) { case PM_SUSPEND: mx2ads_camera_suspend(); break; case PM_RESUME: mx2ads_camera_resume(); break; } return 0;}#endif /* CONFIG_PM*/#include <linux/device.h>#include <linux/dpm.h>#ifdef CONFIG_DPMstatic struct constraints mx2cam_constraints = { .count = 1, .param = {{DPM_MD_HCLK, 0, 0}}, /*to be initialized at module init time */ .asserted = 1,};#endifextern void mx21_ldm_bus_register(struct device *device, struct device_driver *driver);extern void mx21_ldm_bus_unregister(struct device *device, struct device_driver *driver);static intmx2ads_camera_dpm_suspend(struct device *dev, u32 state, u32 level){ switch (level) { case SUSPEND_POWER_DOWN: mx2ads_camera_suspend(); break; } return 0;}static intmx2ads_camera_dpm_resume(struct device *dev, u32 level){ switch (level) { case RESUME_POWER_ON: mx2ads_camera_resume(); break; } return 0;}static struct device_driver mx2ads_camera_driver_ldm = { .name = "mx2ads-cam", .suspend = mx2ads_camera_dpm_suspend, .resume = mx2ads_camera_dpm_resume,};static struct device mx2ads_camera_device_ldm = { .name = "MX2ADS Camera", .bus_id = "camera", .driver = &mx2ads_camera_driver_ldm, .power_state = DPM_POWER_ON,#ifdef CONFIG_DPM .constraints = &mx2cam_constraints,#endif};static intresume_thread(void *data){ int i; daemonize(); reparent_to_init(); strcpy(current->comm, "camera_resume"); for (;;) { down(&capture_pwm.resume_wait); if (capture_pwm.resume_thread_exit) break; for (i = 0; i < CAMIF_CHANNELS_NUM; i++) { if (capture[i].open_count || capture[i].preview) { capture[i].camif->open(i); capture_abort (&capture[i]); capture_new_format (&capture[i]); if (capture[i].streaming) capture_stream_start (&capture[i]); else if (capture[i].preview) capture_grab_frame (&capture[i]); } } capture_pwm.suspended = 0; } complete_and_exit(&capture_pwm.resume_thread_sync, 0); return 0;}#endif /* power management *//* *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -