Linux内核编程(二)杂项设备模型框架

news2024/11/17 5:59:58

本文目录

  • 一、知识点
    • 1. Linux设备分类
    • 2. 设备号
    • 3. Linux 字符设备的几种编程模型
  • 二、杂项设备模型API
    • 1. 杂项设备结构体
    • 2. 注册杂项设备
    • 3. 注销杂项设备
    • 4. copy_from_user
    • 5. copy_to_user
  • 三、字符设备编程

  
查看:内核驱动程序编写环境搭建。

一、知识点

1. Linux设备分类

在 Linux 操作系统下有三类设备:一是字符设备,二是块设备,三是网络设备。

   ●字符设备特点:是一个顺序的数据流设备,对这种设备的读写是按字符进行的,而且这些字符是连续地形成一个数据流。他不具备缓冲区,所以对这种设备的读写是实时的。比如串口,i2c,等。

   ●块设备特点: 是一种具有一定结构的随机存取设备,对这种设备的读写是按块进行的,他使用缓冲区来存放暂时的数据,待条件成熟后,从缓存一次性写入设备或者从设备一次性读到缓冲区。 ddr 内存条,sd 卡,u 盘,emmc,nandflash 这种,它们的传输是有缓冲的。

   ●网络设备特点:络设备是面向数据包的接收和发送而设计的。它并不对应于文件系统(/dev 目录下)的节点,而是由系统分配一个唯一的名字(如 eth0)。以太网,wifi,蓝牙,2/3/4G 模块。一种器件可以同时是 2 种设备,例如蓝牙,它是网络设备,也是字符设备。

   除了网络设备外,字符设备和块设备都是通过文件系统的系统调用接口 open()、close()、write()、read()等函数既可以访问,应用程序可以通过打开设备文件来访问该设备。

2. 设备号

   每个设备文件都都有其文件属性,表示是字符设备(c)还是块设备(b)。
   每个设备文件都有一个设备号,由两部分组成:主设备号和次设备号。其中主设备号用于标识驱动程序,次
设备号用于标识使用同一个设备驱动程序的不同的硬件设备,比如有两个串口,就可以用从设备号来区分他们。

3. Linux 字符设备的几种编程模型

   在目前版本 Linux 3.5 版本内核中,字符设备驱动程序的编程模型有三种:杂项设备驱动模型早期经典字符设备驱动模型Linux 2.6 版本中新出现的 Linux 2.6 标准字符设备驱动模型。本章将具体介绍杂项设备驱动模型来编写字符设备。其余两个模型配置复杂,不常用。

二、杂项设备模型API

   在Linux操作系统中,杂项设备是一类设备文件,用于处理各种非标准或非主要类别的设备。杂项设备通常不属于特定的主要设备类别(如块设备、字符设备等),但它们提供了一种灵活的方式来支持各种特殊硬件或虚拟设备。 头文件:#include <linux/miscdevice.h>

主设备号:固定是 10。
次设备号:0~255, 当传递 255 时候表示自动分配次设备号。

1. 杂项设备结构体

在Linux内核中,struct miscdevice结构体用于定义和管理杂项设备。

struct miscdevice {
    int minor;     //次设备号,使用MISC_DYNAMIC_MINOR表示系统自动分配其次设备号。
    const char *name;  //设备名称,通常会在/dev目录下创建一个对应的设备文件。
    const struct file_operations *fops;//指向文件操作结构的指针,该结构定义了设备文件的操作函数,如打开、关闭、读、写、ioctl等。
  
    ///* 下面的成员是供内核使用 ,驱动编写不需要理会,我们只需要配置上面三个成员即可*
    struct device *parent;
    struct device *this_device;
    const struct attribute_group **groups;
    const char *nodename;
    umode_t mode;
};

   在杂项设备结构体中struct file_operations 是一个非常重要的结构体,它定义了文件操作接口。这些接口允许用户空间程序与内核模块进行交互,通过这些操作可以对设备进行读写、打开、关闭、控制等操作。我们用到哪个就实现哪个函数就行。

struct file_operations {
    struct module *owner; // 指向模块的指针,通常设置为 THIS_MODULE,用于模块引用计数
    loff_t (*llseek) (struct file *, loff_t, int); // 移动文件位置指针,类似于用户空间的 lseek
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); // 读操作函数,从设备读取数据
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); // 写操作函数,向设备写入数据
    ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); // 迭代读操作,适用于较新的文件IO框架
    ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); // 迭代写操作,适用于较新的文件IO框架
    int (*iterate) (struct file *, struct dir_context *); // 文件目录迭代,用于读取目录内容
    int (*iterate_shared) (struct file *, struct dir_context *); // 文件目录迭代的共享版本
    unsigned int (*poll) (struct file *, struct poll_table_struct *); // 轮询操作,用于非阻塞IO
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); // 设备控制操作,无需大内核锁
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long); // 32位系统上与 ioctl 兼容的操作
    int (*mmap) (struct file *, struct vm_area_struct *); // 内存映射操作,将设备内存映射到用户空间
    int (*open) (struct inode *, struct file *); // 打开操作
    int (*flush) (struct file *, fl_owner_t id); // 刷新操作,在文件关闭之前调用
    int (*release) (struct inode *, struct file *); // 释放操作,在文件关闭时调用
    int (*fsync) (struct file *, loff_t, loff_t, int datasync); // 同步操作,将文件缓冲区的数据同步到存储设备
    int (*fasync) (int, struct file *, int); // 异步IO操作的设置
    int (*lock) (struct file *, int, struct file_lock *); // 文件锁操作
    ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); // 发送页面数据
    unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); // 获取未映射区域,用于内存映射
    int (*check_flags)(int); // 检查文件打开标志
    int (*flock) (struct file *, int, struct file_lock *); // 文件锁操作
    ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); // 将数据从管道写入文件
    ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); // 将数据从文件读入管道
    int (*setlease)(struct file *, long, struct file_lock **, void **); // 设置文件租约
    long (*fallocate)(struct file *, int, loff_t, loff_t); // 为文件分配空间
    void (*show_fdinfo)(struct seq_file *m, struct file *); // 显示文件描述符的信息
};

2. 注册杂项设备

返回值:0:表示注册成功;负数:注册失败

int misc_register(struct miscdevice * misc)
//传入杂项设备结构体。

3. 注销杂项设备

不需要判断返回值。

int misc_deregister(struct miscdevice *misc)
//传入杂项设备结构体。

4. copy_from_user

   是 Linux 内核中用于从用户空间拷贝数据到内核空间的函数。这个函数是确保内核空间和用户空间之间数据安全传输的重要机制之一。因为直接访问用户空间内存是不安全的,内核必须通过这些函数来处理数据的传递,以确保不会因为非法内存访问导致系统崩溃。

unsigned long copy_from_user(void *to, const void __user *from, unsigned long n);
//to: 指向内核空间的目标缓冲区。
//from: 指向用户空间的源缓冲区。
//n: 要拷贝的字节数。

5. copy_to_user

   用于将数据从内核空间拷贝到用户空间。这个函数用于内核模块和设备驱动程序中,以安全的方式将数据传递给用户空间。

unsigned long copy_to_user(void __user *to, const void *from, unsigned long n);
//to: 指向用户空间的目标缓冲区。
//from: 指向内核空间的源缓冲区。
//n: 要拷贝的字节数。

三、字符设备编程

编写杂项设备驱动节点给用户使用,编写应用层app.c测试驱动功能是否实现。

hello.c

#include <linux/module.h>     //模块
#include <linux/kernel.h>     //内核
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <asm/uaccess.h>

#define KBUF_SIZE (1024)
#define MIN(x,y) ( (x)<(y)? (x):(y) )      //判断哪个小,选哪个
char kbuf[KBUF_SIZE];

int misc_open(struct inode * node, struct file * fp)
{
    return 0;
}

int misc_release(struct inode *node, struct file *fp)
{
	return 0;
}

ssize_t misc_read(struct file *fp, char __user *ubuf , size_t size, loff_t *offset)
{
	int ret;
	ret=copy_to_user(ubuf, kbuf, MIN(KBUF_SIZE,size));
	if(ret !=0){
		 pr_err("copy_to_user error\r\n");
		 return -EINVAL;
	}   
	return MIN(KBUF_SIZE,size);   //返回成功读取的字节数
}

ssize_t misc_write(struct file *fp, const char __user *ubuf, size_t size, loff_t *offset)
{
   int ret;
   ret=copy_from_user(kbuf, ubuf, MIN(KBUF_SIZE,size));
   if(ret !=0){
     pr_err("copy_from_user error\r\n");
	 return -EINVAL;
   }
    pr_err("%s\r\n",kbuf);         //打印出用户写来的数据
	return MIN(KBUF_SIZE,size);    //返回成功写入的字节数
}

//描述一个文件操作集
const struct file_operations misc_fops={
  .owner=THIS_MODULE,     //文件操作集的拥有者是 本模块。
  .open =misc_open,       //应用层对本模块的驱动节点open时触发的函数
  .release=misc_release,  //应用层对本模块的驱动节点close时触发的函数
  .read=misc_read,        //应用层对本模块的驱动节点read时触发的函数
  .write=misc_write,      //应用层对本模块的驱动节点write时触发的函数
  
};

//描述一个杂项设备
struct miscdevice misc={
 .minor=MISC_DYNAMIC_MINOR, //由内核自动分配次设备号,misc的主设备号为10.
 .name ="qjl",             //在/dev下生成的驱动节点的名称,不能有空格!
 .fops =&misc_fops,
};

static int __init misc_init(void)
{
   int ret;
   ret=misc_register(&misc);  //向内核注册一个杂项设备
   	if(ret <0){
      pr_err("misc_register error\r\n");
	  return -1;
   }

   return 0;
}

static void __exit misc_exit(void)
{
   misc_deregister(&misc);  //从内核注销一个杂项设备
}

module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");

app.c

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

int main(int argc, char **argv)
{
   int fd;
   size_t w_size;
   size_t r_size;
   char w_buff[128]="hello world!";   //向内核写进的数据
   char r_buff[128];
   
   fd = open("/dev/qjl",O_RDWR);
   if(fd <0){
     perror("open error");
	 return -1;
   }
   w_size=write(fd, w_buff, strlen(w_buff));
   printf("w_size:%ld\n",w_size);

 //  lseek(fd,0,SEEK_SET);
   r_size= read(fd, r_buff, sizeof(r_buff));
   printf("w_size:%ld  data:%s\r\n", r_size, r_buff);
   
   close(fd);
   return 0;
}

insmod hello.ko
在这里插入图片描述

在这里插入图片描述

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

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

相关文章

11.2 Go 常用包介绍

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

如何思考生成式人工智能著作权案件中的救济问题

如何思考生成式人工智能著作权案件中的救济问题 迄今为止&#xff0c;在16起指控OpenAI和其他生成人工智能(AI)技术开发商侵犯版权的诉讼中&#xff0c;最引人注目的指控是&#xff0c;为了训练生成人工智能模型而复制受版权保护的作品侵犯了版权。 一些评论员相信&#xff0c…

three.js纹理贴图褪色失真问题解决

网上查的都是加encoding配置&#xff0c;但是最新版本&#xff0c;纹理对象属性名.encoding已经变更为.colorSpace // 纹理贴图加载器 const texLoader new THREE.TextureLoader(); const texture texLoader.load("./test.jpg"); texture.colorSpace THREE.SRGBC…

1.动手学习深度学习课程安排及深度学习数学基础

视频资源B站&#xff1a;动手学习深度学习——李沐 目录 目标内容将学到什么1.N维数组样例2.访问2维数组元素3.数据操作4.线性代数5.矩阵计算6.自动求导 目标 介绍深度学习景点和最新模型 LeNet AlexNet VGG ResNet LSTM BERT… 机器学习基础 损失函数&#xff0c;目标函数&a…

设计师搞得表单页,差点让我看吐血,来教会你。

碰到字段比较多&#xff0c;数据类型也比较多的表单页&#xff0c;该怎么设计了&#xff1f; 设计一个字段非常多、类型很多的移动端表单页时&#xff0c;可以考虑以下几个方面来提高用户体验&#xff1a; 简化表单&#xff1a;将表单字段进行分类和分组&#xff0c;根据用户填…

把Vue文件转至树莓派上遇到的问题和解决方案

把整个文件夹复制进树莓派后&#xff0c;运行 npm run dev ,报错sh: 1: vite: Permission denied 解决方案&#xff1a;删除项目里的 node_modules 重新 npm install 再运行即可 rm -rf node_modules/ npm install 在安装过程中&#xff0c;遇到下图问题&#xff0c;vulnerabi…

【Java笔记】第11章:内部类

前言1. 讲解结语 上期回顾:【Java笔记】第10章&#xff1a;接口 个人主页&#xff1a;C_GUIQU 归属专栏&#xff1a;【Java学习】 前言 各位小伙伴大家好&#xff01;上期小编给大家讲解了Java中的接口&#xff0c;接下来讲讲Java中的内部类&#xff01; 1. 讲解 Java中的内…

【每日刷题】Day63

【每日刷题】Day63 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 414. 第三大的数 - 力扣&#xff08;LeetCode&#xff09; 2. 2265. 统计值等于子树平均值的节点数…

我国间二甲苯零售规模逐渐扩大 进口量有所下滑

我国间二甲苯零售规模逐渐扩大 进口量有所下滑 间二甲苯&#xff08;MX&#xff09;又称为1,3-二甲苯&#xff0c;是苯的两个氢基被两个甲基取代后形成的一种有机化合物。间二甲苯的化学方程式为C8H10&#xff0c;多表现为一种无色透明的液体&#xff0c;不溶于水&#xff0c;但…

人工智能的社会应用:深刻变革的新浪潮

人工智能的社会应用&#xff08;语言文本方面&#xff09; 人工智能在社会应用中的广泛运用体现在多个领域&#xff0c;特别是在语音和文本处理方面。以下是这些技术的一些扩展&#xff1a; 1. 文本翻译&#xff1a; 谷歌翻译&#xff1a;利用深度学习模型&#xff0c;支持100多…

ARM功耗管理框架之SCP

安全之安全(security)博客目录导读 目录 一、功耗管理框架中的SCP 二、SCP的示例 三、SCP固件 四、SCP启动流程 五、SCP的memory map 六、SCP与AP的通信 思考:功耗管理框架?SCP?PPU?LPI?之间的关系?如何配合? 一、功耗管理框架中的SCP 二、SCP的示例

【Python】使用OpenCV特征匹配检测图像中的【特定水印】

如果没有方向 往哪里走都是前方 做自己的光 不需要多亮 曾受过的伤 会长出翅膀 大雨冲刷过的天空会更加明亮 流过泪的眼睛也一样 做自己的光 悄悄的发亮 逆风的方向 更容易飞翔 世界怎样在于你凝视它的目光 那未曾谋面过的远方 或许就在身旁 &#x1f3b5…

Intel 8080接口与Motorola 6800接口定义与应用

本文介绍Intel 8080接口与Motorola 6800接口定义与应用。 Intel 8080接口与Motorola 6800接口是常用的并行总线接口&#xff0c;在MCU与外设直接的接口中经常用到&#xff0c;如MCU与LCD接口&#xff0c;MCU与FPGA之间的接口。本文介绍Intel 8080接口与Motorola 6800接口定义&…

Springboot的小型超市商品展销系统-计算机毕业设计源码01635

摘 要 科技进步的飞速发展引起人们日常生活的巨大变化&#xff0c;电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流&#xff0c;人类发展的历史正进入一个新时代。在现实运用中&#xff0c;应用软件的工作…

通用大模型VS垂直大模型,相辅相成!

1.通用大模型&#xff1a; 如OpenAI的GPT系列、Google的PaLM等&#xff0c;因其广泛的训练数据来源和强大的泛化能力&#xff0c;展现出在多种任务和场景中的应用潜力。它们能够处理从文本生成、代码编写到语言翻译等多种复杂任务&#xff0c;适应性强&#xff0c;减少了针对单…

视频格式转换avi格式怎么弄?分享视频转换方法

视频格式转换avi格式怎么弄&#xff1f;AVI作为一种广泛支持的视频格式&#xff0c;能够在多种设备和播放器上顺畅播放&#xff0c;确保我们的视频内容能够无障碍地分享给朋友或上传至各大平台。其次&#xff0c;AVI格式通常具有较好的兼容性&#xff0c;能够避免格式转换过程中…

模拟信号转RS-485/232,数据采集A/D转换模块 YL21

特点&#xff1a; ● 模拟信号采集&#xff0c;隔离转换 RS-485/232输出 ● 采用12位AD转换器&#xff0c;测量精度优于0.1% ● 通过RS-485/232接口可以程控校准模块精度 ● 信号输入 / 输出之间隔离耐压3000VDC ● 宽电源供电范围&#xff1a;8 ~ 32VDC ● 可靠性高&…

CPN tools学习——可执行的 PN

目录 1添加令牌 2.转换防护Guard 1添加令牌 左侧新建颜色集和变量的声明定义&#xff1a; 为库所分配颜色集&#xff1a;左键tab键 P1处&#xff1a;添加多重集合&#xff0c;表示添加了两个令牌&#xff0c;第一个令牌值为A&#xff0c;第二个为B。 P2处&#xff1a;表示…

VMware清理拖拽缓存

磁盘空间越用越小&#xff0c;如何快速解决磁盘空间的问题&#xff0c;甩掉烦恼 安装VM tools之后可以通过拖拽的方式把文件拉入虚拟机之中。但每一次拖拽&#xff0c;其实都是现在cache文件夹里面生成一个同样的文件&#xff0c;并使用cp拷贝的方式将其拷贝到拖拽放置的目录中…

云平台DNS故障导致网站访问卡顿异常排查过程,wireshark、strace等工具在实际问题排查过程中的应用方法

一、问题现象 项目上使用华为私有云&#xff0c;前段时间华为升级云平台后&#xff0c;云上用户反馈业务系统出现卡顿&#xff0c;之前几秒可以刷新出来的页面现在需要几十秒。提供了一个比较明显的url和curl调用方法。 10.213.x.xxx:8082/files/login curl -H "Content-…