Linux之Input驱动总结

Linux之Input驱动总结

--本贴所贴代码均在mtk系统上完成测试

对于嵌入式产品而言,人机交互的一部分“输入设备”扮演了一个不可或缺的角色,下面来分析在Linux下的输入设备。

一、概述Linux下的input设备

所有的用于对设备进行输入操作的设备,如:鼠标、触摸屏、摇杆、键盘等都是输入设备,这种设备在Linux都是典型的字符设备。其工作机制一般都是输入操作产生一个外部中断或通过查询扫描当前状态,然后启动某种通信方式来获取按键值或坐标值或状态值放在一个缓冲区,字符设备驱动管理该缓冲区,而驱动的read()接口让用户可以读取键值,坐标等数据。

贴一下ipnut设备在Linux下的官方结构图,方便理解:



(这些都是官方的表述,虽然枯燥,但是仔细体会后能有所收获)。

这是输入子系统的组成结构,它是由输入子系统设备驱动层、输入子系统核心层(Input Core)和输入子系统事件处理层(Event Handler)组成。其中设备驱动层提供对硬件各寄存器的读写访问和将底层硬件对用户输入访问的响应转换为标准的输入事件,再通过核心层提交给事件处理层;而核心层对下提供了设备驱动层的编程接口,对上又提供了事件处理层的编程接口;而事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口和驱动层提交来的事件处理。所以这使得我们输入设备的驱动部分不在用关心对设备文件的操作,而是要关心对各硬件寄存器的操作和提交的输入事件。

下图是Linux下的input系统的分层图:


二、input驱动程序分析

Input设备的最重要的结构体是input_dev结构体,它定义在input.h文件中,它包含了你所要该输入设备驱动的所有信息,包括一些api的接口;下面按照下面的步骤我们创建一个在混杂设备驱动中注册的input设备,在源码中分析一些重要接口函数

1)、分配一个输入子设备;

2)、在驱动模块加载函数中设置Input设备支持input子系统的哪些事件;

3)、将Input设备注册到input子系统中;

4)、在Input设备发生输入操作时(如:键盘被按下/抬起、触摸屏被触摸/抬起/移动、鼠标被移动/单击/抬起时等),提交所发生的事件及对应的键值/坐标等状态

5)、释放和卸载。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <mach/hardware.h>
#include <linux/device.h>

#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/kobject.h>
#include <linux/earlysuspend.h>
#include <linux/platform_device.h>
#include <asm/atomic.h>

#define DEVICE_NAME "Driver_Modules"    //在dev下的,该misc设备节点名称
#define ON 1
#define OFF 0

static struct input_dev *Modules_input_dev;

//在这个ioctl函数中做的事情就是发送一个 音量+的press和reless两个状态。
static long Driver_ioctl(struct file *file, unsigned int cmd,unsigned long arg)   
{
    long err = 0;
    printk("[Modules]Driver_ioctl\n");
    input_report_key(Modules_input_dev, KEY_VOLUMEUP, 1);  
  input_sync(Modules_input_dev);
    //发送按键状态就这两个,报告按键状态及按键值,然后报告同步事件。。
    input_report_key(Modules_input_dev, KEY_VOLUMEUP, 0);
    input_sync(Modules_input_dev);
    return err;
}

static int Driver_open(struct inode *inode, struct file *file)
{
    int  err = 0;
    printk("[Modules]Driver_open\n");

    return err ;
}

static int Driver_close(struct inode *inode, struct file *file)
{
    int  err = 0;
    printk("[Modules]Driver_close\n");
    return err ;
}

static int Modules_input_open(struct input_dev *dev)
{
    printk("[Modules]Modules_input_open\n");
    return 0;
}
 //在这个结构体我想就不用介绍了,熟悉字符设备驱动的人都知道这个东西,所有应用层
 //对驱动层的操作都是通过这里实现的。
static struct file_operations DriverModules_ops = {
    .owner = THIS_MODULE,
    .open = Driver_open,
    .release = Driver_close, 
    .unlocked_ioctl = Driver_ioctl,
};

static struct miscdevice DriverModules_misc_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,
    .fops = &DriverModules_ops,
};

static int __init Driver_init(void)
{
    int ret,r;
//完成对input设备的正常操作,下面的注册是最重要的。    Modules_input_dev = input_allocate_device();   //分配一个输入设备
    if (!Modules_input_dev)
        return -ENOMEM;//描述一些input设备的信息,通过cat /proc/bus/input/devices 命令可以查看所有的input设备的信息
    Modules_input_dev->name = "Modules_input";  //input设备的名称    
    Modules_input_dev->id.bustype = BUS_HOST;   //总线类型
    Modules_input_dev->id.vendor = 0x8888;       //产家编号
    Modules_input_dev->id.product = 0x6575;    //产品编号
  Modules_input_dev->id.version = 0x0010;     //版本信息
  
  Modules_input_dev->open = Modules_input_open;  //指定一个该设备的接口
  
  __set_bit(EV_KEY, Modules_input_dev->evbit);    //添加事件的支持,告诉系统将要支持哪些事件,下面再详细介绍。
//按键事件下所支持的按键值
    __set_bit(KEY_VOLUMEDOWN, Modules_input_dev->keybit);
    __set_bit(KEY_VOLUMEUP, Modules_input_dev->keybit);

//完成对一个输入设备的注册
    r = input_register_device(Modules_input_dev);
    if (r) 
    {
        printk("[Modules]register input device failed (%d)\n", r);
        input_free_device(Modules_input_dev);//释放输入设备
        return r;
  }
//注册一个混杂的字符设备,这种注册方式会自动创建设备节点(属于一种特殊的字符设备驱动),它的主设备号是10,注册成功会返回0,注册失败会返回一个错误码;
  ret = misc_register(&DriverModules_misc_dev); 
  if (ret)
   {
        printk("[Modules]register  misc_register failed (%d)\n", ret);
        input_unregister_device(Modules_input_dev);
        return ret;
    }

    printk("[Modules]Driver Modules init \n"); 

}

static void __exit Driver_exit(void)
{
    misc_deregister(&DriverModules_misc_dev);  //卸载混杂设备
    input_unregister_device(Modules_input_dev);  //卸载输入设备
    printk("[Modules]Driver Modules exit \n"); 
}
module_init(Driver_init);
module_exit(Driver_exit);

MODULE_AUTHOR("tangh in szsimtech"); 
MODULE_DESCRIPTION("char Driver modules"); 
MODULE_LICENSE("GPL");

下面的补充我也是找了贴上去的,至于这个两种上报方式有啥区别,我没去深究,在以后用的时候再做补充吧(或者好心网友帮我补充也行)。。。。

**__set_bit(EV_KEY, Modules_input_dev->evbit);
Struct input_dev中有两个成员,一个是evbit;一个是keybit.分别用来表示设备所支持的事件类型和按键类型。
Linux中输入设备的事件类型有(这里只列出了常用的一些,更多请看linux/input.h中):EV_SYN     0x00     同步事件
EV_KEY     0x01     按键事件
EV_REL     0x02     相对坐标                        
EV_ABS     0x03     绝对坐标
EV_MSC     0x04     其它
EV_LED     0x11     LED
EV_SND     0x12     声音
EV_REP     0x14     Repeat
EV_FF      0x15     力反馈

//报告指定type,code的输入事件
Void input_event(struct input_dev *dev,unsigned int type,unsigned int code,int value);
//报告键值
Void input_report_key(struct input_dev *dev,unsigned int code,int value);
//报告相对坐标
Void input_report_rel(struct input_dev *dev,unsigned int code,int value);
//报告绝对坐标
Void input_report_abs(struct input_dev *dev,unsigned int code,int value);Void input_sync(struct input_dev *dev);//报告同步事件
在触摸屏驱动设计中,一次坐标及按下状态的整个报告过程如下:
Input_report_abs(input_dev,ABS_X,x);//X坐标
Input_report_abs(input_dev,ABS_Y,y);//Y坐标
Input_report_abs(input_dev,ABS_PRESSURE,pres);//压力
input_sync(struct input_dev *dev);//同步

三、虚拟按键的处理

开始我还不知道有这么一部分,在mtk驱动里面,细心 的工程师发现在触摸屏的驱动里面上报ctp按键消息就是通过这种方式实现的,也就是说你给一些坐标返回和对应的按键值,由上层自己完成对消息的处理,那么在CTP驱动里面只关系到发送坐标数据就OK了。
这个也是初步理解,具体的实现部分还没做整理。。。。

四、测试

最后一部分就是如何测试,如果只是在linux的环境下完全是处理方式,在android下也可以同样的方式编译出一个可执行的文件,只不过你要去自己去写一个Android.mk.我有一个自己的测试程序,也可以在网上找一个,有需求的话再贴在上面吧。












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值