当前位置: 首页 > 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…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...

嵌入式常见 CPU 架构

架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集&#xff0c;单周期执行&#xff1b;低功耗、CIP 独立外设&#xff1b;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel&#xff08;原始…...

go 里面的指针

指针 在 Go 中&#xff0c;指针&#xff08;pointer&#xff09;是一个变量的内存地址&#xff0c;就像 C 语言那样&#xff1a; a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10&#xff0c;通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋

随着工业以太网的发展&#xff0c;其高效、便捷、协议开放、易于冗余等诸多优点&#xff0c;被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口&#xff0c;具有实时性、开放性&#xff0c;使用TCP/IP和IT标准&#xff0c;符合基于工业以太网的…...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...

Vue3中的computer和watch

computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...