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

2. 字符设备驱动

一、设备号

1.1. 什么是设备号

设备号是用来标记一类设备以及区分这类设备中具体个体的一组号码。

设备号由主设备号和次设备号组成。主设备号的作用为标记一类设备、用于标识设备驱动程序,而次设备号的作用是为了区分这类设备中的具体个体设备及用于标识同一驱动程序下的具体设备;通过该区分,系统可以准确的识别和操作每一个设备和对设备的有效管理,提高设备的利用率和可扩展性。

在Linux中设备号的定义通常使用dev_t,该类型需要包含头文件include/linux/types.h,查看其定义我们可以发现它其实就是一个32位的无符号整型变量;其中主设备号为高12位(同类型驱动个数为0~212−10~2^{12}-102121),次设备号为低20位(挂载设备为0~220−10~2^{20}-102201)。

Linux中为我们提供了相关宏用于处理设备号,这些宏位于include/linux/kdev_t.h中:

#define MINORBITS 20      /* 次设备号位数 */
#define MINORMASK ((1U << MINORBITS) - 1)/* 获取主设备号 */
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
/* 获取次设备号 */
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
/* 主+次组成设备号 */
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))

1.2. 设备号的获取、释放和查看

1.2.1. 获取设备号

获取设备号的方式有两种:静态分配和动态分配,都是Linux内核提供的接口,该接口位于linux/fs.h中。

  • 静态分配register_chrdev_region
    函数原型:
/*** register_chrdev_region() - register a range of device numbers* @from: the first in the desired range of device numbers; must include the major number.* @count: the number of consecutive device numbers required* @name: the name of the device or driver.** Return value is zero on success, a negative error code on failure.
*/
int register_chrdev_region(dev_t from, unsigned count, const char *name);
  • 动态分配alloc_chrdev_region
    函数原型:
/*** alloc_chrdev_region() - register a range of char device numbers* @dev: output parameter for first assigned number* @baseminor: first of the requested range of minor numbers* @count: the number of minor numbers required* @name: the name of the associated device or driver** Allocates a range of char device numbers. The major number will be* chosen dynamically, and returned (along with the first minor number)* in @dev. Returns zero or a negative error code.*/
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);

1.2.2. 释放设备号

  • 释放设备号
    函数原型:
/*** unregister_chrdev_region() - return a range of device numbers* @from: the first in the range of numbers to unregister* @count: the number of device numbers to unregister** This function will unregister a range of @count device numbers,* starting with @from. The caller should normally be the one who* allocated those numbers in the first place...*/
void unregister_chrdev_region(dev_t from, unsigned count);

1.2.3. 查看设备号

  • 指令lsblk
    待补充
  • 查看文件/proc/devices
    通过cat /proc/devices将所有的设备号全部打印出来,如下:
Character devices: # 字符设备1 mem4 /dev/vc/04 tty4 ttyS
Block devices: # 块设备7 loop8 sd9 md
254 mdp
259 blkext

1.3. 栗子

驱动代码

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/kdev_t.h>int Isalloc = 0; /* 是否动态申请设备号:0-静态申请、非0-动态申请 */
int Major = 0;
int Minor = 0;module_param(Isalloc, int, S_IRUGO);
MODULE_PARM_DESC(Isalloc, "e.g.是否动态申请: 0-静态申请(需输入设备号),非0-动态申请(输入设备号无效).");
module_param(Major, int, S_IRUGO);
MODULE_PARM_DESC(Major, "e.g.主设备号");
module_param(Minor, int, S_IRUGO);
MODULE_PARM_DESC(Minor, "e.g.次设备号");dev_t chrdev_region = 0;static int chrdev_region_init(void)
{if (0 == Isalloc){/* 静态申请设备号 */chrdev_region = MKDEV(Major, Minor);/* zhf是驱动程序名称 */int i32Ret = register_chrdev_region(chrdev_region, 1, "zhf");if (0 > i32Ret){printk("register_chrdev_region err %d \n", i32Ret);}}else{/* 动态申请设备号 zhf是驱动程序名称 */int i32Ret = alloc_chrdev_region(&chrdev_region, 0, 1, "zhf");if (0 > i32Ret){printk("alloc_chrdev_region err %d \n", i32Ret);}}/* 设备号打印 */printk("chrdev region ok major:%d minor:%d\n", MAJOR(chrdev_region), MINOR(chrdev_region));return 0;
}static void chrdev_region_exit(void)
{/* 设备号销毁 */unregister_chrdev_region(&chrdev_region, 1);printk("unregister_chrdev_region ok \n");
}module_init(chrdev_region_init);
module_exit(chrdev_region_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhf");

二、字符设备驱动

2.1. 什么是字符设备

字符设备是一种用于传输字符或字节流的设备。其实就是传"acnah"这样的ASSIC码。常见的字符设备包括键盘、鼠标、串口等设备。字符设备以字节为单位进行读取和写入。

字符设备的交互方式:字符设备在系统中会被表示为设备文件,用户可通过打开设备文件与字符设备进行交互。

2.2. 字符设备的操作

2.2.1. 注册字符设备

定义字符类设备需要用到cd

http://www.dtcms.com/a/312806.html

相关文章:

  • LeetCode Hot 100,快速学习,不断更
  • #C语言——刷题攻略:牛客编程入门训练(四):运算
  • Kazam产生.movie.mux后恢复视频为.mp4
  • 小宿科技:AI Agent 的卖铲人
  • zookeeper持久化和恢复原理
  • idea中.xml文件的块注释快捷键
  • Hugging Face 模型文件介绍
  • IDEA查看源码利器XCodeMap插件
  • 【高等数学】第七章 微分方程——第八节 常系数非齐次线性微分方程
  • 【lucene】ByteBuffersIndexInput
  • k8s日志收集
  • Redis面试精讲 Day 8:Stream消息队列设计与实现
  • 对接古老系统的架构实践:封装混乱,走向有序
  • [硬件电路-146]:模拟电路 - DCDC与LDO详解、常见芯片、管脚定义
  • 基于 LangChain + 通义千问 + bge-large 中文 Embedding 搭建一个RAG问答示例
  • TVS二极管数据手册解读
  • 【lucene】ByteBufferGuard
  • Android 之 MVVM架构
  • 【MySQL】MySQL中锁有哪些?
  • Flutter 函数的基本使用
  • day39 力扣198.打家劫舍 力扣213.打家劫舍II 力扣337.打家劫舍 III
  • 常见框架漏洞靶场攻略
  • Java 实现poi方式读取word文件内容
  • 力扣967:连续差相同的数字
  • Mysql1
  • Docker-03.快速入门-部署MySQL
  • python的蛋糕店管理系统
  • MySQL的创建管理表:
  • 求根到叶子节点数字之和
  • 【数据分享】南京诗歌文学地理数据集(获取方式看文末)