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-06-25 16:26:23 -0700
commit576b8cf2a1711ea1bb638b484c092c8c10029925 (patch)
tree6891126b1523aea3c0efcf4ff9fa7ee4be56d988
parenta2c3ad945df6fc746cb5bcc70c89cc454780c065 (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;