blob: 71e6a58d26fc56a8bea99cc14a2ae6b69d07cdeb [file] [log] [blame]
Sebastian Rasmussen7e00a5a2016-02-23 13:37:28 +08001/*
2 * Copyright (C) ST-Ericsson SA 2010-2011
3 * Author: Sebastian Rasmussen <sebastian.rasmussen@stericsson.com>
4 *
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials
16 * provided with the distribution.
17 * 3. Neither the name of the ST-Ericsson SA nor the names of its
18 * contributors may be used to endorse or promote products
19 * derived from this software without specific prior written
20 * permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#include <assert.h>
37#include <ctype.h>
38#include <dirent.h>
39#include <errno.h>
40#include <limits.h>
41#include <stdarg.h>
42#include <stdbool.h>
43#include <stdint.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <unistd.h>
48
49#include "mmc.h"
50
51#define MASKTOBIT0(high) \
52 ((high >= 0) ? ((1ull << ((high) + 1ull)) - 1ull) : 0ull)
53#define MASK(high, low) (MASKTOBIT0(high) & ~MASKTOBIT0(low - 1))
54#define BITS(value, high, low) (((value) & MASK((high), (low))) >> (low))
55#define IDS_MAX 256
56
57struct config {
58 char *idsfile;
59 char *dir;
60 bool verbose;
61 int interfaces;
62 char **interface;
63 char **mmc_ids;
64 char **sd_ids;
65
66 char *type;
67 char *cid;
68 char *csd;
69 char *scr;
70 char *ext_csd;
71};
72
73enum REG_TYPE {
74 CID = 0,
75 CSD,
76 SCR,
77 EXT_CSD,
78};
79
80struct ids_database {
81 char *type;
82 int id;
83 char *manufacturer;
84};
85
86struct ids_database database[] = {
87 {
88 .type = "sd",
89 .id = 0x01,
90 .manufacturer = "Panasonic",
91 },
92 {
93 .type = "sd",
94 .id = 0x02,
95 .manufacturer = "Toshiba/Kingston/Viking",
96 },
97 {
98 .type = "sd",
99 .id = 0x03,
100 .manufacturer = "SanDisk",
101 },
102 {
103 .type = "sd",
104 .id = 0x08,
105 .manufacturer = "Silicon Power",
106 },
107 {
108 .type = "sd",
109 .id = 0x18,
110 .manufacturer = "Infineon",
111 },
112 {
113 .type = "sd",
114 .id = 0x1b,
115 .manufacturer = "Transcend",
116 },
117 {
118 .type = "sd",
119 .id = 0x1c,
120 .manufacturer = "Transcend",
121 },
122 {
123 .type = "sd",
124 .id = 0x1d,
125 .manufacturer = "Corsair",
126 },
127 {
128 .type = "sd",
129 .id = 0x1e,
130 .manufacturer = "Transcend",
131 },
132 {
133 .type = "sd",
134 .id = 0x1f,
135 .manufacturer = "Kingston",
136 },
137 {
138 .type = "sd",
139 .id = 0x28,
140 .manufacturer = "Lexar",
141 },
142 {
143 .type = "sd",
144 .id = 0x30,
145 .manufacturer = "SanDisk",
146 },
147 {
148 .type = "sd",
149 .id = 0x33,
150 .manufacturer = "STMicroelectronics",
151 },
152 {
153 .type = "sd",
154 .id = 0x41,
155 .manufacturer = "Kingston",
156 },
157 {
158 .type = "sd",
159 .id = 0x6f,
160 .manufacturer = "STMicroelectronics",
161 },
162 {
163 .type = "sd",
164 .id = 0x89,
165 .manufacturer = "Unknown",
166 },
167 {
168 .type = "mmc",
169 .id = 0x00,
170 .manufacturer = "SanDisk",
171 },
172 {
173 .type = "mmc",
174 .id = 0x02,
175 .manufacturer = "Kingston/SanDisk",
176 },
177 {
178 .type = "mmc",
179 .id = 0x03,
180 .manufacturer = "Toshiba",
181 },
182 {
183 .type = "mmc",
184 .id = 0x05,
185 .manufacturer = "Unknown",
186 },
187 {
188 .type = "mmc",
189 .id = 0x06,
190 .manufacturer = "Unknown",
191 },
192 {
193 .type = "mmc",
194 .id = 0x11,
195 .manufacturer = "Toshiba",
196 },
197 {
198 .type = "mmc",
199 .id = 0x15,
200 .manufacturer = "Samsung/SanDisk/LG",
201 },
202 {
203 .type = "mmc",
204 .id = 0x37,
205 .manufacturer = "KingMax",
206 },
207 {
208 .type = "mmc",
209 .id = 0x44,
210 .manufacturer = "SanDisk",
211 },
212 {
213 .type = "mmc",
214 .id = 0x2c,
215 .manufacturer = "Kingston",
216 },
217 {
218 .type = "mmc",
219 .id = 0x70,
220 .manufacturer = "Kingston",
221 },
222};
223
224/* Command line parsing functions */
225void usage(void)
226{
227 printf("Usage: print mmc [-h] [-v] <device path ...>\n");
228 printf("\n");
229 printf("Options:\n");
230 printf("\t-h\tShow this help.\n");
231 printf("\t-v\tEnable verbose mode.\n");
232}
233
234int parse_opts(int argc, char **argv, struct config *config)
235{
236 int c;
237
238 while ((c = getopt(argc, argv, "hv")) != -1) {
239 switch (c) {
240 case 'h':
241 usage();
242 return -1;
243 case 'v':
244 config->verbose = true;
245 break;
246 case '?':
247 fprintf(stderr,
248 "Unknown option '%c' encountered.\n\n", c);
249 usage();
250 return -1;
251 case ':':
252 fprintf(stderr,
253 "Argument for option '%c' missing.\n\n", c);
254 usage();
255 return -1;
256 default:
257 fprintf(stderr,
258 "Unimplemented option '%c' encountered.\n", c);
259 break;
260 }
261 }
262
263 if (optind >= argc) {
264 fprintf(stderr, "Expected mmc directory arguments.\n\n");
265 usage();
266 return -1;
267 }
268
269 config->dir = strdup(argv[optind]);
270 return 0;
271}
272
273int parse_ids(struct config *config)
274{
275 unsigned int ids_cnt = sizeof(database) / sizeof(struct ids_database);
276 unsigned int value;
277 char **ids;
278 char *type;
279 int i;
280
281 for (i = 0; i < ids_cnt; i++) {
282 type = database[i].type;
283
284 if (!strcmp(type, "mmc")) {
285 ids = config->mmc_ids;
286 } else if (!strcmp(type, "sd")) {
287 ids = config->sd_ids;
288 } else {
289 fprintf(stderr,
290 "MMC/SD id parse error, unknown type: '%s'.\n",
291 type);
292 return -1;
293 }
294
295 value = database[i].id;
296
297 if (value >= IDS_MAX) {
298 fprintf(stderr,
299 "MMC/SD id parse error, id out of range.\n");
300 return -1;
301 }
302
303 if (ids[value]) {
304 fprintf(stderr,
305 "Duplicate entries: type='%s', id='0x%1x'.\n",
306 type, value);
307 return -1;
308 }
309
310 ids[value] = database[i].manufacturer;
311 }
312
313 return 0;
314}
315
316/* MMC/SD file parsing functions */
317char *read_file(char *name)
318{
319 char *preparsed;
320 char line[4096];
321 FILE *f;
322
323 f = fopen(name, "r");
324 if (!f) {
325 fprintf(stderr, "Could not open MMC/SD file '%s'.\n", name);
326 return NULL;
327 }
328
329 preparsed = fgets(line, sizeof(line), f);
330 if (!preparsed) {
331 if (ferror(f))
332 fprintf(stderr, "Could not read MMC/SD file '%s'.\n",
333 name);
334 else
335 fprintf(stderr,
336 "Could not read data from MMC/SD file '%s'.\n",
337 name);
338
339 if (fclose(f))
340 fprintf(stderr, "Could not close MMC/SD file '%s'.\n",
341 name);
342 return NULL;
343 }
344
345 if (fclose(f)) {
346 fprintf(stderr, "Could not close MMC/SD file '%s'.\n", name);
347 return NULL;
348 }
349
350 line[sizeof(line) - 1] = '\0';
351
352 while (isspace(line[strlen(line) - 1]))
353 line[strlen(line) - 1] = '\0';
354
355 while (isspace(line[0]))
356 strncpy(&line[0], &line[1], sizeof(line));
357
358 return strdup(line);
359}
360
361/* Hexadecimal string parsing functions */
362char *to_binstr(char *hexstr)
363{
364 char *bindigits[] = {
365 "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
366 "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111",
367 };
368 char *binstr;
369
370 binstr = calloc(strlen(hexstr) * 4 + 1, sizeof(char));
371
372 while (hexstr && *hexstr != '\0') {
373 if (!isxdigit(*hexstr))
374 return NULL;
375
376 if (isdigit(*hexstr))
377 strcat(binstr, bindigits[*hexstr - '0']);
378 else if (islower(*hexstr))
379 strcat(binstr, bindigits[*hexstr - 'a']);
380 else
381 strcat(binstr, bindigits[*hexstr - 'A']);
382
383 hexstr++;
384 }
385
386 return binstr;
387}
388
389void bin_to_unsigned(unsigned int *u, char *binstr, int width)
390{
391 *u = 0;
392 assert(width <= 32);
393
394 while (binstr && *binstr != '\0' && width > 0) {
395 *u <<= 1;
396 *u |= *binstr == '0' ? 0 : 1;
397
398 binstr++;
399 width--;
400 }
401}
402
403void bin_to_ascii(char *a, char *binstr, int width)
404{
405 assert(width % 8 == 0);
406 *a = '\0';
407
408 while (binstr && *binstr != '\0' && width > 0) {
409 unsigned int u;
410 char c[2] = { '\0', '\0' };
411 char *s = &c[0];
412
413 bin_to_unsigned(&u, binstr, 8);
414 c[0] = u;
415
416 strcat(a, s);
417 binstr += 8;
418 width -= 8;
419 }
420}
421
422void parse_bin(char *hexstr, char *fmt, ...)
423{
424 va_list args;
425 char *origstr;
426 char *binstr;
427 unsigned long width = 0;
428
429 binstr = to_binstr(hexstr);
430 origstr = binstr;
431
432 va_start(args, fmt);
433
434 while (binstr && fmt && *fmt != '\0') {
435 if (isdigit(*fmt)) {
436 char *rest;
437
438 errno = 0;
439 width = strtoul(fmt, &rest, 10);
440 if (width == ULONG_MAX && errno != 0)
441 fprintf(stderr, "strtoul()");
442 fmt = rest;
443 } else if (*fmt == 'u') {
444 unsigned int *u = va_arg(args, unsigned int *);
445
446 if (u)
447 bin_to_unsigned(u, binstr, width);
448 binstr += width;
449 width = 0;
450 fmt++;
451 } else if (*fmt == 'r') {
452 binstr += width;
453 width = 0;
454 fmt++;
455 } else if (*fmt == 'a') {
456 char *c = va_arg(args, char *);
457
458 if (c)
459 bin_to_ascii(c, binstr, width);
460 binstr += width;
461 width = 0;
462 fmt++;
463 } else {
464 fmt++;
465 }
466 }
467
468 va_end(args);
469 free(origstr);
470}
471
472/* MMC/SD information parsing functions */
473void print_sd_cid(struct config *config, char *cid)
474{
475 static const char *months[] = {
476 "jan", "feb", "mar", "apr", "may", "jun",
477 "jul", "aug", "sep", "oct", "nov", "dec",
478 "invalid0", "invalid1", "invalid2", "invalid3",
479 };
480 unsigned int mid;
481 char oid[3];
482 char pnm[6];
483 unsigned int prv_major;
484 unsigned int prv_minor;
485 unsigned int psn;
486 unsigned int mdt_month;
487 unsigned int mdt_year;
488 unsigned int crc;
489
490 parse_bin(cid, "8u16a40a4u4u32u4r8u4u7u1r",
491 &mid, &oid[0], &pnm[0], &prv_major, &prv_minor, &psn,
492 &mdt_year, &mdt_month, &crc);
493
494 oid[2] = '\0';
495 pnm[5] = '\0';
496
497 if (config->verbose) {
498 printf("======SD/CID======\n");
499
500 printf("\tMID: 0x%02x (", mid);
501 if (config->sd_ids[mid])
502 printf("%s)\n", config->sd_ids[mid]);
503 else
504 printf("Unlisted)\n");
505
506 printf("\tOID: %s\n", oid);
507 printf("\tPNM: %s\n", pnm);
508 printf("\tPRV: 0x%01x%01x ", prv_major, prv_minor);
509 printf("(%d.%d)\n", prv_major, prv_minor);
510 printf("\tPSN: 0x%08x\n", psn);
511 printf("\tMDT: 0x%02x%01x %d %s\n", mdt_year, mdt_month,
512 2000 + mdt_year, months[mdt_month]);
513 printf("\tCRC: 0x%02x\n", crc);
514 } else {
515 if (config->sd_ids[mid])
516 printf("manufacturer: '%s' '%s'\n",
517 config->sd_ids[mid], oid);
518 else
519 printf("manufacturer: 'Unlisted' '%s'\n", oid);
520
521 printf("product: '%s' %d.%d\n", pnm, prv_major, prv_minor);
522 printf("serial: 0x%08x\n", psn);
523 printf("manfacturing date: %d %s\n", 2000 + mdt_year,
524 months[mdt_month]);
525 }
526}
527
528void print_mmc_cid(struct config *config, char *cid)
529{
530 static const char *months[] = {
531 "jan", "feb", "mar", "apr", "may", "jun",
532 "jul", "aug", "sep", "oct", "nov", "dec",
533 "invalid0", "invalid1", "invalid2", "invalid3",
534 };
535 unsigned int mid;
536 unsigned int cbx;
537 unsigned int oid;
538 char pnm[7];
539 unsigned int prv_major;
540 unsigned int prv_minor;
541 unsigned int psn;
542 unsigned int mdt_month;
543 unsigned int mdt_year;
544 unsigned int crc;
545
546 parse_bin(cid, "8u6r2u8u48a4u4u32u4u4u7u1r",
547 &mid, &cbx, &oid, &pnm[0], &psn, &prv_major, &prv_minor,
548 &mdt_year, &mdt_month, &crc);
549
550 pnm[6] = '\0';
551
552 if (config->verbose) {
553 printf("======MMC/CID======\n");
554
555 printf("\tMID: 0x%02x (", mid);
556 if (config->mmc_ids[mid])
557 printf("%s)\n", config->mmc_ids[mid]);
558 else
559 printf("Unlisted)\n");
560
561 printf("\tCBX: 0x%01x (", cbx);
562 switch (cbx) {
563 case 0:
564 printf("card)\n");
565 break;
566 case 1:
567 printf("BGA)\n");
568 break;
569 case 2:
570 printf("PoP)\n");
571 break;
572 case 3:
573 printf("reserved)\n");
574 break;
575 }
576
577 printf("\tOID: 0x%01x\n", oid);
578 printf("\tPNM: %s\n", pnm);
579 printf("\tPRV: 0x%01x%01x ", prv_major, prv_minor);
580 printf("(%d.%d)\n", prv_major, prv_minor);
581 printf("\tPSN: 0x%08x\n", psn);
582 printf("\tMDT: 0x%01x%01x %d %s\n", mdt_month, mdt_year,
583 1997 + mdt_year, months[mdt_month]);
584 printf("\tCRC: 0x%02x\n", crc);
585 } else {
586 if (config->mmc_ids[mid])
587 printf("manufacturer: '%s' '%c'\n",
588 config->mmc_ids[mid], oid);
589 else
590 printf("manufacturer: 'Unlisted' '%c'\n", oid);
591
592 printf("product: '%s' %d.%d\n", pnm, prv_major, prv_minor);
593 printf("serial: 0x%08x\n", psn);
594 printf("manfacturing date: %d %s\n", 1997 + mdt_year,
595 months[mdt_month]);
596 }
597}
598
599void print_sd_csd(struct config *config, char *csd)
600{
601 unsigned int csd_structure;
602 unsigned int taac_timevalue;
603 unsigned int taac_timeunit;
604 unsigned int nsac;
605 unsigned int tran_speed_timevalue;
606 unsigned int tran_speed_transferrateunit;
607 unsigned int ccc;
608 unsigned int read_bl_len;
609 unsigned int read_bl_partial;
610 unsigned int write_blk_misalign;
611 unsigned int read_blk_misalign;
612 unsigned int dsr_imp;
613 unsigned int c_size;
614 unsigned int vdd_r_curr_min;
615 unsigned int vdd_r_curr_max;
616 unsigned int vdd_w_curr_min;
617 unsigned int vdd_w_curr_max;
618 unsigned int c_size_mult;
619 unsigned int erase_blk_en;
620 unsigned int sector_size;
621 unsigned int wp_grp_size;
622 unsigned int wp_grp_enable;
623 unsigned int r2w_factor;
624 unsigned int write_bl_len;
625 unsigned int write_bl_partial;
626 unsigned int file_format_grp;
627 unsigned int copy;
628 unsigned int perm_write_protect;
629 unsigned int tmp_write_protect;
630 unsigned int file_format;
631 unsigned int crc;
632 unsigned int taac;
633 unsigned int tran_speed;
634
635 parse_bin(csd, "2u", &csd_structure);
636
637 if (csd_structure == 0) {
638 parse_bin(csd, "2u6r1r4u3u8u1r4u3u12u4u1u1u1u1u2r12u3u3u3u3u3u"
639 "1u7u7u1u2r3u4u1u5r1u1u1u1u2u2r7u1r",
640 NULL, &taac_timevalue, &taac_timeunit, &nsac,
641 &tran_speed_timevalue,
642 &tran_speed_transferrateunit, &ccc,
643 &read_bl_len, &read_bl_partial,
644 &write_blk_misalign, &read_blk_misalign,
645 &dsr_imp, &c_size, &vdd_r_curr_min,
646 &vdd_r_curr_max, &vdd_w_curr_min,
647 &vdd_w_curr_max, &c_size_mult, &erase_blk_en,
648 &sector_size, &wp_grp_size, &wp_grp_enable,
649 &r2w_factor, &write_bl_len, &write_bl_partial,
650 &file_format_grp, &copy, &perm_write_protect,
651 &tmp_write_protect, &file_format, &crc);
652 } else if (csd_structure == 1) {
653 parse_bin(csd, "2u6r1r4u3u8u1r4u3u12u4u1u1u1u1u6r22u1r1u7u7u1u"
654 "2r3u4u1u5r1u1u1u1u2u2r7u1r",
655 NULL, &taac_timevalue, &taac_timeunit, &nsac,
656 &tran_speed_timevalue,
657 &tran_speed_transferrateunit, &ccc,
658 &read_bl_len, &read_bl_partial,
659 &write_blk_misalign, &read_blk_misalign,
660 &dsr_imp, &c_size, &erase_blk_en, &sector_size,
661 &wp_grp_size, &wp_grp_enable, &r2w_factor,
662 &write_bl_len, &write_bl_partial,
663 &file_format_grp, &copy, &perm_write_protect,
664 &tmp_write_protect, &file_format, &crc);
665
666 vdd_r_curr_min = 0;
667 c_size_mult = 0;
668 } else {
669 printf("Unknown CSD structure: 0x%1x\n", csd_structure);
670 return;
671 }
672
673 taac = taac_timevalue << 3 | taac_timeunit;
674 tran_speed = tran_speed_timevalue << 3 | tran_speed_transferrateunit;
675
676 if (config->verbose) {
677 float value;
678 unsigned long long blocks = 0;
679 int block_size = 0;
680 unsigned long long memory_capacity;
681
682 printf("======SD/CSD======\n");
683
684 printf("\tCSD_STRUCTURE: %d\n", csd_structure);
685 printf("\tTAAC: 0x%02x (", taac);
686
687 switch (taac_timevalue) {
688 case 0x0:
689 value = 0.0f;
690 break;
691 case 0x1:
692 value = 1.0f;
693 break;
694 case 0x2:
695 value = 1.2f;
696 break;
697 case 0x3:
698 value = 1.3f;
699 break;
700 case 0x4:
701 value = 1.5f;
702 break;
703 case 0x5:
704 value = 2.0f;
705 break;
706 case 0x6:
707 value = 2.5f;
708 break;
709 case 0x7:
710 value = 3.0f;
711 break;
712 case 0x8:
713 value = 3.5f;
714 break;
715 case 0x9:
716 value = 4.0f;
717 break;
718 case 0xa:
719 value = 4.5f;
720 break;
721 case 0xb:
722 value = 5.0f;
723 break;
724 case 0xc:
725 value = 5.5f;
726 break;
727 case 0xd:
728 value = 6.0f;
729 break;
730 case 0xe:
731 value = 7.0f;
732 break;
733 case 0xf:
734 value = 8.0f;
735 break;
736 default:
737 value = 0.0f;
738 break;
739 }
740
741 switch (taac_timeunit) {
742 case 0x0:
743 printf("%.2fns)\n", value * 1.0f);
744 break;
745 case 0x1:
746 printf("%.2fns)\n", value * 10.0f);
747 break;
748 case 0x2:
749 printf("%.2fns)\n", value * 100.0f);
750 break;
751 case 0x3:
752 printf("%.2fus)\n", value * 1.0f);
753 break;
754 case 0x4:
755 printf("%.2fus)\n", value * 10.0f);
756 break;
757 case 0x5:
758 printf("%.2fus)\n", value * 100.0f);
759 break;
760 case 0x6:
761 printf("%.2fms)\n", value * 1.0f);
762 break;
763 case 0x7:
764 printf("%.2fms)\n", value * 10.0f);
765 break;
766 }
767
768 if (csd_structure == 1 && taac != 0x0e)
769 printf("Warn: Invalid TAAC (should be 0x0e)\n");
770
771 printf("\tNSAC: %d clocks\n", nsac);
772 if (csd_structure == 1 && nsac != 0x00)
773 printf("Warn: Invalid NSAC (should be 0x00)\n");
774
775 printf("\tTRAN_SPEED: 0x%02x (", tran_speed);
776 switch (tran_speed_timevalue) {
777 case 0x0:
778 value = 0.0f;
779 break;
780 case 0x1:
781 value = 1.0f;
782 break;
783 case 0x2:
784 value = 1.2f;
785 break;
786 case 0x3:
787 value = 1.3f;
788 break;
789 case 0x4:
790 value = 1.5f;
791 break;
792 case 0x5:
793 value = 2.0f;
794 break;
795 case 0x6:
796 value = 2.5f;
797 break;
798 case 0x7:
799 value = 3.0f;
800 break;
801 case 0x8:
802 value = 3.5f;
803 break;
804 case 0x9:
805 value = 4.0f;
806 break;
807 case 0xa:
808 value = 4.5f;
809 break;
810 case 0xb:
811 value = 5.0f;
812 break;
813 case 0xc:
814 value = 5.5f;
815 break;
816 case 0xd:
817 value = 6.0f;
818 break;
819 case 0xe:
820 value = 7.0f;
821 break;
822 case 0xf:
823 value = 8.0f;
824 break;
825 default:
826 value = 0.0f;
827 break;
828 }
829
830 switch (tran_speed_transferrateunit) {
831 case 0x0:
832 printf("%.2fkbit/s)\n", value * 100.0f);
833 break;
834 case 0x1:
835 printf("%.2fMbit/s)\n", value * 1.0f);
836 break;
837 case 0x2:
838 printf("%.2fMbit/s)\n", value * 10.0f);
839 break;
840 case 0x3:
841 printf("%.2fMbit/s)\n", value * 100.0f);
842 break;
843 default:
844 printf("reserved)\n");
845 break;
846 }
847 if (csd_structure == 0 &&
848 (tran_speed != 0x32 && tran_speed != 0x5a))
849 printf("Warn: Invalid TRAN_SPEED "
850 "(should be 0x32 or 0x5a)\n");
851 if (csd_structure == 1 && tran_speed != 0x32 &&
852 tran_speed != 0x5a && tran_speed != 0x0b &&
853 tran_speed != 0x2b)
854 printf("Warn: Invalid TRAN_SPEED "
855 "(should be 0x32, 0x5a, 0x0b or 0x2b\n");
856
857 printf("\tCCC: 0x%03x (class: ", ccc);
858 if (ccc & 0x800)
859 printf("11, ");
860 if (ccc & 0x400)
861 printf("10, ");
862 if (ccc & 0x200)
863 printf("9, ");
864 if (ccc & 0x100)
865 printf("8, ");
866 if (ccc & 0x080)
867 printf("7, ");
868 if (ccc & 0x040)
869 printf("6, ");
870 if (ccc & 0x020)
871 printf("5, ");
872 if (ccc & 0x010)
873 printf("4, ");
874 if (ccc & 0x008)
875 printf("3, ");
876 if (ccc & 0x004)
877 printf("2, ");
878 if (ccc & 0x002)
879 printf("1, ");
880 if (ccc & 0x001)
881 printf("0, ");
882 printf(" )\n");
883
884 if (csd_structure == 0 &&
885 (ccc != 0x5b5 && ccc != 0x7b5 && ccc != 0x5f5))
886 printf("Warn: Invalid CCC (should be 0x5b5, "
887 "0x7b5 or 0x5f5)\n");
888 else if (csd_structure == 1 && ccc != 0x5b5 && ccc != 0x7b5)
889 printf("Warn: Invalid CCC (should be 0x5b5 or 0x7b5)\n");
890
891 printf("\tREAD_BL_LEN: 0x%01x (", read_bl_len);
892 switch (read_bl_len) {
893 case 0x9:
894 printf("512 bytes)\n");
895 break;
896 case 0xa:
897 printf("1024 bytes)\n");
898 break;
899 case 0xb:
900 printf("2048 bytes)\n");
901 break;
902 default:
903 printf("reserved bytes)\n");
904 break;
905 }
906
907 if (csd_structure == 1 && read_bl_len != 0x9)
908 printf("Warn: Invalid READ_BL_LEN (should be 0x9)\n");
909
910 printf("\tREAD_BL_PARTIAL: 0x%01x\n", read_bl_partial);
911 if (csd_structure == 0 && read_bl_partial != 0x01)
912 printf("Warn: Invalid READ_BL_PARTIAL (should be 0x01)\n");
913 else if (csd_structure == 1 && read_bl_partial != 0x00)
914 printf("Warn: Invalid READ_BL_PARTIAL (should be 0x00)\n");
915
916 printf("\tWRITE_BLK_MISALIGN: 0x%01x\n", write_blk_misalign);
917 if (csd_structure == 1 && write_blk_misalign != 0x00)
918 printf("Warn: Invalid WRITE_BLK_MISALIGN (should be 0x00)\n");
919
920 printf("\tREAD_BLK_MISALIGN: 0x%01x\n", read_blk_misalign);
921 if (csd_structure == 1 && read_blk_misalign != 0x00)
922 printf("Warn: Invalid READ_BLK_MISALIGN (should be 0x00)\n");
923
924 printf("\tDSR_IMP: 0x%01x\n", dsr_imp);
925
926 if (csd_structure == 0) {
927 int mult;
928 int blocknr;
929 int block_len;
930
931 printf("\tC_SIZE: 0x%03x\n", c_size);
932 printf("\tVDD_R_CURR_MIN: 0x%01x (", vdd_r_curr_min);
933 switch (vdd_r_curr_min) {
934 case 0x0:
935 printf("0.5mA)\n");
936 break;
937 case 0x1:
938 printf("1mA)\n");
939 break;
940 case 0x2:
941 printf("5mA)\n");
942 break;
943 case 0x3:
944 printf("10mA)\n");
945 break;
946 case 0x4:
947 printf("25mA)\n");
948 break;
949 case 0x5:
950 printf("35mA)\n");
951 break;
952 case 0x6:
953 printf("60mA)\n");
954 break;
955 case 0x7:
956 printf("100mA)\n");
957 break;
958 }
959
960 printf("\tVDD_R_CURR_MAX: 0x%01x (", vdd_r_curr_max);
961 switch (vdd_r_curr_max) {
962 case 0x0:
963 printf("1mA)\n");
964 break;
965 case 0x1:
966 printf("5mA)\n");
967 break;
968 case 0x2:
969 printf("10mA)\n");
970 break;
971 case 0x3:
972 printf("25mA)\n");
973 break;
974 case 0x4:
975 printf("35mA)\n");
976 break;
977 case 0x5:
978 printf("45mA)\n");
979 break;
980 case 0x6:
981 printf("80mA)\n");
982 break;
983 case 0x7:
984 printf("200mA)\n");
985 break;
986 }
987
988 printf("\tVDD_W_CURR_MIN: 0x%01x (", vdd_w_curr_min);
989 switch (vdd_w_curr_min) {
990 case 0x0:
991 printf("0.5mA)\n");
992 break;
993 case 0x1:
994 printf("1mA)\n");
995 break;
996 case 0x2:
997 printf("5mA)\n");
998 break;
999 case 0x3:
1000 printf("10mA)\n");
1001 break;
1002 case 0x4:
1003 printf("25mA)\n");
1004 break;
1005 case 0x5:
1006 printf("35mA)\n");
1007 break;
1008 case 0x6:
1009 printf("60mA)\n");
1010 break;
1011 case 0x7:
1012 printf("100mA)\n");
1013 break;
1014 }
1015
1016 printf("\tVDD_W_CURR_MAX: 0x%01x (", vdd_w_curr_max);
1017 switch (vdd_w_curr_max) {
1018 case 0x0:
1019 printf("1mA)\n");
1020 break;
1021 case 0x1:
1022 printf("5mA)\n");
1023 break;
1024 case 0x2:
1025 printf("10mA)\n");
1026 break;
1027 case 0x3:
1028 printf("25mA)\n");
1029 break;
1030 case 0x4:
1031 printf("35mA)\n");
1032 break;
1033 case 0x5:
1034 printf("45mA)\n");
1035 break;
1036 case 0x6:
1037 printf("80mA)\n");
1038 break;
1039 case 0x7:
1040 printf("200mA)\n");
1041 break;
1042 }
1043
1044 printf("\tC_SIZE_MULT: 0x%01x\n", c_size_mult);
1045
1046 mult = 1 << (c_size_mult + 2);
1047 blocknr = (c_size + 1) * mult;
1048 block_len = 1 << read_bl_len;
1049 blocks = blocknr;
1050 block_size = block_len;
1051 } else if (csd_structure == 1) {
1052 printf("\tC_SIZE: 0x%06x\n", c_size);
1053
1054 printf("\tERASE_BLK_EN: 0x%01x\n", erase_blk_en);
1055 if (erase_blk_en != 0x01)
1056 printf("Warn: Invalid ERASE_BLK_EN (should be 0x01)\n");
1057
1058 printf("\tSECTOR_SIZE: 0x%02x (Erasable sector: %d blocks)\n",
1059 sector_size, sector_size + 1);
1060 if (sector_size != 0x7f)
1061 printf("Warn: Invalid SECTOR_SIZE (should be 0x7f)\n");
1062
1063 printf("\tWP_GRP_SIZE: 0x%02x (Write protect group: %d blocks)\n",
1064 wp_grp_size, wp_grp_size + 1);
1065 if (wp_grp_size != 0x00)
1066 printf("Warn: Invalid WP_GRP_SIZE (should be 0x00)\n");
1067
1068 printf("\tWP_GRP_ENABLE: 0x%01x\n", wp_grp_enable);
1069 if (wp_grp_enable != 0x00)
1070 printf("Warn: Invalid WP_GRP_ENABLE (should be 0x00)\n");
1071
1072 printf("\tR2W_FACTOR: 0x%01x (Write %d times read)\n",
1073 r2w_factor, r2w_factor);
1074 if (r2w_factor != 0x02)
1075 printf("Warn: Invalid R2W_FACTOR (should be 0x02)\n");
1076
1077 printf("\tWRITE_BL_LEN: 0x%01x (", write_bl_len);
1078 switch (write_bl_len) {
1079 case 9:
1080 printf("512 bytes)\n");
1081 break;
1082 case 10:
1083 printf("1024 bytes)\n");
1084 break;
1085 case 11:
1086 printf("2048 bytes)\n");
1087 break;
1088 default:
1089 printf("reserved)\n");
1090 break;
1091 }
1092
1093 if (write_bl_len != 0x09)
1094 printf("Warn: Invalid WRITE_BL_LEN (should be 0x09)\n");
1095
1096 printf("\tWRITE_BL_PARTIAL: 0x%01x\n", write_bl_partial);
1097 if (write_bl_partial != 0x00)
1098 printf("Warn: Invalid WRITE_BL_PARTIAL (should be 0x00)\n");
1099
1100 printf("\tFILE_FORMAT_GRP: 0x%01x\n", file_format_grp);
1101 if (file_format_grp != 0x00)
1102 printf("Warn: Invalid FILE_FORMAT_GRP (should be 0x00)\n");
1103
1104 printf("\tCOPY: 0x%01x\n", copy);
1105 printf("\tPERM_WRITE_PROTECT: 0x%01x\n",
1106 perm_write_protect);
1107 printf("\tTMP_WRITE_PROTECT: 0x%01x\n",
1108 tmp_write_protect);
1109 printf("\tFILE_FORMAT: 0x%01x (",
1110 file_format);
1111
1112 if (file_format_grp == 1) {
1113 printf("reserved)\n");
1114 } else {
1115 switch (file_format) {
1116 case 0:
1117 printf("partition table)\n");
1118 break;
1119 case 1:
1120 printf("no partition table)\n");
1121 break;
1122 case 2:
1123 printf("Universal File Format)\n");
1124 break;
1125 case 3:
1126 printf("Others/unknown)\n");
1127 break;
1128 }
1129 }
1130
1131 if (file_format != 0x00)
1132 printf("Warn: Invalid FILE_FORMAT (should be 0x00)\n");
1133
1134 printf("\tCRC: 0x%01x\n", crc);
1135
1136 memory_capacity = (c_size + 1) * 512ull * 1024ull;
1137 block_size = 512;
1138 blocks = memory_capacity / block_size;
1139 }
1140
1141 memory_capacity = blocks * block_size;
1142
1143 printf("\tCAPACITY: ");
1144 if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0)
1145 printf("%.2fGbyte",
1146 memory_capacity / (1024.0 * 1024.0 * 1024.0));
1147 else if (memory_capacity / (1024ull * 1024ull) > 0)
1148 printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0));
1149 else if (memory_capacity / (1024ull) > 0)
1150 printf("%.2fKbyte", memory_capacity / (1024.0));
1151 else
1152 printf("%.2fbyte", memory_capacity * 1.0);
1153
1154 printf(" (%lld bytes, %lld sectors, %d bytes each)\n",
1155 memory_capacity, blocks, block_size);
1156 } else {
1157 unsigned long long blocks = 0;
1158 int block_size = 0;
1159 unsigned long long memory_capacity;
1160
1161 printf("card classes: ");
1162 if (ccc & 0x800)
1163 printf("11 extension, ");
1164 if (ccc & 0x400)
1165 printf("10 switch, ");
1166 if (ccc & 0x200)
1167 printf("9 I/O mode, ");
1168 if (ccc & 0x100)
1169 printf("8 application specific, ");
1170 if (ccc & 0x080)
1171 printf("7 lock card, ");
1172 if (ccc & 0x040)
1173 printf("6 write protection, ");
1174 if (ccc & 0x020)
1175 printf("5 erase, ");
1176 if (ccc & 0x010)
1177 printf("4 block write, ");
1178 if (ccc & 0x008)
1179 printf("3 reserved, ");
1180 if (ccc & 0x004)
1181 printf("2 block read, ");
1182 if (ccc & 0x002)
1183 printf("1 reserved, ");
1184 if (ccc & 0x001)
1185 printf("0 basic, ");
1186 printf("\b\b\n");
1187
1188 if (csd_structure == 0) {
1189 int mult;
1190 int blocknr;
1191 int block_len;
1192
1193 mult = 1 << (c_size_mult + 2);
1194 blocknr = (c_size + 1) * mult;
1195 block_len = 1 << read_bl_len;
1196 blocks = blocknr;
1197 block_size = block_len;
1198 } else if (csd_structure == 1) {
1199 memory_capacity = (c_size + 1) * 512ull * 1024ull;
1200 block_size = 512;
1201 blocks = memory_capacity / block_size;
1202 }
1203
1204 memory_capacity = blocks * block_size;
1205
1206 printf("capacity: ");
1207 if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0)
1208 printf("%.2fGbyte",
1209 memory_capacity / (1024.0 * 1024.0 * 1024.0));
1210 else if (memory_capacity / (1024ull * 1024ull) > 0)
1211 printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0));
1212 else if (memory_capacity / (1024ull) > 0)
1213 printf("%.2fKbyte", memory_capacity / (1024.0));
1214 else
1215 printf("%.2fbyte", memory_capacity * 1.0);
1216
1217 printf(" (%lld bytes, %lld sectors, %d bytes each)\n",
1218 memory_capacity, blocks, block_size);
1219 }
1220}
1221
1222void print_mmc_csd(struct config *config, char *csd)
1223{
1224 unsigned int csd_structure;
1225 unsigned int spec_vers;
1226 unsigned int taac_timevalue;
1227 unsigned int taac_timeunit;
1228 unsigned int nsac;
1229 unsigned int tran_speed_timevalue;
1230 unsigned int tran_speed_transferrateunit;
1231 unsigned int ccc;
1232 unsigned int read_bl_len;
1233 unsigned int read_bl_partial;
1234 unsigned int write_blk_misalign;
1235 unsigned int read_blk_misalign;
1236 unsigned int dsr_imp;
1237 unsigned int c_size;
1238 unsigned int vdd_r_curr_min;
1239 unsigned int vdd_r_curr_max;
1240 unsigned int vdd_w_curr_min;
1241 unsigned int vdd_w_curr_max;
1242 unsigned int c_size_mult;
1243 unsigned int erase_grp_size;
1244 unsigned int erase_grp_mult;
1245 unsigned int wp_grp_size;
1246 unsigned int wp_grp_enable;
1247 unsigned int default_ecc;
1248 unsigned int r2w_factor;
1249 unsigned int write_bl_len;
1250 unsigned int write_bl_partial;
1251 unsigned int content_prot_app;
1252 unsigned int file_format_grp;
1253 unsigned int copy;
1254 unsigned int perm_write_protect;
1255 unsigned int tmp_write_protect;
1256 unsigned int file_format;
1257 unsigned int ecc;
1258 unsigned int crc;
1259 unsigned int taac;
1260 unsigned int tran_speed;
1261
1262 parse_bin(csd, "2u4u2r1r4u3u8u1r4u3u12u4u1u1u1u1u2r12u3u3u3u3u3u"
1263 "5u5u5u1u2u3u4u1u4r1u1u1u1u1u2u2u7u1r",
1264 &csd_structure, &spec_vers, &taac_timevalue,
1265 &taac_timeunit, &nsac, &tran_speed_timevalue,
1266 &tran_speed_transferrateunit, &ccc, &read_bl_len,
1267 &read_bl_partial, &write_blk_misalign,
1268 &read_blk_misalign, &dsr_imp, &c_size,
1269 &vdd_r_curr_min, &vdd_r_curr_max,
1270 &vdd_w_curr_min, &vdd_w_curr_max, &c_size_mult,
1271 &erase_grp_size, &erase_grp_mult, &wp_grp_size,
1272 &wp_grp_enable, &default_ecc, &r2w_factor,
1273 &write_bl_len, &write_bl_partial, &content_prot_app,
1274 &file_format_grp, &copy, &perm_write_protect,
1275 &tmp_write_protect, &file_format, &ecc, &crc);
1276
1277 taac = taac_timevalue << 3 | taac_timeunit;
1278 tran_speed = tran_speed_timevalue << 3 | tran_speed_transferrateunit;
1279
1280 if (config->verbose) {
1281 float value;
1282 int mult;
1283 int blocknr;
1284 int block_len;
1285 unsigned long long blocks = 0;
1286 int block_size = 0;
1287 unsigned long long memory_capacity;
1288
1289 printf("======MMC/CSD======\n");
1290
1291 printf("\tCSD_STRUCTURE: 0x%01x (", csd_structure);
1292 switch (csd_structure) {
1293 case 0x0:
1294 printf("v1.0)\n");
1295 break;
1296 case 0x1:
1297 printf("v1.1)\n");
1298 break;
1299 case 0x2:
1300 printf("v1.2)\n");
1301 break;
1302 case 0x3:
1303 printf("version in ext_csd)\n");
1304 break;
1305 }
1306
1307 printf("\tSPEC_VERS: 0x%01x (", spec_vers);
1308 switch (spec_vers) {
1309 case 0x0:
1310 printf("v1.0-v1.2)\n");
1311 break;
1312 case 0x1:
1313 printf("v1.4)\n");
1314 break;
1315 case 0x2:
1316 printf("v2.0-v2.2)\n");
1317 break;
1318 case 0x3:
1319 printf("v3.1-v3.31)\n");
1320 break;
1321 case 0x4:
1322 printf("v4.0-v4.3)\n");
1323 break;
1324 default:
1325 printf("reserved)\n");
1326 break;
1327 }
1328
1329 printf("\tTAAC: 0x%02x (", taac);
1330 switch (taac_timevalue) {
1331 case 0x0:
1332 value = 0.0f;
1333 break;
1334 case 0x1:
1335 value = 1.0f;
1336 break;
1337 case 0x2:
1338 value = 1.2f;
1339 break;
1340 case 0x3:
1341 value = 1.3f;
1342 break;
1343 case 0x4:
1344 value = 1.5f;
1345 break;
1346 case 0x5:
1347 value = 2.0f;
1348 break;
1349 case 0x6:
1350 value = 2.5f;
1351 break;
1352 case 0x7:
1353 value = 3.0f;
1354 break;
1355 case 0x8:
1356 value = 3.5f;
1357 break;
1358 case 0x9:
1359 value = 4.0f;
1360 break;
1361 case 0xa:
1362 value = 4.5f;
1363 break;
1364 case 0xb:
1365 value = 5.0f;
1366 break;
1367 case 0xc:
1368 value = 5.5f;
1369 break;
1370 case 0xd:
1371 value = 6.0f;
1372 break;
1373 case 0xe:
1374 value = 7.0f;
1375 break;
1376 case 0xf:
1377 value = 8.0f;
1378 break;
1379 default:
1380 value = 0.0f;
1381 break;
1382 }
1383
1384 switch (taac_timeunit) {
1385 case 0x0:
1386 printf("%.2fns)\n", value * 1.0f);
1387 break;
1388 case 0x1:
1389 printf("%.2fns)\n", value * 10.0f);
1390 break;
1391 case 0x2:
1392 printf("%.2fns)\n", value * 100.0f);
1393 break;
1394 case 0x3:
1395 printf("%.2fus)\n", value * 1.0f);
1396 break;
1397 case 0x4:
1398 printf("%.2fus)\n", value * 10.0f);
1399 break;
1400 case 0x5:
1401 printf("%.2fus)\n", value * 100.0f);
1402 break;
1403 case 0x6:
1404 printf("%.2fms)\n", value * 1.0f);
1405 break;
1406 case 0x7:
1407 printf("%.2fms)\n", value * 10.0f);
1408 break;
1409 }
1410
1411 printf("\tNSAC: %d clocks\n", nsac);
1412 printf("\tTRAN_SPEED: 0x%02x (", tran_speed);
1413 switch (tran_speed_timevalue) {
1414 case 0x0:
1415 value = 0.0f;
1416 break;
1417 case 0x1:
1418 value = 1.0f;
1419 break;
1420 case 0x2:
1421 value = 1.2f;
1422 break;
1423 case 0x3:
1424 value = 1.3f;
1425 break;
1426 case 0x4:
1427 value = 1.5f;
1428 break;
1429 case 0x5:
1430 value = 2.0f;
1431 break;
1432 case 0x6:
1433 value = 2.6f;
1434 break;
1435 case 0x7:
1436 value = 3.0f;
1437 break;
1438 case 0x8:
1439 value = 3.5f;
1440 break;
1441 case 0x9:
1442 value = 4.0f;
1443 break;
1444 case 0xa:
1445 value = 4.5f;
1446 break;
1447 case 0xb:
1448 value = 5.2f;
1449 break;
1450 case 0xc:
1451 value = 5.5f;
1452 break;
1453 case 0xd:
1454 value = 6.0f;
1455 break;
1456 case 0xe:
1457 value = 7.0f;
1458 break;
1459 case 0xf:
1460 value = 8.0f;
1461 break;
1462 default:
1463 value = 0.0f;
1464 break;
1465 }
1466
1467 switch (tran_speed_transferrateunit) {
1468 case 0x0:
1469 printf("%.2fKHz/s)\n", value * 100.0f);
1470 break;
1471 case 0x1:
1472 printf("%.2fMHz/s)\n", value * 1.0f);
1473 break;
1474 case 0x2:
1475 printf("%.2fMHz/s)\n", value * 10.0f);
1476 break;
1477 case 0x3:
1478 printf("%.2fMHz/s)\n", value * 100.0f);
1479 break;
1480 default:
1481 printf("reserved)\n");
1482 break;
1483 }
1484
1485 printf("\tCCC: 0x%03x (class: ", ccc);
1486 if (ccc & 0x800)
1487 printf("11, ");
1488 if (ccc & 0x400)
1489 printf("10, ");
1490 if (ccc & 0x200)
1491 printf("9, ");
1492 if (ccc & 0x100)
1493 printf("8, ");
1494 if (ccc & 0x080)
1495 printf("7, ");
1496 if (ccc & 0x040)
1497 printf("6, ");
1498 if (ccc & 0x020)
1499 printf("5, ");
1500 if (ccc & 0x010)
1501 printf("4, ");
1502 if (ccc & 0x008)
1503 printf("3, ");
1504 if (ccc & 0x004)
1505 printf("2, ");
1506 if (ccc & 0x002)
1507 printf("1, ");
1508 if (ccc & 0x001)
1509 printf("0, ");
1510 printf(" )\n");
1511
1512 printf("\tREAD_BL_LEN: 0x%01x (", read_bl_len);
1513 switch (read_bl_len) {
1514 case 0x0:
1515 printf("1 byte)\n");
1516 break;
1517 case 0x1:
1518 printf("2 byte)\n");
1519 break;
1520 case 0x2:
1521 printf("4 byte)\n");
1522 break;
1523 case 0x3:
1524 printf("8 byte)\n");
1525 break;
1526 case 0x4:
1527 printf("16 byte)\n");
1528 break;
1529 case 0x5:
1530 printf("32 byte)\n");
1531 break;
1532 case 0x6:
1533 printf("64 byte)\n");
1534 break;
1535 case 0x7:
1536 printf("128 byte)\n");
1537 break;
1538 case 0x8:
1539 printf("256 byte)\n");
1540 break;
1541 case 0x9:
1542 printf("512 bytes)\n");
1543 break;
1544 case 0xa:
1545 printf("1024 bytes)\n");
1546 break;
1547 case 0xb:
1548 printf("2048 bytes)\n");
1549 break;
1550 case 0xc:
1551 printf("4096 bytes)\n");
1552 break;
1553 case 0xd:
1554 printf("8192 bytes)\n");
1555 break;
1556 case 0xe:
1557 printf("16K bytes)\n");
1558 break;
1559 default:
1560 printf("reserved bytes)\n");
1561 break;
1562 }
1563
1564 printf("\tREAD_BL_PARTIAL: 0x%01x (", read_bl_partial);
1565 switch (read_bl_partial) {
1566 case 0x0:
1567 printf("only 512 byte and READ_BL_LEN block size)\n");
1568 break;
1569 case 0x1:
1570 printf("less than READ_BL_LEN block size can be used)\n");
1571 break;
1572 }
1573
1574 printf("\tWRITE_BLK_MISALIGN: 0x%01x (", write_blk_misalign);
1575 switch (write_blk_misalign) {
1576 case 0x0:
1577 printf("writes across block boundaries are invalid)\n");
1578 break;
1579 case 0x1:
1580 printf("writes across block boundaries are allowed)\n");
1581 break;
1582 }
1583
1584 printf("\tREAD_BLK_MISALIGN: 0x%01x (", read_blk_misalign);
1585 switch (read_blk_misalign) {
1586 case 0x0:
1587 printf("reads across block boundaries are invalid)\n");
1588 break;
1589 case 0x1:
1590 printf("reads across block boundaries are allowed)\n");
1591 break;
1592 }
1593
1594 printf("\tDSR_IMP: 0x%01x (", dsr_imp);
1595 switch (dsr_imp) {
1596 case 0x0:
1597 printf("configurable driver stage not available)\n");
1598 break;
1599 case 0x1:
1600 printf("configurable driver state available)\n");
1601 break;
1602 }
1603
1604 printf("\tC_SIZE: 0x%03x\n", c_size);
1605 printf("\tVDD_R_CURR_MIN: 0x%01x (", vdd_r_curr_min);
1606 switch (vdd_r_curr_min) {
1607 case 0x0:
1608 printf("0.5mA)\n");
1609 break;
1610 case 0x1:
1611 printf("1mA)\n");
1612 break;
1613 case 0x2:
1614 printf("5mA)\n");
1615 break;
1616 case 0x3:
1617 printf("10mA)\n");
1618 break;
1619 case 0x4:
1620 printf("25mA)\n");
1621 break;
1622 case 0x5:
1623 printf("35mA)\n");
1624 break;
1625 case 0x6:
1626 printf("60mA)\n");
1627 break;
1628 case 0x7:
1629 printf("100mA)\n");
1630 break;
1631 }
1632
1633 printf("\tVDD_R_CURR_MAX: 0x%01x (", vdd_r_curr_max);
1634 switch (vdd_r_curr_max) {
1635 case 0x0:
1636 printf("1mA)\n");
1637 break;
1638 case 0x1:
1639 printf("5mA)\n");
1640 break;
1641 case 0x2:
1642 printf("10mA)\n");
1643 break;
1644 case 0x3:
1645 printf("25mA)\n");
1646 break;
1647 case 0x4:
1648 printf("35mA)\n");
1649 break;
1650 case 0x5:
1651 printf("45mA)\n");
1652 break;
1653 case 0x6:
1654 printf("80mA)\n");
1655 break;
1656 case 0x7:
1657 printf("200mA)\n");
1658 break;
1659 }
1660
1661 printf("\tVDD_W_CURR_MIN: 0x%01x (", vdd_w_curr_min);
1662 switch (vdd_w_curr_min) {
1663 case 0x0:
1664 printf("0.5mA)\n");
1665 break;
1666 case 0x1:
1667 printf("1mA)\n");
1668 break;
1669 case 0x2:
1670 printf("5mA)\n");
1671 break;
1672 case 0x3:
1673 printf("10mA)\n");
1674 break;
1675 case 0x4:
1676 printf("25mA)\n");
1677 break;
1678 case 0x5:
1679 printf("35mA)\n");
1680 break;
1681 case 0x6:
1682 printf("60mA)\n");
1683 break;
1684 case 0x7:
1685 printf("100mA)\n");
1686 break;
1687 }
1688
1689 printf("\tVDD_W_CURR_MAX: 0x%01x (", vdd_w_curr_max);
1690 switch (vdd_w_curr_max) {
1691 case 0x0:
1692 printf("1mA)\n");
1693 break;
1694 case 0x1:
1695 printf("5mA)\n");
1696 break;
1697 case 0x2:
1698 printf("10mA)\n");
1699 break;
1700 case 0x3:
1701 printf("25mA)\n");
1702 break;
1703 case 0x4:
1704 printf("35mA)\n");
1705 break;
1706 case 0x5:
1707 printf("45mA)\n");
1708 break;
1709 case 0x6:
1710 printf("80mA)\n");
1711 break;
1712 case 0x7:
1713 printf("200mA)\n");
1714 break;
1715 }
1716
1717 printf("\tC_SIZE_MULT: 0x%01x\n", c_size_mult);
1718 printf("\tERASE_GRP_SIZE: 0x%02x\n", erase_grp_size);
1719 printf("\tERASE_GRP_MULT: 0x%02x (%d write blocks/erase group)\n",
1720 erase_grp_mult, (erase_grp_size + 1) *
1721 (erase_grp_mult + 1));
1722 printf("\tWP_GRP_SIZE: 0x%02x (%d blocks/write protect group)\n",
1723 wp_grp_size, wp_grp_size + 1);
1724 printf("\tWP_GRP_ENABLE: 0x%01x\n", wp_grp_enable);
1725
1726 printf("\tDEFAULT_ECC: 0x%01x (", default_ecc);
1727 switch (default_ecc) {
1728 case 0:
1729 printf("none)\n");
1730 break;
1731 case 1:
1732 printf("BCH)\n");
1733 break;
1734 default:
1735 printf("reserved)\n");
1736 break;
1737 }
1738
1739 printf("\tR2W_FACTOR: 0x%01x (Write %d times read)\n",
1740 r2w_factor, r2w_factor);
1741
1742 printf("\tWRITE_BL_LEN: 0x%01x (", write_bl_len);
1743 switch (write_bl_len) {
1744 case 0x0:
1745 printf("1 byte)\n");
1746 break;
1747 case 0x1:
1748 printf("2 byte)\n");
1749 break;
1750 case 0x2:
1751 printf("4 byte)\n");
1752 break;
1753 case 0x3:
1754 printf("8 byte)\n");
1755 break;
1756 case 0x4:
1757 printf("16 byte)\n");
1758 break;
1759 case 0x5:
1760 printf("32 byte)\n");
1761 break;
1762 case 0x6:
1763 printf("64 byte)\n");
1764 break;
1765 case 0x7:
1766 printf("128 byte)\n");
1767 break;
1768 case 0x8:
1769 printf("256 byte)\n");
1770 break;
1771 case 0x9:
1772 printf("512 bytes)\n");
1773 break;
1774 case 0xa:
1775 printf("1024 bytes)\n");
1776 break;
1777 case 0xb:
1778 printf("2048 bytes)\n");
1779 break;
1780 case 0xc:
1781 printf("4096 bytes)\n");
1782 break;
1783 case 0xd:
1784 printf("8192 bytes)\n");
1785 break;
1786 case 0xe:
1787 printf("16K bytes)\n");
1788 break;
1789 default:
1790 printf("reserved bytes)\n");
1791 break;
1792 }
1793
1794 printf("\tWRITE_BL_PARTIAL: 0x%01x (", write_bl_partial);
1795 switch (write_bl_partial) {
1796 case 0x0:
1797 printf("only 512 byte and WRITE_BL_LEN block size)\n");
1798 break;
1799 case 0x1:
1800 printf("less than WRITE_BL_LEN block size can be used)\n");
1801 break;
1802 }
1803
1804 printf("\tCONTENT_PROT_APP: 0x%01x\n", content_prot_app);
1805 printf("\tFILE_FORMAT_GRP: 0x%01x\n", file_format_grp);
1806 if (file_format_grp != 0)
1807 printf("Warn: Invalid FILE_FORMAT_GRP\n");
1808
1809 printf("\tCOPY: 0x%01x\n", copy);
1810 printf("\tPERM_WRITE_PROTECT: 0x%01x\n", perm_write_protect);
1811 printf("\tTMP_WRITE_PROTECT: 0x%01x\n", tmp_write_protect);
1812 printf("\tFILE_FORMAT: 0x%01x (", file_format);
1813 if (file_format != 0)
1814 printf("Warn: Invalid FILE_FORMAT\n");
1815
1816 if (file_format_grp == 1) {
1817 printf("reserved)\n");
1818 } else {
1819 switch (file_format) {
1820 case 0:
1821 printf("partition table)\n");
1822 break;
1823 case 1:
1824 printf("no partition table)\n");
1825 break;
1826 case 2:
1827 printf("Universal File Format)\n");
1828 break;
1829 case 3:
1830 printf("Others/unknown)\n");
1831 break;
1832 }
1833 }
1834
1835 printf("\tECC: 0x%01x (", ecc);
1836 switch (ecc) {
1837 case 0:
1838 printf("none)\n");
1839 break;
1840 case 1:
1841 printf("BCH(542,512))\n");
1842 break;
1843 default:
1844 printf("reserved)\n");
1845 break;
1846 }
1847
1848 printf("\tCRC: 0x%01x\n", crc);
1849
1850 mult = 1 << (c_size_mult + 2);
1851 blocknr = (c_size + 1) * mult;
1852 block_len = 1 << read_bl_len;
1853 blocks = blocknr;
1854 block_size = block_len;
1855
1856 memory_capacity = blocks * block_size;
1857
1858 printf("\tCAPACITY: ");
1859 if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0)
1860 printf("%.2fGbyte",
1861 memory_capacity / (1024.0 * 1024.0 * 1024.0));
1862 else if (memory_capacity / (1024ull * 1024ull) > 0)
1863 printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0));
1864 else if (memory_capacity / (1024ull) > 0)
1865 printf("%.2fKbyte", memory_capacity / (1024.0));
1866 else
1867 printf("%.2fbyte", memory_capacity * 1.0);
1868
1869 printf(" (%lld bytes, %lld sectors, %d bytes each)\n",
1870 memory_capacity, blocks, block_size);
1871 } else {
1872 int mult;
1873 int blocknr;
1874 int block_len;
1875 unsigned long long blocks = 0;
1876 int block_size = 0;
1877 unsigned long long memory_capacity;
1878
1879 printf("version: ");
1880 switch (spec_vers) {
1881 case 0x0:
1882 printf("MMC v1.0-v1.2\n");
1883 break;
1884 case 0x1:
1885 printf("MMC v1.4\n");
1886 break;
1887 case 0x2:
1888 printf("MMC v2.0-v2.2\n");
1889 break;
1890 case 0x3:
1891 printf("MMC v3.1-v3.31\n");
1892 break;
1893 case 0x4:
1894 printf("MMC v4.0-v4.3\n");
1895 break;
1896 default:
1897 printf("reserved\n");
1898 break;
1899 }
1900
1901 printf("card classes: ");
1902 if (ccc & 0x800)
1903 printf("11, ");
1904 if (ccc & 0x400)
1905 printf("10, ");
1906 if (ccc & 0x200)
1907 printf("9, ");
1908 if (ccc & 0x100)
1909 printf("8, ");
1910 if (ccc & 0x080)
1911 printf("7, ");
1912 if (ccc & 0x040)
1913 printf("6, ");
1914 if (ccc & 0x020)
1915 printf("5, ");
1916 if (ccc & 0x010)
1917 printf("4, ");
1918 if (ccc & 0x008)
1919 printf("3, ");
1920 if (ccc & 0x004)
1921 printf("2, ");
1922 if (ccc & 0x002)
1923 printf("1, ");
1924 if (ccc & 0x001)
1925 printf("0, ");
1926 printf("\b\b\n");
1927
1928 mult = 1 << (c_size_mult + 2);
1929 blocknr = (c_size + 1) * mult;
1930 block_len = 1 << read_bl_len;
1931 blocks = blocknr;
1932 block_size = block_len;
1933
1934 memory_capacity = blocks * block_size;
1935
1936 printf("capacity: ");
1937 if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0)
1938 printf("%.2fGbyte",
1939 memory_capacity / (1024.0 * 1024.0 * 1024.0));
1940 else if (memory_capacity / (1024ull * 1024ull) > 0)
1941 printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0));
1942 else if (memory_capacity / (1024ull) > 0)
1943 printf("%.2fKbyte", memory_capacity / (1024.0));
1944 else
1945 printf("%.2fbyte", memory_capacity * 1.0);
1946 printf(" (%lld bytes, %lld sectors, %d bytes each)\n",
1947 memory_capacity, blocks, block_size);
1948 }
1949}
1950
1951char *speed_class_speed(unsigned char id, bool ddr)
1952{
1953 if (ddr) {
1954 switch (id) {
1955 case 0x00: return "<4.8MB/s";
1956 case 0x08: return " 4.8MB/s";
1957 case 0x0a: return " 6.0MB/s";
1958 case 0x0f: return " 9.0MB/s";
1959 case 0x14: return "12.0MB/s";
1960 case 0x1e: return "18.0MB/s";
1961 case 0x28: return "24.0MB/s";
1962 case 0x32: return "30.0MB/s";
1963 case 0x3c: return "36.0MB/s";
1964 case 0x46: return "42.0MB/s";
1965 case 0x50: return "48.0MB/s";
1966 case 0x64: return "60.0MB/s";
1967 case 0x78: return "72.0MB/s";
1968 case 0x8c: return "84.0MB/s";
1969 case 0xa0: return "96.0MB/s";
1970 default: return "??.?MB/s";
1971 }
1972 } else {
1973 switch (id) {
1974 case 0x00: return "<2.4MB/s";
1975 case 0x08: return " 2.4MB/s";
1976 case 0x0a: return " 3.0MB/s";
1977 case 0x0f: return " 4.5MB/s";
1978 case 0x14: return " 6.0MB/s";
1979 case 0x1e: return " 9.0MB/s";
1980 case 0x28: return "12.0MB/s";
1981 case 0x32: return "15.0MB/s";
1982 case 0x3c: return "18.0MB/s";
1983 case 0x46: return "21.0MB/s";
1984 case 0x50: return "24.0MB/s";
1985 case 0x64: return "30.0MB/s";
1986 case 0x78: return "36.0MB/s";
1987 case 0x8c: return "42.0MB/s";
1988 case 0xa0: return "48.0MB/s";
1989 default: return "??.?MB/s";
1990 }
1991 }
1992}
1993
1994char speed_class_name(unsigned char id)
1995{
1996 switch (id) {
1997 case 0x00: return '?';
1998 case 0x08: return 'A';
1999 case 0x0a: return 'B';
2000 case 0x0f: return 'C';
2001 case 0x14: return 'D';
2002 case 0x1e: return 'E';
2003 case 0x28: return 'F';
2004 case 0x32: return 'G';
2005 case 0x3c: return 'H';
2006 case 0x46: return 'J';
2007 case 0x50: return 'K';
2008 case 0x64: return 'M';
2009 case 0x78: return 'O';
2010 case 0x8c: return 'R';
2011 case 0xa0: return 'T';
2012 default: return '?';
2013 }
2014}
2015
2016char *power_class_consumption(unsigned int id, bool volt360)
2017{
2018 if (volt360) {
2019 switch (id) {
2020 case 0x0: return "100-200mA";
2021 case 0x1: return "120-220mA";
2022 case 0x2: return "150-250mA";
2023 case 0x3: return "180-280mA";
2024 case 0x4: return "200-300mA";
2025 case 0x5: return "220-320mA";
2026 case 0x6: return "250-350mA";
2027 case 0x7: return "300-400mA";
2028 case 0x8: return "350-450mA";
2029 case 0x9: return "400-500mA";
2030 case 0xa: return "450-550mA";
2031 default: return "reserved";
2032 }
2033 } else {
2034 switch (id) {
2035 case 0x0: return "65-130mA";
2036 case 0x1: return "70-140mA";
2037 case 0x2: return "80-160mA";
2038 case 0x3: return "90-180mA";
2039 case 0x4: return "100-200mA";
2040 case 0x5: return "120-220mA";
2041 case 0x6: return "140-240mA";
2042 case 0x7: return "160-260mA";
2043 case 0x8: return "180-280mA";
2044 case 0x9: return "200-300mA";
2045 case 0xa: return "250-350mA";
2046 default: return "reserved";
2047 }
2048 }
2049}
2050
2051char *sleep_consumption(unsigned int id)
2052{
2053 switch (id) {
2054 case 0x00: return "not defined";
2055 case 0x01: return "2uA";
2056 case 0x02: return "4uA";
2057 case 0x03: return "8uA";
2058 case 0x04: return "16uA";
2059 case 0x05: return "32uA";
2060 case 0x06: return "64uA";
2061 case 0x07: return "128uA";
2062 case 0x08: return "0.256mA";
2063 case 0x09: return "0.512mA";
2064 case 0x0a: return "1.024mA";
2065 case 0x0b: return "2.048mA";
2066 case 0x0c: return "4.096mA";
2067 case 0x0d: return "8.192mA";
2068 default: return "reserved";
2069 }
2070}
2071
2072void print_sd_scr(struct config *config, char *scr)
2073{
2074 unsigned int scr_structure;
2075 unsigned int sd_spec;
2076 unsigned int data_stat_after_erase;
2077 unsigned int sd_security;
2078 unsigned int sd_bus_widths;
2079 unsigned int sd_spec3;
2080 unsigned int ex_security;
2081 unsigned int cmd_support;
2082
2083 parse_bin(scr, "4u4u1u3u4u1u4u9r2u32r",
2084 &scr_structure, &sd_spec, &data_stat_after_erase,
2085 &sd_security, &sd_bus_widths, &sd_spec3,
2086 &ex_security, &cmd_support);
2087
2088 if (config->verbose) {
2089 printf("======SD/SCR======\n");
2090
2091 printf("\tSCR_STRUCTURE: 0x%01x (", scr_structure);
2092 switch (scr_structure) {
2093 case 0:
2094 printf("SCR v1.0)\n");
2095 break;
2096 default:
2097 printf("reserved)\n");
2098 break;
2099 }
2100
2101 printf("\tSD_SPEC: 0x%01x (", sd_spec);
2102 switch (sd_spec) {
2103 case 0:
2104 printf("SD v1.0/1.01)\n");
2105 break;
2106 case 1:
2107 printf("SD v1.10)\n");
2108 break;
2109 case 2:
2110 printf("SD v2.00/v3.0x)\n");
2111 break;
2112 case 3:
2113 printf("SD v4.00)\n");
2114 break;
2115 default:
2116 printf("reserved)\n");
2117 break;
2118 }
2119
2120 printf("\tDATA_STAT_AFTER_ERASE: 0x%01x\n",
2121 data_stat_after_erase);
2122
2123 printf("\tSD_SECURITY: 0x%01x (", sd_security);
2124 switch (sd_security) {
2125 case 0:
2126 printf("no security)\n");
2127 break;
2128 case 1:
2129 printf("not used)\n");
2130 break;
2131 case 2:
2132 printf("SDSC card/security v1.01)\n");
2133 break;
2134 case 3:
2135 printf("SDHC card/security v2.00)\n");
2136 break;
2137 case 4:
2138 printf("SDXC card/security v3.xx)\n");
2139 break;
2140 default:
2141 printf("reserved)\n");
2142 break;
2143 }
2144
2145 printf("\tSD_BUS_WIDTHS: 0x%01x (", sd_bus_widths);
2146 if (BITS(sd_bus_widths, 2, 2))
2147 printf("4bit, ");
2148 if (BITS(sd_bus_widths, 0, 0))
2149 printf("1bit, ");
2150 printf(" bus)\n");
2151
2152 printf("\tSD_SPEC3: 0x%01x (", sd_spec3);
2153 if (sd_spec >= 2) {
2154 switch (sd_spec3) {
2155 case 0:
2156 printf("SD v2.00)\n");
2157 break;
2158 case 1:
2159 printf("SD v3.0x)\n");
2160 break;
2161 }
2162 } else {
2163 printf("SD 1.xx)\n");
2164 }
2165
2166 printf("\tEX_SECURITY: 0x%01x\n", ex_security);
2167
2168 printf("\tCMD_SUPPORT: 0x%01x (", cmd_support);
2169 if (BITS(cmd_support, 1, 1))
2170 printf("CMD23 ");
2171 if (BITS(cmd_support, 0, 0))
2172 printf("CMD20 ");
2173 printf(" )\n");
2174 } else {
2175 printf("version: ");
2176 switch (sd_spec) {
2177 case 0:
2178 printf("SD 1.0/1.01\n");
2179 break;
2180 case 1:
2181 printf("SD 1.10\n");
2182 break;
2183 case 2:
2184 switch (sd_spec3) {
2185 case 0:
2186 printf("SD 2.00\n");
2187 break;
2188 case 1:
2189 printf("SD 3.0x\n");
2190 break;
2191 default:
2192 printf("unknown\n");
2193 break;
2194 }
2195 break;
2196 case 3:
2197 printf("SD 4.00\n");
2198 break;
2199 default:
2200 printf("unknown\n");
2201 break;
2202 }
2203
2204 printf("bus widths: ");
2205 if (BITS(sd_bus_widths, 2, 2))
2206 printf("4bit, ");
2207 if (BITS(sd_bus_widths, 0, 0))
2208 printf("1bit, ");
2209 printf("\b\b\n");
2210 }
2211}
2212
2213/* MMC/SD interface processing functions */
2214void print_info(struct config *config, char *type,
2215 char *cid, char *csd, char *scr, char *ext_csd)
2216{
2217 printf("type: '%s'\n", type);
2218
2219 if (!strcmp(type, "SD") && cid)
2220 print_sd_cid(config, cid);
2221 else if (!strcmp(type, "MMC") && cid)
2222 print_mmc_cid(config, cid);
2223
2224 if (!strcmp(type, "SD") && scr)
2225 print_sd_scr(config, scr);
2226
2227 if (!strcmp(type, "MMC") && csd)
2228 print_mmc_csd(config, csd);
2229 else if (!strcmp(type, "SD") && csd)
2230 print_sd_csd(config, csd);
2231}
2232
2233int process_dir(struct config *config, enum REG_TYPE reg)
2234{
2235 char *type = NULL, *cid = NULL, *csd = NULL, *scr = NULL, *ext_csd = NULL;
2236 int ret = 0;
2237
2238 if (chdir(config->dir) < 0) {
2239 fprintf(stderr,
2240 "MMC/SD information directory '%s' does not exist.\n",
2241 config->dir);
2242 return -1;
2243 }
2244
2245 type = read_file("type");
2246 if (!type) {
2247 fprintf(stderr,
2248 "Could not read card interface type in directory '%s'.\n",
2249 config->dir);
2250 return -1;
2251 }
2252
2253 if (strcmp(type, "MMC") && strcmp(type, "SD")) {
2254 fprintf(stderr, "Unknown type: '%s'\n", type);
2255 ret = -1;
2256 goto err;
2257 }
2258
2259 switch (reg) {
2260 case CID:
2261 cid = read_file("cid");
2262 if (!cid) {
2263 fprintf(stderr,
2264 "Could not read card identity in directory '%s'.\n",
2265 config->dir);
2266 ret = -1;
2267 goto err;
2268 }
2269 break;
2270 case CSD:
2271 csd = read_file("csd");
2272 if (!csd) {
2273 fprintf(stderr,
2274 "Could not read card specific data in "
2275 "directory '%s'.\n", config->dir);
2276 ret = -1;
2277 goto err;
2278 }
2279 break;
2280 case SCR:
2281 if (!strcmp(type, "SD")) {
2282 scr = read_file("scr");
2283 if (!scr) {
2284 fprintf(stderr, "Could not read SD card "
2285 "configuration in directory '%s'.\n",
2286 config->dir);
2287 ret = -1;
2288 goto err;
2289 }
2290 }
2291 break;
2292 case EXT_CSD:
2293 if (!strcmp(type, "MMC")) {
2294 ext_csd = read_file("ext_csd");
2295 if (!ext_csd) {
2296 fprintf(stderr, "Could not read extra specific "
2297 "data in directory '%s'.\n",
2298 config->dir);
2299 ret = -1;
2300 goto err;
2301 }
2302 }
2303 break;
2304 default:
2305 goto err;
2306 }
2307
2308 print_info(config, type, cid, csd, scr, ext_csd);
2309
2310err:
2311 free(ext_csd);
2312 free(scr);
2313 free(csd);
2314 free(cid);
2315 free(type);
2316
2317 return ret;
2318}
2319
2320int lsmmc_main(struct config *config, int argc, char **argv)
2321{
2322 int ret;
2323
2324 memset(config, 0, sizeof(*config));
2325 config->mmc_ids = calloc(IDS_MAX, sizeof(char *));
2326 config->sd_ids = calloc(IDS_MAX, sizeof(char *));
2327 if (!config->mmc_ids || !config->sd_ids) {
2328 fprintf(stderr, "Could not allocate memory for lsmmc.\n");
2329 return -1;
2330 }
2331
2332 ret = parse_opts(argc, argv, config);
2333 if (ret)
2334 return ret;
2335
2336 return parse_ids(config);
2337}
2338
2339void lsmmc_free(struct config *config)
2340{
2341 free(config->mmc_ids);
2342 free(config->sd_ids);
2343 free(config->dir);
2344}
2345
2346int do_read_csd(int argc, char **argv)
2347{
2348 struct config config;
2349 int ret;
2350
2351 CHECK(argc != 2 && argc != 3, "Usage: Print CSD data from <device path>.\n",
2352 exit(1));
2353
2354 ret = lsmmc_main(&config, argc, argv);
2355 if (ret)
2356 goto out;
2357
2358 if (config.dir)
2359 ret = process_dir(&config, CSD);
2360
2361out:
2362 lsmmc_free(&config);
2363
2364 return ret;
2365}
2366
2367int do_read_cid(int argc, char **argv)
2368{
2369 struct config config;
2370 int ret;
2371
2372 CHECK(argc != 2 && argc != 3, "Usage: Print CID data from <device path>.\n",
2373 exit(1));
2374
2375 ret = lsmmc_main(&config, argc, argv);
2376 if (ret)
2377 goto out;
2378
2379 if (config.dir)
2380 ret = process_dir(&config, CID);
2381
2382out:
2383 lsmmc_free(&config);
2384
2385 return ret;
2386}
2387
2388int do_read_scr(int argc, char **argv)
2389{
2390 struct config config;
2391 int ret;
2392
2393 CHECK(argc != 2 && argc != 3, "Usage: Print SCR data from <device path>.\n",
2394 exit(1));
2395
2396 ret = lsmmc_main(&config, argc, argv);
2397 if (ret)
2398 goto out;
2399
2400 if (config.dir)
2401 ret = process_dir(&config, SCR);
2402
2403out:
2404 lsmmc_free(&config);
2405
2406 return ret;
2407}