diff options
author | Pierre Ossman <drzeus@drzeus.cx> | 2007-05-26 13:48:18 +0200 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-09-23 19:45:31 +0200 |
commit | e29a7d73f4277eb92aa64e17017dea33460828ef (patch) | |
tree | 0b8cfe6d145f41c43f86b475fff86627a305af1e /drivers/mmc/core/sdio.c | |
parent | b2bcc798bbb482b2909801280f3c4aff8cbbf5be (diff) | |
download | linux-e29a7d73f4277eb92aa64e17017dea33460828ef.tar.bz2 |
mmc: basic SDIO device model
Add the sdio bus type and basic device handling.
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/core/sdio.c')
-rw-r--r-- | drivers/mmc/core/sdio.c | 72 |
1 files changed, 63 insertions, 9 deletions
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index ac0dd68df8e7..444328581cec 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -13,21 +13,49 @@ #include <linux/mmc/host.h> #include <linux/mmc/card.h> +#include <linux/mmc/sdio_func.h> #include "core.h" #include "bus.h" +#include "sdio_bus.h" #include "mmc_ops.h" #include "sd_ops.h" #include "sdio_ops.h" +static int sdio_init_func(struct mmc_card *card, unsigned int fn) +{ + struct sdio_func *func; + + BUG_ON(fn > SDIO_MAX_FUNCS); + + func = sdio_alloc_func(card); + if (IS_ERR(func)) + return PTR_ERR(func); + + func->num = fn; + + card->sdio_func[fn - 1] = func; + + return 0; +} + /* * Host is being removed. Free up the current card. */ static void mmc_sdio_remove(struct mmc_host *host) { + int i; + BUG_ON(!host); BUG_ON(!host->card); + for (i = 0;i < host->card->sdio_funcs;i++) { + if (host->card->sdio_func[i]) { + sdio_remove_func(host->card->sdio_func[i]); + host->card->sdio_func[i] = NULL; + } + } + mmc_remove_card(host->card); host->card = NULL; } @@ -73,7 +101,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = { int mmc_attach_sdio(struct mmc_host *host, u32 ocr) { int err; - int funcs; + int i, funcs; struct mmc_card *card; BUG_ON(!host); @@ -132,13 +160,16 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) } card->type = MMC_TYPE_SDIO; + card->sdio_funcs = funcs; + + host->card = card; /* * Set card RCA. */ err = mmc_send_relative_addr(host, &card->rca); if (err) - goto free_card; + goto remove; mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); @@ -147,23 +178,46 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) */ err = mmc_select_card(card); if (err) - goto free_card; + goto remove; - host->card = card; + /* + * Initialize (but don't add) all present functions. + */ + for (i = 0;i < funcs;i++) { + err = sdio_init_func(host->card, i + 1); + if (err) + goto remove; + } mmc_release_host(host); + /* + * First add the card to the driver model... + */ err = mmc_add_card(host->card); if (err) - goto reclaim_host; + goto remove_added; + + /* + * ...then the SDIO functions. + */ + for (i = 0;i < funcs;i++) { + err = sdio_add_func(host->card->sdio_func[i]); + if (err) + goto remove_added; + } return 0; -reclaim_host: + +remove_added: + /* Remove without lock if the device has been added. */ + mmc_sdio_remove(host); mmc_claim_host(host); -free_card: - mmc_remove_card(card); - host->card = NULL; +remove: + /* And with lock if it hasn't been added. */ + if (host->card) + mmc_sdio_remove(host); err: mmc_detach_bus(host); mmc_release_host(host); |