Heim >System-Tutorial >LINUX >Einführung in das Linux-Eingabesubsystem

Einführung in das Linux-Eingabesubsystem

WBOY
WBOYnach vorne
2024-02-13 13:09:12869Durchsuche

Das Linux-Eingabesubsystem ist eine Reihe von Treibern, die alle Eingabegeräte im Linux-System unterstützen, einschließlich Tastaturen, Mäuse, Touchscreens, Tablets, Gamecontroller usw. Der Kern des Eingabesubsystems ist das Eingabemodul, das für die Weitergabe von Ereignissen zwischen den beiden Modultypen verantwortlich ist:

  • Gerätetreibermodule: Diese Module kommunizieren mit der Hardware (z. B. über USB) und stellen Ereignisse (Tastendrücke, Mausbewegungen usw.) an das Eingabemodul bereit.
  • Event-Handling-Module: Diese Module erhalten Ereignisse vom Eingabemodul und leiten sie über verschiedene Schnittstellen dorthin weiter, wo sie benötigt werden (z. B. Kernel, GPM, X usw.).

In diesem Artikel stellen wir die grundlegenden Konzepte und die Struktur des Linux-Eingabesubsystems sowie einige häufig verwendete Befehle und Tools vor. Als Beispielsystem verwenden wir Ubuntu 20.04, der Inhalt gilt jedoch auch für andere Linux-Distributionen.

Einführung in das Linux-Eingabesubsystem

Treiberschicht

Konvertieren Sie die zugrunde liegende Hardware-Eingabe in eine einheitliche Ereignisform und melden Sie sie dem Eingabekern.

Kernschicht des Eingabesubsystems

Es stellt der Treiberschicht Eingabegeräte-Registrierungs- und Betriebsschnittstellen zur Verfügung, wie zum Beispiel: input_register_device; benachrichtigt die Ereignisverarbeitungsschicht, um das Ereignis zu verarbeiten, und generiert entsprechende Geräteinformationen unter /Proc.

Ereignisverarbeitungsschicht

Interagiert hauptsächlich mit dem Benutzerbereich (unter Linux werden alle Geräte als Dateien im Benutzerbereich behandelt). Da die FOPs-Schnittstelle in allgemeinen Treibern bereitgestellt wird und das entsprechende Gerätedatei-Nod unter /dev generiert wird, werden diese Der Vorgang wird durch die Ereignisverarbeitung abgeschlossen Schicht im Eingabesubsystem).

Gerätebeschreibung

Die Struktur input_dev dient dazu, die Kernaufgabe des Gerätetreibers zu implementieren: Tastendrücke, Touchscreens und andere Eingabeereignisse (Ereignisse, beschrieben durch die Struktur input_event) an das System zu melden, ohne dass Sie sich mehr um die Dateioperationsschnittstelle kümmern müssen. Der Treiber meldet Ereignisse über inputCore und Eventhandler an den Benutzerbereich.

Eingabegerätefunktion registrieren:

int input_register_device(struct input_dev *dev)

Eingabegerätefunktion abmelden:

void input_unregister_device(struct input_dev *dev)

Treiberimplementierung – Initialisierung (Ereignisunterstützung) set_bit() teilt dem Eingabesubsystem mit, welche Ereignisse und Schlüssel unterstützt werden. Zum Beispiel:

set_bit(EV_KEY,button_dev.evbit)  (其中button_dev是struct input_dev类型)
Es gibt zwei Mitglieder in

struct input_dev****:
**1)** evbit-Ereignistyp (einschließlich EV_RST, EV_REL, EV_MSC, EV_KEY, EV_ABS, EV_REP usw.).
**2)**Keybit-Schlüsseltyp (einschließlich BTN_LEFT, BTN_0, BTN_1, BTN_MIDDLE usw., wenn der Ereignistyp EV_KEY ist).

Treiberimplementierung – Meldeereignisse Die zum Melden von EV_KEY-, EV_REL- und EV_ABS-Ereignissen verwendeten Funktionen sind:

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)

Treiberimplementierung – Berichtsende input_sync()-Synchronisierung wird verwendet, um dem Eingabekern-Subsystem mitzuteilen, dass der Bericht beendet wurde. Im Touchscreen-Gerätetreiber ist der gesamte Berichtsprozess mit einem Klick wie folgt:

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);//同步结束

Beispielanalyse (Schlüssel-Interrupt-Programm):

//按键初始化
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);
}

Zusammenfassung: Das input-Subsystem ist immer noch ein Zeichengerätetreiber, aber die Menge an Code ist stark reduziert. Das ****input-Subsystem muss nur zwei Aufgaben erledigen: Initialisierung und Ereignisberichterstellung (hier in linux*). *** Dies wird durch Interrupts erreicht.

Instanzen

#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");

In diesem Artikel haben wir die grundlegenden Konzepte und die Struktur des Linux-Eingabesubsystems sowie einige häufig verwendete Befehle und Tools kennengelernt. Wir haben gelernt, wie man die Eigenschaften und den Status von Eingabegeräten anzeigt und steuert und wie man die Tools evtest und libinput zum Testen und Debuggen von Eingabegeräten verwendet. Wir haben auch gelernt, wie man udev-Regeln verwendet, um das Verhalten und die Konfiguration von Eingabegeräten anzupassen.

Das Linux-Eingabesubsystem ist ein leistungsstarkes und flexibles Framework, mit dem Sie Ihre Eingabegeräte besser verwalten und nutzen können. Durch die Verwendung des Linux-Eingabesubsystems können Sie Ihre Produktivität und Benutzererfahrung verbessern. Wir empfehlen Ihnen, häufig das Linux-Eingabesubsystem zu verwenden, um Ihre Eingabegeräte bei Verwendung eines Linux-Systems zu optimieren.

Das obige ist der detaillierte Inhalt vonEinführung in das Linux-Eingabesubsystem. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:lxlinux.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen