驱动程序:

 #include "s3c_driver.h"

 #define DRV_DESC                  "S3C24XX button driver"

 /* Driver version*/
#define DRV_MAJOR_VER 1
#define DRV_MINOR_VER 0
#define DRV_REVER_VER 0 #define DEV_NAME DEV_BUTTON_NAME //#define DEV_MAJOR DEV_BUTTON_MAJOR
#ifndef DEV_MAJOR
#define DEV_MAJOR 0 /* dynamic major by default */
#endif #define BUTTON_UP 0 /* Button status is up */
#define BUTTON_DOWN 1 /* Button status is pushed down */
#define BUTTON_UNCERTAIN 2 /* Button status uncerntain */ #define TIMER_DELAY_DOWN (HZ/50) /*Remove button push down dithering timer delay 20ms */
#define TIMER_DELAY_UP (HZ/10) /*Remove button up dithering timer delay 100ms */ static int debug = DISABLE;
static int dev_major = DEV_MAJOR;
static int dev_minor = ; /*============================ Platform Device part ===============================*/
/* Button hardware informtation structure*/
struct s3c_button_info //定义按键结构体信息
{
unsigned char num; /*Button nubmer */ //第几个按键
char * name; /*Button nubmer */ //按键名称
int nIRQ; /*Button IRQ number*/ //按键中断号
unsigned int setting; /*Button IRQ Pin Setting*/ //对应管脚设置为中断模式
unsigned int gpio; /*Button GPIO port */ //按键对应管脚
}; /* The button plaotform device private data structure */
struct s3c_button_platform_data //定义一个platform总线的按键结构体
{
struct s3c_button_info *buttons;
int nbuttons;
}; /* Button hardware informtation data*/
static struct s3c_button_info s3c_buttons[] = { //定义每个按键的结构体信息
[] = {
.num = ,
.name = "KEY1",
.nIRQ = IRQ_EINT0,
.gpio = S3C2410_GPF(),
.setting = S3C2410_GPF0_EINT0,
},
[] = {
.num = ,
.name = "KEY2",
.nIRQ = IRQ_EINT2,
.gpio = S3C2410_GPF(),
.setting = S3C2410_GPF2_EINT2,
},
[] = {
.num = ,
.name = "KEY3",
.nIRQ = IRQ_EINT3,
.gpio = S3C2410_GPF(),
.setting = S3C2410_GPF3_EINT3,
},
[] = {
.num = ,
.name = "KEY4",
.nIRQ = IRQ_EINT4,
.gpio = S3C2410_GPF(),
.setting = S3C2410_GPF4_EINT4,
},
}; /* The button platform device private data */
static struct s3c_button_platform_data s3c_button_data = { //定义button的结构体信息
.buttons = s3c_buttons, //每个button的信息
.nbuttons = ARRAY_SIZE(s3c_buttons), //button的数量
}; struct button_device //定义一个button_device的结构体
{
unsigned char *status; /* The buttons Push down or up status */
struct s3c_button_platform_data *data; /* The buttons hardware information data */ struct timer_list *timers; /* The buttons remove dithering timers */
wait_queue_head_t waitq; /* Wait queue for poll() */
volatile int ev_press; /* Button pressed event */ struct cdev cdev;
struct class *dev_class;
} button_device; static void platform_button_release(struct device * dev)
{
return;
} static struct platform_device s3c_button_device = { //设备节点结构体
.name = "s3c_button",
.id = ,
.dev =
{
.platform_data = &s3c_button_data,
.release = platform_button_release,
},
}; static irqreturn_t s3c_button_intterupt(int irq,void *de_id) //中断处理程序
{
int i;
int found = ;
struct s3c_button_platform_data *pdata = button_device.data; for(i=; i<pdata->nbuttons; i++)
{
if(irq == pdata->buttons[i].nIRQ) //发现某个按键有下降沿
{
found = ;
break;
}
} if(!found) /* An ERROR interrupt */ //内核报中断没有中断,返回错误,基本不会发生
return IRQ_NONE; /* Only when button is up then we will handle this event */
if(BUTTON_UP == button_device.status[i])
{
button_device.status[i] = BUTTON_UNCERTAIN;
mod_timer(&(button_device.timers[i]), jiffies+TIMER_DELAY_DOWN);
} return IRQ_HANDLED;
} static void button_timer_handler(unsigned long data)
{
struct s3c_button_platform_data *pdata = button_device.data;
int num =(int)data;
int status = s3c2410_gpio_getpin( pdata->buttons[num].gpio ); if(LOWLEVEL == status)
{
if(BUTTON_UNCERTAIN == button_device.status[num]) /* Come from interrupt */
{
//dbg_print("Key pressed!\n");
button_device.status[num] = BUTTON_DOWN; printk("%s pressed.\n", pdata->buttons[num].name); /* Wake up the wait queue for read()/poll() */
button_device.ev_press = ;
wake_up_interruptible(&(button_device.waitq));
} /* Cancel the dithering */
mod_timer(&(button_device.timers[num]), jiffies+TIMER_DELAY_UP);
}
else
{
//dbg_print("Key Released!\n");
button_device.status[num] = BUTTON_UP;
// enable_irq(pdata->buttons[num].nIRQ);
} return ;
} /*===================== Button device driver part ===========================*/ static int button_open(struct inode *inode, struct file *file) //打开按键
{
struct button_device *pdev ;
struct s3c_button_platform_data *pdata;
int i, result; pdev = container_of(inode->i_cdev,struct button_device, cdev); //通过i_cdev找到cdev结构体
pdata = pdev->data;
file->private_data = pdev; /* Malloc for all the buttons remove dithering timer */
pdev->timers = (struct timer_list *) kmalloc(pdata->nbuttons*sizeof(struct timer_list), GFP_KERNEL); //为cdev结构体中的timer分配内存
if(NULL == pdev->timers)
{
printk("Alloc %s driver for timers failure.\n", DEV_NAME);
return -ENOMEM;
}
memset(pdev->timers, , pdata->nbuttons*sizeof(struct timer_list)); //初始化timer内存 /* Malloc for all the buttons status buffer */
pdev->status = (unsigned char *)kmalloc(pdata->nbuttons*sizeof(unsigned char), GFP_KERNEL); //为button状态分配内存空间
if(NULL == pdev->status)
{
printk("Alloc %s driver for status failure.\n", DEV_NAME);
result = -ENOMEM;
goto ERROR;
}
memset(pdev->status, , pdata->nbuttons*sizeof(unsigned char)); //初始化状态内存 init_waitqueue_head(&(pdev->waitq)); //加入等待队列 for(i=; i<pdata->nbuttons; i++) //初始化button信息
{
/* Initialize all the buttons status to UP */
pdev->status[i] = BUTTON_UP; //设置为未按 /* Initialize all the buttons' remove dithering timer */
setup_timer(&(pdev->timers[i]), button_timer_handler, i); //设置定时器及调用函数 /* Set all the buttons GPIO to EDGE_FALLING interrupt mode */
s3c2410_gpio_cfgpin(pdata->buttons[i].gpio, pdata->buttons[i].setting); //配置成中断模式
irq_set_irq_type(pdata->buttons[i].nIRQ, IRQ_TYPE_EDGE_FALLING); //中断采用下降沿触发 /* Request for button GPIO pin interrupt */
result = request_irq(pdata->buttons[i].nIRQ, s3c_button_intterupt, IRQF_DISABLED, DEV_NAME, (void *)i);
//注册给内核,一旦发生pdata->buttons[i].nIRQ中断号的中断之后,调用s3c_button_intterupt中断处理程序
if( result )
{
result = -EBUSY;
goto ERROR1;
}
} return ; ERROR1: //出错反向退出
kfree((unsigned char *)pdev->status);
while(--i)
{
disable_irq(pdata->buttons[i].nIRQ);
free_irq(pdata->buttons[i].nIRQ, (void *)i);
} ERROR:
kfree(pdev->timers); return result;
} static int button_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) //读按键信息函数
{
struct button_device *pdev = file->private_data;
struct s3c_button_platform_data *pdata;
int i, ret;
unsigned int status = ; pdata = pdev->data; dbg_print("ev_press: %d\n", pdev->ev_press);
if(!pdev->ev_press) //按键没有按下
{
if(file->f_flags & O_NONBLOCK) //如果是非阻塞模式则返回EAGAIN
{
dbg_print("read() without block mode.\n");
return -EAGAIN;
}
else //阻塞模式加入等待队列
{
/* Read() will be blocked here */
dbg_print("read() blocked here now.\n");
wait_event_interruptible(pdev->waitq, pdev->ev_press); //加入等待队列
}
} pdev->ev_press = ; //将按键设置为未按下 for(i=; i<pdata->nbuttons; i++) //读出按键状态并保存在status中
{
dbg_print("button[%d] status=%d\n", i, pdev->status[i]);
status |= (pdev->status[i]<<i); //这里的status[i]是如何保存各个按键状态信息的?
} ret = copy_to_user(buf, (void *)&status, min(sizeof(status), count)); //将此按键信息发送给用户空间 return ret ? -EFAULT : min(sizeof(status), count);
} static unsigned int button_poll(struct file *file, poll_table * wait) //监视button函数
{
struct button_device *pdev = file->private_data;
unsigned int mask = ; poll_wait(file, &(pdev->waitq), wait); //加入等待队列
if(pdev->ev_press)
{
mask |= POLLIN | POLLRDNORM; /* The data aviable */ //按键按下设置mask值
} return mask;
} static int button_release(struct inode *inode, struct file *file)
{
int i;
struct button_device *pdev = file->private_data;
struct s3c_button_platform_data *pdata;
pdata = pdev->data; for(i=; i<pdata->nbuttons; i++)
{
disable_irq(pdata->buttons[i].nIRQ); //关中断
free_irq(pdata->buttons[i].nIRQ, (void *)i); //删中断
del_timer(&(pdev->timers[i])); //取消timer
} kfree(pdev->timers); //释放timer内存
kfree((unsigned char *)pdev->status); //释放申请的status内存 return ;
} static struct file_operations button_fops = { //功能函数
.owner = THIS_MODULE,
.open = button_open,
.read = button_read,
.poll = button_poll,
.release = button_release,
}; static int s3c_button_probe(struct platform_device *dev)
{
int result = ;
dev_t devno; /* Alloc the device for driver */
if ( != dev_major)
{
devno = MKDEV(dev_major, dev_minor);
result = register_chrdev_region(devno, , DEV_NAME);
}
else
{
result = alloc_chrdev_region(&devno, dev_minor, , DEV_NAME);
dev_major = MAJOR(devno);
} /* Alloc for device major failure */
if (result < )
{
printk("%s driver can't get major %d\n", DEV_NAME, dev_major);
return result;
} /* Initialize button_device structure and register cdev*/
memset(&button_device, , sizeof(button_device));
button_device.data = dev->dev.platform_data;
cdev_init (&(button_device.cdev), &button_fops);
button_device.cdev.owner = THIS_MODULE; result = cdev_add (&(button_device.cdev), devno , );
if (result)
{
printk (KERN_NOTICE "error %d add %s device", result, DEV_NAME);
goto ERROR;
} button_device.dev_class = class_create(THIS_MODULE, DEV_NAME);
if(IS_ERR(button_device.dev_class))
{
printk("%s driver create class failture\n",DEV_NAME);
result = -ENOMEM;
goto ERROR;
} #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
device_create(button_device.dev_class, NULL, devno, NULL, DEV_NAME);
#else
device_create (button_device.dev_class, NULL, devno, DEV_NAME);
#endif printk("S3C %s driver version %d.%d.%d initiliazed.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER); return ; ERROR:
printk("S3C %s driver version %d.%d.%d install failure.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);
cdev_del(&(button_device.cdev));
unregister_chrdev_region(devno, );
return result;
} static int s3c_button_remove(struct platform_device *dev)
{
dev_t devno = MKDEV(dev_major, dev_minor); cdev_del(&(button_device.cdev));
device_destroy(button_device.dev_class, devno);
class_destroy(button_device.dev_class); unregister_chrdev_region(devno, );
printk("S3C %s driver removed\n", DEV_NAME); return ;
} /*===================== Platform Device and driver regist part ===========================*/ static struct platform_driver s3c_button_driver = {
.probe = s3c_button_probe,
.remove = s3c_button_remove,
.driver = {
.name = "s3c_button",
.owner = THIS_MODULE,
},
}; static int __init s3c_button_init(void)
{
int ret = ; ret = platform_device_register(&s3c_button_device);
if(ret)
{
printk(KERN_ERR "%s: Can't register platform device %d\n", __FUNCTION__, ret);
goto fail_reg_plat_dev;
}
dbg_print("Regist S3C %s Device successfully.\n", DEV_NAME); ret = platform_driver_register(&s3c_button_driver);
if(ret)
{
printk(KERN_ERR "%s: Can't register platform driver %d\n", __FUNCTION__, ret);
goto fail_reg_plat_drv;
}
dbg_print("Regist S3C %s Driver successfully.\n", DEV_NAME); return ; fail_reg_plat_drv:
platform_driver_unregister(&s3c_button_driver);
fail_reg_plat_dev:
return ret;
} static void s3c_button_exit(void)
{
platform_driver_unregister(&s3c_button_driver);
dbg_print("S3C %s platform device removed.\n", DEV_NAME); platform_device_unregister(&s3c_button_device);
dbg_print("S3C %s platform driver removed.\n", DEV_NAME);
} module_init(s3c_button_init);
module_exit(s3c_button_exit); module_param(debug, int, S_IRUGO);
module_param(dev_major, int, S_IRUGO);
module_param(dev_minor, int, S_IRUGO); MODULE_AUTHOR(DRV_AUTHOR);
MODULE_DESCRIPTION(DRV_DESC);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:S3C24XX_button");

按键驱动的两个重点:去抖、中断

编写中断程序需要注意的事情:1、Linux不支持中断嵌套  2、中断处理程序不可重用,不可阻塞

应用程序:

 /*********************************************************************************
* Copyright: (C) 2016 2013dianxin_3
* All rights reserved.
*
* Filename: buttonapp.c
* Description: This file
*
* Version: 1.0.0(06/12/2016)
* Author: xiaohexiansheng <1392195453@qq.com>
* ChangeLog: 1, Release initial version on "06/12/2016 01:42:50 PM"
*
********************************************************************************/
#include"plat_ioctl.h"
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include<sys/time.h> #define LED_OFF _IO (PLATDRV_MAGIC, 0x18)
#define LED_ON _IO (PLATDRV_MAGIC, 0x19)
#define BUTTON_STATUS 4
#define KEY1 0x1
#define KEY2 0x2
#define KEY3 0x4
#define KEY4 0x8 int main(int argc, char **argv)
{
int button_fd;
int led_fd;
int ret;
int but_status;
fd_set rdfds; button_fd = open("/dev/button", O_RDWR);
if (button_fd < )
{
printf("Open buttons device faild!\n");
exit();
} led_fd = open("/dev/led", O_RDWR);
if (led_fd < )
{
printf("Open led device faild!\n");
exit();
} printf("Start select....\n"); FD_ZERO(&rdfds);
FD_SET(button_fd, &rdfds); while ()
{
ret = select(button_fd + , &rdfds, NULL, NULL, NULL); if (ret < )
{
printf("select failure\n");
exit();
} if (ret == )
{
printf("select timeout\n");
} else if (ret > )
{
if (FD_ISSET(button_fd, &rdfds) > )
{
read(button_fd, &but_status, sizeof(but_status));
}
} if (but_status & KEY1)
{
ioctl(led_fd, LED_ON, );
sleep();
ioctl(led_fd, LED_OFF, );
} if (but_status & KEY2)
{
ioctl(led_fd, LED_ON, );
sleep();
ioctl(led_fd, LED_OFF, );
} if (but_status & KEY3)
{
ioctl(led_fd, LED_ON, );
sleep();
ioctl(led_fd, LED_OFF, );
} if (but_status & KEY4)
{
ioctl(led_fd, LED_ON, );
sleep();
ioctl(led_fd, LED_OFF, );
}
} close(button_fd);
close(led_fd);
return ;
}

fl2440 platform总线button字符设备驱动的更多相关文章

  1. fl2440 platform总线led字符设备驱动

    首先需要知道的是,设备跟驱动是分开的.设备通过struct device来定义,也可以自己将结构体封装到自己定义的device结构体中: 例如:struct platform_device: 在inc ...

  2. 字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联

    转载自:http://www.kancloud.cn/yueqian_scut/emlinux/106829 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sy ...

  3. [kernel]字符设备驱动、平台设备驱动、设备驱动模型、sysfs几者之间的比较和关联

    转自:http://www.2cto.com/kf/201510/444943.html Linux驱动开发经验总结,绝对干货! 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动 ...

  4. 深入理解Linux字符设备驱动

    文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...

  5. 【转】深入浅出:Linux设备驱动之字符设备驱动

    深入浅出:Linux设备驱动之字符设备驱动 一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据 ...

  6. linux设备驱动之字符设备驱动模型(2)

    在上一篇中我们已经了解了字符设备驱动的原理,也了解了应用层调用内核函数的机制,但是我们每次操作设备,都必须首先通过mknod命令创建一个设备文件名,比如说我们要打开u盘,硬盘等这些设备,难道我们还要自 ...

  7. 蜕变成蝶~Linux设备驱动之字符设备驱动

    一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流 ...

  8. Android字符设备驱动开发基于高通msm8916【原创 】

    本人才疏浅学,写一篇文档总结自己在msm8916平台上移植自己编写的简单的字符设备驱动开发的整个流程.这个小项目的主要功能是开发一个简单的APP,APP通过JNI去调用位于kernel的字符设备驱动. ...

  9. 深入浅出:Linux设备驱动之字符设备驱动

    一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流 ...

随机推荐

  1. Sublime Text 3 遇到的一些小坑的解决方法

    1.[不停弹出更新框]Sublime Text 3 软件会弹出“Update Available”对话框,点击“Cancel”按钮取消:取消之后还是会频繁出现 解决方法:点击菜单栏“Preferenc ...

  2. Shell Script Basics

    https://developer.apple.com/library/mac/documentation/OpenSource/Conceptual/ShellScripting/shell_scr ...

  3. happens-before规则

    happens-before原则: happens-before它是判断数据是否存在竞争.线程是否安全的主要依据.为了保证线程安全我们可以让2个操作具有happens-before关系.(JDK5 开 ...

  4. 【转载】Synflood code

    ''' Syn flood program in python by Tequila/e credits to Silver Moon for base's of syn packets. r s s ...

  5. zoj2318

    zoj2318 题意 一个平面上给出很多圆,其中一个圆为现在自己的位置,问这个圆能不能冲出其它圆的包围(不能与其它圆相交). 分析 将所有圆心平移,使得自己的圆圆心处于原点,将所有圆半径增加自己圆的半 ...

  6. hdu6052

    hdu6052 题意 给出一个 \(n * m\) 的网格矩阵,每个格子都有颜色,随机选出一个子矩阵,问颜色种数的期望. 分析 那么我们可以去算所有矩阵的颜色种数之和,也就是每种颜色出现过的矩阵的个数 ...

  7. 9、Django实战第9天:用户注册功能

    今天完成的是用户注册功能... 首先把注册页面的前端文件register.html复制到templates目录下 编辑users.views.py,创建一个注册的类 class RegisterVie ...

  8. centos7 启用iptables

    在centos 7下启用iptables systemctl stop firewalld.service systemctl disable firewalld.service yum instal ...

  9. Servlet规范简介

    引言 Web 框架一般是通过一个 Servlet 提供统一的请求入口,将指定的资源映射到这个 servlet, 在这个 servlet 中进行框架的初始化配置,访问 Web 页面中的数据,进行逻辑处理 ...

  10. [BZOJ3551][ONTAK2010]Peaks(加强版)(Kruskal重构树,主席树)

    3551: [ONTAK2010]Peaks加强版 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2438  Solved: 763[Submit][ ...