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

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

1.1     ! nbrk        1: /*     $OpenBSD: sdmmc.c,v 1.12 2007/05/31 10:09:01 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: /*
        !            20:  * Host controller independent SD/MMC bus driver based on information
        !            21:  * from SanDisk SD Card Product Manual Revision 2.2 (SanDisk), SDIO
        !            22:  * Simple Specification Version 1.0 (SDIO) and the Linux "mmc" driver.
        !            23:  */
        !            24:
        !            25: #include <sys/param.h>
        !            26: #include <sys/device.h>
        !            27: #include <sys/kernel.h>
        !            28: #include <sys/kthread.h>
        !            29: #include <sys/malloc.h>
        !            30: #include <sys/proc.h>
        !            31: #include <sys/systm.h>
        !            32:
        !            33: #include <scsi/scsi_all.h>
        !            34: #include <scsi/scsiconf.h>
        !            35:
        !            36: #include <dev/sdmmc/sdmmc_ioreg.h>
        !            37: #include <dev/sdmmc/sdmmc_scsi.h>
        !            38: #include <dev/sdmmc/sdmmcchip.h>
        !            39: #include <dev/sdmmc/sdmmcreg.h>
        !            40: #include <dev/sdmmc/sdmmcvar.h>
        !            41:
        !            42: #ifdef SDMMC_IOCTL
        !            43: #include "bio.h"
        !            44: #if NBIO < 1
        !            45: #undef SDMMC_IOCTL
        !            46: #endif
        !            47: #include <dev/biovar.h>
        !            48: #endif
        !            49:
        !            50: int    sdmmc_match(struct device *, void *, void *);
        !            51: void   sdmmc_attach(struct device *, struct device *, void *);
        !            52: int    sdmmc_detach(struct device *, int);
        !            53: void   sdmmc_create_thread(void *);
        !            54: void   sdmmc_task_thread(void *);
        !            55: void   sdmmc_discover_task(void *);
        !            56: void   sdmmc_card_attach(struct sdmmc_softc *);
        !            57: void   sdmmc_card_detach(struct sdmmc_softc *, int);
        !            58: int    sdmmc_enable(struct sdmmc_softc *);
        !            59: void   sdmmc_disable(struct sdmmc_softc *);
        !            60: int    sdmmc_scan(struct sdmmc_softc *);
        !            61: int    sdmmc_init(struct sdmmc_softc *);
        !            62: int    sdmmc_set_bus_width(struct sdmmc_function *);
        !            63: #ifdef SDMMC_IOCTL
        !            64: int    sdmmc_ioctl(struct device *, u_long, caddr_t);
        !            65: #endif
        !            66:
        !            67: #define DEVNAME(sc)    SDMMCDEVNAME(sc)
        !            68:
        !            69: #ifdef SDMMC_DEBUG
        !            70: int sdmmcdebug = 0;
        !            71: extern int sdhcdebug;  /* XXX should have a sdmmc_chip_debug() function */
        !            72: void sdmmc_dump_command(struct sdmmc_softc *, struct sdmmc_command *);
        !            73: #define DPRINTF(n,s)   do { if ((n) <= sdmmcdebug) printf s; } while (0)
        !            74: #else
        !            75: #define DPRINTF(n,s)   do {} while (0)
        !            76: #endif
        !            77:
        !            78: struct cfattach sdmmc_ca = {
        !            79:        sizeof(struct sdmmc_softc), sdmmc_match, sdmmc_attach, sdmmc_detach
        !            80: };
        !            81:
        !            82: struct cfdriver sdmmc_cd = {
        !            83:        NULL, "sdmmc", DV_DULL
        !            84: };
        !            85:
        !            86: int
        !            87: sdmmc_match(struct device *parent, void *match, void *aux)
        !            88: {
        !            89:        struct cfdata *cf = match;
        !            90:        struct sdmmcbus_attach_args *saa = aux;
        !            91:
        !            92:        return strcmp(saa->saa_busname, cf->cf_driver->cd_name) == 0;
        !            93: }
        !            94:
        !            95: void
        !            96: sdmmc_attach(struct device *parent, struct device *self, void *aux)
        !            97: {
        !            98:        struct sdmmc_softc *sc = (struct sdmmc_softc *)self;
        !            99:        struct sdmmcbus_attach_args *saa = aux;
        !           100:
        !           101:        printf("\n");
        !           102:
        !           103:        sc->sct = saa->sct;
        !           104:        sc->sch = saa->sch;
        !           105:
        !           106:        SIMPLEQ_INIT(&sc->sf_head);
        !           107:        TAILQ_INIT(&sc->sc_tskq);
        !           108:        TAILQ_INIT(&sc->sc_intrq);
        !           109:        sdmmc_init_task(&sc->sc_discover_task, sdmmc_discover_task, sc);
        !           110:        sdmmc_init_task(&sc->sc_intr_task, sdmmc_intr_task, sc);
        !           111:        lockinit(&sc->sc_lock, PRIBIO, DEVNAME(sc), 0, LK_CANRECURSE);
        !           112:
        !           113: #ifdef SDMMC_IOCTL
        !           114:        if (bio_register(self, sdmmc_ioctl) != 0)
        !           115:                printf("%s: unable to register ioctl\n", DEVNAME(sc));
        !           116: #endif
        !           117:
        !           118:        /*
        !           119:         * Create the event thread that will attach and detach cards
        !           120:         * and perform other lengthy operations.
        !           121:         */
        !           122: #ifdef DO_CONFIG_PENDING
        !           123:        config_pending_incr();
        !           124: #endif
        !           125:        kthread_create_deferred(sdmmc_create_thread, sc);
        !           126: }
        !           127:
        !           128: int
        !           129: sdmmc_detach(struct device *self, int flags)
        !           130: {
        !           131:        struct sdmmc_softc *sc = (struct sdmmc_softc *)self;
        !           132:
        !           133:        sc->sc_dying = 1;
        !           134:        while (sc->sc_task_thread != NULL) {
        !           135:                wakeup(&sc->sc_tskq);
        !           136:                tsleep(sc, PWAIT, "mmcdie", 0);
        !           137:        }
        !           138:        return 0;
        !           139: }
        !           140:
        !           141: void
        !           142: sdmmc_create_thread(void *arg)
        !           143: {
        !           144:        struct sdmmc_softc *sc = arg;
        !           145:
        !           146:        if (kthread_create(sdmmc_task_thread, sc, &sc->sc_task_thread,
        !           147:            "%s", DEVNAME(sc)) != 0)
        !           148:                printf("%s: can't create task thread\n", DEVNAME(sc));
        !           149:
        !           150: #ifdef DO_CONFIG_PENDING
        !           151:        config_pending_decr();
        !           152: #endif
        !           153: }
        !           154:
        !           155: void
        !           156: sdmmc_task_thread(void *arg)
        !           157: {
        !           158:        struct sdmmc_softc *sc = arg;
        !           159:        struct sdmmc_task *task;
        !           160:        int s;
        !           161:
        !           162:        sdmmc_needs_discover(&sc->sc_dev);
        !           163:
        !           164:        s = splsdmmc();
        !           165:        while (!sc->sc_dying) {
        !           166:                for (task = TAILQ_FIRST(&sc->sc_tskq); task != NULL;
        !           167:                     task = TAILQ_FIRST(&sc->sc_tskq)) {
        !           168:                        splx(s);
        !           169:                        sdmmc_del_task(task);
        !           170:                        task->func(task->arg);
        !           171:                        s = splsdmmc();
        !           172:                }
        !           173:                tsleep(&sc->sc_tskq, PWAIT, "mmctsk", 0);
        !           174:        }
        !           175:        splx(s);
        !           176:
        !           177:        if (ISSET(sc->sc_flags, SMF_CARD_PRESENT))
        !           178:                sdmmc_card_detach(sc, DETACH_FORCE);
        !           179:
        !           180:        sc->sc_task_thread = NULL;
        !           181:        wakeup(sc);
        !           182:        kthread_exit(0);
        !           183: }
        !           184:
        !           185: void
        !           186: sdmmc_add_task(struct sdmmc_softc *sc, struct sdmmc_task *task)
        !           187: {
        !           188:        int s;
        !           189:
        !           190:        s = splsdmmc();
        !           191:        TAILQ_INSERT_TAIL(&sc->sc_tskq, task, next);
        !           192:        task->onqueue = 1;
        !           193:        task->sc = sc;
        !           194:        wakeup(&sc->sc_tskq);
        !           195:        splx(s);
        !           196: }
        !           197:
        !           198: void
        !           199: sdmmc_del_task(struct sdmmc_task *task)
        !           200: {
        !           201:        struct sdmmc_softc *sc = task->sc;
        !           202:        int s;
        !           203:
        !           204:        if (sc == NULL)
        !           205:                return;
        !           206:
        !           207:        s = splsdmmc();
        !           208:        task->sc = NULL;
        !           209:        task->onqueue = 0;
        !           210:        TAILQ_REMOVE(&sc->sc_tskq, task, next);
        !           211:        splx(s);
        !           212: }
        !           213:
        !           214: void
        !           215: sdmmc_needs_discover(struct device *self)
        !           216: {
        !           217:        struct sdmmc_softc *sc = (struct sdmmc_softc *)self;
        !           218:
        !           219:        if (!sdmmc_task_pending(&sc->sc_discover_task))
        !           220:                sdmmc_add_task(sc, &sc->sc_discover_task);
        !           221: }
        !           222:
        !           223: void
        !           224: sdmmc_discover_task(void *arg)
        !           225: {
        !           226:        struct sdmmc_softc *sc = arg;
        !           227:
        !           228:        if (sdmmc_chip_card_detect(sc->sct, sc->sch)) {
        !           229:                if (!ISSET(sc->sc_flags, SMF_CARD_PRESENT)) {
        !           230:                        SET(sc->sc_flags, SMF_CARD_PRESENT);
        !           231:                        sdmmc_card_attach(sc);
        !           232:                }
        !           233:        } else {
        !           234:                if (ISSET(sc->sc_flags, SMF_CARD_PRESENT)) {
        !           235:                        CLR(sc->sc_flags, SMF_CARD_PRESENT);
        !           236:                        sdmmc_card_detach(sc, DETACH_FORCE);
        !           237:                }
        !           238:        }
        !           239: }
        !           240:
        !           241: /*
        !           242:  * Called from process context when a card is present.
        !           243:  */
        !           244: void
        !           245: sdmmc_card_attach(struct sdmmc_softc *sc)
        !           246: {
        !           247:        DPRINTF(1,("%s: attach card\n", DEVNAME(sc)));
        !           248:
        !           249:        SDMMC_LOCK(sc);
        !           250:        CLR(sc->sc_flags, SMF_CARD_ATTACHED);
        !           251:
        !           252:        /*
        !           253:         * Power up the card (or card stack).
        !           254:         */
        !           255:        if (sdmmc_enable(sc) != 0) {
        !           256:                printf("%s: can't enable card\n", DEVNAME(sc));
        !           257:                goto err;
        !           258:        }
        !           259:
        !           260:        /*
        !           261:         * Scan for I/O functions and memory cards on the bus,
        !           262:         * allocating a sdmmc_function structure for each.
        !           263:         */
        !           264:        if (sdmmc_scan(sc) != 0) {
        !           265:                printf("%s: no functions\n", DEVNAME(sc));
        !           266:                goto err;
        !           267:        }
        !           268:
        !           269:        /*
        !           270:         * Initialize the I/O functions and memory cards.
        !           271:         */
        !           272:        if (sdmmc_init(sc) != 0) {
        !           273:                printf("%s: init failed\n", DEVNAME(sc));
        !           274:                goto err;
        !           275:        }
        !           276:
        !           277:        /* Attach SCSI emulation for memory cards. */
        !           278:        if (ISSET(sc->sc_flags, SMF_MEM_MODE))
        !           279:                sdmmc_scsi_attach(sc);
        !           280:
        !           281:        /* Attach I/O function drivers. */
        !           282:        if (ISSET(sc->sc_flags, SMF_IO_MODE))
        !           283:                sdmmc_io_attach(sc);
        !           284:
        !           285:        SET(sc->sc_flags, SMF_CARD_ATTACHED);
        !           286:        SDMMC_UNLOCK(sc);
        !           287:        return;
        !           288: err:
        !           289:        sdmmc_card_detach(sc, DETACH_FORCE);
        !           290:        SDMMC_UNLOCK(sc);
        !           291: }
        !           292:
        !           293: /*
        !           294:  * Called from process context with DETACH_* flags from <sys/device.h>
        !           295:  * when cards are gone.
        !           296:  */
        !           297: void
        !           298: sdmmc_card_detach(struct sdmmc_softc *sc, int flags)
        !           299: {
        !           300:        struct sdmmc_function *sf, *sfnext;
        !           301:
        !           302:        DPRINTF(1,("%s: detach card\n", DEVNAME(sc)));
        !           303:
        !           304:        if (ISSET(sc->sc_flags, SMF_CARD_ATTACHED)) {
        !           305:                /* Detach I/O function drivers. */
        !           306:                if (ISSET(sc->sc_flags, SMF_IO_MODE))
        !           307:                        sdmmc_io_detach(sc);
        !           308:
        !           309:                /* Detach the SCSI emulation for memory cards. */
        !           310:                if (ISSET(sc->sc_flags, SMF_MEM_MODE))
        !           311:                        sdmmc_scsi_detach(sc);
        !           312:
        !           313:                CLR(sc->sc_flags, SMF_CARD_ATTACHED);
        !           314:        }
        !           315:
        !           316:        /* Power down. */
        !           317:        sdmmc_disable(sc);
        !           318:
        !           319:        /* Free all sdmmc_function structures. */
        !           320:        for (sf = SIMPLEQ_FIRST(&sc->sf_head); sf != NULL; sf = sfnext) {
        !           321:                sfnext = SIMPLEQ_NEXT(sf, sf_list);
        !           322:                sdmmc_function_free(sf);
        !           323:        }
        !           324:        SIMPLEQ_INIT(&sc->sf_head);
        !           325:        sc->sc_function_count = 0;
        !           326:        sc->sc_fn0 = NULL;
        !           327: }
        !           328:
        !           329: int
        !           330: sdmmc_enable(struct sdmmc_softc *sc)
        !           331: {
        !           332:        u_int32_t host_ocr;
        !           333:        int error;
        !           334:
        !           335:        /*
        !           336:         * Calculate the equivalent of the card OCR from the host
        !           337:         * capabilities and select the maximum supported bus voltage.
        !           338:         */
        !           339:        host_ocr = sdmmc_chip_host_ocr(sc->sct, sc->sch);
        !           340:        error = sdmmc_chip_bus_power(sc->sct, sc->sch, host_ocr);
        !           341:        if (error != 0) {
        !           342:                printf("%s: can't supply bus power\n", DEVNAME(sc));
        !           343:                goto err;
        !           344:        }
        !           345:
        !           346:        /*
        !           347:         * Select the minimum clock frequency.
        !           348:         */
        !           349:        error = sdmmc_chip_bus_clock(sc->sct, sc->sch, SDMMC_SDCLK_400KHZ);
        !           350:        if (error != 0) {
        !           351:                printf("%s: can't supply clock\n", DEVNAME(sc));
        !           352:                goto err;
        !           353:        }
        !           354:
        !           355:        /* XXX wait for card to power up */
        !           356:        sdmmc_delay(100000);
        !           357:
        !           358:        /* Initialize SD I/O card function(s). */
        !           359:        if ((error = sdmmc_io_enable(sc)) != 0)
        !           360:                goto err;
        !           361:
        !           362:        /* Initialize SD/MMC memory card(s). */
        !           363:        if (ISSET(sc->sc_flags, SMF_MEM_MODE) &&
        !           364:            (error = sdmmc_mem_enable(sc)) != 0)
        !           365:                goto err;
        !           366:
        !           367:        /* XXX respect host and card capabilities */
        !           368:        if (ISSET(sc->sc_flags, SMF_SD_MODE))
        !           369:                (void)sdmmc_chip_bus_clock(sc->sct, sc->sch,
        !           370:                    SDMMC_SDCLK_25MHZ);
        !           371:
        !           372:  err:
        !           373:        if (error != 0)
        !           374:                sdmmc_disable(sc);
        !           375:        return error;
        !           376: }
        !           377:
        !           378: void
        !           379: sdmmc_disable(struct sdmmc_softc *sc)
        !           380: {
        !           381:        /* XXX complete commands if card is still present. */
        !           382:
        !           383:        /* Make sure no card is still selected. */
        !           384:        (void)sdmmc_select_card(sc, NULL);
        !           385:
        !           386:        /* Turn off bus power and clock. */
        !           387:        (void)sdmmc_chip_bus_clock(sc->sct, sc->sch, SDMMC_SDCLK_OFF);
        !           388:        (void)sdmmc_chip_bus_power(sc->sct, sc->sch, 0);
        !           389: }
        !           390:
        !           391: /*
        !           392:  * Set the lowest bus voltage supported by the card and the host.
        !           393:  */
        !           394: int
        !           395: sdmmc_set_bus_power(struct sdmmc_softc *sc, u_int32_t host_ocr,
        !           396:     u_int32_t card_ocr)
        !           397: {
        !           398:        u_int32_t bit;
        !           399:
        !           400:        /* Mask off unsupported voltage levels and select the lowest. */
        !           401:        DPRINTF(1,("%s: host_ocr=%x ", DEVNAME(sc), host_ocr));
        !           402:        host_ocr &= card_ocr;
        !           403:        for (bit = 4; bit < 23; bit++) {
        !           404:                if (ISSET(host_ocr, 1<<bit)) {
        !           405:                        host_ocr &= 3<<bit;
        !           406:                        break;
        !           407:                }
        !           408:        }
        !           409:        DPRINTF(1,("card_ocr=%x new_ocr=%x\n", card_ocr, host_ocr));
        !           410:
        !           411:        if (host_ocr == 0 ||
        !           412:            sdmmc_chip_bus_power(sc->sct, sc->sch, host_ocr) != 0)
        !           413:                return 1;
        !           414:        return 0;
        !           415: }
        !           416:
        !           417: struct sdmmc_function *
        !           418: sdmmc_function_alloc(struct sdmmc_softc *sc)
        !           419: {
        !           420:        struct sdmmc_function *sf;
        !           421:
        !           422:        MALLOC(sf, struct sdmmc_function *, sizeof *sf, M_DEVBUF,
        !           423:            M_WAITOK);
        !           424:        bzero(sf, sizeof *sf);
        !           425:        sf->sc = sc;
        !           426:        sf->number = -1;
        !           427:        sf->cis.manufacturer = SDMMC_VENDOR_INVALID;
        !           428:        sf->cis.product = SDMMC_PRODUCT_INVALID;
        !           429:        sf->cis.function = SDMMC_FUNCTION_INVALID;
        !           430:        return sf;
        !           431: }
        !           432:
        !           433: void
        !           434: sdmmc_function_free(struct sdmmc_function *sf)
        !           435: {
        !           436:        FREE(sf, M_DEVBUF);
        !           437: }
        !           438:
        !           439: /*
        !           440:  * Scan for I/O functions and memory cards on the bus, allocating a
        !           441:  * sdmmc_function structure for each.
        !           442:  */
        !           443: int
        !           444: sdmmc_scan(struct sdmmc_softc *sc)
        !           445: {
        !           446:        /* Scan for I/O functions. */
        !           447:        if (ISSET(sc->sc_flags, SMF_IO_MODE))
        !           448:                sdmmc_io_scan(sc);
        !           449:
        !           450:        /* Scan for memory cards on the bus. */
        !           451:        if (ISSET(sc->sc_flags, SMF_MEM_MODE))
        !           452:                sdmmc_mem_scan(sc);
        !           453:
        !           454:        /* There should be at least one function now. */
        !           455:        if (SIMPLEQ_EMPTY(&sc->sf_head)) {
        !           456:                printf("%s: can't identify card\n", DEVNAME(sc));
        !           457:                return 1;
        !           458:        }
        !           459:        return 0;
        !           460: }
        !           461:
        !           462: /*
        !           463:  * Initialize all the distinguished functions of the card, be it I/O
        !           464:  * or memory functions.
        !           465:  */
        !           466: int
        !           467: sdmmc_init(struct sdmmc_softc *sc)
        !           468: {
        !           469:        struct sdmmc_function *sf;
        !           470:
        !           471:        /* Initialize all identified card functions. */
        !           472:        SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
        !           473:                if (ISSET(sc->sc_flags, SMF_IO_MODE) &&
        !           474:                    sdmmc_io_init(sc, sf) != 0)
        !           475:                        printf("%s: i/o init failed\n", DEVNAME(sc));
        !           476:
        !           477:                if (ISSET(sc->sc_flags, SMF_MEM_MODE) &&
        !           478:                    sdmmc_mem_init(sc, sf) != 0)
        !           479:                        printf("%s: mem init failed\n", DEVNAME(sc));
        !           480:        }
        !           481:
        !           482:        /* Any good functions left after initialization? */
        !           483:        SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
        !           484:                if (!ISSET(sf->flags, SFF_ERROR))
        !           485:                        return 0;
        !           486:        }
        !           487:        /* No, we should probably power down the card. */
        !           488:        return 1;
        !           489: }
        !           490:
        !           491: void
        !           492: sdmmc_delay(u_int usecs)
        !           493: {
        !           494:        int ticks = usecs / (1000000 / hz);
        !           495:
        !           496:        if (ticks > 0)
        !           497:                tsleep(&sdmmc_delay, PWAIT, "mmcdly", ticks);
        !           498:        else
        !           499:                delay(usecs);
        !           500: }
        !           501:
        !           502: int
        !           503: sdmmc_app_command(struct sdmmc_softc *sc, struct sdmmc_command *cmd)
        !           504: {
        !           505:        struct sdmmc_command acmd;
        !           506:        int error;
        !           507:
        !           508:        SDMMC_LOCK(sc);
        !           509:
        !           510:        bzero(&acmd, sizeof acmd);
        !           511:        acmd.c_opcode = MMC_APP_CMD;
        !           512:        acmd.c_arg = 0;
        !           513:        acmd.c_flags = SCF_CMD_AC | SCF_RSP_R1;
        !           514:
        !           515:        error = sdmmc_mmc_command(sc, &acmd);
        !           516:        if (error != 0) {
        !           517:                SDMMC_UNLOCK(sc);
        !           518:                return error;
        !           519:        }
        !           520:
        !           521:        if (!ISSET(MMC_R1(acmd.c_resp), MMC_R1_APP_CMD)) {
        !           522:                /* Card does not support application commands. */
        !           523:                SDMMC_UNLOCK(sc);
        !           524:                return ENODEV;
        !           525:        }
        !           526:
        !           527:        error = sdmmc_mmc_command(sc, cmd);
        !           528:        SDMMC_UNLOCK(sc);
        !           529:        return error;
        !           530: }
        !           531:
        !           532: /*
        !           533:  * Execute MMC command and data transfers.  All interactions with the
        !           534:  * host controller to complete the command happen in the context of
        !           535:  * the current process.
        !           536:  */
        !           537: int
        !           538: sdmmc_mmc_command(struct sdmmc_softc *sc, struct sdmmc_command *cmd)
        !           539: {
        !           540:        int error;
        !           541:
        !           542:        SDMMC_LOCK(sc);
        !           543:
        !           544:        sdmmc_chip_exec_command(sc->sct, sc->sch, cmd);
        !           545:
        !           546: #ifdef SDMMC_DEBUG
        !           547:        sdmmc_dump_command(sc, cmd);
        !           548: #endif
        !           549:
        !           550:        error = cmd->c_error;
        !           551:        wakeup(cmd);
        !           552:
        !           553:        SDMMC_UNLOCK(sc);
        !           554:        return error;
        !           555: }
        !           556:
        !           557: /*
        !           558:  * Send the "GO IDLE STATE" command.
        !           559:  */
        !           560: void
        !           561: sdmmc_go_idle_state(struct sdmmc_softc *sc)
        !           562: {
        !           563:        struct sdmmc_command cmd;
        !           564:
        !           565:        bzero(&cmd, sizeof cmd);
        !           566:        cmd.c_opcode = MMC_GO_IDLE_STATE;
        !           567:        cmd.c_flags = SCF_CMD_BC | SCF_RSP_R0;
        !           568:
        !           569:        (void)sdmmc_mmc_command(sc, &cmd);
        !           570: }
        !           571:
        !           572: /*
        !           573:  * Retrieve (SD) or set (MMC) the relative card address (RCA).
        !           574:  */
        !           575: int
        !           576: sdmmc_set_relative_addr(struct sdmmc_softc *sc,
        !           577:     struct sdmmc_function *sf)
        !           578: {
        !           579:        struct sdmmc_command cmd;
        !           580:
        !           581:        bzero(&cmd, sizeof cmd);
        !           582:
        !           583:        if (ISSET(sc->sc_flags, SMF_SD_MODE)) {
        !           584:                cmd.c_opcode = SD_SEND_RELATIVE_ADDR;
        !           585:                cmd.c_flags = SCF_CMD_BCR | SCF_RSP_R6;
        !           586:        } else {
        !           587:                cmd.c_opcode = MMC_SET_RELATIVE_ADDR;
        !           588:                cmd.c_arg = MMC_ARG_RCA(sf->rca);
        !           589:                cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1;
        !           590:        }
        !           591:
        !           592:        if (sdmmc_mmc_command(sc, &cmd) != 0)
        !           593:                return 1;
        !           594:
        !           595:        if (ISSET(sc->sc_flags, SMF_SD_MODE))
        !           596:                sf->rca = SD_R6_RCA(cmd.c_resp);
        !           597:        return 0;
        !           598: }
        !           599:
        !           600: /*
        !           601:  * Switch card and host to the maximum supported bus width.
        !           602:  */
        !           603: int
        !           604: sdmmc_set_bus_width(struct sdmmc_function *sf)
        !           605: {
        !           606:        struct sdmmc_softc *sc = sf->sc;
        !           607:        struct sdmmc_command cmd;
        !           608:        int error;
        !           609:
        !           610:        SDMMC_LOCK(sc);
        !           611:
        !           612:        if (!ISSET(sc->sc_flags, SMF_SD_MODE)) {
        !           613:                SDMMC_UNLOCK(sc);
        !           614:                return EOPNOTSUPP;
        !           615:        }
        !           616:
        !           617:        if ((error = sdmmc_select_card(sc, sf)) != 0) {
        !           618:                SDMMC_UNLOCK(sc);
        !           619:                return error;
        !           620:        }
        !           621:
        !           622:        bzero(&cmd, sizeof cmd);
        !           623:        cmd.c_opcode = SD_APP_SET_BUS_WIDTH;
        !           624:        cmd.c_arg = SD_ARG_BUS_WIDTH_4;
        !           625:        cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1;
        !           626:        error = sdmmc_app_command(sc, &cmd);
        !           627:        SDMMC_UNLOCK(sc);
        !           628:        return error;
        !           629: }
        !           630:
        !           631: int
        !           632: sdmmc_select_card(struct sdmmc_softc *sc, struct sdmmc_function *sf)
        !           633: {
        !           634:        struct sdmmc_command cmd;
        !           635:        int error;
        !           636:
        !           637:        if (sc->sc_card == sf || (sf && sc->sc_card &&
        !           638:            sc->sc_card->rca == sf->rca)) {
        !           639:                sc->sc_card = sf;
        !           640:                return 0;
        !           641:        }
        !           642:
        !           643:        bzero(&cmd, sizeof cmd);
        !           644:        cmd.c_opcode = MMC_SELECT_CARD;
        !           645:        cmd.c_arg = sf == NULL ? 0 : MMC_ARG_RCA(sf->rca);
        !           646:        cmd.c_flags = SCF_CMD_AC | (sf == NULL ? SCF_RSP_R0 : SCF_RSP_R1);
        !           647:        error = sdmmc_mmc_command(sc, &cmd);
        !           648:        if (error == 0 || sf == NULL)
        !           649:                sc->sc_card = sf;
        !           650:        return error;
        !           651: }
        !           652:
        !           653: #ifdef SDMMC_IOCTL
        !           654: int
        !           655: sdmmc_ioctl(struct device *self, u_long request, caddr_t addr)
        !           656: {
        !           657:        struct sdmmc_softc *sc = (struct sdmmc_softc *)self;
        !           658:        struct sdmmc_command *ucmd;
        !           659:        struct sdmmc_command cmd;
        !           660:        void *data;
        !           661:        int error;
        !           662:
        !           663:        switch (request) {
        !           664: #ifdef SDMMC_DEBUG
        !           665:        case SDIOCSETDEBUG:
        !           666:                sdmmcdebug = (((struct bio_sdmmc_debug *)addr)->debug) & 0xff;
        !           667:                sdhcdebug = (((struct bio_sdmmc_debug *)addr)->debug >> 8) & 0xff;
        !           668:                break;
        !           669: #endif
        !           670:
        !           671:        case SDIOCEXECMMC:
        !           672:        case SDIOCEXECAPP:
        !           673:                ucmd = &((struct bio_sdmmc_command *)addr)->cmd;
        !           674:
        !           675:                /* Refuse to transfer more than 512K per command. */
        !           676:                if (ucmd->c_datalen > 524288)
        !           677:                        return ENOMEM;
        !           678:
        !           679:                /* Verify that the data buffer is safe to copy. */
        !           680:                if ((ucmd->c_datalen > 0 && ucmd->c_data == NULL) ||
        !           681:                    (ucmd->c_datalen < 1 && ucmd->c_data != NULL) ||
        !           682:                    ucmd->c_datalen < 0)
        !           683:                        return EINVAL;
        !           684:
        !           685:                bzero(&cmd, sizeof cmd);
        !           686:                cmd.c_opcode = ucmd->c_opcode;
        !           687:                cmd.c_arg = ucmd->c_arg;
        !           688:                cmd.c_flags = ucmd->c_flags;
        !           689:                cmd.c_blklen = ucmd->c_blklen;
        !           690:
        !           691:                if (ucmd->c_data) {
        !           692:                        data = malloc(ucmd->c_datalen, M_TEMP,
        !           693:                            M_WAITOK | M_CANFAIL);
        !           694:                        if (data == NULL)
        !           695:                                return ENOMEM;
        !           696:                        if (copyin(ucmd->c_data, data, ucmd->c_datalen))
        !           697:                                return EFAULT;
        !           698:
        !           699:                        cmd.c_data = data;
        !           700:                        cmd.c_datalen = ucmd->c_datalen;
        !           701:                }
        !           702:
        !           703:                if (request == SDIOCEXECMMC)
        !           704:                        error = sdmmc_mmc_command(sc, &cmd);
        !           705:                else
        !           706:                        error = sdmmc_app_command(sc, &cmd);
        !           707:                if (error && !cmd.c_error)
        !           708:                        cmd.c_error = error;
        !           709:
        !           710:                bcopy(&cmd.c_resp, ucmd->c_resp, sizeof cmd.c_resp);
        !           711:                ucmd->c_flags = cmd.c_flags;
        !           712:                ucmd->c_error = cmd.c_error;
        !           713:
        !           714:                if (ucmd->c_data && copyout(data, ucmd->c_data,
        !           715:                    ucmd->c_datalen))
        !           716:                        return EFAULT;
        !           717:
        !           718:                if (ucmd->c_data)
        !           719:                        free(data, M_TEMP);
        !           720:                break;
        !           721:
        !           722:        default:
        !           723:                return ENOTTY;
        !           724:        }
        !           725:        return 0;
        !           726: }
        !           727: #endif
        !           728:
        !           729: #ifdef SDMMC_DEBUG
        !           730: void
        !           731: sdmmc_dump_command(struct sdmmc_softc *sc, struct sdmmc_command *cmd)
        !           732: {
        !           733:        int i;
        !           734:
        !           735:        DPRINTF(1,("%s: cmd %u arg=%#x data=%#x dlen=%d flags=%#x "
        !           736:            "proc=\"%s\" (error %d)\n", DEVNAME(sc), cmd->c_opcode,
        !           737:            cmd->c_arg, cmd->c_data, cmd->c_datalen, cmd->c_flags,
        !           738:            curproc ? curproc->p_comm : "", cmd->c_error));
        !           739:
        !           740:        if (cmd->c_error || sdmmcdebug < 1)
        !           741:                return;
        !           742:
        !           743:        printf("%s: resp=", DEVNAME(sc));
        !           744:        if (ISSET(cmd->c_flags, SCF_RSP_136))
        !           745:                for (i = 0; i < sizeof cmd->c_resp; i++)
        !           746:                        printf("%02x ", ((u_char *)cmd->c_resp)[i]);
        !           747:        else if (ISSET(cmd->c_flags, SCF_RSP_PRESENT))
        !           748:                for (i = 0; i < 4; i++)
        !           749:                        printf("%02x ", ((u_char *)cmd->c_resp)[i]);
        !           750:        printf("\n");
        !           751: }
        !           752: #endif

CVSweb