当前位置:编程学习 > C/C++ >>

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

经过前面的配置,S5PV210开发已经可以成功进入Linux控制台了,那么,有了这个环境就可以开始学习Linux驱动的编写和测试了。学习Linux设备驱动,通常是从字符设备驱动开始。我写的第一个驱动程序是Led的,其实也就是熟悉下字符设备驱动的基本结构,本文以中断方式的按键驱动为例,简单的介绍下字符设备驱动程序。

一 按键驱动程序的简单实现

下面是基于中断和消息的按键驱动程序,其工作原理是:当应用程序读取键值时,会调用按键驱动程序的read函数,而我们实现的read函数检测完读取长度后没有直接读取键值而是等待按键消息,如果没有按键,程序会进入休眠状态,这样可以节省大量的CPU,而当我们按键时硬件会产生中断,程序自动进入中断处理函数,在中断处理函数中,驱动程序读取键值存入全局变量并激活read函数中等待的消息,应用程序被迅速唤醒并通过read函数读取键值,如此,完成了获取键值的工作。下面是源码,比较简单,也就不多说了。

源码:


[cpp]
#include <linux/types.h>  
#include <linux/module.h>  
#include <linux/cdev.h>  
#include <linux/fs.h>  
#include <linux/device.h>  
#include <linux/gpio.h>  
#include <linux/irq.h>  
#include <linux/interrupt.h>  
#include <linux/sched.h>   
#include <linux/wait.h>  
#include <linux/uaccess.h>  
 
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]);   
&

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,