原文地址:
一.等待
static struct usb_driver hub_driver = {
.name = "hub",
.probe = hub_probe,
.disconnect = hub_disconnect,
.suspend = hub_suspend,
.resume = hub_resume,
.reset_resume = hub_reset_resume,
.pre_reset = hub_pre_reset,
.post_reset = hub_post_reset,
.ioctl = hub_ioctl,
.id_table = hub_id_table,
.supports_autosuspend = 1,
};
int usb_hub_init(void)
{
if (usb_register(&hub_driver) < 0) {
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))
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;
}
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();
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;
}
在hub_thread执行时,会进入hub_events,但是这时候hub_event_list队列为空,于是hub_events退出并wait
二.唤醒
当主控制器初始化时,会初始化root hub,之后调用:
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
hub_probe()所做的工作:
1.为此root hub申请struct usb_hub结构体并初始化它
2.填充并提交中断in端点(由hub_activate完成)
usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
hub, endpoint->bInterval);
usb_submit_urb(hub->urb, GFP_NOIO);
3.调用kick_khubd(hub)
static void kick_khubd(struct usb_hub *hub)
{
unsigned long flags;
/* Suppress autosuspend until khubd runs */
to_usb_interface(hub->intfdev)->pm_usage_cnt = 1;
spin_lock_irqsave(&hub_event_lock, flags);
if (!hub->disconnected && list_empty(&hub->event_list)) {
list_add_tail(&hub->event_list, &hub_event_list);
wake_up(&khubd_wait);
}
spin_unlock_irqrestore(&hub_event_lock, flags);
}
由于这个时候root hub已经成功初始化了,所以kick_khubd会将root hub的event_list,添加到
hub_event_list,表示root hub已经被识别了,同时wake_up(&khubd_wait)会唤醒上面的等待,
于是hub_events()又一次执行了,但是这次,它是有备而来,因为hub_event_list不为空
三.hub_events
hub_events函数所做的工作:
对每个端口号(共计bNbrPorts个端口,bNbrPorts这个值从hub描述符里边得到,因为此值描述了hub所用用的端口的情况),假如满足下列条件则调用hub_port_connect_change()
1.连接有变化
2.端口本身重新使能,即所谓的enable,这种情况通常就是为了对付电磁干扰的,正如我们前面的判断中所说的那样
3.在复位一个设备的时候发现其描述符变了,这通常对应的是硬件本身有了升级.很显然,第一种情况是真正的物理变化,后两者就算是逻辑变化
代码模型如下:
for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
...
if (connect_change) //对root hub上活跃的port调用hub_port_connect_change
hub_port_connect_change(hub, i,
portstatus, portchange);
...
}
hub_port_connect_change()所做的工作:
1.udev = usb_alloc_dev(hdev, hdev_bus, port1);
原型:struct usb_device *usb_alloc_dev(struct usb_device *parent,
struct usb_bus *bus, unsigned port1)
为探测到的usb设备(包括普通hub,u盘等)分配并初始化udev;
2.status = hub_port_init(hub, udev, port1, i);
先进行两次新的策略(i=0和=1时),如果不行就再进行两次旧的策略(i=2和i=3时).所有这一切只有一个目的,就是为了获得设备的描述符,设置了udev->tt、udev->ttport和udev->ep0.desc.wMaxPacketSize,设置udev->status=
USB_STATE_ADDRESS
3.usb_new_device(udev);
(1)usb_configure_device(udev)->
usb_get_configuration(udev);
a.usb_get_descriptor() //得到设备的描述符(包括设备描述符、配置描述符、接口描述符等)
b.usb_parse_configuration() //分析以上描述符信息,提取出配置、接口等,并赋值给udev结构里相应的字段
(2)device_add(&udev->dev);
将usb设备注册到系统里,这个动作将触发驱动的匹配,由于这是个usb设备,所以万能usb驱动usb_generic_driver会匹配上,
从而generic_probe会得到执行.关于 generic_probe所做的工作,请参考:
http://blog.chinaunix.net/uid-20727076-id-3273535.html
从上面可以看出来,这一次hub_events()调用是由于主控制器初始化调用了hub_probe,从而引发hub_events调用。那root hub初始化完成以后hub_events会如何触发呢?
答案是通过中断!而这个中断的服务函数就是hub_irq,也即是说,凡是真正的有端口变化事件发生,hub_irq就会被调用,而hub_irq()最终会调用kick_khubd(),触发hub的event_list,于是再次调用hub_events().
那hub_irq是什么时候注册的呢?
前面我们讲到:
hub_probe()所做的第二项工作是:填充并提交中断in端点(由hub_activate完成)
usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
hub, endpoint->bInterval);
usb_submit_urb(hub->urb, GFP_NOIO);
hub_irq作为参数传给了usb_fill_int_urb,这样设定以后,只要root hub的端口有变化,hub_irq就会执行到
原文地址:
阅读(469) | 评论(0) | 转发(1) |