一、步骤
1、分配input_dev
2、设置
3、注册
4、硬件相关操作
二、说明
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)];//能产生哪些相对位移事件,x,y,滚轮
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];//能产生哪些绝对位移事件,x,y
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 long evbit[BITS_TO_LONGS(EV_CNT)]可以设置如下时间:
#define EV_SYN 0x00 //表示设备支持所有的事件
#define EV_KEY 0x01 //键盘或者按键,表示一个键码
#define EV_REL 0x02 //鼠标设备,表示一个相对的光标位置结果
#define EV_ABS 0x03 //手写板产生的值,其是一个绝对整数值
#define EV_MSC 0x04 //其他类型
#define EV_LED 0x11 //LED灯设备
#define EV_SND 0x12 //蜂鸣器,输入声音
#define EV_REP 0x14 //允许重复按键类型
#define EV_PWR 0x16 //电源管理事件
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
#define EV_CNT (EV_MAX+1)
三、代码&测试
1、准备key_irq_input.c
#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/gpio_keys.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/spinlock.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <linux/sched.h>
// 操作管脚为gpio14_2
// 该管脚采用boot_sel[1:0]硬件配置复用功能,现单板已经配置为gpio,默认高电平,按键按下为低电平
static void __iomem *key_base; //寄存器基地址
#define gpio_phy_base 0x1214E000 //key管脚物理地址
#define gpio_data key_base + 0x010 //GPIO 数据寄存器 ,0b00_0001_0000
#define gpio_dir key_base + 0x400 //GPIO 方向控制寄存器
#define gpio_is key_base + 0x404 //GPIO 中断触发寄存器
#define gpio_ibe key_base + 0x408 //GPIO 双沿触发中断寄存器
#define gpio_iev key_base + 0x40C //GPIO 触发中断条件寄存器
#define gpio_ie key_base + 0x410 //GPIO 中断屏蔽寄存器
#define gpio_ris key_base + 0x414 //GPIO 原始中断状态寄存器
#define gpio_mis key_base + 0x418 //GPIO 屏蔽状态中断寄存器
#define gpio_ic key_base + 0x41C //GPIO 中断清除寄存器
#define gpio_in 0x00 //配置为输入,1输出 0输入def
#define gpio_out_h 0xFF
#define gpio_out_l 0x00
struct pin_desc
{
int irq;
char *name;
unsigned int pin;
unsigned int key_val;
};
struct pin_desc pins_desc[] =
{
{76, "key_irq", 0x010, KEY_ENTER},
};
static struct input_dev *key_dev_input;
static struct timer_list key_timer;
static struct pin_desc *irq_pd;
static irqreturn_t key_irq(int irq, void *dev_id)
{
//jiffies 为系统中断,10ms中断一次
//HZ为100 (HZ / 100) = 1,jiffies + (HZ / 100) 表示10ms中断一下
irq_pd = (struct pin_desc *)dev_id;
mod_timer(&key_timer, jiffies + (HZ / 100)); //调整定时器时间
iowrite8(0xFF, gpio_ic); //清除中断
return IRQ_HANDLED;
}
static void key_timer_function(unsigned long data)
{
static unsigned int cnt = 0;
unsigned int key;
struct pin_desc *pindesc = irq_pd;
if (!pindesc)
return;
printk("cnt = %d\n", cnt++);
key = ioread8(gpio_data);
printk("key = %d\n", key);
if (key)
{
/* 松开 : 最后一个参数: 0-松开, 1-按下 */
input_event(key_dev_input, EV_KEY, pindesc->key_val, 0);
input_sync(key_dev_input);
}
else
{
/* 按下 */
input_event(key_dev_input, EV_KEY, pindesc->key_val, 1);
input_sync(key_dev_input);
}
}
static int key_irq_input_init(void)
{
int error;
//1、分配一个input_dev结构提
key_dev_input = input_allocate_device();
//2、设置
//2.1能产生哪类事件
set_bit(EV_KEY, key_dev_input->evbit); //按键类型
set_bit(EV_REP, key_dev_input->evbit); //允许重复按键类型
//2.2能产生这类操作的哪些时间
set_bit(KEY_ENTER, key_dev_input->keybit);
//3、注册
error = input_register_device(key_dev_input);
if (error)
{
printk("Unable to register input device, error: %d\n", error);
}
//4、硬件相关操作
key_base = ioremap(gpio_phy_base, 0x1000);
printk("key_data = 0x%x\n", (unsigned int)gpio_data);
iowrite8(gpio_in, gpio_dir); //gpio14_2 配置为输入
iowrite8(0x00, gpio_is); //配置边沿触发
iowrite8(0x00, gpio_iev); //配置下降沿触发
iowrite8(0x04, gpio_ibe); //配置双沿触发
iowrite8(0xFF, gpio_ic); //清除中断
iowrite8(0x04, gpio_ie); //使能gpio14_2中断
init_timer(&key_timer);
key_timer.function = key_timer_function;
add_timer(&key_timer);
//申请按键中断
request_irq(pins_desc[0].irq, key_irq, IRQF_SHARED, pins_desc[0].name, &pins_desc[0]);
return 0;
}
static void key_irq_input_exit(void)
{
free_irq(pins_desc[0].irq, &pins_desc);
del_timer(&key_timer);
input_unregister_device(key_dev_input);
input_free_device(key_dev_input);
}
module_init(key_irq_input_init);
module_exit(key_irq_input_exit);
MODULE_LICENSE("GPL");
2、Makefile参考之前的
3、测试
加载驱动,查看新加模块的主次设备号
/ # insmod key_irq_input.ko
input: Unspecified device as /devices/virtual/input/input0
key_data = 0xfea4e010
/ # ls -l /dev/input/event0
crw------- 1 root root 13, 64 Jan 1 00:05 /dev/input/event0
/ # hexdump /dev/input/event0
cnt = 16
key = 0
0000000 0551 0000 2e89 0009 0001 001c 0001 0000
0000010 0551 0000 2e89 0009 0000 0000 0000 0000
cnt = 17
key = 4
0000020 0551 0000 5149 000b 0001 001c 0000 0000
0000030 0551 0000 5149 000b 0000 0000 0000 0000
参数注解
秒 微秒 类 value
0000000 0551 0000 2e89 0009 0001 001c 0001 0000
0000010 0551 0000 2e89 0009 0000 0000 0000 0000
//KEY_ENTER = 0x1c = 28
//EV_KEY = 0x01 = 0001