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
这一节。