在OpenWRT中修改一个定制的按键输入需要涉及几个地方的修改:
1. 内核修改,添加需要操作的GPIO端口;
2. 在程序中使用netlink机制借助于socket API,检测按键输入。
3. 如果只是简单的操作,可以通过修改/etc/hotplug.d/button/buttons实现。
1、内核修改:
以AR9331为例,源代码路径:
openwrt/build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/linux-3.10.49/arch/mips/ath79
修改对应的mach-xxx.c文件,具体的修改格式,参见其他mach-xxx.c文件。修改完成后,重新编译,更新内核即可。
build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/linux-3.10.49/arch/mips/ath79/match-el-150.c
build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/linux-3.10.49/arch/mips/ath79/match-el-mini.c
示例:
static struct gpio_keys_button mini_gpio_keys[] __initdata = {
{
.desc = "reset",
.type = EV_KEY,
.code = KEY_RESTART,
.debounce_interval = MINI_KEYS_DEBOUNCE_INTERVAL,
.gpio = MINI_GPIO_BTN_RESET,
.active_low = 0,
},
{
.desc = "BTN_6",
.type = EV_KEY,
.code = BTN_6,
.debounce_interval = MINI_KEYS_DEBOUNCE_INTERVAL,
.gpio = MINI_GPIO_BTN6,
.active_low = 1,
},
};
2、使用Netlink机制
应用程序使用netlink,借助于socket API来实现按键的状态获取。当有按键按下的时候,read()函数会返回一个字符串,通过解析字字符串可以得知按下的按键以及按键的行为。
在使用时,必须包含的头文件:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// *******************************************************************
#define BUTTON_CONFIG "BTN_6"
#define BUTTON_CONFIG_SIZE (uint8_t)5
#define BUTTON_RESET "reset"
// *******************************************************************
typedef struct ButtonType {
int type;
int pressedTime;
} ButtonType;
// *******************************************************************
typedef struct ButtonInputEvent {
char *button;
char *action;
} ButtonInputEvent;
// *******************************************************************
// static variables
static ButtonType buttonType;
static ButtonType *type;
static int ButtonFd;
// *******************************************************************
int InitNetlinkSock(void)
{
struct sockaddr_nl snl;
int retval;
memset(&snl, 0x00, sizeof(struct sockaddr_nl));
snl.nl_family = AF_NETLINK;
snl.nl_pid = getpid();
snl.nl_groups = 1;
int hotplug_sock = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT);
if (hotplug_sock == -1) {
printf("error get socket:%s",strerror(errno));
return -1;
}
/* set receive buffersize */
retval = bind(hotplug_sock,(struct sockaddr *)&snl,sizeof(struct sockaddr_nl));
if (retval < 0) {
printf("bind failed:%s",strerror(errno));
close(hotplug_sock);
hotplug_sock = -1;
return -1;
}
return hotplug_sock;
}
int ButtonInputParse( ButtonInputEvent *Button, char *msg)
{
// When a button is pressed or released, we will get the following data:
// string:
// pressed@HOME=/PATH=/sbin:/bin:/usr/sbin:/usr/binSUBSYSTEM=buttonACTION=pressed\
// BUTTON=BTN_7SEEN=1280SEQNUM=658
// Hex:
// 70 72 65 73 73 65 64 40 00 48 4f 4d 45 3d 2f 00 50 41 54 48 3d 2f 73 62 69 6e 3a\
// 2f 62 69 6e 3a 2f 75 73 72 2f 73 62 69 6e 3a 2f 75 73 72 2f 62 69 6e 00 53 55 42\
// 53 59 53 54 45 4d 3d 62 75 74 74 6f 6e 00 41 43 54 49 4f 4e 3d 70 72 65 73 73 65\
// 64 00 42 55 54 54 4f 4e 3d 42 54 4e 5f 37 00 53 45 45 4e 3d 31 32 38 30 00 53 45\
// 51 4e 55 4d 3d 36 35 38 00
// From the message, we will get the button and the action
while(*msg) {
if(!strncmp(msg, "ACTION=", 7)) {
msg += 7;
Button->action = msg;
} else if (!strncmp(msg, "BUTTON=", 7)) {
msg += 7;
Button->button = msg;
return SUCCESS;
}
// advance to after the next \0
while(*msg++);
}
return ERR_FATAL;
}
// *******************************************************************
int GetButtonAction(uint32_t interval)
{
// TODO: add the code to return different command according to
// the interval
return BUTTON_NULL;
}
int ButtonActionParse( ButtonInputEvent *button)
{
if (!strncmp(button->button, BUTTON_CONFIG, BUTTON_CONFIG_SIZE)){
if (!strncmp(button->action, "pressed", 7)) {
type->pressedTime = GetCurrentSysTimeMillisecond();
}
if (!strncmp(button->action, "released", 8)) {
uint32_t time;
time = GetCurrentSysTimeMillisecond();
time = time - type->pressedTime;
type->type = GetButtonAction(time);
return type->type != BUTTON_NULL? SUCCESS: ERR_FATAL;
}
}
return ERR_FATAL;
}
int ButtonInput(uint8_t *inputType)
{
#define NETLINK_BUF_SIZE ((uint32_t)512)
char buf[ NETLINK_BUF_SIZE];
char *msg = buf;
int netlinkSock;
int result;
netlinkSock = ButtonFd;
result = read(netlinkSock, buf, NETLINK_BUF_SIZE - 1);
result = result < NETLINK_BUF_SIZE - 1? result: NETLINK_BUF_SIZE - 1;
buf[result] = '\0';
buf[result + 1] = '\0';
if (0 < result) {
// Now we just handle a button
// TODO: if two or more buttons are pressed,
// we should use other way to handle Buttons input.
ButtonInputEvent button;
result = ButtonInputParse(&button, buf);
if (result == SUCCESS) {
result = ButtonActionParse(&button);
}
*inputType = type->type;
}
return result;
}
// *******************************************************************
int ButtonInputInit(void)
{
type = &buttonType;
ButtonFd = InitNetlinkSock();
return ButtonFd;
}
3、使用/etc/hotplug.d/button/buttons
如何使用Hotplug方式,响应按键。
关于Hotplug的介绍以及一些使用方法。