linux 4.0版本内核的中断注册

前言

Linux4.0的内核,中断注册时(request_irq()),不能使用硬中断号直接注册

要通过设备树获取内核虚拟中断号,然后注册中断。

 

一、旧版本内核的注册方法。如下:

在linux内核中用于申请中断的函数是request_irq(),函数原型在Kernel/irq/manage.c中定义:

 

int request_irq(unsigned int irq, irq_handler_t handler,

unsigned long irqflags, const char *devname, void *dev_id)

 

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

 

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

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

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

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

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

 

二、新版本注册方法

1.int request_irq(unsigned int irq, irq_handler_t handler,

unsigned long irqflags, const char *devname, void *dev_id)

函数没有变化。只是第一个参数发生了变化。第一个参数irq不再是硬中断号,而是linux内核软件中断号,这是内核管理的虚拟中断号。

2.硬件中断是我们通过device tree给出,然后通过函数platform_get_irq(dev, 0)获得软件中断号,再调用上面的注册函数进行中断注册。注册成功后,我们可以通过cat/proc/interrupts来查看我们注册的中断是否对应我们想要的中断号,这里面包含了硬中断号。

node = of_find_compatible_node(NULL,NULL,"itech,irq_test");

irq = of_irq_get(node,0);

上面2个函数一起使用也可以获取中断号,不过中断号一定要在device tree里正常加入。

3.设备树加入新的中断号。

irq_test@42 {

compatible = "itech,irq_test";

reg = <0xff200000 0x1000>;//use in test

interrupt-parent = <&intc>;

interrupts = <0 42 4>;

};

 

4.内核代码参考样例如下:

/*

* irq_test_device.c

* Author: root

*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

#include

#include

 

#define FIBER_UBUS_OFFSET (0x400)

 

//extern void * h2f_lwaxi_mem; //in bridge_remap.ko

struct miscdevice *misc_dev;

//int *fiber_ubus_base;

int irq;

 

static int irq_test_open(struct inode *inode, struct file *filp)

{

printk ("misc in irq_test_open\n");

return 0;

}

 

static int irq_test_release(struct inode *inode, struct file *filp)

{

printk ("misc irq_test_release\n");

return 0;

}

 

static ssize_t irq_test_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)

{

int copied = 0;

printk ("misc irq_test_read\n");

return copied;

}

 

static ssize_t irq_test_write(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)

{

int ret = size;

return ret;

}

static long irq_test_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

{

int ret = 0;

return ret;

}

 

static struct file_operations irq_test_fops =

{

.owner = THIS_MODULE,

.read = irq_test_read,

.write = irq_test_write,

.unlocked_ioctl = irq_test_ioctl,

.open = irq_test_open,

.release = irq_test_release,

};

 

static irqreturn_t irq_test_rx_irq_handler(int irq,void *id) //

{

printk("in kernel interrupt\n");

return IRQ_RETVAL(IRQ_HANDLED);

}

static int irq_test_probe(struct platform_device *dev)

{

struct device_node *node;

struct resource *res;

printk("in irq test device probe\n");

*(fiber_ubus_base + 3) = 0x0;

 

irq = platform_get_irq(dev, 0);

if (irq < 0) {

dev_err(&dev->dev, "no irq resource?\n");

printk("irq= %d \n", irq);

return irq;

}

printk("irq= %d \n", irq);

misc_dev = (struct miscdevice *)kzalloc(sizeof(*misc_dev), GFP_KERNEL);

misc_dev->fops = &irq_test_fops;

misc_dev->name = "irq_test-test";

//主设备号恒为10,自动分配次设备号

misc_dev->minor = MISC_DYNAMIC_MINOR;

//3.注册misc设备

misc_register(misc_dev);

if(request_irq(irq,(irq_handler_t)irq_test_rx_irq_handler, IRQF_TRIGGER_HIGH, "irq_test" , misc_dev->this_device) )

{

printk("requst irq failled \n");

}

res = platform_get_resource(dev, IORESOURCE_MEM, 0);

printk("mem start is 0x%x\n",res->start);

printk("mem end is 0x%x\n",res->end);

msleep(1);

return 0;

}

static int irq_test_remove(struct platform_device *dev)

{

printk("in irq test device remove\n");

// *(fiber_ubus_base + 3) = 0x0;

free_irq(irq,misc_dev->this_device);

misc_deregister(misc_dev);

kfree(misc_dev);

return 0;

}

struct of_device_id dts_table[] = {

{.compatible = "itech,irq_test",},//the name must same int device tree

{},

};

struct platform_driver test_pl = {

.probe = irq_test_probe,

.remove = irq_test_remove,

.driver = {

.name = "irq_test_test_driver",

.of_match_table = dts_table,

},

};

static int __init test_irq_test_init(void)

{

printk("insmod test irq\n");

platform_driver_register(&test_pl);

return 0;

}

/**

* nufront_cap_cleanup - Driver un-registration call

*/

static void __exit test_irq_test_cleanup(void)

{

printk("rmmod test irq\n");

platform_driver_unregister(&test_pl);

}

module_init(test_irq_test_init);

module_exit(test_irq_test_cleanup);

MODULE_AUTHOR("itech_han");

MODULE_LICENSE("GPL");

MODULE_ALIAS("irq_test");

你可能感兴趣的:(linux 4.0版本内核的中断注册)