linux高级字符驱动之输入子系统

输入子系统的作用和框架

  • 什么是输入设备
  1. 按键/keyboard
  2. mouse
  3. touchscreen(触摸屏):gt811,ft56xx
  4. joystick 游戏杆
  • 有多个输入设备需要驱动的时候,假如不考虑输入子系统
  1. gt811
    设备号,创建文件,硬件初始化,实现fop,阻塞,硬件初始化(I2C等)
  2. ft56xx
    设备号,创建文件,硬件初始化,实现fop,阻塞,硬件初始化(I2C等).
  • 多个输入设备的共同点
    获取到数据(硬件操作)-------差异化
    上报给用户(xxx_read,copy_to_user,阻塞)------通用
    多个输入设备,有部分差异,也有部分通用
    内核会考虑,将通用代码编写好,将差异化代码留给驱动工程师
  • 设计成输入子系统:使得应用编程人员和驱动编程人员编程的时候变得简单统一
  1. 兼容所有的输入设备
  2. 统一的编程驱动方法(实现差异化的硬件操作)
  3. 统一的应用操作接口:/dev/input/event0,event1, open("/dev/input/event0,event1"),read(fd,struct input_event) :struct input_event buff 可以认为是一个统一的数据包

框架

  • 框架:驱动分为三层
    在这里插入图片描述
    在这里插入图片描述
    input core层和input handler层内核自带的代码,驱动工程师只需要在input device 设备层编程
    编程:在input device 设备层

输入子系统的编程方式

  • 输入子系统的编程方式—学会简单的输入子系统的开发方式
  • 前提:input 核心层代码 和 input handler 层代码需要在内核中必须有
    /drivers/input/input.c //核心层代码
    /drivers/input/evdev.c //event handler
  • make menuconfig
    Device Drivers—>
    Input device support—>
    在这里插入图片描述
    Generic input layer
    Event interface //input handler层 evdev.c

程序编写步骤:
(1)分配一个 input device 对象
(2)初始化 input device 对象
(3)注册 input device 对象

  • 上报数据
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

参数1:当前input device 上报数据
参数2:上报的是那种数据类型 EV_KEY,EV_ABS
参数3:具体数据时什么:KEY_POWER
参数4:值是什么

  • 用户空间读到的数据:统一的数据包
struct input_event
{
    
    
	struct timeval time;   //时间戳
	__u16 type;  //数据类型
	__u16 code;  //具体数据是什么
	__s32 value;  //值是什么
}
  • 代码实例
#include<linux/init.h>
#include<linux/module.h>
#include<linux/input.h>

struct input_dev *inputdev;

static int __init simple_input_init(void)
{
    
    

    //编写输入子系统代码
    /*
     *(1)分配一个 input device 对象
     *(2)初始化 input device 对象
     *(3)注册 input device 对象
     * */

    int ret;
    inputdev = input_allocate_device(); 
    if(inputdev == NULL)
    {
    
    
        printk(KERN_ERR "input allocate device error\n");
        return -ENOMEM;
    }

    //当前设备能够产生按键数据
    __set_bit(EV_KEY,inputdev->evbit);
    //表示当前设备能够产生power按键
    __set_bit(KEY_POWER,inputdev->keybit);

    ret = input_register_device(inputdev);
    if(ret != 0)
    {
    
    
        printk(KERN_ERR "input register device error\n");
        goto err_0;
        return ret;
    }
    return 0;

err_0:
    input_free_device(inputdev);
    return ret;
}



static void __exit simple_input_exit()
{
    
    
    
    input_unregister_device(inputdev);
    input_free_device(inputdev);

}

module_init(simple_input_init);
module_exit(simple_input_exit);
MODULE_LICENSE("GPL");

用户空间应用程序:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>

int main(void)
{
    
    
	int fd;
	int ret;
	struct input_event event;
	
	fd = open("/dev/event0",O_RDWR);
	if(fd < 0)
	{
    
    
		perror("open");
		exit(1);
	}
	
	while(1)
	{
    
    
		ret = read(fd,&event,sizeof(struct input_event));
		if(ret < 0)
		{
    
    
			perror("read");
			exit(1);
		}
		
		if(event.type == EV_KEY)
		{
    
    
			if(event.code == KEY_POWER)
			{
    
    
				if(event.value)   //按键按下
				{
    
    
					printf("__APP_USER__:power pressed\n");
				}
				else  //按键抬起
				{
    
    
					printf("__APP_USER__:power up\n");
				}
			}
		}
	}
	close(fd);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41782149/article/details/99701533