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

6.Linux按键驱动-阻塞与非阻塞

默认打开文件时候是阻塞的

当设置打开方式为非阻塞时,无数据时会返回。
当设置打开方式为阻塞时,无数据的时候会等待

1.设置打开方式为非阻塞
在这里插入图片描述
立即返回,无法读出,返回-1
在这里插入图片描述

2.设置为阻塞
在这里插入图片描述

核心在于驱动程序中的.read函数的支持
在这里插入图片描述

3.代码实现
应用程序:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <signal.h>static int fd;/* 信号处理函数 */
/*static void sig_func(int sig)
{int val;int num;read(fd,&val,4);num  = val >>8;printf("get button: %d val = %d\n", num, val - num *(1 << 8));
}*/int main(int argc, char** argv)
{int val;int num;struct pollfd fds[1];int timeout_ms = 5000;int ret;int flags;int i;/* 判断输入值是否合法 */if(argc != 2){printf("Usage ./button_app /dev/devname\n");return -1;}fd = open(argv[1], O_RDONLY);if (fd == -1){printf("open err\n");}else{printf("open success\n");}/* 初始化文件监听描述符 *//*fds[0].fd     = fd;fds[0].events = POLLIN;*//*绑定SIGIO和sig_func *///signal(SIGIO, sig_func);/* APP把自己的pid告诉驱动 *///fcntl(fd, F_SETOWN, getpid());/* APP把自己的pid告诉驱动程序 *///flags = fcntl(fd,F_GETFL);/* 获得标志位 *///fcntl(fd, F_SETFL, flags | FASYNC);/* 使能异步通知 *///printf("设置了FASYNC\n");/*while(1){printf("www.100ask.net \n");sleep(2);}*//*while(1){ret = poll(fds, 1, timeout_ms);if((ret == 1) && (fds[0].revents == POLLIN)){read(fd, &val, 4);num  = val >>8;printf("get button: %d val = %d\n", num, val - num *(1 << 8));}else{printf("timeout\n");}}*//* 设置打开方式为非阻塞 */fcntl(fd,F_SETFL,O_NONBLOCK);for (i = 0; i < 10; i++){if (read(fd, &val, 4) == 4)printf("get button: 0x%x\n", val);elseprintf("get button: -1\n");}/* 设置打开方式为阻塞 */flags = fcntl(fd,F_GETFL);fcntl(fd,F_SETFL,flags & ~O_NONBLOCK);while(1){if (read(fd, &val, 4) == 4){num  = val >>8;printf("get button: %d val = %d\n", num, val - num *(1 << 8));}elseprintf("get button: -1\n");}close(fd);return 0;
}

驱动程序:

#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;
};/* 定义全局变量来存储设备树中的所有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__);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");

4.代码路径:

/home/book/nfs_rootfs/CSDN/01_gpio_irq/06_read_key_irq_poll_fasync_block

相关文章:

6.Linux按键驱动-阻塞与非阻塞

默认打开文件时候是阻塞的 当设置打开方式为非阻塞时&#xff0c;无数据时会返回。 当设置打开方式为阻塞时&#xff0c;无数据的时候会等待1.设置打开方式为非阻塞 立即返回&#xff0c;无法读出&#xff0c;返回-1 2.设置为阻塞 核心在于驱动程序中的.read函数的支持 …...

Mac打开环境变量配置文件,source ~/.zshrc无法打开问题解决

本文将会介绍&#xff0c;Mac如何打开zshrc环境变量配置文件。 在搭建开发环境的时候&#xff0c;通常我们需要配置环境变量&#xff0c;例如&#xff1a;ANDROID_HOME、nvm等。 具体的做法是把配置环境变量的命令加入到 shell 的配置文件中。如果你的 shell 是 zsh&#xff…...

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-23

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-23 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-23目录1. Advancements in Visual Language Models for Remote Sensing: Datasets, Capabilities, and Enhancement Techniques摘…...

【C#】搭建环境之CSharp+OpenCV

在我们使用C#编程中&#xff0c;对图片处理时会用到OpenCV库&#xff0c;以及其他视觉厂商提供的封装库&#xff0c;这里因为OpenCV是开源库&#xff0c;所以在VS资源里可以直接安装使用&#xff0c;这里简单说明一下搭建的步骤及实现效果&#xff0c;留存。 1. 项目创建 1.1…...

100种算法【Python版】第25篇——Bidirectional Search算法

本文目录 1 算法原理2 路径计算的算法步骤3 python代码4 算法应用1 算法原理 Bidirectional Search(双向搜索)算法是为了解决图中最短路径问题而提出的一种搜索策略,旨在提高搜索效率。该算法的核心思想是同时从起点和终点进行搜索,直到两个搜索相遇。这种方法有效地减少了…...

WebSocket与Socket

一、定义与用途 Socket Socket&#xff08;套接字&#xff09;是一个抽象层&#xff0c;用于在网络上执行进程间的通信。它为应用程序提供了发送和接收数据的机制&#xff0c;通过IP和端口号来标识网络中唯一的位置。Socket可以使用TCP进行面向连接的可靠通信&#xff0c;也可以…...

Python 3 维护有序列表 bisect

在Python 3中&#xff0c;bisect模块提供了用于维护有序列表的函数&#xff0c;主要用于在有序序列中进行二分查找以及插入操作&#xff0c;以下是其常见用法的介绍&#xff1a; 1. 导入模块 首先需要导入bisect模块&#xff1a; import bisect2. 主要函数及用法 bisect.bi…...

vue版本太低无法执行vue ui命令

连接 ui和create目前都只支持3.0以后得版本才能使用 https://blog.csdn.net/m0_67318913/article/details/136775252?utm_mediumdistribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-136775252-blog-121204604.235v43pc_blog_bottom_relevance…...

数据结构 之 二叉树的遍历------先根遍历(五)

提示&#xff1a;本篇章主要讲解数据结构中树的相关知识。 文章目录 二叉树的遍历为什么要提出这么多遍历方法&#xff1f;先根遍历二叉树&#xff08;TLR&#xff09;先根遍历二叉树的递归算法&#xff08;重点&#xff09;先根遍历二叉树的非递归算法(了解&#xff0c;但是得…...

Xss_less靶场攻略(1-18)

xss-lab-less1 ur特殊字符转义 存在url中 转义符为 %2B& 转义符为 %26空格 转义符为 或 %20/ 转义符为 %2F? 转义符为 %3F% 转义符为 %25#转义符为 %23 转义符为 %3Dimg 标签懒加载 在XSS攻击中&#xff0c;img标签的src属性是一个常见的攻击向量&#xff0c;因为它可以…...

【AI语音克隆整合包及教程】声临其境,让想象成为现实——第二代GPT-SoVITS引领语音克隆新时代!

随着人工智能技术的飞速发展&#xff0c;曾经只能在科幻小说中出现的场景逐渐走进了我们的日常生活。其中&#xff0c;语音克隆技术以其独特魅力&#xff0c;成为了人们关注的焦点。GPT-SoVITS作为一款前沿的语音克隆工具&#xff0c;由RVC变声器创始人“花儿不哭”与AI音色转换…...

echarts属性之dataZoom

dataZoom-slider 滑动条型数据区域缩放组件&#xff08;dataZoomInside&#xff09; 滑动条型数据区域缩放组件提供了数据缩略图显示&#xff0c;缩放&#xff0c;刷选&#xff0c;拖拽&#xff0c;点击快速定位等数据筛选的功能。下图显示了该组件可交互部分 所有属性 data…...

SQLite 语法

SQLite 语法 SQLite 是一种轻量级的数据库管理系统&#xff0c;它遵循 SQL&#xff08;结构化查询语言&#xff09;标准。SQLite 的语法相对简单&#xff0c;易于学习和使用。本文将详细介绍 SQLite 的基本语法&#xff0c;包括数据定义语言&#xff08;DDL&#xff09;、数据…...

逗号运算符应用举例

在main.cpp里输入程序如下&#xff1a; #include <iostream> //使能cin(),cout(); #include <iomanip> //使能setbase(),setfill(),setw(),setprecision(),setiosflags()和resetiosflags(); //setbase( char x )是设置输出数字的基数,如输出进制数则用set…...

Android 玩机知识储备

基础知识 安卓刷机&#xff1a;https://post.smzdm.com/p/724098/安装分区&#xff08;视频&#xff09;: https://www.bilibili.com/video/BV1BY4y1H7Mc/安卓分区&#xff08;文章&#xff09;: https://www.cnblogs.com/unixcs/p/16398969.html开机过程&#xff1a;https://…...

MyBatis 学习记录(六)之逆向工程

MyBatis 学习记录&#xff08;六&#xff09; MyBatis的逆向工程1、创建逆向工程添加依赖和插件创建逆向工程的配置文件执行MBG插件的generate目标最终生成的效果 2、QBC查询 MyBatis的逆向工程 **正向工程&#xff1a;**先创建Java实体类&#xff0c;由框架负责根据实体类生成…...

深度了解flink(七) JobManager(1) 组件启动流程分析

前言 JobManager是Flink的核心进程&#xff0c;主要负责Flink集群的启动和初始化&#xff0c;包含多个重要的组件(JboMaster&#xff0c;Dispatcher&#xff0c;WebEndpoint等)&#xff0c;本篇文章会基于源码分析JobManagr的启动流程&#xff0c;对其各个组件进行介绍&#x…...

PostgreSQL 约束

PostgreSQL 约束 介绍 PostgreSQL 是一种功能强大的开源对象关系数据库系统&#xff0c;它提供了多种约束来确保数据的完整性和一致性。约束是数据库规则&#xff0c;用于限制表中数据的类型和操作。在 PostgreSQL 中&#xff0c;约束可以分为几种类型&#xff0c;包括主键约…...

【Redis】

1、Redis 概述 远程字典服务器&#xff08;Remote Dictionary Server&#xff0c;Redis)&#xff1a;一个开源的、高性能的、轻量级、使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&#xff0c;通过提供多种键值数据类型来试音不同场景下的缓…...

大厂面试真题-MVCC有哪些不好

MVCC&#xff08;Multi-Version Concurrency Control&#xff0c;多版本并发控制&#xff09;虽然具有提高数据库并发性能、避免脏读等优势&#xff0c;但也存在一些缺点。以下是对MVCC缺点的详细归纳&#xff1a; 一、存储开销增加 MVCC需要为每个数据行存储多个版本&#x…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...

wpf在image控件上快速显示内存图像

wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像&#xff08;比如分辨率3000*3000的图像&#xff09;的办法&#xff0c;尤其是想把内存中的裸数据&#xff08;只有图像的数据&#xff0c;不包…...

Python实现简单音频数据压缩与解压算法

Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中&#xff0c;压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言&#xff0c;提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...