1# SDIO 2 3 4## Overview 5 6A Secure Digital Input Output (SDIO) card is an extension of the SD specification to cover I/O functions. SD and SDIO cards are called multimedia cards (MMCs). In the Hardware Driver Foundation (HDF), the SDIO module uses the independent service mode for API adaptation. In this mode, each device independently publishes a service to process external access requests. When receiving an access request, the HDF DeviceManager extracts parameters from the request to call the internal APIs of the target device. In the independent service mode, the HDF DeviceManager provides service management capabilities. However, you need to configure a node for each device, which increases memory usage. 7 8 **Figure 1** Independent service mode 9 10 ![image](figures/independent-service-mode.png) 11 12 13## Available APIs 14 15**SdioDeviceOps**: 16 17 18``` 19// Function template 20struct SdioDeviceOps { 21 int32_t (*incrAddrReadBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size); 22 int32_t (*incrAddrWriteBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size); 23 int32_t (*fixedAddrReadBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size, uint32_t scatterLen); 24 int32_t (*fixedAddrWriteBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size, uint32_t scatterLen); 25 int32_t (*func0ReadBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size); 26 int32_t (*func0WriteBytes)(struct SdioDevice *dev, uint8_t *data, uint32_t addr, uint32_t size); 27 int32_t (*setBlockSize)(struct SdioDevice *dev, uint32_t blockSize); 28 int32_t (*getCommonInfo)(struct SdioDevice *dev, SdioCommonInfo *info, uint32_t infoType); 29 int32_t (*setCommonInfo)(struct SdioDevice *dev, SdioCommonInfo *info, uint32_t infoType); 30 int32_t (*flushData)(struct SdioDevice *dev); 31 int32_t (*enableFunc)(struct SdioDevice *dev); 32 int32_t (*disableFunc)(struct SdioDevice *dev); 33 int32_t (*claimIrq)(struct SdioDevice *dev, SdioIrqHandler *irqHandler); 34 int32_t (*releaseIrq)(struct SdioDevice *dev); 35 int32_t (*findFunc)(struct SdioDevice *dev, struct SdioFunctionConfig *configData); 36 int32_t (*claimHost)(struct SdioDevice *dev); 37 int32_t (*releaseHost)(struct SdioDevice *dev); 38}; 39``` 40 41 **Table 1** Description of the callback functions in SdioDeviceOps 42 43| Function| Input Parameter| Output Parameter| Return Value| Description| 44| -------- | -------- | -------- | -------- | -------- | 45| incrAddrReadBytes | **dev**: structure pointer to the SDIO device controller.<br>**addr**: SDIO address, which is of the uint32_t type.<br>**size**: size of the data to read, which is of the uint32_t type.| **data**: pointer to the output value, which is of the uint8_t type.| HDF_STATUS| Incrementally reads data of a given length from the specified SDIO address.| 46| incrAddrWriteBytes | **dev**: structure pointer to the SDIO device controller.<br>**data**: pointer to the input value, which is of the uint8_t type.<br>**addr**: SDIO address, which is of the uint32_t type.<br>**size**: size of the data to write, which is of the uint32_t type.| –| HDF_STATUS| Incrementally writes data of a given length to the specified SDIO address.| 47| fixedAddrReadBytes | **dev**: structure pointer to the SDIO device controller.<br>**addr**: SDIO address, which is of the uint32_t type.<br>**size**: size of the data to read, which is of the uint32_t type.<br>**scatterLen**: data length, which is of the uint32_t type.| **data**: pointer to the output value, which is of the uint8_t type.| HDF_STATUS| Reads data of a given length from a fixed SDIO address.| 48| fixedAddrWriteBytes | **dev**: structure pointer to the SDIO device controller.<br>**data**: pointer to the input value, which is of the uint8_t type.<br>**addr**: SDIO address, which is of the uint32_t type.<br>**size**: size of the data to write, which is of the uint32_t type.<br>**scatterLen**: data length, which is of the uint32_t type.| –| HDF_STATUS| Writes data of a given length to the fixed SDIO address.| 49| func0ReadBytes | **dev**: structure pointer to the SDIO device controller.<br>**addr**: SDIO address, which is of the uint32_t type.<br>**size**: size of the data to read, which is of the uint32_t type.| **data**: pointer to the output value, which is of the uint8_t type.| HDF_STATUS| Reads data of a given length from the address space of SDIO function 0.| 50| func0WriteBytes | **dev**: structure pointer to the SDIO device controller.<br>**data**: pointer to the input value, which is of the uint8_t type.<br>**addr**: SDIO address, which is of the uint32_t type.<br>**size**: size of the data to write, which is of the uint32_t type.| –| HDF_STATUS| Writes data of a given length to the address space of SDIO function 0.| 51| setBlockSize | **dev**: structure pointer to the SDIO device controller.<br>**blockSize**: block size, which is of the uint32_t type.| –| HDF_STATUS| Sets the block size.| 52| getCommonInfo | **dev**: structure pointer to the SDIO device controller. <br>**infoType**: info type, which is of the uint32_t type.| **info**: structure pointer to the output **SdioFuncInfo**.| HDF_STATUS| Obtains **CommonInfo**. For details, see the **NOTE** below this table.| 53| setCommonInfo | **dev**: structure pointer to the SDIO device controller.<br>**info**: union pointer to the input **SdioFuncInfo**.<br>**infoType**: info type, which is of the uint32_t type.| –| HDF_STATUS| Sets **CommonInfo**. For details, see the **NOTE** below this table.| 54| flushData | **dev**: structure pointer to the SDIO device controller.| –| HDF_STATUS| Called to flush data when the SDIO device needs to be re-initialized or an error occurs.| 55| enableFunc | **dev**: structure pointer to the SDIO device controller.| –| HDF_STATUS| Enables an SDIO device.| 56| disableFunc | **dev**: structure pointer to the SDIO device controller.| –| HDF_STATUS| Disables an SDIO device.| 57| claimIrq | **dev**: structure pointer to the SDIO device controller.<br>**irqHandler**: void function pointer to the interrupt request (IRQ) handler.| –| HDF_STATUS| Claims an SDIO IRQ.| 58| releaseIrq | **dev**: structure pointer to the SDIO device controller.| –| HDF_STATUS| Releases an SDIO IRQ.| 59| findFunc | **dev**: structure pointer to the SDIO device controller.<br>**configData**: structure pointer to the key SDIO function information.| –| HDF_STATUS| Obtains the matching funcNum.| 60| claimHost | **dev**: structure pointer to the SDIO device controller.| –| HDF_STATUS| Claims a host exclusively.| 61| releaseHost | **dev**: structure pointer to the SDIO device controller.| –| HDF_STATUS| Releases the exclusively claimed host.| 62 63 64> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br> 65> CommonInfo includes the following information:<br>- **maxBlockNum**: specifies the maximum number of blocks in a request. <br>- **maxBlockSize**: specifies the maximum number of bytes in a block. <br>- **maxRequestSize**: specifies the maximum number of bytes in a request. <br>- **enTimeout**: specifies the maximum timeout period, in milliseconds. <br>- **funcNum**: specifies the function number, which ranges from 1 to 7. <br>- **irqCap**: specifies the IRQ capabilities. <br>- **(void \*)data** 66 67 68## How to Develop 69 70The SDIO module adaptation involves the following steps: 71 721. Instantiate the driver entry. 73 - Instantiate the **HdfDriverEntry** structure. 74 - Call **HDF_INIT** to register the **HdfDriverEntry** instance with the HDF. 75 762. Configure attribute files. 77 - Add the **deviceNode** information to the **device_info.hcs** file. 78 - (Optional) Add the **sdio_config.hcs** file. 79 803. Instantiate the SDIO controller object. 81 - Initialize **SdioDevice**. 82 - Instantiate **SdioDeviceOps** in the **SdioDevice** object. 83 > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br> 84 > For details about the functions in **SdioDeviceOps**, see [Available APIs](#available-apis). 85 864. Debug the driver. 87 88 (Optional) For new drivers, verify the basic functions, such as the SDIO control status and response to interrupts. 89 90 91## Development Example 92 93The following uses **sdio_adapter.c** as an example to present the information required for implementing device functions. 94 951. Instantiate the driver entry. 96 97 The driver entry must be a global variable of the **HdfDriverEntry** type (defined in **hdf_device_desc.h**), and the value of **moduleName** must be the same as that in **device_info.hcs**. 98 99 In the HDF, the start address of each **HdfDriverEntry** object of all loaded drivers is collected to form a segment address space similar to an array for the upper layer to invoke. 100 101 Generally, the HDF calls the **Bind** function and then the **Init** function to load a driver. If **Init** fails to be called, the HDF calls **Release** to release driver resources and exit. 102 103 SDIO driver entry example: 104 105 ``` 106 struct HdfDriverEntry g_sdioDriverEntry = { 107 .moduleVersion = 1, 108 .Bind = Hi35xxLinuxSdioBind, // See the Bind function. 109 .Init = Hi35xxLinuxSdioInit, // See the Init function. 110 .Release = Hi35xxLinuxSdioRelease, // See the Release function. 111 .moduleName = "HDF_PLATFORM_SDIO",// (Mandatory) The value must be the same as that of moduleName in the .hcs file. 112 }; 113 // Call HDF_INIT to register the driver entry with the HDF. 114 HDF_INIT(g_sdioDriverEntry); 115 ``` 116 1172. Add the **deviceNode** information to the **device_info.hcs** file and configure the device attributes in the **sdio_config.hcs** file. 118 119 The **deviceNode** information is related to registration of the driver entry. The device attribute values are closely related to the default values or value ranges of the **SdioDevice** members at the core layer. 120 121 In this example, there is only one SDIO controller. If there are multiple SDIO controllers, you need to add the **deviceNode** information to the **device_info** file and add the corresponding device attributes to the **sdio_config** file for each controller. 122 123 - **device_info.hcs** configuration example: 124 125 126 ``` 127 root { 128 device_info { 129 match_attr = "hdf_manager"; 130 platform :: host { 131 hostName = "platform_host"; 132 priority = 50; 133 device_sdio :: device { 134 device0 :: deviceNode { 135 policy = 1; 136 priority = 70; 137 permission = 0644; 138 moduleName = "HDF_PLATFORM_SDIO"; // (Mandatory) Driver name, which must be the same as moduleName in the driver entry. 139 serviceName = "HDF_PLATFORM_MMC_2"; // (Mandatory) Unique name of the service published by the driver. 140 deviceMatchAttr = "hisilicon_hi35xx_sdio_0";// (Mandatory) Private data of the controller. The value must be the same as the controller information in sdio_config.hcs. 141 } 142 } 143 } 144 } 145 } 146 ``` 147 148 - **sdio_config.hcs** configuration example: 149 150 151 ``` 152 root { 153 platform { 154 sdio_config { 155 template sdio_controller { 156 match_attr = ""; 157 hostId = 2; // (Mandatory) The value must be 2. For details, see mmc_config.hcs. 158 devType = 2; // (Mandatory) The value must be 2. For details, see mmc_config.hcs. 159 } 160 controller_0x2dd1 :: sdio_controller { 161 match_attr = "hisilicon_hi35xx_sdio_0";// (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs. 162 } 163 } 164 } 165 ``` 166 1673. Initialize the **SdioDevice** object at the core layer, including defining a custom structure (to pass parameters and data) and implementing the **HdfDriverEntry** member functions (**Bind**, **Init**, and **Release**) to instantiate **SdioDeviceOps** in **SdioDevice** (so that the underlying driver functions can be called). 168 169 - Defining a custom structure 170 171 To the driver, the custom structure holds parameters and data. The **DeviceResourceIface** method provided by the HDF reads the values in the **sdio_config.hcs** file to initialize the members in the custom structure and passes important parameters to the object at the core layer. 172 173 174 ``` 175 typedef struct { 176 uint32_t maxBlockNum; // Maximum number of blocks in a request. 177 uint32_t maxBlockSize; // Maximum number of bytes in a block. The value range is 1 to 2048. 178 uint32_t maxRequestSize; // Maximum number of bytes in a request. The value range is 1 to 2048. 179 uint32_t enTimeout; // Maximum timeout period in milliseconds. The value cannot exceed one second. 180 uint32_t funcNum; // Function number, which ranges from 1 to 7. 181 uint32_t irqCap; // IRQ capabilities. 182 void *data; // Private data. 183 } SdioFuncInfo; 184 185 // SdioDevice is the core layer controller structure. The Bind function assigns values to the members of SdioDevice. 186 struct SdioDevice { 187 struct SdDevice sd; 188 struct SdioDeviceOps *sdioOps; 189 struct SdioRegister sdioReg; 190 uint32_t functions; 191 struct SdioFunction *sdioFunc[SDIO_MAX_FUNCTION_NUMBER]; 192 struct SdioFunction *curFunction; 193 struct OsalThread thread; /* irq thread */ 194 struct OsalSem sem; 195 bool irqPending; 196 bool threadRunning; 197 }; 198 ``` 199 200 - Instantiating **SdioDeviceOps** in **SdioDevice** (other members are initialized by **Init**) 201 202 203 ``` 204 static struct SdioDeviceOps g_sdioDeviceOps = { 205 .incrAddrReadBytes = Hi35xxLinuxSdioIncrAddrReadBytes, 206 .incrAddrWriteBytes = Hi35xxLinuxSdioIncrAddrWriteBytes, 207 .fixedAddrReadBytes = Hi35xxLinuxSdioFixedAddrReadBytes, 208 .fixedAddrWriteBytes = Hi35xxLinuxSdioFixedAddrWriteBytes, 209 .func0ReadBytes = Hi35xxLinuxSdioFunc0ReadBytes, 210 .func0WriteBytes = Hi35xxLinuxSdioFunc0WriteBytes, 211 .setBlockSize = Hi35xxLinuxSdioSetBlockSize, 212 .getCommonInfo = Hi35xxLinuxSdioGetCommonInfo, 213 .setCommonInfo = Hi35xxLinuxSdioSetCommonInfo, 214 .flushData = Hi35xxLinuxSdioFlushData, 215 .enableFunc = Hi35xxLinuxSdioEnableFunc, 216 .disableFunc = Hi35xxLinuxSdioDisableFunc, 217 .claimIrq = Hi35xxLinuxSdioClaimIrq, 218 .releaseIrq = Hi35xxLinuxSdioReleaseIrq, 219 .findFunc = Hi35xxLinuxSdioFindFunc, 220 .claimHost = Hi35xxLinuxSdioClaimHost, 221 .releaseHost = Hi35xxLinuxSdioReleaseHost, 222 }; 223 ``` 224 225- **Bind** function 226 227 **Input parameter**: 228 229 **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs information. 230 231 **Return value**: 232 233 **HDF_STATUS** 234 235 The table below describes some status. For more information, see **HDF_STATUS** in the **/drivers/framework/include/utils/hdf_base.h** file. 236 237 **Table 2** Description of HDF_STATUS 238 239 | Status | Description | 240 | ---------------------- | -------------------------- | 241 | HDF_ERR_INVALID_OBJECT | Invalid controller object. | 242 | HDF_ERR_MALLOC_FAIL | Failed to allocate memory. | 243 | HDF_ERR_INVALID_PARAM | Invalid parameter. | 244 | HDF_ERR_IO | I/O error. | 245 | HDF_SUCCESS | Initialization successful. | 246 | HDF_FAILURE | Initialization failed. | 247 248 **Function description**: 249 250 Initializes the custom structure object and **SdioCntlr**, calls the **SdioCntlrAdd** function at the core layer, and performs other initialization operations customized by the vendor. 251 252 ``` 253 static int32_t Hi35xxLinuxSdioBind(struct HdfDeviceObject *obj) 254 { 255 struct MmcCntlr *cntlr = NULL; 256 int32_t ret; 257 ... 258 cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr));// Allocate memory. 259 ... 260 cntlr->ops = &g_sdioCntlrOps; // (Mandatory) struct MmcCntlrOps g_sdioCntlrOps={ 261 // .rescanSdioDev = Hi35xxLinuxSdioRescan,}; 262 cntlr->hdfDevObj = obj; // (Mandatory) Prerequisites for conversion between HdfDeviceObject and MmcCntlr. 263 obj->service = &cntlr->service; // (Mandatory) Prerequisites for conversion between HdfDeviceObject and MmcCntlr. 264 ret = Hi35xxLinuxSdioCntlrParse(cntlr, obj); // (Mandatory) Initialize index and devType of cntlr. If the initialization fails, execute goto _ERR. 265 ... 266 ret = MmcCntlrAdd(cntlr); // (Mandatory) Call the function in mmc_core.c. If the operation fails, execute goto _ERR. 267 ... 268 ret = MmcCntlrAllocDev(cntlr, (enum MmcDevType)cntlr->devType); // (Mandatory) Call the function in mmc_core.c. If the operation fails, execute goto _ERR. 269 ... 270 271 MmcDeviceAddOps(cntlr->curDev, &g_sdioDeviceOps); // (Mandatory) Call the function in mmc_core.c to hook the related functions. 272 HDF_LOGD("Hi35xxLinuxSdioBind: Success!"); 273 return HDF_SUCCESS; 274 275 _ERR: 276 Hi35xxLinuxSdioDeleteCntlr(cntlr); 277 HDF_LOGE("Hi35xxLinuxSdioBind: Fail!"); 278 return HDF_FAILURE; 279 } 280 ``` 281 282- **Init** function 283 284 **Input parameter**: 285 286 **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs information. 287 288 **Return value**: 289 290 **HDF_STATUS** 291 292 **Function description**: 293 294 You can add operations as required. 295 296 ``` 297 static int32_t Hi35xxLinuxSdioInit(struct HdfDeviceObject *obj) 298 { 299 (void)obj;// No operation. You can add operations as required. 300 HDF_LOGD("Hi35xxLinuxSdioInit: Success!"); 301 return HDF_SUCCESS; 302 } 303 ``` 304 305- **Release** function 306 307 **Input parameter**: 308 309 **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs information. 310 311 **Return value**: 312 313 No value is returned. 314 315 **Function description**: 316 317 Releases the memory and deletes the controller. This function assigns values to the **Release** function in the driver entry structure. If the HDF fails to call the **Init** function to initialize the driver, the **Release** function can be called to release driver resources. 318 319 > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br> 320 > All forced conversion operations for obtaining the corresponding object can be successful only when the **Bind** function has the corresponding value assignment operations. 321 322 ``` 323 static void Hi35xxLinuxSdioRelease(struct HdfDeviceObject *obj) 324 { 325 if (obj == NULL) { 326 return; 327 } 328 Hi35xxLinuxSdioDeleteCntlr((struct MmcCntlr *)obj->service);// (Mandatory) Custom function for releasing memory. A forced conversion from HdfDeviceObject to MmcCntlr is involved. 329 } 330 ``` 331