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

时间: 2024-11-14 13:17:51

linux下按键驱动程序的相关文章

Linux下编写驱动程序(VFS)

转:http://hi.baidu.com/firstm25/item/8fe022155e1fa78988a9568f 摘要:设备驱动程序是操作系统内核与机器硬件之间的接口.设备驱动程序为应用程序屏蔽了硬件的细节.那么驱动程序如何书写实现这一接口功能是本文讨论的重点,并以一简单的驱动程序介绍书写细节. 在用户进程调用驱动程序时,系统进入核心态,这时不再是抢先式调度.(应用程序一般是在用户态下进行)也就是说系统必须在驱动程序的子函数返回后才能进行其它的工作,即驱动程序不能进入死循环. 字符型设备

在Linux下的中断方式读取按键驱动程序

// 在Linux下的中断方式读取按键驱动程序 //包含外部中断 休眠 加入poll机制 // 采用异步通知的方式 // 驱动程序发 ---> app接收 (通过kill_fasync()发送) // 为了使设备支持异步通知机制,驱动程序中涉及以下3项工作: // 1. 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID. // 不过此项工作已由内核完成,设备驱动无须处理. // 2. 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序

linux下块设备驱动程序

块设备不能向字符设备那样访问,而是要先将请求放入队列,优化调整顺序后再执行,这种访问方式称为"电梯调度算法". 本篇文章通过ramdisk.nand flash.nor flash来讲解如何写块设备驱动程序. 一.ramdisk 1.因为块设备驱动程序是将请求放入队列然后调整顺序后执行,所以我们需要先定义请求队列: static unsigned char *ramblock_buf; ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);

Linux下PCI设备驱动程序开发 --- PCI驱动程序实现(三)

三.PCI驱动程序实现 1. 关键数据结构 PCI设备上有三种地址空间:PCI的I/O空间.PCI的存储空间和PCI的配置空间.CPU可以访问PCI设备上的所有地址空间,其中I/O空间和存储空间提供给设备驱动程序使用,而配置空间则由Linux内核中的PCI初始化代码使用.内核在启动时负责对所有PCI设备进行初始化,配置好所有的PCI设备,包括中断号以及I/O基址,并在文件/proc/pci中列出所有找到的PCI设备,以及这些设备的参数和属性. Linux驱动程序通常使用结构(struct)来表示

基于输入子系统的按键驱动程序

输入子系统框图: 基于输入子系统的按键驱动程序步骤: 1.分配input_dev结构体 2.设置这个结构体 3.注册 4.硬件相关操作(有数据产生时调用 input_event来上报). 1.分配input_dev结构体 首先要定义这个结构体:static struct input_dev *buttons_dev; 然后在init函数中进行以下操作:buttons_dev = input_allocate_device(); 2.设置这个结构体 使用set_bit来设置这一个位,能设置以下参数

20150216 IMX257实现GPIO-查询按键驱动程序

20150216IMX257实现GPIO-查询按键驱动程序 2015-02-16 李海沿 前面我们介绍了简单的通用字符设备驱动程序,接下来,我们在它的基础上来实现GPIO的查询按键功能. 先附上驱动程序代码 1 /****************************** 2 linux key_query 3 *****************************/ 4 #include <linux/module.h> 5 #include <linux/init.h>

20150216简单的Linux字符设备驱动程序

20150216简单的Linux字符设备驱动程序 2015-02-16 李海沿 关于字符设备驱动程序详细的知识点,本文就不再介绍了,很多同志,看了知识点,还是一头雾水,写不出来,所以,本文从实战出发,带领各位同胞们来实现一个字符设备驱动程序,改程序可作为字符设备的通用模板. 好了废话不多说,先上驱动程序,在驱动程序中加入详细注释: 1 /****************************** 2 linux 字符设备驱动程序 3 *****************************/

IMX257实现GPIO-IRQ中断按键驱动程序

IMX257实现GPIO-IRQ中断按键驱动程序 2015-02-18 李海沿 ????昨天我们已经实现了中断查询的方式实现GPIO按键驱动程序,但是,有一个缺点就是,当我们把应用程序放在后台执行时,即便没有按键,应用程序while循环中的read函数也不断的在运行,严重的导致了CPU资源的浪费. ????本文中,我们在前面按键查询驱动程序的基础上来修改. ????大概介绍一下设计思路吧: ????和前面的差不多,当我们加载驱动时,首先在init函数中,对GPIO功能进行模式设置,都设置为GPI

7.自己写中断方式按键驱动程序

request_irq()和free_irq()分析完毕后,接下来开始编写上升沿中断的按键驱动 如下图,需要设置4个按键的EINT0, EINT2, EINT11, EINT19的模式为双边沿,且设置按键引脚为中断引脚 这里我们只需要使用request_irq函数就行了, 在request_irq函数里会初始chip->set_type(设置引脚和中断模式) 1.首先添加头文件 #include <linux/irq.h> //要用到IRQ_EINT0和IRQT_RISING这些变量 2