input设备驱动开发

1. 作为输入设备的驱动开发者,需要做以下几步:

        在驱动加载模块中,设置你的input设备支持的事件类型,类型参见表1设置;

        注册中断处理函数,例如键盘设备需要编写按键的抬起、放下,触摸屏设备需要编写按下、抬起、绝对移动,鼠标设备需要编写单击、抬起、相对移动,并且需要在必要的时候提交硬件数据(键值/坐标/状态等等);

        将输入设备注册到输入子系统中。

表1:事件类型

EV_SYN     0x00    同步事件
EV_KEY     0x01    按键事件
EV_REL     0x02    相对坐标(如:鼠标移动,报告相对最后一次位置的偏移)
EV_ABS     0x03    绝对坐标(如:触摸屏或操作杆,报告绝对的坐标位置)
EV_MSC     0x04    其它
EV_SW      0x05    开关
EV_LED     0x11    按键/设备灯
EV_SND     0x12    声音/警报
EV_REP     0x14    重复
EV_FF     0x15    力反馈
EV_PWR    0x16    电源
EV_MAX    0x1f    事件类型最大个数和提供位掩码支持
EV_FF_STATUS    0x17   力反馈状态

        Linux输入子系统提供了设备驱动层上报输入事件的函数,在include/linux/input.h中:

//上报按键事件
voidinput_report_key(struct input_dev *dev, unsigned int code, int value); 

//上报相对坐标事件
voidinput_report_rel(struct input_dev *dev, unsigned int code, int value);
 
//上报绝对坐标事件
voidinput_report_abs(struct input_dev *dev, unsigned int code, int value);

        当上报输入事件之后,需要调用下面的函数来通知输入子系统,以处理设备产生的完整事件:

void input_sync(struct input_dev *dev);

        输入子系统的一些位操作NBITS、BIT、LONG经常被用到:

#define NBITS(x) (((x)/BITS_PER_LONG)+1)       //通过位x获取数组的长度
#define BIT(x)   (1UL<<((x)%BITS_PER_LONG))    //返回位x在数组中的位域
#define LONG(x)  ((x)/BITS_PER_LONG)           //返回位x的索引

2. 输入设备驱动的简单案例

        在Linux内核文档的documentation/input下,有一个input-programming.txt文件,讲解了编写输入设备驱动程序的核心步骤。

        提供的案例代码描述了一个button设备,当有按下/释放发生时,BUTTON_IRQ被触发,产生的事件通过BUTTON_PORT引脚获取(即把BUTTON_PORT引脚的电平状态上报),以下是驱动的源代码:

#include <linux/input.h>                                                                                                        
#include <linux/module.h>
#include <linux/init.h>
#include <asm/irq.h>
#include <asm/io.h>

static struct input_dev *button_dev;

//由于案例代码只产生一个按键的值,因此input_sync()在这里不起关键作用。但如果是
//一个触摸屏,即有x坐标和y坐标,则需要通过input_sync()函数把x和y坐标完整地传递
//给输入子系统。
static void button_interrupt(int irq, void*dummy, struct pt_regs *fp)
{
        input_report_key(button_dev, BTN_1, inb(BUTTON_PORT) & 1);
        input_sync(button_dev);
}      
 
static int __init button_init(void)
{
       int error;
       
       if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button",NULL)) {
                printk(KERN_ERR"button.c: Can't allocate irq %d\n", button_irq);
                return -EBUSY;
       }      
        
       button_dev = input_allocate_device();
       if (!button_dev) {
               printk(KERN_ERR"button.c: Not enough memory\n");
               error = -ENOMEM;
               goto err_free_irq;
       }
 
       /* 上报事件类型定为按键 */
       button_dev->evbit[0] = BIT(EV_KEY);
       button_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);

//把button_dev输入设备挂入输入设备链表中,并且通知事件处理层调用connect函数完成
//设备和事件处理(handler)的绑定,当用户打开设备时,便能够调用到相应的事件处理接口
//获得硬件上报的数据了 */
       error = input_register_device(button_dev);
       if (error) {
                printk(KERN_ERR"button.c: Failed to register device\n");
                goto err_free_dev;
       }
       return 0;

err_free_dev:
       input_free_device(button_dev);
err_free_irq:
       free_irq(BUTTON_IRQ, button_interrupt);
       return error;
}
 
static void __exit button_exit(void)
{
      input_unregister_device(button_dev);
      free_irq(BUTTON_IRQ, button_interrupt);
}
 
module_init(button_init);
module_exit(button_exit);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值