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

驱动开发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_createcls = class_create(THIS_MODULE,"mychrdev");if(IS_ERR(cls)){printk("向上提交目录失败\n");return -PTR_ERR(cls);}printk("向上提交目录成功\n");//向上提交设备节点信息 device_createint 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_createcls = class_create(THIS_MODULE,"mychrdev");if(IS_ERR(cls)){printk("向上提交目录失败\n");return -PTR_ERR(cls);}printk("向上提交目录成功\n");//向上提交设备节点信息 device_createint 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));
}

效果演示

http://www.lryc.cn/news/205181.html

相关文章:

  • ElasticSearch:实现高效数据搜索与分析的利器!项目中如何应用落地,让我带你实操指南。
  • 2023了,是时候使用pnpm了!
  • asp.net文档管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio
  • Parallels Client for Mac:改变您远程控制体验的革命性软件
  • Julia数组详解
  • 用事务代码查看视图的函数
  • LuatOS-SOC接口文档(air780E)--libcoap - coap数据处理
  • js控制checkbox单选,获取checkbox的值,选中checkbox
  • MYSQL(事务+锁+MVCC+SQL执行流程)理解(2)
  • ubuntu tools
  • LeetCode 155. 掷骰子等于目标和的方法数:动态规划
  • PostgreSQL数据库从入门到精通系列之五:安装时序数据库TimescaleDB的详细步骤
  • 软件测试(五)自动化 selenium
  • Android grantUriPermission的使用场景和方式
  • 2023高频前端面试题-vue
  • 03初始Docker
  • 1.1、Python基础-注释、变量声明及命名规则、数据类型
  • Python第三方库安装——使用vscode、pycharm安装Python第三方库
  • 【vue】组件通选方式
  • java 使用策略模式减少if
  • 第1章 引论
  • 深入探究Linux文件:.sh、.swp文件的作用与意义 (linux .sh.swp)
  • 优雅的使用String字符串处理各种类型转换
  • Harmony 个人中心(页面交互、跳转、导航、容器组件)
  • AlDente Pro for Mac: 掌控电池充电的终极解决方案
  • tomcat的负载均衡、动静分离(nginx联动)
  • 基于单片机的温湿度检测及远程控制系统设计
  • 前后端交互系统:在Node.js中运行JavaScript
  • Maven学习
  • 《动手学深度学习 Pytorch版》 10.2 注意力汇聚:Nadaraya-Watson 核回归