Linux按键输入实验

warren
2024-11-07 / 0 评论 / 3 阅读 / 正在检测是否收录...

原理分析

按键驱动和LED驱动一样,都是GPIO驱动。一个是读取GPIO的电平,一个是从GPIO输出高低电平。另外还有个区别,LED实验中,led资源只有驱动程序访问;但按键实验中,键值信息不但需要更新而且需要供应用程序读取。所以键值信息就需要用信号量来保护起来。

程序编写

设备树文件修改

添加pinctrl节点

  pinctrl_key: keygrp {
    fsl,pins = <
      MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0xF080 /* KEY0 */
    >;
  };

添加key设备节点

    key{
        #address-cell = <1>;
        #size-cells =  <1>;
        compatible = "warren-key";
        pinctrl-name = "default";
        pinctrl-0 = <&pinctrl_key>;
        key-gpio = <&gpio1 18 GPIO_ACTIVE_HIGH>;
        status = "okay";
    };

驱动程序编写

#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 KEY_CNT     1
#define KEY_NAME    "key"

#define KEY0VALUE   0xF0
#define INVAKEY     0x00

struct key_dev{
    dev_t               devid;
    struct cdev         cdev;
    struct class        *class;
    struct device       *device;
    int                 major;
    int                 minor;
    struct device_node  *nd;
    int                 key_gpio;
    atomic_t            keyvalue;
};

struct key_dev keydev;

static int keyio_init(void)
{
    int ret = 0;
    keydev.nd = of_find_node_by_path("/key");
    if(keydev.nd == NULL){
        return -EINVAL;
    }
    keydev.key_gpio = of_get_named_gpio(keydev.nd, "key-gpio", 0);
    if(keydev.key_gpio < 0){
        printk("can't get key0\r\n");
        return -EINVAL;
    }
    printk("key_gpio=%d\r\n", keydev.key_gpio);

    ret = gpio_request(keydev.key_gpio, "key0");
    gpio_direction_input(keydev.key_gpio);
    return 0;
}



static int key_open(struct inode *inode, struct file *filp)
{
    int ret = 0;
    filp->private_data = &keydev;
    ret = keyio_init();
    if(ret < 0){
        return ret;
    }
    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){
        while(gpio_get_value(dev->key_gpio) != 0);
        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)
{
    atomic_set(&keydev.keyvalue, INVAKEY);

    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);
    }

    keydev.cdev.owner = THIS_MODULE;
    cdev_init(&keydev.cdev, &key_fops);

    cdev_add(&keydev.cdev, keydev.devid, KEY_CNT);

    keydev.class = class_create(THIS_MODULE, KEY_NAME);
    if(IS_ERR(keydev.class)){
        return PTR_ERR(keydev.class);
    }
    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);
    unregister_chrdev_region(keydev.devid, KEY_CNT);

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

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

测试程序编写

#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

int main(int argc, int *argv[])
{
    int fd; 
    char *filename = NULL;
    char keyvalue = 0;
    int retvalue = 0;

    if(argc != 2){
        printf("error usage!\r\n");
        return -1;
    }
    filename = (char*)argv[1];
    fd = open(filename, O_RDWR);
    if(fd < 0){
        printf("file %s open failed\r\n", filename);
        return -1;
    }

    while(1) {
        read(fd, &keyvalue, sizeof(keyvalue));
        if(keyvalue == KEY0VALUE){
            usleep(1);
            if(keyvalue == KEY0VALUE){
                printf("key 0 press, value = %#x\r\n", keyvalue);
                while(1){
                    read(fd, &keyvalue, sizeof(keyvalue));
                    if(keyvalue != KEY0VALUE){
                        break;
                    }
                }
            }
        }
    }
    retvalue = close(fd);
    if(retvalue < 0){
        printf("file %s close failed\r\n", filename);
        return -1;
    }
    return 0;
}
0

评论 (0)

取消