Linux USB subsystem --- EHCI host controller register
[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函数。