TQ2440 中断按键驱动

按键驱动程序:

#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/fs.h>
#include<linux/init.h>
#include<linux/delay.h>
#include<asm/irq.h>
#include<linux/poll.h>
#include<linux/irq.h>
#include<asm/irq.h>
#include<linux/interrupt.h>
#include<asm/uaccess.h>
#include<mach/regs-gpio.h>
#include<mach/hardware.h>
#include<linux/device.h>
#include<linux/miscdevice.h>
#include<linux/cdev.h>

#define DEVICE_NAME "mybuttons"

struct button_irq_desc{
	int irq;	//中断号,中断号唯一表示一个中断
	int pin;	//中断控制的寄存器,该寄存器的值由中断引脚设置,我们希望从该寄存器读出控制信息
	int pin_setting;	//中断的引脚,该引脚的电平由按键来控制,从而最终我们由按键控制了寄存器的值
	int number;		//编号
	char *name;		//名称
};

//用来指定按键所用的外部中断引脚及中断触发方式、名字
static struct button_irq_desc button_irqs[] ={
	{IRQ_EINT1, S3C2410_GPF1, S3C2410_GPF1_EINT1, 0, "KET1"},
	{IRQ_EINT4, S3C2410_GPF4, S3C2410_GPF4_EINT4, 1, "KET2"},
	{IRQ_EINT2, S3C2410_GPF2, S3C2410_GPF2_EINT2, 2, "KET3"},
	{IRQ_EINT0, S3C2410_GPF0, S3C2410_GPF0_EINT0, 3, "KET4"},
};

//按键值
static volatile int key_values;

//等待队列:当没有按键被按下,即没有触发中断时,如果有进程调用read函数,则该进程进入休眠
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
//定义了一个整型变量用于判定按键是否被按下,0未按下,1按下,中断事件标志,中断服务程序将它置1,read函数将其清0
static volatile int ev_press = 0;

//中断服务程序
static irqreturn_t irq_interrupt(int irq,void *dev_id)
{
	struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
	int up;
	up = s3c2410_gpio_getpin(button_irqs->pin);

	if(up)
		key_values = (button_irqs->number+1)+0x80;

	else
		key_values = (button_irqs->number+1);
	ev_press = 1;	//表示中断发生
	wake_up_interruptible(&button_waitq);		//唤醒休眠的进程

	return IRQ_RETVAL(IRQ_HANDLED);
}


static int irq_open(struct inode *inode,struct file *file)
{
        int i;
	int err = 0;
        for(i = 0;i < sizeof(button_irqs)/sizeof(button_irqs[0]);i++)
        {
		//设置引脚
            s3c2410_gpio_cfgpin(button_irqs[i].pin,button_irqs[i].pin_setting);
		//注册中断
		err = request_irq(button_irqs[i].irq,irq_interrupt,IRQ_TYPE_EDGE_BOTH,button_irqs[i].name,(void *)&button_irqs[i]);
// request_irq 的返回值: 0 指示成功,或返回一个负的错误码,如 -EBUSY 表示另一个驱动已经占用了你所请求的中断线。
		if(err)
			break;
        }
	if(err)
	{
		i--;
		for(;i >= 0; i--)
		{
			if(button_irqs[i].irq < 0)
				continue;
			//释放已注册的中断
			disable_irq(button_irqs[i].irq);
			free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);
		}
		return -EBUSY;
	}
	ev_press = 1;
        return 0;
}


static int irq_close(struct inode *inode,struct file *file)
{
	int i;
	for(i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
	{
		//释放已注册的中断
		disable_irq(button_irqs[i].irq);
		free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);
	}
	return 0;
}

static int irq_read(struct file *file,char __user *buff,size_t count,loff_t *offp)
{
	unsigned long err;
	if(!ev_press)
	{
		if(file->f_flags & O_NONBLOCK)
			return -EAGAIN;
		else
			//如果ev_press等于0,则进入休眠
			wait_event_interruptible(button_waitq,ev_press);
	}
	//按键状态复制给用户进程
	err = copy_to_user(buff,&key_values,1);
	//这里ev_press等于1,将它清0
	ev_press = 0;
	return 1;

}

//当用户程序调用select函数时,本函数被调用,如果有按键数据,则select函数会立刻返回,如果没有按键数据,本函数使用poll_wait等待
static unsigned int irq_poll(struct file *file,struct poll_table_struct *wait)
{
	unsigned int mask = 0;
	poll_wait(file,&button_waitq,wait);
	if(ev_press)
		mask |= POLLIN | POLLRDNORM;
	return mask;

}

static struct file_operations buttons_fops =
{
        .owner	 = THIS_MODULE,
        .open 	 = irq_open,
        .release = irq_close,
	.read 	 = irq_read,
	.poll 	 = irq_poll,
};

static struct miscdevice misc = {
        .minor =MISC_DYNAMIC_MINOR,
        .name = DEVICE_NAME,
        .fops = &buttons_fops,
};


static int __init buttons_init(void)
{
        int reg;
        reg = misc_register(&misc);
        printk(DEVICE_NAME" initialized\n");
        return reg;
}

static void __exit buttons_exit(void)
{
        misc_deregister(&misc);
        printk("deregister\n");
}

module_init(buttons_init);
module_exit(buttons_exit);

MODULE_AUTHOR("xh");
MODULE_DESCRIPTION("learn");
MODULE_LICENSE("GPL");


Makefile:

ifneq	($(KERNELRELEASE),)
	obj-m :=key.o
else
#	KERNELDIR :=/lib/modules/2.6.32-21-generic/build
	KERNELDIR :=/opt/EmbedSky/linux-2.6.30.4
	PWD :=$(shell pwd)

default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
	rm -f *.o *.ko
.PHONY:clean



按键测试程序:

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/select.h>
#include<sys/time.h>
#include<errno.h>

#define DEV "/dev/mybuttons"

int main(void)
{
	int i;
	int buttons_fd;
	int key_value = 0;
	struct timeval tv;

	//打开设备文件
	buttons_fd = open(DEV,O_RDWR);
	if(buttons_fd < 0)
	{
		perror(DEV);
		exit(1);
	}
	while(1)
	{
		fd_set rds;
		int ret;
		FD_ZERO(&rds);
		FD_SET(buttons_fd,&rds);
		//设置select超时时间,1s
		tv.tv_sec = 1;
		tv.tv_usec = 0;
		
		//调用select
		ret = select(buttons_fd+1,&rds,NULL,NULL,&tv);
		if(ret < 0)
		{
			perror("select");
			exit(1);
		}
		if(ret == 0)
		{
			printf("Timeout\n");
		}
		//能读到数据
		else if(FD_ISSET(buttons_fd,&rds))	
		{
			//调用read,读取键盘数据
			int ret = read(buttons_fd,&key_value,1);
			if(ret != 1)
			{
				if(errno != EAGAIN)
					perror("read buttons\n");
				continue;
			}
			else
			{	
				//打印
				printf("key_val = 0x%x\n",key_value);
			}

		}
	}
	return 0;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值