您的位置:首页 > 编程语言

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)

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: