All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] mmc-utils: Revamp CSD register parsing
@ 2023-09-28  8:04 Avri Altman
  2023-09-28  8:04 ` [PATCH v2 1/4] mmc-utils: lsmmc: Simplify prinitng manufacturer name Avri Altman
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Avri Altman @ 2023-09-28  8:04 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc; +Cc: Avri Altman

Dust-up this old code that practically left untouched since lsmmc got
merged into mmc-utils.

The first 3 patches are mostly cleanups, where the 4th is fixing a
capacity calculation bug.

v2:
 - remove the first patch from the original series (got accepted)
 - Fix an ARM64 compilation warning
 
 
Avri Altman (3):
  mmc-utils: lsmmc: Simplify prinitng manufacturer name
  mmc-utils: lsmmc: Simplify interface processing functions
  mmc-utils: lsmmc: Disintegrade print_mmc_csd

wanggang26 (1):
  mmc-utils: lsmmc: Fix emmc capacity calculation

 lsmmc.c | 1548 ++++++++++++++++++++++++++-----------------------------
 1 file changed, 719 insertions(+), 829 deletions(-)

-- 
2.42.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 1/4] mmc-utils: lsmmc: Simplify prinitng manufacturer name
  2023-09-28  8:04 [PATCH v2 0/4] mmc-utils: Revamp CSD register parsing Avri Altman
@ 2023-09-28  8:04 ` Avri Altman
  2023-09-28  8:04 ` [PATCH v2 2/4] mmc-utils: lsmmc: Simplify interface processing functions Avri Altman
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Avri Altman @ 2023-09-28  8:04 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc; +Cc: Avri Altman

We used to have this odd way of printing the manufacturer name. To that
end we cached the entire database beforehand which is completely
useless.

While at it, get rid of some more redundant code.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 lsmmc.c | 157 ++++++++++++++++----------------------------------------
 1 file changed, 44 insertions(+), 113 deletions(-)

diff --git a/lsmmc.c b/lsmmc.c
index 85779bb..3b52b9f 100644
--- a/lsmmc.c
+++ b/lsmmc.c
@@ -53,16 +53,19 @@
 #define MASK(high, low)		(MASKTOBIT0(high) & ~MASKTOBIT0(low - 1))
 #define BITS(value, high, low)	(((value) & MASK((high), (low))) >> (low))
 #define IDS_MAX			256
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+enum bus_type {
+	MMC = 1,
+	SD,
+};
 
 struct config {
 	char *idsfile;
 	char *dir;
 	bool verbose;
-	int interfaces;
-	char **interface;
-	char **mmc_ids;
-	char **sd_ids;
 
+	enum bus_type bus;
 	char *type;
 	char *cid;
 	char *csd;
@@ -78,184 +81,151 @@ enum REG_TYPE {
 };
 
 struct ids_database {
-	char *type;
 	int id;
 	char *manufacturer;
 };
 
-struct ids_database database[] = {
+static struct ids_database sd_database[] = {
 	{
-		.type = "sd",
 		.id = 0x01,
 		.manufacturer = "Panasonic",
 	},
 	{
-		.type = "sd",
 		.id = 0x02,
 		.manufacturer = "Toshiba/Kingston/Viking",
 	},
 	{
-		.type = "sd",
 		.id = 0x03,
 		.manufacturer = "SanDisk",
 	},
 	{
-		.type = "sd",
 		.id = 0x08,
 		.manufacturer = "Silicon Power",
 	},
 	{
-		.type = "sd",
 		.id = 0x18,
 		.manufacturer = "Infineon",
 	},
 	{
-		.type = "sd",
 		.id = 0x1b,
 		.manufacturer = "Transcend/Samsung",
 	},
 	{
-		.type = "sd",
 		.id = 0x1c,
 		.manufacturer = "Transcend",
 	},
 	{
-		.type = "sd",
 		.id = 0x1d,
 		.manufacturer = "Corsair/AData",
 	},
 	{
-		.type = "sd",
 		.id = 0x1e,
 		.manufacturer = "Transcend",
 	},
 	{
-		.type = "sd",
 		.id = 0x1f,
 		.manufacturer = "Kingston",
 	},
 	{
-		.type = "sd",
 		.id = 0x27,
 		.manufacturer = "Delkin/Phison",
 	},
 	{
-		.type = "sd",
 		.id = 0x28,
 		.manufacturer = "Lexar",
 	},
 	{
-		.type = "sd",
 		.id = 0x30,
 		.manufacturer = "SanDisk",
 	},
 	{
-		.type = "sd",
 		.id = 0x31,
 		.manufacturer = "Silicon Power",
 	},
 	{
-		.type = "sd",
 		.id = 0x33,
 		.manufacturer = "STMicroelectronics",
 	},
 	{
-		.type = "sd",
 		.id = 0x41,
 		.manufacturer = "Kingston",
 	},
 	{
-		.type = "sd",
 		.id = 0x6f,
 		.manufacturer = "STMicroelectronics",
 	},
 	{
-		.type = "sd",
 		.id = 0x74,
 		.manufacturer = "Transcend",
 	},
 	{
-		.type = "sd",
 		.id = 0x76,
 		.manufacturer = "Patriot",
 	},
 	{
-		.type = "sd",
 		.id = 0x82,
 		.manufacturer = "Gobe/Sony",
 	},
 	{
-		.type = "sd",
 		.id = 0x89,
 		.manufacturer = "Unknown",
 	},
+};
+
+static struct ids_database mmc_database[] = {
 	{
-		.type = "mmc",
 		.id = 0x00,
 		.manufacturer = "SanDisk",
 	},
 	{
-		.type = "mmc",
 		.id = 0x02,
 		.manufacturer = "Kingston/SanDisk",
 	},
 	{
-		.type = "mmc",
 		.id = 0x03,
 		.manufacturer = "Toshiba",
 	},
 	{
-		.type = "mmc",
 		.id = 0x05,
 		.manufacturer = "Unknown",
 	},
 	{
-		.type = "mmc",
 		.id = 0x06,
 		.manufacturer = "Unknown",
 	},
 	{
-		.type = "mmc",
 		.id = 0x11,
 		.manufacturer = "Toshiba",
 	},
 	{
-		.type = "mmc",
 		.id = 0x13,
 		.manufacturer = "Micron",
 	},
 	{
-		.type = "mmc",
 		.id = 0x15,
 		.manufacturer = "Samsung/SanDisk/LG",
 	},
 	{
-		.type = "mmc",
 		.id = 0x37,
 		.manufacturer = "KingMax",
 	},
 	{
-		.type = "mmc",
 		.id = 0x44,
 		.manufacturer = "ATP",
 	},
 	{
-		.type = "mmc",
 		.id = 0x45,
 		.manufacturer = "SanDisk Corporation",
 	},
 	{
-		.type = "mmc",
 		.id = 0x2c,
 		.manufacturer = "Kingston",
 	},
 	{
-		.type = "mmc",
 		.id = 0x70,
 		.manufacturer = "Kingston",
 	},
 	{
-		.type = "mmc",
 		.id = 0xfe,
 		.manufacturer = "Micron",
 	},
@@ -310,47 +280,26 @@ int parse_opts(int argc, char **argv, struct config *config)
 	return 0;
 }
 
-int parse_ids(struct config *config)
+static char *get_manufacturer(struct config *config, unsigned int manid)
 {
-	unsigned int ids_cnt = sizeof(database) / sizeof(struct ids_database);
-	unsigned int value;
-	char **ids;
-	char *type;
+	struct ids_database *db;
+	unsigned int ids_cnt;
 	int i;
 
-	for (i = 0; i < ids_cnt; i++) {
-		type = database[i].type;
-
-		if (!strcmp(type, "mmc")) {
-			ids = config->mmc_ids;
-		} else if (!strcmp(type, "sd")) {
-			ids = config->sd_ids;
-		} else {
-			fprintf(stderr,
-				"MMC/SD id parse error, unknown type: '%s'.\n",
-				type);
-			return -1;
-		}
-
-		value = database[i].id;
-
-		if (value >= IDS_MAX) {
-			fprintf(stderr,
-				"MMC/SD id parse error, id out of range.\n");
-			return -1;
-		}
-
-		if (ids[value]) {
-			fprintf(stderr,
-				"Duplicate entries: type='%s', id='0x%1x'.\n",
-				type, value);
-			return -1;
-		}
+	if (config->bus == MMC) {
+		db = mmc_database;
+		ids_cnt = ARRAY_SIZE(mmc_database);
+	} else {
+		db = sd_database;
+		ids_cnt = ARRAY_SIZE(sd_database);
+	}
 
-		ids[value] = database[i].manufacturer;
+	for (i = 0; i < ids_cnt; i++) {
+		if (db[i].id == manid)
+			return db[i].manufacturer;
 	}
 
-	return 0;
+	return NULL;
 }
 
 /* MMC/SD file parsing functions */
@@ -538,6 +487,7 @@ void print_sd_cid(struct config *config, char *cid)
 	unsigned int mdt_month;
 	unsigned int mdt_year;
 	unsigned int crc;
+	char *manufacturer = NULL;
 
 	parse_bin(cid, "8u16a40a4u4u32u4r8u4u7u1r",
 		&mid, &oid[0], &pnm[0], &prv_major, &prv_minor, &psn,
@@ -546,12 +496,14 @@ void print_sd_cid(struct config *config, char *cid)
 	oid[2] = '\0';
 	pnm[5] = '\0';
 
+	manufacturer = get_manufacturer(config, mid);
+
 	if (config->verbose) {
 		printf("======SD/CID======\n");
 
 		printf("\tMID: 0x%02x (", mid);
-		if (config->sd_ids[mid])
-			printf("%s)\n", config->sd_ids[mid]);
+		if (manufacturer)
+			printf("%s)\n", manufacturer);
 		else
 			printf("Unlisted)\n");
 
@@ -564,9 +516,9 @@ void print_sd_cid(struct config *config, char *cid)
 		       2000 + mdt_year, months[mdt_month]);
 		printf("\tCRC: 0x%02x\n", crc);
 	} else {
-		if (config->sd_ids[mid])
+		if (manufacturer)
 			printf("manufacturer: '%s' '%s'\n",
-			       config->sd_ids[mid], oid);
+			       manufacturer, oid);
 		else
 			printf("manufacturer: 'Unlisted' '%s'\n", oid);
 
@@ -594,6 +546,7 @@ void print_mmc_cid(struct config *config, char *cid)
 	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,
@@ -601,12 +554,14 @@ void print_mmc_cid(struct config *config, char *cid)
 
 	pnm[6] = '\0';
 
+	manufacturer = get_manufacturer(config, mid);
+
 	if (config->verbose) {
 		printf("======MMC/CID======\n");
 
 		printf("\tMID: 0x%02x (", mid);
-		if (config->mmc_ids[mid])
-			printf("%s)\n", config->mmc_ids[mid]);
+		if (manufacturer)
+			printf("%s)\n", manufacturer);
 		else
 			printf("Unlisted)\n");
 
@@ -635,9 +590,9 @@ void print_mmc_cid(struct config *config, char *cid)
 		       1997 + mdt_year, months[mdt_month]);
 		printf("\tCRC: 0x%02x\n", crc);
 	} else {
-		if (config->mmc_ids[mid])
+		if (manufacturer)
 			printf("manufacturer: 0x%02x (%s) oid: 0x%01x\n",
-			       mid, config->mmc_ids[mid], oid);
+			       mid, manufacturer, oid);
 		else
 			printf("manufacturer: 0x%02x (Unlisted) oid: 0x%01x\n", mid, oid);
 
@@ -2308,6 +2263,8 @@ int process_dir(struct config *config, enum REG_TYPE reg)
 		goto err;
 	}
 
+	config->bus = strcmp(type, "MMC") ? SD : MMC;
+
 	switch (reg) {
 	case CID:
 		cid = read_file("cid");
@@ -2369,45 +2326,19 @@ err:
 	return ret;
 }
 
-int lsmmc_main(struct config *config, int argc, char **argv)
-{
-	int ret;
-
-	config->mmc_ids = calloc(IDS_MAX, sizeof(char *));
-	config->sd_ids = calloc(IDS_MAX, sizeof(char *));
-	if (!config->mmc_ids || !config->sd_ids) {
-		fprintf(stderr, "Could not allocate memory for lsmmc.\n");
-		return -1;
-	}
-
-	ret = parse_opts(argc, argv, config);
-	if (ret)
-		return ret;
-
-	return parse_ids(config);
-}
-
-void lsmmc_free(struct config *config)
-{
-	free(config->mmc_ids);
-	free(config->sd_ids);
-	free(config->dir);
-}
-
 static int do_read_reg(int argc, char **argv, enum REG_TYPE reg)
 {
 	struct config cfg = {};
 	int ret;
 
-	ret = lsmmc_main(&cfg, argc, argv);
+	ret = parse_opts(argc, argv, &cfg);
 	if (ret)
-		goto out;
+		return ret;
 
 	if (cfg.dir)
 		ret = process_dir(&cfg, reg);
 
-out:
-	lsmmc_free(&cfg);
+	free(cfg.dir);
 
 	return ret;
 
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v2 2/4] mmc-utils: lsmmc: Simplify interface processing functions
  2023-09-28  8:04 [PATCH v2 0/4] mmc-utils: Revamp CSD register parsing Avri Altman
  2023-09-28  8:04 ` [PATCH v2 1/4] mmc-utils: lsmmc: Simplify prinitng manufacturer name Avri Altman
@ 2023-09-28  8:04 ` Avri Altman
  2023-09-28  8:04 ` [PATCH v2 3/4] mmc-utils: lsmmc: Disintegrade print_mmc_csd Avri Altman
  2023-09-28  8:04 ` [PATCH v2 4/4] mmc-utils: lsmmc: Fix emmc capacity calculation Avri Altman
  3 siblings, 0 replies; 5+ messages in thread
From: Avri Altman @ 2023-09-28  8:04 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc; +Cc: Avri Altman

Call those directly form process_dir() and remove the no longer needed
print_info().

While at it remove the deprecated EXT_CSD handling.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 lsmmc.c | 70 ++++++++++++++++++++-------------------------------------
 1 file changed, 24 insertions(+), 46 deletions(-)

diff --git a/lsmmc.c b/lsmmc.c
index 3b52b9f..e9b0762 100644
--- a/lsmmc.c
+++ b/lsmmc.c
@@ -77,7 +77,6 @@ enum REG_TYPE {
 	CID = 0,
 	CSD,
 	SCR,
-	EXT_CSD,
 };
 
 struct ids_database {
@@ -2217,29 +2216,10 @@ void print_sd_scr(struct config *config, char *scr)
 	}
 }
 
-/* MMC/SD interface processing functions */
-void print_info(struct config *config, char *type,
-	char *cid, char *csd, char *scr, char *ext_csd)
-{
-	printf("type: '%s'\n", type);
-
-	if (!strcmp(type, "SD") && cid)
-		print_sd_cid(config, cid);
-	else if (!strcmp(type, "MMC") && cid)
-		print_mmc_cid(config, cid);
-
-	if (!strcmp(type, "SD") && scr)
-		print_sd_scr(config, scr);
-
-	if (!strcmp(type, "MMC") && csd)
-		print_mmc_csd(config, csd);
-	else if (!strcmp(type, "SD") && csd)
-		print_sd_csd(config, csd);
-}
-
 int process_dir(struct config *config, enum REG_TYPE reg)
 {
-	char *type = NULL, *cid = NULL, *csd = NULL, *scr = NULL, *ext_csd = NULL;
+	char *type = NULL;
+	char *reg_content = NULL;
 	int ret = 0;
 
 	if (chdir(config->dir) < 0) {
@@ -2267,29 +2247,41 @@ int process_dir(struct config *config, enum REG_TYPE reg)
 
 	switch (reg) {
 	case CID:
-		cid = read_file("cid");
-		if (!cid) {
+		reg_content = read_file("cid");
+		if (!reg_content) {
 			fprintf(stderr,
 				"Could not read card identity in directory '%s'.\n",
 				config->dir);
 			ret = -1;
 			goto err;
 		}
+
+		if (config->bus == SD)
+			print_sd_cid(config, reg_content);
+		else
+			print_mmc_cid(config, reg_content);
+
 		break;
 	case CSD:
-		csd = read_file("csd");
-		if (!csd) {
+		reg_content = read_file("csd");
+		if (!reg_content) {
 			fprintf(stderr,
 				"Could not read card specific data in "
 				"directory '%s'.\n", config->dir);
 			ret = -1;
 			goto err;
 		}
+
+		if (config->bus == SD)
+			print_sd_csd(config, reg_content);
+		else
+			print_mmc_csd(config, reg_content);
+
 		break;
 	case SCR:
 		if (!strcmp(type, "SD")) {
-			scr = read_file("scr");
-			if (!scr) {
+			reg_content = read_file("scr");
+			if (!reg_content) {
 				fprintf(stderr, "Could not read SD card "
 					"configuration in directory '%s'.\n",
 					config->dir);
@@ -2297,30 +2289,16 @@ int process_dir(struct config *config, enum REG_TYPE reg)
 				goto err;
 			}
 		}
-		break;
-	case EXT_CSD:
-		if (!strcmp(type, "MMC")) {
-			ext_csd = read_file("ext_csd");
-			if (!ext_csd) {
-				fprintf(stderr, "Could not read extra specific "
-					"data in directory '%s'.\n",
-					config->dir);
-				ret = -1;
-				goto err;
-			}
-		}
+
+		print_sd_scr(config, reg_content);
+
 		break;
 	default:
 		goto err;
 	}
 
-	print_info(config, type, cid, csd, scr, ext_csd);
-
 err:
-	free(ext_csd);
-	free(scr);
-	free(csd);
-	free(cid);
+	free(reg_content);
 	free(type);
 
 	return ret;
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v2 3/4] mmc-utils: lsmmc: Disintegrade print_mmc_csd
  2023-09-28  8:04 [PATCH v2 0/4] mmc-utils: Revamp CSD register parsing Avri Altman
  2023-09-28  8:04 ` [PATCH v2 1/4] mmc-utils: lsmmc: Simplify prinitng manufacturer name Avri Altman
  2023-09-28  8:04 ` [PATCH v2 2/4] mmc-utils: lsmmc: Simplify interface processing functions Avri Altman
@ 2023-09-28  8:04 ` Avri Altman
  2023-09-28  8:04 ` [PATCH v2 4/4] mmc-utils: lsmmc: Fix emmc capacity calculation Avri Altman
  3 siblings, 0 replies; 5+ messages in thread
From: Avri Altman @ 2023-09-28  8:04 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc; +Cc: Avri Altman

Make it more readable and manageable.  No functional change.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 lsmmc.c | 1322 +++++++++++++++++++++++++++----------------------------
 1 file changed, 653 insertions(+), 669 deletions(-)

diff --git a/lsmmc.c b/lsmmc.c
index e9b0762..c984d9a 100644
--- a/lsmmc.c
+++ b/lsmmc.c
@@ -1225,502 +1225,677 @@ void print_sd_csd(struct config *config, char *csd)
 	}
 }
 
-void print_mmc_csd(struct config *config, char *csd)
+static void print_mmc_csd_structure(unsigned int csd_structure)
 {
-	unsigned int csd_structure;
-	unsigned int spec_vers;
-	unsigned int taac_timevalue;
-	unsigned int taac_timeunit;
-	unsigned int nsac;
-	unsigned int tran_speed_timevalue;
-	unsigned int tran_speed_transferrateunit;
-	unsigned int ccc;
-	unsigned int read_bl_len;
-	unsigned int read_bl_partial;
-	unsigned int write_blk_misalign;
-	unsigned int read_blk_misalign;
-	unsigned int dsr_imp;
-	unsigned int c_size;
-	unsigned int vdd_r_curr_min;
-	unsigned int vdd_r_curr_max;
-	unsigned int vdd_w_curr_min;
-	unsigned int vdd_w_curr_max;
-	unsigned int c_size_mult;
-	unsigned int erase_grp_size;
-	unsigned int erase_grp_mult;
-	unsigned int wp_grp_size;
-	unsigned int wp_grp_enable;
-	unsigned int default_ecc;
-	unsigned int r2w_factor;
-	unsigned int write_bl_len;
-	unsigned int write_bl_partial;
-	unsigned int content_prot_app;
-	unsigned int file_format_grp;
-	unsigned int copy;
-	unsigned int perm_write_protect;
-	unsigned int tmp_write_protect;
-	unsigned int file_format;
-	unsigned int ecc;
-	unsigned int crc;
-	unsigned int taac;
-	unsigned int tran_speed;
+	printf("\tCSD_STRUCTURE: 0x%01x (", csd_structure);
+	switch (csd_structure) {
+	case 0x0:
+		printf("v1.0)\n");
+		break;
+	case 0x1:
+		printf("v1.1)\n");
+		break;
+	case 0x2:
+		printf("v1.2)\n");
+		break;
+	case 0x3:
+		printf("version in ext_csd)\n");
+		break;
+	}
+}
 
-	parse_bin(csd, "2u4u2r1r4u3u8u1r4u3u12u4u1u1u1u1u2r12u3u3u3u3u3u"
-		  "5u5u5u1u2u3u4u1u4r1u1u1u1u1u2u2u7u1r",
-		  &csd_structure, &spec_vers, &taac_timevalue,
-		  &taac_timeunit, &nsac, &tran_speed_timevalue,
-		  &tran_speed_transferrateunit, &ccc, &read_bl_len,
-		  &read_bl_partial, &write_blk_misalign,
-		  &read_blk_misalign, &dsr_imp, &c_size,
-		  &vdd_r_curr_min, &vdd_r_curr_max,
-		  &vdd_w_curr_min, &vdd_w_curr_max, &c_size_mult,
-		  &erase_grp_size, &erase_grp_mult, &wp_grp_size,
-		  &wp_grp_enable, &default_ecc, &r2w_factor,
-		  &write_bl_len, &write_bl_partial, &content_prot_app,
-		  &file_format_grp, &copy, &perm_write_protect,
-		  &tmp_write_protect, &file_format, &ecc, &crc);
+static void print_mmc_csd_spec_ver(unsigned int spec_vers)
+{
+	printf("\tSPEC_VERS: 0x%01x (", spec_vers);
+	switch (spec_vers) {
+	case 0x0:
+		printf("v1.0-v1.2)\n");
+		break;
+	case 0x1:
+		printf("v1.4)\n");
+		break;
+	case 0x2:
+		printf("v2.0-v2.2)\n");
+		break;
+	case 0x3:
+		printf("v3.1-v3.31)\n");
+		break;
+	case 0x4:
+		printf("v4.0-v4.3)\n");
+		break;
+	default:
+		printf("reserved)\n");
+		break;
+	}
+}
 
-	taac = taac_timevalue << 3 | taac_timeunit;
-	tran_speed = tran_speed_timevalue << 3 | tran_speed_transferrateunit;
+static void
+print_mmc_csd_taac(unsigned int taac_timevalue, unsigned int taac_timeunit)
+{
+	float value;
+	unsigned int taac = taac_timevalue << 3 | taac_timeunit;
 
-	if (config->verbose) {
-		float value;
-		int mult;
-		int blocknr;
-		int block_len;
-		unsigned long long blocks = 0;
-		int block_size = 0;
-		unsigned long long memory_capacity;
+	printf("\tTAAC: 0x%02x (", taac);
+	switch (taac_timevalue) {
+	case 0x0:
+		value = 0.0f;
+		break;
+	case 0x1:
+		value = 1.0f;
+		break;
+	case 0x2:
+		value = 1.2f;
+		break;
+	case 0x3:
+		value = 1.3f;
+		break;
+	case 0x4:
+		value = 1.5f;
+		break;
+	case 0x5:
+		value = 2.0f;
+		break;
+	case 0x6:
+		value = 2.5f;
+		break;
+	case 0x7:
+		value = 3.0f;
+		break;
+	case 0x8:
+		value = 3.5f;
+		break;
+	case 0x9:
+		value = 4.0f;
+		break;
+	case 0xa:
+		value = 4.5f;
+		break;
+	case 0xb:
+		value = 5.0f;
+		break;
+	case 0xc:
+		value = 5.5f;
+		break;
+	case 0xd:
+		value = 6.0f;
+		break;
+	case 0xe:
+		value = 7.0f;
+		break;
+	case 0xf:
+		value = 8.0f;
+		break;
+	default:
+		value = 0.0f;
+		break;
+	}
 
-		printf("======MMC/CSD======\n");
+	switch (taac_timeunit) {
+	case 0x0:
+		printf("%.2fns)\n", value * 1.0f);
+		break;
+	case 0x1:
+		printf("%.2fns)\n", value * 10.0f);
+		break;
+	case 0x2:
+		printf("%.2fns)\n", value * 100.0f);
+		break;
+	case 0x3:
+		printf("%.2fus)\n", value * 1.0f);
+		break;
+	case 0x4:
+		printf("%.2fus)\n", value * 10.0f);
+		break;
+	case 0x5:
+		printf("%.2fus)\n", value * 100.0f);
+		break;
+	case 0x6:
+		printf("%.2fms)\n", value * 1.0f);
+		break;
+	case 0x7:
+		printf("%.2fms)\n", value * 10.0f);
+		break;
+	}
+}
 
-		printf("\tCSD_STRUCTURE: 0x%01x (", csd_structure);
-		switch (csd_structure) {
-		case 0x0:
-			printf("v1.0)\n");
-			break;
-		case 0x1:
-			printf("v1.1)\n");
-			break;
-		case 0x2:
-			printf("v1.2)\n");
-			break;
-		case 0x3:
-			printf("version in ext_csd)\n");
-			break;
-		}
+static void print_mmc_csd_nsac(unsigned int nsac, unsigned int tran_speed_timevalue,
+			       unsigned int tran_speed_transferrateunit)
+{
+	float value;
+	unsigned int tran_speed = tran_speed_timevalue << 3 | tran_speed_transferrateunit;
+
+	printf("\tNSAC: %u clocks\n", nsac);
+	printf("\tTRAN_SPEED: 0x%02x (", tran_speed);
+	switch (tran_speed_timevalue) {
+	case 0x0:
+		value = 0.0f;
+		break;
+	case 0x1:
+		value = 1.0f;
+		break;
+	case 0x2:
+		value = 1.2f;
+		break;
+	case 0x3:
+		value = 1.3f;
+		break;
+	case 0x4:
+		value = 1.5f;
+		break;
+	case 0x5:
+		value = 2.0f;
+		break;
+	case 0x6:
+		value = 2.6f;
+		break;
+	case 0x7:
+		value = 3.0f;
+		break;
+	case 0x8:
+		value = 3.5f;
+		break;
+	case 0x9:
+		value = 4.0f;
+		break;
+	case 0xa:
+		value = 4.5f;
+		break;
+	case 0xb:
+		value = 5.2f;
+		break;
+	case 0xc:
+		value = 5.5f;
+		break;
+	case 0xd:
+		value = 6.0f;
+		break;
+	case 0xe:
+		value = 7.0f;
+		break;
+	case 0xf:
+		value = 8.0f;
+		break;
+	default:
+		value = 0.0f;
+		break;
+	}
 
-		printf("\tSPEC_VERS: 0x%01x (", spec_vers);
-		switch (spec_vers) {
-		case 0x0:
-			printf("v1.0-v1.2)\n");
-			break;
-		case 0x1:
-			printf("v1.4)\n");
-			break;
-		case 0x2:
-			printf("v2.0-v2.2)\n");
-			break;
-		case 0x3:
-			printf("v3.1-v3.31)\n");
-			break;
-		case 0x4:
-			printf("v4.0-v4.3)\n");
-			break;
-		default:
-			printf("reserved)\n");
-			break;
-		}
+	switch (tran_speed_transferrateunit) {
+	case 0x0:
+		printf("%.2fKHz/s)\n", value * 100.0f);
+		break;
+	case 0x1:
+		printf("%.2fMHz/s)\n", value * 1.0f);
+		break;
+	case 0x2:
+		printf("%.2fMHz/s)\n", value * 10.0f);
+		break;
+	case 0x3:
+		printf("%.2fMHz/s)\n", value * 100.0f);
+		break;
+	default:
+		printf("reserved)\n");
+		break;
+	}
+}
 
-		printf("\tTAAC: 0x%02x (", taac);
-		switch (taac_timevalue) {
-		case 0x0:
-			value = 0.0f;
-			break;
-		case 0x1:
-			value = 1.0f;
-			break;
-		case 0x2:
-			value = 1.2f;
-			break;
-		case 0x3:
-			value = 1.3f;
-			break;
-		case 0x4:
-			value = 1.5f;
-			break;
-		case 0x5:
-			value = 2.0f;
-			break;
-		case 0x6:
-			value = 2.5f;
-			break;
-		case 0x7:
-			value = 3.0f;
-			break;
-		case 0x8:
-			value = 3.5f;
-			break;
-		case 0x9:
-			value = 4.0f;
-			break;
-		case 0xa:
-			value = 4.5f;
-			break;
-		case 0xb:
-			value = 5.0f;
-			break;
-		case 0xc:
-			value = 5.5f;
-			break;
-		case 0xd:
-			value = 6.0f;
-			break;
-		case 0xe:
-			value = 7.0f;
-			break;
-		case 0xf:
-			value = 8.0f;
-			break;
-		default:
-			value = 0.0f;
-			break;
-		}
+static void print_mmc_csd_ccc(unsigned int ccc)
+{
+	printf("\tCCC: 0x%03x (class: ", ccc);
+	if (ccc & 0x800)
+		printf("11, ");
+	if (ccc & 0x400)
+		printf("10, ");
+	if (ccc & 0x200)
+		printf("9, ");
+	if (ccc & 0x100)
+		printf("8, ");
+	if (ccc & 0x080)
+		printf("7, ");
+	if (ccc & 0x040)
+		printf("6, ");
+	if (ccc & 0x020)
+		printf("5, ");
+	if (ccc & 0x010)
+		printf("4, ");
+	if (ccc & 0x008)
+		printf("3, ");
+	if (ccc & 0x004)
+		printf("2, ");
+	if (ccc & 0x002)
+		printf("1, ");
+	if (ccc & 0x001)
+		printf("0, ");
+	printf("  )\n");
+}
 
-		switch (taac_timeunit) {
-		case 0x0:
-			printf("%.2fns)\n", value * 1.0f);
-			break;
-		case 0x1:
-			printf("%.2fns)\n", value * 10.0f);
-			break;
-		case 0x2:
-			printf("%.2fns)\n", value * 100.0f);
-			break;
-		case 0x3:
-			printf("%.2fus)\n", value * 1.0f);
-			break;
-		case 0x4:
-			printf("%.2fus)\n", value * 10.0f);
-			break;
-		case 0x5:
-			printf("%.2fus)\n", value * 100.0f);
-			break;
-		case 0x6:
-			printf("%.2fms)\n", value * 1.0f);
-			break;
-		case 0x7:
-			printf("%.2fms)\n", value * 10.0f);
-			break;
-		}
+static void print_mmc_csd_read_bl_len(unsigned int read_bl_len)
+{
+	printf("\tREAD_BL_LEN: 0x%01x (", read_bl_len);
+	switch (read_bl_len) {
+	case 0x0:
+		printf("1 byte)\n");
+		break;
+	case 0x1:
+		printf("2 byte)\n");
+		break;
+	case 0x2:
+		printf("4 byte)\n");
+		break;
+	case 0x3:
+		printf("8 byte)\n");
+		break;
+	case 0x4:
+		printf("16 byte)\n");
+		break;
+	case 0x5:
+		printf("32 byte)\n");
+		break;
+	case 0x6:
+		printf("64 byte)\n");
+		break;
+	case 0x7:
+		printf("128 byte)\n");
+		break;
+	case 0x8:
+		printf("256 byte)\n");
+		break;
+	case 0x9:
+		printf("512 bytes)\n");
+		break;
+	case 0xa:
+		printf("1024 bytes)\n");
+		break;
+	case 0xb:
+		printf("2048 bytes)\n");
+		break;
+	case 0xc:
+		printf("4096 bytes)\n");
+		break;
+	case 0xd:
+		printf("8192 bytes)\n");
+		break;
+	case 0xe:
+		printf("16K bytes)\n");
+		break;
+	default:
+		printf("reserved bytes)\n");
+		break;
+	}
+}
 
-		printf("\tNSAC: %u clocks\n", nsac);
-		printf("\tTRAN_SPEED: 0x%02x (", tran_speed);
-		switch (tran_speed_timevalue) {
-		case 0x0:
-			value = 0.0f;
-			break;
-		case 0x1:
-			value = 1.0f;
-			break;
-		case 0x2:
-			value = 1.2f;
-			break;
-		case 0x3:
-			value = 1.3f;
-			break;
-		case 0x4:
-			value = 1.5f;
-			break;
-		case 0x5:
-			value = 2.0f;
-			break;
-		case 0x6:
-			value = 2.6f;
-			break;
-		case 0x7:
-			value = 3.0f;
-			break;
-		case 0x8:
-			value = 3.5f;
-			break;
-		case 0x9:
-			value = 4.0f;
-			break;
-		case 0xa:
-			value = 4.5f;
-			break;
-		case 0xb:
-			value = 5.2f;
-			break;
-		case 0xc:
-			value = 5.5f;
-			break;
-		case 0xd:
-			value = 6.0f;
-			break;
-		case 0xe:
-			value = 7.0f;
-			break;
-		case 0xf:
-			value = 8.0f;
-			break;
-		default:
-			value = 0.0f;
-			break;
-		}
+static void print_mmc_csd_read_bl_partial(unsigned int read_bl_partial)
+{
+	printf("\tREAD_BL_PARTIAL: 0x%01x (", read_bl_partial);
+	switch (read_bl_partial) {
+	case 0x0:
+		printf("only 512 byte and READ_BL_LEN block size)\n");
+		break;
+	case 0x1:
+		printf("less than READ_BL_LEN block size can be used)\n");
+		break;
+	}
+}
 
-		switch (tran_speed_transferrateunit) {
-		case 0x0:
-			printf("%.2fKHz/s)\n", value * 100.0f);
-			break;
-		case 0x1:
-			printf("%.2fMHz/s)\n", value * 1.0f);
-			break;
-		case 0x2:
-			printf("%.2fMHz/s)\n", value * 10.0f);
-			break;
-		case 0x3:
-			printf("%.2fMHz/s)\n", value * 100.0f);
-			break;
-		default:
-			printf("reserved)\n");
-			break;
-		}
+static void print_mmc_csd_write_blk_misalign(unsigned int write_blk_misalign)
+{
+	printf("\tWRITE_BLK_MISALIGN: 0x%01x (", write_blk_misalign);
+	switch (write_blk_misalign) {
+	case 0x0:
+		printf("writes across block boundaries are invalid)\n");
+		break;
+	case 0x1:
+		printf("writes across block boundaries are allowed)\n");
+		break;
+	}
+}
 
-		printf("\tCCC: 0x%03x (class: ", ccc);
-		if (ccc & 0x800)
-			printf("11, ");
-		if (ccc & 0x400)
-			printf("10, ");
-		if (ccc & 0x200)
-			printf("9, ");
-		if (ccc & 0x100)
-			printf("8, ");
-		if (ccc & 0x080)
-			printf("7, ");
-		if (ccc & 0x040)
-			printf("6, ");
-		if (ccc & 0x020)
-			printf("5, ");
-		if (ccc & 0x010)
-			printf("4, ");
-		if (ccc & 0x008)
-			printf("3, ");
-		if (ccc & 0x004)
-			printf("2, ");
-		if (ccc & 0x002)
-			printf("1, ");
-		if (ccc & 0x001)
-			printf("0, ");
-		printf("  )\n");
+static void print_mmc_csd_read_blk_misalign(unsigned int read_blk_misalign)
+{
+	printf("\tREAD_BLK_MISALIGN: 0x%01x (", read_blk_misalign);
+	switch (read_blk_misalign) {
+	case 0x0:
+		printf("reads across block boundaries are invalid)\n");
+		break;
+	case 0x1:
+		printf("reads across block boundaries are allowed)\n");
+		break;
+	}
+}
 
-		printf("\tREAD_BL_LEN: 0x%01x (", read_bl_len);
-		switch (read_bl_len) {
-		case 0x0:
-			printf("1 byte)\n");
-			break;
-		case 0x1:
-			printf("2 byte)\n");
-			break;
-		case 0x2:
-			printf("4 byte)\n");
-			break;
-		case 0x3:
-			printf("8 byte)\n");
-			break;
-		case 0x4:
-			printf("16 byte)\n");
-			break;
-		case 0x5:
-			printf("32 byte)\n");
-			break;
-		case 0x6:
-			printf("64 byte)\n");
-			break;
-		case 0x7:
-			printf("128 byte)\n");
-			break;
-		case 0x8:
-			printf("256 byte)\n");
-			break;
-		case 0x9:
-			printf("512 bytes)\n");
-			break;
-		case 0xa:
-			printf("1024 bytes)\n");
-			break;
-		case 0xb:
-			printf("2048 bytes)\n");
-			break;
-		case 0xc:
-			printf("4096 bytes)\n");
-			break;
-		case 0xd:
-			printf("8192 bytes)\n");
-			break;
-		case 0xe:
-			printf("16K bytes)\n");
-			break;
-		default:
-			printf("reserved bytes)\n");
-			break;
-		}
+static void print_mmc_csd_dsr_imp(unsigned int dsr_imp)
+{
+	printf("\tDSR_IMP: 0x%01x (", dsr_imp);
+	switch (dsr_imp) {
+	case 0x0:
+		printf("configurable driver stage not available)\n");
+		break;
+	case 0x1:
+		printf("configurable driver state available)\n");
+		break;
+	}
+}
 
-		printf("\tREAD_BL_PARTIAL: 0x%01x (", read_bl_partial);
-		switch (read_bl_partial) {
-		case 0x0:
-			printf("only 512 byte and READ_BL_LEN block size)\n");
-			break;
-		case 0x1:
-			printf("less than READ_BL_LEN block size can be used)\n");
-			break;
-		}
+static void print_mmc_csd_vdd(unsigned int vdd_r_curr_min, unsigned int vdd_r_curr_max,
+			      unsigned int vdd_w_curr_min, unsigned int vdd_w_curr_max)
+{
+	printf("\tVDD_R_CURR_MIN: 0x%01x (", vdd_r_curr_min);
+	switch (vdd_r_curr_min) {
+	case 0x0:
+		printf("0.5mA)\n");
+		break;
+	case 0x1:
+		printf("1mA)\n");
+		break;
+	case 0x2:
+		printf("5mA)\n");
+		break;
+	case 0x3:
+		printf("10mA)\n");
+		break;
+	case 0x4:
+		printf("25mA)\n");
+		break;
+	case 0x5:
+		printf("35mA)\n");
+		break;
+	case 0x6:
+		printf("60mA)\n");
+		break;
+	case 0x7:
+		printf("100mA)\n");
+		break;
+	}
 
-		printf("\tWRITE_BLK_MISALIGN: 0x%01x (", write_blk_misalign);
-		switch (write_blk_misalign) {
-		case 0x0:
-			printf("writes across block boundaries are invalid)\n");
-			break;
-		case 0x1:
-			printf("writes across block boundaries are allowed)\n");
-			break;
-		}
+	printf("\tVDD_R_CURR_MAX: 0x%01x (", vdd_r_curr_max);
+	switch (vdd_r_curr_max) {
+	case 0x0:
+		printf("1mA)\n");
+		break;
+	case 0x1:
+		printf("5mA)\n");
+		break;
+	case 0x2:
+		printf("10mA)\n");
+		break;
+	case 0x3:
+		printf("25mA)\n");
+		break;
+	case 0x4:
+		printf("35mA)\n");
+		break;
+	case 0x5:
+		printf("45mA)\n");
+		break;
+	case 0x6:
+		printf("80mA)\n");
+		break;
+	case 0x7:
+		printf("200mA)\n");
+		break;
+	}
 
-		printf("\tREAD_BLK_MISALIGN: 0x%01x (", read_blk_misalign);
-		switch (read_blk_misalign) {
-		case 0x0:
-			printf("reads across block boundaries are invalid)\n");
-			break;
-		case 0x1:
-			printf("reads across block boundaries are allowed)\n");
-			break;
-		}
+	printf("\tVDD_W_CURR_MIN: 0x%01x (", vdd_w_curr_min);
+	switch (vdd_w_curr_min) {
+	case 0x0:
+		printf("0.5mA)\n");
+		break;
+	case 0x1:
+		printf("1mA)\n");
+		break;
+	case 0x2:
+		printf("5mA)\n");
+		break;
+	case 0x3:
+		printf("10mA)\n");
+		break;
+	case 0x4:
+		printf("25mA)\n");
+		break;
+	case 0x5:
+		printf("35mA)\n");
+		break;
+	case 0x6:
+		printf("60mA)\n");
+		break;
+	case 0x7:
+		printf("100mA)\n");
+		break;
+	}
 
-		printf("\tDSR_IMP: 0x%01x (", dsr_imp);
-		switch (dsr_imp) {
-		case 0x0:
-			printf("configurable driver stage not available)\n");
-			break;
-		case 0x1:
-			printf("configurable driver state available)\n");
-			break;
-		}
+	printf("\tVDD_W_CURR_MAX: 0x%01x (", vdd_w_curr_max);
+	switch (vdd_w_curr_max) {
+	case 0x0:
+		printf("1mA)\n");
+		break;
+	case 0x1:
+		printf("5mA)\n");
+		break;
+	case 0x2:
+		printf("10mA)\n");
+		break;
+	case 0x3:
+		printf("25mA)\n");
+		break;
+	case 0x4:
+		printf("35mA)\n");
+		break;
+	case 0x5:
+		printf("45mA)\n");
+		break;
+	case 0x6:
+		printf("80mA)\n");
+		break;
+	case 0x7:
+		printf("200mA)\n");
+		break;
+	}
+}
+
+static void print_mmc_csd_default_ecc(unsigned int default_ecc)
+{
+	printf("\tDEFAULT_ECC: 0x%01x (", default_ecc);
+	switch (default_ecc) {
+	case 0:
+		printf("none)\n");
+		break;
+	case 1:
+		printf("BCH)\n");
+		break;
+	default:
+		printf("reserved)\n");
+		break;
+	}
+}
+
+static void print_mmc_csd_write_bl_len(unsigned int write_bl_len)
+{
+	printf("\tWRITE_BL_LEN: 0x%01x (", write_bl_len);
+	switch (write_bl_len) {
+	case 0x0:
+		printf("1 byte)\n");
+		break;
+	case 0x1:
+		printf("2 byte)\n");
+		break;
+	case 0x2:
+		printf("4 byte)\n");
+		break;
+	case 0x3:
+		printf("8 byte)\n");
+		break;
+	case 0x4:
+		printf("16 byte)\n");
+		break;
+	case 0x5:
+		printf("32 byte)\n");
+		break;
+	case 0x6:
+		printf("64 byte)\n");
+		break;
+	case 0x7:
+		printf("128 byte)\n");
+		break;
+	case 0x8:
+		printf("256 byte)\n");
+		break;
+	case 0x9:
+		printf("512 bytes)\n");
+		break;
+	case 0xa:
+		printf("1024 bytes)\n");
+		break;
+	case 0xb:
+		printf("2048 bytes)\n");
+		break;
+	case 0xc:
+		printf("4096 bytes)\n");
+		break;
+	case 0xd:
+		printf("8192 bytes)\n");
+		break;
+	case 0xe:
+		printf("16K bytes)\n");
+		break;
+	default:
+		printf("reserved bytes)\n");
+		break;
+	}
+}
+
+static void print_mmc_csd_write_bl_partial(unsigned int write_bl_partial)
+{
+	printf("\tWRITE_BL_PARTIAL: 0x%01x (", write_bl_partial);
+	switch (write_bl_partial) {
+	case 0x0:
+		printf("only 512 byte and WRITE_BL_LEN block size)\n");
+		break;
+	case 0x1:
+		printf("less than WRITE_BL_LEN block size can be used)\n");
+		break;
+	}
+}
 
-		printf("\tC_SIZE: 0x%03x\n", c_size);
-		printf("\tVDD_R_CURR_MIN: 0x%01x (", vdd_r_curr_min);
-		switch (vdd_r_curr_min) {
-		case 0x0:
-			printf("0.5mA)\n");
-			break;
-		case 0x1:
-			printf("1mA)\n");
-			break;
-		case 0x2:
-			printf("5mA)\n");
-			break;
-		case 0x3:
-			printf("10mA)\n");
-			break;
-		case 0x4:
-			printf("25mA)\n");
-			break;
-		case 0x5:
-			printf("35mA)\n");
-			break;
-		case 0x6:
-			printf("60mA)\n");
-			break;
-		case 0x7:
-			printf("100mA)\n");
-			break;
-		}
+static void print_mmc_csd_file_format(unsigned int file_format, unsigned int file_format_grp)
+{
+	printf("\tFILE_FORMAT: 0x%01x (", file_format);
+	if (file_format != 0)
+		printf("Warn: Invalid FILE_FORMAT\n");
 
-		printf("\tVDD_R_CURR_MAX: 0x%01x (", vdd_r_curr_max);
-		switch (vdd_r_curr_max) {
-		case 0x0:
-			printf("1mA)\n");
-			break;
-		case 0x1:
-			printf("5mA)\n");
-			break;
-		case 0x2:
-			printf("10mA)\n");
-			break;
-		case 0x3:
-			printf("25mA)\n");
-			break;
-		case 0x4:
-			printf("35mA)\n");
+	if (file_format_grp == 1) {
+		printf("reserved)\n");
+	} else {
+		switch (file_format) {
+		case 0:
+			printf("partition table)\n");
 			break;
-		case 0x5:
-			printf("45mA)\n");
+		case 1:
+			printf("no partition table)\n");
 			break;
-		case 0x6:
-			printf("80mA)\n");
+		case 2:
+			printf("Universal File Format)\n");
 			break;
-		case 0x7:
-			printf("200mA)\n");
+		case 3:
+			printf("Others/unknown)\n");
 			break;
 		}
+	}
+}
 
-		printf("\tVDD_W_CURR_MIN: 0x%01x (", vdd_w_curr_min);
-		switch (vdd_w_curr_min) {
-		case 0x0:
-			printf("0.5mA)\n");
-			break;
-		case 0x1:
-			printf("1mA)\n");
-			break;
-		case 0x2:
-			printf("5mA)\n");
-			break;
-		case 0x3:
-			printf("10mA)\n");
-			break;
-		case 0x4:
-			printf("25mA)\n");
-			break;
-		case 0x5:
-			printf("35mA)\n");
-			break;
-		case 0x6:
-			printf("60mA)\n");
-			break;
-		case 0x7:
-			printf("100mA)\n");
-			break;
-		}
+static void print_mmc_csd_ecc(unsigned int ecc)
+{
+	printf("\tECC: 0x%01x (", ecc);
+	switch (ecc) {
+	case 0:
+		printf("none)\n");
+		break;
+	case 1:
+		printf("BCH(542,512))\n");
+		break;
+	default:
+		printf("reserved)\n");
+		break;
+	}
+}
 
-		printf("\tVDD_W_CURR_MAX: 0x%01x (", vdd_w_curr_max);
-		switch (vdd_w_curr_max) {
-		case 0x0:
-			printf("1mA)\n");
-			break;
-		case 0x1:
-			printf("5mA)\n");
-			break;
-		case 0x2:
-			printf("10mA)\n");
-			break;
-		case 0x3:
-			printf("25mA)\n");
-			break;
-		case 0x4:
-			printf("35mA)\n");
-			break;
-		case 0x5:
-			printf("45mA)\n");
-			break;
-		case 0x6:
-			printf("80mA)\n");
-			break;
-		case 0x7:
-			printf("200mA)\n");
-			break;
-		}
+static void print_mmc_csd_capacity(unsigned int c_size, unsigned int c_size_mult,
+				   unsigned int read_bl_len)
+{
+	int mult = 1 << (c_size_mult + 2);
+	unsigned long long blocknr = (c_size + 1) * mult;
+	int block_len = 1 << read_bl_len;
+	unsigned long long memory_capacity;
+
+	printf("\tC_SIZE: 0x%03x\n", c_size);
+	printf("\tC_SIZE_MULT: 0x%01x\n", c_size_mult);
+
+	memory_capacity = blocknr * block_len;
+
+	printf("\tCAPACITY: ");
+	if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0)
+		printf("%.2fGbyte", memory_capacity / (1024.0 * 1024.0 * 1024.0));
+	else if (memory_capacity / (1024ull * 1024ull) > 0)
+		printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0));
+	else if (memory_capacity / (1024ull) > 0)
+		printf("%.2fKbyte", memory_capacity / (1024.0));
+	else
+		printf("%.2fbyte", memory_capacity * 1.0);
+
+	printf(" (%llu bytes, %llu sectors, %d bytes each)\n", memory_capacity, blocknr, block_len);
+}
+
+static void print_mmc_csd(struct config *config, char *csd)
+{
+	unsigned int csd_structure, spec_vers, taac_timevalue, taac_timeunit, nsac;
+	unsigned int tran_speed_timevalue, tran_speed_transferrateunit, ccc, read_bl_len;
+	unsigned int read_bl_partial, write_blk_misalign, read_blk_misalign, dsr_imp;
+	unsigned int c_size, vdd_r_curr_min, vdd_r_curr_max, vdd_w_curr_min, vdd_w_curr_max;
+	unsigned int c_size_mult, erase_grp_size, erase_grp_mult, wp_grp_size, wp_grp_enable;
+	unsigned int default_ecc, r2w_factor, write_bl_len, write_bl_partial, content_prot_app;
+	unsigned int file_format_grp, copy, perm_write_protect, tmp_write_protect, file_format;
+	unsigned int ecc, crc;
+
+	parse_bin(csd, "2u4u2r1r4u3u8u1r4u3u12u4u1u1u1u1u2r12u3u3u3u3u3u"
+		  "5u5u5u1u2u3u4u1u4r1u1u1u1u1u2u2u7u1r",
+		  &csd_structure, &spec_vers, &taac_timevalue,
+		  &taac_timeunit, &nsac, &tran_speed_timevalue,
+		  &tran_speed_transferrateunit, &ccc, &read_bl_len,
+		  &read_bl_partial, &write_blk_misalign,
+		  &read_blk_misalign, &dsr_imp, &c_size,
+		  &vdd_r_curr_min, &vdd_r_curr_max,
+		  &vdd_w_curr_min, &vdd_w_curr_max, &c_size_mult,
+		  &erase_grp_size, &erase_grp_mult, &wp_grp_size,
+		  &wp_grp_enable, &default_ecc, &r2w_factor,
+		  &write_bl_len, &write_bl_partial, &content_prot_app,
+		  &file_format_grp, &copy, &perm_write_protect,
+		  &tmp_write_protect, &file_format, &ecc, &crc);
+
+	if (config->verbose) {
+
+		printf("======MMC/CSD======\n");
+
+		print_mmc_csd_structure(csd_structure);
+
+		print_mmc_csd_spec_ver(spec_vers);
+
+		print_mmc_csd_taac(taac_timevalue, taac_timeunit);
+
+		print_mmc_csd_nsac(nsac, tran_speed_timevalue, tran_speed_transferrateunit);
+
+		print_mmc_csd_ccc(ccc);
+
+		print_mmc_csd_read_bl_len(read_bl_len);
+
+		print_mmc_csd_read_bl_partial(read_bl_partial);
+
+		print_mmc_csd_write_blk_misalign(write_blk_misalign);
+
+		print_mmc_csd_read_blk_misalign(read_blk_misalign);
+
+		print_mmc_csd_dsr_imp(dsr_imp);
+
+		print_mmc_csd_vdd(vdd_r_curr_min, vdd_r_curr_max, vdd_w_curr_min, vdd_w_curr_max);
 
-		printf("\tC_SIZE_MULT: 0x%01x\n", c_size_mult);
 		printf("\tERASE_GRP_SIZE: 0x%02x\n", erase_grp_size);
 		printf("\tERASE_GRP_MULT: 0x%02x (%u write blocks/erase group)\n",
 		       erase_grp_mult, (erase_grp_size + 1) *
@@ -1729,83 +1904,14 @@ void print_mmc_csd(struct config *config, char *csd)
 		       wp_grp_size, wp_grp_size + 1);
 		printf("\tWP_GRP_ENABLE: 0x%01x\n", wp_grp_enable);
 
-		printf("\tDEFAULT_ECC: 0x%01x (", default_ecc);
-		switch (default_ecc) {
-		case 0:
-			printf("none)\n");
-			break;
-		case 1:
-			printf("BCH)\n");
-			break;
-		default:
-			printf("reserved)\n");
-			break;
-		}
+		print_mmc_csd_default_ecc(default_ecc);
 
 		printf("\tR2W_FACTOR: 0x%01x (Write %u times read)\n",
 		       r2w_factor, r2w_factor);
 
-		printf("\tWRITE_BL_LEN: 0x%01x (", write_bl_len);
-		switch (write_bl_len) {
-		case 0x0:
-			printf("1 byte)\n");
-			break;
-		case 0x1:
-			printf("2 byte)\n");
-			break;
-		case 0x2:
-			printf("4 byte)\n");
-			break;
-		case 0x3:
-			printf("8 byte)\n");
-			break;
-		case 0x4:
-			printf("16 byte)\n");
-			break;
-		case 0x5:
-			printf("32 byte)\n");
-			break;
-		case 0x6:
-			printf("64 byte)\n");
-			break;
-		case 0x7:
-			printf("128 byte)\n");
-			break;
-		case 0x8:
-			printf("256 byte)\n");
-			break;
-		case 0x9:
-			printf("512 bytes)\n");
-			break;
-		case 0xa:
-			printf("1024 bytes)\n");
-			break;
-		case 0xb:
-			printf("2048 bytes)\n");
-			break;
-		case 0xc:
-			printf("4096 bytes)\n");
-			break;
-		case 0xd:
-			printf("8192 bytes)\n");
-			break;
-		case 0xe:
-			printf("16K bytes)\n");
-			break;
-		default:
-			printf("reserved bytes)\n");
-			break;
-		}
+		print_mmc_csd_write_bl_len(write_bl_len);
 
-		printf("\tWRITE_BL_PARTIAL: 0x%01x (", write_bl_partial);
-		switch (write_bl_partial) {
-		case 0x0:
-			printf("only 512 byte and WRITE_BL_LEN block size)\n");
-			break;
-		case 0x1:
-			printf("less than WRITE_BL_LEN block size can be used)\n");
-			break;
-		}
+		print_mmc_csd_write_bl_partial(write_bl_partial);
 
 		printf("\tCONTENT_PROT_APP: 0x%01x\n", content_prot_app);
 		printf("\tFILE_FORMAT_GRP: 0x%01x\n", file_format_grp);
@@ -1815,142 +1921,20 @@ void print_mmc_csd(struct config *config, char *csd)
 		printf("\tCOPY: 0x%01x\n", copy);
 		printf("\tPERM_WRITE_PROTECT: 0x%01x\n", perm_write_protect);
 		printf("\tTMP_WRITE_PROTECT: 0x%01x\n", tmp_write_protect);
-		printf("\tFILE_FORMAT: 0x%01x (", file_format);
-		if (file_format != 0)
-			printf("Warn: Invalid FILE_FORMAT\n");
 
-		if (file_format_grp == 1) {
-			printf("reserved)\n");
-		} else {
-			switch (file_format) {
-			case 0:
-				printf("partition table)\n");
-				break;
-			case 1:
-				printf("no partition table)\n");
-				break;
-			case 2:
-				printf("Universal File Format)\n");
-				break;
-			case 3:
-				printf("Others/unknown)\n");
-				break;
-			}
-		}
+		print_mmc_csd_file_format(file_format, file_format_grp);
 
-		printf("\tECC: 0x%01x (", ecc);
-		switch (ecc) {
-		case 0:
-			printf("none)\n");
-			break;
-		case 1:
-			printf("BCH(542,512))\n");
-			break;
-		default:
-			printf("reserved)\n");
-			break;
-		}
+		print_mmc_csd_ecc(ecc);
 
 		printf("\tCRC: 0x%01x\n", crc);
 
-		mult = 1 << (c_size_mult + 2);
-		blocknr = (c_size + 1) * mult;
-		block_len = 1 << read_bl_len;
-		blocks = blocknr;
-		block_size = block_len;
-
-		memory_capacity = blocks * block_size;
-
-		printf("\tCAPACITY: ");
-		if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0)
-			printf("%.2fGbyte",
-			       memory_capacity / (1024.0 * 1024.0 * 1024.0));
-		else if (memory_capacity / (1024ull * 1024ull) > 0)
-			printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0));
-		else if (memory_capacity / (1024ull) > 0)
-			printf("%.2fKbyte", memory_capacity / (1024.0));
-		else
-			printf("%.2fbyte", memory_capacity * 1.0);
-
-		printf(" (%llu bytes, %llu sectors, %d bytes each)\n",
-		       memory_capacity, blocks, block_size);
+		print_mmc_csd_capacity(c_size, c_size_mult, read_bl_len);
 	} else {
-		int mult;
-		int blocknr;
-		int block_len;
-		unsigned long long blocks = 0;
-		int block_size = 0;
-		unsigned long long memory_capacity;
-
-		printf("version: ");
-		switch (spec_vers) {
-		case 0x0:
-			printf("MMC v1.0-v1.2\n");
-			break;
-		case 0x1:
-			printf("MMC v1.4\n");
-			break;
-		case 0x2:
-			printf("MMC v2.0-v2.2\n");
-			break;
-		case 0x3:
-			printf("MMC v3.1-v3.31\n");
-			break;
-		case 0x4:
-			printf("MMC v4.0-v4.3\n");
-			break;
-		default:
-			printf("reserved\n");
-			break;
-		}
-
-		printf("card classes: ");
-		if (ccc & 0x800)
-			printf("11, ");
-		if (ccc & 0x400)
-			printf("10, ");
-		if (ccc & 0x200)
-			printf("9, ");
-		if (ccc & 0x100)
-			printf("8, ");
-		if (ccc & 0x080)
-			printf("7, ");
-		if (ccc & 0x040)
-			printf("6, ");
-		if (ccc & 0x020)
-			printf("5, ");
-		if (ccc & 0x010)
-			printf("4, ");
-		if (ccc & 0x008)
-			printf("3, ");
-		if (ccc & 0x004)
-			printf("2, ");
-		if (ccc & 0x002)
-			printf("1, ");
-		if (ccc & 0x001)
-			printf("0, ");
-		printf("\b\b\n");
+		print_mmc_csd_spec_ver(spec_vers);
 
-		mult = 1 << (c_size_mult + 2);
-		blocknr = (c_size + 1) * mult;
-		block_len = 1 << read_bl_len;
-		blocks = blocknr;
-		block_size = block_len;
-
-		memory_capacity = blocks * block_size;
+		print_mmc_csd_ccc(ccc);
 
-		printf("capacity: ");
-		if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0)
-			printf("%.2fGbyte",
-			       memory_capacity / (1024.0 * 1024.0 * 1024.0));
-		else if (memory_capacity / (1024ull * 1024ull) > 0)
-			printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0));
-		else if (memory_capacity / (1024ull) > 0)
-			printf("%.2fKbyte", memory_capacity / (1024.0));
-		else
-			printf("%.2fbyte", memory_capacity * 1.0);
-		printf(" (%llu bytes, %llu sectors, %d bytes each)\n",
-		       memory_capacity, blocks, block_size);
+		print_mmc_csd_capacity(c_size, c_size_mult, read_bl_len);
 	}
 }
 
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v2 4/4] mmc-utils: lsmmc: Fix emmc capacity calculation
  2023-09-28  8:04 [PATCH v2 0/4] mmc-utils: Revamp CSD register parsing Avri Altman
                   ` (2 preceding siblings ...)
  2023-09-28  8:04 ` [PATCH v2 3/4] mmc-utils: lsmmc: Disintegrade print_mmc_csd Avri Altman
@ 2023-09-28  8:04 ` Avri Altman
  3 siblings, 0 replies; 5+ messages in thread
From: Avri Altman @ 2023-09-28  8:04 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc; +Cc: wanggang26

From: wanggang26 <wanggang26@xiaomi.com>

When the device capacity is larger than 2GB, it shouldn't use c_size but
instead it follows a different calculation using the SEC_COUNT field of
the ext-csd[215:212] - see eMMC spec JESD84-B51 paragraph 7.3.12.

This bug was already in lsmmc when it got merged into mmc-utils, hence
the fixes tag.

Fixes: 4af1749d2350 (mmc-utils: Merge the lsmmc tool into mmc-utils)
Signed-off-by: wanggang26 <wanggang26@xiaomi.com>
---
 lsmmc.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lsmmc.c b/lsmmc.c
index c984d9a..9596722 100644
--- a/lsmmc.c
+++ b/lsmmc.c
@@ -1826,6 +1826,9 @@ static void print_mmc_csd_capacity(unsigned int c_size, unsigned int c_size_mult
 	int block_len = 1 << read_bl_len;
 	unsigned long long memory_capacity;
 
+	if (c_size == 0xfff)
+		return;
+
 	printf("\tC_SIZE: 0x%03x\n", c_size);
 	printf("\tC_SIZE_MULT: 0x%01x\n", c_size_mult);
 
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-09-28  8:07 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-28  8:04 [PATCH v2 0/4] mmc-utils: Revamp CSD register parsing Avri Altman
2023-09-28  8:04 ` [PATCH v2 1/4] mmc-utils: lsmmc: Simplify prinitng manufacturer name Avri Altman
2023-09-28  8:04 ` [PATCH v2 2/4] mmc-utils: lsmmc: Simplify interface processing functions Avri Altman
2023-09-28  8:04 ` [PATCH v2 3/4] mmc-utils: lsmmc: Disintegrade print_mmc_csd Avri Altman
2023-09-28  8:04 ` [PATCH v2 4/4] mmc-utils: lsmmc: Fix emmc capacity calculation Avri Altman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.