linux下按键驱动程序
说明:由于调试的时候minicom出了问题,传送大一点的文件就会失败,所以下面的程序可能会有点问题,请注意
1.button.c
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/moduleparam.h>
#include<linux/init.h>
#include<linux/kdev_t.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<linux/device.h>
//#include<asm/arch/regs-gpio.h>
#include
<mach/regs-gpio.h>
//#include<asm/hardware.h>
#include
<mach/hardware.h>
#include<asm/uaccess.h>
#include<linux/poll.h>
#include<linux/interrupt.h>
#include<asm/irq.h>
#include<asm/io.h>
#include<linux/delay.h>
#define DEV_NAME "linux_buttons"
#define led_on_1 ~(1<<5)
#define led_on_2 ~(1<<6)
#define
led_on_3 ~(1<<7)
#define led_on_4 ~(1<<8)
static int buttons_major, buttons_minor = 0;
static struct cdev
buttons_cdev;
static struct class *buttons_class;
static dev_t dev;
struct button_irq_desc
{
int irq;
int pin;
int
pin_setting;
int number;
char *name;
};
static struct button_irq_desc button_irqs[4]=
{
{IRQ_EINT1,
S3C2410_GPF1, S3C2410_GPF1_EINT1, 0, "KEY1"},
{IRQ_EINT4, S3C2410_GPF4,
S3C2410_GPF4_EINT4, 1, "KEY2"},
{IRQ_EINT2, S3C2410_GPF2,
S3C2410_GPF2_EINT2, 2, "KEY3"},
{IRQ_EINT0, S3C2410_GPF0,
S3C2410_GPF0_EINT0, 3, "KEY4"}
};
static volatile int key_values[] = {0, 0, 0, 0};
static
DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static volatile int ev_press = 0;
static irqreturn_t buttons_interrupt_1(int irq, void *dev_id);
static
irqreturn_t buttons_interrupt_4(int irq, void *dev_id);
static irqreturn_t
buttons_interrupt_2(int irq, void *dev_id);
static irqreturn_t
buttons_interrupt_0(int irq, void *dev_id);
void *sequence_int[]={
buttons_interrupt_1,
buttons_interrupt_4,
buttons_interrupt_2,
buttons_interrupt_0
};
static irqreturn_t buttons_interrupt_1(int irq, void *dev_id)
{
if
(s3c2410_gpio_getpin(S3C2410_GPF1))
{
printk("key_1 down and
the pin is high\n");
mdelay(20);
if
(s3c2410_gpio_getpin(S3C2410_GPF1))
printk("Debounce \n");
writel(led_on_1,S3C2410_GPBDAT);
ev_press = 1;
key_values[0]++;
}
}
static irqreturn_t buttons_interrupt_4(int irq, void *dev_id)
{
if
(s3c2410_gpio_getpin(S3C2410_GPF4))
{
printk("key_2 down and
the pin is high\n");
mdelay(20);
if
(s3c2410_gpio_getpin(S3C2410_GPF4))
printk("Debounce \n");
writel(led_on_2,S3C2410_GPBDAT);
ev_press = 1;
key_values[1]++;
}
}
static irqreturn_t buttons_interrupt_2(int irq, void *dev_id)
{
if
(s3c2410_gpio_getpin(S3C2410_GPF2))
{
printk("key_3 down and
the pin is high\n");
mdelay(20);
if
(s3c2410_gpio_getpin(S3C2410_GPF2))
printk("Debounce \n");
writel(led_on_3,S3C2410_GPBDAT);
ev_press = 1;
key_values[2]++;
}
}
static irqreturn_t buttons_interrupt_0(int irq, void *dev_id)
{
if
(s3c2410_gpio_getpin(S3C2410_GPF0))
{
printk("key_4 down and
the pin is high\n");
mdelay(20);
if
(s3c2410_gpio_getpin(S3C2410_GPF0))
printk("Debounce \n");
writel(led_on_4,S3C2410_GPBDAT);
ev_press = 1;
key_values[3]++;
}
}
static int buttons_open(struct inode *inode, struct file *filp)
{
int i,err;
unsigned long irq_type;
writel((1<<10)|
(1<<12) | (1<<14) | (1<<16),S3C2410_GPBCON);
irq_type = ioread32(S3C2410_EXTINT0);
irq_type &=
~((3<<1) | (3<<5) | (3<<9) | (3<<17));
irq_type
|= ((1<<1) | (1<<5) | (1<<9) | (1<<17));
iowrite32(irq_type, S3C2410_EXTINT0);
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, sequence_int[i], NULL,
button_irqs[i].name, (void *)&button_irqs[i]);
if(err)
break;
}
if (err)
{
i--;
for(; i
>= 0; i--)
{
disable_irq(button_irqs[i].irq);
free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
}
return -EBUSY;
}
return 0;
}
static int buttons_close(struct inode *inode, struct file* file)
{
int i;
for (i = 0; i< 4; i++)
{
disable_irq(button_irqs[i].irq);
free_irq(button_irqs[i].irq,
(void*)&button_irqs[i]);
}
return 0;
}
static int buttons_read(struct file* filp, char __user *buff, size_t
count,loff_t *offp)
{
unsigned long err;
if (!ev_press)
{
if (filp->f_flags & O_NONBLOCK)
{
printk("process is noblock");
return -EAGAIN;
}
else
{
printk("buttons_read read time");
wait_event_interruptible(button_waitq, ev_press);
}
}
ev_press = 0;
err = copy_to_user(buff, key_values, count);
memset(key_values, 0, sizeof(key_values));
return err? -EFAULT :
4;
}
static unsigned int buttons_poll(struct file *filp, poll_table *
wait)
{
unsigned int mask = 0;
poll_wait(filp,
&button_waitq, wait);
if(ev_press)
mask |= POLLIN |
POLLRDNORM;
return mask;
}
static struct file_operations buttons_fops =
{
.owner =
THIS_MODULE,
.open = buttons_open,
.release = buttons_close,
.read = buttons_read,
.poll = buttons_poll
};
static int __init buttons_init(void)
{
int result;
if
(buttons_major) //若是已决定好设备号,则静态分配
{
dev = MKDEV(buttons_major,
buttons_minor);
result = register_chrdev_region(dev, 1,
DEV_NAME);
}
else //动态分配设备号
{
result =
alloc_chrdev_region(&dev, buttons_minor, 1, DEV_NAME);
buttons_major = MAJOR(dev);
}
if (result < 0)
{
printk(KERN_WARNING "buttons:can‘t
get major %d\n", buttons_major);
return result;
}
else
{
printk(KERN_WARNING "registered ok\n buttons_major = %d\n",
buttons_major);
}
cdev_init(&buttons_cdev,
&buttons_fops);//初始化cdev结构
buttons_cdev.owner = THIS_MODULE;
//设置cdev.owner成员为HHIS_MODULE
//buttons_cdev.ops = &buttons_fops;
//设置cdev.ops成员为buttons_fops
result = cdev_add(&buttons_cdev, dev,
1);//设置cdev.dev以及.count成员
if (result < 0)
{
printk(KERN_WARNING "cdev_add failed!\n");
return result;
}
else
{
printk(KERN_WARNING "");
}
buttons_class = class_create(THIS_MODULE, DEV_NAME);//创建class结构
if
(IS_ERR(buttons_class))
{
printk(KERN_ALERT "err:fail in
buttons_class!\n");
return -1;
}
else
{
printk(KERN_WARNING" SUCCESS IN buttons_class!\n");
}
/*创建相应的设备节点*/
device_create(buttons_class, NULL, MKDEV(buttons_major,
0), NULL, DEV_NAME);
printk(KERN_WARNING"SUCCESS IN buttons_CLASS!\n");
return
0;
}
static void __exit buttons_exit(void)
{
int devno =
MKDEV(buttons_major, buttons_minor);
writel(0xffff, S3C2410_GPBDAT);
//关闭LED
unregister_chrdev_region(devno, 1);
//释放设备号
cdev_del(&buttons_cdev);
//删除cdev结构
device_destroy(buttons_class,
devno);//删除设备节点
class_destroy(buttons_class);
///删除class结构
printk(KERN_WARNING"buttons module exit!\n");
}
module_init(buttons_init);
module_exit(buttons_exit);
MODULE_LICENSE("Dual
BSD/GPL");
MODULE_AUTHOR("xiaoheng");
2.buttontest.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/time.h>
#include<errno.h>
int main(void)
{
int i;
int buttons_fd;
int
key_value[4];
buttons_fd = open("/dev/linux_buttons", 0);
if (buttons_fd < 0)
{
perror("open buttons fail");
exit(1);
}
for (;;)
{
printf("test file read time\n");
read(buttons_fd, key_value, sizeof(key_value));
for (i = 0; i < 4; i++)
{
if
(key_value[i] != 0)
printf("K%d pressed, key value =
0x%d\n",i++, key_value[i]);
}
}
close(buttons_fd);
return 0;
}
3.Makefile
obj-m:=button.o
KDIR:=/home/xiaoheng/Desktop/2.6.30.4/opt/EmbedSky/linux-2.6.30.4
all:
make
-C $(KDIR) M=$(shell pwd) modules
clean:
make -C $(KDIR) M=$(shell pwd)
clean