zoukankan      html  css  js  c++  java
  • 20150216 IMX257实现GPIO-查询按键驱动程序

    20150216IMX257实现GPIO-查询按键驱动程序

    2015-02-16 李海沿

    前面我们介绍了简单的通用字符设备驱动程序,接下来,我们在它的基础上来实现GPIO的查询按键功能。

    先附上驱动程序代码

      1 /******************************
      2     linux key_query
      3  *****************************/
      4 #include <linux/module.h>
      5 #include <linux/init.h>
      6 #include <linux/kernel.h>
      7 #include <linux/delay.h>
      8 #include <linux/types.h>
      9 #include <linux/ioctl.h>
     10 #include <linux/gpio.h>
     11 #include <linux/fs.h>
     12 #include <linux/device.h>//包含了用于自动创建设备节点的函数device_create
     13 #include <linux/uaccess.h>//包含了copy_to_user 函数等
     14 
     15 #include "mx257_gpio.h"
     16 #include "mx25_pins.h"
     17 #include "iomux.h"
     18 
     19 #define Driver_NAME "key_query"
     20 #define DEVICE_NAME "key_query"
     21 
     22 #define GPIO2_21    MX25_PIN_CLKO
     23 #define GPIO3_15    MX25_PIN_EXT_ARMCLK
     24 #define GPIO2_10    MX25_PIN_A24
     25 #define GPIO2_11    MX25_PIN_A25
     26 #define GPIO2_8     MX25_PIN_A22
     27 #define GPIO2_9     MX25_PIN_A23
     28 #define GPIO2_6     MX25_PIN_A20
     29 #define GPIO2_7     MX25_PIN_A21
     30 //command
     31 #define key_input     0
     32 #define version        1
     33 //用于保存主设备号
     34 static int major=0;
     35 //用于自动创建设备节点 代替了手动敲mknod命令
     36 //auto to create device node
     37 static struct class *drv_class = NULL;
     38 static struct class_device *drv_class_dev = NULL;
     39 
     40 
     41 /* 应用程序对设备文件/dev/key_query执行open(...)时,
     42  * 就会调用key_open函数*/
     43 static int key_open(struct inode *inode, struct file *file)
     44 {
     45     printk("<0>function open!
    
    ");
     46     
     47     return 0;
     48 }
     49 /*当应用程序中read(fd,buff,sizeof(buff))时调用此key_read函数*/
     50 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
     51 {
     52     int ret;
     53     //nt cnt=0;
     54     unsigned char key_vals[8];
     55     // reading the pins value
     56     key_vals[0] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_6)) ? 1 : 0;
     57     key_vals[1] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_7)) ? 1 : 0;
     58     key_vals[2] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_8)) ? 1 : 0;
     59     key_vals[3] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_9)) ? 1 : 0;
     60     key_vals[4] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_10)) ? 1 : 0;
     61     key_vals[5] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_11)) ? 1 : 0;
     62     key_vals[6] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_21)) ? 1 : 0;
     63     key_vals[7] = gpio_get_value(IOMUX_TO_GPIO(GPIO3_15)) ? 1 : 0;
     64     
     65     ret = copy_to_user(buff,key_vals,sizeof(key_vals));
     66     if(ret){
     67         ;
     68     }
     69     
     70     //printk("<0>%04d key pressed: %d %d %d %d %d %d %d %d
    ",cnt++,key_vals[0],key_vals[1],key_vals[2],key_vals[3],key_vals[4],key_vals[5],key_vals[6],key_vals[7]); 
     71 
     72     return sizeof(key_vals);
     73 }
     74  /* 当应用程序中使用write函数时,调用此函数**/
     75 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
     76 {
     77     printk("<0>function write!
    
    ");
     78     
     79     return 1;
     80 }
     81 
     82 static int  key_release(struct inode *inode, struct file *filp)
     83 {
     84     printk("<0>function release!
    
    ");
     85     return 0;
     86 }
     87  /* 当用户调用ioctl(fd,version,NULL);时,会进入此函数,
     88   * 在SWITCH中配对command,然后执行相应的语句 
     89   * 注意command 一定为整数,需在前面定义*/
     90 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)
     91 {
     92     printk("<0>function ioctl!
    
    ");
     93     switch (command) {
     94         case key_input:
     95             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_21));
     96             gpio_direction_input(IOMUX_TO_GPIO(GPIO3_15));
     97             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_10));
     98             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_11));
     99             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_8));
    100             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_9));
    101             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_6));
    102             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_7));
    103             //设置所有引脚为上拉模式
    104             mxc_iomux_set_pad(GPIO2_6, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
    105             mxc_iomux_set_pad(GPIO2_7, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
    106             //mxc_iomux_set_pad(GPIO2_8, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
    107             mxc_iomux_set_pad(GPIO2_9, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
    108             mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
    109             mxc_iomux_set_pad(GPIO2_11, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
    110             mxc_iomux_set_pad(GPIO2_21, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
    111             //mxc_iomux_set_pad(GPIO3_15, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
    112             break;
    113         case version:
    114             printk("<0>hello,the version is 0.1.0
    
    ");
    115             break;
    116         default:
    117               printk("<0>command error 
    ");
    118             printk("<0>ioctl(fd, (unsigned int)command, (unsigned long) arg;
    ");
    119             printk("<0>command: <key_input> <version>
    
    ");
    120             return -1;
    121     }
    122     return 0;    
    123 }
    124 
    125 /* 这个结构是字符设备驱动程序的核心
    126  * 当应用程序操作设备文件时所调用的open、read、write等函数,
    127  * 最终会调用这个结构中指定的对应函数
    128  */
    129 static struct file_operations key_fops = {
    130     .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    131     .open   =   key_open,     
    132     .read    =    key_read,       
    133     .write    =    key_write,       
    134     .release=   key_release,
    135     .ioctl  =   key_ioctl,    
    136 };
    137     
    138 /*
    139  * 执行insmod命令时就会调用这个函数 
    140  */
    141 static int __init key_init(void)
    142 {
    143     printk("<0>
    Hello,this is %s module!
    
    ",Driver_NAME);
    144     //register and mknod
    145     //注册字符设备,系统会自动分配一个主设备号,保存在major中
    146     major = register_chrdev(0,Driver_NAME,&key_fops);
    147     //自动在/dev/目录下创建设备节点
    148     drv_class = class_create(THIS_MODULE,Driver_NAME);
    149     drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME);    /*/dev/key_query*/
    150 
    151     //set all pins to GPIO mod  ALF5
    152     //设置所有的GPIO引脚为GPIO功能
    153     mxc_request_iomux(GPIO2_21, MUX_CONFIG_ALT5);
    154     mxc_request_iomux(GPIO3_15, MUX_CONFIG_ALT5);
    155       mxc_request_iomux(GPIO2_10, MUX_CONFIG_ALT5);
    156        mxc_request_iomux(GPIO2_11, MUX_CONFIG_ALT5);
    157     mxc_request_iomux(GPIO2_8, MUX_CONFIG_ALT5);
    158     mxc_request_iomux(GPIO2_9, MUX_CONFIG_ALT5);
    159     mxc_request_iomux(GPIO2_6, MUX_CONFIG_ALT5);
    160     mxc_request_iomux(GPIO2_7, MUX_CONFIG_ALT5);
    161     
    162     
    163             printk("<0>have setting all pins to gpio input mod !
    ");
    164     //request IOMUX GPIO
    165     gpio_request(IOMUX_TO_GPIO(GPIO2_21), "GPIO2_21");
    166      gpio_request(IOMUX_TO_GPIO(GPIO3_15), "GPIO3_15");
    167      gpio_request(IOMUX_TO_GPIO(GPIO2_10), "GPIO2_10");
    168        gpio_request(IOMUX_TO_GPIO(GPIO2_11), "GPIO2_11");
    169     gpio_request(IOMUX_TO_GPIO(GPIO2_8), "GPIO2_8");
    170      gpio_request(IOMUX_TO_GPIO(GPIO2_9), "GPIO2_9");
    171       gpio_request(IOMUX_TO_GPIO(GPIO2_6), "GPIO2_6");
    172     gpio_request(IOMUX_TO_GPIO(GPIO2_7), "GPIO2_7");
    173 
    174     return 0;
    175 }
    176 
    177 /*
    178  * 执行rmmod命令时就会调用这个函数 
    179  */
    180 static void __exit key_exit(void)
    181 {
    182     printk("<0>
    Goodbye,%s!
    
    ",Driver_NAME);
    183     //卸载字符设备,释放主设备号
    184     unregister_chrdev(major,Driver_NAME);
    185     //卸载字符设备的设备节点
    186     device_unregister(drv_class_dev);
    187     class_destroy(drv_class);
    188 
    189     /* free gpios */
    190     mxc_free_iomux(GPIO2_21, MUX_CONFIG_ALT5);
    191     mxc_free_iomux(GPIO3_15, MUX_CONFIG_ALT5);
    192     mxc_free_iomux(GPIO2_10, MUX_CONFIG_ALT5);
    193     mxc_free_iomux(GPIO2_11, MUX_CONFIG_ALT5);
    194     mxc_free_iomux(GPIO2_8, MUX_CONFIG_ALT5);
    195     mxc_free_iomux(GPIO2_9, MUX_CONFIG_ALT5);
    196     mxc_free_iomux(GPIO2_6, MUX_CONFIG_ALT5);
    197     mxc_free_iomux(GPIO2_7, MUX_CONFIG_ALT5);
    198 
    199     gpio_free(IOMUX_TO_GPIO(GPIO2_21));
    200     gpio_free(IOMUX_TO_GPIO(GPIO3_15));
    201     gpio_free(IOMUX_TO_GPIO(GPIO2_10));
    202     gpio_free(IOMUX_TO_GPIO(GPIO2_11));
    203     gpio_free(IOMUX_TO_GPIO(GPIO2_8));
    204     gpio_free(IOMUX_TO_GPIO(GPIO2_9));
    205     gpio_free(IOMUX_TO_GPIO(GPIO2_6));
    206     gpio_free(IOMUX_TO_GPIO(GPIO2_7));
    207 
    208 }
    209 
    210 /* 这两行指定驱动程序的初始化函数和卸载函数 */
    211 module_init(key_init);
    212 module_exit(key_exit);
    213 
    214 /* 描述驱动程序的一些信息,不是必须的 */
    215 MODULE_AUTHOR("Lover雪");
    216 MODULE_VERSION("0.1.0");
    217 MODULE_DESCRIPTION("IMX257 key Driver");
    218 MODULE_LICENSE("GPL");
    key.c


    如程序所示,
     

    static int __init key_init(void)

    我们把注册字符设备,创建设备节点,GPIO地址映射,以及GPIO模式的初始化,都在此函数中实现。

    static void __exit key_exit(void)

    在此函数中我们 做了一下三件事,卸载字符设备,释放主设备函,释放GPIO

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

    当应用程序中调用

    read(fd, key_vals,sizeof(key_vals));

    时,该函数就是负责,读取此时,我们GPIO引脚的电平,然后通过COPY_TO_USER函数将我们的gpio引脚的电平传递给应用程序。

    static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)

    当应用程序中,执行代码

    ioctl(fd,key_input,NULL);

    时,就会执行

    switch的case key_input中的代码,将所有的gpio引脚都设置成输入模式。

     然后将所有的GPIO引脚设置为22K上拉模式:

    //设置所有引脚为上拉模式
                mxc_iomux_set_pad(GPIO2_6, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
                mxc_iomux_set_pad(GPIO2_7, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
                //mxc_iomux_set_pad(GPIO2_8, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
                mxc_iomux_set_pad(GPIO2_9, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
                mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
                mxc_iomux_set_pad(GPIO2_11, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
                mxc_iomux_set_pad(GPIO2_21, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
                //mxc_iomux_set_pad(GPIO3_15, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

    经过测试,貌似,GPIO2_8,GPIO3_15两个引脚不能这样设置,由于暂时对IMX257还不太了解,对于这一现象无法解释。

    附上应用程序代码

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <unistd.h>
     4 #include <sys/types.h>
     5 #include <sys/stat.h>
     6 #include <fcntl.h>
     7 #include <termios.h>
     8 #include <errno.h>
     9 #include <limits.h>
    10 #include <asm/ioctls.h>
    11 #include <time.h>
    12 #include <pthread.h>
    13 
    14 #include "mx257_gpio.h"
    15 
    16 #define key_input     0
    17 #define version               1
    18 
    19 
    20 int main(int argc, char **argv)
    21 {
    22     int fd;
    23     int i=0,cnt=0;
    24     unsigned char key_vals[8];
    25     
    26     fd = open("/dev/key_query",O_RDWR);
    27     if(fd < 0){
    28         printf("can't open !!!
    ");
    29     }
    30     ioctl(fd,key_input,NULL);
    31     while(1){
    32         read(fd, key_vals,sizeof(key_vals));
    33         if(!key_vals[0] | !key_vals[1] | !key_vals[2] | !key_vals[3] | !key_vals[4] | !key_vals[5] | !key_vals[6] | !key_vals[7] )
    34             printf("%04d key pressed: %d %d %d %d %d %d %d %d
    ",cnt++,key_vals[0],key_vals[1],key_vals[2],key_vals[3],key_vals[4],key_vals[5],key_vals[6],key_vals[7]);    
    35     }
    36     return 0;
    37 }
    View Code


    在应用程序中,
     

    1. 我们首先使用open来打开设备/dev/key_query。
    1. 使用ioctl函数将所有的GPIO引脚配置为输入模式
    1. 在while循环中使用read函数来不断的读取gpio引脚的电,一旦检测到低电平,就打印所有GPIO引脚当前的电平值

    附上MAKEFILE代码

     1 ifeq ($(KERNELRELEASE),)
     2     KERNELDIR ?= /home/study/system/linux-2.6.31
     3     PWD := $(shell pwd)
     4 modules:
     5     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
     6 modules_install:
     7     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
     8 clean:
     9     rm -rf *.o *~ core .depend  *cmd *.ko *.mod.c .tmp_versions *.markers *.order *.symvers
    10 
    11 else
    12     obj-m := key.o
    13 endif
    View Code


     
     

    编译、加载驱动:

    使用交叉编译工具:

    make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-

    insmod key.ko

    ll /dev/key*

     结果如下:

    执行应用程序:

    cd key/

    arm-none-linux-gnueabi-gcc key_test.c –o key_test

    ./key_test

    结果如下:

  • 相关阅读:
    C#搭建Oauth2.0认证流程以及代码示例
    DirectoryEntry配置IIS7出现ADSI Error:未知错误(0x80005000)
    C# 操作IIS方法集合
    dedecms首页入口的详细注释
    分享几个在线生成网址二维码的API接口
    Windows平台分布式架构实践
    WINDOWS 2008Server 配置nginx 反向代理服务器 安装成服务
    [支付宝]手机网站支付快速接入
    支付宝 app支付 沙盘使用
    支付宝接口开发-手机网站支付-沙箱测试
  • 原文地址:https://www.cnblogs.com/lihaiyan/p/4294510.html
Copyright © 2011-2022 走看看