mini2440按键驱动程序分析

发布者:云淡雅致最新更新时间:2020-06-29 来源: eefocus关键字:mini2440  按键驱动  程序分析 手机看文章 扫描二维码
随时随地手机看文章

先说明一下按键与S3C2440芯片的连接方式:

KEY1 <----> EINT8 <----> GPG0

KEY2 <----> EINT11 <----> GPG3

KEY3 <----> EINT13 <----> GPG5

KEY4 <----> EINT14 <----> GPG6

KEY5 <----> EINT15 <----> GPG7

KEY6 <----> EINT19 <----> GPG11


驱动程序源码如下:

(drivers/char/mini2440_buttons.c)


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include


#define DEVICE_NAME "buttons" //设备名称



/*定义中断所用的结构体*/


struct button_irq_desc

{

    int irq; //按键对应的中断号

    int pin; //按键所对应的GPIO 端口

    int pin_setting; //按键功能设置

    int number; //定义键值,以传递给应用层/用户态

    char *name; //每个按键的名称

};



/*结构体实体定义




*/


static struct button_irq_desc button_irqs [] =

{

    {IRQ_EINT8 , S3C2410_GPG(0) , S3C2410_GPG0_EINT8 , 0, "KEY0"},

    {IRQ_EINT11, S3C2410_GPG(3) , S3C2410_GPG3_EINT11 , 1, "KEY1"},

    {IRQ_EINT13, S3C2410_GPG(5) , S3C2410_GPG5_EINT13 , 2, "KEY2"},

    {IRQ_EINT14, S3C2410_GPG(6) , S3C2410_GPG6_EINT14 , 3, "KEY3"},

    {IRQ_EINT15, S3C2410_GPG(7) , S3C2410_GPG7_EINT15 , 4, "KEY4"},

    {IRQ_EINT19, S3C2410_GPG(11), S3C2410_GPG11_EINT19, 5, "KEY5"},

};


/*开发板上按键的状态变量,注意这里是’0’,对应的ASCII 码为30*/

static volatile char key_values [] = {'0', '0', '0', '0', '0', '0'};


/*因为本驱动是基于中断方式的,在此创建一个等待队列,以配合中断函数使用;当有按键按下并读>取到键值时,将会唤醒

此队列,并设置中断标志,以便能通过 read 函数判断和读取键值传递到用户>态;当没有按键按下时,系统并不*/

/*会轮询按键状态,以节省时钟资源*/

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);


/*中断标识变量,配合上面的队列使用,中断服务程序会把它设置为1,read 函数会把它清零*/

static volatile int ev_press = 0;


/*本按键驱动的中断服务程序*/

static irqreturn_t buttons_interrupt(int irq, void *dev_id)

{

    struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;

    int down;


    // udelay(0);


    /*获取被按下的按键状态*/

    down = !s3c2410_gpio_getpin(button_irqs->pin);


    /*状态改变,按键被按下,从这句可以看出,当按键没有被按下的时候,寄存器的值为1(上拉),

但按键被按下的时候,寄存器对应的值为0*/

    if (down != (key_values[button_irqs->number] & 1)) { // Changed

        /*如果key1 被按下,则key_value[0]就变为’1’,对应的ASCII 码为31*/

        key_values[button_irqs->number] = '0' + down;

        ev_press = 1; /*设置中断标志为1*/

        wake_up_interruptible(&button_waitq); /*唤醒等待队列*/

    }

    return IRQ_RETVAL(IRQ_HANDLED);

}


/**在应用程序执行open(“/dev/buttons”,…)时会调用到此函数,在这里,它的作用主要是注册6 个按

键的中断。


 *所用的中断类型是IRQ_TYPE_EDGE_BOTH,也就是双沿触发,在上升沿和下降沿均会产生中断,这样>做


 **是为了更加有效地判断按键状态


 */


static int s3c24xx_buttons_open(struct inode *inode, struct file *file)

{

    int i;

    int err = 0;

    for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)

    {

        if (button_irqs[i].irq < 0)

        {

            continue;

        }


        /*注册中断函数*/

        err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,

                button_irqs[i].name, (void *)&button_irqs[i]);

        if (err)

            break;

    }


    if (err)

    {

        /*如果出错,释放已经注册的中断,并返回*/

        i--;

        for (; i >= 0; i--)

        {

            if (button_irqs[i].irq < 0)

            {

                continue;

            }

            disable_irq(button_irqs[i].irq);

            free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);

        }

        return -EBUSY;

    }


    /*注册成功,则中断队列标记为1,表示可以通过read 读取*/

    ev_press = 1;

    /*正常返回*/

    return 0;

}


/*


 *此函数对应应用程序的系统调用close(fd)函数,在此,它的主要作用是当关闭设备时释放6 个按键

的中断*处理函数


 */


static int s3c24xx_buttons_close(struct inode *inode, struct file *file)

{

    int i;

    for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)

    {

        if (button_irqs[i].irq < 0)

        {

            continue;

        }


        /*释放中断号,并注销中断处理函数*/

        free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);

    }

    return 0;

}



/*

 *对应应用程序的read(fd,…)函数,主要用来向用户空间传递键值

-----------------------------------------------------------

 *filp:待操作的设备文件file结构体指针

 *buf:待写入所读取数据的用户空间缓冲区指针

 *count:待读取数据字节数

 *f_pos:待读取数据文件位置,写入完成后根据实际写入字节数重新定位

*/

static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

{

    unsigned long err;

    if (!ev_press)

    {

        if (filp->f_flags & O_NONBLOCK)  //阻塞模式?

            /*当中断标识为0 时,并且该设备是以非阻塞方式打开时,返回*/

            return -EAGAIN;   //返回繁忙标志

        else

            /*当中断标识为0 时,并且该设备是以阻塞方式打开时,进入休眠状态,等待被唤醒*/

            wait_event_interruptible(button_waitq, ev_press); //进入休眠,按键等待中断

    }


    /*把中断标识清零*/

    ev_press = 0;  //ev_press清零 (read后要清零,按键中断发生后会被置1)


    /*一组键值被传递到用户空间*/

    //min()返回较小的一个值,用意为:要拷贝的字节数最大只能为key_values占用的字节数大小,最小为count个字节。

    err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count));


    return err ? -EFAULT : min(sizeof(key_values), count);  //拷贝成功,返回拷贝的字节数。否则返回错误标志-EFAULT

}



/*

* unsigned int(*poll)(struct file *filp, struct poll_table * wait);

* 第一个参数是file结构体指针,第二个参数是轮询表指针,poll设备方法完成两件事:

* a -- 对可能引起设备文件状态变化的等待队列调用poll_wait()函数,将对应的等待队列头添加到poll_table,如果没有文件描

* 述符可用来执行 * I/O, 则内核使进程在传递到该系统调用的所有文件描述符对应的等待队列上等待。

* b -- 返回表示是否能对设备进行无阻塞读、写访问的掩码。

* 位掩码:POLLRDNORM, POLLIN,POLLOUT,POLLWRNORM

* 设备可读,通常返回:(POLLIN | POLLRDNORM)

* 设备可写,通常返回:(POLLOUT | POLLWRNORM)

*/

static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait)

{

    unsigned int mask = 0;


    /*把调用poll 或者select 的进程挂入队列,以便被驱动程序唤醒*/

    poll_wait(file, &button_waitq, wait);


    if (ev_press)

        mask |= POLLIN | POLLRDNORM;


    return mask;

}


/*设备操作集*/

/*

THIS_MODULE : __this_module这个符号是在加载到内核后才产生的。insmod命令执行后,会调用kernel/module.c里的一个系统调

用 sys_init_module,它会调用load_module函数,将用户空间传入的整个内核模块文件创建成一个内核模块,并返回一

个struct module结构体,从此,内核中便以这个结构体代表这个内核模块。THIS_MODULE类似进程的CURRENT。

*/

static struct file_operations dev_fops = {

    .owner = THIS_MODULE,

    .open = s3c24xx_buttons_open,

    .release = s3c24xx_buttons_close,

    .read = s3c24xx_buttons_read,

    .poll = s3c24xx_buttons_poll,

};


/*设备结构体

struct miscdevice  {

int minor;    //次设备号,若为 MISC_DYNAMIC_MINOR 自动分配

const char *name; //设备名

const struct file_operations *fops; //设备文件操作结构体

struct list_head list; //misc_list链表头

struct device *parent;

struct device *this_device;

const char *nodename;

mode_t mode;

};

*/

static struct miscdevice misc = {

    .minor = MISC_DYNAMIC_MINOR,

    .name = DEVICE_NAME,

    .fops = &dev_fops,

};


/*设备初始化,主要是注册设备*/

static int __init dev_init(void)

{

    int ret;


    /*把按键设备注册为misc 设备,其设备号是自动分配的*/

    ret = misc_register(&misc);

    printk (DEVICE_NAME"tinitializedn");

    return ret;

}


/*注销设备*/

static void __exit dev_exit(void)

{

    misc_deregister(&misc);

}


module_init(dev_init); //模块初始化,仅当使用insmod/podprobe 命令加载时有用,如果设备不是

通过模块方式加载,此处将不会被调用


module_exit(dev_exit); //卸载模块,当该设备通过模块方式加载后,可以通过rmmod 命令卸载,将

调用此函数


MODULE_LICENSE("GPL");//版权信息


MODULE_AUTHOR("FriendlyARM Inc.");//作者名字


测试程序:


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include


int

main(void)

{

    int buttons_fd;

    char buttons[6] = {'0', '0', '0', '0', '0', '0'};


    buttons_fd = open("/dev/buttons", 0); 

    if(buttons_fd < 0){ 

        perror("open device buttons error!");

        exit(1);

    } 


    for(;;){

        char current_buttons[6];

        int count_of_changed_key;

        int i;

        if(read(buttons_fd, current_buttons, sizeof(current_buttons)) != sizeof(current_buttons)){

            perror("read buttons:");

            exit(1);

        }


        for(i = 0, count_of_changed_key = 0; i < sizeof buttons / sizeof buttons[0]; i++){

            if(buttons[i] != current_buttons[i]){

                buttons[i] = current_buttons[i];

[1] [2]
关键字:mini2440  按键驱动  程序分析 引用地址:mini2440按键驱动程序分析

上一篇:arm移植ssh,实现远程root登录和sftp登录
下一篇:linux驱动之中断管理(for mini2440)

推荐阅读最新更新时间:2024-10-25 12:29

mini2440按键驱动程序分析
先说明一下按键与S3C2440芯片的连接方式: KEY1 ---- EINT8 ---- GPG0 KEY2 ---- EINT11 ---- GPG3 KEY3 ---- EINT13 ---- GPG5 KEY4 ---- EINT14 ---- GPG6 KEY5 ---- EINT15 ---- GPG7 KEY6 ---- EINT19 ---- GPG11 驱动程序源码如下: (drivers/char/mini2440_buttons.c) #include linux/module.h #include linux/kernel.h #include linux/fs.h #include linux
[单片机]
MINI2440 按键输入子系统 驱动及测试代码分析
按键输入子系统驱动: #include linux/module.h #include linux/types.h #include linux/fs.h #include linux/mm.h #include linux/device.h #include linux/errno.h /* for -EBUSY */ #include linux/ioport.h /* for request_region */ #include linux/delay.h /* for loops_per_jiffy */ #include asm/io.h /* for inb_p, outb_p, inb, outb,
[单片机]
Mini2440 按键驱动程序学习笔记
参考了友善之臂的按键驱动程序和韦东山写的《嵌入式Linux应用开发完全手册》【下载见 http://www.linuxidc.com/Linux/2011-01/31114.htm 】一书的第20章—Linux异常处理体系结构部分的按键驱动程序,修改了部分内容,学习了嵌入式Linux下按键驱动程序。 按照习惯,先看原理,对所学习的知识结构有了大致的了解了开始阅读别人的代码,仔细分析代码实现的每个过程。由于时间有限,我只了解了一些概念性的理论和内核代码中部分数据结构,学习的过程还有待深入。对于我这样的初学者来说,想把资料中所介绍的每个原理和具体的实现方法都完全掌握,恐怕不止是时间的问题,我所追求的是一种快速上手的方法,先学会用再深入
[单片机]
linux-2.6.32在mini2440开发板上移植 按键驱动程序移植
编者:按键驱动程序涉及到linux中断程序的编写。 1、按键原理图。 2、驱动程序的编写移植。 在/linux-2.6.32.2/drivers/char/目录下创建一个新的驱动程序文件mini2440_buttons.c,内容及详细注释如下: span style= font-size: 18px; #include linux/module.h #include linux/kernel.h #include linux/fs.h #include linux/init.h #include linux/delay.h #include linux/poll.h #include linux/irq.h #include
[单片机]
linux-2.6.32在<font color='red'>mini2440</font>开发板上移植 <font color='red'>按键</font><font color='red'>驱动</font><font color='red'>程序</font>移植
mini2440 简单按键中断模式驱动程序
Makefile KERN_DIR = /home/grh/kernel_source_code/linux-2.6.32.2 all : make -C $(KERN_DIR) M=`pwd` modules arm-linux-gcc key_interrupt_app.c -o key_interrupt_app clean : make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order obj-m += key_interrupt.o copy : cp key_interrupt.ko key_interrupt_app
[单片机]
<font color='red'>mini2440</font> 简单<font color='red'>按键</font>中断模式<font color='red'>驱动</font><font color='red'>程序</font>
linux-2.6.32在mini2440开发板上移植(17)之按键驱动程序移植
编者:按键驱动程序涉及到linux中断程序的编写。 1、按键原理图。 2、驱动程序的编写移植。 在/linux-2.6.32.2/drivers/char/目录下创建一个新的驱动程序文件mini2440_buttons.c,内容及详细注释如下: #include linux/module.h #include linux/kernel.h #include linux/fs.h #include linux/init.h #include linux/delay.h #include linux/poll.h #include linux/irq.h #include asm/irq.h #incl
[单片机]
linux-2.6.32在<font color='red'>mini2440</font>开发板上移植(17)之<font color='red'>按键</font><font color='red'>驱动</font><font color='red'>程序</font>移植
mini2440 led驱动程序经典分析
Linux内核为2.6.32.2 源码分析工具source insight 前言:在裸机中操作几个gpio口很简单,对控制寄存器和数据寄存器进行配置即可,但要在linux系统中实现同样的功能还是得费上一番周折的。 以下是驱动的源码。 #include …… #define DEVICE_NAME leds //设备名 static unsigned long led_table = { S3C2410_GPB(5), S3C2410_GPB(6), S3C2410_GPB(7), S3C2410_GPB(8), }; static unsigned int led_cfg_table = { S3C2410_GPIO_
[单片机]
Mini2440开发板PWM驱动与测试程序简要分析
先看下电路原理图 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEVICE_NAME pwm #define PWM_IOCTL_SET_FREQ 1 //设置pwm的频率 #define PWM_IOCTL_STOP 0 //停止pwm st
[单片机]
<font color='red'>Mini2440</font>开发板PWM<font color='red'>驱动</font>与测试<font color='red'>程序</font>简要<font color='red'>分析</font>
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved