当前位置: 首页 > article >正文

3.Linux按键驱动-添加循环队列

问题:

采用全局变量g_key存储按键值时,会导致部分按键值丢失,在本节中采用循环队列来读取按键值。

1.添加环形缓冲区的代码

/* 环形缓冲区 */
#define BUF_LEN 128
static int g_keys[BUF_LEN];
static int r, w;

#define NEXT_POS(x) ((x+1) % BUF_LEN)

int is_key_buf_empty(void)
{
	return (r == w);
}

int is_key_buf_full(void)
{
	return (r == NEXT_POS(w));
}

void put_key(int key)
{
	if (!is_key_buf_full())
	{
		g_keys[w] = key;
		w = NEXT_POS(w);
	}
}

int get_key(void)
{
	int key = 0;
	if (!is_key_buf_empty())
	{
		key = g_keys[r];
		r = NEXT_POS(r);
	}
	return key;
}

2.在中断服务程序中,记录按键值,并且唤醒等待队列。在这里插入图片描述
3.在open函数中,等待条件变量。当获得条件变量时,判断条件是否为真,为真时,将数据从内核空间拷贝到用户空间。
在这里插入图片描述
4.代码

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>


/* 定义结构体来描述gpio */
struct gpio_key{
	int gpio;
	struct gpio_desc* gpiod;
	int flag;
	int irq;
};

/* 定义全局变量来存储设备树中的所有gpio节点信息 */
static struct gpio_key* gpio_keys_100ask;

/* 字符设备的主设备号 */
static unsigned int major = 0;
static struct class *gpio_class;
//static int g_key = 0;

/* 定义等待队列 */
static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);


/* 环形缓冲区 */
#define BUF_LEN 128
static int g_keys[BUF_LEN];
static int r, w;

#define NEXT_POS(x) ((x+1) % BUF_LEN)

int is_key_buf_empty(void)
{
	return (r == w);
}

int is_key_buf_full(void)
{
	return (r == NEXT_POS(w));
}

void put_key(int key)
{
	if (!is_key_buf_full())
	{
		g_keys[w] = key;
		w = NEXT_POS(w);
	}
}

int get_key(void)
{
	int key = 0;
	if (!is_key_buf_empty())
	{
		key = g_keys[r];
		r = NEXT_POS(r);
	}
	return key;
}

static ssize_t gpio_read(struct file *fp, char __user *buf, size_t size, loff_t * offset)
{
	int err;
	int key;
	wait_event_interruptible(gpio_key_wait, !is_key_buf_empty());
	key = get_key();
	//err = copy_to_user(buf, &g_key, 4);
	err = copy_to_user(buf, &key, 4);
	//g_key = 0;
	return 4;
}

static const struct file_operations gpio_fops = {
	.owner = THIS_MODULE,
	.read  = gpio_read,
};

static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{
	struct gpio_key* gpio_key = dev_id;
	int val;
	int key;
	val = gpio_get_value(gpio_key->gpio);
	//printk("key %d %d\n", gpio_key->gpio, val);
	//g_key = (gpio_key->gpio << 8) | val;
	key = (gpio_key->gpio << 8) | val;
	
	put_key(key);
	wake_up_interruptible(&gpio_key_wait);
	return IRQ_HANDLED;
}

static int gpio_probe(struct platform_device *pdev)
{
	int count, i;
	struct device_node *node;
	int err;

	node = pdev->dev.of_node;
	count = of_gpio_count(node);
	if (!count)
	{
		printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);
		return -1;
	}
	
	/* 申请资源 */
	gpio_keys_100ask = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);
	if (!gpio_keys_100ask)
	{
		printk("kzalloc error\n");
		return -1;
	}

	/* 获得资源 */
	for (i = 0; i < count; i++)
	{
		gpio_keys_100ask[i].gpio = of_get_gpio(node, i);
		if (gpio_keys_100ask[i].gpio < 0)
		{
			printk("%s %s line %d, of_get_gpio_flags fail\n", __FILE__, __FUNCTION__, __LINE__);
			return -1;
		}
		gpio_keys_100ask[i].gpiod = gpio_to_desc(gpio_keys_100ask[i].gpio);
		gpio_keys_100ask[i].irq   = gpio_to_irq(gpio_keys_100ask[i].gpio);

		/* 申请中断 */
		err = request_irq(gpio_keys_100ask[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "test1_gpio_keys_100ask", &gpio_keys_100ask[i]);
		if (err) 
		{
			printk("request_irq err\n");
		}
	}

	/* 注册字符设备 */
	major = register_chrdev(major, "100ask_key", &gpio_fops);
	if(major < 0)
	{
		printk("register_chrdev err'\n");
		return -1;
	}

	/* 注册类 */
	gpio_class = class_create(THIS_MODULE, "100ask_key_class");

	/* 注册设备 */
	device_create(gpio_class, NULL, MKDEV(major,0), NULL, "100ask_key_button");
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

static int gpio_remove(struct platform_device *pdev)
{
	int count, i;
	struct device_node *node;

	node = pdev->dev.of_node;
	count = of_gpio_count(node);
	device_destroy(gpio_class, MKDEV(major,0));
	class_destroy(gpio_class);
	unregister_chrdev(major, "100ask_key");

	for (i = 0; i < count; i++)
	{
		free_irq(gpio_keys_100ask[i].irq, &gpio_keys_100ask[i]);
	}
	kfree(gpio_keys_100ask);
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}


/*
* 在设备树中添加的节点的compatible属性为:"test1_100ask,test1_gpio_key"
*/
static const struct of_device_id gpio_key_of_match[] = {
	{.compatible = "test1_100ask,test1_gpio_key"},
	{/* 这里必须要有一个空项,表示结束 */}
};

static struct platform_driver gpio_driver = {
	.driver = {
		.name	= "test1_gpio_keys_100ask",
		.of_match_table = gpio_key_of_match,
	},
	.probe	= gpio_probe,
	.remove = gpio_remove,
};

/* 基于platform总线来实现这个程序 */
static int gpio_init(void)  
{
	int ret;

	ret = platform_driver_register(&gpio_driver);
	if (ret != 0)
	{
		printk("platform_driver_register err\n");
		return -1;
	}
	else
	{
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	}
	return ret;
}

static void gpio_exit(void)
{
	platform_driver_unregister(&gpio_driver);
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
}

module_init(gpio_init);
module_exit(gpio_exit);
MODULE_LICENSE("GPL");

5.代码路径:

/home/book/nfs_rootfs/CSDN/01_gpio_irq/03_read_key_irq_circle_buffer

http://www.kler.cn/news/367872.html

相关文章:

  • B端产品常用组件及设计规则 原型图 Axure原型图 交互设计
  • 智能工厂的软件设计 专有名词(juncture/relation/selection):意识形态及认知计算机科学的架构、系统和运用
  • VIVO售后真好:屏幕绿线,4年免费换屏
  • 蓝桥杯第二十场小白入门赛
  • 基于单目视觉目标识别与定位测距原型系统
  • 第二十六节 直方图均衡化
  • 【Android】多渠道打包配置
  • Android 自定义 Dialog 实现列表 单选,多选,搜索
  • Python4
  • 大学新生如何入门编程:选择语言、制定计划及避开学习陷阱
  • Page Cache(页缓存
  • 学习记录:js算法(七十五): 加油站
  • 【C++】异常处理实例详解
  • 探索Spring Boot:构建高性能论坛网站
  • java游戏第六天——总结
  • js中for...in 和 for...of 区别
  • Elasticsearch 与 Lucene 的区别和联系
  • 【动态规划】力扣509. 斐波那契数
  • 基于neo4j关系图谱的协同过滤科研推荐系统
  • Redis 淘汰策略 问题
  • 软考:GPU算力,AI芯片
  • OCR经典神经网络(三)LayoutLM v2算法原理及其在发票数据集上的应用(NER及RE)
  • 【Android】Kotlin教程(6)
  • 算法设计与分析:贪心算法思想的应用
  • Redisson(三)应用场景及demo
  • HTML+CSS实现超酷超炫的3D立方体相册