logo资料库

TI OMAP3 ISP驱动整体框架、流程整理分析.docx

第1页 / 共5页
第2页 / 共5页
第3页 / 共5页
第4页 / 共5页
第5页 / 共5页
资料共5页,全文预览结束
isp_probe isp_initialize_modules ret = omap3isp_csiphy_init(isp); ret = omap3isp_csi2_init(isp); ret = csi2_init_entities(csi2a); ret = omap3isp_video_init(&csi2->video_out, "CSI2a"); ret = omap3isp_ccp2_init(isp); ret = ccp2_init_entities(ccp2); ret = omap3isp_video_init(&ccp2->video_in, "CCP2"); ret = omap3isp_ccdc_init(isp); ret = ccdc_init_entities(ccdc); ret = omap3isp_video_init(&ccdc->video_out, "CCDC"); ret = omap3isp_preview_init(isp); return preview_init_entities(prev); ret = omap3isp_video_init(&prev->video_in, "preview"); ret = omap3isp_video_init(&prev->video_out, "preview"); ret = omap3isp_resizer_init(isp); return resizer_init_entities(res); ret = omap3isp_video_init(&res->video_in, "resizer"); ret omap3isp_video_init(&res->video_out, = "resizer"); //csi2a,ccp2,ccdc,preview,resizer 子设备有向上层开放操作接口(video_device) ret = omap3isp_hist_init(isp); ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops); ret = omap3isp_h3a_aewb_init(isp); return omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops); ret = omap3isp_h3a_af_init(isp); return omap3isp_stat_init(af, //hist,aewb,af 子设备不需要向上层开放操作接口 "AF", &h3a_af_subdev_ops); omap3isp_video_init(struct isp_video *video, const char *name)// 初 始 化 video_device(ispvideo.c) video->video.fops = &isp_video_fops; video->video.vfl_type = VFL_TYPE_GRABBER; video->video.release = video_device_release_empty; video->video.ioctl_ops = &isp_video_ioctl_ops; video->pipe.stream_state = ISP_PIPELINE_STREAM_STOPPED; video_set_drvdata(&video->video, video); omap3isp_video_register csi2a,ccp2,ccdc,preview,resizer ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1); 共 # video_device.fops,video_device.ioctl_ops( 不 同 ),vb2_queue.ops,vb2_queue.mem_ops, 需 要 各 自 实 现 的 是 不 同 的 底 层 硬 件 操 作 v4l2_subdev_ops # preview,resizer 的输入和输出都有上层应用参与处理,所以一个 v4l2_subdev 同时对应 2 个 video_device(2 个不同的设备节点). 子 备 备 只 是 节 点 设 设 用
# 一个 v4l2_subdev 可能没有对应的 video_device,也可能对应不止一个 video_device(挂接在 OMAP ISP 上的外部 sensor 没有实现对应的 video_device) # v4l2_subdev_ops 绑 定 给 v4l2_subdev 由 v4l2_subdev_init 负 责 完 成.v4l2_subdev_call(sd, o, f, args...)用于调用 v4l2_subdev_ops 某函数集中的指定函数 # 为 vb2_queue 绑定 ops 和 mem_ops 函数集,一般在 open 函数中进行.call_ptr_memop(vb, op, args...)用于调用 vb2_queue.mem_ops 里的指定函数. # 上 层 的 调 用 动 作 (fops,ioctl_ops) 最 终 会 落 实 到 3 处 : v4l2_subdev_ops( 针 对 硬 件 ), vb2_queue.ops( 针 对 缓 冲 区 队 列 , 按 需 实 现 ), vb2_queue.mem_ops( 针 对 缓 冲 区 , 使 用 如 videobuf2-dma-contig.c 中的实现) # ISP 各组件共享同一条中断线,中断处理函数通过读取中断状态寄存器来判断中断源. # ISP 内部带有硬件缓冲区,数据在各组件处理期间不需要内存参与,驱动申请的缓冲区用于存储 ISP 处 理后的数据,对应下图中的 4(raw data to YUV4:2:2),3(resize)或者 C(raw data),当有数据存 入驱动维护的缓冲区后,应用层就可取出里面的数据做后续处理(软件转码等) RAW data are processed through the CCDC module and are directly pipelined to the preview engine. Another way is to output directly from the CCDC to memory (C) In the preview block; the format is converted from RAW data to YUV4:2:2 (1). The data can be output to memory (4) or pipelined to the resizer (2). The rescaled YUV4:2:2 image is finally stored in memory (3). In parallel, processed data in the CCDC are used by the H3A module (A), which writes tables of statistics in memory, and by the HIST module (B). The results of the HIST modules are stored in status registers in the HIST module.
static struct v4l2_file_operations isp_video_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, .open = isp_video_open, .release = isp_video_release, .poll = isp_video_poll, .mmap = isp_video_mmap, }; isp_video_open struct isp_video_fh *handle; struct vb2_queue *queue; handle = kzalloc(sizeof(*handle), GFP_KERNEL); v4l2_fh_init(&handle->vfh, &video->video); // 初 始 化 v4l2_fh, 并 把 video_device 的 *ctrl_handler 绑 定 给 v4l2_fh 的 *ctrl_handler(fh->ctrl_handler = vdev->ctrl_handler;) v4l2_fh_add(&handle->vfh); //将 v4l2_fh 链接到 video_device 的 fh_list 链表 queue = &handle->queue; queue->type = video->type; queue->io_modes = VB2_MMAP | VB2_USERPTR; queue->drv_priv = handle; queue->ops = &isp_video_queue_ops; //管理缓冲区队列的函数集 queue->mem_ops = &vb2_dma_contig_memops; // 操 作 缓 冲 区 的 函 数 集,vb2_dma_contig_memops 定义在 videobuf2-dma-contig.c queue->buf_struct_size = sizeof(struct isp_buffer); queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(&handle->queue); //初始化缓冲区队列 memset(&handle->format, 0, sizeof(handle->format)); handle->format.type = video->type; handle->timeperframe.denominator = 1; handle->video = video; file->private_data = &handle->vfh; //v4l2_fh 作为 file->private_data isp_video_reqbufs ret = vb2_reqbufs(&vfh->queue, rb); return ret ? ret : vb2_core_reqbufs(q, req->memory, &req->count); /* Finally, allocate buffers and video memory */ allocated_buffers __vb2_queue_alloc(q, = memory, num_buffers, num_planes, plane_sizes); /* Allocate video buffer memory for the MMAP type */ if (memory == VB2_MEMORY_MMAP) { ret = __vb2_buf_mem_alloc(vb); mem_priv = call_ptr_memop(vb, alloc,
q->alloc_ctx[plane], size, dma_dir, q->gfp_flags); 有 ”queue->mem_ops vb2_dma_contig_memops 里的 vb2_dc_alloc = vb2_dc_alloc 中 &vb2_dma_contig_memops”, 所 以 这 里 调 用 的 是 //ispvideo.c:isp_video_open __setup_offsets(vb); /* * Call the driver-provided buffer initialization * callback, if given. An error in initialization * results in queue setup failure. */ ret = call_vb_qop(vb, buf_init, vb); // 调 用 由 驱 动 实 现 的 vb2_ops.buf_init(ispvideo.c:isp_video_queue_ops 没有实现 buf_init) } isp_video_qbuf ret = vb2_qbuf(&vfh->queue, b); return vb2_internal_qbuf(q, b); return ret ? ret : vb2_core_qbuf(q, b->index, b); ret = __buf_prepare(vb, pb); et = __qbuf_mmap(vb, pb); return ret ? ret : call_vb_qop(vb, buf_prepare, vb); vb2_ops.buf_prepare(ispvideo.c:isp_video_buffer_prepare) isp_video_buffer_prepare // 调 用 由 驱 动 实 现 的 /* * Add to the queued buffers list, a buffer will stay on it until * dequeued in dqbuf. */ list_add_tail(&vb->queued_entry, &q->queued_list); // 把 vb2_buffer 放入 vb2_queue 尾部 /* * If already streaming, give the buffer to driver for processing. * If not, the buffer will be given to driver on next streamon. */ if (q->start_streaming_called) __enqueue_in_driver(vb); call_void_vb_qop(vb, buf_queue, vb); //调用由驱动实现 的 vb2_ops.buf_queue(ispvideo.c) isp_video_buffer_queue /* * If streamon has been called, and we haven't yet called * start_streaming() since not enough buffers were queued, and * we now have reached the minimum number of queued buffers, * then we can finally call start_streaming(). */ if !q->start_streaming_called (q->streaming && &&
q->queued_count >= q->min_buffers_needed) ret = vb2_start_streaming(q); /* * If any buffers were queued before streamon, * we can now pass them to driver for processing. */ list_for_each_entry(vb, &q->queued_list, queued_entry) __enqueue_in_driver(vb); call_void_vb_qop(vb, buf_queue, vb); // 调 用 由驱动实现的 vb2_ops.buf_queue isp_video_buffer_queue q, atomic_read(&q->owned_by_drv_count)); // 调 用 由 驱 动 实 现 的 vb2_ops.start_streaming start_streaming, call_qop(q, ret = isp_video_start_streaming
分享到:
收藏