USB设备的表示

image.png

驱动架构

image.png
USB采用树形拓扑结构,主机侧和设备侧的USB控制器分别称为主机控制器和USB设备控制器,每条总线上只有一个主机控制器, 负责协调主机和设备间的通信, 而设备不能主动向主机发送任何消息

主机控制器驱动

image.png
USB主机控制器有如下规格

  • OHCI(Open Host Controller Interface)
  • UHCI(Universal Host Controller Interface)
  • EHCI(Enhanced Host Controller Interface)
  • xHCI(eXtensible Host Controller Interface)

    usb_hcd

    在Linux内核中, 用**usb_hcd**结构体描述USB主机控制器驱动:
    image.png
    如下函数用于操作usb_hcd

    1. //创建hcd结构体
    2. struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name);
    3. //向内核增加hcd
    4. int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags);
    5. //从内核删除hcd
    6. extern void usb_remove_hcd(struct usb_hcd *hcd);

    Chipidea USB主机驱动解读

    代码位置:drivers/usb/chipidea
    image.png

    设备控制器驱动

    image.png
    所谓的USB设备驱动指的是从主机角度来看,怎样访问被插入的USB设备,而不是指USB设备内部本身运行的固件程序。Linux实现了如下几大类的USB设备驱动,工程师不需要处理通用USB设备(linux已经支持),只是针对特定芯片和厂商编写驱动

  • 音频设备类通信设备类

  • HID(人机接口)设备类
  • 显示设备类
  • 海量存储设备类
  • 电源设备类
  • 打印设备类
  • 集线器设备类

查看USB设备信息:sudo cat /sys/kernel/debug/usb/devices

usb_driver

usb_driver结构体描述一个USB设备驱动。编写新的USB设备驱动时, 主要应该完成的工作是probedisconnect函数,它们分别在设备被插入和拔出的时候调用,用于初始化和释放软硬件资源。

USB只是一个总线,USB设备驱动真正的主体工作仍然是USB设备本身所属类型的驱动,如字符设备、 tty设备、 块设备、 输入设备等。与platform_driver、 i2c_driver类似, usb_driver起到了“牵线”的作用, 即

  • probe里注册相应的字符、tty等设备.
    • 字符设备可以调用usb_register_dev注册驱动,其他设备需要对应设备的注册函数。
  • disconnect注销相应的字符、tty等设备
    • 字符设备注销:usb_deregister_dev

原先对普通的字符等设备的注册和注销一般直接发生在模块加载和卸载函数中,这里用于借助了USB总线,所以需要将真正的读写驱动包含在USB的驱动架构中。

  1. struct usb_driver {
  2. const char *name;
  3. int (*probe) (struct usb_interface *intf,
  4. const struct usb_device_id *id);
  5. void (*disconnect) (struct usb_interface *intf);
  6. int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,
  7. void *buf);
  8. int (*suspend) (struct usb_interface *intf, pm_message_t message);
  9. int (*resume) (struct usb_interface *intf);
  10. int (*reset_resume)(struct usb_interface *intf);
  11. int (*pre_reset)(struct usb_interface *intf);
  12. int (*post_reset)(struct usb_interface *intf);
  13. const struct usb_device_id *id_table;//这个USB驱动所支持的USB设备列表
  14. const struct attribute_group **dev_groups;
  15. struct usb_dynids dynids;
  16. struct usbdrv_wrap drvwrap;
  17. unsigned int no_dynamic_id:1;
  18. unsigned int supports_autosuspend:1;
  19. unsigned int disable_hub_initiated_lpm:1;
  20. unsigned int soft_unbind:1;
  21. };

以下函数用于像内核注册和注销驱动:

  1. #define usb_register(driver) \
  2. usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
  3. extern void usb_deregister(struct usb_driver *);

usb_device_id

usb_driver结构体中的id_table成员标明了本驱动可以用于哪些USB设备,结构体usb_device_id用于描述一个USB设备的各种信息。
当USB核心检测到某个设备的属性和某个驱动程序的usb_device_id结构体所携带的信息一致时,这个驱动程序的probe函数就被执行。

下面的函数和宏用于操作usb_device_id

  1. //生成usb_device_id实例
  2. #define USB_DEVICE(vend, prod) \
  3. .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
  4. .idVendor = (vend), \
  5. .idProduct = (prod)
  6. //根据制造商和产品ID生成usb_device_id实例
  7. #define USB_DEVICE_VER(vend, prod, lo, hi) \
  8. .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \
  9. .idVendor = (vend), \
  10. .idProduct = (prod), \
  11. .bcdDevice_lo = (lo), \
  12. .bcdDevice_hi = (hi)
  13. //根据制造商,产品ID,产品版本生成usb_device_id实例
  14. #define USB_DEVICE_INFO(cl, sc, pr) \
  15. .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, \
  16. .bDeviceClass = (cl), \
  17. .bDeviceSubClass = (sc), \
  18. .bDeviceProtocol = (pr)
  19. //创建一个匹配设备指定类型的usb_device_id实例
  20. #define USB_INTERFACE_INFO(cl, sc, pr) \
  21. .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \
  22. .bInterfaceClass = (cl), \
  23. .bInterfaceSubClass = (sc), \
  24. .bInterfaceProtocol = (pr)

上面函数在定义id_table数组时可以直接调用,返回实例作为数组成员

  1. static struct usb_device_id id_table [] = {
  2. {USB_DEVICE(VENDOR_ID, PRODUCT_ID)},
  3. //当然也可以直接赋值,不用宏
  4. {.idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
  5. { },
  6. };
  7. MODULE_DEVICE_TABLE (usb, id_table);//关联到usb_driver

内核USB设备驱动骨架解读

代码位于:drivers/usb/usb-skeleton.c
image.png

URB处理流程

USB初始化过程中,无论是主机控制器驱动还是根集线器驱动,都是通过URB传输获取设备信息。USB请求块(USB Request Block)是USB设备驱动中用来描述与USB设备通信所用的基本载体和核心数据结构, 非常类似于网络设备驱动中的sk_buff结构体。
image.png