输入事件驱动层源码分析: kernel/driver/input/Evdev.c
static int __init evdev_init(void)
input_register_handler(&evdev_handler);
//第一点:在input.c定义的static struct input_handler *input_table[8]; 填充到一个input_table[]数组中
//第二点:加入到相关链表中
//第三点:在input_dev_list链表中进行匹配
//第四点:匹配结束后:error = handler->connect(handler, dev, id);
-------------------------------------------------------------------------
struct input_handler
{
重点成员:
void *private; 到时候方便引用
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
const struct file_operations *fops;
int minor;
const char *name;
const struct input_device_id *id_table;//handler所支持的devices
}
第二点分析:static struct input_handler evdev_handler这个结构体
static struct input_handler evdev_handler = {
.event = evdev_event, //上报事件
.connect = evdev_connect, //链接
.disconnect = evdev_disconnect, //失去链接
.fops = &evdev_fops, //用户层read write 的接口
.minor = EVDEV_MINOR_BASE, //基准次设备号 这个元素的作用
.name = "evdev", //名字
.id_table = evdev_ids, //id_table 主要是记录了id_table使用的devices的特征
};
第一步:
.id_table = evdev_ids,
第二步:
static struct evdev *evdev_table[EVDEV_MINORS];
//这个结构体主要是
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)
第一步://for循环就是在 找minor这个下表 每一handler都有32位空间
第二步:创建一个evdev结构体
第三步:填充这个结构体
主要是填充:
evdev->minor = minor; //作用 evdev_table[minor]
evdev->handle.dev = input_get_device(dev);
evdev->handle.handler = handler;
evdev->handle.private = evdev; //handler的私有数据 将来有可能在以后需要用到
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
第四步:创建/dev/devices这个文件目录
device_initialize(&evdev->dev);
device_add(&evdev->dev);
第五步:
//相应的链表中去
//把handle放入到一个链表中 主要是通过这个handle来链接 handler和设备
error = input_register_handle(&evdev->handle);
//创建一个handle进行复制
//如果handler->start存在 则调用handler->start()函数
-------------------------------------------------------------------------------
app在调用read /dev/xxx.c函数时
static ssize_t evdev_read(struct file *file, char __user *buffer,size_t count, loff_t *ppos)
第一步:检查用户传进来的大小
第二步:检查你是否是以非阻塞方式打开 ,缓冲区中的数据是否已满
第三步:
/*
* wait_event_interruptible - sleep until a condition gets true
* @wq: the waitqueue to wait on
* @condition: a C expression for the event to wait for
* //当应用进程来读的时候
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
* @condition evaluates to true or a signal is received.
* The @condition is checked each time the waitqueue @wq is woken up.
*
* wake_up() has to be called after changing any variable that could
* change the result of the wait condition.
*
* The function will return -ERESTARTSYS if it was interrupted by a
* signal and 0 if @condition evaluated to true.
*/
/*
注意1:
第一种可能:条件成立
第一点:client这个队列有数据
第二点:evdev->exist为0的 这个handler不存在
condition 为真的时候 函数返回 retval = 0。
第二种可能:
中断返回:return -ERESTARTSYS
注意2:
wake_up() has to be called after changing any variable that could
change the result of the wait condition.
当你发现,condition这个条件要改变的地方时,一定要调用wake_up()
*/
retval = wait_event_interruptible(evdev->wait,client->head != client->tail || !evdev->exist);
第四步:发送给用户
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();
}
static int evdev_open(struct inode *inode, struct file *file) //打开
{
struct evdev *evdev;
struct evdev_client *client;
evdev = evdev_table[i];
client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
client->evdev = evdev;
file->private_data = client; //重点:产生数据
}
------------------------------------------------------------------------------------------------------------------
驱动层:
Button-x210.c
//按键类事件
input_report_key(input, s3c_Keycode[0], 0);
/*
参数1:input
参数2:EV_KEY
参数3:s3c_Keycode[0]
参数4:0
*/
input_event(dev, EV_KEY, code, !!value);
参数1:input
参数2:EV_KEY
参数3:s3c_Keycode[0]
参数4:0
input_handle_event(dev, type, code, value);
static void input_pass_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)
handle->handler->event(handle, type, code, value);//就是与你进行挂在的那个handler
static void evdev_event(struct input_handle *handle,unsigned int type, unsigned int code, int value)
struct evdev *evdev = handle->private;
struct input_event event;
event.time.tv_sec = ts.tv_sec;
event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
event.type = type;
event.code = code;
event.value = value;
client = rcu_dereference(evdev->grab);
if (client)
evdev_pass_event(client, &event);
client->buffer[client->head++] = *event;
client->head &= EVDEV_BUFFER_SIZE - 1;//把数据放入
//唤醒机制 --------在应用层那边就可以进行读了
wake_up_interruptible(&evdev->wait);//那个队列就会被唤醒
驱动层:------提供给我们的接口函数
1.注册 与一个handler相互匹配 static struct input_dev * input;
2.input_report_key(input, s3c_Keycode[0], 0);
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)