]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/mmc/core/sdio_cis.c
Merge branch 'for-2.6.32' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[mv-sheeva.git] / drivers / mmc / core / sdio_cis.c
index 963f2937c5e37da83819249826995aa098751f99..e1035c8958086b92ee9e563028c573d161cd104d 100644 (file)
@@ -40,7 +40,7 @@ static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
                        nr_strings++;
        }
 
-       if (buf[i-1] != '\0') {
+       if (nr_strings < 4) {
                printk(KERN_WARNING "SDIO: ignoring broken CISTPL_VERS_1\n");
                return 0;
        }
@@ -98,6 +98,22 @@ static const unsigned char speed_val[16] =
 static const unsigned int speed_unit[8] =
        { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
 
+/* FUNCE tuples with these types get passed to SDIO drivers */
+static const unsigned char funce_type_whitelist[] = {
+       4 /* CISTPL_FUNCE_LAN_NODE_ID used in Broadcom cards */
+};
+
+static int cistpl_funce_whitelisted(unsigned char type)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(funce_type_whitelist); i++) {
+               if (funce_type_whitelist[i] == type)
+                       return 1;
+       }
+       return 0;
+}
+
 static int cistpl_funce_common(struct mmc_card *card,
                               const unsigned char *buf, unsigned size)
 {
@@ -120,6 +136,10 @@ static int cistpl_funce_func(struct sdio_func *func,
        unsigned vsn;
        unsigned min_size;
 
+       /* let SDIO drivers take care of whitelisted FUNCE tuples */
+       if (cistpl_funce_whitelisted(buf[0]))
+               return -EILSEQ;
+
        vsn = func->card->cccr.sdio_vsn;
        min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
 
@@ -154,13 +174,12 @@ static int cistpl_funce(struct mmc_card *card, struct sdio_func *func,
        else
                ret = cistpl_funce_common(card, buf, size);
 
-       if (ret) {
+       if (ret && ret != -EILSEQ) {
                printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u "
                       "type %u\n", mmc_hostname(card->host), size, buf[0]);
-               return ret;
        }
 
-       return 0;
+       return ret;
 }
 
 typedef 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)
                for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
                        if (cis_tpl_list[i].code == tpl_code)
                                break;
-               if (i >= ARRAY_SIZE(cis_tpl_list)) {
-                       /* this tuple is unknown to the core */
-                       this->next = NULL;
-                       this->code = tpl_code;
-                       this->size = tpl_link;
-                       *prev = this;
-                       prev = &this->next;
-                       printk(KERN_DEBUG
-                              "%s: queuing CIS tuple 0x%02x length %u\n",
-                              mmc_hostname(card->host), tpl_code, tpl_link);
-               } else {
+               if (i < ARRAY_SIZE(cis_tpl_list)) {
                        const struct cis_tpl *tpl = cis_tpl_list + i;
                        if (tpl_link < tpl->min_size) {
                                printk(KERN_ERR
-                                      "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n",
+                                      "%s: bad CIS tuple 0x%02x"
+                                      " (length = %u, expected >= %u)\n",
                                       mmc_hostname(card->host),
                                       tpl_code, tpl_link, tpl->min_size);
                                ret = -EINVAL;
@@ -275,7 +285,30 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
                                ret = tpl->parse(card, func,
                                                 this->data, tpl_link);
                        }
-                       kfree(this);
+                       /*
+                        * We don't need the tuple anymore if it was
+                        * successfully parsed by the SDIO core or if it is
+                        * not going to be parsed by SDIO drivers.
+                        */
+                       if (!ret || ret != -EILSEQ)
+                               kfree(this);
+               } else {
+                       /* unknown tuple */
+                       ret = -EILSEQ;
+               }
+
+               if (ret == -EILSEQ) {
+                       /* this tuple is unknown to the core or whitelisted */
+                       this->next = NULL;
+                       this->code = tpl_code;
+                       this->size = tpl_link;
+                       *prev = this;
+                       prev = &this->next;
+                       printk(KERN_DEBUG
+                              "%s: queuing CIS tuple 0x%02x length %u\n",
+                              mmc_hostname(card->host), tpl_code, tpl_link);
+                       /* keep on analyzing tuples */
+                       ret = 0;
                }
 
                ptr += tpl_link;