diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/sdmmc/sdhc.c | 452 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc.c | 326 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc_io.c | 34 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc_mem.c | 41 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc_scsi.c | 336 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc_scsi.h | 14 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcchip.h | 9 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcvar.h | 55 |
8 files changed, 805 insertions, 462 deletions
diff --git a/sys/dev/sdmmc/sdhc.c b/sys/dev/sdmmc/sdhc.c index 53e111164fe..847dcc06c4c 100644 --- a/sys/dev/sdmmc/sdhc.c +++ b/sys/dev/sdmmc/sdhc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdhc.c,v 1.8 2006/07/17 20:50:58 fgsch Exp $ */ +/* $OpenBSD: sdhc.c,v 1.9 2006/07/18 04:10:35 uwe Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -27,7 +27,6 @@ #include <sys/kthread.h> #include <sys/malloc.h> #include <sys/systm.h> -#include <sys/timeout.h> #include <dev/sdmmc/sdhcreg.h> #include <dev/sdmmc/sdhcvar.h> @@ -35,8 +34,9 @@ #include <dev/sdmmc/sdmmcreg.h> #include <dev/sdmmc/sdmmcvar.h> -#define SDHC_COMMAND_TIMEOUT (hz*2) /* 2 seconds */ -#define SDHC_DATA_TIMEOUT (hz*2) /* 2 seconds */ +#define SDHC_COMMAND_TIMEOUT hz +#define SDHC_BUFFER_TIMEOUT hz +#define SDHC_TRANSFER_TIMEOUT hz struct sdhc_host { struct sdhc_softc *sc; /* host controller device */ @@ -47,18 +47,15 @@ struct sdhc_host { int maxblklen; /* maximum block length */ int flags; /* flags for this host */ u_int32_t ocr; /* OCR value from capabilities */ - struct proc *event_thread; /* event processing thread */ - struct sdmmc_command *cmd; /* current command or NULL */ - struct timeout cmd_to; /* command timeout */ u_int8_t regs[14]; /* host controller state */ + u_int16_t intr_status; /* soft interrupt status */ + u_int16_t intr_error_status; /* soft error status */ }; -#define HDEVNAME(hp) ((hp)->sdmmc->dv_xname) +#define HDEVNAME(hp) ((hp)->sc->sc_dev.dv_xname) /* flag values */ #define SHF_USE_DMA 0x0001 -#define SHF_CARD_PRESENT 0x0002 -#define SHF_CARD_ATTACHED 0x0004 #define HREAD1(hp, reg) \ (bus_space_read_1((hp)->iot, (hp)->ioh, (reg))) @@ -81,25 +78,20 @@ struct sdhc_host { #define HSET2(hp, reg, bits) \ HWRITE2((hp), (reg), HREAD2((hp), (reg)) | (bits)) -void sdhc_create_event_thread(void *); -void sdhc_event_thread(void *); -void sdhc_event_process(struct sdhc_host *); - int sdhc_host_reset(sdmmc_chipset_handle_t); u_int32_t sdhc_host_ocr(sdmmc_chipset_handle_t); int sdhc_host_maxblklen(sdmmc_chipset_handle_t); int sdhc_card_detect(sdmmc_chipset_handle_t); int sdhc_bus_power(sdmmc_chipset_handle_t, u_int32_t); int sdhc_bus_clock(sdmmc_chipset_handle_t, int); -int sdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); -int sdhc_wait_state(struct sdhc_host *, u_int32_t, u_int32_t); +void sdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); int sdhc_start_command(struct sdhc_host *, struct sdmmc_command *); -int sdhc_wait_command(struct sdhc_host *, int); -int sdhc_finish_command(struct sdhc_host *); -void sdhc_transfer_data(struct sdhc_host *); +int sdhc_wait_state(struct sdhc_host *, u_int32_t, u_int32_t); +void sdhc_soft_reset(struct sdhc_host *); +int sdhc_wait_intr(struct sdhc_host *, int, int); +void sdhc_transfer_data(struct sdhc_host *, struct sdmmc_command *); void sdhc_read_data(struct sdhc_host *, u_char *, int); void sdhc_write_data(struct sdhc_host *, u_char *, int); -void sdhc_command_timeout(void *); #ifdef SDHC_DEBUG void sdhc_dump_regs(struct sdhc_host *); @@ -166,7 +158,6 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot, hp->sc = sc; hp->iot = iot; hp->ioh = ioh; - timeout_set(&hp->cmd_to, sdhc_command_timeout, hp); /* * Reset the host controller and enable interrupts. @@ -245,85 +236,16 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot, error = 0; goto err; } - - /* - * Create the event thread that will attach and detach cards - * and perform other lengthy operations. - */ -#ifdef DO_CONFIG_PENDING - config_pending_incr(); -#endif - kthread_create_deferred(sdhc_create_event_thread, hp); return 0; err: - timeout_del(&hp->cmd_to); FREE(hp, M_DEVBUF); sc->sc_host[sc->sc_nhosts - 1] = NULL; sc->sc_nhosts--; return (error); } -void -sdhc_create_event_thread(void *arg) -{ - struct sdhc_host *hp = arg; - - /* If there's a card, attach it. */ - sdhc_event_process(hp); - - if (kthread_create(sdhc_event_thread, hp, &hp->event_thread, - HDEVNAME(hp)) != 0) - printf("%s: can't create event thread\n", HDEVNAME(hp)); - -#ifdef DO_CONFIG_PENDING - config_pending_decr(); -#endif -} - -void -sdhc_event_thread(void *arg) -{ - struct sdhc_host *hp = arg; - - for (;;) { - (void)tsleep((caddr_t)hp, PWAIT, "sdhcev", 0); - sdhc_event_process(hp); - } -} - -void -sdhc_event_process(struct sdhc_host *hp) -{ - /* If there's a card, attach it, if it went away, detach it. */ - if (sdhc_card_detect(hp)) { - if (!ISSET(hp->flags, SHF_CARD_PRESENT)) { - SET(hp->flags, SHF_CARD_PRESENT); - if (sdmmc_card_attach(hp->sdmmc) == 0) - SET(hp->flags, SHF_CARD_ATTACHED); - } - } else { - /* XXX If a command was in progress, abort it. */ - int s = splsdmmc(); - if (hp->cmd != NULL) { - timeout_del(&hp->cmd_to); - printf("%s: interrupted command %u\n", - HDEVNAME(hp), hp->cmd->c_opcode); - hp->cmd = NULL; - } - splx(s); - - if (ISSET(hp->flags, SHF_CARD_PRESENT)) { - CLR(hp->flags, SHF_CARD_PRESENT); - if (ISSET(hp->flags, SHF_CARD_ATTACHED)) { - sdmmc_card_detach(hp->sdmmc, DETACH_FORCE); - CLR(hp->flags, SHF_CARD_ATTACHED); - } - } - } -} - /* * Power hook established by or called from attachment driver. */ @@ -597,39 +519,6 @@ ret: return error; } -/* - * Send a command and data to the card and return the command response - * and data from the card. - * - * If no callback function is specified, execute the command - * synchronously; otherwise, return immediately and call the function - * from the event thread after the command has completed. - */ -int -sdhc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) -{ - struct sdhc_host *hp = sch; - int error; - - if (hp->cmd != NULL) - return EBUSY; - - error = sdhc_start_command(hp, cmd); - if (error != 0) - goto err; - if (cmd->c_done != NULL) - /* Execute this command asynchronously. */ - return error; - - error = sdhc_wait_command(hp, SCF_DONE|SCF_CMD_DONE); - if (error != 0) - goto err; - return sdhc_finish_command(hp); - err: - cmd->c_error = error; - SET(cmd->c_flags, SCF_DONE); - return sdhc_finish_command(hp); -} int sdhc_wait_state(struct sdhc_host *hp, u_int32_t mask, u_int32_t value) @@ -648,6 +537,64 @@ sdhc_wait_state(struct sdhc_host *hp, u_int32_t mask, u_int32_t value) return ETIMEDOUT; } +void +sdhc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) +{ + struct sdhc_host *hp = sch; + int error; + + /* + * Start the MMC command, or mark `cmd' as failed and return. + */ + error = sdhc_start_command(hp, cmd); + if (error != 0) { + cmd->c_error = error; + SET(cmd->c_flags, SCF_ITSDONE); + return; + } + + /* + * Wait until the command phase is done, or until the command + * is marked done for any other reason. + */ + if (!sdhc_wait_intr(hp, SDHC_COMMAND_COMPLETE, + SDHC_COMMAND_TIMEOUT)) { + cmd->c_error = ETIMEDOUT; + SET(cmd->c_flags, SCF_ITSDONE); + return; + } + + /* + * The host controller removes bits [0:7] from the response + * data (CRC) and we pass the data up unchanged to the bus + * driver (without padding). + */ + if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { + if (ISSET(cmd->c_flags, SCF_RSP_136)) { + u_char *p = (u_char *)cmd->c_resp; + int i; + + for (i = 0; i < 15; i++) + *p++ = HREAD1(hp, SDHC_RESPONSE + i); + } else + cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE); + } + + /* + * If the command has data to transfer in any direction, + * execute the transfer now. + */ + if (cmd->c_error == 0 && cmd->c_data != NULL) + sdhc_transfer_data(hp, cmd); + + /* Turn off the LED. */ + HCLR1(hp, SDHC_HOST_CTL, SDHC_LED_ON); + + DPRINTF(("%s: cmd %u done (flags=%#x error=%d)\n", + HDEVNAME(hp), cmd->c_opcode, cmd->c_flags, cmd->c_error)); + SET(cmd->c_flags, SCF_ITSDONE); +} + int sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd) { @@ -658,13 +605,9 @@ sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd) int error; int s; - DPRINTF(("%s: start cmd %u arg=%#x\n", HDEVNAME(hp), cmd->c_opcode, - cmd->c_arg)); - hp->cmd = cmd; - - /* If the card went away, finish the command immediately. */ - if (!ISSET(hp->flags, SHF_CARD_PRESENT)) - return ETIMEDOUT; + DPRINTF(("%s: start cmd %u arg=%#x proc=%#x\"%s\"\n", + HDEVNAME(hp), cmd->c_opcode, cmd->c_arg, curproc, + curproc ? curproc->p_comm : "")); /* * The maximum block length for commands should be the minimum @@ -748,97 +691,13 @@ sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd) HWRITE2(hp, SDHC_TRANSFER_MODE, mode); HWRITE2(hp, SDHC_COMMAND, command); - /* - * Start a software timeout. In the unlikely event that the - * controller's own timeout detection mechanism fails we will - * abort the transfer in software. - */ - timeout_add(&hp->cmd_to, SDHC_COMMAND_TIMEOUT); - splx(s); return 0; } -int -sdhc_wait_command(struct sdhc_host *hp, int flags) -{ - int s; - - for (;;) { - /* Return if the command was aborted. */ - if (hp->cmd == NULL) - return EIO; - - s = splsdmmc(); - - /* Return if the command has reached the awaited state. */ - if (ISSET(hp->cmd->c_flags, flags)) { - splx(s); - return 0; - } - - (void)tsleep((caddr_t)hp, PWAIT, "sdhccmd", 0); - - /* Process card events. */ - sdhc_event_process(hp); - - splx(s); - } -} - -int -sdhc_finish_command(struct sdhc_host *hp) -{ - struct sdmmc_command *cmd = hp->cmd; - int error; - - if (cmd == NULL) { - DPRINTF(("%s: finish NULL cmd\n", HDEVNAME(hp))); - return 0; - } - - /* Cancel command timeout. */ - timeout_del(&hp->cmd_to); - - /* - * The host controller removes bits [0:7] from the response - * data (CRC) and we pass the data up unchanged to the bus - * driver (without padding). - */ - if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { - if (ISSET(cmd->c_flags, SCF_RSP_136)) { - u_char *p = (u_char *)cmd->c_resp; - int i; - - for (i = 0; i < 15; i++) - *p++ = HREAD1(hp, SDHC_RESPONSE + i); - } else - cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE); - } - - if (cmd->c_error == 0 && cmd->c_data != NULL) { - timeout_add(&hp->cmd_to, SDHC_DATA_TIMEOUT); - sdhc_transfer_data(hp); - } - - /* Turn off the LED. */ - HCLR1(hp, SDHC_HOST_CTL, SDHC_LED_ON); - - error = cmd->c_error; - hp->cmd = NULL; - - SET(cmd->c_flags, SCF_DONE); - DPRINTF(("%s: cmd %u done (flags=%#x error=%d)\n", - HDEVNAME(hp), cmd->c_opcode, cmd->c_flags, error)); - if (cmd->c_done != NULL) - cmd->c_done(hp->sdmmc, cmd); - return error; -} - void -sdhc_transfer_data(struct sdhc_host *hp) +sdhc_transfer_data(struct sdhc_host *hp, struct sdmmc_command *cmd) { - struct sdmmc_command *cmd = hp->cmd; u_char *datap = cmd->c_data; int i, datalen; int mask; @@ -849,15 +708,17 @@ sdhc_transfer_data(struct sdhc_host *hp) error = 0; datalen = cmd->c_datalen; - DPRINTF(("%s: resp=%#x ", HDEVNAME(hp), MMC_R1(cmd->c_resp))); - DPRINTF(("datalen %u\n", datalen)); + DPRINTF(("%s: resp=%#x datalen %u\n", HDEVNAME(hp), + MMC_R1(cmd->c_resp), datalen)); + while (datalen > 0) { - error = sdhc_wait_command(hp, SCF_DONE|SCF_BUF_READY); - if (error != 0) + if (!sdhc_wait_intr(hp, SDHC_BUFFER_READ_READY| + SDHC_BUFFER_WRITE_READY, SDHC_BUFFER_TIMEOUT)) { + error = ETIMEDOUT; break; + } - error = sdhc_wait_state(hp, mask, mask); - if (error != 0) + if ((error = sdhc_wait_state(hp, mask, mask)) != 0) break; i = MIN(datalen, cmd->c_blklen); @@ -868,18 +729,15 @@ sdhc_transfer_data(struct sdhc_host *hp) datap += i; datalen -= i; - CLR(cmd->c_flags, SCF_BUF_READY); } - if (error == 0) - error = sdhc_wait_command(hp, SCF_DONE|SCF_XFR_DONE); - - timeout_del(&hp->cmd_to); + if (error == 0 && !sdhc_wait_intr(hp, SDHC_TRANSFER_COMPLETE, + SDHC_TRANSFER_TIMEOUT)) + error = ETIMEDOUT; - if (cmd->c_error == 0) { + if (error != 0) cmd->c_error = error; - SET(cmd->c_flags, SCF_DONE); - } + SET(cmd->c_flags, SCF_ITSDONE); DPRINTF(("%s: data transfer done (error=%d)\n", HDEVNAME(hp), cmd->c_error)); @@ -922,31 +780,47 @@ sdhc_write_data(struct sdhc_host *hp, u_char *datap, int datalen) } } +/* Prepare for another command. */ void -sdhc_command_timeout(void *arg) +sdhc_soft_reset(struct sdhc_host *hp) { - struct sdhc_host *hp = arg; - struct sdmmc_command *cmd = hp->cmd; + DPRINTF(("%s: software reset\n", HDEVNAME(hp))); + HWRITE1(hp, SDHC_SOFTWARE_RESET, SDHC_RESET_DAT|SDHC_RESET_CMD); + sdmmc_delay(10000); +} + +int +sdhc_wait_intr(struct sdhc_host *hp, int mask, int timo) +{ + int status; int s; - if (cmd == NULL) - return; + mask |= SDHC_ERROR_INTERRUPT; s = splsdmmc(); - if (!ISSET(cmd->c_flags, SCF_DONE)) { - DPRINTF(("%s: timeout cmd %u, resetting...\n", - HDEVNAME(hp), cmd->c_opcode)); - cmd->c_error = ETIMEDOUT; - SET(cmd->c_flags, SCF_DONE); - HWRITE1(hp, SDHC_SOFTWARE_RESET, SDHC_RESET_DAT| - SDHC_RESET_CMD); - timeout_add(&hp->cmd_to, hz/2); - } else { - DPRINTF(("%s: timeout cmd %u, resetting...done\n", - HDEVNAME(hp), cmd->c_opcode)); - wakeup(hp); + status = hp->intr_status & mask; + while (status == 0) { + if (tsleep(&hp->intr_status, PWAIT, "hcintr", timo) + == EWOULDBLOCK) { + status |= SDHC_ERROR_INTERRUPT; + break; + } + status = hp->intr_status & mask; + } + hp->intr_status &= ~status; + + DPRINTF(("%s: intr status %#x error %#x\n", HDEVNAME(hp), status, + hp->intr_error_status)); + + /* Command timeout has higher priority than command complete. */ + if (ISSET(status, SDHC_ERROR_INTERRUPT)) { + hp->intr_error_status = 0; + sdhc_soft_reset(hp); + status = 0; } + splx(s); + return status; } /* @@ -956,8 +830,8 @@ int sdhc_intr(void *arg) { struct sdhc_softc *sc = arg; - int done = 0; int host; + int done = 0; /* We got an interrupt, but we don't know from which slot. */ for (host = 0; host < sc->sc_nhosts; host++) { @@ -967,78 +841,62 @@ sdhc_intr(void *arg) if (hp == NULL) continue; + /* Acknowledge interrupts we are about to handle. */ status = HREAD2(hp, SDHC_NINTR_STATUS); + HWRITE2(hp, SDHC_NINTR_STATUS, status); + DPRINTF(("%s: interrupt status=%b\n", HDEVNAME(hp), + status, SDHC_NINTR_STATUS_BITS)); + if (!ISSET(status, SDHC_NINTR_STATUS_MASK)) continue; - /* Clear interrupts we are about to handle. */ - HWRITE2(hp, SDHC_NINTR_STATUS, status); -#ifdef SDHC_DEBUG - printf("%s: interrupt status=%b\n", HDEVNAME(hp), - status, SDHC_NINTR_STATUS_BITS); -#endif + /* Claim this interrupt. */ + done = 1; /* - * Wake up the event thread to service the interrupt(s). + * Service error interrupts. */ - if (ISSET(status, SDHC_BUFFER_READ_READY| - SDHC_BUFFER_WRITE_READY)) { - if (hp->cmd != NULL && - !ISSET(hp->cmd->c_flags, SCF_DONE)) { - SET(hp->cmd->c_flags, SCF_BUF_READY); - wakeup(hp); - } - done++; - } - if (ISSET(status, SDHC_COMMAND_COMPLETE)) { - if (hp->cmd != NULL && - !ISSET(hp->cmd->c_flags, SCF_DONE)) { - SET(hp->cmd->c_flags, SCF_CMD_DONE); - wakeup(hp); - } - done++; - } - if (ISSET(status, SDHC_TRANSFER_COMPLETE)) { - if (hp->cmd != NULL && - !ISSET(hp->cmd->c_flags, SCF_DONE)) { - SET(hp->cmd->c_flags, SCF_XFR_DONE); - wakeup(hp); - } - done++; - } - if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION)) { - wakeup(hp); - done++; - } - if (ISSET(status, SDHC_ERROR_INTERRUPT)) { u_int16_t error; + /* Acknowledge error interrupts. */ error = HREAD2(hp, SDHC_EINTR_STATUS); HWRITE2(hp, SDHC_EINTR_STATUS, error); - DPRINTF(("%s: error interrupt, status=%b\n", HDEVNAME(hp), error, SDHC_EINTR_STATUS_BITS)); - /* XXX command timeout has higher priority - * than command complete */ if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR| - SDHC_DATA_TIMEOUT_ERROR) && hp->cmd != NULL && - !ISSET(hp->cmd->c_flags, SCF_DONE)) { - hp->cmd->c_error = ETIMEDOUT; - SET(hp->cmd->c_flags, SCF_DONE); - /* XXX can this reset be avoided? */ - HWRITE1(hp, SDHC_SOFTWARE_RESET, - SDHC_RESET_DAT|SDHC_RESET_CMD); - timeout_add(&hp->cmd_to, hz/2); + SDHC_DATA_TIMEOUT_ERROR)) { + hp->intr_error_status |= error; + hp->intr_status |= status; + wakeup(&hp->intr_status); } - done++; } + /* + * Wake up the sdmmc event thread to scan for cards. + */ + if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION)) + sdmmc_needs_discover(hp->sdmmc); + + /* + * Wake up the blocking process to service command + * related interrupt(s). + */ + if (ISSET(status, SDHC_BUFFER_READ_READY| + SDHC_BUFFER_WRITE_READY|SDHC_COMMAND_COMPLETE| + SDHC_TRANSFER_COMPLETE)) { + hp->intr_status |= status; + wakeup(&hp->intr_status); + } + + /* + * Service SD card interrupts. + */ if (ISSET(status, SDHC_CARD_INTERRUPT)) { + printf("%s: card interrupt\n", HDEVNAME(hp)); HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); /* XXX service card interrupt */ - printf("%s: card interrupt\n", HDEVNAME(hp)); HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); } } diff --git a/sys/dev/sdmmc/sdmmc.c b/sys/dev/sdmmc/sdmmc.c index 3b89507cb08..fa8890e7c3f 100644 --- a/sys/dev/sdmmc/sdmmc.c +++ b/sys/dev/sdmmc/sdmmc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc.c,v 1.6 2006/06/29 01:35:37 uwe Exp $ */ +/* $OpenBSD: sdmmc.c,v 1.7 2006/07/18 04:10:35 uwe Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -25,6 +25,7 @@ #include <sys/param.h> #include <sys/device.h> #include <sys/kernel.h> +#include <sys/kthread.h> #include <sys/malloc.h> #include <sys/proc.h> #include <sys/systm.h> @@ -40,11 +41,19 @@ int sdmmc_match(struct device *, void *, void *); void sdmmc_attach(struct device *, struct device *, void *); +int sdmmc_detach(struct device *, int); +void sdmmc_create_thread(void *); +void sdmmc_task_thread(void *); +void sdmmc_discover_task(void *); +void sdmmc_card_attach(struct sdmmc_softc *); +void sdmmc_card_detach(struct sdmmc_softc *, int); int sdmmc_enable(struct sdmmc_softc *); void sdmmc_disable(struct sdmmc_softc *); int sdmmc_scan(struct sdmmc_softc *); int sdmmc_init(struct sdmmc_softc *); -int sdmmc_set_bus_width(struct sdmmc_softc *, struct sdmmc_function *); +int sdmmc_set_bus_width(struct sdmmc_function *); + +#define DEVNAME(sc) SDMMCDEVNAME(sc) #ifdef SDMMC_DEBUG #define DPRINTF(s) printf s @@ -53,7 +62,7 @@ int sdmmc_set_bus_width(struct sdmmc_softc *, struct sdmmc_function *); #endif struct cfattach sdmmc_ca = { - sizeof(struct sdmmc_softc), sdmmc_match, sdmmc_attach + sizeof(struct sdmmc_softc), sdmmc_match, sdmmc_attach, sdmmc_detach }; struct cfdriver sdmmc_cd = { @@ -81,25 +90,150 @@ sdmmc_attach(struct device *parent, struct device *self, void *aux) sc->sch = saa->sch; SIMPLEQ_INIT(&sc->sf_head); + TAILQ_INIT(&sc->sc_tskq); + sdmmc_init_task(&sc->sc_discover_task, sdmmc_discover_task, sc); + lockinit(&sc->sc_lock, PRIBIO, DEVNAME(sc), 0, LK_CANRECURSE); + + /* + * Create the event thread that will attach and detach cards + * and perform other lengthy operations. + */ +#ifdef DO_CONFIG_PENDING + config_pending_incr(); +#endif + kthread_create_deferred(sdmmc_create_thread, sc); +} + +int +sdmmc_detach(struct device *self, int flags) +{ + struct sdmmc_softc *sc = (struct sdmmc_softc *)self; + + sc->sc_dying = 1; + while (sc->sc_task_thread != NULL) { + wakeup(&sc->sc_tskq); + tsleep(sc, PWAIT, "mmcdie", 0); + } + return 0; +} + +void +sdmmc_create_thread(void *arg) +{ + struct sdmmc_softc *sc = arg; + + if (kthread_create(sdmmc_task_thread, sc, &sc->sc_task_thread, + "%s", DEVNAME(sc)) != 0) + printf("%s: can't create task thread\n", DEVNAME(sc)); + +#ifdef DO_CONFIG_PENDING + config_pending_decr(); +#endif +} + +void +sdmmc_task_thread(void *arg) +{ + struct sdmmc_softc *sc = arg; + struct sdmmc_task *task; + int s; + + sdmmc_needs_discover(&sc->sc_dev); + + s = splsdmmc(); + while (!sc->sc_dying) { + for (task = TAILQ_FIRST(&sc->sc_tskq); task != NULL; + task = TAILQ_FIRST(&sc->sc_tskq)) { + splx(s); + sdmmc_del_task(task); + task->func(task->arg); + s = splsdmmc(); + } + tsleep(&sc->sc_tskq, PWAIT, "mmctsk", 0); + } + splx(s); + + if (ISSET(sc->sc_flags, SMF_CARD_PRESENT)) + sdmmc_card_detach(sc, DETACH_FORCE); + + sc->sc_task_thread = NULL; + wakeup(sc); + kthread_exit(0); +} + +void +sdmmc_add_task(struct sdmmc_softc *sc, struct sdmmc_task *task) +{ + int s; + + s = splsdmmc(); + TAILQ_INSERT_TAIL(&sc->sc_tskq, task, next); + task->onqueue = 1; + task->sc = sc; + wakeup(&sc->sc_tskq); + splx(s); +} + +void +sdmmc_del_task(struct sdmmc_task *task) +{ + struct sdmmc_softc *sc = task->sc; + int s; + + if (sc == NULL) + return; + + s = splsdmmc(); + task->sc = NULL; + task->onqueue = 0; + TAILQ_REMOVE(&sc->sc_tskq, task, next); + splx(s); +} + +void +sdmmc_needs_discover(struct device *self) +{ + struct sdmmc_softc *sc = (struct sdmmc_softc *)self; + + if (!sdmmc_task_pending(&sc->sc_discover_task)) + sdmmc_add_task(sc, &sc->sc_discover_task); +} + +void +sdmmc_discover_task(void *arg) +{ + struct sdmmc_softc *sc = arg; + + if (sdmmc_chip_card_detect(sc->sct, sc->sch)) { + if (!ISSET(sc->sc_flags, SMF_CARD_PRESENT)) { + SET(sc->sc_flags, SMF_CARD_PRESENT); + sdmmc_card_attach(sc); + } + } else { + if (ISSET(sc->sc_flags, SMF_CARD_PRESENT)) { + CLR(sc->sc_flags, SMF_CARD_PRESENT); + sdmmc_card_detach(sc, DETACH_FORCE); + } + } } /* - * Called from the host driver when a card, or a stack of cards are - * inserted. Return zero if any card drivers have been attached. + * Called from process context when a card is present. */ -int -sdmmc_card_attach(struct device *dev) +void +sdmmc_card_attach(struct sdmmc_softc *sc) { - struct sdmmc_softc *sc = (struct sdmmc_softc *)dev; + DPRINTF(("%s: attach card\n", DEVNAME(sc))); - DPRINTF(("%s: attach card\n", SDMMCDEVNAME(sc))); + SDMMC_LOCK(sc); + CLR(sc->sc_flags, SMF_CARD_ATTACHED); /* * Power up the card (or card stack). */ if (sdmmc_enable(sc) != 0) { - printf("%s: can't enable card\n", SDMMCDEVNAME(sc)); - return 1; + printf("%s: can't enable card\n", DEVNAME(sc)); + goto err; } /* @@ -107,18 +241,16 @@ sdmmc_card_attach(struct device *dev) * allocating a sdmmc_function structure for each. */ if (sdmmc_scan(sc) != 0) { - printf("%s: no functions\n", SDMMCDEVNAME(sc)); - sdmmc_card_detach(dev, DETACH_FORCE); - return 1; + printf("%s: no functions\n", DEVNAME(sc)); + goto err; } /* * Initialize the I/O functions and memory cards. */ if (sdmmc_init(sc) != 0) { - printf("%s: init failed\n", SDMMCDEVNAME(sc)); - sdmmc_card_detach(dev, DETACH_FORCE); - return 1; + printf("%s: init failed\n", DEVNAME(sc)); + goto err; } /* Attach SCSI emulation for memory cards. */ @@ -129,31 +261,39 @@ sdmmc_card_attach(struct device *dev) if (ISSET(sc->sc_flags, SMF_IO_MODE)) sdmmc_io_attach(sc); - return 0; + SET(sc->sc_flags, SMF_CARD_ATTACHED); + SDMMC_UNLOCK(sc); + return; +err: + sdmmc_card_detach(sc, DETACH_FORCE); + SDMMC_UNLOCK(sc); } /* - * Called from host driver with DETACH_* flags from <sys/device.h> + * Called from process context with DETACH_* flags from <sys/device.h> * when cards are gone. */ void -sdmmc_card_detach(struct device *dev, int flags) +sdmmc_card_detach(struct sdmmc_softc *sc, int flags) { - struct sdmmc_softc *sc = (struct sdmmc_softc *)dev; struct sdmmc_function *sf, *sfnext; - DPRINTF(("%s: detach card\n", SDMMCDEVNAME(sc))); + DPRINTF(("%s: detach card\n", DEVNAME(sc))); - /* Power down. */ - sdmmc_disable(sc); + if (ISSET(sc->sc_flags, SMF_CARD_ATTACHED)) { + /* Detach I/O function drivers. */ + if (ISSET(sc->sc_flags, SMF_IO_MODE)) + sdmmc_io_detach(sc); - /* Detach I/O function drivers. */ - if (ISSET(sc->sc_flags, SMF_IO_MODE)) - sdmmc_io_detach(sc); + /* Detach the SCSI emulation for memory cards. */ + if (ISSET(sc->sc_flags, SMF_MEM_MODE)) + sdmmc_scsi_detach(sc); - /* Detach the SCSI emulation for memory cards. */ - if (ISSET(sc->sc_flags, SMF_MEM_MODE)) - sdmmc_scsi_detach(sc); + CLR(sc->sc_flags, SMF_CARD_ATTACHED); + } + + /* Power down. */ + sdmmc_disable(sc); /* Free all sdmmc_function structures. */ for (sf = SIMPLEQ_FIRST(&sc->sf_head); sf != NULL; sf = sfnext) { @@ -178,7 +318,7 @@ sdmmc_enable(struct sdmmc_softc *sc) host_ocr = sdmmc_chip_host_ocr(sc->sct, sc->sch); error = sdmmc_chip_bus_power(sc->sct, sc->sch, host_ocr); if (error != 0) { - printf("%s: can't supply bus power\n", SDMMCDEVNAME(sc)); + printf("%s: can't supply bus power\n", DEVNAME(sc)); goto err; } @@ -187,7 +327,7 @@ sdmmc_enable(struct sdmmc_softc *sc) */ error = sdmmc_chip_bus_clock(sc->sct, sc->sch, SDMMC_SDCLK_400KHZ); if (error != 0) { - printf("%s: can't supply clock\n", SDMMCDEVNAME(sc)); + printf("%s: can't supply clock\n", DEVNAME(sc)); goto err; } @@ -227,6 +367,32 @@ sdmmc_disable(struct sdmmc_softc *sc) (void)sdmmc_chip_bus_power(sc->sct, sc->sch, 0); } +/* + * Set the lowest bus voltage supported by the card and the host. + */ +int +sdmmc_set_bus_power(struct sdmmc_softc *sc, u_int32_t host_ocr, + u_int32_t card_ocr) +{ + u_int32_t bit; + + /* Mask off unsupported voltage levels and select the lowest. */ + DPRINTF(("%s: host_ocr=%x ", DEVNAME(sc), host_ocr)); + host_ocr &= card_ocr; + for (bit = 4; bit < 23; bit++) { + if (ISSET(host_ocr, 1<<bit)) { + host_ocr &= 3<<bit; + break; + } + } + DPRINTF(("card_ocr=%x new_ocr=%x\n", card_ocr, host_ocr)); + + if (host_ocr == 0 || + sdmmc_chip_bus_power(sc->sct, sc->sch, host_ocr) != 0) + return 1; + return 0; +} + struct sdmmc_function * sdmmc_function_alloc(struct sdmmc_softc *sc) { @@ -266,7 +432,7 @@ sdmmc_scan(struct sdmmc_softc *sc) /* There should be at least one function now. */ if (SIMPLEQ_EMPTY(&sc->sf_head)) { - printf("%s: can't identify card\n", SDMMCDEVNAME(sc)); + printf("%s: can't identify card\n", DEVNAME(sc)); return 1; } return 0; @@ -285,11 +451,11 @@ sdmmc_init(struct sdmmc_softc *sc) SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) { if (ISSET(sc->sc_flags, SMF_IO_MODE) && sdmmc_io_init(sc, sf) != 0) - printf("%s: i/o init failed\n", SDMMCDEVNAME(sc)); + printf("%s: i/o init failed\n", DEVNAME(sc)); if (ISSET(sc->sc_flags, SMF_MEM_MODE) && sdmmc_mem_init(sc, sf) != 0) - printf("%s: mem init failed\n", SDMMCDEVNAME(sc)); + printf("%s: mem init failed\n", DEVNAME(sc)); } /* Any good functions left after initialization? */ @@ -307,63 +473,64 @@ sdmmc_delay(u_int usecs) int ticks = usecs / (1000000 / hz); if (ticks > 0) - (void)tsleep(&sdmmc_delay, PWAIT, "sdwait", ticks); + tsleep(&sdmmc_delay, PWAIT, "mmcdly", ticks); else delay(usecs); } -/* - * Set the lowest bus voltage supported by the card and the host. - */ -int -sdmmc_set_bus_power(struct sdmmc_softc *sc, u_int32_t host_ocr, - u_int32_t card_ocr) -{ - u_int32_t bit; - - /* Mask off unsupported voltage levels and select the lowest. */ - DPRINTF(("%s: host_ocr=%x ", SDMMCDEVNAME(sc), host_ocr)); - host_ocr &= card_ocr; - for (bit = 4; bit < 23; bit++) { - if (ISSET(host_ocr, 1<<bit)) { - host_ocr &= 3<<bit; - break; - } - } - DPRINTF(("card_ocr=%x new_ocr=%x\n", card_ocr, host_ocr)); - - if (host_ocr == 0 || - sdmmc_chip_bus_power(sc->sct, sc->sch, host_ocr) != 0) - return 1; - return 0; -} - int sdmmc_app_command(struct sdmmc_softc *sc, struct sdmmc_command *cmd) { struct sdmmc_command acmd; int error; + SDMMC_LOCK(sc); + bzero(&acmd, sizeof acmd); acmd.c_opcode = MMC_APP_CMD; acmd.c_arg = 0; acmd.c_flags = SCF_CMD_AC | SCF_RSP_R1; error = sdmmc_mmc_command(sc, &acmd); - if (error != 0) + if (error != 0) { + SDMMC_UNLOCK(sc); return error; + } - if (!ISSET(MMC_R1(acmd.c_resp), MMC_R1_APP_CMD)) + if (!ISSET(MMC_R1(acmd.c_resp), MMC_R1_APP_CMD)) { /* Card does not support application commands. */ + SDMMC_UNLOCK(sc); return ENODEV; + } - return sdmmc_mmc_command(sc, cmd); + error = sdmmc_mmc_command(sc, cmd); + SDMMC_UNLOCK(sc); + return error; } +/* + * Execute MMC command and data transfers. All interactions with the + * host controller to complete the command happen in the context of + * the current process. + */ int sdmmc_mmc_command(struct sdmmc_softc *sc, struct sdmmc_command *cmd) { - return sdmmc_chip_exec_command(sc->sct, sc->sch, cmd); + int error; + + SDMMC_LOCK(sc); + + sdmmc_chip_exec_command(sc->sct, sc->sch, cmd); + + DPRINTF(("%s: mmc cmd=%p opcode=%d proc=\"%s\" (error %d)\n", + DEVNAME(sc), cmd, cmd->c_opcode, curproc ? curproc->p_comm : + "", cmd->c_error)); + + error = cmd->c_error; + wakeup(cmd); + + SDMMC_UNLOCK(sc); + return error; } /* @@ -413,23 +580,31 @@ sdmmc_set_relative_addr(struct sdmmc_softc *sc, * Switch card and host to the maximum supported bus width. */ int -sdmmc_set_bus_width(struct sdmmc_softc *sc, struct sdmmc_function *sf) +sdmmc_set_bus_width(struct sdmmc_function *sf) { + struct sdmmc_softc *sc = sf->sc; struct sdmmc_command cmd; int error; - if (!ISSET(sc->sc_flags, SMF_SD_MODE)) + SDMMC_LOCK(sc); + + if (!ISSET(sc->sc_flags, SMF_SD_MODE)) { + SDMMC_UNLOCK(sc); return EOPNOTSUPP; + } - if ((error = sdmmc_select_card(sc, sf)) != 0) + if ((error = sdmmc_select_card(sc, sf)) != 0) { + SDMMC_UNLOCK(sc); return error; + } bzero(&cmd, sizeof cmd); cmd.c_opcode = SD_APP_SET_BUS_WIDTH; cmd.c_arg = SD_ARG_BUS_WIDTH_4; cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1; - - return sdmmc_app_command(sc, &cmd); + error = sdmmc_app_command(sc, &cmd); + SDMMC_UNLOCK(sc); + return error; } int @@ -438,8 +613,7 @@ sdmmc_select_card(struct sdmmc_softc *sc, struct sdmmc_function *sf) struct sdmmc_command cmd; int error; - if (sc->sc_card == sf || - (sc->sc_card != NULL && sf != NULL && + if (sc->sc_card == sf || (sf && sc->sc_card && sc->sc_card->rca == sf->rca)) { sc->sc_card = sf; return 0; @@ -469,7 +643,7 @@ sdmmc_decode_csd(struct sdmmc_softc *sc, sdmmc_response resp, csd->csdver = SD_CSD_CSDVER(resp); if (csd->csdver != SD_CSD_CSDVER_1_0) { printf("%s: unknown SD CSD structure version 0x%x\n", - SDMMCDEVNAME(sc), csd->csdver); + DEVNAME(sc), csd->csdver); return 1; } @@ -480,7 +654,7 @@ sdmmc_decode_csd(struct sdmmc_softc *sc, sdmmc_response resp, if (csd->csdver != MMC_CSD_CSDVER_1_0 && csd->csdver != MMC_CSD_CSDVER_2_0) { printf("%s: unknown MMC CSD structure version 0x%x\n", - SDMMCDEVNAME(sc), csd->csdver); + DEVNAME(sc), csd->csdver); return 1; } @@ -530,7 +704,7 @@ sdmmc_decode_cid(struct sdmmc_softc *sc, sdmmc_response resp, break; default: printf("%s: unknown MMC version %d\n", - SDMMCDEVNAME(sc), sf->csd.mmcver); + DEVNAME(sc), sf->csd.mmcver); return 1; } } diff --git a/sys/dev/sdmmc/sdmmc_io.c b/sys/dev/sdmmc/sdmmc_io.c index 1ba852bb4f2..50fdf5034a8 100644 --- a/sys/dev/sdmmc/sdmmc_io.c +++ b/sys/dev/sdmmc/sdmmc_io.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc_io.c,v 1.5 2006/06/19 21:14:30 miod Exp $ */ +/* $OpenBSD: sdmmc_io.c,v 1.6 2006/07/18 04:10:35 uwe Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -178,23 +178,29 @@ sdmmc_io_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) void sdmmc_io_function_enable(struct sdmmc_function *sf) { - struct sdmmc_function *sf0 = sf->sc->sc_fn0; + struct sdmmc_softc *sc = sf->sc; + struct sdmmc_function *sf0 = sc->sc_fn0; u_int8_t rv; + SDMMC_LOCK(sc); rv = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_ENABLE); rv |= (1<<sf->number); sdmmc_io_write_1(sf0, SD_IO_CCCR_FN_ENABLE, rv); + SDMMC_UNLOCK(sc); } void sdmmc_io_function_disable(struct sdmmc_function *sf) { - struct sdmmc_function *sf0 = sf->sc->sc_fn0; + struct sdmmc_softc *sc = sf->sc; + struct sdmmc_function *sf0 = sc->sc_fn0; u_int8_t rv; + SDMMC_LOCK(sc); rv = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_ENABLE); rv &= ~(1<<sf->number); sdmmc_io_write_1(sf0, SD_IO_CCCR_FN_ENABLE, rv); + SDMMC_UNLOCK(sc); } void @@ -289,9 +295,13 @@ sdmmc_io_rw_direct(struct sdmmc_softc *sc, struct sdmmc_function *sf, struct sdmmc_command cmd; int error; + SDMMC_LOCK(sc); + /* Make sure the card is selected. */ - if ((error = sdmmc_select_card(sc, sf)) != 0) + if ((error = sdmmc_select_card(sc, sf)) != 0) { + SDMMC_UNLOCK(sc); return error; + } arg |= ((sf == NULL ? 0 : sf->number) & SD_ARG_CMD52_FUNC_MASK) << SD_ARG_CMD52_FUNC_SHIFT; @@ -307,6 +317,8 @@ sdmmc_io_rw_direct(struct sdmmc_softc *sc, struct sdmmc_function *sf, error = sdmmc_mmc_command(sc, &cmd); *datap = SD_R5_DATA(cmd.c_resp); + + SDMMC_UNLOCK(sc); return error; } @@ -317,9 +329,13 @@ sdmmc_io_rw_extended(struct sdmmc_softc *sc, struct sdmmc_function *sf, struct sdmmc_command cmd; int error; + SDMMC_LOCK(sc); + /* Make sure the card is selected. */ - if ((error = sdmmc_select_card(sc, sf)) != 0) + if ((error = sdmmc_select_card(sc, sf)) != 0) { + SDMMC_UNLOCK(sc); return error; + } arg |= ((sf == NULL ? 0 : sf->number) & SD_ARG_CMD53_FUNC_MASK) << SD_ARG_CMD53_FUNC_SHIFT; @@ -339,7 +355,9 @@ sdmmc_io_rw_extended(struct sdmmc_softc *sc, struct sdmmc_function *sf, if (!ISSET(arg, SD_ARG_CMD53_WRITE)) cmd.c_flags |= SCF_CMD_READ; - return sdmmc_mmc_command(sc, &cmd); + error = sdmmc_mmc_command(sc, &cmd); + SDMMC_UNLOCK(sc); + return error; } u_int8_t @@ -431,6 +449,8 @@ sdmmc_io_send_op_cond(struct sdmmc_softc *sc, u_int32_t ocr, u_int32_t *ocrp) int error; int i; + SDMMC_LOCK(sc); + /* * If we change the OCR value, retry the command until the OCR * we receive in response has the "CARD BUSY" bit set, meaning @@ -453,5 +473,7 @@ sdmmc_io_send_op_cond(struct sdmmc_softc *sc, u_int32_t ocr, u_int32_t *ocrp) } if (error == 0 && ocrp != NULL) *ocrp = MMC_R4(cmd.c_resp); + + SDMMC_UNLOCK(sc); return error; } diff --git a/sys/dev/sdmmc/sdmmc_mem.c b/sys/dev/sdmmc/sdmmc_mem.c index c8cdaaa1e5b..a3daba6411d 100644 --- a/sys/dev/sdmmc/sdmmc_mem.c +++ b/sys/dev/sdmmc/sdmmc_mem.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc_mem.c,v 1.4 2006/06/29 01:40:51 uwe Exp $ */ +/* $OpenBSD: sdmmc_mem.c,v 1.5 2006/07/18 04:10:35 uwe Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -59,7 +59,6 @@ sdmmc_mem_enable(struct sdmmc_softc *sc) */ mmc_mode: if (sdmmc_mem_send_op_cond(sc, 0, &card_ocr) != 0) { - DPRINTF(("flags %x\n", sc->sc_flags)); if (ISSET(sc->sc_flags, SMF_SD_MODE) && !ISSET(sc->sc_flags, SMF_IO_MODE)) { /* Not a SD card, switch to MMC mode. */ @@ -213,10 +212,14 @@ sdmmc_mem_scan(struct sdmmc_softc *sc) int sdmmc_mem_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) { + int error = 0; + + SDMMC_LOCK(sc); if (sdmmc_select_card(sc, sf) != 0 || sdmmc_mem_set_blocklen(sc, sf) != 0) - return 1; - return 0; + error = 1; + SDMMC_UNLOCK(sc); + return error; } /* @@ -230,6 +233,8 @@ sdmmc_mem_send_op_cond(struct sdmmc_softc *sc, u_int32_t ocr, int error; int i; + SDMMC_LOCK(sc); + /* * If we change the OCR value, retry the command until the OCR * we receive in response has the "CARD BUSY" bit set, meaning @@ -257,6 +262,8 @@ sdmmc_mem_send_op_cond(struct sdmmc_softc *sc, u_int32_t ocr, } if (error == 0 && ocrp != NULL) *ocrp = MMC_R3(cmd.c_resp); + + SDMMC_UNLOCK(sc); return error; } @@ -280,14 +287,17 @@ sdmmc_mem_set_blocklen(struct sdmmc_softc *sc, struct sdmmc_function *sf) } int -sdmmc_mem_read_block(struct sdmmc_softc *sc, struct sdmmc_function *sf, - int blkno, u_char *data, size_t datalen) +sdmmc_mem_read_block(struct sdmmc_function *sf, int blkno, u_char *data, + size_t datalen) { + struct sdmmc_softc *sc = sf->sc; struct sdmmc_command cmd; int error; + SDMMC_LOCK(sc); + if ((error = sdmmc_select_card(sc, sf)) != 0) - return error; + goto err; bzero(&cmd, sizeof cmd); cmd.c_data = data; @@ -300,7 +310,7 @@ sdmmc_mem_read_block(struct sdmmc_softc *sc, struct sdmmc_function *sf, error = sdmmc_mmc_command(sc, &cmd); if (error != 0) - return error; + goto err; do { bzero(&cmd, sizeof cmd); @@ -313,18 +323,23 @@ sdmmc_mem_read_block(struct sdmmc_softc *sc, struct sdmmc_function *sf, /* XXX time out */ } while (!ISSET(MMC_R1(cmd.c_resp), MMC_R1_READY_FOR_DATA)); +err: + SDMMC_UNLOCK(sc); return error; } int -sdmmc_mem_write_block(struct sdmmc_softc *sc, struct sdmmc_function *sf, - int blkno, u_char *data, size_t datalen) +sdmmc_mem_write_block(struct sdmmc_function *sf, int blkno, u_char *data, + size_t datalen) { + struct sdmmc_softc *sc = sf->sc; struct sdmmc_command cmd; int error; + SDMMC_LOCK(sc); + if ((error = sdmmc_select_card(sc, sf)) != 0) - return error; + goto err; bzero(&cmd, sizeof cmd); cmd.c_data = data; @@ -337,7 +352,7 @@ sdmmc_mem_write_block(struct sdmmc_softc *sc, struct sdmmc_function *sf, error = sdmmc_mmc_command(sc, &cmd); if (error != 0) - return error; + goto err; do { bzero(&cmd, sizeof cmd); @@ -350,5 +365,7 @@ sdmmc_mem_write_block(struct sdmmc_softc *sc, struct sdmmc_function *sf, /* XXX time out */ } while (!ISSET(MMC_R1(cmd.c_resp), MMC_R1_READY_FOR_DATA)); +err: + SDMMC_UNLOCK(sc); return error; } diff --git a/sys/dev/sdmmc/sdmmc_scsi.c b/sys/dev/sdmmc/sdmmc_scsi.c index 447617112ef..4b8a57ab404 100644 --- a/sys/dev/sdmmc/sdmmc_scsi.c +++ b/sys/dev/sdmmc/sdmmc_scsi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc_scsi.c,v 1.3 2006/06/01 21:53:41 uwe Exp $ */ +/* $OpenBSD: sdmmc_scsi.c,v 1.4 2006/07/18 04:10:35 uwe Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -16,11 +16,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* A SCSI bus emulation to access SD/MMC memory cards. */ +/* A SCSI adapter emulation to access SD/MMC memory cards */ #include <sys/param.h> #include <sys/buf.h> +#include <sys/kernel.h> #include <sys/malloc.h> +#include <sys/proc.h> #include <sys/systm.h> #include <scsi/scsi_all.h> @@ -33,12 +35,57 @@ #define SDMMC_SCSIID_HOST 0x00 #define SDMMC_SCSIID_MAX 0x0f +#define SDMMC_SCSI_MAXCMDS 8 + +struct sdmmc_scsi_target { + struct sdmmc_function *card; +}; + +struct sdmmc_ccb { + struct sdmmc_scsi_softc *ccb_scbus; + struct scsi_xfer *ccb_xs; + int ccb_flags; +#define SDMMC_CCB_F_ERR 0x0001 + void (*ccb_done)(struct sdmmc_ccb *); + u_int32_t ccb_blockno; + u_int32_t ccb_blockcnt; + volatile enum { + SDMMC_CCB_FREE, + SDMMC_CCB_READY, + SDMMC_CCB_QUEUED + } ccb_state; + struct sdmmc_command ccb_cmd; + struct sdmmc_task ccb_task; + TAILQ_ENTRY(sdmmc_ccb) ccb_link; +}; + +TAILQ_HEAD(sdmmc_ccb_list, sdmmc_ccb); + +struct sdmmc_scsi_softc { + struct scsi_adapter sc_adapter; + struct scsi_link sc_link; + struct device *sc_child; + struct sdmmc_scsi_target *sc_tgt; + int sc_ntargets; + struct sdmmc_ccb *sc_ccbs; /* allocated ccbs */ + struct sdmmc_ccb_list sc_ccb_freeq; /* free ccbs */ + struct sdmmc_ccb_list sc_ccb_runq; /* queued ccbs */ +}; + +int sdmmc_alloc_ccbs(struct sdmmc_scsi_softc *, int); +void sdmmc_free_ccbs(struct sdmmc_scsi_softc *); +struct sdmmc_ccb *sdmmc_get_ccb(struct sdmmc_scsi_softc *, int); +void sdmmc_put_ccb(struct sdmmc_ccb *); + int sdmmc_scsi_cmd(struct scsi_xfer *); -int sdmmc_start_xs(struct sdmmc_softc *, struct scsi_xfer *); -int sdmmc_done_xs(struct sdmmc_softc *, struct scsi_xfer *); -void sdmmc_complete(struct sdmmc_softc *, struct scsi_xfer *); +int sdmmc_start_xs(struct sdmmc_softc *, struct sdmmc_ccb *); +void sdmmc_complete_xs(void *); +void sdmmc_done_xs(struct sdmmc_ccb *); +void sdmmc_stimeout(void *); void sdmmc_scsi_minphys(struct buf *); +#define DEVNAME(sc) SDMMCDEVNAME(sc) + #ifdef SDMMC_DEBUG #define DPRINTF(s) printf s #else @@ -73,6 +120,12 @@ sdmmc_scsi_attach(struct sdmmc_softc *sc) scbus->sc_ntargets++; } + /* Preallocate some CCBs and initialize the CCB lists. */ + if (sdmmc_alloc_ccbs(scbus, SDMMC_SCSI_MAXCMDS) != 0) { + printf("%s: can't allocate ccbs\n", sc->sc_dev.dv_xname); + goto free_sctgt; + } + sc->sc_scsibus = scbus; scbus->sc_adapter.scsi_cmd = sdmmc_scsi_cmd; @@ -88,15 +141,45 @@ sdmmc_scsi_attach(struct sdmmc_softc *sc) bzero(&saa, sizeof saa); bcopy(&scbus->sc_link, &saa.scsi_link, sizeof saa.scsi_link); + /* + * Set saa.sf to something, so that SDIO drivers don't need a + * special case to weed out memory cards. + */ + saa.sf = sc->sc_fn0 != NULL ? sc->sc_fn0 : + SIMPLEQ_FIRST(&sc->sf_head); + scbus->sc_child = config_found(&sc->sc_dev, &saa, scsiprint); + if (scbus->sc_child == NULL) { + printf("%s: can't attach scsibus\n", sc->sc_dev.dv_xname); + goto free_ccbs; + } + return; + + free_ccbs: + sc->sc_scsibus = NULL; + sdmmc_free_ccbs(scbus); + free_sctgt: + free(scbus->sc_tgt, M_DEVBUF); + free(scbus, M_DEVBUF); } void sdmmc_scsi_detach(struct sdmmc_softc *sc) { struct sdmmc_scsi_softc *scbus; + struct sdmmc_ccb *ccb; + int s; scbus = sc->sc_scsibus; + if (scbus == NULL) + return; + + /* Complete all open scsi xfers. */ + s = splbio(); + for (ccb = TAILQ_FIRST(&scbus->sc_ccb_runq); ccb != NULL; + ccb = TAILQ_FIRST(&scbus->sc_ccb_runq)) + sdmmc_stimeout(ccb); + splx(s); if (scbus->sc_child != NULL) config_detach(scbus->sc_child, DETACH_FORCE); @@ -104,10 +187,111 @@ sdmmc_scsi_detach(struct sdmmc_softc *sc) if (scbus->sc_tgt != NULL) FREE(scbus->sc_tgt, M_DEVBUF); + sdmmc_free_ccbs(scbus); FREE(scbus, M_DEVBUF); sc->sc_scsibus = NULL; } +/* + * CCB management + */ + +int +sdmmc_alloc_ccbs(struct sdmmc_scsi_softc *scbus, int nccbs) +{ + struct sdmmc_ccb *ccb; + int i; + + scbus->sc_ccbs = malloc(sizeof(struct sdmmc_ccb) * nccbs, + M_DEVBUF, M_NOWAIT); + if (scbus->sc_ccbs == NULL) + return 1; + + TAILQ_INIT(&scbus->sc_ccb_freeq); + TAILQ_INIT(&scbus->sc_ccb_runq); + + for (i = 0; i < nccbs; i++) { + ccb = &scbus->sc_ccbs[i]; + ccb->ccb_scbus = scbus; + ccb->ccb_state = SDMMC_CCB_FREE; + ccb->ccb_flags = 0; + ccb->ccb_xs = NULL; + ccb->ccb_done = NULL; + + TAILQ_INSERT_TAIL(&scbus->sc_ccb_freeq, ccb, ccb_link); + } + return 0; +} + +void +sdmmc_free_ccbs(struct sdmmc_scsi_softc *scbus) +{ + if (scbus->sc_ccbs != NULL) { + free(scbus->sc_ccbs, M_DEVBUF); + scbus->sc_ccbs = NULL; + } +} + +struct sdmmc_ccb * +sdmmc_get_ccb(struct sdmmc_scsi_softc *scbus, int flags) +{ + struct sdmmc_ccb *ccb; + int s; + + s = splbio(); + while ((ccb = TAILQ_FIRST(&scbus->sc_ccb_freeq)) == NULL && + !ISSET(flags, SCSI_NOSLEEP)) + tsleep(&scbus->sc_ccb_freeq, PRIBIO, "getccb", 0); + if (ccb != NULL) { + TAILQ_REMOVE(&scbus->sc_ccb_freeq, ccb, ccb_link); + ccb->ccb_state = SDMMC_CCB_READY; + } + splx(s); + return ccb; +} + +void +sdmmc_put_ccb(struct sdmmc_ccb *ccb) +{ + struct sdmmc_scsi_softc *scbus = ccb->ccb_scbus; + int s; + + s = splbio(); + if (ccb->ccb_state == SDMMC_CCB_QUEUED) + TAILQ_REMOVE(&scbus->sc_ccb_runq, ccb, ccb_link); + ccb->ccb_state = SDMMC_CCB_FREE; + ccb->ccb_flags = 0; + ccb->ccb_xs = NULL; + ccb->ccb_done = NULL; + TAILQ_INSERT_TAIL(&scbus->sc_ccb_freeq, ccb, ccb_link); + if (TAILQ_NEXT(ccb, ccb_link) == NULL) + wakeup(&scbus->sc_ccb_freeq); + splx(s); +} + +/* + * SCSI command emulation + */ + +/* XXX move to some sort of "scsi emulation layer". */ +static void +sdmmc_scsi_decode_rw(struct scsi_xfer *xs, u_int32_t *blocknop, + u_int32_t *blockcntp) +{ + struct scsi_rw *rw; + struct scsi_rw_big *rwb; + + if (xs->cmdlen == 6) { + rw = (struct scsi_rw *)xs->cmd; + *blocknop = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff); + *blockcntp = rw->length ? rw->length : 0x100; + } else { + rwb = (struct scsi_rw_big *)xs->cmd; + *blocknop = _4btol(rwb->addr); + *blockcntp = _2btol(rwb->length); + } +} + int sdmmc_scsi_cmd(struct scsi_xfer *xs) { @@ -117,11 +301,14 @@ sdmmc_scsi_cmd(struct scsi_xfer *xs) struct sdmmc_scsi_target *tgt = &scbus->sc_tgt[link->target]; struct scsi_inquiry_data inq; struct scsi_read_cap_data rcd; + u_int32_t blockno; + u_int32_t blockcnt; + struct sdmmc_ccb *ccb; if (link->target >= scbus->sc_ntargets || tgt->card == NULL || link->lun != 0) { DPRINTF(("%s: sdmmc_scsi_cmd: no target %d\n", - SDMMCDEVNAME(sc), link->target)); + DEVNAME(sc), link->target)); /* XXX should be XS_SENSE and sense filled out */ xs->error = XS_DRIVER_STUFFUP; xs->flags |= ITSDONE; @@ -129,9 +316,9 @@ sdmmc_scsi_cmd(struct scsi_xfer *xs) return COMPLETE; } - DPRINTF(("%s: sdmmc_scsi_cmd: target=%d xs=%p cmd=%#x " - "datalen=%d (poll=%d)\n", SDMMCDEVNAME(sc), link->target, - xs, xs->cmd->opcode, xs->datalen, xs->flags & SCSI_POLL)); + DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (poll=%#x)\n", + DEVNAME(sc), link->target, xs->cmd->opcode, curproc ? + curproc->p_comm : "", xs->flags & SCSI_POLL)); xs->error = XS_NOERROR; @@ -170,66 +357,141 @@ sdmmc_scsi_cmd(struct scsi_xfer *xs) scsi_done(xs); return COMPLETE; - default: DPRINTF(("%s: unsupported scsi command %#x\n", - SDMMCDEVNAME(sc), xs->cmd->opcode)); + DEVNAME(sc), xs->cmd->opcode)); + xs->error = XS_DRIVER_STUFFUP; + scsi_done(xs); + return COMPLETE; + } + + /* A read or write operation. */ + sdmmc_scsi_decode_rw(xs, &blockno, &blockcnt); + + if (blockno >= tgt->card->csd.capacity || + blockno + blockcnt > tgt->card->csd.capacity) { + DPRINTF(("%s: out of bounds %u-%u >= %u\n", DEVNAME(sc), + blockno, blockcnt, tgt->card->csd.capacity)); xs->error = XS_DRIVER_STUFFUP; scsi_done(xs); return COMPLETE; } - /* XXX check bounds */ + ccb = sdmmc_get_ccb(sc->sc_scsibus, xs->flags); + if (ccb == NULL) { + printf("%s: out of ccbs\n", DEVNAME(sc)); + xs->error = XS_DRIVER_STUFFUP; + scsi_done(xs); + return COMPLETE; + } + + ccb->ccb_xs = xs; + ccb->ccb_done = sdmmc_done_xs; + + ccb->ccb_blockcnt = blockcnt; + ccb->ccb_blockno = blockno; - return sdmmc_start_xs(sc, xs); + return sdmmc_start_xs(sc, ccb); } int -sdmmc_start_xs(struct sdmmc_softc *sc, struct scsi_xfer *xs) +sdmmc_start_xs(struct sdmmc_softc *sc, struct sdmmc_ccb *ccb) { - sdmmc_complete(sc, xs); - return COMPLETE; + struct sdmmc_scsi_softc *scbus = sc->sc_scsibus; + struct scsi_xfer *xs = ccb->ccb_xs; + int s; + + timeout_set(&xs->stimeout, sdmmc_stimeout, ccb); + sdmmc_init_task(&ccb->ccb_task, sdmmc_complete_xs, ccb); + + s = splbio(); + TAILQ_INSERT_TAIL(&scbus->sc_ccb_runq, ccb, ccb_link); + ccb->ccb_state = SDMMC_CCB_QUEUED; + splx(s); + + if (ISSET(xs->flags, SCSI_POLL)) { + sdmmc_complete_xs(ccb); + return COMPLETE; + } + + timeout_add(&xs->stimeout, (xs->timeout * hz) / 1000); + sdmmc_add_task(sc, &ccb->ccb_task); + return SUCCESSFULLY_QUEUED; } void -sdmmc_complete(struct sdmmc_softc *sc, struct scsi_xfer *xs) +sdmmc_complete_xs(void *arg) { + struct sdmmc_ccb *ccb = arg; + struct scsi_xfer *xs = ccb->ccb_xs; struct scsi_link *link = xs->sc_link; + struct sdmmc_softc *sc = link->adapter_softc; struct sdmmc_scsi_softc *scbus = sc->sc_scsibus; struct sdmmc_scsi_target *tgt = &scbus->sc_tgt[link->target]; - struct scsi_rw *rw; - struct scsi_rw_big *rwb; - u_int32_t blockno; - u_int32_t blockcnt; int error; + int s; - /* A read or write operation. */ - /* XXX move to some sort of "scsi emulation layer". */ - if (xs->cmdlen == 6) { - rw = (struct scsi_rw *)xs->cmd; - blockno = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff); - blockcnt = rw->length ? rw->length : 0x100; - } else { - rwb = (struct scsi_rw_big *)xs->cmd; - blockno = _4btol(rwb->addr); - blockcnt = _2btol(rwb->length); - } + DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (poll=%#x)" + " complete\n", DEVNAME(sc), link->target, xs->cmd->opcode, + curproc ? curproc->p_comm : "", xs->flags & SCSI_POLL)); + + s = splbio(); if (ISSET(xs->flags, SCSI_DATA_IN)) - error = sdmmc_mem_read_block(sc, tgt->card, blockno, - xs->data, blockcnt * DEV_BSIZE); + error = sdmmc_mem_read_block(tgt->card, ccb->ccb_blockno, + xs->data, ccb->ccb_blockcnt * DEV_BSIZE); else - error = sdmmc_mem_write_block(sc, tgt->card, blockno, - xs->data, blockcnt * DEV_BSIZE); + error = sdmmc_mem_write_block(tgt->card, ccb->ccb_blockno, + xs->data, ccb->ccb_blockcnt * DEV_BSIZE); + if (error != 0) xs->error = XS_DRIVER_STUFFUP; - xs->flags |= ITSDONE; + ccb->ccb_done(ccb); + splx(s); +} + +void +sdmmc_done_xs(struct sdmmc_ccb *ccb) +{ + struct scsi_xfer *xs = ccb->ccb_xs; +#ifdef SDMMC_DEBUG + struct scsi_link *link = xs->sc_link; + struct sdmmc_softc *sc = link->adapter_softc; +#endif + + timeout_del(&xs->stimeout); + + DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (error=%#x)" + " done\n", DEVNAME(sc), link->target, xs->cmd->opcode, + curproc ? curproc->p_comm : "", xs->error)); + xs->resid = 0; + xs->flags |= ITSDONE; + + if (ISSET(ccb->ccb_flags, SDMMC_CCB_F_ERR)) + xs->error = XS_DRIVER_STUFFUP; + + sdmmc_put_ccb(ccb); scsi_done(xs); } void +sdmmc_stimeout(void *arg) +{ + struct sdmmc_ccb *ccb = arg; + int s; + + s = splbio(); + ccb->ccb_flags |= SDMMC_CCB_F_ERR; + if (sdmmc_task_pending(&ccb->ccb_task)) { + sdmmc_del_task(&ccb->ccb_task); + ccb->ccb_done(ccb); + } + splx(s); +} + +void sdmmc_scsi_minphys(struct buf *bp) { /* XXX limit to max. transfer size supported by card/host? */ diff --git a/sys/dev/sdmmc/sdmmc_scsi.h b/sys/dev/sdmmc/sdmmc_scsi.h index 1bf29badbdf..da92079b3e8 100644 --- a/sys/dev/sdmmc/sdmmc_scsi.h +++ b/sys/dev/sdmmc/sdmmc_scsi.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc_scsi.h,v 1.2 2006/06/01 21:53:41 uwe Exp $ */ +/* $OpenBSD: sdmmc_scsi.h,v 1.3 2006/07/18 04:10:35 uwe Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -21,18 +21,6 @@ struct sdmmc_softc; -struct sdmmc_scsi_target { - struct sdmmc_function *card; -}; - -struct sdmmc_scsi_softc { - struct scsi_adapter sc_adapter; - struct scsi_link sc_link; - struct device *sc_child; - struct sdmmc_scsi_target *sc_tgt; - int sc_ntargets; -}; - void sdmmc_scsi_attach(struct sdmmc_softc *); void sdmmc_scsi_detach(struct sdmmc_softc *); diff --git a/sys/dev/sdmmc/sdmmcchip.h b/sys/dev/sdmmc/sdmmcchip.h index 2ac3881dd32..9cd05c0bf3e 100644 --- a/sys/dev/sdmmc/sdmmcchip.h +++ b/sys/dev/sdmmc/sdmmcchip.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmcchip.h,v 1.1 2006/05/28 17:21:14 uwe Exp $ */ +/* $OpenBSD: sdmmcchip.h,v 1.2 2006/07/18 04:10:35 uwe Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -36,7 +36,7 @@ struct sdmmc_chip_functions { int (*bus_power)(sdmmc_chipset_handle_t, u_int32_t); int (*bus_clock)(sdmmc_chipset_handle_t, int); /* command execution */ - int (*exec_command)(sdmmc_chipset_handle_t, + void (*exec_command)(sdmmc_chipset_handle_t, struct sdmmc_command *); }; @@ -71,8 +71,7 @@ struct sdmmcbus_attach_args { sdmmc_chipset_handle_t sch; }; -/* host controller calls to sdmmc */ -int sdmmc_card_attach(struct device *); -void sdmmc_card_detach(struct device *, int); +void sdmmc_needs_discover(struct device *); +void sdmmc_delay(u_int); #endif diff --git a/sys/dev/sdmmc/sdmmcvar.h b/sys/dev/sdmmc/sdmmcvar.h index 3f69068750c..e3718990363 100644 --- a/sys/dev/sdmmc/sdmmcvar.h +++ b/sys/dev/sdmmc/sdmmcvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmcvar.h,v 1.2 2006/06/01 21:53:41 uwe Exp $ */ +/* $OpenBSD: sdmmcvar.h,v 1.3 2006/07/18 04:10:35 uwe Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -45,12 +45,29 @@ struct sdmmc_cid { int mdt; /* manufacturing date */ }; -struct sdmmc_command; - typedef u_int32_t sdmmc_response[4]; -typedef void (*sdmmc_callback)(struct device *, struct sdmmc_command *); + +struct sdmmc_softc; + +struct sdmmc_task { + void (*func)(void *arg); + void *arg; + int onqueue; + struct sdmmc_softc *sc; + TAILQ_ENTRY(sdmmc_task) next; +}; + +#define sdmmc_init_task(xtask, xfunc, xarg) do { \ + (xtask)->func = (xfunc); \ + (xtask)->arg = (xarg); \ + (xtask)->onqueue = 0; \ + (xtask)->sc = NULL; \ +} while (0) + +#define sdmmc_task_pending(xtask) ((xtask)->onqueue) struct sdmmc_command { + struct sdmmc_task c_task; /* task queue entry */ u_int16_t c_opcode; /* SD or MMC command index */ u_int32_t c_arg; /* SD/MMC command argument */ sdmmc_response c_resp; /* response buffer */ @@ -58,10 +75,7 @@ struct sdmmc_command { int c_datalen; /* length of data buffer */ int c_blklen; /* block length */ int c_flags; /* see below */ -#define SCF_DONE 0x0001 /* command is finished */ -#define SCF_BUF_READY 0x0002 /* buffer ready int occurred */ -#define SCF_CMD_DONE 0x0004 /* cmd complete int occurred */ -#define SCF_XFR_DONE 0x0008 /* transfer complete int occurred */ +#define SCF_ITSDONE 0x0001 /* command is complete */ #define SCF_CMD_AC 0x0000 #define SCF_CMD_ADTC 0x0010 #define SCF_CMD_BC 0x0020 @@ -81,7 +95,6 @@ struct sdmmc_command { #define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) #define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) #define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC) - sdmmc_callback c_done; /* callback function */ int c_error; /* errno value on completion */ }; @@ -138,11 +151,18 @@ struct sdmmc_softc { #define SMF_SD_MODE 0x0001 /* host in SD mode (MMC otherwise) */ #define SMF_IO_MODE 0x0002 /* host in I/O mode (SD mode only) */ #define SMF_MEM_MODE 0x0004 /* host in memory mode (SD or MMC) */ +#define SMF_CARD_PRESENT 0x0010 /* card presence noticed */ +#define SMF_CARD_ATTACHED 0x0020 /* card driver(s) attached */ int sc_function_count; /* number of I/O functions (SDIO) */ - void *sc_scsibus; /* SCSI bus emulation softc */ struct sdmmc_function *sc_card; /* selected card */ struct sdmmc_function *sc_fn0; /* function 0, the card itself */ - SIMPLEQ_HEAD(, sdmmc_function) sf_head; + SIMPLEQ_HEAD(, sdmmc_function) sf_head; /* list of card functions */ + int sc_dying; /* bus driver is shutting down */ + struct proc *sc_task_thread; /* asynchronous tasks */ + TAILQ_HEAD(, sdmmc_task) sc_tskq; /* task thread work queue */ + struct sdmmc_task sc_discover_task; /* card attach/detach task */ + struct lock sc_lock; /* lock around host controller */ + void *sc_scsibus; /* SCSI bus emulation softc */ }; /* @@ -156,9 +176,14 @@ struct sdmmc_attach_args { #define IPL_SDMMC IPL_BIO #define splsdmmc() splbio() +#define SDMMC_LOCK(sc) lockmgr(&(sc)->sc_lock, LK_EXCLUSIVE, NULL) +#define SDMMC_UNLOCK(sc) lockmgr(&(sc)->sc_lock, LK_RELEASE, NULL) + +void sdmmc_add_task(struct sdmmc_softc *, struct sdmmc_task *); +void sdmmc_del_task(struct sdmmc_task *); + struct sdmmc_function *sdmmc_function_alloc(struct sdmmc_softc *); void sdmmc_function_free(struct sdmmc_function *); -void sdmmc_delay(u_int); int sdmmc_set_bus_power(struct sdmmc_softc *, u_int32_t, u_int32_t); int sdmmc_mmc_command(struct sdmmc_softc *, struct sdmmc_command *); int sdmmc_app_command(struct sdmmc_softc *, struct sdmmc_command *); @@ -193,9 +218,7 @@ void sdmmc_check_cis_quirks(struct sdmmc_function *); int sdmmc_mem_enable(struct sdmmc_softc *); void sdmmc_mem_scan(struct sdmmc_softc *); int sdmmc_mem_init(struct sdmmc_softc *, struct sdmmc_function *); -int sdmmc_mem_read_block(struct sdmmc_softc *, - struct sdmmc_function *, int, u_char *, size_t); -int sdmmc_mem_write_block(struct sdmmc_softc *, - struct sdmmc_function *, int, u_char *, size_t); +int sdmmc_mem_read_block(struct sdmmc_function *, int, u_char *, size_t); +int sdmmc_mem_write_block(struct sdmmc_function *, int, u_char *, size_t); #endif |