插入usb之后发生了什么
来源:互联网 发布:seo标题和关键字 编辑:程序博客网 时间:2024/05/16 01:40
源码赏析
小实验
/** 这个函数做了两件事情: 1 : 注册hub驱动 2 : 创建名为"khubd"的守护线程,它的作用是检测hub的状态变化。*/int usb_hub_init(void){ /** usb hub也是usb设备。驱动的注册和usb设备驱动的注册方式是一样的。 该函数最终是 :如果usb总线提供了probe就调用总线提供的probe,如果没有提供 那么就调用驱动提供的probe,由于usb总线没有提供probe,那么驱动提供的 hub_probe() 就会被调用了 (注册流程请见我以前博文的赏析) 看看这个hub_driver. static struct usb_driver hub_driver = { .name = "hub", 这个hub_probe第一次调用,是在usb主机控制器的驱动初始化的时候用来探测Root Hub的。 在系统启动后的log中,会打印有:USB hub found .probe = hub_probe, .disconnect = hub_disconnect, 这是休眠、唤醒hub的函数,以后在说。 .suspend = hub_suspend, .resume = hub_resume, ... }; */ if (usb_register(&hub_driver) < 0) { printk(KERN_ERR "%s: can't register hub driver\n",usbcore_name); return -1; } /** 创建了一个守护进程,用于监视hub的状态。 这个守护进程 在后面我们会看到 它会在urb的完成函数hub_irq()->kick_khubd()中被唤醒。 它在什么时候被睡眠? 怎么被唤醒的? 我们往下面看 kthread_run()这个函数底层调用了kthread_create()函数,kthread_create()会唤醒睡眠的2号 进程kthreadd 来创建内核线程,请见我以前的博文的赏析 */ khubd_task = kthread_run(hub_thread,NULL,"khubd"); /** 如果khubd成功创建,那么就返回了。 */ if(!IS_ERR(khubd_task)) { return 0; } /** 以下代码是 内核线程"khubd"创建不成功过的时候执行的 卸载hub驱动 */ usb_deregister(&hub_driver); printk(KERN_ERR "%s: can't start khubd\n", usbcore_name); return -1;}static int hub_thread(void * __unnsed){ /** 内核线程默认是不可以被冷冻的,清除它的PF_NOFREEZE位,让进程可以冷冻。 */ set_freezable(); /** 循环退出的条件: 1 : hub_event_list队列为空 2 : 线程接收到了stop信号。 */ do{ /** 这个函数很庞大、很重要,它里面有这样一段代码: while(1) { spin_lock_irq(&hub_event_lock); if (list_empty(&hub_event_list)) { spin_unlock_irq(&hub_event_lock); break; } ..... } 由上面代码可以知道, 如果hub_event_list为空,那么就会执行下面的wait_event_freezable()进行睡眠。 hub_event_list的初始值就是空,那么就直接break了,返回hub_thread,然后就睡眠,等待事件的到来。 修改了内核代码,这里实验验证了一下,内核打印的log: usbcore: registered new interface driver usbfs usbcore: registered new interface driver hub list_empty----**: 1 添加的code usbcore: registered new device driver usb 如果hub_event_list不为空,就会进行进行usb的枚举,这一部分 我们放在下面欣赏 */ hub_events(); /** 看看它的condition : !list_empty(&hub_event_list) ||kthread_should_stop() 只要接收到stop停止信号或者 hub_event_list为空,那么就会睡眠 在下面的函数kick_khubd()中,是通过list_add_tail(&hub->event_list, &hub_event_list) 来唤醒的。 它的底层调用到了 __wait_event_interruptible()函数, 这个函数会调用set_current_state(TASK_INTERRUPTIBLE);将线程的状态设置成TASK_INTERRUPTIBLE 然后如果没有信号需要处理,就调用schedule()让进程一直休眠直到条件满足为止。 这个函数的分析请见我以前的博文。 */ wait_event_freezable(khubd_wait,!list_empty(&hub_event_list) ||kthread_should_stop()); }while (!kthread_should_stop() || !list_empty(&hub_event_list));}/** Hub正常工作后,usb主机控制器就会定时的询问hub, 如果hub端口上有usb设备的插入、拔出的时候,hub就会把端口的状态变化告诉usb主机控制器 这是通过向usb主机控制器发送urb请求(当然是中断urb了)来实现的。当usb主机控制器处理完成这个urb后, 那么urb的完成函数hub_irq()就被调用了,*/static void hub_irq(struct urb *urb){ struct usb_hub * hub = urb->context; /* 上面获取的urb是这样来的 : static int hub_configure() { 分配一个urb hub->urb = usb_alloc_urb(0, GFP_KERNEL); if (!hub->urb) { ret = -ENOMEM; goto fail; } 填充中断类型的urb,完成函数:hub_irq(). usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval); ..... } */ int status = urb->status; unsigned i; unsigned long bits; ..... /* 调用了这个函数。它会唤醒前面睡眠的线程的 */ kick_khubd(hub);}static void kick_khubd(struct usb_hub *hub){ unsigned long flags; /** hub_irq()是运行在中断上下文的, 这里如果不关闭中断的话,可能会导致死锁的发生 详情请见我以前的博文: http://blog.csdn.net/leesagacious/article/details/48595203 */ spin_lock_irqsave(&hub_event_lock, flags); if (!hub->disconnected && list_empty(&hub->event_list)) { /** 这行代码是为了满足“khubd”守护进程被唤醒的条件的 将hub的event_list添加到hub_event_list尾部 */ list_add_tail(&hub->event_list, &hub_event_list); usb_autopm_get_interface_no_resume(to_usb_interface(hub->intfdev)); /** 终于要唤醒了...... */ wake_up(&khubd_wait); } spin_unlock_irqrestore(&hub_event_lock, flags);}
0 0
- 插入usb之后发生了什么
- new之后发生了什么?
- malloc()之后,内核发生了什么?
- 实例化子类之后发生了什么
- malloc()之后,内核发生了什么?
- malloc()之后,内核发生了什么?
- malloc()之后,内核发生了什么?
- 输入URL之后都发生了什么
- 点击 Run 之后发生了什么?
- 输入网址之后发生了什么
- url enter之后发生了什么
- C++中new和delete之后发生了什么
- 前端面试:页面输入url之后发生了什么?
- 最近发生了什么...
- 发生什么了??
- 预处理发生了什么
- 关于const常量的地址经过const_cast转换之后,发生了什么
- 在 EBS Form 查找界面点 "Find" 之后都发生了什么?
- 3390: [Usaco2004 Dec]Bad Cowtractors牛的报复 最大生成树
- 设计模式感触之代理模式应用
- leetcode总结4 -- 关于two pointers两个容易考的题目
- 华为机试题目
- 包
- 插入usb之后发生了什么
- Swift笔记(一)
- C# 正则表达式
- Heartbeat+DRBD+MySQL高可用架构方案与实施过程细节 【转】
- Spring对RMI的支持
- 3、Java常用的运算符
- Android permission 动态申请、授权
- 快速幂求余
- Kali 2.0 使用 Reaver 的注意事项