Module Name:    src
Committed By:   kiyohara
Date:           Thu Oct  7 12:40:34 UTC 2010

Modified Files:
        src/sys/dev/sdmmc: sdmmc.c sdmmc_cis.c sdmmc_io.c sdmmc_ioreg.h

Log Message:
Fix read CIS.  And pass to attach args the standard function interface code.


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/sdmmc/sdmmc.c
cvs rdiff -u -r1.1 -r1.2 src/sys/dev/sdmmc/sdmmc_cis.c \
    src/sys/dev/sdmmc/sdmmc_ioreg.h
cvs rdiff -u -r1.4 -r1.5 src/sys/dev/sdmmc/sdmmc_io.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/sdmmc/sdmmc.c
diff -u src/sys/dev/sdmmc/sdmmc.c:1.5 src/sys/dev/sdmmc/sdmmc.c:1.6
--- src/sys/dev/sdmmc/sdmmc.c:1.5	Thu Oct  7 12:24:23 2010
+++ src/sys/dev/sdmmc/sdmmc.c	Thu Oct  7 12:40:34 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmc.c,v 1.5 2010/10/07 12:24:23 kiyohara Exp $	*/
+/*	$NetBSD: sdmmc.c,v 1.6 2010/10/07 12:40:34 kiyohara Exp $	*/
 /*	$OpenBSD: sdmmc.c,v 1.18 2009/01/09 10:58:38 jsg Exp $	*/
 
 /*
@@ -50,7 +50,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.5 2010/10/07 12:24:23 kiyohara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.6 2010/10/07 12:40:34 kiyohara Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -376,6 +376,7 @@
 		memset(&saa, 0, sizeof saa);
 		saa.manufacturer = sf->cis.manufacturer;
 		saa.product = sf->cis.product;
+		saa.interface = sf->interface;
 		saa.sf = sf;
 
 		sf->child =

Index: src/sys/dev/sdmmc/sdmmc_cis.c
diff -u src/sys/dev/sdmmc/sdmmc_cis.c:1.1 src/sys/dev/sdmmc/sdmmc_cis.c:1.2
--- src/sys/dev/sdmmc/sdmmc_cis.c:1.1	Tue Apr 21 03:00:30 2009
+++ src/sys/dev/sdmmc/sdmmc_cis.c	Thu Oct  7 12:40:34 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmc_cis.c,v 1.1 2009/04/21 03:00:30 nonaka Exp $	*/
+/*	$NetBSD: sdmmc_cis.c,v 1.2 2010/10/07 12:40:34 kiyohara Exp $	*/
 /*	$OpenBSD: sdmmc_cis.c,v 1.1 2006/06/01 21:53:41 uwe Exp $	*/
 
 /*
@@ -20,7 +20,7 @@
 /* Routines to decode the Card Information Structure of SD I/O cards */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc_cis.c,v 1.1 2009/04/21 03:00:30 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_cis.c,v 1.2 2010/10/07 12:40:34 kiyohara Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -29,45 +29,147 @@
 #include <dev/sdmmc/sdmmcdevs.h>
 #include <dev/sdmmc/sdmmcvar.h>
 
-#ifdef SDMMC_DEBUG
+#include <dev/pcmcia/pcmciareg.h>
+
+#ifdef SDMMCCISDEBUG
 #define DPRINTF(s)	printf s
 #else
 #define DPRINTF(s)	/**/
 #endif
 
 static uint32_t sdmmc_cisptr(struct sdmmc_function *);
+static void decode_funce_common(struct sdmmc_function *, struct sdmmc_cis *,
+				int, uint32_t);
+static void decode_funce_function(struct sdmmc_function *, struct sdmmc_cis *,
+				  int, uint32_t);
+static void decode_vers_1(struct sdmmc_function *, struct sdmmc_cis *, int,
+			  uint32_t);
+
 static uint32_t
 sdmmc_cisptr(struct sdmmc_function *sf)
 {
 	uint32_t cisptr = 0;
 
-	/* XXX where is the per-function CIS pointer register? */
-	if (sf->number != 0)
-		return SD_IO_CIS_START;
-
-	/* XXX is the CIS pointer stored in little-endian format? */
-	cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 0) << 0;
-	cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 1) << 8;
-	cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 2) << 16;
+	/* CIS pointer stored in little-endian format. */
+	if (sf->number == 0) {
+		cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 0) << 0;
+		cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 1) << 8;
+		cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 2) << 16;
+	} else {
+		struct sdmmc_function *sf0 = sf->sc->sc_fn0;
+		int num = sf->number;
+
+		cisptr |= sdmmc_io_read_1(sf0, SD_IO_FBR(num) + 9) << 0;
+		cisptr |= sdmmc_io_read_1(sf0, SD_IO_FBR(num) + 10) << 8;
+		cisptr |= sdmmc_io_read_1(sf0, SD_IO_FBR(num) + 11) << 16;
+	}
 	return cisptr;
 }
 
+static void
+decode_funce_common(struct sdmmc_function *sf, struct sdmmc_cis *cis,
+		    int tpllen, uint32_t reg)
+{
+	const static int speed_val[] =
+	    { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
+	const static int speed_unit[] = { 10, 100, 1000, 10000, };
+	struct sdmmc_function *sf0 = sf->sc->sc_fn0;
+	device_t dev = sf->sc->sc_dev;
+	int fn0_blk_size, max_tran_speed;
+
+	if (sf->number != 0) {
+		aprint_error_dev(dev,
+		    "CISTPL_FUNCE(common) found in function\n");
+		return;
+	}
+	if (tpllen < 4) {
+		aprint_error_dev(dev, "CISTPL_FUNCE(common) too short\n");
+		return;
+	}
+
+	fn0_blk_size = sdmmc_io_read_1(sf0, reg++);
+	fn0_blk_size |= sdmmc_io_read_1(sf0, reg++) << 8;
+	max_tran_speed = sdmmc_io_read_1(sf0, reg++);
+	sf->csd.tran_speed =
+	    speed_val[max_tran_speed >> 3] * speed_unit[max_tran_speed & 7];
+
+	DPRINTF(
+	    ("CISTPL_FUNCE: FN0_BLK_SIZE=0x%x, MAX_TRAN_SPEED=0x%x(%dkHz)\n",
+	    fn0_blk_size, max_tran_speed, sf->csd.tran_speed));
+}
+
+static void
+decode_funce_function(struct sdmmc_function *sf, struct sdmmc_cis *cis,
+		      int tpllen, uint32_t reg)
+{
+	struct sdmmc_function *sf0 = sf->sc->sc_fn0;
+	device_t dev = sf->sc->sc_dev;
+	int sdiox_cccrx, sdiox, max_blk_size;
+
+	sdiox_cccrx = sdmmc_io_read_1(sf0, SD_IO_CCCR_CCCR_SDIO_REV);
+	sdiox = SD_IO_CCCR_SDIO_REV(sdiox_cccrx);
+
+	if (sf->number == 0) {
+		aprint_error_dev(dev,
+		    "CISTPL_FUNCE(function) found in common\n");
+		return;
+	}
+	if (sdiox == CCCR_SDIO_REV_1_00 && tpllen < 0x1c) {
+		aprint_error_dev(dev,
+		    "CISTPL_FUNCE(function) too short (v1.00)\n");
+		return;
+	} else if (sdiox != CCCR_SDIO_REV_1_00 && tpllen < 0x2a) {
+		aprint_error_dev(dev, "CISTPL_FUNCE(function) too short\n");
+		return;
+	}
+
+	max_blk_size = sdmmc_io_read_1(sf0, reg + 11);
+	max_blk_size |= sdmmc_io_read_1(sf0, reg + 12) << 8;
+
+	DPRINTF(("CISTPL_FUNCE: MAX_BLK_SIZE=0x%x\n", max_blk_size));
+}
+
+static void
+decode_vers_1(struct sdmmc_function *sf, struct sdmmc_cis *cis, int tpllen,
+	      uint32_t reg)
+{
+	struct sdmmc_function *sf0 = sf->sc->sc_fn0;
+	device_t dev = sf->sc->sc_dev;
+	int start, ch, count, i;
+
+	if (tpllen < 2) {
+		aprint_error_dev(dev, "CISTPL_VERS_1 too short\n");
+		return;
+	}
+
+	cis->cis1_major = sdmmc_io_read_1(sf0, reg++);
+	cis->cis1_minor = sdmmc_io_read_1(sf0, reg++);
+
+	for (count = 0, start = 0, i = 0; (count < 4) && ((i + 4) < 256); i++) {
+		ch = sdmmc_io_read_1(sf0, reg + i);
+		if (ch == 0xff)
+			break;
+		cis->cis1_info_buf[i] = ch;
+		if (ch == 0) {
+			cis->cis1_info[count] = cis->cis1_info_buf + start;
+			start = i + 1;
+			count++;
+		}
+	}
+
+	DPRINTF(("CISTPL_VERS_1\n"));
+}
+
 int
 sdmmc_read_cis(struct sdmmc_function *sf, struct sdmmc_cis *cis)
 {
+	struct sdmmc_function *sf0 = sf->sc->sc_fn0;
 	device_t dev = sf->sc->sc_dev;
 	uint32_t reg;
-	uint8_t tplcode;
-	uint8_t tpllen;
-	int start, ch, count;
-	int i;
+	uint8_t tplcode, tpllen;
 
 	memset(cis, 0, sizeof *cis);
 
-	/* XXX read per-function CIS */
-	if (sf->number != 0)
-		return 1;
-
 	reg = sdmmc_cisptr(sf);
 	if (reg < SD_IO_CIS_START ||
 	    reg >= (SD_IO_CIS_START + SD_IO_CIS_SIZE - 16)) {
@@ -76,68 +178,81 @@
 	}
 
 	for (;;) {
-		tplcode = sdmmc_io_read_1(sf, reg++);
-		tpllen = sdmmc_io_read_1(sf, reg++);
+		tplcode = sdmmc_io_read_1(sf0, reg++);
+
+		if (tplcode == PCMCIA_CISTPL_NULL) {
+			DPRINTF((" 00\nCISTPL_NONE\n"));
+			continue;
+		}
 
-		if (tplcode == 0xff || tpllen == 0) {
+		tpllen = sdmmc_io_read_1(sf0, reg++);
+		if (tplcode == PCMCIA_CISTPL_END || tpllen == 0) {
 			if (tplcode != 0xff)
 				aprint_error_dev(dev, "CIS parse error at %d, "
 				    "tuple code %#x, length %d\n",
 				    reg, tplcode, tpllen);
+			else {
+				DPRINTF((" ff\nCISTPL_END\n"));
+			}
 			break;
 		}
 
+#ifdef SDMMCCISDEBUG
+		{ 
+			int i;
+
+			/* print the tuple */
+			DPRINTF((" %02x %02x", tplcode, tpllen));
+
+			for (i = 0; i < tpllen; i++) {
+				DPRINTF((" %02x",
+				    sdmmc_io_read_1(sf0, reg + i)));
+				if ((i % 16) == 13)
+					DPRINTF(("\n"));
+			}
+			if ((i % 16) != 14)
+				DPRINTF(("\n"));
+		}
+#endif
+
 		switch (tplcode) {
-		case SD_IO_CISTPL_FUNCID:
+		case PCMCIA_CISTPL_FUNCE:
+			if (sdmmc_io_read_1(sf0, reg++) == 0)
+				decode_funce_common(sf, cis, tpllen, reg);
+			else
+				decode_funce_function(sf, cis, tpllen, reg);
+			reg += (tpllen - 1);
+			break;
+
+		case PCMCIA_CISTPL_FUNCID:
 			if (tpllen < 2) {
 				aprint_error_dev(dev,
 				    "bad CISTPL_FUNCID length\n");
 				reg += tpllen;
 				break;
 			}
-			cis->function = sdmmc_io_read_1(sf, reg);
+			cis->function = sdmmc_io_read_1(sf0, reg);
+			DPRINTF(("CISTPL_FUNCID\n"));
 			reg += tpllen;
 			break;
 
-		case SD_IO_CISTPL_MANFID:
+		case PCMCIA_CISTPL_MANFID:
 			if (tpllen < 4) {
 				aprint_error_dev(dev,
 				    "bad CISTPL_MANFID length\n");
 				reg += tpllen;
 				break;
 			}
-			cis->manufacturer = sdmmc_io_read_1(sf, reg++);
-			cis->manufacturer |= sdmmc_io_read_1(sf, reg++) << 8;
-			cis->product = sdmmc_io_read_1(sf, reg++);
-			cis->product |= sdmmc_io_read_1(sf, reg++) << 8;
+			cis->manufacturer = sdmmc_io_read_1(sf0, reg++);
+			cis->manufacturer |= sdmmc_io_read_1(sf0, reg++) << 8;
+			cis->product = sdmmc_io_read_1(sf0, reg++);
+			cis->product |= sdmmc_io_read_1(sf0, reg++) << 8;
+			DPRINTF(("CISTPL_MANFID\n"));
 			break;
 
-		case SD_IO_CISTPL_VERS_1:
-			if (tpllen < 2) {
-				aprint_error_dev(dev,
-				    "CISTPL_VERS_1 too short\n");
-				reg += tpllen;
-				break;
-			}
-
-			cis->cis1_major = sdmmc_io_read_1(sf, reg++);
-			cis->cis1_minor = sdmmc_io_read_1(sf, reg++);
-
-			for (count = 0, start = 0, i = 0;
-			     (count < 4) && ((i + 4) < 256); i++) {
-				ch = sdmmc_io_read_1(sf, reg + i);
-				if (ch == 0xff)
-					break;
-				cis->cis1_info_buf[i] = ch;
-				if (ch == 0) {
-					cis->cis1_info[count] =
-					    cis->cis1_info_buf + start;
-					start = i + 1;
-					count++;
-				}
-			}
-
-			reg += tpllen - 2;
+		case PCMCIA_CISTPL_VERS_1:
+			decode_vers_1(sf, cis, tpllen, reg);
+			reg += tpllen;
 			break;
 
 		default:
@@ -176,15 +291,6 @@
 	    cis->manufacturer, cis->product);
 
 	printf("%s: function %d: ", device_xname(dev), sf->number);
-	switch (sf->cis.function) {
-	case SDMMC_FUNCTION_WLAN:
-		printf("wireless network adapter");
-		break;
-
-	default:
-		printf("unknown function (%d)", sf->cis.function);
-		break;
-	}
 	printf("\n");
 }
 
Index: src/sys/dev/sdmmc/sdmmc_ioreg.h
diff -u src/sys/dev/sdmmc/sdmmc_ioreg.h:1.1 src/sys/dev/sdmmc/sdmmc_ioreg.h:1.2
--- src/sys/dev/sdmmc/sdmmc_ioreg.h:1.1	Tue Apr 21 03:00:30 2009
+++ src/sys/dev/sdmmc/sdmmc_ioreg.h	Thu Oct  7 12:40:34 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmc_ioreg.h,v 1.1 2009/04/21 03:00:30 nonaka Exp $	*/
+/*	$NetBSD: sdmmc_ioreg.h,v 1.2 2010/10/07 12:40:34 kiyohara Exp $	*/
 /*	$OpenBSD: sdmmc_ioreg.h,v 1.4 2007/06/02 01:48:37 uwe Exp $	*/
 
 /*
@@ -56,9 +56,8 @@
 
 /* SD R4 response (IO OCR) */
 #define SD_IO_OCR_MEM_READY		(1<<31)
-#define SD_IO_OCR_NUM_FUNCTIONS(ocr)	(((ocr) >> 28) & 0x3)
-/* XXX big fat memory present "flag" because we don't know better */
-#define SD_IO_OCR_MEM_PRESENT		(0xf<<24)
+#define SD_IO_OCR_NUM_FUNCTIONS(ocr)	(((ocr) >> 28) & 0x7)
+#define SD_IO_OCR_MEM_PRESENT		(1<<27)
 #define SD_IO_OCR_MASK			0x00fffff0
 
 /* Card Common Control Registers (CCCR) */
@@ -68,13 +67,17 @@
 #define SD_IO_CCCR_CCCR_REV(r)		((r) & 0xf)
 #define  CCCR_CCCR_REV_1_00		0
 #define  CCCR_CCCR_REV_1_10		1
+#define  CCCR_CCCR_REV_1_20		2
 #define SD_IO_CCCR_SDIO_REV(r)		(((r) >> 4) & 0xf)
 #define  CCCR_SDIO_REV_1_00		0
 #define  CCCR_SDIO_REV_1_10		1
+#define  CCCR_SDIO_REV_1_20		2	/* (unreleased) */
+#define  CCCR_SDIO_REV_2_00		3
 #define SD_IO_CCCR_SPEC_REV		0x01
 #define SD_IO_CCCR_SD_PHYS_SPEC_VER(r)	((r) & 0xf)
 #define  CCCR_SD_PHYS_SPEC_VER_1_01	0
 #define  CCCR_SD_PHYS_SPEC_VER_1_10	1
+#define  CCCR_SD_PHYS_SPEC_VER_2_00	2
 #define SD_IO_CCCR_FN_ENABLE		0x02
 #define SD_IO_CCCR_FN_IOREADY		0x03
 #define SD_IO_CCCR_FN_INTEN		0x04
@@ -83,8 +86,8 @@
 #define SD_IO_CCCR_CTL			0x06
 #define  CCCR_CTL_RES			(1<<3)
 #define SD_IO_CCCR_BUS_WIDTH		0x07
-#define  CCCR_BUS_WIDTH_4		(1<<1)
-#define  CCCR_BUS_WIDTH_1		(1<<0)
+#define  CCCR_BUS_WIDTH_4		(2<<0)
+#define  CCCR_BUS_WIDTH_1		(0<<0)
 #define SD_IO_CCCR_CAPABILITY		0x08
 #define  CCCR_CAPS_SDC			(1<<0)
 #define  CCCR_CAPS_SMB			(1<<1) /* Multi-Block support */
@@ -104,22 +107,29 @@
 #define SD_IO_CCCR_FN_READY_FLG		0x0f
 #define SD_IO_CCCR_FN0_BLKSIZ		0x10 /* 0x10-0x11 */
 #define SD_IO_CCCR_POWER_CTL		0x12
+#define SD_IO_CCCR_HIGH_SPEED		0x13
+#define  CCCR_HIGH_SPEED_SHS		(1<<0) /* Support High-Speed */
+#define  CCCR_HIGH_SPEED_EHS		(1<<1) /* Enable High-Speed */
 
 /* Function Basic Registers (FBR) */
 #define SD_IO_FBR_START			0x00100
-#define SD_IO_FBR_SIZE			0x00700
+#define SD_IO_FBR_SIZE			0x100
+#define SD_IO_FBR(func)	((((func) - 1) * SD_IO_FBR_SIZE) + SD_IO_FBR_START)
+#define  FBR_STD_FUNC_IF_CODE(v)	((v) & 0x0f)
 
 /* Card Information Structure (CIS) */
 #define SD_IO_CIS_START			0x01000
 #define SD_IO_CIS_SIZE			0x17000
 
-/* CIS tuple codes (based on PC Card 16) */
-#define SD_IO_CISTPL_VERS_1		0x15
-#define SD_IO_CISTPL_MANFID		0x20
-#define SD_IO_CISTPL_FUNCID		0x21
-#define SD_IO_CISTPL_FUNCE		0x22
-
-/* CISTPL_FUNCID codes */
-#define SDMMC_FUNCTION_WLAN		0x0c
+/* SDIO Standard Function Interface code */
+#define SD_IO_SFIC_NO_STANDARD		0x0
+#define SD_IO_SFIC_UART			0x1
+#define SD_IO_SFIC_TYPEA_BLUETOOTH	0x2	/* Type-A Bluetooth */
+#define SD_IO_SFIC_TYPEB_BLUETOOTH	0x3	/* Type-B Bluetooth */
+#define SD_IO_SFIC_GPS			0x4
+#define SD_IO_SFIC_CAMERA		0x5
+#define SD_IO_SFIC_PHS			0x6
+#define SD_IO_SFIC_WLAN			0x7
+#define SD_IO_SFIC_ATA			0x8	/* Embedded SDIO-ATA */
 
 #endif	/* _SDMMC_IOREG_H_ */

Index: src/sys/dev/sdmmc/sdmmc_io.c
diff -u src/sys/dev/sdmmc/sdmmc_io.c:1.4 src/sys/dev/sdmmc/sdmmc_io.c:1.5
--- src/sys/dev/sdmmc/sdmmc_io.c:1.4	Thu Oct  7 12:28:34 2010
+++ src/sys/dev/sdmmc/sdmmc_io.c	Thu Oct  7 12:40:34 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmc_io.c,v 1.4 2010/10/07 12:28:34 kiyohara Exp $	*/
+/*	$NetBSD: sdmmc_io.c,v 1.5 2010/10/07 12:40:34 kiyohara Exp $	*/
 /*	$OpenBSD: sdmmc_io.c,v 1.10 2007/09/17 01:33:33 krw Exp $	*/
 
 /*
@@ -20,7 +20,7 @@
 /* Routines for SD I/O cards. */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.4 2010/10/07 12:28:34 kiyohara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.5 2010/10/07 12:40:34 kiyohara Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -187,12 +187,20 @@
 int
 sdmmc_io_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
 {
+	struct sdmmc_function *sf0 = sc->sc_fn0;
 	int error = 0;
+	uint8_t reg;
 
 	SDMMC_LOCK(sc);
 
 	if (sf->number == 0) {
-		sdmmc_io_write_1(sf, SD_IO_CCCR_BUS_WIDTH, CCCR_BUS_WIDTH_1);
+		sf->width = 1;
+		reg = sdmmc_io_read_1(sf, SD_IO_CCCR_CAPABILITY);
+		if (!(reg & CCCR_CAPS_LSC) || (reg & CCCR_CAPS_4BLS)) {
+			sdmmc_io_write_1(sf, SD_IO_CCCR_BUS_WIDTH,
+			    CCCR_BUS_WIDTH_4);
+			sf->width = 4;
+		}
 
 		error = sdmmc_read_cis(sf, &sf->cis);
 		if (error) {
@@ -208,6 +216,15 @@
 			sdmmc_print_cis(sf);
 #endif
 
+		reg = sdmmc_io_read_1(sf, SD_IO_CCCR_HIGH_SPEED);
+		if (reg & CCCR_HIGH_SPEED_SHS) {
+			reg |= CCCR_HIGH_SPEED_EHS;
+			sdmmc_io_write_1(sf, SD_IO_CCCR_HIGH_SPEED, reg);
+			sf->csd.tran_speed = 50000;	/* 50MHz */
+
+			/* Wait 400KHz x 8 clock */
+			delay(1);
+		}
 		if (sc->sc_busclk > sf->csd.tran_speed)
 			sc->sc_busclk = sf->csd.tran_speed;
 		error =
@@ -215,6 +232,25 @@
 		if (error)
 			aprint_error_dev(sc->sc_dev,
 			    "can't change bus clock\n");
+	} else {
+		reg = sdmmc_io_read_1(sf0, SD_IO_FBR(sf->number) + 0x000);
+		sf->interface = FBR_STD_FUNC_IF_CODE(reg);
+		if (sf->interface == 0x0f)
+			sf->interface =
+			    sdmmc_io_read_1(sf0, SD_IO_FBR(sf->number) + 0x001);
+		error = sdmmc_read_cis(sf, &sf->cis);
+		if (error) {
+			aprint_error_dev(sc->sc_dev, "couldn't read CIS\n");
+			SET(sf->flags, SFF_ERROR);
+			goto out;
+		}
+
+		sdmmc_check_cis_quirks(sf);
+
+#ifdef SDMMC_DEBUG
+		if (sdmmcdebug)
+			sdmmc_print_cis(sf);
+#endif
 	}
 
 out:

Reply via email to