在了解Linux字符设备先了解一下Linux设备的分类。

Linux设备分类

Linux设备主要分为字符设备、块设备、网络设备。
字符设备:能够像字节流一样被访问且没有缓冲是按顺序访问的设备,当对字符设备发出读写请求,相应的IO操作立即发生。Linux系统中很多设备都是字符设备,绝大多数的设备都是字符设备。比如LED、按键、键盘、串口、传感器、LCD。字符设备驱动通过字符设备文件来访问。
块设备:按照数据块来访问且有缓冲是具有随机访问能力的设备,比如访问硬盘就不是一个字节一个字节的访问,而是直接访问数据块,数据块的大小是固定的但是不同的系统不一样。比如内存、磁盘、SD卡、U盘。块设备驱动通过块设备文件来访问。
网络设备:网络设备由Linux的网络子系统驱动,负责数据包的发送和接收,而不是面向流设备,因此在Linux系统文件系统中网络设备没有节点。访问网络设备不通过文件,通过套接字(网络通信地址)访问。

本文重点讲字符设备。

字符设备

驱动是沟通硬件和上层应用的媒介,字符设备驱动通过字符设备文件来访问,访问设备文件使用文件IO,在用户层访问设备文件和普通文件的方法是没有区别。
那如何找到设备文件相对应的驱动呢?
Linux中所有的设备文件都在/dev目录下,而通过设备号就可以将设备文件和驱动联系起来。

设备号

设备号分为主设备号和次设备号。其中主设备号是用来区分不同类别的设备,而次设备号用来区分一类设备中的不同个体。例如输入设备和输出设备是不同的主设备号,但是输入设备不只一种,像鼠标和键盘都是输入设备就要使用次设备号来区分。
可以在/proc/devices文件中查询哪些主设备号以及被使用了。
字符设备:

块设备:

设备号数据类型:dev_t原型是一个32位无符号整形类型的值(unsigned int ),其中高12位表示主设备号,低20位表示次设备号。

内核中提供了操作设备号的宏

MAJOR(设备号);//通过设备号获取主设备号
MINOR(设备号);//通过设备号获取次设备号
MKDEV(主设备号,次设备号);//通过主设备号和次设备号构造设备号

一起看看宏的原型

#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))

获取主设备号的宏MAJOR是通过将设备号右移20位留下高12位的主设备号。
获取次设备号的宏MINOR是通过将1左移20位(1U表示无符号整型1,C语言默认常数是有符号整型)再减一就变成了前12位为0,后20位为1了。然后与上设备号就获得了低20位的次设备号。
获取设备号的宏MKDEV是通过将主设备左移20位再或上次设备号就得到了完整的设备号。
设备号在内存中属于资源(虽然有很多,估计也用不完,但毕竟是有限的且不同共用),所以需要使用设备号就要向系统申请。

申请设备号

首先需要加上两个头文件。

#include <linux/cdev.h>
#include <linux/fs.h>

系统提供了两种申请方法:静态申请和动态申请。
静态申请

  • 选择一个内核中未被使用的主设备号(在/proc/devices中查看)。
  • 根据设备个数分配次设备号,一般从0开始。
  • 使用宏构造完整的设备号。
  • 调用函数register_chrdev_region向系统申请。
  • 不再使用设备号需要注销,通过函数unregister_chrdev_region实现注销。

int register_chrdev_region(dev_t from, unsigned count, const char *name);
参数:
from - 要申请的起始设备号
count - 设备号个数
name - 设备号在内核中对应的名称
返回0表示成功,返回非0表示失败

void unregister_chrdev_region(dev_t from, unsigned count);
参数:
from - 要注销的起始设备号
count - 设备号个数

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>//主设备号
#define CDD_MAJOR 220
//起始次设备号
#define CDD_MINOR 0
//设备号个数
#define CDD_COUNT 1//设备号
dev_t dev;//加载函数
int cdd_init(void)
{int ret;//构造设备号dev = MKDEV(CDD_MAJOR, CDD_MINOR);// 1.静态申请设备号ret = register_chrdev_region(dev, CDD_COUNT, "cdd_demo");if(ret<0){printk("register_chrdev_region failed!\n");return ret;}printk("register_chrdev_region success!\n");return 0;
}//卸载函数
void cdd_exit(void)
{//注销设备号unregister_chrdev_region(dev, CDD_COUNT);
}//声明为模块的入口和出口
module_init(cdd_init);
module_exit(cdd_exit);MODULE_LICENSE("GPL");//GPL模块许可证

动态申请
就是向系统申请一个设备号,系统自动分配一个没有使用过的设备号。
使用函数alloc_chrdev_region向系统申请。

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name);
参数:
dev - 设备号的地址
baseminor - 起始次设备号
count - 设备号个数
name - 设备号在内核中对应的名称
返回0表示成功,返回非0表示失败

注销使用的也是函数register_chrdev_region。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>//起始次设备号
#define CDD_MINOR 0
//设备号个数
#define CDD_COUNT 1//设备号
dev_t dev;//加载函数
int cdd_init(void)
{int ret;// 2.动态态申请设备号ret = alloc_chrdev_region(&dev, CDD_MINOR, CDD_COUNT, "cdd_demo");if(ret<0){printk("register_chrdev_region failed!\n");return ret;}printk("register_chrdev_region success!\n");printk("major number:%d\n",MAJOR(dev));return 0;
}//卸载函数
void cdd_exit(void)
{//注销设备号unregister_chrdev_region(dev, CDD_COUNT);
}//声明为模块的入口和出口
module_init(cdd_init);
module_exit(cdd_exit);MODULE_LICENSE("GPL");//GPL模块许可证


好了,最后如果有什么说的不对的地方欢迎在评论区指正。

Linux驱动字符设备(设备号的申请)相关推荐

  1. Linux驱动-字符设备驱动

    Linux驱动-字符设备驱动 前言 一.预备知识 1.file_operations结构体 2.地址映射 二.涉及的API函数 1.字符设备驱动 1.1.设备号 1.1.1.register_chrd ...

  2. Linux驱动开发之主设备号找驱动,次设备号找设备

    原创作品,转载时请务必以超链接形式标明文章原始出处:http://blog.csdn.net/gqb666/article/details/8805179,作者:gqb666 一.引言   最近成都地 ...

  3. linux主设备编号从0到多少,Linux驱动开发之主设备号找驱动,次设备号找设备

    一.引言 很久前接触linux驱动就知道主设备号找驱动,次设备号找设备.这句到底怎么理解呢,如何在驱动中实现呢,在介绍该实现之前先看下内核中主次设备号的管理: 二.Linux内核主次设备号的管理 Li ...

  4. linux uart寄存器 代替 printk,Linux驱动学习之设备树(设备树下的LED驱动实验),...

    Linux驱动学习之设备树(设备树下的LED驱动实验), 概念 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.相当于从驱动代码分离出来的配置文件,比如串口的波特率通过设 ...

  5. 【Linux驱动开发】设备树详解(二)设备树语法详解

    ​ 活动地址:CSDN21天学习挑战赛 [Linux驱动开发]设备树详解(一)设备树基础介绍 [Linux驱动开发]设备树详解(二)设备树语法详解 [Linux驱动开发]设备树详解(三)设备树Kern ...

  6. 十五、linux 注册字符类设备和生成节点

    一. 注册字符类设备 • 分配内存空间函数kmalloc         – 分配连续的虚拟地址,用于小内存分配.在include/linux/slab.h文件中.         – 参数1:申请的 ...

  7. 十六、Linux驱动之块设备驱动

    1. 基本概念 块设备是Linux三大设备之一,其驱动模型主要针对磁盘,Flash等存储类设备,块设备(blockdevice)是一种具有一定结构的随机存取设备,对这种设备的读写是按块(所以叫块设备) ...

  8. Linux驱动开发|块设备驱动

    块设备驱动 块设备驱动是 Linux 三大驱动类型之一,块设备驱动比字符设备驱动复杂得多,不同类型的存储设备又对应不同的驱动子系统,下面介绍块设备驱动框架及使用 一.块设备介绍 块设备是针对存储设备的 ...

  9. Linux驱动之平台设备

    <平台设备设备驱动> a:背景: 平台总线是Linux2.6的设备驱动模型中,关心总线,设备和驱动这3个实体.一个现实的Linux设备和驱动通常需要挂接在一种总线上(比如本身依附于PCI, ...

最新文章

  1. 用SHELL脚本来防SSH暴力破解
  2. CentOS7Jenkins安装
  3. 【移动端vue ui框架学习】vue项目如何使用基于vue的UI框架mint ui
  4. 2017.12.1T19_B2_2zuoye
  5. 关于.NET微服务最热门的问题解答
  6. swift 拖动按钮_Swift - 单元格滑动按钮库SwipeCellKit使用详解1(基本用法)
  7. 人与人之间关系的随想
  8. CCP/XCP和T-BOX知识点
  9. C++11多线程实现银行存取款案例
  10. 为 VS Code 配置 C++ task,增加外部库文件并且自动运行脚本 | 应用 powershell 语句
  11. 面试题 -二元查找树转变成排序的双向链表
  12. Ppmap - XSS扫描器
  13. 学神经网络需要什么基础,神经网络从入门到精通
  14. oracle exadata效果,exadata成功案例与性能测试-oracle.pdf
  15. PHP爬取搜狗微信文章内容
  16. Windows强制删除文件的方法
  17. Sqlite3 stmt 机制操作
  18. 基于扩展卡尔曼滤波的多传感器融合定位
  19. 基于SSM的知识库管理系统
  20. 农民股神六万元博出千万身家

热门文章

  1. 计算机网络子网划分工具,子网计算工具(子网划分工具)
  2. 苹果iPad 2倒计时:乔布斯不出席 或出白色版,SW1H
  3. 2022-2028年中国USB键盘行业市场竞争状况及发展趋向分析报告
  4. damn small linux试玩
  5. C++ 中 参数包 (typename ...) 学习笔记
  6. 为什么我们要邀请孙老师来分享?
  7. [C++] 反编译器
  8. 零基础自学R语言 1 R语言介绍 1.3 R扩展软件包的安装与管理
  9. Axure 9 实战案例,动态面板的应用 4.1,省市区三级联动下拉菜单(重制简易版)
  10. 参加工作必备的几款软件