input子系统与实例
Iuput子系统说明
当我们需要编写或调试输入设备时,如keyboard、mouse、touchscreen、joystick,会发现代码会有很多通用的部分,如申请设备号,创建文件,实现fop等操作。内核就会将通用的代码编写好,将差异化的代码留给驱动工程师,使得应用编程人员和驱动编程人员点成的时候变得简单统一。
- Input子系统框架
输入子系统框架可以分为三层,分别是input handler层、input核心层、input dev层。
Input handler层(evdev.c):数据处理者
- 向input.c中注册evdev_handler
- 将evdev_handler添加到链表中
- 实现fops
Input核心层(input.c)
- 注册类
- 在/proc文件系统中创建文件记录信息
- 创建设备
Input dev层:(需要自己编写的)
- 抽象出一个对象,描述设备信息
- 初始化输入设备硬件,获取到数据
- 上报数据
编写步骤:
- 分配输入设备
Inputdev = Input_allocate_device();
- 初始化支持的事件类型和事件码
__set_bit(EV_KEY, inputdev->evbit);
__set_bit(KEY_POWER, inputdev->keybit);
- 注册输入设备
Input_register_device(inputdev);
- 上报数据
Input_event(inputdev, EV_KEY, KEY_POWER, 0);
Input_sync(inputdev);
#include <linux/init.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/gpio_keys.h>
#include <linux/platform_device.h>
#include <linux/fs.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/workqueue.h>
#include <linux/gpio.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/gpio.h>
#define IMX_GPIO_NR(bank, nr) (((bank) -1) * 32 + (nr))
#define GPIO1_31 IMX_GPIO_NR(1,31)
static struct input_dev *inputdev;
struct work_struct my_wq;
void my_wq_func(struct work_struct *work);
struct timer_list my_timer;
int irq;
/*top half*/
static irqreturn_t input_gpio_irq_handler(int irq, void *dev_id)
{
printk(KERN_ALERT "-----------input_gpio_irq_handler------\n" );
schedule_work(&my_wq);
return IRQ_HANDLED;
}
/*bottom half*/
static void my_do_work(struct work_struct *work)
{
gpio_direction_input(GPIO1_31);
//mod_timer(&my_timer, jiffies + HZ/99);
my_timer.expires = jiffies + HZ/100;
add_timer(&my_timer);
}
static void my_timer_function(unsigned long arg)
{
if(!gpio_get_value(GPIO1_31))
{
input_event(inputdev, EV_KEY, KEY_POWER, 0);
input_sync(inputdev);
printk(KERN_ALERT "A\n");
}
else{
input_event(inputdev, EV_KEY, KEY_POWER, 1);
input_sync(inputdev);
printk(KERN_ALERT "B\n");
}
//my_timer.expires = jiffies + HZ/100;
//add_timer(&my_timer);
}
static int __init gpio_input_init(void)
{
printk(KERN_ALERT "-------hsae_gpio_init--------\n");
int ret;
/*分配输入设备*/
inputdev = input_allocate_device();
if (inputdev == NULL)
{
printk(KERN_ALERT "input_allocate_device error!\n");
return -ENOMEM;
}
/*添加/sys/class/event/device信息*/
inputdev->name = "qiwangwang";
inputdev->phys = "gpio-keys/input0";
inputdev->id.bustype = BUS_HOST;
inputdev->id.vendor = 0x0001;
inputdev->id.product = 0x0001;
inputdev->id.version = 0x0100;
/*初始化支持的事件类型*/
__set_bit(EV_KEY, inputdev->evbit);
/*设置支持的事件码*/
__set_bit(KEY_POWER,inputdev->keybit);
/*注册输入设备*/
ret = input_register_device(inputdev);
if (ret != 0)
{
printk(KERN_ALERT "input_register_device error!\n");
goto err_0;
}
/*获取中断号*/
irq = gpio_to_irq(GPIO1_31);
/*注册中断*/
ret = request_irq(irq, input_gpio_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "hsae_gpio_irq", NULL);
if(ret < 0)
{
printk(KERN_ALERT "----request_irq failed----\n");
goto err_1;
}
/*初始化工作队列*/
INIT_WORK(&my_wq, my_do_work);
/*初始化定时器,用于按键消抖*/
init_timer(&my_timer);
my_timer.function = my_timer_function;
//add_timer(&my_timer);
return 0;
err_1:
input_unregister_device(inputdev);
err_0:
input_free_device(inputdev);
return ret;
}
static void __exit gpio_input_exit(void)
{
free_irq(irq, NULL);
del_timer(&my_timer);
input_unregister_device(inputdev);
input_free_device(inputdev);
}
module_init(gpio_input_init);
module_exit(gpio_input_exit);
MODULE_LICENSE("GPL");