#ifndef __IRQ_H__
#define __IRQ_H_
#include <linux/fs.h>
#include <linux/semaphore.h>
#include <linux/wait.h>
#include <linux/cdev.h>
#define IRQ_MAJOR 0
#define DEVICE_NAME &quot;key&quot;
struct key{
// struct cdev cdev;
// struct semaphore* sem;
const char* name;
unsigned long flags;
unsigned int irq;
unsigned int val;
};
struct irq_dev{
struct cdev cdev;
struct semaphore sem;
wait_queue_head_t key_queue;
struct key* pkey;
};
#endif
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank-n.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <mach/irqs.h>
#include <linux/irq.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include &quot;irq.h&quot;
#define IRQ_DEBUG
#ifdef IRQ_DEBUG
#define dprintk(fmt, arg...) printk(&quot;###IRQ DEBUG###%s():&quot;fmt, __func__, ##arg)
#else
#define dprintk(fmt, arg...)
#endif
static int irq_major = IRQ_MAJOR;
struct irq_dev* irq;
static struct key key={
.name = &quot;key0&quot;,
.flags = IRQ_TYPE_EDGE_RISING,
.irq = IRQ_EINT(0),
.val = 0,
};
void tasklet(unsigned long data)
{
dprintk(&quot;data=%d\n&quot;, data);
dprintk(&quot;key!\n&quot;);
dprintk(&quot;S3C64XX_EINT0PEND=0x%x\n&quot;, __raw_readl(S3C64XX_EINT0PEND));
dprintk(&quot;S3C64XX_EINT0CON0=0x%x\n&quot;, __raw_readl(S3C64XX_EINT0CON0));
dprintk(&quot;S3C64XX_EINT0CON1=0x%x\n&quot;, __raw_readl(S3C64XX_EINT0CON1));
dprintk(&quot;S3C64XX_EINT0FLTCON0=0x%x\n&quot;, __raw_readl(S3C64XX_EINT0FLTCON0));
dprintk(&quot;S3C64XX_EINT0FLTCON1=0x%x\n&quot;, __raw_readl(S3C64XX_EINT0FLTCON1));
dprintk(&quot;S3C64XX_EINT0FLTCON2=0x%x\n&quot;, __raw_readl(S3C64XX_EINT0FLTCON2));
dprintk(&quot;S3C64XX_EINT0FLTCON3=0x%x\n&quot;, __raw_readl(S3C64XX_EINT0FLTCON3));
dprintk(&quot;S3C64XX_EINT0MASK=0x%x\n&quot;, __raw_readl(S3C64XX_EINT0MASK));
dprintk(&quot;S3C64XX_SERVICEPEND=0x%x\n&quot;, __raw_readl(S3C64XX_SERVICEPEND));
dprintk(&quot;VIC0IRQSTATUS=0x%x\n&quot;, __raw_readl(VA_VIC0));
dprintk(&quot;VIC0FIQSTATUS=0x%x\n&quot;, __raw_readl(VA_VIC0 + 0x4));
dprintk(&quot;VIC0VECTADDR0 =0x%x\n&quot;, __raw_readl(VA_VIC0 + 0x100));
dprintk(&quot;VICxADDRESS =0x%x\n&quot;, __raw_readl(VA_VIC0 + 0xf00));
dprintk(&quot;1:%x 2:%x 3:%x 4:%x\n&quot;, __raw_readl(VA_VIC0+0x008), __raw_readl(VA_VIC0+0x00c),
__raw_readl(VA_VIC0+0x010),__raw_readl(VA_VIC0+0x014));
}
DECLARE_TASKLET(irq_tasklet, tasklet, 0);
static struct work_struct key_work;
void work_func(struct work_struct* data)
{
dprintk(&quot;VIC0IRQSTATUS=0x%x\n&quot;, __raw_readl(VA_VIC0));
dprintk(&quot;VIC0FIQSTATUS=0x%x\n&quot;, __raw_readl(VA_VIC0 + 0x4));
dprintk(&quot;VIC0VECTADDR0 =0x%x\n&quot;, __raw_readl(VA_VIC0 + 0x100));
dprintk(&quot;VICxADDRESS =0x%x\n&quot;, __raw_readl(VA_VIC0 + 0xf00));
dprintk(&quot;work&quot;);
}
static irqreturn_t interrupt_handler(int irq, void* dev)
{
writel(IRQ_EINT0_3, S3C64XX_EINT0PEND); //clear interrupt flag
tasklet_schedule(&irq_tasklet);
return IRQ_HANDLED;
}
static irqreturn_t interrupt_handl(int irq, void* dev)
{
// writel(IRQ_EINT0_3, S3C64XX_EINT0PEND); //clear interrupt flag
schedule_work(&key_work);
return IRQ_HANDLED;
}
static int irq_open(struct inode* inode, struct file* filp)
{
int err;
dprintk(&quot;open!\n&quot;);
filp->private_data = irq;
dprintk(&quot;VIC0IRQSTATUS=0x%x\n&quot;, __raw_readl(VA_VIC0));
dprintk(&quot;VIC0FIQSTATUS=0x%x\n&quot;, __raw_readl(VA_VIC0 + 0x4));
dprintk(&quot;VIC0VECTADDR0 =0x%x\n&quot;, __raw_readl(VA_VIC0 + 0x100));
dprintk(&quot;VICxADDRESS =0x%x\n&quot;, __raw_readl(VA_VIC0 + 0xf00));
err = request_irq(irq->pkey->irq, interrupt_handler, irq->pkey->flags,
irq->pkey->name, (void*)irq);
if(err)
free_irq(irq->pkey->irq, (void*)irq);
err = request_irq(IRQ_EINT(1), interrupt_handl, IRQ_TYPE_EDGE_FALLING,
&quot;key1&quot;, NULL);
if(err)
free_irq(IRQ_EINT(1), NULL);
return 0;
}
static int irq_close(struct inode* inode, struct file* filp)
{
dprintk(&quot;close!\n&quot;);
filp->private_data = irq;
free_irq(irq->pkey->irq, (void*)irq);
free_irq(IRQ_EINT(1), NULL);
return 0;
}
static ssize_t irq_read(struct file* filp, char __user* buff, size_t count, loff_t* offp)
{
struct irq_dev* irq = filp->private_data;
if(down_interruptible(&irq->sem))
return -ERESTARTSYS;
note:此处要实现阻塞,并在中断服务程序唤醒或者在中断服务中发出一个信号。
up(&irq->sem);
return count;
}
static const struct file_operations irq_fops = {
.open = irq_open,
.release = irq_close,
.read = irq_read,
};
static void irq_setup_cdev(struct irq_dev* dev, int index)
{
int err, devno = MKDEV(irq_major, 0);
cdev_init(&dev->cdev, &irq_fops);
dev->cdev.owner = THIS_MODULE;
err = cdev_add(&dev->cdev, devno, 1);
if(err)
printk(&quot;error add cdev!\n&quot;);
}
struct class* irq_class;
int irq_init(void)
{
int result;
dev_t devno = MKDEV(irq_major, 0);
if(irq_major)
result = register_chrdev_region(devno, 1, DEVICE_NAME);
else{
dprintk(&quot;alloc_chrdev_region\n&quot;);
result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
irq_major = MAJOR(devno);
}
if(result < 0)
return result;
irq = kmalloc(sizeof(struct irq_dev), GFP_KERNEL);
if(!irq){
result = -ENOMEM;
goto malloc_error;
}
memset(irq, 0, sizeof(struct irq_dev));
irq_setup_cdev(irq, 0);
init_MUTEX(&irq->sem);
init_waitqueue_head(&irq->key_queue);
irq->pkey = &key;
INIT_WORK(&key_work, work_func);
irq_class = class_create(THIS_MODULE, &quot;irq_class&quot;);
device_create(irq_class, NULL, MKDEV(irq_major, 0), NULL, &quot;%s&quot;, DEVICE_NAME);
return 0;
malloc_error:
unregister_chrdev_region(devno, 1);
return result;
}
void irq_exit(void)
{
cdev_del(&irq->cdev);
device_destroy(irq_class, MKDEV(irq_major, 0));
class_destroy(irq_class);
kfree(irq);
unregister_chrdev_region(MKDEV(irq_major, 0), 1);
}
module_init(irq_init);
module_exit(irq_exit);
MODULE_LICENSE(&quot;GPL&quot;);
MODULE_AUTHOR(&quot;jf.s <jingfeng.shi@emdoor.com>&quot;);
这是一个临时irq测试tasklet和workqueue的版本,并测试了s3c6410的vic reg ,6410的vic reg貌似问题一大堆,等双休日再研究研究。 |