1. 程式人生 > >LINUX按鍵驅動程序

LINUX按鍵驅動程序

原型 reg hand 延時 div lis 哪些 初始化 提交

《《混雜設備驅動模型》》

《混雜設設備的描述》

<混在設備的概念>

linux系統中,存在一類字符設備,他們擁有相同的主設備號(10),但是次設備號不同,稱這類設備為混在設備(missdevice),所有的混雜設備形成一個鏈表,對設備進行訪問,根據次設備號在鏈表中查找相應的混雜設備。

註意:混雜設備是字符設備的一種。

<混雜設備的設備描述符>

struct miscdevice

{

int minor; /*次設備號*/

const char *name; /*設備名*/

const struct file_operrations *fops; /*文件操作*/

struct list_head list;

struct device *parent;

struct device *this _device ;

};

<設備註冊>

linux系統中歐使用函數 misc_register() 函數來註冊一個混雜設備驅動。

函數原型:

int misc_register(struct miscdevice *misc)

<設備註銷>

函數原型:

int mic_deregister (struct miscdevice * misc)

linux中斷處理》

<裸機中中斷處理流程>

中斷會有一個統一的入口: ldr pc,_irq ——》保存環境處理——》執行:

bl handle_init 指令——》 根據中斷號,調用與之對應的中斷處理程序。

<linux中中斷處理流程分析>

linux系統中也有一個中斷處理的同樣的入口:irq_svc ——》接著做相應的環境保存——》獲取產生中斷的中斷源(寄存器 INTPND)——》利用中斷號找到irq_disc[*]這個結構——》在action 中就有用戶事先填寫編寫好的處理函數

總結:驅動程序需要做哪些事?

1)實現中斷處理過程

2)將中斷處理程序註冊到linux系統中

<linux 中中斷處理程序>

1)註冊中斷

函數原型:
int request_irq(unsigned int irq, void (*handler )(int ,void *,struct pt_regs*),unsigned long flags,const char*devname, void *dev_id)

參數分析:

unsigned int irq: 中斷號

註意:中斷號和中斷類型區別

#define S3C2410_CPUIRQ_OFFSET (16)

#define S3C2410_IRQ(x) ((x) + S3C2410_CPUIRQ_OFFSET)

void *handler (int ,void * , struct pt_regs * ): 中斷處理程序

unsigned long flags :與中斷處理有關的各種的選項

例:

IRQF_DISABLEED (SA_INTERRUPT) :快速中斷處理程序,如果沒有該位,則表示慢速中斷處理程序

註意:快速中斷和慢速中斷的區別

/慢速中斷主要區別在於:快速中斷保證中斷處理的原子性(不被打斷),而慢速中斷則不保證,換句話說就是開啟中斷標誌位 (屏蔽)(處理器 IF,在運行快速中斷程序是關閉的,英因此在服務該中斷時,不會別其他類型的中斷打斷;而調用慢速中斷處理時,其他類型的中斷可以得到服務。

IRQF_SHARED(SA_SHIRQ):表明該中斷號是設備共享的()多個設備可以共享多個中斷。

IRQF_TRIGGER_FALLING: 下降沿產生中斷

const char * devname:設備名

void * dev_id :共享中斷時使用

返回值:

返回0 表示成功

失敗:

返回一個非0 的錯誤值

註意:中斷處理程序是在中斷上下文中運行的,他的行為可能受某些限制:

1)不能使用可能引起阻塞的函數

2)不能使用可能引起調度的函數

2)中斷處理

一般處理流程:

檢查設備是否產生中斷——》清除中斷標誌(要不然下次中斷沒法響應)——》相應的硬件操作

3)註銷中斷

函數原型:

void free_irq(unsigned int irq,void *dev_id)

參數分析:

irq;中斷號

dev_id:對於共享中斷,一個中斷號,對應多個中斷程序,位了將加載的中斷處理程序卸載,將其中對每個中斷處理程序進行編號:dev_id

《中斷分層技術》

<中斷嵌套>

(1)慢速中中斷

當處理慢速中斷當過程中,中斷開關(IF)是關閉當的,即可以被其他中斷打斷,執行本中斷,直到處理完成,再返回執行執之前被打斷當中斷。

註意:如果執行中斷當過程中是被同類型當中斷打斷,此時linux系統是不會執行該中斷當。

(2)快速中斷

不可以被其他中斷打斷

<中斷分層技術>

背景:

中斷處理流程大致可以分為和和硬件有關的工作,和硬件無關當工作,linux系統中,將和硬件有關的工作被放到中斷處理程序中去做,其他的部分放到其他地方做。其目的是減少處理中斷處理的時間。使用以下三中方式處理和硬件無關部分處理。

(1)軟中斷

(2)tasklet

(3)工作隊列

由上圖可以看見,加入說這是一個3核當CPU,每一CPU後面都跟有一個隊列,將和硬件沒有關系的處理程序插入到這些鏈表中,linux內核會為每一個鏈表創建一個線程,系統會在CPU相對空閑的時候把掛著的線程處理一遍,當處理完一個線程該鏈表就會從該隊列中消失。

<使用工作隊列實現分層>

(1)如何實現工作隊列

struct workqueue_struct

{

struct cpu_workqueue_struct *cpu_wq;

struct list_head list;

const char *name; /*workqueue name */

int signalthread;

int freezeable /*freeze threads during suspend*/

int rt;

}

(2)如何描述一個工作

struct work_struct

{

atomic_long_t data;

struct list _head entry;

work_fun_t func;

}

(3)實現步驟

1)創建工作隊列

函數:

create_workqueue(“name”)

2)創建工作

函數:

INIT_WORK(work,fun)

3)提交工作(將工作掛載到工作隊列上)

函數:
queue_work(work_queue,work)

註意:要創建工作隊列,必須遵循GPL協議。

MOUDLE_LICENSE(“GPL”)

註意:但是在大多數情況下並不需要我們定義工作隊列,linux系統會有一個默認當工作隊列keventd_wq,所以只需要將工作掛載到該工作隊列上即可。

掛載函數:

schedule_work(work)
《按鍵去抖》

<背景分析>

在按動按鍵的時候,因硬件設計的缺陷,會導致信號出現尖刺,從而導致輸入信號不準確。

<處理按鍵抖動>

(1)硬件去抖

(2)軟件去抖

一般軟件去抖采用延時的方式:
1for()循環

2)定時延時

Linux系統中使用結構體數組:
struct timer_list

{

struct list_head entry;

unsigned long expires;

viod (*function )(unsigned long);

unsigned long data;

struct tvec_base *base;

}

expires:用來設定時間

function:這個函數指針指向定時結束後需要處理的工作。

來描述一個定時器。

註意:一般操作系統為處理的高效率,一般是不使用for()循環的。只能使用定時器。

<定時器處理流程>

(1)定義定時器變量

(2)初始化定時器

1init_timer()

2)設置超時函數

(3)add_timer()用來向內核註冊定時器

(4)mod_timer()啟動定時器

<多按鍵驅動的優化>

相對於一個按鍵的驅動程序,需要多註冊一個中斷,註冊中斷就需要在對硬件操作部分多做一個引腳的功能配置。

註意:首先要實現相應的硬件驅動程序,才能在應用程序中做相應的系統調用。

<阻塞型驅動程序的設計>

(1)阻塞必要

當一個設備無法滿足用戶的讀寫請求的時候該怎麽辦?例如使用函數然而以後會有數據,或者一個進程企圖向一個設備寫入數據的時候,然而,此時設備沒有做好接受數據的準備,當上述情況發生時,驅動程序應當(缺省的)阻塞進程,使進程進入等待(睡眠)狀態,知道請求得到滿足。

(2)內核等待隊列

在實現阻塞驅動的過程中,也需要一個類似“候車室”的地方來安排阻塞隊列的休息,當喚醒條件成熟時,則可以從候車室中將進程喚醒,這個“候車室”就是等待隊列。

1)定義等待隊列

wait_queue_head_t my_queue

2)初始化等待隊列

init_waitqueue_head(&my_queue)

3)或者定義並初始化等待隊列

DECLARE_WAIT_QUEUE_HEAD(my_queue)

4)進入等待隊列

wait_event(queue,condition)

condition(布爾表達式)為真時,立即返回,否者讓進程進入TASK_UNINTERRUPTIBLE 模式的睡眠,並掛載到queue參數指定的等待隊列上。

wait_event_interrupttible(queue,condition)

condition(布爾表達式)為真時,立即返回,否者讓進程進入TASK_INTERRUPTIBLE的睡眠,並掛載在參數queue參數指定的隊列上。

5)從等待隊列中喚醒

wake_up(wait_queue_t *q)

從等待隊列q 中喚醒狀態為TASK_UNINTERRUPTIBLE,TASK_INTERRUPTIBLE,TASK_KILLABLE 的所有進程

wake_up_interruptible(wait_queue_t *q)

從等待隊列中q中,喚醒狀態為TASK_INTERRUPTIBLE的進程。

(3)阻塞驅動優化

L

LINUX按鍵驅動程序