| 
 
| #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貌似问题一大堆,等双休日再研究研究。
 | 
 |