绝代码农 发表于 2021-8-24 17:38:53

鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备 | ...

什么是设备
设备(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的输出缓冲区内容。<span style="background-color: rgb(255, 255, 255);"> </span>
[*]在鸿蒙,/dev/mem 是一个字符设备, 源文件是 kernel/drivers/char/mem/src/mem.c, 这个设备文件是专门用来读写物理地址用的。里面的内容是所有物理内存的地址以及内容信息。通常只有root用户对其有读写权限。利用 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接口功能介绍
UartOpenUART获取设备句柄
UartClose UART释放设备句柄
UartRead从UART设备中读取指定长度的数据
UartWrite 向UART设备中写入指定长度的数据
UartGetBaud   UART获取波特率
UartSetBaud   UART设置波特率
UartGetAttributeUART获取设备属性
UartSetAttributeUART设置设备属性
UartSetTransModeUART设置传输模式
LCD | 屏显设备
/dev/lcd         液晶(LCD)显示屏<span style="background-color: rgb(255, 255, 255);"> </span>
[*]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模块能力接口。
[*]提供给各厂商实现的能力接口。
鸿蒙内核源码分析.总目录
v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 百篇博客分析| 51 .c .h.o
百万汉字注解.百篇博客分析
百万汉字注解 >> 精读鸿蒙源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee | github | csdn | coding >
百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中< 51cto | csdn | harmony| osc >
关注不迷路.代码即人生

QQ群:790015635 | 入群请填: 666
原创不易,欢迎转载,但请注明出处.

文档来源:https://my.oschina.net/weharmony/blog/5200946
页: [1]
查看完整版本: 鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备 | ...