Note
> vendor driver 常用 api
* v4l2, media controller framework 内部使用api
~ vendor driver 不常用 api
Media Controller API
media-device.h
struct media_device_ops {
int (*link_notify)(struct media_link*link, u32 flags,
unsigned int notification);
struct media_request *(*req_alloc)(struct media_device *mdev);
void (*req_free)(struct media_request *req);
int (*req_validate)(struct media_request *req);
void (*req_queue)(struct media_request *req);
};
> media_device_init();
> media_device_cleanup();
> media_device_register();
> media_device_unregister();
* media_device_register_entity();
* media_device_unregister_entity();
~ media_device_register_entity_notify();
~ media_device_unregister_entity_notify();
* media_device_for_each_entity()
* media_device_for_each_intf()
* media_device_for_each_pad()
* media_device_for_each_link()
link_notify: 在 userspace 调用 ioctl media_device_setup_link() 后会触发 link_notify 回调。
media_device_init: 初始化 media device elements。在 media device registration 之前调用。调用顺序为 media_device_init() -> 注册 media device 内所有的 entity。
创建 pad to pad links,最后调用 media_device_register().media_device_cleanup: media_device_init 的 cleanup 函数。
media_device_register: 注册 media device。在调用 media_device_init() 之前必须要设置好 dev 和 model field。serial, bus_info, hw_revision 是可选的。media_device_unregister: 注销 media device。
media_device_register_entity: 向 media device 注册一个 entity。在注册 video device 和 subdev 的时候都会自动调用该函数注册对应的 entity。
media_device_unregister_entity: 注销 entity。
media_device_register_entity_notify: 注册 media deivce 的 entity notify,在每个 entity 注册时都会调用到该 notify 函数。目前没什么 driver 使用。
media_device_unregister_entity_notify: 注销 entity notify。
media-devnode.h
media controller device node 相关。
media-entity.h
struct media_entity_operations {
int (*get_fwnode_pad)(struct media_entity *entity,
struct fwnode_endpoint *endpoint);
int (*link_setup)(struct media_entity *entity,
const struct media_pad *local,
const struct media_pad *remote, u32 flags);
int (*link_validate)(struct media_link *link);
bool (*has_pad_interdep)(struct media_entity *entity, unsigned int pad0,
unsigned int pad1);
};
* media_entity_for_each_pad()
> is_media_entity_v4l2_video_device();
> is_media_entity_v4l2_subdev();
* media_entity_enum_init();
* media_entity_enum_cleanup();
* media_entity_enum_zero();
* media_entity_enum_set();
* media_entity_enum_clear();
* media_entity_enum_test();
* media_entity_enum_test_and_set();
* media_entity_enum_empty();
* media_entity_enum_intersects();
> media_entity_pads_init();
> media_entity_cleanup()
> media_create_pad_link();
~ media_create_pad_links();
> media_entity_remove_links();
* media_entity_setup_link();
* media_entity_find_link();
> media_pad_remote_pad_first();
> media_pad_remote_pad_unique();
> media_entity_remote_pad_unique();
> media_entity_remote_source_pad_unique()
~ media_pad_is_streaming()
~ media_entity_is_streaming()
* media_pad_pipeline();
> media_entity_get_fwnode_pad();
* media_graph_walk_init();
* media_graph_walk_cleanup();
* media_graph_walk_start();
* media_graph_walk_next();
> media_pipeline_start();
> media_pipeline_stop();
~ media_pipeline_for_each_pad();
~ media_pipeline_for_each_entity();
> video_device_pipeline_alloc_start();
* media_devnode_create();
* media_devnode_remove();
* media_create_intf_link();
* media_remove_intf_link();
* media_remove_intf_links();
* media_create_ancillary_link();
* for_each_media_entity_data_link();
link_setup: 通知 entity link 的状态改变,在 media_entity_setup_link() 中调用。
link_validate: 检查 link 是否 valid,在 media_pipeline_start() 中调用。
is_media_entity_v4l2_video_device: check entity 是否是 video device。
is_media_entity_v4l2_subdev: check entity 是否是 v4l2 subdev。
media_entity_pads_init: 初始化 entity 的 pads, 一般将 pads 数组保存在 entity driver 的 driver private data structure 中。media_entity_cleanup: cleanup entity 的 pads,在 unreigster entity 之后调用,目前是空函数。
media_create_pad_link: 在两个 entity pad 之间创建 link。需要在 media_entity_pads_init() 和 media_device_register_entity() 之后调用。media_entity_remove_links: 把一个 entity 的 links 全部移除。media_entity_setup_link: enable/disable link。会调用到 sink 和 source entity 的 .link_setup 回调。
media_pad_remote_pad_first: 返回与当前 pad 第一个相连的 remote pad,不管是 source/sink pad。media_pad_remote_pad_unique: 返回与当前 pad 单独连接的 remote pad, 如果有多个 pad 相连返回错误。media_entity_remote_pad_unique: 返回与当前 entity 单独相连指定 type 的 remote pad,如果有多个 pad 相连返回错误。。media_entity_remote_source_pad_unique: 返回与当前 entity 单独相连的 remote source pad,如果有多个 pad 相连返回错误。。
media_pad_is_streaming: 检查 pad 是否在 streaming 中,在 media_pipeline_start() 中会被置起。
media_entity_is_streaming: 检查 entity 是否在 streaming 中,在 media_pipeline_start() 中会被置起。
media_pad_pipeline: 返回 pad 属于的 pipeline,在 media_pipeline_start() 之后可以拿到。
media_entity_get_fwnode_pad:
V4L2 API
v4l2-async.h
v4l2-common.h
v4l_err()/v4l_warn()/v4l_info()/v4l_dbg(); // for v4l-i2c drivers
v4l2_err()/v4l2_warn()/v4l2_info()/v4l2_dbg(); // for v4l2_device and v4l2_subdev
v4l2-ctl.h
v4l2-dev.h
* v4l2_prio_init();
* v4l2_prio_change();
* v4l2_prio_open();
* v4l2_prio_close();
* v4l2_prio_max();
* v4l2_prio_check();
> media_entity_to_video_device();
~ to_video_device();
> video_register_device();/video_unregister_device();
* video_register_device_no_warn();
> video_device_alloc();/video_device_release();
> video_device_release_empty();
> v4l2_disable_ioctl();
> video_get_drvdata();/video_set_drvdata(); // get/set video device private data
> video_devdata(); // 获取 file 对应的 video device
> video_drvdata(); // video_get_drvdata());
> video_device_node_name(); // 获取 device name
> video_is_registered(); // 检查 video device 是否已经注册
> video_device_pipeline_start();__video_device_pipeline_start(); // 在 start streaming 中调用
> video_device_pipeline_stop();__video_device_pipeline_stop(); // 在 stop streaming 中调用
> video_device_pipeline_alloc_start(); // 多了 allocate pipeline 的操作,不过一般 pipeline 会嵌在 driver 自定义结构体中,随着上层一起分配。
* video_device_pipeline();
v4l2-device.h
v4l2_device_get();v4l2_device_put();
> v4l2_device_register();/v4l2_device_unregister();
v4l2_device_set_name();
// v4l2_device_disconnect(); // 给 usb 设备使用
> v4l2_device_register_subdev();/v4l2_device_unregister_subdev();
> v4l2_device_register_subdev_nodes(); // 注册所有 subdev 的 device node,通常在.complete 中调用
// v4l2_device_register_ro_subdev_nodes(); // 没人用
v4l2_subdev_notify(); // subdev 通知 v4l2 device
// v4l2_device_supports_requests(); // 内部使用
// v4l2_device_for_each_subdev(); // 遍历所有的 subdev, 只有 pci 和 usb 设备调用
// v4l2_device_call_all(); // 只有 pci 和 usb 设备使用
> v4l2_device_call_until_err(); // call 某个 group id 中所有 subdev 的某个 op, 直到发生错误
// v4l2_device_mask_call_all();/v4l2_device_mask_call_until_err(); // 没人用
// v4l2_device_has_op();/v4l2_device_mask_has_op() // 没人用
v4l2-event.h
v4l2-fh.h
v4l2_fh_init();/v4l2_fh_exit();
v4l2_fh_add();/v4l2_fh_del();
v4l2_fh_open();/v4l2_fh_release():
v4l2_fh_is_singular();
v4l2_fh_is_singular_file();
v4l2-fwnode.h
v4l2_fwnode_endpoint_parse();
v4l2-mc.h
~ v4l2_mc_create_media_graph(); // pci 和 usb 设备使用
~ v4l_enable_media_source();/v4l_disable_media_source();/v4l_vb2q_enable_media_source();
> v4l2_create_fwnode_links_to_pad();
~ v4l2_create_fwnode_links();
~ v4l2_pipeline_pm_get();v4l2_pipeline_pm_put(); // linux-6.17 中已经被废弃
~ v4l2_pipeline_link_notify(); // linux-6.17 中已经被废弃
v4l2_create_fwnode_links_to_pad: 这个函数搜索 fwnode endpoint connections 从 source subdev 到 single sink pad.
在 sink device 的 v4l2-async notifier bound callback 中调用,来创建 link 从 source subdev 到 sink pad. 如果要使用这个函数,必须实现 .get_fwnode_pad media operation
v4l2_create_fwnode_links: 这个函数搜索 fwnode endpoint connections 在 source subdev 和 sink subdev 之间,把他们转化为 media link.
在 sink device 的 v4l2-async notifier bound callback 中调用。如果要使用这个函数,必须实现 .get_fwnode_pad media operation
v4l2-mediabus.h
v4l2_fill_pix_format();
v4l2_fill_mbus_format();
v4l2_fill_pix_format_mplane();
v4l2_fill_mbus_format_mplane();
v4l2-mem2mem.h
> v4l2_m2m_get_curr_priv(); // 返回当前 running instance 的 driver private data
> v4l2_m2m_get_vq(); //
// v4l2_m2m_try_schedule();
> v4l2_m2m_job_finish(); // 当前 instance 完成任务后需要调用,把 device 释放出来。需要在.device_run 之后调用
// v4l2_m2m_buf_done_and_job_finish(); // 给 stateless encoder 使用
> v4l2_m2m_buf_done();
// v4l2_m2m_clear_state(); // clear encoding/decoding state
// v4l2_m2m_mark_stopped(); // set current encoding/decodfing as stopped
// v4l2_m2m_dst_buf_is_last(); // encoding/decoding session draining management state
// v4l2_m2m_has_stopped();
// v4l2_m2m_is_last_draining_src_buf();
// v4l2_m2m_last_buffer_done();
> v4l2_m2m_suspend();/v4l2_m2m_resume();
// 不使用 ioctl helpers 的话 vendor driver 可以自己包装下面一系列函数
v4l2_m2m_reqbufs();
v4l2_m2m_querybuf();
v4l2_m2m_qbuf();/v4l2_m2m_dqbuf();
v4l2_m2m_prepare_buf();
v4l2_m2m_create_bufs();
v4l2_m2m_expbuf();
v4l2_m2m_streamon();v4l2_m2m_streamoff();
v4l2_m2m_poll();
v4l2_m2m_mmap();
// v4l2_m2m_update_start_streaming_state();/v4l2_m2m_update_stop_streaming_state(); // encoder/decoder
// v4l2_m2m_encoder_cmd();
// v4l2_m2m_decoder_cmd();
> v4l2_m2m_init();/v4l2_m2m_release(); // 分配/释放 struct v4l2_m2m_dev, 通常在 probe()/remove() 中调用
> v4l2_m2m_register_media_controller();/v4l2_m2m_unregister_media_controller(); // 注册/注销 media controller
> v4l2_m2m_ctx_init();/v4l2_m2m_ctx_release(); // 分配 m2m ctx, 通常在 open()/release() 中调用
// v4l2_m2m_set_src_buffered();/v4l2_m2m_set_dst_buffered(); // 没人用
> v4l2_m2m_buf_queue(); // 把 buffer 加入到 buffer list
v4l2_m2m_num_src_bufs_ready();/v4l2_m2m_num_dst_bufs_ready(); // 返回 src/dst 中 ready buf 的数量
> v4l2_m2m_next_src_buf();/v4l2_m2m_next_dst_buf(); // 拿下一个 src/dst ready buf
// v4l2_m2m_last_src_buf();v4l2_m2m_last_dst_buf(); // encoder/decoder 用的
v4l2_m2m_for_each_src_buf();v4l2_m2m_for_each_dst_buf(); // 遍历 src/dst ready bufs
v4l2_m2m_for_each_src_buf_safe();/v4l2_m2m_for_each_dst_buf_safe(); // 和上面差不多
v4l2_m2m_get_src_vq();/v4l2_m2m_get_dst_vq(); // 获取 src/dst vb2_queue
> v4l2_m2m_src_buf_remove();v4l2_m2m_dst_buf_remove(); // 从 src/dst buf list 中 remove 一个 buf
v4l2_m2m_src_buf_remove_by_buf();v4l2_m2m_dst_buf_remove_by_buf(); // remove 某个特定的 buf
// v4l2_m2m_src_buf_remove_by_idx();v4l2_m2m_dst_buf_remove_by_idx(); // 没人用
> v4l2_m2m_buf_copy_metadata(); // copy metadata from output buffer to capture buffer
v4l2_m2m_request_queue(); // request api 相关
// ioctl helpers
v4l2_m2m_ioctl_reqbufs();
v4l2_m2m_ioctl_create_bufs();
v4l2_m2m_ioctl_querybuf();
v4l2_m2m_ioctl_expbuf();
v4l2_m2m_ioctl_qbuf();
v4l2_m2m_ioctl_dqbuf();
v4l2_m2m_ioctl_prepare_buf();
v4l2_m2m_ioctl_streamon();
v4l2_m2m_ioctl_streamoff();
// v4l2_m2m_ioctl_encoder_cmd();
// v4l2_m2m_ioctl_decoder_cmd();
// v4l2_m2m_ioctl_try_encoder_cmd();
// v4l2_m2m_ioctl_try_decoder_cmd();
// v4l2_m2m_ioctl_stateless_try_decoder_cmd();
// v4l2_m2m_ioctl_stateless_decoder_cmd();
v4l2_m2m_fop_mmap();
v4l2_m2m_fop_poll();
v4l2-subdev.h
> media_entity_to_v4l2_subdev();
* vdev_to_v4l2_subdev();
* to_v4l2_subdev_fh();
> v4l2_subdev_get_pad_format();
> v4l2_subdev_get_pad_crop();
> v4l2_subdev_get_pad_compose();
> v4l2_set_subdevdata();v4l2_get_subdevdata();
~ v4l2_set_subdev_hostdata();v4l2_get_subdev_hostdata();
~ v4l2_subdev_get_fwnode_pad_1_to_1();
> v4l2_subdev_link_validate_default();
> v4l2_subdev_link_validate();
~ v4l2_subdev_has_pad_interdep();
> v4l2_subdev_init_finalize();
> v4l2_subdev_cleanup();
* v4l2_subdev_lock_state();/v4l2_subdev_unlock_state();
* v4l2_subdev_get_unlocked_active_state();
> v4l2_subdev_get_locked_active_state();
> v4l2_subdev_lock_and_get_active_state();
> v4l2_subdev_get_fmt();
~ v4l2_subdev_set_routing();
~ for_each_active_route();
~ v4l2_subdev_set_routing_with_fmt();
~ v4l2_subdev_state_get_stream_format();
~ v4l2_subdev_state_get_stream_crop();
~ v4l2_subdev_state_get_stream_compose();
~ v4l2_subdev_routing_find_opposite_end();
~ v4l2_subdev_state_get_opposite_stream_format();
~ v4l2_subdev_state_xlate_streams();
~ v4l2_subdev_routing_validate();
~ v4l2_subdev_enable_streams();/v4l2_subdev_disable_streams();
~ v4l2_subdev_s_stream_helper();
> v4l2_subdev_init();
> v4l2_subdev_call();
~ v4l2_subdev_notify_event();
v4l2_subdev_link_validate_default: v4l2_subdev_link_validate:
v4l2_subdev_init_finalize: v4l2_subdev_cleanup:
v4l2_subdev_get_locked_active_state: v4l2_subdev_lock_and_get_active_state:
v4l2_subdev_get_pad_format:
v4l2_subdev_get_pad_crop:
v4l2_subdev_get_pad_compose:
v4l2_subdev_get_fmt: 通用的 v4l2_subdev_pad_ops.get_fmt() 回调