精华内容
下载资源
问答
  • 基于LibUsbDotNet 实现的USB设备的热插拔的上位机,是完整的工程,希望能够帮到大家,谢谢
  • 1.注册USB摄像头插拔事件 bool util::registerDevNitification(QWidget *widget) { #if 1 static const GUID GUID_DEVINTERFACE_LIST[] = { // GUID_DEVINTERFACE_CAMERA_DEVICE { 0x65E8773D, 0x8F56, 0x11D...

    环境:windows

    1. 注册USB摄像头插拔事件

    bool util::registerDevNitification(QWidget *widget)
    {
    #if 1
        static const GUID GUID_DEVINTERFACE_LIST[] =
        {
            // GUID_DEVINTERFACE_CAMERA_DEVICE 
            { 0x65E8773D, 0x8F56, 0x11D0, { 0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96 } },
            // GUID_DEVINTERFACE_USB_DEVICE
            { 0xA5DCBF10, 0x6530, 0x11D2,{ 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } },
            // GUID_DEVINTERFACE_DISK
            { 0x53f56307, 0xb6bf, 0x11d0,{ 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } },
            // GUID_DEVINTERFACE_HID,
            { 0x4D1E55B2, 0xF16F, 0x11CF,{ 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } },
            // GUID_NDIS_LAN_CLASS
            { 0xad498944, 0x762f, 0x11d0,{ 0x8d, 0xcb, 0x00, 0xc0, 0x4f, 0xc3, 0x35, 0x8c } }
             GUID_DEVINTERFACE_COMPORT
            //{ 0x86e0d1e0, 0x8089, 0x11d0, { 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73 } },
             GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR
            //{ 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } },
             GUID_DEVINTERFACE_PARALLEL
            //{ 0x97F76EF0, 0xF883, 0x11D0, { 0xAF, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x84, 0x5C } },
             GUID_DEVINTERFACE_PARCLASS
            //{ 0x811FC6A5, 0xF728, 0x11D0, { 0xA5, 0x37, 0x00, 0x00, 0xF8, 0x75, 0x3E, 0xD1 } }
        };
        //注册插拔事件
        HDEVNOTIFY hDevNotify;
        DEV_BROADCAST_DEVICEINTERFACE NotifacationFiler;
        ZeroMemory(&NotifacationFiler, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
        NotifacationFiler.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
        NotifacationFiler.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    
        for (int i = 0; i < sizeof(GUID_DEVINTERFACE_LIST) / sizeof(GUID); i++)
        {
            NotifacationFiler.dbcc_classguid = GUID_DEVINTERFACE_LIST[i];
    
            hDevNotify = RegisterDeviceNotification((HANDLE)widget->winId(), &NotifacationFiler, DEVICE_NOTIFY_WINDOW_HANDLE);
            if (!hDevNotify)
            {
                qDebug() << "注册失败" << endl;
                return false;
            }
        }
        return true;
    #endif
    }
    

    然后在主窗口调用:

    util::registerDevNitification(this);

    2. 在主窗口实现nativeEvent

    注意插入和拔出都会触发两次通知,所以我过滤掉了第二次通知。

    PDEV_BROADCAST_DEVICEINTERFACE::dbcc_name对应于枚举摄像头时获取到的DevicePath属性,通过这个设备路径我们就能知道具体是哪个摄像头。

    bool CMainWindow::nativeEvent(const QByteArray & eventType, void * message, long * result)
    {
        MSG* msg = reinterpret_cast<MSG*>(message);
        int msgType = msg->message;
        if (msgType == WM_DEVICECHANGE)
        {
            PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
            switch (msg->wParam) {
            case DBT_DEVICEARRIVAL:
                if (lpdb->dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE)
                {
                    PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)lpdb;
                    GUID cameraGuid = { 0x65E8773D, 0x8F56, 0x11D0, { 0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96 } };
                    if (cameraGuid == pDevInf->dbcc_classguid)
                    {
                        // USB插入需要6到10秒才能触发该回调
                        QString devicePath = QString::fromWCharArray(pDevInf->dbcc_name);
                        QStringList parts = devicePath.split('#');
                        if (parts.length() != 4)
                        {
                            qDebug() << "camera logic error";
                            return false;
                        }
                        QString usbPortStr = parts[2];
                        QStringList usbPortParts = usbPortStr.split('&');
                        if (usbPortParts.length() != 4)
                        {
                            qDebug() << "camera logic error";
                            return false;
                        }
                        if ("0000" != usbPortParts[3])
                        {
                            // "0002"不发送信号
                            return false;
                        }
                        qDebug() << qstr("USB摄像头插入");
                        devicePath = devicePath.toLower();
                        emit cameraPlugged(true, devicePath);
                    }
                }
                break;
            case DBT_DEVICEREMOVECOMPLETE:
                if (lpdb->dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE)
                {
                    PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)lpdb;
                    GUID cameraGuid = { 0x65E8773D, 0x8F56, 0x11D0, { 0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96 } };
                    if (cameraGuid == pDevInf->dbcc_classguid)
                    {
                        // USB拔出马上触发
                        QString devicePath = QString::fromWCharArray(pDevInf->dbcc_name);
                        QStringList parts = devicePath.split('#');
                        if (parts.length() != 4)
                        {
                            qDebug() << "camera logic error";
                            return false;
                        }
                        QString usbPortStr = parts[2];
                        QStringList usbPortParts = usbPortStr.split('&');
                        if (usbPortParts.length() != 4)
                        {
                            qDebug() << "camera logic error";
                            return false;
                        }
                        if ("0000" != usbPortParts[3])
                        {
                            // "0002"不发送信号
                            return false;
                        }
                        qDebug() << qstr("USB摄像头拔出");
                        devicePath = devicePath.toLower();
                        emit cameraPlugged(false, devicePath);
                    }
                }
                break;
            }
        }
        return false;
    }

     

    枚举USB摄像头代码:

    bool DeviceEnumerator::enumDevices()
    {
    	HRESULT hr;
    	// enumerate all video capture devices
    	ICreateDevEnum *pCreateDevEnum = NULL;
    	IEnumMoniker *pEm = NULL;
    	IMoniker *pM = NULL;
    	IPropertyBag *pBag = NULL;
    
    	//releaseMoniker();
    
    	hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
    		IID_ICreateDevEnum, (void**)&pCreateDevEnum);
    	if (hr != NOERROR)
    	{
    		qCritical() << "Error Creating Device Enumerator";
    		goto exit;
    	}
    
    	hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEm, 0);
    	if (hr != NOERROR)
    	{
    		qWarning() << "Sorry, you have no video capture hardware";
    		goto exit;
    	}
    
    	while (pEm->Next(1, &pM, NULL) == S_OK)
    	{
    		hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
            if (FAILED(hr))
            {
                pM->Release();
                continue;
            }
    
            VARIANT var;
            VARIANT var2;
            VariantInit(&var);
            VariantInit(&var2);
            hr = pBag->Read(L"FriendlyName", &var, NULL);
            HRESULT hr2 = pBag->Read(L"DevicePath", &var2, NULL);
            if (hr == NOERROR && hr2 == NOERROR)
            {
                QString name = QString::fromUtf16(reinterpret_cast<ushort*>(var.bstrVal));
                if ("screen-capture-recorder" != name)
                {
                    QString devicePath = QString::fromUtf16(reinterpret_cast<ushort*>(var2.bstrVal));
                    qDebug() << devicePath;
    
                    QVariantMap devInfo;
                    devInfo.insert("FriendlyName", name);
                    devInfo.insert("DevicePath", devicePath);
                    devInfo.insert("IMoniker*", reinterpret_cast<int>(pM));
                    m_devInfoList.append(devInfo);
    
                    pM->AddRef();
                }
                SysFreeString(var.bstrVal);
            }
    
            SAFE_RELEASE(pBag);
            SAFE_RELEASE(pM);
    
            if (m_devInfoList.length() >= 2)
            {
                break;
            }
    	}
    
    exit:
    	SAFE_RELEASE(pEm);
    	SAFE_RELEASE(pCreateDevEnum);
    
    	return true;
    }

    dshow根据枚举到的IMoniker打开摄像头,然后拿到h264流,然后就可以播放或推流。

     

     

     

    展开全文
  • Qt之USB热插拔

    2017-12-29 17:47:03
    基于Qt5.5.1的应用程序,支持监控系统设备变化,当插入可移动设备、右键弹出和移除可移动设备时可以实时的通知应用程序
  • Linux USB 驱动开发(四)—— 热插拔那点事

    万次阅读 多人点赞 2016-04-04 16:08:04
    学习USB热插拔之前,先学习一些USB的硬件知识: 一、USB基础概念 1、硬件知识(USB插座和插头)  在最初的标准里,USB接头有4条线:电源,D-,D+,地线。我们暂且把这样的叫做标准的USB接头吧。后来OTG出现了,又增加...

          学习USB热插拔之前,先学习一些USB的硬件知识:

    一、USB基础概念

    1、硬件知识(USB插座和插头)

           在最初的标准里,USB接头有4条线:电源,D-,D+,地线。我们暂且把这样的叫做标准的USB接头吧。后来OTG出现了,又增加了miniUSB接头。而miniUSB接头则有5条线,多了一条ID线,用来标识身份用的。标准USB口只有A型和B型。其中每一型又分为插头和插座,例如A型插头,A型插座等。我们平常电脑上用的那种插座叫做A型USB插座,而相应的插头,叫做A型插头,例如U盘上那种。而像打印机上面那个插座,则是B型插座(比较四方的,没电脑上面那种扁),相应的插头,就是B型插头。也许你见过一头方一头扁的USB延长线,没错了,扁的那头就叫做A型插头,而方的那头,就叫做B型插头,而相应的被插的那两个插座,就分别是A型插座和B型插座了。A型插头是插不进B型插座的,反之亦然。

          miniUSB也分为A型,B型,但增加了一个AB型(不是血型呀,别搞错了,没有O型^_^)。既然它叫做miniUSB,那么当然它就是很小的了,主要是给便携式设备用的,例如MP3、手机、数码相机等。USB是一主多从结构,即一个时刻只能有一台主机。像PC机就是一个主机,其它的只能是设备,因而两个设备之间是无法直接进行通信的。而USB OTG(on the go)的出现,则解决了这个矛盾:一个设备可以在某种场合下,改变身份,以主机的形式出现。因而就出现了AB型的miniUSB插座,不管是A型miniUSB插头,还是B型miniUSB插头,都可以插进去,而靠里面多出的那条ID线来识别它的身份:是主机还是从机。这样两个USB设备就可以直接连接起来,进行数据传送了。 像我们MP3上用的那中miniUSB插座,就是B型的miniUSB插座(注意,有一类miniUSB插座,似乎不是USB规范里面的,因为miniUSB接头应该有5条线,而这种插座只有4条线)。由于USB是支持热插拔的,因此它在接头的设计上也有相应的措施。USB插头的地引脚和电源引脚比较长,而两个数据引脚则比较短,这样在插入到插座中时,首先接通电源和地,然后再接通两个数据线。这样就可以保证电源在数据线之前接通,防止闩锁发生。至于USB电缆,通常我们不怎么关心,买现成的就行了,除非你是生产USB线缆的。在全速模式下需要使用带屏蔽的双绞电缆线,而低速模式模式则可以不用屏蔽和双绞。此外,USB协议规定,USB低速电缆长度不得超过3米,而全速电缆长度不得超过5米。这是因为线缆传输有延迟,要保证能够正确响应,就不能延迟太多。USB标准规定了里面信号线的颜色,其中Vbus为红色,D-为白色,D+为绿色,GND为黑色。然而,我见过很多USB线缆并没有遵循标准,所以大家在使用时要小心,用表测量一下比较可靠。


    2、集线器把USB设备的连接报告给USB主控制器

          首先,在USB集线器的每个下游端口的D+和D-上,分别接了一个15K欧姆的下拉电阻到地。这样,在集线器的端口悬空时,就被这两个下拉电阻拉到了低电平。而在USB设备端,在D+或者D-上接了1.5K欧姆上拉电阻。对于全速和高速设备,上拉电阻是接在D+上;而低速设备则是上拉电阻接在D-上。这样,当设备插入到集线器时,由1.5K的上拉电阻和15K的下拉电阻分压,结果就将差分数据线中的一条拉高了集线器检测到这个状态后,它就报告给USB主控制器(或者通过它上一层的集线器报告给USB主控制器),这样就检测到设备的插入了。USB高速设备先是被识别为全速设备,然后通过HOST和DEVICE两者之间的确认,再切换到高速模式的。在高速模式下,是电流传输模式,这时将D+上的上拉电阻断开。


    二、什么是热插拔

    1、基础概念

         热插拔(hot-plugging或Hot Swap)带电插拔,热插拔功能就是允许用户在不关闭系统,不切断电源的情况下取出和更换损坏的硬盘、电源或板卡等部件,从而提高了系统对灾难的及时恢复能力、扩展性和灵活性等,例如一些面向高端应用的磁盘镜像系统都可以提供磁盘的热插拔功能。具体用学术的说法就是:热替换(Hot replacement)、热添加(hot expansion)和热升级(hot upgrade)


    2、热插拔好处

    系统中加入热插拔的好处包括:

    在系统开机情况下将损坏的模块移除,还可以在开机情况下做更新或扩容而不影响系统操作。

    由于热插拔零件的可靠度提升,还可以将它们用做断电器,而且因为热插拔能够自动恢复,有很多热插拔芯片为系统提供线路供电情况的信号,以便系统做故障分析,因此减少了成本。


    三、Linux 下USB热插拔处理

    1、 Linux下USB HUB的驱动的实现和分析:

           在系统初始化的时候在usb_init函数中调用usb_hub_init函数,就进入了hub的初始化

           在usb_hub_init函数中完成了注册hub驱动,并且利用函数kthread_run创建一个内核线程。该线程用来管理监视hub的状态,所有的情况都通过该线程来报告。

          USB设备是热插拔,这就和PCI设备不同,PCI设备是在系统启动的时候都固定了,因此PCI设备只需要初始化进行枚举就可以了,采用递归算法即可。而USB设备需要热插拔,因此在hub_probe函数中调用hub_configure函数来配置hub,在这个函数中主要是利用函数usb_alloc_urb函数来分配一个urb,利用usb_fill_int_urb来初始化这个urb结构,包括hub的中断服务程序hub_irq的,查询的周期等。

           每当有设备连接到USB接口时,USB总线在查询hub状态信息的时候会触发hub的中断服务程序hub_irq,在该函数中利用kick_khubd将hub结构通过event_list添加到khubd的队列hub_event_list,然后唤醒khubd。进入hub_events函数,该函数用来处理khubd事件队列,从khubd的hub_event_list中的每个usb_hub数据结构。该函数中首先判断hub是否出错,然后通过一个for循环来检测每个端口的状态信息。利用usb_port_status获取端口信息,如果发生变化就调用hub_port_connect_change函数来配置端口等。


    2、软件层次分析

    这里我们先讲讲USB热插拔事件的处理工作。---Khubd守护进程。

    -Khubd守护进程它是一个守护进程,来检查usb port的事件通知HCD和usb core,然后做相应的处理。

    驱动目录drivers/usb/*
    usb/serial  usb 串行设备驱动 (例如usb 3G卡、蓝牙等)
    usb/storage  usb 大储量磁盘驱动(u盘)  
    usb/host usb host usb主机控制器驱动(嵌入式otg:dwc_otg)
    usb/core   usb 核心一些处理代码,所有的驱动相关处理都在这里,也都注册到它里面。
    usb/usb-skeleton.c 经典的usb客户驱动框架,可以参考

    当然还有其他这里不再说明。

    下面贴出USB的整体驱动框架:


    这里我们主要分析khub的工作原理: 硬件层次是hub的工作,如何和host及其设备间通信及相应事件

    [usb/core/hub.c ]

    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;
    }
    这里我们只关心kthread_run(hub_thread, NULL, "khubd"); 然后我们看hub_thread函数
    static int hub_thread(void *__unused)
    {
    	do {
    		hub_events();
    		wait_event_interruptible(khubd_wait,
    				!list_empty(&hub_event_list) ||
    				kthread_should_stop());
    		try_to_freeze();
    	} while (!kthread_should_stop() || !list_empty(&hub_event_list));
    
    	pr_debug("%s: khubd exiting\n", usbcore_name);
    	return 0;
    }

    这里我们看到了hub_events()函数。然后设置运行状态,如果有事件就加入hub_event_list。自此khubd运行起来了。

    这里我们同样贴出它的函数调用流程图(这里懒得自己画了,就剪切了个^^)



    通过流程图我们可以清晰的明白,当usb设备插入usb接口后,khubd运行,它检测到port状态的变化,调用hub_port_connect_change(),如果是新设备那么usb_allco_dev,然后调用usb_new_device来进行配置使usb设备可以正常工作。详细流程请看源码。


    四、USB的枚举过程

           内核辅助线程khubd用来监视与该集线器连接的所有端口,通常情况下,该线程处于休眠状态,当集线器驱动程序检测到USB端口状态变化后,该内核线程立马唤醒

          USB的枚举过程:USB的枚举过程是热插拔USB设备的起始步骤,该过程中,主机控制器获取设备的相关信息并配置好设备,集线器驱动程序负责该枚举过程

    枚举过程主要分如下几步:

    Step1:根集线器报告插入设备导致的端口电流变化,集线器驱动程序检测到这一状态变化后,唤醒khubd线程。

    Step2:khubd识别出电流变化的那个端口

    Step3:khubd通过给控制端点0发送控制URB来实现从1-127中选出一个数作为插入设备的批量端点

    Step4:khubd利用端口0使用的控制URB从插入的设备那里获得设备描述符,然后获得配置描述符,并选择一个合适的。

    Step5:khubd请求USB核心把对应的客户驱动程序和该USB设备挂钩



    展开全文
  • USB热插拔

    千次阅读 2018-10-12 11:13:21
    学习USB热插拔之前,先学习一些USB的硬件知识: 一、USB基础概念 1、硬件知识(USB插座和插头) &nbsp; &nbsp; &nbsp; &nbsp;在最初的标准里,USB接头有4条线:电源,D-,D+,地线。我们暂且把这样的...

    转自:http://blog.csdn.net/zqixiao_09/article/details/51056903  

      学习USB热插拔之前,先学习一些USB的硬件知识:

    一、USB基础概念

    1、硬件知识(USB插座和插头)

           在最初的标准里,USB接头有4条线:电源,D-,D+,地线。我们暂且把这样的叫做标准的USB接头吧。后来OTG出现了,又增加了miniUSB接头。而miniUSB接头则有5条线,多了一条ID线,用来标识身份用的。标准USB口只有A型和B型。其中每一型又分为插头和插座,例如A型插头,A型插座等。我们平常电脑上用的那种插座叫做A型USB插座,而相应的插头,叫做A型插头,例如U盘上那种。而像打印机上面那个插座,则是B型插座(比较四方的,没电脑上面那种扁),相应的插头,就是B型插头。也许你见过一头方一头扁的USB延长线,没错了,扁的那头就叫做A型插头,而方的那头,就叫做B型插头,而相应的被插的那两个插座,就分别是A型插座和B型插座了。A型插头是插不进B型插座的,反之亦然。

          miniUSB也分为A型,B型,但增加了一个AB型(不是血型呀,别搞错了,没有O型^_^)。既然它叫做miniUSB,那么当然它就是很小的了,主要是给便携式设备用的,例如MP3、手机、数码相机等。USB是一主多从结构,即一个时刻只能有一台主机。像PC机就是一个主机,其它的只能是设备,因而两个设备之间是无法直接进行通信的。而USB OTG(on the go)的出现,则解决了这个矛盾:一个设备可以在某种场合下,改变身份,以主机的形式出现。因而就出现了AB型的miniUSB插座,不管是A型miniUSB插头,还是B型miniUSB插头,都可以插进去,而靠里面多出的那条ID线来识别它的身份:是主机还是从机。这样两个USB设备就可以直接连接起来,进行数据传送了。 像我们MP3上用的那中miniUSB插座,就是B型的miniUSB插座(注意,有一类miniUSB插座,似乎不是USB规范里面的,因为miniUSB接头应该有5条线,而这种插座只有4条线)。由于USB是支持热插拔的,因此它在接头的设计上也有相应的措施。USB插头的地引脚和电源引脚比较长,而两个数据引脚则比较短,这样在插入到插座中时,首先接通电源和地,然后再接通两个数据线。这样就可以保证电源在数据线之前接通,防止闩锁发生。至于USB电缆,通常我们不怎么关心,买现成的就行了,除非你是生产USB线缆的。在全速模式下需要使用带屏蔽的双绞电缆线,而低速模式模式则可以不用屏蔽和双绞。此外,USB协议规定,USB低速电缆长度不得超过3米,而全速电缆长度不得超过5米。这是因为线缆传输有延迟,要保证能够正确响应,就不能延迟太多。USB标准规定了里面信号线的颜色,其中Vbus为红色,D-为白色,D+为绿色,GND为黑色。然而,我见过很多USB线缆并没有遵循标准,所以大家在使用时要小心,用表测量一下比较可靠。


    2、集线器把USB设备的连接报告给USB主控制器

          首先,在USB集线器的每个下游端口的D+和D-上,分别接了一个15K欧姆的下拉电阻到地。这样,在集线器的端口悬空时,就被这两个下拉电阻拉到了低电平。而在USB设备端,在D+或者D-上接了1.5K欧姆上拉电阻。对于全速和高速设备,上拉电阻是接在D+上;而低速设备则是上拉电阻接在D-上。这样,当设备插入到集线器时,由1.5K的上拉电阻和15K的下拉电阻分压,结果就将差分数据线中的一条拉高了。集线器检测到这个状态后,它就报告给USB主控制器(或者通过它上一层的集线器报告给USB主控制器),这样就检测到设备的插入了。USB高速设备先是被识别为全速设备,然后通过HOST和DEVICE两者之间的确认,再切换到高速模式的。在高速模式下,是电流传输模式,这时将D+上的上拉电阻断开。


    二、什么是热插拔

    1、基础概念

         热插拔(hot-plugging或Hot Swap)即带电插拔,热插拔功能就是允许用户在不关闭系统,不切断电源的情况下取出和更换损坏的硬盘、电源或板卡等部件,从而提高了系统对灾难的及时恢复能力、扩展性和灵活性等,例如一些面向高端应用的磁盘镜像系统都可以提供磁盘的热插拔功能。具体用学术的说法就是:热替换(Hot replacement)、热添加(hot expansion)和热升级(hot upgrade)


    2、热插拔好处

    系统中加入热插拔的好处包括:

    在系统开机情况下将损坏的模块移除,还可以在开机情况下做更新或扩容而不影响系统操作。

    由于热插拔零件的可靠度提升,还可以将它们用做断电器,而且因为热插拔能够自动恢复,有很多热插拔芯片为系统提供线路供电情况的信号,以便系统做故障分析,因此减少了成本。


    三、Linux 下USB热插拔处理

    1、 Linux下USB HUB的驱动的实现和分析:

           在系统初始化的时候在usb_init函数中调用usb_hub_init函数,就进入了hub的初始化

           在usb_hub_init函数中完成了注册hub驱动,并且利用函数kthread_run创建一个内核线程。该线程用来管理监视hub的状态,所有的情况都通过该线程来报告。

          USB设备是热插拔,这就和PCI设备不同,PCI设备是在系统启动的时候都固定了,因此PCI设备只需要初始化进行枚举就可以了,采用递归算法即可。而USB设备需要热插拔,因此在hub_probe函数中调用hub_configure函数来配置hub,在这个函数中主要是利用函数usb_alloc_urb函数来分配一个urb,利用usb_fill_int_urb来初始化这个urb结构,包括hub的中断服务程序hub_irq的,查询的周期等。

           每当有设备连接到USB接口时,USB总线在查询hub状态信息的时候会触发hub的中断服务程序hub_irq,在该函数中利用kick_khubd将hub结构通过event_list添加到khubd的队列hub_event_list,然后唤醒khubd。进入hub_events函数,该函数用来处理khubd事件队列,从khubd的hub_event_list中的每个usb_hub数据结构。该函数中首先判断hub是否出错,然后通过一个for循环来检测每个端口的状态信息。利用usb_port_status获取端口信息,如果发生变化就调用hub_port_connect_change函数来配置端口等。


    2、软件层次分析

    这里我们先讲讲USB热插拔事件的处理工作。---Khubd守护进程。

    -Khubd守护进程它是一个守护进程,来检查usb port的事件通知HCD和usb core,然后做相应的处理。

    驱动目录drivers/usb/*
    usb/serial  usb 串行设备驱动 (例如usb 3G卡、蓝牙等)
    usb/storage  usb 大储量磁盘驱动(u盘)  
    usb/host usb host usb主机控制器驱动(嵌入式otg:dwc_otg)
    usb/core   usb 核心一些处理代码,所有的驱动相关处理都在这里,也都注册到它里面。
    usb/usb-skeleton.c 经典的usb客户驱动框架,可以参考

    当然还有其他这里不再说明。

    下面贴出USB的整体驱动框架:


    这里我们主要分析khub的工作原理: 硬件层次是hub的工作,如何和host及其设备间通信及相应事件

    [usb/core/hub.c ]

    1. int usb_hub_init(void)  
    2. {  
    3.     if (usb_register(&hub_driver) < 0) {  
    4.         printk(KERN_ERR "%s: can't register hub driver\n",  
    5.             usbcore_name);  
    6.         return -1;  
    7.     }  
    8.   
    9.     khubd_task = kthread_run(hub_thread, NULL, "khubd");  
    10.     if (!IS_ERR(khubd_task))  
    11.         return 0;  
    12.   
    13.     /* Fall through if kernel_thread failed */  
    14.     usb_deregister(&hub_driver);  
    15.     printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);  
    16.   
    17.     return -1;  
    18. }  
    
      
    1. int usb_hub_init(void)
    2. {
    3. if (usb_register(&hub_driver) < 0) {
    4. printk(KERN_ERR "%s: can't register hub driver\n",
    5. usbcore_name);
    6. return -1;
    7. }
    8. khubd_task = kthread_run(hub_thread, NULL, "khubd");
    9. if (!IS_ERR(khubd_task))
    10. return 0;
    11. /* Fall through if kernel_thread failed */
    12. usb_deregister(&hub_driver);
    13. printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);
    14. return -1;
    15. }
    这里我们只关心kthread_run(hub_thread, NULL, "khubd"); 然后我们看hub_thread函数
    1. static int hub_thread(void *__unused)  
    2. {  
    3.     do {  
    4.         hub_events();  
    5.         wait_event_interruptible(khubd_wait,  
    6.                 !list_empty(&hub_event_list) ||  
    7.                 kthread_should_stop());  
    8.         try_to_freeze();  
    9.     } while (!kthread_should_stop() || !list_empty(&hub_event_list));  
    10.   
    11.     pr_debug("%s: khubd exiting\n", usbcore_name);  
    12.     return 0;  
    13. }  
    
      
    1. static int hub_thread(void *__unused)
    2. {
    3. do {
    4. hub_events();
    5. wait_event_interruptible(khubd_wait,
    6. !list_empty(&hub_event_list) ||
    7. kthread_should_stop());
    8. try_to_freeze();
    9. } while (!kthread_should_stop() || !list_empty(&hub_event_list));
    10. pr_debug( "%s: khubd exiting\n", usbcore_name);
    11. return 0;
    12. }

    这里我们看到了hub_events()函数。然后设置运行状态,如果有事件就加入hub_event_list。自此khubd运行起来了。

    这里我们同样贴出它的函数调用流程图(这里懒得自己画了,就剪切了个^^)



    通过流程图我们可以清晰的明白,当usb设备插入usb接口后,khubd运行,它检测到port状态的变化,调用hub_port_connect_change(),如果是新设备那么usb_allco_dev,然后调用usb_new_device来进行配置使usb设备可以正常工作。详细流程请看源码。


    四、USB的枚举过程

           内核辅助线程khubd用来监视与该集线器连接的所有端口,通常情况下,该线程处于休眠状态,当集线器驱动程序检测到USB端口状态变化后,该内核线程立马唤醒

          USB的枚举过程:USB的枚举过程是热插拔USB设备的起始步骤,该过程中,主机控制器获取设备的相关信息并配置好设备,集线器驱动程序负责该枚举过程

    枚举过程主要分如下几步:

    Step1:根集线器报告插入设备导致的端口电流变化,集线器驱动程序检测到这一状态变化后,唤醒khubd线程。

    Step2:khubd识别出电流变化的那个端口

    Step3:khubd通过给控制端点0发送控制URB来实现从1-127中选出一个数作为插入设备的批量端点

    Step4:khubd利用端口0使用的控制URB从插入的设备那里获得设备描述符,然后获得配置描述符,并选择一个合适的。

    Step5:khubd请求USB核心把对应的客户驱动程序和该USB设备挂钩



    展开全文
  • 最近测试发现,运行qt程序,当使用USB触摸屏时,在触摸屏拔出后触摸屏的event节点会消失,当再次插入触摸屏时,即使生成了...在QWSTslibMouseHandlerPrivate::readMouseData()的开始处加入以下代码,即可支持热插拔

    最近测试发现,运行qt程序,当使用USB触摸屏时,在触摸屏拔出后触摸屏的event节点会消失,当再次插入触摸屏时,即使生成了相同的节点,屏幕已经不能点击了。

    解决办法:

    解决办法:修改qt源码,使qt支持触屏的热插拔,使用的qt库为4.8.6

    因为使用的是使用的是tslib库,对应的源码在qt源码中的src/gui/embedded/qmousetslib_qws.cpp

    在QWSTslibMouseHandlerPrivate::readMouseData()的开始处加入以下代码,即可支持热插拔:

    void QWSTslibMouseHandlerPrivate::readMouseData() 
    {
        if(!qt_screen)
            return;
        /* Support usb touchscreen hotplug */
        int version;
        if (ioctl(ts_fd(dev), EVIOCGVERSION, &version) < 0) {
            disconnect(mouseNotifier, 0, 0, 0);
            delete mouseNotifier;
            while (1) {
                if(open()) {
                    mouseNotifier = new QSocketNotifier(ts_fd(dev), QSocketNotifier::Read, this);
                    connect(mouseNotifier, SIGNAL(activated(int)), this, SLOT(readMouseData()));
                    resume();
                    return;
                }
                system("echo waiting for tp ...");
                system("sleep 1");
            }
        }
        /* end */
        ...
    }

    重新编译qt,将生成的libQtGui.so.4.8.6替换到机器上即可。

     

    展开全文
  • 实现android usb光驱 光盘支持 光驱热插拔 光盘热插拔 1.增加vold对Iso9660光盘自动挂载的支持,基于RK3188_RK3066_R-BOX_ANDROID4.4.2-SDK_V1.0.0_140318,也可用于mid 2.实现Iso9660.cpp为vold实现的domount接口 3...
  • qt -evdev默认编译选项,鼠标和键盘热拔插支持文件 /Users/xiejianwei/Qt5.7.0/5.7/Src/qtbase/src/platformsupport/devicediscovery目录下qdevicediscovery_static.cpp和qdevicediscovery_static_p.h, 编辑这2个...
  • 基于WPF的串口助手 自动检测串口 支持热插拔 C#语言 VS2015工程
  • 硬件上来说,可热插拔的设备一般都会对电源部分格外重视,除了包含防止插拔的过程中对正负极可能造成的意外短路之外,热插拔还要保证电源负极先于其他引脚连接进系统,提供ESD放电回路。然后连接进的是电源正极,为...
  • 1、使用Windows API串口编程方法实现的串口工具(**支持热插拔功能**),Serial.cpp为串口通信类。界面是使用MFC编程的。编译工具是vs2017,也可在vs2008编译执行,此zip中包含可执行的源代码和可直接使用的exe。 注意...
  • 之前就做过Qt之支持usb触摸屏热插拔(Qt4.7)_朗朗上口就行啦的博客-CSDN博客的USB触摸屏热插拔,在Qt5的又碰到了被干扰之后恢复,一开始我根据百度的情况,我以为我是界面对触摸屏不支持热插拔,所以就无法操作了。...
  • libusb中的热插拔使用举例

    千次阅读 2020-04-26 13:57:09
    以下为判断usb设备是插入还是拔出状态(热插拔)的测试代码:在Windows下是不支持的,在Linux是支持的,下一个版本可能会支持Windows下的热插拔: #include <chrono> #include <thread> #include <...
  • linux下usb热插拔处理

    2011-12-01 21:30:12
    本文介绍的是linux下处理usb热插拔的方法
  • usb触摸屏断开之后,即使重连,在已经运行的qt程序中,并且系统已经生成了触摸设备节点,qt程序也是能恢复触摸。 解决方法:修改qt源码中的src/gui/embedded/qmousetslib_qws.cpp 在QWSTslibMouseHandlerPrivate...
  • openwrt USB外挂U盘的时候很需要热插拔功能 openwrt官网传送门 当某些事件发生时,Procd(init系统和进程管理守护进程)执行位于/etc/hotplug.d/中的脚本,例如当接口启动或关闭时,检测到新的存储驱动器时,或者...
  • QT5的usb键鼠热插拔支持

    千次阅读 2020-03-05 09:50:09
    有两种方案: 1.利用系统的udev进行热插拔检测,QT...所以很多嵌入式系统都不支持这种方式,除非你的文件系统移植了systemd,systemd有一个systemd-udev的程序专门用于处理热插拔事件,而且systemd文档齐全,像...
  • 配置虚拟机支持USB设备的热插拔

    千次阅读 2015-06-02 20:37:22
    今天,无意中把山寨的JLINK,用segger 4.90给升级了,导致无法使用,非常郁闷。...结果是,虚拟机能动态的支持USB设备。物理机和虚拟机应该是一样的啊。 后来,百度搜了搜,才找到原因。因为我本身用
  • Qt5修改支持热插拔

    2020-11-02 18:33:53
    原文: ...QT5.7.0 嵌入式平台 usb鼠标键盘热插拔问题 - it610.comhttps://www.it610.com/article/1305212461422514176.htm 谢谢作者,真是帮了大忙了,亲测可以解决USB鼠标键盘热插拔问题。
  • USB热拔插事件

    万次阅读 2018-08-26 11:35:41
    前言 USB(Universal Serial ...USB接口常用在诸如USB串行设备驱动(3G/4G上网卡、蓝牙设备、串口设备)、USB大容量磁盘驱动(U盘、移动硬盘)、USB主机控制器驱动(嵌入式otg,dwc_otg)、USB键盘鼠标等,这一些的...
  • Qt4.8.6支持USB触摸屏热插拔

    千次阅读 2016-11-04 14:09:38
    Qt4.8.6支持USB触摸屏热插拔当前环境:qt-everywhere-opensource-src-4.8.6 + tslib-1.4 + linux 3.2.0测试发现,运行qt程序,当使用USB触摸屏时,在触摸屏拔出后触摸屏的event会消失,当再次插入触摸屏时,屏幕已经...
  • USB 设备热插拔的检测

    2020-09-18 18:02:37
    2. 打开软件后, USB 热插拔 。 此时用WM_DEVICECHANGE消息去获取设备信息。 当设备插入或者移除时,系统给当前主窗口发送WM_DEVICECHANGE消息 。 注意: 默认状态, 任何设备都会通知。 所以需要注册指定的通知消息...
  • Linux下实现USB口的热插拔

    千次阅读 2016-08-04 16:15:19
    目前要做一个在嵌入式平台上的USB口的热插拔事件。 经过我现在的分析总结目前有如下方法: 1,定时检查/proc/scsi/scsi文件 此方法只能在PC上,但在嵌入式平台上可用。 2,netlink方式 使用netlink. #...
  • 硬件设计使用了,usb转sd卡的电路,类似sd卡读卡器,经过测试,发现linux系统,usb动,直接插拔sd卡,系统无法热插拔, 经过多方验证,查找到一种复位usb节点的方法,可实现重新加载usb设备,可以类比其他类似...
  • 支持USB触摸屏热插拔: https://blog.csdn.net/kp339/article/details/53034215 QT 支持鼠标和触摸屏输入:https://blog.csdn.net/sean_8180/article/details/82532869
  • usb热插拔的来龙去脉

    千次阅读 2016-02-29 14:44:39
    USB主机是如何检测到设备的插入的呢?首先,在USB集线器的每个下游端口的D+和D-上, 分别接了一个15K欧姆的下拉电阻到地。这样,在集线器的端口悬空时,就被这两个下拉电阻 拉到了低电平。而在USB设备端,在D+...
  • 转自:https://blog.csdn.net/shengzhadon/article/details/51455361QT5.5.1 嵌入式平台 鼠标键盘热插拔问题解决 qt5.7.0编译的默认输入选项是-evdev,不支持usb鼠标热拔插,可以修改qt安装目录/Users/...
  • Linux USB U盘热插拔挂载和卸载

    万次阅读 2016-03-31 16:57:35
    MT7620的U盘热插拔监听,热插拔挂载与卸载。 当插入U盘,则挂载; 当拔出U盘,则卸载。 监听热插拔采用socket监听,由用户层程序监听,并实现自动挂载与卸载。
  • C#USB转串口实现热插拔检测

    千次阅读 2019-08-14 14:04:57
    本程序可实现USB转串口实现热插拔检测: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO.Ports; using System.Linq; ...
  • 问题现象1:当使用Hi3519V10X/Hi3559V100 USB3.0 Device UVC规格时,正常热插拔会必现识别的问题。 问题现象2:当使用Hi3516CV300 USB2.0 Device UVC规格时,快速热插拔出现概率识别问题, 此两种问题现象的解决...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,358
精华内容 3,343
关键字:

usb不支持热插拔