1 /* 2 * (C) Copyright 2001 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <command.h> 10 #include <errno.h> 11 #include <ide.h> 12 #include <malloc.h> 13 #include <part.h> 14 #ifdef CONFIG_SPL_AB 15 #include <spl_ab.h> 16 #endif 17 #include <ubifs_uboot.h> 18 #ifdef CONFIG_ANDROID_AB 19 #include <android_avb/avb_ops_user.h> 20 #include <android_avb/rk_avb_ops_user.h> 21 #endif 22 23 #undef PART_DEBUG 24 25 #ifdef PART_DEBUG 26 #define PRINTF(fmt,args...) printf (fmt ,##args) 27 #else 28 #define PRINTF(fmt,args...) 29 #endif 30 31 DECLARE_GLOBAL_DATA_PTR; 32 33 #ifdef HAVE_BLOCK_DEVICE 34 static struct part_driver *part_driver_lookup_type(struct blk_desc *dev_desc) 35 { 36 struct part_driver *drv = 37 ll_entry_start(struct part_driver, part_driver); 38 const int n_ents = ll_entry_count(struct part_driver, part_driver); 39 struct part_driver *entry; 40 41 if (dev_desc->part_type == PART_TYPE_UNKNOWN) { 42 for (entry = drv; entry != drv + n_ents; entry++) { 43 int ret; 44 45 ret = entry->test(dev_desc); 46 if (!ret) { 47 dev_desc->part_type = entry->part_type; 48 return entry; 49 } 50 } 51 } else { 52 for (entry = drv; entry != drv + n_ents; entry++) { 53 if (dev_desc->part_type == entry->part_type) 54 return entry; 55 } 56 } 57 58 /* Not found */ 59 return NULL; 60 } 61 62 static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) 63 { 64 struct blk_desc *dev_desc; 65 int ret; 66 67 dev_desc = blk_get_devnum_by_typename(ifname, dev); 68 if (!dev_desc) { 69 debug("%s: No device for iface '%s', dev %d\n", __func__, 70 ifname, dev); 71 return NULL; 72 } 73 ret = blk_dselect_hwpart(dev_desc, hwpart); 74 if (ret) { 75 debug("%s: Failed to select h/w partition: err-%d\n", __func__, 76 ret); 77 return NULL; 78 } 79 80 return dev_desc; 81 } 82 83 struct blk_desc *blk_get_dev(const char *ifname, int dev) 84 { 85 return get_dev_hwpart(ifname, dev, 0); 86 } 87 #else 88 struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) 89 { 90 return NULL; 91 } 92 93 struct blk_desc *blk_get_dev(const char *ifname, int dev) 94 { 95 return NULL; 96 } 97 #endif 98 99 #ifdef HAVE_BLOCK_DEVICE 100 101 /* ------------------------------------------------------------------------- */ 102 /* 103 * reports device info to the user 104 */ 105 106 #ifdef CONFIG_LBA48 107 typedef uint64_t lba512_t; 108 #else 109 typedef lbaint_t lba512_t; 110 #endif 111 112 /* 113 * Overflowless variant of (block_count * mul_by / div_by) 114 * when div_by > mul_by 115 */ 116 static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by, lba512_t div_by) 117 { 118 lba512_t bc_quot, bc_rem; 119 120 /* x * m / d == x / d * m + (x % d) * m / d */ 121 bc_quot = block_count / div_by; 122 bc_rem = block_count - div_by * bc_quot; 123 return bc_quot * mul_by + (bc_rem * mul_by) / div_by; 124 } 125 126 void dev_print (struct blk_desc *dev_desc) 127 { 128 lba512_t lba512; /* number of blocks if 512bytes block size */ 129 130 if (dev_desc->type == DEV_TYPE_UNKNOWN) { 131 puts ("not available\n"); 132 return; 133 } 134 135 switch (dev_desc->if_type) { 136 case IF_TYPE_SCSI: 137 printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n", 138 dev_desc->target,dev_desc->lun, 139 dev_desc->vendor, 140 dev_desc->product, 141 dev_desc->revision); 142 break; 143 case IF_TYPE_ATAPI: 144 case IF_TYPE_IDE: 145 case IF_TYPE_SATA: 146 printf ("Model: %s Firm: %s Ser#: %s\n", 147 dev_desc->vendor, 148 dev_desc->revision, 149 dev_desc->product); 150 break; 151 case IF_TYPE_SD: 152 case IF_TYPE_MMC: 153 case IF_TYPE_MTD: 154 case IF_TYPE_USB: 155 case IF_TYPE_NVME: 156 case IF_TYPE_RKNAND: 157 case IF_TYPE_SPINAND: 158 case IF_TYPE_SPINOR: 159 printf("Vendor: %s Rev: %s Prod: %s\n", 160 dev_desc->vendor, 161 dev_desc->revision, 162 dev_desc->product); 163 break; 164 case IF_TYPE_DOC: 165 puts("device type DOC\n"); 166 return; 167 case IF_TYPE_UNKNOWN: 168 puts("device type unknown\n"); 169 return; 170 default: 171 printf("Unhandled device type: %i\n", dev_desc->if_type); 172 return; 173 } 174 puts (" Type: "); 175 if (dev_desc->removable) 176 puts ("Removable "); 177 switch (dev_desc->type & 0x1F) { 178 case DEV_TYPE_HARDDISK: 179 puts ("Hard Disk"); 180 break; 181 case DEV_TYPE_CDROM: 182 puts ("CD ROM"); 183 break; 184 case DEV_TYPE_OPDISK: 185 puts ("Optical Device"); 186 break; 187 case DEV_TYPE_TAPE: 188 puts ("Tape"); 189 break; 190 default: 191 printf ("# %02X #", dev_desc->type & 0x1F); 192 break; 193 } 194 puts ("\n"); 195 if (dev_desc->lba > 0L && dev_desc->blksz > 0L) { 196 ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem; 197 lbaint_t lba; 198 199 lba = dev_desc->lba; 200 201 lba512 = (lba * (dev_desc->blksz/512)); 202 /* round to 1 digit */ 203 /* 2048 = (1024 * 1024) / 512 MB */ 204 mb = lba512_muldiv(lba512, 10, 2048); 205 206 mb_quot = mb / 10; 207 mb_rem = mb - (10 * mb_quot); 208 209 gb = mb / 1024; 210 gb_quot = gb / 10; 211 gb_rem = gb - (10 * gb_quot); 212 #ifdef CONFIG_LBA48 213 if (dev_desc->lba48) 214 printf (" Supports 48-bit addressing\n"); 215 #endif 216 #if defined(CONFIG_SYS_64BIT_LBA) 217 printf (" Capacity: %lu.%lu MB = %lu.%lu GB (%llu x %lu)\n", 218 mb_quot, mb_rem, 219 gb_quot, gb_rem, 220 lba, 221 dev_desc->blksz); 222 #else 223 printf (" Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)\n", 224 mb_quot, mb_rem, 225 gb_quot, gb_rem, 226 (ulong)lba, 227 dev_desc->blksz); 228 #endif 229 } else { 230 puts (" Capacity: not available\n"); 231 } 232 } 233 #endif 234 235 #ifdef HAVE_BLOCK_DEVICE 236 237 void part_init(struct blk_desc *dev_desc) 238 { 239 struct part_driver *drv = 240 ll_entry_start(struct part_driver, part_driver); 241 const int n_ents = ll_entry_count(struct part_driver, part_driver); 242 struct part_driver *entry; 243 244 blkcache_invalidate(dev_desc->if_type, dev_desc->devnum); 245 246 dev_desc->part_type = PART_TYPE_UNKNOWN; 247 for (entry = drv; entry != drv + n_ents; entry++) { 248 int ret; 249 250 ret = entry->test(dev_desc); 251 debug("%s: try '%s': ret=%d\n", __func__, entry->name, ret); 252 if (!ret) { 253 dev_desc->part_type = entry->part_type; 254 break; 255 } 256 } 257 } 258 259 static void print_part_header(const char *type, struct blk_desc *dev_desc) 260 { 261 #if CONFIG_IS_ENABLED(MAC_PARTITION) || \ 262 CONFIG_IS_ENABLED(DOS_PARTITION) || \ 263 CONFIG_IS_ENABLED(ISO_PARTITION) || \ 264 CONFIG_IS_ENABLED(AMIGA_PARTITION) || \ 265 CONFIG_IS_ENABLED(EFI_PARTITION) 266 puts ("\nPartition Map for "); 267 switch (dev_desc->if_type) { 268 case IF_TYPE_IDE: 269 puts ("IDE"); 270 break; 271 case IF_TYPE_SATA: 272 puts ("SATA"); 273 break; 274 case IF_TYPE_SCSI: 275 puts ("SCSI"); 276 break; 277 case IF_TYPE_ATAPI: 278 puts ("ATAPI"); 279 break; 280 case IF_TYPE_USB: 281 puts ("USB"); 282 break; 283 case IF_TYPE_DOC: 284 puts ("DOC"); 285 break; 286 case IF_TYPE_MMC: 287 puts ("MMC"); 288 break; 289 case IF_TYPE_MTD: 290 puts("MTD"); 291 break; 292 case IF_TYPE_HOST: 293 puts ("HOST"); 294 break; 295 case IF_TYPE_NVME: 296 puts ("NVMe"); 297 break; 298 case IF_TYPE_RKNAND: 299 puts("RKNAND"); 300 break; 301 case IF_TYPE_SPINAND: 302 puts("SPINAND"); 303 break; 304 case IF_TYPE_SPINOR: 305 puts("SPINOR"); 306 break; 307 default: 308 puts ("UNKNOWN"); 309 break; 310 } 311 printf (" device %d -- Partition Type: %s\n\n", 312 dev_desc->devnum, type); 313 #endif /* any CONFIG_..._PARTITION */ 314 } 315 316 void part_print(struct blk_desc *dev_desc) 317 { 318 struct part_driver *drv; 319 320 drv = part_driver_lookup_type(dev_desc); 321 if (!drv) { 322 printf("## Unknown partition table type %x\n", 323 dev_desc->part_type); 324 return; 325 } 326 327 PRINTF("## Testing for valid %s partition ##\n", drv->name); 328 print_part_header(drv->name, dev_desc); 329 if (drv->print) 330 drv->print(dev_desc); 331 } 332 333 const char *part_get_type(struct blk_desc *dev_desc) 334 { 335 struct part_driver *drv; 336 337 drv = part_driver_lookup_type(dev_desc); 338 if (!drv) { 339 printf("## Unknown partition table type %x\n", 340 dev_desc->part_type); 341 return NULL; 342 } 343 344 return drv->name; 345 } 346 #endif /* HAVE_BLOCK_DEVICE */ 347 348 int part_get_info(struct blk_desc *dev_desc, int part, 349 disk_partition_t *info) 350 { 351 #ifdef HAVE_BLOCK_DEVICE 352 struct part_driver *drv; 353 354 #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 355 /* The common case is no UUID support */ 356 info->uuid[0] = 0; 357 #endif 358 #ifdef CONFIG_PARTITION_TYPE_GUID 359 info->type_guid[0] = 0; 360 #endif 361 362 drv = part_driver_lookup_type(dev_desc); 363 if (!drv) { 364 debug("## Unknown partition table type %x\n", 365 dev_desc->part_type); 366 return -EPROTONOSUPPORT; 367 } 368 if (!drv->get_info) { 369 PRINTF("## Driver %s does not have the get_info() method\n", 370 drv->name); 371 return -ENOSYS; 372 } 373 if (drv->get_info(dev_desc, part, info) == 0) { 374 PRINTF("## Valid %s partition found ##\n", drv->name); 375 return 0; 376 } 377 #endif /* HAVE_BLOCK_DEVICE */ 378 379 return -1; 380 } 381 382 int part_get_info_whole_disk(struct blk_desc *dev_desc, disk_partition_t *info) 383 { 384 info->start = 0; 385 info->size = dev_desc->lba; 386 info->blksz = dev_desc->blksz; 387 info->bootable = 0; 388 strcpy((char *)info->type, BOOT_PART_TYPE); 389 strcpy((char *)info->name, "Whole Disk"); 390 #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 391 info->uuid[0] = 0; 392 #endif 393 #ifdef CONFIG_PARTITION_TYPE_GUID 394 info->type_guid[0] = 0; 395 #endif 396 397 return 0; 398 } 399 400 int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str, 401 struct blk_desc **dev_desc) 402 { 403 char *ep; 404 char *dup_str = NULL; 405 const char *dev_str, *hwpart_str; 406 int dev, hwpart; 407 408 hwpart_str = strchr(dev_hwpart_str, '.'); 409 if (hwpart_str) { 410 dup_str = strdup(dev_hwpart_str); 411 dup_str[hwpart_str - dev_hwpart_str] = 0; 412 dev_str = dup_str; 413 hwpart_str++; 414 } else { 415 dev_str = dev_hwpart_str; 416 hwpart = 0; 417 } 418 419 dev = simple_strtoul(dev_str, &ep, 16); 420 if (*ep) { 421 printf("** Bad device specification %s %s **\n", 422 ifname, dev_str); 423 dev = -EINVAL; 424 goto cleanup; 425 } 426 427 if (hwpart_str) { 428 hwpart = simple_strtoul(hwpart_str, &ep, 16); 429 if (*ep) { 430 printf("** Bad HW partition specification %s %s **\n", 431 ifname, hwpart_str); 432 dev = -EINVAL; 433 goto cleanup; 434 } 435 } 436 437 *dev_desc = get_dev_hwpart(ifname, dev, hwpart); 438 if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) { 439 printf("** Bad device %s %s **\n", ifname, dev_hwpart_str); 440 dev = -ENOENT; 441 goto cleanup; 442 } 443 444 #ifdef HAVE_BLOCK_DEVICE 445 /* 446 * Updates the partition table for the specified hw partition. 447 * Does not need to be done for hwpart 0 since it is default and 448 * already loaded. 449 */ 450 if(hwpart != 0) 451 part_init(*dev_desc); 452 #endif 453 454 cleanup: 455 free(dup_str); 456 return dev; 457 } 458 459 #define PART_UNSPECIFIED -2 460 #define PART_AUTO -1 461 int blk_get_device_part_str(const char *ifname, const char *dev_part_str, 462 struct blk_desc **dev_desc, 463 disk_partition_t *info, int allow_whole_dev) 464 { 465 int ret = -1; 466 const char *part_str; 467 char *dup_str = NULL; 468 const char *dev_str; 469 int dev; 470 char *ep; 471 int p; 472 int part; 473 disk_partition_t tmpinfo; 474 475 #ifdef CONFIG_SANDBOX 476 /* 477 * Special-case a pseudo block device "hostfs", to allow access to the 478 * host's own filesystem. 479 */ 480 if (0 == strcmp(ifname, "hostfs")) { 481 *dev_desc = NULL; 482 info->start = 0; 483 info->size = 0; 484 info->blksz = 0; 485 info->bootable = 0; 486 strcpy((char *)info->type, BOOT_PART_TYPE); 487 strcpy((char *)info->name, "Sandbox host"); 488 #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 489 info->uuid[0] = 0; 490 #endif 491 #ifdef CONFIG_PARTITION_TYPE_GUID 492 info->type_guid[0] = 0; 493 #endif 494 495 return 0; 496 } 497 #endif 498 499 #ifdef CONFIG_CMD_UBIFS 500 /* 501 * Special-case ubi, ubi goes through a mtd, rathen then through 502 * a regular block device. 503 */ 504 if (0 == strcmp(ifname, "ubi")) { 505 if (!ubifs_is_mounted()) { 506 printf("UBIFS not mounted, use ubifsmount to mount volume first!\n"); 507 return -1; 508 } 509 510 *dev_desc = NULL; 511 memset(info, 0, sizeof(*info)); 512 strcpy((char *)info->type, BOOT_PART_TYPE); 513 strcpy((char *)info->name, "UBI"); 514 #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 515 info->uuid[0] = 0; 516 #endif 517 return 0; 518 } 519 #endif 520 521 /* If no dev_part_str, use bootdevice environment variable */ 522 if (!dev_part_str || !strlen(dev_part_str) || 523 !strcmp(dev_part_str, "-")) 524 dev_part_str = env_get("bootdevice"); 525 526 /* If still no dev_part_str, it's an error */ 527 if (!dev_part_str) { 528 printf("** No device specified **\n"); 529 goto cleanup; 530 } 531 532 /* Separate device and partition ID specification */ 533 part_str = strchr(dev_part_str, ':'); 534 if (part_str) { 535 dup_str = strdup(dev_part_str); 536 dup_str[part_str - dev_part_str] = 0; 537 dev_str = dup_str; 538 part_str++; 539 } else { 540 dev_str = dev_part_str; 541 } 542 543 /* Look up the device */ 544 dev = blk_get_device_by_str(ifname, dev_str, dev_desc); 545 if (dev < 0) 546 goto cleanup; 547 548 /* Convert partition ID string to number */ 549 if (!part_str || !*part_str) { 550 part = PART_UNSPECIFIED; 551 } else if (!strcmp(part_str, "auto")) { 552 part = PART_AUTO; 553 } else { 554 /* Something specified -> use exactly that */ 555 part = (int)simple_strtoul(part_str, &ep, 16); 556 /* 557 * Less than whole string converted, 558 * or request for whole device, but caller requires partition. 559 */ 560 if (*ep || (part == 0 && !allow_whole_dev)) { 561 printf("** Bad partition specification %s %s **\n", 562 ifname, dev_part_str); 563 goto cleanup; 564 } 565 } 566 567 /* 568 * No partition table on device, 569 * or user requested partition 0 (entire device). 570 */ 571 if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) || 572 (part == 0)) { 573 if (!(*dev_desc)->lba) { 574 printf("** Bad device size - %s %s **\n", ifname, 575 dev_str); 576 goto cleanup; 577 } 578 579 /* 580 * If user specified a partition ID other than 0, 581 * or the calling command only accepts partitions, 582 * it's an error. 583 */ 584 if ((part > 0) || (!allow_whole_dev)) { 585 printf("** No partition table - %s %s **\n", ifname, 586 dev_str); 587 goto cleanup; 588 } 589 590 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 591 592 part_get_info_whole_disk(*dev_desc, info); 593 594 ret = 0; 595 goto cleanup; 596 } 597 598 /* 599 * Now there's known to be a partition table, 600 * not specifying a partition means to pick partition 1. 601 */ 602 if (part == PART_UNSPECIFIED) 603 part = 1; 604 605 /* 606 * If user didn't specify a partition number, or did specify something 607 * other than "auto", use that partition number directly. 608 */ 609 if (part != PART_AUTO) { 610 ret = part_get_info(*dev_desc, part, info); 611 if (ret) { 612 printf("** Invalid partition %d **\n", part); 613 goto cleanup; 614 } 615 } else { 616 /* 617 * Find the first bootable partition. 618 * If none are bootable, fall back to the first valid partition. 619 */ 620 part = 0; 621 for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 622 ret = part_get_info(*dev_desc, p, info); 623 if (ret) 624 continue; 625 626 /* 627 * First valid partition, or new better partition? 628 * If so, save partition ID. 629 */ 630 if (!part || info->bootable) 631 part = p; 632 633 /* Best possible partition? Stop searching. */ 634 if (info->bootable) 635 break; 636 637 /* 638 * We now need to search further for best possible. 639 * If we what we just queried was the best so far, 640 * save the info since we over-write it next loop. 641 */ 642 if (part == p) 643 tmpinfo = *info; 644 } 645 /* If we found any acceptable partition */ 646 if (part) { 647 /* 648 * If we searched all possible partition IDs, 649 * return the first valid partition we found. 650 */ 651 if (p == MAX_SEARCH_PARTITIONS + 1) 652 *info = tmpinfo; 653 } else { 654 printf("** No valid partitions found **\n"); 655 ret = -1; 656 goto cleanup; 657 } 658 } 659 if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) { 660 printf("** Invalid partition type \"%.32s\"" 661 " (expect \"" BOOT_PART_TYPE "\")\n", 662 info->type); 663 ret = -1; 664 goto cleanup; 665 } 666 667 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 668 669 ret = part; 670 goto cleanup; 671 672 cleanup: 673 free(dup_str); 674 return ret; 675 } 676 677 /* 678 * For android A/B system, we append the current slot suffix quietly, 679 * this takes over the responsibility of slot suffix appending from 680 * developer to framework. 681 */ 682 static int part_get_info_by_name_option(struct blk_desc *dev_desc, 683 const char *name, 684 disk_partition_t *info, 685 bool strict) 686 { 687 struct part_driver *part_drv; 688 char name_slot[32] = {0}; 689 int none_slot_try = 1; 690 int ret, i; 691 692 part_drv = part_driver_lookup_type(dev_desc); 693 if (!part_drv) 694 return -1; 695 696 if (strict) { 697 none_slot_try = 0; 698 strcpy(name_slot, name); 699 goto lookup; 700 } 701 702 #if defined(CONFIG_ANDROID_AB) || defined(CONFIG_SPL_AB) 703 char *name_suffix = (char *)name + strlen(name) - 2; 704 705 /* Fix can not find partition with suffix "_a" & "_b". If with them, clear */ 706 if (!memcmp(name_suffix, "_a", strlen("_a")) || 707 !memcmp(name_suffix, "_b", strlen("_b"))) 708 memset(name_suffix, 0, 2); 709 #endif 710 #if defined(CONFIG_ANDROID_AB) && !defined(CONFIG_SPL_BUILD) 711 /* 1. Query partition with A/B slot suffix */ 712 if (rk_avb_append_part_slot(name, name_slot)) 713 return -1; 714 #elif defined(CONFIG_SPL_AB) && defined(CONFIG_SPL_BUILD) 715 if (spl_ab_append_part_slot(dev_desc, name, name_slot)) 716 return -1; 717 #else 718 strcpy(name_slot, name); 719 #endif 720 lookup: 721 debug("## Query partition(%d): %s\n", none_slot_try, name_slot); 722 for (i = 1; i < part_drv->max_entries; i++) { 723 ret = part_drv->get_info(dev_desc, i, info); 724 if (ret != 0) { 725 /* no more entries in table */ 726 break; 727 } 728 if (strcmp(name_slot, (const char *)info->name) == 0) { 729 /* matched */ 730 return i; 731 } 732 } 733 734 /* 2. Query partition without A/B slot suffix if above failed */ 735 if (none_slot_try) { 736 none_slot_try = 0; 737 strcpy(name_slot, name); 738 goto lookup; 739 } 740 741 return -1; 742 } 743 744 int part_get_info_by_name(struct blk_desc *dev_desc, const char *name, 745 disk_partition_t *info) 746 { 747 return part_get_info_by_name_option(dev_desc, name, info, false); 748 } 749 750 int part_get_info_by_name_strict(struct blk_desc *dev_desc, const char *name, 751 disk_partition_t *info) 752 { 753 return part_get_info_by_name_option(dev_desc, name, info, true); 754 } 755 756 void part_set_generic_name(const struct blk_desc *dev_desc, 757 int part_num, char *name) 758 { 759 char *devtype; 760 761 switch (dev_desc->if_type) { 762 case IF_TYPE_IDE: 763 case IF_TYPE_SATA: 764 case IF_TYPE_ATAPI: 765 devtype = "hd"; 766 break; 767 case IF_TYPE_SCSI: 768 devtype = "sd"; 769 break; 770 case IF_TYPE_USB: 771 devtype = "usbd"; 772 break; 773 case IF_TYPE_DOC: 774 devtype = "docd"; 775 break; 776 case IF_TYPE_MMC: 777 case IF_TYPE_SD: 778 devtype = "mmcsd"; 779 break; 780 default: 781 devtype = "xx"; 782 break; 783 } 784 785 sprintf(name, "%s%c%d", devtype, 'a' + dev_desc->devnum, part_num); 786 } 787