前言:
由于项目需要,采用qt5.5.1开发界面,要求支持键鼠。经过uboot/kernel/fs的移植之后usb接口的热插拔已经OK,但是QT怎么也不支持热插拔,工作任务和强迫症双层压力下,决心对键鼠的热插拔一探究竟。
首先感谢http://blog.csdn.net/fu851523125/article/details/51190316博主的文章,给了我不少灵感,在下面的文章中我也会引用其文章中的语句。
这里是我综合了自己的理解,采用不同于上面博主的另外一个方法实现。
切入正题
========================================================
诚如QT官网(http://doc.qt.io/qt-5/embedded-linux.html)所述如下,
Mouse
The mouse cursor shows up whenever QT_QPA_EGLFS_HIDECURSOR
(for eglfs) or
QT_QPA_FB_HIDECURSOR
(for linuxfb) is not set and Qt's libudev-based device discovery reports that at least one mouse is available. When
libudev
support is not present, the mouse cursor always show up unless explicitly disabled via the environment variable.
Hot plugging is supported, but only if Qt was configured with libudev
support (that is, if the libudev development headers are present in the sysroot at configure time). This allows connecting or disconnecting an input device while the application
is running.
解释一下:在不设置QT_QPA_EGLFS_HIDECURSOR
(for eglfs) or
QT_QPA_FB_HIDECURSOR
(for linuxfb)两个环境变量的情况下,鼠标是可以显示的,并且只有在支持libudev情况下QT才能支持热插拔。
官网说的很清楚,就是需要支持libudev,查看配置文件configure的帮助信息(执行./configure -h),在列出的信息中没有udev或者libudev的相关信息,但是之前一致过程中存在相关信息的,如下图,说明是没有配置成功的
于是搜索qt源码根目录下(以下表示为QT_ROOT/)的configure没有任何发现,再搜索QT_ROOT/qtbase/目录下的configure,键入【grep -rn "udev" configure】结果如下
1844: libudev)
5251: if [ -n "$PKG_CONFIG" ] && $PKG_CONFIG --exists libudev 2>/dev/null; then
5252: QMAKE_INCDIR_LIBUDEV=`$PKG_CONFIG --cflags-only-I libudev 2>/dev/null | sed -e 's,^-I,,g' -e 's, -I, ,g'`
5253: QMAKE_LIBS_LIBUDEV=`$PKG_CONFIG --libs libudev 2>/dev/null`
5254: QMAKE_CFLAGS_LIBUDEV=`$PKG_CONFIG --cflags libudev 2>/dev/null`
5258: if compileTest unix/libudev "libudev" $QMAKE_CFLAGS_LIBUDEV $QMAKE_LIBS_LIBUDEV; then
5260: QT_CONFIG="$QT_CONFIG libudev"
5262: echo "The libudev functionality test failed!"
说明存在相应的配置,在网上查找相应帮助,有位博主已经尝试过,他的结果是:
需要libudev.h头文件。得移植udev。然后重新配置 使出现libudev enabled,libudev测试通过。
但是拿到开发板上,还是不支持热插拔啊。
我也进行了移植尝试,首先下载udev源码https://www.kernel.org/pub/linux/utils/kernel/hotplug/,我用的qt版本比较高,于是下载比较新的udev-182,解压后配置udev相应的congfigure,然后make,由于中间遇到了各种各样的问题,时间紧迫,时间是个单程票耽误不得,再在网上找资料验证自己的方案可能性有多大。发现一片文章介绍udev/mdev的区别(网址如下:http://www.tuicool.com/articles/Eb6FB3),内容如下
==========================================================
关于udev和mdev之间的区别与联系我发现自己现在还没有把它完整的给区分开来和联系起来.
设备文件系统有devfs,mdev,udev
mdev是udev的简化版本,是busybox中所带的程序,最适合用在嵌入式系统,而udev一般用在PC上的linux中,相对mdev来说要复杂些,devfs是2.4内核引入的,而在2.6内核中却被udev所替代,他们有着共同的优点,只是devfs中存在一些未修复的BUG,作者也停止了对他的维护,最显著的一个区别,采用devfs时,当一个并不存在的设备结点时,他却还能自动的加载对应的设备驱动,而udev则不能,udev认为当加载了不存在的对应的设备驱动的时候不应加载对应的驱动模块,因为加载也没有,浪费了资源.
从本质上来说,udev与mdev他们都是一个应用程序,配置了就可以使用,为了方便使用,我们可以使用busybox自带的mdev,当然也可以去下载udev的源码去编译和移植.
这应该是对udev和mdev的一个理解,我们下次可以再深入一些.
dev 和mdev 是两个使用uevent 机制处理热插拔问题的用户空间程序,两者的实现机理不同。udev 是基于netlink 机制的,它在系统启动时运行了一个deamon 程序udevd,通过监听内核发送的uevent 来执行相应的热拔插动作,包括创建/删除设备节点,加载/卸载驱动模块等等。mdev 是基于uevent_helper 机制的,它在系统启动时修改了内核中的uevnet_helper 变量(通过写/proc/sys/kernel/hotplug),值为“/sbin/mdev”。这样内核产生uevent
时会调用uevent_helper 所指的用户级程序,也就是mdev,来执行相应的热拔插动作。udev 使用的netlink 机制在有大量uevent 的场合效率高,适合用在PC 机上;而mdev 使用的uevent_helper 机制实现简单,适合用在嵌入式系统中。另外要说明的一点是,uevent_helper 的初始值在内核编译时时可配置的,默认值为/sbin/hotplug。如果想修改它的值,写/proc/sys/kernel/hotplug
文件就可以了,例如:
echo “/sbin/mdev” > /proc/sys/kernel/hotplug
补充一点:如果使用的是udevd,那么uevent_helper变量应为空,即
echo “ ” > /proc/sys/kernel/hotplug
这段内容总结的很好,我也看了linux内核有关uevent的代码,的确是这样,这样看来简单的将mdev看做udev的简化版也就不准确了。这样在做嵌入式的文件系统就要注意了,一般只会使用mdev,目前我还不确定能不能只用udev,理论上是可以的,当然两种一起用也是可以的,也就是mdev + udev,但是这时要注意了,写规则时一定要注意,避免让它们重复执行。也就是说udev执行过的,mdev不要再执行了。其实udev最大的特点就是使用了netlink,实质上是一个scoket,这个特别的scoket用来监测uevent,当然,我们也可以自己写一个函数用来监测任何uevent事件。
=====================================================
文章中被我标红的说明我采用的方法不是常规(或者说风险比较大)的方法,于是果断寻找另外的方案。
准备走一下QT的源代码,QT官网指示调试信息如下
Debugging Input Devices
It is possible to print some information to the debug output by enabling the
qt.qpa.input
logging rule, for example by setting the QT_LOGGING_RULES
environment variable to
qt.qpa.input=true
. This is useful for detecting which device is being used, or to troubleshoot device discovery issues.
打开调试信息的输出,即在嵌入式系统执行命令【export QT_LOGGING_RULES=qt.qpa.input=true】 ,再次启动QT后插拔键鼠会出现相应的调试信息。
qt.qpa.input: evdevkeyboard: Using device discovery
qt.qpa.input: udev device discovery for type QFlags(0x8)
qt.qpa.input: Found matching devices ()
qt.qpa.input: evdevmouse: Using device discovery
qt.qpa.input: udev device discovery for type QFlags(0x1|0x2)
qt.qpa.input: Found matching devices ()
qt.qpa.input: evdevtouch: Using device discovery
qt.qpa.input: udev device discovery for type QFlags(0x2|0x4)
搜索上述相应的信息可定位代码位置。具体的代码分析可以见http://blog.csdn.net/fu851523125/article/details/51192065。
于是产生了我最终解决方案的思路,具体见下移篇文章。