USB热插拔机制实现

一.等待

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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MFC(Microsoft Foundation Classes)是微软公司为了简化Windows编程而开发的一套C++类库。实现USB热插拔意味着在程序运行时,可以在不重启计算机的情况下插入或拔出USB设备,并能够正常识别和操作该设备。 要实现MFC中的USB热插拔功能,可以通过以下步骤进行: 1. 导入相关头文件:在MFC程序中,需要引入相关的头文件,例如"afxwin.h"、"usb100.h"等。 2. 初始化USB驱动程序:在程序启动时,需要初始化USB驱动程序,可以通过调用CreateFile函数打开USB设备句柄,并设置参数。 3. 监测USB事件:使用MFC的消息循环机制,通过设置WM_DEVICECHANGE消息来监测USB设备的插拔事件。可以通过重载MFC的消息处理函数来处理WM_DEVICECHANGE消息。 4. 处理USB事件:当收到WM_DEVICECHANGE消息时,可以通过DeviceNotify回调函数获取USB设备的状态,例如插入还是拔出。根据需要,可以执行特定的操作,例如打开设备、读取设备信息、发送数据等。 5. 完成USB设备的初始化和关闭:在处理USB事件时,需要根据设备的插入和拔出状态,进行相应的初始化和关闭操作。当USB设备被插入时,可以打开设备句柄,读取设备信息并进行相关处理;当USB设备被拔出时,需要关闭设备句柄并释放资源。 总之,通过MFC编程可以实现USB热插拔功能。需要注意的是,具体实现过程可能需要根据不同的USB设备和驱动程序进行调整,同时还需要对MFC消息处理和USB编程有一定的理解和经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值