Linux的input子系统是用于处理输入设备,常见的输入设备有键盘,鼠标,触摸屏,手柄等。input子系统有3大框架,包括输入设备驱动层、核心层、事件层,3大框架之间的关系入下图所示。本章先来讲一下输入设备驱动层。
input子系统的输入设备驱动层需要驱动开发人编写,驱动开发人员只需调用input核心层提供的函数就可以完成驱动的注册和事件的上报。
- input设备结构体
struct input_dev {
const char *name; // 设备名
const char *phys;
const char *uniq;
struct input_id id;
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; // 输入事件
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; // 此设备具有哪些按键
unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; // 此设备具有相对坐标
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; // 此设备具有绝对坐标
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; // 此设备支持各种事件位图
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; // 此设备支持led位图
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; // 此设备支持声音位图
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; // 此设备支持力反馈位图
unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; // 此设备支持显示开关位图
...........................
unsigned int num_vals;
unsigned int max_vals;
struct input_value *vals;
bool devres_managed;
};
在input_device结构体,需要关注以下几个成员变量
name: 设备名
evbit : 输入事件
keybit:按键键值(键盘,普通按键)
relbit:相对坐标(鼠标设备)
absbit:绝对坐标(触摸屏设备)
mscbit:杂项位图(不常用)
ledbit:led位图(不常用)
sndbit:声音位图(不常用)
ffbit:力反馈位图(不常用)
swbit:开关位图(不常用)
input子系统需要驱动开发人员注册输入设备的输入事件类型和输入键值。
- 输入事件
内核的input子系统为驱动开发人员定义了一系列的输入事件,所谓的输入事件就是你的设备是输入哪一种输入类型
/*
* Event types
*/
#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)
内核提供上述类型的输入事件,常用的有EV_SYN、EV_KEY、EV_REL、EV_ABS。内核提供了__set_bit函数来设置输入事件。
- 输入键值
输入键值是向内核注册设备上报的键值信息,不同的输入事件有不同的输入键值
/*
* Absolute axes
*/
#define ABS_X 0x00
#define ABS_Y 0x01
#define ABS_Z 0x02
#define ABS_RX 0x03
#define ABS_RY 0x04
#define ABS_RZ 0x05
#define ABS_THROTTLE 0x06
#define ABS_RUDDER 0x07
#define ABS_WHEEL 0x08
#define ABS_GAS 0x09
#define ABS_BRAKE 0x0a
#define ABS_HAT0X 0x10
#define ABS_HAT0Y 0x11
#define ABS_HAT1X 0x12
#define ABS_HAT1Y 0x13
#define ABS_HAT2X 0x14
#define ABS_HAT2Y 0x15
#define ABS_HAT3X 0x16
#define ABS_HAT3Y 0x17
#define ABS_PRESSURE 0x18
#define ABS_DISTANCE 0x19
#define ABS_TILT_X 0x1a
#define ABS_TILT_Y 0x1b
#define ABS_TOOL_WIDTH 0x1c
#define ABS_VOLUME 0x20
#define ABS_MISC 0x28
#define ABS_MT_SLOT 0x2f /* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
#define ABS_MT_POSITION_X 0x35 /* Center X touch position */
#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */
#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */
#define ABS_MT_TOOL_X 0x3c /* Center X tool position */
#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */
#define ABS_MAX 0x3f
#define ABS_CNT (ABS_MAX+1)
绝对位置类型的输入键值信息
/*
* Relative axes
*/
#define REL_X 0x00
#define REL_Y 0x01
#define REL_Z 0x02
#define REL_RX 0x03
#define REL_RY 0x04
#define REL_RZ 0x05
#define REL_HWHEEL 0x06
#define REL_DIAL 0x07
#define REL_WHEEL 0x08
#define REL_MISC 0x09
#define REL_MAX 0x0f
#define REL_CNT (REL_MAX+1)
相对位置事件键值信息
/*
* Keys and buttons
*
* Most of the keys/buttons are modeled after USB HUT 1.12
* (see http://www.usb.org/developers/hidpage).
* Abbreviations in the comments:
* AC - Application Control
* AL - Application Launch Button
* SC - System Control
*/
#define KEY_RESERVED 0
#define KEY_ESC 1
#define KEY_1 2
#define KEY_2 3
#define KEY_3 4
#define KEY_4 5
#define KEY_5 6
#define KEY_6 7
#define KEY_7 8
#define KEY_8 9
#define KEY_9 10
#define KEY_0 11
#define KEY_MINUS 12
#define KEY_EQUAL 13
#define KEY_BACKSPACE 14
#define KEY_TAB 15
#define KEY_Q 16
#define KEY_W 17
#define KEY_E 18
#define KEY_R 19
#define KEY_T 20
#define KEY_Y 21
#define KEY_U 22
#define KEY_I 23
#define KEY_O 24
#define KEY_P 25
#define KEY_LEFTBRACE 26
#define KEY_RIGHTBRACE 27
#define KEY_ENTER 28
#define KEY_LEFTCTRL 29
#define KEY_A 30
#define KEY_S 31
#define KEY_D 32
#define KEY_F 33
#define KEY_G 34
#define KEY_H 35
#define KEY_J 36
#define KEY_K 37
#define KEY_L 38
#define KEY_SEMICOLON 39
#define KEY_APOSTROPHE 40
#define KEY_GRAVE 41
#define KEY_LEFTSHIFT 42
#define KEY_BACKSLASH 43
#define KEY_Z 44
#define KEY_X 45
#define KEY_C 46
#define KEY_V 47
#define KEY_B 48
#define KEY_N 49
#define KEY_M 50
#define KEY_COMMA 51
#define KEY_DOT 52
#define KEY_SLASH 53
#define KEY_RIGHTSHIFT 54
#define KEY_KPASTERISK 55
#define KEY_LEFTALT 56
#define KEY_SPACE 57
#define KEY_CAPSLOCK 58
#define KEY_F1 59
#define KEY_F2 60
#define KEY_F3 61
#define KEY_F4 62
#define KEY_F5 63
#define KEY_F6 64
#define KEY_F7 65
#define KEY_F8 66
#define KEY_F9 67
#define KEY_F10 68
#define KEY_NUMLOCK 69
#define KEY_SCROLLLOCK 70
#define KEY_KP7 71
#define KEY_KP8 72
#define KEY_KP9 73
#define KEY_KPMINUS 74
#define KEY_KP4 75
#define KEY_KP5 76
#define KEY_KP6 77
#define KEY_KPPLUS 78
#define KEY_KP1 79
#define KEY_KP2 80
#define KEY_KP3 81
#define KEY_KP0 82
#define KEY_KPDOT 83
#define KEY_ZENKAKUHANKAKU 85
#define KEY_102ND 86
#define KEY_F11 87
#define KEY_F12 88
#define KEY_RO 89
#define KEY_KATAKANA 90
#define KEY_HIRAGANA 91
#define KEY_HENKAN 92
#define KEY_KATAKANAHIRAGANA 93
#define KEY_MUHENKAN 94
#define KEY_KPJPCOMMA 95
#define KEY_KPENTER 96
#define KEY_RIGHTCTRL 97
#define KEY_KPSLASH 98
#define KEY_SYSRQ 99
#define KEY_RIGHTALT 100
#define KEY_LINEFEED 101
#define KEY_HOME 102
#define KEY_UP 103
#define KEY_PAGEUP 104
#define KEY_LEFT 105
#define KEY_RIGHT 106
#define KEY_END 107
#define KEY_DOWN 108
#define KEY_PAGEDOWN 109
#define KEY_INSERT 110
#define KEY_DELETE 111
#define KEY_MACRO 112
#define KEY_MUTE 113
#define KEY_VOLUMEDOWN 114
#define KEY_VOLUMEUP 115
#define KEY_POWER 116 /* SC System Power Down */
#define KEY_KPEQUAL 117
#define KEY_KPPLUSMINUS 118
#define KEY_PAUSE 119
#define KEY_SCALE 120 /* AL Compiz Scale (Expose) */
#define KEY_KPCOMMA 121
#define KEY_HANGEUL 122
#define KEY_HANGUEL KEY_HANGEUL
#define KEY_HANJA 123
#define KEY_YEN 124
#define KEY_LEFTMETA 125
#define KEY_RIGHTMETA 126
#define KEY_COMPOSE 127
#define KEY_STOP 128 /* AC Stop */
#define KEY_AGAIN 129
#define KEY_PROPS 130 /* AC Properties */
#define KEY_UNDO 131 /* AC Undo */
#define KEY_FRONT 132
#define KEY_COPY 133 /* AC Copy */
#define KEY_OPEN 134 /* AC Open */
#define KEY_PASTE 135 /* AC Paste */
#define KEY_FIND 136 /* AC Search */
#define KEY_CUT 137 /* AC Cut */
#define KEY_HELP 138 /* AL Integrated Help Center */
#define KEY_MENU 139 /* Menu (show menu) */
#define KEY_CALC 140 /* AL Calculator */
#define KEY_SETUP 141
#define KEY_SLEEP 142 /* SC System Sleep */
#define KEY_WAKEUP 143 /* System Wake Up */
#define KEY_FILE 144 /* AL Local Machine Browser */
#define KEY_SENDFILE 145
#define KEY_DELETEFILE 146
#define KEY_XFER 147
#define KEY_PROG1 148
#define KEY_PROG2 149
#define KEY_WWW 150 /* AL Internet Browser */
#define KEY_MSDOS 151
#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */
#define KEY_SCREENLOCK KEY_COFFEE
#define KEY_ROTATE_DISPLAY 153 /* Display orientation for e.g. tablets */
#define KEY_DIRECTION KEY_ROTATE_DISPLAY
#define KEY_CYCLEWINDOWS 154
#define KEY_MAIL 155
#define KEY_BOOKMARKS 156 /* AC Bookmarks */
#define KEY_COMPUTER 157
#define KEY_BACK 158 /* AC Back */
#define KEY_FORWARD 159 /* AC Forward */
#define KEY_CLOSECD 160
#define KEY_EJECTCD 161
#define KEY_EJECTCLOSECD 162
#define KEY_NEXTSONG 163
#define KEY_PLAYPAUSE 164
#define KEY_PREVIOUSSONG 165
#define KEY_STOPCD 166
#define KEY_RECORD 167
#define KEY_REWIND 168
#define KEY_PHONE 169 /* Media Select Telephone */
#define KEY_ISO 170
#define KEY_CONFIG 171 /* AL Consumer Control Configuration */
#define KEY_HOMEPAGE 172 /* AC Home */
#define KEY_REFRESH 173 /* AC Refresh */
#define KEY_EXIT 174 /* AC Exit */
#define KEY_MOVE 175
#define KEY_EDIT 176
#define KEY_SCROLLUP 177
#define KEY_SCROLLDOWN 178
#define KEY_KPLEFTPAREN 179
#define KEY_KPRIGHTPAREN 180
#define KEY_NEW 181 /* AC New */
#define KEY_REDO 182 /* AC Redo/Repeat */
#define KEY_F13 183
#define KEY_F14 184
#define KEY_F15 185
#define KEY_F16 186
#define KEY_F17 187
#define KEY_F18 188
#define KEY_F19 189
#define KEY_F20 190
#define KEY_F21 191
#define KEY_F22 192
#define KEY_F23 193
#define KEY_F24 194
#define KEY_PLAYCD 200
#define KEY_PAUSECD 201
#define KEY_PROG3 202
#define KEY_PROG4 203
#define KEY_DASHBOARD 204 /* AL Dashboard */
#define KEY_SUSPEND 205
#define KEY_CLOSE 206 /* AC Close */
#define KEY_PLAY 207
#define KEY_FASTFORWARD 208
#define KEY_BASSBOOST 209
#define KEY_PRINT 210 /* AC Print */
#define KEY_HP 211
#define KEY_CAMERA 212
#define KEY_SOUND 213
#define KEY_QUESTION 214
#define KEY_EMAIL 215
#define KEY_CHAT 216
#define KEY_SEARCH 217
#define KEY_CONNECT 218
#define KEY_FINANCE 219 /* AL Checkbook/Finance */
#define KEY_SPORT 220
#define KEY_SHOP 221
#define KEY_ALTERASE 222
#define KEY_CANCEL 223 /* AC Cancel */
#define KEY_BRIGHTNESSDOWN 224
#define KEY_BRIGHTNESSUP 225
#define KEY_MEDIA 226
#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video
outputs (Monitor/LCD/TV-out/etc) */
#define KEY_KBDILLUMTOGGLE 228
#define KEY_KBDILLUMDOWN 229
#define KEY_KBDILLUMUP 230
#define KEY_SEND 231 /* AC Send */
#define KEY_REPLY 232 /* AC Reply */
#define KEY_FORWARDMAIL 233 /* AC Forward Msg */
#define KEY_SAVE 234 /* AC Save */
#define KEY_DOCUMENTS 235
#define KEY_BATTERY 236
#define KEY_BLUETOOTH 237
#define KEY_WLAN 238
#define KEY_UWB 239
#define KEY_UNKNOWN 240
#define KEY_VIDEO_NEXT 241 /* drive next video source */
#define KEY_VIDEO_PREV 242 /* drive previous video source */
#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */
#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual
brightness control is off,
rely on ambient */
#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO
#define KEY_DISPLAY_OFF 245 /* display device to off state */
#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */
#define KEY_WIMAX KEY_WWAN
#define KEY_RFKILL 247 /* Key that controls all radios */
#define KEY_MICMUTE 248 /* Mute / unmute the microphone */
按键事件键值信息
键值信息的注册也是用__set_bit函数处理。
- 输入设备事件上报函数
内核为驱动开发者提供了不同事件类型的上报函数,驱动开发者需要根据设备的类型进行选择
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_KEY, code, !!value);
}
static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_REL, code, value);
}
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_ABS, code, value);
}
static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_FF_STATUS, code, value);
}
static inline void input_report_switch(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_SW, code, !!value);
}
static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
}
static inline void input_mt_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_MT_REPORT, 0);
}
设备注册函数和注销函数
input_register_device 设备注册函数
input_unregister_device 设备注销函数
- input设备注册通用框架
通过上述的讲解我们就可以得到一个input设备驱动的通用注册流程
struct input_dev *inpdevdev; // 定义input结构体
void xxxx_handle()
{
input_report_key(inpdevdev,EV_KEY,KEY_0); // 上报键值
input_sync(inpdevdev); // 发送同步信息
}
// 设备注册函数
static int xxxxx_probe(struct platform_device *pdev)
{
inpdevdev = input_allocate_device(); // 为input结构体分配内存
inpdevdev->name = "xxxxxx"; // 设备名字
// 注册事件类型,根据设备的特性来进行注册,以按键为例
__set_bit(EV_KEY,inpdevdev->evbit); // 注册按键事件
__set_bit(KEY_0,inpdevdev->keybit); // 注册键值
// 上面两行设置事件和键值代码也可以用input_set_capability代替
//input_set_capability(inpdevdev,EV_KEY,KEY_0);
input_register_device(inpdevdev); // 注册input设备
return 0;
}
static int xxxx_remove(struct platform_device *pdev)
{
input_unregister_device(inpdevdev); // 注销input设备
return 0;
}
下面来看一下实际例子再加深印象,该例子是ab8500-ponkey.c
struct ab8500_ponkey {
struct input_dev *idev;
struct ab8500 *ab8500;
int irq_dbf;
int irq_dbr;
};
/* AB8500 gives us an interrupt when ONKEY is held */
static irqreturn_t ab8500_ponkey_handler(int irq, void *data)
{
struct ab8500_ponkey *ponkey = data;
if (irq == ponkey->irq_dbf)
input_report_key(ponkey->idev, KEY_POWER, true); // 上报键值
else if (irq == ponkey->irq_dbr)
input_report_key(ponkey->idev, KEY_POWER, false);// 上报键值
input_sync(ponkey->idev); // 发送同步信号
return IRQ_HANDLED;
}
static int ab8500_ponkey_probe(struct platform_device *pdev)
{
struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
struct ab8500_ponkey *ponkey;
struct input_dev *input;
int irq_dbf, irq_dbr;
int error;
irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF");
if (irq_dbf < 0) {
dev_err(&pdev->dev, "No IRQ for ONKEY_DBF, error=%d\n", irq_dbf);
return irq_dbf;
}
irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR");
if (irq_dbr < 0) {
dev_err(&pdev->dev, "No IRQ for ONKEY_DBR, error=%d\n", irq_dbr);
return irq_dbr;
}
ponkey = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_ponkey),
GFP_KERNEL);
if (!ponkey)
return -ENOMEM;
input = devm_input_allocate_device(&pdev->dev); // 给input结构体分配内存
if (!input) // 如果分配失败就返回错误码
return -ENOMEM;
ponkey->idev = input;
ponkey->ab8500 = ab8500;
ponkey->irq_dbf = irq_dbf;
ponkey->irq_dbr = irq_dbr;
input->name = "AB8500 POn(PowerOn) Key"; // input设备名字
input->dev.parent = &pdev->dev; // 父设备
input_set_capability(input, EV_KEY, KEY_POWER); // 设置事件类型为EV_KEY,键值为KEY_POWER
// 申请中断
error = devm_request_any_context_irq(&pdev->dev, ponkey->irq_dbf,
ab8500_ponkey_handler, 0,
"ab8500-ponkey-dbf", ponkey);
if (error < 0) {
dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n",
ponkey->irq_dbf, error);
return error;
}
error = devm_request_any_context_irq(&pdev->dev, ponkey->irq_dbr,
ab8500_ponkey_handler, 0,
"ab8500-ponkey-dbr", ponkey);
if (error < 0) {
dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n",
ponkey->irq_dbr, error);
return error;
}
error = input_register_device(ponkey->idev); // 注册input设备
if (error) {
dev_err(ab8500->dev, "Can't register input device: %d\n", error);
return error;
}
platform_set_drvdata(pdev, ponkey);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id ab8500_ponkey_match[] = {
{ .compatible = "stericsson,ab8500-ponkey", },
{}
};
#endif
static struct platform_driver ab8500_ponkey_driver = {
.driver = {
.name = "ab8500-poweron-key",
.of_match_table = of_match_ptr(ab8500_ponkey_match),
},
.probe = ab8500_ponkey_probe,
};
module_platform_driver(ab8500_ponkey_driver);