Linux內核中斷
- 1. 簡介
- 2. linux內核中中斷的注冊與注銷
- 3. 代碼
- 4. 測驗
1. 簡介
linux的中斷處理程序和ARM裸板中的中斷處理程序是一致的,不同點在于裸板開始時所有的軟體都是自行編程完成的,在linux中很多中斷相關的代碼內核已經實作完畢了,某個中斷產生后應該做什么樣的具體作業沒有完成,這就需要我們自己編程實作,
● 中斷服務程式有如下特點:
(不屬于) 1)中斷處理程式不屬于行程,它運行于中斷背景關系
(不交換) 2)在中斷背景關系中不能做用戶空間和內核空間的資料互動(linux不允許,STM32中裸板中可以)
copy_to_user/copy_from_user /kmalloc
(不阻塞) 3)在中斷背景關系中不允許執行引起阻塞或者睡眠的函式,如:
sleep //睡眠函式
recv //阻塞函式
(堆疊) 4)中斷使用的堆疊為獨立的堆疊空間,堆疊空間為一個4KB的記憶體頁
(快) 5)要求對應的處理程序,執行速度越快越好
2. linux內核中中斷的注冊與注銷
● 注冊
/*
@function:注冊中斷服務程式
@para:
【irq】: 中斷號,內核中將所有的中斷源做了統一的編號, 獲取linux內核中斷號的兩種方式:
1)int gpio_to_irq(unsigned gpio)----將管腳編號gpio轉換為對應的中斷編號
2) xxx_irq.h----IRQ_GPIO_A_START + index
【handler】: 要注冊的irq號中斷源對應的中斷服務程式(用戶端)
btn_isr 也被稱作回呼函式/鉤子函式 (strcmp/open呼叫別人寫的代碼,而我們寫的函式,被系統呼叫,就叫做鉤子函式)
【flags】: 設定哪種情況下觸發irq號中斷
IRQF_TRIGGER_RISING, 上升沿觸發中斷
IRQF_TRIGGER_FALLING
IRQF_TRIGGER_HIGH,高電平觸發中斷
IRQF_TRIGGER_LOW
IRQF_SHARED: 共享中斷
【name】: 名稱
【dev】: 呼叫handler 函式時傳遞的引數(用戶呼叫使用的)
@return:注冊成功回傳0 失敗回傳非0
*/
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
● 注銷
/*
@function:注銷中斷服務程式
@note:當呼叫request_irq(....,dev) 當呼叫free_iqr(.......,dev) 最后一引數要保持一致 不然注銷失敗
*/
void free_irq(unsigned int irq, void *dev)
3. 代碼
硬體上使用了四個按鍵,都是下降沿觸發,
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/interrupt/h>
MODELE_LICENSE("GPL");
struct btn_desc
{
int irq; //中斷號
char *name;
}
struct btn_desc btns[]=
{
{IRQ_GPIO_A_START+28, "K1"},
{IRQ_GPIO_B_START+30, "K2"},
{IRQ_GPIO_B_START+31, "K3"}
{IRQ_GPIO_B_START+9, "K4"},
}
/* 回呼/鉤子函式, 用戶自定義
typedef irqreturn_t (*irq_handler_t)(int, void *);
第一個引數:中斷號
第二個引數:用戶引數
當按鍵觸發的時候的時候,會列印 K1~K4 */
irqreturn_t btn_isr(int irq, void *dev)
{
//int test = *((int *)dev);
sturct btn_sesc *pdata = (sturct btn_desc *)dev;
printk("%s press!\n",pdate->name);
return IRQ_HANDLED;
}
//初始化:注冊中斷服務函式
int __init btn_drv_init(void)
{
//int irq = gqio_to_irq(PAD_GPIO_A + 28); //獲取終端號
for(i=0; i<ARRAY_SIZE(btns); i++))
{
//注冊中斷服務函式 約定一下,按鍵的時候才使用,具體見上文的函式解釋
int ret = request_irq(btns[i].irq, btn_isr, IRQF_RTIGGER_FALLING, btns[i].name, (void *)&(btns[i]));
if(ret)
{
printk("request_irq failed!\n");
return -EAGAIN;
}
}
return 0;
}
//注銷中斷服務程式
void __exit btn_drv_exit(void)
{
int i = 0;
for(i=0; i<ARRAY_SIZE(btns); i++)
{
//int irq = gqio_to_irq(PAD_GPIO_A + 28);
free_irq(btns[i].irq, (void *)&(btns[i]));
}
}
...
module_init(btn_drv_init);
module_exit(btn_drv_exit);
4. 測驗
向內核加載模塊:
insmod btn_drv.ko
insmod: can't insert 'btn_drv.ko': Resource temporarily unavailable
#原因: 內核中自帶了按鍵的驅動程式,在其中通過request_irq的方式注冊了K1對應的中斷服務程式,導致再次呼叫request_irq時注冊失敗
解決方法:
make menuconfig
Device Drivers --->
Input device support --->
[*] Keyboards --->
< > SLsiAP push Keypad support
make uImage #讓開發板使用新內核
cp arch/arm/boot/uImage /tftpboot/
tftp 48000000 uImage
mmc write 48000000 800 3000
重啟后,再向內核加載模塊:
insmod btn_drv.ko
# 按下K1觀察實驗效果
查看中斷資訊:
cat /proc/interrupts
#中斷號 中斷產生的次數
134: 0 GPIO K1
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/234957.html
標籤:其他
