key_drv_int.c: (采用双边沿触发)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/gpio-bank-n.h>
#include <mach/gpio-bank-l.h>
#define S3C6410_GPNDAT_PA (0x7F008834)
#define S3C6410_GPLDAT_PA (0x7F008818)
static volatile unsigned long* gpndat = NULL;
static volatile unsigned long* gpldat = NULL;
struct key_irq_desc{
int irq;
int num;
char *name;
};
static struct key_irq_desc key_irqs[] = {
{IRQ_EINT(0), 0, "KEY0"}, \
{IRQ_EINT(1), 1, "KEY1"}, \
{IRQ_EINT(2), 2, "KEY2"}, \
{IRQ_EINT(3), 3, "KEY3"}, \
{IRQ_EINT(4), 4, "KEY4"}, \
{IRQ_EINT(5), 5, "KEY5"}, \
{IRQ_EINT(19), 6, "KEY6"}, \
{IRQ_EINT(20), 7, "KEY7"}
};
static volatile char key_values[] = {'0', '0', '0', '0', '0', '0', '0', '0'};
static int major = 0;
static struct class* key_drv_int_class;
static DECLARE_WAIT_QUEUE_HEAD(key_waitq);
static volatile int ev_press = 0;
static irqreturn_t key_drv_irq(int irq, void* dev_id)
{
int down;
int key_num;
struct key_irq_desc *key_irqs = (struct key_irq_desc *)dev_id;
key_num = key_irqs->num;
switch(key_num)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
down = !(*gpndat & (1<<key_num));
break;
case 6:
case 7:
down = !(*gpldat & (1 << (key_num + 5)));
break;
default:
down = 0;
break;
}
if (down != (key_values[key_num] & 1))
{
key_values[key_num] = '0' + down;
ev_press = 1;
wake_up_interruptible(&key_waitq);
}
return IRQ_HANDLED;
}
static int key_drv_int_open(struct inode *inode, struct file *filp)
{
int i;
int ret = 0;
for (i=0; i<sizeof(key_irqs)/sizeof(key_irqs[0]); i++)
{
if(key_irqs[i].irq < 0)
{
continue;
}
ret = request_irq(key_irqs[i].irq, key_drv_irq, IRQ_TYPE_EDGE_BOTH, \
key_irqs[i].name, (void *)&key_irqs[i]);
if (ret)
break;
}
/* handle error */
if(ret)
{
i--;
for( ; i>=0; i--)
{
if(key_irqs[i].irq < 0)
{
continue;
}
disable_irq(key_irqs[i].irq);
free_irq(key_irqs[i].irq, (void *)&key_irqs[i]);
}
return -EBUSY;
}
ev_press = 1;
/* map gpio pth_address to virtual address*/
gpndat= ioremap(S3C6410_GPNDAT_PA, 4);
gpldat= ioremap(S3C6410_GPLDAT_PA, 4);
return 0;
}
static ssize_t key_drv_int_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
unsigned long ret;
if (!ev_press)
{
if (file->f_flags & O_NONBLOCK)
{
return -EAGAIN;
}
else
{
wait_event_interruptible(key_waitq, ev_press);
}
}
ev_press = 0;
ret = copy_to_user(buf, &key_values, sizeof(key_values)<count?sizeof(key_values):count);
return ret ? (-EFAULT):(sizeof(key_values)<count?sizeof(key_values):count);
}
static int key_drv_int_close(struct inode *inode, struct file *file)
{
int i;
for (i=0; i<sizeof(key_irqs)/sizeof(key_irqs[0]); i++)
{
if (key_irqs[i].irq < 0)
{
continue;
}
free_irq(key_irqs[i].irq, (void *)&key_irqs[i]);
}
iounmap(gpndat);
iounmap(gpldat);
return 0;
}
static struct file_operations key_drv_int = {
.owner = THIS_MODULE,
.open = key_drv_int_open,
.read = key_drv_int_read,
.release = key_drv_int_close,
};
static int key_drv_int_init(void)
{
major = register_chrdev(0, "key_drv_int", &key_drv_int);
if(major < 0)
{
printk(KERN_ALERT "Register key_drv_int failed!\n");
return -1;
}
printk(KERN_ALERT "Register key_drv_int succeed!\n");
/* 动态创建设备号,根据创建的设备号创建设备节点(/dev/key_drv_poll) */
key_drv_int_class= class_create(THIS_MODULE, "key_drv_int"); /* sysfs */
device_create(key_drv_int_class, NULL, MKDEV(major, 0), NULL, "key_drv_int"); /* /dev/key_drv_int */
return 0;
}
static void key_drv_int_exit(void)
{
device_destroy(key_drv_int_class, MKDEV(major, 0));
class_destroy(key_drv_int_class);
unregister_chrdev(major, "key_drv_int");
printk(KERN_ALERT "Unregister key_drv_int succeed!\n");
}
module_init(key_drv_int_init);
module_exit(key_drv_int_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("key driver use int");
MODULE_AUTHOR("dl CS0921 WTU");
key_app_int.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#define DEVICE_NAME "/dev/key_drv_int"
int main(int argc, char* argv[])
{
int fd;
fd = open(DEVICE_NAME, O_RDWR);
if(fd < 0)
{
printf("Open %s failed!\n", DEVICE_NAME);
exit(-1);
}
unsigned char key_values[8];
for( ; ; )
{
read(fd, key_values, sizeof(key_values));
printf("key(1~8) value: %c %c %c %c %c %c %c %c\n", \
key_values[0], key_values[1], key_values[2], key_values[3],\
key_values[4], key_values[5], key_values[6], key_values[7]);
}
close(fd);
return 0;
}
Makefile
KERNELDIR = /sdb/kernel/linux-2.6.38-tiny6410/linux-2.6.38/
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules clean
obj-m := key_drv_int.o
结果