usb热插拔实现机制
来源:互联网 发布:c语言 getchar字符串 编辑:程序博客网 时间:2024/05/21 09:06
一.等待
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就会执行到
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就会执行到
0
上一篇:usb接口驱动加载流程分析
下一篇:一支使用了DMA的网卡驱动分析
相关热门文章
- Tcpportping
- MySQL主从复制原理、主从复制...
- C++实现多线程安全的单例模式...
- python-tail
- linux下C语言实现动态分配的缓...
- linux 常见服务端口
- 【ROOTFS搭建】busybox的httpd...
- xmanager 2.0 for linux配置
- 什么是shell
- linux socket的bug??
- 系统提供的库函数存在内存泄漏...
- 初学UNIX环境高级编程的,关于...
- chinaunix博客什么时候可以设...
- 一个访问量较大网站的服务器。...
- 收音机驱动与v4l2架构的关系,...
给主人留下些什么吧!~~
评论热议
0 0
- USB热插拔机制实现
- usb热插拔实现机制
- usb debugging的实现机制
- usb debugging的实现机制
- usb debugging的实现机制
- usb debugging的实现机制
- usb debugging的实现机制 转载
- WM_DEVICECHANGE实现USB设备热插拔
- USB实现
- usb battery 机制初探
- linux下实现USB口的热插拔
- Linux下实现USB口的热插拔
- windos下QT实现usb热插拔检测
- USB系统的主从机制
- USB的插入检测机制
- At91sam7s256 USB CDC 实现
- 电脑实现USB启动
- USB RNDIS实现
- EMF--深入研究到骨子里--16
- 没有有效的Qt版本问题
- 嵌入式系统中看门狗的使用总结
- 前端工程师你要知道那么多?
- usb接口驱动加载流程分析
- usb热插拔实现机制
- 一支使用了DMA的网卡驱动分析
- QT项目负责人必须掌握的Ui设计师功能——Promote to !
- qt做的简易 仪表
- 第7周作业1——背包问题
- mdev的使用方法和原理以及实现U盘或SD卡的自动挂载
- 苹果历代iPod产品大全相册
- 拥抱 Qt4.6+(10) 用QtCreator开发ARM程序
- 3G卡片在开发板上的详细解决方法(适用于大多数3G卡片)
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
东北师范大学研究生论坛
东北电力大学成人教育
东北腌酸菜的方法
东北虎是几级保护动物
东北农业大学成人教育学院
东北师范大学教育学研究生
吉林东北虎吧
东北石油大学吧
东北发展吧
东北农业大学吧
东北林业大学吧
东北师范大学吧
东北财经大学研究生吧
东北财经大学考研吧
东北电力大学吧
东北师大考研吧
东北大学考研吧
东北农大吧
东北出马仙吧
东北大学研究生吧
东北园胡同
东北野生大鱼坊
东北坊
东北坊白酒怎么样
东北豆腐坊
东北野生大鱼坊图片
东北电器城
东北家具城
沈阳东北玩具城
东北玩具城
东北陶瓷城
无锡东北塘
无锡东北塘高架
东北塘
东北塘周边宾馆
中建三局东北分公司
东北旺
东北旺仔系列
东北旺土井村
东北旺仔系列1
东北旺附近医院