如果在注册之前子设备模块消失,则此操作可能失败。成功调用此函数后,`subdev->dev`字段将指向`中泰xtp 股票交易接口,v4l2_device`。如果`中泰xtp 股票交易接口,v4l2_device`父设备具有非空`mdev`字段,则子设备实体将自动在媒体设备中注册。您可以使用以下代码取消注册子设备:
v4l2_device_unregister_subdev(sd)
除了-ENOIOCTLCMD之外的任何错误都会导致退出循环并显示该错误。如果没有错误,则返回0。这两个调用的第二个参数是一个组ID。如果是0,那么将调用所有子设备。如果非零,则只调用其组ID与该值匹配的子设备。在桥接驱动程序注册子设备之前,它可以将sd->grp_id设置为任何值。该值由桥接驱动程序拥有,子设备驱动程序永远不会修改或使用它。组ID赋予了桥接驱动程序更多控制回调如何被调用的能力。例如,板子上可能有多个音频芯片,每个芯片都可以改变音量。但通常只有一个芯片会在用户要改变音量时实际使用。您可以将该子设备的组ID设置为例如AUDIO_CONTROLLER,并在调用v4l2_device_call_all时指定该组ID值。这确保它只会去到需要它的子设备处。如果子设备需要通知其v4l2_device父级发生的事件,则可以调用v4l2_subdev_notify。此宏会检查是否定义了notify回调函数,如果没有,则返回-ENODEV。否则,返回notify调用的结果。
如果子设备驱动程序实现了接收端口,子设备驱动程序可以设置v4l2_subdev_pad_ops中的link_validate字段,以提供自己的链接验证函数。对于管道中的每个链接,调用链接结束处的接收端口操作的link_validatepad操作。在这两种情况下,驱动程序仍需负责验证子设备和视频节点之间格式配置的正确性。如果未设置link_validateop,则默认函数v4l2_subdev_link_validate_default将代替。此函数确保链接源和接收端口上的宽度、高度和媒体总线像素代码相等。子设备驱动程序也可以自由使用此函数执行上述检查以及他们自己的检查。1Subdevregistration目前,有两种将子设备注册到V4L2core的方法。第一种可能性是由桥接驱动程序注册子设备。当桥接驱动程序具有连接到其上的子设备的完整信息并且知道何时注册它们时,可以执行此操作。这通常适用于SoC内部的视频数据处理单元或复杂的PCI板、USB相机中的摄像头传感器或连接到SoC中的情况,它们向桥接驱动程序传递有关它们的信息,通常在其平台数据中。在某些情况下,子设备必须异步注册到桥接设备。这种配置的示例是基于设备树的系统,其中与子设备相关的信息独立于桥接设备提供系统,例如,在DT中将子设备定义为I2C设备节点时。在第二种情况下使用的API将在下面进一步描述。使用任何一种注册方法都只会影响探测过程,两种情况下运行时桥接-子设备的交互方式是相同的。在同步情况下,设备驱动程序需要使用以下代码将`v4l2_subdev`注册到`v4l2_device`:
v4l2_device_register_subdev(v4l2_dev, sd)
取消注册后,子设备将从`v4l2_device`注销,`sd->dev`变为`NULL`。这意味着可以安全地卸载子设备模块。重要的是在卸载其模块之前正确注销子设备,以防止任何潜在的问题或冲突。在异步情况下,子设备探测可以独立于桥接驱动的可用性进行调用。然后,子设备驱动程序必须验证是否满足成功探测的所有要求。其中可能包括检查主时钟是否可用。如果其中任何一个条件不满足,驱动程序可能会决定返回`-EPROBE_DEFER`,请求进一步的探测尝试。一旦满足所有条件,应使用`v4l2_async_register_subdev`函数注册子设备。取消注册通过调用`v4l2_async_unregister_subdev`完成。以这种方式注册的子设备将存储在全局子设备列表中,准备由桥接驱动程序选择。桥接驱动程序必须注册通知对象。这是通过调用`v4l2_async_nf_register`来完成的。取消注册通知程序需要调用`v4l2_async_nf_unregister`。前面两个函数都采用两个参数:指向`structv4l2_device`的指针和指向`structv4l2_async_notifier`的指针。在注册通知程序之前,桥接驱动程序必须完成两件事:必须使用`v4l2_async_nf_init`初始化通知程序。桥接驱动程序可以开始形成子设备描述符列表,该列表是桥接设备运行所需的。根据设备类型和驱动程序的需求,可以使用多个函数将子设备描述符添加到通知程序中。`v4l2_async_nf_add_fwnode_remote`和`v4l2_async_nf_add_i2c`用于桥接和ISP驱动程序,用于向通知程序注册其异步子设备。`v4l2_async_register_subdev_sensor`是一个助手函数,用于传感器驱动程序注册自己的异步子设备,但它还会注册通知程序,并为固件中找到的镜头和闪光灯设备进一步注册异步子设备。子设备的通知程序与异步子设备一起取消注册。这些函数分配一个异步子设备描述符,其类型为嵌入到特定于驱动程序的结构体中的`structv4l2_async_subdev`。结构体的`&structv4l2_async_subdev`应该是该结构体的第一个成员:
struct my_async_subdev {
struct v4l2_async_subdev asd;
...
};
struct my_async_subdev *my_asd;
struct fwnode_handle *ep;
...
my_asd = v4l2_async_nf_add_fwnode_remote(¬ifier, ep,
struct my_async_subdev);
fwnode_handle_put(ep);
if (IS_ERR(asd))
return PTR_ERR(asd);
接下来,V4L2core将使用这些描述符异步匹配已注册的子设备。如果检测到匹配,则会调用`.bound`通知回调函数。在定位所有子设备之后,将调用`.complete`回调函数。当从系统中删除子设备时,将调用`.unbind`方法。这三个回调都是可选的。2Callingsubdevoperations使用`v4l2_subdev`的优点是它是一个通用的结构体,不包含任何有关底层硬件的知识。驱动程序可能包含几个使用I2C总线的子设备,但也可能包含通过GPIO引脚控制的子设备。这种区别只有在设置设备时才是相关的,但是一旦子设备被注册,它就是完全透明的。一旦子设备已注册,您可以直接调用ops函数:
err = sd->ops->core->g_std(sd, &norm);
该宏将执行正确的NULL指针检查,并返回-ENODEV、-ENOIOCTLCMD,或实际结果sd->ops->core->g_stdops。还可以调用所有或子设备的子集:
v4l2_device_call_all(v4l2_dev, 0, core, g_std, &norm);
pads数组必须先前初始化过。无需手动设置structmedia_entity函数和名称字段,但如果需要,则必须初始化revision字段。当打开/关闭子设备设备节点时,实体的引用将自动获取/释放。在销毁子设备之前,不要忘记清理媒体实体:
media_entity_cleanup(&sd->entity);
但最好最简单的方法是使用这个宏:
err = v4l2_subdev_call(sd, core, g_std, &norm);
coreops对所有子设备都是通用的,其他类别的实现取决于子设备。例如,视频设备不太可能支持音频操作,反之亦然。这种设置限制了函数指针的数量,同时使添加新操作和类别变得容易。子设备驱动程序使用以下命令初始化v4l2_subdev结构:v4l2_subdev_init。此后,您需要使用唯一名称初始化sd->name,并设置模块所有者。如果使用i2c辅助函数,则会为您完成此操作。如果需要与媒体框架集成,则必须通过调用media_entity_pads_init来初始化嵌入在v4l2_subdev结构中的media_entity结构,如果实体具有端口:
struct media_pad *pads = &my_sd->pads;
int err;
err = media_entity_pads_init(&sd->entity, npads, pads);
文章为作者独立观点,不代表股票交易接口观点