tiny6410_按键驱动程序_中断

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


 

结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值