字符设备框架:管理同主设备号、不同次设备号设备

以下代码针对迅为开发板RK3568,开发板系统是ubuntu20.04,

正文

以下是我写的字符设备框架,实现了管理同主设备号、不同次设备号的功能。

代码:

private_data_test.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h> /* 一个驱动兼容不同设备实验 */ /*
定义一个设备结构体,专门存放设备号、设备类、设备类中的设备。显得很规整。
*/
struct device_test
{
dev_t dev_num; /* 设备号 */
int major; /* 定义 int 类型的主设备号 major */
int minor; /* 定义 int 类型的次设备号 minor */
struct cdev cdev_test; /* 设备暂起名cdev_test */
struct class * class ; /* 类 */
struct device * device; /* 设备 */
char kbuffer[64]; /* 缓存区 buf */
}; /* dev1和dev2的主设备号相同,次设备号不同。 */
static struct device_test dev1;
static struct device_test dev2; static int cdev_test_ops_open (struct inode * inode, struct file * file)
{
dev1.minor = 0; //设置 dev1 的次设备号为 0
dev2.minor = 1; //设置 dev2 的次设备号为 1
/*
container_of 函数
函数原型: container_of(ptr, type, member)
函数功能: 通过结构体变量中某个成员的首地址获取到整个结构体变量的首地址。
函数参数: 第一个参数ptr是结构体变量中某个成员的地址。
第二个参数type是结构体的类型。
第三个参数member是该结构体变量的具体名字。
*/
file->private_data = container_of(inode->i_cdev,struct device_test, cdev_test);//现在程序自动判断是dev1还是dev2
printk(KERN_ERR "This is cdev_test_ops_open in Kernel\r\n");
return 0;
}; static ssize_t cdev_test_ops_read (struct file * file, char __user * buf, size_t size, loff_t * off)
{
struct device_test * test_dev = (struct device_test *)file->private_data;
int ret = 0;
ret = copy_to_user(buf, test_dev->kbuffer, strlen(test_dev->kbuffer)); //拷贝结束且健康,返回0
if(ret != 0) //返回值≠0,就是拷贝到用户态失败。
{
printk(KERN_ERR "copy_to_user, failed\r\n");
return -1;
}
printk(KERN_ERR "copy_to_user, successed\r\n");
printk(KERN_ERR "Kernel Message:This is cdev_test_ops_read\r\n");
return 0;
}; static ssize_t cdev_test_ops_write (struct file *file , const char __user * buf, size_t size, loff_t * off)
{
int ret = 0;
struct device_test * test_dev = (struct device_test *)file->private_data;
if(test_dev->minor == 0)
{
printk(KERN_ERR "This is dev1\r\n");
ret = copy_from_user(test_dev->kbuffer, buf, size); //拷贝结束且健康,返回0
if(ret != 0)
{
printk(KERN_ERR "copy_from_user, failed\r\n");
return -1;
}
printk(KERN_ERR "copy_from_user, successed\r\n");
printk(KERN_ERR "test_dev->kbuffer is %s\r\n", test_dev->kbuffer);
}
else if(test_dev->minor == 1)
{
printk(KERN_ERR "This is dev2\r\n");
ret = copy_from_user(test_dev->kbuffer, buf, size); //拷贝结束且健康,返回0
if(ret != 0)
{
printk(KERN_ERR "copy_from_user, failed\r\n");
return -1;
}
printk(KERN_ERR "copy_from_user, successed\r\n");
printk(KERN_ERR "test_dev->kbuffer is %s\r\n", test_dev->kbuffer);
}
printk(KERN_ERR "This is cdev_test_ops_write in Kernel\r\n");
return 0;
}; static int cdev_test_ops_release (struct inode * inode, struct file * file)
{
printk(KERN_ERR "This is cdev_test_ops_release in Kernel\r\n");
return 0;
}; static struct file_operations cdev_test_ops = {
.owner = THIS_MODULE,
.open = cdev_test_ops_open, //open字段指向 cdev_test_ops_open
.read = cdev_test_ops_read,
.write = cdev_test_ops_write,
.release = cdev_test_ops_release
}; /***************************** 接下来是入口函数 ********************************/ static int __init module_cdev_init(void)
{
int ret = 0; //ret value,返回值 printk(KERN_ERR "Enter Module Init\r\n"); ret = alloc_chrdev_region(&dev1.dev_num, 0, 2, "dynamically alloc dev1 number");
if(ret < 0)
{
printk(KERN_ERR "apply_cdev1_num, failed\r\n");
}
printk(KERN_ERR "apply_cdev1_num, successed\r\n"); dev1.major = MAJOR(dev1.dev_num);
dev1.minor = MINOR(dev1.dev_num);
printk(KERN_ERR "dev1:major is %d,minor is %d\r\n", dev1.major, dev1.minor); /* dev1的一套东西 */
dev1.cdev_test.owner = THIS_MODULE; //将owner字段指向本模块,可以避免在模块的操作正在被使用时卸载该模块
cdev_init(&dev1.cdev_test, &cdev_test_ops);
ret = cdev_add(&dev1.cdev_test, dev1.dev_num, 1);
if(ret < 0)
{
printk(KERN_ERR "cdev_add1, failed\r\n");
}
printk(KERN_ERR "cdev_add1, successed\r\n"); dev1.class = class_create(THIS_MODULE, "test1_class");
dev1.device = device_create(dev1.class, NULL, dev1.dev_num, NULL, "test1_dev"); /* dev2的一套东西 */
ret = alloc_chrdev_region(&dev2.dev_num, 0, 2, "dynamically alloc dev2 number");
if(ret < 0)
{
printk(KERN_ERR "apply_cdev2_num, failed\r\n");
}
dev2.major = MAJOR(dev1.dev_num);
dev2.minor = MINOR(dev1.dev_num + 1);
printk(KERN_ERR "dev2:major is %d,minor is %d\r\n", dev2.major, dev2.minor); dev2.cdev_test.owner = THIS_MODULE;
cdev_init(&dev2.cdev_test, &cdev_test_ops);
ret = cdev_add(&dev2.cdev_test, MKDEV(dev2.major,dev2.minor), 1);
if(ret < 0)
{
printk(KERN_ERR "cdev2_add, failed\r\n");
}
printk(KERN_ERR "cdev2_add, successed\r\n");
dev2.class = class_create(THIS_MODULE, "test2_class");
dev2.device = device_create(dev2.class, NULL, MKDEV(dev2.major,dev2.minor), NULL, "test2_dev"); return 0;
} static void __exit module_cdev_exit(void)
{
cdev_del(&dev1.cdev_test); //删除添加的字符设备 cdev_test
cdev_del(&dev2.cdev_test); //删除添加的字符设备 cdev_test device_destroy(dev1.class, dev1.dev_num); //删除创建的设备
device_destroy(dev2.class, MKDEV(dev2.major,dev2.minor)); //删除创建的设备 class_destroy(dev1.class); //删除创建的类
class_destroy(dev2.class); //删除创建的类 unregister_chrdev_region(dev1.dev_num, 1); // 释放字符驱动设备号
unregister_chrdev_region(dev1.dev_num+1, 1); // 释放字符驱动设备号 printk(KERN_ERR "module_cdev_exit, bye bye\r\n");
} module_init(module_cdev_init); //注册入口函数
module_exit(module_cdev_exit); //注册出口函数 MODULE_LICENSE("GPL");
MODULE_AUTHOR("my_topeet_drv");
MODULE_VERSION("v1.0.0");

app.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> int main(int arc, char *argv[])
{
int fd1, fd2;
char buf1[64] = "/dev/test1, hello dev1 from app layer in user space\n";
char buf2[64] = "/dev/test2, hello dev2 from app layer in user space\n"; /*设备节点1*/
fd1 = open("/dev/test1_dev", O_RDWR, 0666);
if(fd1 < 0)
{
perror("open /dev/test1_dev error\n");
return fd1;
}
write(fd1, buf1, sizeof(buf1));
close(fd1); /*设备节点2*/
fd2 = open("/dev/test2_dev", O_RDWR, 0666);
if(fd2 < 0)
{
perror("open /dev/test2_dev error\n");
return fd2;
}
write(fd2, buf2, sizeof(buf2));
close(fd2); return 0;
}

结果

root@topeet:/home/topeet/myko$ make insmod
insmod private_data_test.ko
[ 83.775025] Enter Module Init
[ 83.775094] apply_cdev1_num, successed
[ 83.775103] dev1:major is 236,minor isroot@topeet:/home/topeet/myko$ 0
[ 83.775115] cdev_add1, successed
[ 83.775735] dev2:major is 236,minor is 1
[ 83.775765] cdev2_add, successed
./a.out
[ 88.615091] This is cdev_test_ops_open in Kernel
[ 88.615177] This isroot@topeet:/home/topeet/myko$ dev1
[ 88.615188] copy_from_user, successed
[ 88.615197] test_dev->kbuffer is /dev/test1, hello dev1 from app layer in user space
[ 88.615197]
[ 88.615205] This is cdev_test_ops_write in Kernel
[ 88.615219] This is cdev_test_ops_release in Kernel
[ 88.615245] This is cdev_test_ops_open in Kernel
[ 88.615254] This is dev2
[ 88.615260] copy_from_user, successed
[ 88.615265] test_dev->kbuffer is /dev/test2, hello dev2 from app layer in user space
[ 88.615265]
[ 88.615271] This is cdev_test_ops_write in Kernel
[ 88.615278] This is cdev_test_ops_release in Kernel

遇到的坑:

1、设备2的设备号,也要使用动态分配语句 alloc_chrdev_region 来做;

2、设备节点名字必须不一样(设备节点名在语句 device_create 里修改);

3、动态分配语句 alloc_chrdev_region 里的第四个参数,在两次获取设备号的语句中,建议写为不一样的为好。

RK3568,字符设备框架:管理同主设备号、不同次设备号设备的更多相关文章

  1. [连载]《C#通讯(串口和网络)框架的设计与实现》-4.设备驱动管理器的设计

    目       录 第四章           设备驱动管理器的设计... 2 4.1           接口定义... 2 4.2           设备容器... 7 4.3          ...

  2. iNeuOS工业互联平台,开放设备驱动管理、服务驱动管理、云组态自定义画布等,促进平台开放、赋能和落地。发布:v2.3版本。

    目       录 1.      概述... 2 2.      iNeuOS平台演示... 2 3.      设备驱动管理... 2 4.      服务驱动管理... 3 5.      云组 ...

  3. Linux字符设备驱动结构(一)--cdev结构体、设备号相关知识机械【转】

    本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50839042 一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符 ...

  4. linux driver ------ platform模型,通过杂项设备(主设备号是10)注册设备节点

    注册完设备和驱动之后,就需要注册设备节点 Linux杂项设备出现的意义在于:有很多简单的外围字符设备,它们功能相对简单,一个设备占用一个主设备号对于内核资源来说太浪费.所以对于这些简单的字符设备它们共 ...

  5. USB 3.0规范中译本第9章 设备框架

    本文为CoryXie原创译文,转载及有任何问题请联系cory.xie#gmail.com. 设备框架可以被分成三层: 最底层是总线接口层,传送和接收包. 中间层处理在总线接口和设备的各种端点之间路由数 ...

  6. 《连载 | 物联网框架ServerSuperIO教程》- 11.实现设备(驱动)与设备(驱动)交互和级联控制。注:设备驱动模拟金三与普京的对话

    1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架Serve ...

  7. IDE 设备(磁盘/CD-ROM)配置不正确。“ide1:1”上具有一个 IDE 从设备,但没有主设备。此配置在虚拟机中无法正常运行。请使用配置编辑器将磁盘/CD-ROM 从“ide1:1”移到“ide1:0”。

    开启vmware报这个错: IDE 设备(磁盘/CD-ROM)配置不正确.“ide1:1”上具有一个 IDE 从设备,但没有主设备.此配置在虚拟机中无法正常运行.请使用配置编辑器将磁盘/CD-ROM ...

  8. iNeuOS工业互联网操作系统,增加设备驱动的自定义参数模板,适配行业个性化设备的应用场景

    目       录 1.      概述... 2 2.      平台演示... 2 3.      应用过程... 2 1.   概述 增加设备驱动的自定义参数模板,适配行业个性化设备的应用场景. ...

  9. 用java开发微信公众号:测试公众号与本地测试环境搭建(一)

    本文为原创,原始地址为:http://www.cnblogs.com/fengzheng/p/5023678.html 俗话说,工欲善其事,必先利其器.要做微信公众号开发,两样东西不可少,那就是要有一 ...

  10. Linux设备驱动开发详解-Note(11)--- Linux 文件系统与设备文件系统(3)

    Linux 文件系统与设备文件系统(3) 成于坚持,败于止步 sysfs 文件系统与 Linux 设备模型 1.sysfs 文件系统 Linux 2.6 内核引入了 sysfs 文件系统,sysfs ...

随机推荐

  1. OpenHarmony编译构建系统详解,从零搭建windows下开发环境,巨方便!

    自从OpenHarmony更新了dev-tool,就可以在windows下构建鸿蒙(轻量型)系统了,这对于进行MCU开发的朋友们,学习鸿蒙OS会友好许多!我们可以更快的构建出系统,方便快速学习和验证. ...

  2. C语言编程-GCC编译过程

    gcc编译 预处理 ->编译->汇编->链接 预处理 gcc -E helloworld.c -o helloworld.i 头文件展开:不检查语法错误,即可以展开任意文件: 宏定义 ...

  3. IoTSharp:基于 .NET 8.0 的开源物联网平台

    前言 想要快速了解物联网的世界吗?如果你对物联网(IoT)感兴趣,或者正打算开发自己的物联网项目.可以试试 IoTSharp,一个基于 .NET 的开源平台. 无论你是初学者还是有经验的大佬,IoTS ...

  4. docker高级篇-docker-compose容器编排介绍及实战

    Docker-compose是什么?能干嘛?解决了哪些痛点? 是什么? Docker-compose是Docker官方推出 的一个工具软件,可以管理多个Docker容器组成的一个应用.你需要编写一个一 ...

  5. 【面试题】Java中子类和父类静态代码块、非静态代码块、构造函数的执行顺序总结一览表

    在面试的时候,有时候我们会被问到这样的问题:子类A继承父类B,A a = new A();则父类B的构造函数.父类B静态代码块.父类B非静态代码块.子类A构造函数.子类A静态代码块.子类A非静态代码块 ...

  6. 面试官:limit 100w,10为什么慢?如何优化?

    在 MySQL 中,limit X,Y 的查询中,X 值越大,那么查询速度也就越慢,例如以下示例: limit 0,10:查询时间大概在 20 毫秒左右. limit 1000000,10:查询时间可 ...

  7. P3792 由乃与大母神原型和偶像崇拜

    题意 给定长为 \(n\) 的数组 \(a\),支持单点修改,\(q\) 次查询区间 \([l,r]\) 是否可以重排为值域上连续的一段. \(n,q\le5\times10^5,a_i\le2.5\ ...

  8. 从Linq的Where方法理解泛型、委托应用场景

       最近遇到了一个问题,Linq的Where里面传递的是什么?Where的功能是什么实现的?没有第一时间答上来,在整理相关资料后决定自行实现Linq的Where方法来加深印象. 什么是泛型   指在 ...

  9. CSP初赛知识点:Linux 系统

    CSP初赛知识点:Linux 系统 前言 近年 CSP 初赛几乎前 5 道选择题都有一两道有关 Linux 系统的使用,所以作为备战 CSP-J/S 2024 的资料,整理下来啦. 祝各位今年所有考试 ...

  10. 2款.NET开源且免费的Git可视化管理工具

    Git是什么? Git是一种分布式版本控制系统,它可以记录文件的修改历史和版本变化,并可以支持多人协同开发.Git最初是由Linux开发者Linus Torvalds创建的,它具有高效.灵活.稳定等优 ...