Linux中设备驱动的分类

从上图可以看到Linux系统将各异的设备分为三大类:字符设备,块设备和网络设备。内核针对每一类设备都提供了对应驱动模型架构,包括基本的内核设施和文件系统接口。

字符设备:在传送过程中以字符为单位,一个字节一个字节的读写,不能随机的读写数据,因为这类设备读写速度比较缓慢(因而其内核设施中不提供缓存机制),常见的字符设备有键盘,鼠标已打印机设备等。

块设备: 是指可以从任意位置读取数据的设备,对这种设备读写是按块为单位读写的。它使用缓存区来暂存数据,等待条件成熟后,会一并将数据写入到设备或者从设备一次性读出到缓冲区。比较U盘,磁盘,SD卡等。

网络设备: 网络设备不同于字符设备和块设备,它是面向报文的。同时在/dev目录下没有设备节点这样一说,在应用层是用户是通过API的socket函数来使用网络设备的。比如网卡等。

设备号的构成

  • 主设备号与次设备号
    关于设备号,我们先通过如下的图来了解一下

    从上图可以看出,c代表的是字符设备,d代码的是块设备。
    对于红色区域来说,1是主设备号,11是次设备号。
    对于绿色区域来说,7是主设备号,0-7代表是次设备号。
    主设备号用来标识对于的设备驱动程序,而次设备号则由驱动程序使用,用来标识它所管理的若干同类设备。
  • 设备号的表示
    在linux系统中,设备号用dev_t表示。这是个32位的无符号整数。
<inclue/linux/types.h>
---------------------------
typedef __kernel_dev_t      dev_t;
typedef __u32 __kernel_dev_t;

在内核中,dev_t的低20位用来表示次设备号,高12位用来表示主设备号。随着Linux系统的演变,上述的主次设备号的分发可能在将来会发生变化,所以设备驱动程序开发者应该避免直接使用主次设备号所占的位宽来获得对于的主设备号或次设备号。为了保证以后主次设备号所占的位数发生变化之后,驱动程序依然可以正常工作,内核提供了如下了几个宏来操作设备号。

<inclue/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))

其中MAJOR宏用来从一个dev_t类型的设备号中提取出主设备号,MINOR宏从来从一个dev_t类型的设备号中提取出此设备号。MKDEV则是将主设备号ma和次设备号mi合成一个dev_t类型的设备号。

假设在内核版本之后对主次设备号所占的位数发生了变化,MINORBITS修改为18位,只要驱动是使用MAJOR和MINOR宏来操作设备号,就不需要修改驱动代码也可以在新内核中使用。

设备号的分配

在内核源码中,设备号的分配主要有两个函数:

  • 静态分配设备号
<fs/char_dev.c>
----------------------------------------------------------
/*** 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)
{struct char_device_struct *cd;dev_t to = from + count;dev_t n, next;for (n = from; n < to; n = next) {next = MKDEV(MAJOR(n)+1, 0);if (next > to)next = to;cd = __register_chrdev_region(MAJOR(n), MINOR(n),next - n, name);if (IS_ERR(cd))goto fail;}
    return 0;
fail:to = n;for (n = from; n < to; n = next) {next = MKDEV(MAJOR(n)+1, 0);kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));}
    return PTR_ERR(cd);
}

该函数是用来在知道主设备号的前提下使用,第一个参数form表示一个设备号,第二个参数count表示次设备的个数,也就是当前驱动程序所管理的同类设备的个数,第三个参数name表示设备或者驱动的名称。成功返回0,失败返回负数。

比如内核代码中使用register_chrdev_region申请设备号示例:

    #define INPUT_MAJOR     13#define INPUT_MAX_CHAR_DEVICES      1024err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0),INPUT_MAX_CHAR_DEVICES, "input");if (err) {pr_err("unable to register char major %d", INPUT_MAJOR);goto fail2;}

以上代码申请了主设备号为13,总共存在1024个次设备,设备的名字为input。

  • 动态分配设备号
<fs/char_dev.c>
--------------------------------------------------------------------------------------
/*** 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)
{struct char_device_struct *cd;cd = __register_chrdev_region(0, baseminor, count, name);if (IS_ERR(cd))
        return PTR_ERR(cd);*dev = MKDEV(cd->major, cd->baseminor);
    return 0;
}

该函数有系统动态的分配设备号,是在主设备号不知情的情况下,让系统给分配设备号。第一个参数dev表示是输出参数,也就是设备号,第二个参数baseminor表示第一个次设备号编号,第三个参数count表示次设备号的个数,第四个参数name也就是设备或者驱动的名称。

内核中使用alloc_chrdev_region的示例:

#define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */
void __init rtc_dev_init(void)
{int err;err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");if (err < 0)pr_err("failed to allocate char dev region\n");
}

上述示例代码是通过alloc_chrdev_region函数申请设备号,设备的个数为16个,设备的名称为rtc设备。

设备号释放

在驱动程序不使用的时候需要释放设备号,因为设备号也是系统的资源,不用的使用需要及时释放资源。已供其他设备使用。

<fs/char_dev.c>
-----------------------------------------------------------------------------------
/*** 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)
{dev_t to = from + count;dev_t n, next;for (n = from; n < to; n = next) {next = MKDEV(MAJOR(n)+1, 0);if (next > to)next = to;kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));}
}

使用该函数可以使用申请的设备号,第一个参数from表示要释放的设备号,第二个参数count表示要释放的个数。

内核使用unregister_chrdev_region的示例:

#define INPUT_MAJOR     13
#define INPUT_MAX_CHAR_DEVICES      1024
static void __exit input_exit(void)
{unregister_chrdev_region(MKDEV(INPUT_MAJOR, 0),INPUT_MAX_CHAR_DEVICES);
}

从上面代码可知,如果调用unregister_chrdev_region就会从系统中释放主设备号13的设备。

Linux设备驱动之字符设备(一)相关推荐

  1. linux的驱动开发——字符设备驱动

    1.字符设备驱动 \qquad字符设备驱动是最基本,最常用的设备.它将千差万别的硬件设备采用统一的接口封装起来,屏蔽了硬件的差异,简化了应用层的操作. 2.描述所有字符设备的结构体 \qquad描述所 ...

  2. 设备驱动,字符设备驱动、(总线)设备驱动模型、sysfs文件系统、平台设备驱动

    以下内容转载于微信公众号:嵌入式企鹅圈.如有侵权,请告知删除. 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术. 对于初学者来说会非常 ...

  3. linux PCI驱动调用字符设备驱动方式

    上一篇文章写了字符设备驱动的基本结构及访问方式,在实际应用时首先需要绑定自己的硬件设备.本篇主要描述字符设备驱动与PCI接口类型的设备访问方式(内核为2.6.24及以上的方法,测试内核为2.6.32) ...

  4. 深入浅出:Linux设备驱动之字符设备驱动

    一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流 ...

  5. 蜕变成蝶~Linux设备驱动之字符设备驱动

    一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流 ...

  6. 嵌入式linux驱动之———字符设备驱动(一)

    一.简介: 在Linux内核驱动中,字符设备是最基本的设备驱动.字符设备是能够像字节流(比如文件)一样被访问的设备,就是说对它的读写是以子为单位的.比如串口在进行收发数据时就是一个字节一个字节进行的. ...

  7. Linux驱动之字符设备驱动

    系列文章目录 第一章 Linux入门之驱动框架 第二章 Linux驱动之字符设备驱动 文章目录 系列文章目录 前言 一.认识字符设备驱动 1.基本概念 2.基本概念 二.字符设备旧框架 1.注册和注销 ...

  8. 字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联

    参考原文:https://www.kancloud.cn/yueqian_scut/emlinux/106829 对原文笔误地方做了修改.重新排版 目录 字符设备驱动.平台设备驱动.设备驱动模型.sy ...

  9. STM32MP157驱动开发——字符设备驱动

    一.简介 字符设备是 Linux 驱动中最基本的一类设备驱动,字符设备就是一个一个字节,按照字节 流进行读写操作的设备,读写数据是分先后顺序的.比如我们最常见的点灯.按键. IIC. SPI, LCD ...

  10. 驱动学习----字符设备驱动框架

    字符设备驱动框架 1.字符设备驱动简介 2.file_operations 3.驱动模块的加载和卸载 4.字符设备的注册与注销 5.实现设备具体操作函数 6.添加LICENSE和作者信息 7.linu ...

最新文章

  1. 干货来袭-整套完整安全的API接口解决方案
  2. Wireshark网络分析实例集锦2.1.2隐藏、删除、重新排序及编辑列
  3. linux 上配置swoole
  4. 中国节能减排行业十四五运行现状及建设应用价值分析报告2021-2027年
  5. SpringBoot各类型参数解析原理(源码)
  6. Deep-Learning-with-Python] 文本序列中的深度学习
  7. 前端电子书单大分享~~~
  8. git 提交遇到error:fail to push some refer to 远程地址(url)
  9. 正态分布表怎么查表_《深入浅出统计学》-读书笔记-再谈正态分布的应用
  10. 修炼!!!——超越项目经理
  11. Java EE产生的背景
  12. mybatis注解开发-动态SQL
  13. swift野梦抄袭 taylor_如何看待蔡健雅新歌《半途》被指抄袭 Taylor Swift 的《Safe Sound》?...
  14. 【考研数学一】微分方程专讲(初步)
  15. 文读懂安防视频监控系统中H.265、SVAC、GB/T28181、ONVIF、PSIA的区别。
  16. 办公逸CTO王斌:提高产品响应速度应注意的二十五个技术细节
  17. Fiddler简单的使用教程(入门级)
  18. 高通平台开发系列讲解(外设篇)高通Camera软件架构
  19. SPSS数据分析流程经验总结
  20. CM211-1增强版2+16_荣耀飞龙开机动画_当贝桌面卡刷固件

热门文章

  1. java的重载 和重写
  2. 8个很实用的在线工具来提高你的Web设计和开发能力
  3. CentosOS 7: 创建Nginx+Https网站
  4. 5.G - 湫湫系列故事——减肥记I
  5. [转]enable spice html5 console access in openstack kilo(centos)
  6. QString字符串拼接【转载】
  7. (十)unity4.6学习Ugui中文文档-------參考-UGUI Canvas Components
  8. ASP.NET第三方控件网站
  9. 自定义音乐播放器的歌词显示view
  10. 网站漏洞渗透检测过程与修复方案