From: Torstein Eide <torsteine@gmail.com>
To: linux-mmc@vger.kernel.org
Cc: Torstein Eide <torsteine+linux@gmail.com>
Subject: [PATCH v2 1/5] mmc-utils: lsmmc: Refactor CID parsing into shared structs
Date: Fri, 15 May 2026 23:37:43 +0200 [thread overview]
Message-ID: <20260515213747.1452692-2-torsteine+linux@gmail.com> (raw)
In-Reply-To: <20260515213747.1452692-1-torsteine+linux@gmail.com>
Add struct sd_cid and struct mmc_cid with parse_sd_cid() and
parse_mmc_cid() helpers. Use them in print_sd_cid(), print_mmc_cid()
and print_list_entry() to eliminate duplicated parse_bin() format
strings and local variable lists.
Also fix print_list_entry() using const char * for the strdup'd
manufacturer string without a matching free().
Signed-off-by: Torstein Eide <torsteine+linux@gmail.com>
---
lsmmc.c | 250 +++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 184 insertions(+), 66 deletions(-)
diff --git a/lsmmc.c b/lsmmc.c
index 799e1ea..8155a5c 100644
--- a/lsmmc.c
+++ b/lsmmc.c
@@ -509,62 +509,89 @@ static void parse_bin(char *hexstr, char *fmt, ...)
free(origstr);
}
-/* MMC/SD information parsing functions */
-static void print_sd_cid(struct config *config, char *cid)
-{
- static const char *months[] = {
- "jan", "feb", "mar", "apr", "may", "jun",
- "jul", "aug", "sep", "oct", "nov", "dec",
- "invalid0", "invalid1", "invalid2", "invalid3",
- };
+struct sd_cid {
unsigned int mid;
char oid[3];
char pnm[6];
unsigned int prv_major;
unsigned int prv_minor;
unsigned int psn;
+ unsigned int mdt_year;
unsigned int mdt_month;
+ unsigned int crc;
+};
+
+struct mmc_cid {
+ unsigned int mid;
+ unsigned int cbx;
+ unsigned int oid;
+ char pnm[7];
+ unsigned int prv_major;
+ unsigned int prv_minor;
+ unsigned int psn;
unsigned int mdt_year;
+ unsigned int mdt_month;
unsigned int crc;
- char *manufacturer = NULL;
+};
- parse_bin(cid, "8u16a40a4u4u32u4r8u4u7u1r",
- &mid, &oid[0], &pnm[0], &prv_major, &prv_minor, &psn,
- &mdt_year, &mdt_month, &crc);
+static void parse_sd_cid(char *raw, struct sd_cid *c)
+{
+ parse_bin(raw, "8u16a40a4u4u32u4r8u4u7u1r",
+ &c->mid, &c->oid[0], &c->pnm[0], &c->prv_major, &c->prv_minor,
+ &c->psn, &c->mdt_year, &c->mdt_month, &c->crc);
+ c->oid[2] = '\0';
+ c->pnm[5] = '\0';
+}
- oid[2] = '\0';
- pnm[5] = '\0';
+static void parse_mmc_cid(char *raw, struct mmc_cid *c)
+{
+ parse_bin(raw, "8u6r2u8u48a4u4u32u4u4u7u1r",
+ &c->mid, &c->cbx, &c->oid, &c->pnm[0], &c->prv_major,
+ &c->prv_minor, &c->psn, &c->mdt_year, &c->mdt_month, &c->crc);
+ c->pnm[6] = '\0';
+}
+
+/* MMC/SD information parsing functions */
+static void print_sd_cid(struct config *config, char *cid)
+{
+ static const char *months[] = {
+ "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec",
+ "invalid0", "invalid1", "invalid2", "invalid3",
+ };
+ struct sd_cid c;
+ char *manufacturer;
- manufacturer = get_manufacturer(config, mid);
+ parse_sd_cid(cid, &c);
+ manufacturer = get_manufacturer(config, c.mid);
if (config->verbose) {
printf("======SD/CID======\n");
- printf("\tMID: 0x%02x (", mid);
+ printf("\tMID: 0x%02x (", c.mid);
if (manufacturer)
printf("%s)\n", manufacturer);
else
printf("Unlisted)\n");
- printf("\tOID: %s\n", oid);
- printf("\tPNM: %s\n", pnm);
- printf("\tPRV: 0x%01x%01x ", prv_major, prv_minor);
- printf("(%u.%u)\n", prv_major, prv_minor);
- printf("\tPSN: 0x%08x\n", psn);
- printf("\tMDT: 0x%02x%01x %u %s\n", mdt_year, mdt_month,
- 2000 + mdt_year, months[mdt_month]);
- printf("\tCRC: 0x%02x\n", crc);
+ printf("\tOID: %s\n", c.oid);
+ printf("\tPNM: %s\n", c.pnm);
+ printf("\tPRV: 0x%01x%01x ", c.prv_major, c.prv_minor);
+ printf("(%u.%u)\n", c.prv_major, c.prv_minor);
+ printf("\tPSN: 0x%08x\n", c.psn);
+ printf("\tMDT: 0x%02x%01x %u %s\n", c.mdt_year, c.mdt_month,
+ 2000 + c.mdt_year, months[c.mdt_month]);
+ printf("\tCRC: 0x%02x\n", c.crc);
} else {
if (manufacturer)
- printf("manufacturer: '%s' '%s'\n",
- manufacturer, oid);
+ printf("manufacturer: '%s' '%s'\n", manufacturer, c.oid);
else
- printf("manufacturer: 'Unlisted' '%s'\n", oid);
+ printf("manufacturer: 'Unlisted' '%s'\n", c.oid);
- printf("product: '%s' %u.%u\n", pnm, prv_major, prv_minor);
- printf("serial: 0x%08x\n", psn);
- printf("manufacturing date: %u %s\n", 2000 + mdt_year,
- months[mdt_month]);
+ printf("product: '%s' %u.%u\n", c.pnm, c.prv_major, c.prv_minor);
+ printf("serial: 0x%08x\n", c.psn);
+ printf("manufacturing date: %u %s\n", 2000 + c.mdt_year,
+ months[c.mdt_month]);
}
}
@@ -575,37 +602,23 @@ static void print_mmc_cid(struct config *config, char *cid)
"jul", "aug", "sep", "oct", "nov", "dec",
"invalid0", "invalid1", "invalid2", "invalid3",
};
- unsigned int mid;
- unsigned int cbx;
- unsigned int oid;
- char pnm[7];
- unsigned int prv_major;
- unsigned int prv_minor;
- unsigned int psn;
- unsigned int mdt_month;
- unsigned int mdt_year;
- unsigned int crc;
- char *manufacturer = NULL;
-
- parse_bin(cid, "8u6r2u8u48a4u4u32u4u4u7u1r",
- &mid, &cbx, &oid, &pnm[0], &prv_major, &prv_minor, &psn,
- &mdt_year, &mdt_month, &crc);
-
- pnm[6] = '\0';
+ struct mmc_cid c;
+ char *manufacturer;
- manufacturer = get_manufacturer(config, mid);
+ parse_mmc_cid(cid, &c);
+ manufacturer = get_manufacturer(config, c.mid);
if (config->verbose) {
printf("======MMC/CID======\n");
- printf("\tMID: 0x%02x (", mid);
+ printf("\tMID: 0x%02x (", c.mid);
if (manufacturer)
printf("%s)\n", manufacturer);
else
printf("Unlisted)\n");
- printf("\tCBX: 0x%01x (", cbx);
- switch (cbx) {
+ printf("\tCBX: 0x%01x (", c.cbx);
+ switch (c.cbx) {
case 0:
printf("card)\n");
break;
@@ -620,25 +633,26 @@ static void print_mmc_cid(struct config *config, char *cid)
break;
}
- printf("\tOID: 0x%01x\n", oid);
- printf("\tPNM: %s\n", pnm);
- printf("\tPRV: 0x%01x%01x ", prv_major, prv_minor);
- printf("(%u.%u)\n", prv_major, prv_minor);
- printf("\tPSN: 0x%08x\n", psn);
- printf("\tMDT: 0x%01x%01x %u %s\n", mdt_month, mdt_year,
- 1997 + mdt_year, months[mdt_month]);
- printf("\tCRC: 0x%02x\n", crc);
+ printf("\tOID: 0x%01x\n", c.oid);
+ printf("\tPNM: %s\n", c.pnm);
+ printf("\tPRV: 0x%01x%01x ", c.prv_major, c.prv_minor);
+ printf("(%u.%u)\n", c.prv_major, c.prv_minor);
+ printf("\tPSN: 0x%08x\n", c.psn);
+ printf("\tMDT: 0x%01x%01x %u %s\n", c.mdt_month, c.mdt_year,
+ 1997 + c.mdt_year, months[c.mdt_month]);
+ printf("\tCRC: 0x%02x\n", c.crc);
} else {
if (manufacturer)
printf("manufacturer: 0x%02x (%s) oid: 0x%01x\n",
- mid, manufacturer, oid);
+ c.mid, manufacturer, c.oid);
else
- printf("manufacturer: 0x%02x (Unlisted) oid: 0x%01x\n", mid, oid);
+ printf("manufacturer: 0x%02x (Unlisted) oid: 0x%01x\n",
+ c.mid, c.oid);
- printf("product: '%s' %u.%u\n", pnm, prv_major, prv_minor);
- printf("serial: 0x%08x\n", psn);
- printf("manufacturing date: %u %s\n", 1997 + mdt_year,
- months[mdt_month]);
+ printf("product: '%s' %u.%u\n", c.pnm, c.prv_major, c.prv_minor);
+ printf("serial: 0x%08x\n", c.psn);
+ printf("manufacturing date: %u %s\n", 1997 + c.mdt_year,
+ months[c.mdt_month]);
}
}
@@ -2270,6 +2284,110 @@ static int do_read_reg(int argc, char **argv, enum REG_TYPE reg)
return ret;
}
+static const char *month_name(unsigned int month)
+{
+ static const char *months[] = {
+ "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec",
+ "invalid0", "invalid1", "invalid2", "invalid3",
+ };
+
+ if (month >= ARRAY_SIZE(months))
+ return "invalid";
+
+ return months[month];
+}
+
+static void print_list_entry(struct config *cfg, const char *devname,
+ const char *blkdev, char *cid)
+{
+ char *mfr;
+ char devnode[32];
+
+ snprintf(devnode, sizeof(devnode), "/dev/%s", blkdev ? blkdev : "?");
+
+ if (cfg->bus == SD) {
+ struct sd_cid c;
+
+ parse_sd_cid(cid, &c);
+ mfr = get_manufacturer(cfg, c.mid);
+ printf("%-14s %-14s SD %-20s %-10s %u.%u 0x%08x %u-%s\n",
+ devname, devnode, mfr ? mfr : "Unlisted", c.pnm,
+ c.prv_major, c.prv_minor, c.psn, 2000 + c.mdt_year,
+ month_name(c.mdt_month));
+ } else {
+ struct mmc_cid c;
+
+ parse_mmc_cid(cid, &c);
+ mfr = get_manufacturer(cfg, c.mid);
+ printf("%-14s %-14s MMC %-20s %-10s %u.%u 0x%08x %u-%s\n",
+ devname, devnode, mfr ? mfr : "Unlisted", c.pnm,
+ c.prv_major, c.prv_minor, c.psn, 1997 + c.mdt_year,
+ month_name(c.mdt_month));
+ }
+
+ free(mfr);
+}
+
+int do_list(int nargs, char **argv)
+{
+ const char *bus_path = "/sys/bus/mmc/devices";
+ DIR *d;
+ struct dirent *ent;
+ bool header_printed = false;
+
+ d = opendir(bus_path);
+ if (!d) {
+ fprintf(stderr, "Cannot open %s\n", bus_path);
+ return -1;
+ }
+
+ struct config cfg = {};
+
+ while ((ent = readdir(d)) != NULL) {
+ char devpath[PATH_MAX];
+ char resolved[PATH_MAX];
+ char *type, *cid, *blkdev;
+
+ if (!strchr(ent->d_name, ':'))
+ continue;
+
+ snprintf(devpath, sizeof(devpath), "%s/%s", bus_path, ent->d_name);
+ if (realpath(devpath, resolved) == NULL)
+ continue;
+
+ type = read_file_at(resolved, "type");
+ if (!type)
+ continue;
+
+ cid = read_file_at(resolved, "cid");
+ if (!cid) {
+ free(type);
+ continue;
+ }
+
+ blkdev = find_block_devname(resolved);
+ cfg.bus = strcmp(type, "MMC") ? SD : MMC;
+
+ if (!header_printed) {
+ printf("%-14s %-14s %-5s%-20s %-10s %-5s %-12s %s\n",
+ "DEVICE", "DEV", "TYPE", "MANUFACTURER", "PRODUCT",
+ "REV", "SERIAL", "DATE");
+ header_printed = true;
+ }
+
+ print_list_entry(&cfg, ent->d_name, blkdev, cid);
+
+ free(blkdev);
+ free(cid);
+ free(type);
+ }
+
+ closedir(d);
+ return 0;
+}
+
+
int do_read_csd(int argc, char **argv)
{
return do_read_reg(argc, argv, CSD);
--
2.53.0
next prev parent reply other threads:[~2026-05-15 21:38 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-15 21:37 [PATCH v2 0/5] mmc-utils: improve lsmmc usability Torstein Eide
2026-05-15 21:37 ` Torstein Eide [this message]
2026-05-15 21:37 ` [PATCH v2 2/5] mmc-utils: lsmmc: Use external .ids files for manufacturer lookup Torstein Eide
2026-05-15 21:37 ` [PATCH v2 3/5] mmc-utils: lsmmc: Accept /dev and /sys/block paths for register reads Torstein Eide
2026-05-15 21:37 ` [PATCH v2 4/5] mmc-utils: lsmmc: Add mmc list command Torstein Eide
2026-05-15 21:37 ` [PATCH v2 5/5] mmc-utils: Add bash completion Torstein Eide
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260515213747.1452692-2-torsteine+linux@gmail.com \
--to=torsteine@gmail.com \
--cc=linux-mmc@vger.kernel.org \
--cc=torsteine+linux@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox