USB 核心回调

usbcore 将执行哪些回调?

Usbcore 将通过驱动程序结构中定义的回调以及驱动程序提交的 URB 的完成处理程序来调用驱动程序。本文档的范围仅限于前者。这两种回调完全相互独立。有关完成回调的信息,请参阅USB 请求块 (URB)

驱动程序结构中定义的回调包括

  1. 热插拔回调

  • @probe

    调用以查看驱动程序是否愿意管理设备上的特定接口。

  • @disconnect

    当接口不再可访问时调用,通常是因为其设备已断开连接(或正在断开连接)或驱动程序模块正在被卸载。

  1. 通过 usbfs 的奇怪后门

  • @ioctl

    用于希望通过“usbfs”文件系统与用户空间通信的驱动程序。这允许设备提供向用户空间公开信息的方式,而不管它们是否在文件系统中显示(或不显示)。

  1. 电源管理 (PM) 回调

  • @suspend

    当设备即将被挂起时调用。

  • @resume

    当设备正在恢复时调用。

  • @reset_resume

    当挂起的设备已重置而不是恢复时调用。

  1. 设备级操作

  • @pre_reset

    当设备即将被重置时调用。

  • @post_reset

    在设备重置后调用

仅当您有非常好的理由时才应使用 ioctl 接口 (2)。现在首选 Sysfs。PM 回调在 USB 的电源管理 中单独介绍。

调用约定

所有回调都是互斥的。无需锁定以防止其他 USB 回调。所有回调都从任务上下文中调用。您可以休眠。但是,重要的是所有休眠都有一个很小的固定时间上限。特别是,您不得调用用户空间并等待结果。

热插拔回调

这些回调旨在将驱动程序与接口关联和取消关联。驱动程序与接口的绑定是独占的。

probe() 回调

int (*probe) (struct usb_interface *intf,
              const struct usb_device_id *id);

接受或拒绝接口。如果您接受该设备,则返回 0,否则返回 -ENODEV 或 -ENXIO。仅当在初始化过程中发生真正的错误,阻止驱动程序接受否则将被接受的设备时,才应使用其他错误代码。强烈建议您使用 usbcore 的工具,usb_set_intfdata(),将数据结构与接口关联,以便您知道将哪个内部状态和标识与特定接口关联。设备将不会被挂起,您可以对您被调用的接口和设备的端点 0 执行 IO。此处进行不需要太长时间的设备初始化是一个好主意。

disconnect() 回调

void (*disconnect) (struct usb_interface *intf);

此回调是断开与接口的任何连接的信号。从该回调返回后,您不允许对设备进行任何 IO。您也不得执行任何其他可能干扰绑定到该接口的另一个驱动程序的操作,例如,电源管理操作。在可以返回此回调之前,必须完成或中止设备上的未完成操作。

如果由于物理断开连接而调用您,则您的所有 URB 将被 usbcore 杀死。请注意,在这种情况下,断开连接将在物理断开连接后的一段时间内被调用。因此,即使在回调之前,您的驱动程序也必须准备好处理失败的 IO。

设备级回调

pre_reset

int (*pre_reset)(struct usb_interface *intf);

驱动程序或用户空间正在触发包含作为参数传递的接口的设备上的重置。停止 IO,等待所有未完成的 URB 完成,并保存您需要恢复的任何设备状态。在调用 post_reset 方法之前,不能再提交 URB。

如果需要在此处分配内存,则如果处于原子上下文中,请使用 GFP_NOIO 或 GFP_ATOMIC。

post_reset

int (*post_reset)(struct usb_interface *intf);

重置已完成。恢复任何已保存的设备状态并重新开始使用该设备。

如果需要在此处分配内存,则如果处于原子上下文中,请使用 GFP_NOIO 或 GFP_ATOMIC。

调用序列

对于未绑定到您的驱动程序的接口,不会调用 probe 以外的回调。

对于绑定到驱动程序的接口,永远不会调用 Probe。因此,在成功的探测之后,将在再次探测同一接口之前调用断开连接。

一旦您的驱动程序绑定到接口,可以在除 pre_reset 和 post_reset 之间之外的任何时间调用 disconnect。 pre_reset 始终后跟 post_reset,即使重置失败或设备已拔出。

挂起始终后跟以下其中之一:恢复、重置恢复或断开连接。