当前位置: 首页 > 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.lryc.cn/news/609323.html

相关文章:

  • IO流-对象流
  • 克罗均线策略思路
  • `npm error code CERT_HAS_EXPIRED‘ 问题
  • Java Stream API 编程实战
  • 2025年渗透测试面试题总结-2025年HW(护网面试) 77-1(题目+回答)
  • 《测试驱动的React开发:从单元验证到集成协同的深度实践》
  • 【2025ICCV-目标检测方向】WaveMamba:用于 RGB-红外目标检测的小波驱动曼巴融合
  • 百度招黑产溯源安全工程师
  • SQL注入SQLi-LABS 靶场less31-38详细通关攻略
  • Maxscript在选择的可编辑多边形每个面上绘制一个内部圆形
  • 【高等数学】第七章 微分方程——第十节 常系数线性微分方程组解法举例
  • [硬件电路-140]:模拟电路 - 信号处理电路 - 锁定放大器概述、工作原理、常见芯片、管脚定义
  • 类与对象(中),咕咕咕
  • Zama的使命
  • 零确认双花攻击
  • 8月3日星期日今日早报简报微语报早读
  • 《从原理到实践:MySQL索引优化与SQL性能调优全解析》
  • 【Redis学习路|第一篇】初步认识Redis
  • C的运算符与表达式
  • BP神经网络:当线性模型已到尽头,如何用“人造大脑”挖掘非线性预测规律?
  • 26李林880高数第二章 一元函数微分学及其应用
  • Kafka 是什么?
  • SpringBoot项目数据脱敏(自定义注解)
  • C语言基础03——数组——习题
  • GPIO交换矩阵和IO_MUX
  • 自动驾驶控制算法——LQR控制算法
  • 直流无刷电机(一)
  • C++ <type_traits> 应用详解
  • 10.Redis 数据类型
  • Maximum Subarray Sum II