1# SDIO
2
3## 概述
4
5### 功能简介
6
7SDIO是安全数字输入输出接口(Secure Digital Input and Output)的缩写,是从SD内存卡接口的基础上演化出来的一种外设接口。SDIO接口兼容以前的SD卡,并且可以连接支持SDIO接口的其他设备。
8
9SDIO接口定义了操作SDIO的通用方法集合,包括:
10
11- 打开/关闭SDIO控制器
12
13- 独占/释放HOST
14
15- 使能/去使能设备
16
17- 申请/释放中断
18
19- 读写、获取/设置公共信息
20
21### 运作机制
22
23在HDF框架中,SDIO的接口适配模式采用独立服务模式。在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,若设备过多可能增加内存占用。
24
25独立服务模式下,核心层不会统一发布一个服务供上层使用,因此这种模式下驱动要为每个控制器发布一个服务,具体表现为:
26
27- 驱动适配者需要实现HdfDriverEntry的Bind钩子函数以绑定服务。
28
29- device_info.hcs文件中deviceNode的policy字段为1或2,不能为0。
30
31SDIO模块各分层作用:
32
33- 接口层提供打开SDIO设备、设置块的大小、读取数据、写数据、设置公共信息、获取公共信息、刷新数据、独占HOST、释放Host、使能SDIO功能设备、去使能SDIO功能设备、申请中断、释放中断关闭SDIO设备的接口。
34
35- 核心层主要提供SDIO控制器的添加、移除及管理的能力,通过钩子函数与适配层交互。
36
37- 适配层主要是将钩子函数的功能实例化,实现具体的功能。
38
39**图 1** SDIO独立服务模式结构图
40
41![SDIO独立服务模式结构图](figures/独立服务模式结构图.png)
42
43SDIO总线有两端,其中一端是主机端(HOST),另一端是设备端(DEVICE)。所有的通信都是由HOST端发出命令开始的,在DEVICE端只要能解析HOST的命令,就可以同HOST进行通信了。SDIO的HOST可以连接多个DEVICE,如图2所示:
44
45- CLK信号:HOST给DEVICE的时钟信号。
46
47- VDD信号:电源信号。
48
49- VSS信号:Ground信号。
50
51- D0-3信号:4条数据线,其中,DAT1信号线复用为中断线,在1BIT模式下DAT0用来传输数据,在4BIT模式下DAT0-DAT3用来传输数据。
52
53- CMD信号:用于HOST发送命令和DEVICE回复响应。
54
55**图 2** SDIO的HOST-DEVICE连接示意图
56
57![SDIO的HOST-DEVICE连接示意图](figures/SDIO的HOST-DEVICE连接示意图.png)
58
59### 约束与限制
60
61SDIO模块API当前仅支持内核态调用。
62
63## 使用指导
64
65### 场景介绍
66
67SDIO的应用比较广泛,目前,有许多手机都支持SDIO功能,并且很多SDIO外设也被开发出来,使得手机外接外设更加容易。常见的SDIO外设有WLAN、GPS、CAMERA、蓝牙等。
68
69### 接口说明
70
71SDIO模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/framework/include/platform/sdio_if.h72
73**表 1** SDIO驱动API接口功能介绍
74
75| 接口名 | 接口描述 |
76| -------- | -------- |
77| DevHandle SdioOpen(int16_t mmcBusNum, struct SdioFunctionConfig \*config) | 打开指定总线号的SDIO控制器 |
78| void SdioClose(DevHandle handle) | 关闭SDIO控制器 |
79| int32_t SdioReadBytes(DevHandle handle, uint8_t \*data, uint32_t addr, uint32_t size) | 从指定地址开始,增量读取指定长度的数据 |
80| int32_t SdioWriteBytes(DevHandle handle, uint8_t \*data, uint32_t addr, uint32_t size) | 从指定地址开始,增量写入指定长度的数据 |
81| int32_t SdioReadBytesFromFixedAddr(DevHandle handle, uint8_t \*data, uint32_t addr, uint32_t size, uint32_t scatterLen) | 从固定地址读取指定长度的数据 |
82| int32_t SdioWriteBytesToFixedAddr(DevHandle handle, uint8_t \*data, uint32_t addr, uint32_t size, uint32_t scatterLen) | 向固定地址写入指定长度的数据 |
83| int32_t SdioReadBytesFromFunc0(DevHandle handle, uint8_t \*data, uint32_t addr, uint32_t size) | 从SDIO function 0的指定地址空间读取指定长度的数据 |
84| int32_t SdioWriteBytesToFunc0(DevHandle handle, uint8_t \*data, uint32_t addr, uint32_t size) | 向SDIO function 0的指定地址空间写入指定长度的数据 |
85| int32_t SdioSetBlockSize(DevHandle handle, uint32_t blockSize) | 设置块的大小 |
86| int32_t SdioGetCommonInfo(DevHandle handle, SdioCommonInfo \*info, SdioCommonInfoType infoType) | 获取公共信息 |
87| int32_t SdioSetCommonInfo(DevHandle handle, SdioCommonInfo \*info, SdioCommonInfoType infoType) | 设置公共信息 |
88| int32_t SdioFlushData(DevHandle handle) | 刷新数据 |
89| void SdioClaimHost(DevHandle handle) | 独占Host |
90| void SdioReleaseHost(DevHandle handle) | 释放Host |
91| int32_t SdioEnableFunc(DevHandle handle) | 使能SDIO功能设备 |
92| int32_t SdioDisableFunc(DevHandle handle) | 去使能SDIO功能设备 |
93| int32_t SdioClaimIrq(DevHandle handle, SdioIrqHandler \*irqHandler) | 申请中断 |
94| int32_t SdioReleaseIrq(DevHandle handle) | 释放中断 |
95
96### 使用流程
97
98使用SDIO的一般流程如图3所示。
99
100**图 3** SDIO使用流程图
101
102![SDIO使用流程图](figures/SDIO使用流程图.png)
103
104#### 打开SDIO控制器
105
106在使用SDIO进行通信前,首先要调用SdioOpen获取SDIO控制器的设备句柄,该函数会返回指定总线号的SDIO控制器的设备句柄。
107
108```c
109DevHandle SdioOpen(int16_t mmcBusNum, struct SdioFunctionConfig *config);
110```
111
112**表 2** SdioOpen函数的参数和返回值描述
113
114| 参数 | 参数描述 |
115| -------- | -------- |
116| mmcBusNum | int16_t类型,总线号 |
117| config | 结构体指针,SDIO功能配置信息 |
118| **返回值** | **返回值描述** |
119| NULL | 获取SDIO控制器的设备句柄失败 |
120| 设备句柄 | SDIO控制器的设备句柄 |
121
122打开SDIO控制器的示例如下:
123
124```c
125DevHandle handle = NULL;
126struct SdioFunctionConfig config;
127config.funcNr = 1;
128config.vendorId = 0x123;
129config.deviceId = 0x456;
130// 打开总线号为1的SDIO控制器
131handle = SdioOpen(1, &config);
132if (handle == NULL) {
133    HDF_LOGE("SdioOpen: open sdio fail!\n");
134	return NULL;
135}
136```
137
138#### 独占HOST
139
140获取到SDIO控制器的设备句柄之后,需要先独占HOST才能进行SDIO后续的一系列操作,独占HOST函数如下所示:
141
142```c
143void SdioClaimHost(DevHandle handle);
144```
145
146**表 3** SdioClaimHost函数的参数描述
147
148| 参数 | 参数描述 |
149| -------- | -------- |
150| handle | DevHandle类型,SDIO控制器的设备句柄 |
151
152独占HOST示例如下:
153
154```c
155SdioClaimHost(handle); // 独占HOST
156```
157
158#### 使能SDIO设备
159
160在访问寄存器之前,需要先使能SDIO设备,使能SDIO设备的函数如下所示:
161
162```c
163int32_t SdioEnableFunc(DevHandle handle);
164```
165
166**表 4** SdioEnableFunc函数的参数和返回值描述
167
168| 参数 | 参数描述 |
169| -------- | -------- |
170| handle | DevHandle类型,SDIO控制器的设备句柄 |
171| **返回值** | **返回值描述** |
172| HDF_SUCCESS | SDIO使能成功 |
173| 负数 | SDIO使能失败 |
174
175使能SDIO设备的示例如下:
176
177```c
178int32_t ret;
179// 使能SDIO设备
180ret = SdioEnableFunc(handle);
181if (ret != HDF_SUCCESS) {
182    HDF_LOGE("SdioEnableFunc: sdio enable func fail, ret:%d\n", ret);
183	return ret;
184}
185```
186
187#### 注册SDIO中断
188
189在通信之前,还需要注册SDIO中断,注册SDIO中断函数如下所示:
190
191```c
192int32_t SdioClaimIrq(DevHandle handle, SdioIrqHandler *handler);
193```
194
195**表 5** SdioClaimIrq函数的参数和返回值描述
196
197| 参数 | 参数描述 |
198| -------- | -------- |
199| handle | DevHandle类型,SDIO控制器的设备句柄 |
200| handler | 函数指针,中断服务函数 |
201| **返回值** | **返回值描述** |
202| HDF_SUCCESS | 注册SDIO中断成功 |
203| 负数 | 注册SDIO中断失败 |
204
205  注册SDIO中的示例如下:
206
207```c
208// 中断服务函数需要根据各自平台的情况去实现
209static void SdioIrqFunc(void *data)
210{
211    if (data == NULL) {
212        HDF_LOGE("SdioIrqFunc: data is NULL.\n");
213        return;
214    }
215    // 需要开发者自行添加具体实现
216}
217
218int32_t ret;
219// 注册SDIO中断
220ret = SdioClaimIrq(handle, SdioIrqFunc);
221if (ret != HDF_SUCCESS) {
222    HDF_LOGE("SdioClaimIrq: sdio claim irq fail, ret:%d\n", ret);
223    return ret;
224}
225```
226
227#### 进行SDIO通信
228
229- 向SDIO设备增量写入指定长度的数据
230
231    对应的接口函数如下所示:
232
233    ```c
234    int32_t SdioWriteBytes(DevHandle handle, uint8_t *data, uint32_t addr, uint32_t size);
235    ```
236
237    **表 6** SdioWriteBytes函数的参数和返回值描述
238
239    | 参数 | 参数描述 |
240    | -------- | -------- |
241    | handle | DevHandle类型,SDIO控制器的设备句柄 |
242    | data | uint8_t类型指针,待写入数据 |
243    | addr | uint32_t类型,待写入数据的起始地址 |
244    | size | uint32_t类型,待写入数据的长度 |
245    | **返回值** | **返回值描述** |
246    | HDF_SUCCESS | SDIO写数据成功 |
247    | 负数 | SDIO写数据失败 |
248
249    向SDIO设备增量写入指定长度的数据的示例如下:
250
251    ```c
252    int32_t ret;
253    uint8_t wbuff[] = {1,2,3,4,5};
254    uint32_t addr = 0x100 + 0x09;
255    // 向SDIO设备起始地址0x109,增量写入5个字节的数据
256    ret = SdioWriteBytes(handle, wbuff, addr, sizeof(wbuff) / sizeof(wbuff[0]));
257    if (ret != HDF_SUCCESS) {
258        HDF_LOGE("SdioWriteBytes: sdio write bytes fail, ret:%d\n", ret);
259        return ret;
260    }
261    ```
262
263- 从SDIO设备增量读取指定长度的数据
264
265    对应的接口函数如下所示:
266
267    ```c
268    int32_t SdioReadBytes(DevHandle handle, uint8_t *data, uint32_t addr, uint32_t size);
269    ```
270
271    **表 7** SdioReadBytes函数的参数和返回值描述
272
273    | 参数 | 参数描述 |
274    | -------- | -------- |
275    | handle | DevHandle类型,SDIO控制器的设备句柄 |
276    | data | uint8_t类型指针,接收读取数据 |
277    | addr | uint32_t类型,待读取数据的起始地址 |
278    | size | uint32_t类型,待读取数据的长度 |
279    | **返回值** | **返回值描述** |
280    | HDF_SUCCESS | SDIO读数据成功 |
281    | 负数 | SDIO读数据失败 |
282
283    从SDIO设备增量读取指定长度的数据的示例如下:
284
285    ```c
286    int32_t ret;
287    uint8_t rbuff[5] = {0};
288    uint32_t addr = 0x100 + 0x09;
289    // 从SDIO设备起始地址0x109,增量读取5个字节的数据
290    ret = SdioReadBytes(handle, rbuff, addr, 5);
291    if (ret != HDF_SUCCESS) {
292        HDF_LOGE("SdioReadBytes: sdio read bytes fail, ret:%d\n", ret);
293        return ret;
294    }
295    ```
296
297- 向SDIO设备的固定地址写入指定长度的数据
298
299    对应的接口函数如下所示:
300
301    ```c
302    int32_t SdioWriteBytesToFixedAddr(DevHandle handle, uint8_t *data, uint32_t addr, uint32_t size, uint32_t scatterLen);
303    ```
304
305    **表 8** SdioWriteBytesToFixedAddr函数的参数和返回值描述
306
307    | 参数 | 参数描述 |
308    | -------- | -------- |
309    | handle | DevHandle类型,SDIO控制器的设备句柄 |
310    | data | uint8_t类型指针,待写入数据 |
311    | addr | uint32_t类型,待写入数据的固定地址 |
312    | size | uint32_t类型,待写入数据的长度 |
313    | scatterLen | uint32_t类型,集散表的长度。如果该字段不为0,则data为集散表类型。 |
314    | **返回值** | **返回值描述** |
315    | HDF_SUCCESS | SDIO写数据成功 |
316    | 负数 | SDIO写数据失败 |
317
318    向SDIO设备的固定地址写入指定长度的数据的示例如下:
319
320    ```c
321    int32_t ret;
322    uint8_t wbuff[] = {1, 2, 3, 4, 5};
323    uint32_t addr = 0x100 + 0x09;
324    // 向SDIO设备固定地址0x109写入5个字节的数据
325    ret = SdioWriteBytesToFixedAddr(handle, wbuff, addr, sizeof(wbuff) / sizeof(wbuff[0]), 0);
326    if (ret != HDF_SUCCESS) {
327        HDF_LOGE("SdioWriteBytesToFixedAddr: sdio write bytes to fixed addr fail, ret:%d\n", ret);
328        return ret;
329    }
330    ```
331
332- 从SDIO设备的固定地址读取指定长度的数据
333
334    对应的接口函数如下所示:
335
336    ```c
337    int32_t SdioReadBytesFromFixedAddr(DevHandle handle, uint8_t *data, uint32_t addr, uint32_t size, uint32_t scatterLen);
338    ```
339
340    **表 9** SdioReadBytesFromFixedAddr函数的参数和返回值描述
341
342    | 参数 | 参数描述 |
343    | -------- | -------- |
344    | handle | DevHandle类型,SDIO控制器的设备句柄 |
345    | data | uint8_t类型指针,接收读取数据 |
346    | addr | uint32_t类型,待读取数据的起始地址 |
347    | size | uint32_t类型,待读取数据的长度 |
348    | scatterLen | uint32_t类型,集散表的长度。如果该字段不为0,则data为集散表类型。 |
349    | **返回值** | **返回值描述** |
350    | HDF_SUCCESS | SDIO读数据成功 |
351    | 负数 | SDIO读数据失败 |
352
353    从SDIO设备的固定地址读取指定长度的数据的示例如下:
354
355    ```c
356    int32_t ret;
357    uint8_t rbuff[5] = {0};
358    uint32_t addr = 0x100 + 0x09;
359    // 从SDIO设备固定地址0x109中读取5个字节的数据
360    ret = SdioReadBytesFromFixedAddr(handle, rbuff, addr, 5, 0);
361    if (ret != HDF_SUCCESS) {
362        HDF_LOGE("SdioReadBytesFromFixedAddr: sdio read bytes from fixed addr fail, ret:%d\n", ret);
363        return ret;
364    }
365    ```
366
367- 向SDIO function 0的指定地址空间写入指定长度的数据
368
369    当前只支持写入一个字节的数据,对应的接口函数如下所示:
370
371    ```c
372    int32_t SdioWriteBytesToFunc0(DevHandle handle, uint8_t *data, uint32_t addr, uint32_t size);
373    ```
374
375    **表 10** SdioWriteBytesToFunc0函数的参数和返回值描述
376
377    | 参数 | 参数描述 |
378    | -------- | -------- |
379    | handle | DevHandle类型,SDIO控制器的设备句柄 |
380    | data | uint8_t类型指针,待写入数据 |
381    | addr | uint32_t类型,待写入数据的起始地址 |
382    | size | uint32_t类型,待写入数据的长度 |
383    | **返回值** | **返回值描述** |
384    | HDF_SUCCESS | SDIO写数据成功 |
385    | 负数 | SDIO写数据失败 |
386
387    向SDIO function 0的指定地址空间写入指定长度的数据的示例如下:
388
389    ```c
390    int32_t ret;
391    uint8_t wbuff = 1;
392    // 向SDIO function 0地址0x2中写入1字节的数据
393    ret = SdioWriteBytesToFunc0(handle, &wbuff, 0x2, 1);
394    if (ret != HDF_SUCCESS) {
395        HDF_LOGE("SdioWriteBytesToFunc0: sdio write bytes to func0 fail, ret:%d\n", ret);
396        return ret;
397    }
398    ```
399
400- 从SDIO function 0的指定地址空间读取指定长度的数据
401
402    当前只支持读取一个字节的数据,对应的接口函数如下所示:
403
404    ```c
405    int32_t SdioReadBytesFromFunc0(DevHandle handle, uint8_t *data, uint32_t addr, uint32_t size);
406    ```
407
408    **表 11** SdioReadBytesFromFunc0函数的参数和返回值描述
409
410    | 参数 | 参数描述 |
411    | -------- | -------- |
412    | handle | DevHandle类型,SDIO控制器的设备句柄 |
413    | data | uint8_t类型指针,接收读取数据 |
414    | addr | uint32_t类型,待读取数据的起始地址 |
415    | size | uint32_t类型,待读取数据的长度 |
416    | **返回值** | **返回值描述** |
417    | HDF_SUCCESS | SDIO读数据成功 |
418    | 负数 | SDIO读数据失败 |
419
420    从SDIO function 0的指定地址空间读取指定长度的数据的示例如下:
421
422    ```c
423    int32_t ret;
424    uint8_t rbuff;
425    /* 从SDIO function 0设备地址0x2中读取1字节的数据 */
426    ret = SdioReadBytesFromFunc0(handle, &rbuff, 0x2, 1);
427    if (ret != 0) {
428        HDF_LOGE("SdioReadBytesFromFunc0: sdio read bytes from func0 fail, ret:%d\n", ret);
429        return ret;
430    }
431    ```
432
433#### 释放SDIO中断
434
435通信完成之后,需要释放SDIO中断,函数如下所示:
436
437int32_t SdioReleaseIrq(DevHandle handle);
438
439**表 12** SdioReleaseIrq函数的参数和返回值描述
440
441| 参数 | 参数描述 |
442| -------- | -------- |
443| handle | DevHandle类型,SDIO控制器的设备句柄 |
444| **返回值** | **返回值描述** |
445| HDF_SUCCESS | 释放SDIO中断成功 |
446| 负数 | 释放SDIO中断失败 |
447
448释放SDIO中断的示例如下:
449
450```c
451int32_t ret;
452// 释放SDIO中断
453ret = SdioReleaseIrq(handle);
454if (ret != HDF_SUCCESS) {
455    HDF_LOGE("SdioReleaseIrq: sdio release irq fail, ret:%d\n", ret);
456    return ret;
457}
458```
459
460#### 去使能SDIO设备
461
462通信完成之后,还需要去使能SDIO设备,函数如下所示:
463
464int32_t SdioDisableFunc(DevHandle handle);
465
466**表 13** SdioDisableFunc函数的参数和返回值描述
467
468| 参数 | 参数描述 |
469| -------- | -------- |
470| handle | DevHandle类型,SDIO控制器的设备句柄 |
471| **返回值** | **返回值描述** |
472| HDF_SUCCESS | 去使能SDIO设备成功 |
473| 负数 | 去使能SDIO设备失败 |
474
475去使能SDIO设备的示例如下:
476
477```c
478int32_t ret;
479// 去使能SDIO设备
480ret = SdioDisableFunc(handle);
481if (ret != HDF_SUCCESS) {
482    HDF_LOGE("SdioDisableFunc: sdio disable func fail, ret:%d\n", ret);
483    return ret;
484}
485```
486
487#### 释放HOST
488
489通信完成之后,还需要释放去HOST,函数如下所示:
490
491```c
492void SdioReleaseHost(DevHandle handle);
493```
494
495**表 14** SdioReleaseHost函数的参数描述
496
497| 参数 | 参数描述 |
498| -------- | -------- |
499| handle | DevHandle类型,SDIO控制器的设备句柄 |
500
501释放HOST的示例如下:
502
503```c
504SdioReleaseHost(handle); // 释放HOST
505```
506
507#### 关闭SDIO控制器
508
509SDIO通信完成之后,最后需要关闭SDIO控制器,函数如下所示:
510
511```c
512void SdioClose(DevHandle handle);
513```
514
515该函数会释放掉申请的资源。
516
517**表 15** SdioClose函数的参数描述
518
519| 参数 | 参数描述 |
520| -------- | -------- |
521| handle | DevHandle类型,SDIO控制器的设备句柄 |
522
523关闭SDIO控制器的示例如下:
524
525```c
526SdioClose(handle); // 关闭SDIO控制器
527```
528
529### 使用实例
530
531本例拟对Hi3516DV300开发板上SDIO设备进行操作。
532
533SDIO设备完整的使用示例如下所示,首先打开总线号为1的SDIO控制器,然后独占HOST、使能设备、注册中断,接着进行SDIO通信(读写等),通信完成之后,释放中断、去使能设备、释放HOST,最后关闭SDIO控制器。
534
535```c
536#include "hdf_log.h"
537#include "sdio_if.h"
538
539#define TEST_FUNC_NUM 1              /* 本测试用例中,使用编号为1的I/O function */
540#define TEST_FBR_BASE_ADDR 0x100     /* 编号为1的I/O function的FBR基地址 */
541#define TEST_ADDR_OFFSET 9           /* 本测试用例中,需要读写的寄存器的地址偏移 */
542#define TEST_DATA_LEN 3              /* 本测试用例中,读写数据的长度 */
543#define TEST_BLOCKSIZE 2             /* 本测试用例中,数据块的大小,单位字节 */
544
545/* 中断服务函数,需要根据各自平台的情况去实现 */
546static void SdioIrqFunc(void *data)
547{
548    if (data == NULL) {
549        HDF_LOGE("SdioIrqFunc: data is NULL.\n");
550        return;
551    }
552    /* 需要开发者自行添加具体的实现 */
553}
554
555void SdioTestSample(void)
556{
557    int32_t ret;
558    DevHandle handle = NULL;
559    uint8_t data[TEST_DATA_LEN] = {0};
560    struct SdioFunctionConfig config = {1, 0x123, 0x456};
561    uint8_t val;
562    uint32_t addr;
563
564    /* 打开总线号为1的SDIO设备 */
565    handle = SdioOpen(1, &config);
566    if (handle == NULL) {
567        HDF_LOGE("SdioOpen: failed!\n");
568        return;
569    }
570    /* 独占HOST */
571    SdioClaimHost(handle);
572    /* 使能SDIO设备 */
573    ret = SdioEnableFunc(handle);
574    if (ret != 0) {
575        HDF_LOGE("SdioEnableFunc: failed, ret %d\n", ret);
576        goto ENABLE_ERR;
577    }
578    /* 注册中断 */
579    ret = SdioClaimIrq(handle, SdioIrqFunc);
580    if (ret != 0) {
581        HDF_LOGE("SdioClaimIrq: failed, ret %d\n", ret);
582        goto CLAIM_IRQ_ERR;
583    }
584    /* 设置块大小为2字节 */
585    ret = SdioSetBlockSize(handle, TEST_BLOCKSIZE);
586    if (ret != 0) {
587        HDF_LOGE("SdioSetBlockSize: failed, ret %d\n", ret);
588        goto COMM_ERR;
589    }
590    /* 从SDIO设备增量地址读取3字节的数据 */
591    addr = TEST_FBR_BASE_ADDR * TEST_FUNC_NUM + TEST_ADDR_OFFSET;
592    ret = SdioReadBytes(handle, data, addr, TEST_DATA_LEN);
593    if (ret != 0) {
594        HDF_LOGE("SdioReadBytes: failed, ret %d\n", ret);
595        goto COMM_ERR;
596    }
597    /* 向SDIO设备增量地址写入3字节的数据 */
598    ret = SdioWriteBytes(handle, data, addr, TEST_DATA_LEN);
599    if (ret != 0) {
600        HDF_LOGE("SdioWriteBytes: failed, ret %d\n", ret);
601        goto COMM_ERR;
602    }
603    /* 从SDIO设备读取1字节的数据 */
604    ret = SdioReadBytes(handle, &val, addr, 1);
605    if (ret != 0) {
606        HDF_LOGE("SdioReadBytes: failed, ret %d\n", ret);
607        goto COMM_ERR;
608    }
609    /* 向SDIO设备写入1字节的数据 */
610    ret = SdioWriteBytes(handle, &val, addr, 1);
611    if (ret != 0) {
612        HDF_LOGE("SdioWriteBytes: failed, ret %d\n", ret);
613        goto COMM_ERR;
614    }
615    /* 从SDIO设备固定地址读取3字节的数据 */
616    ret = SdioReadBytesFromFixedAddr(handle, data, addr, TEST_DATA_LEN, 0);
617    if (ret != 0) {
618        HDF_LOGE("SdioReadBytesFromFixedAddr: failed, ret %d\n", ret);
619        goto COMM_ERR;
620    }
621    /* 向SDIO设备固定地址写入1字节的数据 */
622    ret = SdioWriteBytesToFixedAddr(handle, data, addr, 1, 0);
623    if (ret != 0) {
624        HDF_LOGE("SdioWriteBytesToFixedAddr: failed, ret %d\n", ret);
625        goto COMM_ERR;
626    }
627    /* 从SDIO function 0读取1字节的数据 */
628    addr = 0x02;
629    ret = SdioReadBytesFromFunc0(handle, &val, addr, 1);
630    if (ret != 0) {
631        HDF_LOGE("SdioReadBytesFromFunc0: failed, ret %d\n", ret);
632        goto COMM_ERR;
633    }
634    /* 向SDIO function 0写入1字节的数据 */
635    ret = SdioWriteBytesToFunc0(handle, &val, addr, 1);
636    if (ret != 0) {
637        HDF_LOGE("SdioWriteBytesToFunc0: failed, ret %d\n", ret);
638        goto COMM_ERR;
639    }
640COMM_ERR:
641    /* 释放中断 */
642    ret = SdioReleaseIrq(handle);
643    if (ret != 0) {
644        HDF_LOGE("SdioReleaseIrq: failed, ret %d\n", ret);
645    }
646CLAIM_IRQ_ERR:
647    /* 去使能SDIO设备 */
648    ret = SdioDisableFunc(handle);
649    if (ret != 0) {
650        HDF_LOGE("SdioDisableFunc: failed, ret %d\n", ret);
651    }
652ENABLE_ERR:
653    /* 释放HOST */
654    SdioReleaseHost(handle);
655    /* 关闭SDIO设备 */
656    SdioClose(handle);
657}
658```
659