Edit online

EHCI Driver

24 Jan 2024
Read time: 2 minute(s)

ehci driver 负责把 echi 功能封装成标准的 hcd 驱动。它主要完成两项工作:

  • 注册标准的 hcd 驱动。把 Client Software 传送下来的 urb 映射到 EHCI 的链表中进行传输。

  • 创建一个虚拟的根 hub 设备,即 roothub。

URB Transfer

ehci 注册 hcd 驱动:

static int ehci_platform_probe(struct platform_device *dev)
{

    /* (1) 分配 hcd,并且把 hcd->driver 初始化成 ehci_hc_driver */
    ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides);
    hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
                dev_name(&dev->dev));

    /* (2) 注册标准的 hcd 驱动 */
    err = usb_add_hcd(hcd, irq, IRQF_SHARED);
}

hcd 驱动向上提供了标准接口,最终的实现会调用到 ehci_hc_driver 当中。

staticconststructhc_driverehci_hc_driver={.description=hcd_name,.product_desc="EHCI Host Controller",.hcd_priv_size=sizeof(structehci_hcd),/**generichardwarelinkage*/.irq=ehci_irq,.flags=HCD_MEMORY|HCD_DMA|HCD_USB2|HCD_BH,/**basiclifecycleoperations*/.reset=ehci_setup,.start=ehci_run,.stop=ehci_stop,.shutdown=ehci_shutdown,/**managingi/orequestsandassociateddeviceresources*/.urb_enqueue=ehci_urb_enqueue,.urb_dequeue=ehci_urb_dequeue,.endpoint_disable=ehci_endpoint_disable,.endpoint_reset=ehci_endpoint_reset,.clear_tt_buffer_complete=ehci_clear_tt_buffer_complete,/**schedulingsupport*/.get_frame_number=ehci_get_frame,/**roothubsupport*/.hub_status_data=ehci_hub_status_data,.hub_control=ehci_hub_control,.bus_suspend=ehci_bus_suspend,.bus_resume=ehci_bus_resume,.relinquish_port=ehci_relinquish_port,.port_handed_over=ehci_port_handed_over,.get_resuming_ports=ehci_get_resuming_ports,/**devicesupport*/.free_dev=ehci_remove_device,};

在 urb transfer 过程中,最核心的是调用上述的 ehci_urb_enqueue()ehci_urb_dequeue() 函数。

Roothub

首先创建虚拟的 roothub:

/* (1) 首先创建和初始化 `usb_device` 结构: */
ehci_platform_probe() → usb_add_hcd() → usb_alloc_dev():
struct usb_device *usb_alloc_dev(struct usb_device *parent,
                struct usb_bus *bus, unsigned port1)
{

    /* (1.1) dev 总线初始化为 usb_bus_type */
    dev->dev.bus = &usb_bus_type;
    /* (1.2) dev 类型初始化为 usb_device_type,标明自己是一个 usb device */
    dev->dev.type = &usb_device_type;
    dev->dev.groups = usb_device_groups;

}

/* (2) 然后注册  `usb_device` 结构: */
usb_add_hcd() → register_root_hub() → usb_new_device() → device_add()

然后因为 roothub 并不是在 Usb 物理总线上,所以对它的查询和配置需要特殊处理。详见 Usb Hub Driver 这一节。