9.Linux按键驱动-工作队列

在这里插入图片描述
在这里插入图片描述
1.思路
1.1在gpio结构体中定义工作队列
在这里插入图片描述
1.2 在probe函数中初始化工作队列
在这里插入图片描述
1.3.在中断服务程序中调度工作队列
在这里插入图片描述
1.4工作队列处理函数:
在这里插入图片描述

2.编程
程序:

#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>
#include <linux/poll.h>
#include <linux/fcntl.h>/* 定义结构体来描述gpio */
struct gpio_key{int gpio;struct gpio_desc* gpiod;int flag;int irq;struct timer_list key_timer;struct tasklet_struct tasklet;struct work_struct work;
};/* 定义全局变量来存储设备树中的所有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);
struct fasync_struct * button_fasync;/* 环形缓冲区 */
#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;if(is_key_buf_empty() && (fp->f_flags & O_NONBLOCK)){return -EAGAIN;}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;//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return 4;
}static unsigned int gpio_poll(struct file *fp, struct poll_table_struct *wait)
{//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);poll_wait(fp, &gpio_key_wait, wait);return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
}static int gpio_fasync(int fd , struct file *file, int on)
{//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);if (fasync_helper(fd, file, on, &button_fasync) >= 0){return 0;}else{return -EIO;}
}static const struct file_operations gpio_fops = {.owner = THIS_MODULE,.read  = gpio_read,.poll  = gpio_poll,.fasync = gpio_fasync,
};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);/* 发信号 *///kill_fasync(&button_fasync, SIGIO, POLL_IN);//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);/* 调度tasklet函数 */tasklet_schedule(&gpio_key->tasklet);/* 调度工作队列 */schedule_work(&gpio_key->work);/* 修改定时器超时时间 */printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);mod_timer(&gpio_key->key_timer, jiffies + HZ / 5);return IRQ_HANDLED;
}/* 定时器超时函数 */
static void key_timer_expire(unsigned long arg)
{struct gpio_key* gpio_key = arg;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);/* 发信号 */kill_fasync(&button_fasync, SIGIO, POLL_IN);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);/* 修改定时器超时时间 *///mod_timer(&gpio_key->key_timer, jiffies + HZ / 5);
}/* tasklet处理函数 */
static void key_tasklet_func(unsigned long data)
{struct gpio_key* key = data;int val;val = gpio_get_value(key->gpio);//printk("进入了tasklet函数\n");printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);//printk("key %d value is %d\n", key->gpio, val);
}/* 工作队列对应的处理函数 */
static void key_work_func(struct work_struct *work)
{printk("进入了工作队列中\n");printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
}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");}/* 设置定时器 */setup_timer(&gpio_keys_100ask[i].key_timer, key_timer_expire, &gpio_keys_100ask[i]);//设置定时器超时时间为无穷gpio_keys_100ask[i].key_timer.expires = ~0;/* 添加定时器 */add_timer(&gpio_keys_100ask[i].key_timer);/* 初始化tasklet */tasklet_init(&gpio_keys_100ask[i].tasklet, key_tasklet_func, &gpio_keys_100ask[i]);/* 初始化工作队列 */INIT_WORK(&gpio_keys_100ask[i].work, key_work_func);}/* 注册字符设备 */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");

3.实验结果
在这里插入图片描述
4.代码路径:

/home/book/nfs_rootfs/CSDN/01_gpio_irq/09_read_key_irq_poll_fasync_block_timer_tasklet_workqueue

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/58019.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于微信小程序实现信阳毛尖茶叶商城系统设计与实现

作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参与学生毕业答辩指导&#xff0c;…

xtu 哈希

样例输入# 2 2 1 2 4 1 3 5 7 样例输出# 2 3解题思路&#xff1a;欧拉筛素数 满足题意的素数值一定是从n/2开始的。原因&#xff1a;因为每个哈希函数值最多冲突一次&#xff0c;也就是一个哈希值最多出现2次&#xff0c;最坏的情况&#xff0c;数组中所有哈希值都出现2次&…

【判断推理】逻辑论证之一般质疑

不明确选项&#xff1a;表述不够明确&#xff0c;属于既不能加强、也不能削弱的选项 5.1 无论据有结论的一般质疑 无论据有结论&#xff1a;题干往往由“背景、分析、结论”&#xff0c;用提出反向论据的方式反驳论点。 这类题挺简单的&#xff0c;注意话题一致、主题正确&am…

手机拍证件照,换正装有领衣服及底色的方法

证件照在我们的职业生涯的关键节点是经常会用到的&#xff0c;比如毕业入职、人事档案建立、升迁履历、执业资格考试和领证等&#xff0c;这些重要的证件照往往要求使用正装照&#xff0c;有时候手头没有合适的衣服&#xff0c;或者原先的证件照背景色不符合要求&#xff0c;就…

【Fargo】18:camera获取及预览

QCameraViewfinder.ui Build started at 0:10... 1>------ Build started: Project: Fargo, Configuration: Debug Win32 ------

acaconda基础指令(实用不罗嗦,持续更新)

查看conda版本 conda --version 更新acaconda conda update Anaconda 查看有哪些虚拟环境&#xff08;三条均可&#xff09; conda env listconda info -econda info --envs 创建虚拟环境 conda create -n env_name python3.8 激活虚拟环境 conda activate env_name …

Python图像处理——基于ResNet152的人脸识别签到系统(Pytorch框架)

&#xff08;1&#xff09;数据集制作 本次使用明星做为数据集&#xff0c;首先编写爬虫函数&#xff0c;根据关键字爬取对应的明星&#xff0c;爬取结果保存至data文件夹&#xff0c;并以标签名作为文件名。具体爬取的明星如下&#xff1a; 注&#xff1a;实际应用中&#xf…

【thinkphp8】00005 thinkphp8 Db::table和Db::name的区别

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【th…

FreeRTOS 6:任务创建函数xTaskCreate分析

动态创建任务xTaskCreate xTaskCreate 1、申请堆栈内存&#xff08;返回首地址&#xff09; 2、申请任务控制块内存&#xff08;返回首地址&#xff09; 3、把前面申请的堆栈地址&#xff0c;赋值给控制块的堆栈成员 4、调用prvlnitialiseNewTask初始化任务控制块中的成员 …

linux系统安全:开源的反病毒工具ClamAV的安装配置使用和维护介绍

目录 一、概述 1、开发者 2、功能 3、特性 二、安装ClamAV 1、更新系统包列表 2、安装ClamAV 三、更新病毒库 四、配置ClamAV 1、编辑ClamAV配置文件 2、主要配置选项 &#xff08;1&#xff09;/etc/clamd.conf &#xff08;2&#xff09; /etc/freshclam.conf …

windows下安装python库wordCloud报错

换电脑安装wordcloud半天安装失败&#xff0c;记录一下遇到的坑&#xff0c;也给大家节省点时间。 方法1&#xff1a; 错误呢就是下面这个&#xff0c;说没c编译器&#xff0c;要不就去他给的地址上安装一下&#xff0c;我安装了一下好像没什么选&#xff0c;也没太敢勾选吗&a…

2025 - AI人工智能药物设计 - 中药网络药理学和毒理学的研究

中药网络药理学和毒理学的研究 TCMSP&#xff1a;https://old.tcmsp-e.com/tcmsp.php 然后去pubchem选择&#xff1a;输入Molecule Name 然后进行匹配&#xff1a;得到了smiles 再次通过smiles&#xff1a;COC1C(CC(C2C1OC(CC2O)C3CCCCC3)O)O 然后再次输入&#xff1a;http…

C语言基础(五)【控制语句与循环(上)学习篇】

文章目录 前言一、if - else 语句二、switch-case 语句三、while 循环四、for 循环五、do - while 循环六、break 语句七、continue 语句八、go to 语句总结 前言 C语言是结构化的程序设计语言&#xff0c;这里的结构指的是顺序结构、选择结构、循环结构&#xff0c;因此提供了…

中国人寿财险青岛市分公司:科技赋能,车险服务再升级

中国人寿财险青岛市分公司积极响应国家号召&#xff0c;大力推进车险综合改革&#xff0c;以科技赋能车险服务&#xff0c;实现服务再升级。公司利用AI技术&#xff0c;实现车险报案的自动化处理&#xff0c;大幅缩短了理赔周期。同时&#xff0c;公司还通过大数据分析&#xf…

【力扣】[Java版] 刷题笔记-101. 对称二叉树

题目&#xff1a;101. 对称二叉树 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 解题思路 可以理解为遍历对比&#xff0c;最简单的方法就是递归。 解题过程 递归&#xff1a;左右子树分开遍历&#xff0c;左子树遵循根、左、右的顺序&#xff0c;右子树循…

重学SpringBoot3-Spring WebFlux之SSE服务器发送事件

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ Spring WebFlux之SSE服务器发送事件 1. 什么是 SSE&#xff1f;2. Spring Boot 3 响应式编程与 SSE为什么选择响应式编程实现 SSE&#xff1f; 3. 实现 SSE 的基本步骤3.…

(三)第一个Qt程序“Qt版本的HelloWorld”

一、随记 我们在学习编程语言的时候&#xff0c;各种讲解编程语言的书籍中通常都会以一个非常经典的“HelloWorld”程序展开详细讲解。程序虽然简短&#xff0c;但是“麻雀虽小&#xff0c;五脏俱全”&#xff0c;但是却非常适合用来熟悉程序结构、规范&#xff0c;快速形成对编…

技术杂谈与进阶01--------战时操作系统与国产化数据库 |截止到目前修改时间,本文已上全站综合热榜

写文不易 给我点点关注 和点点赞 点点收藏吧 目录 为什么国产化&#xff1f; 操作系统 suse 统信uos 的阉割版 deepin &#xff08;deepin又名深度操作系统&#xff09; 麒麟 的阉割版 -欧拉 debian 的修改残版 ubuntu 国产数据库 开源数据库 部分开源数据库 …

uniapp使用uni-push模拟推送

uniapp使用uni-push模拟推送 第一步先去uniapp开发者中心添加开通uni-push功能 这里的Android 应用签名可以先用测试的官网有,可以先用这个测试 官方测试链接文档地址 在项目中的配置文件勾选 组件中使用 如果要实时可以去做全局ws //消息推送模版uni.createPushMessage(…

人工智能进程;算子加速的具体计算部分;大模型GPT5:参数18万亿;大模型面临问题

目录 人工智能进程 算子加速的简单理解,举例说明 一、简单理解 二、举例说明 一、算子加速的具体计算部分 二、举例说明 三、算子加速是否仅针对GPU 大模型GPT5:参数18万亿 大模型面临问题 算力集群设计框架 人工智能进程