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