1.input core层中初始化input_dev_list链表与input_handler_list链表
2.初始化input_handler对象,并注册到内核链表中
注册之后会匹配一次
通过结构体中的node成员连接起来构成input_handler链表
注册时,会将handler对象加入到input_table数组中
3.初始化input_dev对象,并注册到input_device_list链表中
注册时匹配一次
struct input_dev {
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
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 hint_events_per_packet;
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
int (*setkeycode)(struct input_dev *dev,
const struct input_keymap_entry *ke,
unsigned int *old_keycode);
int (*getkeycode)(struct input_dev *dev,
struct input_keymap_entry *ke);
struct ff_device *ff;
unsigned int repeat_key;
struct timer_list timer;
int rep[REP_CNT];
struct input_mt_slot *mt;
int mtsize;
int slot;
int trkid;
struct input_absinfo *absinfo;
unsigned long key[BITS_TO_LONGS(KEY_CNT)];
unsigned long led[BITS_TO_LONGS(LED_CNT)];
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
unsigned long sw[BITS_TO_LONGS(SW_CNT)];
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
struct input_handle __rcu *grab;
spinlock_t event_lock;
struct mutex mutex;
unsigned int users;
bool going_away;
bool sync;
struct device dev;
struct list_head h_list;
struct list_head node;
};
static const struct input_device_id *input_match_device(struct input_handler *handler,
struct input_dev *dev)
{
const struct input_device_id *id;
int i;
for (id = handler->id_table; id->flags || id->driver_info; id++) {
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
if (id->bustype != dev->id.bustype)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
if (id->vendor != dev->id.vendor)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
if (id->product != dev->id.product)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
if (id->version != dev->id.version)
continue;
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);
if (!handler->match || handler->match(handler, dev))
return id;
}
return NULL;
}
4.匹配成功后会调用input_handler对象中的evdev_connect方法创建evdev对象
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++)
if (!evdev_table[minor])
break;
if (minor == EVDEV_MINORS) {
pr_err("no more free evdev devices\n");
return -ENFILE;
}
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
if (!evdev)
return -ENOMEM;
INIT_LIST_HEAD(&evdev->client_list);
spin_lock_init(&evdev->client_lock);
mutex_init(&evdev->mutex);
init_waitqueue_head(&evdev->wait);
dev_set_name(&evdev->dev, "event%d", minor);
evdev->exist = true;
evdev->minor = minor;
evdev->handle.dev = input_get_device(dev);
evdev->handle.name = dev_name(&evdev->dev);
evdev->handle.handler = handler;
evdev->handle.private = evdev;
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
evdev->dev.class = &input_class;
evdev->dev.parent = &dev->dev;
evdev->dev.release = evdev_free;
device_initialize(&evdev->dev);
error = input_register_handle(&evdev->handle);
if (error)
goto err_free_evdev;
error = evdev_install_chrdev(evdev);
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;
}
5.evdev对象会产生一个evdev_client对象,这个对象会产生一个缓冲队列(刚产生时队列为空)
里面的evdev成员中有wait_queue_head成员
6.evdev对象会产生一个input_handle对象,这个对象会产生一个input_handler的指针和一个input_dev的指针
这两个指针会分别指向input_handler对象与input_dev对象
7.evdev对象产生后会生成设备节点
8.应用层app通过设备节点访问其中的read函数
因为此时缓冲队列中无资源,所以会进入阻塞状态休眠
9.中断上传资源,通过input_report_key函数,同时用过input_sync唤醒进程
上传数据到到input_handler对象中的evdev_event方法中,数据进入缓冲队列中,此时外部read就可以读写到资源
完整驱动代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
//设计一个描述按键的对象: 名字, irqno, gpio, 按键值,触发方式
struct key_desc{
char *name;
int irqno;
int gpio;
int code;
int flags;// 触发方式
};
struct key_desc all_keys[] = {
[0] = {
.name = "key1_up_eint0",
.irqno = IRQ_EINT(0),
.gpio = S5PV210_GPH0(0),
.code = KEY_UP,
.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
},
[1] = {
.name = "key2_down_eint1",
.irqno = IRQ_EINT(1),
.gpio = S5PV210_GPH0(1),
.code = KEY_DOWN,
.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
},
[2] = {
.name = "key3_left_eint2",
.irqno = IRQ_EINT(2),
.gpio = S5PV210_GPH0(2),
.code = KEY_LEFT,
.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
},
[3] = {
.name = "key4_right_eint3",
.irqno = IRQ_EINT(3),
.gpio = S5PV210_GPH0(3),
.code = KEY_RIGHT,
.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
},
};
static struct input_dev *key_inputdev;
irqreturn_t input_key_irq (int irqno, void *dev_id)
{
struct key_desc *pdesc = (struct key_desc *)dev_id;
int value = gpio_get_value(pdesc->gpio);
if(value)
{
//上报数据
//参数1--哪个设备上报
//参数2--哪个按键
//参数3--按下还是抬起
input_report_key(key_inputdev,pdesc->code,0);
//最后一定要同步--表示上报完毕
input_sync(key_inputdev);
}else
{
input_report_key(key_inputdev,pdesc->code,1);
input_sync(key_inputdev);
}
return IRQ_HANDLED;
}
static int __init input_key_drv_init(void)
{
int ret;
// 1, 分配一个input device对象
key_inputdev= input_allocate_device();
if(key_inputdev == NULL)
{
printk("input_allocate_device error\n");
return -ENOMEM;
}
// 2, 初始化 input device对象
key_inputdev->evbit[0] |= BIT_MASK(EV_KEY);
key_inputdev->keybit[BIT_WORD(KEY_DOWN)] |= BIT_MASK(KEY_DOWN);
key_inputdev->keybit[BIT_WORD(KEY_UP)] |= BIT_MASK(KEY_UP);
key_inputdev->keybit[BIT_WORD(KEY_LEFT)] |= BIT_MASK(KEY_LEFT);
key_inputdev->keybit[BIT_WORD(KEY_RIGHT)] |= BIT_MASK(KEY_RIGHT);
// 3, 注册input device对象
ret = input_register_device(key_inputdev);
if(ret != 0)
{
printk("input_register_device error\n");
goto err_free_dev;
}
// 4, 初始化硬件,并获取到数据之后上报数据
int i;
int irqno;
int flags;
char *name;
for(i=0; i<ARRAY_SIZE(all_keys); i++)
{
name = all_keys[i].name;
irqno = all_keys[i].irqno;
flags = all_keys[i].flags;
ret = request_irq(irqno, input_key_irq, flags, name, &all_keys[i]);
if(ret != 0)
{
printk("request_irq error\n");
return ret;
}
}
return 0;
err_unregister_dev:
input_unregister_device(key_inputdev);
err_free_dev:
input_free_device(key_inputdev);
return ret;
}
static void __exit input_key_drv_exit(void)
{
int i;
int irqno;
for(i=0; i<ARRAY_SIZE(all_keys); i++)
{
irqno = all_keys[i].irqno;
free_irq(irqno, &all_keys[i]);
}
input_unregister_device(key_inputdev);
input_free_device(key_inputdev);
}
module_init(input_key_drv_init);
module_exit(input_key_drv_exit);
MODULE_LICENSE("GPL");
完整app代码
#include <stdio.h>
#include<sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <poll.h>
#include <sys/mman.h>
#include <string.h>
#include <linux/input.h>
int main(int argc, char *argv[])
{
int on; int ret;
int fd;
struct input_event data;
//打开设备
fd = open("/dev/event0", O_RDWR);
if(fd < 0)
{
perror("open");
exit(1);
}
while(1)
{
ret = read(fd, &data, sizeof(struct input_event));
if(ret < 0)
{
perror("open");
exit(1);
}
//拆包
if(data.type == EV_KEY)
{
if(data.code == KEY_DOWN)
{
if(data.value)
{
printf("<app>---KEY_DOWN pressed\n");
}else
{
printf("<app>---KEY_DOWN released\n");
}
}else if(data.code == KEY_UP)
{
if(data.value)
{
printf("<app>---KEY_UP pressed\n");
}else
{
printf("<app>---KEY_UP released\n");
}
}else if(data.code == KEY_LEFT)
{
if(data.value)
{
printf("<app>---KEY_LEFT pressed\n");
}else
{
printf("<app>---KEY_LEFT released\n");
}
}else if(data.code == KEY_RIGHT)
{
if(data.value)
{
printf("<app>---KEY_RIGHT pressed\n");
}else
{
printf("<app>---KEY_RIGHT released\n");
}
}
}
}
close(fd);
}