#ifndef _INPUT_H
#define _INPUT_H
/*
* Copyright (c) 1999-2002 Vojtech Pavlik
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#ifdef __KERNEL__
#include
#include
#else
#include
#include
#include
#include
#endif
/*
* The event structure itself
*/
struct input_event { /* 输入事件 */
struct timeval time; /* 事件发生的时间*/
__u16 type; /* 事件的类型(按键类事件、位移类事件等等) */
__u16 code; /* 事件的值 */
__s32 value; /*1表示事件发生,0表示事件未发生 */
};
/*
* Protocol version.
*/
#define EV_VERSION 0x010000 /* 协议的版本 */
/*
* IOCTLs (0x00 - 0x7f)
*/
struct input_id { /* 输入设备的ID */
__u16 bustype; /* 总线类型 */
__u16 vendor; /* 制造商ID*/
__u16 product; /* 产品ID*/
__u16 version; /* 产品版本 号*/
};
struct input_absinfo { /* 设备的绝对事件类信息 */
__s32 value; /* 值 */
__s32 minimum; /* 最大值 */
__s32 maximum; /* 最小值 */
__s32 fuzz;
__s32 flat;
};
/* 构造的ioctl函数的命令 */
#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ /* 获取驱动的版本信息 */
#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ /* 获取设备的ID */
#define EVIOCGREP _IOR('E', 0x03, int[2]) /* get repeat settings */ /* 获取重复类事件的设置 */
#define EVIOCSREP _IOW('E', 0x03, int[2]) /* set repeat settings */ /* 设置重复类事件 */
#define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */ /* 获取键值 */
#define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */ /* 设置键值 */
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ /* 获取设备的名字 */
#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ /*获取设备的物理地址分布 */
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */ /* 获取唯一的标志 */
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */ /* 获取全局的按键状态 */
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */ /* 获取所有的LED */
#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */ /* 获取声音设备的状态 */
#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */ /* 获取开关设备的状态 */
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */ /* 获取事件位 */
#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */ /* 获取绝对位置的值或范围 */
#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */ /* 设置绝对位置的值或范围 */
#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */
#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
/*
* 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) /* 事件计数 */
/*
* Synchronization events.
*/
/* 同步类事件 */
#define SYN_REPORT 0 /* 同步上报 ,表示以上事件是一组事件*/
#define SYN_CONFIG 1 /* 同步配置 */
#define SYN_MT_REPORT 2 /* 该标志用于多点触摸屏驱动上报事件,上报一个触摸点数据后上报一个SYN_MT_REPOR
表示第一个触摸点的数据上报完毕,依次类推直到所有触摸点的数据发送完毕最后
上报一个SYN_REPORT来表示一组事件结束*/
/*
* 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_DIRECTION 153
#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_ZERO 244 /* brightness off, use ambient */
#define KEY_DISPLAY_OFF 245 /* display device to off state */
#define KEY_WIMAX 246
/* Range 248 - 255 is reserved for special needs of AT keyboard driver */
#define BTN_MISC 0x100
#define BTN_0 0x100
#define BTN_1 0x101
#define BTN_2 0x102
#define BTN_3 0x103
#define BTN_4 0x104
#define BTN_5 0x105
#define BTN_6 0x106
#define BTN_7 0x107
#define BTN_8 0x108
#define BTN_9 0x109
#define BTN_MOUSE 0x110 /* 鼠标类事件 */
#define BTN_LEFT 0x110 /* 左键 */
#define BTN_RIGHT 0x111 /* 右键 */
#define BTN_MIDDLE 0x112 /* 中键 */
#define BTN_SIDE 0x113
#define BTN_EXTRA 0x114
#define BTN_FORWARD 0x115
#define BTN_BACK 0x116
#define BTN_TASK 0x117
#define BTN_JOYSTICK 0x120
#define BTN_TRIGGER 0x120
#define BTN_THUMB 0x121
#define BTN_THUMB2 0x122
#define BTN_TOP 0x123
#define BTN_TOP2 0x124
#define BTN_PINKIE 0x125
#define BTN_BASE 0x126
#define BTN_BASE2 0x127
#define BTN_BASE3 0x128
#define BTN_BASE4 0x129
#define BTN_BASE5 0x12a
#define BTN_BASE6 0x12b
#define BTN_DEAD 0x12f
#define BTN_GAMEPAD 0x130
#define BTN_A 0x130
#define BTN_B 0x131
#define BTN_C 0x132
#define BTN_X 0x133
#define BTN_Y 0x134
#define BTN_Z 0x135
#define BTN_TL 0x136
#define BTN_TR 0x137
#define BTN_TL2 0x138
#define BTN_TR2 0x139
#define BTN_SELECT 0x13a
#define BTN_START 0x13b
#define BTN_MODE 0x13c
#define BTN_THUMBL 0x13d
#define BTN_THUMBR 0x13e
#define BTN_DIGI 0x140
#define BTN_TOOL_PEN 0x140
#define BTN_TOOL_RUBBER 0x141
#define BTN_TOOL_BRUSH 0x142
#define BTN_TOOL_PENCIL 0x143
#define BTN_TOOL_AIRBRUSH 0x144
#define BTN_TOOL_FINGER 0x145
#define BTN_TOOL_MOUSE 0x146
#define BTN_TOOL_LENS 0x147
#define BTN_TOUCH 0x14a /* 能产生触摸类事件 */
#define BTN_STYLUS 0x14b
#define BTN_STYLUS2 0x14c
#define BTN_TOOL_DOUBLETAP 0x14d
#define BTN_TOOL_TRIPLETAP 0x14e
#define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */
#define BTN_WHEEL 0x150
#define BTN_GEAR_DOWN 0x150
#define BTN_GEAR_UP 0x151
#define KEY_OK 0x160
#define KEY_SELECT 0x161
#define KEY_GOTO 0x162
#define KEY_CLEAR 0x163
#define KEY_POWER2 0x164
#define KEY_OPTION 0x165
#define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */
#define KEY_TIME 0x167
#define KEY_VENDOR 0x168
#define KEY_ARCHIVE 0x169
#define KEY_PROGRAM 0x16a /* Media Select Program Guide */
#define KEY_CHANNEL 0x16b
#define KEY_FAVORITES 0x16c
#define KEY_EPG 0x16d
#define KEY_PVR 0x16e /* Media Select Home */
#define KEY_MHP 0x16f
#define KEY_LANGUAGE 0x170
#define KEY_TITLE 0x171
#define KEY_SUBTITLE 0x172
#define KEY_ANGLE 0x173
#define KEY_ZOOM 0x174
#define KEY_MODE 0x175
#define KEY_KEYBOARD 0x176
#define KEY_SCREEN 0x177
#define KEY_PC 0x178 /* Media Select Computer */
#define KEY_TV 0x179 /* Media Select TV */
#define KEY_TV2 0x17a /* Media Select Cable */
#define KEY_VCR 0x17b /* Media Select VCR */
#define KEY_VCR2 0x17c /* VCR Plus */
#define KEY_SAT 0x17d /* Media Select Satellite */
#define KEY_SAT2 0x17e
#define KEY_CD 0x17f /* Media Select CD */
#define KEY_TAPE 0x180 /* Media Select Tape */
#define KEY_RADIO 0x181
#define KEY_TUNER 0x182 /* Media Select Tuner */
#define KEY_PLAYER 0x183
#define KEY_TEXT 0x184
#define KEY_DVD 0x185 /* Media Select DVD */
#define KEY_AUX 0x186
#define KEY_MP3 0x187
#define KEY_AUDIO 0x188
#define KEY_VIDEO 0x189
#define KEY_DIRECTORY 0x18a
#define KEY_LIST 0x18b
#define KEY_MEMO 0x18c /* Media Select Messages */
#define KEY_CALENDAR 0x18d
#define KEY_RED 0x18e
#define KEY_GREEN 0x18f
#define KEY_YELLOW 0x190
#define KEY_BLUE 0x191
#define KEY_CHANNELUP 0x192 /* Channel Increment */
#define KEY_CHANNELDOWN 0x193 /* Channel Decrement */
#define KEY_FIRST 0x194
#define KEY_LAST 0x195 /* Recall Last */
#define KEY_AB 0x196
#define KEY_NEXT 0x197
#define KEY_RESTART 0x198
#define KEY_SLOW 0x199
#define KEY_SHUFFLE 0x19a
#define KEY_BREAK 0x19b
#define KEY_PREVIOUS 0x19c
#define KEY_DIGITS 0x19d
#define KEY_TEEN 0x19e
#define KEY_TWEN 0x19f
#define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */
#define KEY_GAMES 0x1a1 /* Media Select Games */
#define KEY_ZOOMIN 0x1a2 /* AC Zoom In */
#define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */
#define KEY_ZOOMRESET 0x1a4 /* AC Zoom */
#define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */
#define KEY_EDITOR 0x1a6 /* AL Text Editor */
#define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */
#define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */
#define KEY_PRESENTATION 0x1a9 /* AL Presentation App */
#define KEY_DATABASE 0x1aa /* AL Database App */
#define KEY_NEWS 0x1ab /* AL Newsreader */
#define KEY_VOICEMAIL 0x1ac /* AL Voicemail */
#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */
#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */
#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */
#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */
#define KEY_LOGOFF 0x1b1 /* AL Logoff */
#define KEY_DOLLAR 0x1b2
#define KEY_EURO 0x1b3
#define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */
#define KEY_FRAMEFORWARD 0x1b5
#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */
#define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */
#define KEY_DEL_EOL 0x1c0
#define KEY_DEL_EOS 0x1c1
#define KEY_INS_LINE 0x1c2
#define KEY_DEL_LINE 0x1c3
#define KEY_FN 0x1d0
#define KEY_FN_ESC 0x1d1
#define KEY_FN_F1 0x1d2
#define KEY_FN_F2 0x1d3
#define KEY_FN_F3 0x1d4
#define KEY_FN_F4 0x1d5
#define KEY_FN_F5 0x1d6
#define KEY_FN_F6 0x1d7
#define KEY_FN_F7 0x1d8
#define KEY_FN_F8 0x1d9
#define KEY_FN_F9 0x1da
#define KEY_FN_F10 0x1db
#define KEY_FN_F11 0x1dc
#define KEY_FN_F12 0x1dd
#define KEY_FN_1 0x1de
#define KEY_FN_2 0x1df
#define KEY_FN_D 0x1e0
#define KEY_FN_E 0x1e1
#define KEY_FN_F 0x1e2
#define KEY_FN_S 0x1e3
#define KEY_FN_B 0x1e4
#define KEY_BRL_DOT1 0x1f1
#define KEY_BRL_DOT2 0x1f2
#define KEY_BRL_DOT3 0x1f3
#define KEY_BRL_DOT4 0x1f4
#define KEY_BRL_DOT5 0x1f5
#define KEY_BRL_DOT6 0x1f6
#define KEY_BRL_DOT7 0x1f7
#define KEY_BRL_DOT8 0x1f8
#define KEY_BRL_DOT9 0x1f9
#define KEY_BRL_DOT10 0x1fa
#define KEY_NUMERIC_0 0x200 /* used by phones, remote controls, */
#define KEY_NUMERIC_1 0x201 /* and other keypads */
#define KEY_NUMERIC_2 0x202
#define KEY_NUMERIC_3 0x203
#define KEY_NUMERIC_4 0x204
#define KEY_NUMERIC_5 0x205
#define KEY_NUMERIC_6 0x206
#define KEY_NUMERIC_7 0x207
#define KEY_NUMERIC_8 0x208
#define KEY_NUMERIC_9 0x209
#define KEY_NUMERIC_STAR 0x20a
#define KEY_NUMERIC_POUND 0x20b
/* We avoid low common keys in module aliases so they don't get huge. */
#define KEY_MIN_INTERESTING KEY_MUTE
#define KEY_MAX 0x2ff /* 最大按键事件数量 */
#define KEY_CNT (KEY_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) /* 相对位移类事件计数 */
/*
* Absolute axes
*/
#define ABS_X 0x00 /* x方向的绝对位移事件 */
#define ABS_Y 0x01 /* y方向的绝对位移事件 */
#define ABS_Z 0x02 /* z方向的绝对位移事件 */
#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_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 ellipse position */
#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse 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_MAX 0x3f /* 最大绝对位移类事件数量 */
#define ABS_CNT (ABS_MAX+1) /* 绝对位移类事件计数 */
/*
* Switch events
*/
/* 开关事件 */
#define SW_LID 0x00 /* set = lid shut */
#define SW_TABLET_MODE 0x01 /* set = tablet mode */
#define SW_HEADPHONE_INSERT 0x02 /* set = inserted */
#define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any"
set = radio enabled */
#define SW_RADIO SW_RFKILL_ALL /* deprecated */
#define SW_MICROPHONE_INSERT 0x04 /* set = inserted */
#define SW_DOCK 0x05 /* set = plugged into dock */
#define SW_LINEOUT_INSERT 0x06 /* set = inserted */
#define SW_JACK_PHYSICAL_INSERT 0x07 /* set = mechanical switch set */
#define SW_VIDEOOUT_INSERT 0x08 /* set = inserted */
#define SW_MAX 0x0f /* 最大开关类事件数量 */
#define SW_CNT (SW_MAX+1) /* 开关类事件计数 */
/*
* Misc events
*/
/* 混杂事件 */
#define MSC_SERIAL 0x00
#define MSC_PULSELED 0x01
#define MSC_GESTURE 0x02
#define MSC_RAW 0x03
#define MSC_SCAN 0x04
#define MSC_MAX 0x07 /* 最大杂项类事件数量 */
#define MSC_CNT (MSC_MAX+1) /* 混杂类事件计数 */
/*
* LEDs
*/
/* LED事件 */
#define LED_NUML 0x00
#define LED_CAPSL 0x01
#define LED_SCROLLL 0x02
#define LED_COMPOSE 0x03
#define LED_KANA 0x04
#define LED_SLEEP 0x05
#define LED_SUSPEND 0x06
#define LED_MUTE 0x07
#define LED_MISC 0x08
#define LED_MAIL 0x09
#define LED_CHARGING 0x0a
#define LED_MAX 0x0f /* 最大LED类事件数量 */
#define LED_CNT (LED_MAX+1) /* LED类事件计数 */
/*
* Autorepeat values
*/
/* 自动重复值 */
#define REP_DELAY 0x00
#define REP_PERIOD 0x01
#define REP_MAX 0x01
/*
* Sounds
*/
/* 声音类事件 */
#define SND_CLICK 0x00
#define SND_BELL 0x01
#define SND_TONE 0x02
#define SND_MAX 0x07 /* 最大声音类事件数量 */
#define SND_CNT (SND_MAX+1) /* 声音类事件计数 */
/*
* IDs.
*/
#define ID_BUS 0
#define ID_VENDOR 1
#define ID_PRODUCT 2
#define ID_VERSION 3
#define BUS_PCI 0x01
#define BUS_ISAPNP 0x02
#define BUS_USB 0x03
#define BUS_HIL 0x04
#define BUS_BLUETOOTH 0x05
#define BUS_VIRTUAL 0x06
#define BUS_ISA 0x10
#define BUS_I8042 0x11
#define BUS_XTKBD 0x12
#define BUS_RS232 0x13
#define BUS_GAMEPORT 0x14
#define BUS_PARPORT 0x15
#define BUS_AMIGA 0x16
#define BUS_ADB 0x17
#define BUS_I2C 0x18
#define BUS_HOST 0x19
#define BUS_GSC 0x1A
#define BUS_ATARI 0x1B
/*
* MT_TOOL types
*/
#define MT_TOOL_FINGER 0
#define MT_TOOL_PEN 1
/*
* Values describing the status of a force-feedback effect
*/
#define FF_STATUS_STOPPED 0x00
#define FF_STATUS_PLAYING 0x01
#define FF_STATUS_MAX 0x01
/*
* Structures used in ioctls to upload effects to a device
* They are pieces of a bigger structure (called ff_effect)
*/
/*
* All duration values are expressed in ms. Values above 32767 ms (0x7fff)
* should not be used and have unspecified results.
*/
/**
* struct ff_replay - defines scheduling of the force-feedback effect
* @length: duration of the effect
* @delay: delay before effect should start playing
*/
struct ff_replay {
__u16 length;
__u16 delay;
};
/**
* struct ff_trigger - defines what triggers the force-feedback effect
* @button: number of the button triggering the effect
* @interval: controls how soon the effect can be re-triggered
*/
struct ff_trigger {
__u16 button;
__u16 interval;
};
/**
* struct ff_envelope - generic force-feedback effect envelope
* @attack_length: duration of the attack (ms)
* @attack_level: level at the beginning of the attack
* @fade_length: duration of fade (ms)
* @fade_level: level at the end of fade
*
* The @attack_level and @fade_level are absolute values; when applying
* envelope force-feedback core will convert to positive/negative
* value based on polarity of the default level of the effect.
* Valid range for the attack and fade levels is 0x0000 - 0x7fff
*/
struct ff_envelope {
__u16 attack_length;
__u16 attack_level;
__u16 fade_length;
__u16 fade_level;
};
/**
* struct ff_constant_effect - defines parameters of a constant force-feedback effect
* @level: strength of the effect; may be negative
* @envelope: envelope data
*/
struct ff_constant_effect {
__s16 level;
struct ff_envelope envelope;
};
/**
* struct ff_ramp_effect - defines parameters of a ramp force-feedback effect
* @start_level: beginning strength of the effect; may be negative
* @end_level: final strength of the effect; may be negative
* @envelope: envelope data
*/
struct ff_ramp_effect {
__s16 start_level;
__s16 end_level;
struct ff_envelope envelope;
};
/**
* struct ff_condition_effect - defines a spring or friction force-feedback effect
* @right_saturation: maximum level when joystick moved all way to the right
* @left_saturation: same for the left side
* @right_coeff: controls how fast the force grows when the joystick moves
* to the right
* @left_coeff: same for the left side
* @deadband: size of the dead zone, where no force is produced
* @center: position of the dead zone
*/
struct ff_condition_effect {
__u16 right_saturation;
__u16 left_saturation;
__s16 right_coeff;
__s16 left_coeff;
__u16 deadband;
__s16 center;
};
/**
* struct ff_periodic_effect - defines parameters of a periodic force-feedback effect
* @waveform: kind of the effect (wave)
* @period: period of the wave (ms)
* @magnitude: peak value
* @offset: mean value of the wave (roughly)
* @phase: 'horizontal' shift
* @envelope: envelope data
* @custom_len: number of samples (FF_CUSTOM only)
* @custom_data: buffer of samples (FF_CUSTOM only)
*
* Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP,
* FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined
* for the time being as no driver supports it yet.
*
* Note: the data pointed by custom_data is copied by the driver.
* You can therefore dispose of the memory after the upload/update.
*/
struct ff_periodic_effect {
__u16 waveform;
__u16 period;
__s16 magnitude;
__s16 offset;
__u16 phase;
struct ff_envelope envelope;
__u32 custom_len;
__s16 *custom_data;
};
/**
* struct ff_rumble_effect - defines parameters of a periodic force-feedback effect
* @strong_magnitude: magnitude of the heavy motor
* @weak_magnitude: magnitude of the light one
*
* Some rumble pads have two motors of different weight. Strong_magnitude
* represents the magnitude of the vibration generated by the heavy one.
*/
struct ff_rumble_effect {
__u16 strong_magnitude;
__u16 weak_magnitude;
};
/**
* struct ff_effect - defines force feedback effect
* @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING,
* FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM)
* @id: an unique id assigned to an effect
* @direction: direction of the effect
* @trigger: trigger conditions (struct ff_trigger)
* @replay: scheduling of the effect (struct ff_replay)
* @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect,
* ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further
* defining effect parameters
*
* This structure is sent through ioctl from the application to the driver.
* To create a new effect application should set its @id to -1; the kernel
* will return assigned @id which can later be used to update or delete
* this effect.
*
* Direction of the effect is encoded as follows:
* 0 deg -> 0x0000 (down)
* 90 deg -> 0x4000 (left)
* 180 deg -> 0x8000 (up)
* 270 deg -> 0xC000 (right)
*/
struct ff_effect {
__u16 type;
__s16 id;
__u16 direction;
struct ff_trigger trigger;
struct ff_replay replay;
union {
struct ff_constant_effect constant;
struct ff_ramp_effect ramp;
struct ff_periodic_effect periodic;
struct ff_condition_effect condition[2]; /* One for each axis */
struct ff_rumble_effect rumble;
} u;
};
/*
* Force feedback effect types
*/
#define FF_RUMBLE 0x50
#define FF_PERIODIC 0x51
#define FF_CONSTANT 0x52
#define FF_SPRING 0x53
#define FF_FRICTION 0x54
#define FF_DAMPER 0x55
#define FF_INERTIA 0x56
#define FF_RAMP 0x57
#define FF_EFFECT_MIN FF_RUMBLE
#define FF_EFFECT_MAX FF_RAMP
/*
* Force feedback periodic effect types
*/
#define FF_SQUARE 0x58
#define FF_TRIANGLE 0x59
#define FF_SINE 0x5a
#define FF_SAW_UP 0x5b
#define FF_SAW_DOWN 0x5c
#define FF_CUSTOM 0x5d
#define FF_WAVEFORM_MIN FF_SQUARE
#define FF_WAVEFORM_MAX FF_CUSTOM
/*
* Set ff device properties
*/
#define FF_GAIN 0x60
#define FF_AUTOCENTER 0x61
#define FF_MAX 0x7f /* 最大强制反馈类事件数量 */
#define FF_CNT (FF_MAX+1)
#ifdef __KERNEL__
/*
* In-kernel definitions.
*/
#include
#include
#include
#include
/**
* struct input_dev - represents an input device
* @name: name of the device
* @phys: physical path to the device in the system hierarchy
* @uniq: unique identification code for the device (if device has it)
* @id: id of the device (struct input_id)
* @evbit: bitmap of types of events supported by the device (EV_KEY,
* EV_REL, etc.)
* @keybit: bitmap of keys/buttons this device has
* @relbit: bitmap of relative axes for the device
* @absbit: bitmap of absolute axes for the device
* @mscbit: bitmap of miscellaneous events supported by the device
* @ledbit: bitmap of leds present on the device
* @sndbit: bitmap of sound effects supported by the device
* @ffbit: bitmap of force feedback effects supported by the device
* @swbit: bitmap of switches present on the device
* @keycodemax: size of keycode table
* @keycodesize: size of elements in keycode table
* @keycode: map of scancodes to keycodes for this device
* @setkeycode: optional method to alter current keymap, used to implement
* sparse keymaps. If not supplied default mechanism will be used
* @getkeycode: optional method to retrieve current keymap. If not supplied
* default mechanism will be used
* @ff: force feedback structure associated with the device if device
* supports force feedback effects
* @repeat_key: stores key code of the last key pressed; used to implement
* software autorepeat
* @timer: timer for software autorepeat
* @sync: set to 1 when there were no new events since last EV_SYNC
* @abs: current values for reports from absolute axes
* @rep: current values for autorepeat parameters (delay, rate)
* @key: reflects current state of device's keys/buttons
* @led: reflects current state of device's LEDs
* @snd: reflects current state of sound effects
* @sw: reflects current state of device's switches
* @absmax: maximum values for events coming from absolute axes
* @absmin: minimum values for events coming from absolute axes
* @absfuzz: describes noisiness for axes
* @absflat: size of the center flat position (used by joydev)
* @open: this method is called when the very first user calls
* input_open_device(). The driver must prepare the device
* to start generating events (start polling thread,
* request an IRQ, submit URB, etc.)
* @close: this method is called when the very last user calls
* input_close_device().
* @flush: purges the device. Most commonly used to get rid of force
* feedback effects loaded into the device when disconnecting
* from it
* @event: event handler for events sent _to_ the device, like EV_LED
* or EV_SND. The device is expected to carry out the requested
* action (turn on a LED, play sound, etc.) The call is protected
* by @event_lock and must not sleep
* @grab: input handle that currently has the device grabbed (via
* EVIOCGRAB ioctl). When a handle grabs a device it becomes sole
* recipient for all input events coming from the device
* @event_lock: this spinlock is is taken when input core receives
* and processes a new event for the device (in input_event()).
* Code that accesses and/or modifies parameters of a device
* (such as keymap or absmin, absmax, absfuzz, etc.) after device
* has been registered with input core must take this lock.
* @mutex: serializes calls to open(), close() and flush() methods
* @users: stores number of users (input handlers) that opened this
* device. It is used by input_open_device() and input_close_device()
* to make sure that dev->open() is only called when the first
* user opens device and dev->close() is called when the very
* last user closes the device
* @going_away: marks devices that are in a middle of unregistering and
* causes input_open_device*() fail with -ENODEV.
* @dev: driver model's view of this device
* @h_list: list of input handles associated with the device. When
* accessing the list dev->mutex must be held
* @node: used to place the device onto input_dev_list
*/
struct input_dev { /* 表示物理输入设备 */
const char *name; /* 设备名称 */
const char *phys;
const char *uniq;
struct input_id id; /* 设备ID */
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 keycodemax; /* 支持的按键值表的最大个数 */
unsigned int keycodesize; /* 每个键值的字节数 */
void *keycode; /*存储按键值的数组首地址 */
int (*setkeycode)(struct input_dev *dev, int scancode, int keycode); /*修改键值的函数,可选 */
int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode); /* 获取扫描码的键值,可选 */
struct ff_device *ff; /* 强制反馈设备 */
unsigned int repeat_key; /*最近一次按键值,用于连击 */
struct timer_list timer; /*自动连击计时器 */
int sync; /* 最后一次同步后没有新的事件则置1 */
int abs[ABS_MAX + 1]; /* 当前各个绝对坐标的值 */
int rep[REP_MAX + 1]; /* 自动连击的参数*/
unsigned long key[BITS_TO_LONGS(KEY_CNT)]; /* 反映当前设备按键状态的位图 */
unsigned long led[BITS_TO_LONGS(LED_CNT)]; /* 反映当前led设备状态的位图 */
unsigned long snd[BITS_TO_LONGS(SND_CNT)]; /* 反映当前声音效果状态的位图 */
unsigned long sw[BITS_TO_LONGS(SW_CNT)]; /* 反映当前设备开关状态的位图 */
/*驱动代码里一般使用input_set_abs_params函数设置
函数参数从右往左依次代表输入设备指针、坐标轴、最小值、最大值、分辨率、基准值。
最后两个参数也可以填为0,代表设备非常精确并且总能精确的回到中心位置。*/
int absmax[ABS_MAX + 1]; /* 记录各个绝对位移的最大值 */
int absmin[ABS_MAX + 1]; /* 记录各个绝对位移的最小值 */
int absfuzz[ABS_MAX + 1]; /* 记录各个坐标的分辨率 */
int absflat[ABS_MAX + 1]; /* 记录各个坐标的基准值(used by joydev)*/
int (*open)(struct input_dev *dev); /* 打开设备函数,用户会调用input_open_device()时会调用它 */
void (*close)(struct input_dev *dev); /* 关闭设备函数,用户会调用iinput_close_device() 时会调用它*/
int (*flush)(struct input_dev *dev, struct file *file); /* 断开连接时冲洗数据函数*/
/* 在input_handle_event函数里如果最后disposition=INPUT_PASS_TO_DEVICE 则表示将事件提交给 input_dev来处理(有些事件是发
送给设备的,而不是发送给handler处理的,例如led点灯事件、蜂鸣器鸣叫事件等),对于这类事件要调用
input_dev的event()函数来向输入子系统 报告一个将要发送给设备的事件,当报告给输入子系统后,就要求
设备处理这个事件**/
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
struct input_handle *grab; /* 指向 input_handle的指针,主要是用它提供的事件处理函数来处理设备上报的事件*/
spinlock_t event_lock; /* 处理事件的自旋锁 */
struct mutex mutex; /* 互斥体 */
unsigned int users; /* 记录用户打开设备的次数 */
int going_away; /* 标志设备未注册中,会引起调用 input_open_device*() 函数返回 -ENODEV*/
struct device dev; /* 内嵌的设备描述结构体 */
struct list_head h_list; /* handle链表 */
struct list_head node; /* input_dev链表 */
};
#define to_input_dev(d) container_of(d, struct input_dev, dev)
/*
* Verify that we are in sync with input_device_id mod_devicetable.h #defines
*/
#if EV_MAX != INPUT_DEVICE_ID_EV_MAX
#error "EV_MAX and INPUT_DEVICE_ID_EV_MAX do not match"
#endif
#if KEY_MIN_INTERESTING != INPUT_DEVICE_ID_KEY_MIN_INTERESTING
#error "KEY_MIN_INTERESTING and INPUT_DEVICE_ID_KEY_MIN_INTERESTING do not match"
#endif
#if KEY_MAX != INPUT_DEVICE_ID_KEY_MAX
#error "KEY_MAX and INPUT_DEVICE_ID_KEY_MAX do not match"
#endif
#if REL_MAX != INPUT_DEVICE_ID_REL_MAX
#error "REL_MAX and INPUT_DEVICE_ID_REL_MAX do not match"
#endif
#if ABS_MAX != INPUT_DEVICE_ID_ABS_MAX
#error "ABS_MAX and INPUT_DEVICE_ID_ABS_MAX do not match"
#endif
#if MSC_MAX != INPUT_DEVICE_ID_MSC_MAX
#error "MSC_MAX and INPUT_DEVICE_ID_MSC_MAX do not match"
#endif
#if LED_MAX != INPUT_DEVICE_ID_LED_MAX
#error "LED_MAX and INPUT_DEVICE_ID_LED_MAX do not match"
#endif
#if SND_MAX != INPUT_DEVICE_ID_SND_MAX
#error "SND_MAX and INPUT_DEVICE_ID_SND_MAX do not match"
#endif
#if FF_MAX != INPUT_DEVICE_ID_FF_MAX
#error "FF_MAX and INPUT_DEVICE_ID_FF_MAX do not match"
#endif
#if SW_MAX != INPUT_DEVICE_ID_SW_MAX
#error "SW_MAX and INPUT_DEVICE_ID_SW_MAX do not match"
#endif
#define INPUT_DEVICE_ID_MATCH_DEVICE \
(INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT)
#define INPUT_DEVICE_ID_MATCH_DEVICE_AND_VERSION \
(INPUT_DEVICE_ID_MATCH_DEVICE | INPUT_DEVICE_ID_MATCH_VERSION)
struct input_handle;
/**
* struct input_handler - implements one of interfaces for input devices
* @private: driver-specific data
* @event: event handler. This method is being called by input core with
* interrupts disabled and dev->event_lock spinlock held and so
* it may not sleep
* @connect: called when attaching a handler to an input device
* @disconnect: disconnects a handler from input device
* @start: starts handler for given handle. This function is called by
* input core right after connect() method and also when a process
* that "grabbed" a device releases it
* @fops: file operations this driver implements
* @minor: beginning of range of 32 minors for devices this driver
* can provide
* @name: name of the handler, to be shown in /proc/bus/input/handlers
* @id_table: pointer to a table of input_device_ids this driver can
* handle
* @blacklist: pointer to a table of input_device_ids this driver should
* ignore even if they match @id_table
* @h_list: list of input handles associated with the handler
* @node: for placing the driver onto input_handler_list
*
* Input handlers attach to input devices and create input handles. There
* are likely several handlers attached to any given input device at the
* same time. All of them will get their copy of input event generated by
* the device.
*
* Note that input core serializes calls to connect() and disconnect()
* methods.
*/
struct input_handler { /* 事件处理结构体,是输入设备的事件处理接口,为事件处理提供一个统一的函数模板*/
void *private; /* 驱动的私有数据 ,这里的驱动指的是handler处理器*/
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); /* 事件处理函数,会被input核心调用 来处理设备的事件*/
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); /* 该函数用来连接handler和input_dev,在input_attach_handler函数被调用*/
void (*disconnect)(struct input_handle *handle); /* 该函数用来断开handler和input_dev*/
void (*start)(struct input_handle *handle); /* 开始处理输入设备的数据事件,该函数会被input核心在调用 connect后调用*/
const struct file_operations *fops; /* 输入设备作为字符设备的操作函数 */
int minor; /* 次设备号基准值 */
const char *name; /* 名字,会表现在/proc/bus/input/handlers */
const struct input_device_id *id_table; /*表示该驱动所能处理的设备 ID 表指针,其能与input->id匹配则表示该handler能够支持该设备*/
const struct input_device_id *blacklist; /* 忽略的 ID 表指针,该表中存放了驱动程序应该忽略的设备,即使 id_table中找到支持的项,也应该忽略这种设备*/
struct list_head h_list; /* 用于形成struct input_handler链表*/
struct list_head node; /* 该链表用于将其连接到全局input_handler_list链表中,所有的 input_handler都连接在其上*/
};
/**
* struct input_handle - links input device with an input handler
* @private: handler-specific data
* @open: counter showing whether the handle is 'open', i.e. should deliver
* events from its device
* @name: name given to the handle by handler that created it
* @dev: input device the handle is attached to
* @handler: handler that works with the device through this handle
* @d_node: used to put the handle on device's list of attached handles
* @h_node: used to put the handle on handler's list of handles from which
* it gets events
*/
struct input_handle { /* 用来创建 input_dev 和 input_handler之间关系的结构体,事件通过input_handle从input_dev发送到input_handler,
或者从input_handler发送到input_dev*/
void *private; /* 私有数据----->一般用于指向具体的设备指针 */
int open; /* 表示handle是否正在被使用,当使用时,会将事件分发给设备处理*/
const char *name; /* 名字 */
struct input_dev *dev; /* 和该结构体向关联的设备 */
struct input_handler *handler; /* 与设备相关的handler */
struct list_head d_node; /* 该变量用于将handle放到设备相关的链表中,也就是放到input_dev->h_list*/
struct list_head h_node; /* 该变量用于将handle放到input_handler相关的链表中,也就是放到handler->h_lis表示的链表*/
};
struct input_dev *input_allocate_device(void); /*分配input_dev 结构体*/
void input_free_device(struct input_dev *dev);
/* 增加设备的引用计数 */
static inline struct input_dev *input_get_device(struct input_dev *dev)
{
return dev ? to_input_dev(get_device(&dev->dev)) : NULL;
}
/* 减小设备的引用计数 */
static inline void input_put_device(struct input_dev *dev)
{
if (dev)
put_device(&dev->dev);
}
/*获取驱动数据 即return struct input_dev->dev->driver_data*/
static inline void *input_get_drvdata(struct input_dev *dev)
{
return dev_get_drvdata(&dev->dev);
}
/* 设置驱动数据 即struct input_dev->dev->driver_data = data*/
static inline void input_set_drvdata(struct input_dev *dev, void *data)
{
dev_set_drvdata(&dev->dev, data);
}
int __must_check input_register_device(struct input_dev *);
void input_unregister_device(struct input_dev *);
int __must_check input_register_handler(struct input_handler *);
void input_unregister_handler(struct input_handler *);
int input_register_handle(struct input_handle *);
void input_unregister_handle(struct input_handle *);
int input_grab_device(struct input_handle *);
void input_release_device(struct input_handle *);
int input_open_device(struct input_handle *);
void input_close_device(struct input_handle *);
int input_flush_device(struct input_handle* handle, struct file* file);
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value);
/* 报告按键类事件
code为事件码(例如KEY_L),在input.h中定义
value为 事件的值(例如对于按键0表示松开,1表示按下)*/*/
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_KEY, code, !!value);
}
/* 报告相对位移类事件
code为事件码(例如REL_X),在input.h中定义
value为 事件的值(例如对于鼠标来说是坐标)*/
static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_REL, code, value);
}
/* 报告绝对位移类事件
code为事件码(例如ABS_X),在input.h中定义
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);
}
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code);
/* 设置绝对类事件的参数
axis为坐标轴,可以取ABS_X/ABS_Y/ABS_PRESSURE等
min为坐标的最小值
max为坐标的最大值*/
static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
{
dev->absmin[axis] = min;
dev->absmax[axis] = max;
dev->absfuzz[axis] = fuzz;
dev->absflat[axis] = flat;
dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis);
}
int input_get_keycode(struct input_dev *dev, int scancode, int *keycode);
int input_set_keycode(struct input_dev *dev, int scancode, int keycode);
extern struct class input_class;
/**
* struct ff_device - force-feedback part of an input device
* @upload: Called to upload an new effect into device
* @erase: Called to erase an effect from device
* @playback: Called to request device to start playing specified effect
* @set_gain: Called to set specified gain
* @set_autocenter: Called to auto-center device
* @destroy: called by input core when parent input device is being
* destroyed
* @private: driver-specific data, will be freed automatically
* @ffbit: bitmap of force feedback capabilities truly supported by
* device (not emulated like ones in input_dev->ffbit)
* @mutex: mutex for serializing access to the device
* @max_effects: maximum number of effects supported by device
* @effects: pointer to an array of effects currently loaded into device
* @effect_owners: array of effect owners; when file handle owning
* an effect gets closed the effect is automatically erased
*
* Every force-feedback device must implement upload() and playback()
* methods; erase() is optional. set_gain() and set_autocenter() need
* only be implemented if driver sets up FF_GAIN and FF_AUTOCENTER
* bits.
*/
struct ff_device { /* 强制给出反馈的部分输入设备 */
int (*upload)(struct input_dev *dev, struct ff_effect *effect,
struct ff_effect *old);
int (*erase)(struct input_dev *dev, int effect_id);
int (*playback)(struct input_dev *dev, int effect_id, int value);
void (*set_gain)(struct input_dev *dev, u16 gain);
void (*set_autocenter)(struct input_dev *dev, u16 magnitude);
void (*destroy)(struct ff_device *);
void *private;
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
struct mutex mutex;
int max_effects;
struct ff_effect *effects;
struct file *effect_owners[];
};
int input_ff_create(struct input_dev *dev, int max_effects);
void input_ff_destroy(struct input_dev *dev);
int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file);
int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file);
int input_ff_create_memless(struct input_dev *dev, void *data,
int (*play_effect)(struct input_dev *, void *, struct ff_effect *));
#endif
#endif
/*************************************************************************************************************************************/
/* mod_devicetable.h */
/*
* Device tables which are exported to userspace via
* scripts/mod/file2alias.c. You must keep that file in sync with this
* header.
*/
#ifndef LINUX_MOD_DEVICETABLE_H
#define LINUX_MOD_DEVICETABLE_H
#ifdef __KERNEL__
#include
typedef unsigned long kernel_ulong_t;
#endif
#define PCI_ANY_ID (~0)
struct pci_device_id {
__u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/
__u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
__u32 class, class_mask; /* (class,subclass,prog-if) triplet */
kernel_ulong_t driver_data; /* Data private to the driver */
};
#define IEEE1394_MATCH_VENDOR_ID 0x0001
#define IEEE1394_MATCH_MODEL_ID 0x0002
#define IEEE1394_MATCH_SPECIFIER_ID 0x0004
#define IEEE1394_MATCH_VERSION 0x0008
struct ieee1394_device_id {
__u32 match_flags;
__u32 vendor_id;
__u32 model_id;
__u32 specifier_id;
__u32 version;
kernel_ulong_t driver_data
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
/*
* Device table entry for "new style" table-driven USB drivers.
* User mode code can read these tables to choose which modules to load.
* Declare the table as a MODULE_DEVICE_TABLE.
*
* A probe() parameter will point to a matching entry from this table.
* Use the driver_info field for each match to hold information tied
* to that match: device quirks, etc.
*
* Terminate the driver's table with an all-zeroes entry.
* Use the flag values to control which fields are compared.
*/
/**
* struct usb_device_id - identifies USB devices for probing and hotplugging
* @match_flags: Bit mask controlling of the other fields are used to match
* against new devices. Any field except for driver_info may be used,
* although some only make sense in conjunction with other fields.
* This is usually set by a USB_DEVICE_*() macro, which sets all
* other fields in this structure except for driver_info.
* @idVendor: USB vendor ID for a device; numbers are assigned
* by the USB forum to its members.
* @idProduct: Vendor-assigned product ID.
* @bcdDevice_lo: Low end of range of vendor-assigned product version numbers.
* This is also used to identify individual product versions, for
* a range consisting of a single device.
* @bcdDevice_hi: High end of version number range. The range of product
* versions is inclusive.
* @bDeviceClass: Class of device; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Device classes specify behavior of all
* the interfaces on a devices.
* @bDeviceSubClass: Subclass of device; associated with bDeviceClass.
* @bDeviceProtocol: Protocol of device; associated with bDeviceClass.
* @bInterfaceClass: Class of interface; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Interface classes specify behavior only
* of a given interface; other interfaces may support other classes.
* @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
* @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
* @driver_info: Holds information used by the driver. Usually it holds
* a pointer to a descriptor understood by the driver, or perhaps
* device flags.
*
* In most cases, drivers will create a table of device IDs by using
* USB_DEVICE(), or similar macros designed for that purpose.
* They will then export it to userspace using MODULE_DEVICE_TABLE(),
* and provide it to the USB core through their usb_driver structure.
*
* See the usb_match_id() function for information about how matches are
* performed. Briefly, you will normally use one of several macros to help
* construct these entries. Each entry you provide will either identify
* one or more specific products, or will identify a class of products
* which have agreed to behave the same. You should put the more specific
* matches towards the beginning of your table, so that driver_info can
* record quirks of specific products.
*/
struct usb_device_id {
/* which fields to match against? */
__u16 match_flags;
/* Used for product specific matches; range is inclusive */
__u16 idVendor;
__u16 idProduct;
__u16 bcdDevice_lo;
__u16 bcdDevice_hi;
/* Used for device class matches */
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
/* Used for interface class matches */
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
/* not matched against */
kernel_ulong_t driver_info;
};
/* Some useful macros to use to create struct usb_device_id */
#define USB_DEVICE_ID_MATCH_VENDOR 0x0001
#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002
#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004
#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008
#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020
#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040
#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
#define HID_ANY_ID (~0)
struct hid_device_id {
__u16 bus;
__u16 pad1;
__u32 vendor;
__u32 product;
kernel_ulong_t driver_data
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
/* s390 CCW devices */
struct ccw_device_id {
__u16 match_flags; /* which fields to match against */
__u16 cu_type; /* control unit type */
__u16 dev_type; /* device type */
__u8 cu_model; /* control unit model */
__u8 dev_model; /* device model */
kernel_ulong_t driver_info;
};
#define CCW_DEVICE_ID_MATCH_CU_TYPE 0x01
#define CCW_DEVICE_ID_MATCH_CU_MODEL 0x02
#define CCW_DEVICE_ID_MATCH_DEVICE_TYPE 0x04
#define CCW_DEVICE_ID_MATCH_DEVICE_MODEL 0x08
/* s390 AP bus devices */
struct ap_device_id {
__u16 match_flags; /* which fields to match against */
__u8 dev_type; /* device type */
__u8 pad1;
__u32 pad2;
kernel_ulong_t driver_info;
};
#define AP_DEVICE_ID_MATCH_DEVICE_TYPE 0x01
/* s390 css bus devices (subchannels) */
struct css_device_id {
__u8 match_flags;
__u8 type; /* subchannel type */
__u16 pad2;
__u32 pad3;
kernel_ulong_t driver_data;
};
#define ACPI_ID_LEN 16 /* only 9 bytes needed here, 16 bytes are used */
/* to workaround crosscompile issues */
struct acpi_device_id {
__u8 id[ACPI_ID_LEN];
kernel_ulong_t driver_data;
};
#define PNP_ID_LEN 8
#define PNP_MAX_DEVICES 8
struct pnp_device_id {
__u8 id[PNP_ID_LEN];
kernel_ulong_t driver_data;
};
struct pnp_card_device_id {
__u8 id[PNP_ID_LEN];
kernel_ulong_t driver_data;
struct {
__u8 id[PNP_ID_LEN];
} devs[PNP_MAX_DEVICES];
};
#define SERIO_ANY 0xff
struct serio_device_id {
__u8 type;
__u8 extra;
__u8 id;
__u8 proto;
};
/*
* Struct used for matching a device
*/
struct of_device_id
{
char name[32];
char type[32];
char compatible[128];
#ifdef __KERNEL__
void *data;
#else
kernel_ulong_t data;
#endif
};
/* VIO */
struct vio_device_id {
char type[32];
char compat[32];
};
/* PCMCIA */
struct pcmcia_device_id {
__u16 match_flags;
__u16 manf_id;
__u16 card_id;
__u8 func_id;
/* for real multi-function devices */
__u8 function;
/* for pseudo multi-function devices */
__u8 device_no;
__u32 prod_id_hash[4]
__attribute__((aligned(sizeof(__u32))));
/* not matched against in kernelspace*/
#ifdef __KERNEL__
const char * prod_id[4];
#else
kernel_ulong_t prod_id[4]
__attribute__((aligned(sizeof(kernel_ulong_t))));
#endif
/* not matched against */
kernel_ulong_t driver_info;
#ifdef __KERNEL__
char * cisfile;
#else
kernel_ulong_t cisfile;
#endif
};
#define PCMCIA_DEV_ID_MATCH_MANF_ID 0x0001
#define PCMCIA_DEV_ID_MATCH_CARD_ID 0x0002
#define PCMCIA_DEV_ID_MATCH_FUNC_ID 0x0004
#define PCMCIA_DEV_ID_MATCH_FUNCTION 0x0008
#define PCMCIA_DEV_ID_MATCH_PROD_ID1 0x0010
#define PCMCIA_DEV_ID_MATCH_PROD_ID2 0x0020
#define PCMCIA_DEV_ID_MATCH_PROD_ID3 0x0040
#define PCMCIA_DEV_ID_MATCH_PROD_ID4 0x0080
#define PCMCIA_DEV_ID_MATCH_DEVICE_NO 0x0100
#define PCMCIA_DEV_ID_MATCH_FAKE_CIS 0x0200
#define PCMCIA_DEV_ID_MATCH_ANONYMOUS 0x0400
/* Input */
#define INPUT_DEVICE_ID_EV_MAX 0x1f
#define INPUT_DEVICE_ID_KEY_MIN_INTERESTING 0x71
#define INPUT_DEVICE_ID_KEY_MAX 0x2ff /* */
#define INPUT_DEVICE_ID_REL_MAX 0x0f /* */
#define INPUT_DEVICE_ID_ABS_MAX 0x3f /* */
#define INPUT_DEVICE_ID_MSC_MAX 0x07 /* */
#define INPUT_DEVICE_ID_LED_MAX 0x0f /* */
#define INPUT_DEVICE_ID_SND_MAX 0x07 /* */
#define INPUT_DEVICE_ID_FF_MAX 0x7f /* */
#define INPUT_DEVICE_ID_SW_MAX 0x0f /* */
#define INPUT_DEVICE_ID_MATCH_BUS 1 /* 匹配 struct input_device_id的bustype*/
#define INPUT_DEVICE_ID_MATCH_VENDOR 2 /* 匹配 struct input_device_id的vendor*/
#define INPUT_DEVICE_ID_MATCH_PRODUCT 4 /* 匹配 struct input_device_id的product */
#define INPUT_DEVICE_ID_MATCH_VERSION 8 /* 匹配 struct input_device_id的version */
#define INPUT_DEVICE_ID_MATCH_EVBIT 0x0010 /* 匹配事件类型*/
#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x0020 /* 匹配按键类事件的类型*/
#define INPUT_DEVICE_ID_MATCH_RELBIT 0x0040 /*匹配匹配相对位移类事件的类型 */
#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x0080 /* 匹配匹配绝对位移类事件的类型*/
#define INPUT_DEVICE_ID_MATCH_MSCIT 0x0100 /* 匹配混杂类事件*/
#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x0200 /* 匹配LED类事件*/
#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x0400 /* 匹配声音类事件*/
#define INPUT_DEVICE_ID_MATCH_FFBIT 0x0800 /* 匹配强制反馈类事件*/
#define INPUT_DEVICE_ID_MATCH_SWBIT 0x1000 /* 匹配开关类事件 */
struct input_device_id { /* 输入设备的ID */
kernel_ulong_t flags; /* 定义需要匹配input_id的哪些域 */
__u16 bustype; /*总线类型 */
__u16 vendor; /* 制造商ID*/
__u16 product; /* 产品ID*/
__u16 version; /* /* 产品版本 号*/ */
/* 存储支持事件的位图,与input_dev中的同名数据成员功能一致 */
kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];
kernel_ulong_t driver_info; /* 指示结构体中是否含有驱动信息 ,为1时表示驱动能处理所有输入设备的事件*/
};
/* EISA */
#define EISA_SIG_LEN 8
/* The EISA signature, in ASCII form, null terminated */
struct eisa_device_id {
char sig[EISA_SIG_LEN];
kernel_ulong_t driver_data;
};
#define EISA_DEVICE_MODALIAS_FMT "eisa:s%s"
struct parisc_device_id {
__u8 hw_type; /* 5 bits used */
__u8 hversion_rev; /* 4 bits */
__u16 hversion; /* 12 bits */
__u32 sversion; /* 20 bits */
};
#define PA_HWTYPE_ANY_ID 0xff
#define PA_HVERSION_REV_ANY_ID 0xff
#define PA_HVERSION_ANY_ID 0xffff
#define PA_SVERSION_ANY_ID 0xffffffff
/* SDIO */
#define SDIO_ANY_ID (~0)
struct sdio_device_id {
__u8 class; /* Standard interface or SDIO_ANY_ID */
__u16 vendor; /* Vendor or SDIO_ANY_ID */
__u16 device; /* Device ID or SDIO_ANY_ID */
kernel_ulong_t driver_data /* Data private to the driver */
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
/* SSB core, see drivers/ssb/ */
struct ssb_device_id {
__u16 vendor;
__u16 coreid;
__u8 revision;
};
#define SSB_DEVICE(_vendor, _coreid, _revision) \
{ .vendor = _vendor, .coreid = _coreid, .revision = _revision, }
#define SSB_DEVTABLE_END \
{ 0, },
#define SSB_ANY_VENDOR 0xFFFF
#define SSB_ANY_ID 0xFFFF
#define SSB_ANY_REV 0xFF
struct virtio_device_id {
__u32 device;
__u32 vendor;
};
#define VIRTIO_DEV_ANY_ID 0xffffffff
/* i2c */
#define I2C_NAME_SIZE 20
#define I2C_MODULE_PREFIX "i2c:"
struct i2c_device_id { /* i2c设备id */
char name[I2C_NAME_SIZE]; /* 设备的名字 */
kernel_ulong_t driver_data /* Data private to the driver */
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
/* dmi */
enum dmi_field {
DMI_NONE,
DMI_BIOS_VENDOR,
DMI_BIOS_VERSION,
DMI_BIOS_DATE,
DMI_SYS_VENDOR,
DMI_PRODUCT_NAME,
DMI_PRODUCT_VERSION,
DMI_PRODUCT_SERIAL,
DMI_PRODUCT_UUID,
DMI_BOARD_VENDOR,
DMI_BOARD_NAME,
DMI_BOARD_VERSION,
DMI_BOARD_SERIAL,
DMI_BOARD_ASSET_TAG,
DMI_CHASSIS_VENDOR,
DMI_CHASSIS_TYPE,
DMI_CHASSIS_VERSION,
DMI_CHASSIS_SERIAL,
DMI_CHASSIS_ASSET_TAG,
DMI_STRING_MAX,
};
struct dmi_strmatch {
unsigned char slot;
char substr[79];
};
#ifndef __KERNEL__
struct dmi_system_id {
kernel_ulong_t callback;
kernel_ulong_t ident;
struct dmi_strmatch matches[4];
kernel_ulong_t driver_data
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
#else
struct dmi_system_id {
int (*callback)(const struct dmi_system_id *);
const char *ident;
struct dmi_strmatch matches[4];
void *driver_data;
};
/*
* struct dmi_device_id appears during expansion of
* "MODULE_DEVICE_TABLE(dmi, x)". Compiler doesn't look inside it
* but this is enough for gcc 3.4.6 to error out:
* error: storage size of '__mod_dmi_device_table' isn't known
*/
#define dmi_device_id dmi_system_id
#endif
#define DMI_MATCH(a, b) { a, b }
#define PLATFORM_NAME_SIZE 20
#define PLATFORM_MODULE_PREFIX "platform:"
struct platform_device_id { /* 平台总线设备ID */
char name[PLATFORM_NAME_SIZE]; /* 名字 */
kernel_ulong_t driver_data /* 驱动数据(kernel_ulong_t=unsigned long) */
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
#endif /* LINUX_MOD_DEVICETABLE_H */
/*************************************************************************************************************************************/
/* input.c */
/*
* The input core
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_AUTHOR("Vojtech Pavlik
MODULE_DESCRIPTION("Input core");
MODULE_LICENSE("GPL");
#define INPUT_DEVICES 256
/*
* EV_ABS events which should not be cached are listed here.
*/
static unsigned int input_abs_bypass_init_data[] __initdata = {
ABS_MT_TOUCH_MAJOR,
ABS_MT_TOUCH_MINOR,
ABS_MT_WIDTH_MAJOR,
ABS_MT_WIDTH_MINOR,
ABS_MT_ORIENTATION,
ABS_MT_POSITION_X,
ABS_MT_POSITION_Y,
ABS_MT_TOOL_TYPE,
ABS_MT_BLOB_ID,
ABS_MT_TRACKING_ID,
0
};
static unsigned long input_abs_bypass[BITS_TO_LONGS(ABS_CNT)];
static LIST_HEAD(input_dev_list); /* 初始化 输入设备链表头input_dev_list*/
static LIST_HEAD(input_handler_list); /* 初始化 input_handler链表头input_handler_list*/
/*
* input_mutex protects access to both input_dev_list and input_handler_list.
* This also causes input_[un]register_device and input_[un]register_handler
* be mutually exclusive which simplifies locking in drivers implementing
* input handlers.
*/
static DEFINE_MUTEX(input_mutex); /* 定义并初始化互斥锁input_mutex */
static struct input_handler *input_table[8]; /* 事件处理结构体input_handler数组 */
/* 判断是否支持的事件类型,该函数检查input_dev.evbit中相应的位是否被设置,若设置则表示支持则返回非0,否则表示不支持
返回0 ,每一种类型的事件都在input_dev.evbit用一个位来表示,构成一个位图*/
static inline int is_event_supported(unsigned int code,
unsigned long *bm, unsigned int max)
{
return code <= max && test_bit(code, bm);
}
static int input_defuzz_abs_event(int value, int old_val, int fuzz)
{
if (fuzz) {
if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2)
return old_val;
if (value > old_val - fuzz && value < old_val + fuzz)
return (old_val * 3 + value) / 4;
if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2)
return (old_val + value) / 2;
}
return value;
}
/*
* Pass event through all open handles. This function is called with
* dev->event_lock held and interrupts disabled.
*/
/* 将事件交给handler处理的事件处理函数 */
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab); /* 获取input_dev的 struct input_handle *grab指针*/
if (handle) /* 如果handle有定义则调用 handle->handler->event函数来处理事件*/
handle->handler->event(handle, type, code, value);
else
list_for_each_entry_rcu(handle, &dev->h_list, d_node) /* 否则遍历dev->h_list 链表(handle链表)*/
if (handle->open) /* 如果在链表的遍历的handle的open函数有定义(如果该handle被打开,表示该设备已经被一个用户进程
使用(只有handle被打开的情况下才会接收到事件,这就是说,只有设备被用户程序使用时,才有
必要向用户空间导出信息))则调用handle->handler->event 来处理事件*/
handle->handler->event(handle,
type, code, value);
rcu_read_unlock();
}
/*
* Generate software autorepeat event. Note that we take
* dev->event_lock here to avoid racing with input_event
* which may cause keys get "stuck".
*/
/* 定时器dev->timer的处理函数,用于软件产生重复按键类事件 */
static void input_repeat_key(unsigned long data)
{
struct input_dev *dev = (void *) data;
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
if (test_bit(dev->repeat_key, dev->key) &&
is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) { /* 测试是否支持重复类事件,若支持则调用 input_pass_event来将重
复类事件交给相应的handler来处理*/
input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
if (dev->sync) {
/*
* Only send SYN_REPORT if we are not in a middle
* of driver parsing a new hardware packet.
* Otherwise assume that the driver will send
* SYN_REPORT once it's done.
*/
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
}
if (dev->rep[REP_PERIOD])
mod_timer(&dev->timer, jiffies +
msecs_to_jiffies(dev->rep[REP_PERIOD]));
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
/* 自动重复事件 */
static void input_start_autorepeat(struct input_dev *dev, int code)
{
if (test_bit(EV_REP, dev->evbit) &&
dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
dev->timer.data) {
dev->repeat_key = code;
mod_timer(&dev->timer,
jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
}
}
static void input_stop_autorepeat(struct input_dev *dev)
{
del_timer(&dev->timer);
}
/* 表示事件处理方式 */
#define INPUT_IGNORE_EVENT 0 /* 忽略事件 */
#define INPUT_PASS_TO_HANDLERS 1 /*将事件提交给input_handler来处理*/
#define INPUT_PASS_TO_DEVICE 2 /*将事件提交给 input_dev来处理(有些事件是发送给设备的,而不是发送给handler处理的,例如
led点灯事件、蜂鸣器鸣叫事件等),对于这类事件要调用input_dev的event()函数来向输入子系统
报告一个将要发送给设备的事件,当报告给输入子系统后,就要求设备处理这个事件*/
#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) /*将事件提交给input_handler 和input_dev来处理*/
/* 事件处理函数------发送数据 */
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition = INPUT_IGNORE_EVENT; /* 初始化为忽略事件,如果后面没有对该变量重新赋值则忽略事件 */
switch (type) { /* 以事件类型type做switch开关 */
case EV_SYN: /* 同步类事件 */
switch (code) {
case SYN_CONFIG: /* 如果是同步配置则设置将事件提交给input_handler 和input_dev来处理 */
disposition = INPUT_PASS_TO_ALL;
break;
case SYN_REPORT: /* 如果是同步以上上报的一组事件,表示一组事件上报结束 */
if (!dev->sync) { /* 如果dev->sync 为0,则将将其置为1表示最后一次同步后没有心的事件*/
dev->sync = 1;
disposition = INPUT_PASS_TO_HANDLERS; /*将事件提交给input_handler来处理*/
}
break;
case SYN_MT_REPORT: /* 该宏用于多点触摸屏 */
dev->sync = 0;
disposition = INPUT_PASS_TO_HANDLERS;
break;
}
break;
case EV_KEY: /* 按键类事件 */
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
!!test_bit(code, dev->key) != value) {
if (value != 2) {
__change_bit(code, dev->key);
if (value)
input_start_autorepeat(dev, code);
else
input_stop_autorepeat(dev);
}
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case EV_SW: /* 开关类事件 */
if (is_event_supported(code, dev->swbit, SW_MAX) &&
!!test_bit(code, dev->sw) != value) {
__change_bit(code, dev->sw);
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case EV_ABS: /*绝对位移类事件 */
if (is_event_supported(code, dev->absbit, ABS_MAX)) {
if (test_bit(code, input_abs_bypass)) {
disposition = INPUT_PASS_TO_HANDLERS;
break;
}
value = input_defuzz_abs_event(value,
dev->abs[code], dev->absfuzz[code]);
if (dev->abs[code] != value) {
dev->abs[code] = value;
disposition = INPUT_PASS_TO_HANDLERS;
}
}
break;
case EV_REL: /*相对位移类事件 */
if (is_event_supported(code, dev->relbit, REL_MAX) && value)
disposition = INPUT_PASS_TO_HANDLERS;
break;
case EV_MSC: /*杂项类事件 */
if (is_event_supported(code, dev->mscbit, MSC_MAX))
disposition = INPUT_PASS_TO_ALL;
break;
case EV_LED: /*LED类事件 */
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
!!test_bit(code, dev->led) != value) {
__change_bit(code, dev->led);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_SND: /*声音类事件 */
if (is_event_supported(code, dev->sndbit, SND_MAX)) {
if (!!test_bit(code, dev->snd) != !!value)
__change_bit(code, dev->snd);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_REP: /*重复类事件 */
if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
dev->rep[code] = value;
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_FF: /*强制反馈类事件 */
if (value >= 0)
disposition = INPUT_PASS_TO_ALL;
break;
case EV_PWR: /*电源管理类事件 */
disposition = INPUT_PASS_TO_ALL;
break;
}
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
dev->sync = 0; /* 如果不能忽略事件并且事件类型不为上报同步类事件EV_SYN 则dev->sync = 0,
表示一组事件还没有上报完*/
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) /* 如果最后 disposition=INPUT_PASS_TO_DEVICE(表示将事件提交给 input_dev来处理)并且 input_dev
的event字段被设置了则调用 input_dev的event字段指向的处理函数来处理事件*/
dev->event(dev, type, code, value);
if (disposition & INPUT_PASS_TO_HANDLERS) /* 如果 disposition =INPUT_PASS_TO_HANDLERS则表示将事件将事件提交给input_handler来处理,则调用
input_pass_event来处理事件*/
input_pass_event(dev, type, code, value);
}
/**
* input_event() - report new input event
* @dev: device that generated the event
* @type: type of the event
* @code: event code
* @value: value of the event
*
* This function should be used by drivers implementing various input
* devices. See also input_inject_event().
*/
/* 上报指定type、code的输入事件,
type为事件类型(例如EV_KEY等),在input.h中定义
code为事件码(例如KEY_L),在input.h中定义
value为 事件的值(例如对于触摸屏为坐标;对于按键0表示松开,1表示按下)*/
void input_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
unsigned long flags;
if (is_event_supported(type, dev->evbit, EV_MAX)) { /* 判断是否支持的事件类型 */
spin_lock_irqsave(&dev->event_lock, flags);
add_input_randomness(type, code, value); /* 该函数对事件的发送没有一点用处,只是用来对随机滴池增加一些贡献,因
为输入事件是一种随机事件,所以对滴池有贡献 */
input_handle_event(dev, type, code, value); /* 事件处理函数------发送数据 */
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
EXPORT_SYMBOL(input_event);
/**
* input_inject_event() - send input event from input handler
* @handle: input handle to send event through
* @type: type of the event
* @code: event code
* @value: value of the event
*
* Similar to input_event() but will ignore event if device is
* "grabbed" and handle injecting event is not the one that owns
* the device.
*/
/*input_handler是从用户空间拷贝的事件,该函数是将该事件发送到设备 */
void input_inject_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct input_dev *dev = handle->dev;
struct input_handle *grab;
unsigned long flags;
if (is_event_supported(type, dev->evbit, EV_MAX)) { /* 判断设备是否支持该类型的事件 */
spin_lock_irqsave(&dev->event_lock, flags);
rcu_read_lock();
grab = rcu_dereference(dev->grab);
if (!grab || grab == handle) /* 如果设备 没有设置强制的input_handle或者强制设置的handle等于参数handle则调用
input_handle_event来处理事件----发送数据*/
input_handle_event(dev, type, code, value);
rcu_read_unlock();
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
EXPORT_SYMBOL(input_inject_event);
/**
* input_grab_device - grabs device for exclusive use
* @handle: input handle that wants to own the device
*
* When a device is grabbed by an input handle all events generated by
* the device are delivered only to this handle. Also events injected
* by other input handles are ignored while device is grabbed.
*/
/* 强制设置设备的 dev->grab=handle*/
int input_grab_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
int retval;
retval = mutex_lock_interruptible(&dev->mutex);
if (retval)
return retval;
if (dev->grab) {
retval = -EBUSY;
goto out;
}
rcu_assign_pointer(dev->grab, handle);/* struct input_dev *dev->grab=handle */
synchronize_rcu();
out:
mutex_unlock(&dev->mutex);
return retval;
}
EXPORT_SYMBOL(input_grab_device);
/* 释放设备的handle */
static void __input_release_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
if (dev->grab == handle) {
rcu_assign_pointer(dev->grab, NULL); /* dev->grab=NULL */
/* Make sure input_pass_event() notices that grab is gone */
synchronize_rcu();
list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open && handle->handler->start)
handle->handler->start(handle); /* 遍历链表,如果handle被打开则调用handle->handler->start */
}
}
/**
* input_release_device - release previously grabbed device
* @handle: input handle that owns the device
*
* Releases previously grabbed device so that other input handles can
* start receiving input events. Upon release all handlers attached
* to the device have their start() method called so they have a change
* to synchronize device state with the rest of the system.
*/
/* 释放设备强制绑定的handle */
void input_release_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
mutex_lock(&dev->mutex);
__input_release_device(handle); /* 释放设备的handle */
mutex_unlock(&dev->mutex);
}
EXPORT_SYMBOL(input_release_device);
/**
* input_open_device - open input device
* @handle: handle through which device is being accessed
*
* This function should be called by input handlers when they
* want to start receive events from given input device.
*/
/* 打开输入设备 */
int input_open_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
int retval;
retval = mutex_lock_interruptible(&dev->mutex);
if (retval)
return retval;
if (dev->going_away) {
retval = -ENODEV;
goto out;
}
handle->open++; /*增加handle的打开计数 */
if (!dev->users++ && dev->open) /* 如果设备第一次被用户使用并且struct input_dev *dev->open有定义则调用它来打开设备 */
retval = dev->open(dev);
if (retval) {
dev->users--;
if (!--handle->open) {
/*
* Make sure we are not delivering any more events
* through this handle
*/
synchronize_rcu();
}
}
out:
mutex_unlock(&dev->mutex);
return retval;
}
EXPORT_SYMBOL(input_open_device);
/* 刷新设备的数据 */
int input_flush_device(struct input_handle *handle, struct file *file)
{
struct input_dev *dev = handle->dev;
int retval;
retval = mutex_lock_interruptible(&dev->mutex);
if (retval)
return retval;
if (dev->flush) /* 如果struct input_dev *dev->flush存在则调用该函数来 冲洗数据*/
retval = dev->flush(dev, file);
mutex_unlock(&dev->mutex);
return retval;
}
EXPORT_SYMBOL(input_flush_device);
/**
* input_close_device - close input device
* @handle: handle through which device is being accessed
*
* This function should be called by input handlers when they
* want to stop receive events from given input device.
*/
/* 关闭设备 */
void input_close_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
mutex_lock(&dev->mutex);
__input_release_device(handle); /* 释放设备 */
if (!--dev->users && dev->close) /* 如果用户的使用次数减一后为0 并且dev->close有定义则调用它来关闭设备*/
dev->close(dev);
if (!--handle->open) { /* 如果用户的打开设备的次数减一后为0 */
/*
* synchronize_rcu() makes sure that input_pass_event()
* completed and that no more input events are delivered
* through this handle
*/
synchronize_rcu();
}
mutex_unlock(&dev->mutex);
}
EXPORT_SYMBOL(input_close_device);
/*
* Prepare device for unregistering
*/
/* 为设备的注销做准备 */
static void input_disconnect_device(struct input_dev *dev)
{
struct input_handle *handle;
int code;
/*
* Mark device as going away. Note that we take dev->mutex here
* not to protect access to dev->going_away but rather to ensure
* that there are no threads in the middle of input_open_device()
*/
mutex_lock(&dev->mutex);
dev->going_away = 1; /* 标志设备未注册中,会引起调用 input_open_device*() 函数返回 -ENODEV*/
mutex_unlock(&dev->mutex);
spin_lock_irq(&dev->event_lock);
/*
* Simulate keyup events for all pressed keys so that handlers
* are not left with "stuck" keys. The driver may continue
* generate events even after we done here but they will not
* reach any handlers.
*/
if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { /* 测试是否支持按键类事件 */
for (code = 0; code <= KEY_MAX; code++) {
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
__test_and_clear_bit(code, dev->key)) {
input_pass_event(dev, EV_KEY, code, 0); /* 设置无按键类事件产生 */
}
}
input_pass_event(dev, EV_SYN, SYN_REPORT, 1); /* 设置同步类事件 */
}
list_for_each_entry(handle, &dev->h_list, d_node) /* 遍历dev->h_list链表,设置 handle->open = 0即标志handle未打开*/
handle->open = 0;
spin_unlock_irq(&dev->event_lock);
}
static int input_fetch_keycode(struct input_dev *dev, int scancode)
{
switch (dev->keycodesize) {
case 1:
return ((u8 *)dev->keycode)[scancode];
case 2:
return ((u16 *)dev->keycode)[scancode];
default:
return ((u32 *)dev->keycode)[scancode];
}
}
/* 默认的获取扫描码的键值函数*/
static int input_default_getkeycode(struct input_dev *dev,
int scancode, int *keycode)
{
if (!dev->keycodesize)
return -EINVAL;
if (scancode >= dev->keycodemax)
return -EINVAL;
*keycode = input_fetch_keycode(dev, scancode);
return 0;
}
/* 默认的修改键值的函数*/
static int input_default_setkeycode(struct input_dev *dev,
int scancode, int keycode)
{
int old_keycode;
int i;
if (scancode >= dev->keycodemax)
return -EINVAL;
if (!dev->keycodesize)
return -EINVAL;
if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
return -EINVAL;
switch (dev->keycodesize) {
case 1: { /* 1个字节 */
u8 *k = (u8 *)dev->keycode;
old_keycode = k[scancode];
k[scancode] = keycode;
break;
}
case 2: { /* 2个字节 */
u16 *k = (u16 *)dev->keycode;
old_keycode = k[scancode];
k[scancode] = keycode;
break;
}
default: { /* 3个字节 */
u32 *k = (u32 *)dev->keycode;
old_keycode = k[scancode];
k[scancode] = keycode;
break;
}
}
clear_bit(old_keycode, dev->keybit);
set_bit(keycode, dev->keybit);
for (i = 0; i < dev->keycodemax; i++) {
if (input_fetch_keycode(dev, i) == old_keycode) {
set_bit(old_keycode, dev->keybit);
break; /* Setting the bit twice is useless, so break */
}
}
return 0;
}
/**
* input_get_keycode - retrieve keycode currently mapped to a given scancode
* @dev: input device which keymap is being queried
* @scancode: scancode (or its equivalent for device in question) for which
* keycode is needed
* @keycode: result
*
* This function should be called by anyone interested in retrieving current
* keymap. Presently keyboard and evdev handlers use it.
*/
/* 获取键值 */
int input_get_keycode(struct input_dev *dev, int scancode, int *keycode)
{
if (scancode < 0)
return -EINVAL;
return dev->getkeycode(dev, scancode, keycode); /* 调用输入设备的成员函数getkeycode来获取键值 */
}
EXPORT_SYMBOL(input_get_keycode);
/**
* input_get_keycode - assign new keycode to a given scancode
* @dev: input device which keymap is being updated
* @scancode: scancode (or its equivalent for device in question)
* @keycode: new keycode to be assigned to the scancode
*
* This function should be called by anyone needing to update current
* keymap. Presently keyboard and evdev handlers use it.
*/
/* 设置键值 */
int input_set_keycode(struct input_dev *dev, int scancode, int keycode)
{
unsigned long flags;
int old_keycode;
int retval;
if (scancode < 0)
return -EINVAL;
if (keycode < 0 || keycode > KEY_MAX)
return -EINVAL;
spin_lock_irqsave(&dev->event_lock, flags);
retval = dev->getkeycode(dev, scancode, &old_keycode); /* 调用设备的 getkeycode来获取键值*/
if (retval)
goto out;
retval = dev->setkeycode(dev, scancode, keycode); /* 调用设备的 setkeycode来设置键值*/
if (retval)
goto out;
/*
* Simulate keyup event if keycode is not present
* in the keymap anymore
*/
if (test_bit(EV_KEY, dev->evbit) &&
!is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
__test_and_clear_bit(old_keycode, dev->key)) {
input_pass_event(dev, EV_KEY, old_keycode, 0); /* 模拟按键松开 */
if (dev->sync)
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
}
out:
spin_unlock_irqrestore(&dev->event_lock, flags);
return retval;
}
EXPORT_SYMBOL(input_set_keycode);
/* 匹配bit */
#define MATCH_BIT(bit, max) \
for (i = 0; i < BITS_TO_LONGS(max); i++) \ /* 在 遍历struct input_device_id的数组成员evbit?keybit等*/
if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \ /* 对handler->id_table->evbit和dev->evbit等进行相等匹配 */
break; \
if (i != BITS_TO_LONGS(max)) \
continue;
/* 用来对设备事件处理结构体input_handler和 设备 input_dev进行匹配,若匹配则返回handler->id_table*/
static const struct input_device_id *input_match_device(const struct input_device_id *id,
struct input_dev *dev)
{
int i;
for (; id->flags || id->driver_info; id++) { /* 该循环用来匹配id和dev->id中的信息,只要有一项匹配则返回 */
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
if (id->bustype != dev->id.bustype) /* 对handler->id_table->bustype和input_dev->id.bustype进行匹配*/
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
if (id->vendor != dev->id.vendor) /* 对handler->id_table->vendor和input_dev->id.vendor进行匹配*/
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
if (id->product != dev->id.product) /* 对handler->id_table->product 和input_dev->id.product进行匹配*/
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
if (id->version != dev->id.version) /* 对handler->id_table->version和input_dev->id.version进行匹配*/
continue;
/*
如果handler->id_table->flags没有定义或上面的匹配成功则会进入下面的MATCH_BIT
在 遍历struct input_device_id的数组成员evbit、keybit、relbit、absbit、mscbit、ledbit、sndbit、ffbit、swbit,
对handler->id_table->evbit和dev->evbit等进行相等匹配 */
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);
return id;
}
return NULL;
}
/* 遍历 链表input_handler_list,对每个链表中的节点调用input_attach_handler函数来匹配输入设备和
设备的事件处理函数,只有匹配成功,才能进行下一步的关联操作*/
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id; /* 输入设备的ID */
int error;
if (handler->blacklist && input_match_device(handler->blacklist, dev)) /* 如果struct input_handler *handler ->blacklist(忽略设备ID表指针)有定义并且调用
input_match_device函数来对设备 input_dev *dev->id和input_handler ->blacklist进行匹配*/
return -ENODEV;
id = input_match_device(handler->id_table, dev); /* 如果 handler->blacklist 没有定义则直接调用 input_match_device函数来对handler->id_table和dev->id进行匹配*/
if (!id)
return -ENODEV;
error = handler->connect(handler, dev, id); /* 如果匹配成功则调用 handler->connect来将handler与input_dev连接起来*/
if (error && error != -ENODEV)
printk(KERN_ERR
"input: failed to attach handler %s to device %s, "
"error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
return error;
}
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_bus_input_dir;
static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);
static int input_devices_state;
static inline void input_wakeup_procfs_readers(void)
{
input_devices_state++;
wake_up(&input_devices_poll_wait);
}
static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &input_devices_poll_wait, wait);
if (file->f_version != input_devices_state) {
file->f_version = input_devices_state;
return POLLIN | POLLRDNORM;
}
return 0;
}
static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
{
if (mutex_lock_interruptible(&input_mutex))
return NULL;
return seq_list_start(&input_dev_list, *pos);
}
static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
return seq_list_next(v, &input_dev_list, pos);
}
static void input_devices_seq_stop(struct seq_file *seq, void *v)
{
mutex_unlock(&input_mutex);
}
static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
unsigned long *bitmap, int max)
{
int i;
for (i = BITS_TO_LONGS(max) - 1; i > 0; i--)
if (bitmap[i])
break;
seq_printf(seq, "B: %s=", name);
for (; i >= 0; i--)
seq_printf(seq, "%lx%s", bitmap[i], i > 0 ? " " : "");
seq_putc(seq, '\n');
}
static int input_devices_seq_show(struct seq_file *seq, void *v)
{
struct input_dev *dev = container_of(v, struct input_dev, node);
const char *path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
struct input_handle *handle;
seq_printf(seq, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n",
dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version);
seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : "");
seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : "");
seq_printf(seq, "S: Sysfs=%s\n", path ? path : "");
seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : "");
seq_printf(seq, "H: Handlers=");
list_for_each_entry(handle, &dev->h_list, d_node)
seq_printf(seq, "%s ", handle->name);
seq_putc(seq, '\n');
input_seq_print_bitmap(seq, "EV", dev->evbit, EV_MAX);
if (test_bit(EV_KEY, dev->evbit))
input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX);
if (test_bit(EV_REL, dev->evbit))
input_seq_print_bitmap(seq, "REL", dev->relbit, REL_MAX);
if (test_bit(EV_ABS, dev->evbit))
input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX);
if (test_bit(EV_MSC, dev->evbit))
input_seq_print_bitmap(seq, "MSC", dev->mscbit, MSC_MAX);
if (test_bit(EV_LED, dev->evbit))
input_seq_print_bitmap(seq, "LED", dev->ledbit, LED_MAX);
if (test_bit(EV_SND, dev->evbit))
input_seq_print_bitmap(seq, "SND", dev->sndbit, SND_MAX);
if (test_bit(EV_FF, dev->evbit))
input_seq_print_bitmap(seq, "FF", dev->ffbit, FF_MAX);
if (test_bit(EV_SW, dev->evbit))
input_seq_print_bitmap(seq, "SW", dev->swbit, SW_MAX);
seq_putc(seq, '\n');
kfree(path);
return 0;
}
static const struct seq_operations input_devices_seq_ops = {
.start = input_devices_seq_start,
.next = input_devices_seq_next,
.stop = input_devices_seq_stop,
.show = input_devices_seq_show,
};
static int input_proc_devices_open(struct inode *inode, struct file *file)
{
return seq_open(file, &input_devices_seq_ops);
}
static const struct file_operations input_devices_fileops = {
.owner = THIS_MODULE,
.open = input_proc_devices_open,
.poll = input_proc_devices_poll,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
{
if (mutex_lock_interruptible(&input_mutex))
return NULL;
seq->private = (void *)(unsigned long)*pos;
return seq_list_start(&input_handler_list, *pos);
}
static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
seq->private = (void *)(unsigned long)(*pos + 1);
return seq_list_next(v, &input_handler_list, pos);
}
static void input_handlers_seq_stop(struct seq_file *seq, void *v)
{
mutex_unlock(&input_mutex);
}
static int input_handlers_seq_show(struct seq_file *seq, void *v)
{
struct input_handler *handler = container_of(v, struct input_handler, node);
seq_printf(seq, "N: Number=%ld Name=%s",
(unsigned long)seq->private, handler->name);
if (handler->fops)
seq_printf(seq, " Minor=%d", handler->minor);
seq_putc(seq, '\n');
return 0;
}
static const struct seq_operations input_handlers_seq_ops = { /*proc文件系统的handler的操作函数 ,系统调用将最终会调用至此*/
.start = input_handlers_seq_start,
.next = input_handlers_seq_next,
.stop = input_handlers_seq_stop,
.show = input_handlers_seq_show,
};
static int input_proc_handlers_open(struct inode *inode, struct file *file)
{
return seq_open(file, &input_handlers_seq_ops);
}
static const struct file_operations input_handlers_fileops = { /*proc文件系统的handler的操作函数 ,系统调用将会调用至此*/
.owner = THIS_MODULE,
.open = input_proc_handlers_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int __init input_proc_init(void)
{
struct proc_dir_entry *entry;
proc_bus_input_dir = proc_mkdir("bus/input", NULL); /* 在/proc目录下创建目录 "bus/input"*/
if (!proc_bus_input_dir)
return -ENOMEM;
entry = proc_create("devices", 0, proc_bus_input_dir, /* proc文件系统中创建设备 devices即/procbus/input/devices*/
&input_devices_fileops);
if (!entry)
goto fail1;
entry = proc_create("handlers", 0, proc_bus_input_dir, /* proc文件系统中创建设备 handlers即/procbus/input/handlers*/
&input_handlers_fileops);
if (!entry)
goto fail2;
return 0;
fail2: remove_proc_entry("devices", proc_bus_input_dir);
fail1: remove_proc_entry("bus/input", NULL);
return -ENOMEM;
}
static void input_proc_exit(void)
{
remove_proc_entry("devices", proc_bus_input_dir);
remove_proc_entry("handlers", proc_bus_input_dir);
remove_proc_entry("bus/input", NULL);
}
#else /* !CONFIG_PROC_FS */
static inline void input_wakeup_procfs_readers(void) { }
static inline int input_proc_init(void) { return 0; }
static inline void input_proc_exit(void) { }
#endif
#define INPUT_DEV_STRING_ATTR_SHOW(name) \
static ssize_t input_dev_show_##name(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
struct input_dev *input_dev = to_input_dev(dev); \
\
return scnprintf(buf, PAGE_SIZE, "%s\n", \
input_dev->name ? input_dev->name : ""); \
} \
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL)
INPUT_DEV_STRING_ATTR_SHOW(name);
INPUT_DEV_STRING_ATTR_SHOW(phys);
INPUT_DEV_STRING_ATTR_SHOW(uniq);
static int input_print_modalias_bits(char *buf, int size,
char name, unsigned long *bm,
unsigned int min_bit, unsigned int max_bit)
{
int len = 0, i;
len += snprintf(buf, max(size, 0), "%c", name);
for (i = min_bit; i < max_bit; i++)
if (bm[BIT_WORD(i)] & BIT_MASK(i))
len += snprintf(buf + len, max(size - len, 0), "%X,", i);
return len;
}
static int input_print_modalias(char *buf, int size, struct input_dev *id,
int add_cr)
{
int len;
len = snprintf(buf, max(size, 0),
"input:b%04Xv%04Xp%04Xe%04X-",
id->id.bustype, id->id.vendor,
id->id.product, id->id.version);
len += input_print_modalias_bits(buf + len, size - len,
'e', id->evbit, 0, EV_MAX);
len += input_print_modalias_bits(buf + len, size - len,
'k', id->keybit, KEY_MIN_INTERESTING, KEY_MAX);
len += input_print_modalias_bits(buf + len, size - len,
'r', id->relbit, 0, REL_MAX);
len += input_print_modalias_bits(buf + len, size - len,
'a', id->absbit, 0, ABS_MAX);
len += input_print_modalias_bits(buf + len, size - len,
'm', id->mscbit, 0, MSC_MAX);
len += input_print_modalias_bits(buf + len, size - len,
'l', id->ledbit, 0, LED_MAX);
len += input_print_modalias_bits(buf + len, size - len,
's', id->sndbit, 0, SND_MAX);
len += input_print_modalias_bits(buf + len, size - len,
'f', id->ffbit, 0, FF_MAX);
len += input_print_modalias_bits(buf + len, size - len,
'w', id->swbit, 0, SW_MAX);
if (add_cr)
len += snprintf(buf + len, max(size - len, 0), "\n");
return len;
}
static ssize_t input_dev_show_modalias(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct input_dev *id = to_input_dev(dev);
ssize_t len;
len = input_print_modalias(buf, PAGE_SIZE, id, 1);
return min_t(int, len, PAGE_SIZE);
}
static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);
static struct attribute *input_dev_attrs[] = {
&dev_attr_name.attr,
&dev_attr_phys.attr,
&dev_attr_uniq.attr,
&dev_attr_modalias.attr,
NULL
};
static struct attribute_group input_dev_attr_group = {
.attrs = input_dev_attrs,
};
#define INPUT_DEV_ID_ATTR(name) \
static ssize_t input_dev_show_id_##name(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
struct input_dev *input_dev = to_input_dev(dev); \
return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name); \
} \
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL)
INPUT_DEV_ID_ATTR(bustype);
INPUT_DEV_ID_ATTR(vendor);
INPUT_DEV_ID_ATTR(product);
INPUT_DEV_ID_ATTR(version);
static struct attribute *input_dev_id_attrs[] = {
&dev_attr_bustype.attr,
&dev_attr_vendor.attr,
&dev_attr_product.attr,
&dev_attr_version.attr,
NULL
};
static struct attribute_group input_dev_id_attr_group = {
.name = "id",
.attrs = input_dev_id_attrs,
};
static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
int max, int add_cr)
{
int i;
int len = 0;
for (i = BITS_TO_LONGS(max) - 1; i > 0; i--)
if (bitmap[i])
break;
for (; i >= 0; i--)
len += snprintf(buf + len, max(buf_size - len, 0),
"%lx%s", bitmap[i], i > 0 ? " " : "");
if (add_cr)
len += snprintf(buf + len, max(buf_size - len, 0), "\n");
return len;
}
#define INPUT_DEV_CAP_ATTR(ev, bm) \
static ssize_t input_dev_show_cap_##bm(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
struct input_dev *input_dev = to_input_dev(dev); \
int len = input_print_bitmap(buf, PAGE_SIZE, \
input_dev->bm##bit, ev##_MAX, 1); \
return min_t(int, len, PAGE_SIZE); \
} \
static DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL)
INPUT_DEV_CAP_ATTR(EV, ev);
INPUT_DEV_CAP_ATTR(KEY, key);
INPUT_DEV_CAP_ATTR(REL, rel);
INPUT_DEV_CAP_ATTR(ABS, abs);
INPUT_DEV_CAP_ATTR(MSC, msc);
INPUT_DEV_CAP_ATTR(LED, led);
INPUT_DEV_CAP_ATTR(SND, snd);
INPUT_DEV_CAP_ATTR(FF, ff);
INPUT_DEV_CAP_ATTR(SW, sw);
static struct attribute *input_dev_caps_attrs[] = {
&dev_attr_ev.attr,
&dev_attr_key.attr,
&dev_attr_rel.attr,
&dev_attr_abs.attr,
&dev_attr_msc.attr,
&dev_attr_led.attr,
&dev_attr_snd.attr,
&dev_attr_ff.attr,
&dev_attr_sw.attr,
NULL
};
static struct attribute_group input_dev_caps_attr_group = {
.name = "capabilities",
.attrs = input_dev_caps_attrs,
};
static struct attribute_group *input_dev_attr_groups[] = { /* 定义组属性 */
&input_dev_attr_group,
&input_dev_id_attr_group,
&input_dev_caps_attr_group,
NULL
};
/*设备的释放函数*/
static void input_dev_release(struct device *device)
{
struct input_dev *dev = to_input_dev(device);
input_ff_destroy(dev);
kfree(dev); /* 释放dev占用的内存 */
module_put(THIS_MODULE);
}
/*
* Input uevent interface - loading event handlers based on
* device bitfields.
*/
static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
const char *name, unsigned long *bitmap, int max)
{
int len;
if (add_uevent_var(env, "%s=", name))
return -ENOMEM;
len = input_print_bitmap(&env->buf[env->buflen - 1],
sizeof(env->buf) - env->buflen,
bitmap, max, 0);
if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
env->buflen += len;
return 0;
}
static int input_add_uevent_modalias_var(struct kobj_uevent_env *env,
struct input_dev *dev)
{
int len;
if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;
len = input_print_modalias(&env->buf[env->buflen - 1],
sizeof(env->buf) - env->buflen,
dev, 0);
if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
env->buflen += len;
return 0;
}
#define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \
do { \
int err = add_uevent_var(env, fmt, val); \
if (err) \
return err; \
} while (0)
#define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \
do { \
int err = input_add_uevent_bm_var(env, name, bm, max); \
if (err) \
return err; \
} while (0)
#define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev) \
do { \
int err = input_add_uevent_modalias_var(env, dev); \
if (err) \
return err; \
} while (0)
/* 设备的uevent事件处理函数 */
static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
{
struct input_dev *dev = to_input_dev(device);
/* 添加热插拔事件的环境变量 */
INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x",
dev->id.bustype, dev->id.vendor,
dev->id.product, dev->id.version);
if (dev->name)
INPUT_ADD_HOTPLUG_VAR("NAME=\"%s\"", dev->name);
if (dev->phys)
INPUT_ADD_HOTPLUG_VAR("PHYS=\"%s\"", dev->phys);
if (dev->uniq)
INPUT_ADD_HOTPLUG_VAR("UNIQ=\"%s\"", dev->uniq);
INPUT_ADD_HOTPLUG_BM_VAR("EV=", dev->evbit, EV_MAX);
if (test_bit(EV_KEY, dev->evbit))
INPUT_ADD_HOTPLUG_BM_VAR("KEY=", dev->keybit, KEY_MAX);
if (test_bit(EV_REL, dev->evbit))
INPUT_ADD_HOTPLUG_BM_VAR("REL=", dev->relbit, REL_MAX);
if (test_bit(EV_ABS, dev->evbit))
INPUT_ADD_HOTPLUG_BM_VAR("ABS=", dev->absbit, ABS_MAX);
if (test_bit(EV_MSC, dev->evbit))
INPUT_ADD_HOTPLUG_BM_VAR("MSC=", dev->mscbit, MSC_MAX);
if (test_bit(EV_LED, dev->evbit))
INPUT_ADD_HOTPLUG_BM_VAR("LED=", dev->ledbit, LED_MAX);
if (test_bit(EV_SND, dev->evbit))
INPUT_ADD_HOTPLUG_BM_VAR("SND=", dev->sndbit, SND_MAX);
if (test_bit(EV_FF, dev->evbit))
INPUT_ADD_HOTPLUG_BM_VAR("FF=", dev->ffbit, FF_MAX);
if (test_bit(EV_SW, dev->evbit))
INPUT_ADD_HOTPLUG_BM_VAR("SW=", dev->swbit, SW_MAX);
INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev);
return 0;
}
static struct device_type input_dev_type = { /* 定义一个设备类型 */
.groups = input_dev_attr_groups, /* 设备组属性 */
.release = input_dev_release, /*设备的释放函数*/
.uevent = input_dev_uevent, /* 设备的uevent事件处理函数 */
};
struct class input_class = { /* 定义一个类,名字为input,由此可知会在/sys/class目录下创建一个input目录 */
.name = "input",
};
EXPORT_SYMBOL_GPL(input_class);
/**
* input_allocate_device - allocate memory for new input device
*
* Returns prepared struct input_dev or NULL.
*
* NOTE: Use input_free_device() to free devices that have not been
* registered; input_unregister_device() should be used for already
* registered devices.
*/
/* 分配一个输入设备即分配input_dev 结构体,表征一个输入设备 */
struct input_dev *input_allocate_device(void)
{
struct input_dev *dev;
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); /* 分配一个struct input_dev结构体,并初始化为0 */
if (dev) {
dev->dev.type = &input_dev_type; /* 初始化设备类型为 input_dev_type*/
dev->dev.class = &input_class; /* 初始化设备类为 input_class*/
device_initialize(&dev->dev); /* 初始化dev->dev */
mutex_init(&dev->mutex); /* 初始化互斥锁 */
spin_lock_init(&dev->event_lock); /* 初始化自旋锁 */
INIT_LIST_HEAD(&dev->h_list); /* 初始化链表 dev->h_list*/
INIT_LIST_HEAD(&dev->node); /* 初始化链表 dev->node*/
__module_get(THIS_MODULE); /* 模块引用计数加1 */
}
return dev;
}
EXPORT_SYMBOL(input_allocate_device);
/**
* input_free_device - free memory occupied by input_dev structure
* @dev: input device to free
*
* This function should only be used if input_register_device()
* was not called yet or if it failed. Once device was registered
* use input_unregister_device() and memory will be freed once last
* reference to the device is dropped.
*
* Device should be allocated by input_allocate_device().
*
* NOTE: If there are references to the input device then memory
* will not be freed until last reference is dropped.
*/
/* 释放一个输入设备即释放input_dev 结构体
注意释放设备必须要在其他资源释放了并且在设备注销了之后,要不然会产生段错误*/
void input_free_device(struct input_dev *dev)
{
if (dev)
input_put_device(dev);
}
EXPORT_SYMBOL(input_free_device);
/**
* input_set_capability - mark device as capable of a certain event
* @dev: device that is capable of emitting or accepting event
* @type: type of the event (EV_KEY, EV_REL, etc...)
* @code: event code
*
* In addition to setting up corresponding bit in appropriate capability
* bitmap the function also adjusts dev->evbit.
*/
/* 设置此输入设备可告知的事件 */
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
{
switch (type) {
case EV_KEY: /* 按键类事件 */
__set_bit(code, dev->keybit);
break;
case EV_REL: /* 相对位移类事件 */
__set_bit(code, dev->relbit);
break;
case EV_ABS: /* 绝对位移类事件 */
__set_bit(code, dev->absbit);
break;
case EV_MSC: /*杂项类事件 */
__set_bit(code, dev->mscbit);
break;
case EV_SW: /* 开关类事件 */
__set_bit(code, dev->swbit);
break;
case EV_LED: /*LED类事件 */
__set_bit(code, dev->ledbit);
break;
case EV_SND: /* 声音类事件 */
__set_bit(code, dev->sndbit);
break;
case EV_FF: /* 强制反馈类事件 */
__set_bit(code, dev->ffbit);
break;
case EV_PWR: /*电源管理类事件 */
/* do nothing */
break;
default:
printk(KERN_ERR
"input_set_capability: unknown type %u (code %u)\n",
type, code);
dump_stack();
return;
}
__set_bit(type, dev->evbit);
}
EXPORT_SYMBOL(input_set_capability);
/**
* input_register_device - register device with input core
* @dev: device to be registered
*
* This function registers device with input core. The device must be
* allocated with input_allocate_device() and all it's capabilities
* set up before registering.
* If function fails the device must be freed with input_free_device().
* Once device has been successfully registered it can be unregistered
* with input_unregister_device(); input_free_device() should not be
* called in this case.
*/
/* 向核心注册一个输入设备 */
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;
__set_bit(EV_SYN, dev->evbit); /* 设置能产生同步类事件 */
/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
*/
init_timer(&dev->timer); /* 初始化定时器,用于处理重复按下按键而定义的 */
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) { /* 如果输入设备的 input_dev的rep没有定义则设置默认值*/
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key; /* 定时器dev->timer的处理函数,用于软件产生重复按键类事件 */
dev->rep[REP_DELAY] = 250;
dev->rep[REP_PERIOD] = 33;
}
/* 如果input_dev的getkeycode和setkeycode都没有定义则使用默认的函数 */
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); /* 设置设备的名字,input0、input1、........*/
error = device_add(&dev->dev); /* 向设备驱动模型中添加设备 */
if (error)
return error;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); /* 获取设备的路径 */
printk(KERN_INFO "input: %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;
}
list_add_tail(&dev->node, &input_dev_list); /* 将dev->node添加到input_dev_list链表中,input_dev_list链表中包含了系统中所有input_dev设备 */
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);/* 遍历 链表input_handler_list,对每个链表中的节点调用input_attach_handler函数来匹配输入设备和
设备的事件处理函数,只有匹配成功,才能进行下一步的关联操作*/
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
return 0;
}
EXPORT_SYMBOL(input_register_device);
/**
* input_unregister_device - unregister previously registered device
* @dev: device to be unregistered
*
* This function unregisters an input device. Once device is unregistered
* the caller should not try to access it as it may get freed at any moment.
*/
/* 向核心注销一个输入设备 */
void input_unregister_device(struct input_dev *dev)
{
struct input_handle *handle, *next;
input_disconnect_device(dev); /* 取消 dev和 handle的联系*/
mutex_lock(&input_mutex);
list_for_each_entry_safe(handle, next, &dev->h_list, d_node) /* 遍历dev->h_list ,调用handle->handler->disconnect函数来取消联系*/
handle->handler->disconnect(handle);
WARN_ON(!list_empty(&dev->h_list));
del_timer_sync(&dev->timer); /* 删除定时器 */
list_del_init(&dev->node); /*从链表 中 删除dev->node*/
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
device_unregister(&dev->dev); /*向核心注销struct input_dev *dev->dev*/
}
EXPORT_SYMBOL(input_unregister_device);
/**
* input_register_handler - register a new input handler
* @handler: handler to be registered
*
* This function registers a new input handler (interface) for input
* devices in the system and attaches it to all input devices that
* are compatible with the handler.
*/
/* 注册一个新的input_handler处理器,这个handler将为输入设备使用,一个handler可以添加多个支持他的设备中,也就是一个
handler可以处理多个输入设备的事件*/
int input_register_handler(struct input_handler *handler)
{
struct input_dev *dev;
int retval;
retval = mutex_lock_interruptible(&input_mutex); /* 获取互斥锁 */
if (retval)
return retval;
INIT_LIST_HEAD(&handler->h_list); /* 初始化handler->h_list链表头 */
if (handler->fops != NULL) { /* 如果handler->fops有定义则 以次设备号右移5位作为下标查看input_table数组项中是否为空,如果为不空
(说明已经设备已经存在handler了)则做出错处理 */
if (input_table[handler->minor >> 5]) {
retval = -EBUSY;
goto out;
}
input_table[handler->minor >> 5] = handler; /* 将该handler插入input_table数组中 */
}
list_add_tail(&handler->node, &input_handler_list); /* 将handler加入全局的input_handler_list链表中,该链表中包含了系统中所有的input_handler */
list_for_each_entry(dev, &input_dev_list, node) /* 遍历链表input_dev_list,对链表的每个节点(input_dev),调用input_attach_handler来对 input_dev和
handler进行匹配,如果匹配成功则进行下一步的关联操作*/
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
out:
mutex_unlock(&input_mutex);
return retval;
}
EXPORT_SYMBOL(input_register_handler);
/**
* input_unregister_handler - unregisters an input handler
* @handler: handler to be unregistered
*
* This function disconnects a handler from its input devices and
* removes it from lists of known handlers.
*/
/* 注销一个handler */
void input_unregister_handler(struct input_handler *handler)
{
struct input_handle *handle, *next;
mutex_lock(&input_mutex);
list_for_each_entry_safe(handle, next, &handler->h_list, h_node) /* 遍历链表handler->h_list调用handler->disconnect函数将input_dev和其对应的handler分离 */
handler->disconnect(handle);
WARN_ON(!list_empty(&handler->h_list)); /* 判断链表handler->h_list是否为空 */
list_del_init(&handler->node); /* 将节点handler->node从链表中删除,并初始化 节点handler->node*/
if (handler->fops != NULL) /* 如果handler->fops 有定义则将input_table中以下标为设备的次设备号右移5位的数组项设置为空*/
input_table[handler->minor >> 5] = NULL;
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
}
EXPORT_SYMBOL(input_unregister_handler);
/**
* input_register_handle - register a new input handle
* @handle: handle to register
*
* This function puts a new input handle onto device's
* and handler's lists so that events can flow through
* it once it is opened using input_open_device().
*
* This function is supposed to be called from handler's
* connect() method.
*/
/* 注册一个handle到输入子系统 */
int input_register_handle(struct input_handle *handle)
{
struct input_handler *handler = handle->handler; /* 获取该handle的handler指针 */
struct input_dev *dev = handle->dev; /* 获取该handle的dev指针 */
int error;
/*
* We take dev->mutex here to prevent race with
* input_release_device().
*/
error = mutex_lock_interruptible(&dev->mutex); /* 获取互斥锁 */
if (error)
return error;
list_add_tail_rcu(&handle->d_node, &dev->h_list); /* 将handle加入dev->h_list链表中 */
mutex_unlock(&dev->mutex);
/*
* Since we are supposed to be called from ->connect()
* which is mutually exclusive with ->disconnect()
* we can't be racing with input_unregister_handle()
* and so separate lock is not needed here.
*/
list_add_tail(&handle->h_node, &handler->h_list); /* 将handle加入handler->h_list 链表中*/
if (handler->start) /* 如果有定义handler->start,则调用它 */
handler->start(handle);
return 0;
}
EXPORT_SYMBOL(input_register_handle);
/**
* input_unregister_handle - unregister an input handle
* @handle: handle to unregister
*
* This function removes input handle from device's
* and handler's lists.
*
* This function is supposed to be called from handler's
* disconnect() method.
*/
/* 注销一个handle */
void input_unregister_handle(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
list_del_init(&handle->h_node); /* 将 节点handle->h_node从链表中删除,并初始化该删除的节点*/
/*
* Take dev->mutex to prevent race with input_release_device().
*/
mutex_lock(&dev->mutex);
list_del_rcu(&handle->d_node);
mutex_unlock(&dev->mutex);
synchronize_rcu();
}
EXPORT_SYMBOL(input_unregister_handle);
/* input设备的open函数,用户空间open系统调用会调用至该函数 */
static int input_open_file(struct inode *inode, struct file *file)
{
struct input_handler *handler;
const struct file_operations *old_fops, *new_fops = NULL;
int err;
lock_kernel(); /* 获取大内核所 */
/* No load-on-demand here? */
handler = input_table[iminor(inode) >> 5]; /* 以设备的次设备号右移5为引索值在input_handler数组项中查找设备的事件处理函数 (可以
看出一个handler最多可以处理32个设备节点(bit[5:0]最大等于32),以minor(inode) >> 5]作为引索,
即高3位相同的次设备号对应同一个引索)*/
if (!handler || !(new_fops = fops_get(handler->fops))) { /* 获取设备的struct input_handler fops的指针,其对应的对具体的设备操作的字符设备函数集*/
err = -ENODEV;
goto out;
}
/*
* That's _really_ odd. Usually NULL ->open means "nothing special",
* not "no device". Oh, well...
*/
if (!new_fops->open) { /* 如果设备的 struct input_handler fops->open未定义则做出错处理*/
fops_put(new_fops);
err = -ENODEV;
goto out;
}
old_fops = file->f_op; /* 保存设备文件的原来的file_operations指针 */
file->f_op = new_fops; /* 指定对设备的操作函数指针,此后都通过新的文件操作指针来操作设备 */
err = new_fops->open(inode, file); /*调用设备的file_operations结构体中open函数*/
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
out:
unlock_kernel();
return err;
}
static const struct file_operations input_fops = { /* input子系统的字符设备操作函数 */
.owner = THIS_MODULE,
.open = input_open_file,
};
static void __init input_init_abs_bypass(void)
{
const unsigned int *p;
for (p = input_abs_bypass_init_data; *p; p++)
input_abs_bypass[BIT_WORD(*p)] |= BIT_MASK(*p);
}
static int __init input_init(void)
{
int err;
input_init_abs_bypass();
err = class_register(&input_class); /* 注册一个类 */
if (err) {
printk(KERN_ERR "input: unable to register input_dev class\n");
return err;
}
err = input_proc_init(); /* 初始化proc文件系统中的 input*/
if (err)
goto fail1;
err = register_chrdev(INPUT_MAJOR, "input", &input_fops); /*注册一个字符设备,主设备号为13*/
if (err) {
printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
goto fail2;
}
return 0;
fail2: input_proc_exit();
fail1: class_unregister(&input_class);
return err;
}
static void __exit input_exit(void)
{
input_proc_exit();
unregister_chrdev(INPUT_MAJOR, "input");
class_unregister(&input_class);
}
subsys_initcall(input_init);
module_exit(input_exit);
/*************************************************************************************************************************************/
/* evdev.c */
/*
* Event char devices, giving access to raw input device events.
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
/* 该文件为输入子系统定义了默认的事件处理方法,其接收来自底层驱动的大多数事件,并使用相应的
逻辑对其进行处理;该文件从底层接收事件信息将其反应到sys文件中,用户通过sys文件系统的操作就能
够达到处理事件的能力*/
#define EVDEV_MINOR_BASE 64
#define EVDEV_MINORS 32
#define EVDEV_BUFFER_SIZE 64
#include
#include
#include
#include
#include
#include
#include
#include "input-compat.h"
struct evdev { /* 产生事件的的设备,在配对成功的时候生成,由handler->connect生成,对应的设备文件为/class/input/event(n)
如event0,这个设备是用户空间要访问的设备,可以解决它为一个虚拟设备,没有对应的硬件
,但是通过handle->dev就可以找到input_dev*/
int exist; /* 存在标志位 */
int open; /* 打开标志位 */
int minor; /* 设备的次设备号 */
char name[16]; /* 设备的名字 */
struct input_handle handle; /* 关联input_dev和input_handler的handle */
wait_queue_head_t wait; /* 等待队列,当进程读取设备而没有事件产生的时候,进程就会在其上面睡眠 */
struct evdev_client *grab; /* 设备事件处理的客户端 */
struct list_head client_list; /* 客户端链表,说明一个evdev设备可以处理多个evdev_client ,可以有多个进程访问evdev设备 */
spinlock_t client_lock; /* protects client_list */
struct mutex mutex;
struct device dev; /* 内嵌的设备模型中的设备 */
};
struct evdev_client { /* 设备事件处理的客户端 */
struct input_event buffer[EVDEV_BUFFER_SIZE]; /* 存储事件的缓冲区 */
int head; /* buffer数组的引索 */
int tail; /* buffer数组的引索,当head与tail相等的时候,说明没有事件*/
spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct fasync_struct *fasync; /* 异步通知 */
struct evdev *evdev; /* 产生事件的设备 */
struct list_head node; /* 用于形成evdev_client 链表 */
};
static struct evdev *evdev_table[EVDEV_MINORS]; /* 产生事件的设备链表 */
static DEFINE_MUTEX(evdev_table_mutex); /* 初始化互斥锁 */
/* 处理客户端 client对应的事件*/
static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
/*
* Interrupts are disabled, just acquire the lock
*/
spin_lock(&client->buffer_lock); /* 获取自旋锁 */
client->buffer[client->head++] = *event; /* 将事件放入事件缓冲区buffer中 */
client->head &= EVDEV_BUFFER_SIZE - 1;
spin_unlock(&client->buffer_lock);
kill_fasync(&client->fasync, SIGIO, POLL_IN); /* 数据已经到达,这里发送信号来异步通知应用程序事件已经发生可进行相关读写操作了 */
}
/*
* Pass incoming event to all connected clients.
*/
/* 默认的事件处理函数,会被input核心调用 来处理设备的事件*/
static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private; /* 获取指向 struct evdev的指针(在打开函数中设置了handle->private=evdev)*/
struct evdev_client *client;
struct input_event event;
/* 将传递过来的事件赋值给 input_event */
do_gettimeofday(&event.time); /* 获取事件发送时的时间 */
event.type = type;
event.code = code;
event.value = value;
rcu_read_lock();
client = rcu_dereference(evdev->grab);
if (client) /* 如果evdev绑定了client那么处理这个客户端 */
evdev_pass_event(client, &event); /* */
else
list_for_each_entry_rcu(client, &evdev->client_list, node) /* 否则遍历所有的客户端给每个客户端应用程序发送信号来以通知应用程序 */
evdev_pass_event(client, &event);
rcu_read_unlock();
wake_up_interruptible(&evdev->wait); /* 唤醒等待队列上的应用程序 */
}
/* 当打开的文件FASYNC标志被应用程序修改,则该函数就调用fasync_helper 以便从相关进行列表中增加或删除文件*/
static int evdev_fasync(int fd, struct file *file, int on)
{
struct evdev_client *client = file->private_data;
return fasync_helper(fd, file, on, &client->fasync);/* fasync_helper函数来将当前要通知的进程加入一个链表或从链表中删
除当,这取决于应用程序调用fcntl时是否设置了FASYNC标志*/
}
/* 冲洗设备 */
static int evdev_flush(struct file *file, fl_owner_t id)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
int retval;
retval = mutex_lock_interruptible(&evdev->mutex);
if (retval)
return retval;
if (!evdev->exist)
retval = -ENODEV;
else
retval = input_flush_device(&evdev->handle, file); /* 调用核心的冲洗设备函数 */
mutex_unlock(&evdev->mutex);
return retval;
}
/* 释放设备的方法 */
static void evdev_free(struct device *dev)
{
struct evdev *evdev = container_of(dev, struct evdev, dev); /* 通过struct evdev内嵌成员struct device *dev获取指向该 struct evdev 结构体的指针*/
input_put_device(evdev->handle.dev); /* 减小引用计数 */
kfree(evdev); /* 释放evdev占用的内存 */
}
/*
* Grabs an event device (along with underlying input device).
* This function is called with evdev->mutex taken.
*/
/* 强制设置一个事件设备的事件处理的的客户端程序 */
static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
{
int error;
if (evdev->grab)
return -EBUSY;
error = input_grab_device(&evdev->handle); /* 强制设置 evdev->handle->dev->grab= handle*/
if (error)
return error;
rcu_assign_pointer(evdev->grab, client); /*evdev->grab=client */
synchronize_rcu();
return 0;
}
/* 释放evdev强制设置的grab---->client */
static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
{
if (evdev->grab != client)
return -EINVAL;
rcu_assign_pointer(evdev->grab, NULL); /* 设置evdev->grab=NULL*/
synchronize_rcu();
input_release_device(&evdev->handle);
return 0;
}
/* 将evdev和client关联起来即将client挂到evdev->client_list上 */
static void evdev_attach_client(struct evdev *evdev,
struct evdev_client *client)
{
spin_lock(&evdev->client_lock);
list_add_tail_rcu(&client->node, &evdev->client_list); /* 将 client挂到evdev->client_list上 */
spin_unlock(&evdev->client_lock);
synchronize_rcu();
}
/* 将 evdev和client分离*/
static void evdev_detach_client(struct evdev *evdev,
struct evdev_client *client)
{
spin_lock(&evdev->client_lock);
list_del_rcu(&client->node); /*删除client->node 链表*/
spin_unlock(&evdev->client_lock);
synchronize_rcu();
}
/* 打开设备 */
static int evdev_open_device(struct evdev *evdev)
{
int retval;
retval = mutex_lock_interruptible(&evdev->mutex);
if (retval)
return retval;
if (!evdev->exist) /* 如果标志设备存在的标志位evdev->exist=0 */
retval = -ENODEV;
else if (!evdev->open++) { /* 如果标志设备打开的标志位evdev->open=0&&evdev->open++(增加打开计数)表示evdev是第一次打开则调用 input_open_device来打开设备*/
retval = input_open_device(&evdev->handle);
if (retval)
evdev->open--;
}
mutex_unlock(&evdev->mutex);
return retval;
}
/* 关闭设备 */
static void evdev_close_device(struct evdev *evdev)
{
mutex_lock(&evdev->mutex);
if (evdev->exist && !--evdev->open) /* 如果设备存在并且打开计数减1后为0则调用input_close_device来关闭设备 */
input_close_device(&evdev->handle);
mutex_unlock(&evdev->mutex);
}
/*
* Wake up users waiting for IO so they can disconnect from
* dead device.
*/
/* 唤醒睡眠的用户进程以至于它们能够取消和已经不存在的设备的联系 */
static void evdev_hangup(struct evdev *evdev)
{
struct evdev_client *client;
spin_lock(&evdev->client_lock);
list_for_each_entry(client, &evdev->client_list, node)
kill_fasync(&client->fasync, SIGIO, POLL_HUP); /* 遍历链表evdev->client_list,对于链表中的每个成员调用kill_fasync来异步
通知应用程序来取消和设备的连接 */
spin_unlock(&evdev->client_lock);
wake_up_interruptible(&evdev->wait); /* 唤醒 等待队列evdev->wait上的进程)*/
}
/* 关闭设备 */
static int evdev_release(struct inode *inode, struct file *file)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
mutex_lock(&evdev->mutex);
if (evdev->grab == client) /* 如果evdev有强制的设置了 client则释放它 */
evdev_ungrab(evdev, client);
mutex_unlock(&evdev->mutex);
evdev_detach_client(evdev, client); /* 将 evdev和client分离*/
kfree(client); /* 释放客户端 */
evdev_close_device(evdev); /* 关闭设备 */
put_device(&evdev->dev); /* 减小设备的引用计数 */
return 0;
}
/*open系统调用最终将调用至该函数*/
static int evdev_open(struct inode *inode, struct file *file)
{
struct evdev *evdev;
struct evdev_client *client;
int i = iminor(inode) - EVDEV_MINOR_BASE;/* 获取次设备号相对于基设备号的偏移 */
int error;
if (i >= EVDEV_MINORS)
return -ENODEV;
error = mutex_lock_interruptible(&evdev_table_mutex);
if (error)
return error;
evdev = evdev_table[i]; /* 找到设备对应的struct evdev */
if (evdev)
get_device(&evdev->dev); /* 增加设备的引用计数 */
mutex_unlock(&evdev_table_mutex);
if (!evdev)
return -ENODEV;
client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); /* 分配一个 struct evdev_client结构体*/
if (!client) {
error = -ENOMEM;
goto err_put_evdev;
}
spin_lock_init(&client->buffer_lock);
client->evdev = evdev; /* 客户端的evdev指针指向在evdev_table获取到的evdev */
evdev_attach_client(evdev, client); /* 将evdev和client关联起来即将client挂到evdev->client_list上 */
error = evdev_open_device(evdev); /* 打开设备 */
if (error)
goto err_free_client;
file->private_data = client; /* 这里是为了让用户的系统调用read等能够调用到该驱动相应的函数*/
return 0;
err_free_client:
evdev_detach_client(evdev, client);
kfree(client);
err_put_evdev:
put_device(&evdev->dev);
return error;
}
/* 对应应用程序的write系统调用 */
static ssize_t evdev_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_event event;
int retval;
retval = mutex_lock_interruptible(&evdev->mutex);
if (retval)
return retval;
if (!evdev->exist) { /* 如果设备已经不存在了则返回一个错误 */
retval = -ENODEV;
goto out;
}
while (retval < count) { /* count>0 */
if (input_event_from_user(buffer + retval, &event)) { /* 从用户空间拷贝事件 */
retval = -EFAULT;
goto out;
}
input_inject_event(&evdev->handle,
event.type, event.code, event.value);
retval += input_event_size();
}
out:
mutex_unlock(&evdev->mutex);
return retval;
}
/*获取 事件缓冲区 client->buffer里的下一个事件 */
static int evdev_fetch_next_event(struct evdev_client *client,
struct input_event *event)
{
int have_event;
spin_lock_irq(&client->buffer_lock);
have_event = client->head != client->tail; /* 如果have_event=1则说明有事件,否则说明无事件 */
if (have_event) {
*event = client->buffer[client->tail++]; /* event=数组的下一项即下一个事件 */
client->tail &= EVDEV_BUFFER_SIZE - 1;
}
spin_unlock_irq(&client->buffer_lock);
return have_event;
}
/* 读函数 */
static ssize_t evdev_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data; /* 获取struct evdev_client 的指针,在 evdev_open函数中设置了file->private_data = client*/
struct evdev *evdev = client->evdev; /* 获取struct evdev指针 */
struct input_event event;
int retval;
if (count < input_event_size()) /* 判断用户读取的数据大小是否小于事件的大小,如果小于事件的大小则返回错误码 */
return -EINVAL;
if (client->head == client->tail && evdev->exist && /* 如果没有事件并且 evdev使存在的且用户是以无阻塞的方式打开设备的,则返回错误*/
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(evdev->wait, /* 没有事件发生则将进行休眠在等待队列上,唤醒的条件是有事件到来或设备不存在了 */
client->head != client->tail || !evdev->exist);
if (retval) /* 如果能执行上面的语句说明有事件到来或者设备关闭 */
return retval;
if (!evdev->exist) /* 如果是设备不存在了则返回一个错误 */
return -ENODEV;
while (retval + input_event_size() <= count &&
evdev_fetch_next_event(client, &event)) { /*遍历 事件缓冲区 client->buffer里的每个事件 */
if (input_event_to_user(buffer + retval, &event)) /* 将事件发送到用户空间 */
return -EFAULT;
retval += input_event_size(); /* 指向下一个事件 */
}
return retval;
}
/* No kernel lock - fine */
/* 支持poll机制的函数 */
static unsigned int evdev_poll(struct file *file, poll_table *wait)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
poll_wait(file, &evdev->wait, wait); /* 调用该函数来使驱动程序向poll_table 结构添加一个等待队列*/
return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
(evdev->exist ? 0 : (POLLHUP | POLLERR));
}
#ifdef CONFIG_COMPAT
#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
#define BITS_TO_LONGS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1)
#ifdef __BIG_ENDIAN
static int bits_to_user(unsigned long *bits, unsigned int maxbit,
unsigned int maxlen, void __user *p, int compat)
{
int len, i;
if (compat) {
len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t);
if (len > maxlen)
len = maxlen;
for (i = 0; i < len / sizeof(compat_long_t); i++)
if (copy_to_user((compat_long_t __user *) p + i,
(compat_long_t *) bits +
i + 1 - ((i % 2) << 1),
sizeof(compat_long_t)))
return -EFAULT;
} else {
len = BITS_TO_LONGS(maxbit) * sizeof(long);
if (len > maxlen)
len = maxlen;
if (copy_to_user(p, bits, len))
return -EFAULT;
}
return len;
}
#else
static int bits_to_user(unsigned long *bits, unsigned int maxbit,
unsigned int maxlen, void __user *p, int compat)
{
int len = compat ?
BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t) :
BITS_TO_LONGS(maxbit) * sizeof(long);
if (len > maxlen)
len = maxlen;
return copy_to_user(p, bits, len) ? -EFAULT : len;
}
#endif /* __BIG_ENDIAN */
#else
static int bits_to_user(unsigned long *bits, unsigned int maxbit,
unsigned int maxlen, void __user *p, int compat)
{
int len = BITS_TO_LONGS(maxbit) * sizeof(long);
if (len > maxlen)
len = maxlen;
return copy_to_user(p, bits, len) ? -EFAULT : len;
}
#endif /* CONFIG_COMPAT */
static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
{
int len;
if (!str)
return -ENOENT;
len = strlen(str) + 1;
if (len > maxlen)
len = maxlen;
return copy_to_user(p, str, len) ? -EFAULT : len;
}
#define OLD_KEY_MAX 0x1ff
static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user *p, int compat_mode)
{
static unsigned long keymax_warn_time;
unsigned long *bits;
int len;
switch (_IOC_NR(cmd) & EV_MAX) {
case 0: bits = dev->evbit; len = EV_MAX; break;
case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
case EV_REL: bits = dev->relbit; len = REL_MAX; break;
case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
case EV_SW: bits = dev->swbit; len = SW_MAX; break;
default: return -EINVAL;
}
/*
* Work around bugs in userspace programs that like to do
* EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len'
* should be in bytes, not in bits.
*/
if ((_IOC_NR(cmd) & EV_MAX) == EV_KEY && _IOC_SIZE(cmd) == OLD_KEY_MAX) {
len = OLD_KEY_MAX;
if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
printk(KERN_WARNING
"evdev.c(EVIOCGBIT): Suspicious buffer size %u, "
"limiting output to %zu bytes. See "
"http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",
OLD_KEY_MAX,
BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
}
return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
}
#undef OLD_KEY_MAX
/* 执行ioctl函数 */
static long evdev_do_ioctl(struct file *file, unsigned int cmd,
void __user *p, int compat_mode)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_dev *dev = evdev->handle.dev;
struct input_absinfo abs;
struct ff_effect effect;
int __user *ip = (int __user *)p;
int i, t, u, v;
int error;
switch (cmd) {
case EVIOCGVERSION: /* 获取驱动的版本信息 */
return put_user(EV_VERSION, ip); /* 将驱动的版本信息拷贝到用户空间 */
case EVIOCGID: /* 获取设备的ID */
if (copy_to_user(p, &dev->id, sizeof(struct input_id))) /* 将dev->id拷贝到用户空间 */
return -EFAULT;
return 0;
case EVIOCGREP: /* 获取重复类事件的设置 */
if (!test_bit(EV_REP, dev->evbit))
return -ENOSYS;
if (put_user(dev->rep[REP_DELAY], ip))
return -EFAULT;
if (put_user(dev->rep[REP_PERIOD], ip + 1))
return -EFAULT;
return 0;
case EVIOCSREP: /* 设置重复类事件 */
if (!test_bit(EV_REP, dev->evbit))
return -ENOSYS;
if (get_user(u, ip))
return -EFAULT;
if (get_user(v, ip + 1))
return -EFAULT;
input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
return 0;
case EVIOCGKEYCODE: /* 获取键值 */
if (get_user(t, ip))
return -EFAULT;
error = input_get_keycode(dev, t, &v); /* 调用输入子系统核心的函数input_get_keycode来获取键值 */
if (error)
return error;
if (put_user(v, ip + 1))
return -EFAULT;
return 0;
case EVIOCSKEYCODE: /* 设置键值 */
if (get_user(t, ip) || get_user(v, ip + 1))
return -EFAULT;
return input_set_keycode(dev, t, v);
case EVIOCRMFF:
return input_ff_erase(dev, (int)(unsigned long) p, file);
case EVIOCGEFFECTS:
i = test_bit(EV_FF, dev->evbit) ?
dev->ff->max_effects : 0;
if (put_user(i, ip))
return -EFAULT;
return 0;
case EVIOCGRAB:
if (p)
return evdev_grab(evdev, client);
else
return evdev_ungrab(evdev, client);
default:
if (_IOC_TYPE(cmd) != 'E')
return -EINVAL;
if (_IOC_DIR(cmd) == _IOC_READ) { /* 判断是否为读命令 */
if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))
return handle_eviocgbit(dev, cmd, p, compat_mode);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
p, compat_mode);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
p, compat_mode);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
p, compat_mode);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
p, compat_mode);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
return str_to_user(dev->name, _IOC_SIZE(cmd), p);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
t = _IOC_NR(cmd) & ABS_MAX;
abs.value = dev->abs[t];
abs.minimum = dev->absmin[t];
abs.maximum = dev->absmax[t];
abs.fuzz = dev->absfuzz[t];
abs.flat = dev->absflat[t];
if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
return -EFAULT;
return 0;
}
}
if (_IOC_DIR(cmd) == _IOC_WRITE) {
if (_IOC_NR(cmd) == _IOC_NR(EVIOCSFF)) {
if (input_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect))
return -EFAULT;
error = input_ff_upload(dev, &effect, file);
if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
return -EFAULT;
return error;
}
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
t = _IOC_NR(cmd) & ABS_MAX;
if (copy_from_user(&abs, p,
sizeof(struct input_absinfo)))
return -EFAULT;
/*
* Take event lock to ensure that we are not
* changing device parameters in the middle
* of event.
*/
spin_lock_irq(&dev->event_lock);
dev->abs[t] = abs.value;
dev->absmin[t] = abs.minimum;
dev->absmax[t] = abs.maximum;
dev->absfuzz[t] = abs.fuzz;
dev->absflat[t] = abs.flat;
spin_unlock_irq(&dev->event_lock);
return 0;
}
}
}
return -EINVAL;
}
/* evdev的ioctl处理函数 */
static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
void __user *p, int compat_mode)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
int retval;
retval = mutex_lock_interruptible(&evdev->mutex);
if (retval)
return retval;
if (!evdev->exist) { /* 如果设备已经不存在则返回 */
retval = -ENODEV;
goto out;
}
retval = evdev_do_ioctl(file, cmd, p, compat_mode);
out:
mutex_unlock(&evdev->mutex);
return retval;
}
/* 系统调用ioctl最终将会调用至该函数 */
static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0);
}
#ifdef CONFIG_COMPAT
static long evdev_ioctl_compat(struct file *file,
unsigned int cmd, unsigned long arg)
{
return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1);
}
#endif
static const struct file_operations evdev_fops = { /* 用户的open、read等系统调用最终将调用这些函数 */
.owner = THIS_MODULE,
.read = evdev_read,
.write = evdev_write,
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
.unlocked_ioctl = evdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = evdev_ioctl_compat,
#endif
.fasync = evdev_fasync,
.flush = evdev_flush
};
static int evdev_install_chrdev(struct evdev *evdev)
{
/*
* No need to do any locking here as calls to connect and
* disconnect are serialized by the input core
*/
evdev_table[evdev->minor] = evdev;
return 0;
}
/* 从 evdev_table中将相应的数组项删除*/
static void evdev_remove_chrdev(struct evdev *evdev)
{
/*
* Lock evdev table to prevent race with evdev_open()
*/
mutex_lock(&evdev_table_mutex);
evdev_table[evdev->minor] = NULL;
mutex_unlock(&evdev_table_mutex);
}
/*
* Mark device non-existent. This disables writes, ioctls and
* prevents new users from opening the device. Already posted
* blocking reads will stay, however new ones will fail.
*/
/* 标记evdev已经不存在了 */
static void evdev_mark_dead(struct evdev *evdev)
{
mutex_lock(&evdev->mutex);
evdev->exist = 0;
mutex_unlock(&evdev->mutex);
}
/* 完成evdev的清理工作 */
static void evdev_cleanup(struct evdev *evdev)
{
struct input_handle *handle = &evdev->handle;
evdev_mark_dead(evdev); /* 标记evdev已经不存在了 */
evdev_hangup(evdev); /* 异步通知应用程序该设备已经死亡 */
evdev_remove_chrdev(evdev); /* 从 evdev_table中将相应的数组项删除*/
/* evdev is marked dead so no one else accesses evdev->open */
if (evdev->open) { /* 如果设备还在打开中,则刷新设备同时关闭设备 */
input_flush_device(handle, NULL);
input_close_device(handle);
}
}
/*
* Create new evdev device. Note that input core serializes calls
* to connect and disconnect so we don't need to lock evdev_table here.
*/
/* 默认的函数用来连接handler和input_dev,在input_attach_handler函数当设备与handler匹配后被调用*/
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
struct evdev *evdev;
int minor;
int error;
for (minor = 0; minor < EVDEV_MINORS; minor++) /* 遍历evdev_table数组,遍历到数组项为空则返回(EVDEV_MINORS=32,表示evdev_handler 所表示的32个设备文件)*/
if (!evdev_table[minor])
break;
if (minor == EVDEV_MINORS) { /* 如果数组evdev_table没有空项则做出错处理 */
printk(KERN_ERR "evdev: no more free evdev devices\n");
return -ENFILE;
}
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); /* 分配并初始化一个struct evdev */
if (!evdev)
return -ENOMEM;
INIT_LIST_HEAD(&evdev->client_list); /* 初始化 evdev->client_list链表头*/
spin_lock_init(&evdev->client_lock); /* 初始化自旋锁evdev->client_lock */
mutex_init(&evdev->mutex); /* 初始化互斥体evdev->mutex*/
init_waitqueue_head(&evdev->wait); /* 初始化等待队列头 */
snprintf(evdev->name, sizeof(evdev->name), "event%d", minor); /* evdev->name= event%d,%d=minor,最大有32个设备,这个设备将
在/dev/input/目录下显示,例如event0、event1.....*/
evdev->exist = 1; /* 置位标志位exist */
evdev->minor = minor; /* 将遍历数组evdev_table的第一个空项的下标的值作为次设备,赋值为 evdev->minor */
evdev->handle.dev = input_get_device(dev); /* 主要是增加struct input_dev *dev->dev引用计数同时将input_dev的指针赋值给handle的dev字段 */
evdev->handle.name = evdev->name;
evdev->handle.handler = handler; /* 将参数handler赋值给 evdev->handle.handler,这样就通过input_handle将input_dev和input_handler联系起来了*/
evdev->handle.private = evdev; /* input_handle的私有数据字段指向evdev */
dev_set_name(&evdev->dev, evdev->name); /*实际是 evdev->dev->kobj->name-= evdev->name*/
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); /* 可以看出设备的次设备号为64+minor,minor<32 */
evdev->dev.class = &input_class; /* 初始化类 即evdev->dev.class指向输入子系统核心的input_class*/
evdev->dev.parent = &dev->dev; /* evdev->dev.parent (设备的父节点)指向 struct input_dev *dev->dev*/
evdev->dev.release = evdev_free; /* 设备的释放方法,所有向核心注册的device结构都必须要提供该方法 */
device_initialize(&evdev->dev);
error = input_register_handle(&evdev->handle); /* 向输入子系统核心注册一个handle */
if (error)
goto err_free_evdev;
error = evdev_install_chrdev(evdev); /* evdev_table[evdev->minor] = evdev---->将设置好的evdev存放到数组struct evdev *evdev_table[]中*/
if (error)
goto err_unregister_handle;
error = device_add(&evdev->dev); /* 向设备模型中添加一个设备 */
if (error)
goto err_cleanup_evdev;
return 0;
err_cleanup_evdev:
evdev_cleanup(evdev);
err_unregister_handle:
input_unregister_handle(&evdev->handle);
err_free_evdev:
put_device(&evdev->dev);
return error;
}
/* 该函数用来断开handler和input_dev*/
static void evdev_disconnect(struct input_handle *handle)
{
struct evdev *evdev = handle->private;
device_del(&evdev->dev); /* 从驱动核心移除设备 */
evdev_cleanup(evdev); /* 完成evdev的清理工作 */
input_unregister_handle(handle); /* 向input子系统注销该handle */
put_device(&evdev->dev); /* 减少设备的引用计数 */
}
static const struct input_device_id evdev_ids[] = { /* 默认的驱动所能处理的设备 ID 表 */
{ .driver_info = 1 }, /* Matches all devices */ /* 没有定义flags,也就是表示能支持所有的输入设备发出的事件 */
{ }, /* Terminating zero entry */
};
MODULE_DEVICE_TABLE(input, evdev_ids);
static struct input_handler evdev_handler = { /* 默认的事件处理handler */
.event = evdev_event, /* 默认的事件处理函数,会被input核心调用 来处理设备的事件*/
.connect = evdev_connect, /* 默认的函数用来连接handler和input_dev,在input_attach_handler函数被调用*/
.disconnect = evdev_disconnect, /* 默认的函数用来断开handler和input_dev*/
.fops = &evdev_fops, /* 默认的输入设备作为字符设备的操作函数 */
.minor = EVDEV_MINOR_BASE, /*默认的 输入设备的基设备次设备号 (设备所能处理的设备文件的主次设备号的范围为(13,64)~(13,64+32))*/
.name = "evdev", /* 默认的名字 */
.id_table = evdev_ids, /*默认的驱动所能处理的设备 ID 表指针,其能与input->id匹配则表示该handler能够支持该设备*/
};
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler); /* 注册一个handler */
}
static void __exit evdev_exit(void)
{
input_unregister_handler(&evdev_handler); /* 注销一个handler */
}
module_init(evdev_init);
module_exit(evdev_exit);
MODULE_AUTHOR("Vojtech Pavlik
MODULE_DESCRIPTION("Input driver event char devices");
MODULE_LICENSE("GPL");
/*************************************************************************************************************************************/
/* mousedev.c */
/*
* Input driver to ExplorerPS/2 device driver module.
*
* Copyright (c) 1999-2002 Vojtech Pavlik
* Copyright (c) 2004 Dmitry Torokhov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
/* 该文件定义了鼠标事件的处理函数 */
#define MOUSEDEV_MINOR_BASE 32 /* 鼠标设备的基次设备号 */
#define MOUSEDEV_MINORS 32 /* 鼠标设备的次设备号 */
#define MOUSEDEV_MIX 31 /* 混合的鼠标设备的次设备号*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
#include
#endif
MODULE_AUTHOR("Vojtech Pavlik
MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces");
MODULE_LICENSE("GPL");
#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
#define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
#endif
#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y
#define CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
#endif
static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X; /* xres=1024*/
module_param(xres, uint, 0644);
MODULE_PARM_DESC(xres, "Horizontal screen resolution");
static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; /* yres=768*/
module_param(yres, uint, 0644);
MODULE_PARM_DESC(yres, "Vertical screen resolution");
static unsigned tap_time = 200;
module_param(tap_time, uint, 0644);
MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)");
struct mousedev_hw_data { /* 鼠标设备的硬件数据 */
int dx, dy, dz; /*上报的事件的 x,y,z方向的相对位移*/
int x, y; /* 上报的事件的x,y方向的坐标 */
int abs_event; /* 绝对位移类事件标志位 */
unsigned long buttons; /* 按键类事件 */
};
struct mousedev { /* 鼠标设备 */
int exist; /* 设备是否存在标志位 */
int open; /* 设备是否打开标志位 */
int minor ;/* 设备的次设备号 */
char name[16];/*设备的名字 */
struct input_handle handle; /* 设备的handle */
wait_queue_head_t wait; /* 等待队列 */
struct list_head client_list; /* 设备的client链表 */
spinlock_t client_lock; /* protects client_list *//* 链表client_list 访问控制的自旋锁 */
struct mutex mutex; /* 互斥体 */
struct device dev; /*内嵌的设备 */
struct list_head mixdev_node; /* 混杂设备链表 */
int mixdev_open; /* 混杂设备的打开标志位 */
struct mousedev_hw_data packet; /* 鼠标设备的硬件数据包*/
unsigned int pkt_count; /* 数据包的数量 */
int old_x[4], old_y[4]; /* 触摸板是坐标 */
int frac_dx, frac_dy; /* */
unsigned long touch; /*触摸板事件标志位 */
};
enum mousedev_emul {
MOUSEDEV_EMUL_PS2, /*ps/2接口 */
MOUSEDEV_EMUL_IMPS,
MOUSEDEV_EMUL_EXPS
};
struct mousedev_motion { /*鼠标设备的动作 */
int dx, dy, dz; /* x,y,z方向的最小分别率 */
unsigned long buttons; /* 按键类事件 */
};
#define PACKET_QUEUE_LEN 16
struct mousedev_client { /*鼠标设备的客户端 */
struct fasync_struct *fasync; /* 异步通知结构指针 */
struct mousedev *mousedev; /* 指向鼠标设备 */
struct list_head node; /* 用于形成链表 */
struct mousedev_motion packets[PACKET_QUEUE_LEN]; /*鼠标设备的动作数组 ,用于形成环形缓冲区*/
unsigned int head, tail; /* 访问数组的引索 */
spinlock_t packet_lock; /* 访问数组的锁*/
int pos_x, pos_y; /*上一次 x,y坐标的位置 */
signed char ps2[6];
unsigned char ready, buffer, bufsiz; /* ready用来标识数据是否已经准备好,buffer是数组 ps2[6]的引索,bufsiz引索的上限值 */
unsigned char imexseq, impsseq; /* imexseq为数组 mousedev_imex_seq[] 的引索,impsseq为数组 mousedev_imps_seq的引索*/
enum mousedev_emul mode;
unsigned long last_buttons;
};
#define MOUSEDEV_SEQ_LEN 6
static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
static struct input_handler mousedev_handler; /* 鼠标设备的handler */
static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; /* 设备数组 */
static DEFINE_MUTEX(mousedev_table_mutex);
static struct mousedev *mousedev_mix; /* 鼠标设备 */
static LIST_HEAD(mousedev_mix_list); /* 设备链表 */
static void mixdev_open_devices(void);
static void mixdev_close_devices(void);
#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
/* 触摸板事件处理函数 */
static void mousedev_touchpad_event(struct input_dev *dev,
struct mousedev *mousedev,
unsigned int code, int value)
{
int size, tmp;
enum { FRACTION_DENOM = 128 };
switch (code) {
case ABS_X:
fx(0) = value;
if (mousedev->touch && mousedev->pkt_count >= 2) {
size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
if (size == 0)
size = 256 * 2;
tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size;
tmp += mousedev->frac_dx;
mousedev->packet.dx = tmp / FRACTION_DENOM;
mousedev->frac_dx =
tmp - mousedev->packet.dx * FRACTION_DENOM;
}
break;
case ABS_Y:
fy(0) = value;
if (mousedev->touch && mousedev->pkt_count >= 2) {
/* use X size to keep the same scale */
size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
if (size == 0)
size = 256 * 2;
tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size;
tmp += mousedev->frac_dy;
mousedev->packet.dy = tmp / FRACTION_DENOM;
mousedev->frac_dy = tmp -
mousedev->packet.dy * FRACTION_DENOM;
}
break;
}
}
/* 处理绝对位移类事件 */
static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
unsigned int code, int value)
{
int size;
switch (code) {
case ABS_X: /* x方向的绝对位移 */
size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; /* 获取x的方向的位移范围 */
if (size == 0)
size = xres ? : 1;
if (value > dev->absmax[ABS_X]) /* 如果坐标值大于设置的最大绝对位移,则只取最大位移 */
value = dev->absmax[ABS_X];
if (value < dev->absmin[ABS_X]) /* 如果坐标值小于设置的最小绝对位移,则只取最小位移 */
value = dev->absmin[ABS_X];
mousedev->packet.x =
((value - dev->absmin[ABS_X]) * xres) / size; /* 计算转换x方向的坐标 */
mousedev->packet.abs_event = 1; /* 标志产生了绝对位移类事件 */
break;
case ABS_Y: /*y方向的绝对位移 */
size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];/* 获取y的方向的位移范围 */
if (size == 0)
size = yres ? : 1;
if (value > dev->absmax[ABS_Y]) /* 如果坐标值大于设置的最大绝对位移,则只取最大位移 */
value = dev->absmax[ABS_Y];
if (value < dev->absmin[ABS_Y]) /* 如果坐标值小于设置的最小绝对位移,则只取最小位移 */
value = dev->absmin[ABS_Y];
mousedev->packet.y = yres -
((value - dev->absmin[ABS_Y]) * yres) / size; /* 计算转换y方向的坐标 */
mousedev->packet.abs_event = 1;/* 标志产生了绝对位移类事件 */
break;
}
}
/* 处理相对位移类事件 */
static void mousedev_rel_event(struct mousedev *mousedev,
unsigned int code, int value)
{
switch (code) {
case REL_X: /* x方向的相对位移 */
mousedev->packet.dx += value; /* 在原来的坐标的基础上加上相对位移即可 */
break;
case REL_Y: /* y方向的相对位移 */
mousedev->packet.dy -= value;
break;
case REL_WHEEL: /* 滚轮的相对位移 */
mousedev->packet.dz -= value;
break;
}
}
/* 处理按键类事件*/
static void mousedev_key_event(struct mousedev *mousedev,
unsigned int code, int value)
{
int index;
switch (code) {
case BTN_TOUCH:
case BTN_0:
case BTN_LEFT: index = 0; break; /* 左键事件 */
case BTN_STYLUS:
case BTN_1:
case BTN_RIGHT: index = 1; break; /* 右键事件 */
case BTN_2:
case BTN_FORWARD:
case BTN_STYLUS2:
case BTN_MIDDLE: index = 2; break; /* 中键事件 */
case BTN_3:
case BTN_BACK:
case BTN_SIDE: index = 3; break; /*一些鼠标支持的其他事件 */
case BTN_4:
case BTN_EXTRA: index = 4; break; /*一些鼠标支持的额外事件 */
default: return;
}
/*mousedev->packet.buttons 的bit[0]=1代表左键事件, bit[1]=1代表右键事件,bit[2]=1代表中键事件, bit[3]=1代表一些鼠标
支持的其他事件 , bit[4]=1代表一些鼠标支持的额外事件 */
if (value) {
set_bit(index, &mousedev->packet.buttons);
set_bit(index, &mousedev_mix->packet.buttons);
} else {
clear_bit(index, &mousedev->packet.buttons);
clear_bit(index, &mousedev_mix->packet.buttons);
}
}
/* 向 mousedev->client_list链表上挂接的每个client拷贝鼠标信息,最后通知读取事件的进程 */
static void mousedev_notify_readers(struct mousedev *mousedev,
struct mousedev_hw_data *packet)
{
struct mousedev_client *client;
struct mousedev_motion *p;
unsigned int new_head;
int wake_readers = 0;
rcu_read_lock();
list_for_each_entry_rcu(client, &mousedev->client_list, node) { /* 遍历mousedev->client_list链表 */
/* Just acquire the lock, interrupts already disabled */
spin_lock(&client->packet_lock);
p = &client->packets[client->head]; /* 取出鼠标的动作的数据 */
if (client->ready && p->buttons != mousedev->packet.buttons) { /* 客户端程序已经准备好了并且 */
new_head = (client->head + 1) % PACKET_QUEUE_LEN; /* 指向下一个包 */
if (new_head != client->tail) { /* 还没到包尾*/
p = &client->packets[client->head = new_head]; /* 取出下一个包 */
memset(p, 0, sizeof(struct mousedev_motion)); /* 将p指向的包内容清零 */
}
}
if (packet->abs_event) { /* 是绝对位移类事件 */
p->dx += packet->x - client->pos_x; /* x方向的相对位移量为 上报的是x方向的坐标减去上一次的x的坐标*/
p->dy += packet->y - client->pos_y; /* y方向的相对位移量为 上报的是y方向的坐标减去上一次的y的坐标*/
client->pos_x = packet->x; /* 更新上一次的x方向 的坐标*/
client->pos_y = packet->y; /* 更新上一次的y方向 的坐标*/
}
/* 否则不是绝对位移类事件则更新 client->pos_x和client->pos_y */
client->pos_x += packet->dx; /* 上一次的x方向的坐标加上这次事件坐标的相对位移----->就是新的x方向坐标 */
client->pos_x = client->pos_x < 0 ? /* 对x方向的坐标做合法性检查 */
0 : (client->pos_x >= xres ? xres : client->pos_x);
client->pos_y += packet->dy; /* 上一次的y方向的坐标加上这次事件坐标的相对位移----->就是新的y方向坐标 */
client->pos_y = client->pos_y < 0 ? /* 对y方向的坐标做合法性检查 */
0 : (client->pos_y >= yres ? yres : client->pos_y);
/* 更新struct mousedev_motion */
p->dx += packet->dx;
p->dy += packet->dy;
p->dz += packet->dz;
p->buttons = mousedev->packet.buttons;
if (p->dx || p->dy || p->dz ||
p->buttons != client->last_buttons)
client->ready = 1; /* 如果相对位移不为0并且是新的按键事件则设置数据已经准备,客户端可以读取数据了 */
spin_unlock(&client->packet_lock);
if (client->ready) { /* 客户端程序已经准备好了 */
kill_fasync(&client->fasync, SIGIO, POLL_IN); /* 通知应用程序可以读取数据了 */
wake_readers = 1; /* 置位唤醒用户进程的标志位 */
}
}
rcu_read_unlock();
if (wake_readers)
wake_up_interruptible(&mousedev->wait); /* 唤醒等待队列mousedev->wait上的进程 */
}
static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
{
if (!value) {
if (mousedev->touch &&
time_before(jiffies,
mousedev->touch + msecs_to_jiffies(tap_time))) {
/*
* Toggle left button to emulate tap.
* We rely on the fact that mousedev_mix always has 0
* motion packet so we won't mess current position.
*/
set_bit(0, &mousedev->packet.buttons);
set_bit(0, &mousedev_mix->packet.buttons);
mousedev_notify_readers(mousedev, &mousedev_mix->packet);
mousedev_notify_readers(mousedev_mix,
&mousedev_mix->packet);
clear_bit(0, &mousedev->packet.buttons);
clear_bit(0, &mousedev_mix->packet.buttons);
}
mousedev->touch = mousedev->pkt_count = 0;
mousedev->frac_dx = 0;
mousedev->frac_dy = 0;
} else if (!mousedev->touch)
mousedev->touch = jiffies;
}
/* 鼠标设备事件处理函数 */
static void mousedev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct mousedev *mousedev = handle->private;
switch (type) {
case EV_ABS: /* 绝对位移类事件 */
/* Ignore joysticks */
if (test_bit(BTN_TRIGGER, handle->dev->keybit))
return;
if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
mousedev_touchpad_event(handle->dev,
mousedev, code, value);
else
mousedev_abs_event(handle->dev, mousedev, code, value); /* 处理绝对位移类事件 */
break;
case EV_REL: /* 相对位移类事件 */
mousedev_rel_event(mousedev, code, value);
break;
case EV_KEY: /* 按键类事件 */
if (value != 2) {
if (code == BTN_TOUCH &&
test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
mousedev_touchpad_touch(mousedev, value);
else
mousedev_key_event(mousedev, code, value); /* 处理鼠标事件 */
}
break;
case EV_SYN: /* 同步类事件 */
if (code == SYN_REPORT) {
if (mousedev->touch) {
mousedev->pkt_count++;
/*
* Input system eats duplicate events,
* but we need all of them to do correct
* averaging so apply present one forward
*/
fx(0) = fx(1);
fy(0) = fy(1);
}
/* 通知读取数据的应用程序进程 */
mousedev_notify_readers(mousedev, &mousedev->packet);
mousedev_notify_readers(mousedev_mix, &mousedev->packet);
mousedev->packet.dx = mousedev->packet.dy =
mousedev->packet.dz = 0; /* 设置相对偏移量为0并且清除绝对位移类事件的标志位 */
mousedev->packet.abs_event = 0;
}
break;
}
}
static int mousedev_fasync(int fd, struct file *file, int on) /* 支持异步通知 */
{
struct mousedev_client *client = file->private_data;
return fasync_helper(fd, file, on, &client->fasync);
}
/* 释放mousedev */
static void mousedev_free(struct device *dev)
{
struct mousedev *mousedev = container_of(dev, struct mousedev, dev);
input_put_device(mousedev->handle.dev); /* 增加引用计数 */
kfree(mousedev); /* 释放mousedev */
}
/* 打开设备 */
static int mousedev_open_device(struct mousedev *mousedev)
{
int retval;
retval = mutex_lock_interruptible(&mousedev->mutex);
if (retval)
return retval;
if (mousedev->minor == MOUSEDEV_MIX)
mixdev_open_devices();
else if (!mousedev->exist)
retval = -ENODEV;
else if (!mousedev->open++) { /* 如果设备是第一次打开则调用 input核心的input_open_device来打开设备*/
retval = input_open_device(&mousedev->handle);
if (retval)
mousedev->open--;
}
mutex_unlock(&mousedev->mutex);
return retval;
}
/* 关闭设备 */
static void mousedev_close_device(struct mousedev *mousedev)
{
mutex_lock(&mousedev->mutex);
if (mousedev->minor == MOUSEDEV_MIX)
mixdev_close_devices();
else if (mousedev->exist && !--mousedev->open) /* 如果设备还存在并且打开计数为1则调用input核心的input_close_device来关闭设备 */
input_close_device(&mousedev->handle);
mutex_unlock(&mousedev->mutex);
}
/*
* Open all available devices so they can all be multiplexed in one.
* stream. Note that this function is called with mousedev_mix->mutex
* held.
*/
static void mixdev_open_devices(void)
{
struct mousedev *mousedev;
if (mousedev_mix->open++)
return;
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { /* 遍历 mousedev_mix_list链表如果设备未被打开,则打开它*/
if (!mousedev->mixdev_open) {
if (mousedev_open_device(mousedev))
continue;
mousedev->mixdev_open = 1;
}
}
}
/*
* Close all devices that were opened as part of multiplexed
* device. Note that this function is called with mousedev_mix->mutex
* held.
*/
static void mixdev_close_devices(void)
{
struct mousedev *mousedev;
if (--mousedev_mix->open)
return;
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
if (!mousedev->mixdev_open) {
if (mousedev->mixdev_open) {
mousedev->mixdev_open = 0;
mousedev_close_device(mousedev);
}
}
}
/* 将mousedev和client 联系起来*/
static void mousedev_attach_client(struct mousedev *mousedev,
struct mousedev_client *client)
{
spin_lock(&mousedev->client_lock);
list_add_tail_rcu(&client->node, &mousedev->client_list); /* 将client->node插入 mousedev->client_list*/
spin_unlock(&mousedev->client_lock);
synchronize_rcu();
}
static void mousedev_detach_client(struct mousedev *mousedev,
struct mousedev_client *client)
{
spin_lock(&mousedev->client_lock);
list_del_rcu(&client->node); /* 删除 client->node链表*/
spin_unlock(&mousedev->client_lock);
synchronize_rcu();
}
/* 释放设备 */
static int mousedev_release(struct inode *inode, struct file *file)
{
struct mousedev_client *client = file->private_data;
struct mousedev *mousedev = client->mousedev;
mousedev_detach_client(mousedev, client); /* 取消 mousedev和client之间的联系*/
kfree(client); /* 释放客户端结构 */
mousedev_close_device(mousedev); /* 关闭设备 */
put_device(&mousedev->dev); /* 减少设备的引用计数 */
return 0;
}
/* 打开鼠标设备函数 */
static int mousedev_open(struct inode *inode, struct file *file)
{
struct mousedev_client *client;
struct mousedev *mousedev;
int error;
int i;
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (imajor(inode) == MISC_MAJOR)
i = MOUSEDEV_MIX;
else
#endif
i = iminor(inode) - MOUSEDEV_MINOR_BASE; /* 获取此设备号相对于基此设备号的偏移量 */
if (i >= MOUSEDEV_MINORS)
return -ENODEV;
lock_kernel();
error = mutex_lock_interruptible(&mousedev_table_mutex);
if (error) {
unlock_kernel();
return error;
}
mousedev = mousedev_table[i]; /* 获取数组mousedev_table对应的struct mousedev数组项 */
if (mousedev)
get_device(&mousedev->dev); /* 增加设备的引用计数 */
mutex_unlock(&mousedev_table_mutex);
if (!mousedev) {
unlock_kernel();
return -ENODEV;
}
client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); /* 分配一个struct mousedev_client结构体 */
if (!client) {
error = -ENOMEM;
goto err_put_mousedev;
}
spin_lock_init(&client->packet_lock);
client->pos_x = xres / 2; /* 初始化client->pos_x 为512 即初始化鼠标x方向的初始位置*/
client->pos_y = yres / 2; /* 初始化client->pos_y为 384 即初始化鼠标y方向的初始位置*/
client->mousedev = mousedev; /* 指向与之相关联的设备 */
mousedev_attach_client(mousedev, client); /* 将mousedev和client 联系起来*/
error = mousedev_open_device(mousedev); /* 打开设备 */
if (error)
goto err_free_client;
file->private_data = client; /* 将client保存到 file->private_data,这样可方便在其他的函数中使用*/
unlock_kernel();
return 0;
err_free_client:
mousedev_detach_client(mousedev, client);
kfree(client);
err_put_mousedev:
put_device(&mousedev->dev);
unlock_kernel();
return error;
}
static inline int mousedev_limit_delta(int delta, int limit) /* 取-limit
return delta > limit ? limit : (delta < -limit ? -limit : delta);
}
/* 构造包 */
static void mousedev_packet(struct mousedev_client *client,
signed char *ps2_data)
{
struct mousedev_motion *p = &client->packets[client->tail]; /* 获取有效的数据包的后面一个包指针 */
/*
*如果p->dx < 0 ,p->dy < 0 则ps2_data[0] =0x38|(p->buttons & 0x07)
*如果p->dx < 0, p->dy >= 0则ps2_data[0] =0x18|(p->buttons & 0x07)
*如果p->dx >=0,p->dy < 0 则ps2_data[0] =0x28|(p->buttons & 0x07)
*如果p->dx >=0,p->dy >= 0则ps2_data[0] =0x08|(p->buttons & 0x07)
*/
ps2_data[0] = 0x08 |
((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
/* 对数据进行检查 */
ps2_data[1] = mousedev_limit_delta(p->dx, 127); /* 如果 -127<=p->dx<=127则ps2_data[1]=p->dx,否则ps2_data[1]=+-127*/
ps2_data[2] = mousedev_limit_delta(p->dy, 127);
/*更新 p->dx p->dy*/
p->dx -= ps2_data[1];
p->dy -= ps2_data[2];
switch (client->mode) {
case MOUSEDEV_EMUL_EXPS:
ps2_data[3] = mousedev_limit_delta(p->dz, 7); /* 如果 -7<=p->dx<=7则ps2_data[1]=p->dz,否则ps2_data[1]=+-7*/
p->dz -= ps2_data[3]; /*更新 p->dz*/
ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
client->bufsiz = 4;
break;
case MOUSEDEV_EMUL_IMPS:
ps2_data[0] |=
((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
ps2_data[3] = mousedev_limit_delta(p->dz, 127);
p->dz -= ps2_data[3];
client->bufsiz = 4;
break;
case MOUSEDEV_EMUL_PS2:
default:
ps2_data[0] |=
((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
p->dz = 0;
client->bufsiz = 3;
break;
}
if (!p->dx && !p->dy && !p->dz) { /* 说明鼠标没有移动 */
if (client->tail == client->head) { /* 说明数据包无数据 */
client->ready = 0;
client->last_buttons = p->buttons;
} else
client->tail = (client->tail + 1) % PACKET_QUEUE_LEN; /* 更新 */
}
}
/* 向client->ps2[6]缓冲区填充数据,有效数据的个数为client->bufsiz,之后执行如下赋值client->buffer = client->bufsiz;让client->buffer等
于client->ps2[6]数据缓冲区中有效数据的个数*/
static void mousedev_generate_response(struct mousedev_client *client,
int command)
{
client->ps2[0] = 0xfa; /* ACK */
switch (command) {
case 0xeb: /* Poll */
mousedev_packet(client, &client->ps2[1]);
client->bufsiz++; /* account for leading ACK */
break;
case 0xf2: /* Get ID */
switch (client->mode) {
case MOUSEDEV_EMUL_PS2:
client->ps2[1] = 0;
break;
case MOUSEDEV_EMUL_IMPS:
client->ps2[1] = 3;
break;
case MOUSEDEV_EMUL_EXPS:
client->ps2[1] = 4;
break;
}
client->bufsiz = 2;
break;
case 0xe9: /* Get info */
client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
client->bufsiz = 4;
break;
case 0xff: /* Reset */
client->impsseq = client->imexseq = 0;
client->mode = MOUSEDEV_EMUL_PS2;
client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
client->bufsiz = 3;
break;
default:
client->bufsiz = 1;
break;
}
client->buffer = client->bufsiz;
}
/* 向鼠标设备写入数据 */
static ssize_t mousedev_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct mousedev_client *client = file->private_data;
unsigned char c;
unsigned int i;
for (i = 0; i < count; i++) {
if (get_user(c, buffer + i)) /* 从用户空间拷贝一个字节的数据 -----命令*/
return -EFAULT;
spin_lock_irq(&client->packet_lock);
if (c == mousedev_imex_seq[client->imexseq]) {
if (++client->imexseq == MOUSEDEV_SEQ_LEN) {
client->imexseq = 0;
client->mode = MOUSEDEV_EMUL_EXPS;
}
} else
client->imexseq = 0;
if (c == mousedev_imps_seq[client->impsseq]) {
if (++client->impsseq == MOUSEDEV_SEQ_LEN) {
client->impsseq = 0;
client->mode = MOUSEDEV_EMUL_IMPS;
}
} else
client->impsseq = 0;
mousedev_generate_response(client, c);
spin_unlock_irq(&client->packet_lock);
}
kill_fasync(&client->fasync, SIGIO, POLL_IN); /* 发出异步通知可以写入数据了 */
wake_up_interruptible(&client->mousedev->wait); /* 唤醒等待队列上的进程 */
return count;
}
/* 读数据 */
static ssize_t mousedev_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct mousedev_client *client = file->private_data;
struct mousedev *mousedev = client->mousedev;
signed char data[sizeof(client->ps2)];
int retval = 0;
if (!client->ready && !client->buffer && mousedev->exist &&
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(mousedev->wait, /* 休眠等待上的进程,唤醒的条件是设备不存在或数据已经准
备好或缓冲区中已经有数据 */
!mousedev->exist || client->ready || client->buffer);
if (retval)
return retval;
if (!mousedev->exist)
return -ENODEV;
spin_lock_irq(&client->packet_lock);
if (!client->buffer && client->ready) {
mousedev_packet(client, client->ps2);
client->buffer = client->bufsiz; /* 更新引索数组ps2引索指针buffer */
}
if (count > client->buffer)
count = client->buffer;
memcpy(data, client->ps2 + client->bufsiz - client->buffer, count); /* 从 lient->ps2 + client->bufsiz - client->buffer中拷贝count个数据到data*/
client->buffer -= count;
spin_unlock_irq(&client->packet_lock);
if (copy_to_user(buffer, data, count))
return -EFAULT;
return count;
}
/* No kernel lock - fine */
static unsigned int mousedev_poll(struct file *file, poll_table *wait)
{
struct mousedev_client *client = file->private_data;
struct mousedev *mousedev = client->mousedev;
poll_wait(file, &mousedev->wait, wait);
return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) |
(mousedev->exist ? 0 : (POLLHUP | POLLERR));
}
static const struct file_operations mousedev_fops = {
.owner = THIS_MODULE,
.read = mousedev_read,
.write = mousedev_write,
.poll = mousedev_poll,
.open = mousedev_open,
.release = mousedev_release,
.fasync = mousedev_fasync,
};
static int mousedev_install_chrdev(struct mousedev *mousedev)
{
mousedev_table[mousedev->minor] = mousedev; /* 将mousedev放入以次设备号为引索的数组 mousedev_table中*/
return 0;
}
/* 将数组中的相应的项设置为NULL */
static void mousedev_remove_chrdev(struct mousedev *mousedev)
{
mutex_lock(&mousedev_table_mutex);
mousedev_table[mousedev->minor] = NULL;
mutex_unlock(&mousedev_table_mutex);
}
/*
* Mark device non-existent. This disables writes, ioctls and
* prevents new users from opening the device. Already posted
* blocking reads will stay, however new ones will fail.
*/
/* 标记设备已经不存在 */
static void mousedev_mark_dead(struct mousedev *mousedev)
{
mutex_lock(&mousedev->mutex);
mousedev->exist = 0;
mutex_unlock(&mousedev->mutex);
}
/*
* Wake up users waiting for IO so they can disconnect from
* dead device.
*/
/* 给所有的客户端程序发送信号通知他们设备已经不存在,并唤醒他们 */
static void mousedev_hangup(struct mousedev *mousedev)
{
struct mousedev_client *client;
spin_lock(&mousedev->client_lock);
list_for_each_entry(client, &mousedev->client_list, node) /* 遍历客户端链表并调用kill_fasync来给他们发送信号 */
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
spin_unlock(&mousedev->client_lock);
wake_up_interruptible(&mousedev->wait); /* 唤醒等待队列mousedev->wait上的进程 */
}
/* 清除mousedev */
static void mousedev_cleanup(struct mousedev *mousedev)
{
struct input_handle *handle = &mousedev->handle;
mousedev_mark_dead(mousedev); /* 标记设备已经不存在 */
mousedev_hangup(mousedev); /* 给所有的客户端程序发送信号通知他们设备已经不存在,并唤醒他们 */
mousedev_remove_chrdev(mousedev); /* mousedev_table[mousedev->minor] = NULL */
/* mousedev is marked dead so no one else accesses mousedev->open */
if (mousedev->open) /* 如果设备还在打开中则调用 input_close_device来关闭设备*/
input_close_device(handle);
}
/* 分配并初始化一个 struct mousedev */
static struct mousedev *mousedev_create(struct input_dev *dev,
struct input_handler *handler,
int minor)
{
struct mousedev *mousedev;
int error;
mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); /* 为struct mousedev分配内存 */
if (!mousedev) {
error = -ENOMEM;
goto err_out;
}
INIT_LIST_HEAD(&mousedev->client_list); /* 初始化链表mousedev->client_list的头 */
INIT_LIST_HEAD(&mousedev->mixdev_node); /* 初始化链表mousedev->mixdev_node的头 */
spin_lock_init(&mousedev->client_lock); /* 初始化自旋锁mousedev->client_lock */
mutex_init(&mousedev->mutex); /* 初始化互斥体mousedev->mutex */
lockdep_set_subclass(&mousedev->mutex,
minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0);
init_waitqueue_head(&mousedev->wait); /* 初始化等待队列头 mousedev->wait*/
if (minor == MOUSEDEV_MIX)
strlcpy(mousedev->name, "mice", sizeof(mousedev->name)); /* mousedev->name= mice*/
else
snprintf(mousedev->name, sizeof(mousedev->name),
"mouse%d", minor);
/* 初始化struct mousedev *mousedev的成员 */
mousedev->minor = minor;
mousedev->exist = 1;
mousedev->handle.dev = input_get_device(dev);
mousedev->handle.name = mousedev->name;
mousedev->handle.handler = handler;
mousedev->handle.private = mousedev; /* 将 mousedev保存到mousedev->handle.private这样可以方便以后使用*/
dev_set_name(&mousedev->dev, mousedev->name);
mousedev->dev.class = &input_class;
if (dev)
mousedev->dev.parent = &dev->dev;
mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor);
mousedev->dev.release = mousedev_free; /* 设备的释放函数 */
device_initialize(&mousedev->dev); /* 初始化 mousedev->dev*/
if (minor != MOUSEDEV_MIX) { /* 这里我们的minor = MOUSEDEV_MIX */
error = input_register_handle(&mousedev->handle);
if (error)
goto err_free_mousedev;
}
error = mousedev_install_chrdev(mousedev); /* 将mousedev放入数组中即mousedev_table[mousedev->minor] = mousedev */
if (error)
goto err_unregister_handle;
error = device_add(&mousedev->dev); /* 向驱动模型核心添加一个设备 */
if (error)
goto err_cleanup_mousedev;
return mousedev;
err_cleanup_mousedev:
mousedev_cleanup(mousedev);
err_unregister_handle:
if (minor != MOUSEDEV_MIX)
input_unregister_handle(&mousedev->handle);
err_free_mousedev:
put_device(&mousedev->dev);
err_out:
return ERR_PTR(error);
}
/* 释放struct mousedev */
static void mousedev_destroy(struct mousedev *mousedev)
{
device_del(&mousedev->dev); /* 从驱动模型核心删除mousedev->dev */
mousedev_cleanup(mousedev); /* 清除mousedev */
if (mousedev->minor != MOUSEDEV_MIX)
input_unregister_handle(&mousedev->handle);
put_device(&mousedev->dev); /* 增加设备的引用计数 */
}
/* 添加设备mousedev */
static int mixdev_add_device(struct mousedev *mousedev)
{
int retval;
retval = mutex_lock_interruptible(&mousedev_mix->mutex);
if (retval)
return retval;
if (mousedev_mix->open) {
retval = mousedev_open_device(mousedev); /* 打开设备 */
if (retval)
goto out;
mousedev->mixdev_open = 1;
}
get_device(&mousedev->dev); /* 增加引用计数 */
list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); /* 加入链表 mousedev_mix_list*/
out:
mutex_unlock(&mousedev_mix->mutex);
return retval;
}
/* 移除设备 */
static void mixdev_remove_device(struct mousedev *mousedev)
{
mutex_lock(&mousedev_mix->mutex);
if (mousedev->mixdev_open) {
mousedev->mixdev_open = 0;
mousedev_close_device(mousedev); /* 关闭设备 */
}
list_del_init(&mousedev->mixdev_node); /* 将 mousedev->mixdev_node从链表mousedev_mix_list中删除并初始化它*/
mutex_unlock(&mousedev_mix->mutex);
put_device(&mousedev->dev); /* 减小设备的引用计数 */
}
/* 该函数用来连接handler和input_dev,在input_attach_handler函数被调用*/
static int mousedev_connect(struct input_handler *handler,
struct input_dev *dev,
const struct input_device_id *id)
{
struct mousedev *mousedev;
int minor;
int error;
for (minor = 0; minor < MOUSEDEV_MINORS; minor++)
if (!mousedev_table[minor]) /* 获取数组mousedev_table为空的数组项*/
break;
if (minor == MOUSEDEV_MINORS) { /* 如果数组mousedev_table已经满了则做出错处理 */
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
return -ENFILE;
}
mousedev = mousedev_create(dev, handler, minor); /* 分配并初始化一个 struct mousedev */
if (IS_ERR(mousedev))
return PTR_ERR(mousedev);
error = mixdev_add_device(mousedev); /* 添加设备 */
if (error) {
mousedev_destroy(mousedev);
return error;
}
return 0;
}
static void mousedev_disconnect(struct input_handle *handle)
{
struct mousedev *mousedev = handle->private;
mixdev_remove_device(mousedev); /* 移除设备 */
mousedev_destroy(mousedev); /* */
}
static const struct input_device_id mousedev_ids[] = { /* 鼠标设备的ID ,主要是通过事件位图来匹配的*/
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | /* 可以匹配的有事件的类型、按键类事件、相对位移类事件 */
INPUT_DEVICE_ID_MATCH_KEYBIT |
INPUT_DEVICE_ID_MATCH_RELBIT,
.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) }, /* 可以匹配按键类事件和相对位移类事件 */
.keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) }, /* 可以匹配按键类事件类中的左键 */
.relbit = { BIT_MASK(REL_X) | BIT_MASK(REL_Y) }, /* 可以匹配相对位移类事件中的x方向和y方向的位移类事件 */
}, /* A mouse like device, at least one button,
two relative axes */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | /* 可以匹配的有事件的类型、相对位移类事件 */
INPUT_DEVICE_ID_MATCH_RELBIT,
.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) }, /* 可以匹配按键类事件和相对位移类事件 */
.relbit = { BIT_MASK(REL_WHEEL) }, /* 可以匹配滚轮类事件 */
}, /* A separate scrollwheel */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT | /* 可以匹配的有事件的类型、按键类事件、绝对位移类事件 */
INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) }, /* 可以匹配的有事件的类型、绝对位移类事件 */
.keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, /* 可以匹配触摸屏类事件 */
.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, /* 可以匹配绝对x方向的位移和y方向的位移 */
}, /* A tablet like device, at least touch detection,
two absolute axes */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT | /* 可以匹配的有事件的类型、按键类事件、绝对位移类事件 */
INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) }, /* 可以匹配的有事件的类型、绝对位移类事件 */
.keybit = { [BIT_WORD(BTN_TOOL_FINGER)] = /*可以匹配 手指工具类事件 */
BIT_MASK(BTN_TOOL_FINGER) },
.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | /* 可以匹配绝对x方向的位移、y方向的位移、压力事件、工具宽度类事件 */
BIT_MASK(ABS_PRESSURE) |
BIT_MASK(ABS_TOOL_WIDTH) },
}, /* A touchpad */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | /* 可以匹配的有事件的类型、按键类事件、绝对位移类事件 */
INPUT_DEVICE_ID_MATCH_KEYBIT |
INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) }, /* 可以匹配的有事件的类型、绝对位移类事件 */
.keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) }, /* 可以匹配按键类事件类中的左键 */
.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, /* 可以匹配绝对x方向的位移和y方向的位移 */
}, /* Mouse-like device with absolute X and Y but ordinary
clicks, like hp ILO2 High Performance mouse */
{ }, /* Terminating entry */
};
MODULE_DEVICE_TABLE(input, mousedev_ids);
static struct input_handler mousedev_handler = { /* 鼠标设备的handler */
.event = mousedev_event, /* 事件处理函数 */
.connect = mousedev_connect, /* 联系函数 */
.disconnect = mousedev_disconnect, /* 断开函数 */
.fops = &mousedev_fops, /* 设备的操作函数 */
.minor = MOUSEDEV_MINOR_BASE, /* 设备的基次设备号 */
.name = "mousedev", /* 设备的名称 */
.id_table = mousedev_ids, /*设备的ID */
};
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
static struct miscdevice psaux_mouse = { /* ps/2鼠标设备----->作为混杂设备来处理*/
PSMOUSE_MINOR, "psaux", &mousedev_fops
};
static int psaux_registered;
#endif
static int __init mousedev_init(void)
{
int error;
mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX); /* 分配并初始化一个struct mousedev */
if (IS_ERR(mousedev_mix))
return PTR_ERR(mousedev_mix);
error = input_register_handler(&mousedev_handler); /* 向输入子系统核心注册一个handler */
if (error) {
mousedev_destroy(mousedev_mix);
return error;
}
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
error = misc_register(&psaux_mouse); /* 注册一个混杂设备,这里将鼠标设备作为混杂设备来处理的 */
if (error)
printk(KERN_WARNING "mice: could not register psaux device, "
"error: %d\n", error);
else
psaux_registered = 1;
#endif
printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
return 0;
}
static void __exit mousedev_exit(void)
{
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (psaux_registered)
misc_deregister(&psaux_mouse);
#endif
input_unregister_handler(&mousedev_handler);
mousedev_destroy(mousedev_mix);
}
module_init(mousedev_init);
module_exit(mousedev_exit);