Linux驱动开发之按键驱动

开发板原理图

 

设备树修改

 

按键驱动代码

#include "asm-generic/gpio.h"
#include <linux/wait.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/sched.h>
#define KEY_DOWN     0
#define KEY_UP       1
#define KEY_NAME  "key_dev"
#define KEY_NUM    1
struct mykey_dev{
	dev_t dev;
	int major;
	int minor;
	int gpio;
	struct class *class;
	struct cdev cdev;
	struct device *device;
	struct device_node *device_node;
	unsigned int irq;
	wait_queue_head_t rq_head;
	struct timer_list timer;
	unsigned char flags;
	unsigned char keyval;
};

static struct mykey_dev key_dev;
static void timer_function(unsigned long key){

	if(!gpio_get_value(key_dev.gpio)){
		if(key_dev.keyval == KEY_DOWN)
			key_dev.flags = 1;
	}else if(gpio_get_value(key_dev.gpio)){
		if(key_dev.keyval == KEY_UP)
			key_dev.flags = 1;
	}
	wake_up(&key_dev.rq_head);

}
static irqreturn_t interrupt_handel(int irq, void *dev_instance){

	key_dev.flags = 0;
	if (!gpio_get_value(key_dev.gpio)){
		key_dev.keyval = KEY_DOWN;
	}else{
		key_dev.keyval = KEY_UP;
	}
	mod_timer(&key_dev.timer, jiffies+HZ/50);
	// printk("IRQ interrupt handler for %d\n", irq);
	return IRQ_HANDLED;
}


int mykey_open(struct inode *node, struct file *filp){

	filp->private_data = &key_dev;

	return 0;
}

ssize_t mykey_read(struct file *filp, char __user *buff, size_t size, loff_t *offset){

	unsigned char val;
	struct mykey_dev *dev = (struct mykey_dev *)filp->private_data;

	if(!dev->flags){
		if(filp->f_flags & O_NONBLOCK){
			return -EINVAL;
		}else{
			wait_event(dev->rq_head, dev->flags);
		}
	}
	dev->flags = 0;
	val = dev->keyval;
	if(copy_to_user(buff, &val, size))
		return -EFAULT;
	return size;
}
ssize_t mykey_write(struct file *filp, const char __user *buff, size_t size, loff_t *offset){

	return 0;
}
int mykey_release(struct inode *node, struct file *filp){
	return 0;
}

static const struct file_operations mykey_fops = {
	.open = mykey_open,
	.read = mykey_read,
	.write = mykey_write,
	.release = mykey_release,
};

static int __init mykey_init(void)
{
	int ret;

	key_dev.major = 0;
	key_dev.flags = 0;
	key_dev.keyval = KEY_UP;
	if(key_dev.major){
		key_dev.dev = MKDEV(key_dev.major,0);
		ret = register_chrdev_region(key_dev.dev, KEY_NUM, KEY_NAME);
		if (ret)
			return -EINVAL;
	}else{
		ret = alloc_chrdev_region(&key_dev.dev, 0, KEY_NUM, KEY_NAME);
		if (ret)
			return -EINVAL;
	}

	cdev_init(&key_dev.cdev, &mykey_fops);
	ret = cdev_add(&key_dev.cdev, key_dev.dev, KEY_NUM);
	if (ret)
		goto unregister_chrdev;

	key_dev.class = class_create(THIS_MODULE, KEY_NAME);
	if (IS_ERR(key_dev.class)) {
		printk(KERN_ERR "class_create() failed for key_dev\n");
		ret = PTR_ERR(key_dev.class);
		goto unregister_cdev;
	}

	key_dev.device = device_create(key_dev.class, NULL, key_dev.dev, NULL, KEY_NAME);
	if (IS_ERR(key_dev.device)) {
		ret = PTR_ERR(key_dev.device);
		goto destroy_class;
	}

	key_dev.device_node = of_find_node_by_path("/key0");
	if (!key_dev.device_node) {
		pr_crit("could not find key node\n");
		goto destroy_dev;
	}

	key_dev.gpio = of_get_named_gpio(key_dev.device_node, "key-gpios", 0);
	if (!gpio_is_valid(key_dev.gpio)) {
		dev_err(key_dev.device, "no sensor key pin available\n");
		goto destroy_dev;
	}

	printk("gpio_id:%d\n",key_dev.gpio);
	ret = gpio_request(key_dev.gpio, "key");
	if(ret){
		printk("failed to request gpio %d\n", key_dev.gpio);
		goto destroy_dev;
	}

	gpio_direction_input(key_dev.gpio);

	init_waitqueue_head(&key_dev.rq_head);
	key_dev.irq = irq_of_parse_and_map(key_dev.device_node, 0);
	if (!key_dev.irq) {
		pr_warn("Key: unable to parse irq\n");
		goto gpio1_free;
	}

	init_timer(&key_dev.timer);
	key_dev.timer.expires = ~0;
	key_dev.timer.function = timer_function;
	add_timer(&key_dev.timer);
	ret = request_irq(key_dev.irq, interrupt_handel, IRQ_TYPE_EDGE_BOTH, "key_irq", &key_dev);
	if(ret){

		printk("Key request irq failed\n");	
		goto gpio1_free;
	}
	return 0;
gpio1_free:
	gpio_free(key_dev.gpio);
destroy_dev:
	device_destroy(key_dev.class, key_dev.dev);
destroy_class:
	class_destroy(key_dev.class);

unregister_cdev:
	cdev_del(&key_dev.cdev);

unregister_chrdev:
	unregister_chrdev_region(key_dev.dev, KEY_NUM);

	return -EINVAL;
} 

/* This function is called on driver exit */
static void __exit mykey_exit(void)
{
	del_timer(&key_dev.timer);
	free_irq(key_dev.irq, &key_dev);
	gpio_free(key_dev.gpio);
	device_destroy(key_dev.class, key_dev.dev);

	class_destroy(key_dev.class);

	cdev_del(&key_dev.cdev);

	unregister_chrdev_region(key_dev.dev, KEY_NUM);
} 

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

应用层测试代码

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

#define KEY_PATH "/dev/key_dev"
#define KEY_DOWN     0

int main(int argc, char *argv[])
{
	int ret,fd;
	unsigned char val = -1;
	fd = open(KEY_PATH, O_RDONLY);
	if(fd < 0){
		perror("open key_dev file");
		return EXIT_FAILURE;
	}

	while(1){
		ret =  read(fd, &val, 1);
		if(ret < 0){
			perror("read key_dev file");
			goto READ_ERR;
		}
		if(val == KEY_DOWN){
			printf("key_down\n");
		}else{
			printf("key_up\n");
		}
	}

READ_ERR:
	close(fd);
	return 0;
}

 

Makefile参考

 

ARCH = arch
CROSS_COMPILE = arm-linux-gnueabihf
CC = ${CROSS_COMPILE}-gcc
KERNELDIR := /home/linux_0
CURRENT_PATH := $(shell pwd)
	obj-m := mykey.o

build: kernel_modules

kernel_modules:

	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
	$(CC) -o key_test key_test.c
clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
	@rm key_test -f

开发板验证

拷贝到开发板进行验证,加载驱动,执行key_test后,按下按键打印key_down;松开按键打印key_up。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值