mini2440 KEY按键设备驱动(中断模式和查询模式)源代码--(宋宝华框架)
2012-11-02 23:15
435 查看
/*****************************************************************
mini2440 KEY按键设备驱动(中断模式和查询模式)源代码
*****************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
//使用宋宝华推荐的普通字符设备框架
#include <linux/fcntl.h>
#include <linux/cdev.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
#include <linux/device.h>
#include <asm/io.h>
//#include <asm/arch/regs-gpio.h> //2.6.12
#include <mach/regs-gpio.h> // 2.6.32
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/workqueue.h>
#include <linux/semaphore.h>
#include <linux/wait.h>
#include <linux/timer.h>
#include <linux/version.h>
#include <mach/irqs.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <mach/regs-irq.h>
#include <mach/irqs.h>
#include <mach/io.h>
#include <asm/dma.h>
#define LEDOFF 0
#define LEDON 1
//#define DEMO_MAJOR 235 //静态分配
#define DEMO_MAJOR 0 //动态分配
#define DEMO_MINOR 0
int devmajor = DEMO_MAJOR;
int devminor = DEMO_MINOR;
dev_t dev = 0;
//#define KEYIRQ //中断模式
#define KEYPOLL //查询模式
//***************************************************//
//***************key查询模式*********************//
//***************************************************//
#ifdef KEYPOLL //查询模式
//key
static void __iomem *key_base;
#define rGPGCON (*(volatile unsigned long *)(key_base + 0x00))
#define rGPGDAT (*(volatile unsigned long *)(key_base + 0x04))
#define rGPGUP (*(volatile unsigned long *)(key_base + 0x08))
//new
volatile unsigned *rGPBCON_p;
volatile unsigned *rGPBDAT_p;
//设备结构
//设备结构
struct DEMO_dev
{
struct cdev cdev; /* Char device structure*/
};
struct DEMO_dev *DEMO_devices;
struct class *key_class;
int DEMO_open(struct inode *inode, struct file *filp)
{
struct DEMO_dev *demo_dev;
unsigned int temp;
filp->private_data=DEMO_devices;
/*配置GPGCON input: [00]*/
temp = rGPGCON;
temp &= ~((3<<22)|(3<<14)|(3<<12)|(3<<10)|(3<<6)|(3<<0));
rGPGCON = temp;
/*配置CPGUP, 每位置1*/
temp = rGPGUP;
temp |= ((1<<11)|(1<<7)|(1<<6)|(1<<5)|(1<<3)|(1<<0));
rGPGUP = temp;
return 0;
}
int DEMO_release(struct inode *inode, struct file *filp)
{
return 0;
}
int DEMO_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg)
{
return 0;
}
//也可以使用DEMO_write来替代DEMO_ioctl
ssize_t DEMO_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
return 0;
}
ssize_t DEMO_read(struct file *filp,char __user *buff,size_t size,loff_t *offp)
{
int count;
count = sizeof(int);
int temp,key1,key2;
temp =rGPGDAT;
if (copy_to_user(buff, &temp, count))
{
return -EFAULT;
}
return 0;
}
struct file_operations DEMO_fops = {
.owner = THIS_MODULE,
.ioctl = DEMO_ioctl,
.open = DEMO_open,
.write = DEMO_write,
.read = DEMO_read,
.release=DEMO_release,
};
/*******************************************************
MODULE ROUTINE
*******************************************************/
void DEMO_cleanup_module(void)
{
iounmap(key_base);
if (DEMO_devices)
{
cdev_del(&DEMO_devices->cdev);//5 从系统中移除一个字符设备
kfree(DEMO_devices);
}
device_destroy(key_class, MKDEV(devmajor, 0)); //delete device node under /dev
class_destroy(key_class); //delete class created by us
unregister_chrdev_region(dev,1);// 6 释放设备编号
}
int DEMO_init_module(void)
{
int result;
if(devmajor)
{
dev = MKDEV(devmajor, devminor); // 1 获得设备号
result = register_chrdev_region(dev, 1, "key_driver"); // 2 分配设备编号
}
else
{
result = alloc_chrdev_region(&dev, devminor, 1, "key_driver");
// //2 动态分配设备编号
devmajor = MAJOR(dev);
}
if (result < 0)
{
printk(KERN_WARNING "scull: can't get major %d\n", devmajor);
return result;
}
printk(KERN_WARNING "led get major: %d\n", devmajor);
DEMO_devices = kmalloc(sizeof(struct DEMO_dev), GFP_KERNEL);//分配内存给本设备结构体
if (!DEMO_devices)
{
result = -ENOMEM;
goto fail;
}
memset(DEMO_devices, 0, sizeof(struct DEMO_dev));
cdev_init(&DEMO_devices->cdev, &DEMO_fops);//(1) // 字符设备的注册,即将结构嵌入到自己的设备中
DEMO_devices->cdev.owner = THIS_MODULE;
DEMO_devices->cdev.ops = &DEMO_fops; //(2)
result = cdev_add (&DEMO_devices->cdev, dev, 1);// 4 把本设备放内核中
if(result)
{
printk(KERN_NOTICE "Error %d adding DEMO\n", result);
goto fail;
}
//创建节点方法2 使用函数自动创建 方法1是手动创建#mknod /dev/test c 235 0
// 下面方法2.6.32支持。2.6.18 2.6.12不支持
//ioremap
//rGPBCON_p=(volatile unsigned *)ioremap((volatile unsigned *)0x56000010,4);
//rGPBDAT_p=(volatile unsigned *)ioremap((volatile unsigned *)0x56000014,4);
key_base=(volatile unsigned*)ioremap((volatile unsigned *)0x56000060,12);
/* create your own class under /sysfs 2.6.32*/
key_class = class_create(THIS_MODULE, "key_class");
if(IS_ERR(key_class))
{
printk("Err: failed in creating class.\n");
return -1;
}
/* register your own device in sysfs, and this will cause udev to create corresponding device node */
device_create( key_class, NULL, MKDEV(devmajor, 0), NULL, "key_driver");
return 0;
fail:
DEMO_cleanup_module();
return result;
}
module_init(DEMO_init_module);
module_exit(DEMO_cleanup_module);
MODULE_AUTHOR("su");
MODULE_LICENSE("GPL");
//***************************************************//
//***************key中断模式*********************//
//***************************************************//
#elif defined KEYIRQ //KEY中断模式
//设备结构
struct KEY_dev
{
struct cdev cdev; /* Char device structure*/
struct semaphore sem;
wait_queue_head_t rq; /* 定义等待队列头*/
int key;
//底半部的工作队列方法
struct work_struct my_wq; //定义一个工作队列
};
struct KEY_dev *key_devices; //key_devices
static int key_flag=0;
#define key_dev_num 1
//static unsigned long polling_jffs=0;
struct class *key_class; //
/*定义6个按键对应的中断号,在mach头文件中去找*/
//irqs.h中
static int KeyIrqArray[6]=
{
IRQ_EINT8,
IRQ_EINT11,
IRQ_EINT13,
IRQ_EINT14,
IRQ_EINT15,
IRQ_EINT19
};
static irqreturn_t key1_interrupt(int irq, void *dev_id)
{
//* 有了操作系统后这一部分可以省略
volatile unsigned temp=0;
temp = __raw_readl(S3C2410_EINTPEND);
temp |=(1<<8);
__raw_writel(temp,S3C2410_EINTPEND);
temp = __raw_readl(S3C2410_SRCPND);
temp |=(1<<5);
__raw_writel(temp,S3C2410_SRCPND);
temp = __raw_readl(S3C2410_INTPND);
temp |=(1<<5);
__raw_writel(temp,S3C2410_INTPND);
//*/
//中断处理方式一:在中断函数中直接处理
//获取键盘值
key_devices->key=1; //key记录第几个按键按下
key_flag=1;
wake_up_interruptible(&(key_devices->rq));/*唤醒等待队列*/
printk("****key1\n");
return IRQ_HANDLED;
}
// 按键key2采用底半部tasklet的方法
void key2_do_tasklet(unsigned long code)
{
//中断处理方式一:在中断函数中直接处理
//获取键盘值
key_devices->key=2; //key记录第几个按键按下
key_flag=1;
wake_up_interruptible(&(key_devices->rq));/*唤醒等待队列*/
printk("tasklet ***------ key2\n");
}
DECLARE_TASKLET(key_tasklet,key2_do_tasklet,0); //
static irqreturn_t key2_interrupt(int irq,void *dev_id)
{
tasklet_schedule(&key_tasklet);
return IRQ_HANDLED;
}
// 按键key3采用底半部工作队列的方法
void key3_work_func(unsigned long code)
{
//获取键盘值
key_devices->key=3;
key_flag=1;
wake_up_interruptible(&(key_devices->rq));/*唤醒等待队列*/
printk("****key3\n");
}
static irqreturn_t key3_interrupt(int irq, void *dev_id)
{
schedule_work(&key_devices->my_wq);
return IRQ_HANDLED;
}
static irqreturn_t key4_interrupt(int irq, void *dev_id)
{
//中断处理方式一:在中断函数中直接处理
//获取键盘值
key_devices->key=4; //key记录第几个按键按下
key_flag=1;
wake_up_interruptible(&(key_devices->rq));/*唤醒等待队列*/
printk("****key4\n");
return IRQ_HANDLED;
}
static irqreturn_t key5_interrupt(int irq, void *dev_id)
{
//中断处理方式一:在中断函数中直接处理
//获取键盘值
key_devices->key=5; //key记录第几个按键按下
key_flag=1;
wake_up_interruptible(&(key_devices->rq));/*唤醒等待队列*/
printk("****key5\n");
return IRQ_HANDLED;
}
static irqreturn_t key6_interrupt(int irq, void *dev_id)
{
//中断处理方式一:在中断函数中直接处理
//获取键盘值
key_devices->key=6; //key记录第几个按键按下
key_flag=1;
wake_up_interruptible(&(key_devices->rq));/*唤醒等待队列*/
printk("****key6\n");
return IRQ_HANDLED;
}
int key_regist_init(void)
{
//有了操作系统后,下面这些初始化可以不用写,系统帮你做了
//*
volatile unsigned temp = 0;
temp = __raw_readl(S3C2410_GPGCON);
temp &=~( (3<<22)|(3<<14)|(3<<12)|(3<<10)|(3<<6)|3 );
temp |=( (2<<22)|(2<<14)|(2<<12)|(2<<10)|(2<<6)|2 );
__raw_writel(temp,S3C2410_GPGCON);
temp = __raw_readl(S3C2410_GPGUP);
temp &=~( (1<<11)|(1<<17)|(1<<6)|(1<<5)|(1<<3)|(1<<0) );
temp |=( (1<<0)|(1<<2) );
__raw_writel(temp,S3C2410_GPGUP);
//SRCPND
//0= The interrupt has not been requested.
// 1= the interrupt source has asserted the interrupt request.
// EINT8_23 [5] 0=NOt requested, 1= retuested;
temp = __raw_readl(S3C2410_SRCPND);
temp |=(0x1<<5);
__raw_writel(temp,S3C2410_SRCPND);
//INTMOD 0= IRQ MODE, 1= FIQ
// EINT8_23 [5] 0=IRQ, 1= FIQ;
temp = __raw_readl(S3C2410_INTMOD);
temp &=~(0x1<<5);
__raw_writel(temp,S3C2410_INTMOD);
//INTMSK
//Determine which interrupt source is masked. the maskedinterrupt source will not be service
// 0= interrupt service is available , 1= interrupt service is masked.
// EINT8_23 [5] 0=service available, 1= masked;
//both of set to '0'
temp = __raw_readl(S3C2410_INTMSK);
temp &=~(0x1<<5);
__raw_writel(temp,S3C2410_INTMSK);
//INTPND
//indicate the interrupt request status.
// 0 = the interrupt has not been requestd, 1= the interrupt source has asserted the interrupt
//EINT8_23 [5] 0= not request, 1 = requestd;
//both of sign bit set to "1"
temp = __raw_readl(S3C2410_INTPND);
temp |=(1<<5);
__raw_writel(temp,S3C2410_INTPND);
temp = __raw_readl(S3C2410_EXTINT1);
temp &=~((7<<28)|(7<<24)|(7<<20)|(7<<12)|7);
temp |=((2<<28)|(2<<24)|(2<<20)|(2<<12)|2);
__raw_writel(temp,S3C2410_EXTINT1);
temp = __raw_readl(S3C2410_EXTINT2);
temp &=~(0x7<<12);
temp |=(0x2<<12);
__raw_writel(temp,S3C2410_EXTINT2);
temp = __raw_readl(S3C2410_EINTMASK);
temp &=~((1<<19)|(1<<15)|(1<<14)|(1<<13)|(1<<11)|(1<<8));
__raw_writel(temp,S3C2410_EINTMASK);
temp = __raw_readl(S3C2410_EINTPEND);
temp |=((1<<19)|(1<<15)|(1<<14)|(1<<13)|(1<<11)|(1<<8));
__raw_writel(temp,S3C2410_EINTPEND);
//*/
return 0;
}
int KEY_open(struct inode *inode, struct file *filp)
{
struct KEY_dev *dev;
key_regist_init();/*初始化按键寄存器*/
printk("open ok!");
dev=container_of(inode->i_cdev,struct KEY_dev,cdev);
filp->private_data=dev;
return 0;
}
int KEY_release(struct inode *inode, struct file *filp)
{
return 0;
}
int KEY_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg)
{
return 0;
}
//也可以使用KEY_write来替代KEY_ioctl
ssize_t KEY_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
return 0;
}
ssize_t KEY_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
{
int ret=0;
struct KEY_dev *dev=filp->private_data;
memset(buff,0,count);
if(key_flag == 1) //有按键按下的情况
{
key_flag=0;
ret=1;
if (copy_to_user(buff, &dev->key, 4))
{
ret= -EFAULT;
}
}
else //没有按键按下的情况
{
if(filp->f_flags &O_NONBLOCK) //非阻塞
{
return -EAGAIN;
}
else //阻塞
{ //调用wait_event_interruptible休眠
if(wait_event_interruptible(dev->rq,key_flag!=0))//等待时间中断
{
return -ERESTARTSYS;
}
key_flag = 0;
ret=1;
if(copy_to_user(buff,&dev->key,4))
{
ret=-EFAULT;
}
}
}
return ret;
}
struct file_operations KEY_fops = {
.owner = THIS_MODULE,
.ioctl = KEY_ioctl,
.open = KEY_open,
.read = KEY_read,
.release=KEY_release,
};
/*******************************************************
MODULE ROUTINE
*******************************************************/
void KEY_cleanup_module(void)
{
dev_t dev;
dev = MKDEV(devmajor,devminor);
free_irq(KeyIrqArray[0],NULL);//清除按键中断
free_irq(KeyIrqArray[1],NULL);
free_irq(KeyIrqArray[2],NULL);
free_irq(KeyIrqArray[3],NULL);
free_irq(KeyIrqArray[4],NULL);
free_irq(KeyIrqArray[5],NULL);
if (key_devices)
{
cdev_del(&key_devices->cdev);//5 从系统中移除一个字符设备
kfree(key_devices);
}
device_destroy(key_class, MKDEV(devmajor, 0)); //delete device node under /dev
class_destroy(key_class); //delete class created by us
unregister_chrdev_region(dev,1);// 6 释放设备编号
}
int KEY_init_module(void)
{
int result;
dev_t dev = 0;
if(devmajor)
{
dev = MKDEV(devmajor, devminor); // 1 获得设备号
result = register_chrdev_region(dev, 1, "key_driver"); // 2 分配设备编号
}
else
{
result = alloc_chrdev_region(&dev, devminor, 1, "key_driver");
// //2 动态分配设备编号
devmajor = MAJOR(dev);
}
if (result < 0)
{
printk(KERN_WARNING "scull: can't get major %d\n", devmajor);
return result;
}
printk(KERN_WARNING "led get major: %d\n", devmajor);
key_devices = kmalloc(sizeof(struct KEY_dev), GFP_KERNEL);//分配内存给本设备结构体
if (!key_devices)
{
result = -ENOMEM;
goto fail;
}
memset(key_devices, 0, sizeof(struct KEY_dev));
init_MUTEX(&key_devices->sem);
cdev_init(&key_devices->cdev, &KEY_fops);//(1) // 字符设备的注册,即将结构嵌入到自己的设备中
key_devices->cdev.owner = THIS_MODULE;
key_devices->cdev.ops = &KEY_fops; //(2)
result = cdev_add (&key_devices->cdev, dev, 1);// 4 把本设备放内核中
if(result)
{
printk(KERN_NOTICE "Error %d adding KEY\n", result);
goto fail;
}
//创建节点方法2 使用函数自动创建 方法1是手动创建#mknod /dev/test c 235 0
// 下面方法2.6.32支持。2.6.18 2.6.12不支持
/* create your own class under /sysfs 2.6.32*/
//自动创建节点(2.6.32以上内核才支持)手动创建方法:mknod /dev/key_driver c 235 0
key_class = class_create(THIS_MODULE, "key_class");
if(IS_ERR(key_class))
{
printk("Err: failed in creating class.\n");
return -1;
}
/* register your own device in sysfs, and this will cause udev to create corresponding device node */
device_create( key_class, NULL, MKDEV(devmajor, 0), NULL, "key_driver");
/*1申请按键中断*/
printk(KERN_NOTICE "&key1_interrupt=%x key1_interrupt=%x\n",&key1_interrupt,key1_interrupt);
if(request_irq(KeyIrqArray[0],key1_interrupt,IRQ_TYPE_EDGE_FALLING,"simplekey",NULL))
{ //可设置为IRQ_TYPE_EDGE_RISING上长沿触发,IRQ_TYPE_EDGE_FALLING下降沿触发
//"simplekey"用于在/proc/interrupts中显示中断的拥有者
printk("request button irq failed!\n ");
return -1;
}
if(request_irq(KeyIrqArray[1],key2_interrupt,IRQ_TYPE_EDGE_FALLING,"simplekey",NULL))
{
printk("request button irq failed!\n ");
return -1;
}
if(request_irq(KeyIrqArray[2],key3_interrupt,IRQ_TYPE_EDGE_FALLING,"simplekey",NULL))
{
printk("request button irq failed!\n ");
return -1;
}
if(request_irq(KeyIrqArray[3],key4_interrupt,IRQ_TYPE_EDGE_FALLING,"simplekey",NULL))
{
printk("request button irq failed!\n ");
return -1;
}
if(request_irq(KeyIrqArray[4],key5_interrupt,IRQ_TYPE_EDGE_FALLING,"simplekey",NULL))
{
printk("request button irq failed!\n ");
return -1;
}
if(request_irq(KeyIrqArray[5],key6_interrupt,IRQ_TYPE_EDGE_FALLING,"simplekey",NULL))
{
printk("request button irq failed!\n ");
return -1;
}
init_waitqueue_head(&key_devices->rq);/*初始化等待消息队列*/
//初始化底半部工作队列方法
INIT_WORK(&key_devices->my_wq,(void (*) (void *) ) key3_work_func); //最后一个参数NULL不要写否则编译报错(PPT可能有误)
return 0;
fail:
KEY_cleanup_module();
return result;
}
module_init(KEY_init_module);
module_exit(KEY_cleanup_module);
MODULE_AUTHOR("hui");
MODULE_LICENSE("GPL");
#endif
/*****************************************************************
应用程序key_irq中断模式测试源代码:
*****************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEV_NAME "/dev/key_driver"
int main(void)
{
int fd;
int i;
int key;
int retval;
fd_set key_rfd;
fd=open(DEV_NAME,O_RDWR);
printf("fd=%d\n",fd);
if(fd<0)
{
perror("error open\n");
exit(-1);
}
printf("open /dev/key successfully\n");
while(1)
{
read(fd,&key,sizeof(int));
if(0==key)
continue;
printf("get key:sw%d\n",key);
}
return 0;
}
/*****************************************************************
应用程序key_poll查询模式测试源代码:
*****************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MYKEY "/dev/key_driver"
#define KEY1 1
#define KEY2 2
#define KEY3 3
#define KEY4 4
#define KEY5 5
#define KEY6 6
#define NOKEY 0
int fd;
void Delay_MS( unsigned int time) //50 ns
{
unsigned int i,j;
for ( i=0; i<time; i++)
{
for(j=0;j<30000;j++)
{
}
}
}
//函数:KeyScan
//功能:读取按下的按键,并返回按键的标记号
//参数:无
//返回值:int
int KeyScan(void)
{
volatile unsigned int temp,status;
int key=NOKEY; //记录press 的按键
/*注意:GPGDAT先取反,press后GPGDAT原来为0,取反后为1*/
/*再& ,取出到底是哪一位按下,按下的为1*/
read(fd,&status,4);
temp = (~status ) & ((1<<11)|(1<<7)|(1<<6)|(1<<5)|(1<<3)|(1<<0));
switch(temp)
{
case (1<<0): //KEY1
{
key = KEY1;
return key;
}
case (1<<3): //KEY2
{
key = KEY2;
return key;
}
case (1<<5): //KEY3
{
key = KEY3;
return key;
}
case (1<<6): //KEY4
{
key = KEY4;
return key;
}
case (1<<7): //KEY5
{
key = KEY5;
return key;
}
case (1<<11): //KEY6
{
key = KEY6;
return key;
}
default: //NOKEY
return NOKEY;
}
}
volatile unsigned int key_old=NOKEY;
volatile unsigned int key_new=NOKEY;
int Get_Keyvalue(void)
{
int key_1=NOKEY;
int key_2=NOKEY;
key_1=KeyScan();
Delay_MS(20);
key_2=KeyScan();
if(key_1 != key_2) //如果按下的key_1和key_2不相等,说明抖动
{
return NOKEY; //就当作没按下
}
else //如果按下的key_1和key_2相等,说明按住不放,重复
{
key_new=key_2;
if(key_new!=key_old) //按下的跟之前那次比较,如果新按的跟旧按下的不相等
{
key_old=key_new; //旧值更新
return key_old; //返回有按下
}
else if(key_new==key_old) //如果新按的跟旧按下的相等
{
return NOKEY; //就当作没按下
}
}
}
int main()
{
int i=0;
unsigned int cmd;
unsigned int status;
int key;
int g_led_num;
volatile unsigned int temp;
fd = open(MYKEY,O_RDWR);
if (fd < 0)
{
perror("open device key_driver----");
exit(1);
}
while(1)
{
key = Get_Keyvalue();
if(key==1)
{
printf("********1**********\n");
}
if(key==2)
{
printf("********2**********\n");
}
if(key==3)
{
printf("********3**********\n");
}
if(key==4)
{
printf("********4**********\n");
}
if(key==5)
{
printf("********5**********\n");
}
if(key==6)
{
printf("*********6**********\n");
}
}
close(fd)
}
mini2440 KEY按键设备驱动(中断模式和查询模式)源代码
*****************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
//使用宋宝华推荐的普通字符设备框架
#include <linux/fcntl.h>
#include <linux/cdev.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
#include <linux/device.h>
#include <asm/io.h>
//#include <asm/arch/regs-gpio.h> //2.6.12
#include <mach/regs-gpio.h> // 2.6.32
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/workqueue.h>
#include <linux/semaphore.h>
#include <linux/wait.h>
#include <linux/timer.h>
#include <linux/version.h>
#include <mach/irqs.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <mach/regs-irq.h>
#include <mach/irqs.h>
#include <mach/io.h>
#include <asm/dma.h>
#define LEDOFF 0
#define LEDON 1
//#define DEMO_MAJOR 235 //静态分配
#define DEMO_MAJOR 0 //动态分配
#define DEMO_MINOR 0
int devmajor = DEMO_MAJOR;
int devminor = DEMO_MINOR;
dev_t dev = 0;
//#define KEYIRQ //中断模式
#define KEYPOLL //查询模式
//***************************************************//
//***************key查询模式*********************//
//***************************************************//
#ifdef KEYPOLL //查询模式
//key
static void __iomem *key_base;
#define rGPGCON (*(volatile unsigned long *)(key_base + 0x00))
#define rGPGDAT (*(volatile unsigned long *)(key_base + 0x04))
#define rGPGUP (*(volatile unsigned long *)(key_base + 0x08))
//new
volatile unsigned *rGPBCON_p;
volatile unsigned *rGPBDAT_p;
//设备结构
//设备结构
struct DEMO_dev
{
struct cdev cdev; /* Char device structure*/
};
struct DEMO_dev *DEMO_devices;
struct class *key_class;
int DEMO_open(struct inode *inode, struct file *filp)
{
struct DEMO_dev *demo_dev;
unsigned int temp;
filp->private_data=DEMO_devices;
/*配置GPGCON input: [00]*/
temp = rGPGCON;
temp &= ~((3<<22)|(3<<14)|(3<<12)|(3<<10)|(3<<6)|(3<<0));
rGPGCON = temp;
/*配置CPGUP, 每位置1*/
temp = rGPGUP;
temp |= ((1<<11)|(1<<7)|(1<<6)|(1<<5)|(1<<3)|(1<<0));
rGPGUP = temp;
return 0;
}
int DEMO_release(struct inode *inode, struct file *filp)
{
return 0;
}
int DEMO_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg)
{
return 0;
}
//也可以使用DEMO_write来替代DEMO_ioctl
ssize_t DEMO_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
return 0;
}
ssize_t DEMO_read(struct file *filp,char __user *buff,size_t size,loff_t *offp)
{
int count;
count = sizeof(int);
int temp,key1,key2;
temp =rGPGDAT;
if (copy_to_user(buff, &temp, count))
{
return -EFAULT;
}
return 0;
}
struct file_operations DEMO_fops = {
.owner = THIS_MODULE,
.ioctl = DEMO_ioctl,
.open = DEMO_open,
.write = DEMO_write,
.read = DEMO_read,
.release=DEMO_release,
};
/*******************************************************
MODULE ROUTINE
*******************************************************/
void DEMO_cleanup_module(void)
{
iounmap(key_base);
if (DEMO_devices)
{
cdev_del(&DEMO_devices->cdev);//5 从系统中移除一个字符设备
kfree(DEMO_devices);
}
device_destroy(key_class, MKDEV(devmajor, 0)); //delete device node under /dev
class_destroy(key_class); //delete class created by us
unregister_chrdev_region(dev,1);// 6 释放设备编号
}
int DEMO_init_module(void)
{
int result;
if(devmajor)
{
dev = MKDEV(devmajor, devminor); // 1 获得设备号
result = register_chrdev_region(dev, 1, "key_driver"); // 2 分配设备编号
}
else
{
result = alloc_chrdev_region(&dev, devminor, 1, "key_driver");
// //2 动态分配设备编号
devmajor = MAJOR(dev);
}
if (result < 0)
{
printk(KERN_WARNING "scull: can't get major %d\n", devmajor);
return result;
}
printk(KERN_WARNING "led get major: %d\n", devmajor);
DEMO_devices = kmalloc(sizeof(struct DEMO_dev), GFP_KERNEL);//分配内存给本设备结构体
if (!DEMO_devices)
{
result = -ENOMEM;
goto fail;
}
memset(DEMO_devices, 0, sizeof(struct DEMO_dev));
cdev_init(&DEMO_devices->cdev, &DEMO_fops);//(1) // 字符设备的注册,即将结构嵌入到自己的设备中
DEMO_devices->cdev.owner = THIS_MODULE;
DEMO_devices->cdev.ops = &DEMO_fops; //(2)
result = cdev_add (&DEMO_devices->cdev, dev, 1);// 4 把本设备放内核中
if(result)
{
printk(KERN_NOTICE "Error %d adding DEMO\n", result);
goto fail;
}
//创建节点方法2 使用函数自动创建 方法1是手动创建#mknod /dev/test c 235 0
// 下面方法2.6.32支持。2.6.18 2.6.12不支持
//ioremap
//rGPBCON_p=(volatile unsigned *)ioremap((volatile unsigned *)0x56000010,4);
//rGPBDAT_p=(volatile unsigned *)ioremap((volatile unsigned *)0x56000014,4);
key_base=(volatile unsigned*)ioremap((volatile unsigned *)0x56000060,12);
/* create your own class under /sysfs 2.6.32*/
key_class = class_create(THIS_MODULE, "key_class");
if(IS_ERR(key_class))
{
printk("Err: failed in creating class.\n");
return -1;
}
/* register your own device in sysfs, and this will cause udev to create corresponding device node */
device_create( key_class, NULL, MKDEV(devmajor, 0), NULL, "key_driver");
return 0;
fail:
DEMO_cleanup_module();
return result;
}
module_init(DEMO_init_module);
module_exit(DEMO_cleanup_module);
MODULE_AUTHOR("su");
MODULE_LICENSE("GPL");
//***************************************************//
//***************key中断模式*********************//
//***************************************************//
#elif defined KEYIRQ //KEY中断模式
//设备结构
struct KEY_dev
{
struct cdev cdev; /* Char device structure*/
struct semaphore sem;
wait_queue_head_t rq; /* 定义等待队列头*/
int key;
//底半部的工作队列方法
struct work_struct my_wq; //定义一个工作队列
};
struct KEY_dev *key_devices; //key_devices
static int key_flag=0;
#define key_dev_num 1
//static unsigned long polling_jffs=0;
struct class *key_class; //
/*定义6个按键对应的中断号,在mach头文件中去找*/
//irqs.h中
static int KeyIrqArray[6]=
{
IRQ_EINT8,
IRQ_EINT11,
IRQ_EINT13,
IRQ_EINT14,
IRQ_EINT15,
IRQ_EINT19
};
static irqreturn_t key1_interrupt(int irq, void *dev_id)
{
//* 有了操作系统后这一部分可以省略
volatile unsigned temp=0;
temp = __raw_readl(S3C2410_EINTPEND);
temp |=(1<<8);
__raw_writel(temp,S3C2410_EINTPEND);
temp = __raw_readl(S3C2410_SRCPND);
temp |=(1<<5);
__raw_writel(temp,S3C2410_SRCPND);
temp = __raw_readl(S3C2410_INTPND);
temp |=(1<<5);
__raw_writel(temp,S3C2410_INTPND);
//*/
//中断处理方式一:在中断函数中直接处理
//获取键盘值
key_devices->key=1; //key记录第几个按键按下
key_flag=1;
wake_up_interruptible(&(key_devices->rq));/*唤醒等待队列*/
printk("****key1\n");
return IRQ_HANDLED;
}
// 按键key2采用底半部tasklet的方法
void key2_do_tasklet(unsigned long code)
{
//中断处理方式一:在中断函数中直接处理
//获取键盘值
key_devices->key=2; //key记录第几个按键按下
key_flag=1;
wake_up_interruptible(&(key_devices->rq));/*唤醒等待队列*/
printk("tasklet ***------ key2\n");
}
DECLARE_TASKLET(key_tasklet,key2_do_tasklet,0); //
static irqreturn_t key2_interrupt(int irq,void *dev_id)
{
tasklet_schedule(&key_tasklet);
return IRQ_HANDLED;
}
// 按键key3采用底半部工作队列的方法
void key3_work_func(unsigned long code)
{
//获取键盘值
key_devices->key=3;
key_flag=1;
wake_up_interruptible(&(key_devices->rq));/*唤醒等待队列*/
printk("****key3\n");
}
static irqreturn_t key3_interrupt(int irq, void *dev_id)
{
schedule_work(&key_devices->my_wq);
return IRQ_HANDLED;
}
static irqreturn_t key4_interrupt(int irq, void *dev_id)
{
//中断处理方式一:在中断函数中直接处理
//获取键盘值
key_devices->key=4; //key记录第几个按键按下
key_flag=1;
wake_up_interruptible(&(key_devices->rq));/*唤醒等待队列*/
printk("****key4\n");
return IRQ_HANDLED;
}
static irqreturn_t key5_interrupt(int irq, void *dev_id)
{
//中断处理方式一:在中断函数中直接处理
//获取键盘值
key_devices->key=5; //key记录第几个按键按下
key_flag=1;
wake_up_interruptible(&(key_devices->rq));/*唤醒等待队列*/
printk("****key5\n");
return IRQ_HANDLED;
}
static irqreturn_t key6_interrupt(int irq, void *dev_id)
{
//中断处理方式一:在中断函数中直接处理
//获取键盘值
key_devices->key=6; //key记录第几个按键按下
key_flag=1;
wake_up_interruptible(&(key_devices->rq));/*唤醒等待队列*/
printk("****key6\n");
return IRQ_HANDLED;
}
int key_regist_init(void)
{
//有了操作系统后,下面这些初始化可以不用写,系统帮你做了
//*
volatile unsigned temp = 0;
temp = __raw_readl(S3C2410_GPGCON);
temp &=~( (3<<22)|(3<<14)|(3<<12)|(3<<10)|(3<<6)|3 );
temp |=( (2<<22)|(2<<14)|(2<<12)|(2<<10)|(2<<6)|2 );
__raw_writel(temp,S3C2410_GPGCON);
temp = __raw_readl(S3C2410_GPGUP);
temp &=~( (1<<11)|(1<<17)|(1<<6)|(1<<5)|(1<<3)|(1<<0) );
temp |=( (1<<0)|(1<<2) );
__raw_writel(temp,S3C2410_GPGUP);
//SRCPND
//0= The interrupt has not been requested.
// 1= the interrupt source has asserted the interrupt request.
// EINT8_23 [5] 0=NOt requested, 1= retuested;
temp = __raw_readl(S3C2410_SRCPND);
temp |=(0x1<<5);
__raw_writel(temp,S3C2410_SRCPND);
//INTMOD 0= IRQ MODE, 1= FIQ
// EINT8_23 [5] 0=IRQ, 1= FIQ;
temp = __raw_readl(S3C2410_INTMOD);
temp &=~(0x1<<5);
__raw_writel(temp,S3C2410_INTMOD);
//INTMSK
//Determine which interrupt source is masked. the maskedinterrupt source will not be service
// 0= interrupt service is available , 1= interrupt service is masked.
// EINT8_23 [5] 0=service available, 1= masked;
//both of set to '0'
temp = __raw_readl(S3C2410_INTMSK);
temp &=~(0x1<<5);
__raw_writel(temp,S3C2410_INTMSK);
//INTPND
//indicate the interrupt request status.
// 0 = the interrupt has not been requestd, 1= the interrupt source has asserted the interrupt
//EINT8_23 [5] 0= not request, 1 = requestd;
//both of sign bit set to "1"
temp = __raw_readl(S3C2410_INTPND);
temp |=(1<<5);
__raw_writel(temp,S3C2410_INTPND);
temp = __raw_readl(S3C2410_EXTINT1);
temp &=~((7<<28)|(7<<24)|(7<<20)|(7<<12)|7);
temp |=((2<<28)|(2<<24)|(2<<20)|(2<<12)|2);
__raw_writel(temp,S3C2410_EXTINT1);
temp = __raw_readl(S3C2410_EXTINT2);
temp &=~(0x7<<12);
temp |=(0x2<<12);
__raw_writel(temp,S3C2410_EXTINT2);
temp = __raw_readl(S3C2410_EINTMASK);
temp &=~((1<<19)|(1<<15)|(1<<14)|(1<<13)|(1<<11)|(1<<8));
__raw_writel(temp,S3C2410_EINTMASK);
temp = __raw_readl(S3C2410_EINTPEND);
temp |=((1<<19)|(1<<15)|(1<<14)|(1<<13)|(1<<11)|(1<<8));
__raw_writel(temp,S3C2410_EINTPEND);
//*/
return 0;
}
int KEY_open(struct inode *inode, struct file *filp)
{
struct KEY_dev *dev;
key_regist_init();/*初始化按键寄存器*/
printk("open ok!");
dev=container_of(inode->i_cdev,struct KEY_dev,cdev);
filp->private_data=dev;
return 0;
}
int KEY_release(struct inode *inode, struct file *filp)
{
return 0;
}
int KEY_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg)
{
return 0;
}
//也可以使用KEY_write来替代KEY_ioctl
ssize_t KEY_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
return 0;
}
ssize_t KEY_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
{
int ret=0;
struct KEY_dev *dev=filp->private_data;
memset(buff,0,count);
if(key_flag == 1) //有按键按下的情况
{
key_flag=0;
ret=1;
if (copy_to_user(buff, &dev->key, 4))
{
ret= -EFAULT;
}
}
else //没有按键按下的情况
{
if(filp->f_flags &O_NONBLOCK) //非阻塞
{
return -EAGAIN;
}
else //阻塞
{ //调用wait_event_interruptible休眠
if(wait_event_interruptible(dev->rq,key_flag!=0))//等待时间中断
{
return -ERESTARTSYS;
}
key_flag = 0;
ret=1;
if(copy_to_user(buff,&dev->key,4))
{
ret=-EFAULT;
}
}
}
return ret;
}
struct file_operations KEY_fops = {
.owner = THIS_MODULE,
.ioctl = KEY_ioctl,
.open = KEY_open,
.read = KEY_read,
.release=KEY_release,
};
/*******************************************************
MODULE ROUTINE
*******************************************************/
void KEY_cleanup_module(void)
{
dev_t dev;
dev = MKDEV(devmajor,devminor);
free_irq(KeyIrqArray[0],NULL);//清除按键中断
free_irq(KeyIrqArray[1],NULL);
free_irq(KeyIrqArray[2],NULL);
free_irq(KeyIrqArray[3],NULL);
free_irq(KeyIrqArray[4],NULL);
free_irq(KeyIrqArray[5],NULL);
if (key_devices)
{
cdev_del(&key_devices->cdev);//5 从系统中移除一个字符设备
kfree(key_devices);
}
device_destroy(key_class, MKDEV(devmajor, 0)); //delete device node under /dev
class_destroy(key_class); //delete class created by us
unregister_chrdev_region(dev,1);// 6 释放设备编号
}
int KEY_init_module(void)
{
int result;
dev_t dev = 0;
if(devmajor)
{
dev = MKDEV(devmajor, devminor); // 1 获得设备号
result = register_chrdev_region(dev, 1, "key_driver"); // 2 分配设备编号
}
else
{
result = alloc_chrdev_region(&dev, devminor, 1, "key_driver");
// //2 动态分配设备编号
devmajor = MAJOR(dev);
}
if (result < 0)
{
printk(KERN_WARNING "scull: can't get major %d\n", devmajor);
return result;
}
printk(KERN_WARNING "led get major: %d\n", devmajor);
key_devices = kmalloc(sizeof(struct KEY_dev), GFP_KERNEL);//分配内存给本设备结构体
if (!key_devices)
{
result = -ENOMEM;
goto fail;
}
memset(key_devices, 0, sizeof(struct KEY_dev));
init_MUTEX(&key_devices->sem);
cdev_init(&key_devices->cdev, &KEY_fops);//(1) // 字符设备的注册,即将结构嵌入到自己的设备中
key_devices->cdev.owner = THIS_MODULE;
key_devices->cdev.ops = &KEY_fops; //(2)
result = cdev_add (&key_devices->cdev, dev, 1);// 4 把本设备放内核中
if(result)
{
printk(KERN_NOTICE "Error %d adding KEY\n", result);
goto fail;
}
//创建节点方法2 使用函数自动创建 方法1是手动创建#mknod /dev/test c 235 0
// 下面方法2.6.32支持。2.6.18 2.6.12不支持
/* create your own class under /sysfs 2.6.32*/
//自动创建节点(2.6.32以上内核才支持)手动创建方法:mknod /dev/key_driver c 235 0
key_class = class_create(THIS_MODULE, "key_class");
if(IS_ERR(key_class))
{
printk("Err: failed in creating class.\n");
return -1;
}
/* register your own device in sysfs, and this will cause udev to create corresponding device node */
device_create( key_class, NULL, MKDEV(devmajor, 0), NULL, "key_driver");
/*1申请按键中断*/
printk(KERN_NOTICE "&key1_interrupt=%x key1_interrupt=%x\n",&key1_interrupt,key1_interrupt);
if(request_irq(KeyIrqArray[0],key1_interrupt,IRQ_TYPE_EDGE_FALLING,"simplekey",NULL))
{ //可设置为IRQ_TYPE_EDGE_RISING上长沿触发,IRQ_TYPE_EDGE_FALLING下降沿触发
//"simplekey"用于在/proc/interrupts中显示中断的拥有者
printk("request button irq failed!\n ");
return -1;
}
if(request_irq(KeyIrqArray[1],key2_interrupt,IRQ_TYPE_EDGE_FALLING,"simplekey",NULL))
{
printk("request button irq failed!\n ");
return -1;
}
if(request_irq(KeyIrqArray[2],key3_interrupt,IRQ_TYPE_EDGE_FALLING,"simplekey",NULL))
{
printk("request button irq failed!\n ");
return -1;
}
if(request_irq(KeyIrqArray[3],key4_interrupt,IRQ_TYPE_EDGE_FALLING,"simplekey",NULL))
{
printk("request button irq failed!\n ");
return -1;
}
if(request_irq(KeyIrqArray[4],key5_interrupt,IRQ_TYPE_EDGE_FALLING,"simplekey",NULL))
{
printk("request button irq failed!\n ");
return -1;
}
if(request_irq(KeyIrqArray[5],key6_interrupt,IRQ_TYPE_EDGE_FALLING,"simplekey",NULL))
{
printk("request button irq failed!\n ");
return -1;
}
init_waitqueue_head(&key_devices->rq);/*初始化等待消息队列*/
//初始化底半部工作队列方法
INIT_WORK(&key_devices->my_wq,(void (*) (void *) ) key3_work_func); //最后一个参数NULL不要写否则编译报错(PPT可能有误)
return 0;
fail:
KEY_cleanup_module();
return result;
}
module_init(KEY_init_module);
module_exit(KEY_cleanup_module);
MODULE_AUTHOR("hui");
MODULE_LICENSE("GPL");
#endif
/*****************************************************************
应用程序key_irq中断模式测试源代码:
*****************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEV_NAME "/dev/key_driver"
int main(void)
{
int fd;
int i;
int key;
int retval;
fd_set key_rfd;
fd=open(DEV_NAME,O_RDWR);
printf("fd=%d\n",fd);
if(fd<0)
{
perror("error open\n");
exit(-1);
}
printf("open /dev/key successfully\n");
while(1)
{
read(fd,&key,sizeof(int));
if(0==key)
continue;
printf("get key:sw%d\n",key);
}
return 0;
}
/*****************************************************************
应用程序key_poll查询模式测试源代码:
*****************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MYKEY "/dev/key_driver"
#define KEY1 1
#define KEY2 2
#define KEY3 3
#define KEY4 4
#define KEY5 5
#define KEY6 6
#define NOKEY 0
int fd;
void Delay_MS( unsigned int time) //50 ns
{
unsigned int i,j;
for ( i=0; i<time; i++)
{
for(j=0;j<30000;j++)
{
}
}
}
//函数:KeyScan
//功能:读取按下的按键,并返回按键的标记号
//参数:无
//返回值:int
int KeyScan(void)
{
volatile unsigned int temp,status;
int key=NOKEY; //记录press 的按键
/*注意:GPGDAT先取反,press后GPGDAT原来为0,取反后为1*/
/*再& ,取出到底是哪一位按下,按下的为1*/
read(fd,&status,4);
temp = (~status ) & ((1<<11)|(1<<7)|(1<<6)|(1<<5)|(1<<3)|(1<<0));
switch(temp)
{
case (1<<0): //KEY1
{
key = KEY1;
return key;
}
case (1<<3): //KEY2
{
key = KEY2;
return key;
}
case (1<<5): //KEY3
{
key = KEY3;
return key;
}
case (1<<6): //KEY4
{
key = KEY4;
return key;
}
case (1<<7): //KEY5
{
key = KEY5;
return key;
}
case (1<<11): //KEY6
{
key = KEY6;
return key;
}
default: //NOKEY
return NOKEY;
}
}
volatile unsigned int key_old=NOKEY;
volatile unsigned int key_new=NOKEY;
int Get_Keyvalue(void)
{
int key_1=NOKEY;
int key_2=NOKEY;
key_1=KeyScan();
Delay_MS(20);
key_2=KeyScan();
if(key_1 != key_2) //如果按下的key_1和key_2不相等,说明抖动
{
return NOKEY; //就当作没按下
}
else //如果按下的key_1和key_2相等,说明按住不放,重复
{
key_new=key_2;
if(key_new!=key_old) //按下的跟之前那次比较,如果新按的跟旧按下的不相等
{
key_old=key_new; //旧值更新
return key_old; //返回有按下
}
else if(key_new==key_old) //如果新按的跟旧按下的相等
{
return NOKEY; //就当作没按下
}
}
}
int main()
{
int i=0;
unsigned int cmd;
unsigned int status;
int key;
int g_led_num;
volatile unsigned int temp;
fd = open(MYKEY,O_RDWR);
if (fd < 0)
{
perror("open device key_driver----");
exit(1);
}
while(1)
{
key = Get_Keyvalue();
if(key==1)
{
printf("********1**********\n");
}
if(key==2)
{
printf("********2**********\n");
}
if(key==3)
{
printf("********3**********\n");
}
if(key==4)
{
printf("********4**********\n");
}
if(key==5)
{
printf("********5**********\n");
}
if(key==6)
{
printf("*********6**********\n");
}
}
close(fd)
}
相关文章推荐
- mini2440 linux块设备驱动开发源代码(宋宝华框架)
- mini2440 ADC可调电阻设备驱动开发源代码(宋宝华设备驱动框架)
- mini2440 LED设备驱动开发源代码(宋宝华框架)
- mini2440 pwm蜂鸣器设备驱动开发源代码(宋宝华框架)
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-查询+中断+引入poll机制的按键驱动程序
- mini2440 ADC可调电阻驱动程序开发源代码(杂项设备驱动框架)
- 字符设备驱动程序之中断方式的按键驱动
- 【引用】Linux-2.6.32.2内核在mini2440上的移植(十六)---基于中断的按键驱动移植
- 字符设备驱动学习笔记----查询方式取得按键值
- 基于platform总线的中断(按键)字符设备驱动设计
- Linux-2.6.32.2内核在mini2440上的移植(十六)---基于中断的按键驱动移植
- 按键中断的platform bus设备和驱动 收藏
- 按键中断的platform bus设备和驱动
- arm 驱动基础:字符设备之异步通信:按键中断,通知应用程序
- 字符设备驱动-----按键驱动(中断+poll机制)
- ZigBee TI ZStack CC2530 3.15 按键驱动02-中断模式
- 字符设备驱动笔记——查询方式按键驱动(三)
- 字符设备驱动笔记——中断方式按键驱动之代码(六)
- 按键中断的platform bus设备和驱动
- 基于platform总线的中断(按键)字符设备驱动设计