使用F1C200S从零制作掌机之按键输入

使用PE3测试按键,使用10k电阻上拉,按键按下接地。

设备树:

&pio {
        key_pins: key-pins{
                pins = "PE3";
                function = "gpio_in";
        };
};
/ {
        my_key: my-key{
                status = "okay";
                compatible = "allwinner,sunxi-pinctrl-key";
                pinctrl-names = "default";
                pinctrl-0 = <&key_pins>;
                key-gpios = <&pio 4 3 GPIO_ACTIVE_HIGH>;
        };
};

设备树检查:

ls /proc/device-tree/my-key/

驱动程序:

#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 <asm/mach/map.h> 
#include <asm/uaccess.h> 
#include <asm/io.h> 
#include <linux/of.h> 
#include <linux/of_address.h>
#include <linux/platform_device.h> 
#include <linux/of_gpio.h>
#include <linux/semaphore.h>

#define KEY_CNT 1      /* 设备号个数 */ 
#define KEY_NAME "key" /* 名字 */ 
#define KEY0VALUE 0xF0 /*  按键值 */ 
#define INVAKEY   0x00 /* 无效的按键值 */ 

/* key_dev 设备结构体 */ 
struct key_dev{ 
	dev_t devid; /* 设备号 */ 
	struct cdev cdev; /* cdev */ 
	struct class *class; /* 类 */
	struct device *device; /* 设备 */ 
	int major; /* 主设备号 */ 
	int minor; /* 次设备号 */ 
	struct device_node *nd; /* 设备节点 */
	int key_gpio; /* key 所使用的 GPIO 编号 */
	atomic_t keyvalue; /* 按键值 */
}; 

struct key_dev keydev; /* key 设备 */ 

static int keyio_init(void)
{
	keydev.nd = of_find_node_by_path("/my-key");
	if (keydev.nd== NULL) {
		printk("my_key node can not found!\r\n");
		return -EINVAL;
	}

	keydev.key_gpio = of_get_named_gpio(keydev.nd ,"key-gpios", 0);
	if (keydev.key_gpio < 0) {
		printk("can't get key0\r\n");
		return -EINVAL;
	}
	printk("key_gpio=%d\r\n", keydev.key_gpio);

	/* 初始化 key 所使用的 IO */
	gpio_request(keydev.key_gpio, "key0"); /* 请求 IO */
	gpio_direction_input(keydev.key_gpio); /* 设置为输入 */
	return 0;
}

static int key_open(struct inode *inode, struct file *filp) 
{ 
	filp->private_data = &keydev; /* 设置私有数据 */ 
	return 0; 
}

static ssize_t key_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
	int ret = 0;
	unsigned char value;
	struct key_dev *dev = filp->private_data;

	if (gpio_get_value(dev->key_gpio) == 0) { /* key0 按下 */
		while(!gpio_get_value(dev->key_gpio)); /* 等待按键释放 */
		atomic_set(&dev->keyvalue, KEY0VALUE);
	} else { /* 无效的按键值 */
		atomic_set(&dev->keyvalue, INVAKEY);
	}

	value = atomic_read(&dev->keyvalue); /* 保存按键值 */
	ret = copy_to_user(buf, &value, sizeof(value));
	return ret;
}

/* 设备操作函数 */ 
static struct file_operations key_fops = { 
	.owner = THIS_MODULE, 
	.open = key_open, 
	.read = key_read, 
};

static int __init mykey_init(void) 
{
    int ret;

	/* 初始化原子变量 */
	atomic_set(&keydev.keyvalue, INVAKEY);
	
	/* 获取设备树中的属性数据 */
	ret = keyio_init();   /* 初始化按键 IO */
	if (ret < 0) {
		return ret;
	}
	
	/* 注册字符设备驱动 */ 
	/* 1、创建设备号 */ 
	if (keydev.major) { /* 定义了设备号 */ 
		keydev.devid = MKDEV(keydev.major, 0); 
		register_chrdev_region(keydev.devid, KEY_CNT, KEY_NAME); 
	} else { /* 没有定义设备号 */ 
		alloc_chrdev_region(&keydev.devid, 0, KEY_CNT, KEY_NAME); /* 申请设备号 */ 
		keydev.major = MAJOR(keydev.devid); /* 获取主设备号 */ 
		keydev.minor = MINOR(keydev.devid); /* 获取次设备号 */ 
	} 
	printk("keydev major=%d, minor=%d\r\n",keydev.major, keydev.minor); 
	
	/* 2、初始化 cdev */ 
	keydev.cdev.owner = THIS_MODULE; 
	cdev_init(&keydev.cdev, &key_fops); 
	
	/* 3、添加一个 cdev */ 
	ret = cdev_add(&keydev.cdev, keydev.devid, KEY_CNT); 
	
	/* 4、创建类 */ 
	keydev.class = class_create(THIS_MODULE, KEY_NAME); 
	if (IS_ERR(keydev.class)) { 
		return PTR_ERR(keydev.class);
	}
	
	/* 5、创建设备 */ 
	keydev.device = device_create(keydev.class, NULL, keydev.devid, NULL, KEY_NAME); 
	if (IS_ERR(keydev.device)) { 
		return PTR_ERR(keydev.device);
	}

    return 0;
}

static void __exit mykey_exit(void) 
{ 
	/* 注销字符设备 */ 
	cdev_del(&keydev.cdev);/* 删除 cdev */ 
	unregister_chrdev_region(keydev.devid, KEY_CNT); 

	device_destroy(keydev.class, keydev.devid); 
	class_destroy(keydev.class); 
	
	gpio_free(keydev.key_gpio);
} 

module_init(mykey_init); 
module_exit(mykey_exit); 
MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("wangxinchen");

测试程序:

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

#define KEY0VALUE 0XF0
#define INVAKEY 0X00

int main(int argc, char *argv[])
{
    int fd, ret;
    char *filename;
    unsigned char 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 == KEY0VALUE) { /* KEY0 */
            printf("KEY0 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@buildroot: /lib/modules/5.2/key/test]$./keyApp /dev/key
KEY0 Press, value = 0XF0
KEY0 Press, value = 0XF0
KEY0 Press, value = 0XF0
KEY0 Press, value = 0XF0
KEY0 Press, value = 0XF0
KEY0 Press, value = 0XF0
KEY0 Press, value = 0XF0
KEY0 Press, value = 0XF0
KEY0 Press, value = 0XF0
KEY0 Press, value = 0XF0
KEY0 Press, value = 0XF0
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值