Skip to contentSkip to conversation

Secure Digital (SD) support

PATCH In review Pierre Ossman 6 participants 21 messages Mar 3, 2005 – May 6, 2005 MMC, SD and SDIO

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Secure Digital (SD) support

Here are the patches for Secure Digital support that I've been sitting on for a while. I tried to get some feedback on inclusion of this previously but since I didn't get any I'll just submit the thing. It was originally diffed against 2.6.10 but it applies to 2.6.11 just fine (only minor fuzz).

Change summary:

* Detects if connected card is SD or MMC. Marks host as in SD mode if SD is detected (since SD isn't a bus system).
* Reads extra registers from SD cards (SCR) and parses CSD differently depending on SD/MMC mode.
* Support for 4-bit mode. This has been design to be fairly isolated from the SD bit so that it can (hopefully) be reused with MMC.
* New callback added for reading the read-only switch on SD cards.

Changed files:

mmc.c : SD detection and register parsing.
mmc_block.c : Checks read-only flag for cards (not SD-specific). mmc_sysfs.c : Exposes SCR register.
card.h : Added flags to determine card type, RO and new register. host.h : Added flags for bus width, RO test and mode (SD/MMC). mmc.h : Added R6 define and new defines.
protocol.h : Added needed SD commands.

This patch is backwards compatible and only needs updated drivers to take advantage of 4-bit bus and reading the RO switch (unmodified drivers will default to 1-bit bus and write enable).

There might be new bugs that surface with this though. With my own drivers I discovered that very small transfers (< 16 bytes) always failed. Testing is needed but I do not have access to do it myself. MMC should not break with this since MMC is detected before SD.

Rgds
Pierre

include/linux/mmc/card.h +15 -0
diff -uNp linux/include/linux/mmc/card.h linux-wbsd/include/linux/mmc/card.h
@@ -33,6 +33,13 @@ struct mmc_csd {
 	unsigned int		capacity;
 };
 
+struct sd_scr {
+	unsigned char		sda_vsn;
+	unsigned char		bus_widths;
+#define SD_SCR_BUS_WIDTH_1	(1<<0)
+#define SD_SCR_BUS_WIDTH_4	(1<<2)
+};
+
 struct mmc_host;
 
 /*
@@ -47,19 +54,27 @@ struct mmc_card {
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
 #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 */
+	u32			raw_scr[2];	/* raw card SCR */
 	struct mmc_cid		cid;		/* card identification */
 	struct mmc_csd		csd;		/* card specific */
+	struct sd_scr		scr;		/* extra SD information */
 };
 
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #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)
include/linux/mmc/host.h +14 -0
diff -uNp linux/include/linux/mmc/host.h linux-wbsd/include/linux/mmc/host.h
@@ -51,11 +51,17 @@ struct mmc_ios {
 #define MMC_POWER_OFF		0
 #define MMC_POWER_UP		1
 #define MMC_POWER_ON		2
+
+	unsigned char	bus_width;		/* data bus width */
+
+#define MMC_BUS_WIDTH_1		0
+#define MMC_BUS_WIDTH_4		2
 };
 
 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;
@@ -68,6 +74,10 @@ struct mmc_host {
 	unsigned int		f_max;
 	u32			ocr_avail;
 	char			host_name[8];
+	
+	unsigned long		caps;		/* Host capabilities */
+	
+#define MMC_CAP_4_BIT_DATA	(1 << 0)	/* Can the host do 4 bit transfers */
 
 	/* host specific block data */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
@@ -79,6 +89,10 @@ struct mmc_host {
 	/* private data */
 	struct mmc_ios		ios;		/* current io bus settings */
 	u32			ocr;		/* the current OCR setting */
+	
+	unsigned int		mode;		/* current card mode of host */
+#define MMC_MODE_MMC		0
+#define MMC_MODE_SD		1
 
 	struct list_head	cards;		/* devices attached to this host */
 
include/linux/mmc/mmc.h +3 -0
diff -uNp linux/include/linux/mmc/mmc.h linux-wbsd/include/linux/mmc/mmc.h
@@ -37,6 +37,7 @@ struct mmc_command {
 #define MMC_RSP_R1B	(MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_BUSY)
 #define MMC_RSP_R2	(MMC_RSP_LONG|MMC_RSP_CRC)
 #define MMC_RSP_R3	(MMC_RSP_SHORT)
+#define MMC_RSP_R6	(MMC_RSP_SHORT|MMC_RSP_CRC)
 
 	unsigned int		retries;	/* max number of retries */
 	unsigned int		error;		/* command error */
@@ -88,6 +89,8 @@ struct mmc_card;
 
 extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
+extern int mmc_wait_for_app_cmd(struct mmc_host *, unsigned int,
+	struct mmc_command *, int);
 
 extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card);
 
include/linux/mmc/protocol.h +18 -1
diff -uNp linux/include/linux/mmc/protocol.h linux-wbsd/include/linux/mmc/protocol.h
@@ -76,6 +76,16 @@
 #define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
 #define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1b */
 
+/* SD commands                           type  argument     response */
+  /* class 8 */
+/* This is basically the same command as for MMC with some quirks. */
+#define SD_SEND_RELATIVE_ADDR     3   /* ac                      R6  */
+
+  /* Application commands */
+#define SD_APP_SET_BUS_WIDTH      6   /* ac   [1:0] bus width    R1  */
+#define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
+#define SD_APP_SEND_SCR          51   /* adtc                    R1  */
+
 /*
   MMC status in R1
   Type
@@ -113,7 +123,7 @@
 #define R1_STATUS(x)            (x & 0xFFFFE000)
 #define R1_CURRENT_STATE(x)    	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
 #define R1_READY_FOR_DATA	(1 << 8)	/* sx, a */
-#define R1_APP_CMD		(1 << 7)	/* sr, c */
+#define R1_APP_CMD		(1 << 5)	/* sr, c */
 
 /* These are unpacked versions of the actual responses */
 
@@ -199,5 +209,12 @@ struct _mmc_csd {
 #define CSD_SPEC_VER_2      2           /* Implements system specification 2.0 - 2.2 */
 #define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 */
 
+
+/*
+ * SD bus widths
+ */
+#define SD_BUS_WIDTH_1      0
+#define SD_BUS_WIDTH_4      2
+
 #endif  /* MMC_MMC_PROTOCOL_H */
 

Common subdirectories: linux/include/linux/mmc/.svn and linux-wbsd/include/linux/mmc/.svn

drivers/mmc/mmc.c +435 -85

617 lines not on this page · raw message

drivers/mmc/mmc_block.c +8 -2
@@ -95,6 +95,10 @@ static int mmc_blk_open(struct inode *in
 		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;
@@ -387,6 +391,7 @@ static struct mmc_blk_data *mmc_blk_allo
 		md->disk->private_data = md;
 		md->disk->queue = md->queue.queue;
 		md->disk->driverfs_dev = &card->dev;
+		md->disk->flags |= GENHD_FL_REMOVABLE;
 
 		sprintf(md->disk->disk_name, "mmcblk%d", devidx);
 		sprintf(md->disk->devfs_name, "mmc/blk%d", devidx);
@@ -444,9 +449,10 @@ static int mmc_blk_probe(struct mmc_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);
drivers/mmc/mmc_sysfs.c +2 -0
@@ -163,6 +163,7 @@ MMC_ATTR(cid, "%08x%08x%08x%08x\n", card
 	card->raw_cid[2], card->raw_cid[3]);
 MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
 	card->raw_csd[2], card->raw_csd[3]);
+MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
 MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
 MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
 MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
@@ -174,6 +175,7 @@ MMC_ATTR(serial, "0x%08x\n", card->cid.s
 static struct device_attribute *mmc_dev_attributes[] = {
 	&dev_attr_cid,
 	&dev_attr_csd,
+	&dev_attr_scr,
 	&dev_attr_date,
 	&dev_attr_fwrev,
 	&dev_attr_hwrev,
#1 lore raw

Hi!

Quoted 5 lines

Here are the patches for Secure Digital support that I've been sitting on for a while. I tried to get some feedback on inclusion of this previously but since I didn't get any I'll just submit the thing. It was originally diffed against 2.6.10 but it applies to 2.6.11 just fine (only minor fuzz).

This is great! Hopefully it will mean no-more-binary-only-modules-on-zaurus...

Signature · 1 line
64 bytes from 195.113.31.123: icmp_seq=28 ttl=51 time=448769.1 ms         
#2 lore raw
In reply to Pierre Ossman

Hi Pierre,

Quoted 5 lines

Here are the patches for Secure Digital support that I've been sitting on for a while. I tried to get some feedback on inclusion of this previously but since I didn't get any I'll just submit the thing. It was originally diffed against 2.6.10 but it applies to 2.6.11 just fine (only minor fuzz).

lately I got a request for the support of a Bluetooth SD card. These are using SDIO and I think at the moment only memory cards are handled. Do you have any plans for SDIO support?

Regards

Marcel

#3 lore raw
Quoted 4 lines · Marcel Holtmann

Hi Pierre,

Quoted 11 lines
Quoted 4 lines

Here are the patches for Secure Digital support that I've been sitting on for a while. I tried to get some feedback on inclusion of this previously but since I didn't get any I'll just submit the thing. It was originally diffed against 2.6.10 but it applies to 2.6.11 just fine (only minor fuzz).

lately I got a request for the support of a Bluetooth SD card. These are using SDIO and I think at the moment only memory cards are handled. Do you have any plans for SDIO support?

I would if I had some hardware to play with *hint* *hint* ;)
The SDIO spec is publically available on the SD card associations web page so it shouldn't be too difficult to get some basic support. But I can't do much as long as I don't have any hardware to test it with. I might also need specs for the card itself. I haven't looked too much at SDIO at the moment.

Rgds
Pierre

#4 lore raw

Hi Pierre,

Quoted 5 lines
Quoted 3 lines

lately I got a request for the support of a Bluetooth SD card. These are using SDIO and I think at the moment only memory cards are handled. Do you have any plans for SDIO support?

I would if I had some hardware to play with *hint* *hint* ;)

I don't have one of these cards either :(

Quoted 5 lines

The SDIO spec is publically available on the SD card associations web page so it shouldn't be too difficult to get some basic support. But I can't do much as long as I don't have any hardware to test it with. I might also need specs for the card itself. I haven't looked too much at SDIO at the moment.

The Bluetooth HCI transport for SDIO is also available and I think most SD card manufactures are using it.

So what we need is a hardware sponsor. Any volunteers?

Regards

Marcel

#6 lore raw
In reply to Pierre Ossman
Quoted 5 lines · Pierre Ossman

Here are the patches for Secure Digital support that I've been sitting on for a while. I tried to get some feedback on inclusion of this previously but since I didn't get any I'll just submit the thing. It was originally diffed against 2.6.10 but it applies to 2.6.11 just fine (only minor fuzz).

Can we please come to a consensus about GEN_FL_REMOVABLE. After talking to other kernel developers, particularly in the block interface area, I am convinced that it is fundamentally incorrect to set this flag for MMC/SD devices.

Unfortunately, it appears that you're not convinced. This needs resolving since it is an interface issue.

Signature · 3 lines
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core
#7 lore raw
Quoted 8 lines · Russell King
Quoted 4 lines · Pierre Ossman

Here are the patches for Secure Digital support that I've been sitting on for a while. I tried to get some feedback on inclusion of this previously but since I didn't get any I'll just submit the thing. It was originally diffed against 2.6.10 but it applies to 2.6.11 just fine (only minor fuzz).

Quoted 10 lines

Can we please come to a consensus about GEN_FL_REMOVABLE. After talking to other kernel developers, particularly in the block interface area, I am convinced that it is fundamentally incorrect to set this flag for MMC/SD devices.

Unfortunately, it appears that you're not convinced. This needs resolving since it is an interface issue.

Oh, sorry. That part wasn't supposed to be included in there.
As I haven't found any applications depending on any specific behaviour then I'm quite content with your behaviour :) I can make a new patch or you can just undo that line once you've applied the current one.

Rgds
Pierre

#8 lore raw
Quoted 2 lines · Pierre Ossman

I can make a new patch or you can just undo that line once you've applied the current one.

I'd rather not just apply this patch - there's rather a lot there to just apply on top of what's already merged.

Is there any chance you can split it up into a smaller set of changes so it's more obvious what's going on at each stage please?

We'll also need to run this by Linus first, explaining why you believe it's now ok to merge this. (Added Linus...)

Signature · 3 lines
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core
#9 lore raw
Quoted 7 lines · Russell King
Quoted 3 lines · Pierre Ossman

I can make a new patch or you can just undo that line once you've applied the current one.

Quoted 7 lines

I'd rather not just apply this patch - there's rather a lot there to just apply on top of what's already merged.

Is there any chance you can split it up into a smaller set of changes so it's more obvious what's going on at each stage please?

Sure. I'll try to divide it into smaller pieces. It will result in some patches that are just there to prepare for the other ones though (i.e. they don't add any functionality by themselves).

Quoted 5 lines

We'll also need to run this by Linus first, explaining why you believe it's now ok to merge this. (Added Linus...)

First of, I can't really back up the claim that it isn't ok. The SDA has a paragraph about non-disclosure in their "IP Policy" (http://www.sdcard.org/membership/images/ippolicy.pdf) but it also states that exceptions can be granted.

Against this stands the new information that the SDA is changing its policy and making the specs public. This information comes from some of the guys at HP research and hasn't been confirmed by any public statement from SDA. The SDA have, however, already released the SDIO specs. Presumably as part of this new policy.

It was also pointed out in the previous thread by myself, Alan Cox and Ian Molton that SD specs have been publically available from different companies for quite some time. As such it is difficult for anyone to claim that these are secret and can be regulated by a NDA. The only part that hasn't been found in the wild is the spec for the 'secure' parts of the cards. But that also means that it isn't included in this patch so it shouldn't pose a problem.

As always, IANAL so I can't give any definite answer. But from my point of view they would have a very weak case if they tried to claim that the information in this patch is a trade secret.

Rgds
Pierre

#10 lore raw

Pierre Ossman:

Quoted 1 line

First of, I can't really back up the claim that it isn't ok. The SDA has a paragraph about non-disclosure in their "IP Policy" (http://www.sdcard.org/membership/images/ippolicy.pdf) but it also states that exceptions can be granted.

That IP policy covers their members and has no bearing on us as we have no agreements with them.

The code is "our" own so it isn't covered by any IP or copyright restrictions other than the GPL.

There aren't any patents relating to SD cards.

The simple sequences we use have been gleaned from various public documents (intel's website, SD card manufacturer data sheets, etc.) so nobody can claim we're using anything secret.

I therefore can't see a problem with including the code.

Richard

#11 lore raw
In reply to Pierre Ossman
Quoted 6 lines · Pierre Ossman
Quoted 3 lines · Russell King

We'll also need to run this by Linus first, explaining why you believe it's now ok to merge this. (Added Linus...)

Quoted 8 lines

It was also pointed out in the previous thread by myself, Alan Cox and Ian Molton that SD specs have been publically available from different companies for quite some time. As such it is difficult for anyone to claim that these are secret and can be regulated by a NDA. The only part that hasn't been found in the wild is the spec for the 'secure' parts of the cards. But that also means that it isn't included in this patch so it shouldn't pose a problem.

This issue doesn't seem to reach any kind of resolution so I figured I'd take a poke at the people responsible. :)

Just to back up the claim that the specs are in the open here are some links:

http://www.google.com/search?hl=en&q=%22Secure+Digital+Card%22+%22Product+Manual%22+site%3Asandisk.com&btnG=Google+Search

Which gives you several PDF:s with enough information to implement a SD host. The one I've been using is:

http://www.sandisk.com/download/Product%20Manuals/Product%20ManualSDCardv1.7.pdf

Rgds
Pierre

#12 lore raw

cover Secure Digital (SD) support

In reply to Russell King

As promised, here is the patch broken down into smaller pieces. The patch is now divided into six distinct parts:

* Protocol definitions.
* SD card initialisation.
* Reading read-only switch.
* Getting SCR register.
* Exposing SCR register through sysfs.
* Wide (4-bit) bus support.

Rgds
Pierre

#13 lore raw

Re: [PATCH][MMC][1/6] Secure Digital (SD) support : protocol

Protocol definitions.

The basic commands needed for the later patches. The R1_APP_CMD seems to be misdefined in protocol.h so this patch changes it.

include/linux/mmc/mmc.h +1 -0
Index: linux-sd/include/linux/mmc/mmc.h
===================================================================
@@ -37,6 +37,7 @@
 #define MMC_RSP_R1B	(MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_BUSY)
 #define MMC_RSP_R2	(MMC_RSP_LONG|MMC_RSP_CRC)
 #define MMC_RSP_R3	(MMC_RSP_SHORT)
+#define MMC_RSP_R6	(MMC_RSP_SHORT|MMC_RSP_CRC)
 
 	unsigned int		retries;	/* max number of retries */
 	unsigned int		error;		/* command error */
include/linux/mmc/protocol.h +11 -1
Index: linux-sd/include/linux/mmc/protocol.h
===================================================================
@@ -76,6 +76,16 @@
 #define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
 #define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1b */
 
+/* SD commands                           type  argument     response */
+  /* class 8 */
+/* This is basically the same command as for MMC with some quirks. */
+#define SD_SEND_RELATIVE_ADDR     3   /* ac                      R6  */
+
+  /* Application commands */
+#define SD_APP_SET_BUS_WIDTH      6   /* ac   [1:0] bus width    R1  */
+#define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
+#define SD_APP_SEND_SCR          51   /* adtc                    R1  */
+
 /*
   MMC status in R1
   Type
@@ -113,7 +123,7 @@
 #define R1_STATUS(x)            (x & 0xFFFFE000)
 #define R1_CURRENT_STATE(x)    	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
 #define R1_READY_FOR_DATA	(1 << 8)	/* sx, a */
-#define R1_APP_CMD		(1 << 7)	/* sr, c */
+#define R1_APP_CMD		(1 << 5)	/* sr, c */
 
 /* These are unpacked versions of the actual responses */
 
Applied
#14 lore raw

Re: [PATCH][MMC][1/6] Secure Digital (SD) support : protocol

Quoted 4 lines · Pierre Ossman

Protocol definitions.

The basic commands needed for the later patches. The R1_APP_CMD seems to be misdefined in protocol.h so this patch changes it.

Applied, thanks.

Signature · 3 lines
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core
#15 lore raw

Re: [PATCH][MMC][2/6] Secure Digital (SD) support : init

In reply to Pierre Ossman

SD card initialisation.

This patch contains the central parts of the SD support.

The system first tries to detect MMC cards, and if none are found then it procedes to look for an SD card. This is incorrect acording to SD specifications but I find it odd that MMC is supposed to cope with SD commands and not the other way around (since MMC is the older of the two). This behaviour is the one Windows uses and has posed no problems with any cards tested so far.

It provides flags for the card and host to mark them as SD. The host needs to be marked because the MMC layer needs to determine if it should send MMC or SD commands at points where no specific card is involved.

A new helper function called mmc_wait_for_app_cmd() is added to handle the APP commands which are used frequently with SD.

CID and CSD parsing are extended to handle SD formats.

include/linux/mmc/card.h +3 -0
Index: linux-sd/include/linux/mmc/card.h
===================================================================
@@ -47,6 +47,7 @@
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
 #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 */
 	u32			raw_cid[4];	/* raw card CID */
 	u32			raw_csd[4];	/* raw card CSD */
 	struct mmc_cid		cid;		/* card identification */
@@ -56,10 +57,12 @@
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #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_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_name(c)	((c)->cid.prod_name)
 #define mmc_card_id(c)		((c)->dev.bus_id)
include/linux/mmc/mmc.h +2 -0
Index: linux-sd/include/linux/mmc/mmc.h
===================================================================
@@ -88,6 +88,8 @@
 
 extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
+extern int mmc_wait_for_app_cmd(struct mmc_host *, unsigned int,
+	struct mmc_command *, int);
 
 extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card);
 
include/linux/mmc/host.h +4 -0
Index: linux-sd/include/linux/mmc/host.h
===================================================================
@@ -79,6 +79,10 @@
 	/* private data */
 	struct mmc_ios		ios;		/* current io bus settings */
 	u32			ocr;		/* the current OCR setting */
+	
+	unsigned int		mode;		/* current card mode of host */
+#define MMC_MODE_MMC		0
+#define MMC_MODE_SD		1
 
 	struct list_head	cards;		/* devices attached to this host */
 
drivers/mmc/mmc.c +251 -71

382 lines not on this page · raw message

#16 lore raw

Re: [PATCH][MMC][3/6] Secure Digital (SD) support : ro

In reply to Pierre Ossman

Read-only support.

This patch adds a new callback for the drivers to facilitate reading the SD card read-only switch. If the callback is not provided then a warning will be printed and it will default to write-enable.

The read-only switch is a host enforced read-only so the MMC block layer has been changed to not allow rw mounts of ro cards. It also prints a '(ro)' for read-only cards.

include/linux/mmc/card.h +3 -0
Index: linux-sd/include/linux/mmc/card.h
===================================================================
@@ -48,6 +48,7 @@
 #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 @@
 #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)
include/linux/mmc/host.h +1 -0
Index: linux-sd/include/linux/mmc/host.h
===================================================================
@@ -56,6 +56,7 @@
 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;
drivers/mmc/mmc_block.c +7 -2
Index: linux-sd/drivers/mmc/mmc_block.c
===================================================================
@@ -95,6 +95,10 @@
 		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;
@@ -400,9 +404,10 @@
 	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);
drivers/mmc/mmc.c +13 -1
Index: linux-sd/drivers/mmc/mmc.c
===================================================================
@@ -726,8 +726,20 @@
 			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;
+				
+				if (!host->ops->get_ro) {
+					printk(KERN_WARNING "%s: host does not "
+						"support reading read-only "
+						"switch. assuming write-enable.\n",
+						host->host_name);
+				}
+				else {
+					if (host->ops->get_ro(host))
+						mmc_card_set_readonly(card);
+				}
+			}
 		}
 		else {
 			cmd.opcode = MMC_SET_RELATIVE_ADDR;
#17 lore raw

Re: [PATCH][MMC][4/6] Secure Digital (SD) support : SCR

In reply to Pierre Ossman

SCR download.

This patch downloads the SCR register from the card. Unlike the other registers this one is transfered over the data bus. That required some changes to other routines to allow a card to be selected after the host was aquired.

This is one of the more error prone parts. The transfer is very small (8 bytes) and might trigger corner cases in the drivers.

include/linux/mmc/card.h +9 -0
Index: linux-sd/include/linux/mmc/card.h
===================================================================
@@ -33,6 +33,13 @@
 	unsigned int		capacity;
 };
 
+struct sd_scr {
+	unsigned char		sda_vsn;
+	unsigned char		bus_widths;
+#define SD_SCR_BUS_WIDTH_1	(1<<0)
+#define SD_SCR_BUS_WIDTH_4	(1<<2)
+};
+
 struct mmc_host;
 
 /*
@@ -51,8 +58,10 @@
 #define MMC_STATE_READONLY	(1<<4)		/* card is read-only */
 	u32			raw_cid[4];	/* raw card CID */
 	u32			raw_csd[4];	/* raw card CSD */
+	u32			raw_scr[2];	/* raw card SCR */
 	struct mmc_cid		cid;		/* card identification */
 	struct mmc_csd		csd;		/* card specific */
+	struct sd_scr		scr;		/* extra SD information */
 };
 
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
drivers/mmc/mmc.c +134 -10

186 lines not on this page · raw message

#18 lore raw

Re: [PATCH][MMC][5/6] Secure Digital (SD) support : sysfs

In reply to Pierre Ossman

SCR sysfs access.

This provides access to the SCR register via sysfs. Since the latest bk contains some changes to the sysfs part this probably needs updating. The patch is trivial though so it should be easy.

drivers/mmc/mmc_sysfs.c +2 -0
Index: linux-sd/drivers/mmc/mmc_sysfs.c
===================================================================
@@ -163,6 +163,7 @@
 	card->raw_cid[2], card->raw_cid[3]);
 MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
 	card->raw_csd[2], card->raw_csd[3]);
+MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
 MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
 MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
 MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
@@ -174,6 +175,7 @@
 static struct device_attribute *mmc_dev_attributes[] = {
 	&dev_attr_cid,
 	&dev_attr_csd,
+	&dev_attr_scr,
 	&dev_attr_date,
 	&dev_attr_fwrev,
 	&dev_attr_hwrev,
#19 lore raw

Re: [PATCH][MMC][6/6] Secure Digital (SD) support : wide bus

In reply to Pierre Ossman

Wide bus support.

This adds 4-bit bus support to the MMC layer. It is designed to (hopefully) be compatible with a future 4-bit MMC implementation. This is done by seperating the three different instances of bus width defines:

* Protocol definition: SD_BUS_WIDTH_x
* SCR contents: SD_SCR_BUS_WIDTH_x
* Host mode: MMC_BUS_WIDTH_x

They have the same values atm but drivers should not rely on this. MMC_BUS_WIDTH_x is not meant to be SD specific.

The MMC layer changes bus width when a card is selected. This is because the SD spec says that a card is only required to keep a certain bus width as long as it's selected.

Layers further up do not need to know which mode the host/card is in. They will only see a change in speed.

include/linux/mmc/host.h +9 -0
Index: linux-sd/include/linux/mmc/host.h
===================================================================
@@ -51,6 +51,11 @@
 #define MMC_POWER_OFF		0
 #define MMC_POWER_UP		1
 #define MMC_POWER_ON		2
+
+	unsigned char	bus_width;		/* data bus width */
+
+#define MMC_BUS_WIDTH_1		0
+#define MMC_BUS_WIDTH_4		2
 };
 
 struct mmc_host_ops {
@@ -69,7 +74,11 @@
 	unsigned int		f_max;
 	u32			ocr_avail;
 	char			host_name[8];
+	
+	unsigned long		caps;		/* Host capabilities */
 
+#define MMC_CAP_4_BIT_DATA	(1 << 0)	/* Can the host do 4 bit transfers */
+
 	/* host specific block data */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
 	unsigned short		max_hw_segs;	/* see blk_queue_max_hw_segments */
include/linux/mmc/protocol.h +7 -0
Index: linux-sd/include/linux/mmc/protocol.h
===================================================================
@@ -209,5 +209,12 @@
 #define CSD_SPEC_VER_2      2           /* Implements system specification 2.0 - 2.2 */
 #define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 */
 
+
+/*
+ * SD bus widths
+ */
+#define SD_BUS_WIDTH_1      0
+#define SD_BUS_WIDTH_4      2
+
 #endif  /* MMC_MMC_PROTOCOL_H */
 
drivers/mmc/mmc.c +36 -0
Index: linux-sd/drivers/mmc/mmc.c
===================================================================
@@ -335,6 +335,40 @@
 	if (err != MMC_ERR_NONE)
 		return err;
 
+	/*
+	 * Default bus width is 1 bit.
+	 */
+	host->ios.bus_width = MMC_BUS_WIDTH_1;
+	
+	/*
+	 * We can only change the bus width of the selected
+	 * card so therefore we have to put the handling
+	 * here.
+	 */
+	if (host->caps & MMC_CAP_4_BIT_DATA) {
+		/*
+		 * The card is in 1 bit mode by default so
+		 * we only need to change if it supports the
+		 * wider version.
+		 */
+		if (mmc_card_sd(card) &&
+			(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+			struct mmc_command cmd;
+			cmd.opcode = SD_APP_SET_BUS_WIDTH;
+			cmd.arg = SD_BUS_WIDTH_4;
+			cmd.flags = MMC_RSP_R1;
+			
+			err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
+				CMD_RETRIES);
+			if (err != MMC_ERR_NONE)
+				return err;
+			
+			host->ios.bus_width = MMC_BUS_WIDTH_4;
+		}
+	}
+
+	host->ops->set_ios(host, &host->ios);
+
 	return MMC_ERR_NONE;
 }
 
@@ -644,6 +678,7 @@
 	host->ios.vdd = bit;
 	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
 	host->ios.power_mode = MMC_POWER_UP;
+	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ops->set_ios(host, &host->ios);
 
 	mmc_delay(1);
@@ -661,6 +696,7 @@
 	host->ios.vdd = 0;
 	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
 	host->ios.power_mode = MMC_POWER_OFF;
+	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ops->set_ios(host, &host->ios);
 }
 
#20 lore raw

Re: [PATCH][MMC][7/6] Secure Digital (SD) support : Copyright

In reply to Pierre Ossman

I suppose a copyright notice is appropriate to indicate the origins of the SD additions.

mmc.c is the only file with substancial changes so it should be enough with a notice there.

drivers/mmc/mmc.c +2 -0
Index: linux-sd/drivers/mmc/mmc.c
===================================================================
@@ -2,6 +2,8 @@
  *  linux/drivers/mmc/mmc.c
  *
  *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
+ *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
+ *  SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as