diff options
Diffstat (limited to 'drivers/mmc/core/core.c')
| -rw-r--r-- | drivers/mmc/core/core.c | 51 | 
1 files changed, 48 insertions, 3 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 950b97d7412..a2aa860956e 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -140,7 +140,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)  			cmd->retries = 0;  	} -	if (err && cmd->retries) { +	if (err && cmd->retries && !mmc_card_removed(host->card)) {  		/*  		 * Request starter must handle retries - see  		 * mmc_wait_for_req_done(). @@ -247,6 +247,11 @@ static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)  {  	init_completion(&mrq->completion);  	mrq->done = mmc_wait_done; +	if (mmc_card_removed(host->card)) { +		mrq->cmd->error = -ENOMEDIUM; +		complete(&mrq->completion); +		return; +	}  	mmc_start_request(host, mrq);  } @@ -259,7 +264,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host,  		wait_for_completion(&mrq->completion);  		cmd = mrq->cmd; -		if (!cmd->error || !cmd->retries) +		if (!cmd->error || !cmd->retries || +		    mmc_card_removed(host->card))  			break;  		pr_debug("%s: req failed (CMD%u): %d, retrying...\n", @@ -1456,7 +1462,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)  	WARN_ON(host->removed);  	spin_unlock_irqrestore(&host->lock, flags);  #endif - +	host->detect_change = 1;  	mmc_schedule_delayed_work(&host->detect, delay);  } @@ -2049,6 +2055,43 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)  	return -EIO;  } +int _mmc_detect_card_removed(struct mmc_host *host) +{ +	int ret; + +	if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive) +		return 0; + +	if (!host->card || mmc_card_removed(host->card)) +		return 1; + +	ret = host->bus_ops->alive(host); +	if (ret) { +		mmc_card_set_removed(host->card); +		pr_debug("%s: card remove detected\n", mmc_hostname(host)); +	} + +	return ret; +} + +int mmc_detect_card_removed(struct mmc_host *host) +{ +	struct mmc_card *card = host->card; + +	WARN_ON(!host->claimed); +	/* +	 * The card will be considered unchanged unless we have been asked to +	 * detect a change or host requires polling to provide card detection. +	 */ +	if (card && !host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL)) +		return mmc_card_removed(card); + +	host->detect_change = 0; + +	return _mmc_detect_card_removed(host); +} +EXPORT_SYMBOL(mmc_detect_card_removed); +  void mmc_rescan(struct work_struct *work)  {  	static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; @@ -2069,6 +2112,8 @@ void mmc_rescan(struct work_struct *work)  	    && !(host->caps & MMC_CAP_NONREMOVABLE))  		host->bus_ops->detect(host); +	host->detect_change = 0; +  	/*  	 * Let mmc_bus_put() free the bus/bus_ops if we've found that  	 * the card is no longer present.  |