【一】input子系统
【1】input_dev结构体:
struct input_dev {
void *private;
const char *name; //设备名字
const char *phys; //文件路径,比如 input/buttons
const char *uniq;
struct input_id id;
unsigned long evbit[NBITS(EV_MAX)]; //表示支持哪类事件,常用有以下几种事件(可以多选)
//EV_SYN 同步事件,当使用input_event()函数后,就要使用这个上报个同步事件
//EV_KEY 键盘事件
//EV_REL relative相对坐标事件,比如鼠标
//EV_ABS absolute绝对坐标事件,比如摇杆、触摸屏感应
//EV_MSC 其他事件
//EV_LED LED灯事件
//EV_SND sound声音事件
//EV_REP 重复键盘按键事件
//(内部会定义一个定时器,若有键盘按键事件一直按下/松开,就重复定时,时间一到就上报事件)
//EV_FF 受力事件
//EV_PWR 电源事件
//EV_FF_STATUS 受力状态事件
/* 键盘变量定义在:include/linux/input.h, 比如: KEY_L(按键L) */
unsigned long keybit[NBITS(KEY_MAX)]; //存放支持的键盘按键值
unsigned long relbit[NBITS(REL_MAX)]; //存放支持的相对坐标值
unsigned long absbit[NBITS(ABS_MAX)]; //存放支持的绝对坐标值
unsigned long mscbit[NBITS(MSC_MAX)]; //存放支持的其它事件,也就是功能
unsigned long ledbit[NBITS(LED_MAX)]; //存放支持的各种状态LED
unsigned long sndbit[NBITS(SND_MAX)]; //存放支持的各种声音
unsigned long ffbit[NBITS(FF_MAX)]; //存放支持的受力设备
unsigned long swbit[NBITS(SW_MAX)]; //存放支持的开关功能
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
... ...
}
void set_bit(int nr, unsigned long *addr)
功能:设置位图
参数:
@nr 值
@addr 地址
struct input_dev *input_allocate_device(void);
功能:分配input_dev结构体空间
参数:
@void
返回值:成功返回分配好的空间首地址,失败返回NULL
void input_free_device(struct input_dev *dev);
功能:释放input_dev空间
int input_register_device(struct input_dev *);
功能:想内核注册input_dev
参数:
@input_dev结构体指针
返回值:成功返回0,失败返回负数错误码
void input_unregister_device(struct input_dev *);
功能:注销input_dev
注:input是对字符设备驱动的封装,它在底层实现了file_operations
这一套机制而不用我们去填充了,只需按照以上流程即可完成驱动。
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
功能:上报事件
参数:
@dev input_dev结构体指针
@type 事件类型 eg:EV_KEY
@code 具体的类型值 eg:KEY_F1
@value 事件状态值 eg:按下去0,抬起 1
void input_report_key(struct input_dev *dev, unsigned int code, int value)
功能:上报按键事件
参数:
@dev input_dev结构体指针
@code 具体的类型值 eg:KEY_F1
@value 事件状态值 eg:按下去0,抬起 1
void input_sync(struct input_dev *dev)
功能:上报同步事件
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
驱动代码:
/*********************************************************************
*Copyright © 2019 1000phone
*kernel_pthread
*Date and Dition: 2019-05-31 v1.0
*Author:yuwei@1000phone.com
********************************************************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/input.h>
#define DEVCOUNT 3
#define NAME “s5p6818_keys”
#define KEY_A_28 (320 + 28)
#define KEY_B_9 (321 + 9)
#define Debug_log(level)
printk(level “—%s—%s—%d—\n”,FILE,func,LINE)
struct s5p6818_key{
struct task_struct *task;
struct input_dev *xinput;
int irqno0,irqno1;
struct timer_list tm;
};
struct s5p6818_key key;
void key_timer_func(unsigned long args)
{
if(args == key.irqno0){
if(!gpio_get_value(KEY_A_28)){
printk("----KEY_A_28_down----\n");
input_event(key.xinput,EV_KEY,KEY_L,0);
input_sync(key.xinput);
}else{
printk("----KEY_A_28_up----\n");
input_event(key.xinput,EV_KEY,KEY_L,1);
input_sync(key.xinput);
}
}
if(args == key.irqno1){
if(!gpio_get_value(KEY_B_9)){
printk("----KEY_B_9_down----\n");
input_event(key.xinput,EV_KEY,KEY_S,0);
input_sync(key.xinput);
}else{
printk("----KEY_B_9_up----\n");
input_event(key.xinput,EV_KEY,KEY_S,1);
input_sync(key.xinput);
}
}
}
irqreturn_t key_irq_handle(int irq, void *arg)
{
if(irq == key.irqno0){
key.tm.data = irq;
mod_timer(&(key.tm),jiffies+HZ/50);
}
if(irq == key.irqno1){
key.tm.data = irq;
mod_timer(&(key.tm),jiffies+HZ/50);
}
return IRQ_HANDLED;
}
int gpio_keys_open(struct input_dev *dev)
{
Debug_log(KERN_INFO);
return 0;
}
void gpio_keys_close(struct input_dev *dev)
{
Debug_log(KERN_INFO);
}
static int __init demo_init(void)
{
int ret;
key.xinput = input_allocate_device();
if(NULL == key.xinput){
printk(KERN_ERR "input_allocate_device...\n");
ret = -ENOMEM;
goto err0;
}
(key.xinput)->name = "s5p6818_key";
(key.xinput)->phys = "gpio-keys";
(key.xinput)->open = gpio_keys_open;
(key.xinput)->close = gpio_keys_close;
//(key.xinput)->id.bustype = BUS_HOST;
set_bit(EV_KEY,(key.xinput)->evbit);
//set_bit(EV_REL,(key.xinput)->evbit);
set_bit(EV_SYN,(key.xinput)->evbit);
set_bit(KEY_L,(key.xinput)->keybit);
set_bit(KEY_S,(key.xinput)->keybit);
ret = input_register_device((key.xinput));
if(ret < 0){
printk(KERN_INFO "input_register_device failed...\n");
goto err1;
}
key.irqno0 = gpio_to_irq(KEY_A_28);
key.irqno1 = gpio_to_irq(KEY_B_9);
ret = request_irq(key.irqno0,key_irq_handle,IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,\
"key_gpioa28",NULL);
if(ret < 0){
printk(KERN_ERR "request_irq A28 failed...\n");
goto err2;
}
ret = request_irq(key.irqno1,key_irq_handle,IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, \
"key_gpiob9", NULL);
if(ret < 0){
printk(KERN_ERR "request_irq B9 failed...\n");
goto err3;
}
key.tm.expires = 0;
key.tm.function= key_timer_func;
init_timer(&(key.tm));
add_timer(&(key.tm));
Debug_log(KERN_INFO);
return 0;
err3:
free_irq(key.irqno0,NULL);
err2:
input_unregister_device(key.xinput);
err1:
input_free_device(key.xinput);
err0:
return ret;
}
static void __exit demo_exit(void)
{
del_timer(&(key.tm));
free_irq(key.irqno0,NULL);
free_irq(key.irqno1,NULL);
input_unregister_device(key.xinput);
input_free_device(key.xinput);
Debug_log(KERN_INFO);
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“yuwei@1000phone.com”);
MODULE_DESCRIPTION(“This is a demo, about workqueue”);
应用层测试代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdio.h>
#include <errno.h>
struct input_event event;
int main(int argc, const char *argv[])
{
int fd;
fd = open(argv[1] , O_RDWR);
if(fd < 0){
perror(“open”);
return -EINVAL;
}
while(1){
if(!read(fd,&event,sizeof(struct input_event))){
perror(“read”);
return -EINVAL;
}
printf(“type:%d,code:%d,value:%d\n”,event.type,event.code,event.value);
//printf(“code:%d\n”,event.code);
//printf(“value:%d\n”,event.value);
printf("------------------------------------------------------------------------\n");
}
close(fd);
return 0;
}