linux输入子系统之按键驱动
2016-04-08 11:06
603 查看
上一节中,我们讲解了Linux input子系统的框架,到内核源码里详细分析了输入子系统的分离分层的框架等。
这一节,我们来以输入子系统的框架来写一个按键驱动。
问:怎么写符合输入子系统框架的驱动程序?
答:
1. 分配一个input_dev结构体
2. 设置
3. 注册
4. 硬件相关的代码,比如在中断服务程序里上报事件
问:如何分配input_dev结构体?
答:使用input_allocate_device函数
input_dev结构体的重要成员
[cpp] view
plain copy
print?
struct input_dev {
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
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
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
...
}
问:第二步的设置,应该怎么设置,应该设置什么?
答:举例,在此按键驱动里
[cpp] view
plain copy
print?
/* 2.设置 */
/* 2.1 设置按键能产生哪类事件 */
set_bit(EV_KEY,buttons_dev->evbit);
set_bit(EV_REP,buttons_dev->evbit);
/* 2.2 设置能产生这类操作的哪些事件 */
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);
问:有哪些类呢?
答:在input.h里有以下类
[cpp] view
plain copy
print?
#define EV_SYN 0x00 //同步类
#define EV_KEY 0x01 //按键类
#define EV_REL 0x02 //相对位移类
#define EV_ABS 0x03 //绝对位移类
#define EV_MSC 0x04
#define EV_SW 0x05
#define EV_LED 0x11
#define EV_SND 0x12 //声音类
#define EV_REP 0x14 //重复类
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
#define EV_CNT (EV_MAX+1)
问:如何注册?
答:使用input_register_device(struct input_dev *dev)函数来注册
问:此按键驱动的硬件操作包括哪些操作?
答:申请定时器、申请中断操作
驱动源码:
[cpp] view
plain copy
print?
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/module.h>
#include <linux/device.h> //class_create
#include <mach/regs-gpio.h> //S3C2410_GPF1
//#include <asm/arch/regs-gpio.h>
#include <mach/hardware.h>
//#include <asm/hardware.h>
#include <linux/interrupt.h> //wait_event_interruptible
#include <linux/poll.h> //poll
#include <linux/fcntl.h>
#include <linux/input.h>
static struct pin_desc{
int irq;
unsigned char *name;
unsigned int pin;
unsigned int key_val;
};
static struct pin_desc pins_desc[4] = {
{IRQ_EINT1,"K1",S3C2410_GPF1,KEY_L},
{IRQ_EINT4,"K2",S3C2410_GPF4,KEY_S},
{IRQ_EINT2,"K3",S3C2410_GPF2,KEY_ENTER},
{IRQ_EINT0,"K4",S3C2410_GPF0,KEY_LEFTSHIFT},
};
static struct pin_desc *irq_pd;
static struct input_dev *buttons_dev;
static struct timer_list buttons_timer;
/* 用户中断处理函数 */
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
irq_pd = (struct pin_desc *)dev_id;
/* 修改定时器定时时间,定时10ms,即10秒后启动定时器
* HZ 表示100个jiffies,jiffies的单位为10ms,即HZ = 100*10ms = 1s
* 这里HZ/100即定时10ms
*/
mod_timer(&buttons_timer, jiffies + (HZ /100));
return IRQ_HANDLED;
}
/* 定时器处理函数 */
static void buttons_timer_function(unsigned long data)
{
struct pin_desc *pindesc = irq_pd;
unsigned int pinval;
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_input_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 设置能产生这类操作的哪些事件 */
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.硬件相关的设置 */
/* 4.1 定时器相关的操作 */
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
add_timer(&buttons_timer);
/* 4.2 申请中断 */
for(i = 0;i < sizeof(pins_desc)/sizeof(pins_desc[0]);i++)
{
request_irq(pins_desc[i].irq, buttons_irq, IRQ_TYPE_EDGE_BOTH, pins_desc[i].name, &pins_desc[i]);
}
return 0;
}
/* 驱动出口函数 */
static void buttons_input_exit(void)
{
int i;
for(i = 0;i < sizeof(pins_desc)/sizeof(pins_desc[0]);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_input_init); //用于修饰入口函数
module_exit(buttons_input_exit); //用于修饰出口函数
MODULE_AUTHOR("LWJ");
MODULE_DESCRIPTION("Just for Demon");
MODULE_LICENSE("GPL"); //遵循GPL协议
测试步骤方法一:
[cpp] view
plain copy
print?
[WJ2440]# ls
Qt first_test second_test
TQLedtest fourth_drv.ko sixth_drv.ko
app_test fourth_test sixth_test
bin home sixthdrvtest
buttons_all_drv.ko lib sys
buttons_all_test linuxrc third_drv.ko
buttons_input.ko mnt third_test
dev opt tmp
driver_test proc udisk
etc root usr
fifth_drv.ko sbin var
fifth_test sddisk web
first_drv.ko second_drv.ko
[WJ2440]# ls /dev/event* -l
crw-rw---- 1 root root 13, 64 Jan 2 06:04 /dev/event0
[WJ2440]# insmod buttons_input.ko
input: Unspecified device as /devices/virtual/input/input1
[WJ2440]# ls /dev/event* -l
crw-rw---- 1 root root 13, 64 Jan 2 06:04 /dev/event0
crw-rw---- 1 root root 13, 65 Jan 2 06:06 /dev/event1
[WJ2440]# cat /dev/tty1
[WJ2440]# cat /dev/tty1
ls
ls
输入cat /dev/tty1命令后,顺序按下K1,K2,K3则会显示ls
测试步骤方法二、
[cpp] view
plain copy
print?
[WJ2440]# hexdump /dev/event1
0000000 b738 495d 8456 0007 0001 0026 0001 0000
0000010 b738 495d 846f 0007 0000 0000 0000 0000
0000020 b738 495d 2fb8 000a 0001 0026 0000 0000
0000030 b738 495d 2fc7 000a 0000 0000 0000 0000
分析:
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
[cpp] view
plain copy
print?
struct input_event {
struct timeval time; //时间
__u16 type; //类
__u16 code; //类下事件的值
__s32 value; //0-松开, 1-按下,2-重复
};
struct timeval {
__kernel_time_t tv_sec; //秒
__kernel_suseconds_t tv_usec; //微秒
};
疑问:在韦老师视频里,执行exec 0</dev/tty1 //标准输入改为tty1
我自己执行的时候,发现文件系统里并没有exec可执行文件,也就是busybox里没有移植有exec可执行文件,去找韦老师的文件系统时,也没有发现exec可执行文件,请教各位大虾,如果你有执行成功,请告之,感谢。
这一节,我们来以输入子系统的框架来写一个按键驱动。
问:怎么写符合输入子系统框架的驱动程序?
答:
1. 分配一个input_dev结构体
2. 设置
3. 注册
4. 硬件相关的代码,比如在中断服务程序里上报事件
问:如何分配input_dev结构体?
答:使用input_allocate_device函数
input_dev结构体的重要成员
[cpp] view
plain copy
print?
struct input_dev {
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
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
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
...
}
问:第二步的设置,应该怎么设置,应该设置什么?
答:举例,在此按键驱动里
[cpp] view
plain copy
print?
/* 2.设置 */
/* 2.1 设置按键能产生哪类事件 */
set_bit(EV_KEY,buttons_dev->evbit);
set_bit(EV_REP,buttons_dev->evbit);
/* 2.2 设置能产生这类操作的哪些事件 */
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);
问:有哪些类呢?
答:在input.h里有以下类
[cpp] view
plain copy
print?
#define EV_SYN 0x00 //同步类
#define EV_KEY 0x01 //按键类
#define EV_REL 0x02 //相对位移类
#define EV_ABS 0x03 //绝对位移类
#define EV_MSC 0x04
#define EV_SW 0x05
#define EV_LED 0x11
#define EV_SND 0x12 //声音类
#define EV_REP 0x14 //重复类
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
#define EV_CNT (EV_MAX+1)
问:如何注册?
答:使用input_register_device(struct input_dev *dev)函数来注册
问:此按键驱动的硬件操作包括哪些操作?
答:申请定时器、申请中断操作
驱动源码:
[cpp] view
plain copy
print?
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/module.h>
#include <linux/device.h> //class_create
#include <mach/regs-gpio.h> //S3C2410_GPF1
//#include <asm/arch/regs-gpio.h>
#include <mach/hardware.h>
//#include <asm/hardware.h>
#include <linux/interrupt.h> //wait_event_interruptible
#include <linux/poll.h> //poll
#include <linux/fcntl.h>
#include <linux/input.h>
static struct pin_desc{
int irq;
unsigned char *name;
unsigned int pin;
unsigned int key_val;
};
static struct pin_desc pins_desc[4] = {
{IRQ_EINT1,"K1",S3C2410_GPF1,KEY_L},
{IRQ_EINT4,"K2",S3C2410_GPF4,KEY_S},
{IRQ_EINT2,"K3",S3C2410_GPF2,KEY_ENTER},
{IRQ_EINT0,"K4",S3C2410_GPF0,KEY_LEFTSHIFT},
};
static struct pin_desc *irq_pd;
static struct input_dev *buttons_dev;
static struct timer_list buttons_timer;
/* 用户中断处理函数 */
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
irq_pd = (struct pin_desc *)dev_id;
/* 修改定时器定时时间,定时10ms,即10秒后启动定时器
* HZ 表示100个jiffies,jiffies的单位为10ms,即HZ = 100*10ms = 1s
* 这里HZ/100即定时10ms
*/
mod_timer(&buttons_timer, jiffies + (HZ /100));
return IRQ_HANDLED;
}
/* 定时器处理函数 */
static void buttons_timer_function(unsigned long data)
{
struct pin_desc *pindesc = irq_pd;
unsigned int pinval;
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_input_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 设置能产生这类操作的哪些事件 */
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.硬件相关的设置 */
/* 4.1 定时器相关的操作 */
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
add_timer(&buttons_timer);
/* 4.2 申请中断 */
for(i = 0;i < sizeof(pins_desc)/sizeof(pins_desc[0]);i++)
{
request_irq(pins_desc[i].irq, buttons_irq, IRQ_TYPE_EDGE_BOTH, pins_desc[i].name, &pins_desc[i]);
}
return 0;
}
/* 驱动出口函数 */
static void buttons_input_exit(void)
{
int i;
for(i = 0;i < sizeof(pins_desc)/sizeof(pins_desc[0]);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_input_init); //用于修饰入口函数
module_exit(buttons_input_exit); //用于修饰出口函数
MODULE_AUTHOR("LWJ");
MODULE_DESCRIPTION("Just for Demon");
MODULE_LICENSE("GPL"); //遵循GPL协议
测试步骤方法一:
[cpp] view
plain copy
print?
[WJ2440]# ls
Qt first_test second_test
TQLedtest fourth_drv.ko sixth_drv.ko
app_test fourth_test sixth_test
bin home sixthdrvtest
buttons_all_drv.ko lib sys
buttons_all_test linuxrc third_drv.ko
buttons_input.ko mnt third_test
dev opt tmp
driver_test proc udisk
etc root usr
fifth_drv.ko sbin var
fifth_test sddisk web
first_drv.ko second_drv.ko
[WJ2440]# ls /dev/event* -l
crw-rw---- 1 root root 13, 64 Jan 2 06:04 /dev/event0
[WJ2440]# insmod buttons_input.ko
input: Unspecified device as /devices/virtual/input/input1
[WJ2440]# ls /dev/event* -l
crw-rw---- 1 root root 13, 64 Jan 2 06:04 /dev/event0
crw-rw---- 1 root root 13, 65 Jan 2 06:06 /dev/event1
[WJ2440]# cat /dev/tty1
[WJ2440]# cat /dev/tty1
ls
ls
输入cat /dev/tty1命令后,顺序按下K1,K2,K3则会显示ls
测试步骤方法二、
[cpp] view
plain copy
print?
[WJ2440]# hexdump /dev/event1
0000000 b738 495d 8456 0007 0001 0026 0001 0000
0000010 b738 495d 846f 0007 0000 0000 0000 0000
0000020 b738 495d 2fb8 000a 0001 0026 0000 0000
0000030 b738 495d 2fc7 000a 0000 0000 0000 0000
分析:
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
[cpp] view
plain copy
print?
struct input_event {
struct timeval time; //时间
__u16 type; //类
__u16 code; //类下事件的值
__s32 value; //0-松开, 1-按下,2-重复
};
struct timeval {
__kernel_time_t tv_sec; //秒
__kernel_suseconds_t tv_usec; //微秒
};
疑问:在韦老师视频里,执行exec 0</dev/tty1 //标准输入改为tty1
我自己执行的时候,发现文件系统里并没有exec可执行文件,也就是busybox里没有移植有exec可执行文件,去找韦老师的文件系统时,也没有发现exec可执行文件,请教各位大虾,如果你有执行成功,请告之,感谢。
相关文章推荐
- Linux true --空操作,设置退出码为0
- Linux tree --以树状图列出目录的内容
- Linux trap --在脚本中处理信号
- Linux time --测定一个命令的资源使用情况
- Linux test --检查文件和比较值
- Linux telnet --基于TELNET协议的远程登录工具
- Linux文件处理命令
- Linux tee --重定向输出到多个文件
- Linux tar --解压缩工具
- 1.4 linux安装mysql5.7.11
- CentOS7修改设置静态IP和DNS
- linux下 为自己编写的程序 添加tab自动补全 功能
- openssl 升级 /etc/ld.so.conf文件 Linux 动态静态库
- Linux tac --与cat相反的命令
- Linux sync --强制将内存中的文件缓冲内容写到磁盘
- linux暴力密码破解工具hydra安装与使用
- Linux source --重新执行刚修改的初始化文件
- Linux sort --将文本文件内容加以排序
- Linux stat --显示文件或文件系统状态
- Linux ss --获取socket统计信息及显示netstat类型的内容