百篇博客系列篇.本篇为:
v67.xx 鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备
文件系统相关篇为:
- v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一切皆是文件
- v63.xx 鸿蒙内核源码分析(文件系统篇) | 用图书管理说文件系统
- v64.xx 鸿蒙内核源码分析(索引节点篇) | 谁是文件系统最重要的概念
- v65.xx 鸿蒙内核源码分析(挂载目录篇) | 为何文件系统需要挂载
- v66.xx 鸿蒙内核源码分析(根文件系统) | 先挂到
上的文件系统/
- v67.xx 鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备
- v68.xx 鸿蒙内核源码分析(VFS篇) | 文件系统和谐共处的基础
- v69.xx 鸿蒙内核源码分析(文件句柄篇) | 你为什么叫句柄 ?
- v70.xx 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本
什么是设备
设备(device): 是提供输入或输出功能的一种载体,其包括物理设备(对实际存在的物理硬件的抽象)例如,键盘是一种输入设备,硬盘是输入和输出设备。也包括虚拟设备(不依赖于特定的物理硬件,仅是内核自身提供的模拟/虚拟功能). 例如:虚拟控制台是输入和输出设备。每个设备都对应一个文件(设备文件),这些设备文件统一放在一个公共位置
/dev
下管理,通过设备文件(或称设备节点)来使用驱动程序操作设备。
设备按照存取方式的不同,分为两类:
- 字符设备: 字符设备按字符处理。最明显的例子是键盘,其中每个键在设备上生成一个字符。还有鼠标,每一个动作或按钮点击都会发送一个字符到 /dev/mouse 设备。字符设备可理解为商品零售商,可以一件一件的卖,卖的细自然就卖的少.
- 块设备:以更大的块读取数据的存储设备,如IDE硬盘也叫机械硬盘(/dev/hd)、SCSI硬盘也叫固态硬盘(/dev/sd) 和 CD-ROM (/dev/cdrom) 是块设备。输入输出与块设备的交互处理数据块,允许大量数据来回移动提高效率。块设备可理解为商品批发商,必须一箱一箱的卖,卖的粗但吞吐量大.
- 字符设备还是块设备的定义属于内核设备访问层,与实际物理设备的特性无必然联系。设备访问层下面是驱动程序,存取方式取决于驱动程序是否支持,也可以同时支持两种方式访问物理设备,是块设备还是字符设备由使用者(往往是内核)决定。
鸿蒙系统中常见的字符设备如下:
mem | 内存设备
/dev/mem 物理内存的全镜像。可以用来直接存取物理内存。
/dev/kmem 内核看到的虚拟内存的全镜像。其访问的是虚拟内存而不是物理内存。
/dev/null 空设备。也叫黑洞设备,任何写入都将被直接丢弃(但返回"成功");任何读取都将得到EOF(文件结束标志)。
/dev/port 存取I/O端口
/dev/zero 零流源。任何写入都将被直接丢弃(但返回"成功");任何读取都将得到无限多的二进制零流。
/dev/full 满设备。任何写入都将失败,并把errno设为ENOSPC(没有剩余空间);任何读取都将得到无限多的二进制零流。
这个设备通常被用来测试程序在遇到磁盘无剩余空间错误时的行为。
/dev/random 真随机数发生器。以背景噪声数据或硬件随机数发生器作为熵池,读取时会返回小于熵池噪声总数的随机字节。
若熵池空了,读操作将会被阻塞,直到收集到了足够的环境噪声为止。建议用于需要生成高强度密钥的场合。
[注意]虽然允许写入,但企图通过写入此文件来"预存"随机数是徒劳的,因为写入的数据对输出并无影响。
/dev/urandom 伪随机数发生器。更快,但是不够安全。仅用于对安全性要求不高的场合。
即使熵池空了,读操作也不会被阻塞,而是把已经产生的随机数做为种子来产生新的随机数。
[注意]虽然允许写入,但企图通过写入此文件来"预存"随机数是徒劳的,因为写入的数据对输出并无影响。
/dev/aio 异步I/O通知接口
/dev/kmsg 任何对该文件的写入都将作为printk的输出;而读取则得到printk的输出缓冲区内容。
- 在鸿蒙,
是一个字符设备, 源文件是 kernel/drivers/char/mem/src/mem.c, 这个设备文件是专门用来读写物理地址用的。里面的内容是所有物理内存的地址以及内容信息。通常只有root用户对其有读写权限。利用/dev/mem
和mmap
建立起直接读写系统物理内存的渠道。利用/dev/mem
和/dev/mem
导出系统物理地址,免去了用户虚拟地址到内核逻辑地址的繁琐拷贝,提升效率。mmap
//文件和线性区的映射关系 static ssize_t MemMap(struct file *filep, LosVmMapRegion *region) { #ifdef LOSCFG_KERNEL_VM size_t size = region->range.size; PADDR_T paddr = region->pgOff << PAGE_SHIFT; VADDR_T vaddr = region->range.base; LosVmSpace *space = LOS_SpaceGet(vaddr); if ((paddr >= SYS_MEM_BASE) && (paddr < SYS_MEM_END)) { return -EINVAL; } /* Peripheral register memory adds strongly ordered attributes */ region->regionFlags |= VM_MAP_REGION_FLAG_STRONGLY_ORDERED; if (space == NULL) { return -EAGAIN; }//映射 if (LOS_ArchMmuMap(&space->archMmu, vaddr, paddr, size >> PAGE_SHIFT, region->regionFlags) <= 0) { return -EAGAIN; } #else UNUSED(filep); UNUSED(region); #endif return 0; } // vfs 接口实现 static const struct file_operations_vfs g_memDevOps = { MemOpen, /* open */ MemClose, /* close */ MemRead, /* read */ MemWrite, /* write */ NULL, /* seek */ NULL, /* ioctl */ MemMap, /* mmap */ #ifndef CONFIG_DISABLE_POLL NULL, /* poll */ #endif NULL, /* unlink */ }; // 注册/dev/mem 的驱动程序 int DevMemRegister(void) { return register_driver("/dev/mem", &g_memDevOps, 0666, 0); /* 0666: file mode */ }
tty | 终端设备
TTY 是 Teletype 或 Teletypewriter 的缩写,原来是指电传打字机,后来这种设备逐渐键盘和显示器取代。不管是电传打字机还是键盘显示器,都是作为计算机的终端设备存在的,所以 TTY 也泛指计算机的终端(terminal)设备,一般分成以下几种
- 串行端口终端(/dev/ttySn)
- 伪终端(/dev/pty/)
- 控制终端(/dev/tty)
- 控制台终端(/dev/ttyn, /dev/console),将在后续 控制台篇 中详细说明
RTC | 时钟设备
/dev/rtc 实时时钟(Real Time Clock)
- RTC(real-time clock)为操作系统中的实时时钟设备,为操作系统提供精准的实时时间和定时报警功能。当设备下电后,通过外置电池供电,RTC继续记录操作系统时间;设备上电后,RTC提供实时时钟给操作系统,确保断电后系统时间的连续性
- RTC它可以用于产生年、月、日、时、分、秒等信息。目前实时时钟芯片大多采用精度较高的晶体振荡器作为时钟源。有些时钟芯片为了在主电源掉电时还可以工作,会外加电池供电,使时间信息一直保持有效。
- 鸿蒙RTC设备API接口功能介绍
RtcOpen 获取RTC设备驱动句柄 RtcClose 释放RTC设备驱动句柄 RtcReadTime 读RTC时间信息,包括年、月、星期、日、时、分、秒、毫秒 RtcWriteTime 写RTC时间信息,包括年、月、星期、日、时、分、秒、毫秒 RtcReadAlarm 读RTC报警时间信息 RtcWriteAlarm 写RTC报警时间信息 RtcRegisterAlarmCallback 注册报警超时回调函数 RtcAlarmInterruptEnable 使能/去使能RTC报警中断 RtcGetFreq 读RTC外接晶振频率 RtcSetFreq 配置RTC外接晶振频率 RtcReset RTC复位 RtcReadReg 读用户自定义寄存器 RtcWriteReg 写用户自定义寄存器
I2C | 总线设备
/dev/i2c-0 第1个 I2C 适配器
...
/dev/i2c-n 第n-1个 I2C 适配器
- I2C(Inter Integrated Circuit)总线是由Philips公司开发的一种简单、双向二线制同步串行总线。
- I2C以主从方式工作,通常有一个主设备和一个或者多个从设备,主从设备通过SDA(SerialData)串行数据线以及SCL(SerialClock)串行时钟线两根线相连,如下图所示。
- I2C数据的传输必须以一个起始信号作为开始条件,以一个结束信号作为传输的停止条件。数据传输以字节为单位,高位在前,逐个bit进行传输。
- I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址,当主设备需要和某一个从设备通信时,通过广播的方式,将从设备地址写到总线上,如果某个从设备符合此地址,将会发出应答信号,建立传输。
- I2C接口定义了完成I2C传输的通用方法集合,包括:
- I2C控制器管理: 打开或关闭I2C控制器
- I2C消息传输:通过消息传输结构体数组进行自定义传输
- 鸿蒙I2C驱动API接口功能介绍
I2cOpen 打开I2C控制器 I2cClose 关闭I2C控制器 I2cTransfer 自定义传输,I2c消息传输接口
SPI | 串行外设设备
- SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线。
- SPI是由Motorola公司开发,用于在主设备和从设备之间进行通信,常用于与闪存、实时时钟、传感器以及模数转换器等进行通信。
- SPI以主从方式工作,通常有一个主设备和一个或者多个从设备。主设备和从设备之间一般用4根线相连,它们分别是:
- SCLK – 时钟信号,由主设备产生;(Serial Clock)
- MOSI – 主设备数据输出,从设备数据输入;(SPI Bus Master Output/Slave Input)
- MISO – 主设备数据输入,从设备数据输出;(SPI Bus Master Input/Slave Output)。
- CS – 片选,从设备使能信号,由主设备控制。(Chip select)
- SPI主从设备连接示意图
- SPI通信通常由主设备发起,通过以下步骤完成一次通信:
- 通过CS选中要通信的从设备,在任意时刻,一个主设备上最多只能有一个从设备被选中。
- 通过SCLK给选中的从设备提供时钟信号。
- 基于SCLK时钟信号,主设备数据通过MOSI发送给从设备,同时通过MISO接收从设备发送的数据,完成通信。
- 根据SCLK时钟信号的CPOL(Clock Polarity,时钟极性)和CPHA(Clock Phase,时钟相位)的不同组合,SPI有以下四种工作模式:
- CPOL=0,CPHA=0 时钟信号idle状态为低电平,第一个时钟边沿采样数据。
- CPOL=0,CPHA=1 时钟信号idle状态为低电平,第二个时钟边沿采样数据。
- CPOL=1,CPHA=0 时钟信号idle状态为高电平,第一个时钟边沿采样数据。
- CPOL=1,CPHA=1 时钟信号idle状态为高电平,第二个时钟边沿采样数据。
- SPI接口定义了操作SPI设备的通用方法集合,包括:
- SPI设备句柄获取和释放。
- SPI读写: 从SPI设备读取或写入指定长度数据。
- SPI自定义传输:通过消息传输结构体执行任意读写组合过程。
- SPI设备配置:获取和设置SPI设备属性。
- 鸿蒙SPI驱动API接口功能介绍
SpiOpen 获取SPI设备句柄 SpiClose 释放SPI设备句柄 SpiRead 读取指定长度的数据 SpiWrite 写入指定长度的数据 SpiTransfer SPI数据传输接口 SpiSetCfg 根据指定参数,配置SPI设备 SpiGetCfg 获取SPI设备配置参数
UART | 串口设备
/dev/ttyS0 第1个UART串口(Serial port)
...
/dev/ttyS200 第199个UART串口
- 串口设备是终端设备的一种,采用 /dev/ttySn 或 /dev/tts/n 来表示,分别对应于windows系统下的COM1、COM2等。若要向一个端口发送数据,可以在命令行上把标准输出重定向到这些特殊文件名上即可,例如,在命令行提示符下键入:echo test > /dev/ttyS1会把单词”test”发送到连接在ttyS1(COM2)端口的设备上。
- UART(Universal Asynchronous Receiver/Transmitter)通用异步收发传输器,UART 作为异步串口通信协议的一种,工作原理是将传输数据的每个字符一位接一位地传输。是在应用程序开发过程中使用频率最高的数据总线。
- UART应用比较广泛,常用于输出打印信息,也可以外接各种模块,如GPS、蓝牙等。
- UART 串口的特点是将数据一位一位地顺序传送,只要 2 根传输线就可以实现双向通信,一根线发送数据的同时用另一根线接收数据。UART 串口通信有几个重要的参数,分别是波特率、起始位、数据位、停止位和奇偶检验位,对于两个使用 UART 串口通信的端口,这些参数必须匹配,否则通信将无法正常完成。UART 串口传输的数据格式如下图所示:
- 起始位:表示数据传输的开始,电平逻辑为 “0” 。
- 数据位:可能值有 5、6、7、8、9,表示传输这几个 bit 位数据。一般取值为 8,因为一个 ASCII 字符值为 8 位。
- 奇偶校验位:用于接收方对接收到的数据进行校验,校验 “1” 的位数为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性,使用时不需要此位也可以。
- 停止位: 表示一帧数据的结束。电平逻辑为 “1”。
- 波特率:串口通信时的速率,它用单位时间内传输的二进制代码的有效位(bit)数来表示,其单位为每秒比特数 bit/s(bps)。常见的波特率值有 4800、9600、14400、38400、115200等,数值越大数据传输的越快,波特率为 115200 表示每秒钟传输 115200 位数据。
- UART接口定义了操作UART端口的通用方法集合,包括获取、释放设备句柄、读写数据、获取和设置波特率、获取和设置设备属性。
- 鸿蒙UART驱动API接口功能介绍
UartOpen UART获取设备句柄 UartClose UART释放设备句柄 UartRead 从UART设备中读取指定长度的数据 UartWrite 向UART设备中写入指定长度的数据 UartGetBaud UART获取波特率 UartSetBaud UART设置波特率 UartGetAttribute UART获取设备属性 UartSetAttribute UART设置设备属性 UartSetTransMode UART设置传输模式
LCD | 屏显设备
/dev/lcd 液晶(LCD)显示屏
- LCD(Liquid Crystal Display)液晶显示驱动,对LCD进行上电,并通过接口初始化LCD内部寄存器,使LCD正常工作。Display驱动模型基于HDF( Hardware Driver Foundation)驱动框架开发,实现跨OS、跨平台,为LCD硬件提供上下电功能、发送初始化序列功能,使LCD进入正常的工作模式,显示芯片平台侧的图像数据.
- 基于HDF驱动框架的Display驱动模型
Touchscreen | 触摸设备
- Touch(触摸芯片)是 UI 设计中进行人机交互重要的一部分,一个完整的 UI 设计应该包括输入信息和输出信息,LCD 等屏幕设备负责显示输出,那么 Touch 设备就负责触点信息采集作为信息输入。
- Touch 设备与主机通讯一般都是采用 I2C 总线协议来进行数据交互,所以一个 Touch 设备,就是一个标准的 I2C 从设备,而且为了提高接收 Touch 数据的实时性,触摸芯片都会提供中断支持,当有触摸事件(抬起,按下,移动)发生时,会触发中断通知 MCU 有触摸事件。主机可以通过中断回调函数去读取触摸点信息。
- Touchscreen器件的硬件接口相对简单,根据PIN脚的属性,可以简单分为如下三类:
- 电源接口
- IO控制接口
- 通信接口
- Touchscreen驱动用于驱动触摸屏使其正常工作,该驱动主要完成如下工作:对触摸屏驱动IC进行上电、配置硬件管脚并初始化其状态、注册中断、配置通信接口(I2C或SPI)、设定input相关配置、下载及更新固件等操作。
- 鸿蒙基于input驱动模型开发touchscreen器件驱动。Input驱动模型基于HDF驱动框架、PLATFORM接口、OSAL接口进行开发,向上对接规范化的驱动接口HDI(Hardware Driver Interface)层,通过Input-HDI层对外提供硬件能力,即上层input service可以通过HDI接口层获取相应的驱动能力,进而操控touchscreen等输入设备。
- 基于HDF驱动框架的input驱动模型
sensor | 传感设备
/dev/biometric/sensor0/fingerprint 第1个设备的第1个指纹传感器
/dev/biometric/sensor0/iris 第1个设备的第1个虹膜传感器
/dev/biometric/sensor0/retina 第1个设备的第1个视网膜传感器
/dev/biometric/sensor0/voiceprint 第1个设备的第1个声波传感器
/dev/biometric/sensor0/facial 第1个设备的第1个面部传感器
/dev/biometric/sensor0/hand 第1个设备的第1个手掌传感器
/dev/biometric/sensor1/fingerprint 第2个设备的第1个指纹传感器
/dev/biometric/sensor2/fingerprint 第3个设备的第1个指纹传感器
- Sensor(传感器)是物联网重要的一部分,Sensor 之于物联网”就相当于“眼睛之于人类"。人类如果没有了眼睛就看不到这大千的花花世界,对于物联网来说也是一样。
- 如今随着物联网的发展,已经有大量的 Sensor 被开发出来供开发者选择了,如:加速度计(Accelerometer)、磁力计(Magnetometer)、陀螺仪(Gyroscope)、气压计(Barometer/pressure)、湿度计(Humidometer)等。这些传感器,世界上的各大半导体厂商都有生产,虽然增加了市场的可选择性,同时也加大了应用程序开发的难度。因为不同的传感器厂商、不同的传感器都需要配套自己独有的驱动才能运转起来,这样在开发应用程序的时候就需要针对不同的传感器做适配,自然加大了开发难度。
- 为了降低应用开发的难度,增加传感器驱动的可复用性, 鸿蒙Sensor(传感器)驱动模块为上层Sensor服务系统提供稳定的Sensor基础能力API,包括Sensor列表查询、Sensor启停、Sensor订阅及去订阅,Sensor参数配置等功能;基于HDF(Hardware Driver Foundation)驱动框架开发的Sensor驱动模型,实现跨操作系统迁移,器件差异配置等功能。
- 鸿蒙Sensor驱动模型图
watchdog | 看门狗
/dev/watchdog 看门狗(CONFIG_WATCHDOG)
/dev/watchdogs/0 第一只看门狗
...
/dev/watchdogs/n 第n-1只看门狗
- 硬件看门狗(watchdog timer)是一个定时器,其定时输出连接到电路的复位端。在产品化的嵌入式系统中,为了使系统在异常情况下能自动复位,一般都需要引入看门狗。
- 当看门狗启动后,计数器开始自动计数,在计数器溢出前如果没有被复位,计数器溢出就会对 CPU 产生一个复位信号使系统重启(俗称 “被狗咬”)。系统正常运行时,需要在看门狗允许的时间间隔内对看门狗计数器清零(俗称“喂狗“),不让复位信号产生。如果系统不出问题,程序能够按时“喂狗”。一旦程序跑飞,没有“喂狗”,系统“被咬” 复位。
- 鸿蒙看门狗 API接口功能介绍
WatchdogOpen 打开看门狗设备 WatchdogClose 关闭看门狗设备 WatchdogStart 启动看门狗 WatchdogStop 停止看门狗 WatchdogSetTimeout 设置看门狗超时时间 WatchdogGetTimeout 获取看门狗超时时间 WatchdogGetStatus 获取看门狗状态 WatchdogFeed 清除看门狗定时器(喂狗)
WLAN | 无线网络设备
- WLAN是基于HDF(Hardware Driver Foundation)驱动框架开发的模块,该模块可实现跨操作系统迁移,自适应器件差异,模块化拼装编译等功能。各WLAN厂商驱动开发人员可根据WLAN模块提供的向下统一接口适配各自的驱动代码,实现如下能力:建立/关闭WLAN热点、扫描、关联WLAN热点等;对HDI层向上提供能力如下:设置MAC地址、设置发射功率、获取设备的MAC地址等。
- WLAN框架
- WLAN模块有三部分对外开放的API接口
- 对HDI层提供的能力接口。
- 驱动直接调用WLAN模块能力接口。
- 提供给各厂商实现的能力接口。
百篇博客分析.深挖内核地基
给鸿蒙内核源码加注释过程中,整理出以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切.确实有难度,自不量力,但已经出发,回头已是不可能的了。 😛
与代码有bug需不断debug一样,文章和注解内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,
.xx
代表修改的次数,精雕细琢,言简意赅,力求打造精品内容。
编译构建 | 基础工具 | 加载运行 | 进程管理 |
---|---|---|---|
编译环境篇 编译过程篇 环境脚本篇 构建工具篇 gn应用篇 忍者ninja篇 | 双向链表篇 位图管理篇 用栈方式篇 定时器篇 原子操作篇 时间管理篇 | ELF格式篇 ELF解析篇 静态链接篇 重定位篇 进程映像篇 | 进程管理篇 进程概念篇 Fork篇 特殊进程篇 进程回收篇 信号生产篇 信号消费篇 Shell编辑篇 Shell解析篇 |
进程通讯 | 内存管理 | 前因后果 | 任务管理 |
自旋锁篇 互斥锁篇 进程通讯篇 信号量篇 事件控制篇 消息队列篇 | 内存分配篇 内存管理篇 内存汇编篇 内存映射篇 内存规则篇 物理内存篇 | 总目录 调度故事篇 内存主奴篇 源码注释篇 源码结构篇 静态站点篇 | 时钟任务篇 任务调度篇 任务管理篇 调度队列篇 调度机制篇 线程概念篇 并发并行篇 系统调用篇 任务切换篇 |
文件系统 | 硬件架构 | ||
文件概念篇 文件系统篇 索引节点篇 挂载目录篇 根文件系统 字符设备篇 VFS篇 文件句柄篇 管道文件篇 | 汇编基础篇 汇编传参篇 工作模式篇 寄存器篇 异常接管篇 汇编汇总篇 中断切换篇 中断概念篇 中断管理篇 |