一褪猛、混雜設(shè)備模型
1.1吭露、混雜設(shè)備概念
在linux系統(tǒng)中,存在一類字符設(shè)備抢腐,它們擁有相同的主設(shè)備號(hào)(10)姑曙,但次設(shè)備號(hào)不同,我們稱這類設(shè)備為混雜設(shè)備(miscdevice)迈倍。所有的混雜設(shè)備形成一個(gè)鏈表伤靠,對(duì)設(shè)備訪問時(shí),內(nèi)核根據(jù)次設(shè)備號(hào)查找相應(yīng)的混雜設(shè)備。
1.2宴合、設(shè)備描述
Linux中使用 struct miscdevice來描述一個(gè)混雜設(shè)備焕梅。
struct miscdevice {
int minor; /* 次設(shè)備號(hào) */
const char *name; /* 設(shè)備名 */
const struct file_operations *fops; /* 文件操作 */
struct list_head list;
struct device *parent;
struct device *this_device;
}
1.3、設(shè)備注冊(cè)
linux中使用 misc_register 函數(shù)來注冊(cè)一個(gè)混雜設(shè)備驅(qū)動(dòng)卦洽。使用 misc
int misc_register(struct miscdevice *misc)
int misc_deregister(struct miscdevice *misc)
1.4贞言、簡單代碼編寫示例
#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
int key_open(struct inode *node, struct file *filp)
{
return 0 ;
}
struct file_operations key_fops = {
.open = key_open,
};
struct miscdevice key_miscdev = {
.minor = 200 ,
.name = "key",
.fops = &key_fops,
};
static int key_init()
{
misc_register(&key_miscdev);
}
static void key_exit()
{
misc_deregister(&key_miscdev);
}
module_init(key_init);
module_init(key_exit);
二、linux 中斷處理程序
2.1阀蒂、裸機(jī)中斷處理流程
事先需要通過相關(guān)寄存器的初始化该窗,并且將中斷處理程序進(jìn)行注冊(cè),裸機(jī)發(fā)生中斷的時(shí)候蚤霞,CPU先跳到中斷向量表酗失,再根據(jù)中斷源編號(hào),跳轉(zhuǎn)到中斷處理函數(shù)昧绣。期間可能會(huì)有現(xiàn)場(chǎng)保護(hù)與環(huán)境恢復(fù)等問題规肴。
2.2、linux 中斷處理流程分析
irq.svc 拿到產(chǎn)生中斷號(hào),根據(jù)中斷號(hào)找出 irq_desc 結(jié)構(gòu)中 action (存放用戶事先填寫的中斷處理函數(shù)等) 來運(yùn)行夜畴。
2.3拖刃、Linux 中斷處理程序設(shè)計(jì)
2.3.1、中斷注冊(cè)
request_irq函數(shù)用于注冊(cè)中斷贪绘。返回0表示成功兑牡,或者返回一個(gè)錯(cuò)誤碼。
int request_irq(unsigned int irq,void (*handler)(int,void*,struct pt_regs *),unsigned long flags,const char * devname, void *dev_id)
// 中斷號(hào)
unsigned int irq
//中斷處理函數(shù)
void (*handler)(int税灌,void*发绢,struct pt_regs *);
//與中斷管理有關(guān)的各種選項(xiàng)
unsigned long flags
//設(shè)備名
const char * devname
//共享中斷時(shí)使用
void *dev_id
在flags 參數(shù)中,可以選擇一些與中斷管理有關(guān)的選項(xiàng)垄琐,如:
IRQF_DISABLEED (SA_INTERRUPT)
//如果設(shè)置該位,表示一個(gè)“快速”中斷處理程序经柴;如果沒有設(shè)置該位狸窘,那么是一個(gè)“慢速”中斷處理程序。
IRQF_SHARED(SA_SHIRQ)
//該位表明該中斷號(hào)是多個(gè)設(shè)備共享的坯认。
快/慢速中斷的主要區(qū)別在于:快速中斷保證中斷處理的原子性(不被打破)翻擒,而慢速中斷則不保證。換句話說牛哺,也就是“開啟中斷”標(biāo)志位(處理器IF)在運(yùn)行快速中斷處理程序時(shí)是關(guān)閉的陋气,因此在服務(wù)該中斷時(shí),不會(huì)被其他類型的中斷打斷引润;而調(diào)用慢速中斷處理時(shí)巩趁,其他類型的中斷仍可以得到服務(wù)。
共享中斷:多個(gè)硬件共享同一個(gè)中斷號(hào)淳附。裸機(jī)中也時(shí)常有议慰。
2.3.2 中斷處理程序
中斷處理程序的特別之處是在中斷上下文中運(yùn)行的蠢古,它的行為受到某些限制:
- 不能使用可能引起阻塞的函數(shù)。(死循環(huán)别凹,信號(hào)量這類)
- 不能夠使用可能引起調(diào)度的函數(shù)草讶。
中斷處理程序的一般流程:
- 檢測(cè)設(shè)備是否發(fā)生中斷。
- 清除中斷產(chǎn)生標(biāo)識(shí)炉菲。
- 相應(yīng)的硬件操作堕战。
2.3.3 注銷中斷
當(dāng)設(shè)備不再需要使用中斷的時(shí)候(通常在驅(qū)動(dòng)卸載的時(shí)候),應(yīng)當(dāng)把他們注銷拍霜,使用函數(shù):
void free_irq(unsigned int irq, void *dev_id)
根據(jù)不同的 中斷號(hào)和devid 進(jìn)行注銷中斷嘱丢。
2.3.4 完善上節(jié)課代碼
#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/fs.h>
#define GPFCON 0x56000050
irqreturn_t key_int(int irq, void *dev_id)
{
// 1.檢測(cè)是否發(fā)生了按鍵中斷(非共享不用檢查)
// 2.清除已經(jīng)發(fā)生了按鍵中斷(CPU內(nèi)部寄存器,系統(tǒng)已經(jīng)清除)
// 3.打印按鍵值
printk("key down !\n");
return 0 ;
}
void key_hw_init()
{
unsigned int * gpio_config;
unsigned int short delta;
gpio_config = ioremap(GPFCON,4);
delta = readw(gpio_config);
delta &= ~0b11;
dalta |= 0b10 ;
writew(data,gpio_config);
}
int key_open(struct inode *node, struct file *filp)
{
return 0 ;
}
struct file_operations key_fops = {
.open = key_open;
};
struct miscdevice key_miscdev = {
.minor = 200 ,
.name = "key",
.fops = &key_fops,
};
static int key_init()
{
misc_register(&key_miscdev);
//注冊(cè)中斷處理程序
request_irq(IRQ_EINT0,key_int, IRQF_TRIGGER_FALLING, "key" , 0 );
//按鍵初始化
key_hw_init();
return 0 ;
}
static void key_exit()
{
misc_deregister(&key_miscdev);
//卸載中斷處理程序
free_irq(irqno,0);
}
module_init(key_init);
module_init(key_exit);
三沉御、編寫相關(guān)makefile
obj-m := key.o
KDIR:=/home/driver/key_2440
all:
make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
clean:
rm -rf *.ko *.o
注意:相關(guān)代碼來自國嵌屿讽。