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 开发。