aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlbert Herranz <albert_herranz@yahoo.es>2009-10-01 18:44:05 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-10-01 19:11:12 -0400
commited9935f4f9165fb306e59aa41a08be3eafe1486e (patch)
treed4b536382bbb786ef04a2aa8d7e78487fb87875f /drivers
parentbf89c8c867322338f3f2b1255f280a3236b61a69 (diff)
sdio: pass whitelisted cis funce tuples to sdio drivers
Some manufacturers provide vendor information in non-vendor specific CIS tuples. For example, Broadcom uses an Extended Function tuple to provide the MAC address on some of their network cards, as in the case of the Nintendo Wii WLAN daughter card. This patch allows passing whitelisted FUNCE tuples unknown to the SDIO core to a matching SDIO driver instead of rejecting them and failing. Signed-off-by: Albert Herranz <albert_herranz@yahoo.es> Cc: <linux-mmc@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/core/sdio_cis.c65
1 files changed, 49 insertions, 16 deletions
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index 6636354b48ce..e1035c895808 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -98,6 +98,22 @@ static const unsigned char speed_val[16] =
98static const unsigned int speed_unit[8] = 98static const unsigned int speed_unit[8] =
99 { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 }; 99 { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
100 100
101/* FUNCE tuples with these types get passed to SDIO drivers */
102static const unsigned char funce_type_whitelist[] = {
103 4 /* CISTPL_FUNCE_LAN_NODE_ID used in Broadcom cards */
104};
105
106static int cistpl_funce_whitelisted(unsigned char type)
107{
108 int i;
109
110 for (i = 0; i < ARRAY_SIZE(funce_type_whitelist); i++) {
111 if (funce_type_whitelist[i] == type)
112 return 1;
113 }
114 return 0;
115}
116
101static int cistpl_funce_common(struct mmc_card *card, 117static int cistpl_funce_common(struct mmc_card *card,
102 const unsigned char *buf, unsigned size) 118 const unsigned char *buf, unsigned size)
103{ 119{
@@ -120,6 +136,10 @@ static int cistpl_funce_func(struct sdio_func *func,
120 unsigned vsn; 136 unsigned vsn;
121 unsigned min_size; 137 unsigned min_size;
122 138
139 /* let SDIO drivers take care of whitelisted FUNCE tuples */
140 if (cistpl_funce_whitelisted(buf[0]))
141 return -EILSEQ;
142
123 vsn = func->card->cccr.sdio_vsn; 143 vsn = func->card->cccr.sdio_vsn;
124 min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42; 144 min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
125 145
@@ -154,13 +174,12 @@ static int cistpl_funce(struct mmc_card *card, struct sdio_func *func,
154 else 174 else
155 ret = cistpl_funce_common(card, buf, size); 175 ret = cistpl_funce_common(card, buf, size);
156 176
157 if (ret) { 177 if (ret && ret != -EILSEQ) {
158 printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u " 178 printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u "
159 "type %u\n", mmc_hostname(card->host), size, buf[0]); 179 "type %u\n", mmc_hostname(card->host), size, buf[0]);
160 return ret;
161 } 180 }
162 181
163 return 0; 182 return ret;
164} 183}
165 184
166typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *, 185typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,
@@ -253,21 +272,12 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
253 for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++) 272 for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
254 if (cis_tpl_list[i].code == tpl_code) 273 if (cis_tpl_list[i].code == tpl_code)
255 break; 274 break;
256 if (i >= ARRAY_SIZE(cis_tpl_list)) { 275 if (i < ARRAY_SIZE(cis_tpl_list)) {
257 /* this tuple is unknown to the core */
258 this->next = NULL;
259 this->code = tpl_code;
260 this->size = tpl_link;
261 *prev = this;
262 prev = &this->next;
263 printk(KERN_DEBUG
264 "%s: queuing CIS tuple 0x%02x length %u\n",
265 mmc_hostname(card->host), tpl_code, tpl_link);
266 } else {
267 const struct cis_tpl *tpl = cis_tpl_list + i; 276 const struct cis_tpl *tpl = cis_tpl_list + i;
268 if (tpl_link < tpl->min_size) { 277 if (tpl_link < tpl->min_size) {
269 printk(KERN_ERR 278 printk(KERN_ERR
270 "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n", 279 "%s: bad CIS tuple 0x%02x"
280 " (length = %u, expected >= %u)\n",
271 mmc_hostname(card->host), 281 mmc_hostname(card->host),
272 tpl_code, tpl_link, tpl->min_size); 282 tpl_code, tpl_link, tpl->min_size);
273 ret = -EINVAL; 283 ret = -EINVAL;
@@ -275,7 +285,30 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
275 ret = tpl->parse(card, func, 285 ret = tpl->parse(card, func,
276 this->data, tpl_link); 286 this->data, tpl_link);
277 } 287 }
278 kfree(this); 288 /*
289 * We don't need the tuple anymore if it was
290 * successfully parsed by the SDIO core or if it is
291 * not going to be parsed by SDIO drivers.
292 */
293 if (!ret || ret != -EILSEQ)
294 kfree(this);
295 } else {
296 /* unknown tuple */
297 ret = -EILSEQ;
298 }
299
300 if (ret == -EILSEQ) {
301 /* this tuple is unknown to the core or whitelisted */
302 this->next = NULL;
303 this->code = tpl_code;
304 this->size = tpl_link;
305 *prev = this;
306 prev = &this->next;
307 printk(KERN_DEBUG
308 "%s: queuing CIS tuple 0x%02x length %u\n",
309 mmc_hostname(card->host), tpl_code, tpl_link);
310 /* keep on analyzing tuples */
311 ret = 0;
279 } 312 }
280 313
281 ptr += tpl_link; 314 ptr += tpl_link;