本次所涉及到的文件:
include/linux/input.h
drivers/input/input.c
arch/arm/mach-rk30/board-rk30-sdk.c
drivers/input/keyboard/rk29_keys.c
Boot Log:
[ 1.853285] input: rk29-keypad as /devices/platform/rk29-keypad/input/input0
match name → “rk29-keypad”
1、相关配置:
Device Drivers --->
Input device support --->
[*] Keyboards --->
<*> rk29 keyboard
按键驱动对应的源码位置为: drivers/input/keyboard/rk29_keys.c
按键相关的参数从board文件中传递给驱动程序:
2、相关按键属性定义:
arch/arm/mach-rk30/board-rk30-sdk.c
static struct rk29_keys_button key_button[] = {
/***{
.desc = "vol-",
.code = KEY_VOLUMEDOWN,
.gpio = RK30_PIN4_PC5,
.active_low = PRESS_LEV_LOW,
},
{
.desc = "play",
.code = KEY_POWER,
.gpio = RK30_PIN6_PA2,
.active_low = PRESS_LEV_LOW,
//.code_long_press = EV_ENCALL,
.wakeup = 1,
},
{
.desc = "vol+",
.code = KEY_VOLUMEUP,
.adc_value = 1,
.gpio = INVALID_GPIO,
.active_low = PRESS_LEV_LOW,
},*/
#if defined(CONFIG_PROJECT_D200)
{
.desc = "play",
.code = KEY_POWER,
.gpio = RK30_PIN6_PA0,///RK30_PIN2_PA1,///
.active_low = PRESS_LEV_LOW,
//.code_long_press = EV_ENCALL,
.wakeup = 1,
},
#endif
#ifndef RK3000_SDK
/*** {
.desc = "menu",
.code = EV_MENU,
.adc_value = 135,
.gpio = INVALID_GPIO,
.active_low = PRESS_LEV_LOW,
},
{
.desc = "home",
.code = KEY_HOME,
.adc_value = 550,
.gpio = INVALID_GPIO,
.active_low = PRESS_LEV_LOW,
},*/
{
.desc = "esc",
.code = KEY_HOME,///KEY_BACK,
.adc_value = 630,///334,
.gpio = RK30_PIN2_PC7,///INVALID_GPIO,
.active_low = PRESS_LEV_LOW,
},
/*** {
.desc = "camera",
.code = KEY_CAMERA,
.adc_value = 743,
.gpio = INVALID_GPIO,
.active_low = PRESS_LEV_LOW,
},*/
#else
/*** {
.desc = "menu",
.code = EV_MENU,
.adc_value = 155,
.gpio = INVALID_GPIO,
.active_low = PRESS_LEV_LOW,
},
{
.desc = "home",
.code = KEY_HOME,
.adc_value = 630,
.gpio = INVALID_GPIO,
.active_low = PRESS_LEV_LOW,
},*/
{
.desc = "home",
.code = KEY_BACK,
.adc_value = 386,
.gpio = RK30_PIN2_PC7,///INVALID_GPIO,
.active_low = PRESS_LEV_LOW,
},
/*** {
.desc = "camera",
.code = KEY_CAMERA,
.adc_value = 827,
.gpio = INVALID_GPIO,
.active_low = PRESS_LEV_LOW,
},*/
#endif
};
3、相关按键操作:
drivers/input/keyboard/rk29_keys.c
input = input_allocate_device();
分配input_dev结构体,并调用input_register_device(input)对其进行注册,
3.1、input_allocate_device( ):
struct input_dev *input_allocate_device(void)
{
struct input_dev *dev;
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
if (dev) {
dev->dev.type = &input_dev_type; /* 初始化设备结构类型 */
dev->dev.class = &input_class; /* 初始化为输入设备类 */
device_initialize(&dev->dev); /* 初始化device结构体 */
mutex_init(&dev->mutex); /* 初始化互斥锁 */
spin_lock_init(&dev->event_lock); /* 初始化事件自旋锁 */
INIT_LIST_HEAD(&dev->h_list); /* 初始化链表 */
INIT_LIST_HEAD(&dev->node);
__module_get(THIS_MODULE); /* 模块引用 */
}
return dev;
}
注:input_dev类型的指针,该结构体属于输入设备结构体,包含输入设备的一些信息,如设备支持的按键码、设备名称、设备支持的事件等。
关于input_dev结构体更详尽的解释参见:http://bbs.21ic.com/icview-309385-1-1.html
3.2、注册函数input_register_device( )
int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0);
struct input_handler *handler;
const char *path;
int error;
/* Every input device generates EV_SYN/SYN_REPORT events. */
__set_bit(EV_SYN, dev->evbit);
/*
#define EV_SYN 0x00 /* 设备支持所有的事件 */
#define EV_KEY 0x01 /* 键盘或者按键,表示一个键码 */
#define EV_REL 0x02 /* 鼠标设备,相对坐标事件 */
#define EV_ABS 0x03 /* 手写板或摇杆设备,绝对坐标事件 */
#define EV_MSC 0x04 /* 其它类型 */
#define EV_SW 0x05 /* 两态开关时间 */
#define EV_LED 0x11 /* LED灯设备 */
#define EV_SND 0x12 /* 蜂鸣器,输入声音 */
#define EV_REP 0x14 /* 重复按键事件 */
#define EV_FF 0x15 /* 受力事件 */
#define EV_PWR 0x16 /* 电源管理事件 */
#define EV_FF_STATUS 0x17 /* 受力状态事件 */
#define EV_MAX 0x1f /* 事件类型最大个数和提供位掩码支持 */
#define EV_CNT (EV_MAX+1)
详细输入子系统的事件编码信息参见http://blog.csdn.net/droidphone/article/details/8432055
*/
/* KEY_RESERVED is not supposed to be transmitted to userspace. */
__clear_bit(KEY_RESERVED, dev->keybit);
/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
input_cleanse_bitmasks(dev);
if (!dev->hint_events_per_packet)
dev->hint_events_per_packet =
input_estimate_events_per_packet(dev);
/* 初始化timer定时器,为处理重复击键而定义 */
init_timer(&dev->timer);
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
dev->rep[REP_DELAY] = 250;
dev->rep[REP_PERIOD] = 33;
}/* 自动处理重复按键定义 */
if (!dev->getkeycode)
dev->getkeycode = input_default_getkeycode;
/* 检查是否定义,如未定义则使用默认值 */
if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;
dev_set_name(&dev->dev, "input%ld",
(unsigned long) atomic_inc_return(&input_no) - 1);
/* 将input_dev包含的device注册到设备模型中 */
error = device_add(&dev->dev);
if (error)
return error;
/* 打印设备路径,输出调试信息 */
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
pr_info("%s as %s\n",
dev->name ? dev->name : "Unspecified device",
path ? path : "N/A");
kfree(path);
error = mutex_lock_interruptible(&input_mutex);
if (error) {
device_del(&dev->dev);
return error;
}
/* 将input_dev加入到input_dev_list链表中 */
list_add_tail(&dev->node, &input_dev_list);
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
return 0;
}
3.3、input_attach_handler( )
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id; /* 输入设备指针 */
int error;
id = input_match_device(handler, dev);
if (!id)
return -ENODEV;
error = handler->connect(handler, dev, id); /* 连接设备和处理函数 */
if (error && error != -ENODEV)
pr_err("failed to attach handler %s to device %s, error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
return error;
}
3.4、input_match_device( )
static const struct input_device_id *input_match_device(struct input_handler *handler,
struct input_dev *dev)
{
const struct input_device_id *id;
int i;
for (id = handler->id_table; id->flags || id->driver_info; id++) {
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
if (id->bustype != dev->id.bustype)
continue;
/* 匹配设备厂商的信息 */
if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
if (id->vendor != dev->id.vendor)
continue;
/* 匹配设备号的信息 */
if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
if (id->product != dev->id.product)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
if (id->version != dev->id.version)
continue;
/* 使用MATCH_BIT匹配项 */
MATCH_BIT(evbit, EV_MAX);
MATCH_BIT(keybit, KEY_MAX);
MATCH_BIT(relbit, REL_MAX);
MATCH_BIT(absbit, ABS_MAX);
MATCH_BIT(mscbit, MSC_MAX);
MATCH_BIT(ledbit, LED_MAX);
MATCH_BIT(sndbit, SND_MAX);
MATCH_BIT(ffbit, FF_MAX);
MATCH_BIT(swbit, SW_MAX);
if (!handler->match || handler->match(handler, dev))
return id;
}
return NULL;
}
注:注册input_dev的过程就是为input_device设置默认值,并将其挂到input_dev_list。与挂载在input_handler_list中的handler相匹配。如匹配成功,则调用handler的connect函数。
关于此输入子系统部分,发现网上有更为详尽的解释和说明,故贴出地址以备参考:
http://blog.csdn.net/tianxiawuzhei/article/details/7607068
http://blog.csdn.net/weiqing1981127/article/details/8138389