您的位置:首页 > 其它

tiny6410_按键驱动程序_中断

2012-11-11 11:01 387 查看
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


结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: