之前在编写字符设备驱动的时候,是从0开始编写的。然而在内核中有许多框架可以直接使用,不需要我们自己去从零编写,比如输入子系统。
输入子系统:当应用程序需要驱动输入设备,比如键盘,鼠标,游戏手柄等,就需要通过输入子系统来实现(当然也依赖于usb子系统)
以前我们的字符设备驱动程序都是通过一个.c文件来实现的,但我们的输入子系统是通过多个文件来实现的,如下图所示:
核心层input.c向应用程序提供接口,纯软件则是做一些比较稳定的,不需要修改的代码,硬件层则是做一些硬件相关的操作。在内核当中已经帮我们把核心层和纯软件的代码写好了,我们只需要写硬件方面的代码。
在我们的开发板上有四个按钮,我们可以分别设置为键盘上的L键、S键、ENTER键和LEFTSHFIT键功能。
#include <linux/module.h>
#include <linux/version.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/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
struct pin_desc { //引脚描述结构体
int irq;
char *name;
unsigned int pin;
unsigned int key_val;
};
static struct input_dev *buttons_dev; //设置input_dev结构体
static struct timer_list buttons_timer; //定时器
static struct pin_desc *pin_pd;
struct pin_desc pins_desc[4] = {
{IRQ_EINT0,"S1",S3C2410_GPF0,KEY_L},
{IRQ_EINT2,"S1",S3C2410_GPF2,KEY_S},
{IRQ_EINT11,"S1",S3C2410_GPG3,KEY_ENTER},
{IRQ_EINT19,"S1",S3C2410_GPG11,KEY_LEFTSHIFT},
};
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
pin_pd = (struct pin_desc *)dev_id;
mod_timer(&buttons_timer, jiffies+HZ/100); //定时时间为10ms
return IRQ_RETVAL(IRQ_HANDLED);
}
static int timer_buttons(unsigned int data)
{
struct pin_desc *pin_irq = pin_pd;
unsigned int pin_val;
pin_val = s3c2410_gpio_getpin(pin_irq->pin); //得到引脚值
if (pin_val) {
input_event(&buttons_dev, EV_KEY, pin_irq->key_val, 0);
input_sync(&buttons_dev);
}
else {
input_event(&buttons_dev, EV_KEY, pin_irq->key_val, 1);
input_sync(&buttons_dev);
}
return 0;
}
static int __init input_buttons_init(void)
{
buttons_dev = input_allocate_device(); //分配输入子系统结构体
set_bit(EV_KEY,buttons_dev->evbit); //设置这个结构体的触发类型为按键
set_bit(EV_REP,buttons_dev->evbit);
set_bit(KEY_L, buttons_dev->keybit); //可输入L、S、ENTER、LEFTSHIFT键
set_bit(KEY_S, buttons_dev->keybit);
set_bit(KEY_ENTER, buttons_dev->keybit);
set_bit(KEY_LEFTSHIFT, buttons_dev->keybit);
input_register_device(&buttons_dev); //注册
timer_init(&buttons_timer);
buttons_timer.function = ;
add_timer(&buttons_timer);
int i;
for (i=0; i<4; i++) {
request_irq(pins_desc[i].irq, buttons_irq, IRQT_BOTHEDGE, pins_desc[i].name, &pins_desc[i]);
}
}
static void __exit input_buttons_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(buttons_dev);
input_free_device(buttons_dev);
}
MODULE_INIT(input_buttons_init);
MODULE_EXIT(input_buttons_exit);
MODULE_LINCENSE("GPL");