Linux字符设备驱动中同类型多设备节点的创建---一个驱动程序支持多个同类型设备

文章目录

  • 前言
  • 1 代码解析
    • 1.1 驱动层
    • 1.2 应用层
  • 2 运行结果
  • 总结


前言

本期分享的内容相对比较简单,那就是同时注册多个同类型的字符设备驱动,那么这样我们就可以同时支持多个同类型的设备了!下面来带大家看一下:


1 代码解析

1.1 驱动层

//本驱动程序支持主设备号major = 11,次设备号为0,1,2的三个设备
表明驱动程序支持三个同类型的设备,在使用时需要创建真实的设备节点
mknod /dev/mydev0 c 11 0
mknod /dev/mydev1 c 11 1
mknod /dev/mydev2 c 11 2
编写一个驱动程序,可以分别驱动三个设备节点

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include "mychar.h"#define BUF_LEN 		100
#define MYCHAR_DEV_CNT 	3
int major = 11; 		//主设备号
int minor = 0; 			//次设备号
int mychar_num = MYCHAR_DEV_CNT; 	//设备数量struct mychar_dev
{struct cdev mydev; 			//每一类设备都有一个cdev结构体char mydev_buf[BUF_LEN];  	//内核空间int curlen; 				//有效数字从零开始
};//创建MYCHAR_DEV_CNT个设备结构体
struct mychar_dev gmydev_arr[MYCHAR_DEV_CNT];int mychar_open(struct inode *pnode, struct file *pfile)
{pfile->private_data = (void *)container_of(pnode->i_cdev, struct mychar_dev, mydev);printk("mychar open is called!!!\n");return 0;
}ssize_t mychar_read(struct file *pfile, char __user *pbuf, size_t count, loff_t *ppos)
{int size = 0;int ret = 0;struct mychar_dev *pmydev = (struct mychar_dev *)pfile->private_data;if (count > pmydev->curlen){size = pmydev->curlen;}else{size = count;}ret = copy_to_user(pbuf, pmydev->mydev_buf, size);if (ret){printk("copy_to_user failed!\n");return -1;}memcpy(pmydev->mydev_buf, pmydev->mydev_buf + size, pmydev->curlen - size);   //把在mydev_buf中剩下有效数据存放在以mydev_buf的首地址中pmydev->curlen -= size; 			//读走的字节要被减去return size;
}ssize_t mychar_write(struct file *pfile, const char __user *pbuf, size_t count, loff_t *ppos)
{int size = 0;int ret = 0;struct mychar_dev *pmydev = (struct mychar_dev *)pfile->private_data;if (count < BUF_LEN - pmydev->curlen){size = count;}else{size = BUF_LEN - pmydev->curlen;}ret = copy_from_user(pmydev->mydev_buf + pmydev->curlen, pbuf, size);if (ret){printk("copy_from_user failed!\n");return -1;}pmydev->curlen += size;return size;
}long mychar_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
{int __user *pret = (int *)arg;int maxlen = BUF_LEN;int ret = 0;struct mychar_dev *pmydev = (struct mychar_dev *)pfile->private_data;switch(cmd){case MYCHAR_IOCTL_GET_MAXLEN:ret = copy_to_user(pret, &maxlen, sizeof(int));if (ret){printk("fail to copy_to_user!\n");return -1;}break;case MYCHAR_IOCTL_GET_CURLEN:ret = copy_to_user(pret, &pmydev->curlen, sizeof(int));if (ret){printk("fail to copy_from_user!\n");return -1;}break;default:printk("the cmd is unknow!\n");return -1;}return 0;
}int mychar_close(struct inode *pnode, struct file *pfile)
{printk("mychar clsoe is called!!!\n");return 0;
}/* 对字符设备的操作函数 */
struct file_operations myops = {.owner = THIS_MODULE,.open = mychar_open,.write = mychar_write,.read = mychar_read,.unlocked_ioctl = mychar_ioctl,	.release = mychar_close,
};int __init mychar_init(void)
{int ret = 0;int i = 0;dev_t devno = MKDEV(major, minor); 										//组合设备号ret = register_chrdev_region(devno, mychar_num, "mychar"); 				//手动申请设备号if (ret) 																//返回值为0表示申请成功{ret = alloc_chrdev_region(&devno, 0, mychar_num, "mychar"); 	//申请失败则系统自动分配if (ret){printk("get devno failed!\n");return -1;}major = MAJOR(devno); 												//从系统分配的设备号中取出主设备号minor = MINOR(devno); 												//从系统分配的设备号中取出次设备号devno = MKDEV(major, minor); 										//组合设备号}for (i = 0;i < MYCHAR_DEV_CNT;++i){devno = MKDEV(major, minor + i); 										//组合设备号/* 使得设备具有myops中的函数操作方法 */cdev_init(&gmydev_arr[i].mydev, &myops);gmydev_arr[i].mydev.owner = THIS_MODULE;/* 将设备号为devno的这个设备(mydev)添加到内核(内核hash链表中) */cdev_add(&gmydev_arr[i].mydev, devno, 1);}printk("hello world!\n");return 0;
}void __exit mychar_exit(void)
{int i = 0;dev_t devno = MKDEV(major, minor); 						//组合设备号for (i = 0;i < MYCHAR_DEV_CNT;++i){/* 从内核中删除mydev这个设备 */cdev_del(&gmydev_arr[i].mydev);}unregister_chrdev_region(devno, mychar_num); 		//注销设备号printk("bye bye!!!\n");
}MODULE_LICENSE("GPL");
module_init(mychar_init);
module_exit(mychar_exit);

1.2 应用层

应用层的代码没有任何修改!

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include "mychar.h"int main(int argc, const char *argv[])
{int fd = -1;char buf[6];int max = 0;int cur = 0;if (argc < 2){printf("the arguement is too few!\n");return -1;}fd = open(argv[1], O_RDWR);if(fd < 0){printf("fail to open %s\n", argv[1]);return -1;}ioctl(fd, MYCHAR_IOCTL_GET_MAXLEN, &max);printf("max = %d\n", max);write(fd, "hello", 6);printf("max = %d\n", max);ioctl(fd, MYCHAR_IOCTL_GET_CURLEN, &cur);printf("cur = %d\n", cur);read(fd, buf, 6);printf("buf = %s\n", buf);close(fd);fd = -1;return 0;
}

2 运行结果

在这里插入图片描述
每一个设备文件都支持这样的操作,因此运行后的结果是完全一致的!


总结

本期的分享相对来讲比较简单,就是需要将以前的设备修改为数组,那么在驱动程序的入口和出口函数中都需要进行着重修改,也就是循环创建和删除!
最后,各位小伙伴们如果有收获,可以点赞收藏哦,你们的认可是我创作的动力,一起加油!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Flink精讲】Flink性能调优:CPU核数与并行度

常见问题 举个例子 提交任务命令&#xff1a; bin/flink run \ -t yarn-per-job \ -d \ -p 5 \ 指定并行度 -Dyarn.application.queuetest \ 指定 yarn 队列 -Djobmanager.memory.process.size2048mb \ JM2~4G 足够 -Dtaskmanager.memory.process.size4096mb \ 单个 TM2~8G 足…

MySQL知识点总结(五)——锁

MySQL知识点总结&#xff08;五&#xff09;——锁 锁分类表锁 & 行锁如何添加表锁&#xff1f;如何添加行锁&#xff1f; 读锁 & 写锁行锁 & 间隙锁&#xff08;gap lock&#xff09;& 临键锁&#xff08;next-key lock&#xff09; 加锁机制分析可重复读隔离…

OpenAI视频生成Sora技术简析

基本介绍 Sora是春节期间OpenAI发布的产品&#xff0c;主要是通过文字描述生成视频&#xff0c;通过大规模视频数据训练而成的生成模型&#xff0c;当前还没开放试用。官方发布的技术报告&#xff1a;https://openai.com/research/video-generation-models-as-world-simulators…

趣学贝叶斯定理:贝叶斯定理的先验概率、似然和后验概率(1)

在第7章中&#xff0c;我们讨论了如何利用空间推理去推导贝叶斯定理。现在研究如何将贝叶斯定理当作一种概率工具&#xff0c;对不确定性进行逻辑推理。本章将利用贝叶斯定理来计算和量化在给定数据的情况下&#xff0c;信念有多大的可能性为真。为此&#xff0c;需要使用该定理…

019 Spring Boot+Vue 电影院会员管理系统(源代码+数据库+文档)

部分代码地址&#xff1a; https://github.com/XinChennn/xc019-cinema 一、系统介绍 cinema项目是一套电影院会员管理系统&#xff0c;使用前后端分离架构开发包含管理员、会员管理、会员卡管理、电影票、消费记录、数据统计等模块 二、所用技术 后端技术栈&#xff1a; …

【泰山派RK3566】智能语音助手(一)移植Kaldi语音转文字

文章目录 移植过程硬件资源下载测试 移植过程 参考我的这篇博客 【RV1126】移植kaldi实时语音识别 硬件 资源下载 链接&#xff1a;https://pan.baidu.com/s/1x1udT5eNzzQHoPOTCQ182A?pwdlief 提取码&#xff1a;lief –来自百度网盘超级会员V6的分享 下载的文件里面有一个…

全志H713/H618方案:调焦电机(相励磁法步进电机)的驱动原理、适配方法

一、篇头 全志H713平台&#xff0c;作为FHD投影的低成本入门方案&#xff0c;其公板上也配齐了许多投影使用的模组&#xff0c;本文即介绍投影仪调焦所用的步进电机&#xff0c;此模组的驱动原理、配制方法、调试方法。因为条件限制&#xff0c;本文采用的是H618香橙派Z3平台&…

Escalate_Linux(4)-利用SUDO实现提权

利用SUDO实现提权 利用用户的sudo授权获得root的shell cat /etc/passwd cat /etc/sudoers 命令没有权限 echo "cat /etc/sudoers" >/tmp/ls chmod 755 /tmp/ls export PATH/tmp:$PATH /home/user5/script 想办法更改user1的口令 echo echo "user1:xiao…

sql-labs第46关(order by盲注脚本)

一、环境 网上有自己找 二、解释 order by 注入我们看他的true和false来进行注入出来 二、实操 让我们用sort 看看源码 最终我们的id是放到order by后面了 如果我们直接用列去排序 ?sortusername/password username&#xff1a; password&#xff1a; 可以看到顺序是不…

每日五道java面试题之spring篇(六)

目录&#xff1a; 第一题 ApplicationContext通常的实现是什么&#xff1f;第二题 什么是Spring的依赖注入&#xff1f;第三题 依赖注入的基本原则第四题 依赖注入有什么优势&#xff1f;第五题 有哪些不同类型的依赖注入实现方式&#xff1f; 第一题 ApplicationContext通常的…

Python及Pycharm专业版下载安装教程(Python 3.11版)附JetBrains学生认证教程

目录 一、Python下载及安装1、Python下载2、Python安装3、验证是否安装成功 二、PyCharm下载及安装1、PyCharm下载2、PyCharm安装3、激活PyCharm 三、JetBrains学生认证 本篇主要介绍Python和PyCharm专业版的下载及安装方式&#xff0c;以及通过两种方式进行JetBrains学生认证。…

HUAWEI Programming Contest 2024(AtCoder Beginner Contest 342)

D - Square Pair 题目大意 给一长为的数组&#xff0c;问有多少对&#xff0c;两者相乘为非负整数完全平方数 解题思路 一个数除以其能整除的最大的完全平方数&#xff0c;看前面有多少个与其余数相同的数&#xff0c;两者乘积满足条件&#xff08;已经是完全平方数的部分无…