sdio: store vendor strings

Store vendor strings found in CISTPL_VERS_1 so that function drivers
can access them.

Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 1cc1171..733ac95 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -187,6 +187,9 @@
 
 	sdio_free_common_cis(card);
 
+	if (card->info)
+		kfree(card->info);
+
 	kfree(card);
 }
 
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 683d917..0713a8c 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -211,6 +211,9 @@
 
 	sdio_free_func_cis(func);
 
+	if (func->info)
+		kfree(func->info);
+
 	kfree(func);
 }
 
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index 1d03f12..d5e51b1 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -23,6 +23,54 @@
 #include "sdio_cis.h"
 #include "sdio_ops.h"
 
+static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
+			 const unsigned char *buf, unsigned size)
+{
+	unsigned i, nr_strings;
+	char **buffer, *string;
+
+	buf += 2;
+	size -= 2;
+
+	nr_strings = 0;
+	for (i = 0; i < size; i++) {
+		if (buf[i] == 0xff)
+			break;
+		if (buf[i] == 0)
+			nr_strings++;
+	}
+
+	if (buf[i-1] != '\0') {
+		printk(KERN_WARNING "SDIO: ignoring broken CISTPL_VERS_1\n");
+		return 0;
+	}
+
+	size = i;
+
+	buffer = kzalloc(sizeof(char*) * nr_strings + size, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	string = (char*)(buffer + nr_strings);
+
+	for (i = 0; i < nr_strings; i++) {
+		buffer[i] = string;
+		strcpy(string, buf);
+		string += strlen(string) + 1;
+		buf += strlen(buf) + 1;
+	}
+
+	if (func) {
+		func->num_info = nr_strings;
+		func->info = (const char**)buffer;
+	} else {
+		card->num_info = nr_strings;
+		card->info = (const char**)buffer;
+	}
+
+	return 0;
+}
+
 static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func,
 			 const unsigned char *buf, unsigned size)
 {
@@ -119,7 +167,7 @@
 };
 
 static const struct cis_tpl cis_tpl_list[] = {
-	{	0x15,	3,	/* cistpl_vers_1 */	},
+	{	0x15,	3,	cistpl_vers_1		},
 	{	0x20,	4,	cistpl_manfid		},
 	{	0x21,	2,	/* cistpl_funcid */	},
 	{	0x22,	0,	cistpl_funce		},
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index a444431..0d508ac 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -108,6 +108,8 @@
 	struct sdio_cccr	cccr;		/* common card info */
 	struct sdio_cis		cis;		/* common tuple info */
 	struct sdio_func	*sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */
+	unsigned		num_info;	/* number of info strings */
+	const char		**info;		/* info strings */
 	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
 };
 
diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h
index da6a96c3..b050f4d 100644
--- a/include/linux/mmc/sdio_func.h
+++ b/include/linux/mmc/sdio_func.h
@@ -51,6 +51,9 @@
 
 	u8			tmpbuf[4];	/* DMA:able scratch buffer */
 
+	unsigned		num_info;	/* number of info strings */
+	const char		**info;		/* info strings */
+
 	struct sdio_func_tuple *tuples;
 };