目的:对USB作深入学习,在此留下笔记。欢迎讨论。
[Linux 3.2] [driver/usb/host/ehci-hcd.c]
函数:ehci_hcd_init()
static int __init ehci_hcd_init(void)
{
int retval = 0;
if (usb_disabled())
return -ENODEV;
printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name);
set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
printk(KERN_WARNING "Warning! ehci_hcd should always be loaded"
" before uhci_hcd and ohci_hcd, not after\n");
pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
hcd_name,
sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
#ifdef DEBUG
ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root);
if (!ehci_debug_root) {
retval = -ENOENT;
goto err_debug;
}
#endif
#ifdef PLATFORM_DRIVER
retval = platform_driver_register(&PLATFORM_DRIVER);
if (retval < 0)
goto clean0;
#endif
此函数实现的功能如下:
1. 判断USB是否被禁用了,如果有,直接退出。
2. 打印一条信息:ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver.
3. 判断UHCI和OHCI是否已经被加载,如果是打印输入warning 信息。
4. pr_debug: 根据编译内核的debug选项,决定是否输出此段信息。
5. 如果定义了DEBUG,则在debugfs下面的usb目录里面创建一个ehci的目录。
6. 注册一个platform驱动。这个platform驱动是根据PLATFORM_DRIVER的定义而决定。platform_driver_register最后还是调用driver_register实现。
(例:对atmel的EHCI来说,如下所示:)
#ifdef CONFIG_ARCH_AT91
#include "ehci-atmel.c"
#define PLATFORM_DRIVER ehci_atmel_driver
#endif
其中echi_atmel_driver在ehci-atmel.c文件里面定义。
接下来ehci_atmel_driver里的probe函数(ehci_atmel_drv_probe)就会被调用(为什么呢?本文结尾分析)。
ehci_atmel_drv_proble会调用两个关键函数:usb_create_hcd 与 usb_add_hcd。后篇文章对此进行分析。
备注:内核中的初始化顺序。
start_kernel --> reset_init --> kernel_init --> do_basic_setup --> do_initcalls。do_initcalls的实现如下:
extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
static void __init do_initcalls(void)
{
initcall_t *fn;
for (fn = __early_initcall_end; fn < __initcall_end; fn++)
do_one_initcall(*fn);
}
其中__early_initcall_end, __initcall_end, __early_initcall_end是在vmlinux.lds文件里面定义。
arch_initcall();首先被调用。在arch/arm/kernel/setup.c中有arch_initcall(customize_machine),所以先执行mdes->init_machine(). 这是在board文件中定义。对atmel的at91sam9m10g45ek板子,就会先注册ohci和ehci。在platform_driver_register-->driver_register-->bus_add_driver-->driver_attach --> 最后调用到probe函数。