#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <plat/gpio-cfg.h>
#include <plat/gpio-fns.h>
#include <mach/gpio-nrs.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
static dev_t dev;
static struct cdev *my_cdev = NULL;
static struct class *cdev_class = NULL;
static struct device *cdev_class_device = NULL;
static unsigned char key_val;
static volatile int condition = 0;
static DECLARE_WAIT_QUEUE_HEAD(wq);
struct key_desc
{
int pin;
char value;
};
static struct key_desc my_desc[4] = {
{ S3C2410_GPF(1), 0x01 },
{ S3C2410_GPF(4), 0x02 },
{ S3C2410_GPF(2), 0x03 },
{ S3C2410_GPF(0), 0x04 },
};
MODULE_LICENSE("GPL");
static irqreturn_t key_irq(int irq, void *dev_id)
{
struct key_desc *tmp = (struct key_desc *)dev_id;
if(!s3c2410_gpio_getpin(tmp->pin))
{
key_val = tmp->value;
}
else
{
key_val = 0x10|tmp->value;
}
condition = 1;
wake_up_interruptible(&wq);
return IRQ_HANDLED;
}
static int key_open(struct inode *inode, struct file *file)
{
request_irq(IRQ_EINT1 , key_irq, IRQ_TYPE_EDGE_BOTH, "K1", &my_desc[0]);
request_irq(IRQ_EINT4 , key_irq, IRQ_TYPE_EDGE_BOTH, "K2", &my_desc[1]);
request_irq(IRQ_EINT2 , key_irq, IRQ_TYPE_EDGE_BOTH, "K3", &my_desc[2]);
request_irq(IRQ_EINT0 , key_irq, IRQ_TYPE_EDGE_BOTH, "K4", &my_desc[3]);
return 0;
}
static ssize_t key_close(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT1, &my_desc[0]);
free_irq(IRQ_EINT4, &my_desc[1]);
free_irq(IRQ_EINT2, &my_desc[2]);
free_irq(IRQ_EINT0, &my_desc[3]);
return 0;
}
static ssize_t key_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
if(count != 1)
{
return -EINVAL;
}
wait_event_interruptible(wq, condition);
copy_to_user(buf, &key_val, 1);
condition = 0;
return 1;
}
static unsigned key_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
poll_wait(file, &wq, wait);
if(condition)
mask |= POLLIN|POLLRDNORM;
return mask;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = key_open,
.release= key_close,
.read = key_read,
.poll = key_poll,
};
static int key_drv_init(void)
{
int ret = 0;
ret = alloc_chrdev_region(&dev, 0, 4, "mykey");
if(ret < 0)
{
printk("alloc_chrdev_region\n");
}
my_cdev = cdev_alloc();
cdev_init(my_cdev, &fops);
my_cdev->owner = THIS_MODULE;
cdev_add(my_cdev, dev, 4);
cdev_class = class_create(THIS_MODULE, "mykey");
cdev_class_device = device_create(cdev_class, NULL, dev, NULL, "keybutton");
return 0;
}
static void key_drv_exit(void)
{
device_destroy(cdev_class, dev);
class_destroy(cdev_class);
cdev_del(my_cdev);
kzfree(my_cdev);
unregister_chrdev_region(dev, 4);
return ;
}
module_init(key_drv_init);
module_exit(key_drv_exit);
Linux Driver 实现poll
最新推荐文章于 2024-06-06 10:00:00 发布