linux驱动由浅入深系列:中断申请及下半部处理机制

来源:互联网 发布:黄金投资软件 编辑:程序博客网 时间:2024/06/01 11:17

1,  中断申请

使用request_irq函数向系统申请中断。

intrequest_irq(unsigned int irq, irq_handler_t handler,
                        unsigned long irqflags, const char *devname, void *dev_id)

irq是要申请的硬件中断号。

handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。

irqflags是中断处理的属性,若设置了IRQF_DISABLED (老版本中的SA_INTERRUPT,本版zhon已经不支持了),则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;若设置了IRQF_SHARED (老版本中的SA_SHIRQ),则表示多个设备共享中断,若设置了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示对系统熵有贡献,对系统获取随机数有好处。(这几个flag是可以通过或的方式同时使用的)

devname设置中断名称,通常是设备驱动程序的名称  在cat/proc/interrupts中可以看到此名称。

dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。

request_irq()返回0表示成功,返回-INVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断已经被占用且不能共享。 

2,  中断下半部的引入

中断上半部执行过程中是会关闭同级别的中断的,为避免期间同级别中断丢失,需要尽快退出。但中断中有时又存在大量逻辑需要处理,这就引入了中断下半部的概念。在中断上半部尽快读取硬件寄存器,完成硬件操作,然后退出,将大量逻辑操作推迟到下半部完成。

3,  中断下半部的实现方法

a,软中断机制(softirq)                 

b,小任务机制(tasklet)

c,工作队列机制(workqueue)

4,  workqueue

在实际使用中工作队列最为通用,因为softirq、tasklet实际机制类似,响应快于普通进程,期间不允许调度,而一般驱动开发中使用的中断中并没有如此高的要求。

Linux中的Workqueue机制就是为了简化内核线程的创建。通过调用workqueue的接口就能创建内核线程。并且可以根据当前系统CPU的个数创建线程的数量,使得线程处理的事务能够并行化。workqueue是内核中实现简单而有效的机制,他显然简化了内核daemon的创建,方便了用户的编程。

工作队列(workqueue)是另外一种将工作推后执行的形式.工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。最重要的就是工作队列允许被重新调度甚至是睡眠。

5,  workqueue使用方法

INIT_WORK()对应queue_work、schedule_work()

INIT_DELAYED_WORK()对应queue_delayed_work、schedule_delay_work后者就是专门用于可以有延时的,而前者就是没有延时的

 

下面是一个使用workqueue的实例:

 

#include <linux/init.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/platform_device.h>#include <linux/miscdevice.h>#include <linux/fs.h>#include <linux/input.h>#include <linux/workqueue.h>#include <linux/gpio.h>#include <linux/interrupt.h>#define DRIVER_NAME "hello"#define DEVICE_NAME "hello"#define GPIO_KEY72MODULE_LICENSE("Dual BSD/GPL");MODULE_AUTHOR("Radia");static struct input_dev *input;static struct hello_platform_data *pdata;struct hello_platform_data {//设备结构体中的用户自定义结构体 定义    int gpio;    struct work_structhello_wq_work;};static struct hello_platform_data hello_pdata = {   //设备结构体中的用户自定义结构体 填入初始数据    .gpio = GPIO_KEY,};static struct platform_device hello_device = {//设备结构体填入初始数据.name = DRIVER_NAME,.id = -1,.dev = {.platform_data = &hello_pdata,//用户自定义结构体 加入到设备结构体中}};static void hello_wq_work_func(struct work_struct * work){    printk("enter hello_wq_work_func!\n");    int state = (gpio_get_value_cansleep(pdata->gpio) ? 1 : 0) ^ 1;    printk(KERN_EMERG "<0>hello report event val:%d\n", state);input_report_key(input, KEY_VOLUMEUP, !!state);input_sync(input);}static irqreturn_t  button_interrupt(int irq, void *dev_id){    printk("enter button_interrupt!\n");    schedule_work(&pdata->hello_wq_work);return IRQ_HANDLED;}static int hello_probe(struct platform_device *pdv)//在probe时,设备结构体被以参数的形式传递了进来,同时自定义的hello_platform_data也在其中了{    pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);    pdata = pdv->dev.platform_data;//获取到hello_platform_data结构体指针int irq = gpio_to_irq(pdata->gpio);printk(KERN_EMERG "hello key probe\n");    gpio_request(pdata->gpio, "gpio_key_test_button");    gpio_direction_input(pdata->gpio);request_irq(irq, button_interrupt, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "button_irq", NULL);input = input_allocate_device();set_bit(EV_KEY, input->evbit);input->name = "hello_gpio_key";input->id.bustype = BUS_HOST;set_bit(KEY_VOLUMEUP, input->keybit);input_register_device(input);INIT_WORK(&pdata->hello_wq_work, hello_wq_work_func);return 0;}static int hello_remove(struct platform_device *pdv){struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdv);printk(KERN_EMERG "hello key remove\n");input_unregister_device(input);return 0;}static void hello_shutdown(struct platform_device *pdv){}static int hello_suspend(struct platform_device *pdv, pm_message_t pmt){return 0;}static int hello_resume(struct platform_device *pdv){return 0;}static struct platform_driver hello_driver = {//驱动结构体填入初始数据.probe = hello_probe,.remove = hello_remove,.shutdown = hello_shutdown,.suspend = hello_suspend,.resume = hello_resume,.driver = {.name = DRIVER_NAME,.owner = THIS_MODULE,}};static int hello_init(void){int driver_state;printk(KERN_EMERG "hello module has been mount!\n");platform_device_register(&hello_device);//使用设备结构体中的数据将设备进行注册printk(KERN_EMERG "platform_device_register end\n");driver_state = platform_driver_register(&hello_driver);//使用驱动结构体中的数据将驱动进行注册printk(KERN_EMERG "platform_driver_register driver_state is %d\n", driver_state);return 0;}static void hello_exit(void){printk(KERN_EMERG "hello module has been remove!\n");platform_driver_unregister(&hello_driver);}module_init(hello_init);module_exit(hello_exit);


1 0
原创粉丝点击