Linux驱动之input输入子系统

简介:

input输入子系统在实际项目中用的也比较多,按键,触摸屏,鼠标,键盘等,用来实现内核层和应用层数据之间的传递,这里得说明不只有input,还有copy_to_user等,利用input的好处是我们用自己上传数据到应用程序, 我们直接上报这个事件发生了,input自带的机制会实现上传的功能。还有很多开源的工具也是基于input输入来制作的,像tslib触摸检测程序和提取数据。


tips:不要启动QT程序,否则会出错,用cat /dev/tty1 来测试。

驱动程序:

/* 参考drivers\input\keyboard\gpio_keys.c */

#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 <linux/kernel.h>/*内核有关的*/
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <asm/uaccess.h>  //copy_to_user
#include <mach/regs-gpio.h>/*寄存器设置*/
#include <mach/hardware.h>//s3c2410_gpio_getpin等的定义
#include <mach/irqs.h> //IRQ_EINT0等的定义
#include <asm/system.h>

struct pin_desc{     /* 定义一个结构体类型 */
int irq;
char *name;
unsigned int pin;
unsigned int key_val;
};

struct pin_desc pins_desc[4] = {      /* 定义这种类型的结构体数组并赋值 */
{IRQ_EINT0,  "S0", S3C2410_GPF0,   KEY_L},
{IRQ_EINT2,  "S2", S3C2410_GPF2,   KEY_S},
{IRQ_EINT3,  "S3", S3C2410_GPF3,   KEY_ENTER},
{IRQ_EINT4,  "S4", S3C2410_GPF4,   KEY_LEFTSHIFT},
};
static struct input_dev *buttons_dev;     /* 定义input_dev类型的结构体指针 */
static struct pin_desc *irq_pd;
static struct timer_list buttons_timer;
static irqreturn_t buttons_irq(int irq, void *dev_id)   /* 定时器,这里用来消除抖动 */
{
/* 10ms后启动定时器 */
irq_pd = (struct pin_desc *)dev_id;
mod_timer(&buttons_timer, jiffies+HZ/100);
return IRQ_RETVAL(IRQ_HANDLED);
}
static void buttons_timer_function(unsigned long data)
{
struct pin_desc * pindesc = irq_pd;
unsigned int pinval;
if (!pindesc)
return;
pinval = s3c2410_gpio_getpin(pindesc->pin);
if (pinval)
{
/* 松开 : 最后一个参数: 0-松开, 1-按下 */
input_event(buttons_dev, EV_KEY, pindesc->key_val, 0);
input_sync(buttons_dev);

}
else
{
/* 按下 */
input_event(buttons_dev, EV_KEY, pindesc->key_val, 1);
input_sync(buttons_dev);

}
}
static int buttons_init(void)   /* 初始化函数,硬件初始化,注册中断,分配内存 */
{
int i;

/* 1. 分配一个input_dev结构体 */
buttons_dev = input_allocate_device();  /*  */
/* 2. 设置 */
/* 2.1 能产生哪类事件 */
set_bit(EV_KEY, buttons_dev->evbit);
//set_bit(EV_REP, buttons_dev->evbit);
/* 2.2 能产生这类操作里的哪些事件: L,S,ENTER,LEFTSHIT */
set_bit(KEY_L, buttons_dev->keybit);
set_bit(KEY_S, buttons_dev->keybit);
set_bit(KEY_ENTER, buttons_dev->keybit);
set_bit(KEY_LEFTSHIFT, buttons_dev->keybit);
/* 3. 注册 */
input_register_device(buttons_dev);

/* 4. 硬件相关的操作 */
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
add_timer(&buttons_timer);
for (i = 0; i < 4; i++)
{
request_irq(pins_desc[i].irq, buttons_irq, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, pins_desc[i].name, &pins_desc[i]);
}
return 0;
}
static void 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(buttons_init);
module_exit(buttons_exit);
MODULE_LICENSE("GPL");


注册input_dev或input_handler时,会两两比较左边的input_dev和右边的input_handler,
根据input_handler的id_table判断这个input_handler能否支持这个input_dev,
如果能支持,则调用input_handler的connect函数建立"连接"


上面调用input上报事件最终都将调用到input_sync最终也将调用input_envent,该代码还有一个问题,细心的朋友应该看到了,怎么没有看到休眠和唤醒之类的代码呢?这些稳定的部分内核里面已经自带了,在input_event里面来实现唤醒的,这些内核在稳定部分已经实现了,我们只需读到数据直接上报就行了,具体应用程序怎么取读是应用层的事情。


unsigned long evbit[NBITS(EV_MAX)];   // 表示能产生哪类事件
unsigned long keybit[NBITS(KEY_MAX)]; // 表示能产生哪些按键
unsigned long relbit[NBITS(REL_MAX)]; // 表示能产生哪些相对位移事件, x,y,滚轮
unsigned long absbit[NBITS(ABS_MAX)]; // 表示能产生哪些绝对位移事件, x,y


#define EV_SYN 0x00      /* 同步类事件 */
#define EV_KEY 0x01/* 按键类事件 */
#define EV_REL 0x02/* 相对位移类事件 */
#define EV_ABS 0x03/* 绝对位移类事件 */


set_bit(EV_KEY, buttons_dev->evbit);                    /* 能产生按键类事件 */
set_bit(EV_REP, buttons_dev->evbit); /* 能产生重复类事件 */


set_bit(KEY_L, buttons_dev->keybit);            /*能产生(KEY_L这些事件*/
set_bit(KEY_S, buttons_dev->keybit);  /*能产生KEY_S这些事件*/
set_bit(KEY_ENTER, buttons_dev->keybit);     /*能产生KEY_ENTER这些事件*/
set_bit(KEY_LEFTSHIFT, buttons_dev->keybit);    /*能产生KEY_LEFTSHIFT这些事件*/

input_sync(buttons_dev);            /* 上报同步类事件 */

测试方法如下:

1. 
hexdump /dev/event1  (open(/dev/event1), read(), )
           秒        微秒    类  code    value
0000000 0bb2 0000 0e48 000c 0001 0026 0001 0000
0000010 0bb2 0000 0e54 000c 0000 0000 0000 0000
0000020 0bb2 0000 5815 000e 0001 0026 0000 0000
0000030 0bb2 0000 581f 000e 0000 0000 0000 0000


2. 如果没有启动QT:
cat /dev/tty1
按:s2,s3,s4
就可以得到ls


或者:
exec 0</dev/tty1                 /* 把标准输入文件改为tty1,0代表标准输入,1代表标准输出,2代表标准错误 */
然后可以使用按键来输入

目录
相关文章
|
2月前
|
Linux API 调度
Linux系统驱动跟裸机驱动的区别
Linux系统驱动跟裸机驱动的区别
31 0
|
2月前
|
Linux C语言 SoC
嵌入式linux总线设备驱动模型分析
嵌入式linux总线设备驱动模型分析
33 1
|
2月前
|
存储 缓存 Linux
【Shell 命令集合 磁盘维护 】Linux 设置和查看硬盘驱动器参数 hdparm命令使用教程
【Shell 命令集合 磁盘维护 】Linux 设置和查看硬盘驱动器参数 hdparm命令使用教程
38 0
|
2月前
|
分布式计算 关系型数据库 MySQL
Sqoop【部署 01】CentOS Linux release 7.5 安装配置 sqoop-1.4.7 解决警告并验证(附Sqoop1+Sqoop2最新版安装包+MySQL驱动包资源)
【2月更文挑战第8天】Sqoop CentOS Linux release 7.5 安装配置 sqoop-1.4.7 解决警告并验证(附Sqoop1+Sqoop2最新版安装包+MySQL驱动包资源)
103 1
|
5天前
|
存储 监控 Linux
【专栏】如何在 Linux 中列出已安装的驱动器?
【4月更文挑战第28天】在 Linux 中,了解已安装驱动器是系统管理的关键。本文介绍了三种方法:1) 使用 `lsblk` 命令显示设备名、大小和类型;2) `fdisk -l` 命令提供详细分区信息;3) `gnome-disks` 等系统管理工具展示驱动器信息。此外,还讨论了驱动器类型识别、挂载点概念及其应用。通过这些方法,用户能有效地监控和管理 Linux 系统中的驱动器。
|
18天前
|
Linux Go
Linux命令Top 100驱动人生! 面试必备
探索Linux命令不再迷茫!本文分10部分详解20个基础命令,带你由浅入深掌握文件、目录管理和文本处理。 [1]: <https://cloud.tencent.com/developer/article/2396114> [2]: <https://pan.quark.cn/s/865a0bbd5720> [3]: <https://yv4kfv1n3j.feishu.cn/docx/MRyxdaqz8ow5RjxyL1ucrvOYnnH>
70 0
|
1月前
|
Linux
Linux驱动运行灯 Heartbeat
Linux驱动运行灯 Heartbeat
12 0
|
2月前
|
Linux
Linux内核中USB设备驱动实现
Linux内核中USB设备驱动实现
28 0
|
2月前
|
编解码 Linux 对象存储
Linux系统中内核音频驱动实现
Linux系统中内核音频驱动实现
74 2