事件(struct input_event)从设备驱动层 –> 核心层—>事件处理层的经过
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;
}