本次所涉及到的檔案:
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 = ,
},
#endif
#ifndef RK3000_SDK
/*** {
.desc = "menu",
.code = EV_MENU,
.adc_value = ,
.gpio = INVALID_GPIO,
.active_low = PRESS_LEV_LOW,
},
{
.desc = "home",
.code = KEY_HOME,
.adc_value = ,
.gpio = INVALID_GPIO,
.active_low = PRESS_LEV_LOW,
},*/
{
.desc = "esc",
.code = KEY_HOME,///KEY_BACK,
.adc_value = ,///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 = ,
.gpio = INVALID_GPIO,
.active_low = PRESS_LEV_LOW,
},
{
.desc = "home",
.code = KEY_HOME,
.adc_value = ,
.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();
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] = ;
dev->rep[REP_PERIOD] = ;
}/* 自動處理重複按鍵定義 */
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) - );
/* 将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 ;
}
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