Linux系统提供了input子系统,按键、触摸屏、键盘、鼠标等输入都可以利用input接口函数来实现设备驱动。
在Linux内核中,input设备用input_dev结构体描述,使用input子系统实现输入设备驱动的时候,驱动的核心工作是向系统报告按键、触摸屏、键盘、鼠标等输入事件(event,通过input_event结构体描述),不再需要关心文件操作接口,因为input子系统已经完成了文件操作接口。
具体可参考http://blog.csdn.net/ylyuanlu/article/details/6704744
驱动程序代码如下
-
//moudle.h 包含了大量加载模块需要的函数和符号的定义
-
#include <linux/module.h>
-
//kernel.h以便使用printk()等函数
-
#include <linux/kernel.h>
-
//fs.h包含常用的数据结构,如struct file等
-
#include <linux/fs.h>
-
//uaccess.h 包含copy_to_user(),copy_from_user()等函数
-
#include <linux/uaccess.h>
-
//io.h 包含inl(),outl(),readl(),writel()等IO口操作函数
-
#include <linux/io.h>
-
#include <linux/miscdevice.h>
-
#include <linux/pci.h>
-
//init.h来指定你的初始化和清理函数,例如:module_init(init_function)、module_exit(cleanup_function)
-
#include <linux/init.h>
-
#include <linux/delay.h>
-
#include <linux/device.h>
-
#include <linux/cdev.h>
-
#include <linux/gpio.h>
-
#include <linux/irq.h>
-
#include <linux/sched.h>
-
#include <linux/interrupt.h>
-
#include <linux/poll.h>
-
#include <linux/input.h>
-
//irq.h中断与并发请求事件
-
#include <asm/irq.h>
-
//下面这些头文件是IO口在内核的虚拟映射地址,涉及IO口的操作所必须包含
-
//#include <mach/gpio.h>
-
#include <mach/regs-gpio.h>
-
#include <plat/gpio-cfg.h>
-
#include <mach/hardware.h>
-
#include <mach/map.h>
-
-
static struct timer_list button_timer;//定时器
-
static struct input_dev *button_dev;//输入子系统设备
-
-
struct pin_desc {
-
int irq;
-
char *name;
-
unsigned int pin;
-
unsigned int button_val;
-
};
-
-
static struct pin_desc pins_desc[6] = {
-
{IRQ_EINT(0), "S1", S3C64XX_GPN(0), KEY_L},
-
{IRQ_EINT(1), "S2", S3C64XX_GPN(1), KEY_S},
-
{IRQ_EINT(2), "S3", S3C64XX_GPN(2), KEY_ENTER},
-
{IRQ_EINT(3), "S4", S3C64XX_GPN(3), KEY_LEFTSHIFT},
-
{IRQ_EINT(4), "S5", S3C64XX_GPN(4), KEY_BACKSPACE},
-
{IRQ_EINT(5), "S6", S3C64XX_GPN(5), KEY_SPACE},
-
};
-
-
static struct pin_desc *irq_pd;
-
-
/*中断服务函数*/
-
static irqreturn_t button_input_irq(int irq, void *dev_id)
-
{
-
/* 10ms后启动定时器 */
-
irq_pd = (struct pin_desc *)dev_id;
-
mod_timer(&button_timer, jiffies+HZ/100); //jiffies是系统的定时器时间,HZ/100表示10ms
-
-
return IRQ_HANDLED;
-
}
-
-
static void button_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->button_val, 0);
-
-
input_sync(button_dev);
-
}
-
else
-
{
-
/* 按下 */
-
-
input_event(button_dev, EV_KEY, pindesc->button_val, 1);
-
-
input_sync(button_dev);
-
}
-
}
-
-
-
static int button_input_init(void)
-
{
-
int i, ret;
-
-
-
-
/* 1. 分配一个input_dev结构体 */
-
-
button_dev = input_allocate_device();;
-
-
-
-
/* 2. 设置 */
-
-
/* 2.1 能产生哪类事件 */
-
-
set_bit(EV_KEY, button_dev->evbit);//按键类事件
-
-
set_bit(EV_REP, button_dev->evbit);//重复类事件
-
-
-
-
/* 2.2 能产生这类操作里的哪些事件: L,S,ENTER,LEFTSHIT,BACKSPACE,SPACE */
-
-
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);
-
-
set_bit(KEY_BACKSPACE, button_dev->keybit);
-
-
set_bit(KEY_SPACE, button_dev->keybit);
-
-
-
-
/* 3. 注册 */
-
ret = input_register_device(button_dev);
-
-
if( ret )
-
{
-
printk("input_register_device error!\n");
-
return -EFAULT;
-
}
-
-
-
-
/* 4. 硬件相关的操作 */
-
-
init_timer(&button_timer);//初始化定时器
-
button_timer.function = button_timer_function;//设置定时器处理函数
-
add_timer(&button_timer);
-
-
-
-
for (i = 0; i < 6; i++)
-
-
{
-
ret = request_irq(pins_desc[i].irq, button_input_irq, IRQ_TYPE_EDGE_BOTH, pins_desc[i].name, &pins_desc[i]);
-
-
if( ret )
-
{
-
printk("request IRQ_EINT(%d) error!\n",i);
-
free_irq(IRQ_EINT(i), &pins_desc[i]);
-
}
-
-
}
-
-
-
-
return 0;
-
}
-
-
static void button_input_exit(void)
-
{
-
int i;
-
-
for (i = 0; i < 6; i++)
-
-
{
-
-
free_irq(pins_desc[i].irq, &pins_desc[i]);
-
-
}
-
-
-
-
del_timer(&button_timer);
-
-
input_unregister_device(button_dev);
-
-
input_free_device(button_dev);
-
}
-
-
module_init(button_input_init);
-
module_exit(button_input_exit);
-
-
MODULE_LICENSE("GPL");
阅读(1250) | 评论(0) | 转发(0) |