驱动开发,IO模型,信号驱动IO实现过程

news2024/10/7 10:24:40

 1.信号驱动IO框架图

分析:

        信号驱动IO是一种异步IO方式。linux预留了一个信号SIGIO用于进行信号驱动IO。进程主程序注册一个SIGIO信号的信号处理函数,当硬件数据准备就绪后会发起一个硬件中断,在中断的处理函数中向当前进程发送一个SIGIO信号。进程收到SIGIO信号后执行信号处理函数,在信号处理函数中将数据读走即可。

应用层:1.打开设备文件,2注册SIGIO信号处理函数,3回调驱动中的fasync方法,4设置fd对应的驱动程序发送SIGIO信号只发送给当前进程

驱动层:完成异步对象的空间分配和初始化

硬件层:中断处理函数:发送SIGIO信号(用到异步对象的二级指针)

2.实现代码

---pro1.c---应用程序(信号驱动IO)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>

char buf[128] = {0};
int fd;

void sigio_handler(int sig)
{
    read(fd, buf, sizeof(buf));
    printf("buf:%s\n", buf);
}

int main(int argc, const char *argv[])
{

    // 1打开设备文件
    fd = open("/dev/mmyled0", O_RDWR);
    if (fd < 0)
    {
        printf("自定义事件文件失败\n");
        exit(-1);
    }
    // 2注册SIGIO信号的处理函数
    signal(SIGIO, sigio_handler);

    // 3回调驱动中的fasync方法,完成发送信号之前的准备工作
    int flags = fcntl(fd,F_GETFL);  //获取文件描述符属性
    fcntl(fd,F_SETFL,flags|FASYNC);  //添加FASYNC属性就可以回调fasync操作方法
   
    // 4驱动发送信号只发送给当前进程
    fcntl(fd,F_SETOWN,getpid());

    while(1)
    {
        printf("...等待信号驱动IO事件...\n");
        sleep(1);
    }
    close(fd);

    return 0;
}
---pro2.c---应用程序(模拟模拟硬件数据到达)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
    char buf[128] = "hello world";
    int fd = open("/dev/mmyled0", O_RDWR);
    if (fd < 0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }

    write(fd, buf, sizeof(buf));

    close(fd);

    return 0;
}
---driceio.c---驱动程序
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include<linux/poll.h>

char kbuf[128] = {0};
unsigned int major;
struct class *cls;
struct device *dev;
struct fasync_struct *fp;  //定义一个异步对象指针


// 封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
    int ret;
    ret = copy_to_user(ubuf, kbuf, size);
    if (ret)
    {
        printk("copy_to_ user err\n");
        return -EIO;
    }

    return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
    int ret;
    // 从用户拷贝数据,模拟硬件数据
    ret = copy_from_user(kbuf, ubuf, size);
    if (ret)
    {
        printk("copy_from_user err\n");
        return -EIO;
    }
    //内核模块发送信号
    kill_fasync(&fp,SIGIO,POLL_IN);

    return 0;
}
int mycdev_fasync(int fd,struct file *file,int on)  //异步操作方法
{
    //完成发送信号之前的准备工作
    //异步对象空间的分配语言初始化
    fasync_helper(fd,file,on,&fp);
    
    return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

struct file_operations fops = {
    .open = mycdev_open,
    .read = mycdev_read,
    .fasync = mycdev_fasync,
    .write = mycdev_write,
    .release = mycdev_close,
};

// 入口函数
static int __init mycdev_init(void)
{
    major = register_chrdev(0, "myled", &fops);
    if (major < 0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功:major=%d\n", major);

    // 向上提交目录
    cls = class_create(THIS_MODULE, "MYLED");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        return -PTR_ERR(cls);
    }
    printk("向上提交目录成功\n");

    // 向上提交设备节点信息
    int i;
    for (i = 0; i < 3; i++)
    {
        dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mmyled%d", i);
        if (IS_ERR(dev))
        {
            printk("向上提交设备节点信息失败\n");
            return -PTR_ERR(dev);
        }
    }
    printk("向上提交设备节点信息成功\n");

    return 0;
}

// 出口函数
static void __exit mycdev_exit(void)
{
    // 销毁设备节点信息
    int i;
    for (i = 0; i < 3; i++)
    {
        device_destroy(cls, MKDEV(major, i));
    }

    // 销毁目录信息
    class_destroy(cls);

    // 字符设备驱动注销
    unregister_chrdev(major, "myled");
}

// 声明
// 入口函数地址
module_init(mycdev_init);
// 出口函数地址
module_exit(mycdev_exit);
// 遵循的GPL协议
MODULE_LICENSE("GPL");

 

3.测试结果

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

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

相关文章

高内聚低耦合

低耦合 元素(方法、类)与元素依赖度不要太高&#xff1b;我们在设计程序时应该降低元素与元素之间的直接关系&#xff1b;降低元素与元素之间的耦合性&#xff1b; 若当前有方法A与方法B&#xff0c;A依赖与B&#xff0c;当B不存在的时候A就不能正常工作&#xff0c;那么就说…

高可用集群HA、LVS+Keepalived、健康检测

keepalived是集群管理中保证集群高可用(HA)的一个服务软件&#xff0c;其功能类似于heartbeat&#xff0c;用来防止单点故障。 2.工作原理 keepalived是以VRRP协议为实现基础的,当backup收不到vrrp包时就认为master宕掉了&#xff0c;这时就需要根据VRRP的优先级来选举一个ba…

机器学习笔记之无约束优化问题——(阶段性收尾)共轭方向法与Wolfe准则优化方法Python示例

机器学习笔记之无约束优化问题——基于共轭方向法与Wolfe准则优化方法的Python示例 引言小插曲&#xff1a;画图——非标准二次型的等值线算法在图像中的表示基于精确搜索的共轭梯度法基于Wolfe准则的共轭梯度法 附&#xff1a;共轭梯度法完整代码 引言 本节使用 Python \text…

SQL优化--分组优化(group by)

分组操作&#xff0c;我们主要来看看索引对于分组操作的影响。 在没有索引的情况下&#xff0c;执行如下SQL&#xff0c;查询执行计划&#xff1a; explain select profession , count(*) from tb_user group by profession ;然后&#xff0c;我们在针对于 profession &#…

Linux 上的 Wayland 是什么?它与 X 有何不同?

导读Wayland 是 Linux 发行版的替代窗口系统。它取代了老化的 X11 标准。由于它需要修改应用程序才能使用它&#xff0c;因此迄今为止采用速度很慢。在撰写本文时&#xff0c;增强的安全性是相对于 X11 的主要优势。 X11 或 X Window 系统可让您的图形桌面环境显示和控制窗口。…

【C语言】指针的进阶(一)

目录 前言 1. 字符指针 2. 指针数组 3. 数组指针 3.1 数组指针的定义 3.2 &数组名VS数组名 3.3 数组指针的使用 4. 数组参数、指针参数 4.1 一维数组传参 4.2 二维数组传参 4.3 一级指针传参 4.4 二级指针传参 5. 函数指针 前言 指针在C语言中可谓是有着举足轻重的…

MySQL夺命20连问

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

Seata 源码篇之核心思想 - 01

Seata 源码篇之核心思想 - 01 引言基础架构数据源代理分支事务提交和回滚隔离级别解决脏写读未提交读已提交 小结 笔者个人项目中使用到了seata来做分布式事务管理&#xff0c;面试过程中也经常被问到seata的原理&#xff0c;seata源码本身也不是很复杂&#xff0c;所以准备出一…

FWT小结

核心思想&#xff1a;把 a , b a,b a,b 化成 f w t ( a ) , f w t ( b ) fwt(a),fwt(b) fwt(a),fwt(b)&#xff0c;相乘后再化为 a a a 化的过程用的是分治 所以和FFT其实一模一样 OR / AND 卷积 不需要什么技巧&#xff0c;暴力分治转移即可 每次分治下去&#xff0c;…

瑞萨MCU入门教程(非常详细的瑞萨单片机入门教程)

瑞萨MCU零基础入门系列教程 前言 得益于瑞萨强大的MCU、强大的软件开发工具(e studio)&#xff0c;也得益于瑞萨和RA生态工作室提供的支持&#xff0c;我们团队编写了《ARM嵌入式系统中面向对象的模块编程方法》&#xff0c;全书37章&#xff0c;将近500页: 讲解面向对象编程…

硬件笔记:组装“固态 U 盘”的八年,从 100 块到 1000 块

这篇文章&#xff0c;聊聊自从 2015 年开始&#xff0c;到目前为止&#xff0c;我使用固态硬盘组装的高速 U 盘&#xff0c;以及它们的使用体验&#xff0c;以及一些明显的坑。 写在前面 2015 年的 8 月&#xff0c;我剁手下单了一块 32G 大小&#xff0c;NGFF接口的三星 22x…

关于 C/C++ 中在指针前加 const 关键字的作用说明

1. 作用说明&#xff1a; 在指针前加 const 的用途为&#xff1a;不可改变指针指向的内存的值&#xff0c;即将该指向指向的内存中的变量置为只读&#xff08;read-only) 变量。 但是&#xff0c;可以给 const 的指针赋值&#xff0c;即将具有 const 属性的指针指向别的内存地…

Linux 内核镜像分析

文章目录 前言一、概述二、bzImage2.1 镜像分析 三、zImage3.1 镜像分析参考链接 前言 介绍了vmlinux的来源&#xff0c;以及分析方法&#xff1b; 一、概述 在linux系统中&#xff0c;vmlinux&#xff08;vmlinuz&#xff09;是一个包含linux kernel的静态链接的可执行文件…

JavaScript中的原型继承和类继承之间的区别

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 原型继承&#xff08;Prototype Inheritance&#xff09;⭐ 类继承&#xff08;Class Inheritance&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启…

MySQL开启安全审计日志,开启查询日志

MySQL 查询开启日志 在 MySQL 数据库中&#xff0c;开启查询日志是一个非常有用的技术&#xff0c;它能帮助你追踪每一个执行的查询语句&#xff0c;以便更好地优化 SQL 语句和性能。本文将介绍如何在 MySQL 数据库中开启查询日志。 开启查询日志 MySQL 中的查询日志是一种记…

Mysql开启binlog

本案例基于mysql5.7.16实验 1、在linux中进入mysql查询binlog是否打开&#xff0c;执行命令如下&#xff1a; mysql -u root -p 2、查询binlog是否开启命令如下&#xff0c;如果log_bin为OFF则证明mysql的binlog没有打开 show variables like %log_bin%; 3、退出mysql终端&…

OPC DA如何实现跨平台

目录 简介 EntireX DCOM Utgard OPC XML DA OPC UA 协议转换代理 简介 本文介绍OPC DA跨平台通讯的几种方案。 OPC官方说明文档 OPC&#xff08;OLE for Process Control&#xff09;是为过程控制专门设计的OLE 技术&#xff0c;基于COM/DCOM的数据访问的标准。常说的O…

vmware去虚拟化

路径&#xff1a;C:\Program Files (x86)\VMware\VMware Workstation\x64\vmware-vmx.exe &#xff0c;复制一份备份 用16进制工具打开修改这个文件&#xff0c;如winhex 1、搜索 25 73 2E 65 6E 61 62 6C &#xff0c;找到上面有两个"VMware"开头的 2、硬盘SCSI格…

JAVASE---String类

String类的重要性 在C语言中已经涉及到字符串了&#xff0c;但是在C语言中要表示字符串只能使用字符数组或者字符指针&#xff0c;可以使用标准库提供的字符串系列函数完成大部分操作&#xff0c;但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想&#xff0c;而…

Java 类和对象

在面向对象语言中万物皆对象&#xff0c;一切都围绕对象来进行&#xff0c;找对象、建对象&#xff0c;用对象等。 类&#xff1a;把具有相同特征和行为的一组对象抽象为类&#xff0c;类是抽象概念&#xff0c;如人类、车类等&#xff0c;无法具体到每个实体。 对象&#xff…