天天看點

Linux 核心空間與使用者空間異步通信機制

/*
 * @file	exirq.c
 * @author	fzs
 * @date	2016-12-13
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/nmi.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/spinlock.h>

#include <asm/io.h>
#include <asm/irq.h>

volatile unsigned int *pic_vaddr6 = NULL, *pic_vaddr5 = NULL;
extern void open_softirq(int nr, void (*action)(struct softirq_action *));
extern phys_addr_t get_immrbase(void);

static atomic_t ex_interrupt_has_happen = ATOMIC_INIT(0);
static wait_queue_head_t ex_interrupt;

#define MPC85xx_PIC_EIVPR6		0x500c0
#define WAIT_FOR_EXTERN_INTERRUPT	0x1

#if 1
static irqreturn_t exirq_process ( int irq, void *dev_id )
{
	int handled = 0;
	u32 regdata;

//	printk("come in irq_process \n");
#if 1
	regdata = in_be32(pic_vaddr6);

	//printk("pic_eivpr6 value = %x \n", regdata);
	if(regdata & 0x40000000)
	{
		atomic_set(&ex_interrupt_has_happen, 1);
		wake_up_interruptible(&ex_interrupt);	
	}
#endif

	//spin_lock(&i->lock);
	handled = 1;

	//spin_unlock(&i->lock);

	return IRQ_RETVAL(handled);
}
#endif

static long exirq_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
                                                                                       
        switch (cmd)                                                                      
        {
		case WAIT_FOR_EXTERN_INTERRUPT:
			//printk("wait for extern interrupt\n");

			wait_event_interruptible(ex_interrupt,
			atomic_read(&ex_interrupt_has_happen)!=0);
			atomic_set(&ex_interrupt_has_happen, 0);

			//printk("get an interrupt\n");
		break;
		default:
			printk("cmd=%d error\n",cmd);
		break;
	}
	return 0;
}
#if 0
static struct timer_list test_timer;
static void timer_action(unsigned long aa)
{
	atomic_set(&ex_interrupt_has_happen, 1);
	wake_up_interruptible(&ex_interrupt);	
	
	test_timer.expires = jiffies+(HZ*10);
	add_timer(&test_timer);
}
#endif
static struct file_operations exirq_fops = {
         .owner = THIS_MODULE,
         .unlocked_ioctl = exirq_ioctl
};

struct cdev exirq_cdev; 
int major;
int exirq_int_init(void)
{
	unsigned int regdata = 0;
	int ret = 0;


	init_waitqueue_head(&ex_interrupt);
	atomic_set(&ex_interrupt_has_happen, 0);
#if 1
	pic_vaddr6 = ioremap(get_immrbase() + MPC85xx_PIC_EIVPR6, 64);

	/* init EIVPR4 to 0x80000 */
	regdata = 0x80000; /* priority=8; vector=0 */
//	regdata |= 1<<22;
	out_be32(pic_vaddr6, regdata);

	/* init EIDR4 to let core process the int*/
	regdata  = 2;
	out_be32((pic_vaddr6+4), regdata);
#endif
	/* we must use IRQF_SHARED mode. here IRQF_SHARED=0x80 */
	ret = request_irq(16, exirq_process, 0x80, "IRQ4",1); 
	if (ret < 0) 
		printk("irq4 request fail.\n");
	else 
		printk("irq4 request success.\n");
#if 0
	init_timer(&test_timer);

	test_timer.function = timer_action;

	test_timer.expires = jiffies + (HZ * 10);

	add_timer(&test_timer);
#endif
	return 0;
}

static struct class *exirq_cls;
dev_t dev_id;
static int __init exirq_init(void)  
{  
  	printk("exirq init...\n");

  	exirq_int_init();
	
	alloc_chrdev_region(&dev_id, 0, 1, "exirq");
	major = MAJOR(dev_id);

	cdev_init(&exirq_cdev, &exirq_fops);
	cdev_add(&exirq_cdev, dev_id, 1);

	exirq_cls = class_create(THIS_MODULE, "exirq");

	device_create(exirq_cls, NULL, dev_id, NULL, "exirq");	
	/* for test */
	/*
	fpga_int_register_callback(0,test1);
	fpga_int_register_callback(1,test2);
	*/


  	return 0;  
}  

static void __exit exirq_exit(void)  
{
     	printk(KERN_ALERT "exirq driver exit\n");

	device_destroy(exirq_cls, MKDEV(major, 0));
    	class_destroy(exirq_cls);
 
	/* 3.3 删除cdev*/
	cdev_del(&exirq_cdev);
 
	/* 3.4 釋放裝置号*/
	unregister_chrdev_region(MKDEV(major, 0), 1);
	free_irq(16,1);
}  

module_init(exirq_init);  
module_exit(exirq_exit);  
MODULE_LICENSE("GPL");  
MODULE_AUTHOR("fzs");
           
/*
 * @file	exirq.c
 * @author	fzs
 * @date	2016-12-13
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/nmi.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/spinlock.h>

#include <asm/io.h>
#include <asm/irq.h>

volatile unsigned int *pic_vaddr6 = NULL, *pic_vaddr5 = NULL;
extern void open_softirq(int nr, void (*action)(struct softirq_action *));
extern phys_addr_t get_immrbase(void);

static atomic_t ex_interrupt_has_happen = ATOMIC_INIT(0);
static wait_queue_head_t ex_interrupt;

#define MPC85xx_PIC_EIVPR6		0x500c0
#define WAIT_FOR_EXTERN_INTERRUPT	0x1

#if 1
static irqreturn_t exirq_process ( int irq, void *dev_id )
{
	int handled = 0;
	u32 regdata;

//	printk("come in irq_process \n");
#if 1
	regdata = in_be32(pic_vaddr6);

	//printk("pic_eivpr6 value = %x \n", regdata);
	if(regdata & 0x40000000)
	{
		atomic_set(&ex_interrupt_has_happen, 1);
		wake_up_interruptible(&ex_interrupt);	
	}
#endif

	//spin_lock(&i->lock);
	handled = 1;

	//spin_unlock(&i->lock);

	return IRQ_RETVAL(handled);
}
#endif

static long exirq_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
                                                                                       
        switch (cmd)                                                                      
        {
		case WAIT_FOR_EXTERN_INTERRUPT:
			//printk("wait for extern interrupt\n");

			wait_event_interruptible(ex_interrupt,
			atomic_read(&ex_interrupt_has_happen)!=0);
			atomic_set(&ex_interrupt_has_happen, 0);

			//printk("get an interrupt\n");
		break;
		default:
			printk("cmd=%d error\n",cmd);
		break;
	}
	return 0;
}
#if 0
static struct timer_list test_timer;
static void timer_action(unsigned long aa)
{
	atomic_set(&ex_interrupt_has_happen, 1);
	wake_up_interruptible(&ex_interrupt);	
	
	test_timer.expires = jiffies+(HZ*10);
	add_timer(&test_timer);
}
#endif
static struct file_operations exirq_fops = {
         .owner = THIS_MODULE,
         .unlocked_ioctl = exirq_ioctl
};

struct cdev exirq_cdev; 
int major;
int exirq_int_init(void)
{
	unsigned int regdata = 0;
	int ret = 0;


	init_waitqueue_head(&ex_interrupt);
	atomic_set(&ex_interrupt_has_happen, 0);
#if 1
	pic_vaddr6 = ioremap(get_immrbase() + MPC85xx_PIC_EIVPR6, 64);

	/* init EIVPR4 to 0x80000 */
	regdata = 0x80000; /* priority=8; vector=0 */
//	regdata |= 1<<22;
	out_be32(pic_vaddr6, regdata);

	/* init EIDR4 to let core process the int*/
	regdata  = 2;
	out_be32((pic_vaddr6+4), regdata);
#endif
	/* we must use IRQF_SHARED mode. here IRQF_SHARED=0x80 */
	ret = request_irq(16, exirq_process, 0x80, "IRQ4",1); 
	if (ret < 0) 
		printk("irq4 request fail.\n");
	else 
		printk("irq4 request success.\n");
#if 0
	init_timer(&test_timer);

	test_timer.function = timer_action;

	test_timer.expires = jiffies + (HZ * 10);

	add_timer(&test_timer);
#endif
	return 0;
}

static struct class *exirq_cls;
dev_t dev_id;
static int __init exirq_init(void)  
{  
  	printk("exirq init...\n");

  	exirq_int_init();
	
	alloc_chrdev_region(&dev_id, 0, 1, "exirq");
	major = MAJOR(dev_id);

	cdev_init(&exirq_cdev, &exirq_fops);
	cdev_add(&exirq_cdev, dev_id, 1);

	exirq_cls = class_create(THIS_MODULE, "exirq");

	device_create(exirq_cls, NULL, dev_id, NULL, "exirq");	
	/* for test */
	/*
	fpga_int_register_callback(0,test1);
	fpga_int_register_callback(1,test2);
	*/


  	return 0;  
}  

static void __exit exirq_exit(void)  
{
     	printk(KERN_ALERT "exirq driver exit\n");

	device_destroy(exirq_cls, MKDEV(major, 0));
    	class_destroy(exirq_cls);
 
	/* 3.3 删除cdev*/
	cdev_del(&exirq_cdev);
 
	/* 3.4 釋放裝置号*/
	unregister_chrdev_region(MKDEV(major, 0), 1);
	free_irq(16,1);
}  

module_init(exirq_init);  
module_exit(exirq_exit);  
MODULE_LICENSE("GPL");  
MODULE_AUTHOR("fzs");