驱动开发5 阻塞IO实例、IO多路复用

1 阻塞IO

进程1

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    char buf[128] = {0};
    int a,b;
    int fd = open("/dev/myled0",O_RDWR);
    if(fd < 0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
    while(1)
    {
        memset(buf,0,sizeof(buf));
        read(fd,buf,sizeof(buf));
        printf("buf:%s\n",buf);
    }
}

进程2

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

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

驱动程序

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/uaccess.h>

int major;
char kbuf[128] = {0};

unsigned int *vir_rcc;
struct class *cls;
struct device *dev;
//定义等待队列
wait_queue_head_t wq_head;
unsigned int condition=0;
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)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    if(file->f_flags&O_NONBLOCK)//用户程序以非阻塞读写数据
    {}
    else{
        wait_event_interruptible(wq_head,condition);//判断condition的值,为假则进程休眠
    }
    //将获取到的硬件数据拷贝到用户
    int ret = copy_to_user(ubuf,kbuf,size);
    if(ret)
    {
        printk("copy_to_user filed\n");
        return -EIO;
    }
    condition = 0; //表示下一次数据没有准备就绪
    return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size,loff_t *lof)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    int ret;
    ret = copy_from_user(kbuf,ubuf,size);
    if (ret)
    {
        printk("copy_from_user filed\n");
        return -EIO;
    }
    condition = 1;//表示硬件数据就绪
    wake_up_interruptible(&wq_head);//唤醒休眠的进程
    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,
    .write = mycdev_write,
    .release = mycdev_close,
};
static int __init mycdev_init(void)
{
    //初始化等待队列
    init_waitqueue_head(&wq_head);
    //字符设备驱动
    major = register_chrdev(0,"mychrdev",&fops);
    if(major < 0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功:major=%d\n",major);

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

    //向上提交设备节点信息 device_create
    int i;
    for(i=0;i<3;i++)
    {
        dev = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
        if(IS_ERR(dev))
        {
            printk("向上提交设备节点失败\n");
            return -PTR_ERR(dev);
        }
    }
    printk("向上提交设备节点信息成功\n");
    return 0;
}
static void __exit mycdev_exit(void)
{
    //1.销毁设备节点信息
    int i;
    for(i=0;i<3;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //2.销毁目录
    class_destroy(cls);
    //3.注销字符设备驱动
    unregister_chrdev(major,"mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

Makefile

modname ?= demo
arch ?= arm
ifeq ($(arch),arm)  #通过命令行传过来的架构决定怎么编译
#KERBELDIR保存开发板内核源码路径
KERNELDIR := /home/ubuntu/FSMP1A/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61
else
#保存UBUNTU内核源码路径
KERNELDIR := /lib/modules/$(shell uname -r)/build
endif

#PWD保存当前内核模块的路径
PWD := $(shell pwd)
all:
#make modules是模块化编译命令
#make -C $(KERNLEDIR) 执行make之前先切换到KERNELDIR对应的路径
#M=$(PWD)表示进行模块化编译的路径是PWD保存的路径
	make -C $(KERNELDIR) M=$(PWD) modules
clean:
#编译清除
	make -C $(KERNELDIR) M=$(PWD) clean
#将obj-m保存的文件单独链接为内核模块
obj-m :=  $(modname).o

效果演示

2 IO多路复用

驱动程序

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/poll.h>

int major;
char kbuf[128] = {0};

unsigned int *vir_rcc;
struct class *cls;
struct device *dev;
//定义等待队列
wait_queue_head_t wq_head;
unsigned int condition=0;
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)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    if(file->f_flags&O_NONBLOCK)//用户程序以非阻塞读写数据
    {}
    else{
        // wait_event_interruptible(wq_head,condition);//判断condition的值,为假则进程休眠
    }
    //将获取到的硬件数据拷贝到用户
    int ret = copy_to_user(ubuf,kbuf,size);
    if(ret)
    {
        printk("copy_to_user filed\n");
        return -EIO;
    }
    condition = 0; //表示下一次数据没有准备就绪
    return 0;
}

__poll_t mycdev_poll(struct file *file, struct  poll_table_struct *wait)
{
    __poll_t mask = 0;
    // 向上提交等待队列队头
    poll_wait(file, &wq_head, wait);
    // 根据数据是否就绪给定一个合适的返回值
    if (condition)
        mask = POLLIN;
    return mask;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size,loff_t *lof)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    int ret = copy_from_user(kbuf,ubuf,size);
    if (ret)
    {
        printk("copy_from_user filed\n");
        return -EIO;
    }
    condition = 1;//表示硬件数据就绪
    wake_up_interruptible(&wq_head);//唤醒休眠的进程
    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,
    .write = mycdev_write,
    .poll = mycdev_poll,
    .release = mycdev_close,
};

static int __init mycdev_init(void)
{
    //初始化等待队列
    init_waitqueue_head(&wq_head);
    //字符设备驱动
    major = register_chrdev(0,"mychrdev",&fops);
    if(major < 0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功:major=%d\n",major);

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

    //向上提交设备节点信息 device_create
    int i;
    for(i=0;i<3;i++)
    {
        dev = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
        if(IS_ERR(dev))
        {
            printk("向上提交设备节点失败\n");
            return -PTR_ERR(dev);
        }
    }
    printk("向上提交设备节点信息成功\n");
    return 0;
}
static void __exit mycdev_exit(void)
{
    //1.销毁设备节点信息
    int i;
    for(i=0;i<3;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //2.销毁目录
    class_destroy(cls);
    //3.注销字符设备驱动
    unregister_chrdev(major,"mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

进程1:监听多个事件

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>

int main(int argc, char const *argv[])
{
    char buf[128] = {0};
    int fd1,fd2;
    fd1 = open("/dev/input/mouse0",O_RDWR);
    if(fd1 < 0)
    {
        printf("打开鼠标设备失败\n");
        return -1;
    }
    fd2 = open("/dev/myled0",O_RDWR);
    if(fd2 < 0)
    {
        printf("打开设备失败\n");
        return -1;
    }
    // 定义读事件集合
    fd_set readfds;
    while(1)
    {
        // 清空集合
        FD_ZERO(&readfds);
        // 将要监听的事件添加进集合
        FD_SET(fd1, &readfds);
        FD_SET(fd2, &readfds); 
        // 阻塞监听事件
        int ret;
        ret = select(fd2 + 1, &readfds, NULL, NULL, NULL);
        if(ret < 0)
        {
            printf("select 调用失败\n");
            return -1;
        }
        // 判断事件是否发生
        if(FD_ISSET(fd1, &readfds));
        {
            memset(buf, 0, sizeof(buf));
            read(fd1, buf, sizeof(buf));
            printf("鼠标事件发生buf:%s\n", buf);
        }
        if(FD_ISSET(fd2, &readfds))
        {
            memset(buf,0,sizeof(buf));
            read(fd2,buf,sizeof(buf));
            printf("事件发生buf:%s\n",buf);
        }
    }
    // 关闭文件描述符
    close(fd1);
    close(fd2);
    return 0;
}

进程2:模拟自定义事件就绪

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

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

效果演示

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【2021集创赛】Arm杯三等奖:基于FPGA的人脸检测SoC设计

本作品参与极术社区组织的有奖征集|秀出你的集创赛作品风采,免费电子产品等你拿~活动。 团队介绍 参赛单位&#xff1a;合肥工业大学 队伍名称&#xff1a;芯创之家 指导老师&#xff1a;邓红辉、尹勇生 参赛杯赛&#xff1a;Arm杯 参赛人员&#xff1a;王亮 李嘉燊 金京 获奖情…

【WinForm详细教程一】WinForm中的窗体、Label、TextBox及Button控件、RadioButton和CheckBox、ListBox

文章目录 1.WinForm文件结构2. 窗体的常用属性、方法与事件2.1 常用属性&#xff08;可直接在属性中设置&#xff09;2.2 常用方法2.3 常用事件 3.Label、TextBox及Button控件4.RadioButton和CheckBox5.ListBox&#xff08;列表框&#xff09; 1.WinForm文件结构 .sln文件 &am…

Hadoop分布式安装

首先准备好三台服务器或者虚拟机&#xff0c;我本机安装了三个虚拟机&#xff0c;安装虚拟机的步骤参考我之前的一篇 virtualBox虚拟机安装多个主机访问虚拟机虚拟机访问外网配置-CSDN博客 jdk安装 参考文档&#xff1a;Linux 环境下安装JDK1.8并配置环境变量_linux安装jdk1.8并…

干货很干:5个有效引流方法,让客户找上门

如何才能把用户引流到私域&#xff1f;是很多老板&#xff0c;店主&#xff0c;线上创业者的卡点&#xff0c;今天分享5个实用方法&#xff1a; ✅线下导流 ✅巧用搜索 ✅同行互推 ✅社群引流 ✅内容输出 所以引流不仅需要知道方法&#xff0c;还需要知道底层逻辑&#xff0c;也…

uniapp开发微信小程序的巨坑

1、不能使用v-show 2、关于插槽的巨坑 这里我真的是摸索了好久。 小程序版本&#xff1a; hbuilderx版本&#xff1a; 其他版本不知道会不会出现以下情况。 如果组件中带有插槽&#xff0c;那么使用插槽时有以下要注意&#xff1a; 1、如果子组件通过slot&#xff0c;向外…

SQL sever中的函数(基础)

目录 一、聚合函数 1.1聚合函数概述 1.2SUM(求和)函数 1.3AVG(平均值)函数 1.4MIN(最小值)函数 1.5MAX(最大值)函数 1.6COUNT(统计)函数 1.6.1COUNT函数用法分类 1.6.2COUNT函数用法示例 1.7DISTINCT(取不重复记录)函数 1.8查询重复记录 二、数学函数 2.1数学函数…

ELK概述部署和Filebeat 分布式日志管理平台部署

ELK概述部署、Filebeat 分布式日志管理平台部署 一、ELK 简介二、ELK部署2.1、部署准备2.2、优化elasticsearch用户拥有的内存权限2.3、启动elasticsearch是否成功开启2.4、浏览器查看节点信息2.5、安装 Elasticsearch-head 插件2.6、ELK Logstash 部署&#xff08;在 Apache 节…

中国密码算法与NIST标准对比

1. 引言 NIST定义AES为标准的对称密钥加密算法。但NIST被指出可能在加密算法中添加NSA后门。为此&#xff0c;在中国&#xff0c;ShāngM (SM) 系列密码算法&#xff0c;作为TLS 1.3集成和无线认证的备选方案&#xff1a; SM2&#xff1a;定义了认证&#xff08;签名&#xf…

cuda卸载

去查看你的电脑显卡对应的cuda版本&#xff0c;不然还是一整个用不到gpu的情况嘿嘿. 啊啊啊啊打开控制面板看一下&#xff0c;驱动不要乱卸载&#xff1a; 这些东西不能全部卸载了哦&#xff0c;只能卸载含有“CUDA”的那几个&#xff08;其实其他的可能也没有用 但是不懂的哇 …

用Rust和cURL库做一个有趣的爬虫

以下是一个使用 Rust 和 cURL 库的下载器程序&#xff0c;用于从wechat下载音频。此程序使用了 [/get_proxy] 提供的代码。 extern crate curl;use std::io::{self, Read}; use std::process::exit; use curl::easy::Easy;fn main() {let url "https://www.wechat.com/au…

vue3 源码解析(1)— reactive 响应式实现

前言 本文是 vue3 源码解析系列的第一篇文章&#xff0c;项目代码的整体实现是参考了 v3.2.10 版本&#xff0c;项目整体架构可以参考之前我写过的文章 rollup 实现多模块打包。话不多说&#xff0c;让我们通过一个简单例子开始这个系列的文章。 举个例子 <!DOCTYPE html…

Web攻防05_MySQL_二次注入堆叠注入带外注入

文章目录 MYSQL-二次注入-74CMS思路描述&#xff1a;注入条件&#xff1a;案例&#xff1a;74CMS个人中心简历功能 MYSQL-堆叠注入-CTF强网思路描述注入条件案例&#xff1a;2019强网杯-随便注&#xff08;CTF题型&#xff09; MYSQL-带外注入-DNSLOG注入条件使用平台带外应用场…

Mybatis-Plus CRUD

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; Mybatis-Plus CRUD 通用 Service CRUD 封装 IService 接口&#xff0c;进一步封装 CRUD 采用 get 查询、remove 删除 、list 查询集合、page 分页的前缀命名方式区分 …

【0229】libpq库实现压测PG服务器max_connections的最大连接数

1. PG服务器接收的最大连接数 在PG服务的postgresql.conf配置文件中,参数:max_connections 注明了PG服务所能够接受的最大客户端的连接数量。此值默认是100,那么PG服务此参数最大能够调到多大呢? 本文将采用libpq库编写demo来进行压测,并将最终的结论和数据于文章中给出。…

UWB技术在定位系统中的革新应用

超宽带技术&#xff08;Ultra-Wideband, UWB&#xff09;的崛起为定位系统领域带来了前所未有的机遇。其亚米级别的高精度定位、强大的穿透能力以及高速数据传输的特性&#xff0c;使得UWB在室内和室外定位系统中得以广泛应用。本文将深入探讨UWB技术在定位系统中的应用&#x…

关于数据可视化那些事

干巴巴的数据没人看&#xff0c;数据可视化才能直观展现数据要点&#xff0c;提升数据分析、数字化运营决策效率。那关于可视化的实现方式、技巧、工具等&#xff0c;你了解几分&#xff1f;接下来&#xff0c;我们就来聊聊数据可视化那些事。 1、什么是数据可视化&#xff1f…

java 企业工程管理系统软件源码 自主研发 工程行业适用

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&am…

LeetCode刷题---简单组(三)

文章目录 &#x1f352;题目一 20. 有效的括号&#x1f352;解法一&#x1f352;题目二 26. 删除有序数组中的重复项&#x1f352;解法一&#x1f352;题目三 21. 合并两个有序链表&#x1f352;解法一 &#x1f352;题目一 20. 有效的括号 给定一个只包括 ‘(’&#xff0c;‘…

在antd里面渲染MarkDown并且自定义一个锚点目录TOC(重点解决导航目录不跟随文档滚动的问题)

一、整体思路 由于有很多很长的文档需要渲染&#xff0c;我觉得用MarkDown的方式会比较适合管理&#xff0c;所以这两天测试了一下在antd里面集成MarkDown的渲染模块。 总体思路参考&#xff1a; https://blog.csdn.net/Sakuraaaa_/article/details/128400497 感恩大佬的倾情付…

windows安装最新pip官方教程

在执行pip的pip install --upgrade pip更新时&#xff0c;出现如下错误&#xff0c;怎么也无法重新安装&#xff1a; 根据官网的安装教程来 命令的方式一&#xff1a; • 卸载PIP的命令&#xff1a;python -m pip uninstall pip • 重装PIP的命令&#xff1a;python -m ensure…