From a00fc09029f02ca833cf90e5d5625f08c4ac4f51 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 6 Sep 2005 15:18:52 -0700 Subject: [PATCH] [PATCH] sd: read-only switch Support for the read-only switch on SD cards which must be enforced by the host. Signed-off-by: Pierre Ossman Cc: Russell King Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/mmc.c | 39 +++++++++++++++++++++++---------------- drivers/mmc/mmc_block.c | 9 +++++++-- include/linux/mmc/card.h | 3 +++ include/linux/mmc/host.h | 1 + 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 294961a102ca..725c6ad3eb64 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -413,8 +413,7 @@ static void mmc_decode_cid(struct mmc_card *card) card->cid.month = UNSTUFF_BITS(resp, 8, 4); card->cid.year += 2000; /* SD cards year offset */ - } - else { + } else { /* * The selection of the format here is based upon published * specs from sandisk and from what people have reported. @@ -494,8 +493,7 @@ static void mmc_decode_csd(struct mmc_card *card) csd->capacity = (1 + m) << (e + 2); csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); - } - else { + } else { /* * We only understand CSD structure v1.1 and v1.2. * v1.2 has extra information in bits 15, 11 and 10. @@ -738,10 +736,20 @@ static void mmc_discover_cards(struct mmc_host *host) err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE) mmc_card_set_dead(card); - else + else { card->rca = cmd.resp[0] >> 16; - } - else { + + if (!host->ops->get_ro) { + printk(KERN_WARNING "%s: host does not " + "support reading read-only " + "switch. assuming write-enable.\n", + mmc_hostname(host)); + } else { + if (host->ops->get_ro(host)) + mmc_card_set_readonly(card); + } + } + } else { cmd.opcode = MMC_SET_RELATIVE_ADDR; cmd.arg = card->rca << 16; cmd.flags = MMC_RSP_R1; @@ -833,24 +841,23 @@ static void mmc_setup(struct mmc_host *host) int err; u32 ocr; - host->mode = MMC_MODE_MMC; + host->mode = MMC_MODE_SD; mmc_power_up(host); mmc_idle_cards(host); - err = mmc_send_op_cond(host, 0, &ocr); + err = mmc_send_app_op_cond(host, 0, &ocr); /* - * If we fail to detect any cards then try - * searching for SD cards. + * If we fail to detect any SD cards then try + * searching for MMC cards. */ - if (err != MMC_ERR_NONE) - { - err = mmc_send_app_op_cond(host, 0, &ocr); + if (err != MMC_ERR_NONE) { + host->mode = MMC_MODE_MMC; + + err = mmc_send_op_cond(host, 0, &ocr); if (err != MMC_ERR_NONE) return; - - host->mode = MMC_MODE_SD; } host->ocr = mmc_select_voltage(host, ocr); diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index d4eee99c2bf6..fa83f15fdf16 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -95,6 +95,10 @@ static int mmc_blk_open(struct inode *inode, struct file *filp) if (md->usage == 2) check_disk_change(inode->i_bdev); ret = 0; + + if ((filp->f_mode & FMODE_WRITE) && + mmc_card_readonly(md->queue.card)) + ret = -EROFS; } return ret; @@ -403,9 +407,10 @@ static int mmc_blk_probe(struct mmc_card *card) if (err) goto out; - printk(KERN_INFO "%s: %s %s %dKiB\n", + printk(KERN_INFO "%s: %s %s %dKiB %s\n", md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), - (card->csd.capacity << card->csd.read_blkbits) / 1024); + (card->csd.capacity << card->csd.read_blkbits) / 1024, + mmc_card_readonly(card)?"(ro)":""); mmc_set_drvdata(card, md); add_disk(md->disk); diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 538e8c86336c..0e9ec01b9c5b 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -48,6 +48,7 @@ struct mmc_card { #define MMC_STATE_DEAD (1<<1) /* device no longer in stack */ #define MMC_STATE_BAD (1<<2) /* unrecognised device */ #define MMC_STATE_SDCARD (1<<3) /* is an SD card */ +#define MMC_STATE_READONLY (1<<4) /* card is read-only */ u32 raw_cid[4]; /* raw card CID */ u32 raw_csd[4]; /* raw card CSD */ struct mmc_cid cid; /* card identification */ @@ -58,11 +59,13 @@ struct mmc_card { #define mmc_card_dead(c) ((c)->state & MMC_STATE_DEAD) #define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD) #define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD) +#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) #define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD) #define mmc_card_set_bad(c) ((c)->state |= MMC_STATE_BAD) #define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD) +#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) #define mmc_card_name(c) ((c)->cid.prod_name) #define mmc_card_id(c) ((c)->dev.bus_id) diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 845020d90c60..8c5f71376e41 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -62,6 +62,7 @@ struct mmc_ios { struct mmc_host_ops { void (*request)(struct mmc_host *host, struct mmc_request *req); void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios); + int (*get_ro)(struct mmc_host *host); }; struct mmc_card; -- 2.20.1