Home | History | Annotate | Line # | Download | only in sdmmc
sdmmc_cis.c revision 1.1.8.2
      1  1.1.8.2  sborrill /*	$NetBSD: sdmmc_cis.c,v 1.1.8.2 2009/10/07 15:41:13 sborrill Exp $	*/
      2  1.1.8.2  sborrill /*	$OpenBSD: sdmmc_cis.c,v 1.1 2006/06/01 21:53:41 uwe Exp $	*/
      3  1.1.8.2  sborrill 
      4  1.1.8.2  sborrill /*
      5  1.1.8.2  sborrill  * Copyright (c) 2006 Uwe Stuehler <uwe (at) openbsd.org>
      6  1.1.8.2  sborrill  *
      7  1.1.8.2  sborrill  * Permission to use, copy, modify, and distribute this software for any
      8  1.1.8.2  sborrill  * purpose with or without fee is hereby granted, provided that the above
      9  1.1.8.2  sborrill  * copyright notice and this permission notice appear in all copies.
     10  1.1.8.2  sborrill  *
     11  1.1.8.2  sborrill  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12  1.1.8.2  sborrill  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  1.1.8.2  sborrill  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14  1.1.8.2  sborrill  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  1.1.8.2  sborrill  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  1.1.8.2  sborrill  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17  1.1.8.2  sborrill  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  1.1.8.2  sborrill  */
     19  1.1.8.2  sborrill 
     20  1.1.8.2  sborrill /* Routines to decode the Card Information Structure of SD I/O cards */
     21  1.1.8.2  sborrill 
     22  1.1.8.2  sborrill #include <sys/cdefs.h>
     23  1.1.8.2  sborrill __KERNEL_RCSID(0, "$NetBSD: sdmmc_cis.c,v 1.1.8.2 2009/10/07 15:41:13 sborrill Exp $");
     24  1.1.8.2  sborrill 
     25  1.1.8.2  sborrill #include <sys/param.h>
     26  1.1.8.2  sborrill #include <sys/systm.h>
     27  1.1.8.2  sborrill 
     28  1.1.8.2  sborrill #include <dev/sdmmc/sdmmc_ioreg.h>
     29  1.1.8.2  sborrill #include <dev/sdmmc/sdmmcdevs.h>
     30  1.1.8.2  sborrill #include <dev/sdmmc/sdmmcvar.h>
     31  1.1.8.2  sborrill 
     32  1.1.8.2  sborrill #ifdef SDMMC_DEBUG
     33  1.1.8.2  sborrill #define DPRINTF(s)	printf s
     34  1.1.8.2  sborrill #else
     35  1.1.8.2  sborrill #define DPRINTF(s)	/**/
     36  1.1.8.2  sborrill #endif
     37  1.1.8.2  sborrill 
     38  1.1.8.2  sborrill static uint32_t sdmmc_cisptr(struct sdmmc_function *);
     39  1.1.8.2  sborrill static uint32_t
     40  1.1.8.2  sborrill sdmmc_cisptr(struct sdmmc_function *sf)
     41  1.1.8.2  sborrill {
     42  1.1.8.2  sborrill 	uint32_t cisptr = 0;
     43  1.1.8.2  sborrill 
     44  1.1.8.2  sborrill 	/* XXX where is the per-function CIS pointer register? */
     45  1.1.8.2  sborrill 	if (sf->number != 0)
     46  1.1.8.2  sborrill 		return SD_IO_CIS_START;
     47  1.1.8.2  sborrill 
     48  1.1.8.2  sborrill 	/* XXX is the CIS pointer stored in little-endian format? */
     49  1.1.8.2  sborrill 	cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 0) << 0;
     50  1.1.8.2  sborrill 	cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 1) << 8;
     51  1.1.8.2  sborrill 	cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 2) << 16;
     52  1.1.8.2  sborrill 	return cisptr;
     53  1.1.8.2  sborrill }
     54  1.1.8.2  sborrill 
     55  1.1.8.2  sborrill int
     56  1.1.8.2  sborrill sdmmc_read_cis(struct sdmmc_function *sf, struct sdmmc_cis *cis)
     57  1.1.8.2  sborrill {
     58  1.1.8.2  sborrill 	device_t dev = sf->sc->sc_dev;
     59  1.1.8.2  sborrill 	uint32_t reg;
     60  1.1.8.2  sborrill 	uint8_t tplcode;
     61  1.1.8.2  sborrill 	uint8_t tpllen;
     62  1.1.8.2  sborrill 	int start, ch, count;
     63  1.1.8.2  sborrill 	int i;
     64  1.1.8.2  sborrill 
     65  1.1.8.2  sborrill 	memset(cis, 0, sizeof *cis);
     66  1.1.8.2  sborrill 
     67  1.1.8.2  sborrill 	/* XXX read per-function CIS */
     68  1.1.8.2  sborrill 	if (sf->number != 0)
     69  1.1.8.2  sborrill 		return 1;
     70  1.1.8.2  sborrill 
     71  1.1.8.2  sborrill 	reg = sdmmc_cisptr(sf);
     72  1.1.8.2  sborrill 	if (reg < SD_IO_CIS_START ||
     73  1.1.8.2  sborrill 	    reg >= (SD_IO_CIS_START + SD_IO_CIS_SIZE - 16)) {
     74  1.1.8.2  sborrill 		aprint_error_dev(dev, "bad CIS ptr %#x\n", reg);
     75  1.1.8.2  sborrill 		return 1;
     76  1.1.8.2  sborrill 	}
     77  1.1.8.2  sborrill 
     78  1.1.8.2  sborrill 	for (;;) {
     79  1.1.8.2  sborrill 		tplcode = sdmmc_io_read_1(sf, reg++);
     80  1.1.8.2  sborrill 		tpllen = sdmmc_io_read_1(sf, reg++);
     81  1.1.8.2  sborrill 
     82  1.1.8.2  sborrill 		if (tplcode == 0xff || tpllen == 0) {
     83  1.1.8.2  sborrill 			if (tplcode != 0xff)
     84  1.1.8.2  sborrill 				aprint_error_dev(dev, "CIS parse error at %d, "
     85  1.1.8.2  sborrill 				    "tuple code %#x, length %d\n",
     86  1.1.8.2  sborrill 				    reg, tplcode, tpllen);
     87  1.1.8.2  sborrill 			break;
     88  1.1.8.2  sborrill 		}
     89  1.1.8.2  sborrill 
     90  1.1.8.2  sborrill 		switch (tplcode) {
     91  1.1.8.2  sborrill 		case SD_IO_CISTPL_FUNCID:
     92  1.1.8.2  sborrill 			if (tpllen < 2) {
     93  1.1.8.2  sborrill 				aprint_error_dev(dev,
     94  1.1.8.2  sborrill 				    "bad CISTPL_FUNCID length\n");
     95  1.1.8.2  sborrill 				reg += tpllen;
     96  1.1.8.2  sborrill 				break;
     97  1.1.8.2  sborrill 			}
     98  1.1.8.2  sborrill 			cis->function = sdmmc_io_read_1(sf, reg);
     99  1.1.8.2  sborrill 			reg += tpllen;
    100  1.1.8.2  sborrill 			break;
    101  1.1.8.2  sborrill 
    102  1.1.8.2  sborrill 		case SD_IO_CISTPL_MANFID:
    103  1.1.8.2  sborrill 			if (tpllen < 4) {
    104  1.1.8.2  sborrill 				aprint_error_dev(dev,
    105  1.1.8.2  sborrill 				    "bad CISTPL_MANFID length\n");
    106  1.1.8.2  sborrill 				reg += tpllen;
    107  1.1.8.2  sborrill 				break;
    108  1.1.8.2  sborrill 			}
    109  1.1.8.2  sborrill 			cis->manufacturer = sdmmc_io_read_1(sf, reg++);
    110  1.1.8.2  sborrill 			cis->manufacturer |= sdmmc_io_read_1(sf, reg++) << 8;
    111  1.1.8.2  sborrill 			cis->product = sdmmc_io_read_1(sf, reg++);
    112  1.1.8.2  sborrill 			cis->product |= sdmmc_io_read_1(sf, reg++) << 8;
    113  1.1.8.2  sborrill 			break;
    114  1.1.8.2  sborrill 
    115  1.1.8.2  sborrill 		case SD_IO_CISTPL_VERS_1:
    116  1.1.8.2  sborrill 			if (tpllen < 2) {
    117  1.1.8.2  sborrill 				aprint_error_dev(dev,
    118  1.1.8.2  sborrill 				    "CISTPL_VERS_1 too short\n");
    119  1.1.8.2  sborrill 				reg += tpllen;
    120  1.1.8.2  sborrill 				break;
    121  1.1.8.2  sborrill 			}
    122  1.1.8.2  sborrill 
    123  1.1.8.2  sborrill 			cis->cis1_major = sdmmc_io_read_1(sf, reg++);
    124  1.1.8.2  sborrill 			cis->cis1_minor = sdmmc_io_read_1(sf, reg++);
    125  1.1.8.2  sborrill 
    126  1.1.8.2  sborrill 			for (count = 0, start = 0, i = 0;
    127  1.1.8.2  sborrill 			     (count < 4) && ((i + 4) < 256); i++) {
    128  1.1.8.2  sborrill 				ch = sdmmc_io_read_1(sf, reg + i);
    129  1.1.8.2  sborrill 				if (ch == 0xff)
    130  1.1.8.2  sborrill 					break;
    131  1.1.8.2  sborrill 				cis->cis1_info_buf[i] = ch;
    132  1.1.8.2  sborrill 				if (ch == 0) {
    133  1.1.8.2  sborrill 					cis->cis1_info[count] =
    134  1.1.8.2  sborrill 					    cis->cis1_info_buf + start;
    135  1.1.8.2  sborrill 					start = i + 1;
    136  1.1.8.2  sborrill 					count++;
    137  1.1.8.2  sborrill 				}
    138  1.1.8.2  sborrill 			}
    139  1.1.8.2  sborrill 
    140  1.1.8.2  sborrill 			reg += tpllen - 2;
    141  1.1.8.2  sborrill 			break;
    142  1.1.8.2  sborrill 
    143  1.1.8.2  sborrill 		default:
    144  1.1.8.2  sborrill 			aprint_error_dev(dev,
    145  1.1.8.2  sborrill 			    "unknown tuple code %#x, length %d\n",
    146  1.1.8.2  sborrill 			    tplcode, tpllen);
    147  1.1.8.2  sborrill 			reg += tpllen;
    148  1.1.8.2  sborrill 			break;
    149  1.1.8.2  sborrill 		}
    150  1.1.8.2  sborrill 	}
    151  1.1.8.2  sborrill 
    152  1.1.8.2  sborrill 	return 0;
    153  1.1.8.2  sborrill }
    154  1.1.8.2  sborrill 
    155  1.1.8.2  sborrill void
    156  1.1.8.2  sborrill sdmmc_print_cis(struct sdmmc_function *sf)
    157  1.1.8.2  sborrill {
    158  1.1.8.2  sborrill 	device_t dev = sf->sc->sc_dev;
    159  1.1.8.2  sborrill 	struct sdmmc_cis *cis = &sf->cis;
    160  1.1.8.2  sborrill 	int i;
    161  1.1.8.2  sborrill 
    162  1.1.8.2  sborrill 	printf("%s: CIS version %u.%u\n", device_xname(dev), cis->cis1_major,
    163  1.1.8.2  sborrill 	    cis->cis1_minor);
    164  1.1.8.2  sborrill 
    165  1.1.8.2  sborrill 	printf("%s: CIS info: ", device_xname(dev));
    166  1.1.8.2  sborrill 	for (i = 0; i < 4; i++) {
    167  1.1.8.2  sborrill 		if (cis->cis1_info[i] == NULL)
    168  1.1.8.2  sborrill 			break;
    169  1.1.8.2  sborrill 		if (i != 0)
    170  1.1.8.2  sborrill 			aprint_verbose(", ");
    171  1.1.8.2  sborrill 		printf("%s", cis->cis1_info[i]);
    172  1.1.8.2  sborrill 	}
    173  1.1.8.2  sborrill 	printf("\n");
    174  1.1.8.2  sborrill 
    175  1.1.8.2  sborrill 	printf("%s: Manufacturer code 0x%x, product 0x%x\n", device_xname(dev),
    176  1.1.8.2  sborrill 	    cis->manufacturer, cis->product);
    177  1.1.8.2  sborrill 
    178  1.1.8.2  sborrill 	printf("%s: function %d: ", device_xname(dev), sf->number);
    179  1.1.8.2  sborrill 	switch (sf->cis.function) {
    180  1.1.8.2  sborrill 	case SDMMC_FUNCTION_WLAN:
    181  1.1.8.2  sborrill 		printf("wireless network adapter");
    182  1.1.8.2  sborrill 		break;
    183  1.1.8.2  sborrill 
    184  1.1.8.2  sborrill 	default:
    185  1.1.8.2  sborrill 		printf("unknown function (%d)", sf->cis.function);
    186  1.1.8.2  sborrill 		break;
    187  1.1.8.2  sborrill 	}
    188  1.1.8.2  sborrill 	printf("\n");
    189  1.1.8.2  sborrill }
    190  1.1.8.2  sborrill 
    191  1.1.8.2  sborrill void
    192  1.1.8.2  sborrill sdmmc_check_cis_quirks(struct sdmmc_function *sf)
    193  1.1.8.2  sborrill {
    194  1.1.8.2  sborrill 	char *p;
    195  1.1.8.2  sborrill 	int i;
    196  1.1.8.2  sborrill 
    197  1.1.8.2  sborrill 	if (sf->cis.manufacturer == SDMMC_VENDOR_SPECTEC &&
    198  1.1.8.2  sborrill 	    sf->cis.product == SDMMC_PRODUCT_SPECTEC_SDW820) {
    199  1.1.8.2  sborrill 		/* This card lacks the VERS_1 tuple. */
    200  1.1.8.2  sborrill 		static const char cis1_info[] =
    201  1.1.8.2  sborrill 		    "Spectec\0SDIO WLAN Card\0SDW-820\0\0";
    202  1.1.8.2  sborrill 
    203  1.1.8.2  sborrill 		sf->cis.cis1_major = 0x01;
    204  1.1.8.2  sborrill 		sf->cis.cis1_minor = 0x00;
    205  1.1.8.2  sborrill 
    206  1.1.8.2  sborrill 		p = sf->cis.cis1_info_buf;
    207  1.1.8.2  sborrill 		strlcpy(p, cis1_info, sizeof(sf->cis.cis1_info_buf));
    208  1.1.8.2  sborrill 		for (i = 0; i < 4; i++) {
    209  1.1.8.2  sborrill 			sf->cis.cis1_info[i] = p;
    210  1.1.8.2  sborrill 			p += strlen(p) + 1;
    211  1.1.8.2  sborrill 		}
    212  1.1.8.2  sborrill 	}
    213  1.1.8.2  sborrill }
    214