| 1 | #include <linux/init.h>
 | 
  
    | 2 | #include <linux/module.h>
 | 
  
    | 3 | #include <linux/kernel.h>
 | 
  
    | 4 | #include <linux/device.h>
 | 
  
    | 5 | #include <linux/platform_device.h>
 | 
  
    | 6 | #include <linux/ioport.h>
 | 
  
    | 7 | #include <linux/io.h>
 | 
  
    | 8 | #include <linux/wait.h>
 | 
  
    | 9 | #include <linux/sched.h>
 | 
  
    | 10 | #include <linux/semaphore.h>
 | 
  
    | 11 | #include <linux/interrupt.h>
 | 
  
    | 12 | #include <linux/spinlock_types.h>
 | 
  
    | 13 | 
 | 
  
    | 14 | #define UINPUT_BASE 0xff200000
 | 
  
    | 15 | #define UINPUT_SIZE PAGE_SIZE
 | 
  
    | 16 | //#define UINPUT_INT_NUM 72
 | 
  
    | 17 | //#define UINPUT_INT_NUM 352
 | 
  
    | 18 | 
 | 
  
    | 19 | //#define UINPUT_INT_NUM 40 //no irq
 | 
  
    | 20 | //#define UINPUT_INT_NUM 41 //no irq
 | 
  
    | 21 | //#define UINPUT_INT_NUM 71 //HANG
 | 
  
    | 22 | //#define UINPUT_INT_NUM 72 //HANG
 | 
  
    | 23 | //#define UINPUT_INT_NUM 65 //no irq
 | 
  
    | 24 | //#define UINPUT_INT_NUM 0 //not able to insmood
 | 
  
    | 25 | //#define UINPUT_INT_NUM 1 //not able to insmood
 | 
  
    | 26 | //#define UINPUT_INT_NUM 15 //not able to insmood
 | 
  
    | 27 | //#define UINPUT_INT_NUM 40 //working when enabling irq?
 | 
  
    | 28 | //#define UINPUT_INT_NUM 35 //Working
 | 
  
    | 29 | //#define UINPUT_INT_NUM 77 //HANG
 | 
  
    | 30 | //#define UINPUT_INT_NUM 79 //HANG
 | 
  
    | 31 | //#define UINPUT_INT_NUM 42 // no irq
 | 
  
    | 32 | //#define UINPUT_INT_NUM 89 // itq line 2, nbr 17
 | 
  
    | 33 | //#define UINPUT_INT_NUM 43 //no irq
 | 
  
    | 34 | //#define UINPUT_INT_NUM 38 // no_irq
 | 
  
    | 35 | //#define UINPUT_INT_NUM 74 // HANG
 | 
  
    | 36 | //#define UINPUT_INT_NUM 34  // no_irq
 | 
  
    | 37 | //#define UINPUT_INT_NUM 36  // no_irq
 | 
  
    | 38 | //#define UINPUT_INT_NUM 37  // no_irq
 | 
  
    | 39 | //#define UINPUT_INT_NUM 38  // no_irq
 | 
  
    | 40 | //#define UINPUT_INT_NUM 33  // no_irq
 | 
  
    | 41 | //#define UINPUT_INT_NUM 32  // no_irq
 | 
  
    | 42 | //#define UINPUT_INT_NUM 39  // no_irq
 | 
  
    | 43 | //#define UINPUT_INT_NUM 41  // no_irq
 | 
  
    | 44 | //#define UINPUT_INT_NUM 68  // Error not instert, 122??
 | 
  
    | 45 | #define UINPUT_INT_NUM 43  // Error not instert, 123
 | 
  
    | 46 | //#define UINPUT_INT_NUM 40  // Error not instert, 123
 | 
  
    | 47 | 
 | 
  
    | 48 | void *fpga_uinput_mem;
 | 
  
    | 49 | 
 | 
  
    | 50 | static DEFINE_SEMAPHORE(interrupt_mutex);
 | 
  
    | 51 | static DECLARE_WAIT_QUEUE_HEAD(interrupt_wq);
 | 
  
    | 52 | 
 | 
  
    | 53 | static int interrupt_flag = 0;
 | 
  
    | 54 | static DEFINE_SPINLOCK(interrupt_flag_lock);
 | 
  
    | 55 | static uint8_t input_state;
 | 
  
    | 56 | //static int irq_cnt = 0;
 | 
  
    | 57 | 
 | 
  
    | 58 | static irqreturn_t fpga_uinput_interrupt(int irq, void *dev_id)
 | 
  
    | 59 | {
 | 
  
    | 60 | 	if (irq != UINPUT_INT_NUM)
 | 
  
    | 61 |    {
 | 
  
    | 62 | 		return IRQ_NONE;
 | 
  
    | 63 |    }
 | 
  
    | 64 | 	spin_lock(&interrupt_flag_lock);
 | 
  
    | 65 | 	interrupt_flag = 1;
 | 
  
    | 66 | 	input_state = ioread8(fpga_uinput_mem);
 | 
  
    | 67 | 	spin_unlock(&interrupt_flag_lock);
 | 
  
    | 68 | 
 | 
  
    | 69 | 	wake_up_interruptible(&interrupt_wq);
 | 
  
    | 70 | 
 | 
  
    | 71 | 	return IRQ_HANDLED;
 | 
  
    | 72 | }
 | 
  
    | 73 | 
 | 
  
    | 74 | static struct device_driver fpga_uinput_driver = {
 | 
  
    | 75 | 	.name = "fpga_uinput",
 | 
  
    | 76 | 	.bus = &platform_bus_type,
 | 
  
    | 77 | };
 | 
  
    | 78 | 
 | 
  
    | 79 | static ssize_t fpga_uinput_show(struct device_driver *drv, char *buf)
 | 
  
    | 80 | {
 | 
  
    | 81 | 	int ret;
 | 
  
    | 82 | 	if (down_trylock(&interrupt_mutex))
 | 
  
    | 83 |    {
 | 
  
    | 84 |      // irq_cnt++;
 | 
  
    | 85 | 	  // if (irq_cnt == 1000)
 | 
  
    | 86 | 		//{	
 | 
  
    | 87 | 		  // irq_cnt = 0;
 | 
  
    | 88 | 		   printk(KERN_ALERT "KERNEL DEBUG down_trylock: Passed %s %d \n",__FUNCTION__,__LINE__);					
 | 
  
    | 89 | 		//}	
 | 
  
    | 90 | 		return -EAGAIN;
 | 
  
    | 91 |    }
 | 
  
    | 92 | 
 | 
  
    | 93 |    if (wait_event_interruptible(interrupt_wq, interrupt_flag != 0)) {
 | 
  
    | 94 | 		ret = -ERESTART;
 | 
  
    | 95 |       printk(KERN_ALERT "KERNEL DEBUG release_and_exit: Passed %s %d \n",__FUNCTION__,__LINE__);			
 | 
  
    | 96 | 		goto release_and_exit;
 | 
  
    | 97 | 	}
 | 
  
    | 98 | 
 | 
  
    | 99 | 	spin_lock(&interrupt_flag_lock);
 | 
  
    | 100 | 	interrupt_flag = 0;
 | 
  
    | 101 | 	spin_unlock(&interrupt_flag_lock);
 | 
  
    | 102 | 
 | 
  
    | 103 | 	buf[0] = input_state;
 | 
  
    | 104 | 	ret = 1;
 | 
  
    | 105 | 
 | 
  
    | 106 | release_and_exit:
 | 
  
    | 107 | 	up(&interrupt_mutex);
 | 
  
    | 108 | 	return ret;
 | 
  
    | 109 | }
 | 
  
    | 110 | 
 | 
  
    | 111 | static ssize_t fpga_uinput_store(struct device_driver *drv,
 | 
  
    | 112 | 		const char *buf, size_t count)
 | 
  
    | 113 | {
 | 
  
    | 114 | 	return -EROFS;
 | 
  
    | 115 | }
 | 
  
    | 116 | 
 | 
  
    | 117 | static DRIVER_ATTR(fpga_uinput, S_IRUSR, fpga_uinput_show, fpga_uinput_store);
 | 
  
    | 118 | 
 | 
  
    | 119 | static int __init fpga_uinput_init(void)
 | 
  
    | 120 | {
 | 
  
    | 121 | 	int ret;
 | 
  
    | 122 | 	struct resource *res;
 | 
  
    | 123 | 
 | 
  
    | 124 |     printk(KERN_ALERT "KERNEL DEBUG fpga_uinput_init: Passed %s %d \n",__FUNCTION__,__LINE__);	
 | 
  
    | 125 | 	ret = driver_register(&fpga_uinput_driver);
 | 
  
    | 126 | 	if (ret < 0)
 | 
  
    | 127 | 		goto fail_driver_register;
 | 
  
    | 128 | 
 | 
  
    | 129 | 	ret = driver_create_file(&fpga_uinput_driver,
 | 
  
    | 130 | 			&driver_attr_fpga_uinput);
 | 
  
    | 131 | 	if (ret < 0)
 | 
  
    | 132 | 		goto fail_create_file;
 | 
  
    | 133 | 
 | 
  
    | 134 | 	res = request_mem_region(UINPUT_BASE, UINPUT_SIZE, "fpga_uinput");
 | 
  
    | 135 | 	if (res == NULL) {
 | 
  
    | 136 | 		ret = -EBUSY;
 | 
  
    | 137 | 		goto fail_request_mem;
 | 
  
    | 138 | 	}
 | 
  
    | 139 | 
 | 
  
    | 140 | 	fpga_uinput_mem = ioremap(UINPUT_BASE, UINPUT_SIZE);
 | 
  
    | 141 | 	if (fpga_uinput_mem == NULL) {
 | 
  
    | 142 | 		ret = -EFAULT;
 | 
  
    | 143 | 		goto fail_ioremap;
 | 
  
    | 144 | 	}
 | 
  
    | 145 | 
 | 
  
    | 146 | 	ret = request_irq(UINPUT_INT_NUM, fpga_uinput_interrupt,
 | 
  
    | 147 | 			0, "fpga_uinput", NULL);
 | 
  
    | 148 | 	if (ret < 0)
 | 
  
    | 149 | 		goto fail_request_irq;
 | 
  
    | 150 | 
 | 
  
    | 151 | 	return 0;
 | 
  
    | 152 | 
 | 
  
    | 153 | fail_request_irq:
 | 
  
    | 154 | 	iounmap(fpga_uinput_mem);
 | 
  
    | 155 | fail_ioremap:
 | 
  
    | 156 | 	release_mem_region(UINPUT_BASE, UINPUT_SIZE);
 | 
  
    | 157 | fail_request_mem:
 | 
  
    | 158 | 	driver_remove_file(&fpga_uinput_driver, &driver_attr_fpga_uinput);
 | 
  
    | 159 | fail_create_file:
 | 
  
    | 160 | 	driver_unregister(&fpga_uinput_driver);
 | 
  
    | 161 | fail_driver_register:
 | 
  
    | 162 | 	return ret;
 | 
  
    | 163 | }
 | 
  
    | 164 | 
 | 
  
    | 165 | static void __exit fpga_uinput_exit(void)
 | 
  
    | 166 | {
 | 
  
    | 167 | 	free_irq(UINPUT_INT_NUM, NULL);
 | 
  
    | 168 | 	iounmap(fpga_uinput_mem);
 | 
  
    | 169 | 	release_mem_region(UINPUT_BASE, UINPUT_SIZE);
 | 
  
    | 170 | 	driver_remove_file(&fpga_uinput_driver, &driver_attr_fpga_uinput);
 | 
  
    | 171 | 	driver_unregister(&fpga_uinput_driver);
 | 
  
    | 172 | }
 | 
  
    | 173 | 
 | 
  
    | 174 | MODULE_LICENSE("Dual BSD/GPL");
 | 
  
    | 175 | 
 | 
  
    | 176 | module_init(fpga_uinput_init);
 | 
  
    | 177 | module_exit(fpga_uinput_exit);
 |