事件(struct input_event)从设备驱动层 –> 核心层—>事件处理层的通过java
struct input_event {
struct timeval time; //事件发生的时间
__u16 type; //事件的类型
__u16 code; //事件的代码
__s32 value; //事件的值
};
在input.h中有定义:
/** type: 事件的类型 */
#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) //不知道这个设置是为何了,下面is_event_supported()中会判断事件类型值 <= EV_MAX
/** 当事件类型是EV_KEY的时候,code为设备键盘码 0~127为键盘上的按键 */
#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
/* code : 事件的代码 若是事件的类型是EV_KEY 该code为设备键盘码, 0 - 127 : 键盘上的按键代码 若是事件的类型是EV_REL 该code : REL_X REL_Y value : 若是事件的类型是EV_KEY value : 0 松开 1 按下 若是事件的类型是EV_REL value正负值表示 两个方向上的值 详细请参考input.h */
在中断处理函数中,调用input_report_key( )向输入子系统报告发生的事件
/** 向输入子系统发生事件。 dev :发生事件的设备 code : 事件代码 value:事件的值 在中断函数中不须要考虑重复按键的点击状况,这个函数能够检查这个问题,并报告一次事件 */
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
// !!value ?
input_event(dev, EV_KEY, code, !!value);
}
/** input子系统中 任何向核心层报告事件的都会通过这个函数。 */
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
unsigned long flags; //为何不初始化就传递过去了?
/** 判断设备是否支持该事件 is_event_supported(){ 这里的code是上面传递过来的type EV_KEY : 1 EV_CNT : 32 max : 31 既然位图是0~31位,为何还要定义EV_CNT?这里还要判断? code <= max : 事件类型不是 EV_CNT test_bit(code, bm) : 判断evbit的第code位是否被置1了,被置1了,表示支持,为0,表示不支持 return code <= max && test_bit(code, bm); } */
if (is_event_supported(type, dev->evbit, EV_MAX)) {
/* 避免竞态的一种方法:屏蔽本地cpu中断 那么 若是临界区执行完成须要的时间长,那么这里屏蔽中断有点危险 保存本地中断状态, 关闭本地中断, 获取自旋锁 */
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);
}
}
static void input_handle_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
/* 这个disposition变量表示使用什么样的方式处理事件, #define INPUT_IGNORE_EVENT 0 //忽略该事件 #define INPUT_PASS_TO_HANDLERS 1 //将该事件交给handler处理 #define INPUT_PASS_TO_DEVICE 2 //交给input_dev处理 #define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) //handler、input_dev共同处理 */
int disposition = INPUT_IGNORE_EVENT;
//下面是一个大的switch结构,截取EV_KEY部分。
case EV_KEY:
//is_event_supported 判断是否支持该事件。test_bit 测试按键的状态是否改变
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);
}
//设置成INPUT_PASS_TO_HANDLERS,表示由handler来处理这个事件
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
.......
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev, type, code, value);
// 事件交给handler处理,调用input_pass_event函数
if (disposition & INPUT_PASS_TO_HANDLERS)
input_pass_event(dev, type, code, value);
}
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);
if (handle)
handle->handler->event(handle, type, code, value);
else
/* 遍历input_handle链表,取出input_handle指向的input_handler. 调用这个input_handler的event函数。 */
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
if (handle->open) //若是已经被打开
/** 事件由核心层流转到事件处理层。 若是input_handler是evdev的话,那么evdev_event将会被调用 */
handle->handler->event(handle,type, code, value);
rcu_read_unlock();
}
/** 到这里事件处理到达了 事件处理层,咱们知道了事件发生后,input_handler的event函数会被调用。 下面咱们看看 input_handler的event函数 */
static struct input_handler evdev_handler = {
.event = evdev_event, //事件上报后,这个函数会被调用
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids, //这个handler所可以支持的设备列表
};
static void evdev_event(struct input_handle *handle,unsigned int type, unsigned int code, int value)
{
/*取出evdev 在evdev_connect()中设置 把evdev放入到input_handle的私有数据中, evdev->handle.private = evdev; */
struct evdev *evdev = handle->private;
struct evdev_client *client;
struct input_event event;
do_gettimeofday(&event.time);
//根据传入的值 为input_event赋值
event.type = type;
event.code = code;
event.value = value;
rcu_read_lock();
client = rcu_dereference(evdev->grab);
if (client)
evdev_pass_event(client, &event);
else
//遍历client链表,调用evdev_pass_event函数
list_for_each_entry_rcu(client, &evdev->client_list, node)
//调用这个函数来发送
evdev_pass_event(client, &event);
rcu_read_unlock();
//唤醒等待的进程。 那么是在何时被阻塞的呢?
wake_up_interruptible(&evdev->wait);
/** static ssize_t evdev_read(struct file *file, char __user *buffer,size_t count, loff_t *ppos) { /** 若是没有数据&&以非阻塞的方式打开的话,就返回 */
if (client->head == client->tail && evdev->exist &&(file->f_flags & O_NONBLOCK))
{
return -EAGAIN;
}
/** 否则,就休眠。input_event()函数会唤醒的 */
retval = wait_event_interruptible(evdev->wait,client->head != client->tail ||!evdev->exist);
if (retval)
{
return retval;
}
}
*/
}
static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
/** 获取自旋锁 --- 访问临界区----释放自旋锁 */
spin_lock(&client->buffer_lock);
//将事件赋值给客户端的input_event 数组
client->buffer[client->head++] = *event;
client->head &= EVDEV_BUFFER_SIZE - 1;
spin_unlock(&client->buffer_lock);
/** 向应用层发送消息,应用层会执行对应的消息处理函数。 */
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
从上面能够看出 事件最终被放入到了客户端的input_event[]数组中了,
只须要将这个input_event[]数组复制给用户空间便可。
看看用户空间把,用户空间调用read,evdev_read会被调用,
static ssize_t evdev_read(struct file *file, char __user *buffer,size_t count, loff_t *ppos)
{
....
while (retval + input_event_size() <= count &&evdev_fetch_next_event(client, &event)) {
//调用了这个函数来获取事件
if (input_event_to_user(buffer + retval, &event))
return -EFAULT;
retval += input_event_size();
}
return retval;
}
int input_event_to_user(char __user *buffer,const struct input_event *event)
{
//哈哈,copy_to_user 将input_event拷贝到用户空间中
if (copy_to_user(buffer, event, sizeof(struct input_event)))
{
return -EFAULT;
}
return 0;
}