热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

S5PV210(TQ210)学习笔记——按键驱动程序

经过前面的配置,S5PV210开发已经可以成功进入Linux控制台了,那么,有了这个环境就可以开始学习Linux驱动的编写和测试了。学习L

经过前面的配置,S5PV210开发已经可以成功进入Linux控制台了,那么,有了这个环境就可以开始学习Linux驱动的编写和测试了。学习Linux设备驱动,通常是从字符设备驱动开始。由于linux驱动开发具有比较系统的体系结构,我很难在一篇文章中阐述其开发思路,为了简单起见,从本文开始,自行编写的驱动将直接附上代码,对开发过程中感触比较深的地方稍作陈述。

我写的第一个驱动程序是Led的,但是感觉没有必要发出来了,S5PV210(TQ210)的按键驱动程序源码,仅供参考:

 

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include static dev_t devno;
static struct cdev cdev;
static struct class* buttons_class;
static struct device* buttons_device;static wait_queue_head_t button_waitq;static volatile int pressed = 0;
static unsigned char key_val;struct key_desc{unsigned int pin;unsigned char value;
};static struct key_desc key_descs[8] = {[0] = {.pin = S5PV210_GPH0(0),.value = 0x00,},[1] = {.pin = S5PV210_GPH0(1),.value = 0x01,},[2] = {.pin = S5PV210_GPH0(2),.value = 0x02,},[3] = {.pin = S5PV210_GPH0(3),.value = 0x03,},[4] = {.pin = S5PV210_GPH0(4),.value = 0x04,},[5] = {.pin = S5PV210_GPH0(5),.value = 0x05,},[6] = {.pin = S5PV210_GPH2(6),.value = 0x06,},[7] = {.pin = S5PV210_GPH2(7),.value = 0x07,},
};static irqreturn_t buttons_irq(int irq, void *dev_id){volatile struct key_desc *key = (volatile struct key_desc *)dev_id;if(gpio_get_value(key->pin)){key_val = key->value|0x80;}else{key_val = key->value;}pressed = 1;wake_up_interruptible(&button_waitq);return IRQ_RETVAL(IRQ_HANDLED);
}static int buttons_open(struct inode *inode, struct file *file){int ret;ret = request_irq(IRQ_EINT(0), buttons_irq, IRQ_TYPE_EDGE_BOTH, "key1", &key_descs[0]);if(ret)return ret;ret = request_irq(IRQ_EINT(1), buttons_irq, IRQ_TYPE_EDGE_BOTH, "key2", &key_descs[1]);if(ret)return ret;ret = request_irq(IRQ_EINT(2), buttons_irq, IRQ_TYPE_EDGE_BOTH, "key3", &key_descs[2]);if(ret)return ret;ret = request_irq(IRQ_EINT(3), buttons_irq, IRQ_TYPE_EDGE_BOTH, "key4", &key_descs[3]);if(ret)return ret;ret = request_irq(IRQ_EINT(4), buttons_irq, IRQ_TYPE_EDGE_BOTH, "key5", &key_descs[4]);if(ret)return ret;ret = request_irq(IRQ_EINT(5), buttons_irq, IRQ_TYPE_EDGE_BOTH, "key6", &key_descs[5]);if(ret)return ret;ret = request_irq(IRQ_EINT(22), buttons_irq, IRQ_TYPE_EDGE_BOTH, "key7", &key_descs[6]);if(ret)return ret;ret = request_irq(IRQ_EINT(23), buttons_irq, IRQ_TYPE_EDGE_BOTH, "key8", &key_descs[7]);if(ret)return ret;return 0;
}static ssize_t buttons_read(struct file * file, char __user *data, size_t count, loff_t *loff){if(count != 1){printk(KERN_ERR "The driver can only give one key value once!\n");return -ENOMEM;}wait_event_interruptible(button_waitq, pressed);pressed = 0;if(copy_to_user(data, &key_val, 1)){printk(KERN_ERR "The driver can not copy the data to user area!\n");return -ENOMEM;}return 0;
}static int buttons_close(struct inode *inode, struct file *file){free_irq(IRQ_EINT(0), &key_descs[0]);free_irq(IRQ_EINT(1), &key_descs[1]); free_irq(IRQ_EINT(2), &key_descs[2]);free_irq(IRQ_EINT(3), &key_descs[3]);free_irq(IRQ_EINT(4), &key_descs[4]);free_irq(IRQ_EINT(5), &key_descs[5]);free_irq(IRQ_EINT(22), &key_descs[6]);free_irq(IRQ_EINT(23), &key_descs[7]);return 0;
}struct file_operations buttons_ops = {.open = buttons_open,.read = buttons_read,.release = buttons_close,
};int buttons_init(void){int ret;cdev_init(&cdev, &buttons_ops);cdev.owner = THIS_MODULE;ret = alloc_chrdev_region(&devno, 0, 1, "buttons");if(ret){printk(KERN_ERR "alloc char device region faild!\n");return ret;}ret = cdev_add(&cdev, devno, 1);if(ret){printk(KERN_ERR "add char device faild!\n");goto add_error;}buttons_class = class_create(THIS_MODULE, "buttonsdrv");if(IS_ERR(buttons_class)){printk(KERN_ERR "create class error!\n");goto class_error;}buttons_device = device_create(buttons_class, NULL, devno, NULL, "buttons");if(IS_ERR(buttons_device)){printk(KERN_ERR "create buttons device error!\n");goto device_error;}init_waitqueue_head(&button_waitq);return 0;device_error:class_destroy(buttons_class);
class_error:cdev_del(&cdev);
add_error:unregister_chrdev_region(devno,1);return -ENODEV;
}void buttons_exit(void){device_destroy(buttons_class, devno);class_destroy(buttons_class);cdev_del(&cdev);unregister_chrdev_region(devno, 1);
}module_init(buttons_init);
module_exit(buttons_exit);
MODULE_LICENSE("GPL");

测试程序代码:

#include
#include int main(){int fd &#61; open("/dev/buttons", O_RDWR);if(fd <0){printf("open error");;return 0;}unsigned char key;while(1){read(fd, &key, 1);printf("The key &#61; %x\n", key);}close(fd);
}

相比轮询方式的按键驱动程序&#xff0c;中断方式编写的按键驱动程序可以很大程度上节省CPU资源&#xff0c;因此&#xff0c;推荐使用中断方式。

但是&#xff0c;这种方式有个弊端&#xff0c;如果一直接收不到按键&#xff0c;程序就会永远阻塞在这里&#xff0c;幸运的是&#xff0c;linux内核提供了poll机制&#xff0c;可以设置延迟时间&#xff0c;如果在这个时间内受到按键消息则取得键值&#xff0c;反之则超时退出。使内核支持poll非常简单&#xff0c;为file_operations的poll成员提供poll处理函数即可。

 

使内核支持poll还需要以下几步&#xff1a;

添加poll头文件


编写poll处理函数&#xff1a;

static unsigned buttons_poll(struct file *file, poll_table *wait){unsigned int mask &#61; 0;poll_wait(file, &button_waitq, wait);if (pressed)mask |&#61; POLLIN | POLLRDNORM;return mask;
}

将poll处理函数添加给file_operations&#xff1a;

 

 

.poll &#61; buttons_poll,

这样&#xff0c;驱动程序就支持poll机制了。下面是poll方式的测试程序&#xff1a;

 

 

#include
#include
#include
#include
#include int main(int argc, char **argv){int fd;unsigned char key_val;int ret;struct pollfd fds[1];fd &#61; open("/dev/buttons", O_RDWR);if (fd <0){printf("can&#39;t open!\n");}fds[0].fd &#61; fd;fds[0].events &#61; POLLIN;while (1){ret &#61; poll(fds, 1, 5000);if (ret &#61;&#61; 0){printf("time out\n");}else{read(fd, &key_val, 1);printf("key_val &#61; 0x%x\n", key_val);}}return 0;
}

这样按键驱动程序就完成了。如果您在编写测试阶段发现了其他问题&#xff0c;欢迎留言讨论。

 



推荐阅读
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 服务器上的操作系统有哪些,如何选择适合的操作系统?
    本文介绍了服务器上常见的操作系统,包括系统盘镜像、数据盘镜像和整机镜像的数量。同时,还介绍了共享镜像的限制和使用方法。此外,还提供了关于华为云服务的帮助中心,其中包括产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题和视频帮助等技术文档。对于裸金属服务器的远程登录,本文介绍了使用密钥对登录的方法,并提供了部分操作系统配置示例。最后,还提到了SUSE云耀云服务器的特点和快速搭建方法。 ... [详细]
author-avatar
领悟人生的悲欢喜乐_829
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有