linux usb驱动记录(二)
三、usb设备的识别过程 ? ? ? ?在这里梳理一下上一篇博客中的内容:(这张图来自https://blog.csdn.net/lizuobin2/article/details/51931161) 上一篇博客刚好从平台设备、驱动的匹配分析到hub_irq这个函数这里。 static void hub_irq(struct urb *urb) { struct usb_hub *hub = urb->context; int status = urb->status; unsigned i; unsigned long bits; switch (status) { .... case 0: // 端口的状态发生了变化 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 */ kick_khubd(hub); // 重要函数 唤醒hub线程 resubmit: if (hub->quiescing) return; if ((status = usb_submit_urb (hub->urb,GFP_ATOMIC)) != 0 && status != -ENODEV && status != -EPERM) dev_err (hub->intfdev,"resubmit --> %dn",status); } 在kick_khubd(hub)中会唤醒执行wake_up(&khubd_wait)来唤醒一个程序。那么唤醒的到底是哪个程序呢? int usb_hub_init(void) { // 这里注册了hub_driver 这个在上一篇博客中提到过 if (usb_register(&hub_driver) < 0) { } // 这里创建了一个hub_thread 名字叫"khubd" khubd_task = kthread_run(hub_thread,NULL,"khubd"); /* Fall through if kernel_thread failed */ usb_deregister(&hub_driver); printk(KERN_ERR "%s: can‘t start khubdn",usbcore_name); return -1; } 现在可以看看在hub_thread这个线程中做一些什么事? static int hub_thread(void *__unused) { set_freezable(); do { hub_events(); wait_event_freezable(khubd_wait,!list_empty(&hub_event_list) || kthread_should_stop()); } while (!kthread_should_stop() || !list_empty(&hub_event_list)); return 0; } 在这个内核线程中主要执行hub_events(),但是平时应该是休眠状态,直到有事情发生,其他程序中将其唤醒。因此可以说是在hub_irq 函数中唤醒了hub_thread,使得hub_thread能够执行hub_events() 函数。 当有usb设备插入时,主机控制器检测到hub端口状态的变化,会执行hub_irq函数,然后按照下图的函数调用顺序一路往下执行,实现usb设备的识别过程: (1)给新设备分配地址 ? ? ? ?(2)并将该地址告诉usb设备即设置usb地址 (3)发出命令读取描述符 (4)执行usb_new_device和device_add(向总线上添加usb设备)? (5)device_add 之后又会执行usb_device_match函数和generic_probe函数,在generic_probe 函数中 选择和设置 配置 之后又会执行device_add(向usb总线上添加接口设备) ? ? ? ?(6)device_add 之后又会执行usb_device_match函数(这个时候应该就根据id_table和自己写的设备驱动进行匹配操作了)和xx_probe函数(自己驱动的probe函数)。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |