1、roothub通常被集成在了主控制器。
初始化driver/core/usb.c中
static int __init usb_init(void)
{
。。。
retval = usb_hub_init();
if (retval)
goto hub_init_failed;
。。。
return retval;
}
int usb_hub_init(void)
{
if (usb_register(&hub_driver) < 0) { //先注册hub驱动</span></strong>
printk(KERN_ERR "%s: can't register hub driver\n",
usbcore_name);
return -1;
}
khubd_task = kthread_run(hub_thread, NULL, "khubd");
if (!IS_ERR(khubd_task)) //判断创建的进程是否正确</strong>
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;
}
判断空间开辟是否正确判断:通常将最后一页来存放错误号的,当返回的指针指向了最后页就代表错误。
#define MAX_ERRNO 4095
#ifndef __ASSEMBLY__
#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO) //例如32bit 最高地址0xffffffff,最后页地址0xfffff000-0xffffffff
static inline void * __must_check ERR_PTR(long error)
{
return (void *) error;
}
static inline long __must_check PTR_ERR(const void *ptr)
{
return (long) ptr;
}
static inline long __must_check IS_ERR(const void *ptr)
{
return IS_ERR_VALUE((unsigned long)ptr);
}
#define list_entry(ptr,type,member) \
container_of(ptr,type,member) //ptr是type变量中的member成员的指针,通过该ptr得type指针。
static int hub_thread(void *__unused)
{
set_freezable();
do {
hub_events();
wait_event_freezable(khubd_wait,
!list_empty(&hub_event_list) || //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;
}
wait_event_interruptible= sleep until a condition gets true,即条件为假则休眠
总:设置一个链表hub_event_list,设置一个总的函数hub_event()
分:每个hub都有个event_list,当有hub的event_list发生变化时,把该event_list插到hub_event_list中
总:再触发总hub_event()
分:hub_event又根据event_list确定是哪个struct usb_hub或者哪个hub有问题
接着看hub_event
static void hub_events(void)
{
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;
while (1) {
/* Grab the first entry at the beginning of the list */
spin_lock_irq(&hub_event_lock);
if (list_empty(&hub_event_list)) {
spin_unlock_irq(&hub_event_lock);
>break;
}
.....
这里判断 hub_event_list为空,则直接退出该函数,线程hub_thread睡眠