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: Adrian Hunter <adrian.hunter@nokia.com> Acked-by: Matt 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: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
70a3341a71
commit
b62f622812
@@ -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)
|
|||||||
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:
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
* 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)
|
|||||||
|
|
||||||
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)
|
|||||||
"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)
|
||||||
|
Reference in New Issue
Block a user