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