【嵌入式Linux驱动开发】四、输入设备驱动
2019-07-13 00:16 发布
生成海报
输入设备驱动
1. 输入设备概述
输入设备是向计算机输入数据和信息的设备。像键盘、鼠标、触摸屏等设备,都属于输入设备。
2. 输入设备驱动
在内核***/include/linux/input.h中有个重要的结构体:struct input_dev 。每一个input_dev对象就是一个输入设备。驱动程序就是完成input_dev对象的成员填充和input_dev对象的注册。
重要成员:
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //事件
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //按键映射
unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //相对坐标
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //绝对坐标
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; //led
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; //beep
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
不同的输入设备要使用上述对应的成员,比如按键输入就要操作 unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
3. 重要函数
struct input_dev __must_check *input_allocate_device(void); //创建输入设备对象 void input_free_device(struct input_dev *dev); //释放设备对象 int __must_check input_register_device(struct input_dev *); //注册设备 void input_unregister_device(struct input_dev *); //注销设备 static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_KEY, code, !!value);
} //发送input_event
static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
} //发送哨兵报告,即全0的event
4. qt210按键驱动实例
此驱动程序用qt210开发板上的4个按键模拟键盘“L”、“S”、“ENTER”、“BACKSPACE”。驱动中定时器用于滤波,防止按键按下时多次触发中断。
[objc] view
plain copy print ?
#include
#include
#include
#include //输入设备结构体(struct input_dev)
#include //定时器
#include //函数request_irq()
#include //GPIO寄存器虚拟地址的基地址(S5P_VA_GPIO)
#include //中断号
#define GPH2CON (*(volatile u32*)(S5P_VA_GPIO + 0x0c40))
#define GPH2DAT (*(volatile u32*)(S5P_VA_GPIO + 0x0c44))
#define GPH2PUD (*(volatile u32*)(S5P_VA_GPIO + 0x0c48))
#define GPH3CON (*(volatile u32*)(S5P_VA_GPIO + 0x0c60))
#define GPH3DAT (*(volatile u8*)(S5P_VA_GPIO + 0x0c64))
struct key_info {
int irqno;
const char char *name;
unsigned int code;
};
static struct key_info key[ 4 ] = {
[0 ] = {IRQ_EINT( 2 0 ), "COL4" , KEY_L},
[1 ] = {IRQ_EINT( 2 1 ), "COL5" , KEY_S},
[2 ] = {IRQ_EINT( 2 2 ), "COL6" , KEY_BACKSPACE},
[3 ] = {IRQ_EINT( 2 3 ), "COL7" , KEY_ENTER},
};
struct ldm_info {
struct input_dev *pdev;
struct timer_list timer;
};
static struct ldm_info ldm;
static void timer_handler(unsigned long data)
{
struct key_info *p = ( struct key_info *)data;
input_report_key(ldm.pdev , p->code, !(GPH 2 DAT & ( 1 << (p-key+ 4 ))));
input_sync(ldm.pdev );
}
static irqreturn_t key_isr( int irqno, void void *arg)
{
ldm.timer .data = (unsigned long )arg;
mod_timer(&ldm.timer , jiffies + HZ / 1 0 );
return IRQ_HANDLED;
}
static int key_init( void )
{
int ret = 0 ;
GPH2 CON &= ~( 0 xffff << 1 6 );
GPH2 PUD = (GPH 2 PUD & ~( 0 xff << 8 )) | 0 b 1 0 1 0 1 0 1 0 << 8 ;
GPH3 CON = (GPH 3 CON & ~( 0 xf << 4 )) | 1 << 4 ;
ssize_t i = 0 ;
for (i = 0 ; i < ARRAY_SIZE(key); ++i) {
if ((ret = request_irq(key[i] .irqno , key_isr, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, key[i] .name , ( void *)(key + i))) < 0 ) {
printk("request irq %s failed
" , key[i] .name );
goto err_request_irq;
}
}
return 0 ;
err_request_irq:
for (i = i - 1 ; i >= 0 ; --i) {
free_irq(key[i].irqno , ( void *)(key + i));
}
return ret;
}
static int __init ldm_init( void )
{
printk("%s
" , __FUNCTION__);
int ret = 0 ;
ldm.pdev = input_allocate_device();
if (!ldm .pdev ) {
printk("input_allocate_device failed
" );
ret = -ENOMEM;
goto err_input_allocate_device;
}
ldm.pdev ->evbit[ 0 ] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
ldm.pdev ->keybit[BIT_WORD(KEY_BACKSPACE)] = BIT_MASK(KEY_BACKSPACE);
ldm.pdev ->keybit[BIT_WORD(KEY_ENTER)] |= BIT_MASK(KEY_ENTER);
ldm.pdev ->keybit[BIT_WORD(KEY_L)] |= BIT_MASK(KEY_L);
ldm.pdev ->keybit[BIT_WORD(KEY_S)] |= BIT_MASK(KEY_S);
ret = key_init();
if (ret < 0 ) {
printk("key_init failed
" );
goto err_key_init;
}
init_timer(&ldm.timer );
ldm.timer .function = timer_handler;
ret = input_register_device(ldm.pdev );
if (ret < 0 ) {
printk("input_register_device failed
" );
goto err_input_register_device;
}
return 0 ;
err_input_register_device:
err_key_init:
input_free_device(ldm.pdev );
err_input_allocate_device:
return ret;
}
static void __exit ldm_exit( void )
{
printk("%s
" , __FUNCTION__);
input_unregister_device(ldm.pdev );
ssize_t i = 0 ;
for (i = ARRAY_SIZE(key) - 1 ; i >= 0 ; --i) {
free_irq(key[i].irqno , ( void *)(key + i));
}
input_free_device(ldm.pdev );
}
module_init(ldm_init);
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮