嵌入式学习-驱动开发-lesson3-混杂设备驱动模型与linux中断处理流程

一、混杂设备驱动模型

混杂设备属于字符设备中的一种

在Linux驱动中把无法归类的一些的设备定义为混杂设备(miscdevice)。他们共享相同的主设备号MISC_MAJOR(即10),但次设备号不同。
所有的miscdevice设备形成了一个链表,对设备访问时内核根据次设备号查找对应的miscdevice设备,然后调用其file_operations结构中注册的文件操作接口进行操作。miscdevice的API实现在drivers/char/misc.c中。

关于混杂设备的主要概念有:

1).设备描述

Linux中使用struct miscdevice来描述一个混杂设备。

struct miscdevice {
int minor;                                           /* 次设备号*/
const char *name;                              /* 设备名*/
const struct file_operations *fops;     /*文件操作*/
struct list_head list;                            /*misc_list的链表头*/
struct device *parent;                        /*父设备*/
struct device *this_device;                /*当前设备,是device_create的返回值*/
};

2).设备注册

Linux中使用misc_register函数来注册一个混杂设备驱动。

int misc_register(struct miscdevice * misc)

3).设备卸载

misc_deregister

4)混杂设备驱动模型的主要流程

1.初始化struct miscdevice

这部分主要是定义struct miscdevice结构,然后struct miscdevice结构里面的内容根据自己的需要进行填充,如:

struct miscdevice misc = {
    .minor = 200, /*次设备号*/
    .name = "key",
    .fops = &key_ops,
};

2.初始化操作函数集

在上面struct miscdevice结构中已经定义了fops 结构,因此我们接下来需要将其初始化,根据需要填充内容。

struct file_operations key_ops = {
    .open = key_open,
};

然后对自己定义的函数进行扩展。

int key_open(struct inode *node ,struct file *filp)
{

    return 0;   
}

3.注册miscdevice

将此混杂设备注册到内核中去。

    /*注册混杂设备*/
    misc_register(&misc);

4.注销miscdevic

在此驱动卸载的时候,需要将其注销,回收资源。

    /*注销混杂设备*/
    misc_deregister(&misc); 

贴上代码:

/*********************************************
*File name :key.c
*Author    :stone
*Date      :2016/07/28
*Function  :混杂设备驱动模型
*********************************************/

#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/io.h>

int key_open(struct inode *node ,struct file *filp)
{

    return 0;   
}

struct file_operations key_ops = {
    .open = key_open,

};

struct miscdevice misc = {
    .minor = 200, /*次设备号*/
    .name = "key",
    .fops = &key_ops,
};

static int key_init()
{
    /*注册混杂设备*/
    misc_register(&misc);

}

static void key_exit()
{
    /*注销混杂设备*/
    misc_deregister(&misc); 

}

MODULE_LICENSE("GPL");
module_init(key_init);
module_exit(key_exit);

二、linux中断处理流程

1)裸机中断回顾

裸机的中断在”按键中断“一课中有详细的介绍。6410采用向量中断的方式
这里写图片描述
当中断发生的时候,硬件自动判断到是那个中断产生,然后就会跳转到相应的中断寄存器里面,中断寄存器里面存放着这个中断的处理程序的地址,然后根据这个地址,就是我们的中断处理程序了,然后进行相应的处理。

2)linux中断分析

关于linux内核中断流程,下面做一个简单的分析:

arch/arm/kernel/entry-armv.S

1.统一的入口
这里写图片描述

2.在此下面,有一个标号
这里写图片描述

跳转到此标号处,可以看到经过一系列配置,又到了arch_irq_handler_default处
这里写图片描述

3.查找arch_irq_handler_default
arch_irq_handler_default是一个宏,在entry-macro-multi.s函数里面
这里写图片描述
get_irqnr_and_base的作用就是获取中断源,可以进到这个宏里面查看详细的代码,如下:
这里写图片描述
4.asm_do_IRQ
随后,拿到中断号,跳转到asm_do_IRQ 这个函数
这里写图片描述

如上图所示,unsigned int irq 为获取到的中断号,同时又调用generic_handle_irq这个函数

5.generic_handle_irq
这里写图片描述
在generic_handle_irq这个函数中,又调用generic_handle_irq_desc这个函数
这里写图片描述
在这个函数中,又调用desc->handle_irq(irq, desc);这个便是最终的中断处理函数,
将上面的流程进行综合便可以得到下面的这幅图。
这里写图片描述

根据上面的分析和上面的图片,我们可以得知,linux内核中断处理流程和裸机有一定的相似之处,其主要流程如下:
1.irq_svc中断的入口
2.获取中断号
3.根据中断号找到相应的中断
4.到相应的中断处取出事先注册好的中断处理函数

因此,我们的驱动需要做的是:
1.实现中断处理程序
2.注册中断,使内核识别

3)中断处理相关函数

1、中断注册

request_irq函数用于注册中断。
函数原型:

int request_irq(unsigned int irq, void (*handler)(int, void*, structpt_regs *),unsigned long flags,const char *devname,void *dev_id)

函数返回值:
返回0表示成功,或者返回一个错误码

参数:
unsigned int irq
中断号

void (handler)(int,void )
自定义的中断处理函数

* unsigned long flags*
与中断管理有关的各种选项,具体可以查看内核相关
如:
• IRQF_DISABLED(SA_INTERRUPT)
如果设置该位,表示是一个“快速”中断处理程序;
如果没有设置这位,那么是一个“慢速”中断处理程序。
• IRQF_SHARED(SA_SHIRQ)
该位表明该中断号是多个设备共享的。

快/慢速中断的主要区别在于:快速中断保证中断处理的原子性(不被打断),而慢速中断则不保证。换句话说,也就是“开启中断”标志位(处理器IF)在运行快速中断处理程序时是关闭的,因此在服务该中断时,不会被其他类型的中断打断;而调用慢速中断处理时,其它类型的中断仍可以得到服务。

const char * devname
设备名

void *dev_id
共享中断时使用。

2 中断处理程序

中断处理程序的特别之处是在中断上下文中运行的,它的行为受到某些限制:
①.不能使用可能引起阻塞的函数(如果引起阻塞,则整个系统的中断都无法处理)
②.不能使用可能引起调度的函数

其处理流程如下所示:
①检查设备是否产生了中断
②清除中断产生标志
③进行相应的硬件操作

3 注销中断

当设备不再需要使用中断时(通常在驱动卸载时), 应当把它们注销, 使用函数:

void free_irq(unsigned int irq, void *dev_id)

贴上代码:

/*********************************************
*File name :key.c
*Author    :stone
*Date      :2016/07/28
*Function  :混杂设备驱动加上中断处理流程
*********************************************/

#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/io.h>

irqreturn_t key_handle(int irq,void *dev_id)
{
    /*1.检测是否发生按键中断*/

    /*2.清除已经发生的按键中断*/

    /*3.打印按键值*/ 
    printk(KERN_WARNING"key down !\n");

    return 0;
}
int key_open(struct inode *node ,struct file *filp)
{

    return 0;   
}

struct file_operations key_ops = {
    .open = key_open,

};

struct miscdevice misc = {
    .minor = 200, /*次设备号*/
    .name = "key",
    .fops = &key_ops,
};

static int key_init()
{
    /*注册混杂设备*/
    misc_register(&misc);

    /*中断初始化*/
    request_irq(irqno,key_handle,IRQF_TRIGGER_FALLING,"key",0);
                        //IRQF_TRIGGER_FALLING  从高电平到低电平产生中断  下降沿

    return 0;
}

static void key_exit()
{
    /*注销混杂设备*/
    misc_deregister(&misc); 

    /*注销中断*/
    free_irq(irqno,0);
}


MODULE_LICENSE("GPL");

module_init(key_init);
module_exit(key_exit);

菜鸟一枚,如有错误,多多指教。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值