Linux 按键输入实验

按键输入实验驱动程序

#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/slab.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/mach/map.h>

#include <linux/cdev.h>
#include <linux/device.h>

#include <linux/of.h>
#include <linux/of_address.h>

#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/timer.h>
#include <linux/ioctl.h>

#define KEY_CNT 1
#define KEY_NAME "key"
#define KEYVALUE 0XFE
#define KEYNOVALUE 0

struct key_dev {
    int major;
    int minor;
    dev_t devide;//设备号
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct device_node * bl_nd1;/*设备节点*/
    int key_gpio;/*属性编号*/
    atomic_t keyvalue;
};

struct key_dev key;
/*
 * @description		: 打开设备
 * @param - inode 	: 传递给驱动的inode
 * @param - filp 	: 设备文件,file结构体有个叫做private_data的成员变量
 * 					  一般在open的时候将private_data指向设备结构体。
 * @return 			: 0 成功;其他 失败
 */
 static int key_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &key; /* 设置私有数据 */
	printk("chrdevbase open!\r\n");
	return 0;
}

/*
 * @description		: 向设备写数据 
 * @param - filp 	: 设备文件,表示打开的文件描述符
 * @param - buf 	: 要写给设备写入的数据
 * @param - cnt 	: 要写入的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 写入的字节数,如果为负值,表示写入失败
 */
static ssize_t key_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
    struct key_dev *dev=(struct key_dev * )filp->private_data;
    int retvalue;
    unsigned char databuf[1];
    unsigned char ledstat;

    retvalue = copy_from_user(databuf, buf, cnt);
    if(retvalue < 0) {
        printk("kernel write failed!\r\n");
        return -EFAULT;
    }

    ledstat = databuf[0]; /* 获取状态值 */
    if(ledstat == 0) { 
       gpio_set_value(dev->key_gpio,0); /* 打开 LED 灯 */
    } else if(ledstat == 1) {
       gpio_set_value(dev->key_gpio,1); /* 关闭 LED 灯 */
    }
 
	return 0;
}


/*
 * @description		: 从设备读取数据 
 * @param - filp 	: 设备文件,表示打开的文件描述符
 * @param - buf 	: 要写给设备写入的数据
 * @param - cnt 	: 要写入的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 读取的字节数,如果为负值,表示读取失败
 */
static ssize_t key_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    struct key_dev *dev=(struct key_dev * )filp->private_data;
    int value;
    int ret;
    if(gpio_get_value(dev->key_gpio)==0){
        while(!gpio_get_value(dev->key_gpio));
        atomic_set(&key.keyvalue,KEYVALUE);
    }else{
        atomic_set(&key.keyvalue,KEYNOVALUE);
    }
    value=atomic_read(&dev->keyvalue);
    ret = copy_to_user(buf, &value, sizeof(value));
	return ret;
}


/*
 * @description		: ioctl函数,
 * @param - filp 	: 要打开的设备文件(文件描述符)
 * @param - cmd 	: 应用程序发送过来的命令
 * @param - arg 	: 参数
 * @return 			: 0 成功;其他 失败
 */
static long key_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	struct key_dev *dev =  (struct key_dev *)filp->private_data;
	
	return 0;
}

/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */
static int key_release(struct inode *inode, struct file *filp)
{
    struct key_dev *dev=(struct key_dev * )filp->private_data;
	printk("key release!\r\n");
	return 0;
}


static struct file_operations key_ops={
    .owner=THIS_MODULE,
    .open=key_open,
    .release=key_release,
    .write=key_write,
    .read=key_read,
    .unlocked_ioctl = key_unlocked_ioctl,
};


static int __init key1_init(void)
{
    
 
    /*key {
 			compatible = "atkalpha-key";
			pinctrl-names="default";
			pinctrl-0=<&pinctrl_key>; 
			cd-gpio=<&gpio1 18 GPIO_ACTIVE_LOW>;
 			status = "okay";	
 		};*/	

    int ret=0;

    /*获取设备节点*/
    key.bl_nd1=of_find_node_by_path("/key");
    if(key.bl_nd1==NULL)
    {
        printk("of_find_node_by_path failed\r\n");
        return -EINVAL;
    }
    /*获取设备cd-gpio属性的第一个GPIO编号*/
    key.key_gpio=of_get_named_gpio(key.bl_nd1,"cd-gpio",0);
    if(key.key_gpio<0)
    {
        printk("of_get_named_gpio failed\r\n");
        return -EINVAL;
    }

    /*申请一个GPIO管脚*/
    ret=gpio_request(key.key_gpio,"cd-gpio");
    if(ret==0){
        printk("gpio_requests success\n");
    }

    /*将GPIO设置为输出,默认输出高电平*/
    ret=gpio_direction_input(key.key_gpio);
    if(ret<0)
    {
        printk("gpio_direction_input failed\n");
    }

    /*注册设备号*/
    key.major=0;
    if(key.major){
        key.devide=MKDEV(key.major,0);
        register_chrdev_region(key.devide,KEY_CNT,KEY_NAME);
    }else{
        ret=alloc_chrdev_region(&key.devide, 0, KEY_CNT, KEY_NAME);	/* 申请设备号 */
		if(ret<0)
            {
                goto fail_devide;
            }
        key.major = MAJOR(key.devide);	/* 获取分配号的主设备号 */
		key.minor = MINOR(key.devide);	/* 获取分配号的次设备号 */
        printk("major=%d\n",key.major);
        printk("minor=%d\n",key.minor);
    }

     /*初始化cdev*/
    key.cdev.owner=THIS_MODULE;
    cdev_init(&key.cdev, &key_ops);
    
	
	/* 3、添加一个cdev */
	ret= cdev_add(&key.cdev, key.devide, KEY_CNT);
    if(ret<0)
        {
            goto fail_cdev;
        }

    //创建设备节点
	/* 4、创建类 */
	key.class = class_create(THIS_MODULE, KEY_NAME);
	if (IS_ERR(key.class)) {
		ret= PTR_ERR(key.class);
        goto fail_class;
	}

	/* 5、创建设备 */
	key.device = device_create(key.class, NULL, key.devide, NULL, KEY_NAME);
	if (IS_ERR(key.device)) {
		ret=PTR_ERR(key.device);
        goto fail_device;
	}  

    atomic_set(&key.keyvalue,KEYNOVALUE);
   

    return 0;
    fail_device:
        class_destroy(key.class);
    fail_class:
        cdev_del(&key.cdev);
    fail_cdev:
        unregister_chrdev_region(key.devide, KEY_CNT);
    fail_devide:
        return ret;
}

static void __exit key_exit(void)
{

    
    gpio_set_value(key.key_gpio,1);
    device_destroy(key.class,key.devide);
    
    class_destroy(key.class);
    cdev_del(&key.cdev);

    gpio_free(key.key_gpio);
    unregister_chrdev_region(key.devide, KEY_CNT);
    printk("exit\n");
    printk("exit\n");
}


/*模块的加载与卸载*/
module_init(key1_init);
module_exit(key_exit);


MODULE_LICENSE("GPL");
MODULE_AUTHOR("liuchuanqiang");

按键输入实验应用程序

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>

/*
argc:应用程序参数个数
argv[]:具体的参数内容,字符串形式,这个函数中的第一个参数内容./keyAPP;
       第二个参数内容filename;
执行文件格式:
    ./keyAPP /dev/key
*/


#define KEYVALUE 0XFE
#define KEYNOVALUE 0


int main(int argc,char *argv[])
{
    int ret=0;
    int fd=0;
    char *filename;
    int num;
    filename=argv[1];//一个字符串的声明

    printf("filename=%s\n",filename);
    if(argc!=2)
    {
        printf("error\n");
        return -1;
    }
    //打开文件
    fd=open(filename, O_RDWR);
    //判断有没有打开成功
    if(fd<0)
    {
        printf("open failed\r\n");
        return -1;
    }


    while(1){
        read(fd,&num,sizeof(num));
        if(num==KEYVALUE){
            printf("按键值:%#x\n",num);
        }
        
    }
    

//关闭文件
        ret=close(fd);
        if(ret<0)
        {
            printf("close failed\r\n");
            return -1;
        }
   
    return 0;
}

程序说明:

  1. 在设备树中加入按键key的GPIO信息,将key使用的GPIO设置为输入。

pinctrl_key: keygrp {

fsl,pins = <

MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0xF080 /* KEY0 */

>;

};

key {

  compatible = "atkalpha-key";

pinctrl-names="default";

pinctrl-0=<&pinctrl_key>;

cd-gpio=<&gpio1 18 GPIO_ACTIVE_LOW>;

  status = "okay";

  };

        2.在文件操作函数的 key_read函数中写入读取按键值的程序 copy_to_user(buf, &value, sizeof(value));将按键的读取值value传递给buf。

        3.程序其他部分与其他GPIO的输入输出程序相同。

        4、将按键值设置成原子变量,因为按键值是共享资源。

                原子变量使用atomic_set();//设置值;

                atomic_read();//读取值

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值