]> git.hungrycats.org Git - linux/commitdiff
[MMC] Add v2.x and v3.x CID parsing.
authorRussell King <rmk@flint.arm.linux.org.uk>
Sat, 18 Sep 2004 18:47:23 +0000 (19:47 +0100)
committerRussell King <rmk@flint.arm.linux.org.uk>
Sat, 18 Sep 2004 18:47:23 +0000 (19:47 +0100)
drivers/mmc/mmc.c
drivers/mmc/mmc_sysfs.c
include/linux/mmc/card.h

index 6c26fe5dcdd8ef8107e9114b5edbfebc0787599e..3d057384dd171570891cd9854eaa66c8400f6542 100644 (file)
@@ -300,51 +300,110 @@ static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
        return ocr;
 }
 
+#define UNSTUFF_BITS(resp,start,size)                                  \
+       ({                                                              \
+               const u32 __mask = (1 << (size)) - 1;                   \
+               const int __off = 3 - ((start) / 32);                   \
+               const int __shft = (start) & 31;                        \
+               u32 __res;                                              \
+                                                                       \
+               __res = resp[__off] >> __shft;                          \
+               if ((size) + __shft >= 32)                              \
+                       __res |= resp[__off-1] << (32 - __shft);        \
+               __res & __mask;                                         \
+       })
+
+/*
+ * Given the decoded CSD structure, decode the raw CID to our CID structure.
+ */
 static void mmc_decode_cid(struct mmc_card *card)
 {
-       struct mmc_cid *cid = &card->cid;
        u32 *resp = card->raw_cid;
 
-       memset(cid, 0, sizeof(struct mmc_cid));
-
-       cid->manfid       = resp[0] >> 8;
-       cid->prod_name[0] = resp[0];
-       cid->prod_name[1] = resp[1] >> 24;
-       cid->prod_name[2] = resp[1] >> 16;
-       cid->prod_name[3] = resp[1] >> 8;
-       cid->prod_name[4] = resp[1];
-       cid->prod_name[5] = resp[2] >> 24;
-       cid->prod_name[6] = resp[2] >> 16;
-       cid->prod_name[7] = '\0';
-       cid->hwrev        = (resp[2] >> 12) & 15;
-       cid->fwrev        = (resp[2] >> 8) & 15;
-       cid->serial       = (resp[2] & 255) << 16 | (resp[3] >> 16);
-       cid->month        = (resp[3] >> 12) & 15;
-       cid->year         = (resp[3] >> 8) & 15;
+       memset(&card->cid, 0, sizeof(struct mmc_cid));
+
+       /*
+        * The selection of the format here is guesswork based upon
+        * information people have sent to date.
+        */
+       switch (card->csd.mmca_vsn) {
+       case 0: /* MMC v1.? */
+       case 1: /* MMC v1.4 */
+               card->cid.manfid        = UNSTUFF_BITS(resp, 104, 24);
+               card->cid.prod_name[0]  = UNSTUFF_BITS(resp, 96, 8);
+               card->cid.prod_name[1]  = UNSTUFF_BITS(resp, 88, 8);
+               card->cid.prod_name[2]  = UNSTUFF_BITS(resp, 80, 8);
+               card->cid.prod_name[3]  = UNSTUFF_BITS(resp, 72, 8);
+               card->cid.prod_name[4]  = UNSTUFF_BITS(resp, 64, 8);
+               card->cid.prod_name[5]  = UNSTUFF_BITS(resp, 56, 8);
+               card->cid.prod_name[6]  = UNSTUFF_BITS(resp, 48, 8);
+               card->cid.hwrev         = UNSTUFF_BITS(resp, 44, 4);
+               card->cid.fwrev         = UNSTUFF_BITS(resp, 40, 4);
+               card->cid.serial        = UNSTUFF_BITS(resp, 16, 24);
+               card->cid.month         = UNSTUFF_BITS(resp, 12, 4);
+               card->cid.year          = UNSTUFF_BITS(resp, 8, 4) + 1997;
+               break;
+
+       case 2: /* MMC v2.x ? */
+       case 3: /* MMC v3.x ? */
+               card->cid.manfid        = UNSTUFF_BITS(resp, 120, 8);
+               card->cid.oemid         = UNSTUFF_BITS(resp, 104, 16);
+               card->cid.prod_name[0]  = UNSTUFF_BITS(resp, 96, 8);
+               card->cid.prod_name[1]  = UNSTUFF_BITS(resp, 88, 8);
+               card->cid.prod_name[2]  = UNSTUFF_BITS(resp, 80, 8);
+               card->cid.prod_name[3]  = UNSTUFF_BITS(resp, 72, 8);
+               card->cid.prod_name[4]  = UNSTUFF_BITS(resp, 64, 8);
+               card->cid.prod_name[5]  = UNSTUFF_BITS(resp, 56, 8);
+               card->cid.serial        = UNSTUFF_BITS(resp, 16, 32);
+               card->cid.month         = UNSTUFF_BITS(resp, 12, 4);
+               card->cid.year          = UNSTUFF_BITS(resp, 8, 4) + 1997;
+               break;
+
+       default:
+               printk("%s: card has unknown MMCA version %d\n",
+                       card->host->host_name, card->csd.mmca_vsn);
+               mmc_card_set_bad(card);
+               break;
+       }
 }
 
+/*
+ * Given a 128-bit response, decode to our card CSD structure.
+ */
 static void mmc_decode_csd(struct mmc_card *card)
 {
        struct mmc_csd *csd = &card->csd;
-       unsigned int e, m;
+       unsigned int e, m, csd_struct;
        u32 *resp = card->raw_csd;
 
-       csd->mmc_prot    = (resp[0] >> 26) & 15;
-       m = (resp[0] >> 19) & 15;
-       e = (resp[0] >> 16) & 7;
+       /*
+        * We only understand CSD structure v1.1 and v2.
+        * v2 has extra information in bits 15, 11 and 10.
+        */
+       csd_struct = UNSTUFF_BITS(resp, 126, 2);
+       if (csd_struct != 1 && csd_struct != 2) {
+               printk("%s: unrecognised CSD structure version %d\n",
+                       card->host->host_name, csd_struct);
+               mmc_card_set_bad(card);
+               return;
+       }
+
+       csd->mmca_vsn    = UNSTUFF_BITS(resp, 122, 4);
+       m = UNSTUFF_BITS(resp, 115, 4);
+       e = UNSTUFF_BITS(resp, 112, 3);
        csd->tacc_ns     = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
-       csd->tacc_clks   = ((resp[0] >> 8) & 255) * 100;
+       csd->tacc_clks   = UNSTUFF_BITS(resp, 104, 8) * 100;
 
-       m = (resp[0] >> 3) & 15;
-       e = resp[0] & 7;
+       m = UNSTUFF_BITS(resp, 99, 4);
+       e = UNSTUFF_BITS(resp, 96, 3);
        csd->max_dtr      = tran_exp[e] * tran_mant[m];
-       csd->cmdclass     = (resp[1] >> 20) & 0xfff;
+       csd->cmdclass     = UNSTUFF_BITS(resp, 84, 12);
 
-       e = (resp[2] >> 15) & 7;
-       m = (resp[1] << 2 | resp[2] >> 30) & 0x3fff;
+       e = UNSTUFF_BITS(resp, 47, 3);
+       m = UNSTUFF_BITS(resp, 62, 12);
        csd->capacity     = (1 + m) << (e + 2);
 
-       csd->read_blkbits = (resp[1] >> 16) & 15;
+       csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
 }
 
 /*
index bb12e07fe12e62fdd0961e0a76d68e4e761898c4..2b7ebdac77b4868e86fece1badf4afeedc9511d7 100644 (file)
@@ -67,8 +67,9 @@ mmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buf,
 
        i = 0;
        add_env("MMC_CCC=%s", ccc);
-       add_env("MMC_MANFID=%03x", card->cid.manfid);
-       add_env("MMC_SLOT_NAME=%s", card->dev.bus_id);
+       add_env("MMC_MANFID=%06x", card->cid.manfid);
+       add_env("MMC_NAME=%s", mmc_card_name(card));
+       add_env("MMC_OEMID=%04x", card->cid.oemid);
 
        return 0;
 }
@@ -162,12 +163,13 @@ MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
        card->raw_cid[2], card->raw_cid[3]);
 MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
        card->raw_csd[2], card->raw_csd[3]);
-MMC_ATTR(date, "%02d/%04d\n", card->cid.month, 1997 + card->cid.year);
+MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
 MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
 MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
-MMC_ATTR(manfid, "0x%03x\n", card->cid.manfid);
+MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid);
 MMC_ATTR(name, "%s\n", card->cid.prod_name);
-MMC_ATTR(serial, "0x%06x\n", card->cid.serial);
+MMC_ATTR(oemid, "0x%04x\n", card->cid.oemid);
+MMC_ATTR(serial, "0x%08x\n", card->cid.serial);
 
 static struct device_attribute *mmc_dev_attributes[] = {
        &dev_attr_cid,
@@ -177,6 +179,7 @@ static struct device_attribute *mmc_dev_attributes[] = {
        &dev_attr_hwrev,
        &dev_attr_manfid,
        &dev_attr_name,
+       &dev_attr_oemid,
        &dev_attr_serial,
 };
 
index 8b69c1a926b8b60a39afcf23f67abd679172c8b1..44da5ac8f88f961cb30fbd031f25f8cfa6734cd9 100644 (file)
 
 struct mmc_cid {
        unsigned int            manfid;
-       unsigned int            serial;
        char                    prod_name[8];
+       unsigned int            serial;
+       unsigned short          oemid;
+       unsigned short          year;
        unsigned char           hwrev;
        unsigned char           fwrev;
        unsigned char           month;
-       unsigned char           year;
 };
 
 struct mmc_csd {
-       unsigned char           mmc_prot;
+       unsigned char           mmca_vsn;
        unsigned short          cmdclass;
        unsigned short          tacc_clks;
        unsigned int            tacc_ns;