博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
S5PV210(TQ210)学习笔记——按键驱动程序
阅读量:5878 次
发布时间:2019-06-19

本文共 5657 字,大约阅读时间需要 18 分钟。

经过前面的配置,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 = 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 = %x\n", key); } close(fd);}

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

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

 

使内核支持poll还需要以下几步:

添加poll头文件

编写poll处理函数:

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

将poll处理函数添加给file_operations:

 

 

.poll    = buttons_poll,

这样,驱动程序就支持poll机制了。下面是poll方式的测试程序:

 

 

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

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

 

转载地址:http://tzcix.baihongyu.com/

你可能感兴趣的文章
关于 error: LINK1123: failure during conversion to COFF: file invalid or corrupt 错误的解决方案...
查看>>
Linux 进程中 Stop, Park, Freeze【转】
查看>>
文件缓存
查看>>
Scrum实施日记 - 一切从零开始
查看>>
关于存储过程实例
查看>>
配置错误定义了重复的“system.web.extensions/scripting/scriptResourceHandler” 解决办法...
查看>>
PHP盛宴——经常使用函数集锦
查看>>
重写 Ext.form.field 扩展功能
查看>>
Linux下的搜索查找命令的详解(locate)
查看>>
福利丨所有AI安全的讲座里,这可能是最实用的一场
查看>>
开发完第一版前端性能监控系统后的总结(无代码)
查看>>
Python多版本情况下四种快速进入交互式命令行的操作技巧
查看>>
MySQL查询优化
查看>>
【Redis源码分析】如何在Redis中查找大key
查看>>
android app启动过程(转)
查看>>
安装gulp及相关插件
查看>>
如何在Linux用chmod来修改所有子目录中的文件属性?
查看>>
Applet
查看>>
高并发环境下,Redisson实现redis分布式锁
查看>>
关于浏览器的cookie
查看>>