diff options
author | Adrian Hunter <adrian.hunter@nokia.com> | 2009-09-22 19:45:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 10:39:36 -0400 |
commit | b62f622812c5aaacad217fd8f4445562b917df6d (patch) | |
tree | 51ab6f42fa7be7460fb3d6f922f0ad9bacbd54f3 /drivers/mmc/host | |
parent | 70a3341a711f27ae77714ae7dd360a4e7e2d5e7c (diff) |
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>
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 63 |
1 files changed, 61 insertions, 2 deletions
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 20746e4f00b3..a20fafecfc60 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c | |||
@@ -167,6 +167,8 @@ struct omap_hsmmc_host { | |||
167 | int context_loss; | 167 | int context_loss; |
168 | int dpm_state; | 168 | int dpm_state; |
169 | int vdd; | 169 | int vdd; |
170 | int protect_card; | ||
171 | int reqs_blocked; | ||
170 | 172 | ||
171 | struct omap_mmc_platform_data *pdata; | 173 | struct omap_mmc_platform_data *pdata; |
172 | }; | 174 | }; |
@@ -351,6 +353,9 @@ static void send_init_stream(struct omap_hsmmc_host *host) | |||
351 | int reg = 0; | 353 | int reg = 0; |
352 | unsigned long timeout; | 354 | unsigned long timeout; |
353 | 355 | ||
356 | if (host->protect_card) | ||
357 | return; | ||
358 | |||
354 | disable_irq(host->irq); | 359 | disable_irq(host->irq); |
355 | OMAP_HSMMC_WRITE(host->base, CON, | 360 | OMAP_HSMMC_WRITE(host->base, CON, |
356 | OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM); | 361 | OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM); |
@@ -786,6 +791,30 @@ err: | |||
786 | return ret; | 791 | return ret; |
787 | } | 792 | } |
788 | 793 | ||
794 | /* Protect the card while the cover is open */ | ||
795 | static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) | ||
796 | { | ||
797 | if (!mmc_slot(host).get_cover_state) | ||
798 | return; | ||
799 | |||
800 | host->reqs_blocked = 0; | ||
801 | if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) { | ||
802 | if (host->protect_card) { | ||
803 | printk(KERN_INFO "%s: cover is closed, " | ||
804 | "card is now accessible\n", | ||
805 | mmc_hostname(host->mmc)); | ||
806 | host->protect_card = 0; | ||
807 | } | ||
808 | } else { | ||
809 | if (!host->protect_card) { | ||
810 | printk(KERN_INFO "%s: cover is open, " | ||
811 | "card is now inaccessible\n", | ||
812 | mmc_hostname(host->mmc)); | ||
813 | host->protect_card = 1; | ||
814 | } | ||
815 | } | ||
816 | } | ||
817 | |||
789 | /* | 818 | /* |
790 | * Work Item to notify the core about card insertion/removal | 819 | * Work Item to notify the core about card insertion/removal |
791 | */ | 820 | */ |
@@ -803,8 +832,10 @@ static void omap_hsmmc_detect(struct work_struct *work) | |||
803 | 832 | ||
804 | if (slot->card_detect) | 833 | if (slot->card_detect) |
805 | carddetect = slot->card_detect(slot->card_detect_irq); | 834 | carddetect = slot->card_detect(slot->card_detect_irq); |
806 | else | 835 | else { |
836 | omap_hsmmc_protect_card(host); | ||
807 | carddetect = -ENOSYS; | 837 | carddetect = -ENOSYS; |
838 | } | ||
808 | 839 | ||
809 | if (carddetect) { | 840 | if (carddetect) { |
810 | mmc_detect_change(host->mmc, (HZ * 200) / 1000); | 841 | 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 | * interrupts, but not if we are already in interrupt context i.e. | 1071 | * interrupts, but not if we are already in interrupt context i.e. |
1041 | * retries. | 1072 | * retries. |
1042 | */ | 1073 | */ |
1043 | if (!in_interrupt()) | 1074 | if (!in_interrupt()) { |
1044 | spin_lock_irqsave(&host->irq_lock, host->flags); | 1075 | spin_lock_irqsave(&host->irq_lock, host->flags); |
1076 | /* | ||
1077 | * Protect the card from I/O if there is a possibility | ||
1078 | * it can be removed. | ||
1079 | */ | ||
1080 | if (host->protect_card) { | ||
1081 | if (host->reqs_blocked < 3) { | ||
1082 | /* | ||
1083 | * Ensure the controller is left in a consistent | ||
1084 | * state by resetting the command and data state | ||
1085 | * machines. | ||
1086 | */ | ||
1087 | omap_hsmmc_reset_controller_fsm(host, SRD); | ||
1088 | omap_hsmmc_reset_controller_fsm(host, SRC); | ||
1089 | host->reqs_blocked += 1; | ||
1090 | } | ||
1091 | req->cmd->error = -EBADF; | ||
1092 | if (req->data) | ||
1093 | req->data->error = -EBADF; | ||
1094 | spin_unlock_irqrestore(&host->irq_lock, host->flags); | ||
1095 | mmc_request_done(mmc, req); | ||
1096 | return; | ||
1097 | } else if (host->reqs_blocked) | ||
1098 | host->reqs_blocked = 0; | ||
1099 | } | ||
1045 | WARN_ON(host->mrq != NULL); | 1100 | WARN_ON(host->mrq != NULL); |
1046 | host->mrq = req; | 1101 | host->mrq = req; |
1047 | err = omap_hsmmc_prepare_data(host, req); | 1102 | err = omap_hsmmc_prepare_data(host, req); |
@@ -1732,6 +1787,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) | |||
1732 | 1787 | ||
1733 | mmc_host_lazy_disable(host->mmc); | 1788 | mmc_host_lazy_disable(host->mmc); |
1734 | 1789 | ||
1790 | omap_hsmmc_protect_card(host); | ||
1791 | |||
1735 | mmc_add_host(mmc); | 1792 | mmc_add_host(mmc); |
1736 | 1793 | ||
1737 | if (mmc_slot(host).name != NULL) { | 1794 | if (mmc_slot(host).name != NULL) { |
@@ -1897,6 +1954,8 @@ static int omap_hsmmc_resume(struct platform_device *pdev) | |||
1897 | "Unmask interrupt failed\n"); | 1954 | "Unmask interrupt failed\n"); |
1898 | } | 1955 | } |
1899 | 1956 | ||
1957 | omap_hsmmc_protect_card(host); | ||
1958 | |||
1900 | /* Notify the core to resume the host */ | 1959 | /* Notify the core to resume the host */ |
1901 | ret = mmc_resume_host(host->mmc); | 1960 | ret = mmc_resume_host(host->mmc); |
1902 | if (ret == 0) | 1961 | if (ret == 0) |