#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/string.h>
#define THIRD_NAME "third_drv"
static int major = 0;
struct class *third_class = NULL;
struct class_device * third_class_dev = NULL;
volatile unsigned long *gph2con;
volatile unsigned long *gph2dat;
volatile unsigned long *gph3con;
volatile unsigned long *gph3dat;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static volatile int ev_press = 0;
struct button_irq_desc {
int irq;
unsigned long flags;
char *name;
};
static struct button_irq_desc button_irqs[] = {
{IRQ_EINT0, IRQF_TRIGGER_FALLING, "KEY1"},
{IRQ_EINT2, IRQF_TRIGGER_FALLING, "KEY2"},
{IRQ_EINT19, IRQF_TRIGGER_FALLING, "KEY3"},
{IRQ_EINT11, IRQF_TRIGGER_FALLING, "KEY4"},
};
static volatile int press_cnt[] = {0,0,0,0};
struct press_key {
char *name;
unsigned long irq;
unsigned long flags;
unsigned int cnts;
};
static struct press_key press_keys[4] = {
{NULL, 0, 0, 0},
{NULL, 0, 0, 0},
{NULL, 0, 0, 0},
{NULL, 0, 0, 0},
};
static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
volatile int press_i = (void *)dev_id;
strcpy(press_keys[press_i].name ,button_irqs[press_i].name);
press_keys[press_i].irq = button_irqs[press_i].irq;
press_keys[press_i].flags = button_irqs[press_i].flags;
press_keys[press_i].cnts += 1;
// printk("press_cnt[0]=%d \n", press_cnt[0]);
// printk("press_cnt[1]=%d \n", press_cnt[1]);
// printk("press_cnt[2]=%d \n", press_cnt[2]);
// printk("press_cnt[3]=%d \n", press_cnt[3]);
ev_press = 1;
wake_up_interruptible(&button_waitq);
return IRQ_RETVAL(IRQ_HANDLED);
}
static int third_drv_open(struct inode *inode, struct file *file)
{
int i, err;
int button_cnt = sizeof(button_irqs)/sizeof(button_irqs[0]);
for (i = 0; i < button_cnt; i++)
{
err = request_irq(button_irqs[i].irq, buttons_interrupt, button_irqs[i].flags, \
button_irqs[i].name, i);
if (err)
break;
}
if (err)
{
i = 0;
for (i = 0; i < button_cnt; i++ )
free_irq(button_irqs[i].irq, i);
return -EBUSY;
}
return 0;
}
static ssize_t third_drv_read(struct file *file, char __user *buf, size_t count , loff_t *ppos)
{
int ret = 0;
if (count != sizeof(press_cnt))
return -EINVAL;
printk("third_drv_read begin \n");
wait_event_interruptible(button_waitq, ev_press);
copy_to_user(buf, press_keys, sizeof(press_keys));
ev_press = 0;
return sizeof(press_keys);
}
static int third_drv_release(struct inode *inode, struct file *file)
{
int i = 0;
int button_cnt = sizeof(button_irqs)/sizeof(button_irqs[0]);
for (i = 0; i < button_cnt; i++ )
free_irq(button_irqs[i].irq, i);
return 0;
}
static struct file_operations third_drv_fops ={
.owner = THIS_MODULE,
.open = third_drv_open,
.read = third_drv_read,
.release = third_drv_release,
};
static __init int third_drv_init(void)
{
major = register_chrdev(0, THIRD_NAME, &third_drv_fops);
third_class = class_create(THIS_MODULE, "third_drv");
third_class_dev = class_device_create(third_class, NULL, MKDEV(major, 0), NULL, "buttons");
gph2con = (volatile unsigned long *)ioremap(0xe0200c40, 16);
gph2dat = gph2con + 1;
gph3con = (volatile unsigned long *)ioremap(0xE0200C60, 16);
gph3dat = gph3con + 1;
// press_keys = kzalloc(4 * sizeof(struct press_key), GFP_KERNEL);
return 0;
}
static __exit void third_drv_exit(void)
{
// kfree(press_keys);
unregister_chrdev(major, THIRD_NAME);
class_device_unregister(third_class_dev);
class_destroy(third_class);
}
module_init(third_drv_init);
module_exit(third_drv_exit);
MODULE_LICENSE("GPL");
echo 5</dev/buttons
cat /proc/interrupts
ps
ls /proc/771/fd
exec 5<&-