1 /* $OpenBSD: sdmmc_cis.c,v 1.8 2020/04/29 09:44:49 patrick 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 struct sdmmc_function *sf0 = sf->sc->sc_fn0; 41 u_int32_t cisptr = 0; 42 int reg; 43 44 rw_assert_wrlock(&sf->sc->sc_lock); 45 46 reg = SD_IO_CCCR_CISPTR + (sf->number * SD_IO_CCCR_SIZE); 47 cisptr |= sdmmc_io_read_1(sf0, reg + 0) << 0; 48 cisptr |= sdmmc_io_read_1(sf0, reg + 1) << 8; 49 cisptr |= sdmmc_io_read_1(sf0, reg + 2) << 16; 50 51 return cisptr; 52 } 53 54 int 55 sdmmc_read_cis(struct sdmmc_function *sf, struct sdmmc_cis *cis) 56 { 57 struct sdmmc_function *sf0 = sf->sc->sc_fn0; 58 int reg; 59 u_int8_t tplcode; 60 u_int8_t tpllen; 61 62 rw_assert_wrlock(&sf->sc->sc_lock); 63 64 reg = (int)sdmmc_cisptr(sf); 65 if (reg < SD_IO_CIS_START || 66 reg >= (SD_IO_CIS_START+SD_IO_CIS_SIZE-16)) { 67 printf("%s: bad CIS ptr %#x\n", DEVNAME(sf->sc), reg); 68 return 1; 69 } 70 71 for (;;) { 72 tplcode = sdmmc_io_read_1(sf0, reg++); 73 if (tplcode == SD_IO_CISTPL_END) 74 break; 75 if (tplcode == SD_IO_CISTPL_NULL) 76 continue; 77 78 tpllen = sdmmc_io_read_1(sf0, reg++); 79 80 switch (tplcode) { 81 case SD_IO_CISTPL_FUNCID: 82 if (tpllen < 2) { 83 printf("%s: bad CISTPL_FUNCID length\n", 84 DEVNAME(sf->sc)); 85 reg += tpllen; 86 break; 87 } 88 cis->function = sdmmc_io_read_1(sf0, reg); 89 reg += tpllen; 90 break; 91 case SD_IO_CISTPL_MANFID: 92 if (tpllen < 4) { 93 printf("%s: bad CISTPL_MANFID length\n", 94 DEVNAME(sf->sc)); 95 reg += tpllen; 96 break; 97 } 98 cis->manufacturer = sdmmc_io_read_1(sf0, reg++); 99 cis->manufacturer |= sdmmc_io_read_1(sf0, reg++) << 8; 100 cis->product = sdmmc_io_read_1(sf0, reg++); 101 cis->product |= sdmmc_io_read_1(sf0, reg++) << 8; 102 break; 103 case SD_IO_CISTPL_VERS_1: 104 if (tpllen < 2) { 105 printf("%s: CISTPL_VERS_1 too short\n", 106 DEVNAME(sf->sc)); 107 reg += tpllen; 108 break; 109 } 110 { 111 int start, i, ch, count; 112 113 cis->cis1_major = sdmmc_io_read_1(sf0, reg++); 114 cis->cis1_minor = sdmmc_io_read_1(sf0, reg++); 115 116 for (count = 0, start = 0, i = 0; 117 (count < 4) && ((i + 4) < 256); i++) { 118 ch = sdmmc_io_read_1(sf0, reg + i); 119 if (ch == 0xff) 120 break; 121 cis->cis1_info_buf[i] = ch; 122 if (ch == 0) { 123 cis->cis1_info[count] = 124 cis->cis1_info_buf + start; 125 start = i + 1; 126 count++; 127 } 128 } 129 130 reg += tpllen - 2; 131 } 132 break; 133 default: 134 DPRINTF(("%s: unknown tuple code %#x, length %d\n", 135 DEVNAME(sf->sc), tplcode, tpllen)); 136 reg += tpllen; 137 break; 138 } 139 } 140 141 return 0; 142 } 143 144 void 145 sdmmc_print_cis(struct sdmmc_function *sf) 146 { 147 struct sdmmc_cis *cis = &sf->cis; 148 int i; 149 150 printf("%s: CIS version %d.%d\n", DEVNAME(sf->sc), 151 cis->cis1_major, cis->cis1_minor); 152 153 printf("%s: CIS info: ", DEVNAME(sf->sc)); 154 for (i = 0; i < 4; i++) { 155 if (cis->cis1_info[i] == NULL) 156 break; 157 if (i) 158 printf(", "); 159 printf("%s", cis->cis1_info[i]); 160 } 161 printf("\n"); 162 163 printf("%s: Manufacturer code 0x%x, product 0x%x\n", 164 DEVNAME(sf->sc), cis->manufacturer, cis->product); 165 166 printf("%s: function %d: ", DEVNAME(sf->sc), sf->number); 167 switch (sf->cis.function) { 168 case TPLFID_FUNCTION_SDIO: 169 printf("SDIO"); 170 break; 171 default: 172 printf("unknown (%d)", sf->cis.function); 173 break; 174 } 175 printf("\n"); 176 } 177 178 void 179 sdmmc_check_cis_quirks(struct sdmmc_function *sf) 180 { 181 if (sf->cis.manufacturer == SDMMC_VENDOR_SPECTEC && 182 sf->cis.product == SDMMC_PRODUCT_SPECTEC_SDW820) { 183 /* This card lacks the VERS_1 tuple. */ 184 sf->cis.cis1_major = 0x01; 185 sf->cis.cis1_minor = 0x00; 186 sf->cis.cis1_info[0] = "Spectec"; 187 sf->cis.cis1_info[1] = "SDIO WLAN Card"; 188 sf->cis.cis1_info[2] = "SDW-820"; 189 sf->cis.cis1_info[3] = ""; 190 } 191 } 192