嵌入式軟件開發之------淺析inux驅動模型(八)usb驅動

Linux 代碼版本:linux3.0
開發板環境: tiny4412
導讀:在分析 i2c 控制器驅動的時候, i2c 控制器是作爲 pltform_device 註冊到系統 ,然後註冊 platform_driver 匹配後調用到
probe 函數 ,在 probe 函數中 填充 i2c_adapter ,然後實例化 i2c_client。雖然拿 i2c 做對比,但是 usb 驅動框架遠遠比 i2c 複雜,usb 控制器仍然作爲 pltform_device 註冊,然後註冊相應的  platform_driver後最終調用到相應的 probe 函數,下面就將要分析這個過程。

一、usb_init
首先,USB 設備驅動分爲兩個層面,一個是 設備驅動,另一個是 USB 設備中 interface 驅動,每插入一個設備都會先匹配
設備驅動,設備驅動是公共的 usb_generic_driver ,由 usb_generic_driver 將 interface 註冊引發 interface 驅動匹配,
驅動開發工作就是開發 usb 設備 interface 的驅動。
在分析 usb 對應的 pltform_device 前,先看一個 usb_init 函數,

static int __init usb_init(void)
{
	int retval;
	if (nousb) {
		pr_info("%s: USB support disabled\n", usbcore_name);
		return 0;
	}
    
    /*由內核配置項 Kernel hacking  --->
                   [*] Debug Filesystem
     決定是否編譯 debug 的文件系統
     默認會將debugfs掛載在/sys/kernel/debug目錄下,也可以通過mount掛在到別的目錄下:mount -t debugfs none /mnt */
	retval = usb_debugfs_init();
            {
                /*在 debugfs 中創建 usb 的目錄*/
            	usb_debug_root = debugfs_create_dir("usb", NULL);
            	if (!usb_debug_root)
            		return -ENOENT;
                /*創建 devices 文件,此文件裏可以看到 usb 上的設備信息*/
            	usb_debug_devices = debugfs_create_file("devices", 0444,usb_debug_root, NULL,&usbfs_devices_fops);
                
            	if (!usb_debug_devices) {
            		debugfs_remove(usb_debug_root);
            		usb_debug_root = NULL;
            		return -ENOENT;
            	}

            	return 0;
            }
	if (retval)
		goto out;
    /*註冊 usb_bus_type,還記得前面的 platform_bus_type 註冊過程嗎,幾乎一樣的,會在 /sys/bus/下創建 usb 目錄*/
	retval = bus_register(&usb_bus_type);
	if (retval)
		goto bus_register_failed;
    /* usb總線上 每次 device_add 的時候都會調用 usb_bus_nb->notifier_call ,也就是 usb_bus_notify ,主要常見了一些相關
        文件*/
	retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);
            {
                /* usb_bus_type->p->bus_notifier 未賦值,也就是爲 NULL */
            	return blocking_notifier_chain_register(&bus->p->bus_notifier, nb);
                        {
                        	int ret;

                        	/*
                        	 * This code gets used during boot-up, when task switching is
                        	 * not yet working and interrupts must remain disabled.  At
                        	 * such times we must not call down_write().
                        	 */
                        	 /* 啓動過程中 任務調度還沒啓動 ,中斷還是disable的時候走此分支,也就是不能
                                獲取信號量    */
                        	if (unlikely(system_state == SYSTEM_BOOTING))
                        		return notifier_chain_register(&nh->head, n);
                                        {
                                        	while ((*nl) != NULL) {
                                        		if (n->priority > (*nl)->priority)
                                        			break;
                                        		nl = &((*nl)->next);
                                        	}
                                            /* usb_bus_nb->next =  usb_bus_type->p->bus_notifier—>head*/
                                        	n->next = *nl;
                                            /* RCU 機制,相當於 usb_bus_type->p->bus_notifier—>head = usb_bus_nb */
                                        	rcu_assign_pointer(*nl, n);
                                        	return 0;
                                        }
                        	down_write(&nh->rwsem);
                        	ret = notifier_chain_register(&nh->head, n);
                        	up_write(&nh->rwsem);
                        	return ret;
                        }
            }
	if (retval)
		goto bus_notifier_failed;
    /*將 usb 作爲字符設備註冊到系統 ,usb 指 bus,不是usb_device,總線也是一個設備*/
	retval = usb_major_init();
            {
            	int error;

            	error = register_chrdev(USB_MAJOR, "usb", &usb_fops);
            	if (error)
            		printk(KERN_ERR "Unable to get major %d for usb devices\n",
            		       USB_MAJOR);

            	return error;
            }
	if (retval)
		goto major_init_failed;
    /*  註冊 interface 對應的驅動,usb interface  代表一個個功能,驅動開發是針對 interface 開發,
    一個 usb 設備可能和多個 interface 驅動匹配, usb_device_match 也是實現了兩種匹配,一個是usb
    設備的驅動匹配,另一個是和 interface 的驅動匹配*/
	retval = usb_register(&usbfs_driver);
            {
            	return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
                        {
                        	int retval = 0;

                        	if (usb_disabled())
                        		return -ENODEV;
                            /* 註冊 usbfs_driver ,並掛接在 usb_bus_type 上 */
                        	new_driver->drvwrap.for_devices = 0;
                        	new_driver->drvwrap.driver.name = (char *) new_driver->name;
                        	new_driver->drvwrap.driver.bus = &usb_bus_type;
                        	new_driver->drvwrap.driver.probe = usb_probe_interface;
                        	new_driver->drvwrap.driver.remove = usb_unbind_interface;
                        	new_driver->drvwrap.driver.owner = owner;
                        	new_driver->drvwrap.driver.mod_name = mod_name;
                        	spin_lock_init(&new_driver->dynids.lock);
                        	INIT_LIST_HEAD(&new_driver->dynids.list);

                        	retval = driver_register(&new_driver->drvwrap.driver);
                        	if (retval)
                        		goto out;
                            /**/
                        	usbfs_update_special();
                            {
                            	struct inode *inode;
                                /* devices_usbfs_dentry 指向 usbfs 目錄下的 devices ,usbfs 還沒初始化註冊呢,
                                所以 devices_usbfs_dentry 爲 NULL,usbfs 會掛載在 /proc/bus/usb 目錄下*/
                            	if (devices_usbfs_dentry) {
                            		inode = devices_usbfs_dentry->d_inode;
                                    /*其實也就更新了一下 /proc/bus/usb/devices 的時間而已 */
                            		if (inode)
                            			inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
                            	}
                            }
                            
                        	retval = usb_create_newid_file(new_driver);
                                    {
                                    	int error = 0;
                                        /* 如果 no_dynamic_id 設置爲 1 ,usbfs 將通過阻止創建 sysfs 文件
                                        來禁止將 動態 id 添加到驅動 */
                                    	if (usb_drv->no_dynamic_id)
                                    		goto exit;
                                        /* usbfs_driver->probe = driver_probe */
                                    	if (usb_drv->probe != NULL)
                                    		error = driver_create_file(&usb_drv->drvwrap.driver,
                                    					   &driver_attr_new_id);
                                    exit:
                                    	return error;
                                    }
                        	if (retval)
                        		goto out_newid;

                        	retval = usb_create_removeid_file(new_driver);
                        	if (retval)
                        		goto out_removeid;

                        	pr_info("%s: registered new interface driver %s\n",
                        			usbcore_name, new_driver->name);

                        out:
                        	return retval;

                        out_removeid:
                        	usb_remove_newid_file(new_driver);
                        out_newid:
                        	driver_unregister(&new_driver->drvwrap.driver);

                        	printk(KERN_ERR "%s: error %d registering interface "
                        			"	driver %s\n",
                        			usbcore_name, retval, new_driver->name);
                        	goto out;
                        }
            }
	if (retval)
		goto driver_register_failed;
    /* usb_device 的驅動,類似於 i2c-dev ,通過 usbdev_file_operations 進行操作 */
	retval = usb_devio_init();
            {
            	int retval;

            	retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
            					"usb_device");
            	if (retval) {
            		printk(KERN_ERR "Unable to register minors for usb_device\n");
            		goto out;
            	}
            	cdev_init(&usb_device_cdev, &usbdev_file_operations);
            	retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
            	if (retval) {
            		printk(KERN_ERR "Unable to get usb_device major %d\n",
            		       USB_DEVICE_MAJOR);
            		goto error_cdev;
            	}
                #ifdef CONFIG_USB_DEVICE_CLASS
                /* 創建 usb_classdev_class 類, usb_classdev_add    創建設備文件的時候需要用到 */
            	usb_classdev_class = class_create(THIS_MODULE, "usb_device");
            	if (IS_ERR(usb_classdev_class)) {
            		printk(KERN_ERR "Unable to register usb_device class\n");
            		retval = PTR_ERR(usb_classdev_class);
            		cdev_del(&usb_device_cdev);
            		usb_classdev_class = NULL;
            		goto out;
            	}
            	/* devices of this class shadow the major:minor of their parent
            	 * device, so clear ->dev_kobj to prevent adding duplicate entries
            	 * to /sys/dev
            	 */
            	usb_classdev_class->dev_kobj = NULL;
            #endif
                 /* 又將 usbdev_nb 掛接在了 usb_notifier_list 上面,具體調用的時候再分析*/   
            	usb_register_notify(&usbdev_nb);
                {
                	blocking_notifier_chain_register(&usb_notifier_list, nb);
                }
            out:
            	return retval;

            error_cdev:
            	unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
            	goto out;
            }
	if (retval)
		goto usb_devio_init_failed;
    /*默認掛載點 /proc/bus/usb */
	retval = usbfs_init();
            {
            	int retval;
                /* 這裏才註冊 usbfs */
            	retval = register_filesystem(&usb_fs_type);
            	if (retval)
            		return retval;

            	usb_register_notify(&usbfs_nb);

            	/* create mount point for usbfs */
            	usbdir = proc_mkdir("bus/usb", NULL);

            	return 0;
            }
	if (retval)
		goto fs_init_failed;
    /* 初始化 hub 這個函數非常重要,USB 設備枚舉將在這裏完成 ,這裏先不詳細分析,
    後面分析設備插入過程中的時候再分析 */
	retval = usb_hub_init();
            {
                /* 註冊 hub 驅動 , 其實 hub_driver 也是 usb_driver 類型 ,畢竟 hub 也是 usb 設備*/
            	if (usb_register(&hub_driver) < 0) {
                    {
                    	return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
                    }
            		printk(KERN_ERR "%s: can't register hub driver\n",
            			usbcore_name);
            		return -1;
            	}
                /* 創建 khubd 內核線程,有 USB 設備插入時該線程被 激活 ,然後完成設備枚舉 */
            	khubd_task = kthread_run(hub_thread, NULL, "khubd");
                                        
            	if (!IS_ERR(khubd_task))
            		return 0;

            	/* Fall through if kernel_thread failed */
                
            	usb_deregister(&hub_driver); 
            	printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);

            	return -1;
            }
	if (retval)
		goto hub_init_failed;
    /*註冊 usb_generic_driver ,用於和 usb_device 匹配,usb_device 是插入設備時枚舉的 ,
    usb_device 和 usb_generic_driver 通過 usb_bus_type->match 也就是 usb_device_match 匹配,
    匹配成功後 調用 usb_generic_driver->probe 函數,也就是 generic_probe ,所有的 usb 設備
    枚舉後都會匹配此驅動 */
	retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
	if (!retval)
		goto out;

	usb_hub_cleanup();
hub_init_failed:
	usbfs_cleanup();
fs_init_failed:
	usb_devio_cleanup();
usb_devio_init_failed:
	usb_deregister(&usbfs_driver);
driver_register_failed:
	usb_major_cleanup();
major_init_failed:
	bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
bus_notifier_failed:
	bus_unregister(&usb_bus_type);
bus_register_failed:
	usb_debugfs_cleanup();
out:
	return retval;
}

總結一下 , usb_init 主要乾了這麼幾件事:
1. 在debugfs 建立 usb 目錄和 devices 文件*/
2. 註冊 USB 總線
3. 爲 usb bus 註冊字符設備
4. 註冊 usbfs_driver 
5. 爲 usb device 註冊字符設備
6. 註冊 usbfs
7. 註冊 hub_driver 並創建 khubd 線程
8. 註冊 usb_generic_driver

單獨看每一個的動作,都不好理解到底有什麼用,只有放在具體的例子中用到,就很好理解了。

二、usb 控制器註冊

USB 2.0 協議支持 ehci 的同時還兼容 ohci 和 uhci ,這裏只分析 ehci 驅動。
下面是 usb 控制器對應的 platform_device ,通過 platform_device_register 註冊,不再詳細分析。
其中 dma_mask 與 coherent_dma_mask 這兩個參數表示它能尋址的物理地址的範圍。不是所有的硬件都能夠支持 64bit 的尋址範圍 ,所以dma_coherent_mask 則作用於申請一致性DMA緩衝區。

static u64 s5p_device_ehci_dmamask = 0xffffffffUL;

struct platform_device s5p_device_ehci = {
	.name		= "s5p-ehci",
	.id		= -1,
	.num_resources	= ARRAY_SIZE(s5p_ehci_resource),
	.resource	= s5p_ehci_resource,
	.dev		= {
		.dma_mask = &s5p_device_ehci_dmamask,
		.coherent_dma_mask = 0xffffffffUL
	}
};

接下來看 對應的 pltform_driver ,通過 platform_driver_register 註冊 ,然後匹配到 s5p_device_ehci 後調用 s5p_ehci_probe。

static struct platform_driver s5p_ehci_driver = {
	.probe		= s5p_ehci_probe,
	.remove		= __devexit_p(s5p_ehci_remove),
	.shutdown	= s5p_ehci_shutdown,
	.driver = {
		.name	= "s5p-ehci",
		.owner	= THIS_MODULE,
		.pm = &s5p_ehci_pm_ops,
	}
};

接下來該分析 s5p_ehci_probe ,分析過程中將忽略硬件相關的初始化。其中usb_hcd 代表 usb 控制器驅動,
ehci_hcd 是 echi 標準的控控制器 ;hc_driver 則是一系列操作主機控制器的函數。

static int __devinit s5p_ehci_probe(struct platform_device *pdev)
{
	struct s5p_ehci_platdata *pdata;
	struct s5p_ehci_hcd *s5p_ehci;
	struct usb_hcd *hcd;
	struct ehci_hcd *ehci;
	struct resource *res;
	int irq;
	int err;

	pdata = pdev->dev.platform_data;
	if (!pdata) {
		dev_err(&pdev->dev, "No platform data defined\n");
		return -EINVAL;
	}

	s5p_ehci = kzalloc(sizeof(struct s5p_ehci_hcd), GFP_KERNEL);
	if (!s5p_ehci)
		return -ENOMEM;
    /* s5p_ehci->dev = &s5p_device_ehci->dev */
	s5p_ehci->dev = &pdev->dev;

	hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev,ev_name(&pdev->dev));
            {
            	return usb_create_shared_hcd(driver, dev, bus_name, NULL);
                        {   /*開始組裝 hcd */
                        	struct usb_hcd *hcd;

                        	hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
                        	if (!hcd) {
                        		dev_dbg (dev, "hcd alloc failed\n");
                        		return NULL;
                        	}
                            /* soc 上的 usb 並不是從 pcie 上出的,上面形參傳進來的也是     NULL */
                        	if (primary_hcd == NULL) {
                                /* 創建和初始化 bandwidth_mutex 信號量*/
                        		hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
                        				GFP_KERNEL);
                        		if (!hcd->bandwidth_mutex) {
                        			kfree(hcd);
                        			dev_dbg(dev, "hcd bandwidth mutex alloc failed\n");
                        			return NULL;
                        		}
                        		mutex_init(hcd->bandwidth_mutex);
                                /* 賦值 s5p_device_ehci->dev->driver_data = hcd */
                        		dev_set_drvdata(dev, hcd);
                        	} else {
                        		hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
                        		hcd->primary_hcd = primary_hcd;
                        		primary_hcd->primary_hcd = primary_hcd;
                        		hcd->shared_hcd = primary_hcd;
                        		primary_hcd->shared_hcd = hcd;
                        	}
                            /* 初始化引用計數 */
                        	kref_init(&hcd->kref);
                            
                            /* hcd 本身也是 usb_bus   */
                        	usb_bus_init(&hcd->self);
                            {
                                /* 初始化設備地址分配 map */
                            	memset (&bus->devmap, 0, sizeof(struct usb_devmap));
                                /* 此 usb_bus 上的下一個設備號碼爲 1 ,其實也是設備地址*/
                            	bus->devnum_next = 1;
                                /* 初始化 hcd->self->root_hub = NULL */
                            	bus->root_hub = NULL;
                                /* 此 usb_bus 號爲 -1,類似於 platform_device 中的 id */
                            	bus->busnum = -1;
                            	bus->bandwidth_allocated = 0;
                            	bus->bandwidth_int_reqs  = 0;
                            	bus->bandwidth_isoc_reqs = 0;

                            	INIT_LIST_HEAD (&bus->bus_list);
                            }
                        	hcd->self.controller = dev;
                            
                            /* hcd->self.bus_name = "s5p-ehci" */
                        	hcd->self.bus_name = bus_name;
                            /* 前面初始化 s5p_device_ehci->dev->dma_mask = 0xffffffffUL 也就是使用dma */
                        	hcd->self.uses_dma = (dev->dma_mask != NULL);
                            /* 初始化定時器 */
                        	init_timer(&hcd->rh_timer);
                        	hcd->rh_timer.function = rh_timer_func;
                                                    {
                                                       /* 控制器 輪詢 root hub 的狀態 ,後面再分析*/
                                                    	usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);
                                                        
                                                    }
                            /* 將此 hcd 作爲 形參傳給 rh_timer_func */
                            hcd->rh_timer.data = (unsigned long) hcd;
                         #ifdef CONFIG_USB_SUSPEND
                        	INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
                         #endif
                            /* hcd->driver = &s5p_ehci_hc_driver */
                        	hcd->driver = driver;
                            /* 定義時 s5p_ehci_hc_driver.flags	= HCD_MEMORY | HCD_USB2
                            所以 hcd->speed = HCD_MEMORY | HCD_USB2 */
                        	hcd->speed = driver->flags & HCD_MASK;
                            /* s5p_ehci_hc_driver->product_desc = "S5P EHCI Host Controller"
                            所以 hcd->product_desc = "S5P EHCI Host Controller" */
                        	hcd->product_desc = (driver->product_desc) ? driver->product_desc :
                        			"USB Host Controller";
                        	return hcd;
                        }
            }
	if (!hcd) {
		dev_err(&pdev->dev, "Unable to create HCD\n");
		err = -ENOMEM;
		goto fail_hcd;
	}

	s5p_ehci->hcd = hcd;
	s5p_ehci->clk = clk_get(&pdev->dev, "usbhost");

	if (IS_ERR(s5p_ehci->clk)) {
		dev_err(&pdev->dev, "Failed to get usbhost clock\n");
		err = PTR_ERR(s5p_ehci->clk);
		goto fail_clk;
	}

	err = clk_enable(s5p_ehci->clk);
	if (err)
		goto fail_clken;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "Failed to get I/O memory\n");
		err = -ENXIO;
		goto fail_io;
	}

	hcd->rsrc_start = res->start;
	hcd->rsrc_len = resource_size(res);
	hcd->regs = ioremap(res->start, resource_size(res));
	if (!hcd->regs) {
		dev_err(&pdev->dev, "Failed to remap I/O memory\n");
		err = -ENOMEM;
		goto fail_io;
	}

	irq = platform_get_irq(pdev, 0);
	if (!irq) {
		dev_err(&pdev->dev, "Failed to get IRQ\n");
		err = -ENODEV;
		goto fail;
	}
    /* 賦值 s5p_device_ehci->dev->driver_data = s5p_ehci */
	platform_set_drvdata(pdev, s5p_ehci);
    /* 硬件相關初始化 */
	s5p_ehci_phy_init(pdev);
    {
    	struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
    	struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
    	struct usb_hcd *hcd = s5p_ehci->hcd;
    	u32 delay_count = 0;

    	if (pdata && pdata->phy_init) {
    		pdata->phy_init(pdev, S5P_USB_PHY_HOST);

    		while (!readl(hcd->regs) && delay_count < 200) {
    			delay_count++;
    			udelay(1);
    		}
    		if (delay_count)
    			dev_info(&pdev->dev, "waiting time = %d\n",
    				delay_count);
    		s5p_ehci_configurate(hcd);
    		dev_dbg(&pdev->dev, "%s : 0x%x\n", __func__,
    				readl(INSNREG00(hcd->regs)));
    	}
    }
    /* hcd->hcd_priv = ehci */
    /* 將 ehci 指向 hcd 的私有結構 hcd->hcd_priv */
	ehci = hcd_to_ehci(hcd);
	ehci->caps = hcd->regs;
	ehci->regs = hcd->regs +
		HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));

	dbg_hcs_params(ehci, "reset");
	dbg_hcc_params(ehci, "reset");

	/* cache this readonly data; minimize chip reads */
	ehci->hcs_params = readl(&ehci->caps->hcs_params);
    /* 開始註冊 hcd */
	err = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
        {
        	int retval;
        	struct usb_device *rhdev;

        	dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
            /*顯然不是無線的 hcd ,對所有設備都默認授權 */
        	hcd->authorized_default = hcd->wireless? 0 : 1;
        	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

        	/* HC is in reset state, but accessible.  Now do the one-time init,
        	 * bottom up so that hcds can customize the root hubs before khubd
        	 * starts talking to them.  (Note, bus id is assigned early too.)
        	 */
        	if ((retval = hcd_buffer_create(hcd)) != 0) {
                            {
                            	char		name[16];
                            	int		i, size;
                                /* 前面初始化 hcd->self.controller = s5p_device_ehci->dev ,而 
                                 s5p_device_ehci->dev->dma_mask = 0xffffffffUL */
                            	if (!hcd->self.controller->dma_mask &&
                            	    !(hcd->driver->flags & HCD_LOCAL_MEM))
                            		return 0;
                                /* 創建   4 個 dma_pool ,用作緩存 */
                            	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
                            		size = pool_max[i];
                            		if (!size)
                            			continue;
                            		snprintf(name, sizeof name, "buffer-%d", size);
                            		hcd->pool[i] = dma_pool_create(name, hcd->self.controller,size, size, 0);
                            		if (!hcd->pool[i]) {
                            			hcd_buffer_destroy(hcd);
                            			return -ENOMEM;
                            		}
                            	}
                            	return 0;
                            }
        		dev_dbg(hcd->self.controller, "pool alloc failed\n");
        		return retval;
        	}

        	if ((retval = usb_register_bus(&hcd->self)) < 0)
                            {
                            	int result = -E2BIG;
                            	int busnum;

                            	mutex_lock(&usb_bus_list_lock);
                                /* 找到下一個不爲 0 bit 的位置*/
                            	busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
                            	if (busnum >= USB_MAXBUS) {
                            		printk (KERN_ERR "%s: too many buses\n", usbcore_name);
                            		goto error_find_busnum;
                            	}
                                /* 將相應的 bit 置位 ,表明已經被用了 */
                            	set_bit (busnum, busmap.busmap);
                                /* 設置 usb_bus 的號*/
                            	bus->busnum = busnum;

                            	/* Add it to the local list of buses */
                                /* 將 usb0_bus 掛接到一個全局鏈表中 usb_bus_list */
                            	list_add (&bus->bus_list, &usb_bus_list);
                            	mutex_unlock(&usb_bus_list_lock);

                            	usb_notify_add_bus(bus);
                                

                            	dev_info (bus->controller, "new USB bus registered, assigned bus "
                            		  "number %d\n", bus->busnum);
                            	return 0;

                            error_find_busnum:
                            	mutex_unlock(&usb_bus_list_lock);
                            	return result;
                            }
        		goto err_register_bus;
            /* root hub 作爲 usb_device ,爲其分配結構體 並初始化 */
        	if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
                        {
                        	struct usb_device *dev;
                        	struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
                        	unsigned root_hub = 0;
                            
                        	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
                        	if (!dev)
                        		return NULL;

                        	if (!usb_get_hcd(bus_to_hcd(bus))) {
                        		kfree(dev);
                        		return NULL;
                        	}
                        	/* Root hubs aren't true devices, so don't allocate HCD resources */
                            /* usb_hcd->driver = s5p_ehci_hc_driver , s5p_ehci_hc_driver->alloc_dev = NULL */
                        	if (usb_hcd->driver->alloc_dev && parent &&
                        		!usb_hcd->driver->alloc_dev(usb_hcd, dev)) {
                        		usb_put_hcd(bus_to_hcd(bus));
                        		kfree(dev);
                        		return NULL;
                        	}

                        	device_initialize(&dev->dev);
                 
                        	dev->dev.bus = &usb_bus_type;
                            /* 注意此處,註冊爲 usb_device_type ,會匹配 usb_generic_driver 驅動 */
                        	dev->dev.type = &usb_device_type;
                            /* 設備的屬性數組,會創建相應的屬性文件    */
                        	dev->dev.groups = usb_device_groups;
                            /*  前面初始化 hcd->self.controller = s5p_device_ehci->dev ,而 
                                 s5p_device_ehci->dev->dma_mask = 0xffffffffUL 
                                 dev->dev.dma_mask = 0xffffffffUL */
                                 
                        	dev->dev.dma_mask = bus->controller->dma_mask;
                            /* numa 架構知識,用於大型多處理器系統,嵌入式一般用不到 */
                        	set_dev_node(&dev->dev, dev_to_node(bus->controller));
                            /* 初始化此 usb_device 狀態爲 USB_STATE_ATTACHED */
                        	dev->state = USB_STATE_ATTACHED;
                        	atomic_set(&dev->urbnum, 0);
                            /* 初始化 endpoint 0 */
                        	INIT_LIST_HEAD(&dev->ep0.urb_list);
                        	dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
                        	dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
                        	/* ep0 maxpacket comes later, from device descriptor */
                        	usb_enable_endpoint(dev, &dev->ep0, false);
                            {
                            	int epnum = usb_endpoint_num(&ep->desc);
                                            {
                                                /* 未初始化,返回 0 */
                                            	return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
                                            }
                            	int is_out = usb_endpoint_dir_out(&ep->desc);
                                            {
                                                /* 未初始化,結果返回 1 */
                                            	return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
                                            }
                            	int is_control = usb_endpoint_xfer_control(&ep->desc);
                                                {
                                                    /* 未初始化,返回 1 */
                                                	return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
                                                		USB_ENDPOINT_XFER_CONTROL);
                                                }
                                /* reset_ep = false */
                            	if (reset_ep)
                            		usb_hcd_reset_endpoint(dev, ep);
                                    
                            	if (is_out || is_control)
                            		dev->ep_out[epnum] = ep;
                            	if (!is_out || is_control)
                            		dev->ep_in[epnum] = ep;
                                /* endpoint 0 使能 */
                            	ep->enabled = 1;
                            }
                            /* 表明可以開始傳輸 URB */
                        	dev->can_submit = 1;

                        	/* Save readable and stable topology id, distinguishing devices
                        	 * by location for diagnostics, tools, driver model, etc.  The
                        	 * string is a path along hub ports, from the root.  Each device's
                        	 * dev->devpath will be stable until USB is re-cabled, and hubs
                        	 * are often labeled with these port numbers.  The name isn't
                        	 * as stable:  bus->busnum changes easily from modprobe order,
                        	 * cardbus or pci hotplugging, and so on.
                        	 */
                        	 /* parent = NULL */
                        	if (unlikely(!parent)) {
                        		dev->devpath[0] = '0';
                        		dev->route = 0;
                                /* bus->controller = s5p_device_ehci->dev ,意味着會在 
                                /sys/devices/platform/s5p-ehci 創建名爲 usb1 的目錄*/
                        		dev->dev.parent = bus->controller;
                                /* rhdev->kobj->name = "usb1" */
                        		dev_set_name(&dev->dev, "usb%d", bus->busnum);
                                /* root hub 已經可用 */
                        		root_hub = 1;
                        	} else {
                        		/* match any labeling on the hubs; it's one-based */
                        		if (parent->devpath[0] == '0') {
                        			snprintf(dev->devpath, sizeof dev->devpath,
                        				"%d", port1);
                        			/* Root ports are not counted in route string */
                        			dev->route = 0;
                        		} else {
                        			snprintf(dev->devpath, sizeof dev->devpath,
                        				"%s.%d", parent->devpath, port1);
                        			/* Route string assumes hubs have less than 16 ports */
                        			if (port1 < 15)
                        				dev->route = parent->route +
                        					(port1 << ((parent->level - 1)*4));
                        			else
                        				dev->route = parent->route +
                        					(15 << ((parent->level - 1)*4));
                        		}

                        		dev->dev.parent = &parent->dev;
                           
                        		dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);

                        		/* hub driver sets up TT records */
                        	}
                            
                        	dev->portnum = port1;
                            /* 此 usb_device 掛接在 usb_bus 上*/
                        	dev->bus = bus;
                            /* parent = NULL */
                        	dev->parent = parent;
                        	INIT_LIST_HEAD(&dev->filelist);

#ifdef	CONFIG_PM
                        	pm_runtime_set_autosuspend_delay(&dev->dev,
                        			usb_autosuspend_delay * 1000);
                        	dev->connect_time = jiffies;
                        	dev->active_duration = -jiffies;
#endif
                        	if (root_hub)	/* Root hub always ok [and always wired] */
                                /* 驗證通過 */
                        		dev->authorized = 1;
                        	else {
                        		dev->authorized = usb_hcd->authorized_default;
                        		dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
                        	}
                        	return dev;
                        }
        		dev_err(hcd->self.controller, "unable to allocate root hub\n");
        		retval = -ENOMEM;
        		goto err_allocate_root_hub;
        	}
        	hcd->self.root_hub = rhdev;
            /* 前面有初始化 hcd->speed = HCD_USB2 */
        	switch (hcd->speed) {
        	case HCD_USB11:
        		rhdev->speed = USB_SPEED_FULL;
        		break;
        	case HCD_USB2:
        		rhdev->speed = USB_SPEED_HIGH;
        		break;
        	case HCD_USB3:
        		rhdev->speed = USB_SPEED_SUPER;
        		break;
        	default:
        		retval = -EINVAL;
        		goto err_set_rh_speed;
        	}

        	/* wakeup flag init defaults to "everything works" for root hubs,
        	 * but drivers can override it in reset() if needed, along with
        	 * recording the overall controller's system wakeup capability.
        	 */
        	device_init_wakeup(&rhdev->dev, 1);

        	/* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is
        	 * registered.  But since the controller can die at any time,
        	 * let's initialize the flag before touching the hardware.
        	 */
        	 /* 設置 root hub 已經在運行狀態 */
        	set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);

        	/* "reset" is misnamed; its role is now one-time init. the controller
        	 * should already have been reset (and boot firmware kicked off etc).
        	 */
        	 /* hcd->driver->reset = ehci_init */
        	if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
        		dev_err(hcd->self.controller, "can't setup\n");
        		goto err_hcd_driver_setup;
        	}
            /* root hub 可以被輪詢 */
        	hcd->rh_pollable = 1;

        	/* NOTE: root hub and controller capabilities may not be the same */
        	if (device_can_wakeup(hcd->self.controller)&& device_can_wakeup(&hcd->self.root_hub->dev))
        		dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");

        	/* enable irqs just before we start the controller,
        	 * if the BIOS provides legacy PCI irqs.
        	 */
        	if (usb_hcd_is_primary_hcd(hcd) && irqnum) {
        		retval = usb_hcd_request_irqs(hcd, irqnum, irqflags);
        		if (retval)
        			goto err_request_irq;
        	}
            /* 設置 usb 控制器的狀態爲 運行態*/
        	hcd->state = HC_STATE_RUNNING;
            /* hcd->driver->start = ehci_run */
        	retval = hcd->driver->start(hcd);
        	if (retval < 0) {
        		dev_err(hcd->self.controller, "startup error %d\n", retval);
        		goto err_hcd_driver_start;
        	}

        	/* starting here, usbcore will pay attention to this root hub */
            /*可從 root hub 上獲取的電流*/
        	rhdev->bus_mA = min(500u, hcd->power_budget);
            /* 註冊 root hub*/
        	if ((retval = register_root_hub(hcd)) != 0)
                         {
                        	struct device *parent_dev = hcd->self.controller;
                        	struct usb_device *usb_dev = hcd->self.root_hub;
                        	const int devnum = 1;
                        	int retval;
                            /*root hub 是 該 usb_bus 上的第一個設備*/
                        	usb_dev->devnum = devnum;
                            
                        	usb_dev->bus->devnum_next = devnum + 1;
                        	memset (&usb_dev->bus->devmap.devicemap, 0,
                        			sizeof usb_dev->bus->devmap.devicemap);
                        	set_bit (devnum, usb_dev->bus->devmap.devicemap);
                        	usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
                            {
                            	unsigned long flags;
                            	int wakeup = -1;

                            	spin_lock_irqsave(&device_state_lock, flags);
                                /* 前面已經初始化過 usb_dev->state = USB_STATE_ATTACHED */
                            	if (udev->state == USB_STATE_NOTATTACHED)
                            		;	/* do nothing */
                                /* new_state = USB_STATE_ADDRESS */
                            	else if (new_state != USB_STATE_NOTATTACHED) {

                            		/* root hub wakeup capabilities are managed out-of-band
                            		 * and may involve silicon errata ... ignore them here.
                            		 */
                            		 /*前邊有初始化 udev->parent = NULL */
                            		if (udev->parent) {
                            			if (udev->state == USB_STATE_SUSPENDED
                            					|| new_state == USB_STATE_SUSPENDED)
                            				;	/* No change to wakeup settings */
                            			else if (new_state == USB_STATE_CONFIGURED)
                            				wakeup = udev->actconfig->desc.bmAttributes
                            					 & USB_CONFIG_ATT_WAKEUP;
                            			else
                            				wakeup = 0;
                            		}
                            		if (udev->state == USB_STATE_SUSPENDED &&
                            			new_state != USB_STATE_SUSPENDED)
                            			udev->active_duration -= jiffies;
                            		else if (new_state == USB_STATE_SUSPENDED &&
                            				udev->state != USB_STATE_SUSPENDED)
                            			udev->active_duration += jiffies;
                            		udev->state = new_state;
                            	} 
                                else
                            		recursively_mark_NOTATTACHED(udev);
                            	spin_unlock_irqrestore(&device_state_lock, flags);
                            	if (wakeup >= 0)
                            		device_set_wakeup_capable(&udev->dev, wakeup);
                            }

                        	mutex_lock(&usb_bus_list_lock);
                            /* endpoint 0 通信最大包長度爲 64 */
                        	usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
                            /* 獲取設備描述符 */
                        	retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
                                    {
                                    	struct usb_device_descriptor *desc;
                                    	int ret;

                                    	if (size > sizeof(*desc))
                                    		return -EINVAL;
                                    	desc = kmalloc(sizeof(*desc), GFP_NOIO);
                                    	if (!desc)
                                    		return -ENOMEM;
                                        /* 獲取設備描述符 */
                                    	ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);
                                            {
                                            	int i;
                                            	int result;

                                            	memset(buf, 0, size);	/* Make sure we parse really received data */

                                            	for (i = 0; i < 3; ++i) {
                                            		/* retry on length 0 or error; some devices are flakey */
                                            		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
                                            		USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,(type << 8) + index, 
                                            		0, buf, size,USB_CTRL_GET_TIMEOUT);
                                            		if (result <= 0 && result != -ETIMEDOUT)
                                            			continue;
                                            		if (result > 1 && ((u8 *)buf)[1] != type) {
                                            			result = -ENODATA;
                                            			continue;
                                            		}
                                            		break;
                                            	}
                                            	return result;
                                            }
                                    	if (ret >= 0)
                                            /* 將獲取到的設備描述符賦值給 usb_dev->descriptor */
                                    		memcpy(&dev->descriptor, desc, size);
                                    	kfree(desc);
                                    	return ret;
                                    }
                        	if (retval != sizeof usb_dev->descriptor) {
                        		mutex_unlock(&usb_bus_list_lock);
                        		dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
                        				dev_name(&usb_dev->dev), retval);
                        		return (retval < 0) ? retval : -EMSGSIZE;
                        	}

                        	retval = usb_new_device (usb_dev);
                                    {
                                    	int err;
                                        /* udev->parent = NULL */
                                    	if (udev->parent) {
                                    		/* Initialize non-root-hub device wakeup to disabled;
                                    		 * device (un)configuration controls wakeup capable
                                    		 * sysfs power/wakeup controls wakeup enabled/disabled
                                    		 */
                                    		device_init_wakeup(&udev->dev, 0);
                                    	}

                                    	/* Tell the runtime-PM framework the device is active */
                                    	pm_runtime_set_active(&udev->dev);
                                    	pm_runtime_get_noresume(&udev->dev);
                                    	pm_runtime_use_autosuspend(&udev->dev);
                                    	pm_runtime_enable(&udev->dev);

                                    	/* By default, forbid autosuspend for all devices.  It will be
                                    	 * allowed for hubs during binding.
                                    	 */
                                    	usb_disable_autosuspend(udev);
                                        /* 枚舉 usb 設備*/
                                    	err = usb_enumerate_device(udev);	/* Read descriptors */
                                                {
                                                	int err;
                                                    /**/
                                                	if (udev->config == NULL) {
                                                        /* 獲取配置描述符 */
                                                		err = usb_get_configuration(udev);
                                                		if (err < 0) {
                                                			dev_err(&udev->dev, "can't read configurations, error %d\n",
                                                				err);
                                                			goto fail;
                                                		}
                                                	}
                                                	if (udev->wusb == 1 && udev->authorized == 0) {
                                                		udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
                                                		udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
                                                		udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
                                                	}
                                                	else {
                                                		/* read the standard strings and cache them if present */
                                                		udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
                                                		udev->manufacturer = usb_cache_string(udev,
                                                						      udev->descriptor.iManufacturer);
                                                		udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
                                                	}
                                                    /* 枚舉 otg 設備 */
                                                	err = usb_enumerate_device_otg(udev);
                                                fail:
                                                	return err;
                                                }
                                    	if (err < 0)
                                    		goto fail;
                                    	dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
                                    			udev->devnum, udev->bus->busnum,
                                    			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
                                    	/* export the usbdev device-node for libusb */
                                        /* 設置設備號 udev->dev.devt = 189 :0 */
                                    	udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
                                    			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));

                                    	/* Tell the world! */
                                    	announce_device(udev);
                                        {
                                        	dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
                                        		le16_to_cpu(udev->descriptor.idVendor),
                                        		le16_to_cpu(udev->descriptor.idProduct));
                                        	dev_info(&udev->dev,
                                        		"New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
                                        		udev->descriptor.iManufacturer,
                                        		udev->descriptor.iProduct,
                                        		udev->descriptor.iSerialNumber);
                                        	show_string(udev, "Product", udev->product);
                                        	show_string(udev, "Manufacturer", udev->manufacturer);
                                        	show_string(udev, "SerialNumber", udev->serial);
                                        }
                                #ifdef CONFIG_SAMSUNG_SMARTDOCK
                                    	call_battery_notify(udev, 1);
                                #endif

                                    	if (udev->serial)
                                    		add_device_randomness(udev->serial, strlen(udev->serial));
                                    	if (udev->product)
                                    		add_device_randomness(udev->product, strlen(udev->product));
                                    	if (udev->manufacturer)
                                    		add_device_randomness(udev->manufacturer,
                                    				      strlen(udev->manufacturer));

                                    	device_enable_async_suspend(&udev->dev);
                                    	/* Register the device.  The device driver is responsible
                                    	 * for configuring the device and invoking the add-device
                                    	 * notifier chain (used by usbfs and possibly others).
                                    	 */
                                    	 /* 註冊 udev->dev 並創建相關文件,會匹配上 usb_generic_driver 驅動,並
                                        調用 generic_probe 函數 */
                                    	err = device_add(&udev->dev);
                                            {
                                                /* usb_device_match 會根據 dev->type 決定匹配設備驅動還是interface 驅動
                                                所有的 usb 設備都是先匹配 usb_device_type 類型,然後調用到 generic_probe ,根據
                                                generic_probe 函數解析出的 interface ,匹配 usb_if_device_type 調用到具體 驅動的 probe
                                                驅動開發主要是完成一個個 interface 的驅動*/
                                                usb_device_match(struct device *dev, struct device_driver *drv)
                                                {
                                                	/* devices and interfaces are handled separately */
                                                    /* 是否是 usb_device_type 設備*/
                                                	if (is_usb_device(dev)) {
                                                        {
                                                        	return dev->type == &usb_device_type;
                                                        }

                                                		.......
                                                    /* 是否是 usb_if_device_type 設備*/
                                                	} else if (is_usb_interface(dev)) {
                                                	        {
                                                            	return dev->type == &usb_if_device_type;
                                                            }
                                                		
                                                	}

                                                	return 0;
                                                }

                                                ......
                                                
                                                generic_probe(struct usb_device *udev)
                                                {
                                                	int err, c;

                                                	/* Choose and set the configuration.  This registers the interfaces
                                                	 * with the driver core and lets interface drivers bind to them.
                                                	 */
                                                	if (usb_device_is_owned(udev))
                                                        {
                                                        	struct usb_hub *hub;
                                                           /* dev->state = USB_STATE_ATTACHED , udev->parent = NULL */
                                                        	if (udev->state == USB_STATE_NOTATTACHED || !udev->parent)
                                                        		return false;
                                                        	hub = hdev_to_hub(udev->parent);
                                                        	return !!hub->port_owners[udev->portnum - 1];
                                                        }
                                                		;		/* Don't configure if the device is owned */
                                                	else if (udev->authorized == 0)
                                                		dev_err(&udev->dev, "Device is not authorized for usage\n");
                                                	else {
                                                        /* 選擇一個配置 */
                                                		c = usb_choose_configuration(udev);
                                                		if (c >= 0) {
                                                			err = usb_set_configuration(udev, c);
                                                                {
                                                                	int i, ret;
                                                                	struct usb_host_config *cp = NULL;
                                                                	struct usb_interface **new_interfaces = NULL;
                                                                	struct usb_hcd *hcd = bus_to_hcd(dev->bus);
                                                                	int n, nintf;
                                                                    /* 前面有初始化 dev->authorized = 1*/
                                                                	if (dev->authorized == 0 || configuration == -1)
                                                                		configuration = 0;
                                                                	else {
                                                                        /* 檢索出來 選中的配置 */
                                                                		for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
                                                                			if (dev->config[i].desc.bConfigurationValue ==
                                                                					configuration) {
                                                                				cp = &dev->config[i];
                                                                				break;
                                                                			}
                                                                		}
                                                                	}
                                                                	if ((!cp && configuration != 0))
                                                                		return -EINVAL;

                                                                	/* The USB spec says configuration 0 means unconfigured.
                                                                	 * But if a device includes a configuration numbered 0,
                                                                	 * we will accept it as a correctly configured state.
                                                                	 * Use -1 if you really want to unconfigure the device.
                                                                	 */
                                                                	/* usb 標準定義 configuration 意味着未配置,但是在此仍然將接受
                                                                	configuration 爲 0,如果真的想不配置此設備 ,可以將 configuration 置爲 -1 */
                                                                	if (cp && configuration == 0)
                                                                		dev_warn(&dev->dev, "config 0 descriptor??\n");

                                                                	/* Allocate memory for new interfaces before doing anything else,
                                                                	 * so that if we run out then nothing will have changed. */
                                                                	n = nintf = 0;
                                                                	if (cp) {
                                                                        /* 下面爲該 config 包含的所有 interface 分配空間 */
                                                                		nintf = cp->desc.bNumInterfaces;
                                                                		new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),
                                                                				GFP_NOIO);
                                                                		if (!new_interfaces) {
                                                                			dev_err(&dev->dev, "Out of memory\n");
                                                                			return -ENOMEM;
                                                                		}

                                                                		for (; n < nintf; ++n) {
                                                                			new_interfaces[n] = kzalloc(
                                                                					sizeof(struct usb_interface),
                                                                					GFP_NOIO);
                                                                			if (!new_interfaces[n]) {
                                                                				dev_err(&dev->dev, "Out of memory\n");
                                                                				ret = -ENOMEM;
                                                                free_interfaces:
                                                                				while (--n >= 0)
                                                                					kfree(new_interfaces[n]);
                                                                				kfree(new_interfaces);
                                                                				return ret;
                                                                			}
                                                                		}
                                                                        /* 計算電流是否超過提供的範圍 */
                                                                		i = dev->bus_mA - cp->desc.bMaxPower * 2;
                                                                		if (i < 0)
                                                                			dev_warn(&dev->dev, "new config #%d exceeds power "
                                                                					"limit by %dmA\n",
                                                                					configuration, -i);
                                                                	}

                                                                	/* Wake up the device so we can send it the Set-Config request */
                                                                    /*喚醒設備*/
                                                                	ret = usb_autoresume_device(dev);
                                                                	if (ret)
                                                                		goto free_interfaces;

                                                                	/* if it's already configured, clear out old state first.
                                                                	 * getting rid of old interfaces means unbinding their drivers.
                                                                	 */
                                                                	 /* 恰面已經設置過 usb_dev->state = USB_STATE_ADDRESS */
                                                                	if (dev->state != USB_STATE_ADDRESS)
                                                                		usb_disable_device(dev, 1);	/* Skip ep0 */

                                                                	/* Get rid of pending async Set-Config requests for this device */
                                                                    /* 取消已經改變過配置設備掛起的 Set-Config 請求*/
                                                                	cancel_async_set_config(dev);

                                                                	/* Make sure we have bandwidth (and available HCD resources) for this
                                                                	 * configuration.  Remove endpoints from the schedule if we're dropping
                                                                	 * this configuration to set configuration 0.  After this point, the
                                                                	 * host controller will not allow submissions to dropped endpoints.  If
                                                                	 * this call fails, the device state is unchanged.
                                                                	 */
                                                                	mutex_lock(hcd->bandwidth_mutex);
                                                                	ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
                                                                	if (ret < 0) {
                                                                		mutex_unlock(hcd->bandwidth_mutex);
                                                                		usb_autosuspend_device(dev);
                                                                		goto free_interfaces;
                                                                	}

                                                                	/*
                                                                	 * Initialize the new interface structures and the
                                                                	 * hc/hcd/usbcore interface/endpoint state.
                                                                	 */
                                                                	 /*將 configuration 中 interface 註冊成 device ,類型爲   usb_if_device_type
                                                                    將會匹配到 hub_driver ,調用 hub_probe ,完成 hub 的初始化 */
                                                                	for (i = 0; i < nintf; ++i) {
                                                                		struct usb_interface_cache *intfc;
                                                                		struct usb_interface *intf;
                                                                		struct usb_host_interface *alt;

                                                                		cp->interface[i] = intf = new_interfaces[i];
                                                                		intfc = cp->intf_cache[i];
                                                                		intf->altsetting = intfc->altsetting;
                                                                		intf->num_altsetting = intfc->num_altsetting;
                                                                		kref_get(&intfc->ref);

                                                                		alt = usb_altnum_to_altsetting(intf, 0);

                                                                		/* No altsetting 0?  We'll assume the first altsetting.
                                                                		 * We could use a GetInterface call, but if a device is
                                                                		 * so non-compliant that it doesn't have altsetting 0
                                                                		 * then I wouldn't trust its reply anyway.
                                                                		 */
                                                                		if (!alt)
                                                                			alt = &intf->altsetting[0];

                                                                		intf->intf_assoc =
                                                                			find_iad(dev, cp, alt->desc.bInterfaceNumber);
                                                                		intf->cur_altsetting = alt;
                                                                		usb_enable_interface(dev, intf, true);
                                                                		intf->dev.parent = &dev->dev;
                                                                		intf->dev.driver = NULL;
                                                                		intf->dev.bus = &usb_bus_type;
                                                                		intf->dev.type = &usb_if_device_type;
                                                                		intf->dev.groups = usb_interface_groups;
                                                                		intf->dev.dma_mask = dev->dev.dma_mask;
                                                                		INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
                                                                		intf->minor = -1;
                                                                		device_initialize(&intf->dev);
                                                                		pm_runtime_no_callbacks(&intf->dev);
                                                                		dev_set_name(&intf->dev, "%d-%s:%d.%d",
                                                                			dev->bus->busnum, dev->devpath,
                                                                			configuration, alt->desc.bInterfaceNumber);
                                                                	}
                                                                	kfree(new_interfaces);
                                                                    /* 設置 configuration */
                                                                	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                                                                			      USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
                                                                			      NULL, 0, USB_CTRL_SET_TIMEOUT);
                                                                	if (ret < 0 && cp) {
                                                                		/*
                                                                		 * All the old state is gone, so what else can we do?
                                                                		 * The device is probably useless now anyway.
                                                                		 */
                                                                		usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
                                                                		for (i = 0; i < nintf; ++i) {
                                                                			usb_disable_interface(dev, cp->interface[i], true);
                                                                			put_device(&cp->interface[i]->dev);
                                                                			cp->interface[i] = NULL;
                                                                		}
                                                                		cp = NULL;
                                                                	}

                                                                	dev->actconfig = cp;
                                                                	mutex_unlock(hcd->bandwidth_mutex);

                                                                	if (!cp) {
                                                                		usb_set_device_state(dev, USB_STATE_ADDRESS);

                                                                		/* Leave LPM disabled while the device is unconfigured. */
                                                                		usb_autosuspend_device(dev);
                                                                		return ret;
                                                                	}
                                                                	usb_set_device_state(dev, USB_STATE_CONFIGURED);

                                                                	if (cp->string == NULL &&
                                                                			!(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
                                                                		cp->string = usb_cache_string(dev, cp->desc.iConfiguration);

                                                                	/* Now that all the interfaces are set up, register them
                                                                	 * to trigger binding of drivers to interfaces.  probe()
                                                                	 * routines may install different altsettings and may
                                                                	 * claim() any interfaces not yet bound.  Many class drivers
                                                                	 * need that: CDC, audio, video, etc.
                                                                	 */
                                                                	for (i = 0; i < nintf; ++i) {
                                                                		struct usb_interface *intf = cp->interface[i];

                                                                		dev_dbg(&dev->dev,
                                                                			"adding %s (config #%d, interface %d)\n",
                                                                			dev_name(&intf->dev), configuration,
                                                                			intf->cur_altsetting->desc.bInterfaceNumber);
                                                                		device_enable_async_suspend(&intf->dev);
                                                                        /* 註冊 interface ,會匹配調用到 hub_probe */
                                                                		ret = device_add(&intf->dev);
                                                                                  
                                                                		if (ret != 0) {
                                                                			dev_err(&dev->dev, "device_add(%s) --> %d\n",
                                                                				dev_name(&intf->dev), ret);
                                                                			continue;
                                                                		}
                                                                    #ifdef CONFIG_HOST_COMPLIANT_TEST
                                                                		if (usb_get_intfdata(intf) == NULL ) {
                                                                		       dev_info( &intf->dev, "%s : Not match interface - driver detect fail\n",__func__);
                                                                		}
                                                                    #endif
                                                                		create_intf_ep_devs(intf);
                                                                	}

                                                                	usb_autosuspend_device(dev);
                                                                	return 0;
                                                                }
                                                			if (err) {
                                                				dev_err(&udev->dev, "can't set config #%d, error %d\n",
                                                					c, err);
                                                				/* This need not be fatal.  The user can try to
                                                				 * set other configurations. */
                                                			}
                                                		}
                                                	}
                                                	/* USB device state == configured ... usable */
                                                	usb_notify_add_device(udev);

                                                	return 0;
                                                }

                                                ......
                                            }   
                                    	if (err) {
                                    		dev_err(&udev->dev, "can't device_add, error %d\n", err);
                                    		goto fail;
                                    	}
                                        /* endpoint 也是 device */
                                    	(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
                                                
                                    	usb_mark_last_busy(udev);
                                    	pm_runtime_put_sync_autosuspend(&udev->dev);
                                    	return err;

                                    fail:
                                    	usb_set_device_state(udev, USB_STATE_NOTATTACHED);
                                    	pm_runtime_disable(&udev->dev);
                                    	pm_runtime_set_suspended(&udev->dev);
                                    	return err;
                                    }
                        	if (retval) {
                        		dev_err (parent_dev, "can't register root hub for %s, %d\n",
                        				dev_name(&usb_dev->dev), retval);
                        	} else {
                        		spin_lock_irq (&hcd_root_hub_lock);
                                /* root hub 已註冊 */
                        		hcd->rh_registered = 1;
                        		spin_unlock_irq (&hcd_root_hub_lock);

                        		/* Did the HC die before the root hub was registered? */
                        		if (HCD_DEAD(hcd))
                        			usb_hc_died (hcd);	/* This time clean up */
                        	}
                        	mutex_unlock(&usb_bus_list_lock);

                        	return retval;
                        }
        		goto err_register_root_hub;
            /* 創建屬性文件 */
        	retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
        	if (retval < 0) {
        		printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
        		       retval);
        		goto error_create_attr_group;
        	}
        	if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
                /* 控制器 輪詢 root hub 的狀態 */
        		usb_hcd_poll_rh_status(hcd);
               {
                   struct urb	*urb;
                   int		length;
                   unsigned long	flags;
                   char		buffer[6];	/* Any root hubs with > 31 ports? */
                   /* 不可以輪詢 root hub 直接返回 */
                   if (unlikely(!hcd->rh_pollable))
                   	return;
                   if (!hcd->uses_new_polling && !hcd->status_urb)
                   	return;
                   /* hcd->driver->hub_status_data = ehci_hub_status_data 
                   獲取 hub 的狀態 */
                   length = hcd->driver->hub_status_data(hcd, buffer);
                           {
                           	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
                           	u32		temp, status = 0;
                           	u32		mask;
                           	int		ports, i, retval = 1;
                           	unsigned long	flags;
                           	u32		ppcd = 0;

                           	/* if !USB_SUSPEND, root hub timers won't get shut down ... */
                           	if (!HC_IS_RUNNING(hcd->state))
                           		return 0;

                           	/* init status to no-changes */
                           	buf [0] = 0;
                               /* 獲取port 數*/
                           	ports = HCS_N_PORTS (ehci->hcs_params);
                           	if (ports > 7) {
                           		buf [1] = 0;
                           		retval++;
                           	}

                           	/* Some boards (mostly VIA?) report bogus overcurrent indications,
                           	 * causing massive log spam unless we completely ignore them.  It
                           	 * may be relevant that VIA VT8235 controllers, where PORT_POWER is
                           	 * always set, seem to clear PORT_OCC and PORT_CSC when writing to
                           	 * PORT_POWER; that's surprising, but maybe within-spec.
                           	 */
                           	/* 是否忽略過流變化 */
                           	if (!ignore_oc)
                           		mask = PORT_CSC | PORT_PEC | PORT_OCC;
                           	else
                           		mask = PORT_CSC | PORT_PEC;
                           	// PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND

                           	/* no hub change reports (bit 0) for now (power, ...) */

                           	/* port N changes (bit N)? */
                           	spin_lock_irqsave (&ehci->lock, flags);

                           	/* get per-port change detect bits */
                           	if (ehci->has_ppcd)
                           		ppcd = ehci_readl(ehci, &ehci->regs->status) >> 16;

                           	for (i = 0; i < ports; i++) {
                           		/* leverage per-port change bits feature */
                           		if (ehci->has_ppcd && !(ppcd & (1 << i)))
                           			continue;
                           		temp = ehci_readl(ehci, &ehci->regs->port_status [i]);

                           		/*
                           		 * Return status information even for ports with OWNER set.
                           		 * Otherwise khubd wouldn't see the disconnect event when a
                           		 * high-speed device is switched over to the companion
                           		 * controller by the user.
                           		 */

                           		if ((temp & mask) != 0 || test_bit(i, &ehci->port_c_suspend)
                           				|| (ehci->reset_done[i] && time_after_eq(
                           					jiffies, ehci->reset_done[i]))) {
                           			if (i < 7)
                           			    buf [0] |= 1 << (i + 1);
                           			else
                           			    buf [1] |= 1 << (i - 7);
                                       /* 檢測到端口變化 */
                           			status = STS_PCD;
                           		}
                           	}
                           	/* FIXME autosuspend idle root hubs */
                           	spin_unlock_irqrestore (&ehci->lock, flags);
                           	return status ? retval : 0;
                           }
                   if (length > 0) {

                   	/* try to complete the status urb */
                   	spin_lock_irqsave(&hcd_root_hub_lock, flags);
                   	urb = hcd->status_urb;
                   	if (urb) {
                   		clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
                   		hcd->status_urb = NULL;
                   		urb->actual_length = length;
                   		memcpy(urb->transfer_buffer, buffer, length);

                   		usb_hcd_unlink_urb_from_ep(hcd, urb);
                   		spin_unlock(&hcd_root_hub_lock);
                   		usb_hcd_giveback_urb(hcd, urb, 0);
                        {
                        	urb->hcpriv = NULL;
                        	if (unlikely(urb->unlinked))
                        		status = urb->unlinked;
                        	else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
                        			urb->actual_length < urb->transfer_buffer_length &&
                        			!status))
                        		status = -EREMOTEIO;

                        	unmap_urb_for_dma(hcd, urb);
                            /*調用urb完成函數 ,也是就是 hub_irq , hub_driver 中有設置*/
                        	usbmon_urb_complete(&hcd->self, urb, status);
                            /* hub_irq */
                            {
                            	struct usb_hub *hub = urb->context;
                            	int status = urb->status;
                            	unsigned i;
                            	unsigned long bits;

                            	switch (status) {
                            	case -ENOENT:		/* synchronous unlink */
                            	case -ECONNRESET:	/* async unlink */
                            	case -ESHUTDOWN:	/* hardware going away */
                            		return;

                            	default:		/* presumably an error */
                            		/* Cause a hub reset after 10 consecutive errors */
                                /* 連續10次錯誤引起一次 hub reset */
                            		dev_dbg (hub->intfdev, "transfer --> %d\n", status);
                            		if ((++hub->nerrors < 10) || hub->error)
                            			goto resubmit;
                            		hub->error = status;
                            		/* FALL THROUGH */

                            	/* let khubd handle things */
                            	case 0:			/* we got data:  port status changed */
                            		bits = 0;
                            		for (i = 0; i < urb->actual_length; ++i)
                            			bits |= ((unsigned long) ((*hub->buffer)[i]))
                            					<< (i*8);
                            		hub->event_bits[0] = bits;
                            		break;
                            	}

                            	hub->nerrors = 0;

                            	/* Something happened, let khubd figure it out */
                                /*喚醒 khubd 線程,也就是執行 hub_thread 函數,在usb_init中創建  */
                            	kick_khubd(hub);
                                
                            /* 重新提交 該 urb */
                            resubmit:
                            	if (hub->quiescing)
                            		return;

                            	if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
                            			&& status != -ENODEV && status != -EPERM)
                            		dev_err (hub->intfdev, "resubmit --> %d\n", status);
                            }
                            
                        	usb_unanchor_urb(urb);

                        	/* pass ownership to the completion handler */
                        	urb->status = status;
                        	urb->complete (urb);
                        	atomic_dec (&urb->use_count);
                        	if (unlikely(atomic_read(&urb->reject)))
                        		wake_up (&usb_kill_urb_queue);
                        	usb_put_urb (urb);
                        }
                   		spin_lock(&hcd_root_hub_lock);
                   	} else {
                   		length = 0;
                   		set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
                   	}
                   	spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
                   }

                   /* The USB 2.0 spec says 256 ms.  This is close enough and won't
                    * exceed that limit if HZ is 100. The math is more clunky than
                    * maybe expected, this is to make sure that all timers for USB devices
                    * fire at the same time to give the CPU a break in between */
                   if (hcd->uses_new_polling ? HCD_POLL_RH(hcd) :
                   		(length == 0 && hcd->status_urb != NULL))
                  /* 更改定時器時間,並激活定時器    */
                  mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
              }
        	return retval;

        error_create_attr_group:
        	clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
        	if (HC_IS_RUNNING(hcd->state))
        		hcd->state = HC_STATE_QUIESCING;
        	spin_lock_irq(&hcd_root_hub_lock);
        	hcd->rh_registered = 0;
        	spin_unlock_irq(&hcd_root_hub_lock);

#ifdef CONFIG_USB_SUSPEND
        	cancel_work_sync(&hcd->wakeup_work);
#endif
        	mutex_lock(&usb_bus_list_lock);
        	usb_disconnect(&rhdev);		/* Sets rhdev to NULL */
        	mutex_unlock(&usb_bus_list_lock);
        err_register_root_hub:
        	hcd->rh_pollable = 0;
        	clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
        	del_timer_sync(&hcd->rh_timer);
        	hcd->driver->stop(hcd);
        	hcd->state = HC_STATE_HALT;
        	clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
        	del_timer_sync(&hcd->rh_timer);
        err_hcd_driver_start:
        	if (usb_hcd_is_primary_hcd(hcd) && hcd->irq >= 0)
        		free_irq(irqnum, hcd);
        err_request_irq:
        err_hcd_driver_setup:
        err_set_rh_speed:
        	usb_put_dev(hcd->self.root_hub);
        err_allocate_root_hub:
        	usb_deregister_bus(&hcd->self);
        err_register_bus:
        	hcd_buffer_destroy(hcd);
        	return retval;
        }
	if (err) {
		dev_err(&pdev->dev, "Failed to add USB HCD\n");
		goto fail;
	}

	create_ehci_sys_file(ehci);
    {
    #if defined(CONFIG_LINK_DEVICE_HSIC) || defined(CONFIG_LINK_DEVICE_USB)
    	BUG_ON(device_create_file(ehci_to_hcd(ehci)->self.controller,
    			&dev_attr_port_power));
    #endif
    	return device_create_file(ehci_to_hcd(ehci)->self.controller,
    			&dev_attr_ehci_power);
    }
	s5p_ehci->power_on = 1;

#ifdef CONFIG_USB_SUSPEND
	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(&pdev->dev);
#endif
#ifdef CONFIG_MDM_HSIC_PM
	/* halt controller before driving suspend on ths bus */
	ehci->susp_sof_bug = 1;

	set_host_stat(hsic_pm_dev, POWER_ON);
	pm_runtime_allow(&pdev->dev);
	pm_runtime_set_autosuspend_delay(&hcd->self.root_hub->dev, 0);

	pm_runtime_forbid(&pdev->dev);
	enable_periodic(ehci);
#endif

#ifdef CONFIG_EHCI_IRQ_DISTRIBUTION
	if (num_possible_cpus() > 1) {
		s5p_ehci_irq_no = irq;
		s5p_ehci_irq_cpu = s5p_ehci_cpus[num_possible_cpus() - 1];
		irq_set_affinity(s5p_ehci_irq_no, cpumask_of(s5p_ehci_irq_cpu));
		register_cpu_notifier(&s5p_ehci_cpu_notifier);
	}
#endif

#if defined(CONFIG_LINK_DEVICE_HSIC) || defined(CONFIG_LINK_DEVICE_USB)
	/* for cp enumeration */
	pm_runtime_forbid(&pdev->dev);
	/*HSIC IPC control the ACTIVE_STATE*/
	if (pdata && pdata->noti_host_states)
		pdata->noti_host_states(pdev, S5P_HOST_ON);
#endif

	return 0;

fail:
	iounmap(hcd->regs);
fail_io:
	clk_disable(s5p_ehci->clk);
fail_clken:
	clk_put(s5p_ehci->clk);
fail_clk:
	usb_put_hcd(hcd);
fail_hcd:
	kfree(s5p_ehci);
	return err;
}

總結一下,s5p_ehci_probe 主要做了以下工作:
1. 爲 USB 控制器分配了 usb_hcd 並初始化,初始化中註冊了一個輪詢 root hub 狀態的定時器。
2. 硬件相關初始化
3. 註冊 usb_hcd 爲 usb_bus ,分配緩存等,一個 usb 控制器本身就是一條總線。
4. 爲 root hub 申請 usb_device ( hub 本身也是 usb 設備)並初始化相應成員。
5. root hub 硬件相關初始化
6. 註冊 root hub ,其中包括獲取 Device_Descriptor ,枚舉設備,獲取 Configruation_Descriptor ;
   device_add 後,將先匹配到 usb_generic_driver 並調用到 generic_probe ,
   其爲 root 選中一個配置並配置進去,將每一個 配置下的 interface 都註冊爲 usb_device ,類型爲 usb_if_device_type
   ,然後匹配到 hub_driver 調用到 hub_probe 爲 root hub 進行一系列的初始化。所有的 usb 設備被識別後都會先 匹配 usb_generic_driver
   然後再匹配 interface 驅動,而驅動開發工作就是對 usb 設備裏的 interface 進行。
7. 激活定時器,定時查詢 root hub 的狀態,狀態有變就 調用 hub_irq 激活 usb_init 中創建的 khubd 線程,進行設備枚舉並匹配驅動。

三、hub_thread

下面在看一下 khubd 線程的執行函數 hub_thread ,下面獲取到的 hub 狀態有多種,這裏主要是關注 插入設備的事件 ,像喚醒和過流之類的不再分析。

static int hub_thread(void *__unused)
{
	/* khubd needs to be freezable to avoid intefering with USB-PERSIST
	 * port handover.  Otherwise it might see that a full-speed device
	 * was gone before the EHCI controller had handed its port over to
	 * the companion full-speed controller.
	 */
	set_freezable();
    /* 處理事件 */
	do {
		hub_events();
        {
        	struct list_head *tmp;
        	struct usb_device *hdev;
        	struct usb_interface *intf;
        	struct usb_hub *hub;
        	struct device *hub_dev;
        	u16 hubstatus;
        	u16 hubchange;
        	u16 portstatus;
        	u16 portchange;
        	int i, ret;
        	int connect_change;

        	/*
        	 *  We restart the list every time to avoid a deadlock with
        	 * deleting hubs downstream from this one. This should be
        	 * safe since we delete the hub from the event list.
        	 * Not the most efficient, but avoids deadlocks.
        	 */
        	while (1) {

        		/* Grab the first entry at the beginning of the list */
                  /* 如果 hub_event_list 爲空的時候,直接跳出 while 循環*/
        		spin_lock_irq(&hub_event_lock);
        		if (list_empty(&hub_event_list)) {
        			spin_unlock_irq(&hub_event_lock);
        			break;
        		}
                /* 將事件刪除並初始化 */
        		tmp = hub_event_list.next;
        		list_del_init(tmp);
                /*獲取該 event 所在的 hub */
        		hub = list_entry(tmp, struct usb_hub, event_list);
                /* 增加引用計數 */
        		kref_get(&hub->kref);
        		spin_unlock_irq(&hub_event_lock);

        		hdev = hub->hdev;
        		hub_dev = hub->intfdev;
        		intf = to_usb_interface(hub_dev);
        		dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
        				hdev->state, hub->descriptor
        					? hub->descriptor->bNbrPorts
        					: 0,
        				/* NOTE: expects max 15 ports... */
        				(u16) hub->change_bits[0],
        				(u16) hub->event_bits[0]);

        		/* Lock the device, then check to see if we were
        		 * disconnected while waiting for the lock to succeed. */
        		usb_lock_device(hdev);
        		if (unlikely(hub->disconnected))
        			goto loop_disconnected;

        		/* If the hub has died, clean up after it */
                /* 如果 hub 的狀態是 USB_STATE_NOTATTACHED ,則 hub 出錯,並    DISCONNECT  */
        		if (hdev->state == USB_STATE_NOTATTACHED) {
        			hub->error = -ENODEV;
        			hub_quiesce(hub, HUB_DISCONNECT);
        			goto loop;
        		}

        		/* Autoresume */
                /* 喚醒 hub 並增加 hub interface  的 PM-usage */
        		ret = usb_autopm_get_interface(intf);
        		if (ret) {
        			dev_dbg(hub_dev, "Can't autoresume: %d\n", ret);
        			goto loop;
        		}

        		/* If this is an inactive hub, do nothing */
                /* hub 沒激活,啥也不幹 */
        		if (hub->quiescing)
        			goto loop_autopm;
                /* hub 出錯, Reset 一下 */
        		if (hub->error) {
        			dev_dbg (hub_dev, "resetting for error %d\n",
        				hub->error);

        			ret = usb_reset_device(hdev);
        			if (ret) {
        				dev_dbg (hub_dev,
        					"error resetting hub: %d\n", ret);
        				goto loop_autopm;
        			}

        			hub->nerrors = 0;
        			hub->error = 0;
        		}

        		/* deal with port status changes */
                /* 處理 port 口變化*/
        		for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
        			if (test_bit(i, hub->busy_bits))
        				continue;
        			connect_change = test_bit(i, hub->change_bits);
        			if (!test_and_clear_bit(i, hub->event_bits) &&
        					!connect_change)
        				continue;
                    /* 獲取 hub 端口的狀態 */
        			ret = hub_port_status(hub, i,
        					&portstatus, &portchange);
        			if (ret < 0)
        				continue;
                    /* hub 端口狀態有變化 設置 connect_change 爲 1 */
        			if (portchange & USB_PORT_STAT_C_CONNECTION) {
        				clear_port_feature(hdev, i,
        					USB_PORT_FEAT_C_CONNECTION);
        				connect_change = 1;
        			}

        			if (portchange & USB_PORT_STAT_C_ENABLE) {
        				if (!connect_change)
        					dev_dbg (hub_dev,
        						"port %d enable change, "
        						"status %08x\n",
        						i, portstatus);
        				clear_port_feature(hdev, i,
        					USB_PORT_FEAT_C_ENABLE);

        				/*
        				 * EM interference sometimes causes badly
        				 * shielded USB devices to be shutdown by
        				 * the hub, this hack enables them again.
        				 * Works at least with mouse driver.
        				 */
        				if (!(portstatus & USB_PORT_STAT_ENABLE)
        				    && !connect_change
        				    && hdev->children[i-1]) {
        					dev_err (hub_dev,
        					    "port %i "
        					    "disabled by hub (EMI?), "
        					    "re-enabling...\n",
        						i);
        					connect_change = 1;
        				}
        			}

                    /* 狀態變化是 SUSPEND */
        			if (portchange & USB_PORT_STAT_C_SUSPEND) {
        				struct usb_device *udev;

        				clear_port_feature(hdev, i,
        					USB_PORT_FEAT_C_SUSPEND);
        				udev = hdev->children[i-1];
        				if (udev) {
        					/* TRSMRCY = 10 msec */
        					#ifdef CONFIG_MDM_HSIC_PM
        					/* MDM9x15, HSIC deivce */
        					if (udev->quirks & USB_QUIRK_HSIC_TUNE)
        						msleep(10 + 10);
        					else
        					#else
        					msleep(10);
        					#endif

        					usb_lock_device(udev);
        					ret = usb_remote_wakeup(hdev->
        							children[i-1]);
        					usb_unlock_device(udev);
        					if (ret < 0)
        						connect_change = 1;
        				} else {
        					ret = -ENODEV;
        					hub_port_disable(hub, i, 1);
        				}
        				dev_dbg (hub_dev,
        					"resume on port %d, status %d\n",
        					i, ret);
        			}
                    /* 端口變化時應爲 過流 */
        			if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
        				u16 status = 0;
        				u16 unused;

        				dev_dbg(hub_dev, "over-current change on port "
        					"%d\n", i);
        				clear_port_feature(hdev, i,
        					USB_PORT_FEAT_C_OVER_CURRENT);
        				msleep(100);	/* Cool down */
        				hub_power_on(hub, true);
        				hub_port_status(hub, i, &status, &unused);
        				if (status & USB_PORT_STAT_OVERCURRENT)
        					dev_err(hub_dev, "over-current "
        						"condition on port %d\n", i);
        			}
                    /* 端口變化是 因爲 Reset */
        			if (portchange & USB_PORT_STAT_C_RESET) {
        				dev_dbg (hub_dev,
        					"reset change on port %d\n",
        					i);
        				clear_port_feature(hdev, i,
        					USB_PORT_FEAT_C_RESET);
        			}
        			if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
        					hub_is_superspeed(hub->hdev)) {
        				dev_dbg(hub_dev,
        					"warm reset change on port %d\n",
        					i);
        				clear_port_feature(hdev, i,
        					USB_PORT_FEAT_C_BH_PORT_RESET);
        			}
        			if (portchange & USB_PORT_STAT_C_LINK_STATE) {
        				clear_port_feature(hub->hdev, i,
        						USB_PORT_FEAT_C_PORT_LINK_STATE);
        			}
        			if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
        				dev_warn(hub_dev,
        					"config error on port %d\n",
        					i);
        				clear_port_feature(hub->hdev, i,
        						USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
        			}

        			/* Warm reset a USB3 protocol port if it's in
        			 * SS.Inactive state.
        			 */
        			if (hub_is_superspeed(hub->hdev) &&
        				(portstatus & USB_PORT_STAT_LINK_STATE)
        					== USB_SS_PORT_LS_SS_INACTIVE) {
        				dev_dbg(hub_dev, "warm reset port %d\n", i);
        				hub_port_warm_reset(hub, i);
        			}
                    /* hub 端口狀態變化是 連接狀態 變化,如果有設備  插入將在此枚舉設備  */
        			if (connect_change)
        				hub_port_connect_change(hub, i,portstatus, portchange);
                        {
                        	struct usb_device *hdev = hub->hdev;
                        	struct device *hub_dev = hub->intfdev;
                        	struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
                        	unsigned wHubCharacteristics =
                        			le16_to_cpu(hub->descriptor->wHubCharacteristics);
                        	struct usb_device *udev;
                        	int status, i;

                        	dev_dbg (hub_dev,
                        		"port %d, status %04x, change %04x, %s\n",
                        		port1, portstatus, portchange, portspeed(hub, portstatus));
                            /* 如果 hub 有指示燈,則設置端口的 led */
                        	if (hub->has_indicators) {
                        		set_port_led(hub, port1, HUB_LED_AUTO);
                        		hub->indicator[port1-1] = INDICATOR_AUTO;
                        	}

                        #ifdef	CONFIG_USB_OTG
                        	/* during HNP, don't repeat the debounce */
                        	if (hdev->bus->is_b_host)
                        		portchange &= ~(USB_PORT_STAT_C_CONNECTION |
                        				USB_PORT_STAT_C_ENABLE);
                        #endif

                        	/* Try to resuscitate an existing device */
                        	udev = hdev->children[port1-1];
                        	if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
                        			udev->state != USB_STATE_NOTATTACHED) {
                        		usb_lock_device(udev);
                        		if (portstatus & USB_PORT_STAT_ENABLE) {
                        			status = 0;		/* Nothing to do */
                                /* 如果在設備 SUSPENDED 狀態認爲是喚醒事件    */
                        #ifdef CONFIG_USB_SUSPEND
                        		} else if (udev->state == USB_STATE_SUSPENDED &&
                        				udev->persist_enabled) {
                        			/* For a suspended device, treat this as a
                        			 * remote wakeup event.
                        			 */
                        			status = usb_remote_wakeup(udev);
                        #if defined(CONFIG_LINK_DEVICE_HSIC)
                        		} else if (udev->state == USB_STATE_CONFIGURED &&
                        			udev->persist_enabled &&
                        			udev->dev.power.runtime_status == RPM_RESUMING) {
                        			/* usb 1-2 runtime resume was called by host wakeup
                        			 * isr routine . Nothing to do */
                        			pr_info("%s: aleady host-wakup resumed\n", __func__);
                        			status = 0;
                        #endif
                        #endif
                        		} else {
                        #if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_LINK_DEVICE_HSIC)
                        			pr_info("%s: ENODEV, udev->state=%d, rpm=%d\n",
                        				__func__, udev->state,
                        				udev->dev.power.runtime_status);
                        #endif
                        			status = -ENODEV;	/* Don't resuscitate */
                        		}
                        		usb_unlock_device(udev);

                        		if (status == 0) {
                        			clear_bit(port1, hub->change_bits);
                        			return;
                        		}
                        	}

                        	/* Disconnect any existing devices under this port */
                           /* 先將此 port 口上的設備 disconnect */
                        	if (udev)
                        		usb_disconnect(&hdev->children[port1-1]);
                        	clear_bit(port1, hub->change_bits);

                        	/* We can forget about a "removed" device when there's a physical
                        	 * disconnect or the connect status changes.
                        	 */
                        	 /* 對於 插入設備 ,先對hub 的端口進行 干擾消抖 */
                        	if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
                        			(portchange & USB_PORT_STAT_C_CONNECTION))
                        		clear_bit(port1, hub->removed_bits);

                        	if (portchange & (USB_PORT_STAT_C_CONNECTION |
                        				USB_PORT_STAT_C_ENABLE)) {
                        		status = hub_port_debounce(hub, port1);
                        		if (status < 0) {
                        			if (printk_ratelimit())
                        				dev_err(hub_dev, "connect-debounce failed, "
                        						"port %d disabled\n", port1);
                        			portstatus &= ~USB_PORT_STAT_CONNECTION;
                        		} else {
                        			portstatus = status;
                        		}
                        	}

                        	/* Return now if debouncing failed or nothing is connected or
                        	 * the device was "removed".
                        	 */
                        	 /* 處理 信號消抖失敗、沒有插入任何設備或者設備拔出的情況 */
                        	if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
                        			test_bit(port1, hub->removed_bits)) {

                        		/* maybe switch power back on (e.g. root hub was reset) */
                        		if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
                        				&& !port_is_power_on(hub, portstatus))
                        			set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);

                        		if (portstatus & USB_PORT_STAT_ENABLE)
                          			goto done;
                        		return;
                        	}

                        	for (i = 0; i < SET_CONFIG_TRIES; i++) {

                        		/* reallocate for each attempt, since references
                        		 * to the previous one can escape in various ways
                        		 */
                        		/* 給該設備分配 usb_device 結構體,並初始化 */
                        		udev = usb_alloc_dev(hdev, hdev->bus, port1);
                        		if (!udev) {
                        			dev_err (hub_dev,
                        				"couldn't allocate port %d usb_device\n",
                        				port1);
                        			goto done;
                        		}

                        		usb_set_device_state(udev, USB_STATE_POWERED);
                                /* 可獲取的電流就是 hub 的端口電流 */
                         		udev->bus_mA = hub->mA_per_port;
                        		udev->level = hdev->level + 1;
                        		udev->wusb = hub_is_wusb(hub);

                        		/* Only USB 3.0 devices are connected to SuperSpeed hubs. */
                                /* 只有 usb 3.0 的連接的 hub 速度是 USB_SPEED_SUPER */
                        		if (hub_is_superspeed(hub->hdev))
                        			udev->speed = USB_SPEED_SUPER;
                        		else
                        			udev->speed = USB_SPEED_UNKNOWN;

                        		choose_devnum(udev);
                        		if (udev->devnum <= 0) {
                        			status = -ENOTCONN;	/* Don't retry */
                        			goto loop;
                        		}

                        		/* reset (non-USB 3.0 devices) and get descriptor */
                                /* 重啓設備並獲 取描述符 */
                        		status = hub_port_init(hub, udev, port1, i);
                        		if (status < 0)
                        			goto loop;

                        		usb_detect_quirks(udev);
                        		if (udev->quirks & USB_QUIRK_DELAY_INIT)
                        			msleep(1000);

                        		/* consecutive bus-powered hubs aren't reliable; they can
                        		 * violate the voltage drop budget.  if the new child has
                        		 * a "powered" LED, users should notice we didn't enable it
                        		 * (without reading syslog), even without per-port LEDs
                        		 * on the parent.
                        		 */
                        		 /* 插入的是 hub 設備*/
                        		if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
                        				&& udev->bus_mA <= 100) {
                        			u16	devstat;

                        			status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
                        					&devstat);
                        			if (status < 2) {
                        				dev_dbg(&udev->dev, "get status %d ?\n", status);
                        				goto loop_disable;
                        			}
                        			le16_to_cpus(&devstat);
                        			if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
                        				dev_err(&udev->dev,
                        					"can't connect bus-powered hub "
                        					"to this port\n");
                        				if (hub->has_indicators) {
                        					hub->indicator[port1-1] =
                        						INDICATOR_AMBER_BLINK;
                        					schedule_delayed_work (&hub->leds, 0);
                        				}
                        				status = -ENOTCONN;	/* Don't retry */
                        				goto loop_disable;
                        			}
                        		}

                        		/* check for devices running slower than they could */
                                /* 檢查設備是否 工作在 最高速度 ,不工作在最高速會提示連接到高速 hub 上 */
                        		if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200
                        				&& udev->speed == USB_SPEED_FULL
                        				&& highspeed_hubs != 0)
                        			check_highspeed (hub, udev, port1);

                        		/* Store the parent's children[] pointer.  At this point
                        		 * udev becomes globally accessible, although presumably
                        		 * no one will look at it until hdev is unlocked.
                        		 */
                        		status = 0;

                        		/* We mustn't add new devices if the parent hub has
                        		 * been disconnected; we would race with the
                        		 * recursively_mark_NOTATTACHED() routine.
                        		 */
                        		spin_lock_irq(&device_state_lock);
                        		if (hdev->state == USB_STATE_NOTATTACHED)
                        			status = -ENOTCONN;
                        		else
                        			hdev->children[port1-1] = udev;
                        		spin_unlock_irq(&device_state_lock);

                        		/* Run it through the hoops (find a driver, etc) */
                        		if (!status) {
                                    /* 終於開始 枚舉設備 ,獲取描述符,匹配 usb_generic_driver 並調用到 generic_probe ,
                                    選中一個配置並配置進去,將每一個 配置下的 interface 都註冊爲 usb_device,然後匹配到相應
                                    的驅動 */
                        			status = usb_new_device(udev);
                        			if (status) {
                        				spin_lock_irq(&device_state_lock);
                        				hdev->children[port1-1] = NULL;
                        				spin_unlock_irq(&device_state_lock);
                        			}
                        		}

                        		if (status)
                        			goto loop_disable;

                        		status = hub_power_remaining(hub);
                        		if (status)
                        			dev_dbg(hub_dev, "%dmA power budget left\n", status);

                        		return;

                        loop_disable:
                        		hub_port_disable(hub, port1, 1);
                        loop:
                        		usb_ep0_reinit(udev);
                        		release_devnum(udev);
                        		hub_free_dev(udev);
                        		usb_put_dev(udev);
                        		if ((status == -ENOTCONN) || (status == -ENOTSUPP))
                        			break;
                        	}
                        	if (hub->hdev->parent ||
                        			!hcd->driver->port_handed_over ||
                        			!(hcd->driver->port_handed_over)(hcd, port1))
                        		dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
                        				port1);

                        done:
                        	hub_port_disable(hub, port1, 1);
                        	if (hcd->driver->relinquish_port && !hub->hdev->parent)
                        		hcd->driver->relinquish_port(hcd, port1);
                        }
                    
        		} /* end for i */

        		/* deal with hub status changes */
        		if (test_and_clear_bit(0, hub->event_bits) == 0)
        			;	/* do nothing */
        		else if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)
        			dev_err (hub_dev, "get_hub_status failed\n");
        		else {
        			if (hubchange & HUB_CHANGE_LOCAL_POWER) {
        				dev_dbg (hub_dev, "power change\n");
        				clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
        				if (hubstatus & HUB_STATUS_LOCAL_POWER)
        					/* FIXME: Is this always true? */
        					hub->limited_power = 1;
        				else
        					hub->limited_power = 0;
        			}
        			if (hubchange & HUB_CHANGE_OVERCURRENT) {
        				u16 status = 0;
        				u16 unused;

        				dev_dbg(hub_dev, "over-current change\n");
        				clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
        				msleep(500);	/* Cool down */
                                	hub_power_on(hub, true);
        				hub_hub_status(hub, &status, &unused);
        				if (status & HUB_STATUS_OVERCURRENT)
        					dev_err(hub_dev, "over-current "
        						"condition\n");
        			}
        		}

         loop_autopm:
        		/* Balance the usb_autopm_get_interface() above */
        		usb_autopm_put_interface_no_suspend(intf);
         loop:
        		/* Balance the usb_autopm_get_interface_no_resume() in
        		 * kick_khubd() and allow autosuspend.
        		 */
        		usb_autopm_put_interface(intf);
         loop_disconnected:
        		usb_unlock_device(hdev);
        		kref_put(&hub->kref, hub_release);

                } /* end while (1) */
        }
		wait_event_freezable(khubd_wait,
				!list_empty(&hub_event_list) ||
				kthread_should_stop());
	} while (!kthread_should_stop() || !list_empty(&hub_event_list));

	pr_debug("%s: khubd exiting\n", usbcore_name);
	return 0;
} 

當 khubd 線程被喚醒後,會判斷端口是什麼狀態,如過流,休眠還是reset等等,上面只展開了連接狀態變化,
一般是插入或者拔出設備引起,當是插入設備時,要信號防抖啊,reset 設備,分配地址,然後 通過 usb_new_device 函數枚舉設備,和註冊 root hub 時如出一轍。當讀取完各種描述符,先匹配 usb_generic_driver 驅動,並調用 generic_probe 函數 ,然後由 generic_probe 選中一個配置 發給設備 ,將 interface 作爲 usb_device 註冊匹配相應的 驅動。驅動的開發工作就是對着 interface 開發。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章