[BACK]Return to sdmmc_mem.c CVS log [TXT][DIR] Up to [local] / sys / dev / sdmmc

Annotation of sys/dev/sdmmc/sdmmc_mem.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: sdmmc_mem.c,v 1.7 2007/03/18 22:07:16 uwe Exp $       */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: /* Routines for SD/MMC memory cards. */
        !            20:
        !            21: #include <sys/param.h>
        !            22: #include <sys/kernel.h>
        !            23: #include <sys/malloc.h>
        !            24: #include <sys/systm.h>
        !            25:
        !            26: #include <dev/sdmmc/sdmmcchip.h>
        !            27: #include <dev/sdmmc/sdmmcreg.h>
        !            28: #include <dev/sdmmc/sdmmcvar.h>
        !            29:
        !            30: int    sdmmc_decode_csd(struct sdmmc_softc *, sdmmc_response,
        !            31:            struct sdmmc_function *);
        !            32: int    sdmmc_decode_cid(struct sdmmc_softc *, sdmmc_response,
        !            33:            struct sdmmc_function *);
        !            34: void   sdmmc_print_cid(struct sdmmc_cid *);
        !            35:
        !            36: int    sdmmc_mem_send_op_cond(struct sdmmc_softc *, u_int32_t, u_int32_t *);
        !            37: int    sdmmc_mem_set_blocklen(struct sdmmc_softc *, struct sdmmc_function *);
        !            38:
        !            39: #ifdef SDMMC_DEBUG
        !            40: #define DPRINTF(s)     printf s
        !            41: #else
        !            42: #define DPRINTF(s)     /**/
        !            43: #endif
        !            44:
        !            45: /*
        !            46:  * Initialize SD/MMC memory cards and memory in SDIO "combo" cards.
        !            47:  */
        !            48: int
        !            49: sdmmc_mem_enable(struct sdmmc_softc *sc)
        !            50: {
        !            51:        u_int32_t host_ocr;
        !            52:        u_int32_t card_ocr;
        !            53:
        !            54:        /* Set host mode to SD "combo" card or SD memory-only. */
        !            55:        SET(sc->sc_flags, SMF_SD_MODE|SMF_MEM_MODE);
        !            56:
        !            57:        /* Reset memory (*must* do that before CMD55 or CMD1). */
        !            58:        sdmmc_go_idle_state(sc);
        !            59:
        !            60:        /*
        !            61:         * Read the SD/MMC memory OCR value by issuing CMD55 followed
        !            62:         * by ACMD41 to read the OCR value from memory-only SD cards.
        !            63:         * MMC cards will not respond to CMD55 or ACMD41 and this is
        !            64:         * how we distinguish them from SD cards.
        !            65:         */
        !            66:  mmc_mode:
        !            67:        if (sdmmc_mem_send_op_cond(sc, 0, &card_ocr) != 0) {
        !            68:                if (ISSET(sc->sc_flags, SMF_SD_MODE) &&
        !            69:                    !ISSET(sc->sc_flags, SMF_IO_MODE)) {
        !            70:                        /* Not a SD card, switch to MMC mode. */
        !            71:                        CLR(sc->sc_flags, SMF_SD_MODE);
        !            72:                        goto mmc_mode;
        !            73:                }
        !            74:                if (!ISSET(sc->sc_flags, SMF_SD_MODE)) {
        !            75:                        DPRINTF(("%s: can't read memory OCR\n",
        !            76:                            SDMMCDEVNAME(sc)));
        !            77:                        return 1;
        !            78:                } else {
        !            79:                        /* Not a "combo" card. */
        !            80:                        CLR(sc->sc_flags, SMF_MEM_MODE);
        !            81:                        return 0;
        !            82:                }
        !            83:        }
        !            84:
        !            85:        /* Set the lowest voltage supported by the card and host. */
        !            86:        host_ocr = sdmmc_chip_host_ocr(sc->sct, sc->sch);
        !            87:        if (sdmmc_set_bus_power(sc, host_ocr, card_ocr) != 0) {
        !            88:                DPRINTF(("%s: can't supply voltage requested by card\n",
        !            89:                    SDMMCDEVNAME(sc)));
        !            90:                return 1;
        !            91:        }
        !            92:
        !            93:        /* Tell the card(s) to enter the idle state (again). */
        !            94:        sdmmc_go_idle_state(sc);
        !            95:
        !            96:        /* Send the new OCR value until all cards are ready. */
        !            97:        if (sdmmc_mem_send_op_cond(sc, host_ocr, NULL) != 0) {
        !            98:                DPRINTF(("%s: can't send memory OCR\n", SDMMCDEVNAME(sc)));
        !            99:                return 1;
        !           100:        }
        !           101:        return 0;
        !           102: }
        !           103:
        !           104: /*
        !           105:  * Read the CSD and CID from all cards and assign each card a unique
        !           106:  * relative card address (RCA).  CMD2 is ignored by SDIO-only cards.
        !           107:  */
        !           108: void
        !           109: sdmmc_mem_scan(struct sdmmc_softc *sc)
        !           110: {
        !           111:        struct sdmmc_command cmd;
        !           112:        struct sdmmc_function *sf;
        !           113:        u_int16_t next_rca;
        !           114:        int error;
        !           115:        int i;
        !           116:
        !           117:        /*
        !           118:         * CMD2 is a broadcast command understood by SD cards and MMC
        !           119:         * cards.  All cards begin to respond to the command, but back
        !           120:         * off if another card drives the CMD line to a different level.
        !           121:         * Only one card will get its entire response through.  That
        !           122:         * card remains silent once it has been assigned a RCA.
        !           123:         */
        !           124:        for (i = 0; i < 100; i++) {
        !           125:                bzero(&cmd, sizeof cmd);
        !           126:                cmd.c_opcode = MMC_ALL_SEND_CID;
        !           127:                cmd.c_flags = SCF_CMD_BCR | SCF_RSP_R2;
        !           128:
        !           129:                error = sdmmc_mmc_command(sc, &cmd);
        !           130:                if (error == ETIMEDOUT) {
        !           131:                        /* No more cards there. */
        !           132:                        break;
        !           133:                } else if (error != 0) {
        !           134:                        DPRINTF(("%s: can't read CID\n", SDMMCDEVNAME(sc)));
        !           135:                        break;
        !           136:                }
        !           137:
        !           138:                /* In MMC mode, find the next available RCA. */
        !           139:                next_rca = 1;
        !           140:                if (!ISSET(sc->sc_flags, SMF_SD_MODE))
        !           141:                        SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list)
        !           142:                                next_rca++;
        !           143:
        !           144:                /* Allocate a sdmmc_function structure. */
        !           145:                sf = sdmmc_function_alloc(sc);
        !           146:                sf->rca = next_rca;
        !           147:
        !           148:                /*
        !           149:                 * Remember the CID returned in the CMD2 response for
        !           150:                 * later decoding.
        !           151:                 */
        !           152:                bcopy(cmd.c_resp, sf->raw_cid, sizeof sf->raw_cid);
        !           153:
        !           154:                /*
        !           155:                 * Silence the card by assigning it a unique RCA, or
        !           156:                 * querying it for its RCA in the case of SD.
        !           157:                 */
        !           158:                if (sdmmc_set_relative_addr(sc, sf) != 0) {
        !           159:                        printf("%s: can't set mem RCA\n", SDMMCDEVNAME(sc));
        !           160:                        sdmmc_function_free(sf);
        !           161:                        break;
        !           162:                }
        !           163:
        !           164: #if 0
        !           165:                /* Verify that the RCA has been set by selecting the card. */
        !           166:                if (sdmmc_select_card(sc, sf) != 0) {
        !           167:                        printf("%s: can't select mem RCA %d\n",
        !           168:                            SDMMCDEVNAME(sc), sf->rca);
        !           169:                        sdmmc_function_free(sf);
        !           170:                        break;
        !           171:                }
        !           172:
        !           173:                /* Deselect. */
        !           174:                (void)sdmmc_select_card(sc, NULL);
        !           175: #endif
        !           176:
        !           177:                /*
        !           178:                 * If this is a memory-only card, the card responding
        !           179:                 * first becomes an alias for SDIO function 0.
        !           180:                 */
        !           181:                if (sc->sc_fn0 == NULL)
        !           182:                        sc->sc_fn0 = sf;
        !           183:
        !           184:                SIMPLEQ_INSERT_TAIL(&sc->sf_head, sf, sf_list);
        !           185:        }
        !           186:
        !           187:        /*
        !           188:         * All cards are either inactive or awaiting further commands.
        !           189:         * Read the CSDs and decode the raw CID for each card.
        !           190:         */
        !           191:        SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
        !           192:                bzero(&cmd, sizeof cmd);
        !           193:                cmd.c_opcode = MMC_SEND_CSD;
        !           194:                cmd.c_arg = MMC_ARG_RCA(sf->rca);
        !           195:                cmd.c_flags = SCF_CMD_AC | SCF_RSP_R2;
        !           196:
        !           197:                if (sdmmc_mmc_command(sc, &cmd) != 0) {
        !           198:                        SET(sf->flags, SFF_ERROR);
        !           199:                        continue;
        !           200:                }
        !           201:
        !           202:                if (sdmmc_decode_csd(sc, cmd.c_resp, sf) != 0 ||
        !           203:                    sdmmc_decode_cid(sc, sf->raw_cid, sf) != 0) {
        !           204:                        SET(sf->flags, SFF_ERROR);
        !           205:                        continue;
        !           206:                }
        !           207:
        !           208: #ifdef SDMMC_DEBUG
        !           209:                printf("%s: CID: ", SDMMCDEVNAME(sc));
        !           210:                sdmmc_print_cid(&sf->cid);
        !           211: #endif
        !           212:        }
        !           213: }
        !           214:
        !           215: int
        !           216: sdmmc_decode_csd(struct sdmmc_softc *sc, sdmmc_response resp,
        !           217:     struct sdmmc_function *sf)
        !           218: {
        !           219:        struct sdmmc_csd *csd = &sf->csd;
        !           220:
        !           221:        if (ISSET(sc->sc_flags, SMF_SD_MODE)) {
        !           222:                /*
        !           223:                 * CSD version 1.0 corresponds to SD system
        !           224:                 * specification version 1.0 - 1.10. (SanDisk, 3.5.3)
        !           225:                 */
        !           226:                csd->csdver = SD_CSD_CSDVER(resp);
        !           227:                if (csd->csdver != SD_CSD_CSDVER_1_0) {
        !           228:                        printf("%s: unknown SD CSD structure version 0x%x\n",
        !           229:                            SDMMCDEVNAME(sc), csd->csdver);
        !           230:                        return 1;
        !           231:                }
        !           232:
        !           233:                csd->capacity = SD_CSD_CAPACITY(resp);
        !           234:                csd->read_bl_len = SD_CSD_READ_BL_LEN(resp);
        !           235:        } else {
        !           236:                csd->csdver = MMC_CSD_CSDVER(resp);
        !           237:                if (csd->csdver != MMC_CSD_CSDVER_1_0 &&
        !           238:                    csd->csdver != MMC_CSD_CSDVER_2_0) {
        !           239:                        printf("%s: unknown MMC CSD structure version 0x%x\n",
        !           240:                            SDMMCDEVNAME(sc), csd->csdver);
        !           241:                        return 1;
        !           242:                }
        !           243:
        !           244:                csd->mmcver = MMC_CSD_MMCVER(resp);
        !           245:                csd->capacity = MMC_CSD_CAPACITY(resp);
        !           246:                csd->read_bl_len = MMC_CSD_READ_BL_LEN(resp);
        !           247:        }
        !           248:        csd->sector_size = MIN(1 << csd->read_bl_len,
        !           249:            sdmmc_chip_host_maxblklen(sc->sct, sc->sch));
        !           250:        if (csd->sector_size < (1<<csd->read_bl_len))
        !           251:                csd->capacity *= (1<<csd->read_bl_len) /
        !           252:                    csd->sector_size;
        !           253:
        !           254:        return 0;
        !           255: }
        !           256:
        !           257: int
        !           258: sdmmc_decode_cid(struct sdmmc_softc *sc, sdmmc_response resp,
        !           259:     struct sdmmc_function *sf)
        !           260: {
        !           261:        struct sdmmc_cid *cid = &sf->cid;
        !           262:
        !           263:        if (ISSET(sc->sc_flags, SMF_SD_MODE)) {
        !           264:                cid->mid = SD_CID_MID(resp);
        !           265:                cid->oid = SD_CID_OID(resp);
        !           266:                SD_CID_PNM_CPY(resp, cid->pnm);
        !           267:                cid->rev = SD_CID_REV(resp);
        !           268:                cid->psn = SD_CID_PSN(resp);
        !           269:                cid->mdt = SD_CID_MDT(resp);
        !           270:        } else {
        !           271:                switch(sf->csd.mmcver) {
        !           272:                case MMC_CSD_MMCVER_1_0:
        !           273:                case MMC_CSD_MMCVER_1_4:
        !           274:                        cid->mid = MMC_CID_MID_V1(resp);
        !           275:                        MMC_CID_PNM_V1_CPY(resp, cid->pnm);
        !           276:                        cid->rev = MMC_CID_REV_V1(resp);
        !           277:                        cid->psn = MMC_CID_PSN_V1(resp);
        !           278:                        cid->mdt = MMC_CID_MDT_V1(resp);
        !           279:                        break;
        !           280:                case MMC_CSD_MMCVER_2_0:
        !           281:                case MMC_CSD_MMCVER_3_1:
        !           282:                case MMC_CSD_MMCVER_4_0:
        !           283:                        cid->mid = MMC_CID_MID_V2(resp);
        !           284:                        cid->oid = MMC_CID_OID_V2(resp);
        !           285:                        MMC_CID_PNM_V2_CPY(resp, cid->pnm);
        !           286:                        cid->psn = MMC_CID_PSN_V2(resp);
        !           287:                        break;
        !           288:                default:
        !           289:                        printf("%s: unknown MMC version %d\n",
        !           290:                            SDMMCDEVNAME(sc), sf->csd.mmcver);
        !           291:                        return 1;
        !           292:                }
        !           293:        }
        !           294:        return 0;
        !           295: }
        !           296:
        !           297: #ifdef SDMMC_DEBUG
        !           298: void
        !           299: sdmmc_print_cid(struct sdmmc_cid *cid)
        !           300: {
        !           301:        printf("mid=0x%02x oid=0x%04x pnm=\"%s\" rev=0x%02x psn=0x%08x"
        !           302:            " mdt=%03x\n", cid->mid, cid->oid, cid->pnm, cid->rev, cid->psn,
        !           303:            cid->mdt);
        !           304: }
        !           305: #endif
        !           306:
        !           307: /*
        !           308:  * Initialize a SD/MMC memory card.
        !           309:  */
        !           310: int
        !           311: sdmmc_mem_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
        !           312: {
        !           313:        int error = 0;
        !           314:
        !           315:        SDMMC_LOCK(sc);
        !           316:        if (sdmmc_select_card(sc, sf) != 0 ||
        !           317:            sdmmc_mem_set_blocklen(sc, sf) != 0)
        !           318:                error = 1;
        !           319:        SDMMC_UNLOCK(sc);
        !           320:        return error;
        !           321: }
        !           322:
        !           323: /*
        !           324:  * Get or set the card's memory OCR value (SD or MMC).
        !           325:  */
        !           326: int
        !           327: sdmmc_mem_send_op_cond(struct sdmmc_softc *sc, u_int32_t ocr,
        !           328:     u_int32_t *ocrp)
        !           329: {
        !           330:        struct sdmmc_command cmd;
        !           331:        int error;
        !           332:        int i;
        !           333:
        !           334:        SDMMC_LOCK(sc);
        !           335:
        !           336:        /*
        !           337:         * If we change the OCR value, retry the command until the OCR
        !           338:         * we receive in response has the "CARD BUSY" bit set, meaning
        !           339:         * that all cards are ready for identification.
        !           340:         */
        !           341:        for (i = 0; i < 100; i++) {
        !           342:                bzero(&cmd, sizeof cmd);
        !           343:                cmd.c_arg = ocr;
        !           344:                cmd.c_flags = SCF_CMD_BCR | SCF_RSP_R3;
        !           345:
        !           346:                if (ISSET(sc->sc_flags, SMF_SD_MODE)) {
        !           347:                        cmd.c_opcode = SD_APP_OP_COND;
        !           348:                        error = sdmmc_app_command(sc, &cmd);
        !           349:                } else {
        !           350:                        cmd.c_opcode = MMC_SEND_OP_COND;
        !           351:                        error = sdmmc_mmc_command(sc, &cmd);
        !           352:                }
        !           353:                if (error != 0)
        !           354:                        break;
        !           355:                if (ISSET(MMC_R3(cmd.c_resp), MMC_OCR_MEM_READY) ||
        !           356:                    ocr == 0)
        !           357:                        break;
        !           358:                error = ETIMEDOUT;
        !           359:                sdmmc_delay(10000);
        !           360:        }
        !           361:        if (error == 0 && ocrp != NULL)
        !           362:                *ocrp = MMC_R3(cmd.c_resp);
        !           363:
        !           364:        SDMMC_UNLOCK(sc);
        !           365:        return error;
        !           366: }
        !           367:
        !           368: /*
        !           369:  * Set the read block length appropriately for this card, according to
        !           370:  * the card CSD register value.
        !           371:  */
        !           372: int
        !           373: sdmmc_mem_set_blocklen(struct sdmmc_softc *sc, struct sdmmc_function *sf)
        !           374: {
        !           375:        struct sdmmc_command cmd;
        !           376:
        !           377:        bzero(&cmd, sizeof cmd);
        !           378:        cmd.c_opcode = MMC_SET_BLOCKLEN;
        !           379:        cmd.c_arg = sf->csd.sector_size;
        !           380:        cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1;
        !           381:        DPRINTF(("%s: read_bl_len=%d sector_size=%d\n", SDMMCDEVNAME(sc),
        !           382:            1 << sf->csd.read_bl_len, sf->csd.sector_size));
        !           383:
        !           384:        return sdmmc_mmc_command(sc, &cmd);
        !           385: }
        !           386:
        !           387: int
        !           388: sdmmc_mem_read_block(struct sdmmc_function *sf, int blkno, u_char *data,
        !           389:     size_t datalen)
        !           390: {
        !           391:        struct sdmmc_softc *sc = sf->sc;
        !           392:        struct sdmmc_command cmd;
        !           393:        int error;
        !           394:
        !           395:        SDMMC_LOCK(sc);
        !           396:
        !           397:        if ((error = sdmmc_select_card(sc, sf)) != 0)
        !           398:                goto err;
        !           399:
        !           400:        bzero(&cmd, sizeof cmd);
        !           401:        cmd.c_data = data;
        !           402:        cmd.c_datalen = datalen;
        !           403:        cmd.c_blklen = sf->csd.sector_size;
        !           404:        cmd.c_opcode = (datalen / cmd.c_blklen) > 1 ?
        !           405:            MMC_READ_BLOCK_MULTIPLE : MMC_READ_BLOCK_SINGLE;
        !           406:        cmd.c_arg = blkno << 9;
        !           407:        cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1;
        !           408:
        !           409:        error = sdmmc_mmc_command(sc, &cmd);
        !           410:        if (error != 0)
        !           411:                goto err;
        !           412:
        !           413:        /* XXX sdhc(4) does not need this */
        !           414: #ifdef __zaurus__
        !           415:        if (cmd.c_opcode == MMC_READ_BLOCK_MULTIPLE) {
        !           416:                bzero(&cmd, sizeof cmd);
        !           417:                cmd.c_opcode = MMC_STOP_TRANSMISSION;
        !           418:                cmd.c_arg = MMC_ARG_RCA(sf->rca);
        !           419:                cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1B;
        !           420:                error = sdmmc_mmc_command(sc, &cmd);
        !           421:                if (error != 0)
        !           422:                        goto err;
        !           423:        }
        !           424: #endif
        !           425:
        !           426:        do {
        !           427:                bzero(&cmd, sizeof cmd);
        !           428:                cmd.c_opcode = MMC_SEND_STATUS;
        !           429:                cmd.c_arg = MMC_ARG_RCA(sf->rca);
        !           430:                cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1;
        !           431:                error = sdmmc_mmc_command(sc, &cmd);
        !           432:                if (error != 0)
        !           433:                        break;
        !           434:                /* XXX time out */
        !           435:        } while (!ISSET(MMC_R1(cmd.c_resp), MMC_R1_READY_FOR_DATA));
        !           436:
        !           437: err:
        !           438:        SDMMC_UNLOCK(sc);
        !           439:        return error;
        !           440: }
        !           441:
        !           442: int
        !           443: sdmmc_mem_write_block(struct sdmmc_function *sf, int blkno, u_char *data,
        !           444:     size_t datalen)
        !           445: {
        !           446:        struct sdmmc_softc *sc = sf->sc;
        !           447:        struct sdmmc_command cmd;
        !           448:        int error;
        !           449:
        !           450:        SDMMC_LOCK(sc);
        !           451:
        !           452:        if ((error = sdmmc_select_card(sc, sf)) != 0)
        !           453:                goto err;
        !           454:
        !           455:        bzero(&cmd, sizeof cmd);
        !           456:        cmd.c_data = data;
        !           457:        cmd.c_datalen = datalen;
        !           458:        cmd.c_blklen = sf->csd.sector_size;
        !           459:        cmd.c_opcode = (datalen / cmd.c_blklen) > 1 ?
        !           460:            MMC_WRITE_BLOCK_MULTIPLE : MMC_WRITE_BLOCK_SINGLE;
        !           461:        cmd.c_arg = blkno << 9;
        !           462:        cmd.c_flags = SCF_CMD_ADTC | SCF_RSP_R1;
        !           463:
        !           464:        error = sdmmc_mmc_command(sc, &cmd);
        !           465:        if (error != 0)
        !           466:                goto err;
        !           467:
        !           468:        /* XXX sdhc(4) does not need this */
        !           469: #ifdef __zaurus__
        !           470:        if (cmd.c_opcode == MMC_WRITE_BLOCK_MULTIPLE) {
        !           471:                bzero(&cmd, sizeof cmd);
        !           472:                cmd.c_opcode = MMC_STOP_TRANSMISSION;
        !           473:                cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1B;
        !           474:                error = sdmmc_mmc_command(sc, &cmd);
        !           475:                if (error != 0)
        !           476:                        goto err;
        !           477:        }
        !           478: #endif
        !           479:
        !           480:        do {
        !           481:                bzero(&cmd, sizeof cmd);
        !           482:                cmd.c_opcode = MMC_SEND_STATUS;
        !           483:                cmd.c_arg = MMC_ARG_RCA(sf->rca);
        !           484:                cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1;
        !           485:                error = sdmmc_mmc_command(sc, &cmd);
        !           486:                if (error != 0)
        !           487:                        break;
        !           488:                /* XXX time out */
        !           489:        } while (!ISSET(MMC_R1(cmd.c_resp), MMC_R1_READY_FOR_DATA));
        !           490:
        !           491: err:
        !           492:        SDMMC_UNLOCK(sc);
        !           493:        return error;
        !           494: }

CVSweb