按键驱动之使用输入子系统架构
2017-03-04 18:21
453 查看
有关输入子系统我们可以参考 gpio_keys.c这个代码,注:这只是一个例子,没有实际的作用
static struct input_dev *button_dev
/*1.分配一个input_device结构体*/
/*参考gpio_keys.c这个例子,可以知道其分配函数是input_allocate_device*/
/*2. 设置*/
/*怎么设置呢,我们来看看这个结构体里面有什么东西*/
static int button_init(void)
{
/*1.分配一个input_device结构体*/
/*参考gpio_keys.c这个例子,可以知道其分配函数是input_allocate_device*/
button_dev = input_allocate_device();
/*2. 设置*/
/*怎么设置呢,我们来看看这个结构体里面有什么东西*/
看看EV_CNT
当有按键产生时,就用input_event上报, input_event会通过input_device里面的handle,然后handle会找到handler,然后就会找到handler里面的event这个函数
input_event(button_dev, EV_KEY, pindesc->key_val, 0); 第一个参数是input_device,第二个参数是哪一类事件,第三个是哪一个按键,最后一个参数是表示按下还是松开,松开的话表示0,按下表示1
写完驱动之后,我们可以ls -l /dev/event* 来看一看我们的原有的事件
crw-rw---- 1 root root 13, 64 Jan 1 12:01 /dev/event0
加载我们的驱动
crw-rw---- 1 root root 13, 64 Jan 1 12:01 /dev/event0
crw-rw---- 1 root root 13, 65 Jan 1 12:06 /dev/event1
原来只有我们的event0,现在多了一个event1
主设备号是13,次设备号是64 这是怎么回事呢
我们之前说过,我们input_register_device input_device会通过handle找到handler 然后调用connect,能不能支持呢,看下evdev.c
看看它的id_tables
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,
};
static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 },/* Matches all devices */
{ }, /* Terminating zero entry */
}; 看这个注释,匹配所有的设备,当然可以支持我们的按键,然后调用connect函数
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->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
我们加载驱动之后
cat /dev/tty1
用hexdump /dev/event1
按下四个按键可以看到一些数字 如图
0000000 061e 0000 7018 0006 0001 002a 0001 0000
0000010 061e 0000 7024 0006 0000 0000 0000 0000
0000020 061e 0000 f495 0009 0001 002a 0000 0000
0000030 061e 0000 f4a4 0009 0000 0000 0000 0000
0000040 061f 0000 f2ed 000d 0001 001c 0001 0000
0000050 061f 0000 f2fd 000d 0000 0000 0000 0000
0000060 0620 0000 9f7e 0002 0001 001c 0000 0000
0000070 0620 0000 9f87 0002 0000 0000 0000 0000
hexdump
hex是16进制 dump就是显示
这个就是读/dev/event1这个设备把里面的数据显示出来
0000000 061e 0000 7018 0006 0001 002a 0001 0000
前面0000000 这可以省略 ,后面的就是数据 061e 0000 这四个字节表示秒 7018 0006这四个字节表示微秒 0001 表示类 002a表示code
0001 0000表示value
0000010 061e 0000 7024 0006 0000 0000 0000 0000这表示同步类事件
那些值分别代表什么意思是怎么知道的 看input_event的定义
还一种方法就是 cat /dev/tty1
ls 后面回车
驱动代码如下
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
static struct input_dev *button_dev;
struct pin_desc{
int irq;
char *name;
unsigned int pin;
unsigned int key_val;
};
struct pin_desc pins_desc[4] = {
{IRQ_EINT(19), "K4", S5PV210_GPH2(3), KEY_L},
{IRQ_EINT(24), "K5", S5PV210_GPH3(0), KEY_S},
{IRQ_EINT(25), "K6", S5PV210_GPH3(1), KEY_ENTER},
{IRQ_EINT(26), "K7", S5PV210_GPH3(2), KEY_LEFTSHIFT},
};
static struct pin_desc *irq_pd;
static struct timer_list buttons_timer;
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
/* 10ms后启动定时器 */
irq_pd = (struct pin_desc *)dev_id;
mod_timer(&buttons_timer, jiffies+HZ/100);
return IRQ_RETVAL(IRQ_HANDLED);
}
static void buttons_timer_function(unsigned long data)
{
struct pin_desc * pindesc = irq_pd;
unsigned int pinval;
if (!pindesc)
return;
pinval = gpio_get_value(pindesc->pin);
if (pinval)
{
/* 松开 : 最后一个参数: 0-松开, 1-按下 */
input_event(button_dev, EV_KEY, pindesc->key_val, 0);
input_sync(button_dev); //还要上报同步时间
}
else
{
/* 按下 */
input_event(button_dev, EV_KEY, pindesc->key_val, 1);
input_sync(button_dev);
}
}
static int button_init(void)
{
int i;
/*1.分配一个input_device结构体*/
/*参考gpio_keys.c这个例子,可以知道其分配函数是input_allocate_device*/
button_dev=input_allocate_device();
/*2.设置*/
/*2.1 表示可以产生按键类事件*/
set_bit(EV_KEY, button_dev->evbit);
set_bit(EV_REP, button_dev->evbit); //能产生重复类事件
/*2.2 能产生这类事件的哪些操作,我们可以取4个按键,功能设置为L,S,ENTER,LEFTSHIT*/
set_bit(KEY_L, button_dev->keybit);
set_bit(KEY_S, button_dev->keybit);
set_bit(KEY_ENTER, button_dev->keybit);
set_bit(KEY_LEFTSHIFT, button_dev->keybit);
/*3 注册*/
input_register_device(button_dev);
/*硬件相关的操作(比如注册中断之类的)*/
/*注册四个中断*/
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
add_timer(&buttons_timer);
//int i;
for (i = 0; i < 4; i++)
{
request_irq(pins_desc[i].irq, buttons_irq, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, pins_desc[i].name, &pins_desc[i]);
}
return 0;
}
static void button_exit(void)
{
int i;
for (i = 0; i < 4; i++)
{
free_irq(pins_desc[i].irq, &pins_desc[i]);
}
del_timer(&buttons_timer);
input_unregister_device(button_dev);
input_free_device(button_dev);
}
module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("eight");
static struct input_dev *button_dev
/*1.分配一个input_device结构体*/
/*参考gpio_keys.c这个例子,可以知道其分配函数是input_allocate_device*/
/*2. 设置*/
/*怎么设置呢,我们来看看这个结构体里面有什么东西*/
static int button_init(void)
{
/*1.分配一个input_device结构体*/
/*参考gpio_keys.c这个例子,可以知道其分配函数是input_allocate_device*/
button_dev = input_allocate_device();
/*2. 设置*/
/*怎么设置呢,我们来看看这个结构体里面有什么东西*/
看看EV_CNT
当有按键产生时,就用input_event上报, input_event会通过input_device里面的handle,然后handle会找到handler,然后就会找到handler里面的event这个函数
input_event(button_dev, EV_KEY, pindesc->key_val, 0); 第一个参数是input_device,第二个参数是哪一类事件,第三个是哪一个按键,最后一个参数是表示按下还是松开,松开的话表示0,按下表示1
写完驱动之后,我们可以ls -l /dev/event* 来看一看我们的原有的事件
crw-rw---- 1 root root 13, 64 Jan 1 12:01 /dev/event0
加载我们的驱动
crw-rw---- 1 root root 13, 64 Jan 1 12:01 /dev/event0
crw-rw---- 1 root root 13, 65 Jan 1 12:06 /dev/event1
原来只有我们的event0,现在多了一个event1
主设备号是13,次设备号是64 这是怎么回事呢
我们之前说过,我们input_register_device input_device会通过handle找到handler 然后调用connect,能不能支持呢,看下evdev.c
看看它的id_tables
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,
};
static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 },/* Matches all devices */
{ }, /* Terminating zero entry */
}; 看这个注释,匹配所有的设备,当然可以支持我们的按键,然后调用connect函数
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->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
我们加载驱动之后
cat /dev/tty1
用hexdump /dev/event1
按下四个按键可以看到一些数字 如图
0000000 061e 0000 7018 0006 0001 002a 0001 0000
0000010 061e 0000 7024 0006 0000 0000 0000 0000
0000020 061e 0000 f495 0009 0001 002a 0000 0000
0000030 061e 0000 f4a4 0009 0000 0000 0000 0000
0000040 061f 0000 f2ed 000d 0001 001c 0001 0000
0000050 061f 0000 f2fd 000d 0000 0000 0000 0000
0000060 0620 0000 9f7e 0002 0001 001c 0000 0000
0000070 0620 0000 9f87 0002 0000 0000 0000 0000
hexdump
hex是16进制 dump就是显示
这个就是读/dev/event1这个设备把里面的数据显示出来
0000000 061e 0000 7018 0006 0001 002a 0001 0000
前面0000000 这可以省略 ,后面的就是数据 061e 0000 这四个字节表示秒 7018 0006这四个字节表示微秒 0001 表示类 002a表示code
0001 0000表示value
0000010 061e 0000 7024 0006 0000 0000 0000 0000这表示同步类事件
那些值分别代表什么意思是怎么知道的 看input_event的定义
还一种方法就是 cat /dev/tty1
ls 后面回车
驱动代码如下
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
static struct input_dev *button_dev;
struct pin_desc{
int irq;
char *name;
unsigned int pin;
unsigned int key_val;
};
struct pin_desc pins_desc[4] = {
{IRQ_EINT(19), "K4", S5PV210_GPH2(3), KEY_L},
{IRQ_EINT(24), "K5", S5PV210_GPH3(0), KEY_S},
{IRQ_EINT(25), "K6", S5PV210_GPH3(1), KEY_ENTER},
{IRQ_EINT(26), "K7", S5PV210_GPH3(2), KEY_LEFTSHIFT},
};
static struct pin_desc *irq_pd;
static struct timer_list buttons_timer;
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
/* 10ms后启动定时器 */
irq_pd = (struct pin_desc *)dev_id;
mod_timer(&buttons_timer, jiffies+HZ/100);
return IRQ_RETVAL(IRQ_HANDLED);
}
static void buttons_timer_function(unsigned long data)
{
struct pin_desc * pindesc = irq_pd;
unsigned int pinval;
if (!pindesc)
return;
pinval = gpio_get_value(pindesc->pin);
if (pinval)
{
/* 松开 : 最后一个参数: 0-松开, 1-按下 */
input_event(button_dev, EV_KEY, pindesc->key_val, 0);
input_sync(button_dev); //还要上报同步时间
}
else
{
/* 按下 */
input_event(button_dev, EV_KEY, pindesc->key_val, 1);
input_sync(button_dev);
}
}
static int button_init(void)
{
int i;
/*1.分配一个input_device结构体*/
/*参考gpio_keys.c这个例子,可以知道其分配函数是input_allocate_device*/
button_dev=input_allocate_device();
/*2.设置*/
/*2.1 表示可以产生按键类事件*/
set_bit(EV_KEY, button_dev->evbit);
set_bit(EV_REP, button_dev->evbit); //能产生重复类事件
/*2.2 能产生这类事件的哪些操作,我们可以取4个按键,功能设置为L,S,ENTER,LEFTSHIT*/
set_bit(KEY_L, button_dev->keybit);
set_bit(KEY_S, button_dev->keybit);
set_bit(KEY_ENTER, button_dev->keybit);
set_bit(KEY_LEFTSHIFT, button_dev->keybit);
/*3 注册*/
input_register_device(button_dev);
/*硬件相关的操作(比如注册中断之类的)*/
/*注册四个中断*/
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
add_timer(&buttons_timer);
//int i;
for (i = 0; i < 4; i++)
{
request_irq(pins_desc[i].irq, buttons_irq, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, pins_desc[i].name, &pins_desc[i]);
}
return 0;
}
static void button_exit(void)
{
int i;
for (i = 0; i < 4; i++)
{
free_irq(pins_desc[i].irq, &pins_desc[i]);
}
del_timer(&buttons_timer);
input_unregister_device(button_dev);
input_free_device(button_dev);
}
module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("eight");
相关文章推荐
- Linux输入子系统(4):设备驱动层实例之按键驱动
- Linux的input输入子系统:设备驱动之按键驱动
- linux驱动开发之输入子系统编程(一)使用工作队列实现中断下半部
- Linux输入子系统(4):设备驱动层实例之按键驱动
- 输入子系统(3):按键驱动实现
- 基于Tiny4412的Linux按键输入子系统驱动的实现(二)
- mini2440 按键驱动添加输入子系统,让按键可以真正当做键盘一样用
- linux输入子系统之按键驱动
- 输入子系统之按键驱动
- MINI2440 按键输入子系统 驱动及测试代码分析
- button_input 输入子系统之按键驱动
- Linux输入子系统——按键驱动实例
- linux输入子系统--按键驱动
- 基于input输入子系统的按键驱动(2.6.22内核)
- 输入子系统—— 按键驱动
- 基于Tiny4412的Linux按键输入子系统驱动的实现(一)
- linux输入子系统之按键驱动
- Linux驱动开发十:按键中断之输入子系统
- linux输入子系统之按键驱动
- input输入子系统之按键驱动