int32_t SetBatch(int64_t samplingInterval, int64_t reportInterval)
@@ -248,12 +245,10 @@ Sensor驱动模型要求驱动开发者实现的接口功能,参考表3
接口实现参考[SENSOR](#section257750691)章节。
-## 开发指导
+## 开发步骤
Sensor驱动是基于HDF框架、PLATFORM和OSAL基础接口进行开发,不区分操作系统和芯片平台,为不同Sensor器件提供统一的驱动模型。本篇开发指导以加速度计传感器为例,介绍传感器驱动开发。
-### 开发步骤
-
1. 加速度计传感器驱动注册。HDF驱动框架会提供统一的驱动管理模型,通过加速计传感器模块配置信息,识别并加载对应模块驱动。
2. 加速度计传感器驱动初始化和去初始化。HDF驱动框架通过init入口函数,依次启动传感器设备驱动加载和分配传感器设备数据配置资源。HDF驱动框架通过release函数,释放驱动加载的资源和配置。
3. 加速度计传感器寄存器组配置解析。不同类型传感器需要在hcs里配置器件对应的HCS配置文件,然后再设备驱动启动过程中探测器件是否在位,然后加载对应的配置文件,生成配置的结构体对象。
diff --git a/zh-cn/device-dev/driver/driver-peripherals-touch-des.md b/zh-cn/device-dev/driver/driver-peripherals-touch-des.md
index d2e35a9c8822e87d3a8bbdec7be37f0994ca72d8..354ba5fd8ff9534bcda398340836968cd9cca440 100644
--- a/zh-cn/device-dev/driver/driver-peripherals-touch-des.md
+++ b/zh-cn/device-dev/driver/driver-peripherals-touch-des.md
@@ -1,11 +1,8 @@
# TOUCHSCREEN
- [概述](#section175431838101617)
- - [接口说明](#section17667171301711)
-
-- [开发指导](#section65745222184)
- - [开发步骤](#section865734181916)
-
+- [接口说明](#section105459441659)
+- [开发步骤](#section65745222184)
- [开发实例](#section263714411191)
- [设备描述配置](#section18249155619195)
- [板级配置及器件私有配置](#section3571192072014)
@@ -21,13 +18,13 @@
- **Touchscreen驱动层次说明**
- 本节主要介绍基于input驱动模型开发touchscreen器件驱动,其整体的框架模型如[图1](#fig6251184817261)。
+ 本节主要介绍基于input驱动模型开发touchscreen器件驱动,input模型整体的框架如[图1](#fig6251184817261)。
Input驱动模型基于HDF驱动框架、PLATFORM接口、OSAL接口进行开发,向上对接规范化的驱动接口HDI(Hardware Driver Interface)层,通过Input-HDI层对外提供硬件能力,即上层input service可以通过HDI接口层获取相应的驱动能力,进而操控touchscreen等输入设备。
**图 1** 基于HDF驱动框架的input驱动模型
-
+
- **Input驱动模型介绍**
@@ -49,7 +46,7 @@
在HDF(Hardware Driver Foundation)[驱动管理框架](driver-hdf-development.md)的基础上,input驱动模型调用OSAL接口层和Platfom接口层提供的基础接口进行开发,包括bus通信接口、操作系统原生接口(memory、lock、thread、timer等)。由于OSAL接口和Platform接口屏蔽了芯片平台差异,所以基于input驱动模型实现的touchscreen驱动可以进行跨平台、跨OS迁移,以便逐步实现驱动的一次开发,多端部署。
-### 接口说明
+## 接口说明
Touchscreen器件的硬件接口相对简单,根据PIN脚的属性,可以简单分为如下三类:
@@ -58,7 +55,7 @@ Touchscreen器件的硬件接口相对简单,根据PIN脚的属性,可以简
- 通信接口
**图 2** Touchscreen器件常用管脚
-
+
如上图所示的三类接口,分别做简要说明如下:
@@ -73,30 +70,29 @@ Touchscreen器件的硬件接口相对简单,根据PIN脚的属性,可以简
- INT:中断管脚,需要在驱动初始化时,配置为输入上拉状态。在驱动IC检测到外部触摸信号后,通过操作中断管脚来触发中断,器件驱动则会在中断处理函数中进行报点数据读取等操作。
3. **通信接口**
- - I2C:由于touchscreen的报点数据量相对较少,所以一般选用I2C方式传输数据。I2C的具体协议及对应操作接口,可以参考Platform接口层中的[“I2C”使用指南](driver-platform-i2c-des.md#section1695201514281)。
- - SPI:部分厂商,由于需要传递的数据不止报点坐标,而是需要获取基础容值,数据量较大,所以会选用SPI通信方式。SPI的具体协议及对应操作接口,可以参考Platform接口层中的[“SPI” 使用指南](driver-platform-spi-des.md#section71363452477)。
+ - I2C:由于touchscreen的报点数据量相对较少,所以一般选用I2C方式传输数据。I2C的具体协议及对应操作接口,可以参考Platform接口层中的[“I2C”使用指南](driver-platform-i2c-des.md#section5361140416)。
+ - SPI:部分厂商,由于需要传递的数据不止报点坐标,而是需要获取基础容值,数据量较大,所以会选用SPI通信方式。SPI的具体协议及对应操作接口,可以参考Platform接口层中的[“SPI” 使用指南](driver-platform-spi-des.md#section193356154511)。
-## 开发指导
+## 开发步骤
Input驱动模型是基于HDF框架、Platform接口和OSAL接口开发,不区分操作系统和芯片平台,为touchscreen等输入器件提供统一的驱动开发架构。
-- 如下以touchscreen器件驱动为例,说明input驱动模型的完整加载流程:
-
- (1)设备描述配置:由开发者参考已有模板进行设备描述配置,包括驱动加载顺序、板级硬件信息、器件私有数据信息等。
+如下以touchscreen器件驱动为例,说明input驱动模型的完整加载流程:
- (2)加载input设备管理驱动:input设备管理驱动由HDF驱动加载,完成设备manager的创建并对其初始化。
+(1)设备描述配置:由开发者参考已有模板进行设备描述配置,包括驱动加载顺序、板级硬件信息、器件私有数据信息等。
- (3)加载平台驱动:平台驱动由HDF框架加载,主要完成板级配置解析及硬件初始化,并提供器件注册接口。
+(2)加载input设备管理驱动:input设备管理驱动由HDF驱动加载,完成设备manager的创建并对其初始化。
- (4)加载器件驱动:器件驱动也由HDF框架加载,完成器件设备的实例化,包括器件私有配置解析和平台预留的差异化接口适配。
+(3)加载平台驱动:平台驱动由HDF框架加载,主要完成板级配置解析及硬件初始化,并提供器件注册接口。
- (5)器件设备向平台驱动注册:将实例化的器件设备向平台驱动注册,实现设备和驱动的绑定,并完成中断注册、上下电等器件初始化工作。
+(4)加载器件驱动:器件驱动也由HDF框架加载,完成器件设备的实例化,包括器件私有配置解析和平台预留的差异化接口适配。
- (6)input设备注册:在器件初始化完成后,实例化input设备,并将其注册到input manager进行管理。
+(5)器件设备向平台驱动注册:将实例化的器件设备向平台驱动注册,实现设备和驱动的绑定,并完成中断注册、上下电等器件初始化工作。
+(6)input设备注册:在器件初始化完成后,实例化input设备,并将其注册到input manager进行管理。
-### 开发步骤
+请参考如下相关步骤:
1. 设备描述配置
@@ -108,7 +104,7 @@ Input驱动模型是基于HDF框架、Platform接口和OSAL接口开发,不区
3. 实现器件差异化适配接口
- 根据硬件单板设计的通信接口,使用Platform接口层提供的管脚操作接口配置对应的复位管脚、中断管脚以及电源操作,对于GPIO的操作,可参考[GPIO操作接口指导](driver-platform-gpio-des.md#section259614242196)
+ 根据硬件单板设计的通信接口,使用Platform接口层提供的管脚操作接口配置对应的复位管脚、中断管脚以及电源操作,对于GPIO的操作,可参考[GPIO操作接口指导](driver-platform-gpio-des.md#section1635911016188)
## 开发实例
diff --git a/zh-cn/device-dev/driver/driver-peripherals-usb-des.md b/zh-cn/device-dev/driver/driver-peripherals-usb-des.md
deleted file mode 100755
index 86a2769f6fe8f0ddb9b28ea37b1d77f841416e63..0000000000000000000000000000000000000000
--- a/zh-cn/device-dev/driver/driver-peripherals-usb-des.md
+++ /dev/null
@@ -1,1572 +0,0 @@
-# USB
-
-- [概述](#section175431838101617)
- - [接口说明](#section17667171301711)
-
-- [开发指导](#section65745222184)
- - [Host DDK API驱动开发步骤](#section865734181916)
- - [Host RAW API驱动开发步骤](#section865734181916)
- - [Device DDK API驱动开发步骤](#section865734181916)
-
-- [开发实例](#section263714411191)
- - [Host DDK API驱动开发](#section18249155619195)
- - [Host RAW API驱动开发](#section3571192072014)
- - [Device DDK API驱动开发](#section6356758162015)
-
-
-## 概述
-
-USB Host部分,主要包括协议封装、设备管理、驱动安装与卸载等。
-
-USB Device部分,支持USB功能设备的开发,提供USB设备相关功能,主要包括设备管理、配置管理、IO管理,实现USB功能设备创建、配置、数据通信等。
-
-USB Host驱动模型如下图1所示:
-
-**图 1** USB Host驱动模型图
-
-
-**图 2** USB Device驱动模型图
-
-
-USB驱动模型对外开放的API接口能力如下:
-
-- Usb Host DDK提供给用户态可直接调用的驱动能力接口,按照功能分类三大类:DDK初始化类、对interface对象操作类、对request对象操作类,可以提供DDK初始化、interface绑定和释放,打开和关闭操作,request的申请和释放,同步和异步传输等。
-- Usb Deivce DDK提供设备管理、IO管理、配置管理,主要功能有:创建和删除设备、获取和打开接口、同步和异步传输等。
-
-### 接口说明
-
-USB驱动模型Host侧开放的API接口功能,参考表1。
-
-**表 1** USB驱动模型Host侧开放的API接口功能介绍
-
-
-头文件
- |
-接口名称
- |
-功能描述
- |
-
-
-usb_ddk_interface.h
-
-
- |
-int32_t UsbInitHostSdk(struct UsbSession **session);
- |
-USB主机端驱动开发工具包初始化
- |
-
-int32_t UsbExitHostSdk(const struct UsbSession *session);
- |
-USB主机端驱动开发工具包退出
- |
-
-const struct UsbInterface *UsbClaimInterface(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr, uint8_t interfaceIndex);
- |
-获取USB接口对象
- |
-
-int UsbReleaseInterface(const struct UsbInterface *interfaceObj);
- |
-释放USB接口对象
- |
-
-int UsbAddOrRemoveInterface(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr, uint8_t interfaceIndex, UsbInterfaceStatus status);
- |
-增加移除接口
- |
-
-UsbInterfaceHandle *UsbOpenInterface(const struct UsbInterface *interfaceObj);
- |
-打开USB对象接口
- |
-
-int32_t UsbCloseInterface(const UsbInterfaceHandle *interfaceHandle);
- |
-关闭USB接口对象
- |
-
-int32_t UsbSelectInterfaceSetting(const UsbInterfaceHandle *interfaceHandle, uint8_t settingIndex, struct UsbInterface **interfaceObj);
- |
-设置可选配置
- |
-
-int32_t UsbGetPipeInfo(const UsbInterfaceHandle *interfaceHandle, uint8_t settingIndex, uint8_t pipeId, struct UsbPipeInfo *pipeInfo);
- |
-获取指定可选设置的管道信息
- |
-
-int32_t UsbClearInterfaceHalt(const UsbInterfaceHandle *interfaceHandle, uint8_t pipeAddress);
- |
-清除指定索引的管道状态
- |
-
-struct UsbRequest *UsbAllocRequest(const UsbInterfaceHandle *interfaceHandle, int isoPackets, int length);
- |
-分配请求对象
- |
-
-int UsbFreeRequest(const struct UsbRequest *request);
- |
-释放请求对象
- |
-
-int UsbSubmitRequestAsync(const struct UsbRequest *request);
- |
-发送异步请求
- |
-
-int32_t UsbFillRequest(const struct UsbRequest *request, const UsbInterfaceHandle *interfaceHandle, const struct UsbRequestParams *params);
- |
-填充请求
- |
-
-sint UsbCancelRequest(const struct UsbRequest *request);
- |
-取消异步请求
- |
-
-int UsbSubmitRequestSync(const struct UsbRequest *request);
- |
-发送同步请求
- |
-
-usb_raw_api.h
-
-
-
-
-
- |
-int UsbRawInit(struct UsbSession **session);
- |
-USB驱动开发工具包专家模式初始化
- |
-
-int UsbRawExit(const struct UsbSession *session);
- |
-USB驱动开发工具包专家模式退出
- |
-
-UsbRawHandle *UsbRawOpenDevice(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr);
- |
-打开USB设备对象
- |
-
-int UsbRawCloseDevice(const UsbRawHandle *devHandle);
- |
-关闭USB设备对象
- |
-
-int UsbRawSendControlRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbControlRequestData *requestData);
- |
-执行同步控制传输
- |
-
-int UsbRawSendBulkRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRequestData *requestData);
- |
-执行同步批量传输
- |
-
-int UsbRawSendInterruptRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRequestData *requestData);
- |
-执行同步中断传输
- |
-
-int UsbRawGetConfigDescriptor(const UsbRawDevice *rawDev, uint8_t configIndex, struct UsbRawConfigDescriptor **config);
- |
-获取给定设备指定ID的设备配置描述符
- |
-
-void UsbRawFreeConfigDescriptor(const struct UsbRawConfigDescriptor *config);
- |
-释放配置描述符内存空间
- |
-
-int UsbRawGetConfiguration(const UsbRawHandle *devHandle, int *config);
- |
-获取当前激活配置
- |
-
-int UsbRawSetConfiguration(const UsbRawHandle *devHandle, int config);
- |
-设置当前激活配置
- |
-
-int UsbRawGetDescriptor(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawDescriptorParam *param, const unsigned char *data);
- |
-获取描述符信息
- |
-
-UsbRawDevice *UsbRawGetDevice(const UsbRawHandle *devHandle);
- |
-由设备句柄获取设备指针
- |
-
-int UsbRawGetDeviceDescriptor(const UsbRawDevice *rawDev, struct UsbDeviceDescriptor *desc);
- |
-获取给定设备的USB设备描述符
- |
-
-int UsbRawClaimInterface(const UsbRawHandle *devHandle, int interfaceNumber);
- |
-声明给定设备句柄上的接口
- |
-
-int UsbRawReleaseInterface(const UsbRawHandle *devHandle, int interfaceNumber);
- |
-释放之前声明的接口
- |
-
-int UsbRawResetDevice(const UsbRawHandle *devHandle);
- |
-复位设备
- |
-
-struct UsbRawRequest *UsbRawAllocRequest(const UsbRawHandle *devHandle, int isoPackets, int length);
- |
-分配一个带有指定数量的同步包描述符的传输请求
- |
-
-int UsbRawFreeRequest(const struct UsbRawRequest *request);
- |
-释放之前分配的传输请求
- |
-
-int UsbRawFillBulkRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);
- |
-填充批量传输请求所需信息
- |
-
-int UsbRawFillControlSetup(const unsigned char *setup, const struct UsbControlRequestData *requestData);
- |
-填充控制传输设置包所需信息
- |
-
-int UsbRawFillControlRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);
- |
-填充控制传输请求所需信息
- |
-
-int UsbRawFillInterruptRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);
- |
-填充中断传输请求所需信息
- |
-
-int UsbRawFillIsoRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);
- |
-填充同步传输(Isochronous Transfers)请求所需信息
- |
-
-int UsbRawSubmitRequest(const struct UsbRawRequest *request);
- |
-提交一个传输请求
- |
-
-int UsbRawCancelRequest(const struct UsbRawRequest *request);
- |
-取消一个传输请求
- |
-
-int UsbRawHandleRequests(const UsbRawHandle *devHandle);
- |
-传输请求事件完成处理
- |
-
-
-
-
-USB驱动模型Device侧开放的API接口功能,参考表2。
-
-**表 2** USB驱动模型Device侧开放的API接口功能介绍
-
-
-头文件
- |
-接口名称
- |
-功能描述
- |
-
-
-usbfn_device.h
-
-
- |
-const struct UsbFnDevice *UsbFnCreateDevice(const char *udcName, const struct UsbFnDescriptorData *descriptor);
- |
-创建Usb设备
- |
-
-int UsbFnRemoveDevice(struct UsbFnDevice *fnDevice);
- |
-删除Usb设备
- |
-
-const struct UsbFnDevice *UsbFnGetDevice(const char *udcName);
- |
-获取Usb设备
- |
-
-usbfn_interface.h
-
-
-
-
-
- |
-int UsbFnStartRecvInterfaceEvent(struct UsbFnInterface *interface, uint32_t eventMask, UsbFnEventCallback callback, void *context);
- |
-开始接受Event事件
- |
-
-int UsbFnStopRecvInterfaceEvent(struct UsbFnInterface *interface);
- |
-停止接受Event事件
- |
-
-UsbFnInterfaceHandle UsbFnOpenInterface(struct UsbFnInterface *interface);
- |
-打开一个接口
- |
-
-int UsbFnCloseInterface(UsbFnInterfaceHandle handle);
- |
-关闭一个接口
- |
-
-int UsbFnGetInterfacePipeInfo(struct UsbFnInterface *interface, uint8_t pipeId, struct UsbFnPipeInfo *info);
- |
-获取管道信息
- |
-
-int UsbFnSetInterfaceProp(const struct UsbFnInterface *interface, const char *name, const char *value);
- |
-设置自定义属性
- |
-
-usbfn_request.h
-
-
-
-
-
-
-
- |
-struct UsbFnRequest *UsbFnAllocCtrlRequest(UsbFnInterfaceHandle handle, uint32_t len);
- |
-申请一个控制请求
- |
-
-struct UsbFnRequest *UsbFnAllocRequest(UsbFnInterfaceHandle handle, uint8_t pipe, uint32_t len);
- |
-申请一个数据请求
- |
-
-int UsbFnFreeRequest(struct UsbFnRequest *req);
- |
-释放一个请求
- |
-
-int UsbFnSubmitRequestAsync(struct UsbFnRequest *req);
- |
-发送异步请求
- |
-
-int UsbFnSubmitRequestSync(struct UsbFnRequest *req, uint32_t timeout);
- |
-发送同步请求
- |
-
-int UsbFnCancelRequest(struct UsbFnRequest *req);
- |
-取消请求
- |
-
-
-
-
-## 开发指导
-
-USB驱动是基于HDF框架、PLATFORM和OSAL基础接口进行开发,不区分操作系统和芯片平台,为不同USB器件提供统一的驱动模型。本篇开发指导以串口为例,分别介绍USB Host和USB Device驱动开发。
-
-### 开发步骤
-
-### Host DDK API驱动开发步骤
-
-1. 驱动匹配表配置。
-2. 初始化Host DDK。
-3. 待步骤2初始化完后获取UsbInterface接口对象。
-4. 打开步骤3获取到的UsbInterface接口对象,获取对应接口的UsbInterfaceHandle对象。
-5. 根据步骤4获取到的UsbInterfaceHandle对象,获取指定索引为pinpeIndex的pipeInfo信息。
-6. 为步骤4获取到的UsbInterfaceHandle预先分配待发送的IO Request对象。
-7. 根据输入参数params填充步骤6预先分配的IO Request。
-8. 提交IO Request对象,可以选择同步或异步两种模式。
-
-
-### Host RAW API驱动开发步骤
-
-1. 驱动匹配表配置。
-2. 初始化Host RAW,并打开USB设备,然后获取描述符,通过描述符获取接口、端点信息。
-3. 分配Request,并根据传输类型使用如下接口对Request进行填充。
-4. 提交IO Request对象,可以选择同步或异步两种模式。
-
-### Device DDK API驱动开发步骤
-
-1. 构造描述符。
-2. 创建设备,使用步骤1构造的描述符实例化一个USB设备。
-3. 根据创建的设备获取接口(UsbFnDeviceGetInterface),获取Pipe信息(UsbFnInterfaceGetPipeInfo),打开接口获取Handle(UsbFnInterfaceOpen),根据Handle和Pipe号获取Request(UsbFnRequestAlloc)。
-4. 接收Event事件(UsbFnInterfaceStartRecvEvent)如Enable、Setup等事件,回调函数(UsbFnEventCallback)中对Event事件做出响应。
-5. 收发数据,可以选择同步异步发送模式。
-
-## 开发实例
-
-本实例提供USB串口驱动开发示例,并简要对具体关键点进行开发说明。
-
-### Host DDK API驱动开发
-
-```
-root {
- module = "usb_pnp_device";
- usb_pnp_config {
- match_attr = "usb_pnp_match";
- usb_pnp_device_id = "UsbPnpDeviceId";
- UsbPnpDeviceId {
- idTableList = [
- "host_acm_table"
- ];
- host_acm_table {
- //驱动模块名,该字段的值必须和驱动入口结构的moduleName一致
- moduleName = "usbhost_acm";
- //驱动对外发布服务的名称,必须唯一
- serviceName = "usbhost_acm_pnp_service";
- //驱动私有数据匹配关键字
- deviceMatchAttr = "usbhost_acm_pnp_matchAttr";
- //从该字段开始(包含该字段)之后数据长度,以byte为单位
- length = 21;
- //USB驱动匹配规则vendorId+productId+interfaceSubClass+interfaceProtocol+interfaceNumber
- matchFlag = 0x0303;
- //厂商编号
- vendorId = 0x12D1;
- //产品编号
- productId = 0x5000;
- //设备出厂编号,低16位
- bcdDeviceLow = 0x0000;
- //设备出厂编号,高16位
- bcdDeviceHigh = 0x0000;
- //USB分配的设备类代码
- deviceClass = 0;
- //USB分配的子类代码
- deviceSubClass = 0;
- //USB分配的设备协议代码
- deviceProtocol = 0;
- //接口类型,根据实际需要可填写多个
- interfaceClass = [0];
- //接口子类型,根据实际需要可填写多个
- interfaceSubClass = [2, 0];
- //接口所遵循的协议,根据实际需要可填写多个
- interfaceProtocol = [1, 2];
- //接口的编号,根据实际需要可填写多个
- interfaceNumber = [2, 3];
- }
- }
- }
-}
-
-#include "usb_serial.h"
-#include "hdf_base.h"
-#include "hdf_log.h"
-#include "osal_mem.h"
-#include "osal_time.h"
-#include "securec.h"
-#include "usb_ddk_interface.h"
-#include "hdf_usb_pnp_manage.h"
-
-#define HDF_LOG_TAG USB_HOST_ACM
-#define STR_LEN 512
-
-static struct UsbRequest *g_syncRequest = NULL;
-static struct UsbRequest *g_ctrlCmdRequest = NULL;
-static bool g_acmReleaseFlag = false;
-static uint8_t *g_acmReadBuffer = NULL;
-...
-static int SerialCtrlMsg(struct AcmDevice *acm, uint8_t request,
- uint16_t value, void *buf, uint16_t len)
-{
- int ret;
- uint16_t index = acm->intPipe->interfaceId;
- struct UsbControlParams controlParams = {};
- struct UsbRequestParams parmas = {};
- if (acm == NULL || buf == NULL) {
- HDF_LOGE("%{public}s:invalid param", __func__);
- return HDF_ERR_IO;
- }
- if (acm->ctrlReq == NULL) {
- acm->ctrlReq = UsbAllocRequest(acm->ctrDevHandle, 0, len);
- if (acm->ctrlReq == NULL) {
- HDF_LOGE("%{public}s: UsbAllocRequest faild", __func__);
- return HDF_ERR_IO;
- }
- }
-
- controlParams.request = request;
- controlParams.target = USB_REQUEST_TARGET_INTERFACE;
- controlParams.reqType = USB_REQUEST_TYPE_CLASS;
- controlParams.directon = USB_REQUEST_DIR_TO_DEVICE;
- controlParams.value = value;
- controlParams.index = index;
- controlParams.data = buf;
- controlParams.size = len;
-
- parmas.interfaceId = USB_CTRL_INTERFACE_ID;
- parmas.pipeAddress = acm->ctrPipe->pipeAddress;
- parmas.pipeId = acm->ctrPipe->pipeId;
- parmas.requestType = USB_REQUEST_PARAMS_CTRL_TYPE;
- parmas.timeout = USB_CTRL_SET_TIMEOUT;
- parmas.ctrlReq = UsbControlSetUp(&controlParams);
- ret = UsbFillRequest(acm->ctrlReq, acm->ctrDevHandle, &parmas);
- if (HDF_SUCCESS != ret) {
- HDF_LOGE("%{public}s: faile, ret=%{public}d ", __func__, ret);
- return ret;
- }
- ret = UsbSubmitRequestSync(acm->ctrlReq); //发送同步IO Request
- if (HDF_SUCCESS != ret) {
- HDF_LOGE("UsbSubmitRequestSync faile, ret=%{public}d ", ret);
- return ret;
- }
- if (!acm->ctrlReq->compInfo.status) {
- HDF_LOGE("%{public}s status=%{public}d ", __func__, acm->ctrlReq->compInfo.status);
- }
- return HDF_SUCCESS;
-}
-...
-static struct UsbInterface *GetUsbInterfaceById(const struct AcmDevice *acm,
- uint8_t interfaceIndex)
-{
- struct UsbInterface *tmpIf = NULL;
- tmpIf = (struct UsbInterface *)UsbClaimInterface(acm->session, acm->busNum, \
- acm->devAddr, interfaceIndex); //获取UsbInterface接口对象
- return tmpIf;
-}
-...
-static struct UsbPipeInfo *EnumePipe(const struct AcmDevice *acm,
- uint8_t interfaceIndex, UsbPipeType pipeType, UsbPipeDirection pipeDirection)
-{
- uint8_t i;
- int ret;
- struct UsbInterfaceInfo *info = NULL;
- UsbInterfaceHandle *interfaceHandle = NULL;
- if (pipeType == USB_PIPE_TYPE_CONTROL)
- {
- info = &acm->ctrIface->info;
- interfaceHandle = acm->ctrDevHandle;
- }
- else
- {
- info = &acm->iface[interfaceIndex]->info;
- interfaceHandle = InterfaceIdToHandle(acm, info->interfaceIndex);
- }
-
- for (i = 0; i <= info->pipeNum; i++) {
- struct UsbPipeInfo p;
- ret = UsbGetPipeInfo(interfaceHandle, info->curAltSetting, i, &p);//获取指定索引为i的pipeInfo信息
- if (ret < 0) {
- continue;
- }
- if ((p.pipeDirection == pipeDirection) && (p.pipeType == pipeType)) {
- struct UsbPipeInfo *pi = OsalMemCalloc(sizeof(*pi));
- if (pi == NULL) {
- HDF_LOGE("%{public}s: Alloc pipe failed", __func__);
- return NULL;
- }
- p.interfaceId = info->interfaceIndex;
- *pi = p;
- return pi;
- }
- }
- return NULL;
-}
-
-static struct UsbPipeInfo *GetPipe(const struct AcmDevice *acm,
- UsbPipeType pipeType, UsbPipeDirection pipeDirection)
-{
- uint8_t i;
- if (acm == NULL) {
- HDF_LOGE("%{public}s: invalid parmas", __func__);
- return NULL;
- }
- for (i = 0; i < acm->interfaceCnt; i++) {
- struct UsbPipeInfo *p = NULL;
- if (!acm->iface[i]) {
- continue;
- }
- p = EnumePipe(acm, i, pipeType, pipeDirection);
- if (p == NULL) {
- continue;
- }
- return p;
- }
- return NULL;
-}
-
-/* HdfDriverEntry implementations */
-static int32_t UsbSerialDriverBind(struct HdfDeviceObject *device)
-{
- struct UsbPnpNotifyServiceInfo *info = NULL;
- errno_t err;
- struct AcmDevice *acm = NULL;
- if (device == NULL) {
- HDF_LOGE("%s: device is null", __func__);
- return HDF_ERR_INVALID_OBJECT;
- }
- acm = (struct AcmDevice *)OsalMemCalloc(sizeof(*acm));
- if (acm == NULL) {
- HDF_LOGE("%s: Alloc usb serial device failed", __func__);
- return HDF_FAILURE;
- }
- if (OsalMutexInit(&acm->lock) != HDF_SUCCESS) {
- HDF_LOGE("%s:%d OsalMutexInit fail", __func__, __LINE__);
- goto error;
- }
- info = (struct UsbPnpNotifyServiceInfo *)device->priv;
- if (info != NULL) {
- HDF_LOGD("%s:%d busNum=%d,devAddr=%d,interfaceLength=%d", \
- __func__, __LINE__, info->busNum, info->devNum, info->interfaceLength);
- acm->busNum = info->busNum;
- acm->devAddr = info->devNum;
- acm->interfaceCnt = info->interfaceLength;
- err = memcpy_s((void *)(acm->interfaceIndex), USB_MAX_INTERFACES,
- (const void*)info->interfaceNumber, info->interfaceLength);
- if (err != EOK) {
- HDF_LOGE("%s:%d memcpy_s faile err=%d", \
- __func__, __LINE__, err);
- goto lock_error;
- }
- } else {
- HDF_LOGE("%s:%d info is NULL!", __func__, __LINE__);
- goto lock_error;
- }
- acm->device = device;
- device->service = &(acm->service);
- acm->device->service->Dispatch = UsbSerialDeviceDispatch;
- HDF_LOGD("UsbSerialDriverBind=========================OK");
- return HDF_SUCCESS;
-
-lock_error:
- if (OsalMutexDestroy(&acm->lock)) {
- HDF_LOGE("%s:%d OsalMutexDestroy fail", __func__, __LINE__);
- }
-error:
- OsalMemFree(acm);
- acm = NULL;
- return HDF_FAILURE;
-}
-...
-static int AcmAllocReadRequests(struct AcmDevice *acm)
-{
- int ret;
- struct UsbRequestParams readParmas = {};
- for (int i = 0; i < ACM_NR; i++) {
- acm->readReq[i] = UsbAllocRequest(InterfaceIdToHandle(acm, acm->dataInPipe->interfaceId), 0, acm->readSize); //分配待发送的readReq IO Request对象
- if (!acm->readReq[i]) {
- HDF_LOGE("readReq request faild\n");
- goto error;
- }
- readParmas.userData = (void *)acm;
- readParmas.pipeAddress = acm->dataInPipe->pipeAddress;
- readParmas.pipeId = acm->dataInPipe->pipeId;
- readParmas.interfaceId = acm->dataInPipe->interfaceId;
- readParmas.callback = AcmReadBulk;
- readParmas.requestType = USB_REQUEST_PARAMS_DATA_TYPE;
- readParmas.timeout = USB_CTRL_SET_TIMEOUT;
- readParmas.dataReq.numIsoPackets = 0;
- readParmas.dataReq.directon = (acm->dataInPipe->pipeDirection >> USB_PIPE_DIR_OFFSET) & 0x1;
- readParmas.dataReq.length = acm->readSize;
- ret = UsbFillRequest(acm->readReq[i], InterfaceIdToHandle(acm, acm->dataInPipe->interfaceId), &readParmas); //填充待发送的readReq对象
- if (HDF_SUCCESS != ret) {
- HDF_LOGE("%{public}s: UsbFillRequest faile, ret=%{public}d \n", __func__, ret);
- goto error;
- }
- }
- return HDF_SUCCESS;
-
-error:
- AcmFreeReadRequests(acm);
- return HDF_ERR_MALLOC_FAIL;
-}
-
-static int AcmAllocNotifyRequest(struct AcmDevice *acm)
-{
- int ret;
- struct UsbRequestParams intParmas = {};
- acm->notifyReq = UsbAllocRequest(InterfaceIdToHandle(acm, acm->intPipe->interfaceId), 0, acm->intSize); //分配待发送的中断IO Request对象
- if (!acm->notifyReq) {
- HDF_LOGE("notifyReq request fail\n");
- return HDF_ERR_MALLOC_FAIL;
- }
- intParmas.userData = (void *)acm;
- intParmas.pipeAddress = acm->intPipe->pipeAddress;
- intParmas.pipeId = acm->intPipe->pipeId;
- intParmas.interfaceId = acm->intPipe->interfaceId;
- intParmas.callback = AcmCtrlIrq;
- intParmas.requestType = USB_REQUEST_PARAMS_DATA_TYPE;
- intParmas.timeout = USB_CTRL_SET_TIMEOUT;
- intParmas.dataReq.numIsoPackets = 0;
- intParmas.dataReq.directon = (acm->intPipe->pipeDirection >> USB_PIPE_DIR_OFFSET) & DIRECTION_MASK;
- intParmas.dataReq.length = acm->intSize;
- ret = UsbFillRequest(acm->notifyReq, InterfaceIdToHandle(acm, acm->intPipe->interfaceId), &intParmas); //填充预先分配的中断IO Request
- if (HDF_SUCCESS != ret) {
- HDF_LOGE("%{public}s: UsbFillRequest faile, ret=%{public}d \n", __func__, ret);
- goto error;
- }
- return HDF_SUCCESS;
-
-error:
- AcmFreeNotifyReqeust(acm);
- return ret;
-}
-
-static void AcmReleaseInterfaces(struct AcmDevice *acm)
-{
- for (int i = 0; i < acm->interfaceCnt; i++) {
- if (acm->iface[i]) {
- UsbReleaseInterface(acm->iface[i]);
- acm->iface[i] = NULL;
- }
- }
- if (acm->ctrIface) {
- UsbReleaseInterface(acm->ctrIface);
- acm->ctrIface = NULL;
- }
-}
-
-static int32_t AcmClaimInterfaces(struct AcmDevice *acm)
-{
- for (int i = 0; i < acm->interfaceCnt; i++) {
- acm->iface[i] = GetUsbInterfaceById((const struct AcmDevice *)acm, acm->interfaceIndex[i]); //获取UsbInterface接口对象
- if (acm->iface[i] == NULL) {
- HDF_LOGE("%{public}s: interface%{public}d is null", __func__, acm->interfaceIndex[i]);
- goto error;
- }
- }
-
- acm->ctrIface = GetUsbInterfaceById((const struct AcmDevice *)acm, USB_CTRL_INTERFACE_ID); //获取控制接口对应的UsbInterface接口对象
- if (acm->ctrIface == NULL) {
- HDF_LOGE("%{public}s: GetUsbInterfaceById null", __func__);
- goto error;
- }
-
- return HDF_SUCCESS;
-
- error:
- AcmReleaseInterfaces(acm);
- return HDF_FAILURE;
-}
-
-static void AcmCloseInterfaces(struct AcmDevice *acm)
-{
- for (int i = 0; i < acm->interfaceCnt; i++) {
- if (acm->devHandle[i]) {
- UsbCloseInterface(acm->devHandle[i]);
- acm->devHandle[i] = NULL;
- }
- }
- if (acm->ctrDevHandle) {
- UsbCloseInterface(acm->ctrDevHandle);
- acm->ctrDevHandle = NULL;
- }
-}
-
-static int32_t AcmOpenInterfaces(struct AcmDevice *acm)
-{
- for (int i = 0; i < acm->interfaceCnt; i++) {
- if (acm->iface[i]) {
- acm->devHandle[i] = UsbOpenInterface(acm->iface[i]); //打开获取到的UsbInterface接口对象
- if (acm->devHandle[i] == NULL) {
- HDF_LOGE("%{public}s: UsbOpenInterface null", __func__);
- goto error;
- }
- }
- }
- acm->ctrDevHandle = UsbOpenInterface(acm->ctrIface);
- if (acm->ctrDevHandle == NULL) {
- HDF_LOGE("%{public}s: ctrDevHandle UsbOpenInterface null", __func__);
- goto error;
- }
-
- return HDF_SUCCESS;
-
-error:
- AcmCloseInterfaces(acm);
- return HDF_FAILURE;
-}
-
-static int32_t AcmGetPipes(struct AcmDevice *acm)
-{
- acm->dataInPipe = GetPipe(acm, USB_PIPE_TYPE_BULK, USB_PIPE_DIRECTION_IN);//获取dataInPipe的pipeInfo信息
- if (acm->dataInPipe == NULL) {
- HDF_LOGE("dataInPipe is NULL");
- goto error;
- }
-
- acm->dataOutPipe = GetPipe(acm, USB_PIPE_TYPE_BULK, USB_PIPE_DIRECTION_OUT);//获取dataOutPipe的pipeInfo信息
- if (acm->dataOutPipe == NULL) {
- HDF_LOGE("dataOutPipe is NULL");
- goto error;
- }
-
- acm->ctrPipe = EnumePipe(acm, acm->ctrIface->info.interfaceIndex, USB_PIPE_TYPE_CONTROL, USB_PIPE_DIRECTION_OUT); //获取控制pipe的pipeInfo信息
- if (acm->ctrPipe == NULL) {
- HDF_LOGE("ctrPipe is NULL");
- goto error;
- }
-
- acm->intPipe = GetPipe(acm, USB_PIPE_TYPE_INTERRUPT, USB_PIPE_DIRECTION_IN);//获取中断pipe的pipeInfo信息
- if (acm->intPipe == NULL) {
- HDF_LOGE("intPipe is NULL");
- goto error;
- }
-
- acm->readSize = acm->dataInPipe->maxPacketSize;
- acm->writeSize = acm->dataOutPipe->maxPacketSize;
- acm->ctrlSize = acm->ctrPipe->maxPacketSize;
- acm->intSize = acm->intPipe->maxPacketSize;
-
- return HDF_SUCCESS;
-
-error:
- AcmFreePipes(acm);
- return HDF_FAILURE;
-}
-
-static void AcmFreeRequests(struct AcmDevice *acm)
-{
- if (g_syncRequest != NULL) {
- UsbFreeRequest(g_syncRequest);
- g_syncRequest = NULL;
- }
- AcmFreeReadRequests(acm);
- AcmFreeNotifyReqeust(acm);
- AcmFreeWriteRequests(acm);
- AcmWriteBufFree(acm);
-}
-
-static int32_t AcmAllocRequests(struct AcmDevice *acm)
-{
- int32_t ret;
-
- if (AcmWriteBufAlloc(acm) < 0) {
- HDF_LOGE("%{public}s: AcmWriteBufAlloc failed", __func__);
- return HDF_ERR_MALLOC_FAIL;
- }
-
- for (int i = 0; i < ACM_NW; i++) {
- struct AcmWb *snd = &(acm->wb[i]);
- snd->request = UsbAllocRequest(InterfaceIdToHandle(acm, acm->dataOutPipe->interfaceId), 0, acm->writeSize); //分配待发送的IO Request对象
- snd->instance = acm;
- if (snd->request == NULL) {
- HDF_LOGE("%{public}s:%{public}d snd request fail", __func__, __LINE__);
- goto error_alloc_write_req;
- }
- }
-
- ret = AcmAllocNotifyRequest(acm); //分配并填充中断IO Request对象
- if (ret != HDF_SUCCESS) {
- HDF_LOGE("%{public}s:%{public}d AcmAllocNotifyRequest fail", __func__, __LINE__);
- goto error_alloc_int_req;
- }
-
- ret = AcmAllocReadRequests(acm); //分配并填充readReq IO Request对象
- if (ret) {
- HDF_LOGE("%{public}s:%{public}d AcmAllocReadRequests fail", __func__, __LINE__);
- goto error_alloc_read_req;
- }
-
- return HDF_SUCCESS;
-
-error_alloc_read_req:
- AcmFreeNotifyReqeust(acm);
-error_alloc_int_req:
- AcmFreeWriteRequests(acm);
-error_alloc_write_req:
- AcmWriteBufFree(acm);
- return HDF_FAILURE;
-}
-
-static int32_t AcmInit(struct AcmDevice *acm)
-{
- int32_t ret;
- struct UsbSession *session = NULL;
-
- if (acm->initFlag == true) {
- HDF_LOGE("%{public}s:%{public}d: initFlag is true", __func__, __LINE__);
- return HDF_SUCCESS;
- }
-
- ret = UsbInitHostSdk(NULL); //初始化Host DDK
- if (ret != HDF_SUCCESS) {
- HDF_LOGE("%{public}s: UsbInitHostSdk faild", __func__);
- return HDF_ERR_IO;
- }
- acm->session = session;
-
- ret = AcmClaimInterfaces(acm);
- if (ret != HDF_SUCCESS) {
- HDF_LOGE("%{public}s: AcmClaimInterfaces faild", __func__);
- goto error_claim_interfaces;
- }
-
- ret = AcmOpenInterfaces(acm);
- if (ret != HDF_SUCCESS) {
- HDF_LOGE("%{public}s: AcmOpenInterfaces faild", __func__);
- goto error_open_interfaces;
- }
-
- ret = AcmGetPipes(acm);
- if (ret != HDF_SUCCESS) {
- HDF_LOGE("%{public}s: AcmGetPipes failed", __func__);
- goto error_get_pipes;
- }
-
- ret = AcmAllocRequests(acm);
- if (ret != HDF_SUCCESS) {
- HDF_LOGE("%{public}s: AcmAllocRequests failed", __func__);
- goto error_alloc_reqs;
- }
-
- acm->lineCoding.dwDTERate = CpuToLe32(DATARATE);
- acm->lineCoding.bCharFormat = CHARFORMAT;
- acm->lineCoding.bParityType = USB_CDC_NO_PARITY;
- acm->lineCoding.bDataBits = USB_CDC_1_STOP_BITS;
- acm->initFlag = true;
-
- HDF_LOGD("%{public}s:%{public}d========OK", __func__, __LINE__);
- return HDF_SUCCESS;
-
-error_alloc_reqs:
- AcmFreePipes(acm);
-error_get_pipes:
- AcmCloseInterfaces(acm);
-error_open_interfaces:
- AcmReleaseInterfaces(acm);
-error_claim_interfaces:
- UsbExitHostSdk(acm->session);
- acm->session = NULL;
- return ret;
-}
-
-static void AcmRelease(struct AcmDevice *acm)
-{
- if (acm->initFlag == false) {
- HDF_LOGE("%{public}s:%{public}d: initFlag is false", __func__, __LINE__);
- return;
- }
-
- AcmFreeRequests(acm);
- AcmFreePipes(acm);
- AcmCloseInterfaces(acm);
- AcmReleaseInterfaces(acm);
- UsbExitHostSdk(acm->session);
- acm->session = NULL;
-
- acm->initFlag = false;
-}
-
-static int32_t UsbSerialDriverInit(struct HdfDeviceObject *device)
-{
- int32_t ret;
- struct AcmDevice *acm = NULL;
-
- if (device == NULL) {
- HDF_LOGE("%{public}s: device is null", __func__);
- return HDF_ERR_INVALID_OBJECT;
- }
- acm = (struct AcmDevice *)device->service;
- OsalMutexInit(&acm->readLock);
- OsalMutexInit(&acm->writeLock);
- HDF_LOGD("%{public}s:%{public}d busNum=%{public}d,devAddr=%{public}d", \
- __func__, __LINE__, acm->busNum, acm->devAddr);
-
- ret = UsbSerialDeviceAlloc(acm);
- if (ret != HDF_SUCCESS) {
- HDF_LOGE("%{public}s: Serial Device alloc faild", __func__);
- }
-
- acm->initFlag = false;
- g_acmReleaseFlag = false;
-
- HDF_LOGD("%{public}s:%{public}d init ok!", __func__, __LINE__);
-
- return ret;
-}
-
-static void UsbSerialDriverRelease(struct HdfDeviceObject *device)
-{
- struct AcmDevice *acm = NULL;
-
- if (device == NULL) {
- HDF_LOGE("%{public}s: device is NULL", __func__);
- return;
- }
- acm = (struct AcmDevice *)device->service;
- if (acm == NULL) {
- HDF_LOGE("%{public}s: acm is null", __func__);
- return;
- }
-
- g_acmReleaseFlag = true;
-
- if (acm->initFlag == true) {
- HDF_LOGE("%{public}s:%{public}d AcmRelease", __func__, __LINE__);
- AcmRelease(acm);
- }
- UsbSeriaDevicelFree(acm);
- OsalMutexDestroy(&acm->writeLock);
- OsalMutexDestroy(&acm->readLock);
- OsalMutexDestroy(&acm->lock);
- OsalMemFree(acm);
- acm = NULL;
- HDF_LOGD("%{public}s:%{public}d exit", __func__, __LINE__);
-}
-
-struct HdfDriverEntry g_usbSerialDriverEntry = {
- .moduleVersion = 1,
- .moduleName = "usbhost_acm", //驱动模块名称,必须与hcs文件中配置的名称一致
- .Bind = UsbSerialDriverBind,
- .Init = UsbSerialDriverInit,
- .Release = UsbSerialDriverRelease,
-};
-HDF_INIT(g_usbSerialDriverEntry);
-```
-
-### Host RAW API驱动开发
-
-```
-root {
- module = "usb_pnp_device";
- usb_pnp_config {
- match_attr = "usb_pnp_match";
- usb_pnp_device_id = "UsbPnpDeviceId";
- UsbPnpDeviceId {
- idTableList = [
- "host_acm_rawapi_table"
- ];
- host_acm_rawapi_table { //驱动配置匹配表信息
- //驱动模块名,该字段的值必须和驱动入口结构的moduleName一致
- moduleName = "usbhost_acm_rawapi";
- //驱动对外发布服务的名称,必须唯一
- serviceName = "usbhost_acm_rawapi_service";
- //驱动私有数据匹配关键字
- deviceMatchAttr = "usbhost_acm_rawapi_matchAttr";
- //从该字段开始(包含该字段)之后数据长度,以byte为单位
- length = 21;
- //USB驱动匹配规则vendorId+productId+interfaceSubClass+interfaceProtocol+interfaceNumber
- matchFlag = 0x0303;
- //厂商编号
- vendorId = 0x12D1;
- //产品编号
- productId = 0x5000;
- //设备出厂编号,低16位
- bcdDeviceLow = 0x0000;
- //设备出厂编号,高16位
- bcdDeviceHigh = 0x0000;
- //USB分配的设备类代码
- deviceClass = 0;
- //USB分配的子类代码
- deviceSubClass = 0;
- //USB分配的设备协议代码
- deviceProtocol = 0;
- //接口类型,根据实际需要可填写多个
- interfaceClass = [0];
- //接口子类型,根据实际需要可填写多个
- interfaceSubClass = [2, 0];
- //接口所遵循的协议,根据实际需要可填写多个
- interfaceProtocol = [1, 2];
- //接口的编号,根据实际需要可填写多个
- interfaceNumber = [2, 3];
- }
- }
- }
-}
-
-#include "usb_serial_rawapi.h"
-#include
-#include "osal_mem.h"
-#include "osal_time.h"
-#include "securec.h"
-#include "hdf_base.h"
-#include "hdf_log.h"
-#include "hdf_usb_pnp_manage.h"
-
-#define HDF_LOG_TAG USB_HOST_ACM_RAW_API
-#define USB_CTRL_REQ_SIZE 64
-#define USB_IO_THREAD_STACK_SIZE 8192
-#define USB_RAW_IO_SLEEP_MS_TIME 100
-#define USB_RAW_IO_STOP_WAIT_MAX_TIME 3
-
-static struct UsbRawRequest *g_syncRequest = NULL;
-static UsbRawIoProcessStatusType g_stopIoStatus = USB_RAW_IO_PROCESS_RUNNING;
-struct OsalMutex g_stopIoLock;
-static bool g_rawAcmReleaseFlag = false;
-......
-
-static int UsbGetConfigDescriptor(UsbRawHandle *devHandle, struct UsbRawConfigDescriptor **config)
-{
- UsbRawDevice *dev = NULL;
- int activeConfig;
- int ret;
-
- if (devHandle == NULL) {
- HDF_LOGE("%{public}s:%{public}d devHandle is NULL",
- __func__, __LINE__);
- return HDF_ERR_INVALID_PARAM;
- }
-
- ret = UsbRawGetConfiguration(devHandle, &activeConfig);
- if (ret) {
- HDF_LOGE("%{public}s:%{public}d UsbRawGetConfiguration failed, ret=%{public}d",
- __func__, __LINE__, ret);
- return HDF_FAILURE;
- }
- HDF_LOGE("%{public}s:%{public}d activeConfig=%{public}d", __func__, __LINE__, activeConfig);
- dev = UsbRawGetDevice(devHandle);
- if (dev == NULL) {
- HDF_LOGE("%{public}s:%{public}d UsbRawGetDevice failed",
- __func__, __LINE__);
- return HDF_FAILURE;
- }
-
- ret = UsbRawGetConfigDescriptor(dev, activeConfig, config);
- if (ret) {
- HDF_LOGE("UsbRawGetConfigDescriptor failed, ret=%{public}d\n", ret);
- return HDF_FAILURE;
- }
-
- return HDF_SUCCESS;
-}
-...
-static int UsbAllocWriteRequests(struct AcmDevice *acm)
-{
- int i;
-
- for (i = 0; i < ACM_NW; i++) {
- struct AcmWb *snd = &acm->wb[i];
- snd->request = UsbRawAllocRequest(acm->devHandle, 0, acm->dataOutEp->maxPacketSize);
- snd->instance = acm;
- if (snd->request == NULL) {
- HDF_LOGE("%{public}s: UsbRawAllocRequest faild", __func__);
- return HDF_ERR_MALLOC_FAIL;
- }
- }
-
- return HDF_SUCCESS;
-}
-...
-/* HdfDriverEntry implementations */
-static int32_t UsbSerialDriverBind(struct HdfDeviceObject *device)
-{
- struct AcmDevice *acm = NULL;
- struct UsbPnpNotifyServiceInfo *info = NULL;
- errno_t err;
-
- if (device == NULL) {
- HDF_LOGE("%s: device is null", __func__);
- return HDF_ERR_INVALID_OBJECT;
- }
-
- acm = (struct AcmDevice *)OsalMemCalloc(sizeof(*acm));
- if (acm == NULL) {
- HDF_LOGE("%s: Alloc usb serial device failed", __func__);
- return HDF_FAILURE;
- }
- if (OsalMutexInit(&acm->lock) != HDF_SUCCESS) {
- HDF_LOGE("%s:%d OsalMutexInit fail", __func__, __LINE__);
- goto error;
- }
-
- info = (struct UsbPnpNotifyServiceInfo *)device->priv;
- if (info != NULL) {
- acm->busNum = info->busNum;
- acm->devAddr = info->devNum;
- acm->interfaceCnt = info->interfaceLength;
- err = memcpy_s((void *)(acm->interfaceIndex), USB_MAX_INTERFACES,
- (const void*)info->interfaceNumber, info->interfaceLength);
- if (err != EOK) {
- HDF_LOGE("%s:%d memcpy_s faile err=%d", \
- __func__, __LINE__, err);
- goto lock_error;
- }
- } else {
- HDF_LOGE("%s:%d info is NULL!", __func__, __LINE__);
- goto lock_error;
- }
-
- device->service = &(acm->service);
- device->service->Dispatch = UsbSerialDeviceDispatch;
- acm->device = device;
- HDF_LOGD("UsbSerialDriverBind=========================OK");
- return HDF_SUCCESS;
-
-lock_error:
- if (OsalMutexDestroy(&acm->lock)) {
- HDF_LOGE("%s:%d OsalMutexDestroy fail", __func__, __LINE__);
- }
-error:
- OsalMemFree(acm);
- acm = NULL;
- return HDF_FAILURE;
-}
-...
-static int UsbAllocReadRequests(struct AcmDevice *acm)
-{
- struct UsbRawFillRequestData reqData;
- int size = acm->dataInEp->maxPacketSize;
- int ret;
-
- for (int i = 0; i < ACM_NR; i++) {
- acm->readReq[i] = UsbRawAllocRequest(acm->devHandle, 0, size);
- if (!acm->readReq[i]) {
- HDF_LOGE("readReq request faild\n");
- return HDF_ERR_MALLOC_FAIL;
- }
-
- reqData.endPoint = acm->dataInEp->addr;
- reqData.numIsoPackets = 0;
- reqData.callback = AcmReadBulkCallback;
- reqData.userData = (void *)acm;
- reqData.timeout = USB_CTRL_SET_TIMEOUT;
- reqData.length = size;
-
- ret = UsbRawFillBulkRequest(acm->readReq[i], acm->devHandle, &reqData);
- if (ret) {
- HDF_LOGE("%{public}s: FillBulkRequest faile, ret=%{public}d \n",
- __func__, ret);
- return HDF_FAILURE;
- }
- }
-
- return HDF_SUCCESS;
-}
-...
-static int UsbAllocNotifyRequest(struct AcmDevice *acm)
-{
- struct UsbRawFillRequestData fillRequestData;
- int size = acm->notifyEp->maxPacketSize;
- int ret;
-
- acm->notifyReq = UsbRawAllocRequest(acm->devHandle, 0, size);
- if (!acm->notifyReq) {
- HDF_LOGE("notifyReq request fail\n");
- return HDF_ERR_MALLOC_FAIL;
- }
-
- fillRequestData.endPoint = acm->notifyEp->addr;
- fillRequestData.length = size;
- fillRequestData.numIsoPackets = 0;
- fillRequestData.callback = AcmNotifyReqCallback;
- fillRequestData.userData = (void *)acm;
- fillRequestData.timeout = USB_CTRL_SET_TIMEOUT;
-
- ret = UsbRawFillInterruptRequest(acm->notifyReq, acm->devHandle, &fillRequestData);
- if (ret) {
- HDF_LOGE("%{public}s: FillInterruptRequest faile, ret=%{public}d", __func__, ret);
- return HDF_FAILURE;
- }
-
- return HDF_SUCCESS;
-}
-...
-static int32_t UsbSerialInit(struct AcmDevice *acm)
-{
- struct UsbSession *session = NULL;
- UsbRawHandle *devHandle = NULL;
- int32_t ret;
-
- if (acm->initFlag == true) {
- HDF_LOGE("%{public}s:%{public}d: initFlag is true", __func__, __LINE__);
- return HDF_SUCCESS;
- }
-
- ret = UsbRawInit(NULL);
- if (ret) {
- HDF_LOGE("%{public}s:%{public}d UsbRawInit faild", __func__, __LINE__);
- return HDF_ERR_IO;
- }
- acm->session = session;
-
- devHandle = UsbRawOpenDevice(session, acm->busNum, acm->devAddr);
- if (devHandle == NULL) {
- HDF_LOGE("%{public}s:%{public}d UsbRawOpenDevice faild", __func__, __LINE__);
- ret = HDF_FAILURE;
- goto err_open_device;
- }
- acm->devHandle = devHandle;
- ret = UsbGetConfigDescriptor(devHandle, &acm->config);
- if (ret) {
- HDF_LOGE("%{public}s:%{public}d UsbGetConfigDescriptor faild", __func__, __LINE__);
- ret = HDF_FAILURE;
- goto err_get_desc;
- }
- ret = UsbParseConfigDescriptor(acm, acm->config);
- if (ret != HDF_SUCCESS) {
- HDF_LOGE("%{public}s:%{public}d UsbParseConfigDescriptor faild", __func__, __LINE__);
- ret = HDF_FAILURE;
- goto err_parse_desc;
- }
-
- ret = AcmWriteBufAlloc(acm);
- if (ret < 0) {
- HDF_LOGE("%{public}s:%{public}d AcmWriteBufAlloc faild", __func__, __LINE__);
- ret = HDF_FAILURE;
- goto err_alloc_write_buf;
- }
- ret = UsbAllocWriteRequests(acm);
- if (ret < 0) {
- HDF_LOGE("%{public}s:%{public}d UsbAllocWriteRequests faild", __func__, __LINE__);
- ret = HDF_FAILURE;
- goto err_alloc_write_reqs;
- }
- ret = UsbAllocNotifyRequest(acm);
- if (ret) {
- HDF_LOGE("%{public}s:%{public}d UsbAllocNotifyRequests faild", __func__, __LINE__);
- goto err_alloc_notify_req;
- }
- ret = UsbAllocReadRequests(acm);
- if (ret) {
- HDF_LOGE("%{public}s:%{public}d UsbAllocReadRequests faild", __func__, __LINE__);
- goto err_alloc_read_reqs;
- }
- ret = UsbStartIo(acm);
- if (ret) {
- HDF_LOGE("%{public}s:%{public}d UsbAllocReadRequests faild", __func__, __LINE__);
- goto err_start_io;
- }
-
- acm->lineCoding.dwDTERate = CpuToLe32(DATARATE);
- acm->lineCoding.bCharFormat = CHARFORMAT;
- acm->lineCoding.bParityType = USB_CDC_NO_PARITY;
- acm->lineCoding.bDataBits = USB_CDC_1_STOP_BITS;
-
- ret = UsbRawSubmitRequest(acm->notifyReq);
- if (ret) {
- HDF_LOGE("%{public}s:%{public}d UsbRawSubmitRequest failed", __func__, __LINE__);
- goto err_submit_req;
- }
-
- acm->initFlag = true;
-
- HDF_LOGD("%{public}s:%{public}d=========================OK", __func__, __LINE__);
-
- return HDF_SUCCESS;
-
-err_submit_req:
- UsbStopIo(acm);
-err_start_io:
- UsbFreeReadRequests(acm);
-err_alloc_read_reqs:
- UsbFreeNotifyReqeust(acm);
- err_alloc_notify_req:
- UsbFreeWriteRequests(acm);
-err_alloc_write_reqs:
- AcmWriteBufFree(acm);
-err_alloc_write_buf:
- UsbReleaseInterfaces(acm);
-err_parse_desc:
- UsbRawFreeConfigDescriptor(acm->config);
- acm->config = NULL;
-err_get_desc:
- (void)UsbRawCloseDevice(devHandle);
-err_open_device:
- UsbRawExit(acm->session);
-
- return ret;
-}
-
-static void UsbSerialRelease(struct AcmDevice *acm)
-{
- if (acm->initFlag == false) {
- HDF_LOGE("%{public}s:%{public}d: initFlag is false", __func__, __LINE__);
- return;
- }
-
- /* stop io thread and release all resources */
- UsbStopIo(acm);
- if (g_syncRequest != NULL) {
- UsbRawFreeRequest(g_syncRequest);
- g_syncRequest = NULL;
- }
- UsbFreeReadRequests(acm);
- UsbFreeNotifyReqeust(acm);
- UsbFreeWriteRequests(acm);
- AcmWriteBufFree(acm);
- (void)UsbRawCloseDevice(acm->devHandle);
- UsbReleaseInterfaces(acm);
- UsbRawFreeConfigDescriptor(acm->config);
- acm->config = NULL;
- UsbRawExit(acm->session);
-
- acm->initFlag = false;
-}
-
-static int32_t UsbSerialDriverInit(struct HdfDeviceObject *device)
-{
- struct AcmDevice *acm = NULL;
- int32_t ret;
-
- if (device == NULL) {
- HDF_LOGE("%{public}s:%{public}d device is null", __func__, __LINE__);
- return HDF_ERR_INVALID_OBJECT;
- }
- acm = (struct AcmDevice *)device->service;
- OsalMutexInit(&acm->readLock);
- OsalMutexInit(&acm->writeLock);
-
- ret = UsbSerialDeviceAlloc(acm);
- if (ret != HDF_SUCCESS) {
- HDF_LOGE("%{public}s:%{public}d UsbSerialDeviceAlloc faild", __func__, __LINE__);
- }
-
- acm->initFlag = false;
- g_rawAcmReleaseFlag = false;
-
- HDF_LOGD("%{public}s:%{public}d init ok!", __func__, __LINE__);
-
- return ret;
-}
-
-static void UsbSerialDriverRelease(struct HdfDeviceObject *device)
-{
- struct AcmDevice *acm = NULL;
- if (device == NULL) {
- HDF_LOGE("%{public}s: device is NULL", __func__);
- return;
- }
-
- acm = (struct AcmDevice *)device->service;
- if (acm == NULL) {
- HDF_LOGE("%{public}s: acm is null", __func__);
- return;
- }
-
- g_rawAcmReleaseFlag = true;
-
- if (acm->initFlag == true) {
- HDF_LOGE("%{public}s:%{public}d UsbSerialRelease", __func__, __LINE__);
- UsbSerialRelease(acm);
- }
- UsbSeriaDevicelFree(acm);
- OsalMutexDestroy(&acm->writeLock);
- OsalMutexDestroy(&acm->readLock);
- OsalMutexDestroy(&acm->lock);
- OsalMemFree(acm);
- acm = NULL;
- HDF_LOGD("%{public}s:%{public}d exit", __func__, __LINE__);
-}
-
-struct HdfDriverEntry g_usbSerialRawDriverEntry = {
- .moduleVersion = 1,
- .moduleName = "usbhost_acm_rawapi", //驱动模块名称,必须与hcs文件中配置的名称一致
- .Bind = UsbSerialDriverBind,
- .Init = UsbSerialDriverInit,
- .Release = UsbSerialDriverRelease,
-};
-HDF_INIT(g_usbSerialRawDriverEntry);
-```
-
-### Device DDK API驱动开发
-USB ACM设备核心代码路径为drivers\peripheral\usb\gadget\function\acm\cdcacm.c,其使用示例如下所示,首先根据描述符创建设备,然后获取接口,打开接口,获取Pipe信息,接收Event事件,接着进行USB通信(读写等),设备卸载时候,关闭接口,停止Event接收,删除设备。
-
-```
-1、创建设备
-static int32_t AcmCreateFuncDevice(struct UsbAcmDevice *acm,
- struct DeviceResourceIface *iface)
-{
- struct UsbFnDevice *fnDev = NULL;
-struct UsbFnDescriptorData descData;
-uint8_t useHcs;
- ...
-if (useHcs == 0) {
- descData.type = USBFN_DESC_DATA_TYPE_DESC;
- descData.descriptor = &g_masterFuncDevice;
-} else {
- descData.type = USBFN_DESC_DATA_TYPE_PROP;
- descData.property = device->property;
-}
-/* 创建设备 */
- fnDev = (struct UsbFnDevice *)UsbFnDeviceCreate(acm->udcName, &descData);
- if (fnDev == NULL) {
- HDF_LOGE("%{public}s: create usb function device failed", __func__);
- return HDF_FAILURE;
- }
- ...
-}
-2、获取接口,打开接口,获取Pipe信息
-static int32_t AcmParseEachPipe(struct UsbAcmDevice *acm, struct UsbAcmInterface *iface)
-{
- ...
- for (i = 0; i < fnIface->info.numPipes; i++) {
- struct UsbFnPipeInfo pipeInfo;
-/* 获取pipe信息 */
- ret = UsbFnInterfaceGetPipeInfo(fnIface, i, &pipeInfo);
- ...
- }
- return HDF_SUCCESS;
-}
-/* 获取接口,打开接口获取handle */
-static int32_t AcmParseEachIface(struct UsbAcmDevice *acm, struct UsbFnDevice *fnDev)
-{
- ...
- for (i = 0; i < fnDev->numInterfaces; i++) {
- /* 获取接口 */
- fnIface = (struct UsbFnInterface *)UsbFnDeviceGetInterface(fnDev, i);
- ...
- /* 打开接口 */
- handle = UsbFnInterfaceOpen(fnIface);
- ...
- }
- return HDF_SUCCESS;
-}
-3、接收Event事件
-static int32_t AcmAllocCtrlRequests(struct UsbAcmDevice *acm, int num)
-{
- ...
- req = UsbFnCtrlRequestAlloc(acm->ctrlIface.handle,
- sizeof(struct UsbCdcLineCoding) + sizeof(struct UsbCdcLineCoding));
- ...
-}
-static int32_t AcmDriverInit(struct HdfDeviceObject *device)
-{
-...
-/* 开始接收Event */
- ret = UsbFnInterfaceStartRecvEvent(acm->ctrlIface.fn, 0xff, UsbAcmEventCallback, acm);
- ...
-}
-4、进行USB通信(读写等)
-static int32_t AcmSendNotifyRequest(struct UsbAcmDevice *acm, uint8_t type,
- uint16_t value, void *data, uint32_t length)
-{
-...
-/* 异步发送 */
- ret = UsbFnRequestSubmitAsync(req);
- ...
-}
-5、关闭接口,停止Event接收,删除设备
-static int32_t AcmReleaseFuncDevice(struct UsbAcmDevice *acm)
-{
-int32_t ret;
-/* 关闭接口 */
- (void)UsbFnInterfaceClose(acm->ctrlIface.handle);
-(void)UsbFnInterfaceClose(acm->dataIface.handle);
-/* 停止接收Event */
-(void)UsbFnInterfaceStopRecvEvent(acm->ctrlIface.fn);
-/* 删除设备 */
- ret = UsbFnDeviceRemove(acm->fnDev);
- if (ret != HDF_SUCCESS) {
- HDF_LOGE("%{public}s: remove usb function device failed", __func__);
- }
- return ret;
-}
-```
-
diff --git a/zh-cn/device-dev/driver/driver-peripherals.md b/zh-cn/device-dev/driver/driver-peripherals.md
index 8ef4078014c768b384834ecc52071d22ae7fbcda..61a697d04f8ee2ec878fa520879695fc0be5a8c5 100644
--- a/zh-cn/device-dev/driver/driver-peripherals.md
+++ b/zh-cn/device-dev/driver/driver-peripherals.md
@@ -1,4 +1,4 @@
-# 外设驱动开发
+# 外设驱动使用
- **[LCD](driver-peripherals-lcd-des.md)**
diff --git a/zh-cn/device-dev/driver/driver-platform-adc-develop.md b/zh-cn/device-dev/driver/driver-platform-adc-develop.md
index 084a45ae25196225fac94efb74f7d4aac468217c..c82f0ed7ced87fb97f94629ccb3eace00811ffb6 100755
--- a/zh-cn/device-dev/driver/driver-platform-adc-develop.md
+++ b/zh-cn/device-dev/driver/driver-platform-adc-develop.md
@@ -1,317 +1,424 @@
-# ADC
-
-- [概述](#1)
-- [开发步骤](#2)
-- [开发实例](#3)
-
-## 概述
-
-ADC(Analog to Digital Converter),即模拟-数字转换器,是一种将模拟信号转换成对应数字信号的设备,在HDF框架中,ADC模块接口适配模式采用统一服务模式,这需要一个设备服务来作为ADC模块的管理器,统一处理外部访问,这会在配置文件中有所体现。统一服务模式适合于同类型设备对象较多的情况,如ADC可能同时具备十几个控制器,采用独立服务模式需要配置更多的设备节点,且服务会占据内存资源。
-
-
-
-## 开发步骤
-
-ADC模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
-
-1. **实例化驱动入口:**
-
- - 实例化HdfDriverEntry结构体成员。
- - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
-
-2. **配置属性文件:**
-
- - 在device_info.hcs文件中添加deviceNode描述。
- - 【可选】添加adc_config.hcs器件属性文件。
-
-3. **实例化ADC控制器对象:**
-
- - 初始化AdcDevice成员。
- - 实例化AdcDevice成员AdcMethod,其定义和成员说明见下
-
-4. **驱动调试:**
- - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,信号采集的成功与否等。
-
->  **说明:**
-> AdcMethod定义
->
-> ```c
-> struct AdcMethod {
-> int32_t (*read)(struct AdcDevice *device, uint32_t channel, uint32_t *val);
-> int32_t (*start)(struct AdcDevice *device);
-> int32_t (*stop)(struct AdcDevice *device);
-> };
-> ```
->
-> 表1 AdcMethod结构体成员的回调函数功能说明
->
-> |函数成员|入参|出参|返回值|功能|
-> |-|-|-|-|-|
-> |read|**device**: 结构体指针,核心层ADC控制器; **channel**:uint32_t,传入的通道号;|**val**:uint32_t指针,要传出的信号数据;|HDF_STATUS相关状态|读取ADC采样的信号数据|
-> |stop |**device**: 结构体指针,核心层ADC控制器;|无|HDF_STATUS相关状态|关闭ADC设备|
-> |start |**device**: 结构体指针,核心层ADC控制器;|无|HDF_STATUS相关状态|开启ADC设备|
-
-
-## 开发实例
-
-接下来以 adc_hi35xx.c 为示例, 展示需要厂商提供哪些内容来完整实现设备功能
-
-1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
-
- 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
-
-- ADC驱动入口参考
-
- > ADC模块这种类型的控制器会出现很多个设备挂接的情况,因而在HDF框架中首先会为这类型的设备创建一个管理器对象。这样,需要打开某个设备时,管理器对象会根据指定参数查找到指定设备。
- >
- > ADC管理器的驱动由核心层实现,**厂商不需要关注这部分内容的实现,这个但在实现Init函数的时候需要调用核心层的AdcDeviceAdd函数,它会实现相应功能。**
-
- ```c
- static struct HdfDriverEntry g_hi35xxAdcDriverEntry = {
- .moduleVersion = 1,
- .Init = Hi35xxAdcInit,
- .Release = Hi35xxAdcRelease,
- .moduleName = "hi35xx_adc_driver",//【必要且与hcs文件里面的名字匹配】
- };
- HDF_INIT(g_hi35xxAdcDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中
-
- //核心层adc_core.c管理器服务的驱动入口
- struct HdfDriverEntry g_adcManagerEntry = {
- .moduleVersion = 1,
- .Init = AdcManagerInit,
- .Release = AdcManagerRelease,
- .moduleName = "HDF_PLATFORM_ADC_MANAGER",//这与device_info文件中device0对应
- };
- HDF_INIT(g_adcManagerEntry);
- ```
-
-2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在adc_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值对于厂商驱动的实现以及核心层AdcDevice相关成员的默认值或限制范围有密切关系。
-
- **统一服务模式**的特点是device_info文件中第一个设备节点必须为ADC管理器,其各项参数必须如下设置:
-
- |成员名|值|
- |-|-|
- |moduleName | 固定为 HDF_PLATFORM_ADC_MANAGER|
- |serviceName| 无|
- |policy| 具体配置为0,不发布服务|
- |deviceMatchAttr| 没有使用,可忽略|
-
- **从第二个节点开始配置具体ADC控制器信息**,此节点并不表示某一路ADC控制器,而是代表一个资源性质设备,用于描述一类ADC控制器的信息。**本例只有一个ADC设备,如有多个设备,则需要在device_info文件增加deviceNode信息,以及在adc_config文件中增加对应的器件属性**。
-
-- device_info.hcs 配置参考
-
- ```c
- root {
- device_info {
- platform :: host {
- device_adc :: device {
- device0 :: deviceNode {
- policy = 0;
- priority = 50;
- permission = 0644;
- moduleName = "HDF_PLATFORM_ADC_MANAGER";
- serviceName = "HDF_PLATFORM_ADC_MANAGER";
- }
- device1 :: deviceNode {
- policy = 0; // 等于0,不需要发布服务
- priority = 55; // 驱动启动优先级
- permission = 0644; // 驱动创建设备节点权限
- moduleName = "hi35xx_adc_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致;
- serviceName = "HI35XX_ADC_DRIVER"; //【必要】驱动对外发布服务的名称,必须唯一
- deviceMatchAttr = "hisilicon_hi35xx_adc";//【必要】用于配置控制器私有数据,要与adc_config.hcs中对应控制器保持一致
- } // 具体的控制器信息在 adc_config.hcs 中
- }
- }
- }
- }
- ```
-
-- adc_config.hcs 配置参考
-
- ```c
- root {
- platform {
- adc_config_hi35xx {
- match_attr = "hisilicon_hi35xx_adc";
- template adc_device {
- regBasePhy = 0x120e0000;//寄存器物理基地址
- regSize = 0x34; //寄存器位宽
- deviceNum = 0; //设备号
- validChannel = 0x1; //有效通道
- dataWidth = 10; //信号接收的数据位宽
- scanMode = 1; //扫描模式
- delta = 0; //delta参数
- deglitch = 0;
- glitchSample = 5000;
- rate = 20000;
- }
- device_0 :: adc_device {
- deviceNum = 0;
- validChannel = 0x2;
- }
- }
- }
- }
- ```
-
-3. 完成驱动入口注册之后,最后一步就是以核心层AdcDevice对象的初始化为核心,包括初始化厂商自定义结构体(传递参数和数据),实例化AdcDevice成员AdcMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)
-
-
-- 自定义结构体参考
-
- > 从驱动的角度看,自定义结构体是参数和数据的载体,而且adc_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层AdcDevice对象,例如设备号、总线号等。
-
- ```c
- struct Hi35xxAdcDevice {
- struct AdcDevice device;//【必要】是核心层控制对象,具体描述见下面
- volatile unsigned char *regBase;//【必要】寄存器基地址
- volatile unsigned char *pinCtrlBase;
- uint32_t regBasePhy; //【必要】寄存器物理基地址
- uint32_t regSize; //【必要】寄存器位宽
- uint32_t deviceNum; //【必要】设备号
- uint32_t dataWidth; //【必要】信号接收的数据位宽
- uint32_t validChannel; //【必要】有效通道
- uint32_t scanMode; //【必要】扫描模式
- uint32_t delta;
- uint32_t deglitch;
- uint32_t glitchSample;
- uint32_t rate; //【必要】采样率
- };
-
- //AdcDevice是核心层控制器结构体,其中的成员在Init函数中会被赋值
- struct AdcDevice {
- const struct AdcMethod *ops;
- OsalSpinlock spin;
- uint32_t devNum;
- uint32_t chanNum;
- const struct AdcLockMethod *lockOps;
- void *priv;
- };
- ```
-
-
-- **【重要】** AdcDevice成员回调函数结构体AdcMethod的实例化,AdcLockMethod回调函数结构体本例未实现,若要实例化,可参考I2C驱动开发,其他成员在Init函数中初始化
-
- ```c
- static const struct AdcMethod g_method = {
- .read = Hi35xxAdcRead,
- .stop = Hi35xxAdcStop,
- .start = Hi35xxAdcStart,
- };
- ```
-
-- **init函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)
- >
- > |状态(值)|问题描述|
- > |:-|:-:|
- > |HDF_ERR_INVALID_OBJECT|控制器对象非法|
- > |HDF_ERR_INVALID_PARAM |参数非法|
- > |HDF_ERR_MALLOC_FAIL |内存分配失败|
- > |HDF_ERR_IO |I/O 错误|
- > |HDF_SUCCESS |传输成功|
- > |HDF_FAILURE |传输失败|
- >
- > **函数说明:**
- > 初始化自定义结构体对象,初始化AdcDevice成员,并调用核心层AdcDeviceAdd函数。
-
- ```c
- static int32_t Hi35xxAdcInit(struct HdfDeviceObject *device)
- {
- int32_t ret;
- struct DeviceResourceNode *childNode = NULL;
- ...
- //遍历、解析adc_config.hcs中的所有配置节点,并分别调用Hi35xxAdcParseInit函数来初始化device
- DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
- ret = Hi35xxAdcParseInit(device, childNode);//函数定义见下
- ...
- }
- return ret;
- }
-
- static int32_t Hi35xxAdcParseInit(struct HdfDeviceObject *device, struct DeviceResourceNode *node)
- {
- int32_t ret;
- struct Hi35xxAdcDevice *hi35xx = NULL; //【必要】自定义结构体对象
- (void)device;
-
- hi35xx = (struct Hi35xxAdcDevice *)OsalMemCalloc(sizeof(*hi35xx)); //【必要】内存分配
- ...
- ret = Hi35xxAdcReadDrs(hi35xx, node); //【必要】将adc_config文件的默认值填充到结构体中
- ...
- hi35xx->regBase = OsalIoRemap(hi35xx->regBasePhy, hi35xx->regSize);//【必要】地址映射
- ...
- hi35xx->pinCtrlBase = OsalIoRemap(HI35XX_ADC_IO_CONFIG_BASE, HI35XX_ADC_IO_CONFIG_SIZE);
- ...
- Hi35xxAdcDeviceInit(hi35xx); //【必要】ADC设备的初始化
- hi35xx->device.priv = (void *)node; //【必要】存储设备属性
- hi35xx->device.devNum = hi35xx->deviceNum;//【必要】初始化AdcDevice成员
- hi35xx->device.ops = &g_method; //【必要】AdcMethod的实例化对象的挂载
- ret = AdcDeviceAdd(&hi35xx->device); //【必要且重要】调用此函数填充核心层结构体,返回成功信号后驱动才完全接入平台核心层
- ...
- return HDF_SUCCESS;
-
- __ERR__:
- if (hi35xx != NULL) { //不成功的话,需要反向执行初始化相关函数
- if (hi35xx->regBase != NULL) {
- OsalIoUnmap((void *)hi35xx->regBase);
- hi35xx->regBase = NULL;
- }
- AdcDeviceRemove(&hi35xx->device);
- OsalMemFree(hi35xx);
- }
- return ret;
- }
- ```
-
-- **Release 函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > 无
- >
- > **函数说明:**
- > 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
-
- ```c
- static void Hi35xxAdcRelease(struct HdfDeviceObject *device)
- {
- const struct DeviceResourceNode *childNode = NULL;
- ...
- //遍历、解析adc_config.hcs中的所有配置节点,并分别进行release操作
- DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
- Hi35xxAdcRemoveByNode(childNode);//函数定义见下
- }
- }
-
- static void Hi35xxAdcRemoveByNode(const struct DeviceResourceNode *node)
- {
- int32_t ret;
- int32_t deviceNum;
- struct AdcDevice *device = NULL;
- struct Hi35xxAdcDevice *hi35xx = NULL;
- struct DeviceResourceIface *drsOps = NULL;
-
- drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
- ...
- ret = drsOps->GetUint32(node, "deviceNum", (uint32_t *)&deviceNum, 0);
- ...
- //可以调用AdcDeviceGet函数通过设备的deviceNum获取AdcDevice对象, 以及调用AdcDeviceRemove函数来释放AdcDevice对象的内容
- device = AdcDeviceGet(deviceNum);
- if (device != NULL && device->priv == node) {
- AdcDevicePut(device);
- AdcDeviceRemove(device); //【必要】主要是从管理器驱动那边移除AdcDevice对象
- hi35xx = (struct Hi35xxAdcDevice *)device;//【必要】通过强制转换获取自定义的对象并进行release操作
- OsalIoUnmap((void *)hi35xx->regBase);
- OsalMemFree(hi35xx);
- }
- return;
- }
- ```
\ No newline at end of file
+# ADC
+
+- [概述](#section268031773165048)
+- [接口说明](#section752964871810)
+- [开发步骤](#section100579767165048)
+- [开发实例](#section1745221471165048)
+
+## 概述
+
+ADC(Analog to Digital Converter),即模拟-数字转换器,是一种将模拟信号转换成对应数字信号的设备,在HDF框架中,ADC模块接口适配模式采用统一服务模式,这需要一个设备服务来作为ADC模块的管理器,统一处理外部访问,这会在配置文件中有所体现。统一服务模式适合于同类型设备对象较多的情况,如ADC可能同时具备十几个控制器,采用独立服务模式需要配置更多的设备节点,且服务会占据内存资源。
+
+**图 1** ADC统一服务
+
+
+## 接口说明
+
+AdcMethod定义:
+
+```
+struct AdcMethod {
+ int32_t (*read)(struct AdcDevice *device, uint32_t channel, uint32_t *val);
+ int32_t (*start)(struct AdcDevice *device);
+ int32_t (*stop)(struct AdcDevice *device);
+};
+```
+
+**表 1** AdcMethod结构体成员的回调函数功能说明
+
+
+函数成员
+ |
+入参
+ |
+出参
+ |
+返回值
+ |
+功能
+ |
+
+
+read
+ |
+device: 结构体指针,核心层ADC控制器;channel:uint32_t,传入的通道号;
+ |
+val:uint32_t指针,要传出的信号数据;
+ |
+HDF_STATUS相关状态
+ |
+读取ADC采样的信号数据
+ |
+
+stop
+ |
+device: 结构体指针,核心层ADC控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+关闭ADC设备
+ |
+
+start
+ |
+device: 结构体指针,核心层ADC控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+开启ADC设备
+ |
+
+
+
+
+## 开发步骤
+
+ADC模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
+
+1. **实例化驱动入口:**
+ - 实例化HdfDriverEntry结构体成员。
+ - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
+
+2. **配置属性文件:**
+ - 在device\_info.hcs文件中添加deviceNode描述。
+ - 【可选】添加adc\_config.hcs器件属性文件。
+
+3. **实例化ADC控制器对象:**
+ - 初始化AdcDevice成员。
+ - 实例化AdcDevice成员AdcMethod。
+
+ > **说明:**
+ >实例化AdcDevice成员AdcMethod,其定义和成员说明见[接口说明](#section752964871810)。
+
+
+4. **驱动调试:**
+
+ 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,信号采集的成功与否等。
+
+
+## 开发实例
+
+接下来以 adc\_hi35xx.c 为示例, 展示需要厂商提供哪些内容来完整实现设备功能。
+
+1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
+
+ 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
+
+ ADC驱动入口参考:
+
+ ADC模块这种类型的控制器会出现很多个设备挂接的情况,因而在HDF框架中首先会为这类型的设备创建一个管理器对象。这样,需要打开某个设备时,管理器对象会根据指定参数查找到指定设备。
+
+ ADC管理器的驱动由核心层实现,厂商不需要关注这部分内容的实现,这个但在实现Init函数的时候需要调用核心层的AdcDeviceAdd函数,它会实现相应功能。
+
+ ```
+ static struct HdfDriverEntry g_hi35xxAdcDriverEntry = {
+ .moduleVersion = 1,
+ .Init = Hi35xxAdcInit,
+ .Release = Hi35xxAdcRelease,
+ .moduleName = "hi35xx_adc_driver",//【必要且与HCS文件里面的名字匹配】
+ };
+ HDF_INIT(g_hi35xxAdcDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中
+
+ //核心层adc_core.c管理器服务的驱动入口
+ struct HdfDriverEntry g_adcManagerEntry = {
+ .moduleVersion = 1,
+ .Init = AdcManagerInit,
+ .Release = AdcManagerRelease,
+ .moduleName = "HDF_PLATFORM_ADC_MANAGER",//这与device_info文件中device0对应
+ };
+ HDF_INIT(g_adcManagerEntry);
+ ```
+
+2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在adc\_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值对于厂商驱动的实现以及核心层AdcDevice相关成员的默认值或限制范围有密切关系。
+
+ 统一服务模式的特点是device\_info文件中第一个设备节点必须为ADC管理器,其各项参数必须如下设置:
+
+
+ 成员名
+ |
+ 值
+ |
+
+
+ moduleName
+ |
+ 固定为 HDF_PLATFORM_ADC_MANAGER
+ |
+
+ serviceName
+ |
+ 无
+ |
+
+ policy
+ |
+ 具体配置为0,不发布服务
+ |
+
+ deviceMatchAttr
+ |
+ 没有使用,可忽略
+ |
+
+
+
+
+ 从第二个节点开始配置具体ADC控制器信息,此节点并不表示某一路ADC控制器,而是代表一个资源性质设备,用于描述一类ADC控制器的信息。本例只有一个ADC设备,如有多个设备,则需要在device\_info文件增加deviceNode信息,以及在adc\_config文件中增加对应的器件属性。
+
+ - device\_info.hcs 配置参考。
+
+ ```
+ root {
+ device_info {
+ platform :: host {
+ device_adc :: device {
+ device0 :: deviceNode {
+ policy = 0;
+ priority = 50;
+ permission = 0644;
+ moduleName = "HDF_PLATFORM_ADC_MANAGER";
+ serviceName = "HDF_PLATFORM_ADC_MANAGER";
+ }
+ device1 :: deviceNode {
+ policy = 0; // 等于0,不需要发布服务
+ priority = 55; // 驱动启动优先级
+ permission = 0644; // 驱动创建设备节点权限
+ moduleName = "hi35xx_adc_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致;
+ serviceName = "HI35XX_ADC_DRIVER"; //【必要】驱动对外发布服务的名称,必须唯一
+ deviceMatchAttr = "hisilicon_hi35xx_adc";//【必要】用于配置控制器私有数据,要与adc_config.hcs中对应控制器保持一致
+ } // 具体的控制器信息在 adc_config.hcs 中
+ }
+ }
+ }
+ }
+ ```
+
+ - adc\_config.hcs 配置参考。
+
+ ```
+ root {
+ platform {
+ adc_config_hi35xx {
+ match_attr = "hisilicon_hi35xx_adc";
+ template adc_device {
+ regBasePhy = 0x120e0000;//寄存器物理基地址
+ regSize = 0x34; //寄存器位宽
+ deviceNum = 0; //设备号
+ validChannel = 0x1; //有效通道
+ dataWidth = 10; //信号接收的数据位宽
+ scanMode = 1; //扫描模式
+ delta = 0; //delta参数
+ deglitch = 0;
+ glitchSample = 5000;
+ rate = 20000;
+ }
+ device_0 :: adc_device {
+ deviceNum = 0;
+ validChannel = 0x2;
+ }
+ }
+ }
+ }
+ ```
+
+3. 完成驱动入口注册之后,最后一步就是以核心层AdcDevice对象的初始化为核心,包括初始化厂商自定义结构体(传递参数和数据),实例化AdcDevice成员AdcMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
+ - 自定义结构体参考。
+
+ 从驱动的角度看,自定义结构体是参数和数据的载体,而且adc\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层AdcDevice对象,例如设备号、总线号等。
+
+ ```
+ struct Hi35xxAdcDevice {
+ struct AdcDevice device;//【必要】是核心层控制对象,具体描述见下面
+ volatile unsigned char *regBase;//【必要】寄存器基地址
+ volatile unsigned char *pinCtrlBase;
+ uint32_t regBasePhy; //【必要】寄存器物理基地址
+ uint32_t regSize; //【必要】寄存器位宽
+ uint32_t deviceNum; //【必要】设备号
+ uint32_t dataWidth; //【必要】信号接收的数据位宽
+ uint32_t validChannel; //【必要】有效通道
+ uint32_t scanMode; //【必要】扫描模式
+ uint32_t delta;
+ uint32_t deglitch;
+ uint32_t glitchSample;
+ uint32_t rate; //【必要】采样率
+ };
+
+ //AdcDevice是核心层控制器结构体,其中的成员在Init函数中会被赋值
+ struct AdcDevice {
+ const struct AdcMethod *ops;
+ OsalSpinlock spin;
+ uint32_t devNum;
+ uint32_t chanNum;
+ const struct AdcLockMethod *lockOps;
+ void *priv;
+ };
+ ```
+
+ - AdcDevice成员回调函数结构体AdcMethod的实例化,AdcLockMethod回调函数结构体本例未实现,若要实例化,可参考I2C驱动开发,其他成员在Init函数中初始化。
+
+ ```
+ static const struct AdcMethod g_method = {
+ .read = Hi35xxAdcRead,
+ .stop = Hi35xxAdcStop,
+ .start = Hi35xxAdcStart,
+ };
+ ```
+
+ - init函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。
+
+
+ 状态(值)
+ |
+ 问题描述
+ |
+
+
+ HDF_ERR_INVALID_OBJECT
+ |
+ 控制器对象非法
+ |
+
+ HDF_ERR_INVALID_PARAM
+ |
+ 参数非法
+ |
+
+ HDF_ERR_MALLOC_FAIL
+ |
+ 内存分配失败
+ |
+
+ HDF_ERR_IO
+ |
+ I/O 错误
+ |
+
+ HDF_SUCCESS
+ |
+ 传输成功
+ |
+
+ HDF_FAILURE
+ |
+ 传输失败
+ |
+
+
+
+
+ 函数说明:
+
+ 初始化自定义结构体对象,初始化AdcDevice成员,并调用核心层AdcDeviceAdd函数。
+
+ ```
+ static int32_t Hi35xxAdcInit(struct HdfDeviceObject *device)
+ {
+ int32_t ret;
+ struct DeviceResourceNode *childNode = NULL;
+ ...
+ //遍历、解析adc_config.hcs中的所有配置节点,并分别调用Hi35xxAdcParseInit函数来初始化device
+ DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
+ ret = Hi35xxAdcParseInit(device, childNode);//函数定义见下
+ ...
+ }
+ return ret;
+ }
+
+ static int32_t Hi35xxAdcParseInit(struct HdfDeviceObject *device, struct DeviceResourceNode *node)
+ {
+ int32_t ret;
+ struct Hi35xxAdcDevice *hi35xx = NULL; //【必要】自定义结构体对象
+ (void)device;
+
+ hi35xx = (struct Hi35xxAdcDevice *)OsalMemCalloc(sizeof(*hi35xx)); //【必要】内存分配
+ ...
+ ret = Hi35xxAdcReadDrs(hi35xx, node); //【必要】将adc_config文件的默认值填充到结构体中
+ ...
+ hi35xx->regBase = OsalIoRemap(hi35xx->regBasePhy, hi35xx->regSize);//【必要】地址映射
+ ...
+ hi35xx->pinCtrlBase = OsalIoRemap(HI35XX_ADC_IO_CONFIG_BASE, HI35XX_ADC_IO_CONFIG_SIZE);
+ ...
+ Hi35xxAdcDeviceInit(hi35xx); //【必要】ADC设备的初始化
+ hi35xx->device.priv = (void *)node; //【必要】存储设备属性
+ hi35xx->device.devNum = hi35xx->deviceNum;//【必要】初始化AdcDevice成员
+ hi35xx->device.ops = &g_method; //【必要】AdcMethod的实例化对象的挂载
+ ret = AdcDeviceAdd(&hi35xx->device); //【必要且重要】调用此函数填充核心层结构体,返回成功信号后驱动才完全接入平台核心层
+ ...
+ return HDF_SUCCESS;
+
+ __ERR__:
+ if (hi35xx != NULL) { //不成功的话,需要反向执行初始化相关函数
+ if (hi35xx->regBase != NULL) {
+ OsalIoUnmap((void *)hi35xx->regBase);
+ hi35xx->regBase = NULL;
+ }
+ AdcDeviceRemove(&hi35xx->device);
+ OsalMemFree(hi35xx);
+ }
+ return ret;
+ }
+ ```
+
+ - Release 函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ 无。
+
+ 函数说明:
+
+ 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
+
+ ```
+ static void Hi35xxAdcRelease(struct HdfDeviceObject *device)
+ {
+ const struct DeviceResourceNode *childNode = NULL;
+ ...
+ //遍历、解析adc_config.hcs中的所有配置节点,并分别进行release操作
+ DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
+ Hi35xxAdcRemoveByNode(childNode);//函数定义见下
+ }
+ }
+
+ static void Hi35xxAdcRemoveByNode(const struct DeviceResourceNode *node)
+ {
+ int32_t ret;
+ int32_t deviceNum;
+ struct AdcDevice *device = NULL;
+ struct Hi35xxAdcDevice *hi35xx = NULL;
+ struct DeviceResourceIface *drsOps = NULL;
+
+ drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
+ ...
+ ret = drsOps->GetUint32(node, "deviceNum", (uint32_t *)&deviceNum, 0);
+ ...
+ //可以调用AdcDeviceGet函数通过设备的deviceNum获取AdcDevice对象, 以及调用AdcDeviceRemove函数来释放AdcDevice对象的内容
+ device = AdcDeviceGet(deviceNum);
+ if (device != NULL && device->priv == node) {
+ AdcDevicePut(device);
+ AdcDeviceRemove(device); //【必要】主要是从管理器驱动那边移除AdcDevice对象
+ hi35xx = (struct Hi35xxAdcDevice *)device;//【必要】通过强制转换获取自定义的对象并进行release操作
+ OsalIoUnmap((void *)hi35xx->regBase);
+ OsalMemFree(hi35xx);
+ }
+ return
+ ```
+
+
+
diff --git a/zh-cn/device-dev/driver/driver-platform-develop.md b/zh-cn/device-dev/driver/driver-platform-develop.md
deleted file mode 100755
index 53685a6ada0c5c400426bd550413589093df75cc..0000000000000000000000000000000000000000
--- a/zh-cn/device-dev/driver/driver-platform-develop.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# 平台驱动开发
- - **[GPIO](driver-platform-gpio-develop.md)**
- - **[I2C](driver-platform-i2c-develop.md)**
- - **[RTC](driver-platform-rtc-develop.md)**
- - **[SDIO](driver-platform-sdio-develop.md)**
- - **[SPI](driver-platform-spi-develop.md)**
- - **[UART](driver-platform-uart-develop.md)**
- - **[WATCHDOG](driver-platform-watchdog-develop.md)**
- - **[MIPI_DSI](driver-platform-mipidsi-develop.md)**
- - **[MMC](driver-platform-mmc-develop.md)**
- - **[PWM](driver-platform-pwm-develop.md)**
- - **[ADC](driver-platform-adc-develop.md)**
diff --git a/zh-cn/device-dev/driver/driver-platform-gpio-des.md b/zh-cn/device-dev/driver/driver-platform-gpio-des.md
index d4e67c7a5167857f6a3091f277b3da9a98c26490..28cc26f4f695d821cc92e153a7c18c65e95fda4b 100644
--- a/zh-cn/device-dev/driver/driver-platform-gpio-des.md
+++ b/zh-cn/device-dev/driver/driver-platform-gpio-des.md
@@ -1,8 +1,7 @@
-# GPIO
+# GPIO
- [概述](#section1635911016188)
- - [接口说明](#section17715915181611)
-
+- [接口说明](#section589913442203)
- [使用指导](#section259614242196)
- [使用流程](#section103477714216)
- [确定GPIO管脚号](#section370083272117)
@@ -22,63 +21,63 @@ GPIO接口定义了操作GPIO管脚的标准方法集合,包括:
- 设置管脚中断服务函数:设置一个管脚的中断响应函数,以及中断触发方式
- 使能和禁止管脚中断:禁止或使能管脚中断
-### 接口说明
+## 接口说明
**表 1** GPIO驱动API接口功能介绍
-
-功能分类
+
+功能分类
|
-接口名
+ | 接口名
|
-描述
+ | 描述
|
-GPIO读写
+ | GPIO读写
|
-GpioRead
+ | GpioRead
|
-读管脚电平值
+ | 读管脚电平值
|
-GpioWrite
+ | GpioWrite
|
-写管脚电平值
+ | 写管脚电平值
|
-GPIO配置
+ | GPIO配置
|
-GpioSetDir
+ | GpioSetDir
|
-设置管脚方向
+ | 设置管脚方向
|
-GpioGetDir
+ | GpioGetDir
|
-获取管脚方向
+ | 获取管脚方向
|
-GPIO中断设置
+ | GPIO中断设置
|
-GpioSetIrq
+ | GpioSetIrq
|
-设置管脚对应的中断服务函数
+ | 设置管脚对应的中断服务函数
|
-GpioUnSetIrq
+ | GpioUnSetIrq
|
-取消管脚对应的中断服务函数
+ | 取消管脚对应的中断服务函数
|
-GpioEnableIrq
+ | GpioEnableIrq
|
-使能管脚中断
+ | 使能管脚中断
|
-GpioDisableIrq
+ | GpioDisableIrq
|
-禁止管脚中断
+ | 禁止管脚中断
|
@@ -91,12 +90,10 @@ GPIO接口定义了操作GPIO管脚的标准方法集合,包括:
### 使用流程
-GPIO标准API通过GPIO管脚号来操作指定管脚,使用GPIO的一般流程如[图1](#fig1399416053717)所示。
-
-**图 1** GPIO使用流程图
-
+GPIO标准API通过GPIO管脚号来操作指定管脚,使用GPIO的一般流程如[图1](#fig16151101653713)所示。
-
+**图 1** GPIO使用流程图
+
### 确定GPIO管脚号
diff --git a/zh-cn/device-dev/driver/driver-platform-gpio-develop.md b/zh-cn/device-dev/driver/driver-platform-gpio-develop.md
index 7f587b81c15f62a0e6e91ef97b80bc1a4263bec5..5d4d63ac1f17b61d2fbec88f74129c8b4aac61d4 100755
--- a/zh-cn/device-dev/driver/driver-platform-gpio-develop.md
+++ b/zh-cn/device-dev/driver/driver-platform-gpio-develop.md
@@ -1,285 +1,418 @@
-# GPIO
-
-- [概述](#1)
-- [开发步骤](#2)
-- [开发实例](#3)
-
-## 概述
-
-GPIO(General-purpose input/output)即通用型输入输出,在HDF框架中,
-GPIO的接口适配模式采用无服务模式,用于不需要在用户态提供API的设备类型,或者没有用户态和内核区分的OS系统,其关联方式是DevHandle直接指向设备对象内核态地址(DevHandle是一个void类型指针)。
-
-图 1 无服务模式结构图
-
-
-## 开发步骤
-
-GPIO模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。GPIO控制器分组管理所有管脚,相关参数会在属性文件中有所体现;驱动入口和接口函数的实例化环节是厂商驱动接入HDF的核心环节。
-
-1. **实例化驱动入口:**
- - 实例化HdfDriverEntry结构体成员。
- - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
-
-2. **配置属性文件:**
-
- - 在device_info.hcs文件中添加deviceNode描述。
- - 【可选】添加gpio_config.hcs器件属性文件。
-
-3. **实例化GPIO控制器对象:**
-
- - 初始化GpioCntlr成员。
- - 实例化GpioCntlr成员GpioMethod,其定义和成员**说明**见下
-
-4. **驱动调试:**
- - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如GPIO控制状态,中断响应情况等。
-
->  **说明:**
->
-> GpioMethod定义
->
-> ```c
-> struct GpioMethod {
-> int32_t (*request)(struct GpioCntlr *cntlr, uint16_t local);// 【可选】
-> int32_t (*release)(struct GpioCntlr *cntlr, uint16_t local);// 【可选】
-> int32_t (*write)(struct GpioCntlr *cntlr, uint16_t local, uint16_t val);
-> int32_t (*read)(struct GpioCntlr *cntlr, uint16_t local, uint16_t *val);
-> int32_t (*setDir)(struct GpioCntlr *cntlr, uint16_t local, uint16_t dir);
-> int32_t (*getDir)(struct GpioCntlr *cntlr, uint16_t local, uint16_t *dir);
-> int32_t (*toIrq)(struct GpioCntlr *cntlr, uint16_t local, uint16_t *irq);// 【可选】
-> int32_t (*setIrq)(struct GpioCntlr *cntlr, uint16_t local, uint16_t mode, GpioIrqFunc func, void *arg);
-> int32_t (*unsetIrq)(struct GpioCntlr *cntlr, uint16_t local);
-> int32_t (*enableIrq)(struct GpioCntlr *cntlr, uint16_t local);
-> int32_t (*disableIrq)(struct GpioCntlr *cntlr, uint16_t local);
-> };
-> ```
->
-> 表1 GpioMethod结构体成员的回调函数功能说明
->
-> |函数成员|入参|出参|返回值|功能|
-> |-|-|-|-|-|
-> |write |**cntlr**:结构体指针,核心层GPIO控制器; **local**:uint16_t,GPIO端口标识号 ; **val**:uint16_t,电平传入值; |无| HDF_STATUS相关状态 | GPIO引脚写入电平值 |
-> |read |**cntlr**:结构体指针,核心层GPIO控制器; **local**:uint16_t,GPIO端口标识; |**val**:uint16_t 指针, 用于传出电平值 ;| HDF_STATUS相关状态 | GPIO引脚读取电平值 |
-> |setDir |**cntlr**:结构体指针,核心层GPIO控制器; **local**:uint16_t,GPIO端口标识号 ; **dir**:uint16_t,管脚方向传入值; |无| HDF_STATUS相关状态 | 设置GPIO引脚输入/输出方向 |
-> |getDir |**cntlr**:结构体指针,核心层GPIO控制器; **local**:uint16_t,GPIO端口标识号 ; |**dir**:uint16_t 指针, 用于传出管脚方向值 ;| HDF_STATUS相关状态 | 读GPIO引脚输入/输出方向 |
-> |setIrq |**cntlr**:结构体指针,核心层GPIO控制器; **local**:uint16_t,GPIO端口标识号; **mode**:uint16_t,表示触发模式(边沿或电平); **func**:函数指针,中断服务程序 ; **arg**:void指针,中断服务程序入参;|无| HDF_STATUS相关状态 |将GPIO引脚设置为中断模式 |
-> |unsetIrq |**cntlr**:结构体指针,核心层GPIO控制器; **local**:uint16_t,GPIO端口标识号 ; |无| HDF_STATUS相关状态 |取消GPIO中断设置 |
-> |enableIrq |**cntlr**:结构体指针,核心层GPIO控制器; **local**:uint16_t,GPIO端口标识号; |无| HDF_STATUS相关状态 |使能GPIO管脚中断 |
-> |disableIrq|**cntlr**:结构体指针,核心层GPIO控制器; **local**:uint16_t,GPIO端口标识号; |无| HDF_STATUS相关状态 |禁止GPIO管脚中断 |
-
-
-
-
-## 开发实例
-下方将以gpio_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
-
-1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
-
- 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
-
-- GPIO 驱动入口参考
-
- ```c
- struct HdfDriverEntry g_gpioDriverEntry = {
- .moduleVersion = 1,
- .Bind = Pl061GpioBind, //GPIO不需要实现Bind,本例是一个空实现,厂商可根据自身需要添加相关操作
- .Init = Pl061GpioInit, //见Init参考
- .Release = Pl061GpioRelease, //见Release参考
- .moduleName = "hisi_pl061_driver",//【必要且需要与HCS文件中里面的moduleName匹配】
- };
- //调用HDF_INIT将驱动入口注册到HDF框架中
- HDF_INIT(g_gpioDriverEntry);
- ```
-
-2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 gpio_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层GpioCntlr 成员的默认值或限制范围有密切关系。
-
- **本例只有一个GPIO控制器,如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在gpio_config文件中增加对应的器件属性**。
-
-- device_info.hcs 配置参考
-
- ```c
- root {
- device_info {
- platform :: host {
- hostName = "platform_host";
- priority = 50;
- device_gpio :: device {
- device0 :: deviceNode {
- policy = 0; // 等于0,不需要发布服务
- priority = 10; // 驱动启动优先级
- permission = 0644; // 驱动创建设备节点权限
- moduleName = "hisi_pl061_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致;
- deviceMatchAttr = "hisilicon_hi35xx_pl061";//【必要】用于配置控制器私有数据,要与 gpio_config.hcs 中
- //对应控制器保持一致,其他控制器信息也在文件中
- }
- }
- }
- }
- }
- ```
-
-- gpio_config.hcs 配置参考
-
- ```c
- root {
- platform {
- gpio_config {
- controller_0x120d0000 {
- match_attr = "hisilicon_hi35xx_pl061"; //【必要】必须和device_info.hcs中的deviceMatchAttr值一致
- groupNum = 12; //【必要】GPIO组索引 需要根据设备情况填写
- bitNum = 8; //【必要】每组GPIO管脚数
- regBase = 0x120d0000;//【必要】物理基地址
- regStep = 0x1000; //【必要】寄存器偏移步进
- irqStart = 48; //【必要】开启中断
- irqShare = 0; //【必要】共享中断
- }
- }
- }
- }
- ```
-
-3. 完成驱动入口注册之后,最后一步就是以核心层GpioCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化GpioCntlr成员GpioMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)
-
-
-- 自定义结构体参考
-
- > 从驱动的角度看,自定义结构体是参数和数据的载体,而且gpio_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层GpioCntlr对象,例如索引、管脚数等。
-
- ```c
- struct Pl061GpioCntlr {
- struct GpioCntlr cntlr;//【必要】 是核心层控制对象,其成员定义见下面
- volatile unsigned char *regBase; //【必要】寄存器基地址
- uint32_t phyBase; //【必要】 物理基址
- uint32_t regStep; //【必要】 寄存器偏移步进
- uint32_t irqStart; //【必要】 中断开启
- uint16_t groupNum; //【必要】 用于描述厂商的GPIO端口号的参数
- uint16_t bitNum; //【必要】 用于描述厂商的GPIO端口号的参数
- uint8_t irqShare; //【必要】 共享中断
- struct Pl061GpioGroup *groups; //【可选】 根据厂商需要设置
- };
- struct Pl061GpioGroup { //包括寄存器地址,中断号,中断函数和和锁
- volatile unsigned char *regBase;
- unsigned int index;
- unsigned int irq;
- OsalIRQHandle irqFunc;
- OsalSpinlock lock;
- };
-
- // GpioCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值
- struct GpioCntlr {
- struct IDeviceIoService service;
- struct HdfDeviceObject *device;
- struct GpioMethod *ops;
- struct DListHead list;
- OsalSpinlock spin;
- uint16_t start;
- uint16_t count;
- struct GpioInfo *ginfos;
- void *priv;
- };
- ```
-
-- **【重要】** GpioCntlr成员回调函数结构体GpioMethod的实例化,其他成员在Init函数中初始化
-
- ```c
- //GpioMethod结构体成员都是回调函数,厂商需要根据表1完成相应的函数功能。
- static struct GpioMethod g_method = {
- .request = NULL,
- .release = NULL,
- .write = Pl061GpioWrite, //写管脚
- .read = Pl061GpioRead, //读管脚
- .setDir = Pl061GpioSetDir, //设置管脚方向
- .getDir = Pl061GpioGetDir, //获取管脚方向
- .toIrq = NULL,
- .setIrq = Pl061GpioSetIrq, //设置管脚中断,如不具备此能力可忽略
- .unsetIrq = Pl061GpioUnsetIrq, //取消管脚中断设置,如不具备此能力可忽略
- .enableIrq = Pl061GpioEnableIrq, //使能管脚中断,如不具备此能力可忽略
- .disableIrq = Pl061GpioDisableIrq,//禁止管脚中断,如不具备此能力可忽略
- };
- ```
-
-
-- **Init函数参考**
-
- > **入参:**
- > HdfDeviceObject这个是整个驱动对外暴露的接口参数,具备HCS配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态(下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)
- >
- > |状态(值)|问题描述|
- > |:-|:-:|
- > |HDF_ERR_INVALID_OBJECT|控制器对象非法|
- > |HDF_ERR_MALLOC_FAIL |内存分配失败|
- > |HDF_ERR_INVALID_PARAM |参数非法|
- > |HDF_ERR_IO |I/O 错误|
- > |HDF_SUCCESS |初始化成功|
- > |HDF_FAILURE |初始化失败|
- >
- > **函数说明:**
- > 初始化自定义结构体对象,初始化GpioCntlr成员,调用核心层GpioCntlrAdd函数,【可选】接入VFS
-
- ```c
- static int32_t Pl061GpioInit(struct HdfDeviceObject *device)
- {
- ...
- struct Pl061GpioCntlr *pl061 = &g_pl061;//利用静态全局变量完成初始化
- //static struct Pl061GpioCntlr g_pl061 = {
- // .groups = NULL,
- // .groupNum = PL061_GROUP_MAX,
- // .bitNum = PL061_BIT_MAX,
- //};
- ret = Pl061GpioReadDrs(pl061, device->property);//利用从gpio_config.HCS文件读取的属性值来初始化自定义结构体对象成员
- ...
- pl061->regBase = OsalIoRemap(pl061->phyBase, pl061->groupNum * pl061->regStep);//地址映射
- ...
- ret = Pl061GpioInitCntlrMem(pl061); // 内存分配
- ...
- pl061->cntlr.count = pl061->groupNum * pl061->bitNum;//【必要】管脚数量计算
- pl061->cntlr.priv = (void *)device->property; //【必要】存储设备属性
- pl061->cntlr.ops = &g_method; // 【必要】GpioMethod的实例化对象的挂载
- pl061->cntlr.device = device; // 【必要】使HdfDeviceObject与GpioCntlr可以相互转化的前提
- ret = GpioCntlrAdd(&pl061->cntlr); // 【必要】调用此函数填充核心层结构体,返回成功信号后驱动才完全接入平台核心层
- ...
- Pl061GpioDebugCntlr(pl061);
- #ifdef PL061_GPIO_USER_SUPPORT //【可选】若支持用户级的虚拟文件系统,则接入
- if (GpioAddVfs(pl061->bitNum) != HDF_SUCCESS) {
- HDF_LOGE("%s: add vfs fail!", __func__);
- }
- #endif
- ...
- }
- ```
-
-- **Release 函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > 无
- >
- > **函数说明:**
- > 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
-
- ```c
- static void Pl061GpioRelease(struct HdfDeviceObject *device)
- {
- struct GpioCntlr *cntlr = NULL;
- struct Pl061GpioCntlr *pl061 = NULL;
- ...
- cntlr = GpioCntlrFromDevice(device);//【必要】通过强制转换获取核心层控制对象
- //return (device == NULL) ? NULL : (struct GpioCntlr *)device->service;
- ...
- #ifdef PL061_GPIO_USER_SUPPORT
- GpioRemoveVfs();//与Init中GpioAddVfs相反
- #endif
- GpioCntlrRemove(cntlr); //【必要】取消设备信息、服务等内容在核心层上的挂载
- pl061 = ToPl061GpioCntlr(cntlr); //return (struct Pl061GpioCntlr *)cntlr;
- Pl061GpioRleaseCntlrMem(pl061); //【必要】锁和内存的释放
- OsalIoUnmap((void *)pl061->regBase);//【必要】解除地址映射
- pl061->regBase = NULL;
- }
- ```
-
-
-
+# GPIO
+
+- [概述](#section1826197354103451)
+- [接口说明](#section752964871810)
+- [开发步骤](#section731175315103451)
+- [开发实例](#section800425816103451)
+
+## 概述
+
+GPIO(General-purpose input/output)即通用型输入输出,在HDF框架中,
+
+GPIO的接口适配模式采用无服务模式,用于不需要在用户态提供API的设备类型,或者没有用户态和内核区分的OS系统,其关联方式是DevHandle直接指向设备对象内核态地址(DevHandle是一个void类型指针)。
+
+**图 1** GPIO无服务模式结构图
+
+
+## 接口说明
+
+GpioMethod定义:
+
+```
+struct GpioMethod {
+ int32_t (*request)(struct GpioCntlr *cntlr, uint16_t local);// 【可选】
+ int32_t (*release)(struct GpioCntlr *cntlr, uint16_t local);// 【可选】
+ int32_t (*write)(struct GpioCntlr *cntlr, uint16_t local, uint16_t val);
+ int32_t (*read)(struct GpioCntlr *cntlr, uint16_t local, uint16_t *val);
+ int32_t (*setDir)(struct GpioCntlr *cntlr, uint16_t local, uint16_t dir);
+ int32_t (*getDir)(struct GpioCntlr *cntlr, uint16_t local, uint16_t *dir);
+ int32_t (*toIrq)(struct GpioCntlr *cntlr, uint16_t local, uint16_t *irq);// 【可选】
+ int32_t (*setIrq)(struct GpioCntlr *cntlr, uint16_t local, uint16_t mode, GpioIrqFunc func, void *arg);
+ int32_t (*unsetIrq)(struct GpioCntlr *cntlr, uint16_t local);
+ int32_t (*enableIrq)(struct GpioCntlr *cntlr, uint16_t local);
+ int32_t (*disableIrq)(struct GpioCntlr *cntlr, uint16_t local);
+}
+```
+
+**表 1** GpioMethod结构体成员的回调函数功能说明
+
+
+函数成员
+ |
+入参
+ |
+出参
+ |
+返回值
+ |
+功能
+ |
+
+
+write
+ |
+cntlr:结构体指针,核心层GPIO控制器;local:uint16_t,GPIO端口标识号 ;val:uint16_t,电平传入值;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+GPIO引脚写入电平值
+ |
+
+read
+ |
+cntlr:结构体指针,核心层GPIO控制器;local:uint16_t,GPIO端口标识;
+ |
+val:uint16_t 指针,用于传出电平值 ;
+ |
+HDF_STATUS相关状态
+ |
+GPIO引脚读取电平值
+ |
+
+setDir
+ |
+cntlr:结构体指针,核心层GPIO控制器;local:uint16_t,GPIO端口标识号 ;dir:uint16_t,管脚方向传入值;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+设置GPIO引脚输入/输出方向
+ |
+
+getDir
+ |
+cntlr:结构体指针,核心层GPIO控制器;local:uint16_t,GPIO端口标识号 ;
+ |
+dir:uint16_t 指针,用于传出管脚方向值 ;
+ |
+HDF_STATUS相关状态
+ |
+读GPIO引脚输入/输出方向
+ |
+
+setIrq
+ |
+cntlr:结构体指针,核心层GPIO控制器;local:uint16_t,GPIO端口标识号;mode:uint16_t,表示触发模式(边沿或电平);func:函数指针,中断服务程序 ;arg:void指针,中断服务程序入参;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+将GPIO引脚设置为中断模式
+ |
+
+unsetIrq
+ |
+cntlr:结构体指针,核心层GPIO控制器;local:uint16_t,GPIO端口标识号 ;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+取消GPIO中断设置
+ |
+
+enableIrq
+ |
+cntlr:结构体指针,核心层GPIO控制器;local:uint16_t,GPIO端口标识号;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+使能GPIO管脚中断
+ |
+
+disableIrq
+ |
+cntlr:结构体指针,核心层GPIO控制器;local:uint16_t,GPIO端口标识号;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+禁止GPIO管脚中断
+ |
+
+
+
+
+## 开发步骤
+
+GPIO模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。GPIO控制器分组管理所有管脚,相关参数会在属性文件中有所体现;驱动入口和接口函数的实例化环节是厂商驱动接入HDF的核心环节。
+
+1. **实例化驱动入口:**
+ - 实例化HdfDriverEntry结构体成员。
+ - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
+
+2. **配置属性文件:**
+ - 在device\_info.hcs文件中添加deviceNode描述。
+ - 【可选】添加gpio\_config.hcs器件属性文件。
+
+3. **实例化GPIO控制器对象:**
+ - 初始化GpioCntlr成员。
+ - 实例化GpioCntlr成员GpioMethod。
+
+ > **说明:**
+ >实例化GpioCntlr成员GpioMethod,详见[接口说明](#section752964871810)。
+
+
+4. **驱动调试:**
+
+ 【可选】针对新增驱动程序,建议验证驱动基本功能,例如GPIO控制状态,中断响应情况等。
+
+
+## 开发实例
+
+下方将以gpio\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
+
+1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
+
+ 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
+
+ GPIO 驱动入口参考:
+
+ ```
+ struct HdfDriverEntry g_gpioDriverEntry = {
+ .moduleVersion = 1,
+ .Bind = Pl061GpioBind, //GPIO不需要实现Bind,本例是一个空实现,厂商可根据自身需要添加相关操作
+ .Init = Pl061GpioInit, //见Init参考
+ .Release = Pl061GpioRelease, //见Release参考
+ .moduleName = "hisi_pl061_driver",//【必要且需要与HCS文件中里面的moduleName匹配】
+ };
+ //调用HDF_INIT将驱动入口注册到HDF框架中
+ HDF_INIT(g_gpioDriverEntry);
+ ```
+
+2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 gpio\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层GpioCntlr 成员的默认值或限制范围有密切关系。
+
+ 本例只有一个GPIO控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在gpio\_config文件中增加对应的器件属性。
+
+ - device\_info.hcs 配置参考。
+
+ ```
+ root {
+ device_info {
+ platform :: host {
+ hostName = "platform_host";
+ priority = 50;
+ device_gpio :: device {
+ device0 :: deviceNode {
+ policy = 0; // 等于0,不需要发布服务
+ priority = 10; // 驱动启动优先级
+ permission = 0644; // 驱动创建设备节点权限
+ moduleName = "hisi_pl061_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致;
+ deviceMatchAttr = "hisilicon_hi35xx_pl061";//【必要】用于配置控制器私有数据,要与 gpio_config.hcs 中
+ //对应控制器保持一致,其他控制器信息也在文件中
+ }
+ }
+ }
+ }
+ }
+ ```
+
+ - gpio\_config.hcs 配置参考。
+
+ ```
+ root {
+ platform {
+ gpio_config {
+ controller_0x120d0000 {
+ match_attr = "hisilicon_hi35xx_pl061"; //【必要】必须和device_info.hcs中的deviceMatchAttr值一致
+ groupNum = 12; //【必要】GPIO组索引 需要根据设备情况填写
+ bitNum = 8; //【必要】每组GPIO管脚数
+ regBase = 0x120d0000;//【必要】物理基地址
+ regStep = 0x1000; //【必要】寄存器偏移步进
+ irqStart = 48; //【必要】开启中断
+ irqShare = 0; //【必要】共享中断
+ }
+ }
+ }
+ }
+ ```
+
+3. 完成驱动入口注册之后,最后一步就是以核心层GpioCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化GpioCntlr成员GpioMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
+ - 自定义结构体参考。
+
+ 从驱动的角度看,自定义结构体是参数和数据的载体,而且gpio\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层GpioCntlr对象,例如索引、管脚数等。
+
+ ```
+ struct Pl061GpioCntlr {
+ struct GpioCntlr cntlr;//【必要】 是核心层控制对象,其成员定义见下面
+ volatile unsigned char *regBase; //【必要】寄存器基地址
+ uint32_t phyBase; //【必要】 物理基址
+ uint32_t regStep; //【必要】 寄存器偏移步进
+ uint32_t irqStart; //【必要】 中断开启
+ uint16_t groupNum; //【必要】 用于描述厂商的GPIO端口号的参数
+ uint16_t bitNum; //【必要】 用于描述厂商的GPIO端口号的参数
+ uint8_t irqShare; //【必要】 共享中断
+ struct Pl061GpioGroup *groups; //【可选】 根据厂商需要设置
+ };
+ struct Pl061GpioGroup { //包括寄存器地址,中断号,中断函数和和锁
+ volatile unsigned char *regBase;
+ unsigned int index;
+ unsigned int irq;
+ OsalIRQHandle irqFunc;
+ OsalSpinlock lock;
+ };
+
+ // GpioCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值
+ struct GpioCntlr {
+ struct IDeviceIoService service;
+ struct HdfDeviceObject *device;
+ struct GpioMethod *ops;
+ struct DListHead list;
+ OsalSpinlock spin;
+ uint16_t start;
+ uint16_t count;
+ struct GpioInfo *ginfos;
+ void *priv;
+ };
+ ```
+
+ - GpioCntlr成员回调函数结构体GpioMethod的实例化,其他成员在Init函数中初始化。
+
+ ```
+ //GpioMethod结构体成员都是回调函数,厂商需要根据表1完成相应的函数功能。
+ static struct GpioMethod g_method = {
+ .request = NULL,
+ .release = NULL,
+ .write = Pl061GpioWrite, //写管脚
+ .read = Pl061GpioRead, //读管脚
+ .setDir = Pl061GpioSetDir, //设置管脚方向
+ .getDir = Pl061GpioGetDir, //获取管脚方向
+ .toIrq = NULL,
+ .setIrq = Pl061GpioSetIrq, //设置管脚中断,如不具备此能力可忽略
+ .unsetIrq = Pl061GpioUnsetIrq, //取消管脚中断设置,如不具备此能力可忽略
+ .enableIrq = Pl061GpioEnableIrq, //使能管脚中断,如不具备此能力可忽略
+ .disableIrq = Pl061GpioDisableIrq,//禁止管脚中断,如不具备此能力可忽略
+ };
+ ```
+
+ - Init函数参考
+
+ 入参:
+
+ HdfDeviceObject这个是整个驱动对外暴露的接口参数,具备HCS配置文件的信息。
+
+ 返回值:
+
+ HDF\_STATUS相关状态(下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。
+
+ **表 2** Init函数说明
+
+
+ 状态(值)
+ |
+ 问题描述
+ |
+
+
+ HDF_ERR_INVALID_OBJECT
+ |
+ 控制器对象非法
+ |
+
+ HDF_ERR_MALLOC_FAIL
+ |
+ 内存分配失败
+ |
+
+ HDF_ERR_INVALID_PARAM
+ |
+ 参数非法
+ |
+
+ HDF_ERR_IO
+ |
+ I/O 错误
+ |
+
+ HDF_SUCCESS
+ |
+ 初始化成功
+ |
+
+ HDF_FAILURE
+ |
+ 初始化失败
+ |
+
+
+
+
+ 函数说明:
+
+ 初始化自定义结构体对象,初始化GpioCntlr成员,调用核心层GpioCntlrAdd函数,【可选】接入VFS。
+
+ ```
+ static int32_t Pl061GpioInit(struct HdfDeviceObject *device)
+ {
+ ...
+ struct Pl061GpioCntlr *pl061 = &g_pl061;//利用静态全局变量完成初始化
+ //static struct Pl061GpioCntlr g_pl061 = {
+ // .groups = NULL,
+ // .groupNum = PL061_GROUP_MAX,
+ // .bitNum = PL061_BIT_MAX,
+ //};
+ ret = Pl061GpioReadDrs(pl061, device->property);//利用从gpio_config.HCS文件读取的属性值来初始化自定义结构体对象成员
+ ...
+ pl061->regBase = OsalIoRemap(pl061->phyBase, pl061->groupNum * pl061->regStep);//地址映射
+ ...
+ ret = Pl061GpioInitCntlrMem(pl061); // 内存分配
+ ...
+ pl061->cntlr.count = pl061->groupNum * pl061->bitNum;//【必要】管脚数量计算
+ pl061->cntlr.priv = (void *)device->property; //【必要】存储设备属性
+ pl061->cntlr.ops = &g_method; // 【必要】GpioMethod的实例化对象的挂载
+ pl061->cntlr.device = device; // 【必要】使HdfDeviceObject与GpioCntlr可以相互转化的前提
+ ret = GpioCntlrAdd(&pl061->cntlr); // 【必要】调用此函数填充核心层结构体,返回成功信号后驱动才完全接入平台核心层
+ ...
+ Pl061GpioDebugCntlr(pl061);
+ #ifdef PL061_GPIO_USER_SUPPORT //【可选】若支持用户级的虚拟文件系统,则接入
+ if (GpioAddVfs(pl061->bitNum) != HDF_SUCCESS) {
+ HDF_LOGE("%s: add vfs fail!", __func__);
+ }
+ #endif
+ ...
+ }
+ ```
+
+ - Release 函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ 无。
+
+ 函数说明:
+
+ 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
+
+ ```
+ static void Pl061GpioRelease(struct HdfDeviceObject *device)
+ {
+ struct GpioCntlr *cntlr = NULL;
+ struct Pl061GpioCntlr *pl061 = NULL;
+ ...
+ cntlr = GpioCntlrFromDevice(device);//【必要】通过强制转换获取核心层控制对象
+ //return (device == NULL) ? NULL : (struct GpioCntlr *)device->service;
+ ...
+ #ifdef PL061_GPIO_USER_SUPPORT
+ GpioRemoveVfs();//与Init中GpioAddVfs相反
+ #endif
+ GpioCntlrRemove(cntlr); //【必要】取消设备信息、服务等内容在核心层上的挂载
+ pl061 = ToPl061GpioCntlr(cntlr); //return (struct Pl061GpioCntlr *)cntlr;
+ Pl061GpioRleaseCntlrMem(pl061); //【必要】锁和内存的释放
+ OsalIoUnmap((void *)pl061->regBase);//【必要】解除地址映射
+ pl061->regBase = NULL;
+ }
+ ```
+
+
+
diff --git a/zh-cn/device-dev/driver/driver-platform-i2c-des.md b/zh-cn/device-dev/driver/driver-platform-i2c-des.md
index ec00c3728c1015b057c0424337e80e1fa350ffe2..535b49a332609ead27020ebe764726d1b8551095 100644
--- a/zh-cn/device-dev/driver/driver-platform-i2c-des.md
+++ b/zh-cn/device-dev/driver/driver-platform-i2c-des.md
@@ -1,8 +1,7 @@
-# I2C
+# I2C
- [概述](#section5361140416)
- - [接口说明](#section459052019177)
-
+- [接口说明](#section545869122317)
- [使用指导](#section1695201514281)
- [使用流程](#section1338373417288)
- [打开I2C控制器](#section13751110132914)
@@ -25,10 +24,10 @@
- I2C消息传输:通过消息传输结构体数组进行自定义传输
**图 1** I2C物理连线示意图
- 
+ 
-### 接口说明
+## 接口说明
**表 1** I2C驱动API接口功能介绍
@@ -70,12 +69,10 @@
### 使用流程
-使用I2C设备的一般流程如[图2](#fig166181128151112)所示。
-
-**图 2** I2C设备使用流程图
-
+使用I2C设备的一般流程如[图2](#fig183017194234)所示。
-
+**图 2** I2C设备使用流程图
+
### 打开I2C控制器
diff --git a/zh-cn/device-dev/driver/driver-platform-i2c-develop.md b/zh-cn/device-dev/driver/driver-platform-i2c-develop.md
index b62b1a3d3708b749888a146a38d2d70f2ee914cd..a056cf3e1b7dd380288879309cf7ac5621676a3c 100755
--- a/zh-cn/device-dev/driver/driver-platform-i2c-develop.md
+++ b/zh-cn/device-dev/driver/driver-platform-i2c-develop.md
@@ -1,309 +1,401 @@
-# I2C
-
-- [概述](#1)
-- [开发步骤](#2)
-- [开发实例](#3)
-
-
-## 概述
-
-I2C(Inter Integrated Circuit)总线是由Philips公司开发的一种简单、双向二线制同步串行总线,在HDF框架中,I2C模块接口适配模式采用统一服务模式,这需要一个设备服务来作为I2C模块的管理器,统一处理外部访问,这会在配置文件中有所体现。统一服务模式适合于同类型设备对象较多的情况,如I2C可能同时具备十几个控制器,采用独立服务模式需要配置更多的设备节点,且服务会占据内存资源。
-
-图 1 统一服务模式结构图
-
-
-## 开发步骤
-
-I2C模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
-
-1. **实例化驱动入口:**
-
- - 实例化HdfDriverEntry结构体成员。
- - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
-
-2. **配置属性文件:**
-
- - 在device_info.hcs文件中添加deviceNode描述。
- - 【可选】添加i2c_config.hcs器件属性文件。
-
-3. **实例化I2C控制器对象:**
-
- - 初始化I2cCntlr成员。
- - 实例化I2cCntlr成员I2cMethod和I2cLockMethod,其定义和成员说明见下
-
-4. **驱动调试:**
- - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,消息传输的成功与否等。
-
->  **说明:**
-> I2cMethod和I2cLockMethod定义
->
-> ```c
-> struct I2cMethod {
-> int32_t (*transfer)(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count);
-> };
-> struct I2cLockMethod {//锁机制操作结构体
-> int32_t (*lock)(struct I2cCntlr *cntlr);//加锁
-> void (*unlock)(struct I2cCntlr *cntlr); //解锁
-> };
-> ```
-> 表1 I2cMethod结构体成员的回调函数功能说明
-> |函数成员|入参|出参|返回值|功能|
-> |-|-|-|-|-|
-> |transfer |**cntlr**:结构体指针,核心层I2C控制器; **msgs**:结构体指针,用户消息 ; **count**:uint16_t,消息数量 |无|HDF_STATUS相关状态| 传递用户消息|
-
-## 开发实例
-
-下方将以i2c_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
-
-1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
-
- 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
-
-- I2C驱动入口参考
-
- > I2C模块这种类型的控制器会出现很多个设备挂接的情况,因而在HDF框架中首先会为这类型的设备创建一个管理器对象,并同时对外发布一个管理器服务来统一处理外部访问。这样,用户需要打开某个设备时,会先获取到管理器服务,然后管理器服务根据用户指定参数查找到指定设备。
- >
- > I2C管理器服务的驱动由核心层实现,**厂商不需要关注这部分内容的实现,这个但在实现Init函数的时候需要调用核心层的I2cCntlrAdd函数,它会实现相应功能。**
-
-
- ```c
- struct HdfDriverEntry g_i2cDriverEntry = {
- .moduleVersion = 1,
- .Init = Hi35xxI2cInit,
- .Release = Hi35xxI2cRelease,
- .moduleName = "hi35xx_i2c_driver",//【必要且与config.hcs文件里面匹配】
- };
- HDF_INIT(g_i2cDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中
-
- //核心层i2c_core.c 管理器服务的驱动入口
- struct HdfDriverEntry g_i2cManagerEntry = {
- .moduleVersion = 1,
- .Bind = I2cManagerBind,
- .Init = I2cManagerInit,
- .Release = I2cManagerRelease,
- .moduleName = "HDF_PLATFORM_I2C_MANAGER",//这与device_info文件中device0对应
- };
- HDF_INIT(g_i2cManagerEntry);
- ```
-
-2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在i2c_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值对于厂商驱动的实现以及核心层I2cCntlr相关成员的默认值或限制范围有密切关系。
-
- **统一服务模式**的特点是device_info文件中第一个设备节点必须为I2C管理器,其各项参数必须如下设置:
-
- |成员名|值|
- |-|-|
- |moduleName | 固定为 HDF_PLATFORM_I2C_MANAGER|
- |serviceName| 固定为 HDF_PLATFORM_I2C_MANAGER|
- |policy| 具体配置为1或2取决于是否对用户态可见|
- |deviceMatchAttr| 没有使用,可忽略|
-
- **从第二个节点开始配置具体I2C控制器信息**,此节点并不表示某一路I2C控制器,而是代表一个资源性质设备,用于描述一类I2C控制器的信息。多个控制器之间相互区分的参数是busID和reg_pbase,这在i2c_config文件中有所体现。
-
-- device_info.hcs 配置参考
-
- ```c
- root {
- device_info {
- match_attr = "hdf_manager";
- device_i2c :: device {
- device0 :: deviceNode {
- policy = 2;
- priority = 50;
- permission = 0644;
- moduleName = "HDF_PLATFORM_I2C_MANAGER";
- serviceName = "HDF_PLATFORM_I2C_MANAGER";
- deviceMatchAttr = "hdf_platform_i2c_manager";
- }
- device1 :: deviceNode {
- policy = 0; // 等于0,不需要发布服务
- priority = 55; // 驱动启动优先级
- permission = 0644; // 驱动创建设备节点权限
- moduleName = "hi35xx_i2c_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致;
- serviceName = "HI35XX_I2C_DRIVER"; //【必要】驱动对外发布服务的名称,必须唯一
- deviceMatchAttr = "hisilicon_hi35xx_i2c";//【必要】用于配置控制器私有数据,要与i2c_config.hcs中对应控制器保持一致
- // 具体的控制器信息在 i2c_config.hcs 中
- }
- }
- }
- }
- ```
-
-- i2c_config.hcs 配置参考
-
- ```c
- root {
- platform {
- i2c_config {
- match_attr = "hisilicon_hi35xx_i2c";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致
- template i2c_controller { //模板公共参数,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省
- bus = 0; //【必要】i2c 识别号
- reg_pbase = 0x120b0000; //【必要】物理基地址
- reg_size = 0xd1; //【必要】寄存器位宽
- irq = 0; //【可选】根据厂商需要来使用
- freq = 400000; //【可选】根据厂商需要来使用
- clk = 50000000; //【可选】根据厂商需要来使用
- }
- controller_0x120b0000 :: i2c_controller {
- bus = 0;
- }
- controller_0x120b1000 :: i2c_controller {
- bus = 1;
- reg_pbase = 0x120b1000;
- }
- ...
- }
- }
- }
- ```
-
-3. 完成驱动入口注册之后,最后一步就是以核心层I2cCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化I2cCntlr成员I2cMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)
-
-
-- 自定义结构体参考
-
- > 从驱动的角度看,自定义结构体是参数和数据的载体,而且i2c_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层I2cCntlr对象,例如设备号、总线号等。
-
- ```c
- // 厂商自定义功能结构体
- struct Hi35xxI2cCntlr {
- struct I2cCntlr cntlr; //【必要】是核心层控制对象,具体描述见下面
- OsalSpinlock spin; //【必要】厂商需要基于此锁变量对各个 i2c 操作函数实现对应的加锁解锁
- volatile unsigned char *regBase; //【必要】寄存器基地址
- uint16_t regSize; //【必要】寄存器位宽
- int16_t bus; //【必要】i2c_config.hcs 文件中可读取具体值
- uint32_t clk; //【可选】厂商自定义
- uint32_t freq; //【可选】厂商自定义
- uint32_t irq; //【可选】厂商自定义
- uint32_t regBasePhy; //【必要】寄存器物理基地址
- };
-
- // I2cCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值
- struct I2cCntlr {
- struct OsalMutex lock;
- void *owner;
- int16_t busId;
- void *priv;
- const struct I2cMethod *ops;
- const struct I2cLockMethod *lockOps;
- };
- ```
-
-- **【重要】** I2cCntlr成员回调函数结构体I2cMethod的实例化,和锁机制回调函数结构体I2cLockMethod实例化,其他成员在Init函数中初始化
-
- ```c
- // i2c_hi35xx.c 中的示例
- static const struct I2cMethod g_method = {
- .transfer = Hi35xxI2cTransfer,
- };
-
- static const struct I2cLockMethod g_lockOps = {
- .lock = Hi35xxI2cLock, //加锁函数
- .unlock = Hi35xxI2cUnlock,//解锁函数
- };
- ```
-
-- **init函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)
- >
- > |状态(值)|问题描述|
- > |:-|:-:|
- > |HDF_ERR_INVALID_OBJECT|控制器对象非法|
- > |HDF_ERR_INVALID_PARAM |参数非法|
- > |HDF_ERR_MALLOC_FAIL |内存分配失败|
- > |HDF_ERR_IO |I/O 错误|
- > |HDF_SUCCESS |传输成功|
- > |HDF_FAILURE |传输失败|
- >
- > **函数说明:**
- > 初始化自定义结构体对象,初始化I2cCntlr成员,调用核心层I2cCntlrAdd函数,【可选】接入VFS
-
- ```c
- static int32_t Hi35xxI2cInit(struct HdfDeviceObject *device)
- {
- ...
- //遍历、解析 i2c_config.hcs 中的所有配置节点,并分别进行初始化,需要调用Hi35xxI2cParseAndInit函数
- DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
- ret = Hi35xxI2cParseAndInit(device, childNode);//函数定义见下
- ...
- }
- ...
- }
-
- static int32_t Hi35xxI2cParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
- {
- struct Hi35xxI2cCntlr *hi35xx = NULL;
- ...
- hi35xx = (struct Hi35xxI2cCntlr *)OsalMemCalloc(sizeof(*hi35xx)); // 内存分配
- ...
- hi35xx->regBase = OsalIoRemap(hi35xx->regBasePhy, hi35xx->regSize); // 地址映射
- ...
- Hi35xxI2cCntlrInit(hi35xx); // 【必要】i2c设备的初始化
-
- hi35xx->cntlr.priv = (void *)node; //【必要】存储设备属性
- hi35xx->cntlr.busId = hi35xx->bus; //【必要】初始化I2cCntlr成员busId
- hi35xx->cntlr.ops = &g_method; //【必要】I2cMethod的实例化对象的挂载
- hi35xx->cntlr.lockOps = &g_lockOps; //【必要】I2cLockMethod的实例化对象的挂载
- (void)OsalSpinInit(&hi35xx->spin); //【必要】锁的初始化
- ret = I2cCntlrAdd(&hi35xx->cntlr); //【必要】调用此函数填充核心层结构体,返回成功信号后驱动才完全接入平台核心层
- ...
- #ifdef USER_VFS_SUPPORT
- (void)I2cAddVfsById(hi35xx->cntlr.busId);//【可选】若支持用户级的虚拟文件系统,则接入
- #endif
- return HDF_SUCCESS;
- __ERR__: //不成功的话,需要反向执行初始化相关函数
- if (hi35xx != NULL) {
- if (hi35xx->regBase != NULL) {
- OsalIoUnmap((void *)hi35xx->regBase);
- hi35xx->regBase = NULL;
- }
- OsalMemFree(hi35xx);
- hi35xx = NULL;
- }
- return ret;
- }
- ```
-
-- **Release 函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > 无
- >
- > **函数说明:**
- > 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。
-
- ```c
- static void Hi35xxI2cRelease(struct HdfDeviceObject *device)
- {
- ...
- //与Hi35xxI2cInit一样,需要将对每个节点分别进行释放
- DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
- Hi35xxI2cRemoveByNode(childNode);//函数定义见下
- }
- }
-
- static void Hi35xxI2cRemoveByNode(const struct DeviceResourceNode *node)
- {
- ...
- //【必要】可以调用 I2cCntlrGet 函数通过设备的 busid 获取 I2cCntlr 对象, 以及调用 I2cCntlrRemove 函数来释放 I2cCntlr 对象的内容
- cntlr = I2cCntlrGet(bus);
- if (cntlr != NULL && cntlr->priv == node) {
- ...
- I2cCntlrRemove(cntlr);
- //【必要】解除地址映射,锁和内存的释放
- hi35xx = (struct Hi35xxI2cCntlr *)cntlr;
- OsalIoUnmap((void *)hi35xx->regBase);
- (void)OsalSpinDestroy(&hi35xx->spin);
- OsalMemFree(hi35xx);
- }
- return;
- }
- ```
-
+# I2C
+
+- [概述](#section2040078630114257)
+- [接口说明](#section752964871810)
+- [开发步骤](#section1085786591114257)
+- [开发实例](#section1773332551114257)
+
+## 概述
+
+I2C\(Inter Integrated Circuit\)总线是由Philips公司开发的一种简单、双向二线制同步串行总线,在HDF框架中,I2C模块接口适配模式采用统一服务模式,这需要一个设备服务来作为I2C模块的管理器,统一处理外部访问,这会在配置文件中有所体现。统一服务模式适合于同类型设备对象较多的情况,如I2C可能同时具备十几个控制器,采用独立服务模式需要配置更多的设备节点,且服务会占据内存资源。
+
+**图 1** I2C统一服务模式结构图
+
+
+## 接口说明
+
+I2cMethod和I2cLockMethod定义:
+
+```
+struct I2cMethod {
+int32_t (*transfer)(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count);
+};
+struct I2cLockMethod {//锁机制操作结构体
+ int32_t (*lock)(struct I2cCntlr *cntlr);//加锁
+ void (*unlock)(struct I2cCntlr *cntlr); //解锁
+};
+```
+
+**表 1** I2cMethod结构体成员的回调函数功能说明
+
+
+函数成员
+ |
+入参
+ |
+出参
+ |
+返回值
+ |
+功能
+ |
+
+
+transfer
+ |
+cntlr:结构体指针,核心层I2C控制器;msgs:结构体指针,用户消息 ;count:uint16_t,消息数量
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+传递用户消息
+ |
+
+
+
+
+## 开发步骤
+
+I2C模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
+
+1. **实例化驱动入口:**
+ - 实例化HdfDriverEntry结构体成员。
+ - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
+
+2. **配置属性文件:**
+ - 在device\_info.hcs文件中添加deviceNode描述。
+ - 【可选】添加i2c\_config.hcs器件属性文件。
+
+3. **实例化I2C控制器对象:**
+ - 初始化I2cCntlr成员。
+ - 实例化I2cCntlr成员I2cMethod和I2cLockMethod。
+
+ > **说明:**
+ >实例化I2cCntlr成员I2cMethod和I2cLockMethod,详见[接口说明](#section752964871810)。
+
+
+4. **驱动调试:**
+
+ 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,消息传输的成功与否等。
+
+
+## 开发实例
+
+下方将以i2c\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
+
+1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
+
+ 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
+
+ I2C驱动入口参考:
+
+ I2C模块这种类型的控制器会出现很多个设备挂接的情况,因而在HDF框架中首先会为这类型的设备创建一个管理器对象,并同时对外发布一个管理器服务来统一处理外部访问。这样,用户需要打开某个设备时,会先获取到管理器服务,然后管理器服务根据用户指定参数查找到指定设备。
+
+ I2C管理器服务的驱动由核心层实现,厂商不需要关注这部分内容的实现,这个但在实现Init函数的时候需要调用核心层的I2cCntlrAdd函数,它会实现相应功能。
+
+ ```
+ struct HdfDriverEntry g_i2cDriverEntry = {
+ .moduleVersion = 1,
+ .Init = Hi35xxI2cInit,
+ .Release = Hi35xxI2cRelease,
+ .moduleName = "hi35xx_i2c_driver",//【必要且与config.hcs文件里面匹配】
+ };
+ HDF_INIT(g_i2cDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中
+
+ //核心层i2c_core.c 管理器服务的驱动入口
+ struct HdfDriverEntry g_i2cManagerEntry = {
+ .moduleVersion = 1,
+ .Bind = I2cManagerBind,
+ .Init = I2cManagerInit,
+ .Release = I2cManagerRelease,
+ .moduleName = "HDF_PLATFORM_I2C_MANAGER",//这与device_info文件中device0对应
+ };
+ HDF_INIT(g_i2cManagerEntry);
+ ```
+
+2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在i2c\_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值对于厂商驱动的实现以及核心层I2cCntlr相关成员的默认值或限制范围有密切关系。
+
+ 统一服务模式的特点是device\_info文件中第一个设备节点必须为I2C管理器,其各项参数必须如[表2](#table96651915911)设置:
+
+ **表 2** 统一服务模式的特点
+
+
+ 成员名
+ |
+ 值
+ |
+
+
+ moduleName
+ |
+ 固定为 HDF_PLATFORM_I2C_MANAGER
+ |
+
+ serviceName
+ |
+ 固定为 HDF_PLATFORM_I2C_MANAGER
+ |
+
+ policy
+ |
+ 具体配置为1或2取决于是否对用户态可见
+ |
+
+ deviceMatchAttr
+ |
+ 没有使用,可忽略
+ |
+
+
+
+
+ 从第二个节点开始配置具体I2C控制器信息,此节点并不表示某一路I2C控制器,而是代表一个资源性质设备,用于描述一类I2C控制器的信息。多个控制器之间相互区分的参数是busID和reg\_pbase,这在i2c\_config文件中有所体现。
+
+ - device\_info.hcs 配置参考。
+
+ ```
+ root {
+ device_info {
+ match_attr = "hdf_manager";
+ device_i2c :: device {
+ device0 :: deviceNode {
+ policy = 2;
+ priority = 50;
+ permission = 0644;
+ moduleName = "HDF_PLATFORM_I2C_MANAGER";
+ serviceName = "HDF_PLATFORM_I2C_MANAGER";
+ deviceMatchAttr = "hdf_platform_i2c_manager";
+ }
+ device1 :: deviceNode {
+ policy = 0; // 等于0,不需要发布服务
+ priority = 55; // 驱动启动优先级
+ permission = 0644; // 驱动创建设备节点权限
+ moduleName = "hi35xx_i2c_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致;
+ serviceName = "HI35XX_I2C_DRIVER"; //【必要】驱动对外发布服务的名称,必须唯一
+ deviceMatchAttr = "hisilicon_hi35xx_i2c";//【必要】用于配置控制器私有数据,要与i2c_config.hcs中对应控制器保持一致
+ // 具体的控制器信息在 i2c_config.hcs 中
+ }
+ }
+ }
+ }
+ ```
+
+ - i2c\_config.hcs 配置参考。
+
+ ```
+ root {
+ platform {
+ i2c_config {
+ match_attr = "hisilicon_hi35xx_i2c";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致
+ template i2c_controller { //模板公共参数,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省
+ bus = 0; //【必要】i2c 识别号
+ reg_pbase = 0x120b0000; //【必要】物理基地址
+ reg_size = 0xd1; //【必要】寄存器位宽
+ irq = 0; //【可选】根据厂商需要来使用
+ freq = 400000; //【可选】根据厂商需要来使用
+ clk = 50000000; //【可选】根据厂商需要来使用
+ }
+ controller_0x120b0000 :: i2c_controller {
+ bus = 0;
+ }
+ controller_0x120b1000 :: i2c_controller {
+ bus = 1;
+ reg_pbase = 0x120b1000;
+ }
+ ...
+ }
+ }
+ }
+ ```
+
+3. 完成驱动入口注册之后,最后一步就是以核心层I2cCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化I2cCntlr成员I2cMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
+ - 自定义结构体参考
+
+ 从驱动的角度看,自定义结构体是参数和数据的载体,而且i2c\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层I2cCntlr对象,例如设备号、总线号等。
+
+ ```
+ // 厂商自定义功能结构体
+ struct Hi35xxI2cCntlr {
+ struct I2cCntlr cntlr; //【必要】是核心层控制对象,具体描述见下面
+ OsalSpinlock spin; //【必要】厂商需要基于此锁变量对各个 i2c 操作函数实现对应的加锁解锁
+ volatile unsigned char *regBase; //【必要】寄存器基地址
+ uint16_t regSize; //【必要】寄存器位宽
+ int16_t bus; //【必要】i2c_config.hcs 文件中可读取具体值
+ uint32_t clk; //【可选】厂商自定义
+ uint32_t freq; //【可选】厂商自定义
+ uint32_t irq; //【可选】厂商自定义
+ uint32_t regBasePhy; //【必要】寄存器物理基地址
+ };
+
+ // I2cCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值
+ struct I2cCntlr {
+ struct OsalMutex lock;
+ void *owner;
+ int16_t busId;
+ void *priv;
+ const struct I2cMethod *ops;
+ const struct I2cLockMethod *lockOps;
+ };
+ ```
+
+ - I2cCntlr成员回调函数结构体I2cMethod的实例化,和锁机制回调函数结构体I2cLockMethod实例化,其他成员在Init函数中初始化。
+
+ ```
+ // i2c_hi35xx.c 中的示例
+ static const struct I2cMethod g_method = {
+ .transfer = Hi35xxI2cTransfer,
+ };
+
+ static const struct I2cLockMethod g_lockOps = {
+ .lock = Hi35xxI2cLock, //加锁函数
+ .unlock = Hi35xxI2cUnlock,//解锁函数
+ };
+ ```
+
+ - init函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。
+
+ **表 3** init函数入参及返回值参考
+
+
+ 状态(值)
+ |
+ 问题描述
+ |
+
+
+ HDF_ERR_INVALID_OBJECT
+ |
+ 控制器对象非法
+ |
+
+ HDF_ERR_INVALID_PARAM
+ |
+ 参数非法
+ |
+
+ HDF_ERR_MALLOC_FAIL
+ |
+ 内存分配失败
+ |
+
+ HDF_ERR_IO
+ |
+ I/O 错误
+ |
+
+ HDF_SUCCESS
+ |
+ 传输成功
+ |
+
+ HDF_FAILURE
+ |
+ 传输失败
+ |
+
+
+
+
+ 函数说明:
+
+ 初始化自定义结构体对象,初始化I2cCntlr成员,调用核心层I2cCntlrAdd函数,【可选】接入VFS。
+
+ ```
+ static int32_t Hi35xxI2cInit(struct HdfDeviceObject *device)
+ {
+ ...
+ //遍历、解析 i2c_config.hcs 中的所有配置节点,并分别进行初始化,需要调用Hi35xxI2cParseAndInit函数
+ DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
+ ret = Hi35xxI2cParseAndInit(device, childNode);//函数定义见下
+ ...
+ }
+ ...
+ }
+
+ static int32_t Hi35xxI2cParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
+ {
+ struct Hi35xxI2cCntlr *hi35xx = NULL;
+ ...
+ hi35xx = (struct Hi35xxI2cCntlr *)OsalMemCalloc(sizeof(*hi35xx)); // 内存分配
+ ...
+ hi35xx->regBase = OsalIoRemap(hi35xx->regBasePhy, hi35xx->regSize); // 地址映射
+ ...
+ Hi35xxI2cCntlrInit(hi35xx); // 【必要】i2c设备的初始化
+
+ hi35xx->cntlr.priv = (void *)node; //【必要】存储设备属性
+ hi35xx->cntlr.busId = hi35xx->bus; //【必要】初始化I2cCntlr成员busId
+ hi35xx->cntlr.ops = &g_method; //【必要】I2cMethod的实例化对象的挂载
+ hi35xx->cntlr.lockOps = &g_lockOps; //【必要】I2cLockMethod的实例化对象的挂载
+ (void)OsalSpinInit(&hi35xx->spin); //【必要】锁的初始化
+ ret = I2cCntlrAdd(&hi35xx->cntlr); //【必要】调用此函数填充核心层结构体,返回成功信号后驱动才完全接入平台核心层
+ ...
+ #ifdef USER_VFS_SUPPORT
+ (void)I2cAddVfsById(hi35xx->cntlr.busId);//【可选】若支持用户级的虚拟文件系统,则接入
+ #endif
+ return HDF_SUCCESS;
+ __ERR__: //不成功的话,需要反向执行初始化相关函数
+ if (hi35xx != NULL) {
+ if (hi35xx->regBase != NULL) {
+ OsalIoUnmap((void *)hi35xx->regBase);
+ hi35xx->regBase = NULL;
+ }
+ OsalMemFree(hi35xx);
+ hi35xx = NULL;
+ }
+ return ret;
+ }
+ ```
+
+ - Release 函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ 无。
+
+ 函数说明:
+
+ 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。
+
+ ```
+ static void Hi35xxI2cRelease(struct HdfDeviceObject *device)
+ {
+ ...
+ //与Hi35xxI2cInit一样,需要将对每个节点分别进行释放
+ DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
+ Hi35xxI2cRemoveByNode(childNode);//函数定义见下
+ }
+ }
+
+ static void Hi35xxI2cRemoveByNode(const struct DeviceResourceNode *node)
+ {
+ ...
+ //【必要】可以调用 I2cCntlrGet 函数通过设备的 busid 获取 I2cCntlr 对象, 以及调用 I2cCntlrRemove 函数来释放 I2cCntlr 对象的内容
+ cntlr = I2cCntlrGet(bus);
+ if (cntlr != NULL && cntlr->priv == node) {
+ ...
+ I2cCntlrRemove(cntlr);
+ //【必要】解除地址映射,锁和内存的释放
+ hi35xx = (struct Hi35xxI2cCntlr *)cntlr;
+ OsalIoUnmap((void *)hi35xx->regBase);
+ (void)OsalSpinDestroy(&hi35xx->spin);
+ OsalMemFree(hi35xx);
+ }
+ return;
+ }
+ ```
+
+
+
diff --git a/zh-cn/device-dev/driver/driver-platform-mipidsi-des.md b/zh-cn/device-dev/driver/driver-platform-mipidsi-des.md
index c7cf01ca02d5c96f9c97447abf11a0d7bdb79ee7..3e8de1b4db84629edeaffe83ff0a3f02ab05ea89 100644
--- a/zh-cn/device-dev/driver/driver-platform-mipidsi-des.md
+++ b/zh-cn/device-dev/driver/driver-platform-mipidsi-des.md
@@ -1,8 +1,7 @@
-# MIPI DSI
+# MIPI DSI
- [概述](#section16806142183217)
- - [接口说明](#section129611916132011)
-
+- [接口说明](#section12720125432316)
- [使用指导](#section037231715335)
- [使用流程](#section49299119344)
- [获取MIPI-DSI操作句柄](#section5126155683811)
@@ -20,10 +19,10 @@
- 图1显示了简化的DSI接口。从概念上看,符合DSI的接口与基于DBI-2和DPI-2标准的接口具有相同的功能。它向外围设备传输像素或命令数据,并且可以从外围设备读取状态或像素信息。主要区别在于,DSI对所有像素数据、命令和事件进行序列化,而在传统接口中,这些像素数据、命令和事件通常需要附加控制信号才能在并行数据总线上传输。
**图 1** DSI发送、接收接口
- 
+ 
-### 接口说明
+## 接口说明
**表 1** MIPI-DSI API接口功能介绍
@@ -94,12 +93,10 @@
### 使用流程
-使用MIPI-DSI的一般流程如[图2](#fig99821771782)所示。
-
-**图 2** MIPI-DSI使用流程图
-
+使用MIPI-DSI的一般流程如[图2](#fig129103491241)所示。
-
+**图 2** MIPI-DSI使用流程图
+
### 获取MIPI-DSI操作句柄
diff --git a/zh-cn/device-dev/driver/driver-platform-mipidsi-develop.md b/zh-cn/device-dev/driver/driver-platform-mipidsi-develop.md
index 5dc633c45be6a6d6bbff017d0f17eccea67c3a1f..8bf3895f465ff6d2da893f246b11b140fc5d4f49 100755
--- a/zh-cn/device-dev/driver/driver-platform-mipidsi-develop.md
+++ b/zh-cn/device-dev/driver/driver-platform-mipidsi-develop.md
@@ -1,235 +1,339 @@
-# MIPI-DSI
-
-- [概述](#1)
-- [开发步骤](#2)
-- [开发实例](#3)
-
-## 概述
-
-DSI(Display Serial Interface)是由移动行业处理器接口联盟(Mobile Industry Processor Interface \(MIPI\) Alliance)制定的规范。在HDF框架中,
-MIPI-DSI的接口适配模式采用无服务模式,用于不需要在用户态提供API的设备类型,或者没有用户态和内核区分的OS系统,其关联方式是DevHandle直接指向设备对象内核态地址(DevHandle是一个void类型指针)。
-
-图 1 无服务模式结构图
-
-
-## 开发步骤
-
-MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
-
-1. **实例化驱动入口:**
-
- - 实例化HdfDriverEntry结构体成员。
- - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
-
-2. **配置属性文件:**
-
- - 在device_info.hcs文件中添加deviceNode描述。
- - 【可选】添加mipidsi_config.hcs器件属性文件。
-
-3. **实例化MIPIDSI控制器对象:**
-
- - 初始化MipiDsiCntlr成员。
- - 实例化MipiDsiCntlr成员MipiDsiCntlrMethod,其定义和成员**说明**见下
-
-4. **驱动调试:**
- - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,数据传输的成功与否等。
-
->  **说明:**
->
-> MipiDsiCntlrMethod定义
->
-> ```c
-> struct MipiDsiCntlrMethod { // 核心层结构体的成员函数
-> int32_t (*setCntlrCfg)(struct MipiDsiCntlr *cntlr);
-> int32_t (*setCmd)(struct MipiDsiCntlr *cntlr, struct DsiCmdDesc *cmd);
-> int32_t (*getCmd)(struct MipiDsiCntlr *cntlr, struct DsiCmdDesc *cmd, uint32_t readLen, uint8_t *out);
-> void (*toHs)(struct MipiDsiCntlr *cntlr);
-> void (*toLp)(struct MipiDsiCntlr *cntlr);
-> void (*enterUlps)(struct MipiDsiCntlr *cntlr);//【可选】进入超低功耗模式
-> void (*exitUlps)(struct MipiDsiCntlr *cntlr); //【可选】退出超低功耗模式
-> int32_t (*powerControl)(struct MipiDsiCntlr *cntlr, uint8_t enable);//【可选】使能/去使能功耗控制
-> int32_t (*attach)(struct MipiDsiCntlr *cntlr);//【可选】将一个DSI设备连接上host
-> };
-> ```
->
-> 表1 MipiDsiCntlrMethod成员的回调函数功能说明
-> |成员函数|入参|出参|返回状态|功能|
-> |-|-|-|-|-|
-> |setCntlrCfg | **cntlr**: 结构体指针,MipiDsi控制器 ; | 无 |HDF_STATUS相关状态 | 设置控制器参数 |
-> |setCmd | **cntlr**: 结构体指针,MipiDsi控制器 ; **cmd**: 结构体指针,指令传入值|无|HDF_STATUS相关状态| 向显示设备发送指令 |
-> |getCmd | **cntlr**: 结构体指针,MipiDsi控制器 ; |**cmd**: 结构体指针, 用于传出指令值;|HDF_STATUS相关状态|从显示设备读取信息指令 |
-> |toHs | **cntlr**: 结构体指针,MipiDsi控制器 ; | 无 |HDF_STATUS相关状态 |设置为高速模式|
-> |toLp | **cntlr**: 结构体指针,MipiDsi控制器 ; | 无 |HDF_STATUS相关状态 |设置为低电模式 |
-
-## 开发实例
-
-下方将以mipi_tx_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
-
-
-1. 一般来说,驱动开发首先需要在 xx_config.hcs 中配置器件属性,并在device_info.hcs文件中添加deviceNode描述。器件属性值与核心层MipiDsiCntlr 成员的默认值或限制范围有密切关系,deviceNode信息与驱动入口注册相关。
-
- **但本例中MIPI控制器无需配置额外属性,如有厂商需要,则需要在device_info文件的deviceNode增加deviceMatchAttr信息,以及增加mipidsi_config文件**。
-
-- device_info.hcs 配置参考
-
- ```c
- root {
- device_info {
- match_attr = "hdf_manager";
- platform :: host {
- hostName = "platform_host";
- priority = 50;
- device_mipi_dsi:: device {
- device0 :: deviceNode {
- policy = 0;
- priority = 150;
- permission = 0644;
- moduleName = "HDF_MIPI_TX"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致;
- serviceName = "HDF_MIPI_TX"; // 【必要且唯一】驱动对外发布服务的名称
- }
- }
- }
- }
- }
- ```
-
-2. 完成器件属性文件的配置之后,下一步请实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HdfDriverEntry结构体的函数指针成员会被厂商操作函数填充,HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组,方便调用。
-
- 一般在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
-
-- MIPI-DSI驱动入口参考
-
- ```c
- struct HdfDriverEntry g_mipiTxDriverEntry = {
- .moduleVersion = 1,
- .Init = Hi35xxMipiTxInit, //见Init参考
- .Release = Hi35xxMipiTxRelease,//见Release参考
- .moduleName = "HDF_MIPI_TX", //【必要】需要与device_info.hcs 中保持一致。
- };
- HDF_INIT(g_mipiTxDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中
- ```
-
-3. 完成驱动入口注册之后,最后一步就是以核心层MipiDsiCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化MipiDsiCntlr成员MipiDsiCntlrMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)
-
-- 自定义结构体参考
-
- > 从驱动的角度看,自定义结构体是参数和数据的载体,一般来说,config文件中的数值也会用来初始化结构体成员,但本例的mipidsi无器件属性文件,故基本成员结构与MipiDsiCntlr无太大差异。
-
- ```c
- typedef struct {
- unsigned int devno; // 设备号
- short laneId[LANE_MAX_NUM]; // lane号
- OutPutModeTag outputMode; // 输出模式选择:刷新模式,命令行模式和视频流模式
- VideoModeTag videoMode; // 显示设备的同步模式
- OutputFormatTag outputFormat; // 输出DSI图像数据格式:RGB or YUV
- SyncInfoTag syncInfo; // 时序相关的设置
- unsigned int phyDataRate; // mbps
- unsigned int pixelClk; // KHz
- } ComboDevCfgTag;
-
- // MipiDsiCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值
- struct MipiDsiCntlr {
- struct IDeviceIoService service;
- struct HdfDeviceObject *device;
- unsigned int devNo; // 设备号
- struct MipiCfg cfg;
- struct MipiDsiCntlrMethod *ops;
- struct OsalMutex lock;
- void *priv;
- };
- ```
-
-- **【重要】** MipiDsiCntlr成员回调函数结构体MipiDsiCntlrMethod的实例化,其他成员在Init函数中初始化
-
- ```c
- static struct MipiDsiCntlrMethod g_method = {
- .setCntlrCfg = Hi35xxSetCntlrCfg,
- .setCmd = Hi35xxSetCmd,
- .getCmd = Hi35xxGetCmd,
- .toHs = Hi35xxToHs,
- .toLp = Hi35xxToLp,
- };
- ```
-
-- **Init函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)
- >
- > |状态(值)|问题描述|
- > |:-|:-:|
- > |HDF_ERR_INVALID_OBJECT | 无效对象 |
- > |HDF_ERR_MALLOC_FAIL |内存分配失败|
- > |HDF_ERR_INVALID_PARAM |无效参数|
- > |HDF_ERR_IO |I/O 错误|
- > |HDF_SUCCESS |执行成功|
- > |HDF_FAILURE |执行失败|
- >
- > **函数说明:**
- > MipiDsiCntlrMethod的实例化对象的挂载,调用MipiDsiRegisterCntlr,以及其他厂商自定义初始化操作
-
- ```c
- static int32_t Hi35xxMipiTxInit(struct HdfDeviceObject *device)
- {
- int32_t ret;
- g_mipiTx.priv = NULL; //g_mipiTx是定义的全局变量
- //static struct MipiDsiCntlr g_mipiTx {
- // .devNo=0
- //};
- g_mipiTx.ops = &g_method;//MipiDsiCntlrMethod的实例化对象的挂载
- ret = MipiDsiRegisterCntlr(&g_mipiTx, device);//【必要】调用核心层函数和g_mipiTx初始化核心层全局变量
- ...
- return MipiTxDrvInit(0); //【必要】厂商对设备的初始化,形式不限
- }
-
- //mipi_dsi_core.c核心层
- int32_t MipiDsiRegisterCntlr(struct MipiDsiCntlr *cntlr, struct HdfDeviceObject *device)
- {
- ...
- //定义的全局变量:static struct MipiDsiHandle g_mipiDsihandle[MAX_CNTLR_CNT];
- if (g_mipiDsihandle[cntlr->devNo].cntlr == NULL) {
- (void)OsalMutexInit(&g_mipiDsihandle[cntlr->devNo].lock);
- (void)OsalMutexInit(&(cntlr->lock));
-
- g_mipiDsihandle[cntlr->devNo].cntlr = cntlr;//初始化MipiDsiHandle成员
- g_mipiDsihandle[cntlr->devNo].priv = NULL;
- cntlr->device = device; //使HdfDeviceObject与MipiDsiHandle可以相互转化的前提
- device->service = &(cntlr->service); //使HdfDeviceObject与MipiDsiHandle可以相互转化的前提
- cntlr->priv = NULL;
- ...
- return HDF_SUCCESS;
- }
- ...
- return HDF_FAILURE;
- }
- ```
-
-- **Release函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > 无
- >
- > **函数说明:**
- > 该函数需要在驱动入口结构体中赋值给 Release 接口, 当 HDF 框架调用 Init 函数初始化驱动失败时,可以调用 Release 释放驱动资源, 该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
-
- ```c
- static void Hi35xxMipiTxRelease(struct HdfDeviceObject *device)
- {
- struct MipiDsiCntlr *cntlr = NULL;
- ...
- cntlr = MipiDsiCntlrFromDevice(device);//这里有HdfDeviceObject到MipiDsiCntlr的强制转化
- //return (device == NULL) ? NULL : (struct MipiDsiCntlr *)device->service;
- ...
- MipiTxDrvExit(); //【必要】对厂商设备所占资源的释放
- MipiDsiUnregisterCntlr(&g_mipiTx); //空函数
- g_mipiTx.priv = NULL;
- HDF_LOGI("%s: unload mipi_tx driver 1212!", __func__);
- }
- ```
-
+# MIPI-DSI
+
+- [概述](#section1266787503161538)
+- [接口说明](#section752964871810)
+- [开发步骤](#section545182932161538)
+- [开发实例](#section1167576616161538)
+
+## 概述
+
+DSI(Display Serial Interface)是由移动行业处理器接口联盟(Mobile Industry Processor Interface \(MIPI\) Alliance)制定的规范。在HDF框架中,MIPI-DSI的接口适配模式采用无服务模式,用于不需要在用户态提供API的设备类型,或者没有用户态和内核区分的OS系统,其关联方式是DevHandle直接指向设备对象内核态地址(DevHandle是一个void类型指针)。
+
+**图 1** DSI无服务模式结构图
+
+
+## 接口说明
+
+MipiDsiCntlrMethod定义:
+
+```
+struct MipiDsiCntlrMethod { // 核心层结构体的成员函数
+ int32_t (*setCntlrCfg)(struct MipiDsiCntlr *cntlr);
+ int32_t (*setCmd)(struct MipiDsiCntlr *cntlr, struct DsiCmdDesc *cmd);
+ int32_t (*getCmd)(struct MipiDsiCntlr *cntlr, struct DsiCmdDesc *cmd, uint32_t readLen, uint8_t *out);
+ void (*toHs)(struct MipiDsiCntlr *cntlr);
+ void (*toLp)(struct MipiDsiCntlr *cntlr);
+ void (*enterUlps)(struct MipiDsiCntlr *cntlr);//【可选】进入超低功耗模式
+ void (*exitUlps)(struct MipiDsiCntlr *cntlr); //【可选】退出超低功耗模式
+ int32_t (*powerControl)(struct MipiDsiCntlr *cntlr, uint8_t enable);//【可选】使能/去使能功耗控制
+ int32_t (*attach)(struct MipiDsiCntlr *cntlr);//【可选】将一个DSI设备连接上host
+};
+```
+
+**表 1** MipiDsiCntlrMethod成员的回调函数功能说明
+
+
+成员函数
+ |
+入参
+ |
+出参
+ |
+返回状态
+ |
+功能
+ |
+
+
+setCntlrCfg
+ |
+cntlr: 结构体指针,MipiDsi控制器 ;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+设置控制器参数
+ |
+
+setCmd
+ |
+cntlr: 结构体指针,MipiDsi控制器 ;cmd: 结构体指针,指令传入值
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+向显示设备发送指令
+ |
+
+getCmd
+ |
+cntlr: 结构体指针,MipiDsi控制器 ;
+ |
+cmd: 结构体指针,用于传出指令值;
+ |
+HDF_STATUS相关状态
+ |
+从显示设备读取信息指令
+ |
+
+toHs
+ |
+cntlr: 结构体指针,MipiDsi控制器 ;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+设置为高速模式
+ |
+
+toLp
+ |
+cntlr: 结构体指针,MipiDsi控制器 ;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+设置为低电模式
+ |
+
+
+
+
+## 开发步骤
+
+MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
+
+1. **实例化驱动入口:**
+ - 实例化HdfDriverEntry结构体成员。
+ - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
+
+2. **配置属性文件:**
+ - 在device\_info.hcs文件中添加deviceNode描述。
+ - 【可选】添加mipidsi\_config.hcs器件属性文件。
+
+3. **实例化MIPIDSI控制器对象:**
+ - 初始化MipiDsiCntlr成员。
+ - 实例化MipiDsiCntlr成员MipiDsiCntlrMethod。
+
+ > **说明:**
+ >实例化MipiDsiCntlr成员MipiDsiCntlrMethod,其定义和成员说明见[接口说明](#section752964871810)。
+
+
+4. **驱动调试:**
+
+ 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,数据传输的成功与否等。
+
+
+## 开发实例
+
+下方将以mipi\_tx\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
+
+1. 一般来说,驱动开发首先需要在 xx\_config.hcs 中配置器件属性,并在device\_info.hcs文件中添加deviceNode描述。器件属性值与核心层MipiDsiCntlr 成员的默认值或限制范围有密切关系,deviceNode信息与驱动入口注册相关。
+
+ 但本例中MIPI控制器无需配置额外属性,如有厂商需要,则需要在device\_info文件的deviceNode增加deviceMatchAttr信息,以及增加mipidsi\_config文件。
+
+ device\_info.hcs 配置参考:
+
+ ```
+ root {
+ device_info {
+ match_attr = "hdf_manager";
+ platform :: host {
+ hostName = "platform_host";
+ priority = 50;
+ device_mipi_dsi:: device {
+ device0 :: deviceNode {
+ policy = 0;
+ priority = 150;
+ permission = 0644;
+ moduleName = "HDF_MIPI_TX"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致;
+ serviceName = "HDF_MIPI_TX"; // 【必要且唯一】驱动对外发布服务的名称
+ }
+ }
+ }
+ }
+ }
+ ```
+
+2. 完成器件属性文件的配置之后,下一步请实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HdfDriverEntry结构体的函数指针成员会被厂商操作函数填充,HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组,方便调用。
+
+ 一般在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
+
+ - MIPI-DSI驱动入口参考。
+
+ ```
+ struct HdfDriverEntry g_mipiTxDriverEntry = {
+ .moduleVersion = 1,
+ .Init = Hi35xxMipiTxInit, //见Init参考
+ .Release = Hi35xxMipiTxRelease,//见Release参考
+ .moduleName = "HDF_MIPI_TX", //【必要】需要与device_info.hcs 中保持一致。
+ };
+ HDF_INIT(g_mipiTxDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中
+ ```
+
+3. 完成驱动入口注册之后,最后一步就是以核心层MipiDsiCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化MipiDsiCntlr成员MipiDsiCntlrMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
+ - 自定义结构体参考。
+
+ 从驱动的角度看,自定义结构体是参数和数据的载体,一般来说,config文件中的数值也会用来初始化结构体成员,但本例的mipidsi无器件属性文件,故基本成员结构与MipiDsiCntlr无太大差异。
+
+ ```
+ typedef struct {
+ unsigned int devno; // 设备号
+ short laneId[LANE_MAX_NUM]; // lane号
+ OutPutModeTag outputMode; // 输出模式选择:刷新模式,命令行模式和视频流模式
+ VideoModeTag videoMode; // 显示设备的同步模式
+ OutputFormatTag outputFormat; // 输出DSI图像数据格式:RGB or YUV
+ SyncInfoTag syncInfo; // 时序相关的设置
+ unsigned int phyDataRate; // mbps
+ unsigned int pixelClk; // KHz
+ } ComboDevCfgTag;
+
+ // MipiDsiCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值
+ struct MipiDsiCntlr {
+ struct IDeviceIoService service;
+ struct HdfDeviceObject *device;
+ unsigned int devNo; // 设备号
+ struct MipiCfg cfg;
+ struct MipiDsiCntlrMethod *ops;
+ struct OsalMutex lock;
+ void *priv;
+ };
+ ```
+
+ - MipiDsiCntlr成员回调函数结构体MipiDsiCntlrMethod的实例化,其他成员在Init函数中初始化。
+
+ ```
+ static struct MipiDsiCntlrMethod g_method = {
+ .setCntlrCfg = Hi35xxSetCntlrCfg,
+ .setCmd = Hi35xxSetCmd,
+ .getCmd = Hi35xxGetCmd,
+ .toHs = Hi35xxToHs,
+ .toLp = Hi35xxToLp,
+ };
+ ```
+
+ - Init函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。
+
+
+ 状态(值)
+ |
+ 问题描述
+ |
+
+
+ HDF_ERR_INVALID_OBJECT
+ |
+ 无效对象
+ |
+
+ HDF_ERR_MALLOC_FAIL
+ |
+ 内存分配失败
+ |
+
+ HDF_ERR_INVALID_PARAM
+ |
+ 无效参数
+ |
+
+ HDF_ERR_IO
+ |
+ I/O 错误
+ |
+
+ HDF_SUCCESS
+ |
+ 执行成功
+ |
+
+ HDF_FAILURE
+ |
+ 执行失败
+ |
+
+
+
+
+ 函数说明:
+
+ MipiDsiCntlrMethod的实例化对象的挂载,调用MipiDsiRegisterCntlr,以及其他厂商自定义初始化操作。
+
+ ```
+ static int32_t Hi35xxMipiTxInit(struct HdfDeviceObject *device)
+ {
+ int32_t ret;
+ g_mipiTx.priv = NULL; //g_mipiTx是定义的全局变量
+ //static struct MipiDsiCntlr g_mipiTx {
+ // .devNo=0
+ //};
+ g_mipiTx.ops = &g_method;//MipiDsiCntlrMethod的实例化对象的挂载
+ ret = MipiDsiRegisterCntlr(&g_mipiTx, device);//【必要】调用核心层函数和g_mipiTx初始化核心层全局变量
+ ...
+ return MipiTxDrvInit(0); //【必要】厂商对设备的初始化,形式不限
+ }
+
+ //mipi_dsi_core.c核心层
+ int32_t MipiDsiRegisterCntlr(struct MipiDsiCntlr *cntlr, struct HdfDeviceObject *device)
+ {
+ ...
+ //定义的全局变量:static struct MipiDsiHandle g_mipiDsihandle[MAX_CNTLR_CNT];
+ if (g_mipiDsihandle[cntlr->devNo].cntlr == NULL) {
+ (void)OsalMutexInit(&g_mipiDsihandle[cntlr->devNo].lock);
+ (void)OsalMutexInit(&(cntlr->lock));
+
+ g_mipiDsihandle[cntlr->devNo].cntlr = cntlr;//初始化MipiDsiHandle成员
+ g_mipiDsihandle[cntlr->devNo].priv = NULL;
+ cntlr->device = device; //使HdfDeviceObject与MipiDsiHandle可以相互转化的前提
+ device->service = &(cntlr->service); //使HdfDeviceObject与MipiDsiHandle可以相互转化的前提
+ cntlr->priv = NULL;
+ ...
+ return HDF_SUCCESS;
+ }
+ ...
+ return HDF_FAILURE;
+ }
+ ```
+
+ - Release函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ 无。
+
+ 函数说明:
+
+ 该函数需要在驱动入口结构体中赋值给 Release 接口, 当 HDF 框架调用 Init 函数初始化驱动失败时,可以调用 Release 释放驱动资源, 该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作前提是在Init函数中具备对应赋值的操作。
+
+ ```
+ static void Hi35xxMipiTxRelease(struct HdfDeviceObject *device)
+ {
+ struct MipiDsiCntlr *cntlr = NULL;
+ ...
+ cntlr = MipiDsiCntlrFromDevice(device);//这里有HdfDeviceObject到MipiDsiCntlr的强制转化
+ //return (device == NULL) ? NULL : (struct MipiDsiCntlr *)device->service;
+ ...
+ MipiTxDrvExit(); //【必要】对厂商设备所占资源的释放
+ MipiDsiUnregisterCntlr(&g_mipiTx); //空函数
+ g_mipiTx.priv = NULL;
+ HDF_LOGI("%s: unload mipi_tx driver 1212!", __func__);
+ }
+ ```
+
+
+
diff --git a/zh-cn/device-dev/driver/driver-platform-mmc-develop.md b/zh-cn/device-dev/driver/driver-platform-mmc-develop.md
index a8c18fd7bc0a2f14c9ce52b971e28029981c343d..b8e0219717ffd428bad3623de5cafc7b17b5b95a 100755
--- a/zh-cn/device-dev/driver/driver-platform-mmc-develop.md
+++ b/zh-cn/device-dev/driver/driver-platform-mmc-develop.md
@@ -1,379 +1,552 @@
-# MMC
-
-- [概述](#1)
-- [开发步骤](#2)
-- [开发实例](#3)
-
-## 概述
-
-MMC(MultiMedia Card),即多媒体卡,在HDF框架中,MMC的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。
-
-独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
-
-
-图 1 独立服务模式结构图
-
-
-
-## 开发步骤
-
-MMC模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
-
-1. **实例化驱动入口:**
- - 实例化HdfDriverEntry结构体成员。
- - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
-
-2. **配置属性文件:**
-
- - 在device_info.hcs文件中添加deviceNode描述。
- - 【可选】添加mmc_config.hcs器件属性文件。
-
-3. **实例化MMC控制器对象:**
- - 初始化MmcCntlr成员。
- - 实例化MmcCntlr成员MmcCntlrOps,其定义和成员说明见下
-
-4. **驱动调试:**
- - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,设备启动是否成功等。
-
->  **说明:**
->
-> MmcCntlrOps定义
-> ```c
-> struct MmcCntlrOps {
-> int32_t (*request)(struct MmcCntlr *cntlr, struct MmcCmd *cmd);
-> int32_t (*setClock)(struct MmcCntlr *cntlr, uint32_t clock);
-> int32_t (*setPowerMode)(struct MmcCntlr *cntlr, enum MmcPowerMode mode);
-> int32_t (*setBusWidth)(struct MmcCntlr *cntlr, enum MmcBusWidth width);
-> int32_t (*setBusTiming)(struct MmcCntlr *cntlr, enum MmcBusTiming timing);
-> int32_t (*setSdioIrq)(struct MmcCntlr *cntlr, bool enable);
-> int32_t (*hardwareReset)(struct MmcCntlr *cntlr);
-> int32_t (*systemInit)(struct MmcCntlr *cntlr);
-> int32_t (*setEnhanceSrobe)(struct MmcCntlr *cntlr, bool enable);
-> int32_t (*switchVoltage)(struct MmcCntlr *cntlr, enum MmcVolt volt);
-> bool (*devReadOnly)(struct MmcCntlr *cntlr);
-> bool (*devPluged)(struct MmcCntlr *cntlr);
-> bool (*devBusy)(struct MmcCntlr *cntlr);
-> int32_t (*tune)(struct MmcCntlr *cntlr, uint32_t cmdCode);
-> int32_t (*rescanSdioDev)(struct MmcCntlr *cntlr);
-> };
-> ```
->
-> 表1 MmcCntlrOps结构体成员的回调函数功能说明
-> |成员函数|入参|返回值|功能|
-> |-|-|-|-|
-> |doRequest |**cntlr**: 核心层结构体指针,mmc控制器 ; **cmd**: 结构体指针,传入命令值 |HDF_STATUS相关状态|request相应处理|
-> |setClock |**cntlr**: 核心层结构体指针,mmc控制器 ; **clock**: 时钟传入值 |HDF_STATUS相关状态|设置时钟频率|
-> |setPowerMode |**cntlr**: 核心层结构体指针,mmc控制器 ; **mode**: 枚举值(见MmcPowerMode定义),功耗模式 |HDF_STATUS相关状态|设置功耗模式|
-> |setBusWidth |**cntlr**: 核心层结构体指针,mmc控制器 ; **width**: 枚举值(见MmcBusWidth定义),总线带宽 |HDF_STATUS相关状态|设置总线带宽|
-> |setBusTiming |**cntlr**: 核心层结构体指针,mmc控制器 ; **timing**: 枚举值(见MmcBusTiming定义),总线时序 |HDF_STATUS相关状态|设置总线时序|
-> |setSdioIrq |**cntlr**: 核心层结构体指针,mmc控制器 ; **enable**: 布尔值,控制中断|HDF_STATUS相关状态|使能/去使能SDIO中断|
-> |hardwareReset |**cntlr**: 核心层结构体指针,mmc控制器 ; |HDF_STATUS相关状态|复位硬件 |
-> |systemInit |**cntlr**: 核心层结构体指针,mmc控制器 ; |HDF_STATUS相关状态|系统初始化 |
-> |setEnhanceSrobe |**cntlr**: 核心层结构体指针,mmc控制器 ; **enable**: 布尔值,设置功能 |HDF_STATUS相关状态|设置增强选通 |
-> |switchVoltage |**cntlr**: 核心层结构体指针,mmc控制器 ; **volt**: 枚举值,电压值(3.3,1.8,1.2V); |HDF_STATUS相关状态|设置电压值 |
-> |devReadOnly |**cntlr**: 核心层结构体指针,mmc控制器 ; |布尔值 |检验设备是否只读 |
-> |cardPluged |**cntlr**: 核心层结构体指针,mmc控制器 ; |布尔值 |检验设备是否拔出|
-> |devBusy |**cntlr**: 核心层结构体指针,mmc控制器 ; |布尔值 |检验设备是否忙碌|
-> |tune |**cntlr**: 核心层结构体指针,mmc控制器 ; **cmdCode**: uint32_t,命令代码; |HDF_STATUS相关状态|调谐 |
-> |rescanSdioDev |**cntlr**: 核心层结构体指针,mmc控制器 ; |HDF_STATUS相关状态|扫描并添加SDIO设备,|
-
-
-## 开发实例
-
-下方将以himci.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
-
-1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
-
- 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
-
-- MMC驱动入口参考
-
- ```c
- struct HdfDriverEntry g_mmcDriverEntry = {
- .moduleVersion = 1,
- .Bind = HimciMmcBind, //见Bind参考
- .Init = HimciMmcInit, //见Init参考
- .Release = HimciMmcRelease, //见Release参考
- .moduleName = "hi3516_mmc_driver",//【必要且与HCS文件中里面的moduleName匹配】
- };
- HDF_INIT(g_mmcDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中
- ```
-
-2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在mmc_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层MmcCntlr成员的默认值或限制范围有密切关系。
-
- **如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在mmc_config文件中增加对应的器件属性。**。
-
-
-- device_info.hcs 配置参考
-
- ```c
- root {
- device_info {
- match_attr = "hdf_manager";
- platform :: host {
- hostName = "platform_host";
- priority = 50;
- device_mmc:: device {
- device0 :: deviceNode {
- policy = 2;
- priority = 10;
- permission = 0644;
- moduleName = "hi3516_mmc_driver"; //【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致;
- serviceName = "HDF_PLATFORM_MMC_0"; //【必要】驱动对外发布服务的名称,必须唯一
- deviceMatchAttr = "hi3516_mmc_emmc";//【必要】用于配置控制器私有数据,要与 mmc_config.hcs 中对应控制器保持一致
- }
- device1 :: deviceNode {
- policy = 1;
- priority = 20;
- permission = 0644;
- moduleName = "hi3516_mmc_driver";
- serviceName = "HDF_PLATFORM_MMC_1";
- deviceMatchAttr = "hi3516_mmc_sd"; //SD类型
- }
- device2 :: deviceNode {
- policy = 1;
- priority = 30;
- permission = 0644;
- moduleName = "hi3516_mmc_driver";
- serviceName = "HDF_PLATFORM_MMC_2";
- deviceMatchAttr = "hi3516_mmc_sdio";//SDIO类型
- }
- }
- }
- }
- }
- ```
-
-- mmc_config.hcs 配置参考
-
- ```c
- root {
- platform {
- mmc_config {
- template mmc_controller {//模板公共参数,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省
- match_attr = "";
- voltDef = 0; // 3.3V
- freqMin = 50000; //【必要】最小频率值
- freqMax = 100000000; //【必要】最大频率值
- freqDef = 400000; //【必要】默认频率值
- maxBlkNum = 2048; //【必要】最大的block号
- maxBlkSize = 512; //【必要】最大的block个数
- ocrDef = 0x300000; //【必要】工作电压设置相关
- caps2 = 0; //【必要】属性寄存器相关,见mmc_caps.h 中 MmcCaps2 定义
- regSize = 0x118; //【必要】寄存器位宽
- hostId = 0; //【必要】主机号
- regBasePhy = 0x10020000;//【必要】寄存器物理基地址
- irqNum = 63; //【必要】中断号
- devType = 2; //【必要】模式选择:emmc, SD, SDIO ,COMBO
- caps = 0x0001e045; //【必要】属性寄存器相关,见mmc_caps.h 中 MmcCaps 定义
- }
- controller_0x10100000 :: mmc_controller {
- match_attr = "hi3516_mmc_emmc";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致
- hostId = 0;
- regBasePhy = 0x10100000;
- irqNum = 96;
- devType = 0; // emmc类型
- caps = 0xd001e045;
- caps2 = 0x60;
- }
- controller_0x100f0000 :: mmc_controller {
- match_attr = "hi3516_mmc_sd";
- hostId = 1;
- regBasePhy = 0x100f0000;
- irqNum = 62;
- devType = 1; // sd类型
- caps = 0xd001e005;
- }
- controller_0x10020000 :: mmc_controller {
- match_attr = "hi3516_mmc_sdio";
- hostId = 2;
- regBasePhy = 0x10020000;
- irqNum = 63;
- devType = 2; // sdio类型
- caps = 0x0001e04d;
- }
- }
- }
- }
- ```
-
-3. 完成驱动入口注册之后,最后一步就是以核心层MmcCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化MmcCntlr成员MmcCntlrOps(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)
-
-- 自定义结构体参考
-
- > 从驱动的角度看,自定义结构体是参数和数据的载体,而且mmc_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员 ,一些重要数值也会传递给核心层对象。
-
- ```c
- struct HimciHost {
- struct MmcCntlr *mmc;//【必要】核心层结构体
- struct MmcCmd *cmd; //【必要】核心层结构体,传递命令的,相关命令见枚举量 MmcCmdCode
- //【可选】根据厂商驱动需要添加
- void *base;
- enum HimciPowerStatus powerStatus;
- uint8_t *alignedBuff;
- uint32_t buffLen;
- struct scatterlist dmaSg;
- struct scatterlist *sg;
- uint32_t dmaSgNum;
- DMA_ADDR_T dmaPaddr;
- uint32_t *dmaVaddr;
- uint32_t irqNum;
- bool isTuning;
- uint32_t id;
- struct OsalMutex mutex;
- bool waitForEvent;
- HIMCI_EVENT himciEvent;
- };
- //MmcCntlr是核心层控制器结构体,其中的成员在bind函数中会被赋值
- struct MmcCntlr {
- struct IDeviceIoService service;
- struct HdfDeviceObject *hdfDevObj;
- struct PlatformDevice device;
- struct OsalMutex mutex;
- struct OsalSem released;
- uint32_t devType;
- struct MmcDevice *curDev;
- struct MmcCntlrOps *ops;
- struct PlatformQueue *msgQueue;
- uint16_t index;
- uint16_t voltDef;
- uint32_t vddBit;
- uint32_t freqMin;
- uint32_t freqMax;
- uint32_t freqDef;
- union MmcOcr ocrDef;
- union MmcCaps caps;
- union MmcCaps2 caps2;
- uint32_t maxBlkNum;
- uint32_t maxBlkSize;
- uint32_t maxReqSize;
- bool devPluged;
- bool detecting;
- void *priv;
- };
- ```
-
-
-- **【重要】** MmcCntlr成员回调函数结构体MmcCntlrOps的实例化,其他成员在Bind函数中初始化
-
- ```c
- static struct MmcCntlrOps g_himciHostOps = {
- .request = HimciDoRequest,
- .setClock = HimciSetClock,
- .setPowerMode = HimciSetPowerMode,
- .setBusWidth = HimciSetBusWidth,
- .setBusTiming = HimciSetBusTiming,
- .setSdioIrq = HimciSetSdioIrq,
- .hardwareReset = HimciHardwareReset,
- .systemInit = HimciSystemInit,
- .setEnhanceSrobe= HimciSetEnhanceSrobe,
- .switchVoltage = HimciSwitchVoltage,
- .devReadOnly = HimciDevReadOnly,
- .devPluged = HimciCardPluged,
- .devBusy = HimciDevBusy,
- .tune = HimciTune,
- .rescanSdioDev = HimciRescanSdioDev,
- };
- ```
-
-- **Bind函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)
- >
- > |状态(值)|问题描述|
- > |:-|:-:|
- > |HDF_ERR_INVALID_OBJECT|控制器对象非法|
- > |HDF_ERR_MALLOC_FAIL |内存分配失败|
- > |HDF_ERR_INVALID_PARAM |参数非法|
- > |HDF_ERR_IO |I/O 错误|
- > |HDF_SUCCESS |初始化成功|
- > |HDF_FAILURE |初始化失败|
- >
- > **函数说明:**
- > MmcCntlr,HimciHost,HdfDeviceObject之间互相赋值,方便其他函数可以相互转化,初始化自定义结构体HimciHost对象,初始化MmcCntlr成员,调用核心层MmcCntlrAdd函数。
-
- ```c
- static int32_t HimciMmcBind(struct HdfDeviceObject *obj)
- {
- struct MmcCntlr *cntlr = NULL;
- struct HimciHost *host = NULL;
- int32_t ret;
- cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr));
- host = (struct HimciHost *)OsalMemCalloc(sizeof(struct HimciHost));
-
- host->mmc = cntlr; //【必要】使HimciHost与MmcCntlr可以相互转化的前提
- cntlr->priv = (void *)host; //【必要】使HimciHost与MmcCntlr可以相互转化的前提
- cntlr->ops = &g_himciHostOps; //【必要】MmcCntlrOps的实例化对象的挂载
- cntlr->hdfDevObj = obj; //【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提
- obj->service = &cntlr->service; //【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提
- ret = MmcCntlrParse(cntlr, obj); //【必要】 初始化 cntlr. 失败就 goto _ERR;
- ...
- ret = HimciHostParse(host, obj); //【必要】 初始化 host对象的相关属性,失败就 goto _ERR;
- ...
- ret = HimciHostInit(host, cntlr);//厂商自定义的初始化,失败就 goto _ERR;
- ...
- ret = MmcCntlrAdd(cntlr); //调用核心层函数 失败就 goto _ERR;
- ...
- (void)MmcCntlrAddDetectMsgToQueue(cntlr);//将卡检测消息添加到队列中。
- HDF_LOGD("HimciMmcBind: success.");
- return HDF_SUCCESS;
- _ERR:
- HimciDeleteHost(host);
- HDF_LOGD("HimciMmcBind: fail, err = %d.", ret);
- return ret;
- }
- ```
-
-
-- **Init函数参考**
-
- > **入参:**
- > HdfDeviceObject是整个驱动对外暴露的接口参数,具备HCS配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态
- >
- > **函数说明:**
- > 实现ProcMciInit
-
- ```c
- static int32_t HimciMmcInit(struct HdfDeviceObject *obj)
- {
- static bool procInit = false;
- (void)obj;
- if (procInit == false) {
- if (ProcMciInit() == HDF_SUCCESS) {
- procInit = true;
- HDF_LOGD("HimciMmcInit: proc init success.");
- }
- }
- HDF_LOGD("HimciMmcInit: success.");
- return HDF_SUCCESS;
- }
- ```
-
-- **Release函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > 无
- >
- > **函数说明:**
- > 释放内存和删除控制器等操作,该函数需要在驱动入口结构体中赋值给Release接口,当HDF框架调用Init函数初始化驱动失败时,可以调用 Release释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
-
- ```c
- static void HimciMmcRelease(struct HdfDeviceObject *obj)
- {
- struct MmcCntlr *cntlr = NULL;
- ...
- cntlr = (struct MmcCntlr *)obj->service;//这里有HdfDeviceObject到MmcCntlr的强制转化,通过service成员,赋值见Bind函数
- ...
- HimciDeleteHost((struct HimciHost *)cntlr->priv);//厂商自定义的内存释放函数,这里有MmcCntlr到HimciHost的强制转化
- }
- ```
+# MMC
+
+- [概述](#section1846388309162704)
+- [接口说明](#section752964871810)
+- [开发步骤](#section1617495117162704)
+- [开发实例](#section1220893490162704)
+
+## 概述
+
+MMC(MultiMedia Card),即多媒体卡,在HDF框架中,MMC的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
+
+**图 1** MMC独立服务模式结构图
+
+
+## 接口说明
+
+MmcCntlrOps定义:
+
+```
+struct MmcCntlrOps {
+ int32_t (*request)(struct MmcCntlr *cntlr, struct MmcCmd *cmd);
+ int32_t (*setClock)(struct MmcCntlr *cntlr, uint32_t clock);
+ int32_t (*setPowerMode)(struct MmcCntlr *cntlr, enum MmcPowerMode mode);
+ int32_t (*setBusWidth)(struct MmcCntlr *cntlr, enum MmcBusWidth width);
+ int32_t (*setBusTiming)(struct MmcCntlr *cntlr, enum MmcBusTiming timing);
+ int32_t (*setSdioIrq)(struct MmcCntlr *cntlr, bool enable);
+ int32_t (*hardwareReset)(struct MmcCntlr *cntlr);
+ int32_t (*systemInit)(struct MmcCntlr *cntlr);
+ int32_t (*setEnhanceSrobe)(struct MmcCntlr *cntlr, bool enable);
+ int32_t (*switchVoltage)(struct MmcCntlr *cntlr, enum MmcVolt volt);
+ bool (*devReadOnly)(struct MmcCntlr *cntlr);
+ bool (*devPluged)(struct MmcCntlr *cntlr);
+ bool (*devBusy)(struct MmcCntlr *cntlr);
+ int32_t (*tune)(struct MmcCntlr *cntlr, uint32_t cmdCode);
+ int32_t (*rescanSdioDev)(struct MmcCntlr *cntlr);
+};
+```
+
+**表 1** MmcCntlrOps结构体成员的回调函数功能说明
+
+
+成员函数
+ |
+入参
+ |
+返回值
+ |
+功能
+ |
+
+
+doRequest
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;cmd: 结构体指针,传入命令值
+ |
+HDF_STATUS相关状态
+ |
+request相应处理
+ |
+
+setClock
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;clock: 时钟传入值
+ |
+HDF_STATUS相关状态
+ |
+设置时钟频率
+ |
+
+setPowerMode
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;mode: 枚举值(见MmcPowerMode定义),功耗模式
+ |
+HDF_STATUS相关状态
+ |
+设置功耗模式
+ |
+
+setBusWidth
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;width: 枚举值(见MmcBusWidth定义),总线带宽
+ |
+HDF_STATUS相关状态
+ |
+设置总线带宽
+ |
+
+setBusTiming
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;timing: 枚举值(见MmcBusTiming定义),总线时序
+ |
+HDF_STATUS相关状态
+ |
+设置总线时序
+ |
+
+setSdioIrq
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;enable: 布尔值,控制中断
+ |
+HDF_STATUS相关状态
+ |
+使能/去使能SDIO中断
+ |
+
+hardwareReset
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;
+ |
+HDF_STATUS相关状态
+ |
+复位硬件
+ |
+
+systemInit
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;
+ |
+HDF_STATUS相关状态
+ |
+系统初始化
+ |
+
+setEnhanceSrobe
+ |
+cntlr: 核心层结构体指针,mmc控制器 ;enable: 布尔值,设置功能
+ |
+HDF_STATUS相关状态
+ |
+设置增强选通
+ |
+
+switchVoltage
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;volt: 枚举值,电压值(3.3,1.8,1.2V);
+ |
+HDF_STATUS相关状态
+ |
+设置电压值
+ |
+
+devReadOnly
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;
+ |
+布尔值
+ |
+检验设备是否只读
+ |
+
+cardPluged
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;
+ |
+布尔值
+ |
+检验设备是否拔出
+ |
+
+devBusy
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;
+ |
+布尔值
+ |
+检验设备是否忙碌
+ |
+
+tune
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;cmdCode: uint32_t,命令代码;
+ |
+HDF_STATUS相关状态
+ |
+调谐
+ |
+
+rescanSdioDev
+ |
+cntlr: 核心层结构体指针;mmc控制器 ;
+ |
+HDF_STATUS相关状态
+ |
+扫描并添加SDIO设备
+ |
+
+
+
+
+## 开发步骤
+
+MMC模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
+
+1. **实例化驱动入口:**
+ - 实例化HdfDriverEntry结构体成员。
+ - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
+
+2. **配置属性文件:**
+ - 在device\_info.hcs文件中添加deviceNode描述。
+ - 【可选】添加mmc\_config.hcs器件属性文件。
+
+3. **实例化MMC控制器对象:**
+ - 初始化MmcCntlr成员。
+ - 实例化MmcCntlr成员MmcCntlrOps。
+
+ > **说明:**
+ >实例化MmcCntlr成员MmcCntlrOps,其定义和成员说明见[接口说明](#section752964871810)。
+
+
+4. **驱动调试:**
+
+ 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,设备启动是否成功等。
+
+
+## 开发实例
+
+下方将以himci.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
+
+1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
+
+ 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
+
+ MMC驱动入口参考:
+
+ ```
+ struct HdfDriverEntry g_mmcDriverEntry = {
+ .moduleVersion = 1,
+ .Bind = HimciMmcBind, //见Bind参考
+ .Init = HimciMmcInit, //见Init参考
+ .Release = HimciMmcRelease, //见Release参考
+ .moduleName = "hi3516_mmc_driver",//【必要且与HCS文件中里面的moduleName匹配】
+ };
+ HDF_INIT(g_mmcDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中
+ ```
+
+2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在mmc\_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层MmcCntlr成员的默认值或限制范围有密切关系。
+
+ 如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在mmc\_config文件中增加对应的器件属性**。**
+
+ - device\_info.hcs 配置参考。
+
+ ```
+ root {
+ device_info {
+ match_attr = "hdf_manager";
+ platform :: host {
+ hostName = "platform_host";
+ priority = 50;
+ device_mmc:: device {
+ device0 :: deviceNode {
+ policy = 2;
+ priority = 10;
+ permission = 0644;
+ moduleName = "hi3516_mmc_driver"; //【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致;
+ serviceName = "HDF_PLATFORM_MMC_0"; //【必要】驱动对外发布服务的名称,必须唯一
+ deviceMatchAttr = "hi3516_mmc_emmc";//【必要】用于配置控制器私有数据,要与 mmc_config.hcs 中对应控制器保持一致
+ }
+ device1 :: deviceNode {
+ policy = 1;
+ priority = 20;
+ permission = 0644;
+ moduleName = "hi3516_mmc_driver";
+ serviceName = "HDF_PLATFORM_MMC_1";
+ deviceMatchAttr = "hi3516_mmc_sd"; //SD类型
+ }
+ device2 :: deviceNode {
+ policy = 1;
+ priority = 30;
+ permission = 0644;
+ moduleName = "hi3516_mmc_driver";
+ serviceName = "HDF_PLATFORM_MMC_2";
+ deviceMatchAttr = "hi3516_mmc_sdio";//SDIO类型
+ }
+ }
+ }
+ }
+ }
+ ```
+
+ - mmc\_config.hcs 配置参考。
+
+ ```
+ root {
+ platform {
+ mmc_config {
+ template mmc_controller {//模板公共参数,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省
+ match_attr = "";
+ voltDef = 0; // 3.3V
+ freqMin = 50000; //【必要】最小频率值
+ freqMax = 100000000; //【必要】最大频率值
+ freqDef = 400000; //【必要】默认频率值
+ maxBlkNum = 2048; //【必要】最大的block号
+ maxBlkSize = 512; //【必要】最大的block个数
+ ocrDef = 0x300000; //【必要】工作电压设置相关
+ caps2 = 0; //【必要】属性寄存器相关,见mmc_caps.h 中 MmcCaps2 定义
+ regSize = 0x118; //【必要】寄存器位宽
+ hostId = 0; //【必要】主机号
+ regBasePhy = 0x10020000;//【必要】寄存器物理基地址
+ irqNum = 63; //【必要】中断号
+ devType = 2; //【必要】模式选择:emmc, SD, SDIO ,COMBO
+ caps = 0x0001e045; //【必要】属性寄存器相关,见mmc_caps.h 中 MmcCaps 定义
+ }
+ controller_0x10100000 :: mmc_controller {
+ match_attr = "hi3516_mmc_emmc";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致
+ hostId = 0;
+ regBasePhy = 0x10100000;
+ irqNum = 96;
+ devType = 0; // emmc类型
+ caps = 0xd001e045;
+ caps2 = 0x60;
+ }
+ controller_0x100f0000 :: mmc_controller {
+ match_attr = "hi3516_mmc_sd";
+ hostId = 1;
+ regBasePhy = 0x100f0000;
+ irqNum = 62;
+ devType = 1; // sd类型
+ caps = 0xd001e005;
+ }
+ controller_0x10020000 :: mmc_controller {
+ match_attr = "hi3516_mmc_sdio";
+ hostId = 2;
+ regBasePhy = 0x10020000;
+ irqNum = 63;
+ devType = 2; // sdio类型
+ caps = 0x0001e04d;
+ }
+ }
+ }
+ }
+ ```
+
+3. 完成驱动入口注册之后,最后一步就是以核心层MmcCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化MmcCntlr成员MmcCntlrOps(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
+ - 自定义结构体参考。
+
+ 从驱动的角度看,自定义结构体是参数和数据的载体,而且mmc\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员 ,一些重要数值也会传递给核心层对象。
+
+ ```
+ struct HimciHost {
+ struct MmcCntlr *mmc;//【必要】核心层结构体
+ struct MmcCmd *cmd; //【必要】核心层结构体,传递命令的,相关命令见枚举量 MmcCmdCode
+ //【可选】根据厂商驱动需要添加
+ void *base;
+ enum HimciPowerStatus powerStatus;
+ uint8_t *alignedBuff;
+ uint32_t buffLen;
+ struct scatterlist dmaSg;
+ struct scatterlist *sg;
+ uint32_t dmaSgNum;
+ DMA_ADDR_T dmaPaddr;
+ uint32_t *dmaVaddr;
+ uint32_t irqNum;
+ bool isTuning;
+ uint32_t id;
+ struct OsalMutex mutex;
+ bool waitForEvent;
+ HIMCI_EVENT himciEvent;
+ };
+ //MmcCntlr是核心层控制器结构体,其中的成员在bind函数中会被赋值
+ struct MmcCntlr {
+ struct IDeviceIoService service;
+ struct HdfDeviceObject *hdfDevObj;
+ struct PlatformDevice device;
+ struct OsalMutex mutex;
+ struct OsalSem released;
+ uint32_t devType;
+ struct MmcDevice *curDev;
+ struct MmcCntlrOps *ops;
+ struct PlatformQueue *msgQueue;
+ uint16_t index;
+ uint16_t voltDef;
+ uint32_t vddBit;
+ uint32_t freqMin;
+ uint32_t freqMax;
+ uint32_t freqDef;
+ union MmcOcr ocrDef;
+ union MmcCaps caps;
+ union MmcCaps2 caps2;
+ uint32_t maxBlkNum;
+ uint32_t maxBlkSize;
+ uint32_t maxReqSize;
+ bool devPluged;
+ bool detecting;
+ void *priv;
+ };
+ ```
+
+ - MmcCntlr成员回调函数结构体MmcCntlrOps的实例化,其他成员在Bind函数中初始化。
+
+ ```
+ static struct MmcCntlrOps g_himciHostOps = {
+ .request = HimciDoRequest,
+ .setClock = HimciSetClock,
+ .setPowerMode = HimciSetPowerMode,
+ .setBusWidth = HimciSetBusWidth,
+ .setBusTiming = HimciSetBusTiming,
+ .setSdioIrq = HimciSetSdioIrq,
+ .hardwareReset = HimciHardwareReset,
+ .systemInit = HimciSystemInit,
+ .setEnhanceSrobe= HimciSetEnhanceSrobe,
+ .switchVoltage = HimciSwitchVoltage,
+ .devReadOnly = HimciDevReadOnly,
+ .devPluged = HimciCardPluged,
+ .devBusy = HimciDevBusy,
+ .tune = HimciTune,
+ .rescanSdioDev = HimciRescanSdioDev,
+ };
+ ```
+
+ - Bind函数参考
+
+ 入参**:**
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。
+
+
+ 状态(值)
+ |
+ 问题描述
+ |
+
+
+ HDF_ERR_INVALID_OBJECT
+ |
+ 控制器对象非法
+ |
+
+ HDF_ERR_MALLOC_FAIL
+ |
+ 内存分配失败
+ |
+
+ HDF_ERR_INVALID_PARAM
+ |
+ 参数非法
+ |
+
+ HDF_ERR_IO
+ |
+ I/O 错误
+ |
+
+ HDF_SUCCESS
+ |
+ 初始化成功
+ |
+
+ HDF_FAILURE
+ |
+ 初始化失败
+ |
+
+
+
+
+ 函数说明:
+
+ MmcCntlr,HimciHost,HdfDeviceObject之间互相赋值,方便其他函数可以相互转化,初始化自定义结构体HimciHost对象,初始化MmcCntlr成员,调用核心层MmcCntlrAdd函数。
+
+ ```
+ static int32_t HimciMmcBind(struct HdfDeviceObject *obj)
+ {
+ struct MmcCntlr *cntlr = NULL;
+ struct HimciHost *host = NULL;
+ int32_t ret;
+ cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr));
+ host = (struct HimciHost *)OsalMemCalloc(sizeof(struct HimciHost));
+
+ host->mmc = cntlr; //【必要】使HimciHost与MmcCntlr可以相互转化的前提
+ cntlr->priv = (void *)host; //【必要】使HimciHost与MmcCntlr可以相互转化的前提
+ cntlr->ops = &g_himciHostOps; //【必要】MmcCntlrOps的实例化对象的挂载
+ cntlr->hdfDevObj = obj; //【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提
+ obj->service = &cntlr->service; //【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提
+ ret = MmcCntlrParse(cntlr, obj); //【必要】 初始化 cntlr. 失败就 goto _ERR;
+ ...
+ ret = HimciHostParse(host, obj); //【必要】 初始化 host对象的相关属性,失败就 goto _ERR;
+ ...
+ ret = HimciHostInit(host, cntlr);//厂商自定义的初始化,失败就 goto _ERR;
+ ...
+ ret = MmcCntlrAdd(cntlr); //调用核心层函数 失败就 goto _ERR;
+ ...
+ (void)MmcCntlrAddDetectMsgToQueue(cntlr);//将卡检测消息添加到队列中。
+ HDF_LOGD("HimciMmcBind: success.");
+ return HDF_SUCCESS;
+ _ERR:
+ HimciDeleteHost(host);
+ HDF_LOGD("HimciMmcBind: fail, err = %d.", ret);
+ return ret;
+ }
+ ```
+
+ - Init函数参考
+
+ 入参:
+
+ HdfDeviceObject是整个驱动对外暴露的接口参数,具备HCS配置文件的信息。
+
+ 返回值:
+
+ HDF\_STATUS相关状态。
+
+ 函数说明:
+
+ 实现ProcMciInit。
+
+ ```
+ static int32_t HimciMmcInit(struct HdfDeviceObject *obj)
+ {
+ static bool procInit = false;
+ (void)obj;
+ if (procInit == false) {
+ if (ProcMciInit() == HDF_SUCCESS) {
+ procInit = true;
+ HDF_LOGD("HimciMmcInit: proc init success.");
+ }
+ }
+ HDF_LOGD("HimciMmcInit: success.");
+ return HDF_SUCCESS;
+ }
+ ```
+
+ - Release函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ 无。
+
+ 函数说明:
+
+ 释放内存和删除控制器等操作,该函数需要在驱动入口结构体中赋值给Release接口,当HDF框架调用Init函数初始化驱动失败时,可以调用 Release释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
+
+ ```
+ static void HimciMmcRelease(struct HdfDeviceObject *obj)
+ {
+ struct MmcCntlr *cntlr = NULL;
+ ...
+ cntlr = (struct MmcCntlr *)obj->service;//这里有HdfDeviceObject到MmcCntlr的强制转化,通过service成员,赋值见Bind函数
+ ...
+ HimciDeleteHost((struct HimciHost *)cntlr->priv);//厂商自定义的内存释放函数,这里有MmcCntlr到HimciHost的强制转化
+ }
+ ```
+
+
+
diff --git a/zh-cn/device-dev/driver/driver-platform-pwm-des.md b/zh-cn/device-dev/driver/driver-platform-pwm-des.md
new file mode 100644
index 0000000000000000000000000000000000000000..80d67a89dc0e6f067a30829dc8fd953d8cef2042
--- /dev/null
+++ b/zh-cn/device-dev/driver/driver-platform-pwm-des.md
@@ -0,0 +1,579 @@
+# PWM
+
+- [概述](#section1043395117296)
+- [接口说明](#section3939192652418)
+- [使用指导](#section435718267334)
+ - [使用流程](#section113655616347)
+ - [获取PWM设备句柄](#section17816586359)
+ - [设置PWM周期](#section920214812397)
+ - [设置PWM占空比](#section519712820405)
+ - [设置PWM极性](#section12383334115)
+ - [使能PWM](#section382684811414)
+ - [禁用PWM](#section16545114404218)
+ - [获取PWM设备配置信息](#section117101243144311)
+ - [设置PWM设备配置信息](#section13834163604414)
+ - [释放PWM设备句柄](#section12987111511450)
+
+- [使用实例](#section138636719469)
+
+## 概述
+
+PWM是脉冲宽度调制(Pulse Width Modulation)的缩写,是一种对模拟信号电平进行数字编码并将其转换为脉冲的技术。常用于马达控制、背光亮度调节等。
+
+PWM接口定义了操作PWM设备的通用方法集合,包括:
+
+- PWM设备句柄获取和释放。
+- PWM周期、占空比、极性的设置。
+- PWM使能和关闭。
+- PWM配置信息的获取和设置
+
+## 接口说明
+
+**表 1** PWM驱动API接口功能介绍
+
+
+功能分类
+ |
+接口名
+ |
+描述
+ |
+
+
+PWM设备句柄获取和释放
+ |
+PwmOpen
+ |
+获取PWM设备句柄
+ |
+
+PwmClose
+ |
+释放PWM设备句柄
+ |
+
+PWM周期、占空比、极性的设置
+ |
+PwmSetPeriod
+ |
+设置PWM周期
+ |
+
+PwmSetDuty
+ |
+设置PWM占空比
+ |
+
+PwmSetPolarity
+ |
+设置PWM极性
+ |
+
+PWM使能和关闭
+ |
+PwmEnable
+ |
+使能PWM
+ |
+
+PwmDisable
+ |
+禁用PWM
+ |
+
+PWM配置信息的获取和设置
+
+ |
+PwmSetConfig
+ |
+设置PWM设备配置信息
+ |
+
+PwmGetConfig
+ |
+获取PWM设备配置信息
+ |
+
+
+
+
+> **说明:**
+>本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。
+
+## 使用指导
+
+### 使用流程
+
+使用PWM的一般流程如[图1](#fig23885455594)所示。
+
+**图 1** PWM使用流程图
+
+
+
+
+### 获取PWM设备句柄
+
+在操作PWM设备时,首先要调用PwmOpen获取PWM设备句柄,该函数会返回指定设备号的PWM设备句柄。
+
+DevHandle PwmOpen\(uint32\_t num\);
+
+**表 2** PwmOpen参数和返回值描述
+
+
+参数
+ |
+参数描述
+ |
+
+num
+ |
+PWM设备号
+ |
+
+返回值
+ |
+返回值描述
+ |
+
+NULL
+ |
+获取PWM设备句柄失败
+ |
+
+设备句柄
+ |
+对应的PWM设备句柄
+ |
+
+
+
+
+假设系统中的PWM设备号为0,获取该PWM设备句柄的示例如下:
+
+```
+uint32_t num = 0; /* PWM设备号 */
+DevHandle pwm = NULL; /* PWM设备句柄 /
+
+/* 获取PWM设备句柄 */
+pwm = PwmOpen(num);
+if (pwm == NULL) {
+ HDF_LOGE("PwmOpen: pwm%d failed", num);
+ return;
+}
+```
+
+### 设置PWM周期
+
+int32\_t PwmSetPeriod\(DevHandle handle, uint32\_t period\);
+
+**表 3** PwmSetPeriod参数和返回值描述
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+PWM设备句柄
+ |
+
+period
+ |
+周期,单位纳秒
+ |
+
+返回值
+ |
+返回值描述
+ |
+
+0
+ |
+设置周期成功
+ |
+
+负数
+ |
+设置周期失败
+ |
+
+
+
+
+```
+int32_t ret;
+uint32_t period = 1000; /* 周期1000纳秒 */
+ret = PwmSetPeriod(pwm, period); /* 设置PWM周期 */
+if (ret != 0) {
+ HDF_LOGE("PwmSetPeriod: failed, ret %d", ret);
+}
+```
+
+### 设置PWM占空比
+
+int32\_t PwmSetDuty\(DevHandle handle, uint32\_t duty\);
+
+**表 4** PwmSetDuty参数和返回值描述
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+PWM设备句柄
+ |
+
+duty
+ |
+占空比,单位纳秒
+ |
+
+返回值
+ |
+返回值描述
+ |
+
+0
+ |
+设置占空比成功
+ |
+
+负数
+ |
+设置占空比失败
+ |
+
+
+
+
+```
+int32_t ret;
+uint32_t duty = 500; /* 占空比500纳秒 */
+ret = PwmSetDuty(pwm, duty); /* 设置PWM占空比 */
+if (ret != 0) {
+ HDF_LOGE("PwmSetDuty: failed, ret %d", ret);
+}
+```
+
+### 设置PWM极性
+
+int32\_t PwmSetPolarity\(DevHandle handle, uint8\_t polarity\);
+
+**表 5** PwmSetPolarity参数和返回值描述
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+PWM设备句柄
+ |
+
+polarity
+ |
+极性,PWM_NORMAL_POLARITY为正常极性,PWM_INVERTED_POLARITY为反转极性。
+ |
+
+返回值
+ |
+返回值描述
+ |
+
+0
+ |
+设置极性成功
+ |
+
+负数
+ |
+设置极性失败
+ |
+
+
+
+
+```
+int32_t ret;
+uint8_t polarity = PWM_INVERTED_POLARITY; /* 反转极性 */
+ret = PwmSetPolarity(pwm, polarity); /* 设置PWM反转极性 */
+if (ret != 0) {
+ HDF_LOGE("PwmSetPolarity: failed, ret %d", ret);
+}
+```
+
+### 使能PWM
+
+int32\_t PwmEnable\(DevHandle handle\);
+
+**表 6** PwmEnable参数和返回值描述
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+PWM设备句柄
+ |
+
+返回值
+ |
+返回值描述
+ |
+
+0
+ |
+使能PWM成功
+ |
+
+负数
+ |
+使能PWM失败
+ |
+
+
+
+
+```
+int32_t ret;
+ret = PwmEnable(pwm); /* 使能PWM */
+if (ret != 0) {
+ HDF_LOGE("PwmEnable: failed, ret %d", ret);
+}
+```
+
+### 禁用PWM
+
+int32\_t PwmDisable\(DevHandle handle\);
+
+**表 7** PwmDisable参数和返回值描述
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+PWM设备句柄
+ |
+
+返回值
+ |
+返回值描述
+ |
+
+0
+ |
+关闭PWM成功
+ |
+
+负数
+ |
+关闭PWM失败
+ |
+
+
+
+
+```
+int32_t ret;
+ret = PwmDisable(pwm); /* 禁用PWM */
+if (ret != 0) {
+ HDF_LOGE("PwmDisable: failed, ret %d", ret);
+}
+```
+
+### 获取PWM设备配置信息
+
+int32\_t PwmGetConfig\(DevHandle handle, struct PwmConfig \*config\);
+
+**表 8** PwmGetConfig参数和返回值描述
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+PWM设备句柄
+ |
+
+config
+ |
+PWM设备配置信息
+ |
+
+返回值
+ |
+返回值描述
+ |
+
+0
+ |
+获取配置成功
+ |
+
+负数
+ |
+获取配置失败
+ |
+
+
+
+
+```
+int32_t ret;
+struct PwmConfig config= {0}; /* PWM配置信息 */
+ret = PwmGetConfig(pwm, &config); /* 获取PWM设备配置信息 */
+if (ret != 0) {
+ HDF_LOGE("PwmGetConfig: failed, ret %d", ret);
+}
+```
+
+### 设置PWM设备配置信息
+
+int32\_t PwmSetConfig\(DevHandle handle, struct PwmConfig \*config\);
+
+**表 9** PwmSetConfig参数和返回值描述
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+PWM设备句柄
+ |
+
+config
+ |
+PWM设备配置信息
+ |
+
+返回值
+ |
+返回值描述
+ |
+
+0
+ |
+设置配置成功
+ |
+
+负数
+ |
+设置配置失败
+ |
+
+
+
+
+```
+int32_t ret;
+struct PwmConfig config= {0}; /* PWM配置信息 */
+config.duty = 500; /* 占空比500纳秒 */
+config.period = 1000; /* 周期1000纳秒 */
+config.number = 0; /* 一直输出方波 */
+config.polarity = PWM_NORMAL_POLARITY; /* 正常极性 */
+ret = PwmSetConfig(pwm, &config); /* 设置PWM设备配置信息 */
+if (ret != 0) {
+ HDF_LOGE("PwmSetConfig: failed, ret %d\n", ret);
+}
+```
+
+### 释放PWM设备句柄
+
+void PwmClose\(DevHandle handle\);
+
+该函数会释放掉由PwmClose申请的资源。
+
+**表 10** PwmClose参数描述
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+PWM设备句柄
+ |
+
+
+
+
+```
+PwmClose(pwm); /* 释放PWM设备句柄 */
+```
+
+## 使用实例
+
+PWM设备完整的使用示例如下所示,首先获取PWM设备句柄,然后设置PWM设备配置信息,使能PWM,最后释放PWM设备句柄。
+
+```
+#include "hdf_log.h"
+#include "osal_time.h"
+#include "pwm_if.h"
+
+void PwmTestSample(void)
+{
+ int32_t ret;
+ struct PwmConfig config; /* PWM配置信息 */
+ DevHandle pwm = NULL; /* PWM设备句柄 */
+
+ pwm = PwmOpen(0); /* 获取PWM设备句柄 */
+ if (pwm == NULL) {
+ HDF_LOGE("PwmOpen: pwm0 failed");
+ return;
+ }
+ /* 获取PWM设备配置信息 */
+ ret = PwmGetConfig(pwm, &config);
+ if (ret != 0) {
+ HDF_LOGE("PwmGetConfig: failed, ret %d\n", ret);
+ goto err;
+ }
+ config.duty = 500; /* 占空比500纳秒 */
+ config.period = 1000; /* 周期1000纳秒 */
+ /* 设置PWM设备配置信息 */
+ ret = PwmSetConfig(pwm, &config);
+ if (ret != 0) {
+ HDF_LOGE("PwmSetConfig: failed, ret %d\n", ret);
+ goto err;
+ }
+ /* 使能PWM */
+ ret = PwmEnable(pwm);
+ if (ret != 0) {
+ HDF_LOGE("PwmEnable: failed, ret %d\n", ret);
+ goto err;
+ }
+ /* 睡眠10秒 */
+ OsalSleep(10);
+ /* 禁用PWM */
+ ret = PwmDisable(pwm);
+ if (ret != 0) {
+ HDF_LOGE("PwmDisable: failed, ret %d\n", ret);
+ goto err;
+ }
+err:
+ /* 释放PWM设备句柄 */
+ PwmClose(pwm);
+}
+```
+
diff --git a/zh-cn/device-dev/driver/driver-platform-pwm-develop.md b/zh-cn/device-dev/driver/driver-platform-pwm-develop.md
index dd2e846b7809d31d3e8777b2026426c092c16f7a..123d12aee05a96359f76da4a2cd2f0691ae9b8df 100755
--- a/zh-cn/device-dev/driver/driver-platform-pwm-develop.md
+++ b/zh-cn/device-dev/driver/driver-platform-pwm-develop.md
@@ -1,275 +1,351 @@
-# PWM
-
-- [概述](#1)
-- [开发步骤](#2)
-- [开发实例](#3)
-
-## 概述
-
-PWM(Pulse Width Modulator)即脉冲宽度调节器,在HDF框架中,PWM的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。
-
-独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
-
-图 1 独立服务模式结构图
-
-
-## 开发步骤
-
-PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及填充核心层接口函数。
-
-1. **实例化驱动入口:**
- - 实例化HdfDriverEntry结构体成员。
- - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
-
-2. **配置属性文件:**
-
- - 在device_info.hcs文件中添加deviceNode描述。
- - 【可选】添加pwm_config.hcs器件属性文件。
-
-3. **实例化PWM控制器对象:**
-
- - 初始化PwmDev成员。
- - 实例化PwmDev成员PwmMethod,其定义和成员说明见下
-
-4. **驱动调试:**
- - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如PWM控制状态,中断响应情况等。
-
->  **说明:**
->
-> PwmMethod定义
-> ```c
-> struct PwmMethod {
-> int32_t (*setConfig)(struct PwmDev *pwm, struct PwmConfig *config);
-> int32_t (*open)(struct PwmDev *pwm);
-> int32_t (*close)(struct PwmDev *pwm);
-> };
-> ```
->
-> 表1 PwmMethod结构体成员的回调函数功能说明
-> |成员函数|入参|返回值|功能|
-> |-|-|-|-|
-> |setConfig|**pwm**: 结构体指针,核心层PWM控制器; **config**: 结构体指针,属性传入值;|HDF_STATUS相关状态|配置属性|
-> |open |**pwm**: 结构体指针,核心层PWM控制器;|HDF_STATUS相关状态|打开设备|
-> |close|**pwm**: 结构体指针,核心层PWM控制器;|HDF_STATUS相关状态|关闭设备|
-
-## 开发实例
-
-下方将以pwm_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
-
-1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
-
- 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
-
-- PWM驱动入口参考
-
- ```c
- struct HdfDriverEntry g_hdfPwm = {
- .moduleVersion = 1,
- .moduleName = "HDF_PLATFORM_PWM",//【必要 且与 HCS文件中里面的moduleName匹配】
- .Bind = HdfPwmBind,
- .Init = HdfPwmInit,
- .Release = HdfPwmRelease,
- };
- //调用HDF_INIT将驱动入口注册到HDF框架中
- HDF_INIT(g_hdfPwm);
- ```
-
-2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 pwm_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层PwmDev成员的默认值或限制范围有密切关系。
-
- **如有更多个器件信息,则需要在device_info文件增加deviceNode信息,以及在pwm_config文件中增加对应的器件属性**。
-
-- device_info.hcs 配置参考
-
- ```c
- root {
- device_info {
- platform :: host {
- hostName = "platform_host";
- priority = 50;
- device_pwm :: device {//为每一个 pwm 控制器配置一个HDF设备节点,存在多个时【必须】添加,否则不用
- device0 :: deviceNode {
- policy = 1; // 等于1,向内核态发布服务
- priority = 80; // 驱动启动优先级
- permission = 0644;// 驱动创建设备节点权限
- moduleName = "HDF_PLATFORM_PWM"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致;
- serviceName = "HDF_PLATFORM_PWM_0";//【必要且唯一】驱动对外发布服务的名称
- deviceMatchAttr = "hisilicon_hi35xx_pwm_0";//【必要】用于配置控制器私有数据,要与 pwm_config.hcs 中对应
- // 控制器保持一致,具体的控制器信息在 pwm_config.hcs 中
- }
- device1 :: deviceNode {
- policy = 1;
- priority = 80;
- permission = 0644;
- moduleName = "HDF_PLATFORM_PWM";
- serviceName = "HDF_PLATFORM_PWM_1";
- deviceMatchAttr = "hisilicon_hi35xx_pwm_1";
- }
- }
- }
- }
- }
- ```
-
-- pwm_config.hcs 配置参考
-
- ```c
- root {
- platform {
- pwm_config {
- template pwm_device { //【必要】模板配置,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省
- serviceName = "";
- match_attr = "";
- num = 0; //【必要】设备号
- base = 0x12070000; //【必要】地址映射需要
- }
- device_0x12070000 :: pwm_device {
- match_attr = "hisilicon_hi35xx_pwm_0";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致
- }
- device_0x12070020 :: pwm_device { //存在多个设备时【必须】添加,否则不用
- match_attr = "hisilicon_hi35xx_pwm_1";
- num = 1;
- base = 0x12070020; //【必要】地址映射需要
- }
- }
- }
- }
- ```
-
-3. 完成驱动入口注册之后,最后一步就是以核心层PwmDev对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化PwmDev成员PwmMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)
-
-- 自定义结构体参考
-
- > 从驱动的角度看,自定义结构体是参数和数据的载体,而且pwm_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号等。
-
- ```c
- struct HiPwm {
- struct PwmDev dev; //【必要】 核心层结构体
- volatile unsigned char *base;
- struct HiPwmRegs *reg; // 设备属性结构体,可自定义
- bool supportPolarity;
- };
-
- // PwmDev是核心层控制器结构体,其中的成员在Init函数中会被赋值
- struct PwmDev {
- struct IDeviceIoService service;
- struct HdfDeviceObject *device;
- struct PwmConfig cfg; //属性结构体,相关定义见下
- struct PwmMethod *method; //钩子函数模板
- bool busy;
- uint32_t num; //设备号
- OsalSpinlock lock;
- void *priv; //私有数据,一般存储自定义结构体首地址,方便调用
- };
- struct PwmConfig {
- uint32_t duty; // 占空时间 nanoseconds
- uint32_t period; // pwm 周期 nanoseconds
- uint32_t number; // pwm 连续个数
- uint8_t polarity; // Polarity
- // ------------------- | --------------
- // PWM_NORMAL_POLARITY | Normal polarity
- // PWM_INVERTED_POLARITY | Inverted polarity
- //
- uint8_t status; // 运行状态
- // ------------------ | -----------------
- // PWM_DISABLE_STATUS | Disabled
- // PWM_ENABLE_STATUS | Enabled
- };
- ```
-
-
-- **【重要】** PwmDev成员回调函数结构体PwmMethod的实例化,其他成员在Init函数中初始化
-
- ```c
- // pwm_hi35xx.c 中的示例:钩子函数的填充
- struct PwmMethod g_pwmOps = {
- .setConfig = HiPwmSetConfig,//配置属性
- };
- ```
-
-- **Init函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)
- >
- > |状态(值)|问题描述|
- > |:-|:-:|
- > |HDF_ERR_INVALID_OBJECT|控制器对象非法|
- > |HDF_ERR_MALLOC_FAIL |内存分配失败|
- > |HDF_ERR_INVALID_PARAM |参数非法|
- > |HDF_ERR_IO |I/O 错误|
- > |HDF_SUCCESS |初始化成功|
- > |HDF_FAILURE |初始化失败|
- >
- > **函数说明:**
- > 初始化自定义结构体对象,初始化PwmDev成员,调用核心层PwmDeviceAdd函数。
-
- ```c
- //此处bind函数为空函数,可与init函数结合,也可根据厂商需要实现相关操作
- static int32_t HdfPwmBind(struct HdfDeviceObject *obj)
- {
- (void)obj;
- return HDF_SUCCESS;
- }
-
- static int32_t HdfPwmInit(struct HdfDeviceObject *obj)
- {
- int ret;
- struct HiPwm *hp = NULL;
- ...
- hp = (struct HiPwm *)OsalMemCalloc(sizeof(*hp));
- ...
- ret = HiPwmProbe(hp, obj); //【必要】实现见下
- ...
- return ret;
- }
-
- static int32_t HiPwmProbe(struct HiPwm *hp, struct HdfDeviceObject *obj)
- {
- uint32_t tmp;
- struct DeviceResourceIface *iface = NULL;
-
- iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);//初始化自定义结构体HiPwm
- ...
-
- hp->reg = (struct HiPwmRegs *)hp->base; //初始化自定义结构体HiPwm
- hp->supportPolarity = false; //初始化自定义结构体HiPwm
- hp->dev.method = &g_pwmOps; //PwmMethod的实例化对象的挂载
- hp->dev.cfg.duty = PWM_DEFAULT_DUTY_CYCLE; //初始化PwmDev
- hp->dev.cfg.period = PWM_DEFAULT_PERIOD; //初始化PwmDev
- hp->dev.cfg.polarity = PWM_DEFAULT_POLARITY; //初始化PwmDev
- hp->dev.cfg.status = PWM_DISABLE_STATUS; //初始化PwmDev
- hp->dev.cfg.number = 0; //初始化PwmDev
- hp->dev.busy = false; //初始化PwmDev
- if (PwmDeviceAdd(obj, &(hp->dev)) != HDF_SUCCESS) {//【重要】调用核心层函数,初始化hp->dev 的设备和服务
- OsalIoUnmap((void *)hp->base);
- return HDF_FAILURE;
- }
- return HDF_SUCCESS;
- }
- ```
-
-- **Release 函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > 无
- >
- > **函数说明:**
- > 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。
-
- ```c
- static void HdfPwmRelease(struct HdfDeviceObject *obj)
- {
- struct HiPwm *hp = NULL;
- ...
- hp = (struct HiPwm *)obj->service;//这里有HdfDeviceObject到HiPwm的强制转化
- ...
- PwmDeviceRemove(obj, &(hp->dev));//【必要】调用核心层函数,释放PwmDev的设备和服务,这里有HiPwm到PwmDev的强制转化
- HiPwmRemove(hp); //释放HiPwm
- }
- ```
\ No newline at end of file
+# PWM
+
+- [概述](#section1591602238164144)
+- [接口说明](#section752964871810)
+- [开发步骤](#section967396342164144)
+- [开发实例](#section1883877829164144)
+
+## 概述
+
+PWM(Pulse Width Modulator)即脉冲宽度调节器,在HDF框架中,PWM的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
+
+**图 1** PWM独立服务模式结构图
+
+
+## 接口说明
+
+PwmMethod定义:
+
+```
+struct PwmMethod {
+ int32_t (*setConfig)(struct PwmDev *pwm, struct PwmConfig *config);
+ int32_t (*open)(struct PwmDev *pwm);
+ int32_t (*close)(struct PwmDev *pwm);
+};
+```
+
+**表 1** PwmMethod结构体成员的回调函数功能说明
+
+
+成员函数
+ |
+入参
+ |
+返回值
+ |
+功能
+ |
+
+
+setConfig
+ |
+pwm: 结构体指针,核心层PWM控制器;
+config: 结构体指针,属性传入值;
+ |
+HDF_STATUS相关状态
+ |
+配置属性
+ |
+
+open
+ |
+pwm: 结构体指针,核心层PWM控制器;
+ |
+HDF_STATUS相关状态
+ |
+打开设备
+ |
+
+close
+ |
+pwm: 结构体指针,核心层PWM控制器;
+ |
+HDF_STATUS相关状态
+ |
+关闭设备
+ |
+
+
+
+
+## 开发步骤
+
+PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及填充核心层接口函数。
+
+1. **实例化驱动入口:**
+ - 实例化HdfDriverEntry结构体成员。
+ - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
+
+2. **配置属性文件:**
+ - 在device\_info.hcs文件中添加deviceNode描述。
+ - 【可选】添加pwm\_config.hcs器件属性文件。
+
+3. **实例化PWM控制器对象:**
+ - 初始化PwmDev成员。
+ - 实例化PwmDev成员PwmMethod。
+
+ > **说明:**
+ >实例化PwmDev成员PwmMethod,其定义和成员说明见[接口说明](#section752964871810)。
+
+
+4. **驱动调试:**
+
+ 【可选】针对新增驱动程序,建议验证驱动基本功能,例如PWM控制状态,中断响应情况等。
+
+
+## 开发实例
+
+下方将以pwm\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
+
+1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
+
+ 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
+
+ PWM驱动入口参考
+
+ ```
+ struct HdfDriverEntry g_hdfPwm = {
+ .moduleVersion = 1,
+ .moduleName = "HDF_PLATFORM_PWM",//【必要 且与 HCS文件中里面的moduleName匹配】
+ .Bind = HdfPwmBind,
+ .Init = HdfPwmInit,
+ .Release = HdfPwmRelease,
+ };
+ //调用HDF_INIT将驱动入口注册到HDF框架中
+ HDF_INIT(g_hdfPwm);
+ ```
+
+2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 pwm\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层PwmDev成员的默认值或限制范围有密切关系。 如有更多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在pwm\_config文件中增加对应的器件属性**。**
+ - device\_info.hcs 配置参考。
+
+ ```
+ root {
+ device_info {
+ platform :: host {
+ hostName = "platform_host";
+ priority = 50;
+ device_pwm :: device {//为每一个 pwm 控制器配置一个HDF设备节点,存在多个时【必须】添加,否则不用
+ device0 :: deviceNode {
+ policy = 1; // 等于1,向内核态发布服务
+ priority = 80; // 驱动启动优先级
+ permission = 0644;// 驱动创建设备节点权限
+ moduleName = "HDF_PLATFORM_PWM"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致;
+ serviceName = "HDF_PLATFORM_PWM_0";//【必要且唯一】驱动对外发布服务的名称
+ deviceMatchAttr = "hisilicon_hi35xx_pwm_0";//【必要】用于配置控制器私有数据,要与 pwm_config.hcs 中对应
+ // 控制器保持一致,具体的控制器信息在 pwm_config.hcs 中
+ }
+ device1 :: deviceNode {
+ policy = 1;
+ priority = 80;
+ permission = 0644;
+ moduleName = "HDF_PLATFORM_PWM";
+ serviceName = "HDF_PLATFORM_PWM_1";
+ deviceMatchAttr = "hisilicon_hi35xx_pwm_1";
+ }
+ }
+ }
+ }
+ }
+ ```
+
+ - pwm\_config.hcs 配置参考。
+
+ ```
+ root {
+ platform {
+ pwm_config {
+ template pwm_device { //【必要】模板配置,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省
+ serviceName = "";
+ match_attr = "";
+ num = 0; //【必要】设备号
+ base = 0x12070000; //【必要】地址映射需要
+ }
+ device_0x12070000 :: pwm_device {
+ match_attr = "hisilicon_hi35xx_pwm_0";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致
+ }
+ device_0x12070020 :: pwm_device { //存在多个设备时【必须】添加,否则不用
+ match_attr = "hisilicon_hi35xx_pwm_1";
+ num = 1;
+ base = 0x12070020; //【必要】地址映射需要
+ }
+ }
+ }
+ }
+ ```
+
+3. 完成驱动入口注册之后,最后一步就是以核心层PwmDev对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化PwmDev成员PwmMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
+ - 自定义结构体参考。
+
+ 从驱动的角度看,自定义结构体是参数和数据的载体,而且pwm\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号等。
+
+ ```
+ struct HiPwm {
+ struct PwmDev dev; //【必要】 核心层结构体
+ volatile unsigned char *base;
+ struct HiPwmRegs *reg; // 设备属性结构体,可自定义
+ bool supportPolarity;
+ };
+
+ // PwmDev是核心层控制器结构体,其中的成员在Init函数中会被赋值
+ struct PwmDev {
+ struct IDeviceIoService service;
+ struct HdfDeviceObject *device;
+ struct PwmConfig cfg; //属性结构体,相关定义见下
+ struct PwmMethod *method; //钩子函数模板
+ bool busy;
+ uint32_t num; //设备号
+ OsalSpinlock lock;
+ void *priv; //私有数据,一般存储自定义结构体首地址,方便调用
+ };
+ struct PwmConfig {
+ uint32_t duty; // 占空时间 nanoseconds
+ uint32_t period; // pwm 周期 nanoseconds
+ uint32_t number; // pwm 连续个数
+ uint8_t polarity; // Polarity
+ // ------------------- | --------------
+ // PWM_NORMAL_POLARITY | Normal polarity
+ // PWM_INVERTED_POLARITY | Inverted polarity
+ //
+ uint8_t status; // 运行状态
+ // ------------------ | -----------------
+ // PWM_DISABLE_STATUS | Disabled
+ // PWM_ENABLE_STATUS | Enabled
+ };
+ ```
+
+ - PwmDev成员回调函数结构体PwmMethod的实例化,其他成员在Init函数中初始化。
+
+ ```
+ // pwm_hi35xx.c 中的示例:钩子函数的填充
+ struct PwmMethod g_pwmOps = {
+ .setConfig = HiPwmSetConfig,//配置属性
+ };
+ ```
+
+ - Init函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。
+
+
+ 状态(值)
+ |
+ 问题描述
+ |
+
+
+ HDF_ERR_INVALID_OBJECT
+ |
+ 控制器对象非法
+ |
+
+ HDF_ERR_MALLOC_FAIL
+ |
+ 内存分配失败
+ |
+
+ HDF_ERR_INVALID_PARAM
+ |
+ 参数非法
+ |
+
+ HDF_ERR_IO
+ |
+ I/O 错误
+ |
+
+ HDF_SUCCESS
+ |
+ 初始化成功
+ |
+
+ HDF_FAILURE
+ |
+ 初始化失败
+ |
+
+
+
+
+ 函数说明:
+
+ 初始化自定义结构体对象,初始化PwmDev成员,调用核心层PwmDeviceAdd函数。
+
+ ```
+ //此处bind函数为空函数,可与init函数结合,也可根据厂商需要实现相关操作
+ static int32_t HdfPwmBind(struct HdfDeviceObject *obj)
+ {
+ (void)obj;
+ return HDF_SUCCESS;
+ }
+
+ static int32_t HdfPwmInit(struct HdfDeviceObject *obj)
+ {
+ int ret;
+ struct HiPwm *hp = NULL;
+ ...
+ hp = (struct HiPwm *)OsalMemCalloc(sizeof(*hp));
+ ...
+ ret = HiPwmProbe(hp, obj); //【必要】实现见下
+ ...
+ return ret;
+ }
+
+ static int32_t HiPwmProbe(struct HiPwm *hp, struct HdfDeviceObject *obj)
+ {
+ uint32_t tmp;
+ struct DeviceResourceIface *iface = NULL;
+
+ iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);//初始化自定义结构体HiPwm
+ ...
+
+ hp->reg = (struct HiPwmRegs *)hp->base; //初始化自定义结构体HiPwm
+ hp->supportPolarity = false; //初始化自定义结构体HiPwm
+ hp->dev.method = &g_pwmOps; //PwmMethod的实例化对象的挂载
+ hp->dev.cfg.duty = PWM_DEFAULT_DUTY_CYCLE; //初始化PwmDev
+ hp->dev.cfg.period = PWM_DEFAULT_PERIOD; //初始化PwmDev
+ hp->dev.cfg.polarity = PWM_DEFAULT_POLARITY; //初始化PwmDev
+ hp->dev.cfg.status = PWM_DISABLE_STATUS; //初始化PwmDev
+ hp->dev.cfg.number = 0; //初始化PwmDev
+ hp->dev.busy = false; //初始化PwmDev
+ if (PwmDeviceAdd(obj, &(hp->dev)) != HDF_SUCCESS) {//【重要】调用核心层函数,初始化hp->dev 的设备和服务
+ OsalIoUnmap((void *)hp->base);
+ return HDF_FAILURE;
+ }
+ return HDF_SUCCESS;
+ }
+ ```
+
+ - Release 函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ 无。
+
+ 函数说明:
+
+ 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。
+
+ ```
+ static void HdfPwmRelease(struct HdfDeviceObject *obj)
+ {
+ struct HiPwm *hp = NULL;
+ ...
+ hp = (struct HiPwm *)obj->service;//这里有HdfDeviceObject到HiPwm的强制转化
+ ...
+ PwmDeviceRemove(obj, &(hp->dev));//【必要】调用核心层函数,释放PwmDev的设备和服务,这里有HiPwm到PwmDev的强制转化
+ HiPwmRemove(hp); //释放HiPwm
+ }
+ ```
+
+
+
diff --git a/zh-cn/device-dev/driver/driver-platform-rtc-des.md b/zh-cn/device-dev/driver/driver-platform-rtc-des.md
index fb55001feb78e4e003f25a829f51539e4893d310..521a9ceefe94cfbb6dfb3870867b800b68fbdcb0 100644
--- a/zh-cn/device-dev/driver/driver-platform-rtc-des.md
+++ b/zh-cn/device-dev/driver/driver-platform-rtc-des.md
@@ -1,8 +1,7 @@
-# RTC
+# RTC
- [概述](#section104842041574)
- - [接口说明](#section3373340142215)
-
+- [接口说明](#section20331159102519)
- [使用指导](#section20636145604113)
- [使用流程](#section16919828134215)
- [创建RTC设备句柄](#section1131212144310)
@@ -16,7 +15,7 @@
RTC\(real-time clock\)为操作系统中的实时时钟设备,为操作系统提供精准的实时时间和定时报警功能。当设备下电后,通过外置电池供电,RTC继续记录操作系统时间;设备上电后,RTC提供实时时钟给操作系统,确保断电后系统时间的连续性。
-### 接口说明
+## 接口说明
**表 1** RTC设备API接口功能介绍
@@ -116,12 +115,10 @@ RTC\(real-time clock\)为操作系统中的实时时钟设备,为操作系统
在操作系统启动过程中,驱动管理模块根据配置文件加载RTC驱动,RTC驱动会检测RTC器件并初始化驱动。
-使用RTC设备的一般流程如[图1](#fig166181128151112)所示。
-
-**图 1** RTC设备使用流程图
-
+使用RTC设备的一般流程如[图1](#fig1610020107333)所示。
-
+**图 1** RTC设备使用流程图
+
### 创建RTC设备句柄
diff --git a/zh-cn/device-dev/driver/driver-platform-rtc-develop.md b/zh-cn/device-dev/driver/driver-platform-rtc-develop.md
index ed31512235c1824e98cc594ede3027bdd0aca0c0..6a72063974617e607f0f69dd8fdf7888e434bf4c 100755
--- a/zh-cn/device-dev/driver/driver-platform-rtc-develop.md
+++ b/zh-cn/device-dev/driver/driver-platform-rtc-develop.md
@@ -1,295 +1,461 @@
-# RTC
-
-- [概述](#1)
-- [开发步骤](#2)
-- [开发实例](#3)
-
-## 概述
-
-RTC(real-time clock)为操作系统中的实时时钟设备,在HDF框架中,RTC的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。
-
-独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
-
-图 1 独立服务模式结构图
-
-
-## 开发步骤
-
-RTC模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及填充核心层接口函数。
-
-
-1. **实例化驱动入口:**
- - 实例化HdfDriverEntry结构体成员。
- - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
-
-2. **配置属性文件:**
-
- - 在device_info.hcs文件中添加deviceNode描述。
- - 【可选】添加rtc_config.hcs器件属性文件。
-
-3. **实例化RTC控制器对象:**
-
- - 初始化RtcHost成员。
- - 实例化RtcHost成员RtcMethod,其定义和成员说明见下
-
-4. **驱动调试:**
- - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如RTC控制状态,中断响应情况等。
-
->  **说明:**
->
-> RtcMethod定义
->
-> ```c
-> struct RtcMethod {
-> int32_t (*ReadTime)(struct RtcHost *host, struct RtcTime *time);
-> int32_t (*WriteTime)(struct RtcHost *host, const struct RtcTime *time);
-> int32_t (*ReadAlarm)(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, struct RtcTime *time);
-> int32_t (*WriteAlarm)(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, const struct RtcTime *time);
-> int32_t (*RegisterAlarmCallback)(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, RtcAlarmCallback cb);
-> int32_t (*AlarmInterruptEnable)(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, uint8_t enable);
-> int32_t (*GetFreq)(struct RtcHost *host, uint32_t *freq);
-> int32_t (*SetFreq)(struct RtcHost *host, uint32_t freq);
-> int32_t (*Reset)(struct RtcHost *host);
-> int32_t (*ReadReg)(struct RtcHost *host, uint8_t usrDefIndex, uint8_t *value);
-> int32_t (*WriteReg)(struct RtcHost *host, uint8_t usrDefIndex, uint8_t value);
-> };
-> ```
->
-> 表1 RtcMethod结构体成员的回调函数功能说明
->
-> |函数|入参|出参|返回值|功能|
-> |-|-|-|-|-|
-> |ReadTime |**host**: 结构体指针,核心层RTC控制器 ; |**time**: 结构体指针, 传出的时间值; |HDF_STATUS相关状态| 读RTC时间信息 |
-> |WriteTime |**host**: 结构体指针,核心层RTC控制器 ; **time**: 结构体指针,时间传入值; |无 |HDF_STATUS相关状态| 写RTC时间信息(包括毫秒~年) |
-> |ReadAlarm |**host**: 结构体指针,核心层RTC控制器 ; **alarmIndex**: 枚举值,闹钟报警索引 ;|**time**: 结构体指针, 传出的时间值;|HDF_STATUS相关状态| 读RTC报警时间信息 |
-> |WriteAlarm |**host**: 结构体指针,核心层RTC控制器 ; **alarmIndex**: 枚举值,闹钟报警索引 ; **time**: 结构体指针,时间传入值;|无|HDF_STATUS相关状态| 写RTC报警时间信息 |
-> |RegisterAlarmCallback|**host**: 结构体指针,核心层RTC控制器 ; **alarmIndex**: 枚举值,闹钟报警索引 ; **cb**:函数指针,回调函数; |无|HDF_STATUS相关状态| 注册报警超时回调函数|
-> |AlarmInterruptEnable |**host**: 结构体指针,核心层RTC控制器 ; **alarmIndex**: 枚举值,闹钟报警索引 ; **enable**: 布尔值,控制报警; |无|HDF_STATUS相关状态| 使能/去使能RTC报警中断 |
-> |GetFreq |**host**: 结构体指针,核心层RTC控制器 ; |**freq**: uint32_t指针, 传出的频率值;|HDF_STATUS相关状态| 读RTC外接晶振频率 |
-> |SetFreq |**host**: 结构体指针,核心层RTC控制器 ; **freq**: uint32_t,频率传入值; |无|HDF_STATUS相关状态| 配置RTC外接晶振频率 |
-> |Reset |**host**: 结构体指针,核心层RTC控制器 ; |无|HDF_STATUS相关状态| RTC复位 |
-> |ReadReg |**host**: 结构体指针,核心层RTC控制器 ; **usrDefIndex**: 结构体,用户自定义寄存器索引; |**value**: uint8_t指针, 传出的寄存器值;|HDF_STATUS相关状态| 按照用户定义的寄存器索引, 读取对应的寄存器配置, 一个索引对应一字节的配置值 |
-> |WriteReg |**host**: 结构体指针,核心层RTC控制器 ; **usrDefIndex**: 结构体,用户自定义寄存器索引; **value**: uint8_t,寄存器传入值; |无|HDF_STATUS相关状态| 按照用户定义的寄存器索引, 设置对应的寄存器配置, 一个索引对应一字节的配置值|
-
-## 开发实例
-
-下方将以rtc_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
-
-1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
-
- 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
-
-- RTC驱动入口参考
-
- ```c
- struct HdfDriverEntry g_rtcDriverEntry = {
- .moduleVersion = 1,
- .Bind = HiRtcBind, //见Bind参考
- .Init = HiRtcInit, //见Init参考
- .Release = HiRtcRelease, //见Release参考
- .moduleName = "HDF_PLATFORM_RTC",//【必要】且与 HCS 里面的名字匹配
- };
- //调用HDF_INIT将驱动入口注册到HDF框架中
- HDF_INIT(g_rtcDriverEntry);
- ```
-
-2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 rtc_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层RtcHost成员的默认值或限制范围有密切关系。
-
- **本例只有一个RTC控制器,如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在rtc_config文件中增加对应的器件属性**。
-
-- device_info.hcs 配置参考
-
- ```c
- root {
- device_info {
- platform :: host {
- device_rtc :: device {
- device0 :: deviceNode {
- policy = 1; //2:用户态可见,1:内核态可见,0:不需要发布服务
- priority = 30; //优先级越大,值越小
- permission = 0644; //驱动创建设备节点权限
- moduleName = "HDF_PLATFORM_RTC"; //【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致;
- serviceName = "HDF_PLATFORM_RTC"; //【必要】驱动对外发布服务的名称,必须唯一
- deviceMatchAttr = "hisilicon_hi35xx_rtc";//【必要】需要与设备hcs文件中的 match_attr 匹配
- }
- }
- }
- }
- }
- ```
-
-- rtc_config.hcs 配置参考
-
- ```c
- root {
- platform {
- rtc_config {
- controller_0x12080000 {
- match_attr = "hisilicon_hi35xx_rtc";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致
- rtcSpiBaseAddr = 0x12080000; //地址映射相关
- regAddrLength = 0x100; //地址映射相关
- irq = 37; //中断号
- supportAnaCtrl = false;
- supportLock = false;
- anaCtrlAddr = 0xff;
- lock0Addr = 0xff;
- lock1Addr = 0xff;
- lock2Addr = 0xff;
- lock3Addr = 0xff;
- }
- }
- }
- }
- ```
-
-3. 完成驱动入口注册之后,最后一步就是以核心层RtcHost对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化RtcHost成员RtcMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)
-
-- 自定义结构体参考
-
- > 从驱动的角度看,自定义结构体是参数和数据的载体,而且rtc_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员。
-
- ```c
- struct RtcConfigInfo {
- uint32_t spiBaseAddr; //地址映射相关
- volatile void *remapBaseAddr; //地址映射相关
- uint16_t regAddrLength; //地址映射相关
- uint8_t supportAnaCtrl; //是否支持anactrl
- uint8_t supportLock; //是否支持锁
- uint8_t irq; //中断号
- uint8_t alarmIndex; //闹钟索引
- uint8_t anaCtrlAddr; //anactrl地址
- struct RtcLockAddr lockAddr; //锁地址
- RtcAlarmCallback cb; //回调函数
- struct OsalMutex mutex; //互斥锁
- };
-
- // RtcHost是核心层控制器结构体,其中的成员在Init函数中会被赋值
- struct RtcHost {
- struct IDeviceIoService service;
- struct HdfDeviceObject *device;
- struct RtcMethod *method;
- void *data;
- };
- ```
-
-- **【重要】** RtcHost成员回调函数结构体RtcMethod的实例化,其他成员在Init函数中初始化
-
- ```c
- // rtc_hi35xx.c 中的示例:钩子函数的填充
- static struct RtcMethod g_method = {
- .ReadTime = HiRtcReadTime,
- .WriteTime = HiRtcWriteTime,
- .ReadAlarm = HiReadAlarm,
- .WriteAlarm = HiWriteAlarm,
- .RegisterAlarmCallback = HiRegisterAlarmCallback,
- .AlarmInterruptEnable = HiAlarmInterruptEnable,
- .GetFreq = HiGetFreq,
- .SetFreq = HiSetFreq,
- .Reset = HiReset,
- .ReadReg = HiReadReg,
- .WriteReg = HiWriteReg,
- };
- ```
-
-
-- **Bind 函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)
- >
- > |状态(值)|问题描述|
- > |:-|:-:|
- > |HDF_ERR_INVALID_OBJECT|控制器对象非法|
- > |HDF_ERR_MALLOC_FAIL |内存分配失败|
- > |HDF_ERR_INVALID_PARAM |参数非法|
- > |HDF_ERR_IO |I/O 错误|
- > |HDF_SUCCESS |初始化成功|
- > |HDF_FAILURE |初始化失败|
- >
- > **函数说明:**
- > 关联HdfDeviceObject对象和RtcHost
-
- ```c
- static int32_t HiRtcBind(struct HdfDeviceObject *device)
- {
- struct RtcHost *host = NULL;
- host = RtcHostCreate(device); //实际是申请内存并挂接device: host->device = device;
- //使HdfDeviceObject与RtcHost可以相互转化的前提
- ...
- device->service = &host->service;//使HdfDeviceObject与RtcHost可以相互转化的前提
- //方便后续通过调用RtcHostFromDevice 实现全局性质的host 使用
- return HDF_SUCCESS;
- }
- ```
-
-
-- **Init函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态
- >
- > **函数说明:**
- > 初始化自定义结构体对象,初始化RtcHost成员。
-
- ```c
- static int32_t HiRtcInit(struct HdfDeviceObject *device)
- {
- struct RtcHost *host = NULL;
- struct RtcConfigInfo *rtcInfo = NULL;
- ...
- host = RtcHostFromDevice(device);//这里有HdfDeviceObject到RtcHost的强制转化
- rtcInfo = OsalMemCalloc(sizeof(*rtcInfo));
- ...
- //HiRtcConfigData 会从设备配置树中读取属性填充rtcInfo 的supportAnaCtrl, supportLock, spiBaseAddr, regAddrLength, irq
- //为HiRtcSwInit 和HiRtcSwInit 提供参数,...函数内部处理失败后内存释放等操作
- if (HiRtcConfigData(rtcInfo, device->property) != 0) {
- ...
- }
- if (HiRtcSwInit(rtcInfo) != 0) {//地址映射以及中断注册相关
- ...
- }
- if (HiRtcHwInit(rtcInfo) != 0) {//初始化anaCtrl 和 lockAddr 相关内容
- ...
- }
-
- host->method = &g_method;//RtcMethod的实例化对象的挂载
- host->data = rtcInfo; //使RtcConfigInfo与RtcHost可以相互转化的前提
- HDF_LOGI("Hdf dev service:%s init success!", HdfDeviceGetServiceName(device));
- return HDF_SUCCESS;
- }
- ```
-
-- **Release 函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > 无
- >
- > **函数说明:**
- > 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init或Bind函数中具备对应赋值的操作。
-
- ```c
- static void HiRtcRelease(struct HdfDeviceObject *device)
- {
- struct RtcHost *host = NULL;
- struct RtcConfigInfo *rtcInfo = NULL;
- ...
- host = RtcHostFromDevice(device); //这里有HdfDeviceObject到RtcHost的强制转化
- rtcInfo = (struct RtcConfigInfo *)host->data;//这里有RtcHost到RtcConfigInfo的强制转化
- if (rtcInfo != NULL) {
- HiRtcSwExit(rtcInfo);
- OsalMemFree(rtcInfo); //释放RtcConfigInfo
- host->data = NULL;
- }
- RtcHostDestroy(host); //释放RtcHost
- }
- ```
-
+# RTC
+
+- [概述](#section509989381142407)
+- [接口说明](#section752964871810)
+- [开发步骤](#section1784450860142407)
+- [开发实例](#section1594883301142407)
+
+## 概述
+
+RTC\(real-time clock\)为操作系统中的实时时钟设备,在HDF框架中,RTC的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
+
+**图 1** RTC独立服务模式结构图
+
+
+## 接口说明
+
+RtcMethod定义:
+
+```
+struct RtcMethod {
+ int32_t (*ReadTime)(struct RtcHost *host, struct RtcTime *time);
+ int32_t (*WriteTime)(struct RtcHost *host, const struct RtcTime *time);
+ int32_t (*ReadAlarm)(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, struct RtcTime *time);
+ int32_t (*WriteAlarm)(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, const struct RtcTime *time);
+ int32_t (*RegisterAlarmCallback)(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, RtcAlarmCallback cb);
+ int32_t (*AlarmInterruptEnable)(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, uint8_t enable);
+ int32_t (*GetFreq)(struct RtcHost *host, uint32_t *freq);
+ int32_t (*SetFreq)(struct RtcHost *host, uint32_t freq);
+ int32_t (*Reset)(struct RtcHost *host);
+ int32_t (*ReadReg)(struct RtcHost *host, uint8_t usrDefIndex, uint8_t *value);
+ int32_t (*WriteReg)(struct RtcHost *host, uint8_t usrDefIndex, uint8_t value);
+};
+```
+
+**表 1** RtcMethod结构体成员的回调函数功能说明
+
+
+函数
+ |
+入参
+ |
+出参
+ |
+返回值
+ |
+功能
+ |
+
+
+ReadTime
+ |
+host: 结构体指针,核心层RTC控制器 ;
+ |
+time: 结构体指针,传出的时间值;
+ |
+HDF_STATUS相关状态
+ |
+读RTC时间信息
+ |
+
+WriteTime
+ |
+host: 结构体指针,核心层RTC控制器 ;time: 结构体指针,时间传入值;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+写RTC时间信息(包括毫秒~年)
+ |
+
+ReadAlarm
+ |
+host: 结构体指针,核心层RTC控制器 ;alarmIndex: 枚举值,闹钟报警索引 ;
+ |
+time: 结构体指针,传出的时间值;
+ |
+HDF_STATUS相关状态
+ |
+读RTC报警时间信息
+ |
+
+WriteAlarm
+ |
+host: 结构体指针,核心层RTC控制器 ;alarmIndex: 枚举值,闹钟报警索引 ;time: 结构体指针,时间传入值;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+写RTC报警时间信息
+ |
+
+RegisterAlarmCallback
+ |
+host: 结构体指针,核心层RTC控制器 ;alarmIndex: 枚举值,闹钟报警索引 ;cb:函数指针,回调函数;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+注册报警超时回调函数
+ |
+
+AlarmInterruptEnable
+ |
+host: 结构体指针,核心层RTC控制器 ;alarmIndex: 枚举值,闹钟报警索引 ;enable: 布尔值,控制报警;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+使能/去使能RTC报警中断
+ |
+
+GetFreq
+ |
+host: 结构体指针,核心层RTC控制器 ;
+ |
+freq: uint32_t指针,传出的频率值;
+ |
+HDF_STATUS相关状态
+ |
+读RTC外接晶振频率
+ |
+
+SetFreq
+ |
+host: 结构体指针,核心层RTC控制器 ;freq: uint32_t,频率传入值;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+配置RTC外接晶振频率
+ |
+
+Reset
+ |
+host: 结构体指针,核心层RTC控制器 ;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+RTC复位
+ |
+
+ReadReg
+ |
+host: 结构体指针,核心层RTC控制器 ;usrDefIndex: 结构体,用户自定义寄存器索引;
+ |
+value: uint8_t指针,传出的寄存器值;
+ |
+HDF_STATUS相关状态
+ |
+按照用户定义的寄存器索引,读取对应的寄存器配置,一个索引对应一字节的配置值
+ |
+
+WriteReg
+ |
+host: 结构体指针,核心层RTC控制器 ;usrDefIndex: 结构体,用户自定义寄存器索引;value: uint8_t,寄存器传入值;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+按照用户定义的寄存器索引,设置对应的寄存器配置,一个索引对应一字节的配置值
+ |
+
+
+
+
+## 开发步骤
+
+RTC模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及填充核心层接口函数。
+
+1. **实例化驱动入口:**
+ - 实例化HdfDriverEntry结构体成员。
+ - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
+
+2. **配置属性文件:**
+ - 在device\_info.hcs文件中添加deviceNode描述。
+ - 【可选】添加rtc\_config.hcs器件属性文件。
+
+3. **实例化RTC控制器对象:**
+ - 初始化RtcHost成员。
+ - 实例化RtcHost成员RtcMethod。
+
+ > **说明:**
+ >实例化RtcHost成员RtcMethod,其定义和成员说明见[接口说明](#section752964871810)。
+
+
+4. **驱动调试:**
+
+ 【可选】针对新增驱动程序,建议验证驱动基本功能,例如RTC控制状态,中断响应情况等。
+
+
+## 开发实例
+
+下方将以rtc\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
+
+1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
+
+ 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
+
+ RTC驱动入口参考:
+
+ ```
+ struct HdfDriverEntry g_rtcDriverEntry = {
+ .moduleVersion = 1,
+ .Bind = HiRtcBind, //见Bind参考
+ .Init = HiRtcInit, //见Init参考
+ .Release = HiRtcRelease, //见Release参考
+ .moduleName = "HDF_PLATFORM_RTC",//【必要】且与 HCS 里面的名字匹配
+ };
+ //调用HDF_INIT将驱动入口注册到HDF框架中
+ HDF_INIT(g_rtcDriverEntry);
+ ```
+
+2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 rtc\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层RtcHost成员的默认值或限制范围有密切关系。
+
+ 本例只有一个RTC控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在rtc\_config文件中增加对应的器件属性。
+
+ - device\_info.hcs 配置参考。
+
+ ```
+ root {
+ device_info {
+ platform :: host {
+ device_rtc :: device {
+ device0 :: deviceNode {
+ policy = 1; //2:用户态可见,1:内核态可见,0:不需要发布服务
+ priority = 30; //优先级越大,值越小
+ permission = 0644; //驱动创建设备节点权限
+ moduleName = "HDF_PLATFORM_RTC"; //【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致
+ serviceName = "HDF_PLATFORM_RTC"; //【必要】驱动对外发布服务的名称,必须唯一
+ deviceMatchAttr = "hisilicon_hi35xx_rtc";//【必要】需要与设备hcs文件中的 match_attr 匹配
+ }
+ }
+ }
+ }
+ }
+ ```
+
+ - rtc\_config.hcs 配置参考。
+
+ ```
+ root {
+ platform {
+ rtc_config {
+ controller_0x12080000 {
+ match_attr = "hisilicon_hi35xx_rtc";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致
+ rtcSpiBaseAddr = 0x12080000; //地址映射相关
+ regAddrLength = 0x100; //地址映射相关
+ irq = 37; //中断号
+ supportAnaCtrl = false;
+ supportLock = false;
+ anaCtrlAddr = 0xff;
+ lock0Addr = 0xff;
+ lock1Addr = 0xff;
+ lock2Addr = 0xff;
+ lock3Addr = 0xff;
+ }
+ }
+ }
+ }
+ ```
+
+3. 完成驱动入口注册之后,最后一步就是以核心层RtcHost对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化RtcHost成员RtcMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
+ - 自定义结构体参考。
+
+ 从驱动的角度看,自定义结构体是参数和数据的载体,而且rtc\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员。
+
+ ```
+ struct RtcConfigInfo {
+ uint32_t spiBaseAddr; //地址映射相关
+ volatile void *remapBaseAddr; //地址映射相关
+ uint16_t regAddrLength; //地址映射相关
+ uint8_t supportAnaCtrl; //是否支持anactrl
+ uint8_t supportLock; //是否支持锁
+ uint8_t irq; //中断号
+ uint8_t alarmIndex; //闹钟索引
+ uint8_t anaCtrlAddr; //anactrl地址
+ struct RtcLockAddr lockAddr; //锁地址
+ RtcAlarmCallback cb; //回调函数
+ struct OsalMutex mutex; //互斥锁
+ };
+
+ // RtcHost是核心层控制器结构体,其中的成员在Init函数中会被赋值
+ struct RtcHost {
+ struct IDeviceIoService service;
+ struct HdfDeviceObject *device;
+ struct RtcMethod *method;
+ void *data;
+ };
+ ```
+
+ - RtcHost成员回调函数结构体RtcMethod的实例化,其他成员在Init函数中初始化。
+
+ ```
+ // rtc_hi35xx.c 中的示例:钩子函数的填充
+ static struct RtcMethod g_method = {
+ .ReadTime = HiRtcReadTime,
+ .WriteTime = HiRtcWriteTime,
+ .ReadAlarm = HiReadAlarm,
+ .WriteAlarm = HiWriteAlarm,
+ .RegisterAlarmCallback = HiRegisterAlarmCallback,
+ .AlarmInterruptEnable = HiAlarmInterruptEnable,
+ .GetFreq = HiGetFreq,
+ .SetFreq = HiSetFreq,
+ .Reset = HiReset,
+ .ReadReg = HiReadReg,
+ .WriteReg = HiWriteReg,
+ };
+ ```
+
+ - Bind 函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。
+
+ **表 2** Bind 函数入参及返回值对照表
+
+
+ 状态(值)
+ |
+ 问题描述
+ |
+
+
+ HDF_ERR_INVALID_OBJECT
+ |
+ 控制器对象非法
+ |
+
+ HDF_ERR_MALLOC_FAIL
+ |
+ 内存分配失败
+ |
+
+ HDF_ERR_INVALID_PARAM
+ |
+ 参数非法
+ |
+
+ HDF_ERR_IO
+ |
+ I/O 错误
+ |
+
+ HDF_SUCCESS
+ |
+ 初始化成功
+ |
+
+ HDF_FAILURE
+ |
+ 初始化失败
+ |
+
+
+
+
+ 函数说明:
+
+ 关联HdfDeviceObject对象和RtcHost。
+
+ ```
+ static int32_t HiRtcBind(struct HdfDeviceObject *device)
+ {
+ struct RtcHost *host = NULL;
+ host = RtcHostCreate(device); //实际是申请内存并挂接device: host->device = device;
+ //使HdfDeviceObject与RtcHost可以相互转化的前提
+ ...
+ device->service = &host->service;//使HdfDeviceObject与RtcHost可以相互转化的前提
+ //方便后续通过调用RtcHostFromDevice 实现全局性质的host 使用
+ return HDF_SUCCESS;
+ }
+ ```
+
+ - Init函数参考
+
+ 入参**:**
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值**:**
+
+ HDF\_STATUS相关状态。
+
+ 函数说明:
+
+ 初始化自定义结构体对象,初始化RtcHost成员。
+
+ ```
+ static int32_t HiRtcInit(struct HdfDeviceObject *device)
+ {
+ struct RtcHost *host = NULL;
+ struct RtcConfigInfo *rtcInfo = NULL;
+ ...
+ host = RtcHostFromDevice(device);//这里有HdfDeviceObject到RtcHost的强制转化
+ rtcInfo = OsalMemCalloc(sizeof(*rtcInfo));
+ ...
+ //HiRtcConfigData 会从设备配置树中读取属性填充rtcInfo 的supportAnaCtrl, supportLock, spiBaseAddr, regAddrLength, irq
+ //为HiRtcSwInit 和HiRtcSwInit 提供参数,...函数内部处理失败后内存释放等操作
+ if (HiRtcConfigData(rtcInfo, device->property) != 0) {
+ ...
+ }
+ if (HiRtcSwInit(rtcInfo) != 0) {//地址映射以及中断注册相关
+ ...
+ }
+ if (HiRtcHwInit(rtcInfo) != 0) {//初始化anaCtrl 和 lockAddr 相关内容
+ ...
+ }
+
+ host->method = &g_method;//RtcMethod的实例化对象的挂载
+ host->data = rtcInfo; //使RtcConfigInfo与RtcHost可以相互转化的前提
+ HDF_LOGI("Hdf dev service:%s init success!", HdfDeviceGetServiceName(device));
+ return HDF_SUCCESS;
+ }
+ ```
+
+ - Release 函数参考
+
+ 入参**:**
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值**:**
+
+ 无。
+
+ 函数说明:
+
+ 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作前提是在Init或Bind函数中具备对应赋值的操作。
+
+ ```
+ static void HiRtcRelease(struct HdfDeviceObject *device)
+ {
+ struct RtcHost *host = NULL;
+ struct RtcConfigInfo *rtcInfo = NULL;
+ ...
+ host = RtcHostFromDevice(device); //这里有HdfDeviceObject到RtcHost的强制转化
+ rtcInfo = (struct RtcConfigInfo *)host->data;//这里有RtcHost到RtcConfigInfo的强制转化
+ if (rtcInfo != NULL) {
+ HiRtcSwExit(rtcInfo);
+ OsalMemFree(rtcInfo); //释放RtcConfigInfo
+ host->data = NULL;
+ }
+ RtcHostDestroy(host); //释放RtcHost
+ }
+ ```
+
+
+
diff --git a/zh-cn/device-dev/driver/driver-platform-sdio-des.md b/zh-cn/device-dev/driver/driver-platform-sdio-des.md
index 1d85e6496ea6abc547afcdc1536b5068eb1acdbc..a3a0d13450beed13fea5e28b162d594ca2620fb9 100644
--- a/zh-cn/device-dev/driver/driver-platform-sdio-des.md
+++ b/zh-cn/device-dev/driver/driver-platform-sdio-des.md
@@ -1,8 +1,7 @@
-# SDIO
+# SDIO
- [概述](#section1155271783811)
- - [接口说明](#section08064247248)
-
+- [接口说明](#section12601496259)
- [使用指导](#section1878939192515)
- [使用流程](#section1490685512255)
- [打开SDIO控制器](#section10782428132616)
@@ -29,14 +28,12 @@
- D0-3信号:4条数据线,其中,DAT1信号线复用为中断线,在1BIT模式下DAT0用来传输数据,在4BIT模式下DAT0-DAT3用来传输数据。
- CMD信号:用于HOST发送命令和DEVICE回复响应。
- **图 1** SDIO的HOST-DEVICE连接示意图
-
-
- 
+ **图 1** SDIO的HOST-DEVICE连接示意图
+ 
- SDIO接口定义了操作SDIO的通用方法集合,包括打开/关闭SDIO控制器、独占/释放HOST、使能/去使能设备、申请/释放中断、读写、获取/设置公共信息等。
-### 接口说明
+## 接口说明
**表 1** SDIO驱动API接口功能介绍
@@ -165,12 +162,10 @@
### 使用流程
-使用SDIO的一般流程如[图2](#fig1343742311264)所示。
-
-**图 2** SDIO使用流程图
-
+使用SDIO的一般流程如[图2](#fig1969028202613)所示。
-
+**图 2** SDIO使用流程图
+
### 打开SDIO控制器
diff --git a/zh-cn/device-dev/driver/driver-platform-sdio-develop.md b/zh-cn/device-dev/driver/driver-platform-sdio-develop.md
index cb8883babfaef39add44768b1ed927f336be3849..1c59197f4862db914d4f55c82cbee223f47783eb 100755
--- a/zh-cn/device-dev/driver/driver-platform-sdio-develop.md
+++ b/zh-cn/device-dev/driver/driver-platform-sdio-develop.md
@@ -1,306 +1,532 @@
-# SDIO
-
-- [概述](#1)
-- [开发步骤](#2)
-- [开发实例](#3)
-
-## 概述
-
-SDIO由SD卡发展而来,被统称为mmc(MultiMediaCard),相关技术差别不大,在HDF框架中,
-SDIO的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。
-
-独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
-
-图 1 独立服务模式结构图
-
-
-## 开发步骤
-
-SDIO模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及填充核心层接口函数。
-
-
-1. **实例化驱动入口:**
- - 实例化HdfDriverEntry结构体成员。
- - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
-
-2. **配置属性文件:**
-
- - 在device_info.hcs文件中添加deviceNode描述。
- - 【可选】添加sdio_config.hcs器件属性文件。
-
-3. **实例化SDIO控制器对象:**
-
- - 初始化SdioDevice成员。
- - 实例化SdioDevice成员SdioDeviceOps,其定义和成员说明见下
-
-4. **驱动调试:**
- - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如SDIO控制状态,中断响应情况等。
-
->  **说明:**
->
-> SdioDeviceOps定义
->
-> ```c
-> // 函数模板
-> struct SdioDeviceOps {
-> int32_t (*incrAddrReadBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size);
-> int32_t (*incrAddrWriteBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size);
-> int32_t (*fixedAddrReadBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size, uint32_t scatterLen);
-> int32_t (*fixedAddrWriteBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size, uint32_t scatterLen);
-> int32_t (*func0ReadBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size);
-> int32_t (*func0WriteBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size);
-> int32_t (*setBlockSize)(struct SdioDevice *dev, uint32_t blockSize);
-> int32_t (*getCommonInfo)(struct SdioDevice *dev, SdioCommonInfo *info, uint32_t infoType);
-> int32_t (*setCommonInfo)(struct SdioDevice *dev, SdioCommonInfo *info, uint32_t infoType);
-> int32_t (*flushData)(struct SdioDevice *dev);
-> int32_t (*enableFunc)(struct SdioDevice *dev);
-> int32_t (*disableFunc)(struct SdioDevice *dev);
-> int32_t (*claimIrq)(struct SdioDevice *dev, SdioIrqHandler *irqHandler);
-> int32_t (*releaseIrq)(struct SdioDevice *dev);
-> int32_t (*findFunc)(struct SdioDevice *dev, struct SdioFunctionConfig *configData);
-> int32_t (*claimHost)(struct SdioDevice *dev);
-> int32_t (*releaseHost)(struct SdioDevice *dev);
-> };
-> ```
->
-> 表1 SdioDeviceOps结构体成员的回调函数功能说明
->
-> |函数|入参|出参|返回值|功能|
-> |-|-|-|-|-|
-> |incrAddrReadBytes, |**dev**: 结构体指针,SDIO设备控制器; **addr**: uint32_t,地址值; **size**: uint32_t,大小 |**data**: uint8_t指针,传出值;|HDF_STATUS相关状态| 从指定的SDIO地址增量读取给定长度的数据 |
-> |incrAddrWriteBytes, |**dev**: 结构体指针,SDIO设备控制器; **data**: uint8_t指针,传入值; **addr**: uint32_t,地址值; **size**: uint32_t,大小 |无|HDF_STATUS相关状态| 将给定长度的数据增量写入指定的SDIO地址 |
-> |fixedAddrReadBytes, |**dev**: 结构体指针,SDIO设备控制器; **addr**: uint32_t,地址值; **size**: uint32_t,大小; **scatterLen**: uint32_t,数据长度;|**data**: uint8_t指针,传出值;|HDF_STATUS相关状态| 从固定SDIO地址读取给定长度的数据。 |
-> |fixedAddrWriteBytes,|**dev**: 结构体指针,SDIO设备控制器; **data**: uint8_t指针,传入值; **addr**: uint32_t,地址值; **size**: uint32_t,大小; **scatterLen**: uint32_t,数据长度;|无|HDF_STATUS相关状态| 将给定长度的数据写入固定SDIO地址 |
-> |func0ReadBytes, |**dev**: 结构体指针,SDIO设备控制器; **addr**: uint32_t,地址值; **size**: uint32_t,大小; |**data**: uint8_t指针,传出值;|HDF_STATUS相关状态| 从SDIO函数0的地址空间读取给定长度的数据。 |
-> |func0WriteBytes, |**dev**: 结构体指针,SDIO设备控制器; **data**: uint8_t指针,传入值; **addr**: uint32_t,地址值; **size**: uint32_t,大小; |无|HDF_STATUS相关状态| 将给定长度的数据写入SDIO函数0的地址空间。 |
-> |setBlockSize, |**dev**: 结构体指针,SDIO设备控制器; **blockSize**: uint32_t,Block大小 |无|HDF_STATUS相关状态| 设置block大小|
-> |getCommonInfo, |**dev**: 联合体指针,SDIO设备控制器; **infoType**: uint32_t,info类型; |**info**: 结构体指针,传出SdioFuncInfo信息;|HDF_STATUS相关状态| 获取CommonInfo,说明见下 |
-> |setCommonInfo, |**dev**: 结构体指针,SDIO设备控制器; **info**: 联合体指针,SdioFuncInfo信息传入; **infoType**: uint32_t,info类型; |无|HDF_STATUS相关状态| 设置CommonInfo,说明见下 |
-> |flushData, |**dev**: 结构体指针,SDIO设备控制器; |无|HDF_STATUS相关状态|当SDIO需要重新初始化或发生意外错误时调用的函数|
-> |enableFunc, |**dev**: 结构体指针,SDIO设备控制器; |无|HDF_STATUS相关状态|使能SDIO设备 |
-> |disableFunc, |**dev**: 结构体指针,SDIO设备控制器; |无|HDF_STATUS相关状态|去使能SDIO设备 |
-> |claimIrq, |**dev**: 结构体指针,SDIO设备控制器; **irqHandler**: void函数指针; |无|HDF_STATUS相关状态|注册SDIO中断 |
-> |releaseIrq, |**dev**: 结构体指针,SDIO设备控制器; |无|HDF_STATUS相关状态|释放SDIO中断|
-> |findFunc, |**dev**: 结构体指针,SDIO设备控制器; **configData**: 结构体指针, SDIO函数关键信息 |无|HDF_STATUS相关状态|寻找匹配的funcNum|
-> |claimHost, |**dev**: 结构体指针,SDIO设备控制器; |无|HDF_STATUS相关状态|独占HOST |
-> |releaseHost, |**dev**: 结构体指针,SDIO设备控制器; |无|HDF_STATUS相关状态|释放HOST |
->
-> > **CommonInfo说明:**
-> > 包括maxBlockNum(单个request中最大block数), maxBlockSize(单个block最大字节数), maxRequestSize(单个Request最大字节数), enTimeout(最大超时时间,毫秒), funcNum(功能编号1~7), irqCap(IRQ capabilities), (void \*)data.
-
-## 开发实例
-
-下方将以sdio_adapter.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
-
-1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
-
- 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
-
-- SDIO 驱动入口参考
-
- ```c
- struct HdfDriverEntry g_sdioDriverEntry = {
- .moduleVersion = 1,
- .Bind = Hi35xxLinuxSdioBind, //见Bind参考
- .Init = Hi35xxLinuxSdioInit, //见Init参考
- .Release = Hi35xxLinuxSdioRelease,//见Release参考
- .moduleName = "HDF_PLATFORM_SDIO",//【必要 且与 HCS文件中里面的moduleName匹配】
- };
- //调用HDF_INIT将驱动入口注册到HDF框架中
- HDF_INIT(g_sdioDriverEntry);
- ```
-
-2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 sdio_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层SdioDevice成员的默认值或限制范围有密切关系。
-
- **本例只有一个SDIO控制器,如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在sdio_config文件中增加对应的器件属性**。
-
-- device_info.hcs 配置参考
-
- ```c
- root {
- device_info {
- match_attr = "hdf_manager";
- platform :: host {
- hostName = "platform_host";
- priority = 50;
- device_sdio :: device {
- device0 :: deviceNode {
- policy = 1;
- priority = 70;
- permission = 0644;
- moduleName = "HDF_PLATFORM_SDIO"; //【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致;
- serviceName = "HDF_PLATFORM_MMC_2"; //【必要】驱动对外发布服务的名称,必须唯一
- deviceMatchAttr = "hisilicon_hi35xx_sdio_0";//【必要】用于配置控制器私有数据,要与sdio_config.hcs中对应控制器保持一致
- }
- }
- }
- }
- }
- ```
-
-- sdio_config.hcs 配置参考
-
- ```c
- root {
- platform {
- sdio_config {
- template sdio_controller {
- match_attr = "";
- hostId = 2; //【必要】模式固定为2,在mmc_config.hcs有介绍
- devType = 2; //【必要】模式固定为2,在mmc_config.hcs有介绍
- }
- controller_0x2dd1 :: sdio_controller {
- match_attr = "hisilicon_hi35xx_sdio_0";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致
- }
- }
- }
- ```
-
-3. 完成驱动入口注册之后,最后一步就是以核心层SdioDevice对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化SdioDevice成员SdioDeviceOps(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)
-
-- 自定义结构体参考
-
- > 从驱动的角度看,自定义结构体是参数和数据的载体,而且sdio_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象。
-
- ```c
- typedef struct {
- uint32_t maxBlockNum; // 单个request最大的block个数
- uint32_t maxBlockSize; // 单个block最大的字节数1~2048
- uint32_t maxRequestSize; // 单个request最大的字节数 1~2048
- uint32_t enTimeout; // 最大超时时间,单位毫秒,且不能超过一秒
- uint32_t funcNum; // 函数编号1~7
- uint32_t irqCap; // 中断能力
- void *data; // 私有数据
- } SdioFuncInfo;
-
- //SdioDevice是核心层控制器结构体,其中的成员在Bind函数中会被赋值
- struct SdioDevice {
- struct SdDevice sd;
- struct SdioDeviceOps *sdioOps;
- struct SdioRegister sdioReg;
- uint32_t functions;
- struct SdioFunction *sdioFunc[SDIO_MAX_FUNCTION_NUMBER];
- struct SdioFunction *curFunction;
- struct OsalThread thread; /* irq thread */
- struct OsalSem sem;
- bool irqPending;
- bool threadRunning;
- };
- ```
-
-- **【重要】** SdioDevice成员回调函数结构体SdioDeviceOps的实例化,其他成员在Init函数中初始化
-
- ```c
- static struct SdioDeviceOps g_sdioDeviceOps = {
- .incrAddrReadBytes = Hi35xxLinuxSdioIncrAddrReadBytes,
- .incrAddrWriteBytes = Hi35xxLinuxSdioIncrAddrWriteBytes,
- .fixedAddrReadBytes = Hi35xxLinuxSdioFixedAddrReadBytes,
- .fixedAddrWriteBytes = Hi35xxLinuxSdioFixedAddrWriteBytes,
- .func0ReadBytes = Hi35xxLinuxSdioFunc0ReadBytes,
- .func0WriteBytes = Hi35xxLinuxSdioFunc0WriteBytes,
- .setBlockSize = Hi35xxLinuxSdioSetBlockSize,
- .getCommonInfo = Hi35xxLinuxSdioGetCommonInfo,
- .setCommonInfo = Hi35xxLinuxSdioSetCommonInfo,
- .flushData = Hi35xxLinuxSdioFlushData,
- .enableFunc = Hi35xxLinuxSdioEnableFunc,
- .disableFunc = Hi35xxLinuxSdioDisableFunc,
- .claimIrq = Hi35xxLinuxSdioClaimIrq,
- .releaseIrq = Hi35xxLinuxSdioReleaseIrq,
- .findFunc = Hi35xxLinuxSdioFindFunc,
- .claimHost = Hi35xxLinuxSdioClaimHost,
- .releaseHost = Hi35xxLinuxSdioReleaseHost,
- };
- ```
-
-- **Bind函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)
- >
- > |状态(值)|问题描述|
- > |:-|:-:|
- > |HDF_ERR_INVALID_OBJECT|控制器对象非法|
- > |HDF_ERR_MALLOC_FAIL |内存分配失败|
- > |HDF_ERR_INVALID_PARAM |参数非法|
- > |HDF_ERR_IO |I/O 错误|
- > |HDF_SUCCESS |初始化成功|
- > |HDF_FAILURE |初始化失败|
- >
- > **函数说明:**
- > 初始化自定义结构体对象,初始化SdioCntlr成员,调用核心层SdioCntlrAdd函数,以及其他厂商自定义初始化操作
-
- ```c
- static int32_t Hi35xxLinuxSdioBind(struct HdfDeviceObject *obj)
- {
- struct MmcCntlr *cntlr = NULL;
- int32_t ret;
- ...
- cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr));// 分配内存
- ...
- cntlr->ops = &g_sdioCntlrOps; //【必要】struct MmcCntlrOps g_sdioCntlrOps={
- // .rescanSdioDev = Hi35xxLinuxSdioRescan,};
- cntlr->hdfDevObj = obj; //【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提
- obj->service = &cntlr->service;//【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提
- ret = Hi35xxLinuxSdioCntlrParse(cntlr, obj);//【必要】初始化cntlr 的 index, devType, 失败则 goto _ERR;
- ...
- ret = MmcCntlrAdd(cntlr); //【必要】调用核心层mmc_core.c的函数, 失败则 goto _ERR;
- ...
- ret = MmcCntlrAllocDev(cntlr, (enum MmcDevType)cntlr->devType);//【必要】调用核心层mmc_core.c的函数, 失败则 goto _ERR;
- ...
-
- MmcDeviceAddOps(cntlr->curDev, &g_sdioDeviceOps);//【必要】调用核心层mmc_core.c的函数, 钩子函数挂载
- HDF_LOGD("Hi35xxLinuxSdioBind: Success!");
- return HDF_SUCCESS;
-
- _ERR:
- Hi35xxLinuxSdioDeleteCntlr(cntlr);
- HDF_LOGE("Hi35xxLinuxSdioBind: Fail!");
- return HDF_FAILURE;
- }
- ```
-
-
-- **Init函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态
- >
- > **函数说明:**
- > 无操作,可根据厂商需要添加
-
- ```c
- static int32_t Hi35xxLinuxSdioInit(struct HdfDeviceObject *obj)
- {
- (void)obj;//无操作,可根据厂商需要添加
- HDF_LOGD("Hi35xxLinuxSdioInit: Success!");
- return HDF_SUCCESS;
- }
- ```
-
-- **Release函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > 无
- >
- > **函数说明:**
- > 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Bind函数中具备对应赋值的操作。
-
- ```c
- static void Hi35xxLinuxSdioRelease(struct HdfDeviceObject *obj)
- {
- if (obj == NULL) {
- return;
- }
- Hi35xxLinuxSdioDeleteCntlr((struct MmcCntlr *)obj->service);//【必要】自定义的内存释放函数,这里有HdfDeviceObject到MmcCntlr的强制转化
- }
- ```
-
+# SDIO
+
+- [概述](#section1347805272150053)
+- [接口说明](#section752964871810)
+- [开发步骤](#section581179475150053)
+- [开发实例](#section2112250242150053)
+
+## 概述
+
+SDIO由SD卡发展而来,被统称为mmc(MultiMediaCard),相关技术差别不大,在HDF框架中,SDIO的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
+
+**图 1** SDIO独立服务模式结构图
+
+
+## 接口说明
+
+SdioDeviceOps定义:
+
+```
+// 函数模板
+struct SdioDeviceOps {
+ int32_t (*incrAddrReadBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size);
+ int32_t (*incrAddrWriteBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size);
+ int32_t (*fixedAddrReadBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size, uint32_t scatterLen);
+ int32_t (*fixedAddrWriteBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size, uint32_t scatterLen);
+ int32_t (*func0ReadBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size);
+ int32_t (*func0WriteBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size);
+ int32_t (*setBlockSize)(struct SdioDevice *dev, uint32_t blockSize);
+ int32_t (*getCommonInfo)(struct SdioDevice *dev, SdioCommonInfo *info, uint32_t infoType);
+ int32_t (*setCommonInfo)(struct SdioDevice *dev, SdioCommonInfo *info, uint32_t infoType);
+ int32_t (*flushData)(struct SdioDevice *dev);
+ int32_t (*enableFunc)(struct SdioDevice *dev);
+ int32_t (*disableFunc)(struct SdioDevice *dev);
+ int32_t (*claimIrq)(struct SdioDevice *dev, SdioIrqHandler *irqHandler);
+ int32_t (*releaseIrq)(struct SdioDevice *dev);
+ int32_t (*findFunc)(struct SdioDevice *dev, struct SdioFunctionConfig *configData);
+ int32_t (*claimHost)(struct SdioDevice *dev);
+ int32_t (*releaseHost)(struct SdioDevice *dev);
+};
+```
+
+**表 1** SdioDeviceOps结构体成员的回调函数功能说明
+
+
+函数
+ |
+入参
+ |
+出参
+ |
+返回值
+ |
+功能
+ |
+
+
+incrAddrReadBytes
+ |
+dev: 结构体指针,SDIO设备控制器;addr: uint32_t,地址值;size: uint32_t,大小
+ |
+data: uint8_t指针,传出值;
+ |
+HDF_STATUS相关状态
+ |
+从指定的SDIO地址增量读取给定长度的数据
+ |
+
+incrAddrWriteBytes
+ |
+dev: 结构体指针,SDIO设备控制器;data: uint8_t指针,传入值;addr: uint32_t,地址值;size: uint32_t,大小
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+将给定长度的数据增量写入指定的SDIO地址
+ |
+
+fixedAddrReadBytes
+ |
+dev: 结构体指针,SDIO设备控制器;addr: uint32_t,地址值;size: uint32_t,大小;scatterLen: uint32_t,数据长度;
+ |
+data: uint8_t指针,传出值;
+ |
+HDF_STATUS相关状态
+ |
+从固定SDIO地址读取给定长度的数据。
+ |
+
+fixedAddrWriteBytes
+ |
+dev: 结构体指针,SDIO设备控制器;data: uint8_t指针,传入值;addr: uint32_t,地址值;size: uint32_t,大小;scatterLen: uint32_t,数据长度;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+将给定长度的数据写入固定SDIO地址
+ |
+
+func0ReadBytes
+ |
+dev: 结构体指针,SDIO设备控制器;addr: uint32_t,地址值;size: uint32_t,大小;
+ |
+data: uint8_t指针,传出值;
+ |
+HDF_STATUS相关状态
+ |
+从SDIO函数0的地址空间读取给定长度的数据。
+ |
+
+func0WriteBytes
+ |
+dev: 结构体指针,SDIO设备控制器;data: uint8_t指针,传入值;addr: uint32_t,地址值;size: uint32_t,大小;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+将给定长度的数据写入SDIO函数0的地址空间。
+ |
+
+setBlockSize
+ |
+dev: 结构体指针,SDIO设备控制器;blockSize: uint32_t,Block大小
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+设置block大小
+ |
+
+getCommonInfo
+ |
+dev: 联合体指针,SDIO设备控制器;infoType: uint32_t,info类型;
+ |
+info: 结构体指针,传出SdioFuncInfo信息;
+ |
+HDF_STATUS相关状态
+ |
+获取CommonInfo,说明见下
+ |
+
+setCommonInfo
+ |
+dev: 结构体指针,SDIO设备控制器;info: 联合体指针,SdioFuncInfo信息传入;infoType: uint32_t,info类型;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+设置CommonInfo,说明见下
+ |
+
+flushData
+ |
+dev: 结构体指针,SDIO设备控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+当SDIO需要重新初始化或发生意外错误时调用的函数
+ |
+
+enableFunc
+ |
+dev: 结构体指针,SDIO设备控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+使能SDIO设备
+ |
+
+disableFunc
+ |
+dev: 结构体指针,SDIO设备控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+去使能SDIO设备
+ |
+
+claimIrq
+ |
+dev: 结构体指针,SDIO设备控制器;irqHandler: void函数指针;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+注册SDIO中断
+ |
+
+releaseIrq
+ |
+dev: 结构体指针,SDIO设备控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+释放SDIO中断
+ |
+
+findFunc
+ |
+dev: 结构体指针,SDIO设备控制器;configData: 结构体指针, SDIO函数关键信息
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+寻找匹配的funcNum
+ |
+
+claimHost
+ |
+dev: 结构体指针,SDIO设备控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+独占HOST
+ |
+
+releaseHost
+ |
+dev: 结构体指针,SDIO设备控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+释放HOST
+ |
+
+
+
+
+> **说明:**
+>CommonInfo包括maxBlockNum\(单个request中最大block数\), maxBlockSize\(单个block最大字节数\), maxRequestSize\(单个Request最大字节数\), enTimeout\(最大超时时间,毫秒\), funcNum\(功能编号1\~7\), irqCap\(IRQ capabilities\), \(void \*\)data.
+
+## 开发步骤
+
+SDIO模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及填充核心层接口函数。
+
+1. **实例化驱动入口:**
+ - 实例化HdfDriverEntry结构体成员。
+ - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
+
+2. **配置属性文件:**
+ - 在device\_info.hcs文件中添加deviceNode描述。
+ - 【可选】添加sdio\_config.hcs器件属性文件。
+
+3. **实例化SDIO控制器对象:**
+ - 初始化SdioDevice成员。
+ - 实例化SdioDevice成员SdioDeviceOps。
+
+ > **说明:**
+ >实例化SdioDevice成员SdioDeviceOps,其定义和成员说明见[接口说明](#section752964871810)。
+
+
+4. **驱动调试:**
+
+ 【可选】针对新增驱动程序,建议验证驱动基本功能,例如SDIO控制状态,中断响应情况等。
+
+
+## 开发实例
+
+下方将以sdio\_adapter.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
+
+1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
+
+ 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
+
+ SDIO 驱动入口参考:
+
+ ```
+ struct HdfDriverEntry g_sdioDriverEntry = {
+ .moduleVersion = 1,
+ .Bind = Hi35xxLinuxSdioBind, //见Bind参考
+ .Init = Hi35xxLinuxSdioInit, //见Init参考
+ .Release = Hi35xxLinuxSdioRelease,//见Release参考
+ .moduleName = "HDF_PLATFORM_SDIO",//【必要 且与 HCS文件中里面的moduleName匹配】
+ };
+ //调用HDF_INIT将驱动入口注册到HDF框架中
+ HDF_INIT(g_sdioDriverEntry);
+ ```
+
+2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 sdio\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层SdioDevice成员的默认值或限制范围有密切关系。
+
+ 本例只有一个SDIO控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在sdio\_config文件中增加对应的器件属性。
+
+ - device\_info.hcs 配置参考:
+
+ ```
+ root {
+ device_info {
+ match_attr = "hdf_manager";
+ platform :: host {
+ hostName = "platform_host";
+ priority = 50;
+ device_sdio :: device {
+ device0 :: deviceNode {
+ policy = 1;
+ priority = 70;
+ permission = 0644;
+ moduleName = "HDF_PLATFORM_SDIO"; //【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致;
+ serviceName = "HDF_PLATFORM_MMC_2"; //【必要】驱动对外发布服务的名称,必须唯一
+ deviceMatchAttr = "hisilicon_hi35xx_sdio_0";//【必要】用于配置控制器私有数据,要与sdio_config.hcs中对应控制器保持一致
+ }
+ }
+ }
+ }
+ }
+ ```
+
+ - sdio\_config.hcs 配置参考:
+
+ ```
+ root {
+ platform {
+ sdio_config {
+ template sdio_controller {
+ match_attr = "";
+ hostId = 2; //【必要】模式固定为2,在mmc_config.hcs有介绍
+ devType = 2; //【必要】模式固定为2,在mmc_config.hcs有介绍
+ }
+ controller_0x2dd1 :: sdio_controller {
+ match_attr = "hisilicon_hi35xx_sdio_0";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致
+ }
+ }
+ }
+ ```
+
+3. 完成驱动入口注册之后,最后一步就是以核心层SdioDevice对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化SdioDevice成员SdioDeviceOps(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
+ - 自定义结构体参考:
+
+ 从驱动的角度看,自定义结构体是参数和数据的载体,而且sdio\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象。
+
+ ```
+ typedef struct {
+ uint32_t maxBlockNum; // 单个request最大的block个数
+ uint32_t maxBlockSize; // 单个block最大的字节数1~2048
+ uint32_t maxRequestSize; // 单个request最大的字节数 1~2048
+ uint32_t enTimeout; // 最大超时时间,单位毫秒,且不能超过一秒
+ uint32_t funcNum; // 函数编号1~7
+ uint32_t irqCap; // 中断能力
+ void *data; // 私有数据
+ } SdioFuncInfo;
+
+ //SdioDevice是核心层控制器结构体,其中的成员在Bind函数中会被赋值
+ struct SdioDevice {
+ struct SdDevice sd;
+ struct SdioDeviceOps *sdioOps;
+ struct SdioRegister sdioReg;
+ uint32_t functions;
+ struct SdioFunction *sdioFunc[SDIO_MAX_FUNCTION_NUMBER];
+ struct SdioFunction *curFunction;
+ struct OsalThread thread; /* irq thread */
+ struct OsalSem sem;
+ bool irqPending;
+ bool threadRunning;
+ };
+ ```
+
+ - SdioDevice成员回调函数结构体SdioDeviceOps的实例化,其他成员在Init函数中初始化。
+
+ ```
+ static struct SdioDeviceOps g_sdioDeviceOps = {
+ .incrAddrReadBytes = Hi35xxLinuxSdioIncrAddrReadBytes,
+ .incrAddrWriteBytes = Hi35xxLinuxSdioIncrAddrWriteBytes,
+ .fixedAddrReadBytes = Hi35xxLinuxSdioFixedAddrReadBytes,
+ .fixedAddrWriteBytes = Hi35xxLinuxSdioFixedAddrWriteBytes,
+ .func0ReadBytes = Hi35xxLinuxSdioFunc0ReadBytes,
+ .func0WriteBytes = Hi35xxLinuxSdioFunc0WriteBytes,
+ .setBlockSize = Hi35xxLinuxSdioSetBlockSize,
+ .getCommonInfo = Hi35xxLinuxSdioGetCommonInfo,
+ .setCommonInfo = Hi35xxLinuxSdioSetCommonInfo,
+ .flushData = Hi35xxLinuxSdioFlushData,
+ .enableFunc = Hi35xxLinuxSdioEnableFunc,
+ .disableFunc = Hi35xxLinuxSdioDisableFunc,
+ .claimIrq = Hi35xxLinuxSdioClaimIrq,
+ .releaseIrq = Hi35xxLinuxSdioReleaseIrq,
+ .findFunc = Hi35xxLinuxSdioFindFunc,
+ .claimHost = Hi35xxLinuxSdioClaimHost,
+ .releaseHost = Hi35xxLinuxSdioReleaseHost,
+ };
+ ```
+
+ - Bind函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。
+
+ **表 2** Bind函数入参及返回值
+
+
+ 状态(值)
+ |
+ 问题描述
+ |
+
+
+ HDF_ERR_INVALID_OBJECT
+ |
+ 控制器对象非法
+ |
+
+ HDF_ERR_MALLOC_FAIL
+ |
+ 内存分配失败
+ |
+
+ HDF_ERR_INVALID_PARAM
+ |
+ 参数非法
+ |
+
+ HDF_ERR_IO
+ |
+ I/O 错误
+ |
+
+ HDF_SUCCESS
+ |
+ 初始化成功
+ |
+
+ HDF_FAILURE
+ |
+ 初始化失败
+ |
+
+
+
+
+ 函数说明:
+
+ 初始化自定义结构体对象,初始化SdioCntlr成员,调用核心层SdioCntlrAdd函数,以及其他厂商自定义初始化操作。
+
+ ```
+ static int32_t Hi35xxLinuxSdioBind(struct HdfDeviceObject *obj)
+ {
+ struct MmcCntlr *cntlr = NULL;
+ int32_t ret;
+ ...
+ cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr));// 分配内存
+ ...
+ cntlr->ops = &g_sdioCntlrOps; //【必要】struct MmcCntlrOps g_sdioCntlrOps={
+ // .rescanSdioDev = Hi35xxLinuxSdioRescan,};
+ cntlr->hdfDevObj = obj; //【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提
+ obj->service = &cntlr->service;//【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提
+ ret = Hi35xxLinuxSdioCntlrParse(cntlr, obj);//【必要】初始化cntlr 的 index, devType, 失败则 goto _ERR;
+ ...
+ ret = MmcCntlrAdd(cntlr); //【必要】调用核心层mmc_core.c的函数, 失败则 goto _ERR;
+ ...
+ ret = MmcCntlrAllocDev(cntlr, (enum MmcDevType)cntlr->devType);//【必要】调用核心层mmc_core.c的函数, 失败则 goto _ERR;
+ ...
+
+ MmcDeviceAddOps(cntlr->curDev, &g_sdioDeviceOps);//【必要】调用核心层mmc_core.c的函数, 钩子函数挂载
+ HDF_LOGD("Hi35xxLinuxSdioBind: Success!");
+ return HDF_SUCCESS;
+
+ _ERR:
+ Hi35xxLinuxSdioDeleteCntlr(cntlr);
+ HDF_LOGE("Hi35xxLinuxSdioBind: Fail!");
+ return HDF_FAILURE;
+ }
+ ```
+
+ - Init函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ HDF\_STATUS相关状态。
+
+ 函数说明:
+
+ 无操作,可根据厂商需要添加。
+
+ ```
+ static int32_t Hi35xxLinuxSdioInit(struct HdfDeviceObject *obj)
+ {
+ (void)obj;//无操作,可根据厂商需要添加
+ HDF_LOGD("Hi35xxLinuxSdioInit: Success!");
+ return HDF_SUCCESS;
+ }
+ ```
+
+ - Release函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ 无。
+
+ 函数说明:
+
+ 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作前提是在Bind函数中具备对应赋值的操作。
+
+ ```
+ static void Hi35xxLinuxSdioRelease(struct HdfDeviceObject *obj)
+ {
+ if (obj == NULL) {
+ return;
+ }
+ Hi35xxLinuxSdioDeleteCntlr((struct MmcCntlr *)obj->service);//【必要】自定义的内存释放函数,这里有HdfDeviceObject到MmcCntlr的强制转化
+ }
+ ```
+
+
+
diff --git a/zh-cn/device-dev/driver/driver-platform-spi-des.md b/zh-cn/device-dev/driver/driver-platform-spi-des.md
index b903ae469fc1ff91ea3a0bf0ad2713ea20e0de09..033a3b0e06d8469ad5cce3955b0b971c0a5af27a 100644
--- a/zh-cn/device-dev/driver/driver-platform-spi-des.md
+++ b/zh-cn/device-dev/driver/driver-platform-spi-des.md
@@ -1,8 +1,7 @@
-# SPI
+# SPI
- [概述](#section193356154511)
- - [接口说明](#section232141411476)
-
+- [接口说明](#section1325964832615)
- [使用指导](#section71363452477)
- [使用流程](#section32846814820)
- [获取SPI设备句柄](#section1927265711481)
@@ -24,12 +23,10 @@
- CS – 片选,从设备使能信号,由主设备控制。
-- 一个主设备和两个从设备的连接示意图如[图1](#fig15227181812587)所示,Device A和Device B共享主设备的SCLK、MISO和MOSI三根引脚,Device A的片选CS0连接主设备的CS0,Device B的片选CS1连接主设备的CS1。
-
-**图 1** SPI主从设备连接示意图。
-
+- 一个主设备和两个从设备的连接示意图如[图1](#fig89085710359)所示,Device A和Device B共享主设备的SCLK、MISO和MOSI三根引脚,Device A的片选CS0连接主设备的CS0,Device B的片选CS1连接主设备的CS1。
-
+**图 1** SPI主从设备连接示意图。
+
- SPI通信通常由主设备发起,通过以下步骤完成一次通信:
@@ -54,7 +51,7 @@
> **说明:**
>当前只支持主机模式,不支持从机模式。
-### 接口说明
+## 接口说明
**表 1** SPI驱动API接口功能介绍
@@ -119,12 +116,10 @@
### 使用流程
-使用SPI的一般流程如[图2](#fig23885455594)所示。
-
-**图 2** SPI使用流程图
-
+使用SPI的一般流程如[图2](#fig1586912310348)所示。
-
+**图 2** SPI使用流程图
+
### 获取SPI设备句柄
diff --git a/zh-cn/device-dev/driver/driver-platform-spi-develop.md b/zh-cn/device-dev/driver/driver-platform-spi-develop.md
index 705791a44c4cbc25286e710cb264007dd831fc2a..30865e6ae085c5825530053318f69bde8ab8cab4 100755
--- a/zh-cn/device-dev/driver/driver-platform-spi-develop.md
+++ b/zh-cn/device-dev/driver/driver-platform-spi-develop.md
@@ -1,354 +1,449 @@
-# SPI
-
-- [概述](#1)
-- [开发步骤](#2)
-- [开发实例](#3)
-
-## 概述
-
-SPI是串行外设接口(Serial Peripheral Interface)的缩写,在HDF框架中,SPI的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。
-
-独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
-
-图 1 独立服务模式结构图
-
-
-## 开发步骤
-
-SPI模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
-
-1. **实例化驱动入口:**
- - 实例化HdfDriverEntry结构体成员。
- - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
-
-2. **配置属性文件:**
-
- - 在device_info.hcs文件中添加deviceNode描述。
- - 【可选】添加spi_config.hcs器件属性文件。
-
-3. **实例化SPI控制器对象:**
-
- - 初始化SpiCntlr成员。
- - 实例化SpiCntlr成员SpiCntlrMethod,其定义和成员说明见下
-
-4. **驱动调试:**
- - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如spi控制状态,中断响应情况等。
-
->  **说明:**
->
-> SpiCntlrMethod定义
-> ```c
-> struct SpiCntlrMethod {
-> int32_t (*GetCfg)(struct SpiCntlr *cntlr, struct SpiCfg *cfg);
-> int32_t (*SetCfg)(struct SpiCntlr *cntlr, struct SpiCfg *cfg);
-> int32_t (*Transfer)(struct SpiCntlr *cntlr, struct SpiMsg *msg, uint32_t count);
-> int32_t (*Open)(struct SpiCntlr *cntlr);
-> int32_t (*Close)(struct SpiCntlr *cntlr);
-> };
-> ```
-> 表1 SpiCntlrMethod结构体成员的回调函数功能说明
->
-> |成员函数|入参|返回值|功能|
-> |-|-|-|-|
-> |Transfer |**cntlr**: 结构体指针,核心层spi控制器 ; **msg**: 结构体指针,Spi消息; **count**: uint32_t,消息个数 |HDF_STATUS相关状态|传输消息|
-> |SetCfg |**cntlr**: 结构体指针,核心层spi控制器 ; **cfg**: 结构体指针,Spi属性 |HDF_STATUS相关状态|设置控制器属性 |
-> |GetCfg |**cntlr**: 结构体指针,核心层spi控制器 ; **cfg**: 结构体指针,Spi属性 |HDF_STATUS相关状态|获取控制器属性 |
-> |Open |**cntlr**: 结构体指针,核心层spi控制器 ; |HDF_STATUS相关状态|打开SPI |
-> |Close |**cntlr**: 结构体指针,核心层spi控制器 ; |HDF_STATUS相关状态|关闭SPI |
-
-## 开发实例
-
-下方将以spi_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
-
-1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
-
- 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
-
-- SPI驱动入口参考
-
- ```c
- struct HdfDriverEntry g_hdfSpiDevice = {
- .moduleVersion = 1,
- .moduleName = "HDF_PLATFORM_SPI",//【必要 且与 HCS文件中里面的moduleName匹配】
- .Bind = HdfSpiDeviceBind, //见Bind参考
- .Init = HdfSpiDeviceInit, //见Init参考
- .Release = HdfSpiDeviceRelease, //见Release参考
- };
- //调用HDF_INIT将驱动入口注册到HDF框架中
- HDF_INIT(g_hdfSpiDevice);
- ```
-
-2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 spi_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层SpiCntlr 成员的默认值或限制范围有密切关系。
-**本例只有一个SPI控制器,如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在spi_config文件中增加对应的器件属性**。
-
-- device_info.hcs 配置参考
-
- ```c
- root {
- device_info {
- match_attr = "hdf_manager";
- platform :: host {
- hostName = "platform_host";
- priority = 50;
- device_spi :: device { //为每一个 SPI 控制器配置一个HDF设备节点
- device0 :: deviceNode {
- policy = 1;
- priority = 60;
- permission = 0644;
- moduleName = "HDF_PLATFORM_SPI";
- serviceName = "HDF_PLATFORM_SPI_0";
- deviceMatchAttr = "hisilicon_hi35xx_spi_0";
- }
- device1 :: deviceNode {
- policy = 1;
- priority = 60;
- permission = 0644;
- moduleName = "HDF_PLATFORM_SPI"; // 【必要】用于指定驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
- serviceName = "HDF_PLATFORM_SPI_1"; // 【必要且唯一】驱动对外发布服务的名称
- deviceMatchAttr = "hisilicon_hi35xx_spi_1";// 需要与设备hcs文件中的 match_attr 匹配
- }
- ...
- }
- }
- }
- }
- ```
-
-- spi_config.hcs 配置参考
-
- ```c
- root {
- platform {
- spi_config {//每一个SPI控制器配置私有数据
- template spi_controller {//模板公共参数, 继承该模板的节点如果使用模板中的默认值, 则节点字段可以缺省
- serviceName = "";
- match_attr = "";
- transferMode = 0; // 数据传输模式:中断传输(0),流控传输(1),DMA传输(2)
- busNum = 0; // 总线号
- clkRate = 100000000;
- bitsPerWord = 8; // 传输位宽
- mode = 19; // SPI 数据的输入输出模式
- maxSpeedHz = 0; // 最大时钟频率
- minSpeedHz = 0; // 最小时钟频率
- speed = 2000000; // 当前消息传输速度
- fifoSize = 256; // FIFO大小
- numCs = 1; // 片选号
- regBase = 0x120c0000; // 地址映射需要
- irqNum = 100; // 中断号
- REG_CRG_SPI = 0x120100e4; // CRG_REG_BASE(0x12010000) + 0x0e4
- CRG_SPI_CKEN = 0;
- CRG_SPI_RST = 0;
- REG_MISC_CTRL_SPI = 0x12030024; // MISC_REG_BASE(0x12030000) + 0x24
- MISC_CTRL_SPI_CS = 0;
- MISC_CTRL_SPI_CS_SHIFT = 0;
- }
- controller_0x120c0000 :: spi_controller {
- busNum = 0; //【必要】总线号
- CRG_SPI_CKEN = 0x10000; // (0x1 << 16) 0:close clk, 1:open clk
- CRG_SPI_RST = 0x1; // (0x1 << 0) 0:cancel reset, 1:reset
- match_attr = "hisilicon_hi35xx_spi_0";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致
- }
- controller_0x120c1000 :: spi_controller {
- busNum = 1;
- CRG_SPI_CKEN = 0x20000; // (0x1 << 17) 0:close clk, 1:open clk
- CRG_SPI_RST = 0x2; // (0x1 << 1) 0:cancel reset, 1:reset
- match_attr = "hisilicon_hi35xx_spi_1";
- regBase = 0x120c1000; //【必要】地址映射需要
- irqNum = 101; //【必要】中断号
- }
- ...
- // 【可选】可新增,但需要在 device_info.hcs 添加对应的节点
- }
- }
- }
- ```
-
-3. 完成驱动入口注册之后,最后一步就是以核心层SpiCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化SpiCntlr成员SpiCntlrMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)
-
-- 自定义结构体参考
-
- > 从驱动的角度看,自定义结构体是参数和数据的载体,而且spi_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号、总线号等。
-
- ```c
- struct Pl022 {//对应于hcs中的参数
- struct SpiCntlr *cntlr;
- struct DListHead deviceList;
- struct OsalSem sem;
- volatile unsigned char *phyBase;
- volatile unsigned char *regBase;
- uint32_t irqNum;
- uint32_t busNum;
- uint32_t numCs;
- uint32_t curCs;
- uint32_t speed;
- uint32_t fifoSize;
- uint32_t clkRate;
- uint32_t maxSpeedHz;
- uint32_t minSpeedHz;
- uint32_t regCrg;
- uint32_t clkEnBit;
- uint32_t clkRstBit;
- uint32_t regMiscCtrl;
- uint32_t miscCtrlCsShift;
- uint32_t miscCtrlCs;
- uint16_t mode;
- uint8_t bitsPerWord;
- uint8_t transferMode;
- };
-
- //SpiCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值
- struct SpiCntlr {
- struct IDeviceIoService service;
- struct HdfDeviceObject *device;
- uint32_t busNum;
- uint32_t numCs;
- uint32_t curCs;
- struct OsalMutex lock;
- struct SpiCntlrMethod *method;
- struct DListHead list;
- void *priv;
- };
- ```
-
-
-- **【重要】** SpiCntlr成员回调函数结构体SpiCntlrMethod的实例化,其他成员在Init函数中初始化
-
- ```c
- // spi_hi35xx.c 中的示例:钩子函数的实例化
- struct SpiCntlrMethod g_method = {
- .Transfer = Pl022Transfer,
- .SetCfg = Pl022SetCfg,
- .GetCfg = Pl022GetCfg,
- .Open = Pl022Open,
- .Close = Pl022Close,
- };
- ```
-
-
-- **Bind 函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态
- >
- > **函数说明:**
- > 将 SpiCntlr 对象同 HdfDeviceObject 进行了关联
-
- ```c
- static int32_t HdfSpiDeviceBind(struct HdfDeviceObject *device)
- {
- ...
- return (SpiCntlrCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;
- }
-
- struct SpiCntlr *SpiCntlrCreate(struct HdfDeviceObject *device)
- {
- struct SpiCntlr *cntlr = NULL; //创建核心层 SpiCntlr 对象
- ...
- cntlr = (struct SpiCntlr *)OsalMemCalloc(sizeof(*cntlr));//分配内存
- ...
- cntlr->device = device; //使HdfDeviceObject与SpiCntlr可以相互转化的前提
- device->service = &(cntlr->service);//使HdfDeviceObject与SpiCntlr可以相互转化的前提
- (void)OsalMutexInit(&cntlr->lock); //锁初始化
- DListHeadInit(&cntlr->list); //添加对应的节点
- cntlr->priv = NULL;
- return cntlr;
- }
- ```
-
-
-- **Init函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)
- >
- > |状态(值)|问题描述|
- > |:-|:-:|
- > |HDF_ERR_INVALID_OBJECT|控制器对象非法|
- > |HDF_ERR_MALLOC_FAIL |内存分配失败|
- > |HDF_ERR_INVALID_PARAM |参数非法|
- > |HDF_ERR_IO |I/O 错误|
- > |HDF_SUCCESS |初始化成功|
- > |HDF_FAILURE |初始化失败|
- >
- > **函数说明:**
- > 初始化自定义结构体对象,初始化SpiCntlr成员。
-
- ```c
- static int32_t HdfSpiDeviceInit(struct HdfDeviceObject *device)
- {
- int32_t ret;
- struct SpiCntlr *cntlr = NULL;
- ...
- cntlr = SpiCntlrFromDevice(device);//这里有HdfDeviceObject到SpiCntlr的强制转化,通过service成员,赋值见Bind函数
- //return (device == NULL) ? NULL : (struct SpiCntlr *)device->service;
- ...
- ret = Pl022Init(cntlr, device);//【必要】实例化厂商自定义操作对象,示例见下
- ...
- ret = Pl022Probe(cntlr->priv);
- ...
- return ret;
- }
-
- static int32_t Pl022Init(struct SpiCntlr *cntlr, const struct HdfDeviceObject *device)
- {
- int32_t ret;
- struct Pl022 *pl022 = NULL;
- ...
- pl022 = (struct Pl022 *)OsalMemCalloc(sizeof(*pl022));//申请内存
- ...
- ret = SpiGetBaseCfgFromHcs(pl022, device->property); //初始化busNum, numCs, speed, fifoSize, clkRate,
- //mode, bitsPerWord, transferMode参数值
- ...
- ret = SpiGetRegCfgFromHcs(pl022, device->property); //初始化regBase, phyBase, irqNum, regCrg, clkEnBit,
- //clkRstBit, regMiscCtrl, regMiscCtrl, miscCtrlCs,
- //miscCtrlCsShift参数值
- ...
- //计算最大,最小速度对应的频率
- pl022->maxSpeedHz = (pl022->clkRate) / ((SCR_MIN + 1) * CPSDVSR_MIN);
- pl022->minSpeedHz = (pl022->clkRate) / ((SCR_MAX + 1) * CPSDVSR_MAX);
- DListHeadInit(&pl022->deviceList);//初始化DList链表
- pl022->cntlr = cntlr; //使Pl022与SpiCntlr可以相互转化的前提
- cntlr->priv = pl022; //使Pl022与SpiCntlr可以相互转化的前提
- cntlr->busNum = pl022->busNum; //挂载总线号
- cntlr->method = &g_method; //SpiCntlrMethod的实例化对象的挂载
- ...
- ret = Pl022CreatAndInitDevice(pl022);
- if (ret != 0) {
- Pl022Release(pl022); //初始化失败就释放Pl022对象
- return ret;
- }
- return 0;
- }
- ```
-
-- **Release函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > 无
- >
- > **函数说明:**
- > 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
-
- ```c
- static void HdfSpiDeviceRelease(struct HdfDeviceObject *device)
- {
- struct SpiCntlr *cntlr = NULL;
- ...
- cntlr = SpiCntlrFromDevice(device);//这里有HdfDeviceObject到SpiCntlr的强制转化,通过service成员,赋值见Bind函数
- // return (device==NULL) ?NULL:(struct SpiCntlr *)device->service;
- ...
- if (cntlr->priv != NULL) {
- Pl022Remove((struct Pl022 *)cntlr->priv);//这里有SpiCntlr到Pl022的强制转化
- }
- SpiCntlrDestroy(cntlr); //释放Pl022对象
- }
- ```
+# SPI
+
+- [概述](#section84922229152909)
+- [接口说明](#section752964871810)
+- [开发步骤](#section799667984152909)
+- [开发实例](#section956157227152909)
+
+## 概述
+
+SPI是串行外设接口(Serial Peripheral Interface)的缩写,在HDF框架中,SPI的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
+
+**图 1** SPI独立服务模式结构图
+
+
+## 接口说明
+
+SpiCntlrMethod定义:
+
+```
+struct SpiCntlrMethod {
+ int32_t (*GetCfg)(struct SpiCntlr *cntlr, struct SpiCfg *cfg);
+ int32_t (*SetCfg)(struct SpiCntlr *cntlr, struct SpiCfg *cfg);
+ int32_t (*Transfer)(struct SpiCntlr *cntlr, struct SpiMsg *msg, uint32_t count);
+ int32_t (*Open)(struct SpiCntlr *cntlr);
+ int32_t (*Close)(struct SpiCntlr *cntlr);
+};
+```
+
+**表 1** SpiCntlrMethod结构体成员的回调函数功能说明
+
+
+成员函数
+ |
+入参
+ |
+返回值
+ |
+功能
+ |
+
+
+Transfer
+ |
+cntlr: 结构体指针,核心层spi控制器;msg: 结构体指针,Spi消息;count: uint32_t,消息个数
+ |
+HDF_STATUS相关状态
+ |
+传输消息
+ |
+
+SetCfg
+ |
+cntlr: 结构体指针,核心层spi控制器;cfg: 结构体指针,Spi属性
+ |
+HDF_STATUS相关状态
+ |
+设置控制器属性
+ |
+
+GetCfg
+ |
+cntlr: 结构体指针,核心层spi控制器;cfg: 结构体指针,Spi属性
+ |
+HDF_STATUS相关状态
+ |
+获取控制器属性
+ |
+
+Open
+ |
+cntlr: 结构体指针,核心层spi控制器;
+ |
+HDF_STATUS相关状态
+ |
+打开SPI
+ |
+
+Close
+ |
+cntlr: 结构体指针,核心层spi控制器;
+ |
+HDF_STATUS相关状态
+ |
+关闭SPI
+ |
+
+
+
+
+## 开发步骤
+
+SPI模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
+
+1. **实例化驱动入口:**
+ - 实例化HdfDriverEntry结构体成员。
+ - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
+
+2. **配置属性文件:**
+ - 在device\_info.hcs文件中添加deviceNode描述。
+ - 【可选】添加spi\_config.hcs器件属性文件。
+
+3. **实例化SPI控制器对象:**
+ - 初始化SpiCntlr成员。
+ - 实例化SpiCntlr成员SpiCntlrMethod。
+
+ > **说明:**
+ >实例化SpiCntlr成员SpiCntlrMethod,其定义和成员说明见[接口说明](#section752964871810)。
+
+
+4. **驱动调试:**
+
+ 【可选】针对新增驱动程序,建议验证驱动基本功能,例如spi控制状态,中断响应情况等。
+
+
+## 开发实例
+
+下方将以spi\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
+
+1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
+
+ 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
+
+ SPI驱动入口参考:
+
+ ```
+ struct HdfDriverEntry g_hdfSpiDevice = {
+ .moduleVersion = 1,
+ .moduleName = "HDF_PLATFORM_SPI",//【必要 且与 HCS文件中里面的moduleName匹配】
+ .Bind = HdfSpiDeviceBind, //见Bind参考
+ .Init = HdfSpiDeviceInit, //见Init参考
+ .Release = HdfSpiDeviceRelease, //见Release参考
+ };
+ //调用HDF_INIT将驱动入口注册到HDF框架中
+ HDF_INIT(g_hdfSpiDevice);
+ ```
+
+2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 spi\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层SpiCntlr 成员的默认值或限制范围有密切关系。
+
+ 本例只有一个SPI控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在spi\_config文件中增加对应的器件属性。
+
+ - device\_info.hcs 配置参考。
+
+ ```
+ root {
+ device_info {
+ match_attr = "hdf_manager";
+ platform :: host {
+ hostName = "platform_host";
+ priority = 50;
+ device_spi :: device { //为每一个 SPI 控制器配置一个HDF设备节点
+ device0 :: deviceNode {
+ policy = 1;
+ priority = 60;
+ permission = 0644;
+ moduleName = "HDF_PLATFORM_SPI";
+ serviceName = "HDF_PLATFORM_SPI_0";
+ deviceMatchAttr = "hisilicon_hi35xx_spi_0";
+ }
+ device1 :: deviceNode {
+ policy = 1;
+ priority = 60;
+ permission = 0644;
+ moduleName = "HDF_PLATFORM_SPI"; // 【必要】用于指定驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
+ serviceName = "HDF_PLATFORM_SPI_1"; // 【必要且唯一】驱动对外发布服务的名称
+ deviceMatchAttr = "hisilicon_hi35xx_spi_1";// 需要与设备hcs文件中的 match_attr 匹配
+ }
+ ...
+ }
+ }
+ }
+ }
+ ```
+
+ - spi\_config.hcs 配置参考。
+
+ ```
+ root {
+ platform {
+ spi_config {//每一个SPI控制器配置私有数据
+ template spi_controller {//模板公共参数, 继承该模板的节点如果使用模板中的默认值, 则节点字段可以缺省
+ serviceName = "";
+ match_attr = "";
+ transferMode = 0; // 数据传输模式:中断传输(0),流控传输(1),DMA传输(2)
+ busNum = 0; // 总线号
+ clkRate = 100000000;
+ bitsPerWord = 8; // 传输位宽
+ mode = 19; // SPI 数据的输入输出模式
+ maxSpeedHz = 0; // 最大时钟频率
+ minSpeedHz = 0; // 最小时钟频率
+ speed = 2000000; // 当前消息传输速度
+ fifoSize = 256; // FIFO大小
+ numCs = 1; // 片选号
+ regBase = 0x120c0000; // 地址映射需要
+ irqNum = 100; // 中断号
+ REG_CRG_SPI = 0x120100e4; // CRG_REG_BASE(0x12010000) + 0x0e4
+ CRG_SPI_CKEN = 0;
+ CRG_SPI_RST = 0;
+ REG_MISC_CTRL_SPI = 0x12030024; // MISC_REG_BASE(0x12030000) + 0x24
+ MISC_CTRL_SPI_CS = 0;
+ MISC_CTRL_SPI_CS_SHIFT = 0;
+ }
+ controller_0x120c0000 :: spi_controller {
+ busNum = 0; //【必要】总线号
+ CRG_SPI_CKEN = 0x10000; // (0x1 << 16) 0:close clk, 1:open clk
+ CRG_SPI_RST = 0x1; // (0x1 << 0) 0:cancel reset, 1:reset
+ match_attr = "hisilicon_hi35xx_spi_0";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致
+ }
+ controller_0x120c1000 :: spi_controller {
+ busNum = 1;
+ CRG_SPI_CKEN = 0x20000; // (0x1 << 17) 0:close clk, 1:open clk
+ CRG_SPI_RST = 0x2; // (0x1 << 1) 0:cancel reset, 1:reset
+ match_attr = "hisilicon_hi35xx_spi_1";
+ regBase = 0x120c1000; //【必要】地址映射需要
+ irqNum = 101; //【必要】中断号
+ }
+ ...
+ // 【可选】可新增,但需要在 device_info.hcs 添加对应的节点
+ }
+ }
+ }
+ ```
+
+3. 完成驱动入口注册之后,最后一步就是以核心层SpiCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化SpiCntlr成员SpiCntlrMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
+ - 自定义结构体参考。
+
+ 从驱动的角度看,自定义结构体是参数和数据的载体,而且spi\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号、总线号等。
+
+ ```
+ struct Pl022 {//对应于hcs中的参数
+ struct SpiCntlr *cntlr;
+ struct DListHead deviceList;
+ struct OsalSem sem;
+ volatile unsigned char *phyBase;
+ volatile unsigned char *regBase;
+ uint32_t irqNum;
+ uint32_t busNum;
+ uint32_t numCs;
+ uint32_t curCs;
+ uint32_t speed;
+ uint32_t fifoSize;
+ uint32_t clkRate;
+ uint32_t maxSpeedHz;
+ uint32_t minSpeedHz;
+ uint32_t regCrg;
+ uint32_t clkEnBit;
+ uint32_t clkRstBit;
+ uint32_t regMiscCtrl;
+ uint32_t miscCtrlCsShift;
+ uint32_t miscCtrlCs;
+ uint16_t mode;
+ uint8_t bitsPerWord;
+ uint8_t transferMode;
+ };
+
+ //SpiCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值
+ struct SpiCntlr {
+ struct IDeviceIoService service;
+ struct HdfDeviceObject *device;
+ uint32_t busNum;
+ uint32_t numCs;
+ uint32_t curCs;
+ struct OsalMutex lock;
+ struct SpiCntlrMethod *method;
+ struct DListHead list;
+ void *priv;
+ };
+ ```
+
+ - SpiCntlr成员回调函数结构体SpiCntlrMethod的实例化,其他成员在Init函数中初始化。
+
+ ```
+ // spi_hi35xx.c 中的示例:钩子函数的实例化
+ struct SpiCntlrMethod g_method = {
+ .Transfer = Pl022Transfer,
+ .SetCfg = Pl022SetCfg,
+ .GetCfg = Pl022GetCfg,
+ .Open = Pl022Open,
+ .Close = Pl022Close,
+ };
+ ```
+
+ - Bind 函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值**:**
+
+ HDF\_STATUS相关状态。
+
+ 函数说明**:**
+
+ 将 SpiCntlr 对象同 HdfDeviceObject 进行了关联。
+
+ ```
+ static int32_t HdfSpiDeviceBind(struct HdfDeviceObject *device)
+ {
+ ...
+ return (SpiCntlrCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;
+ }
+
+ struct SpiCntlr *SpiCntlrCreate(struct HdfDeviceObject *device)
+ {
+ struct SpiCntlr *cntlr = NULL; //创建核心层 SpiCntlr 对象
+ ...
+ cntlr = (struct SpiCntlr *)OsalMemCalloc(sizeof(*cntlr));//分配内存
+ ...
+ cntlr->device = device; //使HdfDeviceObject与SpiCntlr可以相互转化的前提
+ device->service = &(cntlr->service);//使HdfDeviceObject与SpiCntlr可以相互转化的前提
+ (void)OsalMutexInit(&cntlr->lock); //锁初始化
+ DListHeadInit(&cntlr->list); //添加对应的节点
+ cntlr->priv = NULL;
+ return cntlr;
+ }
+ ```
+
+ - Init函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值**:**
+
+ HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。
+
+ **表 2** init函数入参和返回值
+
+
+ 状态(值)
+ |
+ 问题描述
+ |
+
+
+ HDF_ERR_INVALID_OBJECT
+ |
+ 控制器对象非法
+ |
+
+ HDF_ERR_MALLOC_FAIL
+ |
+ 内存分配失败
+ |
+
+ HDF_ERR_INVALID_PARAM
+ |
+ 参数非法
+ |
+
+ HDF_ERR_IO
+ |
+ I/O 错误
+ |
+
+ HDF_SUCCESS
+ |
+ 初始化成功
+ |
+
+ HDF_FAILURE
+ |
+ 初始化失败
+ |
+
+
+
+
+ 函数说明**:**
+
+ 初始化自定义结构体对象,初始化SpiCntlr成员。
+
+ ```
+ static int32_t HdfSpiDeviceInit(struct HdfDeviceObject *device)
+ {
+ int32_t ret;
+ struct SpiCntlr *cntlr = NULL;
+ ...
+ cntlr = SpiCntlrFromDevice(device);//这里有HdfDeviceObject到SpiCntlr的强制转化,通过service成员,赋值见Bind函数
+ //return (device == NULL) ? NULL : (struct SpiCntlr *)device->service;
+ ...
+ ret = Pl022Init(cntlr, device);//【必要】实例化厂商自定义操作对象,示例见下
+ ...
+ ret = Pl022Probe(cntlr->priv);
+ ...
+ return ret;
+ }
+
+ static int32_t Pl022Init(struct SpiCntlr *cntlr, const struct HdfDeviceObject *device)
+ {
+ int32_t ret;
+ struct Pl022 *pl022 = NULL;
+ ...
+ pl022 = (struct Pl022 *)OsalMemCalloc(sizeof(*pl022));//申请内存
+ ...
+ ret = SpiGetBaseCfgFromHcs(pl022, device->property); //初始化busNum, numCs, speed, fifoSize, clkRate,mode, bitsPerWord, transferMode参数值
+ ...
+ ret = SpiGetRegCfgFromHcs(pl022, device->property); //初始化regBase, phyBase, irqNum, regCrg, clkEnBit,clkRstBit, regMiscCtrl, regMiscCtrl, miscCtrlCs,miscCtrlCsShift参数值
+ ...
+ //计算最大,最小速度对应的频率
+ pl022->maxSpeedHz = (pl022->clkRate) / ((SCR_MIN + 1) * CPSDVSR_MIN);
+ pl022->minSpeedHz = (pl022->clkRate) / ((SCR_MAX + 1) * CPSDVSR_MAX);
+ DListHeadInit(&pl022->deviceList);//初始化DList链表
+ pl022->cntlr = cntlr; //使Pl022与SpiCntlr可以相互转化的前提
+ cntlr->priv = pl022; //使Pl022与SpiCntlr可以相互转化的前提
+ cntlr->busNum = pl022->busNum; //给SpiCntlr的busNum赋值
+ cntlr->method = &g_method; //SpiCntlrMethod的实例化对象的挂载
+ ...
+ ret = Pl022CreatAndInitDevice(pl022);
+ if (ret != 0) {
+ Pl022Release(pl022); //初始化失败就释放Pl022对象
+ return ret;
+ }
+ return 0;
+ }
+ ```
+
+ - Release函数参考
+
+ 入参**:**
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ 无。
+
+ 函数说明:
+
+ 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
+
+ ```
+ static void HdfSpiDeviceRelease(struct HdfDeviceObject *device)
+ {
+ struct SpiCntlr *cntlr = NULL;
+ ...
+ cntlr = SpiCntlrFromDevice(device);//这里有HdfDeviceObject到SpiCntlr的强制转化,通过service成员,赋值见Bind函数
+ // return (device==NULL) ?NULL:(struct SpiCntlr *)device->service;
+ ...
+ if (cntlr->priv != NULL) {
+ Pl022Remove((struct Pl022 *)cntlr->priv);//这里有SpiCntlr到Pl022的强制转化
+ }
+ SpiCntlrDestroy(cntlr); //释放Pl022对象
+ }
+ ```
+
+
+
diff --git a/zh-cn/device-dev/driver/driver-platform-uart-des.md b/zh-cn/device-dev/driver/driver-platform-uart-des.md
index 182cad984a49051847129210d7cce9e9db7bbcdd..d094332869782c3d4bf9ec999fe44327939d19a8 100644
--- a/zh-cn/device-dev/driver/driver-platform-uart-des.md
+++ b/zh-cn/device-dev/driver/driver-platform-uart-des.md
@@ -1,8 +1,7 @@
-# UART
+# UART
- [概述](#section833012453535)
- - [接口说明](#section1680292311549)
-
+- [接口说明](#section1928742202715)
- [使用指导](#section12779050105412)
- [使用流程](#section1858116395510)
- [获取UART设备句柄](#section124512065617)
@@ -27,21 +26,17 @@
- RTS:发送请求信号,用于指示本设备是否准备好,可接受数据,和对端CTS相连;
- CTS:允许发送信号,用于判断是否可以向对端发送数据,和对端RTS相连;
- **图 1** 2线UART设备连接示意图
-
-
- 
-
- **图 2** 4线UART设备连接示意图
-
+ **图 1** 2线UART设备连接示意图
+ 
- 
+ **图 2** 4线UART设备连接示意图
+ 
- UART通信之前,收发双方需要约定好一些参数:波特率、数据格式(起始位、数据位、校验位、停止位)等。通信过程中,UART通过TX发送给对端数据,通过RX接收对端发送的数据。当UART接收缓存达到预定的门限值时,RTS变为不可发送数据,对端的CTS检测到不可发送数据,则停止发送数据。
- UART接口定义了操作UART端口的通用方法集合,包括获取、释放设备句柄、读写数据、获取和设置波特率、获取和设置设备属性。
-### 接口说明
+## 接口说明
**表 1** UART驱动API接口功能介绍
@@ -122,12 +117,10 @@
### 使用流程
-使用UART的一般流程如[图3](#fig1852173020185)所示。
-
-**图 3** UART使用流程图
-
+使用UART的一般流程如[图3](#fig99673244388)所示。
-
+**图 3** UART使用流程图
+
### 获取UART设备句柄
diff --git a/zh-cn/device-dev/driver/driver-platform-uart-develop.md b/zh-cn/device-dev/driver/driver-platform-uart-develop.md
index f087e7df7b4dc89607be5080d4d65822c5ecdf1a..03aca8344b3dfa0be34f75bfc1242c713687d23c 100755
--- a/zh-cn/device-dev/driver/driver-platform-uart-develop.md
+++ b/zh-cn/device-dev/driver/driver-platform-uart-develop.md
@@ -1,390 +1,547 @@
-# UART
-
-- [概述](#1)
-- [开发步骤](#2)
-- [开发实例](#3)
-
-## 概述
-
-UART是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)的缩写,在HDF框架中,uart的接口适配模式采用独立服务模式。在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。
-
-独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
-
-图 1 独立服务模式结构图
-
-
-## 开发步骤
-
-uart模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
-
-1. **实例化驱动入口:**
- - 实例化HdfDriverEntry结构体成员。
- - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
-
-2. **配置属性文件:**
-
- - 在device_info.hcs文件中添加deviceNode描述。
- - 【可选】添加uart_config.hcs器件属性文件。
-
-3. **实例化UART控制器对象:**
-
- - 初始化UartHost成员。
- - 实例化UartHost成员UartHostMethod,其定义和成员说明见下
-
-4. **驱动调试:**
- - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如UART控制状态,中断响应情况等。
-
->  **说明:**
-> UartHostMethod定义
->
-> ```c
-> struct UartHostMethod {
-> int32_t (*Init)(struct UartHost *host);
-> int32_t (*Deinit)(struct UartHost *host);
-> int32_t (*Read)(struct UartHost *host, uint8_t *data, uint32_t size);
-> int32_t (*Write)(struct UartHost *host, uint8_t *data, uint32_t size);
-> int32_t (*GetBaud)(struct UartHost *host, uint32_t *baudRate);
-> int32_t (*SetBaud)(struct UartHost *host, uint32_t baudRate);
-> int32_t (*GetAttribute)(struct UartHost *host, struct UartAttribute *attribute);
-> int32_t (*SetAttribute)(struct UartHost *host, struct UartAttribute *attribute);
-> int32_t (*SetTransMode)(struct UartHost *host, enum UartTransMode mode);
-> int32_t (*pollEvent)(struct UartHost *host, void *filep, void *table);
-> };
-> ```
->
-> 表1 UartHostMethod结构体成员的回调函数功能说明
->
-> |函数|入参|出参|返回值|功能|
-> |-|-|-|-|-|
-> |Init |**host**: 结构体指针,核心层uart控制器; |无|HDF_STATUS相关状态|初始化Uart设备|
-> |Deinit |**host**: 结构体指针,核心层uart控制器; |无|HDF_STATUS相关状态| 去初始化Uart设备 |
-> |Read |**host**: 结构体指针,核心层uart控制器; **size**:uint32_t,数据大小; |**data**: uint8_t指针,传出的数据 |HDF_STATUS相关状态|接收数据 RX |
-> |Write |**host**: 结构体指针,核心层uart控制器; **data**:uint8_t指针,传入数据; **size**:uint32_t,数据大小; |无|HDF_STATUS相关状态|发送数据 TX |
-> |SetBaud |**host**: 结构体指针,核心层uart控制器; **baudRate**: uint32_t指针,波特率传入值; |无|HDF_STATUS相关状态| 设置波特率 |
-> |GetBaud |**host**: 结构体指针,核心层uart控制器; |**baudRate**: uint32_t指针,传出的波特率; |HDF_STATUS相关状态|获取当前设置的波特率|
-> |GetAttribute |**host**: 结构体指针,核心层uart控制器; |**attribute**: 结构体指针,传出的属性值 (见uart_if.h中UartAttribute定义)|HDF_STATUS相关状态| 获取设备uart相关属性|
-> |SetAttribute |**host**: 结构体指针,核心层uart控制器; **attribute**: 结构体指针,属性传入值; |无|HDF_STATUS相关状态| 设置设备uart相关属性 |
-> |SetTransMode |**host**: 结构体指针,核心层uart控制器; **mode**: 枚举值(见uart_if.h中 UartTransMode定义),传输模式 |无|HDF_STATUS相关状态| 设置传输模式 |
-> |PollEvent |**host**: 结构体指针,核心层uart控制器; **filep**: void 指针,file ; **table**: void 指针,poll_table ;|无|HDF_STATUS相关状态|poll机制|
-
-
-## 开发实例
-
-下方将以uart_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
-
-1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
-
- 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
-
-- UART驱动入口参考
-
- ```c
- struct HdfDriverEntry g_hdfUartDevice = {
- .moduleVersion = 1,
- .moduleName = "HDF_PLATFORM_UART",//【必要且与 HCS 里面的名字匹配】
- .Bind = HdfUartDeviceBind, //见Bind参考
- .Init = HdfUartDeviceInit, //见Init参考
- .Release = HdfUartDeviceRelease, //见Release参考
- };
- //调用HDF_INIT将驱动入口注册到HDF框架中
- HDF_INIT(g_hdfUartDevice);
- ```
-
-2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 uart_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层UartHost成员的默认值或限制范围有密切关系。
-
- **本例只有一个UART控制器,如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在uart_config文件中增加对应的器件属性**。
-
-- device_info.hcs 配置参考
-
- ```c
- root {
- device_info {
- match_attr = "hdf_manager";
- platform :: host {
- hostName = "platform_host";
- priority = 50;
- device_uart :: device {
- device0 :: deviceNode {
- policy = 1; //驱动服务发布的策略,policy大于等于1(用户态可见为2,仅内核态可见为1);
- priority = 40; //驱动启动优先级
- permission = 0644; //驱动创建设备节点权限
- moduleName = "HDF_PLATFORM_UART"; //驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
- serviceName = "HDF_PLATFORM_UART_0";//驱动对外发布服务的名称,必须唯一,必须要按照HDF_PLATFORM_UART_X的格式,X为UART控制器编号
- deviceMatchAttr = "hisilicon_hi35xx_uart_0";//驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值一致
- }
- device1 :: deviceNode {
- policy = 2;
- permission = 0644;
- priority = 40;
- moduleName = "HDF_PLATFORM_UART";
- serviceName = "HDF_PLATFORM_UART_1";
- deviceMatchAttr = "hisilicon_hi35xx_uart_1";
- }
- ...
- }
- }
- }
- }
- ```
-
-- uart_config.hcs 配置参考
-
- ```c
- root {
- platform {
- template uart_controller {//模板公共参数, 继承该模板的节点如果使用模板中的默认值, 则节点字段可以缺省
- match_attr = "";
- num = 0; //【必要】设备号
- baudrate = 115200; //【必要】波特率,数值可按需填写
- fifoRxEn = 1; //【必要】使能接收FIFO
- fifoTxEn = 1; //【必要】使能发送FIFO
- flags = 4; //【必要】标志信号
- regPbase = 0x120a0000; //【必要】地址映射需要
- interrupt = 38; //【必要】中断号
- iomemCount = 0x48; //【必要】地址映射需要
- }
- controller_0x120a0000 :: uart_controller {
- match_attr = "hisilicon_hi35xx_uart_0";//【必要】必须和device_info.hcs中对应的设备的deviceMatchAttr值一致
- }
- controller_0x120a1000 :: uart_controller {
- num = 1;
- baudrate = 9600;
- regPbase = 0x120a1000;
- interrupt = 39;
- match_attr = "hisilicon_hi35xx_uart_1";
- }
- ...
- // 【可选】可新增,但需要在 device_info.hcs 添加对应的节点
- }
- }
- ```
-
-3. 完成驱动入口注册之后,最后一步就是以核心层UartHost对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化UartHost成员UartHostMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)
-
-- 自定义结构体参考
-
- > 从驱动的角度看,自定义结构体是参数和数据的载体,而且uart_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号等。
-
- ```c
- struct UartPl011Port { //接口相关的结构体
- int32_t enable;
- unsigned long physBase; //物理地址
- uint32_t irqNum; //中断号
- uint32_t defaultBaudrate;//默认波特率
- uint32_t flags; //标志信号,下面三个宏与之相关
- #define PL011_FLG_IRQ_REQUESTED (1 << 0)
- #define PL011_FLG_DMA_RX_REQUESTED (1 << 1)
- #define PL011_FLG_DMA_TX_REQUESTED (1 << 2)
- struct UartDmaTransfer *rxUdt; //DMA传输相关
- struct UartDriverData *udd; //见下
- };
- struct UartDriverData { //数据传输相关的结构体
- uint32_t num;
- uint32_t baudrate; //波特率(可设置)
- struct UartAttribute attr; //数据位、停止位等传输属性相关
- struct UartTransfer *rxTransfer; //缓冲区相关,可理解为FIFO结构
- wait_queue_head_t wait; //条件变量相关的排队等待信号
- int32_t count; //数据数量
- int32_t state; //uart控制器状态
- #define UART_STATE_NOT_OPENED 0
- #define UART_STATE_OPENING 1
- #define UART_STATE_USEABLE 2
- #define UART_STATE_SUSPENED 3
- uint32_t flags; //状态标志
- #define UART_FLG_DMA_RX (1 << 0)
- #define UART_FLG_DMA_TX (1 << 1)
- #define UART_FLG_RD_BLOCK (1 << 2)
- RecvNotify recv; //函数指针类型,指向串口数据接收函数
- struct UartOps *ops; //自定义函数指针结构体,详情见device/hisilicon/drivers/uart/uart_pl011.c
- void *private; //一般用来存储UartPl011Port首地址,方便调用
- };
-
- // UartHost是核心层控制器结构体,其中的成员在Init函数中会被赋值
- struct UartHost {
- struct IDeviceIoService service;
- struct HdfDeviceObject *device;
- uint32_t num;
- OsalAtomic atom;
- void *priv; //一般存储厂商自定义结构体首地址,方便后者被调用
- struct UartHostMethod *method; //核心层钩子函数,厂商需要实现其成员函数功能并实例化
- };
- ```
-
-- **【重要】** UartHost成员回调函数结构体UartHostMethod的实例化,其他成员在Bind函数中初始化
-
- ```c
- // uart_hi35xx.c 中的示例:钩子函数的实例化
- struct UartHostMethod g_uartHostMethod = {
- .Init = Hi35xxInit,
- .Deinit = Hi35xxDeinit,
- .Read = Hi35xxRead,
- .Write = Hi35xxWrite,
- .SetBaud = Hi35xxSetBaud,
- .GetBaud = Hi35xxGetBaud,
- .SetAttribute = Hi35xxSetAttribute,
- .GetAttribute = Hi35xxGetAttribute,
- .SetTransMode = Hi35xxSetTransMode,
- .pollEvent = Hi35xxPollEvent,
- };
- ```
-
-
-- **Bind函数参考**
-
- > **入参:**
- > HdfDeviceObject 这个是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)
- >
- > |状态(值)|问题描述|
- > |:-|:-:|
- > |HDF_ERR_INVALID_OBJECT|控制器对象非法|
- > |HDF_ERR_MALLOC_FAIL |内存分配失败|
- > |HDF_ERR_INVALID_PARAM |参数非法|
- > |HDF_ERR_IO |I/O 错误|
- > |HDF_SUCCESS |初始化成功|
- > |HDF_FAILURE |初始化失败|
- >
- > **函数说明:**
- > 初始化自定义结构体对象,初始化UartHost成员
-
- ```c
- //uart_hi35xx.c
- static int32_t HdfUartDeviceBind(struct HdfDeviceObject *device)
- {
- ...
- return (UartHostCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;//【必须做】调用核心层函数 UartHostCreate
- }
- //uart_core.c 核心层 UartHostCreate 函数说明
- struct UartHost *UartHostCreate(struct HdfDeviceObject *device)
- {
- struct UartHost *host = NULL; //新建 UartHost
- ...
- host = (struct UartHost *)OsalMemCalloc(sizeof(*host));//分配内存
- ...
- host->device = device; //【必要】使HdfDeviceObject与UartHost可以相互转化的前提
- device->service = &(host->service);//【必要】使HdfDeviceObject与UartHost可以相互转化的前提
- host->device->service->Dispatch = UartIoDispatch;//为 service 成员的 Dispatch 方法赋值
- OsalAtomicSet(&host->atom, 0); //原子量初始化或者原子量设置
- host->priv = NULL;
- host->method = NULL;
- return host;
- }
- ```
-
-
-- **Init函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > HDF_STATUS相关状态
- >
- > **函数说明:**
- > 初始化自定义结构体对象,初始化UartHost成员,调用核心层UartAddDev函数,接入VFS
-
- ```c
- int32_t HdfUartDeviceInit(struct HdfDeviceObject *device)
- {
- int32_t ret;
- struct UartHost *host = NULL;
- HDF_LOGI("%s: entry", __func__);
- ...
- host = UartHostFromDevice(device);//通过service成员后强制转为UartHost,赋值是在Bind函数中
- ...
- ret = Hi35xxAttach(host, device); //完成UartHost对象的初始化,见下
- ...
- host->method = &g_uartHostMethod; //UartHostMethod的实例化对象的挂载
- return ret;
- }
- //完成 UartHost 对象的初始化
- static int32_t Hi35xxAttach(struct UartHost *host, struct HdfDeviceObject *device)
- {
- int32_t ret;
- //udd 和 port 对象是厂商自定义的结构体对象,可根据需要实现相关功能
- struct UartDriverData *udd = NULL;
- struct UartPl011Port *port = NULL;
- ...
- // 【必要相关功能】步骤【1】~【7】主要实现对 udd 对象的实例化赋值,然后赋值给核心层UartHost对象上
- udd = (struct UartDriverData *)OsalMemCalloc(sizeof(*udd));//【1】
- ...
- port = (struct UartPl011Port *)OsalMemCalloc(sizeof(struct UartPl011Port));//【2】
- ...
- udd->ops = Pl011GetOps();//【3】设备开启、关闭、属性设置、发送操作等函数挂载
- udd->recv = PL011UartRecvNotify;//【4】数据接收通知函数(条件锁机制)挂载
- udd->count = 0; //【5】
- port->udd = udd; //【6】使UartPl011Port与UartDriverData可以相互转化的前提
- ret = UartGetConfigFromHcs(port, device->property);//【必要】 此步骤是将 HdfDeviceObject 的属性传递给厂商自定义结构体
- // 用于相关操作,示例代码见下
- ...
- udd->private = port; //【7】
-
- host->priv = udd; //【必要】使UartHost与UartDriverData可以相互转化的前提
- host->num = udd->num;//【必要】uart 设备号
- UartAddDev(host); //【必要】核心层uart_dev.c 中的函数,作用:注册了一个字符设备节点到vfs, 这样从用户态可以通过这个虚拟文件节点访问uart
- return HDF_SUCCESS;
- }
-
- static int32_t UartGetConfigFromHcs(struct UartPl011Port *port, const struct DeviceResourceNode *node)
- {
- uint32_t tmp, regPbase, iomemCount;
- struct UartDriverData *udd = port->udd;
- struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
- ...
- //通过请求参数提取相应的值,并赋值给厂商自定义的结构体
- if (iface->GetUint32(node, "num", &udd->num, 0) != HDF_SUCCESS) {
- HDF_LOGE("%s: read busNum fail", __func__);
- return HDF_FAILURE;
- }
- ...
- return 0;
- }
- ```
-
-- **Release函数参考**
-
- > **入参:**
- > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
- >
- > **返回值:**
- > 无
- >
- > **函数说明:**
- > 该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源, 该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
-
- ```c
- void HdfUartDeviceRelease(struct HdfDeviceObject *device)
- {
- struct UartHost *host = NULL;
- ...
- host = UartHostFromDevice(device);//这里有HdfDeviceObject到UartHost的强制转化,通过service成员,赋值见Bind函数
- ...
- if (host->priv != NULL) {
- Hi35xxDetach(host); //厂商自定义的内存释放函数,见下
- }
- UartHostDestroy(host); //调用核心层函数释放host
- }
-
- static void Hi35xxDetach(struct UartHost *host)
- {
- struct UartDriverData *udd = NULL;
- struct UartPl011Port *port = NULL;
- ...
- udd = host->priv; //这里有UartHost到UartDriverData的转化
- ...
- UartRemoveDev(host);//VFS注销
- port = udd->private;//这里有UartDriverData到UartPl011Port的转化
- if (port != NULL) {
- if (port->physBase != 0) {
- OsalIoUnmap((void *)port->physBase);//地址反映射
- }
- (void)OsalMemFree(port);
- udd->private = NULL;
- }
- (void)OsalMemFree(udd);//释放UartDriverData
- host->priv = NULL;
- }
- ```
-
+# UART
+
+- [概述](#section1761881586154520)
+- [接口说明](#section752964871810)
+- [开发步骤](#section944397404154520)
+- [开发实例](#section774610224154520)
+
+## 概述
+
+UART是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)的缩写,在HDF框架中,UART的接口适配模式采用独立服务模式。在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
+
+**图 1** UART独立服务模式结构图
+
+
+## 接口说明
+
+UartHostMethod定义:
+
+```
+struct UartHostMethod {
+ int32_t (*Init)(struct UartHost *host);
+ int32_t (*Deinit)(struct UartHost *host);
+ int32_t (*Read)(struct UartHost *host, uint8_t *data, uint32_t size);
+ int32_t (*Write)(struct UartHost *host, uint8_t *data, uint32_t size);
+ int32_t (*GetBaud)(struct UartHost *host, uint32_t *baudRate);
+ int32_t (*SetBaud)(struct UartHost *host, uint32_t baudRate);
+ int32_t (*GetAttribute)(struct UartHost *host, struct UartAttribute *attribute);
+ int32_t (*SetAttribute)(struct UartHost *host, struct UartAttribute *attribute);
+ int32_t (*SetTransMode)(struct UartHost *host, enum UartTransMode mode);
+ int32_t (*pollEvent)(struct UartHost *host, void *filep, void *table);
+};
+```
+
+**表 1** UartHostMethod结构体成员的回调函数功能说明
+
+
+函数
+ |
+入参
+ |
+出参
+ |
+返回值
+ |
+功能
+ |
+
+
+Init
+ |
+host: 结构体指针,核心层uart控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+初始化Uart设备
+ |
+
+Deinit
+ |
+host: 结构体指针,核心层uart控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+去初始化Uart设备
+ |
+
+Read
+ |
+host: 结构体指针,核心层uart控制器;size:uint32_t,数据大小;
+ |
+data: uint8_t指针,传出的数据
+ |
+HDF_STATUS相关状态
+ |
+接收数据 RX
+ |
+
+Write
+ |
+host: 结构体指针,核心层uart控制器;data:uint8_t指针,传入数据;size:uint32_t,数据大小;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+发送数据 TX
+ |
+
+SetBaud
+ |
+host: 结构体指针,核心层uart控制器;baudRate: uint32_t指针,波特率传入值;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+设置波特率
+ |
+
+GetBaud
+ |
+host: 结构体指针,核心层uart控制器;
+ |
+baudRate: uint32_t指针,传出的波特率;
+ |
+HDF_STATUS相关状态
+ |
+获取当前设置的波特率
+ |
+
+GetAttribute
+ |
+host: 结构体指针,核心层uart控制器;
+ |
+attribute: 结构体指针,传出的属性值(见uart_if.h中UartAttribute定义)
+ |
+HDF_STATUS相关状态
+ |
+获取设备uart相关属性
+ |
+
+SetAttribute
+ |
+host: 结构体指针,核心层uart控制器;attribute: 结构体指针,属性传入值;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+设置设备uart相关属性
+ |
+
+SetTransMode
+ |
+host: 结构体指针,核心层uart控制器;mode: 枚举值(见uart_if.h中UartTransMode定义),传输模式
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+设置传输模式
+ |
+
+PollEvent
+ |
+host: 结构体指针,核心层uart控制器;filep: void 指针,file ;table: void 指针,poll_table ;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+poll机制
+ |
+
+
+
+
+## 开发步骤
+
+UART模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
+
+1. **实例化驱动入口:**
+ - 实例化HdfDriverEntry结构体成员。
+ - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
+
+2. **配置属性文件:**
+ - 在device\_info.hcs文件中添加deviceNode描述。
+ - 【可选】添加uart\_config.hcs器件属性文件。
+
+3. **实例化UART控制器对象:**
+ - 初始化UartHost成员。
+ - 实例化UartHost成员UartHostMethod。
+
+ > **说明:**
+ >实例化UartHost成员UartHostMethod,其定义和成员说明见[接口说明](#section752964871810)。
+
+
+4. **驱动调试:**
+
+ 【可选】针对新增驱动程序,建议验证驱动基本功能,例如UART控制状态,中断响应情况等。
+
+
+## 开发实例
+
+下方将以uart\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
+
+1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
+
+ 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
+
+ UART驱动入口参考:
+
+ ```
+ struct HdfDriverEntry g_hdfUartDevice = {
+ .moduleVersion = 1,
+ .moduleName = "HDF_PLATFORM_UART",//【必要且与 HCS 里面的名字匹配】
+ .Bind = HdfUartDeviceBind, //见Bind参考
+ .Init = HdfUartDeviceInit, //见Init参考
+ .Release = HdfUartDeviceRelease, //见Release参考
+ };
+ //调用HDF_INIT将驱动入口注册到HDF框架中
+ HDF_INIT(g_hdfUartDevice);
+ ```
+
+2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 uart\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层UartHost成员的默认值或限制范围有密切关系。
+
+ 本例只有一个UART控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在uart\_config文件中增加对应的器件属性。
+
+ - device\_info.hcs 配置参考。
+
+ ```
+ root {
+ device_info {
+ match_attr = "hdf_manager";
+ platform :: host {
+ hostName = "platform_host";
+ priority = 50;
+ device_uart :: device {
+ device0 :: deviceNode {
+ policy = 1; //驱动服务发布的策略,policy大于等于1(用户态可见为2,仅内核态可见为1);
+ priority = 40; //驱动启动优先级
+ permission = 0644; //驱动创建设备节点权限
+ moduleName = "HDF_PLATFORM_UART"; //驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
+ serviceName = "HDF_PLATFORM_UART_0";//驱动对外发布服务的名称,必须唯一,必须要按照HDF_PLATFORM_UART_X的格式,X为UART控制器编号
+ deviceMatchAttr = "hisilicon_hi35xx_uart_0";//驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值一致
+ }
+ device1 :: deviceNode {
+ policy = 2;
+ permission = 0644;
+ priority = 40;
+ moduleName = "HDF_PLATFORM_UART";
+ serviceName = "HDF_PLATFORM_UART_1";
+ deviceMatchAttr = "hisilicon_hi35xx_uart_1";
+ }
+ ...
+ }
+ }
+ }
+ }
+ ```
+
+ - uart\_config.hcs 配置参考。
+
+ ```
+ root {
+ platform {
+ template uart_controller {//模板公共参数, 继承该模板的节点如果使用模板中的默认值, 则节点字段可以缺省
+ match_attr = "";
+ num = 0; //【必要】设备号
+ baudrate = 115200; //【必要】波特率,数值可按需填写
+ fifoRxEn = 1; //【必要】使能接收FIFO
+ fifoTxEn = 1; //【必要】使能发送FIFO
+ flags = 4; //【必要】标志信号
+ regPbase = 0x120a0000; //【必要】地址映射需要
+ interrupt = 38; //【必要】中断号
+ iomemCount = 0x48; //【必要】地址映射需要
+ }
+ controller_0x120a0000 :: uart_controller {
+ match_attr = "hisilicon_hi35xx_uart_0";//【必要】必须和device_info.hcs中对应的设备的deviceMatchAttr值一致
+ }
+ controller_0x120a1000 :: uart_controller {
+ num = 1;
+ baudrate = 9600;
+ regPbase = 0x120a1000;
+ interrupt = 39;
+ match_attr = "hisilicon_hi35xx_uart_1";
+ }
+ ...
+ // 【可选】可新增,但需要在 device_info.hcs 添加对应的节点
+ }
+ }
+ ```
+
+3. 完成驱动入口注册之后,最后一步就是以核心层UartHost对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化UartHost成员UartHostMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
+ - 自定义结构体参考。
+
+ 从驱动的角度看,自定义结构体是参数和数据的载体,而且uart\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号等。
+
+ ```
+ struct UartPl011Port { //接口相关的结构体
+ int32_t enable;
+ unsigned long physBase; //物理地址
+ uint32_t irqNum; //中断号
+ uint32_t defaultBaudrate;//默认波特率
+ uint32_t flags; //标志信号,下面三个宏与之相关
+ #define PL011_FLG_IRQ_REQUESTED (1 << 0)
+ #define PL011_FLG_DMA_RX_REQUESTED (1 << 1)
+ #define PL011_FLG_DMA_TX_REQUESTED (1 << 2)
+ struct UartDmaTransfer *rxUdt; //DMA传输相关
+ struct UartDriverData *udd; //见下
+ };
+ struct UartDriverData { //数据传输相关的结构体
+ uint32_t num;
+ uint32_t baudrate; //波特率(可设置)
+ struct UartAttribute attr; //数据位、停止位等传输属性相关
+ struct UartTransfer *rxTransfer; //缓冲区相关,可理解为FIFO结构
+ wait_queue_head_t wait; //条件变量相关的排队等待信号
+ int32_t count; //数据数量
+ int32_t state; //uart控制器状态
+ #define UART_STATE_NOT_OPENED 0
+ #define UART_STATE_OPENING 1
+ #define UART_STATE_USEABLE 2
+ #define UART_STATE_SUSPENED 3
+ uint32_t flags; //状态标志
+ #define UART_FLG_DMA_RX (1 << 0)
+ #define UART_FLG_DMA_TX (1 << 1)
+ #define UART_FLG_RD_BLOCK (1 << 2)
+ RecvNotify recv; //函数指针类型,指向串口数据接收函数
+ struct UartOps *ops; //自定义函数指针结构体,详情见device/hisilicon/drivers/uart/uart_pl011.c
+ void *private; //一般用来存储UartPl011Port首地址,方便调用
+ };
+
+ // UartHost是核心层控制器结构体,其中的成员在Init函数中会被赋值
+ struct UartHost {
+ struct IDeviceIoService service;
+ struct HdfDeviceObject *device;
+ uint32_t num;
+ OsalAtomic atom;
+ void *priv; //一般存储厂商自定义结构体首地址,方便后者被调用
+ struct UartHostMethod *method; //核心层钩子函数,厂商需要实现其成员函数功能并实例化
+ };
+ ```
+
+ - UartHost成员回调函数结构体UartHostMethod的实例化,其他成员在Bind函数中初始化。
+
+ ```
+ // uart_hi35xx.c 中的示例:钩子函数的实例化
+ struct UartHostMethod g_uartHostMethod = {
+ .Init = Hi35xxInit,
+ .Deinit = Hi35xxDeinit,
+ .Read = Hi35xxRead,
+ .Write = Hi35xxWrite,
+ .SetBaud = Hi35xxSetBaud,
+ .GetBaud = Hi35xxGetBaud,
+ .SetAttribute = Hi35xxSetAttribute,
+ .GetAttribute = Hi35xxGetAttribute,
+ .SetTransMode = Hi35xxSetTransMode,
+ .pollEvent = Hi35xxPollEvent,
+ };
+ ```
+
+ - Bind函数参考
+
+ 入参:
+
+ HdfDeviceObject 这个是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ **返回值:**
+
+ HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。
+
+ **表 2** Bind函数入参和返回值
+
+
+ 状态(值)
+ |
+ 问题描述
+ |
+
+
+ HDF_ERR_INVALID_OBJECT
+ |
+ 控制器对象非法
+ |
+
+ HDF_ERR_MALLOC_FAIL
+ |
+ 内存分配失败
+ |
+
+ HDF_ERR_INVALID_PARAM
+ |
+ 参数非法
+ |
+
+ HDF_ERR_IO
+ |
+ I/O 错误
+ |
+
+ HDF_SUCCESS
+ |
+ 初始化成功
+ |
+
+ HDF_FAILURE
+ |
+ 初始化失败
+ |
+
+
+
+
+ 函数说明:
+
+ 初始化自定义结构体对象,初始化UartHost成员。
+
+ ```
+ //uart_hi35xx.c
+ static int32_t HdfUartDeviceBind(struct HdfDeviceObject *device)
+ {
+ ...
+ return (UartHostCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;//【必须做】调用核心层函数 UartHostCreate
+ }
+ //uart_core.c 核心层 UartHostCreate 函数说明
+ struct UartHost *UartHostCreate(struct HdfDeviceObject *device)
+ {
+ struct UartHost *host = NULL; //新建 UartHost
+ ...
+ host = (struct UartHost *)OsalMemCalloc(sizeof(*host));//分配内存
+ ...
+ host->device = device; //【必要】使HdfDeviceObject与UartHost可以相互转化的前提
+ device->service = &(host->service);//【必要】使HdfDeviceObject与UartHost可以相互转化的前提
+ host->device->service->Dispatch = UartIoDispatch;//为 service 成员的 Dispatch 方法赋值
+ OsalAtomicSet(&host->atom, 0); //原子量初始化或者原子量设置
+ host->priv = NULL;
+ host->method = NULL;
+ return host;
+ }
+ ```
+
+ - Init函数参考
+
+ 入参**:**
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ HDF\_STATUS相关状态。
+
+ 函数说明:
+
+ 初始化自定义结构体对象,初始化UartHost成员,调用核心层UartAddDev函数,接入VFS。
+
+ ```
+ int32_t HdfUartDeviceInit(struct HdfDeviceObject *device)
+ {
+ int32_t ret;
+ struct UartHost *host = NULL;
+ HDF_LOGI("%s: entry", __func__);
+ ...
+ host = UartHostFromDevice(device);//通过service成员后强制转为UartHost,赋值是在Bind函数中
+ ...
+ ret = Hi35xxAttach(host, device); //完成UartHost对象的初始化,见下
+ ...
+ host->method = &g_uartHostMethod; //UartHostMethod的实例化对象的挂载
+ return ret;
+ }
+ //完成 UartHost 对象的初始化
+ static int32_t Hi35xxAttach(struct UartHost *host, struct HdfDeviceObject *device)
+ {
+ int32_t ret;
+ //udd 和 port 对象是厂商自定义的结构体对象,可根据需要实现相关功能
+ struct UartDriverData *udd = NULL;
+ struct UartPl011Port *port = NULL;
+ ...
+ // 【必要相关功能】步骤【1】~【7】主要实现对 udd 对象的实例化赋值,然后赋值给核心层UartHost对象上
+ udd = (struct UartDriverData *)OsalMemCalloc(sizeof(*udd));//【1】
+ ...
+ port = (struct UartPl011Port *)OsalMemCalloc(sizeof(struct UartPl011Port));//【2】
+ ...
+ udd->ops = Pl011GetOps();//【3】设备开启、关闭、属性设置、发送操作等函数挂载
+ udd->recv = PL011UartRecvNotify;//【4】数据接收通知函数(条件锁机制)挂载
+ udd->count = 0; //【5】
+ port->udd = udd; //【6】使UartPl011Port与UartDriverData可以相互转化的前提
+ ret = UartGetConfigFromHcs(port, device->property);//【必要】 此步骤是将 HdfDeviceObject 的属性传递给厂商自定义结构体
+ // 用于相关操作,示例代码见下
+ ...
+ udd->private = port; //【7】
+
+ host->priv = udd; //【必要】使UartHost与UartDriverData可以相互转化的前提
+ host->num = udd->num;//【必要】uart 设备号
+ UartAddDev(host); //【必要】核心层uart_dev.c 中的函数,作用:注册了一个字符设备节点到vfs, 这样从用户态可以通过这个虚拟文件节点访问uart
+ return HDF_SUCCESS;
+ }
+
+ static int32_t UartGetConfigFromHcs(struct UartPl011Port *port, const struct DeviceResourceNode *node)
+ {
+ uint32_t tmp, regPbase, iomemCount;
+ struct UartDriverData *udd = port->udd;
+ struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
+ ...
+ //通过请求参数提取相应的值,并赋值给厂商自定义的结构体
+ if (iface->GetUint32(node, "num", &udd->num, 0) != HDF_SUCCESS) {
+ HDF_LOGE("%s: read busNum fail", __func__);
+ return HDF_FAILURE;
+ }
+ ...
+ return 0;
+ }
+ ```
+
+ - Release函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ 无。
+
+ 函数说明:
+
+ 该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源, 该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
+
+ ```
+ void HdfUartDeviceRelease(struct HdfDeviceObject *device)
+ {
+ struct UartHost *host = NULL;
+ ...
+ host = UartHostFromDevice(device);//这里有HdfDeviceObject到UartHost的强制转化,通过service成员,赋值见Bind函数
+ ...
+ if (host->priv != NULL) {
+ Hi35xxDetach(host); //厂商自定义的内存释放函数,见下
+ }
+ UartHostDestroy(host); //调用核心层函数释放host
+ }
+
+ static void Hi35xxDetach(struct UartHost *host)
+ {
+ struct UartDriverData *udd = NULL;
+ struct UartPl011Port *port = NULL;
+ ...
+ udd = host->priv; //这里有UartHost到UartDriverData的转化
+ ...
+ UartRemoveDev(host);//VFS注销
+ port = udd->private;//这里有UartDriverData到UartPl011Port的转化
+ if (port != NULL) {
+ if (port->physBase != 0) {
+ OsalIoUnmap((void *)port->physBase);//地址反映射
+ }
+ (void)OsalMemFree(port);
+ udd->private = NULL;
+ }
+ (void)OsalMemFree(udd);//释放UartDriverData
+ host->priv = NULL;
+ }
+ ```
+
+
+
diff --git a/zh-cn/device-dev/driver/driver-platform-watchdog-des.md b/zh-cn/device-dev/driver/driver-platform-watchdog-des.md
index 57f2d55bc5fb03474aad9ff7042334c214ec7632..fcc46c34fcc16906c9f15e55016aea94513f3f58 100644
--- a/zh-cn/device-dev/driver/driver-platform-watchdog-des.md
+++ b/zh-cn/device-dev/driver/driver-platform-watchdog-des.md
@@ -1,8 +1,7 @@
-# WATCHDOG
+# WATCHDOG
- [概述](#section14918241977)
- - [接口说明](#section20177131219818)
-
+- [接口说明](#section1180575010271)
- [使用指导](#section10103184312813)
- [使用流程](#section10181195910815)
- [打开看门狗设备](#section66089201107)
@@ -20,7 +19,7 @@
看门狗(watchdog),又叫看门狗计时器(watchdog timer),是一种硬件的计时设备,当系统的主程序发生某些错误时,导致未及时清除看门狗计时器的计时值,这时看门狗计时器就会对系统发出复位信号,使系统从悬停状态恢复到正常运作状态。
-### 接口说明
+## 接口说明
**表 1** 看门狗 API接口功能介绍
@@ -93,12 +92,10 @@
### 使用流程
-使用看门狗的一般流程如[图1](#fig19134125410189)所示。
-
-**图 1** 看门狗使用流程图
-
+使用看门狗的一般流程如[图1](#fig430533913392)所示。
-
+**图 1** 看门狗使用流程图
+
### 打开看门狗设备
diff --git a/zh-cn/device-dev/driver/driver-platform-watchdog-develop.md b/zh-cn/device-dev/driver/driver-platform-watchdog-develop.md
index 85f75ad85201fdea2ea2ef35c9d69b300e87ee80..dbfcba6136a653dfa85e047b05555d4f75601793 100755
--- a/zh-cn/device-dev/driver/driver-platform-watchdog-develop.md
+++ b/zh-cn/device-dev/driver/driver-platform-watchdog-develop.md
@@ -1,253 +1,365 @@
-# WatchDog
-
-- [概述](#1)
-- [开发步骤](#2)
-- [开发实例](#3)
-
-## 概述
-
-看门狗(Watchdog),又叫看门狗计时器(Watchdog timer),是一种硬件的计时设备,在HDF框架中,Watchdog接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。
-
-独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
-
-图 1 独立服务模式结构图
-
-
-## 开发步骤
-
-Watchdog模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
-
-1. **实例化驱动入口:**
- - 实例化HdfDriverEntry结构体成员。
- - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
-
-2. **配置属性文件:**
-
- - 在device_info.hcs文件中添加deviceNode描述。
- - 【可选】添加watchdog_config.hcs器件属性文件。
-
-3. **实例化Watchdog控制器对象:**
-
- - 初始化WatchdogCntlr成员。
- - 实例化WatchdogCntlr成员WatchdogMethod,其定义和成员**说明**见下
-
-4. **驱动调试:**
- - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,超时时间设置的成功与否等。
-
->  **说明:**
-> WatchdogMethod定义
->
-> ```c
-> struct WatchdogMethod {
-> int32_t (*getStatus)(struct WatchdogCntlr *wdt, int32_t *status);
-> int32_t (*setTimeout)(struct WatchdogCntlr *wdt, uint32_t seconds);
-> int32_t (*getTimeout)(struct WatchdogCntlr *wdt, uint32_t *seconds);
-> int32_t (*start)(struct WatchdogCntlr *wdt);
-> int32_t (*stop)(struct WatchdogCntlr *wdt);
-> int32_t (*feed)(struct WatchdogCntlr *wdt);
-> int32_t (*getPriv)(struct WatchdogCntlr *wdt); //【可选】如果WatchdogCntlr 中的priv成员存在,则按需进行实例化
-> void (*releasePriv)(struct WatchdogCntlr *wdt);//【可选】
-> };
-> ```
->
-> 表1 WatchdogMethod成员的回调函数功能说明
-> |成员函数|入参|出参|返回值|功能|
-> |-|-|-|-|-|
-> |getStatus |**wdt**: 结构体指针,核心层WDG控制器; |**status**: int32_t指针, 表示狗的状态(打开或关闭); |HDF_STATUS相关状态|获取看门狗所处的状态|
-> |start |**wdt**: 结构体指针,核心层WDG控制器; |无 |HDF_STATUS相关状态|打开开门狗 |
-> |stop |**wdt**: 结构体指针,核心层WDG控制器; |无 |HDF_STATUS相关状态|关闭开门狗 |
-> |setTimeout|**wdt**: 结构体指针,核心层WDG控制器; **seconds**: uint32_t,时间传入值;|无|HDF_STATUS相关状态|设置超时时间值,单位秒, 需要保证看门狗实际运行的时间符合该值 |
-> |getTimeout|**wdt**: 结构体指针,核心层WDG控制器; |**seconds**: uint32_t, 传出的时间值|HDF_STATUS相关状态|回读设置的超时时间值 |
-> |feed |**wdt**: 结构体指针,核心层WDG控制器; |无 |HDF_STATUS相关状态|喂狗 |
-
-
-## 开发实例
-
-下方将以watchdog_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
-
-1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
-
- 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
-
-- Watchdog驱动入口参考
-
- ```c
- struct HdfDriverEntry g_watchdogDriverEntry = {
- .moduleVersion = 1,
- .Bind = Hi35xxWatchdogBind, //见Bind参考
- .Init = Hi35xxWatchdogInit, //见Init参考
- .Release = Hi35xxWatchdogRelease, //见Release参考
- .moduleName = "HDF_PLATFORM_WATCHDOG",//【必要且与HCS文件中里面的moduleName匹配】
- };
- HDF_INIT(g_watchdogDriverEntry);//调用HDF_INIT将驱动入口注册到HDF框架中
- ```
-
-2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 watchdog_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层WatchdogCntlr 成员的默认值或限制范围有密切关系。
-
- **本例只有一个Watchdog控制器,如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在watchdog_config文件中增加对应的器件属性**。
-
-- device_info.hcs 配置参考
-
- ```c
- root {
- device_info {
- match_attr = "hdf_manager";
- device_watchdog :: device { // 设备节点
- device0 :: deviceNode { // 驱动的DeviceNode节点
- policy = 1; // policy字段是驱动服务发布的策略,如果需要面向用户态,则为2
- priority = 20; // 驱动启动优先级
- permission = 0644; // 驱动创建设备节点权限
- moduleName = "HDF_PLATFORM_WATCHDOG";
- // 【必要】驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
- serviceName = "HDF_PLATFORM_WATCHDOG_0";
- // 【必要且唯一】驱动对外发布服务的名称
- deviceMatchAttr = "hisilicon_hi35xx_watchdog_0";
- // 【必要】驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
- }
- }
- }
- }
- ```
-
-- watchdog_config.hcs 配置参考
-
- ```c
- root {
- platform {
- template watchdog_controller {//【必要】模板配置,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省
- id = 0;
- match_attr = "";
- regBase = 0x12050000; //【必要】地址映射需要
- regStep = 0x1000; //【必要】地址映射需要
- }
- controller_0x12050000 :: watchdog_controller {//【必要】是作为设备驱动私有数据匹配的关键字
- match_attr = "hisilicon_hi35xx_watchdog_0"; //【必要】必须和device_info.hcs中的deviceMatchAttr值一致
- }
- //存在多个 watchdog 时【必须】添加,否则不用
- ...
- }
- }
- ```
-
-3. 完成驱动入口注册之后,最后一步就是以核心层WatchdogCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化WatchdogCntlr成员WatchdogMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)
-
-- 自定义结构体参考
-
- > 从驱动的角度看,自定义结构体是参数和数据的载体,而且watchdog_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层WatchdogCntlr对象,例如索引、管脚数等。
-
- ```c
- struct Hi35xxWatchdog {
- struct WatchdogCntlr wdt; //【必要】是链接上下层的载体,具体描述见下面
- OsalSpinlock lock;
- volatile unsigned char *regBase;//【必要】地址映射需要
- uint32_t phyBase; //【必要】地址映射需要
- uint32_t regStep; //【必要】地址映射需要
- };
- //WatchdogCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值
- struct WatchdogCntlr {
- struct IDeviceIoService service;//驱动服务
- struct HdfDeviceObject *device; //驱动设备
- OsalSpinlock lock; //在HDF核心层调用时从系统代码实现了一个自旋锁的机制,挂载的变量需要是相同的变量,不建议挂载
- struct WatchdogMethod *ops; //接口回调函数
- int16_t wdtId; //WDG设备的识别id
- void *priv; //存储指针
- };
- ```
-
-- **【重要】** WatchdogCntlr成员回调函数结构体WatchdogMethod的实例化,其他成员在Init和Bind函数中初始化
-
- ```c
- static struct WatchdogMethod g_method = {
- .getStatus = Hi35xxWatchdogGetStatus,
- .start = Hi35xxWatchdogStart,
- .stop = Hi35xxWatchdogStop,
- .setTimeout = Hi35xxWatchdogSetTimeout,
- .getTimeout = Hi35xxWatchdogGetTimeout,
- .feed = Hi35xxWatchdogFeed,
- };
- ```
-
-
-- **Init函数和Bind函数参考**
-
- > **入参:**
- > HdfDeviceObject :HDF框架给每一个驱动创建的设备对象,用来保存设备相关的私有数据和服务接口
- >
- > **返回值:**
- > HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)
- >
- > |状态(值)|问题描述|
- > |:-|:-:|
- > |HDF_ERR_INVALID_OBJECT|找不到 WDG 设备|
- > |HDF_ERR_MALLOC_FAIL |内存分配失败|
- > |HDF_ERR_IO |I/O 错误|
- > |HDF_SUCCESS |初始化成功|
- > |HDF_FAILURE |初始化失败|
- >
- > **函数说明:**
- > 初始化自定义结构体对象,初始化WatchdogCntlr成员,调用核心层WatchdogCntlrAdd函数。
-
- ```c
- //一般而言,Init函数需要根据入参(HdfDeviceObject对象)的属性值初始化Hi35xxWatchdog结构体的成员,
- //但本例中是在bind函数中实现的
- static int32_t Hi35xxWatchdogInit(struct HdfDeviceObject *device)
- {
- (void)device;
- return HDF_SUCCESS;
- }
-
- static int32_t Hi35xxWatchdogBind(struct HdfDeviceObject *device)
- {
- int32_t ret;
- struct Hi35xxWatchdog *hwdt = NULL;
- ...
- hwdt = (struct Hi35xxWatchdog *)OsalMemCalloc(sizeof(*hwdt));//Hi35xxWatchdog 结构体的内存申请
- ...
- hwdt->regBase = OsalIoRemap(hwdt->phyBase, hwdt->regStep); //地址映射
- ...
-
- hwdt->wdt.priv = (void *)device->property;//【可选】此处是将设备属性的内容赋值给priv成员,但后续没有调用priv成员,
- // 如果需要用到priv成员,需要额外实例化WatchdogMethod的getPriv和releasePriv成员函数
- hwdt->wdt.ops = &g_method; //【必要】将实例化后的对象赋值给ops成员,就可以实现顶层调用WatchdogMethod成员函数
- hwdt->wdt.device = device; //【必要】这是为了方便HdfDeviceObject与WatchdogcCntlr相互转化
- ret = WatchdogCntlrAdd(&hwdt->wdt); //【必要】调用此函数初始化核心层结构体,返回成功信号后驱动才完全接入平台核心层
- if (ret != HDF_SUCCESS) { // 不成功的话,需要释放初始化函数申请的资源
- OsalIoUnmap((void *)hwdt->regBase);
- OsalMemFree(hwdt);
- return ret;
- }
- return HDF_SUCCESS;
- }
- ```
-
-- **Release函数参考**
-
- > **入参:**
- > HdfDeviceObject :HDF框架给每一个驱动创建的设备对象,用来保存设备相关的私有数据和服务接口
- >
- > **返回值:**
- > 无
- >
- > **函数说明:**
- > 该函数需要在驱动入口结构体中赋值给Release,当HDF框架调用Init函数初始化驱动失败时,可以调用Release释放驱动资源。该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
-
- ```c
- static void Hi35xxWatchdogRelease(struct HdfDeviceObject *device)
- {
- struct WatchdogCntlr *wdt = NULL;
- struct Hi35xxWatchdog *hwdt = NULL;
- ...
- wdt = WatchdogCntlrFromDevice(device); //这里通过service成员将HdfDeviceObject强制转化为WatchdogCntlr
- //return (device == NULL) ? NULL : (struct WatchdogCntlr *)device->service;
- if (wdt == NULL) {
- return;
- }
- WatchdogCntlrRemove(wdt); //核心层函数,实际执行wdt->device->service = NULL以及cntlr->lock的释放
- hwdt = (struct Hi35xxWatchdog *)wdt; //这里将WatchdogCntlr强制转化为HimciHost
- if (hwdt->regBase != NULL) { //解除地址映射
- OsalIoUnmap((void *)hwdt->regBase);
- hwdt->regBase = NULL;
- }
- OsalMemFree(hwdt); //释放厂商自定义对象占用的内存
- }
- ```
+# WatchDog
+
+- [概述](#section1315827527160117)
+- [接口说明](#section752964871810)
+- [开发步骤](#section477974542160117)
+- [开发实例](#section1832270347160117)
+
+## 概述
+
+看门狗(Watchdog),又叫看门狗计时器(Watchdog timer),是一种硬件的计时设备,在HDF框架中,Watchdog接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
+
+**图 1** Watchdog独立服务模式结构图
+
+
+## 接口说明
+
+WatchdogMethod定义:
+
+```
+struct WatchdogMethod {
+ int32_t (*getStatus)(struct WatchdogCntlr *wdt, int32_t *status);
+ int32_t (*setTimeout)(struct WatchdogCntlr *wdt, uint32_t seconds);
+ int32_t (*getTimeout)(struct WatchdogCntlr *wdt, uint32_t *seconds);
+ int32_t (*start)(struct WatchdogCntlr *wdt);
+ int32_t (*stop)(struct WatchdogCntlr *wdt);
+ int32_t (*feed)(struct WatchdogCntlr *wdt);
+ int32_t (*getPriv)(struct WatchdogCntlr *wdt); //【可选】如果WatchdogCntlr 中的priv成员存在,则按需实例化
+ void (*releasePriv)(struct WatchdogCntlr *wdt);//【可选】
+};
+```
+
+**表 1** WatchdogMethod成员的回调函数功能说明
+
+
+成员函数
+ |
+入参
+ |
+出参
+ |
+返回值
+ |
+功能
+ |
+
+
+getStatus
+ |
+wdt: 结构体指针,核心层WDG控制器;
+ |
+status: int32_t指针,表示狗的状态(打开或关闭);
+ |
+HDF_STATUS相关状态
+ |
+获取看门狗所处的状态
+ |
+
+start
+ |
+wdt: 结构体指针,核心层WDG控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+打开开门狗
+ |
+
+stop
+ |
+wdt: 结构体指针,核心层WDG控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+关闭开门狗
+ |
+
+setTimeout
+ |
+wdt: 结构体指针,核心层WDG控制器;seconds: uint32_t,时间传入值;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+设置超时时间值,单位秒,需要保证看门狗实际运行的时间符合该值
+ |
+
+getTimeout
+ |
+wdt: 结构体指针,核心层WDG控制器;
+ |
+seconds: uint32_t,传出的时间值
+ |
+HDF_STATUS相关状态
+ |
+回读设置的超时时间值
+ |
+
+feed
+ |
+wdt: 结构体指针,核心层WDG控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+喂狗
+ |
+
+
+
+
+## 开发步骤
+
+Watchdog模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
+
+1. **实例化驱动入口:**
+ - 实例化HdfDriverEntry结构体成员。
+ - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
+
+2. **配置属性文件:**
+ - 在device\_info.hcs文件中添加deviceNode描述。
+ - 【可选】添加watchdog\_config.hcs器件属性文件。
+
+3. **实例化Watchdog控制器对象:**
+ - 初始化WatchdogCntlr成员。
+ - 实例化WatchdogCntlr成员WatchdogMethod。
+
+ > **说明:**
+ >实例化WatchdogCntlr成员WatchdogMethod,其定义和成员说明见[接口说明](#section752964871810)。
+
+
+4. **驱动调试:**
+
+ 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,超时时间设置的成功与否等。
+
+
+## 开发实例
+
+下方将以watchdog\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
+
+1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
+
+ 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
+
+ Watchdog驱动入口参考:
+
+ ```
+ struct HdfDriverEntry g_watchdogDriverEntry = {
+ .moduleVersion = 1,
+ .Bind = Hi35xxWatchdogBind, //见Bind参考
+ .Init = Hi35xxWatchdogInit, //见Init参考
+ .Release = Hi35xxWatchdogRelease, //见Release参考
+ .moduleName = "HDF_PLATFORM_WATCHDOG",//【必要且与HCS文件中里面的moduleName匹配】
+ };
+ HDF_INIT(g_watchdogDriverEntry);//调用HDF_INIT将驱动入口注册到HDF框架中
+ ```
+
+2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 watchdog\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层WatchdogCntlr 成员的默认值或限制范围有密切关系。
+
+ 本例只有一个Watchdog控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在watchdog\_config文件中增加对应的器件属性。
+
+ - device\_info.hcs 配置参考。
+
+ ```
+ root {
+ device_info {
+ match_attr = "hdf_manager";
+ device_watchdog :: device { // 设备节点
+ device0 :: deviceNode { // 驱动的DeviceNode节点
+ policy = 1; // policy字段是驱动服务发布的策略,如果需要面向用户态,则为2
+ priority = 20; // 驱动启动优先级
+ permission = 0644; // 驱动创建设备节点权限
+ moduleName = "HDF_PLATFORM_WATCHDOG";
+ // 【必要】驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
+ serviceName = "HDF_PLATFORM_WATCHDOG_0";
+ // 【必要且唯一】驱动对外发布服务的名称
+ deviceMatchAttr = "hisilicon_hi35xx_watchdog_0";
+ // 【必要】驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
+ }
+ }
+ }
+ }
+ ```
+
+ - watchdog\_config.hcs 配置参考。
+
+ ```
+ root {
+ platform {
+ template watchdog_controller {//【必要】模板配置,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省
+ id = 0;
+ match_attr = "";
+ regBase = 0x12050000; //【必要】地址映射需要
+ regStep = 0x1000; //【必要】地址映射需要
+ }
+ controller_0x12050000 :: watchdog_controller {//【必要】是作为设备驱动私有数据匹配的关键字
+ match_attr = "hisilicon_hi35xx_watchdog_0"; //【必要】必须和device_info.hcs中的deviceMatchAttr值一致
+ }
+ //存在多个 watchdog 时【必须】添加,否则不用
+ ...
+ }
+ }
+ ```
+
+3. 完成驱动入口注册之后,最后一步就是以核心层WatchdogCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化WatchdogCntlr成员WatchdogMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
+ - 自定义结构体参考。
+
+ 从驱动的角度看,自定义结构体是参数和数据的载体,而且watchdog\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层WatchdogCntlr对象,例如索引、管脚数等。
+
+ ```
+ struct Hi35xxWatchdog {
+ struct WatchdogCntlr wdt; //【必要】是链接上下层的载体,具体描述见下面
+ OsalSpinlock lock;
+ volatile unsigned char *regBase;//【必要】地址映射需要
+ uint32_t phyBase; //【必要】地址映射需要
+ uint32_t regStep; //【必要】地址映射需要
+ };
+ //WatchdogCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值
+ struct WatchdogCntlr {
+ struct IDeviceIoService service;//驱动服务
+ struct HdfDeviceObject *device; //驱动设备
+ OsalSpinlock lock; //此变量在HDF核心层被调用来实现自旋锁功能
+ struct WatchdogMethod *ops; //接口回调函数
+ int16_t wdtId; //WDG设备的识别id
+ void *priv; //存储指针
+ };
+ ```
+
+ - WatchdogCntlr成员回调函数结构体WatchdogMethod的实例化,其他成员在Init和Bind函数中初始化。
+
+ ```
+ static struct WatchdogMethod g_method = {
+ .getStatus = Hi35xxWatchdogGetStatus,
+ .start = Hi35xxWatchdogStart,
+ .stop = Hi35xxWatchdogStop,
+ .setTimeout = Hi35xxWatchdogSetTimeout,
+ .getTimeout = Hi35xxWatchdogGetTimeout,
+ .feed = Hi35xxWatchdogFeed,
+ };
+ ```
+
+ - Init函数和Bind函数参考
+
+ 入参**:**
+
+ HdfDeviceObject :HDF框架给每一个驱动创建的设备对象,用来保存设备相关的私有数据和服务接口。
+
+ 返回值**:**
+
+ HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。
+
+ **表 2** Init函数和Bind函数入参和返回值
+
+
+ 状态(值)
+ |
+ 问题描述
+ |
+
+
+ HDF_ERR_INVALID_OBJECT
+ |
+ 找不到 WDG 设备
+ |
+
+ HDF_ERR_MALLOC_FAIL
+ |
+ 内存分配失败
+ |
+
+ HDF_ERR_IO
+ |
+ I/O 错误
+ |
+
+ HDF_SUCCESS
+ |
+ 初始化成功
+ |
+
+ HDF_FAILURE
+ |
+ 初始化失败
+ |
+
+
+
+
+ 函数说明**:**
+
+ 初始化自定义结构体对象,初始化WatchdogCntlr成员,调用核心层WatchdogCntlrAdd函数。
+
+ ```
+ //一般而言,Init函数需要根据入参(HdfDeviceObject对象)的属性值初始化Hi35xxWatchdog结构体的成员,
+ //但本例中是在bind函数中实现的
+ static int32_t Hi35xxWatchdogInit(struct HdfDeviceObject *device)
+ {
+ (void)device;
+ return HDF_SUCCESS;
+ }
+
+ static int32_t Hi35xxWatchdogBind(struct HdfDeviceObject *device)
+ {
+ int32_t ret;
+ struct Hi35xxWatchdog *hwdt = NULL;
+ ...
+ hwdt = (struct Hi35xxWatchdog *)OsalMemCalloc(sizeof(*hwdt));//Hi35xxWatchdog 结构体的内存申请
+ ...
+ hwdt->regBase = OsalIoRemap(hwdt->phyBase, hwdt->regStep); //地址映射
+ ...
+ hwdt->wdt.priv = (void *)device->property;//【可选】此处是将设备属性的内容赋值给priv成员,但后续没有调用 priv 成员,
+ // 如果需要用到priv成员,需要额外实例化WatchdogMethod的getPriv和releasePriv成员函数
+ hwdt->wdt.ops = &g_method; //【必要】将实例化后的对象赋值给ops成员,就可以实现顶层调用WatchdogMethod成员函数
+ hwdt->wdt.device = device; //【必要】这是为了方便HdfDeviceObject与WatchdogcCntlr相互转化
+ ret = WatchdogCntlrAdd(&hwdt->wdt); //【必要】调用此函数初始化核心层结构体,返回成功信号后驱动才完全接入平台核心层
+ if (ret != HDF_SUCCESS) { //不成功的话,需要释放Init函数申请的资源
+ OsalIoUnmap((void *)hwdt->regBase);
+ OsalMemFree(hwdt);
+ return ret;
+ }
+ return HDF_SUCCESS;
+ }
+ ```
+
+ - Release函数参考
+
+ 入参:
+
+ HdfDeviceObject :HDF框架给每一个驱动创建的设备对象,用来保存设备相关的私有数据和服务接口。
+
+ 返回值**:**
+
+ 无。
+
+ 函数说明**:**
+
+ 该函数需要在驱动入口结构体中赋值给Release,当HDF框架调用Init函数初始化驱动失败时,可以调用Release释放驱动资源。该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
+
+ ```
+ static void Hi35xxWatchdogRelease(struct HdfDeviceObject *device)
+ {
+ struct WatchdogCntlr *wdt = NULL;
+ struct Hi35xxWatchdog *hwdt = NULL;
+ ...
+ wdt = WatchdogCntlrFromDevice(device);//这里会通过service成员将HdfDeviceObject转化为WatchdogCntlr
+ //return (device == NULL) ? NULL : (struct WatchdogCntlr *)device->service;
+ if (wdt == NULL) {
+ return;
+ }
+ WatchdogCntlrRemove(wdt); //核心层函数,实际执行wdt->device->service = NULL以及cntlr->lock的释放
+ hwdt = (struct Hi35xxWatchdog *)wdt; //这里将WatchdogCntlr转化为HimciHost
+ if (hwdt->regBase != NULL) { //解除地址映射
+ OsalIoUnmap((void *)hwdt->regBase);
+ hwdt->regBase = NULL;
+ }
+ OsalMemFree(hwdt); //释放厂商自定义对象占用的内存
+ }
+ ```
+
+
+
diff --git a/zh-cn/device-dev/driver/driver-platform.md b/zh-cn/device-dev/driver/driver-platform.md
index 8c34624b9f491bcc9858feb1c988bce30c133541..017b58ac18c54d64ed5cf536984ce2dd5ae10dc5 100644
--- a/zh-cn/device-dev/driver/driver-platform.md
+++ b/zh-cn/device-dev/driver/driver-platform.md
@@ -16,4 +16,6 @@
- **[MIPI DSI](driver-platform-mipidsi-des.md)**
+- **[PWM](driver-platform-pwm-des.md)**
+
diff --git a/zh-cn/device-dev/driver/driver.md b/zh-cn/device-dev/driver/driver.md
index 58ee5fe7bc877da89acf3d2c7a5f08d2fd2f0a69..da3839d4de7c68822c784f3f6b1fe32c1457baae 100644
--- a/zh-cn/device-dev/driver/driver.md
+++ b/zh-cn/device-dev/driver/driver.md
@@ -1,9 +1,11 @@
-# 驱动使用指南
+# 驱动
- **[HDF驱动框架](driver-hdf.md)**
-- **[平台驱动](driver-platform.md)**
+- **[平台驱动开发](driver-develop.md)**
-- **[外设](driver-peripherals.md)**
+- **[平台驱动使用](driver-platform.md)**
+
+- **[外设驱动使用](driver-peripherals.md)**
diff --git "a/zh-cn/device-dev/driver/figure/Touchscreen\345\231\250\344\273\266\345\270\270\347\224\250\347\256\241\350\204\232.png" "b/zh-cn/device-dev/driver/figure/Touchscreen\345\231\250\344\273\266\345\270\270\347\224\250\347\256\241\350\204\232.png"
deleted file mode 100755
index 2d78b7c7f6994107238e21a1a21b55a5ec7b84a1..0000000000000000000000000000000000000000
Binary files "a/zh-cn/device-dev/driver/figure/Touchscreen\345\231\250\344\273\266\345\270\270\347\224\250\347\256\241\350\204\232.png" and /dev/null differ
diff --git "a/zh-cn/device-dev/driver/figure/USB-Device\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png" "b/zh-cn/device-dev/driver/figure/USB-Device\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png"
deleted file mode 100755
index 3766cf8117505a0d47720dcbccc1030536921bdb..0000000000000000000000000000000000000000
Binary files "a/zh-cn/device-dev/driver/figure/USB-Device\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png" and /dev/null differ
diff --git "a/zh-cn/device-dev/driver/figure/USB-Host\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png" "b/zh-cn/device-dev/driver/figure/USB-Host\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png"
deleted file mode 100755
index 6bea2992afd00b031176998278c0bcfce0f8e843..0000000000000000000000000000000000000000
Binary files "a/zh-cn/device-dev/driver/figure/USB-Host\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png" and /dev/null differ
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001170262141.png "b/zh-cn/device-dev/driver/figures/2\347\272\277UART\350\256\276\345\244\207\350\277\236\346\216\245\347\244\272\346\204\217\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001170262141.png
rename to "zh-cn/device-dev/driver/figures/2\347\272\277UART\350\256\276\345\244\207\350\277\236\346\216\245\347\244\272\346\204\217\345\233\276.png"
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001123582482.png "b/zh-cn/device-dev/driver/figures/4\347\272\277UART\350\256\276\345\244\207\350\277\236\346\216\245\347\244\272\346\204\217\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001123582482.png
rename to "zh-cn/device-dev/driver/figures/4\347\272\277UART\350\256\276\345\244\207\350\277\236\346\216\245\347\244\272\346\204\217\345\233\276.png"
diff --git "a/zh-cn/device-dev/driver/figure/\347\273\237\344\270\200\346\234\215\345\212\241\346\250\241\345\274\217.png" "b/zh-cn/device-dev/driver/figures/ADC\347\273\237\344\270\200\346\234\215\345\212\241.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/driver/figure/\347\273\237\344\270\200\346\234\215\345\212\241\346\250\241\345\274\217.png"
rename to "zh-cn/device-dev/driver/figures/ADC\347\273\237\344\270\200\346\234\215\345\212\241.png"
diff --git "a/zh-cn/device-dev/driver/figure/DSI\345\217\221\351\200\201-\346\216\245\346\224\266\346\216\245\345\217\243.png" "b/zh-cn/device-dev/driver/figures/DSI\345\217\221\351\200\201-\346\216\245\346\224\266\346\216\245\345\217\243.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/driver/figure/DSI\345\217\221\351\200\201-\346\216\245\346\224\266\346\216\245\345\217\243.png"
rename to "zh-cn/device-dev/driver/figures/DSI\345\217\221\351\200\201-\346\216\245\346\224\266\346\216\245\345\217\243.png"
diff --git "a/zh-cn/device-dev/driver/figure/\346\227\240\346\234\215\345\212\241\346\250\241\345\274\217.png" "b/zh-cn/device-dev/driver/figures/DSI\346\227\240\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/driver/figure/\346\227\240\346\234\215\345\212\241\346\250\241\345\274\217.png"
rename to "zh-cn/device-dev/driver/figures/DSI\346\227\240\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png"
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001170187071.png "b/zh-cn/device-dev/driver/figures/GPIO\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001170187071.png
rename to "zh-cn/device-dev/driver/figures/GPIO\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
diff --git "a/zh-cn/device-dev/driver/figures/GPIO\346\227\240\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" "b/zh-cn/device-dev/driver/figures/GPIO\346\227\240\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png"
new file mode 100644
index 0000000000000000000000000000000000000000..833ff6cc89e49ed4210dd68a502e4b304ac1c273
Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/GPIO\346\227\240\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" differ
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001054564784.png "b/zh-cn/device-dev/driver/figures/HDF\351\251\261\345\212\250\346\250\241\345\236\213.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001054564784.png
rename to "zh-cn/device-dev/driver/figures/HDF\351\251\261\345\212\250\346\250\241\345\236\213.png"
diff --git "a/zh-cn/device-dev/driver/figure/I2C\347\211\251\347\220\206\350\277\236\347\272\277\347\244\272\346\204\217\345\233\276.png" "b/zh-cn/device-dev/driver/figures/I2C\347\211\251\347\220\206\350\277\236\347\272\277\347\244\272\346\204\217\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/driver/figure/I2C\347\211\251\347\220\206\350\277\236\347\272\277\347\244\272\346\204\217\345\233\276.png"
rename to "zh-cn/device-dev/driver/figures/I2C\347\211\251\347\220\206\350\277\236\347\272\277\347\244\272\346\204\217\345\233\276.png"
diff --git "a/zh-cn/device-dev/driver/figures/I2C\347\273\237\344\270\200\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" "b/zh-cn/device-dev/driver/figures/I2C\347\273\237\344\270\200\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png"
new file mode 100644
index 0000000000000000000000000000000000000000..838f9a4416d901eb29b5d203b559b3dcfe29fed9
Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/I2C\347\273\237\344\270\200\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" differ
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001123509750.png "b/zh-cn/device-dev/driver/figures/I2C\350\256\276\345\244\207\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001123509750.png
rename to "zh-cn/device-dev/driver/figures/I2C\350\256\276\345\244\207\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001123514210.png "b/zh-cn/device-dev/driver/figures/MIPI-DSI\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001123514210.png
rename to "zh-cn/device-dev/driver/figures/MIPI-DSI\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
diff --git "a/zh-cn/device-dev/driver/figure/MIPI-DSI\346\216\245\345\217\243.png" "b/zh-cn/device-dev/driver/figures/MIPI-DSI\346\216\245\345\217\243.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/driver/figure/MIPI-DSI\346\216\245\345\217\243.png"
rename to "zh-cn/device-dev/driver/figures/MIPI-DSI\346\216\245\345\217\243.png"
diff --git "a/zh-cn/device-dev/driver/figure/\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217.png" "b/zh-cn/device-dev/driver/figures/MMC\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/driver/figure/\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217.png"
rename to "zh-cn/device-dev/driver/figures/MMC\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png"
diff --git "a/zh-cn/device-dev/driver/figures/PWM\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" "b/zh-cn/device-dev/driver/figures/PWM\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png"
new file mode 100644
index 0000000000000000000000000000000000000000..23324872566e5affac8baa186a30b64b3257f673
Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/PWM\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" differ
diff --git "a/zh-cn/device-dev/driver/figures/RTC\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" "b/zh-cn/device-dev/driver/figures/RTC\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png"
new file mode 100644
index 0000000000000000000000000000000000000000..23324872566e5affac8baa186a30b64b3257f673
Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/RTC\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" differ
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001123675706.png "b/zh-cn/device-dev/driver/figures/RTC\350\256\276\345\244\207\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001123675706.png
rename to "zh-cn/device-dev/driver/figures/RTC\350\256\276\345\244\207\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001123540984.png "b/zh-cn/device-dev/driver/figures/SDIO\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001123540984.png
rename to "zh-cn/device-dev/driver/figures/SDIO\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
diff --git "a/zh-cn/device-dev/driver/figures/SDIO\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" "b/zh-cn/device-dev/driver/figures/SDIO\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png"
new file mode 100644
index 0000000000000000000000000000000000000000..23324872566e5affac8baa186a30b64b3257f673
Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/SDIO\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" differ
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001054280608.png "b/zh-cn/device-dev/driver/figures/SDIO\347\232\204HOST-DEVICE\350\277\236\346\216\245\347\244\272\346\204\217\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001054280608.png
rename to "zh-cn/device-dev/driver/figures/SDIO\347\232\204HOST-DEVICE\350\277\236\346\216\245\347\244\272\346\204\217\345\233\276.png"
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001123742254.png "b/zh-cn/device-dev/driver/figures/SPI\344\270\273\344\273\216\350\256\276\345\244\207\350\277\236\346\216\245\347\244\272\346\204\217\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001123742254.png
rename to "zh-cn/device-dev/driver/figures/SPI\344\270\273\344\273\216\350\256\276\345\244\207\350\277\236\346\216\245\347\244\272\346\204\217\345\233\276.png"
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001123703482.png "b/zh-cn/device-dev/driver/figures/SPI\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001123703482.png
rename to "zh-cn/device-dev/driver/figures/SPI\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
diff --git "a/zh-cn/device-dev/driver/figures/SPI\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" "b/zh-cn/device-dev/driver/figures/SPI\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png"
new file mode 100644
index 0000000000000000000000000000000000000000..23324872566e5affac8baa186a30b64b3257f673
Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/SPI\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" differ
diff --git "a/zh-cn/device-dev/driver/figure/Sensor\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png" "b/zh-cn/device-dev/driver/figures/Sensor\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/driver/figure/Sensor\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png"
rename to "zh-cn/device-dev/driver/figures/Sensor\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png"
diff --git "a/zh-cn/device-dev/driver/figure/TTL\346\216\245\345\217\243.png" "b/zh-cn/device-dev/driver/figures/TTL\346\216\245\345\217\243.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/driver/figure/TTL\346\216\245\345\217\243.png"
rename to "zh-cn/device-dev/driver/figures/TTL\346\216\245\345\217\243.png"
diff --git "a/zh-cn/device-dev/driver/figures/Touchscreen\345\231\250\344\273\266\345\270\270\347\224\250\347\256\241\350\204\232.png" "b/zh-cn/device-dev/driver/figures/Touchscreen\345\231\250\344\273\266\345\270\270\347\224\250\347\256\241\350\204\232.png"
new file mode 100644
index 0000000000000000000000000000000000000000..6d33da5cc9efaa7d7d880623735e32a37f171dd8
Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/Touchscreen\345\231\250\344\273\266\345\270\270\347\224\250\347\256\241\350\204\232.png" differ
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001170227689.png "b/zh-cn/device-dev/driver/figures/UART\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001170227689.png
rename to "zh-cn/device-dev/driver/figures/UART\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
diff --git "a/zh-cn/device-dev/driver/figures/UART\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" "b/zh-cn/device-dev/driver/figures/UART\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png"
new file mode 100644
index 0000000000000000000000000000000000000000..23324872566e5affac8baa186a30b64b3257f673
Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/UART\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" differ
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001170383063.png "b/zh-cn/device-dev/driver/figures/WLAN\346\241\206\346\236\266.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001170383063.png
rename to "zh-cn/device-dev/driver/figures/WLAN\346\241\206\346\236\266.png"
diff --git "a/zh-cn/device-dev/driver/figure/\346\216\245\345\217\243\345\210\206\345\270\203\345\233\2764.png" "b/zh-cn/device-dev/driver/figures/WLAN\346\250\241\345\235\227\345\274\200\346\224\276\350\203\275\345\212\233\345\210\206\345\270\203\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/driver/figure/\346\216\245\345\217\243\345\210\206\345\270\203\345\233\2764.png"
rename to "zh-cn/device-dev/driver/figures/WLAN\346\250\241\345\235\227\345\274\200\346\224\276\350\203\275\345\212\233\345\210\206\345\270\203\345\233\276.png"
diff --git "a/zh-cn/device-dev/driver/figures/Watchdog\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" "b/zh-cn/device-dev/driver/figures/Watchdog\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png"
new file mode 100644
index 0000000000000000000000000000000000000000..23324872566e5affac8baa186a30b64b3257f673
Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/Watchdog\347\213\254\347\253\213\346\234\215\345\212\241\346\250\241\345\274\217\347\273\223\346\236\204\345\233\276.png" differ
diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206372673.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206372673.png
new file mode 100644
index 0000000000000000000000000000000000000000..4fe8c2506c044bb280a52138a9936e8d7d2e8c01
Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206372673.png differ
diff --git "a/zh-cn/device-dev/driver/figure/\345\237\272\344\272\216HDF\351\251\261\345\212\250\346\241\206\346\236\266\347\232\204Display\351\251\261\345\212\250\346\250\241\345\236\213.png" "b/zh-cn/device-dev/driver/figures/\345\237\272\344\272\216HDF\351\251\261\345\212\250\346\241\206\346\236\266\347\232\204Display\351\251\261\345\212\250\346\250\241\345\236\213.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/driver/figure/\345\237\272\344\272\216HDF\351\251\261\345\212\250\346\241\206\346\236\266\347\232\204Display\351\251\261\345\212\250\346\250\241\345\236\213.png"
rename to "zh-cn/device-dev/driver/figures/\345\237\272\344\272\216HDF\351\251\261\345\212\250\346\241\206\346\236\266\347\232\204Display\351\251\261\345\212\250\346\250\241\345\236\213.png"
diff --git "a/zh-cn/device-dev/driver/figure/\345\237\272\344\272\216HDF\351\251\261\345\212\250\346\241\206\346\236\266\347\232\204input\351\251\261\345\212\250\346\250\241\345\236\213.png" "b/zh-cn/device-dev/driver/figures/\345\237\272\344\272\216HDF\351\251\261\345\212\250\346\241\206\346\236\266\347\232\204input\351\251\261\345\212\250\346\250\241\345\236\213.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/driver/figure/\345\237\272\344\272\216HDF\351\251\261\345\212\250\346\241\206\346\236\266\347\232\204input\351\251\261\345\212\250\346\250\241\345\236\213.png"
rename to "zh-cn/device-dev/driver/figures/\345\237\272\344\272\216HDF\351\251\261\345\212\250\346\241\206\346\236\266\347\232\204input\351\251\261\345\212\250\346\250\241\345\236\213.png"
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001170229891.png "b/zh-cn/device-dev/driver/figures/\347\234\213\351\227\250\347\213\227\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001170229891.png
rename to "zh-cn/device-dev/driver/figures/\347\234\213\351\227\250\347\213\227\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
diff --git a/zh-cn/device-dev/driver/figure/zh-cn_image_0000001053405727.png "b/zh-cn/device-dev/driver/figures/\351\205\215\347\275\256\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/driver/figure/zh-cn_image_0000001053405727.png
rename to "zh-cn/device-dev/driver/figures/\351\205\215\347\275\256\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
diff --git a/zh-cn/device-dev/get-code/sourcecode-acquire.md b/zh-cn/device-dev/get-code/sourcecode-acquire.md
index 24dbe526dfc776f3e675abda9363786e70f14149..758442de39bd29a3cfe356e680138330764d7cd4 100644
--- a/zh-cn/device-dev/get-code/sourcecode-acquire.md
+++ b/zh-cn/device-dev/get-code/sourcecode-acquire.md
@@ -1,7 +1,7 @@
-# 源码获取
+# 获取源码
- [OpenHarmony介绍](#section6370143622110)
-- [源码获取概述](#section12763342204)
+- [获取源码概述](#section12763342204)
- [获取方式1:从码云仓库获取](#section537312010229)
- [适用场景](#section10881513459)
- [前提条件](#section102871547153314)
@@ -14,15 +14,16 @@
- [获取方式3:从镜像站点获取](#section1186691118430)
- [获取方式4:从github镜像仓库获取\(每天UTC时间23点同步\)](#section23448418360)
-- [源码目录简介](#section1072115612811)
+- [源码目录](#section1072115612811)
+
## OpenHarmony介绍
OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展。
-开源代码仓库地址:[https://openharmony.gitee.com](https://openharmony.gitee.com)
+开源代码仓库地址:[https://openharmony.gitee.com](https://openharmony.gitee.com)。
-## 源码获取概述
+## 获取源码概述
本文档将介绍如何获取OpenHarmony源码并说明OpenHarmony的源码目录结构。OpenHarmony的代码以[组件](../bundles/oem_bundle_standard_des.md)的形式开放,开发者可以通过如下其中一种方式获取:
@@ -95,7 +96,7 @@ OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及
- **OpenHarmony 发布版本代码获取**
- OpenHarmony发布版本源码获取方式请参考版本[Release-Notes](../../release-notes/Readme.md)。
+ OpenHarmony发布版本源码获取方式请参考[Release-Notes](../../release-notes/Readme.md)。
## 获取方式2:从DevEco Marketplace获取
@@ -174,9 +175,7 @@ OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及
为了获得更好的下载性能,您可以选择从以下站点的镜像库获取源码或者对应的解决方案。
-> **说明:**
->- 本部分只提供OpenHarmony Master最新版本和LTS最新版本的源码获取方式, 其他版本源码获取方式以及具体版本信息请参考[Release-Notes](../../release-notes/Readme.md)。
->- 当前Master 1.0版本已经不再维护。
+本部分只提供OpenHarmony Master最新版本和LTS最新版本的源码获取方式, 其他版本源码获取方式以及具体版本信息请参考[Release-Notes](../../release-notes/Readme.md)。
**表 1** 源码获取路径
@@ -271,56 +270,11 @@ OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及
SHA256校验码
|
-全量代码(标准系统)
- |
-2.0 Canary
- |
-站点1,站点2
- |
-SHA256校验码
- |
-
-全量代码(轻量和小型系统)
- |
-1.0(不再维护)
- |
-站点
- |
-SHA256 校验码
- |
-
-Hi3861解决方案(二进制)
- |
-1.0(不再维护)
- |
-站点
- |
-SHA256 校验码
- |
-
-Hi3518解决方案(二进制)
- |
-1.0(不再维护)
- |
-站点
- |
-SHA256 校验码
- |
-
-Hi3516解决方案(二进制)
- |
-1.0(不再维护)
- |
-站点
- |
-SHA256 校验码
- |
-
RELEASE-NOTES
|
-1.0(不再维护)
+ | 2.2 Beta2
|
-站点
+ | 站点
|
-
|
@@ -364,7 +318,7 @@ repo sync -c
repo forall -c 'git lfs pull'
```
-## 源码目录简介
+## 源码目录
下表是OpenHarmony源码的目录及简单说明:
diff --git a/zh-cn/device-dev/guide/Readme-CN.md b/zh-cn/device-dev/guide/Readme-CN.md
index ce9d01e0c1e707e51ead27f2c25026118818f59e..29da041335cb35e904727db70752dcf564d4ad1e 100755
--- a/zh-cn/device-dev/guide/Readme-CN.md
+++ b/zh-cn/device-dev/guide/Readme-CN.md
@@ -2,7 +2,8 @@
- [轻量和小型系统设备](device-lite.md)
- [WLAN连接类产品](device-wlan.md)
- - [LED外设控制](oem_wifi_sdk_des.md)
+ - [LED外设控制](device-wlan-led.md)
+ - [LED外设控制](oem_wifi_sdk_des.md)
- [集成三方SDK](device-wlan-sdk.md)
- [无屏摄像头类产品](device-iotcamera.md)
- [摄像头控制](device-iotcamera-control.md)
diff --git a/zh-cn/device-dev/guide/device-camera-control-demo-photoguide.md b/zh-cn/device-dev/guide/device-camera-control-demo-photoguide.md
index 0cae9c359bf6c5b036a4f947635d7c2ca289b65a..a55b60504e286f231b135395125d3cc098a5fbe4 100644
--- a/zh-cn/device-dev/guide/device-camera-control-demo-photoguide.md
+++ b/zh-cn/device-dev/guide/device-camera-control-demo-photoguide.md
@@ -310,7 +310,7 @@
};
```
-3. 实现相机状态回调的派生类,当相机状态发生变化(配置成功/失败,创建成功/失败\)时,自定义操作。
+3. 实现相机状态回调的派生类,自定义相机状态发生变化(配置成功/失败,创建成功/失败\)时的操作。
```
class SampleCameraStateMng : public CameraStateCallback {
@@ -363,7 +363,7 @@
camKit->CreateCamera(camId, CamStateMng, eventHdlr);
```
-6. 根据[步骤1](#zh-cn_topic_0000001052170554_li378084192111)、[步骤2](#zh-cn_topic_0000001052170554_li8716104682913)、[步骤3](#zh-cn_topic_0000001052170554_li6671035102514)中的回调设计,camera实例创建成功后会进行配置操作,主流程中app需要设计同步机制。
+6. 根据[步骤1](#zh-cn_topic_0000001052170554_li378084192111)、[步骤2](#zh-cn_topic_0000001052170554_li8716104682913)、[步骤3](#zh-cn_topic_0000001052170554_li6671035102514)中的回调设计,同步等待 OnCreated 回调拿到 cam\_ 之后,进行相关操作。
```
void OnCreated(Camera &c) override
diff --git a/zh-cn/device-dev/guide/device-camera-control-example.md b/zh-cn/device-dev/guide/device-camera-control-example.md
index b6d605b04e649928de22fc84d90d947128c5dd2e..0c5aafaf121c932471eb5025961474b1aea60587 100644
--- a/zh-cn/device-dev/guide/device-camera-control-example.md
+++ b/zh-cn/device-dev/guide/device-camera-control-example.md
@@ -1,6 +1,6 @@
# 应用实例
-本示例将运行源码中的camera示例代码,通过本示例可以实现对开发板拍照、录像及预览功能的控制。
+本示例将运行源码中的camera示例代码,通过本示例可以实现使用开发板进行拍照、录像及预览等功能。
- 本示例源码路径为“applications/sample/camera/media/camera\_sample.cpp”。
- 在运行本示例前需先完成编译烧录、运行镜像等步骤,相关操作请参考[Hi3516快速入门](../quick-start/oem_minitinier_des_3516.md#section26131214194212)。
@@ -26,38 +26,38 @@
1. 通过cd命令进入可执行程序的末端路径,启动camera\_sample,执行命令如下图。
**图 1** 启动示例
- 
+ 
运行后的控制命令如串口打印所示,按s键停止当前操作(包括录像和预览),按q键退出示例程序。
2. 按1进行拍照,拍照的文件格式为jpg,存储在/sdcard,文件名Capture\*
**图 2** 输入拍照指令后串口打印日志
- 
+ 
若想查看保存文件,可在退出程序后进入文件系统查看,退出后重新进入请回到步骤1。
**图 3** 查看文件图
- 
+ 
3. 按2进行录像,录像的文件格式为mp4,存储在/sdcard,文件名Record\*,按s键停止
**图 4** 输入录像指令后串口打印日志
- 
+ 
4. 按3进行预览,预览图像直接送至显示屏,按s键停止。
**图 5** 输入预览指令后串口打印日志
- 
+ 
预览效果如下
**图 6** 预览效果
- 
+ 
5. 按q键退出
**图 7** 输出退出指令后串口打印日志
- 
+ 
diff --git a/zh-cn/device-dev/guide/device-camera-visual-addpage.md b/zh-cn/device-dev/guide/device-camera-visual-addpage.md
index 3929ffbf6aee8d1ecf8ff07da1e3ceeadfa7b2db..8733bfb1e6d4795483ae7e763c0e6fed857fdc64 100644
--- a/zh-cn/device-dev/guide/device-camera-visual-addpage.md
+++ b/zh-cn/device-dev/guide/device-camera-visual-addpage.md
@@ -8,7 +8,7 @@
空气质量监测App包含两个界面(Page),工程创建完成后会生成一个名为index的Page,可以作为首页。工程目录如下图所示:
**图 1** 工程目录
-
+
## 创建详情页
@@ -17,18 +17,18 @@
1. pages目录右键 ,弹出的菜单中选择New、JS Page。
**图 2** 添加页面
- 
+ 
2. 输入Page名称。
**图 3** 输入页面名称
- 
+ 
3. 确认创建结果。
详情页创建完成后应用工程目录如下图所示,每个Page包括三个文件:布局文件hml、样式文件css、业务逻辑代码js。
**图 4** 完整工程目录
- 
+ 
diff --git a/zh-cn/device-dev/guide/device-camera-visual-faqs.md b/zh-cn/device-dev/guide/device-camera-visual-faqs.md
index e595cc85c3a246c0cbea8bbb2a58b8c00da0ad69..a9caab498818cf56c85a73b6ca958d210d0505b1 100755
--- a/zh-cn/device-dev/guide/device-camera-visual-faqs.md
+++ b/zh-cn/device-dev/guide/device-camera-visual-faqs.md
@@ -1,128 +1,148 @@
# 常见问题
-1. 是否存在一个全局变量,所有的页面都可以访问?
-
- 当前框架中不存在所有Page都可以访问的全局变量。
-
-2. 如何获取dom中的元素?
-
- 通过ref属性获取dom中的元素,详细示例如下图所示;获取的元素只能使用它的方法,不能改变属性。
-
- ```
-
-
-
-
-
-
- /* index.js */
- export default {
- data: {
- images:[
- {src:"common/frame1.png"},
- {src:"common/frame2.png"},
- {src:"common/frame3.png"}
- ]
- },
- handleClick(){
- //通过$refs属性获取对应的组件,在hml中,组件的ref属性要设置为animator
- const animator = this.$refs.animator;
- const state = animator.getState();
- if(state == "paused"){
- animator.resume();
- }else if(state == "stopped"){
- animator.start();
- }else{
- animator.pause();
- }
+- [视觉应用常见问题](#section147421736145813)
+ - [是否存在一个全局变量,所有的页面都可以访问?](#section294382614018)
+ - [如何获取dom中的元素](#section1423713435019)
+ - [如何在页面间传值?](#section119822143117)
+ - [list如何滚动到某个item?](#section188663819111)
+ - [text支持多行吗?](#section205741157418)
+ - [为什么控件不显示?](#section1345810151025)
+ - [如何实现页面滑动?](#section1724052813218)
+ - [Left、Top为什么不生效?](#section34659571520)
+ - [动态绑定为什么不生效?](#section1758881511313)
+ - [如何实现相对定位和绝对定位?](#section1378730235)
+ - [如何控制控件的显示与隐藏?](#section1243424718312)
+ - [使用Margin时,有什么注意事项?](#section7923357414)
+ - [使用事件订阅时,有什么注意事项?](#section91641925548)
+ - [使用动态绑定时,有什么注意事项?](#section1292412431744)
+ - [swiper loop属性如何生效?](#section1136434952)
+ - [使用数组时,有什么注意事项?](#section1979819133510)
+
+
+## 视觉应用常见问题
+
+### 是否存在一个全局变量,所有的页面都可以访问?
+
+当前框架中不存在所有Page都可以访问的全局变量。
+
+### 如何获取dom中的元素
+
+通过ref属性获取dom中的元素,详细示例如下图所示;获取的元素只能使用它的方法,不能改变属性。
+
+```
+
+
+
+
+
+
+/* index.js */
+export default {
+ data: {
+ images:[
+ {src:"common/frame1.png"},
+ {src:"common/frame2.png"},
+ {src:"common/frame3.png"}
+ ]
+ },
+ handleClick(){
+ //通过$refs属性获取对应的组件,在hml中,组件的ref属性要设置为animator
+ const animator = this.$refs.animator;
+ const state = animator.getState();
+ if(state == "paused"){
+ animator.resume();
+ }else if(state == "stopped"){
+ animator.start();
+ }else{
+ animator.pause();
}
}
- ```
+}
+```
-3. 如何在页面间传值?
+### 如何在页面间传值?
- 通过router.replace方法中的params参数来传递,参考代码如下:
+通过router.replace方法中的params参数来传递,参考代码如下:
- 第一个页面传递数据:
+第一个页面传递数据:
- ```
- router.replace({
- uri:'pages/detail/detail', //要跳转的页面uri
- params:{transferData:this.data} //传递的数据,数据个数和名称开发者自己定义,
- });
- ```
+```
+router.replace({
+ uri:'pages/detail/detail', //要跳转的页面uri
+ params:{transferData:this.data} //传递的数据,数据个数和名称开发者自己定义,
+});
+```
- 第二个界面接受数据:
+第二个界面接受数据:
- ```
- onInit(){
- const data = this.transferData; //在onInit函数中接受传递的数据
- }
- ```
+```
+onInit(){
+ const data = this.transferData; //在onInit函数中接受传递的数据
+}
+```
-4. list如何滚动到某个item?
+### list如何滚动到某个item?
- 通过list的scrollTo方法滚动到指定的item,参数是目标item的index。Index参数可以通过scrollend事件获取或者开发者指定。
+通过list的scrollTo方法滚动到指定的item,参数是目标item的index。Index参数可以通过scrollend事件获取或者开发者指定。
-5. text支持多行吗?
+### text支持多行吗?
- text支持多行。通过回车键换行或者是不设置text的高度属性,由控件自动根据内容换行。
+text支持多行。通过回车键换行或者是不设置text的高度属性,由控件自动根据内容换行。
-6. 为什么控件不显示?
+### 为什么控件不显示?
- **现象描述**
+**现象描述**
- 开发者在hml文件中添加的控件无法显示
+开发者在hml文件中添加的控件无法显示
- **可能原因**
+**可能原因**
- - 未设置width和height值;
- - 样式设置错误。
+- 未设置width和height值;
+- 样式设置错误。
- **处理步骤**
+**处理步骤**
- \(1\)检查是否设置width和height值,组件必须显式设置width和height值;
+\(1\)检查是否设置width和height值,组件必须显式设置width和height值;
- \(2\)检查组件的样式设置是否正确。
+\(2\)检查组件的样式设置是否正确。
-7. 如何实现页面滑动?
+### 如何实现页面滑动?
- 实现页面滑动目前有三种方式:scroll(根组件大小超过屏幕的大小即自动实现scroll效果)、list、swiper。开发者可以参考开发文档查看三者的区别,并加以使用。
+实现页面滑动目前有三种方式:scroll(根组件大小超过屏幕的大小即自动实现scroll效果)、list、swiper。开发者可以参考开发文档查看三者的区别,并加以使用。
-8. Left、Top为什么不生效?
+### Left、Top为什么不生效?
- 除根节点外,Left、Top配合Stack组件使用才有效果。
+除根节点外,Left、Top配合Stack组件使用才有效果。
-9. 动态绑定为什么不生效?
+### 动态绑定为什么不生效?
- 在进行绑定时,必须先将要绑定的对象或者对象的属性进行定义,不能先绑定后定义。
+在进行绑定时,必须先将要绑定的对象或者对象的属性进行定义,不能先绑定后定义
-10. 如何实现相对定位和绝对定位?
+### 如何实现相对定位和绝对定位?
- 使用div、stack(top left属性)来实现相对和绝对定位。
+使用div、stack(top left属性)来实现相对和绝对定位。
-11. 如何控制控件的显示与隐藏?
+### 如何控制控件的显示与隐藏?
- 通过display、show和if来控制控件的显示与隐藏。区别在于:if为false时,组件会从VDOM中移除,而show仅是渲染时不可见,组件依然存在于VDOM中。
+通过display、show和if来控制控件的显示与隐藏。区别在于:if为false时,组件会从VDOM中移除,而show仅是渲染时不可见,组件依然存在于VDOM中。
-12. 使用Margin时,有什么注意事项?
+### 使用Margin时,有什么注意事项?
- Stack组件不支持其子组件设置margin属性。
+Stack组件不支持其子组件设置margin属性。
-13. 使用事件订阅时,有什么注意事项?
+### 使用事件订阅时,有什么注意事项?
- 在应用运行期间只存在一个page,所以router.replace跳转是先销毁前一个页面,然后在新创建一个界面。因此,如果涉及到事件订阅的页面,每次页面创建时要进行事件订阅,跳转离开界面前取消事件订阅。
+在应用运行期间只存在一个page,所以router.replace跳转是先销毁前一个页面,然后在新创建一个界面。因此,如果涉及到事件订阅的页面,每次页面创建时要进行事件订阅,跳转离开界面前取消事件订阅。
-14. 使用动态绑定时,有什么注意事项?
+### 使用动态绑定时,有什么注意事项?
- 过多的动态绑定会消耗较多的内存,若非业务需要,尽量不要使用太多的动态绑定。
+过多的动态绑定会消耗较多的内存,若非业务需要,尽量不要使用太多的动态绑定。
-15. swiper loop属性如何生效?
+### swiper loop属性如何生效?
- 去掉第一个组件或者去掉最后一个组件,剩余的长度大于swiper长度,loop生效。
+去掉第一个组件或者去掉最后一个组件,剩余的长度大于swiper长度,loop生效。
-16. 使用数组时,有什么注意事项?
-
- 数组元素不宜过多,尽量避免对大数组进行频繁操作。
+### 使用数组时,有什么注意事项?
+数组元素不宜过多,尽量避免对大数组进行频繁操作。
diff --git a/zh-cn/device-dev/guide/device-camera-visual-firstpage.md b/zh-cn/device-dev/guide/device-camera-visual-firstpage.md
index bbfa60c30d6d6a901aa1e190145711955b69af50..0e2d0cd3cff4ded0aef4f91258cb363c01a69bb9 100644
--- a/zh-cn/device-dev/guide/device-camera-visual-firstpage.md
+++ b/zh-cn/device-dev/guide/device-camera-visual-firstpage.md
@@ -2,7 +2,7 @@
应用首页主要展示城市的空气质量概况。首页总共有两屏(可以根据需求设置多屏),每屏显示一个城市的空气质量信息:主要包括AQI指数、城市名称、污染物指数、更新时间和信息来源等数据。
-从第一章节中的[显示效果图](device-camera-visual-overview.md#fig18250512195914)分析可知,首页由三部分组成:
+从第一章节中的[显示效果图](device-camera-visual-overview.md)分析可知,首页由三部分组成:
- 标题栏:位于页面正上方,位置固定,包括应用退出按钮和页面标题。
- 信息栏:主要展示城市的空气信息指标等内容;该页面根据用户需求可设置多屏,且能循环滑动。
@@ -83,7 +83,7 @@
代码编写完成后,在模拟器中运行项目,显示效果如下图所示:
**图 1** 标题栏效果
- 
+ 
3. 实现城市空气质量信息的多屏左右滑动,需要使用“swiper”组件。
@@ -175,7 +175,7 @@
代码编写完成后,模拟器运行效果如下:
**图 2** 标题栏和信息栏效果
- 
+ 
5. 添加页面位置指示器:由于当前swiper不支持设置indicator,需要开发者自己来实现该效果。在根节点中添加一个子组件div,并设置相应样式;然后在该div中添加两个子组件div,设置两个div的border-radius,并在swiper滑动事件中动态改变对应div的背景色来实现该效果。
@@ -187,7 +187,7 @@
```
**图 3** 页面位置指示器效果图
- 
+ 
6. 所有组件设置样式、动画效果和数据动态绑定,完整代码如下所示:
diff --git a/zh-cn/device-dev/guide/device-camera-visual-overview.md b/zh-cn/device-dev/guide/device-camera-visual-overview.md
index a7e9895e2dceb1911879973ef697791cc59e649d..3f9b8cde1f8bf951302522a824c50862168a7026 100644
--- a/zh-cn/device-dev/guide/device-camera-visual-overview.md
+++ b/zh-cn/device-dev/guide/device-camera-visual-overview.md
@@ -8,8 +8,6 @@
空气质量监测App是一款展示城市空气质量信息的应用,有两个页面组成:首页和详情页,在DevEco Studio模拟器中的显示效果如下图所示:
-**图 1** 空气质量监测 App显示效果图
-
-
-
+**图 1** 空气质量监测 App显示效果图
+
diff --git a/zh-cn/device-dev/guide/device-camera-visual-prepare.md b/zh-cn/device-dev/guide/device-camera-visual-prepare.md
index 55ed7451c0ecdf7d2ab9fd9f896374287a1c5efb..d9dce9afe76703bc0554c5f75ae705f26e35e943 100644
--- a/zh-cn/device-dev/guide/device-camera-visual-prepare.md
+++ b/zh-cn/device-dev/guide/device-camera-visual-prepare.md
@@ -15,7 +15,7 @@
2. 选择“Smart Vision”下的“Empty Feature Ability”模板。
- 
+ 
3. 点击**Next**,进入到工程配置阶段,需要根据向导配置工程的基本信息。
- **Project Name**:工程的名称,可以自定义。
diff --git a/zh-cn/device-dev/guide/device-camera-visual-run.md b/zh-cn/device-dev/guide/device-camera-visual-run.md
index 59cea7e09931c4aff998255917c9ec2804d5eb3a..dfbdc4472ce32fff064a3dd720db102152ce1477 100644
--- a/zh-cn/device-dev/guide/device-camera-visual-run.md
+++ b/zh-cn/device-dev/guide/device-camera-visual-run.md
@@ -20,7 +20,7 @@
4. 应用安装完成后,可点击桌面应用图标启动应用,进行操作。
**图 1** 桌面
- 
+ 
5. 卸载应用(可选)。
diff --git a/zh-cn/device-dev/guide/device-clock-guide.md b/zh-cn/device-dev/guide/device-clock-guide.md
index 8df6da73488802189b88e132e1d28c3845996403..a29494b1407d890eb135708eef3cba271565608e 100644
--- a/zh-cn/device-dev/guide/device-clock-guide.md
+++ b/zh-cn/device-dev/guide/device-clock-guide.md
@@ -16,10 +16,8 @@
时钟App是一款显示实时时间的应用,显示效果如下图所示:
-**图 1** 时钟应用显示效果图
-
-
-
+**图 1** 时钟应用显示效果图
+
## 开发准备
@@ -29,7 +27,7 @@
应用的功能是通过表盘和数字显示实时时间。
-从[显示效果图](device-clock-guide.md#fig7763172132019)分析可知,页面由两个部分组成:
+从[显示效果图](#fig176772511186)分析可知,页面由两个部分组成:
- 表盘栏:主要展示一个动态的钟表,且钟表指针能准确转动。
- 数字时间栏:主要以数字形式显示当前时间。
diff --git a/zh-cn/device-dev/guide/device-driver-demo.md b/zh-cn/device-dev/guide/device-driver-demo.md
index 1220e92265d08302120f54b3173db207529d966f..6345e8ccf46f3c2ce265f60647ba45dc5499e1f5 100644
--- a/zh-cn/device-dev/guide/device-driver-demo.md
+++ b/zh-cn/device-dev/guide/device-driver-demo.md
@@ -19,18 +19,10 @@
HDF驱动框架为常用外围设备提供了标准的驱动框架,驱动开发者只需将驱动适配至HDF驱动框架,即可通过HDF驱动框架提供的接口操作外围设备。
-本文以I2C为例。其时序流程如[图1](#fig148041484161)所示。
+本文以I2C为例。其时序流程如[图1](#fig9596628607)所示。
-**图 1** I2C时序流程图
-
-
-
-
-- User Business:用户业务驱动。
-- i2cManagerEntry:I2C管理器入口,注册I2cManager到HDF驱动框架。
-- I2cManager:I2C管理器,管理I2C控制器。
-- I2cCntlr:I2C控制器。
-- i2cDriverEntry:I2C控制器入口,注册I2cCntlr到HDF驱动框架。
+**图 1** I2C时序流程图
+
## 环境准备
diff --git a/zh-cn/device-dev/guide/device-iotcamera-control-demo-photodevguide.md b/zh-cn/device-dev/guide/device-iotcamera-control-demo-photodevguide.md
index 31edc27814baddb754614c87ca0225979ef408ff..f317784dbd25862f4752c69d6526335f03069fc9 100644
--- a/zh-cn/device-dev/guide/device-iotcamera-control-demo-photodevguide.md
+++ b/zh-cn/device-dev/guide/device-iotcamera-control-demo-photodevguide.md
@@ -310,7 +310,7 @@
};
```
-3. 实现相机状态回调的派生类,当相机状态发生变化(配置成功/失败,创建成功/失败\)时,自定义操作。
+3. 实现相机状态回调的派生类,自定义相机状态发生变化(配置成功/失败,创建成功/失败\)时的操作。
```
class SampleCameraStateMng : public CameraStateCallback {
@@ -363,7 +363,7 @@
camKit->CreateCamera(camId, CamStateMng, eventHdlr);
```
-6. 根据[步骤1](#zh-cn_topic_0000001052170554_li378084192111)、[步骤2](#zh-cn_topic_0000001052170554_li8716104682913)、[步骤3](#zh-cn_topic_0000001052170554_li6671035102514)中的回调设计,camera实例创建成功后会进行配置操作,主流程中app需要设计同步机制。
+6. 根据[步骤1](#zh-cn_topic_0000001052170554_li378084192111)、[步骤2](#zh-cn_topic_0000001052170554_li8716104682913)、[步骤3](#zh-cn_topic_0000001052170554_li6671035102514)中的回调设计,同步等待 OnCreated 回调拿到 cam\_ 之后,进行相关操作。
```
void OnCreated(Camera &c) override
diff --git a/zh-cn/device-dev/guide/device-iotcamera-control-example.md b/zh-cn/device-dev/guide/device-iotcamera-control-example.md
index 56bd5df7ff309943182b86a5da61732f251f9fdd..c5dfe01f028576b13feb79575245731c1876f9d3 100644
--- a/zh-cn/device-dev/guide/device-iotcamera-control-example.md
+++ b/zh-cn/device-dev/guide/device-iotcamera-control-example.md
@@ -18,28 +18,28 @@
1. 通过cd命令进入可执行程序的末端路径,启动camera\_sample,执行命令如下图。
**图 1** 启动示例
- 
+ 
运行后的控制命令如串口打印所示,按s键停止当前操作(包括录像和预览),按q键退出示例程序。
2. 按1进行拍照,拍照的文件格式为jpg,存储在/sdcard,文件名Capture\*
**图 2** 输入拍照指令后串口打印日志
- 
+ 
若想查看保存文件,可在退出程序后进入文件系统查看,退出后重新进入请回到步骤1。
**图 3** 查看文件图
- 
+ 
3. 按2进行录像,录像的文件格式为mp4,存储在/sdcard,文件名Record\*,按s键停止
**图 4** 输入录像指令后串口打印日志
- 
+ 
4. 按q键退出
**图 5** 输出退出指令后串口打印日志
- 
+ 
diff --git a/zh-cn/device-dev/guide/device-outerdriver-demo.md b/zh-cn/device-dev/guide/device-outerdriver-demo.md
index 523d084d55a16489d99fe4c2816d9beb13e77433..0e74ff079e4d4eb0131359eb3ac9d1aa477cb7f9 100644
--- a/zh-cn/device-dev/guide/device-outerdriver-demo.md
+++ b/zh-cn/device-dev/guide/device-outerdriver-demo.md
@@ -28,7 +28,7 @@
Hi3516DV300开发板套件所提供的触摸屏器件IC为GT911,该器件采用标准I2C与主机通信,通过6pin软排线与主板连接。6pin分布以及实物连接图如下图所示:
-
+
### Input模型简介
diff --git a/zh-cn/device-dev/guide/device-wlan-led.md b/zh-cn/device-dev/guide/device-wlan-led.md
new file mode 100644
index 0000000000000000000000000000000000000000..5486cf40030d5bf1de2b54d8e5aafb4e0b8f6cb3
--- /dev/null
+++ b/zh-cn/device-dev/guide/device-wlan-led.md
@@ -0,0 +1,5 @@
+# LED外设控制
+
+- **[LED外设控制](oem_wifi_sdk_des.md)**
+
+
diff --git a/zh-cn/device-dev/guide/device-wlan-sdk.md b/zh-cn/device-dev/guide/device-wlan-sdk.md
index 8106f68cd6202a165547b6db59ae734fe01e6e6b..745d8ec4ae5e62110365bbd8647cd9e46b667980 100644
--- a/zh-cn/device-dev/guide/device-wlan-sdk.md
+++ b/zh-cn/device-dev/guide/device-wlan-sdk.md
@@ -121,7 +121,7 @@ OpenHarmony已规划用于编译业务libs的目录domains/iot/link/libbuild/
完成以上3点后,需在代码根目录下执行命令“hb build -T //domains/iot/link:iot”,等待执行完成,检查out/hispark\_pegasus/wifiiot\_hispark\_pegasus/libs/目录下是否生成了目标库文件。
-
+
将库文件拷贝到device/hisilicon/hispark\_pegasus/sdk\_liteos/3rd\_sdk/demolink/libs/ 目录下,并将domains/iot/link/libbuild/ 目录中的.c和.h文件清除。
diff --git a/zh-cn/device-dev/guide/device-wlan-touch.md b/zh-cn/device-dev/guide/device-wlan-touch.md
new file mode 100644
index 0000000000000000000000000000000000000000..2736daf4e21899d4fdc083b852d1869a70e57343
--- /dev/null
+++ b/zh-cn/device-dev/guide/device-wlan-touch.md
@@ -0,0 +1,19 @@
+# 碰一碰
+
+- **[碰一碰概述](onehop-overview.md)**
+
+- **[准备工作](onehop-dev-prerequisites.md)**
+
+- **[开发Hi3861设备侧功能](onehop-dev-hi3861.md)**
+
+- **[开发原子化服务](onehop-dev-atomic-service.md)**
+
+- **[写入NFC标签信息](onehop-write-nfc-info.md)**
+
+- **[配置服务关联意图](onehop-configuration-device-tag.md)**
+
+- **[碰一碰拉起原子化服务](onehop-open-atomic-service.md)**
+
+- **[参考信息](onehop-reference-info.md)**
+
+
diff --git a/zh-cn/device-dev/guide/device-wlan.md b/zh-cn/device-dev/guide/device-wlan.md
index ece3a35d670fe43de2892f4eae35b6d8f25a4e29..026cb3d7e593b8578addb252afe33907c223e1a0 100644
--- a/zh-cn/device-dev/guide/device-wlan.md
+++ b/zh-cn/device-dev/guide/device-wlan.md
@@ -1,6 +1,8 @@
# WLAN连接类产品
-- **[LED外设控制](oem_wifi_sdk_des.md)**
+- **[碰一碰](device-wlan-touch.md)**
+
+- **[LED外设控制](device-wlan-led.md)**
- **[集成三方SDK](device-wlan-sdk.md)**
diff --git a/zh-cn/device-dev/guide/figures/2021-01-27_170334-4.png b/zh-cn/device-dev/guide/figures/2021-01-27_170334-4.png
new file mode 100644
index 0000000000000000000000000000000000000000..5b573a4ddfe89fe25cb1b567736823244fdb9e97
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/2021-01-27_170334-4.png differ
diff --git "a/zh-cn/device-dev/guide/figure/\347\273\230\345\233\2761.png" b/zh-cn/device-dev/guide/figures/6-pin-distribution-and-physical-connection.png
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\347\273\230\345\233\2761.png"
rename to zh-cn/device-dev/guide/figures/6-pin-distribution-and-physical-connection.png
diff --git a/zh-cn/device-dev/guide/figure/zh-cn_image_0000001169991055.png "b/zh-cn/device-dev/guide/figures/I2C\346\227\266\345\272\217\346\265\201\347\250\213\345\233\276.png"
similarity index 100%
rename from zh-cn/device-dev/guide/figure/zh-cn_image_0000001169991055.png
rename to "zh-cn/device-dev/guide/figures/I2C\346\227\266\345\272\217\346\265\201\347\250\213\345\233\276.png"
diff --git "a/zh-cn/device-dev/guide/figure/LED\351\227\252\347\203\201\345\233\276.gif" "b/zh-cn/device-dev/guide/figures/LED\351\227\252\347\203\201\345\233\276.gif"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/LED\351\227\252\347\203\201\345\233\276.gif"
rename to "zh-cn/device-dev/guide/figures/LED\351\227\252\347\203\201\345\233\276.gif"
diff --git a/zh-cn/device-dev/guide/figures/ability-gallery-service.png b/zh-cn/device-dev/guide/figures/ability-gallery-service.png
new file mode 100644
index 0000000000000000000000000000000000000000..63fb6627393fc1a8a2bca6964fa2900d0dd308bc
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/ability-gallery-service.png differ
diff --git a/zh-cn/device-dev/guide/figures/ability-test.png b/zh-cn/device-dev/guide/figures/ability-test.png
new file mode 100644
index 0000000000000000000000000000000000000000..cafda84ac7195a758ae8526ab747ef8483f56129
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/ability-test.png differ
diff --git a/zh-cn/device-dev/guide/figures/add_tools.png b/zh-cn/device-dev/guide/figures/add_tools.png
new file mode 100644
index 0000000000000000000000000000000000000000..8737e531e2536d7e7e485af539ace34ea747da8d
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/add_tools.png differ
diff --git a/zh-cn/device-dev/guide/figures/build-project.png b/zh-cn/device-dev/guide/figures/build-project.png
new file mode 100644
index 0000000000000000000000000000000000000000..24c23b9f35a4a1edaf57f6dd983c32138adf8594
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/build-project.png differ
diff --git a/zh-cn/device-dev/guide/figures/build-success.png b/zh-cn/device-dev/guide/figures/build-success.png
new file mode 100644
index 0000000000000000000000000000000000000000..26d93f832bef054618d31d8e2cecf6684ecdb891
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/build-success.png differ
diff --git a/zh-cn/device-dev/guide/figures/burn_settings.png b/zh-cn/device-dev/guide/figures/burn_settings.png
new file mode 100644
index 0000000000000000000000000000000000000000..a510dcecc23495dc515a8deecce580a660cf721b
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/burn_settings.png differ
diff --git a/zh-cn/device-dev/guide/figures/choose-nfc.png b/zh-cn/device-dev/guide/figures/choose-nfc.png
new file mode 100644
index 0000000000000000000000000000000000000000..ca1ab3357646a62189296995c1319c6bff1ad28e
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/choose-nfc.png differ
diff --git a/zh-cn/device-dev/guide/figures/choose-product-id.png b/zh-cn/device-dev/guide/figures/choose-product-id.png
new file mode 100644
index 0000000000000000000000000000000000000000..7c91963c5c582b87df8129619dbec2613e97a81e
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/choose-product-id.png differ
diff --git a/zh-cn/device-dev/guide/figures/choose-requested-product-id.png b/zh-cn/device-dev/guide/figures/choose-requested-product-id.png
new file mode 100644
index 0000000000000000000000000000000000000000..ae19e372316109341eeb80ca452c2252c994c59b
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/choose-requested-product-id.png differ
diff --git a/zh-cn/device-dev/guide/figures/choose-template.png b/zh-cn/device-dev/guide/figures/choose-template.png
new file mode 100644
index 0000000000000000000000000000000000000000..2932ec5fd69fc4e786c698afdbf95ab64e23be1d
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/choose-template.png differ
diff --git a/zh-cn/device-dev/guide/figures/component-reference-code.png b/zh-cn/device-dev/guide/figures/component-reference-code.png
new file mode 100644
index 0000000000000000000000000000000000000000..21b9b6e4cb88a620d07cf7c37a3795b9adc87397
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/component-reference-code.png differ
diff --git a/zh-cn/device-dev/guide/figures/configure-project.png b/zh-cn/device-dev/guide/figures/configure-project.png
new file mode 100644
index 0000000000000000000000000000000000000000..f1f80f3a77db74d3f730e13b165a1113e699c04f
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/configure-project.png differ
diff --git a/zh-cn/device-dev/guide/figures/console.png b/zh-cn/device-dev/guide/figures/console.png
new file mode 100644
index 0000000000000000000000000000000000000000..f7cbec3ffbad85fe4449d0cbc1ce754c84001e74
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/console.png differ
diff --git a/zh-cn/device-dev/guide/figures/control-module-icon.png b/zh-cn/device-dev/guide/figures/control-module-icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..45f126abf60662d98f881d884d8483557a5ea831
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/control-module-icon.png differ
diff --git a/zh-cn/device-dev/guide/figures/control-module.png b/zh-cn/device-dev/guide/figures/control-module.png
new file mode 100644
index 0000000000000000000000000000000000000000..a515a1739fe19fbce722621e26b39cc1239a11d4
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/control-module.png differ
diff --git a/zh-cn/device-dev/guide/figures/copy-hals-and-winder.png b/zh-cn/device-dev/guide/figures/copy-hals-and-winder.png
new file mode 100644
index 0000000000000000000000000000000000000000..966e00018189222882bb6b1ef13c8599e75eadbf
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/copy-hals-and-winder.png differ
diff --git a/zh-cn/device-dev/guide/figures/date-and-time-picker.png b/zh-cn/device-dev/guide/figures/date-and-time-picker.png
new file mode 100644
index 0000000000000000000000000000000000000000..2259c361916fc0590c53faf47e006c7639d73725
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/date-and-time-picker.png differ
diff --git a/zh-cn/device-dev/guide/figures/date-picker.png b/zh-cn/device-dev/guide/figures/date-picker.png
new file mode 100644
index 0000000000000000000000000000000000000000..204e40fa8aa4c8f3ab9196b2f0e2f2e178cdeaed
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/date-picker.png differ
diff --git a/zh-cn/device-dev/guide/figure/zh-cn_image_0000001078563230.png b/zh-cn/device-dev/guide/figures/device-wlan-sdk-files.png
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/guide/figure/zh-cn_image_0000001078563230.png
rename to zh-cn/device-dev/guide/figures/device-wlan-sdk-files.png
diff --git a/zh-cn/device-dev/guide/figures/display-component.png b/zh-cn/device-dev/guide/figures/display-component.png
new file mode 100644
index 0000000000000000000000000000000000000000..b4b7a38ccb93bf2583539382beb7e8e68dd97b7d
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/display-component.png differ
diff --git a/zh-cn/device-dev/guide/figures/edit-configurations.png b/zh-cn/device-dev/guide/figures/edit-configurations.png
new file mode 100644
index 0000000000000000000000000000000000000000..a9657f5b25dd269d6189ad9308b05da2c8c55e40
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/edit-configurations.png differ
diff --git a/zh-cn/device-dev/guide/figure/zh-cn_image_0000001082434703.png b/zh-cn/device-dev/guide/figures/empty-feature-ability.png
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/guide/figure/zh-cn_image_0000001082434703.png
rename to zh-cn/device-dev/guide/figures/empty-feature-ability.png
diff --git a/zh-cn/device-dev/guide/figures/enum-component.png b/zh-cn/device-dev/guide/figures/enum-component.png
new file mode 100644
index 0000000000000000000000000000000000000000..05c06aa0a7939700fc0128d6a20eacc6cce0dd4d
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/enum-component.png differ
diff --git a/zh-cn/device-dev/guide/figures/enum-dialog.png b/zh-cn/device-dev/guide/figures/enum-dialog.png
new file mode 100644
index 0000000000000000000000000000000000000000..e0f09313354c53ebd068201f702318746022c489
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/enum-dialog.png differ
diff --git a/zh-cn/device-dev/guide/figures/fa-information.png b/zh-cn/device-dev/guide/figures/fa-information.png
new file mode 100644
index 0000000000000000000000000000000000000000..d5cedb3ccefbbe62f97896918d464a0c2bd33d0e
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/fa-information.png differ
diff --git a/zh-cn/device-dev/guide/figures/harmonyos-tag.png b/zh-cn/device-dev/guide/figures/harmonyos-tag.png
new file mode 100644
index 0000000000000000000000000000000000000000..459a69f9ef8a469b0b44ca6f68be6cf4aef27275
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/harmonyos-tag.png differ
diff --git a/zh-cn/device-dev/guide/figures/harmonyos-test-ability-model.png b/zh-cn/device-dev/guide/figures/harmonyos-test-ability-model.png
new file mode 100644
index 0000000000000000000000000000000000000000..725d1c24c440f3f1c8a63750015184089c15e043
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/harmonyos-test-ability-model.png differ
diff --git a/zh-cn/device-dev/guide/figures/harmonyos-test-ability.png b/zh-cn/device-dev/guide/figures/harmonyos-test-ability.png
new file mode 100644
index 0000000000000000000000000000000000000000..5fc3dd6e556fd7bfcfd02f7438c92907e4e670e5
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/harmonyos-test-ability.png differ
diff --git a/zh-cn/device-dev/guide/figures/hi3861-burning-succeeded-7.png b/zh-cn/device-dev/guide/figures/hi3861-burning-succeeded-7.png
new file mode 100644
index 0000000000000000000000000000000000000000..3628f3f4778012a577d4ee28c703669eb5533594
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/hi3861-burning-succeeded-7.png differ
diff --git a/zh-cn/device-dev/guide/figures/hi3861-record-the-serial-port-number-5.png b/zh-cn/device-dev/guide/figures/hi3861-record-the-serial-port-number-5.png
new file mode 100644
index 0000000000000000000000000000000000000000..43496f076a463ec6fbf320b358a32505284ff40f
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/hi3861-record-the-serial-port-number-5.png differ
diff --git a/zh-cn/device-dev/guide/figures/hi3861-restart-the-development-board.png b/zh-cn/device-dev/guide/figures/hi3861-restart-the-development-board.png
new file mode 100644
index 0000000000000000000000000000000000000000..e6b632288105421a07bd4f8d542293deb0d35fd2
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/hi3861-restart-the-development-board.png differ
diff --git a/zh-cn/device-dev/guide/figures/hi3861-upload-6.png b/zh-cn/device-dev/guide/figures/hi3861-upload-6.png
new file mode 100644
index 0000000000000000000000000000000000000000..8dde7632636856203030c2abf0867f03abaafcba
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/hi3861-upload-6.png differ
diff --git a/zh-cn/device-dev/guide/figures/import-project-confirm.png b/zh-cn/device-dev/guide/figures/import-project-confirm.png
new file mode 100644
index 0000000000000000000000000000000000000000..27fe1d133a31b275a2788cab1f5b37dd3450a7df
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/import-project-confirm.png differ
diff --git a/zh-cn/device-dev/guide/figures/import-project-setting.png b/zh-cn/device-dev/guide/figures/import-project-setting.png
new file mode 100644
index 0000000000000000000000000000000000000000..b522b9b1e490b5ba65a0afd021cd5f472110136c
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/import-project-setting.png differ
diff --git a/zh-cn/device-dev/guide/figures/import-project.png b/zh-cn/device-dev/guide/figures/import-project.png
new file mode 100644
index 0000000000000000000000000000000000000000..5ba534eaf39165891a31c7837ae7ff4126f6414c
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/import-project.png differ
diff --git a/zh-cn/device-dev/guide/figures/increase-decrease-component.png b/zh-cn/device-dev/guide/figures/increase-decrease-component.png
new file mode 100644
index 0000000000000000000000000000000000000000..c3071b280090668be88dec25ab2b2dc1dbf8f0d7
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/increase-decrease-component.png differ
diff --git a/zh-cn/device-dev/guide/figures/info-dialog.png b/zh-cn/device-dev/guide/figures/info-dialog.png
new file mode 100644
index 0000000000000000000000000000000000000000..4278ae472f7a8cff0b96b79ac5d45f2f0719e8e2
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/info-dialog.png differ
diff --git a/zh-cn/device-dev/guide/figures/launch-atomic-service-procedure.png b/zh-cn/device-dev/guide/figures/launch-atomic-service-procedure.png
new file mode 100644
index 0000000000000000000000000000000000000000..76ce1f3a2ec4dde0bdffc9d172a281810a7c1f69
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/launch-atomic-service-procedure.png differ
diff --git a/zh-cn/device-dev/guide/figures/multi-column-picker.png b/zh-cn/device-dev/guide/figures/multi-column-picker.png
new file mode 100644
index 0000000000000000000000000000000000000000..de0593b498af83a865fa9097d86dd07967ddcdaa
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/multi-column-picker.png differ
diff --git a/zh-cn/device-dev/guide/figures/multifunction-component.png b/zh-cn/device-dev/guide/figures/multifunction-component.png
new file mode 100644
index 0000000000000000000000000000000000000000..ac18eff592c4b0b64f8527a98cf3257be9b9cb87
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/multifunction-component.png differ
diff --git a/zh-cn/device-dev/guide/figures/onehop-develop-procedure.png b/zh-cn/device-dev/guide/figures/onehop-develop-procedure.png
new file mode 100644
index 0000000000000000000000000000000000000000..e27414c7a920a45629071565c24464fa58055b30
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/onehop-develop-procedure.png differ
diff --git a/zh-cn/device-dev/guide/figures/onehop-procedure.png b/zh-cn/device-dev/guide/figures/onehop-procedure.png
new file mode 100644
index 0000000000000000000000000000000000000000..11f12f6d18e849d13b0a63be07f1d58296035257
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/onehop-procedure.png differ
diff --git a/zh-cn/device-dev/guide/figures/place-product-diagram.png b/zh-cn/device-dev/guide/figures/place-product-diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..b7fe68aadf4a045bd8657054a07d3d4328b004ca
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/place-product-diagram.png differ
diff --git a/zh-cn/device-dev/guide/figures/process-component.png b/zh-cn/device-dev/guide/figures/process-component.png
new file mode 100644
index 0000000000000000000000000000000000000000..f6b0fbe0aa28be6d9c39fe45cafb63d87d809659
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/process-component.png differ
diff --git a/zh-cn/device-dev/guide/figures/project-structure.png b/zh-cn/device-dev/guide/figures/project-structure.png
new file mode 100644
index 0000000000000000000000000000000000000000..67c7a082f6fd2dc4e160567a2bc6735bba4fe2b8
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/project-structure.png differ
diff --git a/zh-cn/device-dev/guide/figures/project_settings.png b/zh-cn/device-dev/guide/figures/project_settings.png
new file mode 100644
index 0000000000000000000000000000000000000000..f869bc8e66050bd10c558724fa210fb1a84163f4
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/project_settings.png differ
diff --git a/zh-cn/device-dev/guide/figures/prototype-test.png b/zh-cn/device-dev/guide/figures/prototype-test.png
new file mode 100644
index 0000000000000000000000000000000000000000..d4568aa761be14e665667fcfa5c95bad8613f2a1
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/prototype-test.png differ
diff --git a/zh-cn/device-dev/guide/figures/radio-dialog.png b/zh-cn/device-dev/guide/figures/radio-dialog.png
new file mode 100644
index 0000000000000000000000000000000000000000..097edb23307ec360d2757e2ea99368b71ba124af
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/radio-dialog.png differ
diff --git a/zh-cn/device-dev/guide/figures/request-product-id.png b/zh-cn/device-dev/guide/figures/request-product-id.png
new file mode 100644
index 0000000000000000000000000000000000000000..97a69009db01ebb605958a67b75ada00abb635ba
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/request-product-id.png differ
diff --git a/zh-cn/device-dev/guide/figures/reversal-component.png b/zh-cn/device-dev/guide/figures/reversal-component.png
new file mode 100644
index 0000000000000000000000000000000000000000..182da8bd6953af4884ceb7aaffee88d8e5022ecd
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/reversal-component.png differ
diff --git a/zh-cn/device-dev/guide/figures/run-entry.png b/zh-cn/device-dev/guide/figures/run-entry.png
new file mode 100644
index 0000000000000000000000000000000000000000..7cd572c6ebbb57e8d33b38df67c0fd0bb26fc4cc
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/run-entry.png differ
diff --git a/zh-cn/device-dev/guide/figures/set-config-i2c-support.png b/zh-cn/device-dev/guide/figures/set-config-i2c-support.png
new file mode 100644
index 0000000000000000000000000000000000000000..1921ee61abb7bf05674558121ebb6c812dc627df
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/set-config-i2c-support.png differ
diff --git a/zh-cn/device-dev/guide/figures/set-sn-number.png b/zh-cn/device-dev/guide/figures/set-sn-number.png
new file mode 100644
index 0000000000000000000000000000000000000000..a11388839398cfc8aa2ff14a989ef2e12e36ea07
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/set-sn-number.png differ
diff --git a/zh-cn/device-dev/guide/figures/text-picker.png b/zh-cn/device-dev/guide/figures/text-picker.png
new file mode 100644
index 0000000000000000000000000000000000000000..60a1be0310ef2f7fc5ccfbbc7a09479650b1b77f
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/text-picker.png differ
diff --git a/zh-cn/device-dev/guide/figures/time-picker.png b/zh-cn/device-dev/guide/figures/time-picker.png
new file mode 100644
index 0000000000000000000000000000000000000000..b68a0fb2725be2da70aa09680028071f8acc7eef
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/time-picker.png differ
diff --git a/zh-cn/device-dev/guide/figures/write-to-buffer.png b/zh-cn/device-dev/guide/figures/write-to-buffer.png
new file mode 100644
index 0000000000000000000000000000000000000000..cc3e9353cd011bdbf23089ed0a857cbafb5aab40
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/write-to-buffer.png differ
diff --git a/zh-cn/device-dev/guide/figures/written-to-tag.png b/zh-cn/device-dev/guide/figures/written-to-tag.png
new file mode 100644
index 0000000000000000000000000000000000000000..3e3b0d15d509b30cbdc96faaecadc8553cbe1e37
Binary files /dev/null and b/zh-cn/device-dev/guide/figures/written-to-tag.png differ
diff --git "a/zh-cn/device-dev/guide/figure/\345\220\257\345\212\250\347\244\272\344\276\213.png" "b/zh-cn/device-dev/guide/figures/\345\220\257\345\212\250\347\244\272\344\276\213.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\345\220\257\345\212\250\347\244\272\344\276\213.png"
rename to "zh-cn/device-dev/guide/figures/\345\220\257\345\212\250\347\244\272\344\276\213.png"
diff --git "a/zh-cn/device-dev/guide/figure/\345\256\214\346\225\264\345\267\245\347\250\213\347\233\256\345\275\225.png" "b/zh-cn/device-dev/guide/figures/\345\256\214\346\225\264\345\267\245\347\250\213\347\233\256\345\275\225.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\345\256\214\346\225\264\345\267\245\347\250\213\347\233\256\345\275\225.png"
rename to "zh-cn/device-dev/guide/figures/\345\256\214\346\225\264\345\267\245\347\250\213\347\233\256\345\275\225.png"
diff --git "a/zh-cn/device-dev/guide/figure/\345\267\245\347\250\213\347\233\256\345\275\225.png" "b/zh-cn/device-dev/guide/figures/\345\267\245\347\250\213\347\233\256\345\275\225.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\345\267\245\347\250\213\347\233\256\345\275\225.png"
rename to "zh-cn/device-dev/guide/figures/\345\267\245\347\250\213\347\233\256\345\275\225.png"
diff --git a/zh-cn/device-dev/guide/figure/Clock.png "b/zh-cn/device-dev/guide/figures/\346\227\266\351\222\237\345\272\224\347\224\250\346\230\276\347\244\272\346\225\210\346\236\234\345\233\276.png"
similarity index 100%
rename from zh-cn/device-dev/guide/figure/Clock.png
rename to "zh-cn/device-dev/guide/figures/\346\227\266\351\222\237\345\272\224\347\224\250\346\230\276\347\244\272\346\225\210\346\236\234\345\233\276.png"
diff --git "a/zh-cn/device-dev/guide/figure/\346\237\245\347\234\213\346\226\207\344\273\266\345\233\276.png" "b/zh-cn/device-dev/guide/figures/\346\237\245\347\234\213\346\226\207\344\273\266\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\346\237\245\347\234\213\346\226\207\344\273\266\345\233\276.png"
rename to "zh-cn/device-dev/guide/figures/\346\237\245\347\234\213\346\226\207\344\273\266\345\233\276.png"
diff --git "a/zh-cn/device-dev/guide/figure/\346\240\207\351\242\230\346\240\217\345\222\214\344\277\241\346\201\257\346\240\217\346\225\210\346\236\234.png" "b/zh-cn/device-dev/guide/figures/\346\240\207\351\242\230\346\240\217\345\222\214\344\277\241\346\201\257\346\240\217\346\225\210\346\236\234.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\346\240\207\351\242\230\346\240\217\345\222\214\344\277\241\346\201\257\346\240\217\346\225\210\346\236\234.png"
rename to "zh-cn/device-dev/guide/figures/\346\240\207\351\242\230\346\240\217\345\222\214\344\277\241\346\201\257\346\240\217\346\225\210\346\236\234.png"
diff --git "a/zh-cn/device-dev/guide/figure/\346\240\207\351\242\230\346\240\217\346\225\210\346\236\234.png" "b/zh-cn/device-dev/guide/figures/\346\240\207\351\242\230\346\240\217\346\225\210\346\236\234.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\346\240\207\351\242\230\346\240\217\346\225\210\346\236\234.png"
rename to "zh-cn/device-dev/guide/figures/\346\240\207\351\242\230\346\240\217\346\225\210\346\236\234.png"
diff --git "a/zh-cn/device-dev/guide/figure/\346\241\214\351\235\242.png" "b/zh-cn/device-dev/guide/figures/\346\241\214\351\235\242.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\346\241\214\351\235\242.png"
rename to "zh-cn/device-dev/guide/figures/\346\241\214\351\235\242.png"
diff --git "a/zh-cn/device-dev/guide/figure/\346\267\273\345\212\240\351\241\265\351\235\242.png" "b/zh-cn/device-dev/guide/figures/\346\267\273\345\212\240\351\241\265\351\235\242.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\346\267\273\345\212\240\351\241\265\351\235\242.png"
rename to "zh-cn/device-dev/guide/figures/\346\267\273\345\212\240\351\241\265\351\235\242.png"
diff --git a/zh-cn/device-dev/guide/figure/Video_2020-07-25_173141.gif "b/zh-cn/device-dev/guide/figures/\347\251\272\346\260\224\350\264\250\351\207\217\347\233\221\346\265\213-App\346\230\276\347\244\272\346\225\210\346\236\234\345\233\276.gif"
old mode 100755
new mode 100644
similarity index 100%
rename from zh-cn/device-dev/guide/figure/Video_2020-07-25_173141.gif
rename to "zh-cn/device-dev/guide/figures/\347\251\272\346\260\224\350\264\250\351\207\217\347\233\221\346\265\213-App\346\230\276\347\244\272\346\225\210\346\236\234\345\233\276.gif"
diff --git "a/zh-cn/device-dev/guide/figure/\350\276\223\345\205\245\345\275\225\345\203\217\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png" "b/zh-cn/device-dev/guide/figures/\350\276\223\345\205\245\345\275\225\345\203\217\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\350\276\223\345\205\245\345\275\225\345\203\217\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png"
rename to "zh-cn/device-dev/guide/figures/\350\276\223\345\205\245\345\275\225\345\203\217\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png"
diff --git "a/zh-cn/device-dev/guide/figure/\350\276\223\345\205\245\346\213\215\347\205\247\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png" "b/zh-cn/device-dev/guide/figures/\350\276\223\345\205\245\346\213\215\347\205\247\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\350\276\223\345\205\245\346\213\215\347\205\247\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png"
rename to "zh-cn/device-dev/guide/figures/\350\276\223\345\205\245\346\213\215\347\205\247\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png"
diff --git "a/zh-cn/device-dev/guide/figure/\350\276\223\345\205\245\351\241\265\351\235\242\345\220\215\347\247\260.png" "b/zh-cn/device-dev/guide/figures/\350\276\223\345\205\245\351\241\265\351\235\242\345\220\215\347\247\260.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\350\276\223\345\205\245\351\241\265\351\235\242\345\220\215\347\247\260.png"
rename to "zh-cn/device-dev/guide/figures/\350\276\223\345\205\245\351\241\265\351\235\242\345\220\215\347\247\260.png"
diff --git "a/zh-cn/device-dev/guide/figure/\350\276\223\345\205\245\351\242\204\350\247\210\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png" "b/zh-cn/device-dev/guide/figures/\350\276\223\345\205\245\351\242\204\350\247\210\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\350\276\223\345\205\245\351\242\204\350\247\210\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png"
rename to "zh-cn/device-dev/guide/figures/\350\276\223\345\205\245\351\242\204\350\247\210\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png"
diff --git "a/zh-cn/device-dev/guide/figure/\350\276\223\345\207\272\351\200\200\345\207\272\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png" "b/zh-cn/device-dev/guide/figures/\350\276\223\345\207\272\351\200\200\345\207\272\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\350\276\223\345\207\272\351\200\200\345\207\272\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png"
rename to "zh-cn/device-dev/guide/figures/\350\276\223\345\207\272\351\200\200\345\207\272\346\214\207\344\273\244\345\220\216\344\270\262\345\217\243\346\211\223\345\215\260\346\227\245\345\277\227.png"
diff --git "a/zh-cn/device-dev/guide/figure/\351\241\265\351\235\242\344\275\215\347\275\256\346\214\207\347\244\272\345\231\250\346\225\210\346\236\234\345\233\276.png" "b/zh-cn/device-dev/guide/figures/\351\241\265\351\235\242\344\275\215\347\275\256\346\214\207\347\244\272\345\231\250\346\225\210\346\236\234\345\233\276.png"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\351\241\265\351\235\242\344\275\215\347\275\256\346\214\207\347\244\272\345\231\250\346\225\210\346\236\234\345\233\276.png"
rename to "zh-cn/device-dev/guide/figures/\351\241\265\351\235\242\344\275\215\347\275\256\346\214\207\347\244\272\345\231\250\346\225\210\346\236\234\345\233\276.png"
diff --git "a/zh-cn/device-dev/guide/figure/\351\242\204\350\247\210\346\225\210\346\236\234.jpg" "b/zh-cn/device-dev/guide/figures/\351\242\204\350\247\210\346\225\210\346\236\234.jpg"
old mode 100755
new mode 100644
similarity index 100%
rename from "zh-cn/device-dev/guide/figure/\351\242\204\350\247\210\346\225\210\346\236\234.jpg"
rename to "zh-cn/device-dev/guide/figures/\351\242\204\350\247\210\346\225\210\346\236\234.jpg"
diff --git a/zh-cn/device-dev/guide/oem_wifi_sdk_des.md b/zh-cn/device-dev/guide/oem_wifi_sdk_des.md
index 03d75354c30d9f2f2b6ae3642486ad5a98162960..add96b6c88418f5fa8e5a87ea7daee4f55c22427 100644
--- a/zh-cn/device-dev/guide/oem_wifi_sdk_des.md
+++ b/zh-cn/device-dev/guide/oem_wifi_sdk_des.md
@@ -106,5 +106,5 @@ OpenHarmony WLAN模组基于Hi3861平台提供了丰富的外设操作能力,
完成以上两步后,按下RST键复位模组,可发现LED在周期性闪烁,与预期相符,验证完毕。
**图 1** LED闪烁图
-
+
diff --git a/zh-cn/device-dev/kernel/Readme-CN.md b/zh-cn/device-dev/kernel/Readme-CN.md
index ad85f2b2a7f98dd16dfe9bfead16c12a78d2f18a..b63423d773efc9efdb195e0bd5a5bf548736e90f 100755
--- a/zh-cn/device-dev/kernel/Readme-CN.md
+++ b/zh-cn/device-dev/kernel/Readme-CN.md
@@ -109,7 +109,6 @@
- [cpup](kernel-small-debug-shell-cmd-cpup.md)
- [date](kernel-small-debug-shell-cmd-date.md)
- [dmesg](kernel-small-debug-shell-cmd-dmesg.md)
- - [du](kernel-small-debug-shell-file-du.md)
- [exec](kernel-small-debug-shell-cmd-exec.md)
- [free](kernel-small-debug-shell-cmd-free.md)
- [help](kernel-small-debug-shell-cmd-help.md)
@@ -119,7 +118,6 @@
- [memcheck](kernel-small-debug-shell-cmd-memcheck.md)
- [oom](kernel-small-debug-shell-cmd-oom.md)
- [pmm](kernel-small-debug-shell-cmd-pmm.md)
- - [reboot](kernel-small-debug-shell-cmd-reboot.md)
- [reset](kernel-small-debug-shell-cmd-reset.md)
- [sem](kernel-small-debug-shell-cmd-sem.md)
- [stack](kernel-small-debug-shell-cmd-stack.md)
@@ -127,7 +125,6 @@
- [swtmr](kernel-small-debug-shell-cmd-swtmr.md)
- [systeminfo](kernel-small-debug-shell-cmd-sysinfo.md)
- [task](kernel-small-debug-shell-cmd-task.md)
- - [top](kernel-small-debug-shell-cmd-top.md)
- [uname](kernel-small-debug-shell-cmd-uname.md)
- [vmm](kernel-small-debug-shell-cmd-vmm.md)
- [watch](kernel-small-debug-shell-cmd-watch.md)
@@ -143,7 +140,6 @@
- [lsfd](kernel-small-debug-shell-file-lsfd.md)
- [mkdir](kernel-small-debug-shell-file-mkdir.md)
- [mount](kernel-small-debug-shell-file-mount.md)
- - [mv](kernel-small-debug-shell-file-mv.md)
- [partinfo](kernel-small-debug-shell-file-partinfo.md)
- [partition](kernel-small-debug-shell-file-partition.md)
- [pwd](kernel-small-debug-shell-file-pwd.md)
@@ -157,6 +153,7 @@
- [网络命令](kernel-small-debug-shell-net.md)
- [arp](kernel-small-debug-shell-net-arp.md)
- [dhclient](kernel-small-debug-shell-net-dhclient.md)
+ - [dns](kernel-small-debug-shell-net-dns.md)
- [ifconfig](kernel-small-debug-shell-net-ifconfig.md)
- [ipdebug](kernel-small-debug-shell-net-ipdebug.md)
- [netstat](kernel-small-debug-shell-net-netstat.md)
@@ -174,6 +171,15 @@
- [内存信息统计](kernel-small-debug-memory-info.md)
- [内存泄漏检测](kernel-small-debug-memory-leak.md)
- [踩内存检测](kernel-small-debug-memory-corrupt.md)
+ - [用户态内存调测](kernel-small-debug-user.md)
+ - [基本概念](kernel-small-debug-user-concept.md)
+ - [运行机制](kernel-small-debug-user-function.md)
+ - [使用指导](kernel-small-debug-user-guide.md)
+ - [接口说明](kernel-small-debug-user-guide-api.md)
+ - [使用说明](kernel-small-debug-user-guide-use.md)
+ - [接口调用方式](kernel-small-debug-user-guide-use-api.md)
+ - [命令行参数方式](kernel-small-debug-user-guide-use-cli.md)
+ - [常见问题场景](kernel-small-debug-user-faqs.md)
- [其他内核调测手段](kernel-small-debug-other.md)
- [临终遗言](kernel-small-debug-trace-other-lastwords.md)
- [常见问题定位方法](kernel-small-debug-trace-other-faqs.md)
diff --git "a/zh-cn/device-dev/kernel/figure/free\346\265\201\347\250\213\345\233\276.png" "b/zh-cn/device-dev/kernel/figure/free\346\265\201\347\250\213\345\233\276.png"
new file mode 100644
index 0000000000000000000000000000000000000000..a8e6e991fc5a81574ad92c44d45bff71c450bbc3
Binary files /dev/null and "b/zh-cn/device-dev/kernel/figure/free\346\265\201\347\250\213\345\233\276.png" differ
diff --git "a/zh-cn/device-dev/kernel/figure/malloc\351\200\232\350\277\207mmap\346\234\272\345\210\266\347\224\263\350\257\267\345\206\205\345\255\230\347\232\204\345\206\205\345\255\230\345\270\203\345\261\200.png" "b/zh-cn/device-dev/kernel/figure/malloc\351\200\232\350\277\207mmap\346\234\272\345\210\266\347\224\263\350\257\267\345\206\205\345\255\230\347\232\204\345\206\205\345\255\230\345\270\203\345\261\200.png"
new file mode 100644
index 0000000000000000000000000000000000000000..ff50b0e8ef50063df83834091a8d0c0992372599
Binary files /dev/null and "b/zh-cn/device-dev/kernel/figure/malloc\351\200\232\350\277\207mmap\346\234\272\345\210\266\347\224\263\350\257\267\345\206\205\345\255\230\347\232\204\345\206\205\345\255\230\345\270\203\345\261\200.png" differ
diff --git "a/zh-cn/device-dev/kernel/figure/node\350\212\202\347\202\271\345\244\264\344\277\241\346\201\257\346\267\273\345\212\240\346\240\241\351\252\214\345\200\274.png" "b/zh-cn/device-dev/kernel/figure/node\350\212\202\347\202\271\345\244\264\344\277\241\346\201\257\346\267\273\345\212\240\346\240\241\351\252\214\345\200\274.png"
new file mode 100644
index 0000000000000000000000000000000000000000..9a49391cd3d662305134251f4ee4261c10852106
Binary files /dev/null and "b/zh-cn/device-dev/kernel/figure/node\350\212\202\347\202\271\345\244\264\344\277\241\346\201\257\346\267\273\345\212\240\346\240\241\351\252\214\345\200\274.png" differ
diff --git "a/zh-cn/device-dev/kernel/figure/\345\240\206\345\206\205\345\255\230\350\212\202\347\202\271\344\277\241\346\201\257.png" "b/zh-cn/device-dev/kernel/figure/\345\240\206\345\206\205\345\255\230\350\212\202\347\202\271\344\277\241\346\201\257.png"
new file mode 100644
index 0000000000000000000000000000000000000000..131519e92cadb00d4ae33f180fba7e410120f98f
Binary files /dev/null and "b/zh-cn/device-dev/kernel/figure/\345\240\206\345\206\205\345\255\230\350\212\202\347\202\271\344\277\241\346\201\257.png" differ
diff --git "a/zh-cn/device-dev/kernel/figure/\345\240\206\345\206\205\345\255\230\350\212\202\347\202\271\344\277\241\346\201\257\351\223\276\350\241\250.png" "b/zh-cn/device-dev/kernel/figure/\345\240\206\345\206\205\345\255\230\350\212\202\347\202\271\344\277\241\346\201\257\351\223\276\350\241\250.png"
new file mode 100644
index 0000000000000000000000000000000000000000..17c3d03c4b35ad7b8d31e9ec091d683d498a0d90
Binary files /dev/null and "b/zh-cn/device-dev/kernel/figure/\345\240\206\345\206\205\345\255\230\350\212\202\347\202\271\344\277\241\346\201\257\351\223\276\350\241\250.png" differ
diff --git "a/zh-cn/device-dev/kernel/figure/\346\263\204\346\274\217\347\202\271\344\273\243\347\240\201\350\241\214\345\256\232\344\275\215\346\265\201\347\250\213.png" "b/zh-cn/device-dev/kernel/figure/\346\263\204\346\274\217\347\202\271\344\273\243\347\240\201\350\241\214\345\256\232\344\275\215\346\265\201\347\250\213.png"
new file mode 100644
index 0000000000000000000000000000000000000000..0b882d1347c0aa55aa855808847bfb2fad8d8693
Binary files /dev/null and "b/zh-cn/device-dev/kernel/figure/\346\263\204\346\274\217\347\202\271\344\273\243\347\240\201\350\241\214\345\256\232\344\275\215\346\265\201\347\250\213.png" differ
diff --git "a/zh-cn/device-dev/kernel/figure/\350\275\273\351\207\217\347\263\273\347\273\237\345\212\250\346\200\201\345\206\205\345\255\230\346\240\270\345\277\203\347\256\227\346\263\225.png" "b/zh-cn/device-dev/kernel/figure/\350\275\273\351\207\217\347\263\273\347\273\237\345\212\250\346\200\201\345\206\205\345\255\230\346\240\270\345\277\203\347\256\227\346\263\225.png"
new file mode 100644
index 0000000000000000000000000000000000000000..bd73700c41d62b47005ad0612c74f2823a1921a9
Binary files /dev/null and "b/zh-cn/device-dev/kernel/figure/\350\275\273\351\207\217\347\263\273\347\273\237\345\212\250\346\200\201\345\206\205\345\255\230\346\240\270\345\277\203\347\256\227\346\263\225.png" differ
diff --git a/zh-cn/device-dev/kernel/kernel-mini-basic-memory-dynamic.md b/zh-cn/device-dev/kernel/kernel-mini-basic-memory-dynamic.md
index 64cccc6f91955f7bcea0a30fc581c94e86bb95ff..5dfdb5bab67a1e03b3fb3b5e8e91e84be5a82631 100644
--- a/zh-cn/device-dev/kernel/kernel-mini-basic-memory-dynamic.md
+++ b/zh-cn/device-dev/kernel/kernel-mini-basic-memory-dynamic.md
@@ -16,7 +16,7 @@
OpenHarmony LiteOS-M动态内存在TLSF算法的基础上,对区间的划分进行了优化,获得更优的性能,降低了碎片率。动态内存核心算法框图如下:
**图 1** 动态内存核心算法
-
+
根据空闲内存块的大小,使用多个空闲链表来管理。根据内存空闲块大小分为两个部分:\[4, 127\]和\[27, 231\],如上图size class所示:
diff --git a/zh-cn/device-dev/kernel/kernel-small-debug-user-concept.md b/zh-cn/device-dev/kernel/kernel-small-debug-user-concept.md
new file mode 100644
index 0000000000000000000000000000000000000000..5266e039bf2804a3b0c564af61a486dda14fcfa6
--- /dev/null
+++ b/zh-cn/device-dev/kernel/kernel-small-debug-user-concept.md
@@ -0,0 +1,6 @@
+# 基本概念
+
+Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、踩内存分析以及backtrace功能等维测手段,可以提高用户态内存相关问题的定位效率。
+
+采用了对malloc/free接口进行插桩,保存关键节点信息,然后程序在申请和释放内存时进行内存节点完整性校验,最后在程序结束时通过统计节点信息得到内存统计信息并根据统计信息判断内存是否泄漏的设计思想。
+
diff --git a/zh-cn/device-dev/kernel/kernel-small-debug-user-faqs.md b/zh-cn/device-dev/kernel/kernel-small-debug-user-faqs.md
new file mode 100644
index 0000000000000000000000000000000000000000..064b627e16376bc316754ed0b2046cfda7d2bf7d
--- /dev/null
+++ b/zh-cn/device-dev/kernel/kernel-small-debug-user-faqs.md
@@ -0,0 +1,52 @@
+# 常见问题场景
+
+- [UAF\(Use after free\)](#section4427132815445)
+- [Double free](#section827194818458)
+- [堆内存节点被踩](#section1763741216461)
+
+## UAF\(Use after free\)
+
+- 申请小块内存(不大于0x1c000字节)
+
+ free之后:
+
+ 读操作:读取free之后的内存大概率是魔术数字\(0xFEFEFEFE\)
+
+ > **说明:**
+ >free之后的堆内存不会立即释放进堆内存池,会先放至固定长度的队列中,并置魔术数字0xFE,队列满后会将先放至队列中的内存块释放进堆内存池
+
+ 写操作:无法校验。
+
+
+- 申请大块内存(大于0x1c000)
+
+ 堆内存由malloc通过调用mmap接口申请,free之后若仍访问该内存,则用户程序异常(该内存区间已被unmap)。
+
+
+## Double free
+
+Double free时,用户程序将会异常退出。
+
+## 堆内存节点被踩
+
+- 申请小块内存(不大于0x1c000)
+
+ 堆内存节点被踩时,用户程序将会异常退出,并输出破坏被踩节点的可能的堆内存申请调用栈,对于野指针踩内存情况无法校验出来。例如用户程序mem\_check中存在堆内存越界踩的情况,利用命令行方式可以获得踩内存的可能的具体位置。
+
+ ```
+ OHOS # ./mem_check --mwatch
+ OHOS #
+ ==PID:6== Memory integrity information:
+ [TID:28 allocated addr: 0x272e1ea0, size: 0x120] The possible attacker was allocated from:
+ #00: [0x640e8] -> /lib/libc.so
+ #01: [0x21d0] -> mem_check
+ ```
+
+ 可以通过调用栈解析脚本对调用栈信息进行解析。
+
+
+- 申请大块内存(大于0x1c000)
+
+ 堆内存由malloc通过mmap接口申请,申请得到的堆内存块前后各置一个size为PAGE\_SIZE大小的区间,设置无读写权限,读写操作会触发用户程序异常。
+
+
diff --git a/zh-cn/device-dev/kernel/kernel-small-debug-user-function.md b/zh-cn/device-dev/kernel/kernel-small-debug-user-function.md
new file mode 100644
index 0000000000000000000000000000000000000000..96783b00693d4c85e2f82aed7e5cfb49444d07da
--- /dev/null
+++ b/zh-cn/device-dev/kernel/kernel-small-debug-user-function.md
@@ -0,0 +1,58 @@
+# 运行机制
+
+- [内存泄漏检查](#section142061581018)
+- [堆内存统计](#section136902041337)
+- [内存完整性检查](#section196491231761)
+
+## 内存泄漏检查
+
+对于每个进程,内存调测模块维护了128个链表(当前系统的线程最大数量为128个),每个链表的索引为线程ID。
+
+申请内存时:保存关键信息到内存节点控制块,根据当前线程ID将内存节点控制块挂到对应链表;
+
+释放内存时:根据需要释放的内存地址匹配内存节点控制块并将该控制块删除。
+
+**图 1** 堆内存节点信息链表
+
+
+申请内存时,返回地址会被保存到LR寄存器中。进程运行过程中,系统会在内存节点控制块中添加疑似泄漏点对应的lr等信息。如下图所示:
+
+**图 2** 堆内存节点信息
+
+
+其中,TID表示线程ID;PID表示进程ID;ptr表示申请的内存地址;size表示申请的内存大小;lr\[n\]表示函数调用栈地址,变量n可以根据具体场景的需要进行配置。
+
+释放内存时,将free等接口的入参指针与node的ptr字段进行匹配,如果相同则删除该内存节点控制块信息。
+
+用户通过串口或文件等方式,将各个进程内存调测信息导出,利用addr2line工具将导出的信息转换成导致内存泄漏的代码行,便可以解决内存泄露问题。
+
+**图 3** 泄漏点代码行定位流程
+
+
+## 堆内存统计
+
+用户态线程堆内存使用统计具有一定的实际意义,统计线程申请的堆内存占比,为用户程序的内存使用优化提供数据支持。用户态堆内存统计模块主要涉及的接口为malloc和free。如[图1](#fig4294145810543),每个进程维护128个链表,链表索引即线程ID,申请内存时系统将ptr和size信息记录在内存节点控制块中并将节点控制块挂在以线程ID为头信息的链表上,堆内存释放时根据ptr从对应的链表上移除相应的堆内存块信息;同时计算出当前线程所持有的堆内存总的使用量,并更新当前进程的堆内存使用量和堆内存使用峰值。
+
+## 内存完整性检查
+
+- 使用malloc申请内存(小于等于0x1c000bytes时通过堆分配算法分配)
+
+ 用户程序申请堆内存时,在堆内存节点处添加校验值等信息,如果校验值异常,则很有可能是前一块堆内存使用越界导致的(目前无法识别校验值被野指针破坏的场景)。在内存申请、释放时校验内存节点校验值的正确性,若内存节点被破坏,校验失败时则输出tid、pid及当前被踩节点前一块堆内存申请时保存的调用栈信息,通过addr2line工具可获得具体的代码行信息,辅助用户解决问题。
+
+ **图 4** node节点头信息添加校验值
+ 
+
+ free堆内存时,不会立即把该内存块释放掉,而是在内存中写入魔术数字0xFE,并放到free队列中\(保证在一定时间内不会再被malloc函数分配\),当有野指针或use-after-free的情况对该内存进行读取的操作时,能够发现数据异常,但是对于写操作则无法判断出来。
+
+ **图 5** free流程图
+ 
+
+
+- 使用malloc申请内存(大于0x1c000bytes时通过mmap申请)
+
+ 当malloc通过mmap申请大块内存时,在返回给用户使用的内存区间头和尾分别多申请一个页,一个页PAGE\_SIZE当前为0x1000,这两个页分别通过mprotect接口设置权限为PROT\_NONE(无可读可写权限),可以有效防止内存越界读写问题:越界读写数据时由于无读写权限而导致用户程序异常,根据异常调用栈信息可找到相应的代码逻辑。
+
+ **图 6** malloc通过mmap机制申请内存的内存布局
+ 
+
+
diff --git a/zh-cn/device-dev/kernel/kernel-small-debug-user-guide-api.md b/zh-cn/device-dev/kernel/kernel-small-debug-user-guide-api.md
new file mode 100644
index 0000000000000000000000000000000000000000..d87b20aeba05abcdccfc0e8f9a4ad6bf9513996e
--- /dev/null
+++ b/zh-cn/device-dev/kernel/kernel-small-debug-user-guide-api.md
@@ -0,0 +1,55 @@
+# 接口说明
+
+**表 1** 内存调测模块接口
+
+
+功能分类
+ |
+接口名
+ |
+描述
+ |
+
+
+内存调测功能
+ |
+mem_check_init
+ |
+初始化内存检测模块。
+ |
+
+watch_mem
+ |
+获取线程级堆内存使用信息。
+ |
+
+check_leak
+ |
+检查是否有堆内存泄漏。
+ |
+
+check_heap_integrity
+ |
+检查堆内存的完整性。
+ |
+
+调用栈回溯功能
+ |
+backtrace
+ |
+获取调用栈地址信息。
+ |
+
+backtrace_symbols
+ |
+根据地址信息获取符号信息。
+ |
+
+print_trace
+ |
+输出函数调用栈信息。
+ |
+
+
+
+
diff --git a/zh-cn/device-dev/kernel/kernel-small-debug-user-guide-use-api.md b/zh-cn/device-dev/kernel/kernel-small-debug-user-guide-use-api.md
new file mode 100644
index 0000000000000000000000000000000000000000..d5b8010de25a7b9bd4958befc77a5839322551c4
--- /dev/null
+++ b/zh-cn/device-dev/kernel/kernel-small-debug-user-guide-use-api.md
@@ -0,0 +1,147 @@
+# 接口调用方式
+
+- [示例代码](#section5490173592518)
+- [编译](#section534302242515)
+- [调测信息](#section1017419992515)
+- [调用栈解析](#section1485163282417)
+
+## 示例代码
+
+代码功能:显式调用调测模块的相关接口对用户代码进行内存校验。
+
+```
+#include
+#include
+#include
+#include // 包含提供内存调测接口声明的头文件
+
+#define MALLOC_LEAK_SIZE 0x300
+
+void func(void) {
+ char *ptr = malloc(MALLOC_LEAK_SIZE);
+ memset(ptr, '3', MALLOC_LEAK_SIZE);
+}
+
+int main()
+{
+ mem_check_init(NULL); // 通过串口输出内存调测信息,必须在用户程序第一次申请堆内存之前调用(一般在main函数入口调用),否则调测信息不准确。
+ // mem_check_init("/storage/mem_debug.txt"); // 内存调测信息输出到/storage/mem_debug.txt文件中,如果该文件创建失败,则信息通过串口输出。
+ char *ptr = malloc(MALLOC_LEAK_SIZE);
+ memset(ptr, '1', MALLOC_LEAK_SIZE);
+
+ watch_mem(); // 在当前代码逻辑处查看线程级内存统计信息。
+ func();
+ check_heap_integrity(); // 检查堆内存节点完整性。
+ check_leak(); // 在当前代码逻辑处检查堆内存是否泄漏(一般在程序退出之前校验比较准确,若在malloc和free调用逻辑之间做校验,则结果不准确)。
+ return 0;
+}
+```
+
+## 编译
+
+```
+$ clang -o mem_check mem_check.c -funwind-tables -rdynamic -g -mfloat-abi=softfp -mcpu=cortex-a7 -mfpu=neon-vfpv4 -target arm-liteos --sysroot=/home//harmony/out/hispark_taurus/ipcamera_hispark_taurus/sysroot $(clang -mfloat-abi=softfp -mcpu=cortex-a7 -mfpu=neon-vfpv4 -target arm-liteos -print-file-name=libunwind.a)
+```
+
+> **说明:**
+>- 本编译示例基于将编译器的路径写入环境变量中,即.bashrc文件中。
+>- 编译用户程序及所需的lib库时,需要添加编译选项-funwind-tables,-rdynamic,-g,用于栈回溯。
+>- -mfloat-abi=softfp,-mcpu=cortex-a7,-mfpu=neon-vfpv4编译选项用于指定具体的芯片架构、浮点数计算优化、fpu,与具体的libc库使用的编译选项保持一致,否则链接时可能出现找不到libc库文件。
+>- -target arm-liteos用于指定编译器相关库文件路径。
+>- --sysroot=/home//harmony/out/hispark\_taurus/ipcamera\_hispark\_taurus/sysroot用于指定编译器库文件搜索根目录,假设OpenHarmony工程代码存放路径为/home//harmony。其中out/hispark\_taurus/ipcamera\_hispark\_taurus路径为在编译时,hb set命令指定的具体产品,本示例选择的是ipcamera\_hispark\_taurus产品。
+>- $\(clang -mfloat-abi=softfp -mcpu=cortex-a7 -mfpu=neon-vfpv4 -target arm-liteos -print-file-name=libunwind.a\)用于指定相应的unwind库的路径。
+
+## 调测信息
+
+```
+OHOS # ./mem_check
+OHOS #
+==PID:4== Heap memory statistics(bytes): // 堆内存统计信息
+ [Check point]: // check点调用栈
+ #00: [0x86c] -> mem_check
+ #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
+
+ [TID: 18, Used: 0x320] // 18号线程堆内存占用,当前进程仅一个线程
+
+==PID:4== Total heap: 0x320 byte(s), Peak: 0x320 byte(s)
+
+Check heap integrity ok! // 堆内存完整性检查
+
+==PID:4== Detected memory leak(s): // 内存泄漏信息及调用栈
+ [Check point]:
+ #00: [0x2da4c] -> /lib/libc.so
+ #01: [0x878] -> mem_check
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x850] -> mem_check
+ #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x810] -> mem_check
+ #01: [0x870] -> mem_check
+ #02: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
+
+==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
+
+==PID:4== Detected memory leak(s):
+ [Check point]:
+ #00: [0x2da4c] -> /lib/libc.so
+ #01: [0x111ec] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x850] -> mem_check
+ #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x810] -> mem_check
+ #01: [0x870] -> mem_check
+ #02: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
+
+==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
+
+Check heap integrity ok!
+```
+
+## 调用栈解析
+
+提供parse\_mem\_info.sh脚本可以对调用栈进行解析,解析脚本存放的路径:kernel/liteos\_a/tools/scripts/parse\_memory/parse\_mem\_info.sh。利用脚本可以将相应的调测信息转换成具体的源码行号,如下命令所示,mem\_debug.txt保存的是内存调测信息,elf1、elf2等文件是需要解析的elf文件。
+
+```
+$ ./parse_mem_info.sh mem_debug.txt elf1 elf2 elf3 ...
+```
+
+例如:
+
+```
+$ ./parse_mem_info.sh mem_debug.txt mem_check
+Compiler is [gcc/llvm]: llvm
+Now using addr2line ...
+
+==PID:4== Heap memory statistics(bytes):
+ [Check point]:
+ #00: [0x86c] at /usr1/xxx/TEST_ELF/mem_check.c:22
+ #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
+
+ [TID: 18, Used: 0x320]
+
+==PID:4== Total heap: 0x320 byte(s), Peak: 0x320 byte(s)
+
+Check heap integrity ok!
+
+==PID:4== Detected memory leak(s):
+ [Check point]:
+ #00: [0x2da4c] -> /lib/libc.so
+ #01: [0x878] at /usr1/xxx/TEST_ELF/mem_check.c:28
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x850] at /usr1/xxx/TEST_ELF/mem_check.c:17
+ #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x810] at /usr1/xxx/TEST_ELF/mem_check.c:9
+ #01: [0x870] at /usr1/xxx/TEST_ELF/mem_check.c:24
+ #02: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
+
+==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
+```
+
diff --git a/zh-cn/device-dev/kernel/kernel-small-debug-user-guide-use-cli.md b/zh-cn/device-dev/kernel/kernel-small-debug-user-guide-use-cli.md
new file mode 100644
index 0000000000000000000000000000000000000000..129757a1faba0e63fbce58035d6375a4b458bdb2
--- /dev/null
+++ b/zh-cn/device-dev/kernel/kernel-small-debug-user-guide-use-cli.md
@@ -0,0 +1,229 @@
+# 命令行参数方式
+
+- [示例代码](#section13793104782316)
+- [编译](#section1676431122320)
+- [使用mwatch参数命令](#section1703415132311)
+- [调用栈解析](#section1880675510221)
+- [使用mrecord参数命令](#section071022822210)
+
+对用户态进程进行内存相关的检查时,除了接口调用方式还可以通过命令行方式进行内存统计、内存泄漏或内存完整性检查。
+
+```
+--mwatch:初始化内存调测功能,注册信号。内存调测信息将从串口输出;
+--mrecord :初始化内存调测功能,注册信号。内存调测信息将保存至f_path文件,若f_path创建失败,则内存调测信息将从串口输出
+```
+
+在待调测的进程未退出时可使用信号机制获取对应信息:
+
+```
+kill -35 # 查看线程级堆内存占用
+kill -36 # 检查是否存在堆内存泄漏
+kill -37 # 检查堆内存头节点是否完整
+```
+
+## 示例代码
+
+代码功能:构造内存问题利用命令行方式进行内存调测。
+
+```
+#include
+#include
+#include
+
+#define MALLOC_LEAK_SIZE 0x300
+
+void func(void) {
+ char *ptr = malloc(MALLOC_LEAK_SIZE);
+ memset(ptr, '3', MALLOC_LEAK_SIZE);
+}
+
+int main()
+{
+ char *ptr = malloc(MALLOC_LEAK_SIZE);
+ memset(ptr, '1', MALLOC_LEAK_SIZE);
+ func();
+ while (1);
+}
+```
+
+## 编译
+
+参考[接口调用一节](kernel-small-debug-user-guide-use-api.md#section534302242515)。
+
+## 使用mwatch参数命令
+
+```
+OHOS # ./mem_check --mwatch // 利用task命令可以查到mem_check进程的pid为4
+OHOS #
+OHOS # kill -35 4 // 查看堆内存统计信息
+OHOS #
+==PID:4== Heap memory statistics(bytes):
+ [Check point]:
+ #00: [0x58dfc] -> /lib/libc.so
+
+ [TID: 18, Used: 0x640]
+
+==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
+
+OHOS # kill -36 4 // 检查是否存在堆内存泄漏
+OHOS #
+==PID:4== Detected memory leak(s):
+ [Check point]:
+ #00: [0x2da4c] -> /lib/libc.so
+ #01: [0x58dfc] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x724] -> mem_check
+ #01: <(null)+0x2555a9dc>[0x219dc] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x6ec] -> mem_check
+ #01: [0x740] -> mem_check
+ #02: <(null)+0x2555a9dc>[0x219dc] -> /lib/libc.so
+
+==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
+
+OHOS # kill -37 4 // 检查堆内存头节点的完整性
+OHOS #
+Check heap integrity ok!
+```
+
+## 调用栈解析
+
+将调测信息保存至test.txt文件中,利用脚本进行解析,获取内存泄漏的具体行号。
+
+```
+$ ./parse_mem_info.sh test.txt mem_check
+Compiler is [gcc/llvm]: llvm
+Now using addr2line ...
+
+==PID:4== Detected memory leak(s):
+ [Check point]:
+ #00: [0x2da4c] -> /lib/libc.so
+ #01: [0x58dfc] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x724] at /usr1/xxx/TEST_ELF/mem_check.c:14
+ #01: <(null)+0x2555a9dc>[0x219dc] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x6ec] at /usr1/xxx/TEST_ELF/mem_check.c:8
+ #01: [0x740] at /usr1/xxx/TEST_ELF/mem_check.c:19
+ #02: <(null)+0x2555a9dc>[0x219dc] -> /lib/libc.so
+
+==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
+```
+
+## 使用mrecord参数命令
+
+1. 执行用户程序并指定记录内存调测信息的文件路径
+
+ ```
+ OHOS # ./mem_check --mrecord /storage/check.txt
+ ```
+
+2. 利用kill -35 统计内存信息,该信息将会输出到文件中,使用cat命令查看
+
+ ```
+ OHOS # kill -35 4
+ OHOS # Memory statistics information saved in /storage/pid(4)_check.txt
+
+ OHOS # cat /storage/pid(4)_check.txt
+
+ ==PID:4== Heap memory statistics(bytes):
+ [Check point]:
+ #00: [0x5973c] -> /lib/libc.so
+
+ [TID: 18, Used: 0x640]
+
+ ==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
+ ```
+
+3. 利用kill -36 校验内存完整性,该信息将会输出到文件中,使用cat命令查看
+
+ ```
+ OHOS # kill -36 4
+ OHOS # Leak check information saved in /storage/pid(4)_check.txt
+
+ OHOS # cat /storage/pid(4)_check.txt
+
+ ==PID:4== Heap memory statistics(bytes):
+ [Check point]:
+ #00: [0x5973c] -> /lib/libc.so
+
+ [TID: 18, Used: 0x640]
+
+ ==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
+
+ ==PID:4== Detected memory leak(s):
+ [Check point]:
+ #00: [0x2e38c] -> /lib/libc.so
+ #01: [0x5973c] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x724] -> mem_check
+ #01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x6ec] -> mem_check
+ #01: [0x740] -> mem_check
+ #02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
+
+ ==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
+ ```
+
+4. 利用kill -9 杀掉当前进程,进程退出后会默认校验内存完整性,该信息将会输出到文件中,使用cat命令查看
+
+ ```
+ OHOS # kill -9 4
+ OHOS # Leak check information saved in /storage/pid(4)_check.txt
+
+ Check heap integrity ok!
+
+ OHOS # cat /storage/pid(4)_check.txt
+ OHOS #
+ ==PID:4== Heap memory statistics(bytes):
+ [Check point]:
+ #00: [0x5973c] -> /lib/libc.so
+
+ [TID: 18, Used: 0x640]
+
+ ==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
+
+ ==PID:4== Detected memory leak(s):
+ [Check point]:
+ #00: [0x2e38c] -> /lib/libc.so
+ #01: [0x5973c] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x724] -> mem_check
+ #01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x6ec] -> mem_check
+ #01: [0x740] -> mem_check
+ #02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
+
+ ==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
+
+ ==PID:4== Detected memory leak(s):
+ [Check point]:
+ #00: [0x2e38c] -> /lib/libc.so
+ #01: [0x11b2c] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x724] -> mem_check
+ #01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
+
+ [TID:18 Leak:0x320 byte(s)] Allocated from:
+ #00: [0x6ec] -> mem_check
+ #01: [0x740] -> mem_check
+ #02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
+
+ ==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
+ ```
+
+
+> **说明:**
+>上述连续记录的信息会逐步追加到初始化时所指定的文件中,故最后cat文件时,文件中还包含历史记录的信息内容。
+
diff --git a/zh-cn/device-dev/kernel/kernel-small-debug-user-guide-use.md b/zh-cn/device-dev/kernel/kernel-small-debug-user-guide-use.md
new file mode 100644
index 0000000000000000000000000000000000000000..693255e5ed286d06891ed866b675c38997834340
--- /dev/null
+++ b/zh-cn/device-dev/kernel/kernel-small-debug-user-guide-use.md
@@ -0,0 +1,17 @@
+# 使用说明
+
+编译OpenHarmony工程时默认编译的是debug版本,即libc库已经集成内存调测相关的接口实现,用户可以根据具体需要决定是否使能内存调测功能。
+
+堆内存调测功能提供两种方式供用户使用:接口调用及命令行参数。
+
+- 接口调用:优点是可以较精确的检查某一段代码逻辑的堆内存相关信息,缺点是需要修改用户代码。
+- 命令行参数:优点是无需修改用户代码,缺点是无法精确的校验某一段逻辑的堆内存信息。
+
+> **说明:**
+>内存调测功能使能后,进程退出时会默认进行一次堆内存泄漏和堆内存完整性检查。内存调测功能未使能时,堆内存统计、堆内存泄漏检查、堆内存完整性校验功能不会开启,调用相关调测接口无响应。
+
+- **[接口调用方式](kernel-small-debug-user-guide-use-api.md)**
+
+- **[命令行参数方式](kernel-small-debug-user-guide-use-cli.md)**
+
+
diff --git a/zh-cn/device-dev/kernel/kernel-small-debug-user-guide.md b/zh-cn/device-dev/kernel/kernel-small-debug-user-guide.md
new file mode 100644
index 0000000000000000000000000000000000000000..cd541f2cfd02c351f76a6716252266bb87a7d488
--- /dev/null
+++ b/zh-cn/device-dev/kernel/kernel-small-debug-user-guide.md
@@ -0,0 +1,7 @@
+# 使用指导
+
+- **[接口说明](kernel-small-debug-user-guide-api.md)**
+
+- **[使用说明](kernel-small-debug-user-guide-use.md)**
+
+
diff --git a/zh-cn/device-dev/kernel/kernel-small-debug-user.md b/zh-cn/device-dev/kernel/kernel-small-debug-user.md
new file mode 100644
index 0000000000000000000000000000000000000000..e36276326b878149ba308f8f0a75c5b526425b0a
--- /dev/null
+++ b/zh-cn/device-dev/kernel/kernel-small-debug-user.md
@@ -0,0 +1,17 @@
+# 用户态内存调测
+
+- **[基本概念](kernel-small-debug-user-concept.md)**
+
+- **[运行机制](kernel-small-debug-user-function.md)**
+
+- **[使用指导](kernel-small-debug-user-guide.md)**
+
+- **[常见问题场景](kernel-small-debug-user-faqs.md)**
+
+- **[Linux内核概述](kernel-standard-overview.md)**
+
+- **[OpenHarmony开发板Patch使用指导](kernel-standard-patch.md)**
+
+- **[Linux内核编译与构建指导](kernel-standard-build.md)**
+
+
diff --git a/zh-cn/device-dev/subsystems/subsys-security-sigverify.md b/zh-cn/device-dev/subsystems/subsys-security-sigverify.md
index 7c46ac23f5d5892104ed36a6b7b357fb5b3d8f8d..b1a14628ca79609c129d807ba52adbecfd12a9f1 100644
--- a/zh-cn/device-dev/subsystems/subsys-security-sigverify.md
+++ b/zh-cn/device-dev/subsystems/subsys-security-sigverify.md
@@ -92,5 +92,5 @@
### 生成OpenHarmony签名应用
-参考文档:https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/%E9%85%8D%E7%BD%AEOpenHarmony%E5%BA%94%E7%94%A8%E7%AD%BE%E5%90%8D%E4%BF%A1%E6%81%AF.md
+参考文档:https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/configuring-openharmony-app-signature.md
diff --git a/zh-cn/readme.md b/zh-cn/readme.md
index ac183bb6a815c6346024d80a7df0dcd9636c6b4b..a8aeda8b9cf5977171b6dffec98508f3d0248110 100644
--- a/zh-cn/readme.md
+++ b/zh-cn/readme.md
@@ -17,6 +17,7 @@
- Security:[隐私与安全](device-dev/security/Readme-CN.md)
- guide:开发示例
+ - [碰一碰](device-dev/guide/device-wlan-touch.md)
- [WLAN连接类产品](device-dev/guide/device-wlan.md)(LED外设控制、集成三方SDK)
- [无屏摄像头类产品](device-dev/guide/device-iotcamera-control.md)(摄像头控制)
- [带屏摄像头类产品](device-dev/guide/device-camera.md)(屏幕和摄像头控制、视觉应用开发)
|
---|
|