0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

驱动之路#24:Linux设备四种读写模型

BSP调试从0到1 来源:嵌入式分享 作者:嵌入式分享 2026-05-06 16:26 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

正文

Linux 设备四种读写模型——其实核心就 4 种方式:查询、休眠 - 唤醒、poll、异步通知。它们不是中断本身,而是 “应用 - 驱动” 的上层交互逻辑(中断是底层硬件触发机制),但高效交互几乎都依赖中断实现。

1 查询方式

核心原理:应用层主动、周期性查询设备状态,不管设备是否就绪,CPU 都在循环检查 —— 像你每隔 1 分钟去门口看快递到没到。

代码示例(应用层):

#include#include#includeintmain(){ intfd =open("/dev/key", O_RDWR); if(fd < 0) {perror("open");return-1; } intkey_state; while(1) {   read(fd, &key_state,sizeof(key_state));// 主动查询   if(key_state ==1) {     printf("按键按下!n");     break;    }   usleep(100000);// 100ms查一次,仍占CPU  } close(fd); return0;}

优缺点与场景

优点:实现最简单,无需驱动复杂逻辑,调试方便

缺点:CPU 占用率极高(哪怕设备几小时没响应),浪费资源

适用场景:仅调试或极简单设备(如 LED 状态查询),生产环境慎用!

2 休眠 - 唤醒

核心原理:设备未就绪时,应用进程主动休眠(释放 CPU 给其他任务);当设备就绪(如按键按下触发中断),驱动唤醒进程继续执行 —— 像你听到门铃(中断)再去取快递,否则在家休息。

代码示例(驱动 + 应用):

驱动层(关键逻辑)#include#includestaticwait_queue_head_tkey_waitq;// 等待队列staticintkey_pressed =0;// 设备就绪标记// 读操作:未就绪则休眠staticssize_tkey_read(structfile *filp,char__user *buf,size_tcount,loff_t*ppos){ wait_event_interruptible(key_waitq, key_pressed);// 休眠 copy_to_user(buf, &key_pressed,sizeof(key_pressed));  key_pressed =0; returnsizeof(key_pressed);}// 中断服务函数:设备就绪时唤醒irqreturn_tkey_isr(intirq,void*dev_id){  key_pressed =1; wake_up_interruptible(&key_waitq);// 唤醒进程 returnIRQ_HANDLED;}
应用层(极简)intmain(){ intfd =open("/dev/key", O_RDWR); intkey_state; read(fd, &key_state,sizeof(key_state));// 阻塞等待 printf("按键按下!n"); close(fd); return0;}

优缺点与场景

优点:CPU 占用率极低(休眠时 0 占用),实现简单

缺点:不支持超时,只能阻塞等待单个设备

适用场景:大多数字符设备(按键、串口、传感器),嵌入式开发首选!

3 poll 方式

核心原理:结合 “查询” 和 “休眠 - 唤醒” 的优点:应用层通过poll()/select()设置超时时间,内核监控多个设备 —— 超时前设备就绪则立即返回,超时后也会唤醒,避免无限阻塞。

像你告诉快递员 “10 分钟内到就等,超时不等”,还能同时等快递和外卖。

代码示例(驱动 + 应用):

驱动层(poll 函数实现)#includestaticunsignedintkey_poll(structfile *filp,structpoll_table_struct *wait){ unsignedintmask =0; poll_wait(filp, &key_waitq, wait);// 加入等待队列 if(key_pressed) {    mask |= POLLIN | POLLRDNORM;// 标记可读就绪  } returnmask;}// 驱动操作集绑定staticconststructfile_operationskey_fops = {  .owner = THIS_MODULE,  .read = key_read,  .poll = key_poll,// 关键:绑定poll函数};应用层(监控按键 + 超时)#includeintmain(){ intfd =open("/dev/key", O_RDWR | O_NONBLOCK); structpollfdfds[1] = {{fd, POLLIN,0}};// 关注可读事件 while(1) {   intret =poll(fds,1,1000);// 等待1秒   if(ret >0&& (fds[0].revents & POLLIN)) {     intkey_state;     read(fd, &key_state,sizeof(key_state));     printf("按键按下!n");     break;    }elseif(ret ==0) {     printf("等待超时...n");    }  } close(fd); return0;}

优缺点与场景

优点:CPU 占用率低,支持超时、支持多设备同时监控,兼容得阻塞 IO

缺点:实现复杂,高并发下开销大

适用场景:多设备监听、需超时(串口 + 网卡)

4 异步通知

核心原理:完全反转交互方向:应用层无需查询 / 等待,设备就绪时(触发中断),驱动主动发送信号(如 SIGIO)通知应用层,应用层执行信号处理函数 —— 像快递员直接把快递送上门,不用你等。

代码示例(驱动 + 应用)

驱动层(异步通知实现)#includestaticstructfasync_struct*key_async;// 异步通知初始化staticintkey_fasync(intfd,structfile *filp,intmode){ returnfasync_helper(fd, filp, mode, &key_async);}// 中断服务函数:发送信号irqreturn_tkey_isr(intirq,void*dev_id){ if(key_async) {   kill_fasync(&key_async, SIGIO, POLL_IN);// 发送SIGIO信号  } returnIRQ_HANDLED;}
应用层(信号处理)#includevoidsigio_handler(intsignum){// 信号处理函数 intfd =open("/dev/key", O_RDWR); intkey_state; read(fd, &key_state,sizeof(key_state)); printf("异步通知:按键按下!n"); close(fd);}intmain(){ intfd =open("/dev/key", O_RDWR); fcntl(fd, F_SETOWN,getpid());// 设置信号接收进程 intflags =fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags | FASYNC);// 启用异步通知 signal(SIGIO, sigio_handler);// 注册信号处理函数 // 主线程可自由执行其他逻辑 while(1) {   printf("主线程运行中...n");   sleep(1);  } close(fd); return0;}

优缺点与场景

优点:CPU 占用率最低,完全异步,应用层无阻塞

缺点:实现复杂(需处理信号安全),信号可能丢失

适用场景:高实时性设备(网卡、磁盘 IO)、应用层需同时处理多任务的场景


本人专注 Linux 驱动 & Linux/Android BSP 开发调试,可接外包项目/技术支持/问题定位。有需求或交个朋友可加微信:【Chen_WeChat2025】。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    88

    文章

    11825

    浏览量

    219617
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    如何理解Linux内核中的PCIe驱动

    我们习惯了用 Verilog 去死磕 PCIe 的底层协议状态机。但一旦越过硬件边界来到操作系统层面,Linux 内核是如何接管并驱动这些 PCI/PCIe 设备的呢?由于不同的 CPU 架构实现了
    的头像 发表于 04-11 17:22 1294次阅读

    驱动之路#20:Pinctrl 在手,引脚复用很顺手

     欢迎关注,每周更新!☞ 本合集分享的是,我当初学习Linux驱动的来时路——《《驱动之路》开篇:自序pinctrl节点下(rk3576-pinctrl.dtsi),定义具体的引脚配置
    的头像 发表于 04-07 21:18 529次阅读
    <b class='flag-5'>驱动</b><b class='flag-5'>之路</b>#20:Pinctrl 在手,引脚复用很顺手

    变频器四种制动方式

    解决的核心问题。目前主流的变频器制动方式主要包括能耗制动、回馈制动、直流制动和电容制动四种,每种方式各具特点,适用于不同的工况场景。
    的头像 发表于 03-25 16:31 286次阅读

    Linux内核驱动开发的技术核心精要

    (如wmb)保证CPU写操作对DMA可见,避免数据错乱。 设备驱动模型设备Linux
    发表于 03-10 13:56

    驱动之路#04:LCD 驱动程序分析(基于RK3576)

      题图:河北太行山脉,山头密密麻麻都被太阳能板覆盖了。 欢迎关注,每周更新!☞ 本合集分享的是,我当初学习Linux驱动的来时路——《《驱动之路》开篇:自序      // 通用面板
    的头像 发表于 02-17 08:20 1w次阅读
    <b class='flag-5'>驱动</b><b class='flag-5'>之路</b>#04:LCD <b class='flag-5'>驱动</b>程序分析(基于RK3576)

    低成本CAN扩展方案怎么选?CSM331A四种模式一次说清

    MCU需要CAN功能但预算有限?CSM331A协议转换芯片用SPI/UART就能扩展,四种模式从快到稳任你选。ZLG致远电子推出的CSM331A协议转换芯片,配合一个CAN收发器,就能通过SPI
    的头像 发表于 02-09 11:50 459次阅读
    低成本CAN扩展方案怎么选?CSM331A<b class='flag-5'>四种</b>模式一次说清

    是德示波器DSOX1202A与电脑的四种连接方式及操作步骤详解

    是德科技(Keysight)DSOX1202A示波器作为高精度电子测量设备,广泛应用于电子工程、通信测试与自动化调试场景。为实现数据实时采集、波形分析与远程控制,用户需通过USB、LAN、GPIB或串口将示波器与电脑互联。本文将结合官方指南与实操经验,系统介绍四种连接方式
    的头像 发表于 01-13 17:48 1908次阅读
    是德示波器DSOX1202A与电脑的<b class='flag-5'>四种</b>连接方式及操作步骤详解

    【免费送书】成为硬核Linux开发者:《Linux 设备驱动开发(第 2 版)》

    Linux系统的设备驱动开发,一直给人门槛较高的印象,主要因内核机制抽象、需深度理解硬件原理、开发调试难度大所致。2021年,一本讲解驱动开发的专著问世即获市场青睐,畅销近万册——这便
    的头像 发表于 11-18 08:06 1878次阅读
    【免费送书】成为硬核<b class='flag-5'>Linux</b>开发者:《<b class='flag-5'>Linux</b> <b class='flag-5'>设备</b><b class='flag-5'>驱动</b>开发(第 2 版)》

    【书籍评测活动NO.67】成为硬核Linux开发者:《Linux 设备驱动开发(第 2 版)》

    Linux设备模型(LDM) ,助力读者理解kobject/kset的设备管理逻辑及sysfs暴露设备属性的方式,为开发高效稳定的
    发表于 11-17 17:52

    四种MOS管驱动电路方案介绍

    这个电控界的MOS管,但想让它听话,还得靠驱动电路!整理了 4 常用方案。
    的头像 发表于 10-17 09:33 4752次阅读
    <b class='flag-5'>四种</b>MOS管<b class='flag-5'>驱动</b>电路方案介绍

    一图看懂绿电直连的四种玩法

    通过 “总览框架 + 分模式图解” 的形式,用可视化逻辑拆解绿电直连的四种核心模式,涵盖每种模式的核心特征、适用场景、参与主体三大关键信息,帮你快速区分不同 “玩法” 的差异与适配性。
    的头像 发表于 10-15 10:18 1642次阅读
    一图看懂绿电直连的<b class='flag-5'>四种</b>玩法

    从入门到精通:基于开源代码的BLE四种模式开发详解

    Bluetooth Smart,是蓝牙4.0及更高版本引入的低功耗无线通信技术,专为低带宽、间歇性数据传输的物联网(IoT)和穿戴设备设计。   一、Air8000蓝牙大模式 Air8000蓝牙支持四种模式,分别是中心
    的头像 发表于 10-09 18:00 726次阅读
    从入门到精通:基于开源代码的BLE<b class='flag-5'>四种</b>模式开发详解

    全网最全CSA3412,BCT4340,VL162,MCU/ USB3.1 正反插10G bps四种解决方案

    CSA3412,BCT4340,VL162,MCU/ USB3.1 全网最全正反插10G bps四种解决方案
    的头像 发表于 09-25 03:06 986次阅读
    全网最全CSA3412,BCT4340,VL162,MCU/ USB3.1 正反插10G bps<b class='flag-5'>四种</b>解决方案

    zephyr设备驱动程序模型

        1:Zephyr 内核支持多种设备驱动程序。驱动程序是否可用取决于board 和驱动程序。 Zephyr 设备
    的头像 发表于 07-29 10:34 867次阅读
    zephyr<b class='flag-5'>设备</b><b class='flag-5'>驱动</b>程序<b class='flag-5'>模型</b>

    RDMA简介3之四种子协议对比

    RDMA协议共有四种子协议,分别为InfiniBand、iWARP、RoCE v1和RoCE v2协议。这四种协议使用统一的RDMA API,但在具体的网络层级实现上有所不同,如图1所示,接下来将
    发表于 06-04 16:05