Input Subsystem

Introduction to the Input Subsystem Framework

The Input subsystem is a framework in the Linux kernel for managing the event flow of input devices (such as keyboard, mouse, touch screen, etc.). Input devices can be physical devices or software-simulated devices. In Linux, all input devices are represented as input event streams, which are read and passed to userspace by the input subsystem.

The Input subsystem provides the following core functions:

接收和处理输入事件:输入子系统负责接收并处理来自输入设备的输入事件。输入事件包括按键、鼠标移动、滚轮滚动、触摸屏触摸等。

事件过滤和处理:输入子系统支持事件过滤和处理。例如,可以禁用鼠标滚轮,或者将按键事件映射到其他键。

事件传递到用户空间:输入子系统将事件传递到用户空间,以便应用程序可以响应用户的输入。

设备节点的创建:输入子系统为每个输入设备创建一个设备节点,应用程序可以使用设备节点访问输入设备的事件流。

The following is the skeleton of the Input subsystem:

输入设备驱动程序:输入设备驱动程序负责接收来自硬件或软件的输入事件,并将事件传递给输入子系统。输入设备驱动程序通常在内核中作为模块编译,可以在系统启动时加载。输入设备驱动程序需要实现input_dev结构体,并使用input_register_device函数注册设备。

输入子系统核心:输入子系统核心负责管理输入设备和事件流。它包括输入事件的处理、过滤和传递到用户空间的代码。

应用程序:应用程序可以使用读取输入设备节点的方式来访问输入设备的事件流。当输入事件发生时,应用程序可以从输入设备节点中读取事件,并对其进行处理。

设备节点:输入子系统为每个输入设备创建一个设备节点。应用程序可以使用读取设备节点的方式来访问输入设备的事件流。

The input subsystem also provides tools and APIs to make working with input devices easier for application developers. For example, libinput is a userspace library that facilitates handling events from a variety of input devices. Alternatively, there are some command-line tools, such as evtest, that can be used to test and debug input devices.

example demo

The following is an example of an input device driver that uses GPIO buttons, including device tree and application layer interfaces:

Driver code (input-gpio-keys.c):

#include <linux/input.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>

#define DRIVER_NAME "input-gpio-keys"

static struct input_dev *input_dev;
static int gpio_pin;
static int gpio_irq;

static irqreturn_t input_gpio_isr(int irq, void *dev_id)
{
    
    
    int val = gpio_get_value(gpio_pin);
    input_event(input_dev, EV_KEY, KEY_ENTER, val);
    input_sync(input_dev);
    return IRQ_HANDLED;
}

static int input_gpio_probe(struct platform_device *pdev)
{
    
    
    struct device_node *np = pdev->dev.of_node;
    const char *name = np->name;
    int ret;

    ret = of_property_read_u32(np, "gpio-pin", &gpio_pin);
    if (ret) {
    
    
        dev_err(&pdev->dev, "Failed to read gpio-pin property\n");
        return ret;
    }

    gpio_request(gpio_pin, name);
    gpio_direction_input(gpio_pin);
    gpio_irq = gpio_to_irq(gpio_pin);

    ret = request_irq(gpio_irq, input_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, name, NULL);
    if (ret < 0) {
    
    
        dev_err(&pdev->dev, "Failed to request IRQ: %d\n", ret);
        return ret;
    }

    input_dev = input_allocate_device();
    if (!input_dev) {
    
    
        dev_err(&pdev->dev, "Failed to allocate input device\n");
        return -ENOMEM;
    }

    input_dev->name = name;
    input_dev->id.bustype = BUS_HOST;
    input_dev->evbit[0] = BIT_MASK(EV_KEY);
    input_dev->keybit[BIT_WORD(KEY_ENTER)] = BIT_MASK(KEY_ENTER);

    ret = input_register_device(input_dev);
    if (ret) {
    
    
        dev_err(&pdev->dev, "Failed to register input device\n");
        input_free_device(input_dev);
        return ret;
    }

    dev_info(&pdev->dev, "Initialized input-gpio-keys driver\n");
    return 0;
}

static int input_gpio_remove(struct platform_device *pdev)
{
    
    
    input_unregister_device(input_dev);
    free_irq(gpio_irq, NULL);
    gpio_free(gpio_pin);
    return 0;
}

static const struct of_device_id input_gpio_of_match[] = {
    
    
    {
    
     .compatible = "input-gpio-keys" },
    {
    
    },
};
MODULE_DEVICE_TABLE(of, input_gpio_of_match);

static struct platform_driver input_gpio_driver = {
    
    
    .driver = {
    
    
        .name = DRIVER_NAME,
        .of_match_table = input_gpio_of_match,
    },
    .probe = input_gpio_probe,
    .remove = input_gpio_remove,
};

module_platform_driver(input_gpio_driver);

MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("GPIO input driver");
MODULE_LICENSE("GPL");

Device tree code (input-gpio-keys.dts):

/dts-v1/;
#include "gpio-keys.dtsi"

/ {
    
    
    compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
    model = "Raspberry Pi 3 Model B";
    aliases {
    
    
        gpio_keys0 = &gpio_keys;
    };
};

&gpio {
    
    
    gpio_keys {
    
    
        compatible = "input-gpio-keys";
        gpios = <&gpio 17 >;
    gpio-pin = <17>;
    linux,keycode = <28>;
    debounce-interval = <50>;
};

Application layer code:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>

#define DEVICE_NAME "/dev/input/by-path/platform-input-gpio-keys-event"

int main(int argc, char **argv)
{
    
    
    int fd;
    struct input_event ev;

    fd = open(DEVICE_NAME, O_RDONLY);
    if (fd < 0) {
    
    
        printf("Failed to open device\n");
        return -1;
    }

    printf("Press Ctrl-C to exit\n");
    while (1) {
    
    
        read(fd, &ev, sizeof(ev));
        if (ev.type == EV_KEY && ev.code == KEY_ENTER) {
    
    
            printf("Button state: %d\n", ev.value);
        }
    }

    close(fd);
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_31057589/article/details/130412131