本章將介紹Linux輸入子系統的驅動開發。Linux的輸入子系統不僅支援滑鼠、鍵盤等常規輸入裝置,而且還支援蜂鳴器、觸控螢幕等裝置。本章將對Linux輸入子系統進行詳細的分析。
輸入子系統大致實現方法:
底層驅動層(input_dev)-----<通過結構體input_handle關聯>-----輸入事件處理層類介面(input_handler)-----<輸入核心層input.c>-----應用程式層
17.1 input子系統入門
輸入子系統又叫input子系統。其構建非常靈活,只需要調用一些簡單的函數,就可以將一個輸入裝置的功能呈現給應用程式。本節將從一個執行個體開始,介紹編寫輸入子系統驅動程式的方法。
17.1.1 簡單的執行個體
本節將講述一個簡單的輸入裝置驅動執行個體。這個輸入裝置只有一個按鍵,按鍵被串連到一條中斷線上,當按鍵被按下時,將產生一個中斷,核心將檢測到這個中斷,並對其進行處理。該執行個體的代碼如下:
01 #include <asm/irq.h>
02 #include <asm/io.h>
03 static struct input_dev *button_dev; /*輸入裝置結構體*/
04 static irqreturn_t button_interrupt(int irq, void *dummy) /*中斷處理函數*/
05 {
06 input_report_key(button_dev, BTN_0, inb(BUTTON_PORT) & 1);
/*向輸入子系統報告產生按鍵事件*/
07 input_sync(button_dev); /*通知接收者,一個報告發送完畢*/
08 return IRQ_HANDLED;
09 }
10 static int __init button_init(void) /*載入函數*/
11 {
12 int error;
13 if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) /*申請中斷處理函數*/
14 {
15 /*申請失敗,則列印出錯資訊*/
16 printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_
irq);
17 return -EBUSY;
18 }
19 button_dev = input_allocate_device(); /*分配一個裝置結構體*/
20 if (!button_dev) /*判斷分配是否成功*/
21 {
22 printk(KERN_ERR "button.c: Not enough memory\n");
23 error = -ENOMEM;
24 goto err_free_irq;
25 }
26 button_dev->evbit[0] = BIT_MASK(EV_KEY); /*設定按鍵資訊*/
27 button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
28 error = input_register_device(button_dev); /*註冊一個輸入裝置*/
29 if (error)
30 {
31 printk(KERN_ERR "button.c: Failed to register device\n");
32 goto err_free_dev;
33 }
34 return 0;
35 err_free_dev: /*以下是錯誤處理*/
36 input_free_device(button_dev);
37 err_free_irq:
38 free_irq(BUTTON_IRQ, button_interrupt);
39 return error;
40 }
41 static void __exit button_exit(void) /*卸載函數*/
42 {
43 input_unregister_device(button_dev); /*登出按鍵裝置*/
44 free_irq(BUTTON_IRQ, button_interrupt); /*釋放按鍵佔用的中斷線*/
45 }
46 module_init(button_init);
47 module_exit(button_exit);
這個執行個體程式碼比較簡單,在初始化函數button_init()中註冊了一個中斷處理函數,然後調用input_allocate_device()函數分配了一個input_dev結構體,並調用input_register_device()函數對其進行了註冊。在中斷處理函數button_interrupt()中,執行個體將接收到的按鍵資訊上報給input子系統。從而通過input子系統,向使用者態程式提供按鍵輸入資訊。
本執行個體採用了中斷方式,除了中斷相關的代碼外,執行個體中包含了一些input子系統提供的函數,現對其中一些重要的函數進行分析。
第19行的input_allocate_device()函數在記憶體中為輸入裝置結構體分配一個空間,並對其主要的成員進行了初始化。驅動開發人員為了更深入的瞭解input子系統,應該對其代碼有一點的認識,該函數的代碼如下:
- struct input_dev *input_allocate_device(void)
- {
- struct input_dev *dev;
- dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
/*分配一個input_dev結構體,並初始化為0*/
- if (dev) {
- dev->dev.type = &input_dev_type; /*初始化裝置的類型*/
- dev->dev.class = &input_class; /*設定為輸入裝置類*/
- device_initialize(&dev->dev); /*初始化device結構*/
- mutex_init(&dev->mutex); /*初始化互斥鎖*/
- spin_lock_init(&dev->event_lock); /*初始化事件自旋鎖*/
- INIT_LIST_HEAD(&dev->h_list); /*初始化鏈表*/
- INIT_LIST_HEAD(&dev->node); /*初始化鏈表*/
- __module_get(THIS_MODULE); /*模組引用技術加1*/
- }
- return dev;
- }
該函數返回一個指向input_dev類型的指標,該結構體是一個輸入裝置結構體,包含了輸入裝置的一些相關資訊,如裝置支援的按鍵碼、裝置的名稱、裝置支援的事件等。在本章用到這個結構體時,將對其進行詳細介紹。此處將注意力集中在執行個體中的函數上。