Commit b62f6228 authored by Adrian Hunter's avatar Adrian Hunter Committed by Linus Torvalds

omap_hsmmc: protect the card when the cover is open

Depending on the manufacturer, there is a small possibility that removing
a card while it is being written to, can render the card permanently
unusable.  To prevent that, the card is made inaccessible when the cover
is open.
Signed-off-by: default avatarAdrian Hunter <adrian.hunter@nokia.com>
Acked-by: default avatarMatt Fleming <matt@console-pimps.org>
Cc: Ian Molton <ian@mnementh.co.uk>
Cc: "Roberto A. Foglietta" <roberto.foglietta@gmail.com>
Cc: Jarkko Lavinen <jarkko.lavinen@nokia.com>
Cc: Denis Karpov <ext-denis.2.karpov@nokia.com>
Cc: Pierre Ossman <pierre@ossman.eu>
Cc: Philip Langdale <philipl@overt.org>
Cc: "Madhusudhan" <madhu.cr@ti.com>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 70a3341a
...@@ -167,6 +167,8 @@ struct omap_hsmmc_host { ...@@ -167,6 +167,8 @@ struct omap_hsmmc_host {
int context_loss; int context_loss;
int dpm_state; int dpm_state;
int vdd; int vdd;
int protect_card;
int reqs_blocked;
struct omap_mmc_platform_data *pdata; struct omap_mmc_platform_data *pdata;
}; };
...@@ -351,6 +353,9 @@ static void send_init_stream(struct omap_hsmmc_host *host) ...@@ -351,6 +353,9 @@ static void send_init_stream(struct omap_hsmmc_host *host)
int reg = 0; int reg = 0;
unsigned long timeout; unsigned long timeout;
if (host->protect_card)
return;
disable_irq(host->irq); disable_irq(host->irq);
OMAP_HSMMC_WRITE(host->base, CON, OMAP_HSMMC_WRITE(host->base, CON,
OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM); OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
...@@ -786,6 +791,30 @@ err: ...@@ -786,6 +791,30 @@ err:
return ret; return ret;
} }
/* Protect the card while the cover is open */
static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
{
if (!mmc_slot(host).get_cover_state)
return;
host->reqs_blocked = 0;
if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) {
if (host->protect_card) {
printk(KERN_INFO "%s: cover is closed, "
"card is now accessible\n",
mmc_hostname(host->mmc));
host->protect_card = 0;
}
} else {
if (!host->protect_card) {
printk(KERN_INFO "%s: cover is open, "
"card is now inaccessible\n",
mmc_hostname(host->mmc));
host->protect_card = 1;
}
}
}
/* /*
* Work Item to notify the core about card insertion/removal * Work Item to notify the core about card insertion/removal
*/ */
...@@ -803,8 +832,10 @@ static void omap_hsmmc_detect(struct work_struct *work) ...@@ -803,8 +832,10 @@ static void omap_hsmmc_detect(struct work_struct *work)
if (slot->card_detect) if (slot->card_detect)
carddetect = slot->card_detect(slot->card_detect_irq); carddetect = slot->card_detect(slot->card_detect_irq);
else else {
omap_hsmmc_protect_card(host);
carddetect = -ENOSYS; carddetect = -ENOSYS;
}
if (carddetect) { if (carddetect) {
mmc_detect_change(host->mmc, (HZ * 200) / 1000); mmc_detect_change(host->mmc, (HZ * 200) / 1000);
...@@ -1040,8 +1071,32 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) ...@@ -1040,8 +1071,32 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
* interrupts, but not if we are already in interrupt context i.e. * interrupts, but not if we are already in interrupt context i.e.
* retries. * retries.
*/ */
if (!in_interrupt()) if (!in_interrupt()) {
spin_lock_irqsave(&host->irq_lock, host->flags); spin_lock_irqsave(&host->irq_lock, host->flags);
/*
* Protect the card from I/O if there is a possibility
* it can be removed.
*/
if (host->protect_card) {
if (host->reqs_blocked < 3) {
/*
* Ensure the controller is left in a consistent
* state by resetting the command and data state
* machines.
*/
omap_hsmmc_reset_controller_fsm(host, SRD);
omap_hsmmc_reset_controller_fsm(host, SRC);
host->reqs_blocked += 1;
}
req->cmd->error = -EBADF;
if (req->data)
req->data->error = -EBADF;
spin_unlock_irqrestore(&host->irq_lock, host->flags);
mmc_request_done(mmc, req);
return;
} else if (host->reqs_blocked)
host->reqs_blocked = 0;
}
WARN_ON(host->mrq != NULL); WARN_ON(host->mrq != NULL);
host->mrq = req; host->mrq = req;
err = omap_hsmmc_prepare_data(host, req); err = omap_hsmmc_prepare_data(host, req);
...@@ -1732,6 +1787,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) ...@@ -1732,6 +1787,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
mmc_host_lazy_disable(host->mmc); mmc_host_lazy_disable(host->mmc);
omap_hsmmc_protect_card(host);
mmc_add_host(mmc); mmc_add_host(mmc);
if (mmc_slot(host).name != NULL) { if (mmc_slot(host).name != NULL) {
...@@ -1897,6 +1954,8 @@ static int omap_hsmmc_resume(struct platform_device *pdev) ...@@ -1897,6 +1954,8 @@ static int omap_hsmmc_resume(struct platform_device *pdev)
"Unmask interrupt failed\n"); "Unmask interrupt failed\n");
} }
omap_hsmmc_protect_card(host);
/* Notify the core to resume the host */ /* Notify the core to resume the host */
ret = mmc_resume_host(host->mmc); ret = mmc_resume_host(host->mmc);
if (ret == 0) if (ret == 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment