Linux学习:输入子系统 input

一、输入子系统

针对输入设备设计:触摸屏、键盘、按键、传感器、鼠标......

二、每种设备都属于字符设备驱动,程序的写法步骤也相同

1、实现入口函数 xxx_init() 和卸载函数 xxx_exit()

2、申请设备号 register_chrdev() --- 与内核相关

3、创建设备文件(节点) class_create() 和 device_create() --- 与内核相关

4、硬件初始化

  GPIO操作 --- 与硬件相关

  注册中断 --- 与硬件相关

  初始化等待队列 --- 与内核相关

  初始化定时器 --- 与内核相关

5、构建 file_operations 结构,实现操作硬件方法 xxx_open/xxx_read... --- 与硬件相关

三、引入输入子系统:

1、不需要每个步骤都编写,只需要编写部分代码即可

2、不同类的输入设备,编写驱动的方式是一样的

3、应用程序读取输入设备的数据结构是统一的

输入设备按照产生的数据的类型进行分类:

1、产生按键数据 --- 每个按键都是一个整数

  按键、键盘

2、产生绝对数据 --- 每个数据都有最大值和最小值

  触摸屏、传感器

3、产生相对数据 --- 某个收据是相对另一个数据的

  鼠标

四、输入子系统的框架

  -------------------------------------------------------------------------------

  应用层:

  -------------------------------------------------------------------------------

  input handler 层:

    知道如何将数据交给用户,不知道如何从硬件获取数据

    driver/input/evdev.c

  -------------------------------------------------------------------------------

  input core 层:

    维护两个链表,和上下两层交互

    /driver/input/input.c

  -------------------------------------------------------------------------------

  input device 层:

    知道如何从硬件获取数据,不知道如何将数据交给用户

  -------------------------------------------------------------------------------

  硬件:

    触摸屏、键盘、鼠标、按键......

  -------------------------------------------------------------------------------

五、输入子系统的驱动编程方法:

1、构建 input device 对象

2、初始化 input device 对象

3、注册 input device 对象

4、硬件初始化

六、描述一个具体的输入设备对象常用的参数:

struct input_dev {
  const char *name;  // 设备名称
  const char *phys;    // 物理路径
  const char *uniq;    // 设备唯一的识别码
  struct input_id id;    // 设备id,如果有多个输入设备,可以通过此id找到需要的设备
    __u16 bustype;    // 总线类型
    __u16 vendor;      // VID
    __u16 product;      // PID
    __u16 version;      // 版本号
  unsigned long evbit[BITS_TO_LONGS(EV_CNT)];  // 设备支持的事件类型
  unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];  // 此设备具有哪些按键
  unsigned long relbit[BITS_TO_LONGS(REL_CNT)];   // 此设备具有相对坐标
  unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];  // 此设备具有相对坐标
  ... ...
  struct device dev; //父类
  struct list_head  h_list;
  struct list_head  node; //节点
};

evbit 是只有 1 个元素的 long 型数组,总共占 32 位,每种类型占一位,存在的就将对应位置 1

unsigned long evbit[BITS_TO_LONGS(EV_CNT)];

keybit 是含 24 个元素的 long 型数组,总共 768 位,最大支持 768 种按键,每一种按键占一位,存在的就将对应位置 1

unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];

七、常用函数

// 上报按键数据

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)

//  同步 (唤醒等待队列  /driver/input/evdev.c -> evdev_event -> wake_up_interruptible(&evdev->wait);)

input_sync(input_key);

input_key_drv.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/irq.h>

static struct input_dev *input_key;
static int irqno;

irqreturn_t input_key_handler(int irqno, void *dev_id)
{
    int value;

    printk("---%s---\n", __FUNCTION__);

    value = gpio_get_value(EXYNOS4_GPX1(1));
//    value = gpio_direction_input(EXYNOS4_GPX1(1));
    printk("---<DRV>--- %d\n", value);
    input_report_key(input_key, KEY_HOME, !value);
    input_sync(input_key);

    return IRQ_HANDLED;
}

static int __init input_key_drv_init(void)
{
    int ret;

    input_key = input_allocate_device();
    if (input_key == NULL)
    {
        printk("input_allocate_device fail!\n");
        return -ENOMEM;
    }

    input_key->name = "input_key";
    input_key->phys = "abcd";
    input_key->uniq = "efgh";
    input_key->id.bustype = BUS_HOST;
    input_key->id.product = 0x1234;
    input_key->id.vendor = 0x5678;
    input_key->id.version = 0x9ABC;

    input_key->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY);
    input_key->keybit[BIT_WORD(KEY_HOME)] |= BIT_MASK(KEY_HOME);

    ret = input_register_device(input_key);
    if (ret != 0)
    {
        printk("input_register_device fail!\n");
        ret = -ENOMEM;
        goto input_free;
    }

    irqno = gpio_to_irq(EXYNOS4_GPX1(1));
    ret = request_irq(irqno, input_key_handler, IRQ_TYPE_EDGE_BOTH, "input_eint9", NULL);
    if (ret < 0)
    {
        printk("request_irq fail!\n");
        ret = -EBUSY;
        goto input_unregister;
    }

    return 0;

input_unregister:
    input_unregister_device(input_key);

input_free:
    input_free_device(input_key);

    return ret;
}

static void __exit input_key_drv_exit(void)
{
    free_irq(irqno, NULL);
    input_unregister_device(input_key);
    input_free_device(input_key);
}

module_init(input_key_drv_init);
module_exit(input_key_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Aaron Lee");

key_app.c

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

#include <linux/input.h>

struct input_event key_info;

int main(void)
{
    int fd;
    int ret;

    fd = open("/dev/input/event1", O_RDWR);
    if (fd < 0)
    {
        perror("open");
        exit(1);
    }

    while (1)
    {
        read(fd, &key_info, sizeof(struct input_event));
        if (key_info.type == EV_KEY)
            if (key_info.code == KEY_HOME)
                printf("---<APP>--- KEY_HOME %s\n", key_info.value ? "down" : "up");
    }

    close(fd);

    return 0;
}
时间: 2024-10-10 00:31:15

Linux学习:输入子系统 input的相关文章

Linux输入子系统(Input Subsystem)

Linux输入子系统(Input Subsystem) http://blog.csdn.net/lbmygf/article/details/7360084 input子系统分析  http://blog.chinaunix.net/uid-27717694-id-3758334.html

linux 的 输入子系统 与 平台设备系统个人理解

首先 ,   输入子系统跟平台设备之间没有必然联系 输入子系统,默认主设备号13,自己使用的时候要定义次设备号 ,输入子系统 ,完成一些复杂的输入功能  ,鼠标,键盘,等等输入.是一些输入设备的合集 平台设备驱动 ,是一种程序框架的,一种方式,将设备驱动的硬件配置,和软件处理分开来写. 具体知道套路就可以了,不用深究 原文地址:https://www.cnblogs.com/niuxiaojie521/p/11127257.html

Linux/Android——输入子系统input_event传递

在前文Linux/Android--usb触摸屏驱动 - usbtouchscreen中记录了如何在kernel中添加input device 类型为touchscreen的驱动, 这在整个输入体系中是最下层的设备驱动部分,往上一层就是linux内核的管理驱动input系统,kernel中的源码位置:/kernel/drivers/input/input.c 撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/42099381 到目前

Linux/Android——输入子系统input_event传递 (二)【转】

本文转载自:http://blog.csdn.net/jscese/article/details/42099381 在前文Linux/Android——usb触摸屏驱动 - usbtouchscreen (一)中记录了如何在kernel中添加input device 类型为touchscreen的驱动, 这在整个输入体系中是最下层的设备驱动部分,往上一层就是linux内核的管理驱动input系统,kernel中的源码位置:/kernel/drivers/input/input.c 撰写不易,转

linux输入子系统(6)-input子系统介绍及结构图

注:本系列转自: http://www.ourunix.org/post/290.html input子系统介绍         输入设备(如按键,键盘,触摸屏,鼠标,蜂鸣器等)是典型的字符设备,其一般的工作机制是底层在按键,触摸等动作发生时产生一个中断(或驱动通过timer定时查询),然后cpu通过SPI,I2C或者外部存储器总线读取键值,坐标等数据,放一个缓冲区,字符设备驱动管理该缓冲区,而驱动的read()接口让用户可以读取键值,坐标等数据.         在Linux中,输入子系统是由

Linux 输入子系统

Technorati 标签: Kernel 输入子系统 Input      在Linux中,输入设备(如按键.键盘.触摸屏.鼠标等)是典型的字符设备,其一般的工作机理,是底层在按键.触摸时,触发一个中断,或者驱动通过定时器定时查询,通过这两种方式通知CPU,CPU然后通过SPI.I2C或I/O接口读取键值.坐标等数据,放入缓冲区,字符设备驱动管理该缓冲区,向上提供read接口供应用程序使用.      在上述的工作流程中,只有终端.读取数值是根具体硬件设备相关,而输入事件的缓冲区管理以及字符设

linux 输入子系统(1) -Event types

输入系统协议用类型types和编码codecs来表示输入设备的值并用此来通知用户空间的应用程序. input协议是一个基于状态的协议,只有当相应事件编码对应的参数值发生变化时才会发送该事件.不过,状态是由Linux的输入子系统进行维护,驱动程序无需维护输入的状态,就算参数值没有变化时向输入子系统发出事件也不会有问题.用户空间可以用linux/input.h 中定义的EVIOCG*ioctls来获得当前事件编码和参数的状态.设备的所支持的上报事件种类也可以通过sysfs的class/input/e

Linux输入子系统(转)

Linux输入子系统(Input Subsystem) 1.1.input子系统概述 输入设备(如按键,键盘,触摸屏,鼠标等)是典型的字符设备,其一般的工作机制是低层在按键,触摸等动作发生时产生一个中断(或驱动通过timer定时查询),然后cpu通过SPI,I2C或者外部存储器总线读取键值,坐标等数据,放一个缓冲区,字符设备驱动管理该缓冲区,而驱动的read()接口让用户可以读取键值,坐标等数据. 在Linux中,输入子系统是由输入子系统设备驱动层.输入子系统核心层(Input Core)和输入

Linux驱动开发之输入子系统

2020-02-15 关键字: Linux 中输入设备大致可分以下几种: 1.按键/键盘(keyboard) 2.鼠标(mouse) 3.触摸屏(touchscreen) 4.游戏杆(joystick) 输入子系统的目的是为了屏蔽众多输入设备在硬件上的差异化,使得在开发输入设备的程序时能更简单统一.输入子系统屏蔽差异的方式就是为各种输入设备与上层应用提供统一的编程接口. Linux 输入子系统是一种编程框架,它可以自上而下分为以下几种层次: 1.应用层 2.input handler层:数据处理