=======查询方式来取得按键值(占资源)==========================
查看原理图:
按键s1-s6 对应eint0-5 寄存器为 gpn0-5
按键s7-s8对应eint19-20 寄存器为 gpl11-12
查看芯片手册:
1 搭建驱动框架
2 初始化寄存器
3 在初始化函数中建立地址映射
4 在 open函数中将寄存器设为输入引角
5 在read函数中返回八个引角的电平
读dat寄存器的值
将数据返回用户空间
6 在exit函数中释放内存映射
示例代码如下:
/****************************************
*第三个驱动程序,查询方式实现按键驱动
*****************************************/
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank-n.h>
#include <mach/gpio-bank-l.h>
#include <linux/device.h>
#include <linux/kernel.h>
static struct class *button_dev_class;
static struct device *button_dev_class_dev;
int major;
/*初始化寄存器*/
//s1-s6
volatile unsigned long *gpncon = NULL;
volatile unsigned long *gpndat = NULL;
//s7-s8
volatile unsigned long *gplcon = NULL;
volatile unsigned long *gpldat = NULL;
static int button_dev_open(struct inode*inode, struct file *file)
{
printk("button_dev_open!\n");
//配置gpn0-5为输入(对应位清零)
*gpncon&= ~((0x3<<(0*2))|(0x3<<(1*2))|(0x3<<(2*2))|(0x3<<(3*2))|(0x3<<(4*2))|(0x3<<(5*2)));
//gpl11 、12为输入(对应位清零)
*gplcon&= ~((0xF << (3*4)) | (0xF << (4*4)));
return0;
}
static ssize_t button_dev_read(struct file*file,const char __user *buf,size_t size,loff_t * ppos){
//printk("button_dev_read!\n");
//返回八个引角的电平
unsignedchar key_vals[8];
intregval;
if(size!=sizeof(key_vals)){
return -EINVAL;
}
/*读gpn0-5*/
regval=*gpndat;
key_vals[0]=(regval& (1<<0)) ? 1 : 0;
key_vals[1]=(regval& (1<<1)) ? 1 : 0;
key_vals[2]=(regval& (1<<2)) ? 1 : 0;
key_vals[3]=(regval& (1<<3)) ? 1 : 0;
key_vals[4]=(regval& (1<<4)) ? 1 : 0;
key_vals[5]=(regval& (1<<5)) ? 1 : 0;
/*读gpl11、12*/
regval=*gpldat;
key_vals[6]=(regval& (1<<11)) ? 1 : 0;
key_vals[7]=(regval& (1<<12)) ? 1 : 0;
/*将数据返回用户空间 */
copy_to_user(buf,key_vals,sizeof(key_vals));
returnsizeof(key_vals);
}
static struct file_operationsbutton_dev_fops = {
.owner = THIS_MODULE,
.open = button_dev_open,
.read = button_dev_read,
};
/*注册驱动程序*/
static int __init button_dev_init(void){
/*major设备的主设备号,name是驱动程序的名称,fops默认的是file_operations结构*/
//如果主设备号为0,系统会自动分配
major=register_chrdev(0,"button_dev",&button_dev_fops);
button_dev_class= class_create(THIS_MODULE, "button_dev");
//创建设备节点
button_dev_class_dev=device_create(button_dev_class,//
button_dev_class_dev,//
MKDEV(major,0),//
NULL,//
"button_dev");//
//建立地址映射
//s1-s5
gpncon=(volatileunsigned long *)ioremap(0x7F008830,32);
gpndat=(volatileunsigned long *)ioremap(0x7F008834,32);
//s7-s8
gplcon=(volatileunsigned long *)ioremap(0x7F008814,32);
gpldat=(volatileunsigned long *)ioremap(0x7F008818,32);
return0;
}
static void __exit button_dev_exit(void){
/*major和name必须和注册时的值一致*/
unregister_chrdev(major,"button_dev");
//删除设备节点
device_destroy(major,button_dev_class_dev);
class_destroy(button_dev_class);
iounmap(gpncon);
iounmap(gpndat);
iounmap(gplcon);
iounmap(gpldat);
}
module_init(button_dev_init);
module_exit(button_dev_exit);
MODULE_AUTHOR("RETACN");
MODULE_DESCRIPTION("BUTTONdriver");
MODULE_LICENSE("GPL");
编写测试程序,示例代码如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
/*测试查询方式按键驱动*/
int main(int argc,char **argv){
intfd;
intval=1;
unsignedchar key_vals[8];
intcount=0;
fd=open("/dev/button_dev",O_RDWR);
if(fd<0){
printf("can not open!\n");
}
while(1){
read(fd,key_vals,sizeof(key_vals));
//如果值为0,说明有按键按下
if(!key_vals[0] || !key_vals[1] //
|| !key_vals[2] || !key_vals[3] //
|| !key_vals[4] || !key_vals[5] //
|| !key_vals[6] || !key_vals[7]){//
printf("%04dkey pressed :%d %d %d %d %d %d %d %d \n",//
count++,//
key_vals[0],//
key_vals[1],//
key_vals[2],//
key_vals[3],//
key_vals[4],//
key_vals[5],//
key_vals[6],//
key_vals[7]);//
}
}
return0;
}