mmc: sdio: Export SDIO revision and info strings to userspace
authorPali Rohár <pali@kernel.org>
Mon, 27 Jul 2020 13:38:37 +0000 (15:38 +0200)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 7 Sep 2020 07:11:29 +0000 (09:11 +0200)
For SDIO functions, SDIO cards and SD COMBO cards are exported revision
number and info strings from CISTPL_VERS_1 structure. Revision number
should indicate compliance of standard and info strings should contain
product information in same format as product information for PCMCIA cards.

Product information for PCMCIA cards should contain following strings in
this order: Manufacturer, Product Name, Lot number, Programming Conditions.

Note that not all SDIO cards export all those info strings in that order as
described in PCMCIA Metaformat Specification.

Signed-off-by: Pali Rohár <pali@kernel.org>
Link: https://lore.kernel.org/r/20200727133837.19086-5-pali@kernel.org
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/core/bus.c
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_bus.c

index 70207f11a6548e2c6c1e0ba5d38eb7b2b3aae891..c2e70b757dd12c603ad9a5cbe7086b24841eec99 100644 (file)
@@ -68,6 +68,7 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct mmc_card *card = mmc_dev_to_card(dev);
        const char *type;
+       unsigned int i;
        int retval = 0;
 
        switch (card->type) {
@@ -98,6 +99,17 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
                                        card->cis.vendor, card->cis.device);
                if (retval)
                        return retval;
+
+               retval = add_uevent_var(env, "SDIO_REVISION=%u.%u",
+                                       card->major_rev, card->minor_rev);
+               if (retval)
+                       return retval;
+
+               for (i = 0; i < card->num_info; i++) {
+                       retval = add_uevent_var(env, "SDIO_INFO%u=%s", i+1, card->info[i]);
+                       if (retval)
+                               return retval;
+               }
        }
 
        /*
index 5a2210c25aa7a65082c1471ab0094db46b8daa0a..429ca14fa7e179a9b4f1f63edd59a673b9f82849 100644 (file)
@@ -709,10 +709,34 @@ static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL);
 
 MMC_DEV_ATTR(vendor, "0x%04x\n", card->cis.vendor);
 MMC_DEV_ATTR(device, "0x%04x\n", card->cis.device);
+MMC_DEV_ATTR(revision, "%u.%u\n", card->major_rev, card->minor_rev);
+
+#define sdio_info_attr(num)                                                                    \
+static ssize_t info##num##_show(struct device *dev, struct device_attribute *attr, char *buf)  \
+{                                                                                              \
+       struct mmc_card *card = mmc_dev_to_card(dev);                                           \
+                                                                                               \
+       if (num > card->num_info)                                                               \
+               return -ENODATA;                                                                \
+       if (!card->info[num-1][0])                                                              \
+               return 0;                                                                       \
+       return sprintf(buf, "%s\n", card->info[num-1]);                                         \
+}                                                                                              \
+static DEVICE_ATTR_RO(info##num)
+
+sdio_info_attr(1);
+sdio_info_attr(2);
+sdio_info_attr(3);
+sdio_info_attr(4);
 
 static struct attribute *sd_std_attrs[] = {
        &dev_attr_vendor.attr,
        &dev_attr_device.attr,
+       &dev_attr_revision.attr,
+       &dev_attr_info1.attr,
+       &dev_attr_info2.attr,
+       &dev_attr_info3.attr,
+       &dev_attr_info4.attr,
        &dev_attr_cid.attr,
        &dev_attr_csd.attr,
        &dev_attr_scr.attr,
@@ -738,9 +762,15 @@ static umode_t sd_std_is_visible(struct kobject *kobj, struct attribute *attr,
        struct device *dev = container_of(kobj, struct device, kobj);
        struct mmc_card *card = mmc_dev_to_card(dev);
 
-       /* CIS vendor and device ids are available only for Combo cards */
-       if ((attr == &dev_attr_vendor.attr || attr == &dev_attr_device.attr) &&
-           card->type != MMC_TYPE_SD_COMBO)
+       /* CIS vendor and device ids, revision and info string are available only for Combo cards */
+       if ((attr == &dev_attr_vendor.attr ||
+            attr == &dev_attr_device.attr ||
+            attr == &dev_attr_revision.attr ||
+            attr == &dev_attr_info1.attr ||
+            attr == &dev_attr_info2.attr ||
+            attr == &dev_attr_info3.attr ||
+            attr == &dev_attr_info4.attr
+           ) && card->type != MMC_TYPE_SD_COMBO)
                return 0;
 
        return attr->mode;
index 7b40553d3934118893229fb536aca363728bcde7..694a212cbe25ab307bf9e1af966ffd31f498fb65 100644 (file)
 
 MMC_DEV_ATTR(vendor, "0x%04x\n", card->cis.vendor);
 MMC_DEV_ATTR(device, "0x%04x\n", card->cis.device);
+MMC_DEV_ATTR(revision, "%u.%u\n", card->major_rev, card->minor_rev);
 MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr);
 MMC_DEV_ATTR(rca, "0x%04x\n", card->rca);
 
+#define sdio_info_attr(num)                                                                    \
+static ssize_t info##num##_show(struct device *dev, struct device_attribute *attr, char *buf)  \
+{                                                                                              \
+       struct mmc_card *card = mmc_dev_to_card(dev);                                           \
+                                                                                               \
+       if (num > card->num_info)                                                               \
+               return -ENODATA;                                                                \
+       if (!card->info[num-1][0])                                                              \
+               return 0;                                                                       \
+       return sprintf(buf, "%s\n", card->info[num-1]);                                         \
+}                                                                                              \
+static DEVICE_ATTR_RO(info##num)
+
+sdio_info_attr(1);
+sdio_info_attr(2);
+sdio_info_attr(3);
+sdio_info_attr(4);
+
 static struct attribute *sdio_std_attrs[] = {
        &dev_attr_vendor.attr,
        &dev_attr_device.attr,
+       &dev_attr_revision.attr,
+       &dev_attr_info1.attr,
+       &dev_attr_info2.attr,
+       &dev_attr_info3.attr,
+       &dev_attr_info4.attr,
        &dev_attr_ocr.attr,
        &dev_attr_rca.attr,
        NULL,
index 2384829c8fb2be1662d5f3f7f83d95640adb0395..3d709029e07ce17679eb4de055d314caecd2bae8 100644 (file)
@@ -42,12 +42,36 @@ static DEVICE_ATTR_RO(field)
 sdio_config_attr(class, "0x%02x\n", func->class);
 sdio_config_attr(vendor, "0x%04x\n", func->vendor);
 sdio_config_attr(device, "0x%04x\n", func->device);
+sdio_config_attr(revision, "%u.%u\n", func->major_rev, func->minor_rev);
 sdio_config_attr(modalias, "sdio:c%02Xv%04Xd%04X\n", func->class, func->vendor, func->device);
 
+#define sdio_info_attr(num)                                                                    \
+static ssize_t info##num##_show(struct device *dev, struct device_attribute *attr, char *buf)  \
+{                                                                                              \
+       struct sdio_func *func = dev_to_sdio_func(dev);                                         \
+                                                                                               \
+       if (num > func->num_info)                                                               \
+               return -ENODATA;                                                                \
+       if (!func->info[num-1][0])                                                              \
+               return 0;                                                                       \
+       return sprintf(buf, "%s\n", func->info[num-1]);                                         \
+}                                                                                              \
+static DEVICE_ATTR_RO(info##num)
+
+sdio_info_attr(1);
+sdio_info_attr(2);
+sdio_info_attr(3);
+sdio_info_attr(4);
+
 static struct attribute *sdio_dev_attrs[] = {
        &dev_attr_class.attr,
        &dev_attr_vendor.attr,
        &dev_attr_device.attr,
+       &dev_attr_revision.attr,
+       &dev_attr_info1.attr,
+       &dev_attr_info2.attr,
+       &dev_attr_info3.attr,
+       &dev_attr_info4.attr,
        &dev_attr_modalias.attr,
        NULL,
 };
@@ -98,6 +122,7 @@ static int
 sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct sdio_func *func = dev_to_sdio_func(dev);
+       unsigned int i;
 
        if (add_uevent_var(env,
                        "SDIO_CLASS=%02X", func->class))
@@ -107,6 +132,15 @@ sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
                        "SDIO_ID=%04X:%04X", func->vendor, func->device))
                return -ENOMEM;
 
+       if (add_uevent_var(env,
+                       "SDIO_REVISION=%u.%u", func->major_rev, func->minor_rev))
+               return -ENOMEM;
+
+       for (i = 0; i < func->num_info; i++) {
+               if (add_uevent_var(env, "SDIO_INFO%u=%s", i+1, func->info[i]))
+                       return -ENOMEM;
+       }
+
        if (add_uevent_var(env,
                        "MODALIAS=sdio:c%02Xv%04Xd%04X",
                        func->class, func->vendor, func->device))