1 /* 2 * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <malloc.h> 9 #include <asm/arch/vendor.h> 10 #include <boot_rkimg.h> 11 12 /* tag for vendor check */ 13 #define VENDOR_TAG 0x524B5644 14 /* The Vendor partition contains the number of Vendor blocks */ 15 #define VENDOR_PART_NUM 4 16 /* align to 64 bytes */ 17 #define VENDOR_BTYE_ALIGN 0x3F 18 #define VENDOR_BLOCK_SIZE 512 19 20 /* --- Emmc define --- */ 21 /* Starting address of the Vendor in memory. */ 22 #define EMMC_VENDOR_PART_OFFSET (1024 * 7) 23 /* 24 * The number of memory blocks used by each 25 * Vendor structure(128 * 512B = 64KB) 26 */ 27 #define EMMC_VENDOR_PART_BLKS 128 28 /* The maximum number of items in each Vendor block */ 29 #define EMMC_VENDOR_ITEM_NUM 126 30 31 /* --- Spi/Spi Nand/SLC/MLC define --- */ 32 /* The Vendor partition contains the number of Vendor blocks */ 33 #define FLASH_VENDOR_PART_OFFSET 8 34 /* 35 * The number of memory blocks used by each 36 * Vendor structure(8 * 512B = 4KB) 37 */ 38 #define FLASH_VENDOR_PART_BLKS 8 39 /* The maximum number of items in each Vendor block */ 40 #define FLASH_VENDOR_ITEM_NUM 62 41 42 /* Vendor uinit test define */ 43 int vendor_storage_test(void); 44 45 struct vendor_item { 46 u16 id; 47 u16 offset; 48 u16 size; 49 u16 flag; 50 }; 51 52 struct vendor_hdr { 53 u32 tag; 54 u32 version; 55 u16 next_index; 56 u16 item_num; 57 u16 free_offset; /* Free space offset */ 58 u16 free_size; /* Free space size */ 59 }; 60 61 /* 62 * Different types of Flash vendor info are different. 63 * EMMC:EMMC_VENDOR_PART_BLKS * BLOCK_SIZE(512) = 64KB; 64 * Spi Nor/Spi Nand/SLC/MLC: FLASH_VENDOR_PART_BLKS * 65 * BLOCK_SIZE(512) = 4KB. 66 * hash: For future expansion. 67 * version2: Together with hdr->version, it is used to 68 * ensure the current Vendor block content integrity. 69 * (version2 == hdr->version):Data valid; 70 * (version2 != hdr->version):Data invalid. 71 */ 72 struct vendor_info { 73 struct vendor_hdr *hdr; 74 struct vendor_item *item; 75 u8 *data; 76 u32 *hash; 77 u32 *version2; 78 }; 79 /* 80 * Calculate the offset of each field for emmc. 81 * Emmc vendor info size: 64KB 82 */ 83 #define EMMC_VENDOR_INFO_SIZE (EMMC_VENDOR_PART_BLKS * VENDOR_BLOCK_SIZE) 84 #define EMMC_VENDOR_DATA_OFFSET (sizeof(struct vendor_hdr) + EMMC_VENDOR_ITEM_NUM * sizeof(struct vendor_item)) 85 #define EMMC_VENDOR_HASH_OFFSET (EMMC_VENDOR_INFO_SIZE - 8) 86 #define EMMC_VENDOR_VERSION2_OFFSET (EMMC_VENDOR_INFO_SIZE - 4) 87 /* 88 * Calculate the offset of each field for spi nor/spi nand/slc/mlc. 89 * Flash vendor info size: 4KB 90 */ 91 #define FLASH_VENDOR_INFO_SIZE (FLASH_VENDOR_PART_BLKS * VENDOR_BLOCK_SIZE) 92 #define FLASH_VENDOR_DATA_OFFSET (sizeof(struct vendor_hdr) + FLASH_VENDOR_ITEM_NUM * sizeof(struct vendor_item)) 93 #define FLASH_VENDOR_HASH_OFFSET (FLASH_VENDOR_INFO_SIZE - 8) 94 #define FLASH_VENDOR_VERSION2_OFFSET (FLASH_VENDOR_INFO_SIZE - 4) 95 96 /* vendor info */ 97 static struct vendor_info vendor_info; 98 /* The storage type of the device */ 99 static int bootdev_type; 100 101 /**********************************************************/ 102 /* vendor API implementation */ 103 /**********************************************************/ 104 static int vendor_ops(u8 *buffer, u32 addr, u32 n_sec, int write) 105 { 106 struct blk_desc *dev_desc; 107 unsigned int lba = 0; 108 int ret = 0; 109 110 dev_desc = rockchip_get_bootdev(); 111 if (!dev_desc) { 112 printf("%s: dev_desc is NULL!\n", __func__); 113 return -ENODEV; 114 } 115 /* Get the offset address according to the device type */ 116 switch (dev_desc->if_type) { 117 case IF_TYPE_MMC: 118 /* 119 * The location of VendorStorage in Flash is shown in the 120 * following figure. The starting address of the VendorStorage 121 * partition is 3.5MB(EMMC_VENDOR_PART_OFFSET*BLOCK_SIZE(512)), 122 * and the partition size is 256KB. 123 * ---------------------------------------------------- 124 * | 3.5MB | VendorStorage | | 125 * ---------------------------------------------------- 126 */ 127 lba = EMMC_VENDOR_PART_OFFSET; 128 debug("[Vendor INFO]:VendorStorage offset address=0x%x\n", lba); 129 break; 130 case IF_TYPE_RKNAND: 131 case IF_TYPE_SPINOR: 132 case IF_TYPE_SPINAND: 133 /* 134 * The location of VendorStorage in Flash is shown in the 135 * following figure. The starting address of the VendorStorage 136 * partition is 4KB (FLASH_VENDOR_PART_OFFSET * BLOCK_SIZE), 137 * and the partition size is 16KB. 138 * ---------------------------------------------------- 139 * | 4KB | VendorStorage | | 140 * ---------------------------------------------------- 141 */ 142 lba = FLASH_VENDOR_PART_OFFSET; 143 debug("[Vendor INFO]:VendorStorage offset address=0x%x\n", lba); 144 break; 145 default: 146 printf("[Vendor ERROR]:Boot device type is invalid!\n"); 147 return -ENODEV; 148 } 149 if (write) 150 ret = blk_dwrite(dev_desc, lba + addr, n_sec, buffer); 151 else 152 ret = blk_dread(dev_desc, lba + addr, n_sec, buffer); 153 debug("[Vendor INFO]:op=%s, ret=%d\n", write ? "write" : "read", ret); 154 155 return ret; 156 } 157 158 /* 159 * The VendorStorage partition is divided into four parts 160 * (vendor 0-3) and its structure is shown in the following figure. 161 * The init function is used to select the latest and valid vendor. 162 * 163 * |******************** FLASH ********************| 164 * ------------------------------------------------- 165 * | vendor0 | vendor1 | vendor2 | vendor3 | 166 * ------------------------------------------------- 167 * Notices: 168 * 1. "version" and "version2" are used to verify that the vendor 169 * is valid (equal is valid). 170 * 2. the "version" value is larger, indicating that the current 171 * verndor data is new. 172 */ 173 int vendor_storage_init(void) 174 { 175 int ret = 0; 176 int ret_size; 177 u8 *buffer; 178 u32 size, i; 179 u32 max_ver = 0; 180 u32 max_index = 0; 181 u16 data_offset, hash_offset; 182 u16 version2_offset, part_size; 183 struct blk_desc *dev_desc; 184 185 dev_desc = rockchip_get_bootdev(); 186 if (!dev_desc) { 187 printf("[Vendor ERROR]:Invalid boot device type(%d)\n", 188 bootdev_type); 189 return -ENODEV; 190 } 191 192 switch (dev_desc->if_type) { 193 case IF_TYPE_MMC: 194 size = EMMC_VENDOR_INFO_SIZE; 195 part_size = EMMC_VENDOR_PART_BLKS; 196 data_offset = EMMC_VENDOR_DATA_OFFSET; 197 hash_offset = EMMC_VENDOR_HASH_OFFSET; 198 version2_offset = EMMC_VENDOR_VERSION2_OFFSET; 199 break; 200 case IF_TYPE_RKNAND: 201 case IF_TYPE_SPINOR: 202 case IF_TYPE_SPINAND: 203 size = FLASH_VENDOR_INFO_SIZE; 204 part_size = FLASH_VENDOR_PART_BLKS; 205 data_offset = FLASH_VENDOR_DATA_OFFSET; 206 hash_offset = FLASH_VENDOR_HASH_OFFSET; 207 version2_offset = FLASH_VENDOR_VERSION2_OFFSET; 208 break; 209 default: 210 debug("[Vendor ERROR]:Boot device type is invalid!\n"); 211 ret = -ENODEV; 212 break; 213 } 214 /* Invalid bootdev type */ 215 if (ret) 216 return ret; 217 218 /* Initialize */ 219 bootdev_type = dev_desc->if_type; 220 221 /* Always use, no need to release */ 222 buffer = (u8 *)malloc(size); 223 if (!buffer) { 224 printf("[Vendor ERROR]:Malloc failed!\n"); 225 return -ENOMEM; 226 } 227 /* Pointer initialization */ 228 vendor_info.hdr = (struct vendor_hdr *)buffer; 229 vendor_info.item = (struct vendor_item *)(buffer + sizeof(struct vendor_hdr)); 230 vendor_info.data = buffer + data_offset; 231 vendor_info.hash = (u32 *)(buffer + hash_offset); 232 vendor_info.version2 = (u32 *)(buffer + version2_offset); 233 234 /* Find valid and up-to-date one from (vendor0 - vendor3) */ 235 for (i = 0; i < VENDOR_PART_NUM; i++) { 236 ret_size = vendor_ops((u8 *)vendor_info.hdr, 237 part_size * i, part_size, 0); 238 if (ret_size != part_size) { 239 ret = -EIO; 240 goto out; 241 } 242 243 if ((vendor_info.hdr->tag == VENDOR_TAG) && 244 (*(vendor_info.version2) == vendor_info.hdr->version)) { 245 if (max_ver < vendor_info.hdr->version) { 246 max_index = i; 247 max_ver = vendor_info.hdr->version; 248 } 249 } 250 } 251 252 if (max_ver) { 253 debug("[Vendor INFO]:max_ver=%d, vendor_id=%d.\n", max_ver, max_index); 254 /* 255 * Keep vendor_info the same as the largest 256 * version of vendor 257 */ 258 if (max_index != (VENDOR_PART_NUM - 1)) { 259 ret_size = vendor_ops((u8 *)vendor_info.hdr, 260 part_size * max_index, part_size, 0); 261 if (ret_size != part_size) { 262 ret = -EIO; 263 goto out; 264 } 265 } 266 } else { 267 debug("[Vendor INFO]:Reset vendor info...\n"); 268 memset((u8 *)vendor_info.hdr, 0, size); 269 vendor_info.hdr->version = 1; 270 vendor_info.hdr->tag = VENDOR_TAG; 271 /* data field length */ 272 vendor_info.hdr->free_size = 273 ((u32)(size_t)vendor_info.hash 274 - (u32)(size_t)vendor_info.data); 275 *(vendor_info.version2) = vendor_info.hdr->version; 276 } 277 debug("[Vendor INFO]:ret=%d.\n", ret); 278 279 out: 280 return ret; 281 } 282 283 /* 284 * @id: item id, first 4 id is occupied: 285 * VENDOR_SN_ID 286 * VENDOR_WIFI_MAC_ID 287 * VENDOR_LAN_MAC_ID 288 * VENDOR_BLUETOOTH_ID 289 * @pbuf: read data buffer; 290 * @size: read bytes; 291 * 292 * return: bytes equal to @size is success, other fail; 293 */ 294 int vendor_storage_read(u16 id, void *pbuf, u16 size) 295 { 296 int ret = 0; 297 u32 i; 298 u16 offset; 299 struct vendor_item *item; 300 301 /* init vendor storage */ 302 if (!bootdev_type) { 303 ret = vendor_storage_init(); 304 if (ret < 0) 305 return ret; 306 } 307 308 item = vendor_info.item; 309 for (i = 0; i < vendor_info.hdr->item_num; i++) { 310 if ((item + i)->id == id) { 311 debug("[Vendor INFO]:Find the matching item, id=%d\n", id); 312 /* Correct the size value */ 313 if (size > (item + i)->size) 314 size = (item + i)->size; 315 offset = (item + i)->offset; 316 memcpy(pbuf, (vendor_info.data + offset), size); 317 return size; 318 } 319 } 320 debug("[Vendor ERROR]:No matching item, id=%d\n", id); 321 322 return -EINVAL; 323 } 324 325 /* 326 * @id: item id, first 4 id is occupied: 327 * VENDOR_SN_ID 328 * VENDOR_WIFI_MAC_ID 329 * VENDOR_LAN_MAC_ID 330 * VENDOR_BLUETOOTH_ID 331 * @pbuf: write data buffer; 332 * @size: write bytes; 333 * 334 * return: bytes equal to @size is success, other fail; 335 */ 336 int vendor_storage_write(u16 id, void *pbuf, u16 size) 337 { 338 int cnt, ret = 0; 339 u32 i, next_index, align_size; 340 struct vendor_item *item; 341 u16 part_size, max_item_num, offset; 342 343 /* init vendor storage */ 344 if (!bootdev_type) { 345 ret = vendor_storage_init(); 346 if (ret < 0) 347 return ret; 348 } 349 350 switch (bootdev_type) { 351 case IF_TYPE_MMC: 352 part_size = EMMC_VENDOR_PART_BLKS; 353 max_item_num = EMMC_VENDOR_ITEM_NUM; 354 break; 355 case IF_TYPE_RKNAND: 356 case IF_TYPE_SPINOR: 357 case IF_TYPE_SPINAND: 358 part_size = FLASH_VENDOR_PART_BLKS; 359 max_item_num = FLASH_VENDOR_ITEM_NUM; 360 break; 361 default: 362 ret = -ENODEV; 363 break; 364 } 365 /* Invalid bootdev? */ 366 if (ret < 0) 367 return ret; 368 369 next_index = vendor_info.hdr->next_index; 370 /* algin to 64 bytes*/ 371 align_size = (size + VENDOR_BTYE_ALIGN) & (~VENDOR_BTYE_ALIGN); 372 if (size > align_size) 373 return -EINVAL; 374 375 item = vendor_info.item; 376 /* If item already exist, update the item data */ 377 for (i = 0; i < vendor_info.hdr->item_num; i++) { 378 if ((item + i)->id == id) { 379 debug("[Vendor INFO]:Find the matching item, id=%d\n", id); 380 offset = (item + i)->offset; 381 memcpy((vendor_info.data + offset), pbuf, size); 382 (item + i)->size = size; 383 vendor_info.hdr->version++; 384 *(vendor_info.version2) = vendor_info.hdr->version; 385 vendor_info.hdr->next_index++; 386 if (vendor_info.hdr->next_index >= VENDOR_PART_NUM) 387 vendor_info.hdr->next_index = 0; 388 cnt = vendor_ops((u8 *)vendor_info.hdr, part_size * next_index, part_size, 1); 389 return (cnt == part_size) ? size : -EIO; 390 } 391 } 392 /* 393 * If item does not exist, and free size is enough, 394 * creat a new one 395 */ 396 if ((vendor_info.hdr->item_num < max_item_num) && 397 (vendor_info.hdr->free_size >= align_size)) { 398 debug("[Vendor INFO]:Create new Item, id=%d\n", id); 399 item = vendor_info.item + vendor_info.hdr->item_num; 400 item->id = id; 401 item->offset = vendor_info.hdr->free_offset; 402 item->size = size; 403 404 vendor_info.hdr->free_offset += align_size; 405 vendor_info.hdr->free_size -= align_size; 406 memcpy((vendor_info.data + item->offset), pbuf, size); 407 vendor_info.hdr->item_num++; 408 vendor_info.hdr->version++; 409 vendor_info.hdr->next_index++; 410 *(vendor_info.version2) = vendor_info.hdr->version; 411 if (vendor_info.hdr->next_index >= VENDOR_PART_NUM) 412 vendor_info.hdr->next_index = 0; 413 414 cnt = vendor_ops((u8 *)vendor_info.hdr, part_size * next_index, part_size, 1); 415 return (cnt == part_size) ? size : -EIO; 416 } 417 debug("[Vendor ERROR]:Vendor has no space left!\n"); 418 419 return -ENOMEM; 420 } 421 422 /**********************************************************/ 423 /* vendor API uinit test */ 424 /**********************************************************/ 425 /* Reset the vendor storage space to the initial state */ 426 static void vendor_test_reset(void) 427 { 428 u16 i, part_size; 429 u32 size; 430 431 switch (bootdev_type) { 432 case IF_TYPE_MMC: 433 size = EMMC_VENDOR_INFO_SIZE; 434 part_size = EMMC_VENDOR_PART_BLKS; 435 break; 436 case IF_TYPE_RKNAND: 437 case IF_TYPE_SPINOR: 438 case IF_TYPE_SPINAND: 439 size = FLASH_VENDOR_INFO_SIZE; 440 part_size = FLASH_VENDOR_PART_BLKS; 441 break; 442 default: 443 size = 0; 444 part_size = 0; 445 break; 446 } 447 /* Invalid bootdev? */ 448 if (!size) 449 return; 450 451 memset((u8 *)vendor_info.hdr, 0, size); 452 vendor_info.hdr->version = 1; 453 vendor_info.hdr->tag = VENDOR_TAG; 454 /* data field length */ 455 vendor_info.hdr->free_size = (unsigned long)vendor_info.hash - 456 (unsigned long)vendor_info.data; 457 *(vendor_info.version2) = vendor_info.hdr->version; 458 /* write to flash. */ 459 for (i = 0; i < VENDOR_PART_NUM; i++) 460 vendor_ops((u8 *)vendor_info.hdr, part_size * i, part_size, 1); 461 } 462 463 /* 464 * A total of four tests 465 * 1.All items test. 466 * 2.Overrides the maximum number of items test. 467 * 3.Single Item memory overflow test. 468 * 4.Total memory overflow test. 469 */ 470 int vendor_storage_test(void) 471 { 472 u16 id, size, j, item_num; 473 u32 total_size; 474 u8 *buffer = NULL; 475 int ret = 0; 476 477 if (!bootdev_type) { 478 ret = vendor_storage_init(); 479 if (ret) { 480 printf("%s: vendor storage init failed, ret=%d\n", 481 __func__, ret); 482 return ret; 483 } 484 } 485 486 /* 487 * Calculate the maximum number of items and the maximum 488 * allocable memory for each item. 489 */ 490 switch (bootdev_type) { 491 case IF_TYPE_MMC: 492 item_num = EMMC_VENDOR_ITEM_NUM; 493 total_size = (unsigned long)vendor_info.hash - 494 (unsigned long)vendor_info.data; 495 size = total_size/item_num; 496 break; 497 case IF_TYPE_RKNAND: 498 case IF_TYPE_SPINOR: 499 case IF_TYPE_SPINAND: 500 item_num = FLASH_VENDOR_ITEM_NUM; 501 total_size = (unsigned long)vendor_info.hash - 502 (unsigned long)vendor_info.data; 503 size = total_size/item_num; 504 break; 505 default: 506 total_size = 0; 507 break; 508 } 509 /* Invalid bootdev? */ 510 if (!total_size) 511 return -ENODEV; 512 /* 64 bytes are aligned and rounded down */ 513 size = (size/64)*64; 514 /* malloc memory */ 515 buffer = (u8 *)malloc(size); 516 if (!buffer) { 517 printf("[Vendor Test]:Malloc failed(size=%d)!\n", size); 518 return -ENOMEM; 519 } 520 printf("[Vendor Test]:Test Start...\n"); 521 printf("[Vendor Test]:Before Test, Vendor Resetting.\n"); 522 vendor_test_reset(); 523 524 /* FIRST TEST: test all items can be used correctly */ 525 printf("[Vendor Test]:<All Items Used> Test Start...\n"); 526 printf("[Vendor Test]:item_num=%d, size=%d.\n", 527 item_num, size); 528 /* 529 * Write data, then read the data, and compare the 530 * data consistency 531 */ 532 for (id = 0; id < item_num; id++) { 533 memset(buffer, id, size); 534 ret = vendor_storage_write(id, buffer, size); 535 if (ret < 0) { 536 printf("[Vendor Test]:vendor write failed(id=%d)!\n", id); 537 free(buffer); 538 return ret; 539 } 540 } 541 /* Read data */ 542 for (id = 0; id < item_num; id++) { 543 memset(buffer, 0, size); 544 ret = vendor_storage_read(id, buffer, size); 545 if (ret < 0) { 546 printf("[Vendor Test]:vendor read failed(id=%d)!\n", id); 547 free(buffer); 548 return ret; 549 } 550 /* check data Correctness */ 551 for (j = 0; j < size; j++) { 552 if (*(buffer + j) != id) { 553 printf("[Vendor Test]:Unexpected error occurs(id=%d)\n", id); 554 printf("the data content is:\n"); 555 print_buffer(0, buffer, 1, size, 16); 556 557 free(buffer); 558 return -1; 559 } 560 } 561 debug("\t#id=%03d success,data=0x%02x,size=%d.\n", id, *buffer, size); 562 } 563 printf("[Vendor Test]:<All Items Used> Test End,States:OK\n"); 564 565 /* 566 * SECOND TEST: Overrides the maximum number of items to see if the 567 * return value matches the expectation 568 */ 569 printf("[Vendor Test]:<Overflow Items Cnt> Test Start...\n"); 570 /* Any id value that was not used before */ 571 id = item_num; 572 printf("[Vendor Test]:id=%d, size=%d.\n", id, size); 573 ret = vendor_storage_write(id, buffer, size); 574 if (ret == -ENOMEM) 575 printf("[Vendor Test]:<Overflow Items Cnt> Test End,States:OK\n"); 576 else 577 printf("[Vendor Test]:<Overflow Items Cnt> Test End,States:Failed\n"); 578 579 /* free buffer, remalloc later */ 580 free(buffer); 581 buffer = NULL; 582 /* 583 * remalloc memory and recalculate size to test memory overflow 584 * (1) item_num > 10: Memory is divided into 10 blocks, 585 * 11th memory will overflow. 586 * (2) 10 > item_num > 1: Memory is divided into item_num-1 587 * blocks. item_num block, memory will overflow. 588 * (3) item_num = 1: size = total_size + 512 Bytes, The first 589 * block, memory will overflow. 590 * The reason to do so is to minimize the size of the memory, 591 * making malloc easier to perform successfully. 592 */ 593 item_num = (item_num > 10) ? 10 : (item_num - 1); 594 size = item_num ? (total_size / item_num) : (total_size + 512); 595 size = (size + VENDOR_BTYE_ALIGN) & (~VENDOR_BTYE_ALIGN); 596 /* Find item_num value that can make the memory overflow */ 597 for (id = 0; id <= item_num; id++) { 598 if (((id + 1) * size) > total_size) { 599 item_num = id; 600 break; 601 } 602 } 603 /* malloc */ 604 buffer = (u8 *)malloc(size); 605 if (buffer == NULL) { 606 printf("[Vendor Test]:Malloc failed(size=%d)!\n", size); 607 return -ENOMEM; 608 } 609 610 /* THIRD TEST: Single Item memory overflow test */ 611 printf("[Vendor Test]:<Single Item Memory Overflow> Test Start...\n"); 612 /* The value can be arbitrary */ 613 memset(buffer, 'a', size); 614 /* Any id value that was used before */ 615 id = 0; 616 printf("[Vendor Test]:id=%d, size=%d.\n", id, size); 617 ret = vendor_storage_write(id, buffer, size); 618 if (ret == size) 619 printf("[Vendor Test]:<Single Item Memory Overflow> Test End, States:OK\n"); 620 else 621 printf("[Vendor Test]:<Single Item Memory Overflow> Test End, States:Failed\n"); 622 623 /* FORTH TEST: Total memory overflow test */ 624 printf("[Vendor Test]:<Total memory overflow> Test Start...\n"); 625 printf("[Vendor Test]:item_num=%d, size=%d.\n", item_num, size); 626 627 vendor_test_reset(); 628 for (id = 0; id <= item_num; id++) { 629 memset(buffer, id, size); 630 ret = vendor_storage_write(id, buffer, size); 631 if (ret < 0) { 632 if ((id == item_num) && (ret == -ENOMEM)) { 633 printf("[Vendor Test]:<Total memory overflow> Test End, States:OK\n"); 634 break; 635 } else { 636 printf("[Vendor Test]:<Total memory overflow> Test End, States:Failed\n"); 637 break; 638 } 639 } 640 debug("\t#id=%03d success,data=0x%02x,size=%d.\n", id, *buffer, size); 641 } 642 643 /* Test end */ 644 printf("[Vendor Test]:After Test, Vendor Resetting...\n"); 645 vendor_test_reset(); 646 printf("[Vendor Test]:Test End.\n"); 647 free(buffer); 648 649 return 0; 650 } 651