OK6410的单个按键驱动程序(Linux),测试通过

来源:互联网 发布:tas软件下载 编辑:程序博客网 时间:2024/06/03 08:37
#include<linux/kernel.h>   #include<linux/fs.h>#include<linux/init.h>#include<linux/delay.h>#include <linux/wait.h>#include <linux/sched.h>//#include<linux/poll.h>#include<linux/irq.h>#include<asm/irq.h>#include<linux/interrupt.h>#include<asm/uaccess.h>#include<asm/io.h>#include <linux/ioport.h>#include<asm/signal.h>#include<mach/regs-gpio.h>#include<mach/hardware.h>#include<linux/platform_device.h>#include<linux/cdev.h>#include<linux/timer.h>#include<linux/delay.h>#include<linux/types.h>#include<linux/module.h>#include <linux/gpio.h>#include <plat/gpio-cfg.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/miscdevice.h>#define DEVICE_NAME "buttons"//设备名#define KEY_UP 1//抬起标志#define KEY_DOWN 0//按下标志#define KEY_MID 2  //不确定标?#define KEY_DELAY_1 (HZ/40)//按键按下过滤延时20msstatic volatile int key_status;//状态标志数组(0,1,2三态)static volatile char key_values;//最终输出状态结果('0','1'两态,确保read时不会读到KEY_MIDD状态)static struct timer_list key_timers; //6按键去抖动定时器/*因为本驱动是基于中断方式的,在此创建一个等待队列,以配合中断函数使用;当有按键按下并读>取到键值时,将会唤醒此队列,并设置中断标志,以便能通过 read 函数判断和读取键值传递到用户>态;当没有按键按下时,系统并不*//*会轮询按键状态,以节省时钟资源*/static DECLARE_WAIT_QUEUE_HEAD(button_key_waitq);/*中断标识变量,配合上面的队列使用,中断服务程序会把它设置为1,read 函数会把它清零*/static volatile int ev_press = 0;/*   设备 */struct key_irq_desc{      //dev_idint irq;int number;char *name;};/*   设备结构体 */static struct key_irq_desc key_irq[]={{IRQ_EINT(1),0,"KEY1"},};/*   标识按下按键的编号 */static volatile int key_press=0;//标识按下的按键的编号/*中断处理例程*/static irqreturn_t key_interrupt(int irq,void *dev_id){if(key_status==KEY_UP || key_status==KEY_DOWN){key_status=KEY_MID;key_timers.expires=jiffies+KEY_DELAY_1;add_timer(&key_timers);}return IRQ_RETVAL(IRQ_HANDLED);}/*function 函数定义*/static void timer_call(unsigned long number){if(gpio_get_value(S3C64XX_GPN(1))==0){key_status=KEY_DOWN;key_values=0;}else{key_status=KEY_UP;key_values=1;}ev_press=1;wake_up_interruptible(&button_key_waitq);}/*   对应open函数 */static int s3c64xx_buttons_open(struct inode *inode,struct file *file){int err=0;key_values=1;key_status=KEY_UP;/*注册中断函数*/err=request_irq(key_irq[0].irq,key_interrupt,IRQ_TYPE_EDGE_BOTH,key_irq[0].name,(void *)&key_irq[0]);if (err)    {        /*如果出错,返回*/printk(KERN_ALERT "KEY REQUEST failed (%d)\n",err);        return -EBUSY;    }setup_timer(&key_timers,timer_call,0);    /*注册成功,则中断队列标记为1,表示可以通过read 读取*/    ev_press = 0;    /*正常返回*/    return 0;}   /*   对应read函数   无论count参数是多少,都输出完整key_buff数组 */static int s3c64xx_buttons_read(struct file *filp,char __user *buff,size_t count,loff_t *offp){unsigned long err;if (!(filp->f_flags & O_NONBLOCK)){if (!ev_press){/*当中断标识为0 时,并且该设备是以阻塞方式打开时,进入休眠状态,等待被唤醒*/wait_event_interruptible(button_key_waitq, ev_press);}}/*把中断标识清零*/ev_press = 0;/*一组键值被传递到用户空间*/err = copy_to_user(buff, (const void *)&key_values, min(sizeof(key_values), count));return err ? -EFAULT : min(sizeof(key_values), count);}/*   对应release函数 */static int s3c64xx_buttons_close(struct inode *inode,struct file *filp){if (key_irq[0].irq > 0)free_irq(key_irq[0].irq,(void *)&key_irq[0]);del_timer(&key_timers);return 0;}/*设备操作集*/static struct file_operations dev_fops = {    .owner = THIS_MODULE,    .open = s3c64xx_buttons_open,    .release = s3c64xx_buttons_close,    .read = s3c64xx_buttons_read,};static struct miscdevice misc = {.minor = MISC_DYNAMIC_MINOR,.name = DEVICE_NAME,.fops = &dev_fops,};/*设备初始化,主要是注册设备*/static int __init dev_init(void){    int ret;//set gpn0 to input s3c_gpio_cfgpin(S3C64XX_GPN(0), S3C_GPIO_SFN(0));//上拉有效s3c_gpio_setpull(S3C64XX_GPN(0), S3C_GPIO_PULL_UP);    /*把按键设备注册为misc 设备,其设备号是自动分配的*/    ret = misc_register(&misc);    printk (DEVICE_NAME"\tinitialized\n");    return ret;}/*注销设备*/static void __exit dev_exit(void){    misc_deregister(&misc);}module_init(dev_init);module_exit(dev_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("easylwl_wondfo");


0 0
原创粉丝点击