插入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