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