1/* 2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15/* 16 * Simple virtio-mmio block driver emulating MMC device (spec 4.3). 17 */ 18 19#include "los_vm_iomap.h" 20#include "mmc_block.h" 21#include "dmac_core.h" 22#include "osal.h" 23#include "osal/osal_io.h" 24#include "virtmmio.h" 25 26/* 27 * Kernel take care lock & cache(bcache), we only take care I/O. 28 * When I/O is carrying, we must wait for completion. Since any 29 * time there is only one I/O request come here, we can use the 30 * most simple virt-queue -- only have 4 descriptors: one for 31 * "request header", one for "I/O buffer", one for "response", 32 * and one left unused. That is, the driver and the device are 33 * always in synchonous mode! 34 */ 35#define VIRTQ_REQUEST_QSZ 4 36 37#define VIRTIO_BLK_F_RO (1 << 5) 38#define VIRTIO_BLK_F_BLK_SIZE (1 << 6) 39#define VIRTMMIO_BLK_NAME "virtblock" 40#define VIRTBLK_DRIVER "/dev/mmcblk" 41#define VIRTBLK_DEF_BLK_SIZE 8192 42 43struct VirtblkConfig { 44 uint64_t capacity; 45 uint32_t segMax; 46 struct VirtblkGeometry { 47 uint16_t cylinders; 48 uint8_t heads; 49 uint8_t sectors; 50 } geometry; 51 uint32_t blkSize; 52 uint8_t otherFieldsOmitted[0]; 53}; 54 55/* request type: only support IN, OUT */ 56#define VIRTIO_BLK_T_IN 0 57#define VIRTIO_BLK_T_OUT 1 58#define VIRTIO_BLK_T_FLUSH 4 59#define VIRTIO_BLK_T_DISCARD 11 60#define VIRTIO_BLK_T_WRITE_ZEROES 13 61 62/* response status */ 63#define VIRTIO_BLK_S_OK 0 64#define VIRTIO_BLK_S_IOERR 1 65#define VIRTIO_BLK_S_UNSUPP 2 66 67struct VirtblkReq { 68 uint32_t type; 69 uint32_t reserved; 70 uint64_t startSector; 71}; 72 73struct Virtblk { 74 struct VirtmmioDev dev; 75 76 uint64_t capacity; /* in 512-byte-sectors */ 77 uint32_t blkSize; /* block(cluster) size */ 78 struct VirtblkReq req; /* static memory for request */ 79 uint8_t resp; /* and response */ 80 DmacEvent event; /* for waiting I/O completion */ 81}; 82 83#define FAT32_MAX_CLUSTER_SECS 128 84 85static bool Feature0(uint32_t features, uint32_t *supported, void *dev) 86{ 87 struct Virtblk *blk = dev; 88 struct VirtblkConfig *conf = (void *)(blk->dev.base + VIRTMMIO_REG_CONFIG); 89 uint32_t bs; 90 91 if (features & VIRTIO_BLK_F_RO) { 92 HDF_LOGE("[%s]not support readonly device", __func__); 93 return false; 94 } 95 96 blk->blkSize = VIRTBLK_DEF_BLK_SIZE; 97 if (features & VIRTIO_BLK_F_BLK_SIZE) { 98 bs = conf->blkSize; 99 if ((bs >= MMC_SEC_SIZE) && (bs <= FAT32_MAX_CLUSTER_SECS * MMC_SEC_SIZE) && 100 ((bs & (bs - 1)) == 0)) { 101 blk->blkSize = bs; 102 *supported |= VIRTIO_BLK_F_BLK_SIZE; 103 } 104 } 105 106 blk->capacity = conf->capacity; 107 return true; 108} 109 110static bool Feature1(uint32_t features, uint32_t *supported, void *dev) 111{ 112 (void)dev; 113 if (features & VIRTIO_F_VERSION_1) { 114 *supported |= VIRTIO_F_VERSION_1; 115 } else { 116 HDF_LOGE("[%s]virtio-mmio block has no VERSION_1 feature", __func__); 117 return false; 118 } 119 120 return true; 121} 122 123static void PopulateRequestQ(const struct Virtblk *blk) 124{ 125 const struct Virtq *q = &blk->dev.vq[0]; 126 int i = 0; 127 128 q->desc[i].pAddr = VMM_TO_DMA_ADDR((VADDR_T)&blk->req); 129 q->desc[i].len = sizeof(struct VirtblkReq); 130 q->desc[i].flag = VIRTQ_DESC_F_NEXT; 131 q->desc[i].next = i + 1; 132 133 i++; 134 q->desc[i].next = i + 1; 135 136 i++; 137 q->desc[i].pAddr = VMM_TO_DMA_ADDR((VADDR_T)&blk->resp); 138 q->desc[i].len = sizeof(uint8_t); 139 q->desc[i].flag = VIRTQ_DESC_F_WRITE; 140} 141 142static uint8_t VirtblkIO(struct Virtblk *blk, uint32_t cmd, uint64_t startSector, 143 uint8_t *buf, uint32_t sectors) 144{ 145 uint32_t ret; 146 struct Virtq *q = &blk->dev.vq[0]; 147 148 /* fill in and notify virt queue */ 149 blk->req.type = cmd; 150 blk->req.startSector = startSector; 151 q->desc[1].pAddr = VMM_TO_DMA_ADDR((VADDR_T)buf); 152 q->desc[1].len = sectors * MMC_SEC_SIZE; 153 if (cmd == VIRTIO_BLK_T_IN) { 154 q->desc[1].flag = VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; 155 } else { /* must be VIRTIO_BLK_T_OUT */ 156 q->desc[1].flag = VIRTQ_DESC_F_NEXT; 157 } 158 q->avail->ring[q->avail->index % q->qsz] = 0; 159 DSB; 160 q->avail->index++; 161 OSAL_WRITEL(0, blk->dev.base + VIRTMMIO_REG_QUEUENOTIFY); 162 163 /* wait for completion */ 164 if ((ret = DmaEventWait(&blk->event, 1, HDF_WAIT_FOREVER)) != 1) { 165 HDF_LOGE("[%s]FATAL: wait event failed: %u", __func__, ret); 166 return VIRTIO_BLK_S_IOERR; 167 } 168 169 return blk->resp; 170} 171 172static uint32_t VirtblkIRQhandle(uint32_t swIrq, void *dev) 173{ 174 (void)swIrq; 175 struct Virtblk *blk = dev; 176 struct Virtq *q = &blk->dev.vq[0]; 177 178 if (!(OSAL_READL(blk->dev.base + VIRTMMIO_REG_INTERRUPTSTATUS) & VIRTMMIO_IRQ_NOTIFY_USED)) { 179 return 1; 180 } 181 182 (void)DmaEventSignal(&blk->event, 1); 183 q->last++; 184 185 OSAL_WRITEL(VIRTMMIO_IRQ_NOTIFY_USED, blk->dev.base + VIRTMMIO_REG_INTERRUPTACK); 186 return 0; 187} 188 189static void VirtblkDeInit(struct Virtblk *blk) 190{ 191 if (blk->dev.irq & ~_IRQ_MASK) { 192 OsalUnregisterIrq(blk->dev.irq & _IRQ_MASK, blk); 193 } 194 LOS_DmaMemFree(blk); 195} 196 197static struct Virtblk *VirtblkInitDev(void) 198{ 199 struct Virtblk *blk = NULL; 200 VADDR_T base; 201 uint16_t qsz; 202 int len, ret; 203 204 len = sizeof(struct Virtblk) + VirtqSize(VIRTQ_REQUEST_QSZ); 205 if ((blk = LOS_DmaMemAlloc(NULL, len, sizeof(void *), DMA_CACHE)) == NULL) { 206 HDF_LOGE("[%s]alloc virtio-block memory failed", __func__); 207 return NULL; 208 } 209 memset_s(blk, len, 0, len); 210 211 if (!VirtmmioDiscover(VIRTMMIO_DEVICE_ID_BLK, &blk->dev)) { 212 goto ERR_OUT; 213 } 214 215 VirtmmioInitBegin(&blk->dev); 216 if (!VirtmmioNegotiate(&blk->dev, Feature0, Feature1, blk)) { 217 goto ERR_OUT1; 218 } 219 base = ALIGN((VADDR_T)blk + sizeof(struct Virtblk), VIRTQ_ALIGN_DESC); 220 qsz = VIRTQ_REQUEST_QSZ; 221 if (VirtmmioConfigQueue(&blk->dev, base, &qsz, 1) == 0) { 222 goto ERR_OUT1; 223 } 224 225 if ((ret = DmaEventInit(&blk->event)) != HDF_SUCCESS) { 226 HDF_LOGE("[%s]initialize event control block failed: %#x", __func__, ret); 227 goto ERR_OUT1; 228 } 229 ret = OsalRegisterIrq(blk->dev.irq, OSAL_IRQF_TRIGGER_NONE, (OsalIRQHandle)VirtblkIRQhandle, 230 VIRTMMIO_BLK_NAME, blk); 231 if (ret != HDF_SUCCESS) { 232 HDF_LOGE("[%s]register IRQ failed: %d", __func__, ret); 233 goto ERR_OUT1; 234 } 235 blk->dev.irq |= ~_IRQ_MASK; 236 237 PopulateRequestQ(blk); 238 VritmmioInitEnd(&blk->dev); /* now virt queue can be used */ 239 return blk; 240 241ERR_OUT1: 242 VirtmmioInitFailed(&blk->dev); 243ERR_OUT: 244 VirtblkDeInit(blk); 245 return NULL; 246} 247 248 249/* 250 * MMC code 251 * 252 * HDF MmcCntlr act like an application adapter, they discover MMC device, 253 * send I/O request, receive response data. 254 * We act like a card adapter, receive requests, control MMC bus, drive 'card' 255 * execution, and report result. Yes, we are part of MmcCntlr -- MMC controller! 256 * Every hardware internal information are in our scope, such as state, CRC, RCA. 257 * So, we COULD(SHOULD) safely ignore them! 258 */ 259 260#define OCR_LE_2G (0x00FF8080 | MMC_CARD_BUSY_STATUS) 261#define OCR_GT_2G (0x40FF8080 | MMC_CARD_BUSY_STATUS) 262#define CAPACITY_2G (0x80000000 / 512) 263#define READ_BL_LEN 11 264#define C_SIZE_MULT 7 265#define U32_BITS 32 266 267/* 268 * Example bits: start=62 bits=4 value=0b1011 269 * 270 * bit127 271 * resp[0] 272 * resp[1] 1 0 273 * resp[2] 1 1 274 * resp[3] 275 * bit0 276 * 277 * NOTE: no error check, related 'resp' bits must be zeroed and set only once. 278 */ 279static void FillCidCsdBits(uint32_t *resp, int start, int bits, uint32_t value) 280{ 281 uint32_t index, lsb; 282 283 index = CID_LEN - 1 - start / U32_BITS; /* CSD has the same length */ 284 lsb = start % U32_BITS; 285 resp[index] |= value << lsb; 286 287 if (lsb + bits > U32_BITS) { 288 resp[index - 1] |= value >> (U32_BITS - lsb); 289 } 290} 291 292#define MMC_CID_CBX_SBIT 112 293#define MMC_CID_CBX_WIDTH 2 294#define MMC_CID_PNM_SBYTE 3 295#define MMC_CID_PNM_BYTES 6 296#define MMC_CID_PSN_SBYTE 10 297static void VirtMmcFillRespCid(struct MmcCmd *cmd, const struct Virtblk *blk) 298{ 299 uint8_t *b = (uint8_t *)cmd->resp; 300 301 /* embedded card, so can leverage kernel eMMC rootfs support */ 302 FillCidCsdBits(cmd->resp, MMC_CID_CBX_SBIT, MMC_CID_CBX_WIDTH, 1); 303 304 (void)memcpy_s(&b[MMC_CID_PNM_SBYTE], MMC_CID_PNM_BYTES, VIRTMMIO_BLK_NAME, MMC_CID_PNM_BYTES); 305 *(uint32_t *)&b[MMC_CID_PSN_SBYTE] = (uint32_t)blk; /* unique sn */ 306 /* leave other fields random */ 307} 308 309#define MMC_CSD_STRUCT_SBIT 126 310#define MMC_CSD_STRUCT_WIDTH 2 311 312#define MMC_CSD_VERS_SBIT 122 313#define MMC_CSD_VERS_WIDTH 4 314 315#define MMC_CSD_CCC_SBIT 84 316#define MMC_CSD_CCC_WIDTH 12 317 318#define MMC_CSD_RBLEN_SBIT 80 319#define MMC_CSD_RBLEN_WIDTH 4 320 321#define MMC_CSD_RBPART_SBIT 79 322 323#define MMC_CSD_WBMISALIGN_SBIT 78 324 325#define MMC_CSD_RBMISALIGN_SBIT 77 326 327#define MMC_CSD_DSRIMP_SBIT 76 328 329#define MMC_CSD_CSIZE_SBIT 62 330#define MMC_CSD_CSIZE_WIDTH 12 331#define MMC_CSD_CSIZE_VAL 0xFFF 332 333#define MMC_CSD_CSIZEMUL_SBIT 47 334#define MMC_CSD_CSIZEMUL_WIDTH 3 335 336#define MMC_CSD_EGRPSIZE_SBIT 42 337#define MMC_CSD_EGRPSIZE_WIDTH 5 338#define MMC_CSD_EGRPSIZE_VAL 31 339 340#define MMC_CSD_EGRPMULT_SBIT 37 341#define MMC_CSD_EGRPMULT_WIDTH 5 342#define MMC_CSD_EGRPMULT_VAL 15 343 344#define MMC_CSD_WBLEN_SBIT 22 345#define MMC_CSD_WBLEN_WIDTH 4 346 347#define MMC_CSD_WBPART_SBIT 21 348 349#define MMC_CSD_FFORMGRP_SBIT 15 350 351#define MMC_CSD_FFORMAT_SBIT 10 352#define MMC_CSD_FFORMAT_WIDTH 2 353static void VirtMmcFillRespCsd(struct MmcCmd *cmd, const struct Virtblk *blk) 354{ 355 FillCidCsdBits(cmd->resp, MMC_CSD_STRUCT_SBIT, MMC_CSD_STRUCT_WIDTH, MMC_CSD_STRUCTURE_VER_1_2); 356 FillCidCsdBits(cmd->resp, MMC_CSD_VERS_SBIT, MMC_CSD_VERS_WIDTH, MMC_CSD_SPEC_VER_4); 357 FillCidCsdBits(cmd->resp, MMC_CSD_CCC_SBIT, MMC_CSD_CCC_WIDTH, MMC_CSD_CCC_BASIC | 358 MMC_CSD_CCC_BLOCK_READ | MMC_CSD_CCC_BLOCK_WRITE); 359 FillCidCsdBits(cmd->resp, MMC_CSD_RBPART_SBIT, 1, 0); /* READ_BL_PARTIAL: no */ 360 FillCidCsdBits(cmd->resp, MMC_CSD_WBMISALIGN_SBIT, 1, 0); /* WRITE_BLK_MISALIGN: no */ 361 FillCidCsdBits(cmd->resp, MMC_CSD_RBMISALIGN_SBIT, 1, 0); /* READ_BLK_MISALIGN: no */ 362 FillCidCsdBits(cmd->resp, MMC_CSD_DSRIMP_SBIT, 1, 0); /* DSR_IMP: no */ 363 if (blk->capacity > CAPACITY_2G) { 364 uint32_t e = U32_BITS - __builtin_clz(blk->blkSize) - 1; 365 FillCidCsdBits(cmd->resp, MMC_CSD_RBLEN_SBIT, MMC_CSD_RBLEN_WIDTH, e); /* READ_BL_LEN */ 366 FillCidCsdBits(cmd->resp, MMC_CSD_WBLEN_SBIT, MMC_CSD_WBLEN_WIDTH, e); /* WRITE_BL_LEN */ 367 FillCidCsdBits(cmd->resp, MMC_CSD_CSIZE_SBIT, MMC_CSD_CSIZE_WIDTH, MMC_CSD_CSIZE_VAL); 368 } else { /* ensure c_size can up to 2G (512B can't) */ 369 FillCidCsdBits(cmd->resp, MMC_CSD_RBLEN_SBIT, MMC_CSD_RBLEN_WIDTH, READ_BL_LEN); 370 FillCidCsdBits(cmd->resp, MMC_CSD_WBLEN_SBIT, MMC_CSD_WBLEN_WIDTH, READ_BL_LEN); 371 uint32_t size = blk->capacity*MMC_SEC_SIZE / (1<<READ_BL_LEN) / (1<<(C_SIZE_MULT+2)) - 1; 372 FillCidCsdBits(cmd->resp, MMC_CSD_CSIZE_SBIT, MMC_CSD_CSIZE_WIDTH, size); /* C_SIZE */ 373 } 374 FillCidCsdBits(cmd->resp, MMC_CSD_CSIZEMUL_SBIT, MMC_CSD_CSIZEMUL_WIDTH, C_SIZE_MULT); 375 FillCidCsdBits(cmd->resp, MMC_CSD_EGRPSIZE_SBIT, MMC_CSD_EGRPSIZE_WIDTH, MMC_CSD_EGRPSIZE_VAL); 376 FillCidCsdBits(cmd->resp, MMC_CSD_EGRPMULT_SBIT, MMC_CSD_EGRPMULT_WIDTH, MMC_CSD_EGRPMULT_VAL); 377 FillCidCsdBits(cmd->resp, MMC_CSD_WBPART_SBIT, 1, 0); /* WRITE_BL_PARTIAL: no */ 378 FillCidCsdBits(cmd->resp, MMC_CSD_FFORMGRP_SBIT, 1, 0); /* FILE_FORMAT_GRP */ 379 FillCidCsdBits(cmd->resp, MMC_CSD_FFORMAT_SBIT, MMC_CSD_FFORMAT_WIDTH, 0); /* hard disk-like */ 380 /* leave other fields random */ 381} 382 383#define EMMC_EXT_CSD_CMD_SET_REV 189 384#define EMMC_EXT_CSD_CMD_SET 191 385#define EMMC_EXT_CSD_ACC_SIZE 225 386#define EMMC_EXT_CSD_S_CMD_SET 504 387static void VirtMmcFillDataExtCsd(const struct MmcCmd *cmd, const struct Virtblk *blk) 388{ 389 uint8_t *b = (uint8_t *)cmd->data->dataBuffer; 390 391 b[EMMC_EXT_CSD_S_CMD_SET] = 0; /* standard MMC */ 392 b[EMMC_EXT_CSD_ACC_SIZE] = blk->blkSize / MMC_SEC_SIZE; 393 b[EMMC_EXT_CSD_REL_WR_SEC_C] = blk->blkSize / MMC_SEC_SIZE; 394 *(uint32_t*)&b[EMMC_EXT_CSD_SEC_CNT] = blk->capacity; 395 b[EMMC_EXT_CSD_CARD_TYPE] = EMMC_EXT_CSD_CARD_TYPE_26 | EMMC_EXT_CSD_CARD_TYPE_52; 396 b[EMMC_EXT_CSD_STRUCTURE] = EMMC_EXT_CSD_STRUCTURE_VER_1_2; 397 b[EMMC_EXT_CSD_REV] = EMMC_EXT_CSD_REV_1_3; 398 b[EMMC_EXT_CSD_CMD_SET] = 0; /* standard MMC */ 399 b[EMMC_EXT_CSD_CMD_SET_REV] = 0; /* v4.0 */ 400 b[EMMC_EXT_CSD_BUS_WIDTH] = EMMC_EXT_CSD_BUS_WIDTH_1; 401 /* leave other fields random */ 402} 403 404#define MMC_RESP_STATE_BIT 9 405static inline void VirtMmcFillRespR1(struct MmcCmd *cmd) 406{ 407 cmd->resp[0] = READY_FOR_DATA | (STATE_READY << MMC_RESP_STATE_BIT); 408 cmd->resp[1] = cmd->cmdCode; 409} 410 411static int32_t VirtMmcIO(const struct MmcCntlr *cntlr, const struct MmcCmd *cmd) 412{ 413 struct Virtblk *blk = cntlr->priv; 414 uint64_t startSector = (uint64_t)cmd->argument; 415 uint32_t io, ret; 416 417 if (cntlr->curDev->state.bits.blockAddr == 0) { 418 startSector >>= MMC_SEC_SHIFT; 419 } 420 421 if (cmd->data->dataFlags == DATA_READ) { 422 io = VIRTIO_BLK_T_IN; 423 } else { 424 io = VIRTIO_BLK_T_OUT; 425 } 426 427 ret = VirtblkIO(blk, io, startSector, cmd->data->dataBuffer, cmd->data->blockNum); 428 if (ret == VIRTIO_BLK_S_OK) { 429 cmd->data->returnError = HDF_SUCCESS; 430 } else { 431 HDF_LOGE("[%s]QEMU backend I/O error", __func__); 432 cmd->data->returnError = HDF_ERR_IO; 433 } 434 435 return HDF_SUCCESS; 436} 437 438static int32_t VirtMmcDoRequest(struct MmcCntlr *cntlr, struct MmcCmd *cmd) 439{ 440 if ((cntlr == NULL) || (cntlr->priv == NULL) || (cmd == NULL)) { 441 return HDF_ERR_INVALID_OBJECT; 442 } 443 struct Virtblk *blk = cntlr->priv; 444 445 cmd->returnError = HDF_SUCCESS; 446 switch (cmd->cmdCode) { 447 case GO_IDLE_STATE: // CMD0 448 break; 449 case SEND_OP_COND: // CMD1 450 if (blk->capacity > CAPACITY_2G) { 451 cmd->resp[0] = OCR_GT_2G; 452 } else { 453 cmd->resp[0] = OCR_LE_2G; 454 } 455 break; 456 case ALL_SEND_CID: // CMD2, fall through 457 case SEND_CID: // CMD10 458 VirtMmcFillRespCid(cmd, blk); 459 break; 460 case SEND_EXT_CSD: // CMD8, fall through 461 VirtMmcFillDataExtCsd(cmd, blk); 462 cmd->data->returnError = HDF_SUCCESS; 463 case SET_RELATIVE_ADDR: // CMD3, fall through 464 case SWITCH: // CMD6, fall through 465 case SELECT_CARD: // CMD7, fall through 466 case SEND_STATUS: // CMD13 467 VirtMmcFillRespR1(cmd); 468 break; 469 case SEND_CSD: // CMD9 470 VirtMmcFillRespCsd(cmd, blk); 471 break; 472 case READ_SINGLE_BLOCK: // CMD17, fall through 473 case READ_MULTIPLE_BLOCK: // CMD18, fall through 474 case WRITE_BLOCK: // CMD24, fall through 475 case WRITE_MULTIPLE_BLOCK: // CMD25 476 return VirtMmcIO(cntlr, cmd); 477 default: 478 HDF_LOGE("[%s]unsupported command: %u", __func__, cmd->cmdCode); 479 cmd->returnError = HDF_ERR_NOT_SUPPORT; 480 } 481 return cmd->returnError; 482} 483 484static bool VirtMmcPlugged(struct MmcCntlr *cntlr) 485{ 486 (void)cntlr; 487 return true; 488} 489 490static bool VirtMmcBusy(struct MmcCntlr *cntlr) 491{ 492 (void)cntlr; 493 return false; 494} 495 496static struct MmcCntlrOps g_virtblkOps = { 497 .request = VirtMmcDoRequest, 498 .devPlugged = VirtMmcPlugged, 499 .devBusy = VirtMmcBusy, 500}; 501 502 503/* 504 * HDF entry 505 */ 506 507static void HdfVirtblkRelease(struct HdfDeviceObject *deviceObject) 508{ 509 struct MmcCntlr *cntlr = deviceObject->priv; 510 struct Virtblk *blk = cntlr->priv; 511 512 if (blk) { 513 VirtblkDeInit(blk); 514 } 515 if (cntlr->curDev != NULL) { 516 MmcDeviceRemove(cntlr->curDev); 517 OsalMemFree(cntlr->curDev); 518 cntlr->curDev = NULL; 519 } 520 MmcCntlrRemove(cntlr); 521 OsalMemFree(cntlr); 522} 523 524static int32_t HdfVirtblkBind(struct HdfDeviceObject *obj) 525{ 526 struct MmcCntlr *cntlr = NULL; 527 struct Virtblk *blk = NULL; 528 int32_t ret; 529 530 if (obj == NULL) { 531 HDF_LOGE("[%s]HdfDeviceObject is NULL", __func__); 532 return HDF_ERR_INVALID_OBJECT; 533 } 534 535 cntlr = OsalMemCalloc(sizeof(struct MmcCntlr)); 536 if (cntlr == NULL) { 537 HDF_LOGE("[%s]alloc MmcCntlr memory failed", __func__); 538 return HDF_ERR_MALLOC_FAIL; 539 } 540 541 if ((blk = VirtblkInitDev()) == NULL) { 542 OsalMemFree(cntlr); 543 return HDF_FAILURE; 544 } 545 546 obj->service = &cntlr->service; 547 obj->priv = cntlr; 548 cntlr->priv = blk; 549 cntlr->ops = &g_virtblkOps; 550 cntlr->hdfDevObj = obj; 551 if ((ret = MmcCntlrParse(cntlr, obj)) != HDF_SUCCESS) { 552 goto _ERR; 553 } 554 555 if ((ret = MmcCntlrAdd(cntlr, true)) != HDF_SUCCESS) { 556 goto _ERR; 557 } 558 (void)MmcCntlrAddDetectMsgToQueue(cntlr); 559 560 return HDF_SUCCESS; 561 562_ERR: /* Bind failure, so we must call release manually. */ 563 HdfVirtblkRelease(obj); 564 return ret; 565} 566 567static int32_t HdfVirtblkInit(struct HdfDeviceObject *device) 568{ 569 if (device == NULL) { 570 HDF_LOGE("[%s]device is null", __func__); 571 return HDF_ERR_INVALID_PARAM; 572 } 573 574 return HDF_SUCCESS; 575} 576 577struct HdfDriverEntry g_virtBlockEntry = { 578 .moduleVersion = 1, 579 .moduleName = "HDF_VIRTIO_BLOCK", 580 .Bind = HdfVirtblkBind, 581 .Init = HdfVirtblkInit, 582 .Release = HdfVirtblkRelease, 583}; 584 585HDF_INIT(g_virtBlockEntry); 586