热插拔消息
热插拔消息的格式
如上图所示,消息的前 4 个字节标识了消息的类型,为大端格式。当前定义的消息类型位于 SylixOS/system/hotplugLib/hotplugLib.h 头文件中,例如:USB 键盘、USB 鼠标、SD 存储卡、SDIO 无线网卡等。在实际的硬件平台上,设备驱动也可以定义自己的热插拔消息类型。
第 5 个字节为设备状态,0 表示拔出,1 表示插入。
从第 6 个字节开始,表示设备的名称,其内容为一个以 \0 结束的字符串,应用程序应该以此为结束符得到完整的名称。该名称为一个设备的完整路径名称,如 /dev/ttyUSB0、/media/sdcard0 等。由于 SylixOS 中,一个完整路径名称的最大长度为 512,加上结束字符 \0,因此,dev name 字段的最大长度为 513。
紧跟着设备名称(\0 字符结尾)的是 4 个可用于灵活扩展的参数,均为 4 字节长度。这 4 个参数可适应不同设备消息的特殊处理。SylixOS 未规定每个参数的具体用法和存储格式(大端或小端),完全由设备驱动定义。
从上面我们可以知道,一个热插拔消息的最大长度为:4 + 1 + 513 + 4 + 4 + 4 + 4 = 534 字节。
处理热插拔消息
下面将通过一个具体的例子介绍如何通过/dev/hotplug 设备获取并处理热插拔消息。
#include <stdio.h>
#include <string.h>
#define MSG_LEN_MAX (534)
int main(int argc, char *argv[])
{
UINT8 pucMsgBuff[MSG_LEN_MAX];
INT iFd;
INT32 iMsgType;
BOOL bInsert;
CHAR *pcDevName;
UINT8 *pucArg;
UINT8 *pucTemp;
ssize_t sstReadLen;
iFd = open("/dev/hotplug", O_RDONLY);
if (iFd < 0) {
fprintf(stderr, "open /dev/hotplug failed.\n");
return (-1);
}
while (1) {
sstReadLen = read(iFd, pucMsgBuff, MSG_LEN_MAX);
if (sstReadLen < 0) {
fprintf(stderr, "read hotplug message error.\n");
close(iFd);
return (-1);
}
if (sstReadLen < 5) {
continue;
}
/*
* 解析热插拔消息
*/
pucTemp = pucMsgBuff;
iMsgType = (pucTemp[0] << 24)
| (pucTemp[1] << 16)
| (pucTemp[2] << 8)
| (pucTemp[3]);
pucTemp += 4;
bInsert = *pucTemp ? TRUE : FALSE;
pucTemp += 1;
pcDevName = (CHAR *)pucTemp;
pucArg = pucTemp + strlen(pcDevName) + 1;
printf("get new hotplug message >>\n"
" message type: %d\n"
"device status: %s\n"
" device name: %s\n"
" arg0: 0x%01x%01x%01x%01x\n"
" arg1: 0x%01x%01x%01x%01x\n"
" arg2: 0x%01x%01x%01x%01x\n"
" arg3: 0x%01x%01x%01x%01x\n",
iMsgType,
bInsert ? "insert" : "remove",
pcDevName,
pucArg[0], pucArg[1], pucArg[2], pucArg[3],
pucArg[4], pucArg[5], pucArg[6], pucArg[7],
pucArg[8], pucArg[9], pucArg[10], pucArg[11],
pucArg[12], pucArg[13], pucArg[14], pucArg[15]);
}
close(iFd);
return (0);
}
在上面的程序中,对获得的热插拔消息进行了简单的错误处理,即消息长度至少应该为 5 个字节长,因为一个热插拔消息必然包含消息类型和设备的插入/拔出状态两个信息。
注意:
在程序中处理消息类型时,需要按照大端数据存储格式进行解析,即低地址的字节代表的是高字节数据。消息的额外参数的起始地址即为设备名称起始地址加上其长度和结束字符的地址。
程序运行后,假如我们插入或拔出 SD 存储卡,将会打印如下的信息:
插入 SD 存储卡 :
get new hotplug message >>
message type: 346
device status: insert
device name: /media/sdcard0
arg0: 0x0000
arg1: 0x0000
arg2: 0x0000
arg3: 0x0000
拔出 SD 存储卡 :
get new hotplug message >>
message type: 346
device status: remove
device name: /media/sdcard0
arg0: 0x0000
arg1: 0x0000
arg2: 0x0000
arg3: 0x0000
上面显示消息类型的值为十进制的 346,对比 SylixOS/system/hotplugLib/hotplugLib.h 文件中定义的消息类型,等于 LW_HOTPLUG_MSG_SD_STORAGE(0x0100 + 90),这正是 SD 存储卡设备的热插拔消息。消息中的设备名称为 /media/sdcard0,这是 SylixOS 中 SD 存储卡的标准命名方式。此外其他的存储设备也会默认挂载在 /media 目录下,如 U 盘的名称为 /media/udisk0。4 个额外参数的值均为 0,说明 SD 存储卡对应的热插拔消息并未使用这个额外参数(实际上,大部分热插拔消息都未使用额外参数)。
上面的程序为一个通用的检测系统中所有热插拔消息的示例,没有针对具体的消息类型处理对应的额外参数信息,仅仅将其值以十六进制的方式打印出来。由于 /dev/hotplug 设备能够被任何程序多次打开,因此在实际使用中,一个程序通常只需要读取自己关心的热插拔消息类型即可,比如 SylixOS 中的 xinput 模块,它只监测输入设备的状态,如 USB 鼠标、USB 键盘等。
注意:
当用户注册了 usb 相关驱动模块后,系统将接管 usb,键盘鼠标等设备若要使用,需要添加环境变量,然后重启 SylixOS 设备即可:
# env
......
MOUSE=/dev/input/mouse0:/dev/input/touch0
......
# ls /dev/input/
kbd0 mse0
# KEYBOARD=$KEYBOARD:/dev/input/kbd0
# varsave
environment variables save to /etc/profile success.