一、输入子系统模型解析
1.为什么需要输入子系统
按写按键驱动时:需要注册1个字符启动;open,read与用户程序交互;硬件设置。
这些数据都是要输入的,所以可以全部整合成输入子系统。
2.输入子系统的模型
输入子系统由
设备驱动层(input device driver),核心层(input core)和事件驱动层(event driver)三部份组成。
任何一次输入事件,如鼠标移动,按键按下,都需要通过InputDeviceDriver->InputCore->EventDrive才能到达用户空间的应用程序。
设备驱动层:
将底层的硬件输入转化为统一事件型式,向输入核心(InputCore)汇报。
输入核心层:
为设备驱动层提供输入设备注册与操作接口,如:nput_register_device;通知事件处理层对事件进行处理;
事件驱动层:
主要作用是和用户空间交互,如提供read,open等设备方法,创建设备文件等。
3.编写代码
key.c
-
#include <linux/module.h>
-
#include <linux/init.h>
-
#include <linux/miscdevice.h>
-
#include <linux/fs.h>
-
#include <asm/uaccess.h>
-
#include <linux/io.h>
-
#include <linux/irqreturn.h>
-
#include <linux/interrupt.h>
-
#include <linux/uaccess.h>
-
#include <linux/input.h> /*上报的按键编号*/
-
-
#define GPFCON (volatile unsigned long*) 0x56000050
-
#define GPFDAT (volatile unsigned long*) 0x56000054
-
-
unsigned int *gpio_data;
-
-
struct work_struct *work1;
-
-
struct timer_list key_timer;
-
-
wait_queue_head_t key_q;
-
-
unsigned int key_num = 0;
-
-
struct input_dev *button_dev; //创建input_dev结构
-
-
void key_timer_func(unsigned long data)
-
{
-
unsigned int key_val;
-
key_val = readw(gpio_data);
-
if((key_val & 0x01) == 0)
-
{
-
key_num = 4;
-
input_report_key(button_dev, KEY_4, 1); //上报事件,button_dev结构发送了KEY_4事件,按下了
-
}
-
else if((key_val& 0x02) == 0)
-
{
-
key_num = 1;
-
input_report_key(button_dev, KEY_1, 1); //上报事件
-
}
-
else if((key_val & 0x04) == 0)
-
{
-
key_num = 3;
-
input_report_key(button_dev, KEY_3, 1); //上报事件
-
}
-
else if((key_val & 0x10) == 0)
-
{
-
key_num = 2;
-
input_report_key(button_dev, KEY_2, 1); //上报事件
-
}
-
-
input_sync(button_dev); //上报结束
-
}
-
-
void work1_func(struct work_struct *work)
-
{
-
mod_timer(&key_timer, jiffies + HZ/10);
-
}
-
-
irqreturn_t key_int(int irq, void *dev_id)
-
{
-
//1.检测是否发生了按键中断
-
-
//2.清除已经发生的按键中断
-
-
//3.提交下半部
-
schedule_work(work1);
-
-
return IRQ_HANDLED;
-
}
-
-
void key_hw_init()
-
{
-
unsigned int *gpio_config;
-
unsigned short data;
-
-
gpio_config = ioremap(GPFCON, 4);
-
gpio_data = ioremap(GPFDAT, 4);
-
data = readw(gpio_config);
-
data &= ~0x33f;
-
data |= 0x22a;
-
writew(data, gpio_config);
-
}
-
-
static int button_init()
-
{
-
int ret;
-
//分配输入型设备结构
-
button_dev = input_allocate_device(); //分配input_dev结构
-
-
//申明所支持的事件类型
-
set_bit(EV_KEY, button_dev->evbit); //申明驱动可能上报的事件类型
-
-
/*上报可能的键编号*/
-
set_bit(KEY_1,button_dev->keybit); //申明可能上报的
-
set_bit(KEY_2,button_dev->keybit);
-
set_bit(KEY_3,button_dev->keybit);
-
set_bit(KEY_4,button_dev->keybit);
-
-
/*注册输入型设备*/
-
input_register_device(button_dev); //注册input_dev结构
-
-
//按键初始化
-
key_hw_init();
-
-
//注册中断处理程序
-
ret = request_irq(IRQ_EINT0, &key_int, IRQF_TRIGGER_FALLING, "tq2440key", 0);
-
ret = request_irq(IRQ_EINT1, &key_int, IRQF_TRIGGER_FALLING, "tq2440key", 0);
-
ret = request_irq(IRQ_EINT2, &key_int, IRQF_TRIGGER_FALLING, "tq2440key", 0);
-
ret = request_irq(IRQ_EINT4, &key_int, IRQF_TRIGGER_FALLING, "tq2440key", 0);
-
-
//创建工作
-
work1 = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
-
INIT_WORK(work1, work1_func);
-
-
//初始化定时器
-
init_timer(&key_timer);
-
key_timer.function = key_timer_func;
-
-
//注册定时器
-
add_timer(&key_timer);
-
-
//初始化等待队列
-
init_waitqueue_head(&key_q);
-
return 0;
-
}
-
-
static void button_exit()
-
{
-
input_unregister_device(button_dev); //注销input_dev结构
-
}
-
-
module_init(button_init);
-
module_exit(button_exit);
key_app.c:
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include <sys/ioctl.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <sys/select.h>
-
#include <sys/time.h>
-
#include <errno.h>
-
#include <linux/input.h>
-
int main(void)
-
{
-
int buttons_fd;
-
int key_value,i=0,count;
-
-
struct input_event ev_key;
-
buttons_fd = open("/dev/event1", O_RDWR); //这里的设备名为/dev/evnet1
-
if (buttons_fd < 0) {
-
perror("open device buttons");
-
exit(1);
-
}
-
-
for (;;) {
-
count = read(buttons_fd,&ev_key,sizeof(struct input_event)); //从设备中读取input_event事件
-
// printf("count=%d\n",count);
-
for(i=0; i<(int)count/sizeof(struct input_event); i++)
-
if(EV_KEY==ev_key.type)
-
printf("type:%d,code:%d,value:%d\n", ev_key.type,ev_key.code-1,ev_key.value);
-
if(EV_SYN==ev_key.type)
-
printf("syn event\n\n");
-
-
}
-
-
close(buttons_fd);
-
return 0;
-
}
二、输入子系统原理分析
1.子系统核心架构
2.输入子系统设备注册
2.1设备注册
input_register_device:
-
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]) {
-
dev->timer.data = (long) dev;
-
dev->timer.function = input_repeat_key;
-
dev->rep[REP_DELAY] = 250;
-
dev->rep[REP_PERIOD] = 33;
-
}
-
-
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);
-
-
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);
-
-
list_for_each_entry(handler, &input_handler_list, node) //从input_handler_list遍历找到能处理input_dev的handler
-
input_attach_handler(dev, handler); //将dev设备和handler处理事件匹配
-
-
input_wakeup_procfs_readers();
-
-
mutex_unlock(&input_mutex);
-
-
return 0;
-
}
input_attach_handler:
-
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
-
{
-
const struct input_device_id *id;
-
int error;
-
-
if (handler->blacklist && input_match_device(handler->blacklist, dev))
-
return -ENODEV;
-
-
id = input_match_device(handler->id_table, dev); //handler中有id_table(ID表)和dev
-
if (!id)
-
return -ENODEV;
-
-
error = handler->connect(handler, dev, id); //找到对应的id后进行匹配,handler和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;
-
}
evdev.c>>evdev_handler(事件层):
-
static struct input_handler evdev_handler = {
-
.event = evdev_event, //event事件,下面会用到(事件处理)
-
.connect = evdev_connect, //连接函数
-
.disconnect = evdev_disconnect,
-
.fops = &evdev_fops, //操作函数集,在下面事件上报时,open中使用
-
.minor = EVDEV_MINOR_BASE,
-
.name = "evdev",
-
.id_table = evdev_ids, //事件驱动id表
-
};
evdev_connect:
-
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++) //检查minor是否在evdev_table中
-
if (!evdev_table[minor])
-
break;
-
-
if (minor == EVDEV_MINORS) { //检查minor是否有空闲
-
printk(KERN_ERR "evdev: no more free evdev devices\n");
-
return -ENFILE;
-
}
-
-
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); //分配evdev空间
-
if (!evdev)
-
return -ENOMEM;
-
-
INIT_LIST_HEAD(&evdev->client_list); //加入链表
-
spin_lock_init(&evdev->client_lock); //初始化自旋锁
-
mutex_init(&evdev->mutex); //初始化mutex
-
init_waitqueue_head(&evdev->wait);
-
-
snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
-
evdev->exist = 1; //evdev初始化
-
evdev->minor = minor;
-
-
evdev->handle.dev = input_get_device(dev);
-
evdev->handle.name = evdev->name;
-
evdev->handle.handler = handler;
-
evdev->handle.private = evdev;
-
-
dev_set_name(&evdev->dev, evdev->name);
-
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
-
evdev->dev.class = &input_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;
-
}
但是这里没有注册硬件驱动,实在input_init中注册了硬件驱动:
-
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();
-
if (err)
-
goto fail1;
-
-
err = register_chrdev(INPUT_MAJOR, "input", &input_fops); //这里注册驱动的函数(老版本的),input_fops是操作函数集
-
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;
-
}
2.2 事件上报
input_report_key:
-
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
-
{
-
input_event(dev, EV_KEY, code, !!value); //调用input_event函数
-
}
input_event:
-
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);
-
}
-
}
input_handle_event:
-
static void input_handle_event(struct input_dev *dev,
-
unsigned int type, unsigned int code, int value)
-
{
-
int disposition = INPUT_IGNORE_EVENT;
-
-
..........
-
-
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
-
dev->sync = 0;
-
-
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
-
dev->event(dev, type, code, value);
-
-
if (disposition & INPUT_PASS_TO_HANDLERS)
-
input_pass_event(dev, type, code, value); //此处调用input_pass_event,看名字就是传递事件
-
}
input_pass_event:
-
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); //这里handle和handler,在注册时建立联系了。事件来了,就用event来处理
-
else
-
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
-
if (handle->open)
-
handle->handler->event(handle,
-
type, code, value);
-
rcu_read_unlock();
-
}
evdev_event:
-
static void evdev_event(struct input_handle *handle,
-
unsigned int type, unsigned int code, int value)
-
{
-
struct evdev *evdev = handle->private;
-
struct evdev_client *client;
-
struct input_event event;
-
-
do_gettimeofday(&event.time); //写入事件的type,code,value
-
event.type = type;
-
event.code = code;
-
event.value = value;
-
-
rcu_read_lock();
-
-
client = rcu_dereference(evdev->grab);
-
if (client)
-
evdev_pass_event(client, &event); //调用保存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);
-
}
evdev_pass_event:
-
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; //将事件保存到buff中
-
client->head &= EVDEV_BUFFER_SIZE - 1;
-
spin_unlock(&client->buffer_lock);
-
-
kill_fasync(&client->fasync, SIGIO, POLL_IN);
-
}
2.3 应用程序如何关联驱动
input_fops:
-
static const struct file_operations input_fops = {
-
.owner = THIS_MODULE,
-
.open = input_open_file, //打开设备
-
};
input_open_file:
-
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];
-
if (!handler || !(new_fops = fops_get(handler->fops))) { //将handler->fops赋值给new_fops,handler是evdev_handler(也有file_operations)
-
err = -ENODEV;
-
goto out;
-
}
-
-
/*
-
* That's _really_ odd. Usually NULL ->open means "nothing special",
-
* not "no device". Oh, well...
-
*/
-
if (!new_fops->open) {
-
fops_put(new_fops);
-
err = -ENODEV;
-
goto out;
-
}
-
old_fops = file->f_op;
-
file->f_op = new_fops; //这里将替换的new_fops替换了,打开时的fops。下一次读的时候就会调用evdev_handler中的操作集了。如读
-
-
err = new_fops->open(inode, file);
-
-
if (err) {
-
fops_put(file->f_op);
-
file->f_op = fops_get(old_fops);
-
}
-
fops_put(old_fops);
-
out:
-
unlock_kernel();
-
return err;
-
}
evdev_fops(handler->fops):
-
static const struct file_operations evdev_fops = { //各种操作集在这里,事件中的只有open
-
.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
-
};
其中evdev_read:
-
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 *evdev = client->evdev;
-
struct input_event event;
-
int retval;
-
-
if (count < input_event_size())
-
return -EINVAL;
-
-
if (client->head == client->tail && evdev->exist &&
-
(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)) {
-
-
if (input_event_to_user(buffer + retval, &event)) //将信息传递给用户层
-
return -EFAULT;
-
-
retval += input_event_size();
-
}
-
-
return retval;
-
}
evdev_fetch_next_event:
-
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;
-
if (have_event) {
-
*event = client->buffer[client->tail++]; //在Buffer中取出事件
-
client->tail &= EVDEV_BUFFER_SIZE - 1;
-
}
-
-
spin_unlock_irq(&client->buffer_lock);
-
-
return have_event;
-
}
阅读(651) | 评论(0) | 转发(0) |