Video4Linux框架简介(2) - v4l2_device

本文介绍了一个基于PCI的V4L2基础驱动程序实例,包括如何创建和注册v4l2设备对象,实现设备的探针和移除函数,并展示了如何管理和维护子设备列表。
V4L2 PCI基础驱动程序实例


struct v4l2_device (1)

(译注: 第一步,先基于你的桥接驱动(譬如这里就是PCI设备),添加一个v4l2设备对象,通常v4l2设备都不是独立存在的。)

#include <linux/videodev2.h>     // 每个V4L2驱动都需要添加这两个头文件
#include <media/v4l2-device.h>
MODULE_DESCRIPTION("V4L2 PCI Skeleton Driver");
MODULE_AUTHOR("Hans Verkuil");
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(pci, skeleton_pci_tbl);
struct skeleton {
struct pci_dev *pdev;
struct v4l2_device v4l2_dev;    //v4l2设备对象,实际上,它不像是一个设备,
                                 //而是一系列v4l2设备以及控制的顶层结构,这一点在后续
                                 //提到框架时会再说明
};
static const struct pci_device_id skeleton_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_FOO, PCI_DEVICE_ID_BAR) },
{ 0, }
};
<skeleton_probe>    // 待添加
<skeleton_remove>   // 待添加

static struct pci_driver skeleton_driver = {
.name = KBUILD_MODNAME,
.probe = skeleton_probe,
.remove = skeleton_remove,
.id_table = skeleton_pci_tbl,
};
module_pci_driver(skeleton_driver); 


struct v4l2_device (2)

(译注: 第二步,添加注册和注销函数)


static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct skeleton *skel;
int ret;
pci_enable_device(pdev);
pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
skel = devm_kzalloc(&pdev->dev, sizeof(struct skeleton), GFP_KERNEL);
if (!skel)
return -ENOMEM;
skel->pdev = pdev;
ret = v4l2_device_register(&pdev->dev, &skel->v4l2_dev); //诸如设置名字,锁等资源的初始化
if (ret)
goto disable_pci;
dev_info(&pdev->dev, "V4L2 PCI Skeleton Driver loaded\n");
return 0;
disable_pci:
pci_disable_device(pdev);
return ret;
}
static void skeleton_remove(struct pci_dev *pdev)
{
struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
struct skeleton *skel = container_of(v4l2_dev, struct skeleton, v4l2_dev);
v4l2_device_unregister(&skel->v4l2_dev);  //与register相对应,注销所用到的资源
pci_disable_device(skel->pdev);
}


总结一下 struct v4l2_device:


●首先,它是V4L2驱动的顶级结构。
●Misnomer:更好的名称应该是v4l2_root(译注:关于这一点 Verkuil本人和内核社区提交过修改,不过由于涉及的修改实在太多,被reject了)。
●v4l2_device_(un)register应已调用v4l2_root_init / exit。
●维护子设备(v4l2_subdev)列表。
●具有对子设备的notify()回调。
●当最后一个设备引用释放时调用release()回调。



### v4l2_devicev4l2_dev 在 V4L2 框架中的关系与区别 在 V4L2Video for Linux Two)框架中,`v4l2_device` 和 `v4l2_dev` 是两个相关但不同的概念。以下是它们的详细关系和区别。 #### 1. `v4l2_device` 的定义与作用 `v4l2_device` 是 V4L2 框架中的核心结构体之一,用于表示视频设备的抽象[^1]。它通常嵌入到驱动程序的自定义结构体中,并负责管理子设备、控制接口以及其他资源。 - **功能**: - 子设备管理:通过调用 `v4l2_device_register_subdev` 方法将子设备注册到主设备中[^2]。 - 控制接口:提供统一的控制接口,用于管理设备的所有控制参数。 - 资源清理:在设备注销时,确保所有关联的子设备和其他资源被正确释放。 #### 2. `v4l2_dev` 的定义与作用 `v4l2_dev` 并不是 V4L2 框架中的标准术语或结构体名称。通常情况下,开发者可能将其作为对 `v4l2_device` 的简写或缩写使用。例如,在某些代码片段中,`v4l2_dev` 可能是 `v4l2_device` 的别名或指针变量名[^3]。 如果 `v4l2_dev` 确实是一个独立的概念,则需要明确其具体定义和用途。以下假设其为 `v4l2_device` 的简化形式进行讨论。 #### 3. 关系总结 - **命名差异**:`v4l2_device` 是 V4L2 框架中正式定义的结构体名称,而 `v4l2_dev` 更可能是开发者为了简化代码而使用的别名或指针变量名。 - **功能一致性**:无论使用 `v4l2_device` 还是 `v4l2_dev`,其核心功能均围绕视频设备的管理展开,包括子设备注册、控制接口管理和资源清理等。 - **代码示例**: ```c struct my_v4l2_driver { struct v4l2_device v4l2_dev; // 正式定义 struct device *dev; // 指向底层硬件设备 }; static int my_probe(struct platform_device *pdev) { struct my_v4l2_driver *drv; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (!drv) return -ENOMEM; v4l2_device_set_name(&drv->v4l2_dev, "my_v4l2", &pdev->id); // 设置设备名称 drv->v4l2_dev.mdev = &drv->media_dev; // 关联 media_device int ret = v4l2_device_register(&pdev->dev, &drv->v4l2_dev); // 注册 v4l2_device if (ret < 0) return ret; return 0; } ``` 在上述代码中,`v4l2_dev` 可能被用作 `drv->v4l2_dev` 的简化形式。 #### 4. 区别总结 | 特性 | `v4l2_device` | `v4l2_dev` | |---------------------|------------------------------------------------|------------------------------------------| | **定义来源** | V4L2 框架中的标准结构体 | 开发者自定义的别名或指针变量名 | | **功能范围** | 视频设备的高层次抽象 | 同 `v4l2_device` | | **使用场景** | 驱动程序的核心组件 | 可能作为 `v4l2_device` 的简化形式使用 | --- ### 示例代码 以下是一个典型的 `v4l2_device` 使用示例,其中 `v4l2_dev` 被用作简化形式: ```c #include <linux/videodev2.h> #include <media/v4l2-device.h> struct my_v4l2_driver { struct v4l2_device v4l2_dev; // 正式定义 struct device *dev; // 指向底层硬件设备 }; static int my_probe(struct platform_device *pdev) { struct my_v4l2_driver *drv; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (!drv) return -ENOMEM; struct v4l2_device *v4l2_dev = &drv->v4l2_dev; // 使用简化形式 v4l2_device_set_name(v4l2_dev, "my_v4l2", &pdev->id); v4l2_dev->mdev = &drv->media_dev; int ret = v4l2_device_register(&pdev->dev, v4l2_dev); if (ret < 0) return ret; return 0; } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值