本文描述如何在应用中通过不轮询的方式对TF卡热拔插的检测。文中根据实际项目实现所写,部分内容有载抄至其它博客,如有侵权,请在评论中与我联系!
在项目中要实现对TF卡热拔插的检测,最初是采用轮询的方式帧测/dev目录下的结点来实现。但这种方式有两个缺点:一是在应用层一直要占用CPU,二是要放在一个循环中,不利于代码模块化。所以后来让系统帧测卡热拔插事件,再给指定的应用进程发信号的方式来实现。这样就不用在应用层去轮询检测,只要注册相应的信号函数,再在函数中判断卡的插入和拔出状态就可以了。
在这里要用到内核mdev机制,如下为其简单介绍:
mdev是busybox自带的一个简化版的udev,功能类似。都是帧测内核的uevent事件来感知系统的热拔插事件。
作用是在系统启动和热插拔 或动态加载驱动程序时,自动产生驱动程序所需的节点文件。文件系统中的/dev目录下的设备节点都是由mdev创建的。使用mdev时不加参数就是用hotplug机制来决定创建什么样的设备文件。而用mdev -s命令是表示用sys文件系统提供的信息来创建设备文件的.
mdev -s扫描/sys/class和/sys/block中所有的类设备目录,如果在目录中含有名为"dev"的文件,且文件中包含的是设备号,则mdev就利用这些信息为这个设备在/dev下创建设备节点。
在这里就要用到其热插拔时自动生成/dev下文件节点的功能。当有此事件时,发送一个信号到应用进程,再在注册的信号函数中判断/dev目录下对应的卡设备节点是否存在来识别卡插入或排出。具体实现方法如下:
1.在buildroot配置menuconfig中打开对mdev的支持。我当前使用的BusyBox 1.18.x版本,未查到mdev的选项,只有udev选项。所以我就打开了udev选项,也是可行的。这部分还有待澄清。具体打开方式读者可以自行查找,在此就不作说明了。
2.因mdev依赖于sys文件系统下的节点信息,所以在内核启动的时候要挂载sys文件系统。并还要做相关的配置。可以在启动脚本中执行如下命令
mount -t devfs none /dev
mount -t sysfs sysfs /sys
echo /sbin/mdev > /proc/sys/kernel/hotplug /* 系统感知到热拔插事件时执行/sbin/mdev程序 */
mdev -s /* 根据/sys/目录下的结节信息创建/dev/目录下的设备节点 */
3.配置/etc/mdev.conf文件,该文件作用是mdev帧到热拔插事件时,会执行里面的操作。这样我们就可以根据需求自定义一些操作。
mmcblk0 0:0 777 * kill -s SIGUSR2 `pidof car_video`
上述意思是当发现mmcblk0这个设备时,给用户空间card_video这个进程发送SIGUSR2信号。
4.在card_video这个进程中,使用signal(SIGUSR2, card_detection);注册信号函数,在函数中就可以通过判断/dev下的卡结点是否存在来识别卡插入还是拔出状态。进而做进一步操作。
关于mdev.conf文件格式,将busybox中的说明摘抄如下:
-------------
MDEV Config (/etc/mdev.conf)
-------------
Mdev has an optional config file for controlling ownership/permissions of
device nodes if your system needs something more than the default root/root
660 permissions.
The file has the format:
or @
For example:
hd[a-z][0-9]* 0:3 660
The config file parsing stops at the first matching line. If no line is
matched, then the default of 0:0 660 is used. To set your own default, simply
create your own total match like so:
.* 1:1 777
You can rename/move device nodes by using the next optional field.
So if you want to place the device node into a subdirectory, make sure the path
has a trailing /. If you want to rename the device node, just place the name.
hda 0:3 660 =drives/
This will move "hda" into the drives/ subdirectory.
hdb 0:3 660 =cdrom
This will rename "hdb" to "cdrom".
Similarly, ">path" renames/moves the device but it also creates
a direct symlink /dev/DEVNAME to the renamed/moved device.
If you also enable support for executing your own commands, then the file has
the format:
or
The special characters have the meaning:
@ Run after creating the device.
$ Run before removing the device.
* Run both after creating and before removing the device.
The command is executed via the system() function (which means you're giving a
command to the shell), so make sure you have a shell installed at /bin/sh. You
should also keep in mind that the kernel executes hotplug helpers with stdin,
stdout, and stderr connected to /dev/null.
For your convenience, the shell env var $MDEV is set to the device name. So if
the device "hdc" was matched, MDEV would be set to "hdc".