summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Nelson <eric.nelson@boundarydevices.com>2012-06-25 16:26:23 -0700
committerEric Nelson <eric.nelson@boundarydevices.com>2012-10-14 14:32:51 -0700
commit9c6cc2d08329a9c627d6ba961990777a54e447ef (patch)
tree5b4470f654eac419c4a7524e4a178ef8f9679a28
parent42c793e3815eb86de7ea99c52fc75a598ae0353a (diff)
sdio_cis: hack for broken wl127x CIS
-rw-r--r--drivers/mmc/core/sdio_cis.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index 541bdb89e0c5..3b0ca8379897 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -230,6 +230,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
int ret;
struct sdio_func_tuple *this, **prev;
unsigned i, ptr = 0;
+ unsigned ptr_null_end;
/*
* Note that this works for the common CIS (function number 0) as
@@ -258,6 +259,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
BUG_ON(*prev);
+ ptr_null_end = (ptr | 0xff) + 1;
do {
unsigned char tpl_code, tpl_link;
@@ -269,6 +271,9 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
if (tpl_code == 0xff)
break;
+ if ((tpl_code == 0x00) && (ptr == ptr_null_end))
+ break; /* patch for misbehaving rtl8712 card */
+
/* null entries have no link field or data */
if (tpl_code == 0x00)
continue;
@@ -282,9 +287,10 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
break;
this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL);
- if (!this)
- return -ENOMEM;
-
+ if (!this) {
+ ret = -ENOMEM;
+ break;
+ }
for (i = 0; i < tpl_link; i++) {
ret = mmc_io_rw_direct(card, 0, 0,
ptr + i, 0, &this->data[i]);
@@ -328,6 +334,12 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
* not going to be queued for a driver.
*/
kfree(this);
+ if (ret) {
+ printk(KERN_WARNING "%s: dropping invalid"
+ " CIS tuple 0x%02x (%u bytes)\n",
+ mmc_hostname(card->host),
+ tpl_code, tpl_link);
+ }
}
ptr += tpl_link;