目的:对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函数。





Logo

更多推荐