V4L2 -- Event

2.14 V4L2 events V4L2 events 提供了一种方法给 userspace 传递 events. struct v4l2_subscribed_event { struct list_head list; u32 type; u32 id; u32 flags; struct v4l2_fh *fh; struct list_head node; const struct v4l2_subscribed_event_ops *ops; unsigned int elems; unsigned int first; unsigned int in_use; struct v4l2_kevent events[] __counted_by(elems); }; list: 加入到 v4l2_fh->subscribed list 的链表节点。 type: event type, 在 videodev2.h 中定义。 id: event 的 control id, 根据 event 的 (type, id) 二元组就能找到对应的 event. flags: 从 userspace 传入的 v4l2_event_subscription->flags 中拷贝过来。...

2025-06-19 · 1 min

V4L2 -- Subdev

2.7 V4L2 sub-devices 许多 drivers 需要和 sub-devices 交流,这些子设备可以处理 audio, video muxing, encoding, decoding 等等。 对于 webcams, 常见的 sub-devices 有 sensors, camera controllers. 通过 v4l2_subdev_init(sd, &ops) 来初始化 v4l2_subdev. 接着需要设置 sd->name. 如果需要和 media framework 聚合,那么需要初始化 media_entity 成员,如果 entity 有 pads 还需要调用media_entity_pads_init. struct v4l2_subdev { #if defined(CONFIG_MEDIA_CONTROLLER) struct media_entity entity; #endif struct list_head list; struct module *owner; bool owner_v4l2_dev; u32 flags; struct v4l2_device *v4l2_dev; const struct v4l2_subdev_ops *ops; const struct v4l2_subdev_internal_ops *internal_ops; struct v4l2_ctrl_handler *ctrl_handler; char name[52]; u32 grp_id; void *dev_priv; void *host_priv; struct video_device *devnode; struct device *dev; struct fwnode_handle *fwnode; struct list_head async_list; struct list_head async_subdev_endpoint_list; struct v4l2_async_notifier *subdev_notifier; struct list_head asc_list; struct v4l2_subdev_platform_data *pdata; struct mutex *state_lock; struct led_classdev *privacy_led; struct v4l2_subdev_state *active_state; u64 enabled_streams; }; owner_v4l2_dev: 如果和 v4l2_dev->dev 的 owner 一致,则为 true....

2025-06-19 · 7 min

V4L2 -- File Handler

2.6 V4L2 File handlers struct v4l2_fh 提供了一种方式,使得 file 方便地处理 V4L2 中的一些 specific data. 初始化:v4l2_fh_init(), 必须在 driver 的 v4l2_file_operations->open() 回调中调用, 会置起 video_device 的 V4L2_FL_USES_V4L2_FH flag. 在 userspace open device node 后,调用到 v4l2_fh_open, 会把 file->private_data 设置为 fh. 许多情况下 v4l2_fh 都会嵌入在更大的结构体中,这时需要调用 v4l2_fh_init() 和 v4l2_fh_add 在.open() 回调 v4l2_fh_del() 和 v4l2_fh_exit() 在.release() 回调 struct v4l2_fh { struct list_head list; struct video_device *vdev; struct v4l2_ctrl_handler *ctrl_handler; enum v4l2_priority prio; wait_queue_head_t wait; struct mutex subscribe_lock; struct list_head subscribed; struct list_head available; unsigned int navailable; u32 sequence; struct v4l2_m2m_ctx *m2m_ctx; }; list: 链接到 video_device 的 fh_list....

2025-06-19 · 1 min

V4L2 -- V4L2 Device

2.5 V4L2 device v4l2 用来抽象最顶层的 v4l2 设备,包含一系列子设备。 通过v4l2_device_register(dev, v4l2_dev)注册。 还需要设置好 v4l2->mdev 为 media_device 结构体。 在调用 v4l2_device_register 之前如果没有设置 v4l2_device->name,那么会自动分配。 还可以提供一个 notify 回调,给 subdev 向 v4l2_device 发送 event,events 定义在v4l2-subdev.h,官方文档里写只能使用 v4l2-subdev.h 中定义的 event,但看到有的 driver 自定义了一些 event。 通过v4l2_device_unregister()注销,如果是 hotpluggable 设备,在此之前还需要调用v4l2_device_disconnect() v4l2-device.h: Data Structure and APIs struct v4l2_device { struct device *dev; struct media_device *mdev; struct list_head subdevs; spinlock_t lock; char name[36]; void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg); struct v4l2_ctrl_handler *ctrl_handler; struct v4l2_prio_state prio; struct kref ref; void (*release)(struct v4l2_device *v4l2_dev); }; dev: 底层 device 设备。...

2025-06-19 · 2 min

V4L2 -- Video Device

Introduction linux/samples/v4l/v4l2-pci-skeleton.c 有一个 driver 模板。 2.2 Structure of a V4L driver device instances | +-sub-device instances | \-V4L2 device nodes | \-filehandle instances 2.3 Structure of the V4L2 framework v4l2 framework 中分别使用以下几个结构体来依次代表上面的结构: struct v4l2_device struct v4l2_subdev struct video_device struct v4l2_fh 2.4 Video device video device 用于抽象系统注册的 v4l2 /dev 设备节点,以便用户空间可以进行交互。 可以通过 video_device_alloc() 分配,也可以嵌入在更大的结构体中,这样则需要自定义 release 函数。 如果是嵌入在更大的结构体中,并且没有要释放的资源,可以使用 video_device_release_empty()。 最后通过 video_register_device() 注册。 struct video_device 其中一些 fields 需要我们手动去初始化,包括: fops, device_caps, queue, ioctl_ops, lock, prio....

2025-06-19 · 4 min

DMA Buf

Data Structure struct dma_buf { size_t size; struct file *file; struct list_head attachments; const struct dma_buf_ops *ops; unsigned vmapping_counter; struct iosys_map vmap_ptr; const char *exp_name; const char *name; spinlock_t name_lock; struct module *owner; void *priv; struct dma_resv *resv; wait_queue_head_t poll; struct dma_buf_poll_cb_t { struct dma_fence_cb cb; wait_queue_head_t *poll; __poll_t active; } cb_in, cb_out; #endif } struct dma_buf_ops { bool cache_sgt_mapping; int (*attach)(struct dma_buf *, struct dma_buf_attachment *); void (*detach)(struct dma_buf *, struct dma_buf_attachment *); int (*pin)(struct dma_buf_attachment *attach); void (*unpin)(struct dma_buf_attachment *attach); struct sg_table * (*map_dma_buf)(struct dma_buf_attachment *, enum dma_data_direction); void (*unmap_dma_buf)(struct dma_buf_attachment *, struct sg_table *, enum dma_data_direction); void (*release)(struct dma_buf *); int (*begin_cpu_access)(struct dma_buf *, enum dma_data_direction); int (*end_cpu_access)(struct dma_buf *, enum dma_data_direction); int (*mmap)(struct dma_buf *, struct vm_area_struct *vma); int (*vmap)(struct dma_buf *dmabuf, struct iosys_map *map); void (*vunmap)(struct dma_buf *dmabuf, struct iosys_map *map); }; cache_sgt_mapping, ....

2025-04-24 · 3 min

DRM(1) -- DRM internals

DRM Internals Driver Initialization driver 首先需要静态初始化一个 struct drm_driver 结构体,然后调用 drm_dev_alloc() 来 创建一个 struct drm_device 结构体,初始化必要的 fields 后,最后调用 drm_dev_register() 注册 drm_device. Driver Information 在 struct drm_driver 结构体中的.major, .minor, .patchlevel, .name, .desc .date 字段用于描述 driver 的基本信息。 通过 DRM_IOCTL_VERSION 和 DRM_IOCTL_SET_VERSION 两个 ioctl 可以获取和设置 driver 基本信息。 Module Initialization 在 drm_module.h 中提供了一些封装的 api 来注册 module platform/pci driver: drm_module_pci_driver(__pci_drv); drm_module_platform_driver(__platform_drv); Device Instance and Driver Handling 这里有一个 driver 的 template, 具体查看官方文档。 如果需要支持热插拔 drm 设备,比如 USB, DT overlay unload, 需要使用 drm_dev_unplug() 代替 drm_dev_unregister()....

2025-04-15 · 5 min

DRM(11) -- Bridge

Overview struct drm_bridge 代表挂在 encoder 后面的设备。当 drm_encoder 不能完全代表整个 encoder chain 的时候, drm_bridge 就有用了。 Encoder –> Bridge A –> Bridge B drm bridge 和 drm panel 一样,不是 drm_mode_object, 对 userspace 是不可见的。他们只是用来提供额外的 hooks 来得到 encoder chain 最终的理想输出。 Display driver 负责把 encoder link 到第一个 bridge,通过devm_drm_of_get_bridge()获取 bridge,再通过drm_bridge_attach()将 bridge attach 到 encoder 上。 Bridge driver 负责把自己 link 到下一级 bridge,通过在 drm_bridges_funcs.attach 中调用drm_bridge_attach()。 最后一级 Bridge driver 还参与实现 drm connector, 通过drm_bridge_connector_init() helper 来创建 drm_connector. 或者通过 bridge 暴露出来的 connector 相关操作函数来手动实现 connector....

2025-04-15 · 4 min

xv6_lecture2 C in xv6

经典的一道指针和数组题: 假设 x 的地址为 0x7fffdfbf7f00, 打印出来的值分别是多少? #include <stdio.h> int main() { int x[5]; printf("%p\n", x); printf("%p\n", x+1); printf("%p\n", &x) printf("%p\n", &x+1); return 0; } 0x7fffdfbf7f00 # 打印的数组的地址 0x7fffdfbf7f04 # 打印的是数组第二个元素的地址 0x7fffdfbf7f00 # &x也是数组的地址 0x7fffdfbf7f14 # x + sizeof(x)的地址

2024-12-26 · 1 min

DRM(13) -- Memory Management

Introduction DRM 核心包括两个内存管理器,分别是 Translation Table Manager(TTM) 和 Graphics Execution Manager(GEM). TTM 是第一个被开发的 DRM 内存管理器。它提供了一个单一的用户空间 API 来满足所有硬件的需求,支持统一内存体系结构 (Unified Memory Architecture,UMA) 设备和具有专用视频 RAM (即大多数离散显卡) 的设备。这导致了一大段复杂的代码,结果很难用于驱动程序开发。 由于 TTM 的复杂性,GEM 最初是由英特尔 (Intel) 赞助的一个项目。GEM 没有提供每个图形内存相关问题的解决方案,而是确定了驱动程序之间的公共代码,并创建了一个支持库来共享它。GEM 的初始化和执行要求比 TTM 简单,但没有视频 RAM 管理功能,因此仅限于 UMA 设备。 GEM Initialization 在 struct drm_driver driver feature 中设置 DRIVER_GEM bit. 中间层会自动调用drm_gem_init()来完成 GEM 的初始化。 GEM Objects Creation GEM object 由结构体 struct drm_gem_object表示,通过drm_gem_oject_init()初始化,利用 shmem 来分配 anonymous pageable memory. 如果 hardware 需要 physical contiguous system memory(通常是嵌入式设备需求), 那么可以不需要使用 shmem, 而是通过drm_gem_private_object_init()初始化。...

2024-12-10 · 3 min