Maison  >  Article  >  Tutoriel système  >  Introduction au sous-système d'entrée Linux

Introduction au sous-système d'entrée Linux

WBOY
WBOYavant
2024-02-13 13:09:12781parcourir

Le sous-système d'entrée Linux est un ensemble de pilotes qui prennent en charge tous les périphériques d'entrée du système Linux, notamment les claviers, les souris, les écrans tactiles, les tablettes, les contrôleurs de jeu, etc. Le cœur du sous-système d'entrée est le module d'entrée, qui est responsable de la transmission des événements entre les deux types de modules :

  • Modules de pilote de périphérique : ces modules communiquent avec le matériel (par exemple via USB) et fournissent des événements (appuis sur des touches, mouvements de la souris, etc.) au module d'entrée.
  • Modules de gestion d'événements : ces modules récupèrent les événements du module d'entrée et les transmettent là où ils sont nécessaires (par exemple, noyau, GPM, X, etc.) via diverses interfaces.

Dans cet article, nous présenterons les concepts de base et la structure du sous-système d'entrée Linux, ainsi que certaines commandes et outils couramment utilisés. Nous utiliserons Ubuntu 20.04 comme exemple de système, mais le contenu s'applique également à d'autres distributions Linux.

Introduction au sous-système dentrée Linux

Couche pilote

Convertissez l'entrée matérielle sous-jacente en un formulaire d'événement unifié et signalez-la à l'Input Core.

Couche centrale du sous-système d'entrée

Il fournit à la couche pilote des interfaces d'enregistrement et de fonctionnement du périphérique d'entrée, telles que : input_register_device ; notifie la couche de traitement des événements pour traiter l'événement ; génère les informations de périphérique correspondantes sous /Proc.

Couche de traitement des événements

Interagit principalement avec l'espace utilisateur (sous Linux, tous les périphériques sont traités comme des fichiers dans l'espace utilisateur. Puisque l'interface fops est fournie dans les pilotes généraux et que le nœud de fichier de périphérique correspondant est généré sous /dev, ces L'opération est complétée par le traitement des événements couche dans le sous-système d’entrée).

Description de l'appareil

La structure input_dev consiste à implémenter le travail de base du pilote de périphérique : signaler les pressions sur les touches, les écrans tactiles et autres événements d'entrée (événements, décrits via la structure input_event) au système, et n'a plus besoin de se soucier de l'interface d'exploitation des fichiers. Le pilote signale les événements à l'espace utilisateur via inputCore et Eventhandler.

Fonction d'enregistrement du périphérique d'entrée :

int input_register_device(struct input_dev *dev)

Fonction de désenregistrement du périphérique d'entrée :

void input_unregister_device(struct input_dev *dev)

Implémentation du pilote - initialisation (prise en charge des événements) set_bit() indique au sous-système d'entrée quels événements et clés sont pris en charge. Par exemple :

set_bit(EV_KEY,button_dev.evbit)  (其中button_dev是struct input_dev类型)
Il y a deux membres dans

struct input_dev**** :
**1)** Type d'événement evbit (y compris EV_RST, EV_REL, EV_MSC, EV_KEY, EV_ABS, EV_REP, etc.).
**2)**Type de clé keybit (y compris BTN_LEFT, BTN_0, BTN_1, BTN_MIDDLE, etc. lorsque le type d'événement est EV_KEY).

Implémentation du pilote - reporting des événements Les fonctions utilisées pour signaler les événements EV_KEY, EV_REL, EV_ABS sont :

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)

Implémentation du pilote - la synchronisation input_sync() de fin de rapport est utilisée pour indiquer au sous-système principal d'entrée que le rapport est terminé. Dans le pilote de périphérique à écran tactile, l'ensemble du processus de reporting en un seul clic est le suivant :

input_reprot_abs(input_dev,ABS_X,x);   //x坐标
input_reprot_abs(input_dev,ABS_Y,y);   // y坐标
input_reprot_abs(input_dev,ABS_PRESSURE,1);
input_sync(input_dev);//同步结束

Exemple d'analyse (programme d'interruption de clé) :

//按键初始化
static int __init button_init(void)
{//申请中断
    if(request_irq(BUTTON_IRQ,button_interrupt,0,”button”,NUll))
        return –EBUSY;
    set_bit(EV_KEY,button_dev.evbit); //支持EV_KEY事件
    set_bit(BTN_0,button_dev.keybit); //支持设备两个键
    set_bit(BTN_1,button_dev.keybit); //
    input_register_device(&button_dev);//注册input设备
}
/*在按键中断中报告事件*/
Static void button_interrupt(int irq,void *dummy,struct pt_regs *fp)
{
    input_report_key(&button_dev,BTN_0,inb(BUTTON_PORT0));//读取寄存器BUTTON_PORT0的值
    input_report_key(&button_dev,BTN_1,inb(BUTTON_PORT1));
    input_sync(&button_dev);
}

Résumé : Le sous-système input est toujours un pilote de périphérique de caractères, mais la quantité de code est considérablement réduite. Le sous-système ****input n'a besoin d'effectuer que deux tâches : l'initialisation et le rapport d'événements (ici dans linux*. *** est obtenu grâce à des interruptions).

Instances

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

struct input_dev *button_dev;
struct button_irq_desc {
    int irq;
    int pin;
    int pin_setting;
    int number;
    char *name;
};

/*定义一个结构体数组*/
static struct button_irq_desc button_irqs [] = {
    {IRQ_EINT8 , S3C2410_GPG0 , S3C2410_GPG0_EINT8 , 0, "KEY0"},
    {IRQ_EINT11, S3C2410_GPG3 , S3C2410_GPG3_EINT11 , 1, "KEY1"},
    {IRQ_EINT13, S3C2410_GPG5 , S3C2410_GPG5_EINT13 , 2, "KEY2"},
    {IRQ_EINT14, S3C2410_GPG6 , S3C2410_GPG6_EINT14 , 3, "KEY3"},
    {IRQ_EINT15, S3C2410_GPG7 , S3C2410_GPG7_EINT15 , 4, "KEY4"},
    {IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_EINT19, 5, "KEY5"},
};

static int key_values = 0;
static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
    struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
    int down;
    udelay(0);
/*获取按键值*/
down = !s3c2410_gpio_getpin(button_irqs->pin); //down: 1(按下),0(弹起)
if (!down) {
    /*报告事件*/
    key_values = button_irqs->number;
    //printk("====>rising key_values=%d\n",key_values);
    if(key_values==0)
        input_report_key(button_dev, KEY_1, 0);
    if(key_values==1)
        input_report_key(button_dev, KEY_2, 0);
    if(key_values==2)
        input_report_key(button_dev, KEY_3, 0);
    if(key_values==3)
        input_report_key(button_dev, KEY_4, 0);
    if(key_values==4)
        input_report_key(button_dev, KEY_5, 0);
    if(key_values==5)
        input_report_key(button_dev, KEY_6, 0);
    /*报告结束*/
    input_sync(button_dev);
    }
else {
    key_values = button_irqs->number;
    //printk("====>falling key_values=%d\n",key_values);
    if(key_values==0)
        input_report_key(button_dev, KEY_1, 1);
    if(key_values==1)
        input_report_key(button_dev, KEY_2, 1);
    if(key_values==2)
        input_report_key(button_dev, KEY_3, 1);
    if(key_values==3)
        input_report_key(button_dev, KEY_4, 1);
    if(key_values==4)
        input_report_key(button_dev, KEY_5, 1);
    if(key_values==5)
        input_report_key(button_dev, KEY_6, 1);
    input_sync(button_dev);
    }
    return IRQ_RETVAL(IRQ_HANDLED);
}
static int s3c24xx_request_irq(void)
{
    int i;
    int err = 0;
    for (i = 0; i if (button_irqs[i].irq continue;
        }
        /* IRQ_TYPE_EDGE_FALLING,IRQ_TYPE_EDGE_RISING,IRQ_TYPE_EDGE_BOTH */
        err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,
        button_irqs[i].name, (void *)&button_irqs[i]);
        if (err)
            break;
    }
    /*错误处理*/
    if (err) {
        i--;
        for (; i >= 0; i--) {
            if (button_irqs[i].irq continue;
            }
            disable_irq(button_irqs[i].irq);
          free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
        }
        return -EBUSY;
    }
    return 0;
}
static int __init dev_init(void)
{
    /*request irq*/
    s3c24xx_request_irq();
    /* Initialise input stuff */
    button_dev = input_allocate_device();
    if (!button_dev) {
        printk(KERN_ERR "Unable to allocate the input device !!\n");
        return -ENOMEM;
    }
    button_dev->name = "s3c2440_button";
    button_dev->id.bustype = BUS_RS232;
    button_dev->id.vendor = 0xDEAD;
    button_dev->id.product = 0xBEEF;
    button_dev->id.version = 0x0100;

    button_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT(EV_SYN);
    //set_bit(EV_KEY, button_dev->evbit)//支持EV_KEY事件
    /*设置支持哪些按键*/
    set_bit(KEY_1, button_dev->keybit);
    set_bit(KEY_2, button_dev->keybit);
    set_bit(KEY_3, button_dev->keybit);
    set_bit(KEY_4, button_dev->keybit);
    set_bit(KEY_5, button_dev->keybit);
    set_bit(KEY_6, button_dev->keybit);
    //printk("KEY_RESERVED=%d ,KEY_1=%d",KEY_RESERVED,KEY_1);
    input_register_device(button_dev); //注册input设备

    printk ("initialized\n");

    return 0;
}

static void __exit dev_exit(void)
{
    int i;

    for (i = 0; i if (button_irqs[i].irq continue;
        }
        free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
    }

    input_unregister_device(button_dev);
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Xie");

Dans cet article, nous avons appris les concepts de base et la structure du sous-système d'entrée Linux, ainsi que certaines commandes et outils couramment utilisés. Nous avons appris comment afficher et contrôler les propriétés et l'état des périphériques d'entrée, et comment utiliser les outils evtest et libinput pour tester et déboguer les périphériques d'entrée. Nous avons également appris à utiliser les règles udev pour personnaliser le comportement et la configuration des périphériques d'entrée.

Le sous-système d'entrée Linux est un framework puissant et flexible qui vous permet de mieux gérer et utiliser vos périphériques d'entrée. En utilisant le sous-système de saisie Linux, vous pouvez améliorer votre productivité et votre expérience utilisateur. Nous vous recommandons d'utiliser souvent le sous-système d'entrée Linux pour optimiser vos périphériques d'entrée lorsque vous utilisez un système Linux.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer