[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 <drzeus@drzeus.cx> Cc: Russell King <rmk@arm.linux.org.uk> Cc: David Brownell <david-b@pacbell.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
committed by
Linus Torvalds
parent
335eadf2ef
commit
a00fc09029
@@ -413,8 +413,7 @@ static void mmc_decode_cid(struct mmc_card *card)
|
|||||||
card->cid.month = UNSTUFF_BITS(resp, 8, 4);
|
card->cid.month = UNSTUFF_BITS(resp, 8, 4);
|
||||||
|
|
||||||
card->cid.year += 2000; /* SD cards year offset */
|
card->cid.year += 2000; /* SD cards year offset */
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
/*
|
/*
|
||||||
* The selection of the format here is based upon published
|
* The selection of the format here is based upon published
|
||||||
* specs from sandisk and from what people have reported.
|
* 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->capacity = (1 + m) << (e + 2);
|
||||||
|
|
||||||
csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
|
csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
/*
|
/*
|
||||||
* We only understand CSD structure v1.1 and v1.2.
|
* We only understand CSD structure v1.1 and v1.2.
|
||||||
* v1.2 has extra information in bits 15, 11 and 10.
|
* 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);
|
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
|
||||||
if (err != MMC_ERR_NONE)
|
if (err != MMC_ERR_NONE)
|
||||||
mmc_card_set_dead(card);
|
mmc_card_set_dead(card);
|
||||||
else
|
else {
|
||||||
card->rca = cmd.resp[0] >> 16;
|
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.opcode = MMC_SET_RELATIVE_ADDR;
|
||||||
cmd.arg = card->rca << 16;
|
cmd.arg = card->rca << 16;
|
||||||
cmd.flags = MMC_RSP_R1;
|
cmd.flags = MMC_RSP_R1;
|
||||||
@@ -833,24 +841,23 @@ static void mmc_setup(struct mmc_host *host)
|
|||||||
int err;
|
int err;
|
||||||
u32 ocr;
|
u32 ocr;
|
||||||
|
|
||||||
host->mode = MMC_MODE_MMC;
|
host->mode = MMC_MODE_SD;
|
||||||
|
|
||||||
mmc_power_up(host);
|
mmc_power_up(host);
|
||||||
mmc_idle_cards(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
|
* If we fail to detect any SD cards then try
|
||||||
* searching for SD cards.
|
* searching for MMC cards.
|
||||||
*/
|
*/
|
||||||
if (err != MMC_ERR_NONE)
|
if (err != MMC_ERR_NONE) {
|
||||||
{
|
host->mode = MMC_MODE_MMC;
|
||||||
err = mmc_send_app_op_cond(host, 0, &ocr);
|
|
||||||
|
err = mmc_send_op_cond(host, 0, &ocr);
|
||||||
if (err != MMC_ERR_NONE)
|
if (err != MMC_ERR_NONE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
host->mode = MMC_MODE_SD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
host->ocr = mmc_select_voltage(host, ocr);
|
host->ocr = mmc_select_voltage(host, ocr);
|
||||||
|
@@ -95,6 +95,10 @@ static int mmc_blk_open(struct inode *inode, struct file *filp)
|
|||||||
if (md->usage == 2)
|
if (md->usage == 2)
|
||||||
check_disk_change(inode->i_bdev);
|
check_disk_change(inode->i_bdev);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
|
if ((filp->f_mode & FMODE_WRITE) &&
|
||||||
|
mmc_card_readonly(md->queue.card))
|
||||||
|
ret = -EROFS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -403,9 +407,10 @@ static int mmc_blk_probe(struct mmc_card *card)
|
|||||||
if (err)
|
if (err)
|
||||||
goto out;
|
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),
|
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);
|
mmc_set_drvdata(card, md);
|
||||||
add_disk(md->disk);
|
add_disk(md->disk);
|
||||||
|
@@ -48,6 +48,7 @@ struct mmc_card {
|
|||||||
#define MMC_STATE_DEAD (1<<1) /* device no longer in stack */
|
#define MMC_STATE_DEAD (1<<1) /* device no longer in stack */
|
||||||
#define MMC_STATE_BAD (1<<2) /* unrecognised device */
|
#define MMC_STATE_BAD (1<<2) /* unrecognised device */
|
||||||
#define MMC_STATE_SDCARD (1<<3) /* is an SD card */
|
#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_cid[4]; /* raw card CID */
|
||||||
u32 raw_csd[4]; /* raw card CSD */
|
u32 raw_csd[4]; /* raw card CSD */
|
||||||
struct mmc_cid cid; /* card identification */
|
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_dead(c) ((c)->state & MMC_STATE_DEAD)
|
||||||
#define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD)
|
#define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD)
|
||||||
#define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD)
|
#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_present(c) ((c)->state |= MMC_STATE_PRESENT)
|
||||||
#define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD)
|
#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_bad(c) ((c)->state |= MMC_STATE_BAD)
|
||||||
#define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD)
|
#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_name(c) ((c)->cid.prod_name)
|
||||||
#define mmc_card_id(c) ((c)->dev.bus_id)
|
#define mmc_card_id(c) ((c)->dev.bus_id)
|
||||||
|
@@ -62,6 +62,7 @@ struct mmc_ios {
|
|||||||
struct mmc_host_ops {
|
struct mmc_host_ops {
|
||||||
void (*request)(struct mmc_host *host, struct mmc_request *req);
|
void (*request)(struct mmc_host *host, struct mmc_request *req);
|
||||||
void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
|
void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
|
||||||
|
int (*get_ro)(struct mmc_host *host);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mmc_card;
|
struct mmc_card;
|
||||||
|
Reference in New Issue
Block a user