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