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