首頁  >  文章  >  系統教程  >  Linux輸入子系統簡介

Linux輸入子系統簡介

WBOY
WBOY轉載
2024-02-13 13:09:12781瀏覽

Linux輸入子系統是一組驅動程序,它支援Linux系統上的所有輸入設備,包括鍵盤、滑鼠、觸控螢幕、手寫板、遊戲手把等。輸入子系統的核心是input模組,它負責在兩類模組之間傳遞事件:

  • 裝置驅動模組:這些模組與硬體通訊(例如透過USB),並向input模組提供事件(按鍵、滑鼠移動等)。
  • 事件處理模組:這些模組從input模組取得事件,並透過各種介面將它們傳遞到需要的地方(例如核心、GPM、X等)。

在本文中,我們將介紹Linux輸入子系統的基本概念和架構,以及一些常用的指令和工具。我們將使用Ubuntu 20.04作為範例係統,但這些內容也適用於其他Linux發行版。

Linux輸入子系統簡介

驅動層

#將底層的硬體輸入轉換為統一事件形式,想輸入核心(Input Core)報告。

輸入子系統核心層

#它承上啟下為驅動層提供輸入設備註冊與操作接口,如:input_register_device;通知事件處理層對事件進行處理;在/Proc下產生相應的設備資訊。

事件處理層

#主要是和用戶空間交互(Linux中在用戶空間將所有的設備都當作文件來處理,由於在一般的驅動程序中都有提供fops接口,以及在/dev下生成相應的設備文件nod ,這些操作在輸入子系統中由事件處理層完成)。

裝置描述

input_dev結構是實現裝置驅動核心工作:向系統報告按鍵、觸控螢幕等輸入事件(event,透過input_event結構描述),不再需要關心檔案操作介面。驅動報告事件經過inputCore和Eventhandler到達用戶空間。

註冊輸入裝置函數:

#
int input_register_device(struct input_dev *dev)

註銷輸入裝置函數:

void input_unregister_device(struct input_dev *dev)

驅動實作-初始化(事件支援)set_bit()告訴input輸入子系統支援哪些事件,哪些按鍵。例如:

set_bit(EV_KEY,button_dev.evbit)  (其中button_dev是struct input_dev类型)

struct input_dev****中有兩個成員為:
# **1)**evbit事件類型(包括EV_RST,EV_REL,EV_MSC,EV_KEY,EV_ABS,EV_REP等)。
**2)**keybit按鍵類型(當事件類型為EV_KEY時包含BTN_LEFT,BTN_0,BTN_1,BTN_MIDDLE等)。

驅動實作-報告事件用於報告EV_KEY,EV_REL,EV_ABS事件的函數分別為:

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)

驅動實作-報告結束input_sync()同步用於告訴input core子系統報告結束,觸控螢幕裝置驅動程式中,一次點擊的整個報告過程如下:

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

實例分析(按鍵中斷程式):

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

總結:input子系統仍然是字元裝置驅動程序,但是程式碼量減少很多,****input子系統只需要完成兩個工作:初始化和事件報告(這裡在linux****中是透過中斷來實現的)。

實例

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

在本文中,我們學習了Linux輸入子系統的基本概念和架構,以及一些常用的指令和工具。我們了解如何檢視和控制輸入裝置的屬性和狀態,以及如何使用evtest和libinput工具來測試和偵錯輸入裝置。我們也學習如何使用udev規則來自訂輸入設備的行為和配置。

Linux輸入子系統是一個強大且靈活的框架,它可以讓你更好地管理和使用你的輸入裝置。透過使用Linux輸入子系統,你可以提高你的工作效率和使用者體驗。我們建議你在使用Linux系統時,經常使用Linux輸入子系統來優化你的輸入裝置。

以上是Linux輸入子系統簡介的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:lxlinux.net。如有侵權,請聯絡admin@php.cn刪除