使用gpio子系统和pinctrl子系统实现按键的操作

使用gpio子系统和pinctrl子系统实现按键的操作

步骤一:看硬件原理图,获知按键用到的IO口。由以下两图可知key0用的是UART_CTS
在这里插入图片描述
在这里插入图片描述
步骤二:查imx6ull的参考手册,获取寄存器相关信息。
第一张图显示的寄存器设置的IO复用的信息,也就是将IO复用为GPIO1_IO18,对应的寄存器的值为0x05.
在这里插入图片描述
在这里插入图片描述
下边的图设置的是GPIO1_IO18的电器属性,如:上拉、下拉、开漏、频率。。。。对应寄存器的值为0xF080.在这里插入图片描述
步骤三:设备树配置。
在这里插入图片描述
在这里插入图片描述
上图中MX6UL_PAD_UART1_CTS_B__GPIO1_IO18是一个宏定义,
在这里插入图片描述

!!!要注意驱动里边注释的问题,分配内存的地方,用完记得释放
key_drv.c

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define KEYVALUE 0XF0   //按键值
#define INVAKEY  0X00   //无效按键值

struct newchrkey_dev{
	struct device_node *dev_nod;
	int key_gpio;
	int major;
	int minor;
	dev_t devid;
	struct cdev cdev;
	struct device *device;
	struct class *cls;
	atomic_t my_atomic;
};

struct newchrkey_dev *newchrkey;

static int key_drv_open (struct inode *inod, struct file *filp){
	printk("----------------%s---------------\n",__FUNCTION__);
	filp->private_data = newchrkey;
	return 0;
}
static ssize_t key_drv_read (struct file *filp, char __user *buf, size_t cnt, loff_t *offt){
	//printk("----------------%s---------------\n",__FUNCTION__);
	int val,ret;
	struct newchrkey_dev *dev = filp->private_data;
		
	if(gpio_get_value(dev->key_gpio) == 0){//按键按下
		while(!gpio_get_value(dev->key_gpio));
		atomic_set(&dev->my_atomic,KEYVALUE);
	}else{
		atomic_set(&dev->my_atomic,INVAKEY);
	}
	val = atomic_read(&dev->my_atomic);
	ret = copy_to_user(buf,&val,sizeof(val));
	return ret;
}
static ssize_t key_drv_write (struct file *filp, const char __user *buf, size_t cnt, loff_t *offt){
	printk("----------------%s---------------\n",__FUNCTION__);
	return 0;
}
static int key_drv_release (struct inode *inod, struct file *filp){
	printk("----------------%s---------------\n",__FUNCTION__);
	atomic_inc(&newchrkey->my_atomic);
	return 0;
}	

static struct file_operations newchrkey_fops = {
	.owner = THIS_MODULE,
	.open = key_drv_open,
	.read = key_drv_read,
	.write = key_drv_write,
	.release = key_drv_release,
};

static int __init key_drv_init(void){
	printk("----------------%s---------------\n",__FUNCTION__);

	newchrkey = (struct newchrkey_dev *)kzalloc(sizeof(struct newchrkey_dev), GFP_KERNEL);
	if(newchrkey == NULL){
		printk("newchrkey kzalloc failed!!!\n");
		return -1;
	}

	atomic_set(&newchrkey->my_atomic,INVAKEY);
	
	int ret;
	//01.从设备树获取key的节点信息
	newchrkey->dev_nod = of_find_node_by_path("/gpio_key");
	if(newchrkey->dev_nod == NULL){
		printk("can not find gpio_key int dts!!\n");
		return -EINVAL;
	}else{
		printk("gpio_key have been found!!\n");
	}

	//02.获取gpio属性信息
	newchrkey->key_gpio = of_get_named_gpio(newchrkey->dev_nod, "key-gpio", 0);
	if(newchrkey->key_gpio < 0){
		printk("can not get key-gpio!!\n");
		return EINVAL;
	}
	printk("key_gpio = %d \n",newchrkey->key_gpio);

	/* 初始化key所使用的IO */
	//注意!!!!
	//gpio_request()使用过后,不用gpio_free()释放,当第二次insmod时会出现段错误。。
	//本人就犯了这个错误
	gpio_request(newchrkey->key_gpio, "--key");	/* 请求IO */

	//03.设置gpio为输入
	ret = gpio_direction_input(newchrkey->key_gpio);
	if(ret<0){
		printk("can not set gpio !!\n");
	}
	printk("gpio number have gotten!!\n");

	//注册字符设备驱动
	//1.向系统申请设备号
	if(newchrkey->major){
		newchrkey->devid = MKDEV(newchrkey->major, 0);
		register_chrdev_region(newchrkey->devid, 1, "Pf_key");
	}else{
		printk("register chrdev!!\n");
		/*犯过错误:一下函数的第一个参数没有取地址,在insmod时出现段错误*/
		alloc_chrdev_region(&newchrkey->devid, 0, 1, "Pf_key");
		
		newchrkey->major = MAJOR(newchrkey->devid);
		newchrkey->minor = MINOR(newchrkey->devid);
		printk(">>>>>>>>>>>register chrdev!!\n");
		
	}
	printk("major: %d ,minor: %d \n",newchrkey->major,newchrkey->minor);

	//2.初始化cdev
	newchrkey->cdev.owner = THIS_MODULE;
	cdev_init(&newchrkey->cdev, &newchrkey_fops);

	//3.添加一个cdev到系统
	cdev_add(&newchrkey->cdev, newchrkey->devid, 1);

	//4.创建一个设备
	newchrkey->cls = class_create(THIS_MODULE, "Pf_key");
	if(IS_ERR(newchrkey->cls)){
		return PTR_ERR(newchrkey->cls); 
	}
	newchrkey->device = device_create(newchrkey->cls, NULL, newchrkey->devid, NULL, "Pf_key");
	if(IS_ERR(newchrkey->device)){
		return PTR_ERR(newchrkey->device); 
	}
	return 0;
}

static void __exit key_drv_exit(void){
	printk("----------------%s---------------\n",__FUNCTION__);

	//注意!!!!
	//gpio_request()使用过后,不用gpio_free()释放,当第二次insmod时会出现段错误
	
	gpio_free(newchrkey->key_gpio);

	cdev_del(&newchrkey->cdev);
	unregister_chrdev_region(newchrkey->devid, 1);

	device_destroy(newchrkey->cls, newchrkey->devid);
	class_destroy(newchrkey->cls);

	kfree(newchrkey);
}

module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("PEIFENG");


key_app.c

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"

/* 定义按键值 */
#define KEYVALUE	0XF0
#define INVAKEY		0X00

/*
 * @description		: main主程序
 * @param - argc 	: argv数组元素个数
 * @param - argv 	: 具体参数
 * @return 			: 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
	int fd, ret;
	char *filename;
	int keyvalue;
	
	if(argc != 2){
		printf("Error Usage!\r\n");
		return -1;
	}

	filename = argv[1];

	/* 打开key驱动 */
	fd = open(filename, O_RDWR);
	if(fd < 0){
		printf("file %s open failed!\r\n", argv[1]);
		return -1;
	}

	/* 循环读取按键值数据! */
	while(1) {
		read(fd, &keyvalue, sizeof(keyvalue));
		if (keyvalue == KEYVALUE) {	/* KEY */
			printf("KEY Press, value = %#X\r\n", keyvalue);	/* 按下 */
		}
	}

	ret= close(fd); /* 关闭文件 */
	if(ret < 0){
		printf("file %s close failed!\r\n", argv[1]);
		return -1;
	}
	return 0;
}

[root@farsight drv_module]# insmod key_drv.ko
----------------key_drv_init---------------
gpio_key have been found!!
key_gpio = 18
Unable to handle kernel paging request at virtual address 7f0002f8
pgd = 88554000
[7f0002f8] *pgd=8877a811, *pte=00000000, *ppte=00000000
Internal error: Oops: 7 [#1] PREEMPT SMP ARM
Modules linked in: key_drv(O+) [last unloaded: key_drv]
CPU: 0 PID: 117 Comm: insmod Tainted: G           O    4.1.15 #5
Hardware name: Freescale i.MX6 Ultralite (Device Tree)
task: 8825a600 ti: 88788000 task.ti: 88788000
PC is at strnlen+0xc/0x54
LR is at string+0x30/0xec
pc : [<802b36e4>]    lr : [<802b49bc>]    psr: a0000093
sp : 88789ce8  ip : ffffffff  fp : 88789d18
r10: 88789dd0  r9 : 80820d74  r8 : 00000002
r7 : 0000ffff  r6 : 7f0002f8  r5 : 80c34b88  r4 : 80c347b3
r3 : ff0a0004  r2 : 7f0002f8  r1 : ffffffff  r0 : 7f0002f8
Flags: NzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 10c53c7d  Table: 8855406a  DAC: 00000015
Process insmod (pid: 117, stack limit = 0x88788210)
Stack: (0x88789ce8 to 0x8878a000)
9ce0:                   ff0a0004 80c347b3 80a0fdbf 80c34b88 80a0fdc1 802b6504
9d00: 80c34b88 ff0a0004 ffffffff ffffffff 80c347a8 000003e0 ff0a0004 ffffffff
9d20: 88789d5c 000003e0 ffffffff 00000000 80c33d58 00000000 80bf3e58 80c33d58
9d40: 00000000 802b6d38 80b8c9f0 8006b360 80bf3e58 80c347a8 88789d64 807f0858
9d60: 00000000 8006b570 00000000 00000000 60000013 00000000 00000000 00000000
9d80: 00000000 8006b7c4 880abd28 880d42d8 00000000 88746440 8008f96c 88747ec0
9da0: 00000326 8006b7e8 80a0fdb4 88789dcc 00000326 807ea9b8 8855d280 88789dcc
9dc0: fffffff0 802dc168 80a0fdb4 00000012 7f0002f8 808307c0 fffffff0 802dc7dc
9de0: 7f004574 8855d280 00000000 7f0060dc 7f006000 80b83698 80b83698 7f006000
9e00: 80b83698 80b83698 00000000 80009704 8bc658e0 88001f00 88747180 807eb708
9e20: 00000000 00000000 8040003e 800aeea8 80b83604 8bc65840 00000000 8040003e
9e40: 00000001 00000001 88789e5c 88001f00 000000d0 80b7f260 00000326 800e0eb8
9e60: 7f00441c 00000001 887463c0 7f004464 7f00441c 88747ec0 00000326 8009092c
9e80: 7f004464 7f00441c 88789f50 00000001 00000001 800924d0 7f004428 00007fff
9ea0: 8008ffcc 0000065f 80006830 00000000 8008f9e0 88789f50 001d2909 7f004564
9ec0: a0aa259c 00000000 00000000 7f004428 6e72656b 00006c65 00000000 00000000
9ee0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
9f00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
9f20: 00000000 80aa4770 00000000 00002212 017ea4f2 00000000 a0aa3212 001d2909
9f40: 88788000 00000000 00000000 800928bc a0aa1000 00002212 a0aa209c a0aa1f3b
9f60: a0aa2eec 00000578 000007c8 00000000 00000000 00000000 00000020 00000021
9f80: 00000018 00000015 00000013 00000000 00000000 7ec10e34 00000069 00000080
9fa0: 8000f644 8000f4c0 00000000 7ec10e34 017e82e0 00002212 001d2909 00000000
9fc0: 00000000 7ec10e34 00000069 00000080 7ec10e38 001d2909 7ec10e38 00000000
9fe0: 00000000 7ec10ab8 00038a9c 0000bc00 60000010 017e82e0 2001ebfe 0005e280
[<802b36e4>] (strnlen) from [<802b49bc>] (string+0x30/0xec)
[<802b49bc>] (string) from [<802b6504>] (vsnprintf+0x154/0x38c)
[<802b6504>] (vsnprintf) from [<802b6d38>] (vscnprintf+0xc/0x24)
[<802b6d38>] (vscnprintf) from [<8006b360>] (vprintk_emit+0xa0/0x504)
[<8006b360>] (vprintk_emit) from [<8006b7e8>] (vprintk_default+0x24/0x2c)
[<8006b7e8>] (vprintk_default) from [<807ea9b8>] (printk+0x70/0x88)
[<807ea9b8>] (printk) from [<802dc168>] (gpiod_request+0x74/0xdc)
[<802dc168>] (gpiod_request) from [<7f0060dc>] (key_drv_init+0xdc/0x264 [key_drv                                                                                        ])
[<7f0060dc>] (key_drv_init [key_drv]) from [<80009704>] (do_one_initcall+0x80/0x                                                                                        1d4)
[<80009704>] (do_one_initcall) from [<8009092c>] (do_init_module+0x58/0x1b0)
[<8009092c>] (do_init_module) from [<800924d0>] (load_module+0x1988/0x1c70)
[<800924d0>] (load_module) from [<800928bc>] (SyS_init_module+0x104/0x128)
[<800928bc>] (SyS_init_module) from [<8000f4c0>] (ret_fast_syscall+0x0/0x3c)
Code: e12fff1e e3510000 01a00001 012fff1e (e5d02000)
---[ end trace e331051ea7f3f506 ]---
note: insmod[117] exited with preempt_count 1
Segmentation fault

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值