?? mx27_v4l2_capture.c
字號(hào):
*/ case VIDIOC_S_FBUF:{ struct v4l2_framebuffer *fb = arg; cam->v4l2_fb.flags = fb->flags; cam->v4l2_fb.fmt.pixelformat = fb->fmt.pixelformat; break; } case VIDIOC_G_PARM:{ struct v4l2_streamparm *parm = arg; if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { pr_debug("VIDIOC_G_PARM invalid type\n"); retval = -EINVAL; break; } parm->parm.capture = cam->streamparm.parm.capture; break; } case VIDIOC_S_PARM:{ struct v4l2_streamparm *parm = arg; retval = mxc_v4l2_s_param(cam, parm); break; } /* linux v4l2 bug, kernel c0485619 user c0405619 */ case VIDIOC_ENUMSTD:{ struct v4l2_standard *e = arg; *e = cam->standard; pr_debug("VIDIOC_ENUMSTD call\n"); retval = 0; break; } case VIDIOC_G_STD:{ v4l2_std_id *e = arg; *e = cam->standard.id; break; } case VIDIOC_S_STD:{ break; } case VIDIOC_ENUMOUTPUT: { struct v4l2_output *output = arg; if (output->index >= num_registered_fb) { retval = -EINVAL; break; } strncpy(output->name, registered_fb[output->index]->fix.id, 31); output->type = V4L2_OUTPUT_TYPE_ANALOG; output->audioset = 0; output->modulator = 0; output->std = V4L2_STD_UNKNOWN; break; } case VIDIOC_G_OUTPUT: { int *p_output_num = arg; *p_output_num = cam->output; break; } case VIDIOC_S_OUTPUT: { int *p_output_num = arg; if (*p_output_num >= num_registered_fb) { retval = -EINVAL; break; } cam->output = *p_output_num; break; } case VIDIOC_G_INPUT: { int *p_input_index = arg; retval = mxc_get_video_input(cam); if (0 == retval) *p_input_index = 1; else *p_input_index = -ENODEV; break; } case VIDIOC_ENUM_FMT: case VIDIOC_TRY_FMT: case VIDIOC_QUERYCTRL: case VIDIOC_ENUMINPUT: case VIDIOC_S_INPUT: case VIDIOC_G_TUNER: case VIDIOC_S_TUNER: case VIDIOC_G_FREQUENCY: case VIDIOC_S_FREQUENCY: default: retval = -EINVAL; break; } up(&cam->busy_lock); return retval;}/* * V4L interface - ioctl function * * @return None */static intmxc_v4l_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return video_usercopy(inode, file, cmd, arg, mxc_v4l_do_ioctl);}/*! * V4L interface - mmap function * * @param file structure file * * * @param vma structure vm_area_struct * * * @return status 0 Success, EINTR busy lock error, ENOBUFS remap_page error */static int mxc_mmap(struct file *file, struct vm_area_struct *vma){ struct video_device *dev = video_devdata(file); unsigned long size; int res = 0; cam_data *cam = dev->priv; pr_debug("pgoff=0x%lx, start=0x%lx, end=0x%lx\n", vma->vm_pgoff, vma->vm_start, vma->vm_end); /* make this _really_ smp-safe */ if (down_interruptible(&cam->busy_lock)) return -EINTR; size = vma->vm_end - vma->vm_start; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, size, vma->vm_page_prot)) { pr_debug("mxc_mmap: remap_pfn_range failed\n"); res = -ENOBUFS; goto mxc_mmap_exit; } vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ mxc_mmap_exit: up(&cam->busy_lock); return res;}/*! * V4L interface - poll function * * @param file structure file * * * @param wait structure poll_table * * * @return status POLLIN | POLLRDNORM */static unsigned int mxc_poll(struct file *file, poll_table * wait){ struct video_device *dev = video_devdata(file); cam_data *cam = dev->priv; wait_queue_head_t *queue = NULL; int res = POLLIN | POLLRDNORM; if (down_interruptible(&cam->busy_lock)) return -EINTR; queue = &cam->enc_queue; poll_wait(file, queue, wait); up(&cam->busy_lock); return res;}static structfile_operations mxc_v4l_fops = { .owner = THIS_MODULE, .open = mxc_v4l_open, .release = mxc_v4l_close, .read = mxc_v4l_read, .ioctl = mxc_v4l_ioctl, .mmap = mxc_mmap, .poll = mxc_poll,};static struct video_device mxc_v4l_template = { .owner = THIS_MODULE, .name = "Mxc Camera", .type = 0, .type2 = VID_TYPE_CAPTURE, .hardware = 0, .fops = &mxc_v4l_fops, .release = video_device_release,};static void camera_platform_release(struct device *device){}/*! Device Definition for Mt9v111 devices */static struct platform_device mxc_v4l2_devices = { .name = "mxc_v4l2", .dev = { .release = camera_platform_release, }, .id = 0,};extern struct camera_sensor camera_sensor_if;/*!* Camera V4l2 callback function.** @return status*/static void camera_callback(u32 mask, void *dev){ struct mxc_v4l_frame *done_frame; struct mxc_v4l_frame *ready_frame; cam_data *cam = (cam_data *) dev; if (cam == NULL) return; if (mask == 1) { cam->overflow = 1; } if (list_empty(&cam->working_q)) { if (empty_wq_cnt == 0) { printk(KERN_ERR "camera_callback: working queue empty %d\n", empty_wq_cnt); } empty_wq_cnt++; if (list_empty(&cam->ready_q)) { cam->skip_frame++; } else { ready_frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); list_del(cam->ready_q.next); list_add_tail(&ready_frame->queue, &cam->working_q); cam->enc_update_eba(ready_frame->paddress, &cam->ping_pong_csi); } return; } done_frame = list_entry(cam->working_q.next, struct mxc_v4l_frame, queue); if (done_frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) { done_frame->buffer.flags |= V4L2_BUF_FLAG_DONE; done_frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; if (list_empty(&cam->ready_q)) { cam->skip_frame++; } else { ready_frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); list_del(cam->ready_q.next); list_add_tail(&ready_frame->queue, &cam->working_q); cam->enc_update_eba(ready_frame->paddress, &cam->ping_pong_csi); } /* Added to the done queue */ list_del(cam->working_q.next); list_add_tail(&done_frame->queue, &cam->done_q); /* Wake up the queue */ cam->enc_counter++; wake_up_interruptible(&cam->enc_queue); } else { printk(KERN_ERR "camera_callback :buffer not queued\n"); }}/*! * initialize cam_data structure * * @param cam structure cam_data * * * @return status 0 Success */static void init_camera_struct(cam_data * cam){ int i; /* Default everything to 0 */ memset(cam, 0, sizeof(cam_data)); init_MUTEX(&cam->param_lock); init_MUTEX(&cam->busy_lock); cam->video_dev = video_device_alloc(); if (cam->video_dev == NULL) return; *(cam->video_dev) = mxc_v4l_template; video_set_drvdata(cam->video_dev, cam); dev_set_drvdata(&mxc_v4l2_devices.dev, (void *)cam); cam->video_dev->minor = -1; for (i = 0; i < FRAME_NUM; i++) { cam->frame[i].width = 0; cam->frame[i].height = 0; cam->frame[i].paddress = 0; } init_waitqueue_head(&cam->enc_queue); init_waitqueue_head(&cam->still_queue); /* setup cropping */ cam->crop_bounds.left = 0; cam->crop_bounds.width = 800; cam->crop_bounds.top = 0; cam->crop_bounds.height = 600; cam->crop_current = cam->crop_defrect = cam->crop_bounds; cam->streamparm.parm.capture.capturemode = 0; cam->standard.index = 0; cam->standard.id = V4L2_STD_UNKNOWN; cam->standard.frameperiod.denominator = 30; cam->standard.frameperiod.numerator = 1; cam->standard.framelines = 600; cam->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; cam->streamparm.parm.capture.timeperframe = cam->standard.frameperiod; cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME; cam->overlay_on = false; cam->capture_on = false; cam->skip_frame = 0; cam->v4l2_fb.capability = V4L2_FBUF_CAP_EXTERNOVERLAY; cam->v4l2_fb.flags = V4L2_FBUF_FLAG_PRIMARY; cam->v2f.fmt.pix.sizeimage = 352 * 288 * 3 / 2; cam->v2f.fmt.pix.bytesperline = 288 * 3 / 2; cam->v2f.fmt.pix.width = 288; cam->v2f.fmt.pix.height = 352; cam->v2f.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; cam->win.w.width = 160; cam->win.w.height = 160; cam->win.w.left = 0; cam->win.w.top = 0; cam->cam_sensor = &camera_sensor_if; cam->enc_callback = camera_callback; init_waitqueue_head(&cam->power_queue); cam->int_lock = SPIN_LOCK_UNLOCKED; spin_lock_init(&cam->int_lock);}extern void gpio_sensor_active(void);extern void gpio_sensor_inactive(void);/*! * camera_power function * Turn Sensor power On/Off * * @param cameraOn true to turn camera on, otherwise shut down * * @return status */static u8 camera_power(bool cameraOn){ if (cameraOn == true) { gpio_sensor_active(); csi_enable_mclk(csi_mclk_flag_backup, true, true); } else { csi_mclk_flag_backup = csi_read_mclk_flag(); csi_enable_mclk(csi_mclk_flag_backup, false, false); gpio_sensor_inactive(); } return 0;}/*! * This function is called to put the sensor in a low power state. Refer to the * document driver-model/driver.txt in the kernel source tree for more * information. * * @param pdev the device structure used to give information on which I2C * to suspend * @param state the power state the device is entering * * @return The function returns 0 on success and -1 on failure. */static int mxc_v4l2_suspend(struct platform_device *pdev, pm_message_t state){ cam_data *cam = platform_get_drvdata(pdev); if (cam == NULL) { return -1; } cam->low_power = true; if (cam->overlay_on == true) stop_preview(cam); if ((cam->capture_on == true) && cam->enc_disable) { cam->enc_disable(cam); } camera_power(false); return 0;}/*! * This function is called to bring the sensor back from a low power state.Refer * to the document driver-model/driver.txt in the kernel source tree for more * information. * * @param pdev the device structure * * @return The function returns 0 on success and -1 on failure */static int mxc_v4l2_resume(struct platform_device *pdev){ cam_data *cam = platform_get_drvdata(pdev); if (cam == NULL) { return -1; } cam->low_power = false; wake_up_interruptible(&cam->power_queue); if (cam->overlay_on == true) start_preview(cam); if (cam->capture_on == true) mxc_streamon(cam); camera_power(true); return 0;}/*! * This structure contains pointers to the power management callback functions. */static struct platform_driver mxc_v4l2_driver = { .driver = { .name = "mxc_v4l2", .owner = THIS_MODULE, .bus = &platform_bus_type, }, .probe = NULL, .remove = NULL, .suspend = mxc_v4l2_suspend, .resume = mxc_v4l2_resume, .shutdown = NULL,};/*! * Entry point for the V4L2 * * @return Error code indicating success or failure */static __init int camera_init(void){ u8 err = 0; cam_data *cam; if ((g_cam = cam = kmalloc(sizeof(cam_data), GFP_KERNEL)) == NULL) { pr_debug("failed to mxc_v4l_register_camera\n"); return -1; } init_camera_struct(cam); /* Register the I2C device */ err = platform_device_register(&mxc_v4l2_devices); if (err != 0) { pr_debug("camera_init: platform_device_register failed.\n"); video_device_release(cam->video_dev); kfree(cam); g_cam = NULL; } /* Register the device driver structure. */ err = platform_driver_register(&mxc_v4l2_driver); if (err != 0) { platform_device_unregister(&mxc_v4l2_devices); pr_debug("camera_init: driver_register failed.\n"); video_device_release(cam->video_dev); kfree(cam); g_cam = NULL; return err; } /* register v4l device */ if (video_register_device(cam->video_dev, VFL_TYPE_GRABBER, video_nr) == -1) { platform_driver_unregister(&mxc_v4l2_driver); platform_device_unregister(&mxc_v4l2_devices); video_device_release(cam->video_dev); kfree(cam); g_cam = NULL; pr_debug("video_register_device failed\n"); return -1; } return err;}/*! * Exit and cleanup for the V4L2 * */static void __exit camera_exit(void){ pr_debug("unregistering video\n"); video_unregister_device(g_cam->video_dev); platform_driver_unregister(&mxc_v4l2_driver); platform_device_unregister(&mxc_v4l2_devices); if (g_cam->open_count) { pr_debug("camera open -- setting ops to NULL\n"); } else { pr_debug("freeing camera\n"); mxc_free_frame_buf(g_cam); kfree(g_cam); g_cam = NULL; }}module_init(camera_init);module_exit(camera_exit);module_param(video_nr, int, -1);MODULE_AUTHOR("Freescale Semiconductor, Inc.");MODULE_DESCRIPTION("V4L2 capture driver for Mxc based cameras");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("video");
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -