From a3090936c7c1799d8d71f59eaeebe32f11a25b5e Mon Sep 17 00:00:00 2001 From: iagranat <47638460+iagranat@users.noreply.github.com> Date: Tue, 16 Apr 2024 11:25:24 +0300 Subject: [PATCH 01/26] Allow HEX/S19 file size up to 256M --- MotorolaFile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MotorolaFile.c b/MotorolaFile.c index b276b36..fce4b31 100755 --- a/MotorolaFile.c +++ b/MotorolaFile.c @@ -110,8 +110,8 @@ bool S19FileToBin(const char* filePath, unsigned char* vData, unsigned long* Fil FILE* Filin; /* input files */ /* size in bytes */ - const long MEMORY_SIZE = 1024 * 1024 * 4; - const long ADDRESS_MASK = 0x003FFFFF; + const long MEMORY_SIZE = 1024 * 1024 * 256; + const long ADDRESS_MASK = 0xFFFFFFFF; const int MAX_LINE_SIZE = 512; const int CKS_8 = 0; From b48d74213943f6035cf9d4410f65ceac2ed40d85 Mon Sep 17 00:00:00 2001 From: Willy Hsiao Date: Wed, 24 Apr 2024 23:05:16 +0800 Subject: [PATCH 02/26] Add macOS compatibility - Changed where to find `ChipInfoDb.dedicfg` file when built on macOS - Allow longer path length --- parse.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/parse.c b/parse.c index d119979..fc190aa 100755 --- a/parse.c +++ b/parse.c @@ -5,6 +5,7 @@ #include #include +#define pathbufsize 1024 #define testbufsize 256 #define linebufsize 512 #define filebufsize 1024 * 1024 @@ -14,12 +15,13 @@ //using namespace pugi; //xml_document doc; +#ifdef __linux__ FILE* openChipInfoDb(void) { FILE* fp = NULL; - char Path[linebufsize]; + char Path[pathbufsize]; - memset(Path, 0, linebufsize); + memset(Path, 0, pathbufsize); if (readlink("/proc/self/exe", Path, 512) != -1) { dirname(Path); strcat(Path, "/ChipInfoDb.dedicfg"); @@ -41,6 +43,32 @@ FILE* openChipInfoDb(void) return fp; } +#endif + +#ifdef __APPLE__ +FILE* openChipInfoDb(void) +{ + FILE* fp = NULL; + char Path[pathbufsize]; + uint32_t size = sizeof(Path); + + memset(Path, 0, pathbufsize); + if (_NSGetExecutablePath(Path, &size) == 0) { + strcpy(Path, dirname(Path)); + strcat(Path, "/ChipInfoDb.dedicfg"); + if ((fp = fopen(Path, "rt")) == NULL) { + // ChipInfoDb.dedicfg not in program directory + strcpy(Path, dirname(Path)); + strcpy(Path, dirname(Path)); + strcat(Path, "/share/DediProg/ChipInfoDb.dedicfg"); + if ((fp = fopen(Path, "rt")) == NULL) + fprintf(stderr, "Error opening file: %s\n", Path); + } + } + + return fp; +} +#endif long fsize(FILE* fp) { From 25e8c97c27012e10978c082aa0b189ed8ca965a4 Mon Sep 17 00:00:00 2001 From: Benwang217 Date: Fri, 10 May 2024 11:53:25 +0800 Subject: [PATCH 03/26] Update ChipInfoDb.dedicfg Add MS25UM51345G --- ChipInfoDb.dedicfg | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ChipInfoDb.dedicfg b/ChipInfoDb.dedicfg index b78899a..1c3bf6c 100644 --- a/ChipInfoDb.dedicfg +++ b/ChipInfoDb.dedicfg @@ -25746,6 +25746,32 @@ RDIDCommand="0x9F"/> ManufactureID="0x34" UniqueID="0x342A1A"/> + + Date: Tue, 28 May 2024 13:44:29 +0800 Subject: [PATCH 04/26] Update ChipInfoDb.dedicfg Add W25Q512NM-IQ --- ChipInfoDb.dedicfg | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ChipInfoDb.dedicfg b/ChipInfoDb.dedicfg index 1c3bf6c..9d13746 100644 --- a/ChipInfoDb.dedicfg +++ b/ChipInfoDb.dedicfg @@ -25081,6 +25081,26 @@ RDIDCommand="0x9F"/> IDNumber="3" RDIDCommand="0x9F"/> + + Date: Tue, 28 May 2024 14:36:09 +0800 Subject: [PATCH 05/26] Update ChipInfoDb.dedicfg --- ChipInfoDb.dedicfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChipInfoDb.dedicfg b/ChipInfoDb.dedicfg index 9d13746..936af99 100644 --- a/ChipInfoDb.dedicfg +++ b/ChipInfoDb.dedicfg @@ -8,7 +8,7 @@ - +Fw25q Class="W25Pxx_Large" UniqueID="0xEF6020" Description="512 Mbit, Low Voltage, Serial Flash Memory With 166MHz SPI Bus Interface" - Manufacturer="Winbond Electronics Corp + Manufacturer="Winbond Electronics Corp" ManufactureUrl="http://www.winbond.com/" Voltage="1.8V" Clock="166Mhz" From 290a7c2ad1f462c255a588033c3c96f90c4c0115 Mon Sep 17 00:00:00 2001 From: Benwang217 Date: Tue, 28 May 2024 16:26:02 +0800 Subject: [PATCH 06/26] Update ChipInfoDb.dedicfg Change W25Q512NW class to S25FLxxx_Large --- ChipInfoDb.dedicfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChipInfoDb.dedicfg b/ChipInfoDb.dedicfg index 936af99..51cd58f 100644 --- a/ChipInfoDb.dedicfg +++ b/ChipInfoDb.dedicfg @@ -25063,7 +25063,7 @@ RDIDCommand="0x9F"/> Date: Thu, 27 Jun 2024 13:25:49 +0800 Subject: [PATCH 07/26] Update ChipInfoDb.dedicfg --- ChipInfoDb.dedicfg | 1 - 1 file changed, 1 deletion(-) diff --git a/ChipInfoDb.dedicfg b/ChipInfoDb.dedicfg index 51cd58f..0aee655 100644 --- a/ChipInfoDb.dedicfg +++ b/ChipInfoDb.dedicfg @@ -8,7 +8,6 @@ -Fw25q Date: Mon, 8 Jul 2024 11:55:54 +0200 Subject: [PATCH 08/26] Disable forcing of default compiler --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 139e5c0..226303a 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ endif endif PROGRAM = dpcmd -CC = gcc +CC ?= gcc PREFIX ?= /usr/local PKG_CONFIG ?= pkg-config From 436ac5c0664e8e8529b72d19aa4f88f41ab9f419 Mon Sep 17 00:00:00 2001 From: Justin Katerberg Date: Thu, 11 Jul 2024 15:40:27 -0400 Subject: [PATCH 09/26] Fix flashing with muliple dediprogs --- dpcmd.c | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/dpcmd.c b/dpcmd.c index ec4d1cd..44d2cb1 100644 --- a/dpcmd.c +++ b/dpcmd.c @@ -546,27 +546,6 @@ int main(int argc, char* argv[]) g_usb_busnum = (unsigned char)r; } - // Filter by DP Device num, same as setting --device flag - // Only touches target device since it is before OpenUSB() - env = getenv("DPCMD_DEVNUM"); - if (env) { - r = strtoul(env, NULL, 10); - if (r == ULONG_MAX || r >= 256) { - fprintf(stderr, "E: invalid device number in" - " DPCMD_DEVNUM\n"); - return 1; - } - g_uiDevNum = (unsigned char)r; - bDevice = true; - } - - - if (OpenUSB() == 0) - iExitCode = EXCODE_FAIL_USB; - - LeaveStandaloneMode(0); - QueryBoard(0); - while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { switch (c) { case '?': @@ -752,6 +731,12 @@ int main(int argc, char* argv[]) } } + if (OpenUSB() == 0) + iExitCode = EXCODE_FAIL_USB; + + LeaveStandaloneMode(0); + QueryBoard(0); + int dev_cnt = get_usb_dev_cnt(); if (CheckProgrammerInfo()) { @@ -1113,7 +1098,8 @@ void sin_handler(int sig) int Handler(void) { - if (Is_usbworking(0) == true) { + //if (Is_usbworking(0) == true) { + if (Is_usbworking(g_uiDevNum - 1) == true) { #if 0 if(m_vm.count("fix-device")) { @@ -1123,7 +1109,6 @@ int Handler(void) AssignedDevice(); #endif - if ((g_ucOperation & BLINK) == BLINK) { BlinkProgrammer(); return EXCODE_PASS; @@ -1173,7 +1158,7 @@ bool InitProject(void) { //printf("bool InitProject(void)\n"); int dev_cnt = get_usb_dev_cnt(); - if (Is_usbworking(0)) { + if (Is_usbworking(g_uiDevNum-1)) { int targets[4] = { STARTUP_APPLI_CARD, STARTUP_APPLI_SF_1, @@ -1246,7 +1231,7 @@ void CloseProject(void) bool DetectChip(void) { int dev_cnt = get_usb_dev_cnt(); - Chip_Info = GetFirstDetectionMatch(strTypeName, 0); + Chip_Info = GetFirstDetectionMatch(strTypeName, g_uiDevNum-1); if (g_uiDevNum == 0) { for (int i = 0; i < dev_cnt; i++) { if (!Is_usbworking(i)) { From 55b40139f4837e242a6a79cfa5aa17c9888ed84c Mon Sep 17 00:00:00 2001 From: Tymoteusz Burak Date: Mon, 22 Jul 2024 15:05:30 +0200 Subject: [PATCH 10/26] Makefile: add conditional stripping This patch introduces a `NOSTRIP` conditional flag to the `install` target in the Makefile. The purpose of this flag is to allow the disabling of binary stripping during installation. This is particularly useful in development environments, such as BitBake, which handle stripping internally. When `NOSTRIP` is set to `1`, the `strip` command will be skipped during the installation process, preventing potential conflicts or redundant operations. Signed-off-by: Tymoteusz Burak --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 139e5c0..8b33320 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,9 @@ install: $(PROGRAM) [ $(shell id -u) -eq 0 ] || (echo "Error: install needs root privileges" && false) install -v -o 0 -g 0 -m 755 -d $(DESTDIR)$(PREFIX)/bin $(DESTDIR)$(PREFIX)/share/DediProg echo -n "install: " && install -v -o 0 -g 0 -m 0755 $(PROGRAM) $(DESTDIR)$(PREFIX)/bin/$(PROGRAM) +ifneq ($(NOSTRIP),1) strip $(DESTDIR)$(PREFIX)/bin/$(PROGRAM) +endif install -v -o 0 -g 0 -m 755 -d $(DESTDIR)$(PREFIX)/share/DediProg echo -n "install: " && install -v -o 0 -g 0 -m 0644 ChipInfoDb.dedicfg $(DESTDIR)$(PREFIX)/share/DediProg/ChipInfoDb.dedicfg install -v -o 0 -g 0 -m 755 -d $(DESTDIR)/etc/udev/rules.d From 7fd01ee6a6b6a5ecb02899bb5d8e8187d4cf3973 Mon Sep 17 00:00:00 2001 From: Benwang217 Date: Fri, 13 Sep 2024 09:31:43 +0800 Subject: [PATCH 11/26] Update dpcmd.c restore from #87 --- dpcmd.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dpcmd.c b/dpcmd.c index 44d2cb1..5851a90 100644 --- a/dpcmd.c +++ b/dpcmd.c @@ -1098,8 +1098,8 @@ void sin_handler(int sig) int Handler(void) { - //if (Is_usbworking(0) == true) { - if (Is_usbworking(g_uiDevNum - 1) == true) { + if (Is_usbworking(0) == true) { + //if (Is_usbworking(g_uiDevNum - 1) == true) { #if 0 if(m_vm.count("fix-device")) { @@ -1158,7 +1158,8 @@ bool InitProject(void) { //printf("bool InitProject(void)\n"); int dev_cnt = get_usb_dev_cnt(); - if (Is_usbworking(g_uiDevNum-1)) { +if (Is_usbworking(0) == true) { +// if (Is_usbworking(g_uiDevNum-1)) { int targets[4] = { STARTUP_APPLI_CARD, STARTUP_APPLI_SF_1, @@ -1231,7 +1232,7 @@ void CloseProject(void) bool DetectChip(void) { int dev_cnt = get_usb_dev_cnt(); - Chip_Info = GetFirstDetectionMatch(strTypeName, g_uiDevNum-1); + Chip_Info = GetFirstDetectionMatch(strTypeName, 0); if (g_uiDevNum == 0) { for (int i = 0; i < dev_cnt; i++) { if (!Is_usbworking(i)) { From 11c3d01ccbd51c831792bd995ac7283afd9fbf2c Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Tue, 8 Oct 2024 13:39:03 -0400 Subject: [PATCH 12/26] Initial FreeBSD build support openChipInfoDb is mostly a copy of the __APPLE__ version for now. --- dpcmd.c | 1 + parse.c | 11 +++++++++-- usbdriver.c | 4 ++++ usbdriver.h | 4 ++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/dpcmd.c b/dpcmd.c index 5851a90..2fcb3d0 100644 --- a/dpcmd.c +++ b/dpcmd.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/parse.c b/parse.c index fc190aa..cd18c77 100755 --- a/parse.c +++ b/parse.c @@ -4,6 +4,9 @@ #include #include #include +#ifdef __FreeBSD__ +#include +#endif #define pathbufsize 1024 #define testbufsize 256 @@ -15,7 +18,7 @@ //using namespace pugi; //xml_document doc; -#ifdef __linux__ +#if defined(__linux__) FILE* openChipInfoDb(void) { FILE* fp = NULL; @@ -45,7 +48,7 @@ FILE* openChipInfoDb(void) } #endif -#ifdef __APPLE__ +#if defined(__APPLE__) || defined(__FreeBSD__) FILE* openChipInfoDb(void) { FILE* fp = NULL; @@ -53,7 +56,11 @@ FILE* openChipInfoDb(void) uint32_t size = sizeof(Path); memset(Path, 0, pathbufsize); +#if defined(__APPLE__) if (_NSGetExecutablePath(Path, &size) == 0) { +#else + if (elf_aux_info(AT_EXECPATH, Path, size) == 0) { +#endif strcpy(Path, dirname(Path)); strcat(Path, "/ChipInfoDb.dedicfg"); if ((fp = fopen(Path, "rt")) == NULL) { diff --git a/usbdriver.c b/usbdriver.c index 62bc35c..13e5e37 100755 --- a/usbdriver.c +++ b/usbdriver.c @@ -1,7 +1,11 @@ #include "usbdriver.h" #include "FlashCommand.h" #include "project.h" +#ifdef __FreeBSD__ +#include +#else #include +#endif #include unsigned int m_nbDeviceDetected = 0; diff --git a/usbdriver.h b/usbdriver.h index e5862d4..1553f50 100755 --- a/usbdriver.h +++ b/usbdriver.h @@ -3,7 +3,11 @@ #ifndef DEDI_USB_DRIVER #define DEDI_USB_DRIVER +#ifdef __FreeBSD__ +#include +#else #include +#endif #include #include #include From 56ca673ba38ec7e1585ce232d30f6d339b12d337 Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Tue, 8 Oct 2024 13:49:23 -0400 Subject: [PATCH 13/26] Print actual OS name, not always Linux --- dpcmd.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/dpcmd.c b/dpcmd.c index 2fcb3d0..8df9506 100644 --- a/dpcmd.c +++ b/dpcmd.c @@ -502,7 +502,17 @@ int main(int argc, char* argv[]) unsigned long r; char* env; - printf("\nDpCmd Linux 1.14.20.%02d Engine Version:\nLast Built on %s\n\n", GetConfigVer(), __DATE__); // 1. new feature.bug.configS + printf("\nDpCmd %s 1.14.20.%02d Engine Version:\nLast Built on %s\n\n", +#if defined(__APPLE__) + "macOS", +#elif defined(__FreeBSD__) + "FreeBSD", +#elif defined(__linux__) + "Linux", +#else + "Unknown", +#endif + GetConfigVer(), __DATE__); // 1. new feature.bug.configS g_ucOperation = 0; GetLogPath(g_LogPath); From 5fe3eb602c487a806e4f7155c3f0945fe5a0a52e Mon Sep 17 00:00:00 2001 From: Jon Date: Wed, 23 Oct 2024 16:09:57 -0500 Subject: [PATCH 14/26] Add a FreeBSD check around including the sys/limits.h file --- dpcmd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dpcmd.c b/dpcmd.c index 8df9506..bb1f2ef 100644 --- a/dpcmd.c +++ b/dpcmd.c @@ -10,7 +10,9 @@ #include #include #include +#ifdef __FreeBSD__ #include +#endif #include #include #include From c75fbd53778d9562a094a5445f56f6858c1a4c71 Mon Sep 17 00:00:00 2001 From: Jon Date: Wed, 23 Oct 2024 16:11:05 -0500 Subject: [PATCH 15/26] Update readme to indicate that pkg-config is required for linking --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3584add..2f8cca4 100755 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ Linux software for Dediprog SF100 and SF600 SPI flash programmers ## Building To compile the project, first install required dependencies: - libusb-1.0 + - pkg-config - won't link to libusb without this package Change to the directory where the sources are located and build using make: ```bash From e9416f6d25d9effa063fc02a623794af64f265ef Mon Sep 17 00:00:00 2001 From: Benwang217 Date: Thu, 14 Nov 2024 10:02:37 +0800 Subject: [PATCH 16/26] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 2f8cca4..23397ac 100755 --- a/README.md +++ b/README.md @@ -11,6 +11,10 @@ Change to the directory where the sources are located and build using make: $ cd SF100Linux $ make ``` +or use +```bash +$ make install +``` The resulting binary should be called `dpcmd` and located in the root of the source tree. There is no install target at the moment. From 42edbcc60217f3fb39d5c6e5a68bedaa32844482 Mon Sep 17 00:00:00 2001 From: Benwang217 Date: Thu, 14 Nov 2024 16:04:57 +0800 Subject: [PATCH 17/26] Update dpcmd.c Change version --- dpcmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpcmd.c b/dpcmd.c index bb1f2ef..9031beb 100644 --- a/dpcmd.c +++ b/dpcmd.c @@ -504,7 +504,7 @@ int main(int argc, char* argv[]) unsigned long r; char* env; - printf("\nDpCmd %s 1.14.20.%02d Engine Version:\nLast Built on %s\n\n", + printf("\nDpCmd %s 1.14.21.%02d Engine Version:\nLast Built on %s\n\n", #if defined(__APPLE__) "macOS", #elif defined(__FreeBSD__) From 8777b9cacd95ce541e1d8d2dd885aff9bdcc2975 Mon Sep 17 00:00:00 2001 From: Benwang217 Date: Thu, 14 Nov 2024 16:33:17 +0800 Subject: [PATCH 18/26] Update project.c Fix programmer SN display issue --- project.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project.c b/project.c index 79dbbc3..3b31633 100755 --- a/project.c +++ b/project.c @@ -859,9 +859,9 @@ void threadRun(void* Type) if (g_uiAddr == 0 && g_uiLen == 0) { if(is_SF700_Or_SF600PG2(Index)){ if (g_bIsSF700[Index] == true) - printf("\nDevice %d (SF7%05X):", Index + 1, dwUID); + printf("\nDevice %d (SF7%05d):", Index + 1, dwUID); else if (g_bIsSF600PG2[Index] == true) - printf("\nDevice %d (S6%05X):", Index + 1, dwUID); + printf("\nDevice %d (S6B%05d):", Index + 1, dwUID); } else { if ((dwUID / 600000) == 0) From 3c93e575f6c5763f206ba547ec7446d5832ceb09 Mon Sep 17 00:00:00 2001 From: Benwang217 Date: Wed, 26 Feb 2025 10:36:59 +0800 Subject: [PATCH 19/26] 1. Synchronize Linux chip database with Windows(UTF16) 2. Using libxml-2.0 to resolve chip database 3. Support SPI NAND --- ChipInfoDb.h | 3 +- FlashCommand.c | 91 +++ FlashCommand.h | 3 + Macro.h | 281 +++++++-- Makefile | 4 +- README.md | 1 + SerialFlash.c | 1642 +++++++++++++++++++++++++++++++++++++++++++++--- SerialFlash.h | 22 + dpcmd.c | 599 +++++++++++++++--- dpcmd.h | 27 +- parse.c | 658 ++++++++++++++++++- project.c | 703 +++++++++++++++++---- project.h | 9 + usbdriver.c | 16 +- usbdriver.h | 2 + 15 files changed, 3709 insertions(+), 352 deletions(-) diff --git a/ChipInfoDb.h b/ChipInfoDb.h index 8def8e1..f4ded47 100755 --- a/ChipInfoDb.h +++ b/ChipInfoDb.h @@ -28,6 +28,7 @@ int Dedi_Search_Chip_Db(long RDIDCommand, long UniqueID, CHIP_INFO* Chip_Info, i int Dedi_Search_Chip_Db(char* TypeName, long RDIDCommand, long UniqueID, CHIP_INFO* Chip_Info, int search_all); #endif int Dedi_Search_Chip_Db_ByTypeName(char* TypeName, CHIP_INFO* Chip_Info); -FILE* openChipInfoDb(void); +//FILE* openChipInfoDb(void); +bool GetChipDbPath(char *Path); #endif diff --git a/FlashCommand.c b/FlashCommand.c index 02bcb28..838d783 100755 --- a/FlashCommand.c +++ b/FlashCommand.c @@ -232,3 +232,94 @@ int FlashCommand_SendCommand_SetupPacketForBulkRead(struct CAddressRange* AddrRa // send rq via control pipe return OutCtrlRequest(&rq, vInstruction, rq.Length, Index); } + +int FlashCommand_SendCommand_SetupPacketForBulkReadNAND(unsigned int dwAddr, unsigned int PageNum, unsigned char modeRead,WORD pageSize, WORD blockPages, unsigned char ReadCom,unsigned char AddrLen, unsigned char ReadDummyLen,unsigned char nCA, int USBIndex) +{ + unsigned char vInstruction[18]; + vInstruction[0]=(dwAddr & 0xff) ; + vInstruction[1]=((dwAddr>>8) & 0xff); + vInstruction[2]=((dwAddr>>16) & 0xff); + vInstruction[3]=((dwAddr>>24) & 0xff); + + //dwLength + vInstruction[4]=((unsigned char)(PageNum & 0xff)); // lowest byte of length : page number + vInstruction[5]=((unsigned char)( (PageNum >> 8) & 0xff)); // highest byte of length: page number + vInstruction[6]=((unsigned char)( (PageNum >> 16) & 0xff) ); + vInstruction[7]=((unsigned char)( (PageNum >> 24) & 0xff) ); + + //dwMode + vInstruction[8]=(modeRead); + vInstruction[9]=(modeRead>>8); + + //pagesize + vInstruction[10]=((unsigned char)(pageSize)); + vInstruction[11]=((unsigned char)(pageSize>>8)); + + //blockpages + vInstruction[12]=((unsigned char)(blockPages)); + vInstruction[13]=((unsigned char)(blockPages>>8)); + + vInstruction[14]=((unsigned char)(ReadCom));//cmd + + vInstruction[15]=((unsigned char)AddrLen);//addrLen + + vInstruction[16]=((unsigned char)(ReadDummyLen)); + + vInstruction[17]=((unsigned char)nCA); + + CNTRPIPE_RQ rq ; + rq.Function = URB_FUNCTION_VENDOR_ENDPOINT ; + rq.Direction = VENDOR_DIRECTION_OUT ; + rq.Request = DTC_READ_NAND ; + rq.Value = 0 ; + rq.Index = 0 ; + rq.Length = (unsigned long)(sizeof(vInstruction)) ;//40 + + // send rq via control pipe + return OutCtrlRequest(&rq, vInstruction,rq.Length,USBIndex); +} + +bool FlashCommand_SendCommand_SetupPacketForBulkWriteNAND(unsigned int dwAddr, size_t dwLength,unsigned char modeWrite,WORD pageSize, WORD blockPages, unsigned char WriteCom,unsigned char AddrLen, unsigned char WriteDummyLen,unsigned char nCA, int USBIndex) +{ + unsigned char vInstruction[40]={0}; + //dwAddr; + vInstruction[0]=(dwAddr & 0xff); + vInstruction[1]=((dwAddr>>8) & 0xff); + vInstruction[2]=((dwAddr>>16) & 0xff); + vInstruction[3]=((dwAddr>>24) & 0xff); + + //dwLength + vInstruction[4]=((unsigned char)(dwLength & 0xff)); // lowest byte of length : page number + vInstruction[5]=((unsigned char)( (dwLength >> 8) & 0xff)); // highest byte of length: page number + vInstruction[6]=((unsigned char)( (dwLength >> 16) & 0xff) ); + vInstruction[7]=((unsigned char)( (dwLength >> 24) & 0xff) ); + + //dwMode + vInstruction[8]=((unsigned char)modeWrite); + vInstruction[9]=((unsigned char)(modeWrite>>8)); + + //pagesize + vInstruction[10]=((unsigned char)pageSize); + vInstruction[11]=((unsigned char)(pageSize>>8)); + + //blockpages + vInstruction[12]=(blockPages); + vInstruction[13]=((unsigned char)(blockPages>>8)); + vInstruction[14]=(WriteCom);//cmd + vInstruction[15]=(AddrLen);//addrLen + vInstruction[16]=(4); + vInstruction[17]=(nCA); + + CNTRPIPE_RQ rq ; + + rq.Function = URB_FUNCTION_VENDOR_ENDPOINT ; + rq.Direction = VENDOR_DIRECTION_OUT ; + rq.Request = WRITE_NAND ; + rq.Value = 0 ; + rq.Index = 0 ; + rq.Length = sizeof(vInstruction); + + // send rq via control pipe + return OutCtrlRequest(&rq, vInstruction,rq.Length,USBIndex); +} + diff --git a/FlashCommand.h b/FlashCommand.h index cb7dcdb..b520da2 100755 --- a/FlashCommand.h +++ b/FlashCommand.h @@ -23,5 +23,8 @@ int FlashCommand_SendCommand_SetupPacketForBulkWrite(struct CAddressRange* AddrR int FlashCommand_SendCommand_SetupPacketForAT45DBBulkWrite(struct CAddressRange* AddrRange, unsigned char modeWrite, unsigned char WriteCom, int Index); int FlashCommand_SendCommand_SetupPacketForBulkRead(struct CAddressRange* AddrRange, unsigned char modeRead, unsigned char ReadCom, unsigned int AddrLen, unsigned int DummyLen, int Index); +int FlashCommand_SendCommand_SetupPacketForBulkReadNAND(unsigned int dwAddr, unsigned int PageNum, unsigned char modeRead,WORD pageSize, WORD blockPages, unsigned char ReadCom,unsigned char AddrLen, unsigned char ReadDummyLen,unsigned char nCA, int USBIndex); +bool FlashCommand_SendCommand_SetupPacketForBulkWriteNAND(unsigned int dwAddr, size_t dwLength,unsigned char modeWrite,WORD pageSize, WORD blockPages, unsigned char WriteCom,unsigned char AddrLen, unsigned char WriteDummyLen,unsigned char nCA, int USBIndex); + #endif //FLASHCOMMANDS diff --git a/Macro.h b/Macro.h index a1bdec9..acb6abf 100755 --- a/Macro.h +++ b/Macro.h @@ -9,14 +9,15 @@ #include // new defined macros +#define IS_NAND_FLASH {if()} //programmer info RQ #define PROGINFO_REQUEST 0x08 #define SET_VCC 0x09 ///< set VCC #define SET_VPP 0x03 ///< set VPP -#define SET_CS 0x14 -#define SET_IOMODE 0x15 -#define SET_SPICLK 0x61 -#define SET_HOLD 0x1D +//#define SET_CS 0x14 +//#define SET_IOMODE 0x15 +//#define SET_SPICLK 0x61 +//#define SET_HOLD 0x1D #define SET_SA 0x0A //first field of RQ @@ -30,6 +31,11 @@ //#define READ_EEPROM 0x05 //#define WRITE_EEPROM 0x06 // values of Request Field of a setup packet + +typedef unsigned short WORD; +typedef unsigned char BYTE; +typedef unsigned long DWORD; + typedef struct FirmwareInfo { char Programmer[20]; char Version[10]; @@ -51,13 +57,33 @@ typedef enum { READ_EEPROM = 0x05, WRITE_EEPROM = 0x06, - CHECK_SD_CARD = 0x65, GET_BUTTON_STATUS = 0x11, + GET_UID = 0x12, + SET_CS = 0x14, + SET_IOMODE = 0x15, + FW_UPDATE = 0x1A, + FPGA_UPDATE = 0x1B, + READ_FPGA_VERSION = 0x1C, + SET_HOLD = 0x1D, + DTC_READ_NAND = 0x40, + WRITE_NAND = 0x50, + MICRON_XIP_RESET =0x99, + SET_SPICLK = 0x61, + DOWNLOAD_PROJECT =0x63, + GET_PROJECT_NAME =0x64, + CHECK_SD_CARD = 0x65, + READ_PROJECT =0x66, + DL_IC_INFO_NAND =0x67, + READ_IC_INFO_NAND =0x68, + READ_ONBOARD_NAND =0x73, + GET_FW_STATUS =0x9B, //0x9A: Set //0x9B:Get } USB_CMD; typedef struct ChipInfo { char TypeName[100]; + char ICType[16]; size_t UniqueID; + size_t ChipIDMask; char Class[100]; char Description[256]; @@ -66,6 +92,7 @@ typedef struct ChipInfo { char Voltage[20]; char Clock[20]; char ProgramIOMethod[20]; + char type[16]; size_t ManufactureID; size_t JedecDeviceID; @@ -88,7 +115,164 @@ typedef struct ChipInfo { size_t RDIDCommand; size_t Timeout; size_t VoltageInMv; + // SPI NAND + size_t SpareSizeInByte;//NAND + size_t nCA_Rd; + size_t nCA_Wr; + size_t DefaultDataUnitSize; + size_t DefaultErrorBits; + size_t BBMark; + size_t SupportedProduct; + size_t ECCParityGroup; + size_t ECCProtectStartAddr; + size_t ECCProtectDis; + size_t ECCProtectLength; + bool ECCEnable; + + bool QPIEnable; + size_t ChipEraseTime; + size_t EraseCmd; + size_t ProgramCmd; + size_t ReadCmd; + size_t ProtectBlockMask; + size_t UnlockCmd; + size_t RDSRCnt; + size_t WRSRCnt; + size_t WRSRCmd; + size_t RDSRCmd; + size_t WRCRCmd; + size_t RDCRCmd; + size_t QEbitAddr; + bool SupportLUT; + } CHIP_INFO; +#pragma pack(push,1) +typedef struct spi_nand_info{ + unsigned short Hearder;//A1A1 + unsigned short Version;//0x0001 + unsigned short Type;//0x0001 for spi nand + unsigned short STsize;//size of this struct + unsigned int ChipID; + unsigned int ChipIDMask; + unsigned short RealPagesize; //for real OP. include spare area size , when scanBB , this size not include spare area size + unsigned short PagesPerBlock; + unsigned int Blocks; + //24 + + unsigned int BlockIndex; + unsigned int BlockCount; + + //32 + unsigned short EN_spareArea; + unsigned short SPA_pagesize; //spare area pagesize + unsigned short MA_pagesize; //main area pagesize + + unsigned char BeCmd; + unsigned char RdCmd; + unsigned char WrCmd; + unsigned char AddrLen; + unsigned char nCA_Rd; + unsigned char nCA_Wr; + unsigned char Dummy; +//44 + + unsigned short MaxERR_bits; + unsigned short BBMark; + unsigned char BB_BYTE_TYPE;//0:not skip, 0x11:~0xFF, 0x10:~0x00, 0x21: ~0xFFFF, 0x20:~0x0000 + unsigned char BBM_TYPE;//0:no BBM, 1: skip BB, 2:others + + unsigned short BBK_TOTAL;//only useful after BB scan. + + //52 + unsigned char StartBB; //set 0: no start BB,set 1, start BB scan. If ready, device will set 2. + unsigned char UNprotect_type;// 1 enable. other default + unsigned char En_internalECC;//0 disable, 1 enable. 0xff default +//55 + unsigned int EraseStartBlock; + unsigned int EraseEndBlock; +//63 + unsigned char EraseMode;//0:not enable; 1: force erase; 2: skip bad block(must Start BB before) +//64 + unsigned char EraseStatus;//0:Pass; 1: Fail + + unsigned char saveSTA; //enable save STA + //66 + unsigned short rfu0; + unsigned short perPageSizeForErrBit; + unsigned char ReadSatus_mode;//1:w25N512G + + unsigned short VFMODE; //[3]==0:old:[3:0]MaxErrorBit, [15:4]:ErrorBit reset size; size={256xErrorBit[7:4]+ErrorBit[15:8]} + //[3]==1:new: [15:8]Max Error Bit allowed + //[2:0]==MODE 0:DS 1:DSDSDS..DS 2:DDDD...DSSSS...S 3:DDD...D 4: for internal ECC skip + + unsigned short VFCOFGL; //for mode 0,1,2,3: + unsigned short VFCOFGH; //[31:16]: Data Unit size; + //[15:0]: Ecc Unit size; + //for mode 4: + //[31:16]: User Data mask + //[15:0]: Internal ECC address mask + unsigned short staPVpagesize; + unsigned int staPVpages; + unsigned int staPVsize; + unsigned char rfu[34]; + unsigned short crc; +}SELECT_SPI_NAND_INFO; +#pragma pack(pop) + +struct EraseCommand +{ + unsigned char ChipErase; + unsigned char SectorErase; + unsigned char DieErase; + unsigned char RFU2; +} ; +struct ReadCommand +{ + unsigned char SingleRead; + unsigned char DualRead; + unsigned char QuadRead; + unsigned char RFU3; +} ; +struct ProgramCommand +{ + unsigned char SingleProgram; + unsigned char DualProgram; + unsigned char QuadProgram; + unsigned char RFU4; +} ; + +struct CNANDContext +{ + //bool is_S25FL128P_256KSectors; + const unsigned short cbyRLine[5];// = {0x111,0x121,0x122,0x141,0x144}; + const unsigned short cbyPLine[5] ;//= {0x111,0x111,0x111,0x141,0x144}; + unsigned int realPageSize; + unsigned int realSpareAreaSize; + unsigned int realBlockSize; + unsigned int realChipSize; + struct EraseCommand EraseCmd; + struct ReadCommand ReadCmd; + struct ProgramCommand ProgramCmd; +}; + +struct Block_Parameter +{ + unsigned int block_sart; + unsigned int block_cnt; + unsigned int block_end; +}; + +struct ProgrgmPatitionTable +{ + unsigned int pt_cnt; + struct Block_Parameter PT[]; +}; + +struct BadBlockTable +{ + unsigned short cnt; + unsigned short bbt[255]; +}; //third field of RQ #define CTRL_TIMEOUT 3000 ///< time out for control pipe or for firmwire @@ -124,6 +308,10 @@ typedef struct ChipInfo { #define BULK_AT45xx_READ 0x03 ///< fast read via bulk pipes #define BULK_4BYTE_FAST_READ 0x04 ///< For size is bigger than 128Mb #define BULK_4BYTE_FAST_READ_MICRON 0x05 //for 0x0c +#define BULK_FAST_READ_DIE2 0x06 ///< fast read via bulk pipes +#define BULK_4BYTE_NORM_READ 0x07 //FW 7.2.26_FPGA_D +#define BULK_QUAD_READ 0x09 //FW 7.2.29 + //for flash card #define POLLING 0x02 ///< polling @@ -168,7 +356,7 @@ typedef struct ChipInfo { #define SUPPORT_ATO #define SUPPORT_FIDELIX #define SUPPORT_FUDAN - +#define SUPPORT_GIGADEVICE // memory support list #ifdef SUPPORT_NANTRONICS #define SUPPORT_NANTRONICS_N25Sxx "N25Sxx" @@ -178,6 +366,12 @@ typedef struct ChipInfo { #define SUPPORT_ATO_ATO25Qxx "ATO25Qxx" #endif +#ifdef SUPPORT_GIGADEVICE + #define SUPPORT_GIGADEVICE_GD25SXXX_LARGE "GD25Sxxx_Large" + #define SUPPORT_GIGADEVICE_GD5F1GQ4xCx "GD5F1GQ4xCx" +#endif + + #ifdef SUPPORT_ST #define SUPPORT_ST_M25PExx "M25PExx" #define SUPPORT_ST_M25Pxx "M25Pxx" @@ -298,6 +492,10 @@ typedef struct ChipInfo { #define BIT13 0x2000 #define BIT14 0x4000 #define BIT15 0x8000 +#define BIT16 0x10000 +#define BIT17 0x20000 +#define BIT18 0x40000 + #define ERASE BIT0 #define PROGRAM BIT1 @@ -314,6 +512,10 @@ typedef struct ChipInfo { #define LIST_TYPE BIT12 #define LOADFILEWITHVERIFY BIT13 #define CHECK_INFO BIT14 +#define SPECIAL_ERASE BIT15 +#define SPECIAL_PROGRAM BIT16 +#define SPECIAL_AUTO BIT17 +#define BATCH_WITH_FORCEERASE BIT18 struct CAddressRange { size_t start; @@ -321,39 +523,6 @@ struct CAddressRange { size_t length; }; -struct memory_id { - char TypeName[20]; - size_t UniqueID; - char Class[20]; - char Description[20]; - - char Manufacturer[20]; - char ManufactureUrl[20]; - char Voltage[20]; - char Clock[20]; - char ProgramIOMethod[20]; - - size_t ManufactureID; - size_t JedecDeviceID; - size_t AlternativeID; - - size_t ChipSizeInByte; - size_t SectorSizeInByte; - size_t PageSizeInByte; - size_t BlockSizeInByte; - - size_t MaxErasableSegmentInByte; - - size_t AddrWidth; - - bool DualID; - size_t VppSupport; - bool MXIC_WPmode; - size_t IDNumber; - size_t RDIDCommand; - size_t Timeout; -}; - enum { SITE_NORMAL = 0, SITE_BUSY, @@ -377,4 +546,38 @@ typedef enum { } VCC_VALUE; +typedef enum +{ + IO_Single = 0x00, + IO_Dual1 =0x01, + IO_Dual2 =0x02,//sf600 not support 122 + IO_Quad1 =0x03, + IO_Quad2 =0x04, + IO_Quad3 =0x05, // Quad command 4-4-4 + IO_Octa1 =0x89, // Octal command for Macronix (888) + IO_Octa2 =0x88, // Octal command for Micron (888) +} IO_VALUE; + + +enum { // value dedicated by the spec + STARTUP_APPLI_SF_1 = 0, + STARTUP_APPLI_CARD = 1, + STARTUP_APPLI_SF_2 = 2, + STARTUP_APPLI_SF_SKT = 3, + + STARTUP_SPECIFY_LATER = 0xFE, + STARTUP_PREVIOUS = 0xFF +}; + +enum { + clk_24M = 0x00, + clk_8M = 0x01, + clk_12M = 0x02, + clk_3M = 0x03, + clk_2180K = 0x04, + clk_1500K = 0x05, + clk_750K = 0x06, + clk_375K = 0x07, +}; + #endif //_MACRO_H diff --git a/Makefile b/Makefile index d9da281..c4a1677 100644 --- a/Makefile +++ b/Makefile @@ -18,11 +18,11 @@ PREFIX ?= /usr/local PKG_CONFIG ?= pkg-config CFLAGS ?= -O2 -Wall -std=gnu99 -CFLAGS += $(shell $(PKG_CONFIG) --cflags libusb-1.0) +CFLAGS += $(shell $(PKG_CONFIG) --cflags libusb-1.0 libxml-2.0) LDFLAGS ?= LDFLAGS += -lpthread -LDFLAGS += $(shell $(PKG_CONFIG) --libs libusb-1.0) +LDFLAGS += $(shell $(PKG_CONFIG) --libs libusb-1.0 libxml-2.0) DEPDIR := .deps DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.d diff --git a/README.md b/README.md index 23397ac..3e8b107 100755 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ Linux software for Dediprog SF100 and SF600 SPI flash programmers ## Building To compile the project, first install required dependencies: - libusb-1.0 + - libxml-2.0 - pkg-config - won't link to libusb without this package Change to the directory where the sources are located and build using make: diff --git a/SerialFlash.c b/SerialFlash.c index 9d462b7..9314e92 100755 --- a/SerialFlash.c +++ b/SerialFlash.c @@ -2,7 +2,9 @@ #include "ChipInfoDb.h" #include "FlashCommand.h" #include "project.h" +#include "dpcmd.h" #include "usbdriver.h" +#include "board.h" #include #include @@ -10,11 +12,19 @@ extern int m_isCanceled; extern int m_bProtectAfterWritenErase; extern int m_boEnReadQuadIO; extern int m_boEnWriteQuadIO; -extern CHIP_INFO Chip_Info; +extern bool g_bSpareAreaUseFile; +extern bool g_bNandForceErase; +extern CHIP_INFO g_ChipInfo; +extern struct CNANDContext g_NANDContext; +extern bool g_bNandInternalECC; +extern int g_iNandBadBlockManagement; +extern struct BadBlockTable g_BBT[16]; extern volatile bool g_bIsSF600[16]; extern volatile bool g_bIsSF700[16]; extern volatile bool g_bIsSF600PG2[16]; +extern unsigned char *pBufferforLoadedFile; extern bool Is_NewUSBCommand(int Index); +extern unsigned int CRC32(unsigned char* v, unsigned long size); unsigned char mcode_WRSR = 0x01; unsigned char mcode_WRDI = 0x04; @@ -81,7 +91,7 @@ bool AT45doRDSR(unsigned char* cSR, int Index) bool AT45WaitForWIP(int USBIndex) { unsigned char cSR; - size_t i = Chip_Info.Timeout * 100; + size_t i = g_ChipInfo.Timeout * 100; if (i == 0) i = 0x10000; // wait until WIP = 0 @@ -114,7 +124,7 @@ unsigned char getWriteMode(int USBIndex) AT45DB642D = 0x1F28, }; - switch (Chip_Info.UniqueID) { + switch (g_ChipInfo.UniqueID) { case AT45DB011D: case AT45DB021D: case AT45DB041D: @@ -144,9 +154,9 @@ void SetPageSize(CHIP_INFO* mem, int USBIndex) mem->PageSizeInByte = pageSize[writeMode]; if (!(writeMode & 0x1)) // for AT45DB:0x1F2200 - 0x1F2800 - mem->ChipSizeInByte = Chip_Info.ChipSizeInByte / 256 * 8 + Chip_Info.ChipSizeInByte; + mem->ChipSizeInByte = g_ChipInfo.ChipSizeInByte / 256 * 8 + g_ChipInfo.ChipSizeInByte; else - mem->ChipSizeInByte = Chip_Info.ChipSizeInByte; + mem->ChipSizeInByte = g_ChipInfo.ChipSizeInByte; AT45ChipSize = mem->ChipSizeInByte; AT45PageSize = mem->PageSizeInByte; @@ -268,11 +278,11 @@ bool AT45batchErase(size_t* vAddrs, size_t AddrSize, int USBIndex) CHIP_INFO mem_id; int i; SetPageSize(&mem_id, USBIndex); - if (strcmp(Chip_Info.Class, SUPPORT_ATMEL_45DBxxxB) == 0) { - mem_id.PageSizeInByte = Chip_Info.PageSizeInByte; - mem_id.ChipSizeInByte = Chip_Info.ChipSizeInByte; + if (strcmp(g_ChipInfo.Class, SUPPORT_ATMEL_45DBxxxB) == 0) { + mem_id.PageSizeInByte = g_ChipInfo.PageSizeInByte; + mem_id.ChipSizeInByte = g_ChipInfo.ChipSizeInByte; } - mem_id.SectorSizeInByte = Chip_Info.SectorSizeInByte; + mem_id.SectorSizeInByte = g_ChipInfo.SectorSizeInByte; struct CAddressRange range; @@ -424,11 +434,11 @@ bool AT45chipErase(unsigned int Addr, unsigned int Length, int USBIndex) CHIP_INFO mem_id; SetPageSize(&mem_id, USBIndex); - if (strcmp(Chip_Info.Class, SUPPORT_ATMEL_45DBxxxB) == 0) { - mem_id.PageSizeInByte = Chip_Info.PageSizeInByte; - mem_id.ChipSizeInByte = Chip_Info.ChipSizeInByte; + if (strcmp(g_ChipInfo.Class, SUPPORT_ATMEL_45DBxxxB) == 0) { + mem_id.PageSizeInByte = g_ChipInfo.PageSizeInByte; + mem_id.ChipSizeInByte = g_ChipInfo.ChipSizeInByte; } - mem_id.SectorSizeInByte = Chip_Info.SectorSizeInByte; + mem_id.SectorSizeInByte = g_ChipInfo.SectorSizeInByte; // AT45xxx_protectBlock(false,USBIndex); struct CAddressRange range; @@ -979,7 +989,7 @@ bool S25FSxxS_Large_doRDCF3V(unsigned char *cSR, int Index) bool S70FSxxx_Large_waitForWIP(bool die1, int Index) { unsigned char cSR; - size_t i = Chip_Info.Timeout * 100; + size_t i = g_ChipInfo.Timeout * 100; if (i == 0) i = MAX_TRIALS; // wait until WIP = 0 @@ -995,7 +1005,7 @@ bool S70FSxxx_Large_waitForWIP(bool die1, int Index) bool SerialFlash_waitForWIP(int Index) { unsigned char cSR; - size_t i = Chip_Info.Timeout * 100; + size_t i = g_ChipInfo.Timeout * 100; if (i == 0) i = MAX_TRIALS; // wait until WIP = 0 @@ -1128,7 +1138,7 @@ bool AT26Fxxx_protectBlock(int bProtect, int Index) UNPROTECTSECTOR = 0x39, // Write Disable READPROTECTIONREGISTER = 0x3C, // Write Disable }; - if (AT26DF041 == Chip_Info.UniqueID) + if (AT26DF041 == g_ChipInfo.UniqueID) return true; // feature is not supported on this chip bool result = false; @@ -1154,7 +1164,7 @@ bool AT26Fxxx_protectBlock(int bProtect, int Index) vInstruction[0] = bProtect ? PROTECTSECTOR : UNPROTECTSECTOR; size_t iUniformSectorSize = 0x10000; // always regarded as 64K - size_t cnt = Chip_Info.ChipSizeInByte / iUniformSectorSize; + size_t cnt = g_ChipInfo.ChipSizeInByte / iUniformSectorSize; size_t i; for (i = 0; i < cnt; ++i) { SerialFlash_doWREN(Index); @@ -1177,7 +1187,7 @@ bool AT26Fxxx_protectBlock(int bProtect, int Index) return false; } - if (AT26DF081A == Chip_Info.UniqueID || AT26DF004 == Chip_Info.UniqueID) // 8K each for the last 64K + if (AT26DF081A == g_ChipInfo.UniqueID || AT26DF004 == g_ChipInfo.UniqueID) // 8K each for the last 64K { vInstruction[1] = (unsigned char)(cnt - 1); for (i = 1; i < 8; ++i) { @@ -1260,7 +1270,7 @@ bool CS25FLxxx_LargedoUnlockDYB(unsigned int cSR, int Index) int i; unsigned int topend, bottomstart, end; - if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S25FLxx_Large) != NULL) //256 + if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S25FLxx_Large) != NULL) //256 { topend = 0x20000; bottomstart = 0x1fe0000; @@ -1314,19 +1324,19 @@ bool CS25FLxxx_LargedoUnlockDYB(unsigned int cSR, int Index) int SerialFlash_protectBlock(int bProtect, int Index) { - if (strcmp(Chip_Info.Class, SUPPORT_SST_25xFxx) == 0 || strstr(Chip_Info.Class, SUPPORT_SST_25xFxxB) != NULL) // || strstr(Chip_Info.Class,SUPPORT_SST_25xFxxC)!=NULL) + if (strcmp(g_ChipInfo.Class, SUPPORT_SST_25xFxx) == 0 || strstr(g_ChipInfo.Class, SUPPORT_SST_25xFxxB) != NULL) // || strstr(g_ChipInfo.Class,SUPPORT_SST_25xFxxC)!=NULL) return SST25xFxx_protectBlock(bProtect, Index); - else if (strstr(Chip_Info.Class, SUPPORT_SST_25xFxxA) != NULL) + else if (strstr(g_ChipInfo.Class, SUPPORT_SST_25xFxxA) != NULL) return SST25xFxxA_protectBlock(bProtect, Index); - else if (strstr(Chip_Info.Class, SUPPORT_ATMEL_AT25FSxxx) != NULL || strstr(Chip_Info.Class, SUPPORT_ATMEL_AT25Fxxx) != NULL) + else if (strstr(g_ChipInfo.Class, SUPPORT_ATMEL_AT25FSxxx) != NULL || strstr(g_ChipInfo.Class, SUPPORT_ATMEL_AT25Fxxx) != NULL) return AT25FSxxx_protectBlock(bProtect, Index); - else if (strstr(Chip_Info.Class, SUPPORT_ATMEL_AT26xxx) != NULL) + else if (strstr(g_ChipInfo.Class, SUPPORT_ATMEL_AT26xxx) != NULL) return AT26Fxxx_protectBlock(bProtect, Index); - else if (strstr(Chip_Info.Class, SUPPORT_MACRONIX_MX25Lxxx) != NULL || strstr(Chip_Info.Class, SUPPORT_MACRONIX_MX25Lxxx_Large) != NULL) { + else if (strstr(g_ChipInfo.Class, SUPPORT_MACRONIX_MX25Lxxx) != NULL || strstr(g_ChipInfo.Class, SUPPORT_MACRONIX_MX25Lxxx_Large) != NULL) { unsigned char tmpSRVal; bool result; result = CMX25LxxxdoRDSCUR(&tmpSRVal, Index); - if (result == true && (tmpSRVal & 0x80) && Chip_Info.MXIC_WPmode == true) { + if (result == true && (tmpSRVal & 0x80) && g_ChipInfo.MXIC_WPmode == true) { if (bProtect != false) return true; SerialFlash_doWREN(Index); @@ -1334,11 +1344,11 @@ int SerialFlash_protectBlock(int bProtect, int Index) unsigned char v = GBULK; return FlashCommand_SendCommand_OutOnlyInstruction(&v, 1, Index); } - } else if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S25FLxx) != NULL || strstr(Chip_Info.Class, SUPPORT_SPANSION_S25FLxx_Large) != NULL) { - if (bProtect == false && strstr(Chip_Info.TypeName, "Secure") != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S25FLxx) != NULL || strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S25FLxx_Large) != NULL) { + if (bProtect == false && strstr(g_ChipInfo.TypeName, "Secure") != NULL) { CS25FLxxx_LargedoUnlockDYB(0, Index); } - } else if (strstr(Chip_Info.Class, SUPPORT_SST_26xFxxC) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_SST_26xFxxC) != NULL) { unsigned char v = 0x98; SerialFlash_waitForWEL(Index); FlashCommand_SendCommand_OutOnlyInstruction(&v, 1, Index); @@ -1665,7 +1675,7 @@ bool CN25Qxxx_MutipleDIe_LargeWREAR(unsigned char cSR, int Index) bool CS25FLxx_LargeEnable4ByteAddrMode(bool Enable4Byte, int Index) { - if ((strstr(Chip_Info.TypeName, "S25FL512Sxxxxxx1x") != NULL) || (strstr(Chip_Info.TypeName, "S25FL512Sxxxxxx1x(Secure)") != NULL)) { + if ((strstr(g_ChipInfo.TypeName, "S25FL512Sxxxxxx1x") != NULL) || (strstr(g_ChipInfo.TypeName, "S25FL512Sxxxxxx1x(Secure)") != NULL)) { SerialFlash_waitForWEL(Index); if (Enable4Byte) { unsigned char v[2]; @@ -1788,15 +1798,15 @@ int S70FSxxx_Large_Enable4ByteAddrMode(int Enable4Byte, int Index) //Simon: unused ??? int SerialFlash_Enable4ByteAddrMode(int bEnable, int Index) { - if (strstr(Chip_Info.Class, SUPPORT_EON_EN25QHxx_Large) != NULL || strstr(Chip_Info.Class, SUPPORT_MACRONIX_MX25Lxxx_Large) != NULL || strstr(Chip_Info.Class, SUPPORT_WINBOND_W25Pxx_Large) != NULL || strstr(Chip_Info.Class, SUPPORT_WINBOND_W25Qxx_Large) != NULL) + if (strstr(g_ChipInfo.Class, SUPPORT_EON_EN25QHxx_Large) != NULL || strstr(g_ChipInfo.Class, SUPPORT_MACRONIX_MX25Lxxx_Large) != NULL || strstr(g_ChipInfo.Class, SUPPORT_WINBOND_W25Pxx_Large) != NULL || strstr(g_ChipInfo.Class, SUPPORT_WINBOND_W25Qxx_Large) != NULL) return CEN25QHxx_LargeEnable4ByteAddrMode(bEnable, Index); - else if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S70FSxx_Large) != NULL) + else if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S70FSxx_Large) != NULL) return S70FSxxx_Large_Enable4ByteAddrMode(bEnable, Index); - else if (strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large) != NULL) + else if (strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large) != NULL) return CN25Qxxx_LargeEnable4ByteAddrMode(bEnable, Index); - else if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S25FLxx_Large) != NULL) + else if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S25FLxx_Large) != NULL) return CS25FLxx_LargeEnable4ByteAddrMode(bEnable, Index); - else if(Chip_Info.ChipSizeInByte > 0x1000000) + else if(g_ChipInfo.ChipSizeInByte > 0x1000000) return Universal_LargeEnable4ByteAddrMode(bEnable, Index); return SerialFlash_TRUE; @@ -1856,23 +1866,23 @@ int SerialFlash_rangeBlankCheck(struct CAddressRange* Range, int Index) */ int SerialFlash_rangeProgram(struct CAddressRange* AddrRange, unsigned char* vData, int Index) { - if (strstr(Chip_Info.Class, SUPPORT_ATMEL_45DBxxxB) != NULL || strstr(Chip_Info.Class, SUPPORT_ATMEL_45DBxxxD) != NULL) + if (strstr(g_ChipInfo.Class, SUPPORT_ATMEL_45DBxxxB) != NULL || strstr(g_ChipInfo.Class, SUPPORT_ATMEL_45DBxxxD) != NULL) return AT45rangeProgram(AddrRange, vData, mcode_Program, mcode_ProgramCode_4Adr, Index); - else if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S25FLxx_Large) != NULL) { + else if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S25FLxx_Large) != NULL) { if ((g_bIsSF600[Index] == true) || (g_bIsSF700[Index] == true) || (g_bIsSF600PG2[Index] == true)) return SerialFlash_bulkPipeProgram(AddrRange, vData, mcode_Program, mcode_ProgramCode_4Adr, Index); else return SerialFlash_bulkPipeProgram(AddrRange, vData, PP_4ADDR_256BYTE_12, mcode_ProgramCode_4Adr, Index); - } else if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S25FLxxL_Large) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S25FLxxL_Large) != NULL) { return SerialFlash_bulkPipeProgram(AddrRange, vData, mcode_Program, mcode_ProgramCode_4Adr_12, Index); - } else if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S70FSxx_Large) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S70FSxx_Large) != NULL) { if ((g_bIsSF600[Index] == true) || (g_bIsSF700[Index] == true)|| (g_bIsSF600PG2[Index] == true)) { return SerialFlash_bulkPipeProgram(AddrRange, vData, PP_4ADDR_256BYTE_S70FS01GS, mcode_ProgramCode_4Adr_12, Index); } else return false; - } else if (strstr(Chip_Info.Class, SUPPORT_WINBOND_W25Mxx_Large) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_WINBOND_W25Mxx_Large) != NULL) { return SerialFlash_bulkPipeProgram_twoDie(AddrRange, vData, mcode_Program, mcode_ProgramCode_4Adr, Index); - } else if (strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL) { return SerialFlash_bulkPipeProgram_Micron_4Die(AddrRange, vData, mcode_Program, mcode_ProgramCode_4Adr, Index); } else { return SerialFlash_bulkPipeProgram(AddrRange, vData, mcode_Program, mcode_ProgramCode_4Adr, Index); @@ -1881,21 +1891,21 @@ int SerialFlash_rangeProgram(struct CAddressRange* AddrRange, unsigned char* vDa int SerialFlash_rangeRead(struct CAddressRange* AddrRange, unsigned char* vData, int Index) { - if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S25FLxx_Large) != NULL) { + if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S25FLxx_Large) != NULL) { if ((g_bIsSF600[Index] == true) || (g_bIsSF700[Index] == true)|| (g_bIsSF600PG2[Index] == true)) return SerialFlash_bulkPipeRead(AddrRange, vData, BULK_4BYTE_FAST_READ, mcode_ReadCode, Index); else return SerialFlash_bulkPipeRead(AddrRange, vData, BULK_4BYTE_FAST_READ_MICRON, mcode_ReadCode, Index); - } else if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S25FLxxL_Large) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S25FLxxL_Large) != NULL) { return SerialFlash_bulkPipeRead(AddrRange, vData, mcode_Read, mcode_ReadCode, Index); - } else if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S70FSxx_Large) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S70FSxx_Large) != NULL) { if ((g_bIsSF600[Index] == true) || (g_bIsSF700[Index] == true)|| (g_bIsSF600PG2[Index] == true)) return SerialFlash_bulkPipeRead(AddrRange, vData, BULK_4BYTE_FAST_READ, mcode_ReadCode_0C, Index); else return false; - } else if (strstr(Chip_Info.Class, SUPPORT_WINBOND_W25Mxx_Large) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_WINBOND_W25Mxx_Large) != NULL) { return SerialFlash_bulkPipeRead_twoDie(AddrRange, vData, (unsigned char)mcode_Read, (unsigned char)mcode_ReadCode_0C, Index); - } else if (strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL) { return SerialFlash_bulkPipeRead_Micron_4die(AddrRange, vData, (unsigned char)mcode_Read, (unsigned char)mcode_ReadCode_0C, Index); } else return SerialFlash_bulkPipeRead(AddrRange, vData, (unsigned char)mcode_Read, (unsigned char)mcode_ReadCode, Index); @@ -2047,7 +2057,7 @@ int SerialFlash_batchErase(uintptr_t* vAddrs, size_t AddrSize, int Index) rq.Length = 5; for (i = 0; i < AddrSize; i++) { SerialFlash_waitForWEL(Index); - if (Chip_Info.ChipSizeInByte > 0x1000000) { + if (g_ChipInfo.ChipSizeInByte > 0x1000000) { // MSB~ LSB (31...0) vInstruction[1] = (unsigned char)((vAddrs[i] >> 24) & 0xff); //MSB vInstruction[2] = (unsigned char)((vAddrs[i] >> 16) & 0xff); //M @@ -2073,7 +2083,7 @@ int SerialFlash_batchErase(uintptr_t* vAddrs, size_t AddrSize, int Index) int SerialFlash_rangeErase(unsigned char cmd, size_t sectionSize, struct CAddressRange* AddrRange, int Index) { - if (strstr(Chip_Info.Class, SUPPORT_ATMEL_45DBxxxB) != NULL || strstr(Chip_Info.Class, SUPPORT_ATMEL_45DBxxxD) != NULL) + if (strstr(g_ChipInfo.Class, SUPPORT_ATMEL_45DBxxxB) != NULL || strstr(g_ChipInfo.Class, SUPPORT_ATMEL_45DBxxxD) != NULL) return AT45rangSectorErase(sectionSize, *AddrRange, Index); if (SerialFlash_protectBlock(false, Index) == SerialFlash_FALSE) @@ -2106,7 +2116,7 @@ int SerialFlash_rangeErase(unsigned char cmd, size_t sectionSize, struct CAddres // MSB~ LSB (23...0) size_t addr = (AddrRange->start + i * sectionSize); - if (Chip_Info.ChipSizeInByte > 0x1000000) { + if (g_ChipInfo.ChipSizeInByte > 0x1000000) { // MSB~ LSB (31...0) vInstruction[1] = (unsigned char)((addr >> 24) & 0xff); //MSB vInstruction[2] = (unsigned char)((addr >> 16) & 0xff); //M @@ -2193,12 +2203,12 @@ bool SerialFlash_chipErase(int Index) { if (!SerialFlash_StartofOperation(Index)) return false; - if (strstr(Chip_Info.Class, SUPPORT_ATMEL_45DBxxxB) != NULL || strstr(Chip_Info.Class, SUPPORT_ATMEL_45DBxxxD) != NULL) - return AT45chipErase(0, Chip_Info.ChipSizeInByte, Index); - if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S70FSxx_Large) != NULL) - return S70FSxxx_Large_chipErase(0, Chip_Info.ChipSizeInByte, Index); - if (strstr(Chip_Info.Class, SUPPORT_WINBOND_W25Mxx_Large) != NULL) - return W25Mxx_Large_chipErase(0, Chip_Info.ChipSizeInByte, Index); + if (strstr(g_ChipInfo.Class, SUPPORT_ATMEL_45DBxxxB) != NULL || strstr(g_ChipInfo.Class, SUPPORT_ATMEL_45DBxxxD) != NULL) + return AT45chipErase(0, g_ChipInfo.ChipSizeInByte, Index); + if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S70FSxx_Large) != NULL) + return S70FSxxx_Large_chipErase(0, g_ChipInfo.ChipSizeInByte, Index); + if (strstr(g_ChipInfo.Class, SUPPORT_WINBOND_W25Mxx_Large) != NULL) + return W25Mxx_Large_chipErase(0, g_ChipInfo.ChipSizeInByte, Index); if (SerialFlash_protectBlock(false, Index) == SerialFlash_FALSE) return false; @@ -2227,8 +2237,8 @@ int SerialFlash_DieErase(int Index) unsigned char re; vInstruction[0] = mcode_ChipErase; - size_t dieNum = ((strstr(Chip_Info.Class, "2Die") != NULL) ? 2 : 4); - size_t die_size = Chip_Info.ChipSizeInByte / dieNum; + size_t dieNum = ((strstr(g_ChipInfo.Class, "2Die") != NULL) ? 2 : 4); + size_t die_size = g_ChipInfo.ChipSizeInByte / dieNum; size_t i; for (i = 0; i < dieNum; i++) { SerialFlash_waitForWEL(Index); @@ -2272,9 +2282,9 @@ int SerialFlash_bulkPipeProgram(struct CAddressRange* AddrRange, unsigned char* divider = 7; break; case PP_PROGRAM_ANYSIZE_PAGESIZE: - if(Chip_Info.PageSizeInByte == 0x200) + if(g_ChipInfo.PageSizeInByte == 0x200) divider = 9; - else if(Chip_Info.PageSizeInByte == 0x400) + else if(g_ChipInfo.PageSizeInByte == 0x400) divider = 10; else divider = 8; @@ -2284,7 +2294,7 @@ int SerialFlash_bulkPipeProgram(struct CAddressRange* AddrRange, unsigned char* break; } - if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S25FLxxS_Large) != NULL) + if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S25FLxxS_Large) != NULL) { unsigned char cSR; S25FSxxS_Large_doRDCF3V(&cSR, Index); @@ -2332,7 +2342,7 @@ int SerialFlash_bulkPipeProgram(struct CAddressRange* AddrRange, unsigned char* down_range.length = down_range.end - down_range.start; packageNum = down_range.length >> divider; - FlashCommand_SendCommand_SetupPacketForBulkWrite(&down_range, modeWrite, WriteCom, Chip_Info.PageSizeInByte, Chip_Info.AddrWidth, Index); + FlashCommand_SendCommand_SetupPacketForBulkWrite(&down_range, modeWrite, WriteCom, g_ChipInfo.PageSizeInByte, g_ChipInfo.AddrWidth, Index); for (i = 0; i < packageNum; ++i) { BulkPipeWrite((unsigned char*)(itr_begin + (i << divider)), 1 << divider, USB_TIMEOUT, Index); if (m_isCanceled) @@ -2342,7 +2352,7 @@ int SerialFlash_bulkPipeProgram(struct CAddressRange* AddrRange, unsigned char* } } else { size_t packageNum = (AddrRange->end - AddrRange->start) >> divider; - FlashCommand_SendCommand_SetupPacketForBulkWrite(AddrRange, modeWrite, WriteCom, 1 << divider, Chip_Info.AddrWidth, Index); + FlashCommand_SendCommand_SetupPacketForBulkWrite(AddrRange, modeWrite, WriteCom, 1 << divider, g_ChipInfo.AddrWidth, Index); for (i = 0; i < packageNum; ++i) { BulkPipeWrite((unsigned char*)((itr_begin + (i << divider))), 1 << divider, USB_TIMEOUT, Index); if (m_isCanceled) @@ -2439,7 +2449,7 @@ int SerialFlash_bulkPipeProgram_Micron_4Die(struct CAddressRange* AddrRange, uns down_range.length = down_range.end - down_range.start; packageNum = down_range.length >> divider; - FlashCommand_SendCommand_SetupPacketForBulkWrite(&down_range, modeWrite, WriteCom, Chip_Info.PageSizeInByte, Chip_Info.AddrWidth, Index); + FlashCommand_SendCommand_SetupPacketForBulkWrite(&down_range, modeWrite, WriteCom, g_ChipInfo.PageSizeInByte, g_ChipInfo.AddrWidth, Index); for (i = 0; i < packageNum; ++i) { BulkPipeWrite((unsigned char*)(itr_begin + (i << divider)), 1 << divider, USB_TIMEOUT, Index); if (m_isCanceled) @@ -2470,7 +2480,7 @@ int SerialFlash_bulkPipeProgram_Micron_4Die(struct CAddressRange* AddrRange, uns down_range.start=AddrRange->start-(0x1000000*EAR); size_t packageNum = (down_range.end - down_range.start) >> divider; - FlashCommand_SendCommand_SetupPacketForBulkWrite(&down_range, modeWrite, WriteCom, Chip_Info.PageSizeInByte, Chip_Info.AddrWidth, Index); + FlashCommand_SendCommand_SetupPacketForBulkWrite(&down_range, modeWrite, WriteCom, g_ChipInfo.PageSizeInByte, g_ChipInfo.AddrWidth, Index); for (i = 0; i < packageNum; ++i) { BulkPipeWrite((unsigned char*)((itr_begin + (i << divider))), 1 << divider, USB_TIMEOUT, Index); if (m_isCanceled) @@ -2574,7 +2584,7 @@ int SerialFlash_bulkPipeProgram_twoDie(struct CAddressRange* AddrRange, unsigned down_range.length = down_range.end - down_range.start; packageNum = down_range.length >> divider; - FlashCommand_SendCommand_SetupPacketForBulkWrite(&down_range_die2, modeWrite, WriteCom, Chip_Info.PageSizeInByte,Chip_Info.AddrWidth, Index); + FlashCommand_SendCommand_SetupPacketForBulkWrite(&down_range_die2, modeWrite, WriteCom, g_ChipInfo.PageSizeInByte,g_ChipInfo.AddrWidth, Index); for (i = 0; i < packageNum; ++i) { BulkPipeWrite((unsigned char*)(itr_begin + (i << divider)), 1 << divider, USB_TIMEOUT, Index); if (m_isCanceled) @@ -2599,7 +2609,7 @@ int SerialFlash_bulkPipeProgram_twoDie(struct CAddressRange* AddrRange, unsigned } size_t packageNum = (AddrRange->end - AddrRange->start) >> divider; - FlashCommand_SendCommand_SetupPacketForBulkWrite(&down_range_die2, modeWrite, WriteCom, Chip_Info.PageSizeInByte, Chip_Info.AddrWidth, Index); + FlashCommand_SendCommand_SetupPacketForBulkWrite(&down_range_die2, modeWrite, WriteCom, g_ChipInfo.PageSizeInByte, g_ChipInfo.AddrWidth, Index); for (i = 0; i < packageNum; ++i) { BulkPipeWrite((unsigned char*)((itr_begin + (i << divider))), 1 << divider, USB_TIMEOUT, Index); if (m_isCanceled) @@ -2627,7 +2637,7 @@ int SerialFlash_bulkPipeRead(struct CAddressRange* AddrRange, unsigned char* vDa int ret = 0; if (!SerialFlash_StartofOperation(Index)) return false; - if (!(strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large_2Die) != NULL && strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL && ((g_bIsSF600[Index] == true) || (g_bIsSF700[Index] == true)|| (g_bIsSF600PG2[Index] == true)))) + if (!(strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large_2Die) != NULL && strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL && ((g_bIsSF600[Index] == true) || (g_bIsSF700[Index] == true)|| (g_bIsSF600PG2[Index] == true)))) SerialFlash_Enable4ByteAddrMode(true, Index); if (SerialFlash_EnableQuadIO(true, m_boEnReadQuadIO, Index) == SerialFlash_FALSE) @@ -2649,7 +2659,7 @@ int SerialFlash_bulkPipeRead(struct CAddressRange* AddrRange, unsigned char* vDa loop = (range_temp.end - range_temp.start) / 0x1000000; for (j = 0; j < loop; j++) { - if (((g_bIsSF600[Index] == false) && (g_bIsSF700[Index] == false)&& (g_bIsSF600PG2[Index] == false)) && (strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large_2Die) != NULL || strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL)) // for sf100 + if (((g_bIsSF600[Index] == false) && (g_bIsSF700[Index] == false)&& (g_bIsSF600PG2[Index] == false)) && (strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large_2Die) != NULL || strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL)) // for sf100 { unsigned char re = 0; int numOfRetry = 5; @@ -2680,7 +2690,7 @@ int SerialFlash_bulkPipeRead(struct CAddressRange* AddrRange, unsigned char* vDa read_range.length = read_range.end - read_range.start; pageNum = read_range.length >> 9; - FlashCommand_SendCommand_SetupPacketForBulkRead(&read_range, modeRead, ReadCom, Chip_Info.AddrWidth,Chip_Info.ReadDummyLen, Index); + FlashCommand_SendCommand_SetupPacketForBulkRead(&read_range, modeRead, ReadCom, g_ChipInfo.AddrWidth,g_ChipInfo.ReadDummyLen, Index); for (i = 0; i < pageNum; ++i) { ret = BulkPipeRead(vData + (BufferLocation + i) * (1<<9), USB_TIMEOUT, Index); if ((ret != (1<<9)) || m_isCanceled) @@ -2691,7 +2701,7 @@ int SerialFlash_bulkPipeRead(struct CAddressRange* AddrRange, unsigned char* vDa } } else { unsigned char EAR = (AddrRange->start * 0x1000000) >> 24; - if (((g_bIsSF600[Index] == false) && (g_bIsSF700[Index] == false) && (g_bIsSF600PG2[Index] == false)) && (strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large_2Die) != NULL || strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL)) { + if (((g_bIsSF600[Index] == false) && (g_bIsSF700[Index] == false) && (g_bIsSF600PG2[Index] == false)) && (strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large_2Die) != NULL || strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL)) { unsigned char re = 0; int numOfRetry = 5; do { @@ -2709,7 +2719,7 @@ int SerialFlash_bulkPipeRead(struct CAddressRange* AddrRange, unsigned char* vDa } } pageNum = AddrRange->length >> 9; - FlashCommand_SendCommand_SetupPacketForBulkRead(AddrRange, modeRead, ReadCom,Chip_Info.AddrWidth,Chip_Info.ReadDummyLen, Index); + FlashCommand_SendCommand_SetupPacketForBulkRead(AddrRange, modeRead, ReadCom,g_ChipInfo.AddrWidth,g_ChipInfo.ReadDummyLen, Index); for (i = 0; i < pageNum; ++i) { ret = BulkPipeRead(vData + i * ret, USB_TIMEOUT, Index); if ((ret != 512) || m_isCanceled) { @@ -2798,7 +2808,7 @@ int SerialFlash_bulkPipeRead_Micron_4die(struct CAddressRange* AddrRange, unsign read_range.length = read_range.end - read_range.start; pageNum = read_range.length >> 9; - FlashCommand_SendCommand_SetupPacketForBulkRead(&read_range, modeRead, ReadCom, Chip_Info.AddrWidth,Chip_Info.ReadDummyLen, Index); + FlashCommand_SendCommand_SetupPacketForBulkRead(&read_range, modeRead, ReadCom, g_ChipInfo.AddrWidth,g_ChipInfo.ReadDummyLen, Index); for (i = 0; i < pageNum; ++i) { ret = BulkPipeRead(vData + (BufferLocation + i) * (1<<9), USB_TIMEOUT, Index); if ((ret != (1<<9)) || m_isCanceled) @@ -2831,7 +2841,7 @@ int SerialFlash_bulkPipeRead_Micron_4die(struct CAddressRange* AddrRange, unsign read_range.end=AddrRange->end-(0x1000000*EAR); read_range.start=AddrRange->start-(0x1000000*EAR); pageNum = read_range.length >> 9; - FlashCommand_SendCommand_SetupPacketForBulkRead(&read_range, modeRead, ReadCom,Chip_Info.AddrWidth,Chip_Info.ReadDummyLen, Index); + FlashCommand_SendCommand_SetupPacketForBulkRead(&read_range, modeRead, ReadCom,g_ChipInfo.AddrWidth,g_ChipInfo.ReadDummyLen, Index); for (i = 0; i < pageNum; ++i) { ret = BulkPipeRead(vData + i * ret, USB_TIMEOUT, Index); if ((ret != 512) || m_isCanceled) { @@ -2909,7 +2919,7 @@ int SerialFlash_bulkPipeRead_twoDie(struct CAddressRange* AddrRange, unsigned ch SerialFlash_doSelectDie(0,Index); } pageNum = read_range.length >> 9; - FlashCommand_SendCommand_SetupPacketForBulkRead(&read_range, modeRead, ReadCom,Chip_Info.AddrWidth,Chip_Info.ReadDummyLen, Index); + FlashCommand_SendCommand_SetupPacketForBulkRead(&read_range, modeRead, ReadCom,g_ChipInfo.AddrWidth,g_ChipInfo.ReadDummyLen, Index); for (i = 0; i < pageNum; ++i) { ret = BulkPipeRead(vData + (BufferLocation + i) * 512, USB_TIMEOUT, Index); if ((ret != 512) || m_isCanceled) @@ -2937,7 +2947,7 @@ int SerialFlash_bulkPipeRead_twoDie(struct CAddressRange* AddrRange, unsigned ch pageNum = range_die2.length >> 9; - FlashCommand_SendCommand_SetupPacketForBulkRead(&range_die2, modeRead, ReadCom,Chip_Info.AddrWidth,Chip_Info.ReadDummyLen, Index); + FlashCommand_SendCommand_SetupPacketForBulkRead(&range_die2, modeRead, ReadCom,g_ChipInfo.AddrWidth,g_ChipInfo.ReadDummyLen, Index); for (i = 0; i < pageNum; ++i) { ret = BulkPipeRead(vData + i * ret, USB_TIMEOUT, Index); @@ -2988,33 +2998,40 @@ int SerialFlash_is_protectbits_set(int Index) } bool SerialFlash_StartofOperation(int Index) { - if (strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large_2Die) != NULL || strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL || strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large) != NULL) { + if (strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large_2Die) != NULL || strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL || strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large) != NULL) { if (CN25Qxxx_Large_doWRVCR(0xFB, Index) == false) return false; if (CN25Qxxx_Large_doWRENVCR(0xFF, Index) == false) return false; return true; - } else if (strstr(Chip_Info.Class, SUPPORT_ST_M25Pxx) != NULL) { - if (strstr(Chip_Info.TypeName, "N25Q064") != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_ST_M25Pxx) != NULL) { + if (strstr(g_ChipInfo.TypeName, "N25Q064") != NULL) { if (CN25Qxxx_Large_doWRVCR(0xFB, Index) == false) return false; if (CN25Qxxx_Large_doWRENVCR(0xDF, Index) == false) return false; } - if (strstr(Chip_Info.TypeName, "N25Q128") != NULL) { + if (strstr(g_ChipInfo.TypeName, "N25Q128") != NULL) { if (CN25Qxxx_Large_doWRVCR(0xFB, Index) == false) return false; if (CN25Qxxx_Large_doWRENVCR(0xF7, Index) == false) return false; } } - if (strstr(Chip_Info.Class, SUPPORT_MACRONIX_MX25Lxxx_Large) != NULL) { - if ((strstr(Chip_Info.TypeName, "MX66U1G45GXDJ54") != NULL) || (strstr(Chip_Info.TypeName, "MX66U2G45GXRI54") != NULL)) { + if (strstr(g_ChipInfo.Class, SUPPORT_MACRONIX_MX25Lxxx_Large) != NULL) { + if ((strstr(g_ChipInfo.TypeName, "MX66U1G45GXDJ54") != NULL) || (strstr(g_ChipInfo.TypeName, "MX66U2G45GXRI54") != NULL)) { MX25Lxxx_Large_doWRCR(0x70, Index); } } + if((strstr(g_ChipInfo.TypeName,"TC58CVG1S3HRAIG" ) != NULL) ||(strstr(g_ChipInfo.TypeName,"TC58CVG1S3HRAIJ") != NULL) + ||(strstr(g_ChipInfo.TypeName,"TC58CVG0S3HRAIJ") != NULL)) + { + if(!SF_Nand_HSBSet(Index)) + return false; + } + return true; } @@ -3022,3 +3039,1468 @@ bool SerialFlash_EndofOperation(int Index) { return true; } + +void crc16l(WORD *crc, unsigned char rawdata) // +{ + unsigned int i; + for(i=0x80; i!=0; i>>=1) + { + if((*crc&0x8000)!=0) + {*crc<<=1; *crc^=0x1021;} + else + *crc<<=1; + if((rawdata&i)!=0) + *crc^=0x1021; + } + +} + +void CalculateCrc(WORD *crc, unsigned char* start, unsigned int Length) +{ + unsigned int i; + + for (i=0; i>16)|((g_ChipInfo.JedecDeviceID&0xFF00))|((g_ChipInfo.JedecDeviceID&0xFF)<<16)); + nandInfo.ChipIDMask=g_ChipInfo.ChipIDMask; + nandInfo.RealPagesize=g_ChipInfo.PageSizeInByte; //when scan bb, the size not include spare area size + nandInfo.PagesPerBlock=g_ChipInfo.BlockSizeInByte/g_ChipInfo.PageSizeInByte; + nandInfo.Blocks=g_ChipInfo.ChipSizeInByte/g_ChipInfo.BlockSizeInByte; + nandInfo.BlockCount=0; + nandInfo.BlockIndex=0; + + nandInfo.EN_spareArea= g_bSpareAreaUseFile; + nandInfo.MA_pagesize=g_ChipInfo.PageSizeInByte; + nandInfo.BeCmd=g_NANDContext.EraseCmd.ChipErase; + nandInfo.RdCmd=g_NANDContext.ReadCmd.SingleRead; + nandInfo.WrCmd=g_NANDContext.ProgramCmd.SingleProgram;//m_serial.ProgramCode; + nandInfo.AddrLen=g_ChipInfo.AddrWidth; + nandInfo.nCA_Rd=g_ChipInfo.nCA_Rd; + nandInfo.nCA_Wr=g_ChipInfo.nCA_Wr; + nandInfo.Dummy=g_ChipInfo.ReadDummyLen; + nandInfo.MaxERR_bits=g_ChipInfo.DefaultErrorBits; + nandInfo.BBMark=g_ChipInfo.BBMark;//800H is reserved for initial bad block mark + nandInfo.BB_BYTE_TYPE=0x11; //~0xFF + nandInfo.BBM_TYPE=0x00; + nandInfo.BBK_TOTAL=0; + nandInfo.UNprotect_type=1;//m_serial.is_EnableUnprotect; + nandInfo.En_internalECC= 0;//(g_bNandInternalECC)?1:0; + nandInfo.EraseStartBlock=0;//1:default enable + nandInfo.EraseEndBlock=(g_NANDContext.realChipSize/g_NANDContext.realBlockSize); + nandInfo.EraseStatus=0; + nandInfo.saveSTA=0; + nandInfo.rfu0=0; + nandInfo.perPageSizeForErrBit=g_ChipInfo.DefaultDataUnitSize; + if(strstr(g_ChipInfo.TypeName, "GD5F4GM5UExxG") != NULL) + nandInfo.SPA_pagesize=g_ChipInfo.SpareSizeInByte>>16;//g_ChipInfo.SpareSizeInBytem_context->chip.realSpareAreaSize; + else + nandInfo.SPA_pagesize=g_NANDContext.realSpareAreaSize; + + nandInfo.VFMODE= ((1<<3)|(g_ChipInfo.DefaultErrorBits<<8)); + //[3]==1:new: [15:8]Max Error Bit allowed + //[2:0]==MODE 0:DS 1:DSDSDS..DS 2:DDDD...DSSSS...S 3:DDD...D 4: for internal ECC skip + nandInfo.VFCOFGL=nandInfo.SPA_pagesize; + //for mode 0,1,2,3: + //[31:16]: Data Unit size; + //[15:0]: Ecc Unit size; + nandInfo.VFCOFGH=nandInfo.MA_pagesize; + //for mode 4: + //[31:16]: User Data mask + //[15:0]: Internal ECC address mask + nandInfo.staPVpagesize=nandInfo.SPA_pagesize; + nandInfo.staPVpages=nandInfo.MA_pagesize; + nandInfo.staPVsize=nandInfo.staPVpagesize*nandInfo.staPVpages; + + if(isErase == true){ + if(g_bNandForceErase ==true) + nandInfo.EraseMode=1; //force erase + else + nandInfo.EraseMode=2;//skip BB + + nandInfo.StartBB=0;////set 1, start BB scan + nandInfo.saveSTA=0; + }else{ + nandInfo.EraseMode=0; //do not erase, just scan bad block + nandInfo.StartBB=1; + nandInfo.saveSTA=0; // no standalone + } + if(strstr(g_ChipInfo.Class,"W25N512GWxIN")) + nandInfo.ReadSatus_mode=2;//2:w25N512G + else + nandInfo.ReadSatus_mode=1;//1:other + + for(int i=0;i<34;i++) + nandInfo.rfu[i]=0; + + nandInfo.ReadSatus_mode=1;//1:other + memcpy(buf, &nandInfo.Hearder,sizeof(nandInfo)); + WORD crc=0xffff; + CalculateCrc(&crc,buf,sizeof(nandInfo)-2); + nandInfo.crc=crc; + // + memset(buf,0,sizeof(nandInfo)); + memcpy(buf, &nandInfo.Hearder,sizeof(nandInfo)); + + if(!DownloadICInfoForNand(0x200,USBIndex)) + return; + + BulkPipeWrite(buf,sizeof(buf),USB_TIMEOUT,USBIndex); + + #if 0 + printf(" nandInfo.Hearder=0xA1A1;\n "); + printf(" nandInfo.Version=0x01; \n "); + printf(" nandInfo.Type=0x01; \n"); + printf(" nandInfo.STsize=%d; \n",nandInfo.STsize); + printf(" nandInfo.ChipID=0x%x\n",nandInfo.ChipID); + printf(" nandInfo.ChipIDMask=0x%lx\n",g_ChipInfo.ChipIDMask); + printf(" nandInfo.RealPagesize=0x%x\n",nandInfo.RealPagesize); + printf(" nandInfo.PagesPerBlock=0x%x\n",nandInfo.PagesPerBlock); + printf(" nandInfo.Blocks=0x%x\n",nandInfo.Blocks); + printf(" nandInfo.EN_spareArea=0x%x\n",nandInfo.EN_spareArea); + printf(" nandInfo.SPA_pagesize=0x%x\n",nandInfo.SPA_pagesize); + printf(" nandInfo.MA_pagesize=0x%x\n",nandInfo.MA_pagesize); + printf(" nandInfo.BeCmd=0x%x\n",nandInfo.BeCmd); + printf(" nandInfo.RdCmd=0x%x\n",nandInfo.RdCmd); + printf(" nandInfo.WrCmd=0x%x\n",nandInfo.WrCmd); + printf(" nandInfo.AddrLen=0x%x\n",nandInfo.AddrLen); + printf(" nandInfo.nCA_Rd=0x%x\n",nandInfo.nCA_Rd); + printf(" nandInfo.nCA_Wr=0x%x\n",nandInfo.nCA_Wr); + printf(" nandInfo.Dummy=0x%x\n",nandInfo.Dummy); + printf(" nandInfo.MaxERR_bits=0x%x\n",nandInfo.MaxERR_bits); + printf(" nandInfo.BBMark=0x%x\n",nandInfo.BBMark); + printf(" nandInfo.BB_BYTE_TYPE=0x%x\n",nandInfo.BB_BYTE_TYPE); + printf(" nandInfo.BBM_TYPE=0x%x\n",nandInfo.BBM_TYPE); + printf(" nandInfo.BBK_TOTAL=0x%x\n",nandInfo.BBK_TOTAL); + printf(" nandInfo.StartBB=0x%x\n",nandInfo.StartBB); + printf(" nandInfo.UNprotect_type=0x%x\n",nandInfo.UNprotect_type); + printf(" nandInfo.En_internalECC=0x%x\n",nandInfo.En_internalECC); + printf(" nandInfo.EraseStartBlock=0x%x\n",nandInfo.EraseStartBlock); + printf(" nandInfo.EraseEndBlock=0x%x\n",nandInfo.EraseEndBlock); + printf(" nandInfo.EraseMode=0x%x\n",nandInfo.EraseMode); + printf(" nandInfo.EraseStatus=0x%x\n",nandInfo.EraseStatus); + printf(" nandInfo.saveSTA=0x%x\n",nandInfo.saveSTA); + printf(" nandInfo.VFMODE=0x%x\n",nandInfo.VFMODE); + printf(" nandInfo.VFCOFGL=0x%x\n",nandInfo.VFCOFGL); + printf(" nandInfo.VFCOFGH=0x%x\n",nandInfo.VFCOFGH); + printf(" nandInfo.staPVpagesize=0x%x\n",nandInfo.staPVpagesize); + printf(" nandInfo.staPVpages=0x%x\n",nandInfo.staPVpages); + printf(" nandInfo.staPVsize=0x%x\n",nandInfo.staPVsize); + printf(" nandInfo.perPageSizeForErrBit=0x%x\n",nandInfo.perPageSizeForErrBit); + printf(" nandInfo.ReadSatus_mode=0x%x\n",nandInfo.ReadSatus_mode); + printf(" nandInfo.crc=0x%x\n",nandInfo.crc); + #endif +} + +bool SPINAND_ScanBadBlock( unsigned short *BBT, unsigned short *BBT_Cnt, int USBIndex) +{ + if (!SerialFlash_StartofOperation(USBIndex)) + return false; + #if 1 + SELECT_SPI_NAND_INFO nandInfo; + DownloadICInfo( false, USBIndex); + #else + SELECT_SPI_NAND_INFO nandInfo; + nandInfo.Hearder=0xA1A1; + nandInfo.Version=0x01; + nandInfo.Type=0x01; + + nandInfo.STsize=sizeof(nandInfo); + nandInfo.ChipID=(((g_ChipInfo.JedecDeviceID&0xFF0000)>>16)|((g_ChipInfo.JedecDeviceID&0xFF00))|((g_ChipInfo.JedecDeviceID&0xFF)<<16)); + nandInfo.ChipIDMask=g_ChipInfo.ChipIDMask; + + nandInfo.RealPagesize=g_ChipInfo.PageSizeInByte; //when scan bb, the size not include spare area size + + nandInfo.PagesPerBlock=g_ChipInfo.BlockSizeInByte/g_ChipInfo.PageSizeInByte; + nandInfo.Blocks=g_ChipInfo.ChipSizeInByte/g_ChipInfo.BlockSizeInByte; + #if 0 + printf(" nandInfo.Hearder=0xA1A1;\n "); + printf(" nandInfo.Version=0x01; \n "); + printf(" nandInfo.Type=0x01; \n"); + printf(" nandInfo.STsize=%d; \n",nandInfo.STsize); + printf(" nandInfo.ChipID=0x%x\n",nandInfo.ChipID); + printf(" nandInfo.ChipIDMask=0x%lx\n",g_ChipInfo.ChipIDMask); + printf(" nandInfo.RealPagesize=0x%x\n",nandInfo.RealPagesize); + printf(" nandInfo.PagesPerBlock=0x%x\n",nandInfo.PagesPerBlock); + printf(" nandInfo.Blocks=0x%x\n",nandInfo.Blocks); + #endif + nandInfo.BlockCount=0; + nandInfo.BlockIndex=0; + + nandInfo.EN_spareArea= g_bSpareAreaUseFile; + if(strstr(g_ChipInfo.TypeName, "GD5F4GM5UExxG") != NULL) + nandInfo.SPA_pagesize=g_ChipInfo.SpareSizeInByte>>16;//g_ChipInfo.SpareSizeInBytem_context->chip.realSpareAreaSize; + else + nandInfo.SPA_pagesize=g_NANDContext.realSpareAreaSize; + nandInfo.MA_pagesize=g_ChipInfo.PageSizeInByte; + #if 0 + printf(" nandInfo.EN_spareArea=0x%x\n",nandInfo.EN_spareArea); + printf(" nandInfo.SPA_pagesize=0x%x\n",nandInfo.SPA_pagesize); + printf(" nandInfo.MA_pagesize=0x%x\n",nandInfo.MA_pagesize); + #endif + nandInfo.BeCmd=g_NANDContext.EraseCmd.ChipErase; + nandInfo.RdCmd=g_NANDContext.ReadCmd.SingleRead; + nandInfo.WrCmd=g_NANDContext.ProgramCmd.SingleProgram;//m_serial.ProgramCode; + nandInfo.AddrLen=g_ChipInfo.AddrWidth; + nandInfo.nCA_Rd=g_ChipInfo.nCA_Rd; + nandInfo.nCA_Wr=g_ChipInfo.nCA_Wr; + nandInfo.Dummy=g_ChipInfo.ReadDummyLen; + nandInfo.MaxERR_bits=g_ChipInfo.DefaultErrorBits; + #if 0 + printf(" nandInfo.BeCmd=0x%x\n",nandInfo.BeCmd); + printf(" nandInfo.RdCmd=0x%x\n",nandInfo.RdCmd); + printf(" nandInfo.WrCmd=0x%x\n",nandInfo.WrCmd); + printf(" nandInfo.AddrLen=0x%x\n",nandInfo.AddrLen); + printf(" nandInfo.nCA_Rd=0x%x\n",nandInfo.nCA_Rd); + printf(" nandInfo.nCA_Wr=0x%x\n",nandInfo.nCA_Wr); + printf(" nandInfo.Dummy=0x%x\n",nandInfo.Dummy); + printf(" nandInfo.MaxERR_bits=0x%x\n",nandInfo.MaxERR_bits); + #endif + nandInfo.BBMark=g_ChipInfo.BBMark;//800H is reserved for initial bad block mark + nandInfo.BB_BYTE_TYPE=0x11; //~0xFF + nandInfo.BBM_TYPE=0x00; + nandInfo.BBK_TOTAL=0; + #if 0 + printf(" nandInfo.BBMark=0x%x\n",nandInfo.BBMark); + printf(" nandInfo.BB_BYTE_TYPE=0x%x\n",nandInfo.BB_BYTE_TYPE); + printf(" nandInfo.BBM_TYPE=0x%x\n",nandInfo.BBM_TYPE); + printf(" nandInfo.BBK_TOTAL=0x%x\n",nandInfo.BBK_TOTAL); + #endif + nandInfo.StartBB=1; + nandInfo.UNprotect_type=1;//m_serial.is_EnableUnprotect; + nandInfo.En_internalECC= 0;//(g_bNandInternalECC)?1:0; + nandInfo.EraseStartBlock=0;//1:default enable + nandInfo.EraseEndBlock=(g_NANDContext.realChipSize/g_NANDContext.realBlockSize); + nandInfo.EraseMode=0; //do not erase + nandInfo.EraseStatus=0; + nandInfo.saveSTA=0; + #if 0 + printf(" nandInfo.StartBB=0x%x\n",nandInfo.StartBB); + printf(" nandInfo.UNprotect_type=0x%x\n",nandInfo.UNprotect_type); + printf(" nandInfo.En_internalECC=0x%x\n",nandInfo.En_internalECC); + printf(" nandInfo.EraseStartBlock=0x%x\n",nandInfo.EraseStartBlock); + printf(" nandInfo.EraseEndBlock=0x%x\n",nandInfo.EraseEndBlock); + printf(" nandInfo.EraseMode=0x%x\n",nandInfo.EraseMode); + printf(" nandInfo.EraseStatus=0x%x\n",nandInfo.EraseStatus); + printf(" nandInfo.saveSTA=0x%x\n",nandInfo.saveSTA); + #endif + nandInfo.rfu0=0; + nandInfo.perPageSizeForErrBit=g_ChipInfo.DefaultDataUnitSize; + + if(strstr(g_ChipInfo.Class,"W25N512GWxIN")) + nandInfo.ReadSatus_mode=2;//2:w25N512G + else + nandInfo.ReadSatus_mode=1;//1:other + #if 0 + nandInfo.VFMODE= ((1<<3)|(g_ChipInfo.DefaultErrorBits<<8)); + //[3]==1:new: [15:8]Max Error Bit allowed + //[2:0]==MODE 0:DS 1:DSDSDS..DS 2:DDDD...DSSSS...S 3:DDD...D 4: for internal ECC skip + nandInfo.VFCOFGL=nandInfo.SPA_pagesize; + //for mode 0,1,2,3: + //[31:16]: Data Unit size; + //[15:0]: Ecc Unit size; + nandInfo.VFCOFGH=nandInfo.MA_pagesize; + //for mode 4: + //[31:16]: User Data mask + //[15:0]: Internal ECC address mask + nandInfo.staPVpagesize=0xcdcd;//nandInfo.SPA_pagesize; + nandInfo.staPVpages=0xcdcdcdcd;//nandInfo.MA_pagesize; + nandInfo.staPVsize=0xcdcdcdcd;//nandInfo.staPVpagesize*nandInfo.staPVpages; + printf(" nandInfo.VFMODE=0x%x\n",nandInfo.VFMODE); + printf(" nandInfo.VFCOFGL=0x%x\n",nandInfo.VFCOFGL); + printf(" nandInfo.VFCOFGH=0x%x\n",nandInfo.VFCOFGH); + printf(" nandInfo.staPVpagesize=0x%x\n",nandInfo.staPVpagesize); + printf(" nandInfo.staPVpages=0x%x\n",nandInfo.staPVpages); + printf(" nandInfo.staPVsize=0x%x\n",nandInfo.staPVsize); + #endif + for(int i=0;i<34;i++) + nandInfo.rfu[i]=0; + + nandInfo.ReadSatus_mode=1;//1:other + #if 0 + printf(" nandInfo.perPageSizeForErrBit=0x%x\n",nandInfo.perPageSizeForErrBit); + printf(" nandInfo.ReadSatus_mode=0x%x\n",nandInfo.ReadSatus_mode); + #endif + unsigned char buf[sizeof(nandInfo)]={0}; + memcpy(buf, &nandInfo.Hearder,sizeof(nandInfo)); + WORD crc=0xffff; + CalculateCrc(&crc,buf,sizeof(nandInfo)-2); + nandInfo.crc=crc; + //printf(" nandInfo.crc=0x%x\n",nandInfo.crc); + memset(buf,0,sizeof(nandInfo)); + memcpy(buf, &nandInfo.Hearder,sizeof(nandInfo)); + //printf(" sizeof(nandInfo)=%ld\n", sizeof(nandInfo)); + #endif + Sleep(2000); + Nand_ReadICInfo(&nandInfo,BBT,BBT_Cnt,USBIndex); + return true; +} + +bool DownloadICInfoForNand(DWORD dwInfoLen, int USBIndex)//SF700 +{ + CNTRPIPE_RQ rq ; + + unsigned char vInfoLen[4]; //0x200 + dwInfoLen=dwInfoLen>>9; + vInfoLen[0] = ((unsigned char)(dwInfoLen)); + vInfoLen[1] = ((unsigned char)(dwInfoLen>>8)); + vInfoLen[2] = ((unsigned char)(dwInfoLen>>16)); + vInfoLen[3] = ((unsigned char)(dwInfoLen>>24)); + + rq.Function = URB_FUNCTION_VENDOR_ENDPOINT ; + rq.Direction = VENDOR_DIRECTION_OUT ; + rq.Request = DL_IC_INFO_NAND ; + rq.Value = 0 ; + rq.Index = 0 ; + rq.Length = 1; + + if(!OutCtrlRequest(&rq, vInfoLen, 1,USBIndex)) + return false; + + return true; +} + +bool ReadICInfoForNand(DWORD dwInfoLen, int USBIndex) +{ //SF700 + CNTRPIPE_RQ rq ; + + unsigned char vInfoLen[4]; //0x200 + + vInfoLen[0] = (dwInfoLen); + vInfoLen[1] = (dwInfoLen>>8); + vInfoLen[2] = (dwInfoLen>>16); + vInfoLen[3] = (dwInfoLen>>24); + + rq.Function = URB_FUNCTION_VENDOR_ENDPOINT ; + rq.Direction = VENDOR_DIRECTION_OUT ; + rq.Request = READ_IC_INFO_NAND ; + rq.Value = 0 ; + rq.Index = 0 ; + rq.Length = 4 ; + + if(!OutCtrlRequest(&rq, vInfoLen, sizeof(vInfoLen), USBIndex)) + return false; + return true; +} + + +bool Nand_ReadICInfo(SELECT_SPI_NAND_INFO *nandInfo, unsigned short *BBT, unsigned short *BBT_Cnt,int USBIndex) +{ +#define min(a, b) (a > b ? b : a) + + unsigned char vData[0x400]; + //SELECT_SPI_NAND_INFO nandInfo; + if(!ReadICInfoForNand(0x400,USBIndex)) + return false; + + for(int i=0;i<2;i++) + { + if(!BulkPipeRead(vData+i*0x200, USB_TIMEOUT, USBIndex)) + return false ; + } + memcpy((unsigned char*)&nandInfo->Hearder,vData, sizeof(SELECT_SPI_NAND_INFO)); + //printf("nandInfo.BBK_TOTAL=%d\n",nandInfo->BBK_TOTAL); + memcpy(BBT,vData+0x200,min((nandInfo->BBK_TOTAL*2),0x200)); + *BBT_Cnt = nandInfo->BBK_TOTAL; + //for(unsigned int i=0; i < min((nandInfo.BBK_TOTAL),0x100); i++) + // printf("BBT[%d]=%d\n",i, BBT[i]); + return true; +} + +bool Nand_waitForWEL(int USBIndex) +{ + size_t i = g_ChipInfo.Timeout*100; + unsigned char cSR; + unsigned char vOut[2]; + + vOut[0] = WREN; + if(!FlashCommand_SendCommand_OutOnlyInstruction(vOut,1,USBIndex)) + return false; + Sleep(1); + i = g_ChipInfo.Timeout*100; + do{ + vOut[0] = 0x0F;//.GetFeatures; + vOut[1] = 0xC0;//.push_back(m_context->serialFlash.SRStatus); + if(!FlashCommand_SendCommand_OneOutOneIn(vOut,2,&cSR,1,USBIndex)) + return false; + Sleep(100); + }while(((cSR & 0x02)== 0) && (i-- > 1)) ; + + return true; +} +bool Nand_waitForOIP(int USBIndex) +{ + size_t i = g_ChipInfo.Timeout*100; + unsigned char cSR; + unsigned char vOut[2]; + do{ + vOut[0] = 0x0F;//.GetFeatures; + vOut[1] = 0xC0;//.push_back(m_context->serialFlash.SRStatus); + if(!FlashCommand_SendCommand_OneOutOneIn(vOut,2,&cSR,1,USBIndex)) + return false; + Sleep(100); + }while((cSR & 0x01) && (i-- > 1)) ; + + if((i<=0)||((cSR&0x0C)!=0)) + return false; + + Sleep(2); + return true; +} + +bool Nand_WRSRProtection(unsigned char cSR,int USBIndex) +{ + if(!Nand_waitForWEL(USBIndex)) + return false; + unsigned char vOut[3]; + vOut[0] = 0x1F;//.push_back(m_context->serialFlash.SetFeatures); + vOut[1] = 0xA0;//.push_back(m_context->serialFlash.SRProtection); + vOut[2] = cSR;//.push_back(cSR); + if(!FlashCommand_SendCommand_OutOnlyInstruction(vOut,sizeof(vOut),USBIndex)) + return false; + Sleep(2); + return true; +} + +bool Nand_WRSRFeature1(unsigned char cSR,int USBIndex) +{ + if(!Nand_waitForWEL(USBIndex)) + return false; + unsigned char vOut[3]; + vOut[0] = 0x1F;//.push_back(m_context->serialFlash.SetFeatures); + vOut[1] = 0xB0;//.push_back(m_context->serialFlash.SRFeature1); + vOut[2] = cSR;//.push_back(cSR); + if(!FlashCommand_SendCommand_OutOnlyInstruction(vOut,sizeof(vOut),USBIndex)) + return false; + Sleep(2); + return true; +} +bool Nand_WRSRStatus(unsigned char cSR,int USBIndex) +{ + if(!Nand_waitForWEL(USBIndex)) + return false; + unsigned char vOut[3]; + vOut[0] = 0x1F;//. push_back(m_context->serialFlash.SetFeatures); + vOut[1] = 0xC0;//.push_back(m_context->serialFlash.SRStatus); + vOut[2] = cSR;//.push_back(cSR); + if(!FlashCommand_SendCommand_OutOnlyInstruction(vOut,sizeof(vOut), USBIndex)) + return false; + Sleep(2); + return true; +} +bool Nand_WRSRFeature2(unsigned char cSR,int USBIndex) +{ + if(!Nand_waitForWEL(USBIndex)) + return false; + unsigned char vOut[3]; + vOut[0] = 0x1F;//.push_back(m_context->serialFlash.SetFeatures); + vOut[1] = 0xD0;//.push_back(m_context->serialFlash.SRFeature2); + vOut[2] = cSR;//.push_back(cSR); + if(!FlashCommand_SendCommand_OutOnlyInstruction(vOut, sizeof(vOut), USBIndex)) + return false; + Sleep(2); + return true; +} + +bool Nand_RDSRProtection(unsigned char *cSR,int USBIndex) +{ + unsigned char vOut[2], vIn ; + vOut[0] = 0x0F;//.push_back(m_context->serialFlash.GetFeatures); + vOut[1] = 0xA0;//.push_back(m_context->serialFlash.SRProtection); + if(!FlashCommand_SendCommand_OneOutOneIn(vOut,sizeof(vOut), &vIn, 1, USBIndex)) + return false; + *cSR=vIn; + return true; +} + +bool Nand_RDSRFeature1(unsigned char *cSR,int USBIndex) +{ + unsigned char vOut[2], vIn ; + vOut[0] = 0x0F;//.push_back(m_context->serialFlash.GetFeatures); + vOut[1] = 0xB0;//.push_back(m_context->serialFlash.SRFeature1); + if(!FlashCommand_SendCommand_OneOutOneIn(vOut, sizeof(vOut), &vIn, 1, USBIndex)) + return false; + *cSR=vIn; + return true; +} +bool Nand_RDSRStatus1(unsigned char *cSR,int USBIndex) +{ + unsigned char vOut[2], vIn ; + vOut[0] = 0x0F;//.push_back(m_context->serialFlash.GetFeatures); + vOut[1] = 0xC0;//.push_back(m_context->serialFlash.SRStatus); + if(!FlashCommand_SendCommand_OneOutOneIn(vOut, sizeof(vOut), &vIn, 1, USBIndex)) + return false; + *cSR=vIn; + return true; +} +bool Nand_RDSRFeature2(unsigned char *cSR,int USBIndex) +{ + unsigned char vOut[2], vIn ; + vOut[0] = 0x0F;//.push_back(m_context->serialFlash.GetFeatures); + vOut[1] = 0xD0;//.push_back(m_context->serialFlash.SRFeature2); + if(!FlashCommand_SendCommand_OneOutOneIn(vOut, sizeof(vOut), &vIn, 1, USBIndex)) + return false; + *cSR=vIn; + return true; +} + + +bool Nand_Winbond_RDSR1(unsigned char *cSR,int USBIndex) +{ + unsigned char vOut[2], vIn ; + vOut[0] = 0x0F;//.push_back(m_context->serialFlash.GetFeatures); + vOut[1] = 0xA0;//.push_back(m_context->serialFlash.Winbond_SR1); + if(!FlashCommand_SendCommand_OneOutOneIn(vOut, sizeof(vOut), &vIn, 1, USBIndex)) + return false; + *cSR=vIn; + return true; +} +bool Nand_Winbond_RDSR2(unsigned char *cSR,int USBIndex) +{ + unsigned char vOut[2], vIn ; + vOut[0] = 0x0F;//.push_back(m_context->serialFlash.GetFeatures); + vOut[1] = 0xB0;//.push_back(m_context->serialFlash.Winbond_SR2); + if(!FlashCommand_SendCommand_OneOutOneIn(vOut, sizeof(vOut), &vIn, 1, USBIndex)) + return false; + *cSR=vIn; + return true; +} +bool Nand_Winbond_RDSR3(unsigned char *cSR,int USBIndex) +{ + unsigned char vOut[2], vIn ; + vOut[0] = 0x0F;//.push_back(m_context->serialFlash.GetFeatures); + vOut[1] = 0xC0;//.push_back(m_context->serialFlash.Winbond_SR3); + if(!FlashCommand_SendCommand_OneOutOneIn(vOut, sizeof(vOut), &vIn, 1, USBIndex)) + return false; + *cSR=vIn; + return true; +} + +bool Nand_Winbond_WRSR1(unsigned char cSR,int USBIndex) +{ + if(!Nand_waitForWEL(USBIndex)) + return false; + unsigned char vOut[3]; + vOut[0] = 0x1F;//.push_back(m_context->serialFlash.SetFeatures); + vOut[1] = 0xA0;//.push_back(m_context->serialFlash.Winbond_SR1); + vOut[2] = cSR;//.push_back(cSR); + if(!FlashCommand_SendCommand_OutOnlyInstruction(vOut, sizeof(vOut), USBIndex)) + return false; + return true; +} +bool Nand_Winbond_WRSR2(unsigned char cSR,int USBIndex) +{ + if(!Nand_waitForWEL(USBIndex)) + return false; + unsigned char vOut[3]; + vOut[0] = 0x1F;//.push_back(m_context->serialFlash.SetFeatures); + vOut[1] = 0xB0;//.push_back(m_context->serialFlash.Winbond_SR2); + vOut[2] = cSR;//.push_back(cSR); + if(!FlashCommand_SendCommand_OutOnlyInstruction(vOut, sizeof(vOut), USBIndex)) + return false; + return true; +} + +bool SF_Nand_HSBSet( int Index) +{ + unsigned char cSR=0; + Nand_RDSRFeature1(&cSR,Index); + Nand_WRSRFeature1(cSR&0xFD,Index);//HSB + Nand_RDSRFeature1(&cSR,Index); + + if((cSR&0x02)!=0x00) + return false; + return true; +} + +bool SPINAND_ProtectBlock(bool bProtect,int USBIndex) +{ + //Protect A0H BRWD/Reserved/BP2/BP1/BP0/INV/CMP/Reserve + bool result = false ; + unsigned char tmpSRVal=0; + unsigned char dstSRVal =0; + int numOfRetry = 100 ; + + result = Nand_RDSRProtection(&dstSRVal,USBIndex) ; + + // un-protect block ,set BRWD BP2 BP1 BP0 to 0 + dstSRVal &= (~0xFD) ; + + // protect block ,set BP2 BP1 BP2 to 1 + if(bProtect){ + dstSRVal += 0xFD ; // B8 : 1011 1000 + } + + if((g_ChipInfo.ProtectBlockMask & 0x02) ||((strstr(g_ChipInfo.TypeName,"S35ML01G3") != NULL) ||(strstr(g_ChipInfo.TypeName,"S35ML02G3")!= NULL) + ||(strstr(g_ChipInfo.TypeName, "S35ML04G3")!=NULL))) + { + dstSRVal |= 0x02; + result = Nand_WRSRProtection(dstSRVal,USBIndex) ; + } + do + { // WIP = TRUE; + result &= Nand_WRSRProtection(dstSRVal,USBIndex) ; + result &= Nand_RDSRProtection(&tmpSRVal,USBIndex) ; + + if(! result) + return false; + numOfRetry -- ; + }while( (tmpSRVal & 0x01) && numOfRetry > 0); + + + if((tmpSRVal ^ dstSRVal)& 0x0C ) + return false; + + return true; + +} + +bool Nand_BUFSet( int USBIndex) +{ + unsigned char cSR=0; + Nand_Winbond_RDSR2(&cSR,USBIndex); + cSR&=0xF9; + Nand_Winbond_WRSR2(cSR|0x08,USBIndex); + Nand_Winbond_RDSR2(&cSR,USBIndex); + if((cSR&0x08)!=0x08) + return false; + return true; +} + +bool Nand_CaculateErrorBit(unsigned char *pData, unsigned char *pFile, unsigned int ptr_size) +{ + unsigned int WholeFileLenth = ptr_size;//vData.size(); + //unsigned int UnitCount = 0; + if(g_bSpareAreaUseFile == true) + { + for(unsigned int PageCount=0 ; PageCount< WholeFileLenth/g_NANDContext.realPageSize ; PageCount++) + { + unsigned char aPageSizeReadBuf[g_NANDContext.realPageSize]; + unsigned char aPageSizeFileBuf[g_NANDContext.realPageSize]; + memset(aPageSizeReadBuf, 0xFF, g_NANDContext.realPageSize); + memset(aPageSizeFileBuf, 0xFF, g_NANDContext.realPageSize); + memcpy(aPageSizeReadBuf, pData+PageCount*g_NANDContext.realPageSize, g_NANDContext.realPageSize); + memcpy(aPageSizeFileBuf, pFile+PageCount*g_NANDContext.realPageSize, g_NANDContext.realPageSize); + + unsigned int DataUnitCount = (g_NANDContext.realPageSize/g_ChipInfo.DefaultDataUnitSize); + + for(unsigned int i=0;i>c)&0x01)!=((uc2>>c)&0x01)) + { + if(errorbit>c)&0x01)!=((uc2>>c)&0x01)) + { + if(errorbit>9, mcode_ProgramCode_4Adr,g_NANDContext.realPageSize, + BlockPages,mcode_Program,g_ChipInfo.AddrWidth, g_ChipInfo.ReadDummyLen,g_ChipInfo.nCA_Wr,USBIndex); + size_t WriteCounter=g_NANDContext.realBlockSize>>9 ; + for(size_t i = 0; i < WriteCounter; ++ i) + { + BulkPipeWrite(pBuf, 1<<9, USB_TIMEOUT,USBIndex); + pBuf += (1<<9); + } + free(pBuf); + return true; +} + + +unsigned int SF_GetLoop(const struct CAddressRange* AddrRange, unsigned int uiUnit) +{ + struct CAddressRange AddrLoop;//(*AddrRange); + AddrLoop.start = AddrRange->start; + AddrLoop.end= AddrRange->end; + AddrLoop.start= AddrRange->start-(AddrRange->start%uiUnit); + AddrLoop.end= AddrLoop.end + ((AddrLoop.end % uiUnit)? (uiUnit-(AddrLoop.end % uiUnit)):0); + AddrLoop.length = AddrLoop.end-AddrLoop.start; + unsigned int loop = AddrLoop.length/uiUnit; + return loop; +} + +bool SPINAND_EnableInternalECC(bool is_ENECC,int USBIndex) +{ + unsigned char ucData=0,ucTempData=0; + // if((g_ChipInfo.TypeName,"MX35LF1G24") != NULL)) + // return true; + if(!g_ChipInfo.ECCEnable) + return true; + if(!Nand_RDSRFeature1(&ucData,USBIndex)) + return false; + ucTempData=ucData; + + + if(is_ENECC) + { + if((ucTempData&0x10) == 0x10) + return true; + if(!Nand_WRSRFeature1(ucData|0x10,USBIndex)) + return false; + if(!Nand_RDSRFeature1(&ucTempData,USBIndex)) + return false; + if(ucTempData==(ucData|0x10)) + return true; + else + return false; + } + else + { + ucData&=0xEF; + if(!Nand_WRSRFeature1(ucData,USBIndex)) + return false; + if(!Nand_RDSRFeature1(&ucTempData,USBIndex)) + return false; + if((ucTempData&0x10)==0x10) + return false; + } + return true; +} + +bool SPINAND_DisableContinueRead(int USBIndex) +{ + if((strstr(g_ChipInfo.TypeName,"MT29F4G") != NULL) + ||(strstr(g_ChipInfo.TypeName,"F50L4G41XB") != NULL) + ||(strstr(g_ChipInfo.TypeName,"TC58CVG2S0HRAIJ") != NULL)) + { + unsigned char ucData=0,ucTempData=0; + + if(!Nand_RDSRFeature1(&ucData,USBIndex)) + return false; + if(!Nand_WRSRFeature1(ucData&0xFC,USBIndex)) + return false; + if(!Nand_RDSRFeature1(&ucTempData,USBIndex)) + return false; + if(ucTempData!=(ucData&0xFC)) + return false; + } + else if((strstr(g_ChipInfo.TypeName, "W25N512GWxIT") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N512GWxIG") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N512GVxxG") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N512GVxxR") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N01GWxxIG") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N01GVxxIT") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N01GVxxIG") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N01JWxxIG") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N01JWxxIT") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N02JWxxIC") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N02JWxxIF") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W35N01JWxxxG") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W35N01JWxxxT") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N04KVxxIR") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N04KVxxIU") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N02KVxxIR") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N01KVxxIR") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N01KVxxIU") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N04KWxxIR") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N04KWxxIU") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W35N02JW") != NULL)) + { + if(!SPINAND_EnableInternalECC(true,USBIndex)) + return false; + if(!Nand_BUFSet(USBIndex)) + return false; + } + return true; +} + +bool SPINAND_EnableQuadIO(bool bENQuad,bool boRW,int Index) +{ + if(!boRW) + { + return true; + } + if((strstr(g_ChipInfo.TypeName,"W25N512GWxIT") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N512GWxIG") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N512GVxxG") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N512GVxxT") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N512GVxxR") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N512GWxIG") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N01GWxxIG") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N01GVxxIT") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N01GVxxIG") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N01JWxxIG") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N01JWxxIT") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N02JWxxIC") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W25N02JWxxIF") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W35N01JWxxxG") != NULL) + ||(strstr(g_ChipInfo.TypeName,"W35N01JWxxxT") != NULL) + ||(strstr(g_ChipInfo.TypeName,"S35ML02G3") != NULL)) + { + + return true; + } + unsigned char ucData=0,ucTempData=0; + + if(!Nand_RDSRFeature1(&ucData,Index)) + return false; + if(!bENQuad) //disable quad io + { + ucData&=0xFE; + if(!Nand_WRSRFeature1(ucData,Index)) + return false; + if(!Nand_RDSRFeature1(&ucTempData,Index)) + return false; + if(ucTempData!=ucData) + return false; + } + else + { + if(!Nand_WRSRFeature1(ucData|0x01,Index)) + return false; + if(!Nand_RDSRFeature1(&ucTempData,Index)) + return false; + if(ucTempData!=(ucData|0x01)) + return false; + } + return true; +} + +bool SPINAND_chipErase(int USBIndex) +{ + if(! SPINAND_ProtectBlock(false,USBIndex) ) + return false ; + + unsigned short vICInfo[0x200]; + unsigned short cnt=0; + unsigned char ucSR=0; + SELECT_SPI_NAND_INFO nandInfo; + SetSPIClockDefault(USBIndex); + DownloadICInfo(true,USBIndex); + SetSPIClock(USBIndex); + //Sleep(2000); + Nand_ReadICInfo(&nandInfo,vICInfo,&cnt,USBIndex); + + if(nandInfo.EraseStatus!=0) + { + return false ; + } + + if(!Nand_RDSRStatus1(&ucSR,USBIndex)) + return false; + return true ; +} + + +bool Nand_bulkPipeVerify(struct CAddressRange* AddrRange,unsigned char modeRead,unsigned char ReadCom, int USBIndex) +{ +// if(!&g_ChipInfo) +// return false; + + size_t BlockPages=g_NANDContext.realBlockSize/g_NANDContext.realPageSize; + unsigned char *pData = NULL;//[0x1000000]; + unsigned char *pFile = pBufferforLoadedFile; + size_t ReadCounter=0; + size_t divider=16; + + pData = (unsigned char*)malloc(g_NANDContext.realBlockSize); + memset(pData, 0xFF, g_NANDContext.realBlockSize); + DWORD StartBlock = AddrRange->start/g_NANDContext.realBlockSize; + DWORD StartPage = AddrRange->start/g_NANDContext.realPageSize; + + unsigned int dwAddr=0; + if(BlockPages==256) + dwAddr=((StartPage & 0x3F)|((StartBlock<<6)& 0x7FFC0 )); + else if(BlockPages==128) + dwAddr=((StartPage & 0x7F)|((StartBlock<<7)& 0x7FF80 )); + else + dwAddr=((StartPage & 0x3F)|((StartBlock<<6)& 0x3FFC0)) ; + + struct CAddressRange read_range;//(AddrRange); + read_range.start = AddrRange->start; + read_range.end = AddrRange->end; + read_range.length = AddrRange->length; + + size_t RealReadSize=read_range.length; + + FlashCommand_SendCommand_SetupPacketForBulkReadNAND(dwAddr,RealReadSize>>9, modeRead,g_NANDContext.realPageSize,BlockPages,ReadCom,g_ChipInfo.AddrWidth,g_ChipInfo.ReadDummyLen,g_ChipInfo.nCA_Rd,USBIndex); + + ReadCounter=(RealReadSize/(1< vData(RunUnitSize,0xFF); + pData = (unsigned char* )malloc(RunUnitSize); + memset(pData, 0xFF, RunUnitSize); + + if((AddrRange->start/RunUnitSize)!=(AddrRange->end/RunUnitSize)) + { + struct CAddressRange range_temp;//(*AddrRange); + range_temp.start=AddrRange->start; + range_temp.end=AddrRange->end; + range_temp.length=AddrRange->end-AddrRange->start; + + //size_t baseAddr=AddrRange->start-(AddrRange->start%RunUnitSize); + size_t loop=SF_GetLoop(AddrRange ,RunUnitSize); + + for(size_t j=0; jstart-(AddrRange->start%RunUnitSize)+(RunUnitSize*(j+1)); + + if(j==0) + range_temp.start=AddrRange->start; + else + range_temp.start=AddrRange->start-(AddrRange->start%RunUnitSize)+(RunUnitSize*j); + + DWORD StartBlock = range_temp.start/g_NANDContext.realBlockSize; + DWORD StartPage = range_temp.start/g_NANDContext.realPageSize; + + range_temp.length = range_temp.end-range_temp.start; + unsigned int dwAddr=0; + if(BlockPages==256) + dwAddr=((StartPage & 0x3F)|((StartBlock<<6)& 0x7FFC0 )); + else if(BlockPages==128) + dwAddr=((StartPage & 0x7F)|((StartBlock<<7)& 0x7FF80)) ; + else + dwAddr=((StartPage & 0x3F)|((StartBlock<<6)& 0x3FFC0)) ; + + size_t ReadCounter=range_temp.length >> divider ; + if((range_temp.length%(1<start/g_NANDContext.realBlockSize; + DWORD StartPage = AddrRange->start/g_NANDContext.realPageSize; + unsigned int dwAddr=0; + if(BlockPages==256) + dwAddr=((StartPage & 0x3F)|((StartBlock<<6)& 0x7FFC0)) ; + else if(BlockPages==128) + dwAddr=((StartPage & 0x7F)|((StartBlock<<7)& 0x7FF80)) ; + else + dwAddr=((StartPage & 0x3F)|((StartBlock<<6)& 0x3FFC0)) ; + + size_t ReadCounter=AddrRange->length >> divider ; + if((AddrRange->length%(1<length/512, modeRead,g_NANDContext.realPageSize,BlockPages,ReadCom,g_ChipInfo.AddrWidth,g_ChipInfo.ReadDummyLen,g_ChipInfo.nCA_Rd,USBIndex); + + + for(size_t i = 0; i < ReadCounter; i++) + { + if(!BulkPipeReadEx(&pData[(i<length-(i<length; i++) + { + if(pData[i] != 0xFF) + { + free(pData); + return false ; + } + } + + } + + free(pData); + return true; +} + +bool Nand_bulkPipeRead(const struct CAddressRange* AddrRange, unsigned char* pBuff,unsigned char modeRead,unsigned char ReadCom,int USBIndex) +{ + unsigned char *pData= NULL;// = new unsigned char[0x1000000]; + unsigned char *pTemp = pBuff; +// unsigned char BBTscan=0; + + size_t BlockPages= g_NANDContext.realBlockSize/g_NANDContext.realPageSize; + + size_t divider=16; + size_t RunUnitSize=0; + switch(g_NANDContext.realBlockSize) + { + default: + case 0x44000: + case 0x22000: + RunUnitSize = 0x880000; + break; + case 0x42000: + case 0x21000: + RunUnitSize=0x840000; + break; + case 0x20800: + RunUnitSize=0x820000; + break; + case 0x20400: + RunUnitSize=0x810000; + break; + } + //vector vData(RunUnitSize,0xFF); + pData = (unsigned char* )malloc(RunUnitSize); + memset(pData, 0xFF, RunUnitSize); + + if((AddrRange->start/RunUnitSize)!=(AddrRange->end/RunUnitSize)) + { + struct CAddressRange range_temp;//(*AddrRange); + range_temp.start=AddrRange->start; + range_temp.end=AddrRange->end; + range_temp.length=AddrRange->end-AddrRange->start; + + //size_t baseAddr=AddrRange->start-(AddrRange->start%RunUnitSize); + size_t loop=SF_GetLoop(AddrRange ,RunUnitSize); + + for(size_t j=0; jstart-(AddrRange->start%RunUnitSize)+(RunUnitSize*(j+1)); + + if(j==0) + range_temp.start=AddrRange->start; + else + range_temp.start=AddrRange->start-(AddrRange->start%RunUnitSize)+(RunUnitSize*j); + + DWORD StartBlock = range_temp.start/g_NANDContext.realBlockSize; + DWORD StartPage = range_temp.start/g_NANDContext.realPageSize; + + range_temp.length = range_temp.end-range_temp.start; + unsigned int dwAddr=0; + if(BlockPages==256) + dwAddr=((StartPage & 0x3F)|((StartBlock<<6)& 0x7FFC0 )); + else if(BlockPages==128) + dwAddr=((StartPage & 0x7F)|((StartBlock<<7)& 0x7FF80)) ; + else + dwAddr=((StartPage & 0x3F)|((StartBlock<<6)& 0x3FFC0)) ; + + size_t ReadCounter=range_temp.length >> divider ; + if((range_temp.length%(1<start/g_NANDContext.realBlockSize; + DWORD StartPage = AddrRange->start/g_NANDContext.realPageSize; + unsigned int dwAddr=0; + if(BlockPages==256) + dwAddr=((StartPage & 0x3F)|((StartBlock<<6)& 0x7FFC0)) ; + else if(BlockPages==128) + dwAddr=((StartPage & 0x7F)|((StartBlock<<7)& 0x7FF80)) ; + else + dwAddr=((StartPage & 0x3F)|((StartBlock<<6)& 0x3FFC0)) ; + + size_t ReadCounter=AddrRange->length >> divider ; + if((AddrRange->length%(1<length/512, modeRead,g_NANDContext.realPageSize,BlockPages,ReadCom,g_ChipInfo.AddrWidth,g_ChipInfo.ReadDummyLen,g_ChipInfo.nCA_Rd,USBIndex); + + + for(size_t i = 0; i < ReadCounter; i++) + { + if(!BulkPipeReadEx(&pData[(i<length-(i<length); + } + + free(pData); + return true; +} + +bool SPINAND_RangeVerify( const struct CAddressRange* AddrRange,int USBIndex) +{ + if(!SPINAND_DisableContinueRead(USBIndex)) + return false; +// if(!SPINAND_EnableQuadIO(true,true,USBIndex)) +// return false; + size_t loop=SF_GetLoop(AddrRange ,g_NANDContext.realBlockSize); + //printf("SPINAND_RangeVerify(), AddrRange->start=%ld, AddrRange->end=%ld, loop=%ld\n", AddrRange->start, AddrRange->end,loop); + bool bIsBadBlock = false; + bool result = true; + size_t StartBlock = AddrRange->start/g_NANDContext.realBlockSize; + struct CAddressRange tempRange; + for(unsigned short i=StartBlock; i<(loop+StartBlock); i++) + { + if(g_iNandBadBlockManagement == 0) + { + bIsBadBlock = false; + for(unsigned short j=0; j>divider, modeWrite,g_NANDContext.realPageSize, + BlockPages,WriteCom,g_ChipInfo.AddrWidth, g_ChipInfo.ReadDummyLen,g_ChipInfo.nCA_Wr,USBIndex); + + size_t WriteCounter=g_NANDContext.realBlockSize >> divider ; + if((g_NANDContext.realBlockSize %(1<chip.realBlockSize; + result = false; + cnt++; + } + #endif + + return result; +} + +bool SPINAND_RangeRead(const struct CAddressRange* Range,unsigned char *pBuff, int USBIndex) +{ + if(!SPINAND_DisableContinueRead(USBIndex)) + return false; + // if(!SPINAND_EnableQuadIO(true,true,USBIndex)) + // return false; + if(Nand_bulkPipeRead(Range, pBuff, BULK_QUAD_READ,mcode_ReadCode,USBIndex)) + return false; + // if(!SPINAND_EnableQuadIO(false,true,USBIndex)) + // return false; + return true; +} + +bool SPINAND_RangeProgram(const struct CAddressRange* Range,int USBIndex) +{ + return true; +} + +bool Nand_SpecialRangeErase(unsigned int BlockIndex, unsigned int BlockCnt,int USBIndex) +{ + SetSPIClockValue(0x02,USBIndex); + + unsigned short BBT[0x200]; + unsigned short BBTCnt = 0; + + SPINAND_ScanBadBlock(BBT, &BBTCnt, USBIndex); + + if(BBTCnt >= 0x200) + return false; + + unsigned int TotalBlockCnt = g_NANDContext.realChipSize/g_NANDContext.realBlockSize; + DWORD PageCnt = g_NANDContext.realBlockSize/g_NANDContext.realPageSize; + DWORD addr = 0; + bool skip = false; + unsigned char ucSR=0; + unsigned char v[4];// m_context->serialFlash.EraseCmd.ChipErase); + v[0] = mcode_ChipErase; + for(size_t i=BlockIndex; i<(BlockIndex+BlockCnt); i++) + { + skip = false; + for(unsigned int j=0; j> 16) & 0xff) ; //MSB + v[2] = (unsigned char)((addr >> 8) & 0xff) ; //M + v[3] = (unsigned char)(addr & 0xff) ; //LSB + FlashCommand_SendCommand_OutOnlyInstruction(v, sizeof(v), USBIndex); + + do + { + if(!Nand_RDSRStatus1(&ucSR,USBIndex)) + return false; + if((ucSR & (0x05)) == 0x05) // erase flag and busy flag are set + { + MarkNewBadBlock(addr, USBIndex); + if(BlockCnt < TotalBlockCnt) + BlockCnt++; + break; + } + }while(ucSR & 0x01); + + + } + SetSPIClock(USBIndex); + + return true ; +} + +bool SPINand_SpecialErase(unsigned int BlockIndex, unsigned int BlockCnt, int USBIndex) +{ + bool result = true; + if(!SPINAND_DisableContinueRead(USBIndex)) + return false; + if(! SPINAND_ProtectBlock(false,USBIndex) ) + return false ; + result = Nand_SpecialRangeErase(BlockIndex, BlockCnt, USBIndex); + return result; +} + diff --git a/SerialFlash.h b/SerialFlash.h index aece02e..a5f8152 100755 --- a/SerialFlash.h +++ b/SerialFlash.h @@ -107,5 +107,27 @@ size_t GetChipSize(void); size_t GetPageSize(void); bool SerialFlash_StartofOperation(int Index); bool SerialFlash_EndofOperation(int Index); +bool DownloadICInfoForNand(DWORD dwInfoLen, int USBIndex);//SF700 +bool Nand_ReadICInfo(SELECT_SPI_NAND_INFO *nandInfo, unsigned short *BBT, unsigned short *BBT_Cnt, int USBIndex); +bool SPINAND_ScanBadBlock( unsigned short *BBT, unsigned short *BBT_Cnt, int USBIndex); +bool SF_Nand_HSBSet( int Index); +bool SPINAND_chipErase(int USBIndex); +bool SPINAND_ProtectBlock(bool bProtect,int USBIndex); +void DownloadICInfo(bool isErase, int USBIndex); +bool SPINAND_RangeBlankCheck(const struct CAddressRange* Range,int USBIndex); +bool SPINAND_RangeProgram(const struct CAddressRange* Range,int USBIndex); +bool SPINAND_BlockProgram(const DWORD dwAddr, const unsigned char *pData, unsigned char modeWrite,unsigned char WriteCom,int USBIndex); +bool SPINAND_EnableInternalECC(bool is_ENECC,int USBIndex); +bool Nand_CaculateErrorBit(unsigned char *pData, unsigned char *pFile, unsigned int ptr_size); +bool SPINAND_RangeVerify( const struct CAddressRange* AddrRange,int USBIndex); +bool Nand_bulkPipeRead(const struct CAddressRange* AddrRange, unsigned char* pBuff,unsigned char modeRead,unsigned char ReadCom,int USBIndex); +bool SPINAND_RangeRead(const struct CAddressRange* Range,unsigned char *pBuff, int USBIndex); +bool SPINand_SpecialErase(unsigned int BlockIndex, unsigned int BlockCnt, int USBIndex); + + + + + + #endif //SERIALFLASHS diff --git a/dpcmd.c b/dpcmd.c index 9031beb..f5ba1d7 100644 --- a/dpcmd.c +++ b/dpcmd.c @@ -17,6 +17,9 @@ #include #include #include +#include +#include + #define min(a, b) (a > b ? b : a) extern unsigned char* pBufferForLastReadData[16]; @@ -48,7 +51,8 @@ bool g_bEnableVpp = false; int g_StartupMode = STARTUP_APPLI_SF_1; bool g_bStatus = true; -CHIP_INFO Chip_Info; +CHIP_INFO g_ChipInfo; +struct CNANDContext g_NANDContext = {{0x111,0x121,0x122,0x141,0x144}, {0x111,0x111,0x111,0x141,0x144},0,0,0,0}; char* l_opt_arg; struct CAddressRange DownloadAddrRange; struct CAddressRange UploadAddrRange; @@ -77,14 +81,23 @@ char* g_parameter_vcc = "NO"; char* g_parameter_blink = "0"; char* g_parameter_fw = "\0"; char g_LogPath[512] = { 0 }; +char* g_parameter_special_program = "\0"; +char* g_parameter_special_auto = "\0"; +char* g_parameter_batch_with_forceerase = "\0"; +char* g_parameter_block_index = "\0"; +char* g_parameter_block_count = "\0"; +char* g_parameter_sparearea_use_file = "\0"; +char* g_parameter_skip_bad_block = "\0"; +char* g_parameter_file_offset = "\0"; +char* g_parameter_internal_ecc = "\0"; + /* to address by BUS:DEV; we'll parse the instructions from either the * environment or command line options and * usbdriver.c:FindUSBDevices() will acknowledge these settings */ extern unsigned g_usb_devnum; extern unsigned g_usb_busnum; -unsigned long g_ucOperation; -struct memory_id g_ChipID; +unsigned long long g_ucOperation; char g_board_type[8]; char g_FPGA_ver[8]; char g_FW_ver[10]; @@ -96,10 +109,18 @@ int m_isCanceled = 0; int m_bProtectAfterWritenErase = 0; int m_boEnReadQuadIO = 0; int m_boEnWriteQuadIO = 0; +int g_iNandBadBlockManagement = 0; //0:skip, 1:no management +int g_iNandBlockIndex = 0; +int g_iNandBlockCount = 0; + volatile bool g_is_operation_on_going = false; bool g_is_operation_successful[16] = { false }; bool g_bDisplayTimer = true; bool isSendFFsequence = false; +bool g_bSpareAreaUseFile = false; +bool g_bNandForceErase = false; +bool g_bNandInternalECC = true; +bool g_bIsNANDFlash = false; /* only print timing progress info if this many seconds ellapsed * before the last time we did */ //static float g_tv_display_delta_s = 0.5; @@ -119,6 +140,7 @@ static const char* msg_info_checking = "\nChecking, please wait ..."; static const char* msg_info_erasing = "\nErasing, please wait ..."; static const char* msg_info_programming = "\nProgramming, please wait ..."; static const char* msg_info_reading = "\nReading, please wait ..."; +static const char* msg_info_scanning = "\nScanning blocks, please wait ..."; static const char* msg_info_auto = "\nAuto Sequences, please wait ..."; static const char* msg_info_verifying = "\nVerifying, please wait ..."; static const char* msg_info_chipblank = "\nThe chip is blank"; @@ -136,53 +158,70 @@ static const char* msg_info_verifyfail = "\nError: Verify Failed"; static const char* msg_info_firmwareupdate = "\nUpdating firmware, please wait..."; static const char* msg_info_firmwareupdateOK = "\nUpdate firmware OK"; static const char* msg_info_firmwareupdatefail = "\nError: Update firmware Failed"; +static const char* msg_info_scanBBOK = "\nScan Bad Block OK"; +static const char* msg_info_scanBBfail = "\nError: Scan Bad Block Failed"; + char* const short_options = "?Ldber:p:u:z:sf:I:R:a:l:vx:T:S:N:B:t:g:c:PO:ik:1:4:U:E:"; struct option long_options[] = { { "help", 0, NULL, '?' }, - { "list", 0, NULL, 'L' }, - { "detect", 0, NULL, 'd' }, + { "nand-BlockCount ", 1, NULL, 'A' }, + { "blink", 1, NULL, 'B' }, { "check", 0, NULL, 'C' }, - { "blank", 0, NULL, 'b' }, - { "erase", 0, NULL, 'e' }, - { "read", 1, NULL, 'r' }, - { "prog", 1, NULL, 'p' }, - { "auto", 1, NULL, 'u' }, - { "batch", 1, NULL, 'z' }, - { "sum", 0, NULL, 's' }, - { "fsum", 1, NULL, 'f' }, + { "device", 1, NULL, 'D' }, + { "nand-SpareAreaUseFile", 1, NULL, 'E' }, + { "sp", 1, NULL, 'F' }, + { "devnum", 1, NULL, 'G' }, + { "busnum", 1, NULL, 'H' }, { "raw-instruction", 1, NULL, 'I' }, + { "force-erase", 0, NULL, 'J' }, + { "se", 0, NULL, 'K' }, + { "list", 0, NULL, 'L' }, + { "su", 1, NULL, 'M' }, + { "lock-length", 1, NULL, 'N' }, + { "log", 1, NULL, 'O' }, + { "vpp", 0, NULL, 'P' }, + { "nand-BlockIndex", 1, NULL, 'Q' }, { "raw-require-return", 1, NULL, 'R' }, - { "addr", 1, NULL, 'a' }, - { "length", 1, NULL, 'l' }, - { "verify", 0, NULL, 'v' }, - { "fill", 1, NULL, 'x' }, + { "lock-start", 1, NULL, 'S' }, { "type", 1, NULL, 'T' }, - { "lock-start", 1, NULL, 'S' }, - { "lock-length", 1, NULL, 'N' }, - { "blink", 1, NULL, 'B' }, - { "device", 1, NULL, 'D' }, - { "device-SN", 1, NULL, 'X' }, - // { "fix-device", 1, NULL, 'F' }, + { "update-fw", 1, NULL, 'U' }, { "list-device-id", 1, NULL, 'V' }, { "loadFile-with-verify", 1, NULL, 'W' }, - { "timeout", 1, NULL, 't' }, - { "target", 1, NULL, 'g' }, + { "device-SN", 1, NULL, 'X' }, + { "nand-batch-forceerase", 1, NULL, 'Y' }, + { "nand-skip-bad-block ", 1, NULL, 'Z' }, + + { "addr", 1, NULL, 'a' }, + { "blank", 0, NULL, 'b' }, { "vcc", 1, NULL, 'c' }, - { "vpp", 0, NULL, 'P' }, - { "log", 1, NULL, 'O' }, + { "detect", 0, NULL, 'd' }, + { "erase", 0, NULL, 'e' }, + { "fsum", 1, NULL, 'f' }, + { "target", 1, NULL, 'g' }, { "silent", 0, NULL, 'i' }, + { "nand-file-offset", 1, NULL, 'j' }, { "spi-clk", 1, NULL, 'k' }, + { "length", 1, NULL, 'l' }, + { "nand-internal-ecc ", 1, NULL, 'm' }, + { "nand-BlockCount", 1, NULL, 'n' }, + + { "prog", 1, NULL, 'p' }, + + { "read", 1, NULL, 'r' }, + { "sum", 0, NULL, 's' }, + { "timeout", 1, NULL, 't' }, + { "auto", 1, NULL, 'u' }, + { "verify", 0, NULL, 'v' }, + + { "fill", 1, NULL, 'x' }, + + { "batch", 1, NULL, 'z' }, + { "set-io1", 1, NULL, '1' }, { "set-io4", 1, NULL, '4' }, - { "update-fw", 1, NULL, 'U' }, - // { "display-delta", 1, NULL, 'E' }, - { "devnum", 1, NULL, 'G' }, - { "busnum", 1, NULL, 'H' }, - { 0, 0, 0, 0 }, - }; int OpenUSB(void); @@ -341,6 +380,17 @@ int Sequence() { // *** the calling order in the following block must be kept as is *** bool boResult = true; + if (strstr(g_ChipInfo.ICType, "SPI_NAND") != NULL) + { + g_bIsNANDFlash = true; + FillNANDContext(); + } + + if((g_ucOperation & ERASE) == 0 && (g_ucOperation & SPECIAL_ERASE)==0) + { + boResult = ScanBB(); + } + boResult &= BlankCheck(); if (boResult == false) { if (!(g_ucOperation & ERASE)) @@ -352,10 +402,18 @@ int Sequence() return EXCODE_FAIL_ERASE; } + boResult &= SpecialErase(); + if (boResult == false) + return EXCODE_FAIL_PROG; + boResult &= Program(); if (boResult == false) return EXCODE_FAIL_PROG; + //boResult &= SpecialProgram(); + //if (boResult == false) + // return EXCODE_FAIL_PROG; + boResult &= Read(); if (boResult == false) return EXCODE_FAIL_READ; @@ -369,9 +427,9 @@ int Sequence() if (g_ucOperation & CSUM) { if (g_uiLen == 0) { if (g_uiDevNum == 0) - return CRC32(pBufferForLastReadData[0], Chip_Info.ChipSizeInByte); + return CRC32(pBufferForLastReadData[0], g_ChipInfo.ChipSizeInByte); else - return CRC32(pBufferForLastReadData[g_uiDevNum - 1], Chip_Info.ChipSizeInByte); + return CRC32(pBufferForLastReadData[g_uiDevNum - 1], g_ChipInfo.ChipSizeInByte); } else { if (g_uiDevNum == 0) return CRC32(pBufferForLastReadData[0], g_uiLen); @@ -462,6 +520,32 @@ void WriteLog(int ErrorCode, bool Init) int GetConfigVer() { +#if 1 + char file_path[512]; + xmlDocPtr doc; + xmlNodePtr cur_node; + xmlChar *chip_attribute; + int Ver = 0; + + if (GetChipDbPath(file_path) == false) + { + return 1; + } + + doc = xmlParseFile(file_path); + cur_node = xmlDocGetRootElement(doc); // DediProgChipDatabase + while (cur_node != NULL) { + if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"DediProgChipDatabase"))) { + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"Ver"); + Ver = strtol((char*)chip_attribute, NULL, 10); + xmlFree(chip_attribute); + } + + cur_node = cur_node->next; + } + xmlFreeDoc(doc); + return Ver; +#else char file_line_buf[512]; char test[80]; char *pch, *tok; @@ -487,6 +571,7 @@ int GetConfigVer() } fclose(fp); return Ver; +#endif } int main(int argc, char* argv[]) @@ -497,6 +582,7 @@ int main(int argc, char* argv[]) #endif int c; + int temp = 0; int iExitCode = EXCODE_PASS; bool bDetect = false; bool bDevice = false; @@ -523,6 +609,8 @@ int main(int argc, char* argv[]) cli_classic_usage(false); return 0; } + if (ListTypes()) + return EXCODE_PASS; /* * Obtain the (optional) bus number and device number to @@ -559,6 +647,12 @@ int main(int argc, char* argv[]) g_usb_busnum = (unsigned char)r; } + if (OpenUSB() == 0) + iExitCode = EXCODE_FAIL_USB; + + LeaveStandaloneMode(0); + QueryBoard(0); + while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { switch (c) { case '?': @@ -739,17 +833,57 @@ int main(int argc, char* argv[]) } g_usb_busnum = (unsigned)r; break; + //SPI NAND + case 'E': + g_parameter_sparearea_use_file = optarg; + sscanf(g_parameter_sparearea_use_file, "%d", &temp); + g_bSpareAreaUseFile = ((temp==0)? false:true); + break; + case 'F': + g_parameter_special_program = optarg; + g_ucOperation |= SPECIAL_PROGRAM; + break; + case 'J': + g_bNandForceErase = true; + g_ucOperation |= ERASE; + break; + case 'K': + g_bNandForceErase = false; + g_ucOperation |= SPECIAL_ERASE; + break; + case 'M': + g_parameter_special_auto = optarg; + g_ucOperation |= SPECIAL_AUTO; + break; + case 'Q': + g_parameter_block_index = optarg; + sscanf(g_parameter_block_index, "%d", &g_iNandBlockIndex); + break; + case 'Y': + g_parameter_batch_with_forceerase = optarg; + g_ucOperation |= BATCH_WITH_FORCEERASE; + break; + case 'Z': + g_parameter_skip_bad_block = optarg; + sscanf(g_parameter_skip_bad_block, "%d", &g_iNandBadBlockManagement); + break; + case 'j': + g_parameter_file_offset = optarg; + break; + case 'm': + g_parameter_internal_ecc = optarg; + sscanf(g_parameter_internal_ecc, "%d", &temp); + g_bNandInternalECC = ((temp == 0)? true:false); + break; + case 'n': + g_parameter_block_count = optarg; + sscanf(g_parameter_block_count, "%d", &g_iNandBlockCount); + break; default: break; } } - if (OpenUSB() == 0) - iExitCode = EXCODE_FAIL_USB; - - LeaveStandaloneMode(0); - QueryBoard(0); - int dev_cnt = get_usb_dev_cnt(); if (CheckProgrammerInfo()) { @@ -785,11 +919,11 @@ int main(int argc, char* argv[]) printf("\nDevice %d (DP%06d):\tdetecting chip\n", g_uiDevNum, dwUID); } WriteLog(iExitCode, true); - Chip_Info = GetFirstDetectionMatch(strTypeName, g_uiDevNum - 1); - if (Chip_Info.UniqueID != 0) { + g_ChipInfo = GetFirstDetectionMatch(strTypeName, g_uiDevNum - 1); + if (g_ChipInfo.UniqueID != 0) { if (strlen(strTypeName)) { printf("By reading the chip ID, the chip applies to [ %s ]\n\n", strTypeName); - printf("%s chip size is %zd bytes.\n", Chip_Info.TypeName, Chip_Info.ChipSizeInByte); + printf("%s chip size is %zd bytes.\n", g_ChipInfo.TypeName, g_ChipInfo.ChipSizeInByte); } else { printf("%s", msg_err_identifychip); iExitCode = EXCODE_FAIL_IDENTIFY; @@ -817,11 +951,11 @@ int main(int argc, char* argv[]) printf("\nDevice %d (DP%06d):\tdetecting chip\n", i + 1, dwUID); } WriteLog(iExitCode, true); - Chip_Info = GetFirstDetectionMatch(strTypeName, i); - if (Chip_Info.UniqueID != 0) { + g_ChipInfo = GetFirstDetectionMatch(strTypeName, i); + if (g_ChipInfo.UniqueID != 0) { if (strlen(strTypeName)) { printf("By reading the chip ID, the chip applies to [ %s ]\n", strTypeName); - printf("%s chip size is %zd bytes.\n", Chip_Info.TypeName, Chip_Info.ChipSizeInByte); + printf("%s chip size is %zd bytes.\n", g_ChipInfo.TypeName, g_ChipInfo.ChipSizeInByte); } else { printf("%s", msg_err_identifychip); iExitCode = EXCODE_FAIL_IDENTIFY; @@ -835,13 +969,13 @@ int main(int argc, char* argv[]) } else if (g_uiDevNum != 0) { WriteLog(iExitCode, true); printf("%d,\tdetecting chip\n", g_uiDevNum); - Chip_Info = GetFirstDetectionMatch(strTypeName, g_uiDevNum - 1); + g_ChipInfo = GetFirstDetectionMatch(strTypeName, g_uiDevNum - 1); - if (Chip_Info.UniqueID != 0) { + if (g_ChipInfo.UniqueID != 0) { //printf("strlen(strTypeName)=%ld\n",strlen(strTypeName)); if (strlen(strTypeName)) { printf(" \tBy reading the chip ID, the chip applies to [ %s ]\n\n", strTypeName); - printf(" \t%s chip size is %zd bytes.\n", Chip_Info.TypeName, Chip_Info.ChipSizeInByte); + printf(" \t%s chip size is %zd bytes.\n", g_ChipInfo.TypeName, g_ChipInfo.ChipSizeInByte); } else { printf("%s", msg_err_identifychip); iExitCode = EXCODE_FAIL_IDENTIFY; @@ -870,6 +1004,7 @@ int main(int argc, char* argv[]) } WriteLog(iExitCode, true); } + if (iExitCode != EXCODE_PASS) goto Exit; iExitCode = Handler(); @@ -972,6 +1107,7 @@ void cli_classic_usage(bool IsShowExample) "Remark: -x only works with -p"); printf("(space is not needed between the switches and parameters. E.g. dpcmd -ubio.bin)\n"); + printf("SPI NOR : Basic Switches(switches in this group are mutual exclusive):\n"); printf(" -? [ --help ] show this help message\n" " --list print supported chip list\n" " --check get programmer information\n" @@ -1006,7 +1142,7 @@ void cli_classic_usage(bool IsShowExample) " dpcmd --raw-instruction \"06|01 0C|05\" \n" " --raw-require-return \"0|0|1\" \n" "\n" - "Optional Switches that add fine-tune ability to Basic Switches:\n" + "SPI NOR : Optional Switches that add fine-tune ability to Basic Switches:\n" " -a [ --addr ] arg hexadecimal starting address hexadecimal(e.g.\n" " 0x1000),\n" " - works with --prog/read/sum/auto only\n" @@ -1048,7 +1184,7 @@ void cli_classic_usage(bool IsShowExample) // " - n: Prompt the device ID of programmer connected to USBn.\n" " --loadFile-with-verify arg -Load a bin/hex/s19 file and verify with the memory conten.\n" "\n" - "Miscellaneous options:\n" + "SPI NOR : Miscellaneous options:\n" " -t [ --timeout ] arg (=300) Timeout value in seconds\n" " -g [ --target ] arg (=1) Target Options\n" " Available values:\n" @@ -1089,11 +1225,140 @@ void cli_classic_usage(bool IsShowExample) " -E [ --display-delta ] arg (=0.5) wait this many seconds\n" " before refreshing the screen\n" "\n" + "SPI NAND : Basic Switches(switches in this group are mutual exclusive):\n" + " -h [ --help ] show this help message\n" + " --blink arg \n" + // " - 0 : Blink green LED 3 times from USB1 to USBn\n" + // " (Default)\n" + // " note: the sequence is assigned by OS during USB plug-in\n" + " - 1: Blink the programmer connected to USB1 3 times.\n" + " --list print supported chip list\n" + " -c [ --check ] check programmer information\n" + " -d [ --detect ] detect chip\n" + " -b [ --blank ] blank check\n" + " -e [ --erase ] erase entire chip\n" + " --force-erase enable hard copy erase\n" + " -r [ --read ] arg read chip contents and save to a bin/hex/s19 file\n" + " - use STDOUT for the console.\n" + " -p [ --prog ] arg program chip without erase\n" + " -z [ --batch ] arg\n" + " automatically run the following sequence:\n" + " - check if the chip is blank or not;\n" + " - erase the chip memory which skip bad block(if\n" + " not blank);\n" + " - program a whole file starting from address 0\n" + /* " --se erase entire chip and mark a new bad block, if\n" + " bad block is generated during erase\n" + " --sp arg program chip without erase\n" + " and mark a new bad block, if bad block is\n" + " generated during programming\n" + " - instructions must be enclosed in double\n" + " quotation marks(\"\")\n" + " - use \"|\" to load partition file and data file\n" + " Example:\n" + " dpcmd --sp \"xxx.dpmbn|aaa.bin\"\n" + " --su arg automatically run the following sequence:\n" + " - Erase only the blocks with data length and mark\n" + " a new bad block\n" + " - Program only the erased blocks with the file\n" + " data from address 0\n" + " or according to partition file\n" + " - instructions must be enclosed in double\n" + " quotation marks(\"\")\n" + " - use \"|\" to load partition file and data file\n" + " Example:\n" + " dpcmd --su \"xxx.dpmbn|aaa.bin\"\n" + " --nand-batch-forceerase arg automatically run the following sequence:\n" + " - check if the chip is blank or not;\n" + " - force erase the entire chip(if not blank);\n" + " - program a whole file starting from address 0\n"*/ + " -s [ --sum ] display chip content checksum\n" + " -f [ --fsum ] arg display the file checksum\n" + " - needs to work with a file\n" + " --raw-instruction arg issue raw serial flash instructions.\n" + " - use spaces(\" \") to delimit bytes.\n" + " - instructions must be enclosed in double\n" + " quotation marks(\"\")\n" + " - use \"|\" to send continuous command\n" + " Example:\n" + " ./dpcmd --raw-instruction 06\n" + " ./dpcmd --raw-instruction \"06|02 00 00 00 11 22 33\"\n" + " --raw-require-return arg decimal bytes of result to return in decimal\n" + " after issuing raw instructions.\n" + " - used along with --raw-instruction only.\n" + " Example:\n" + " dpcmd --raw-instruction \"03 FF 00 12\" --raw-require-return 1\n" + " dpcmd --raw-instruction \"06|05\" --raw-require-return \"0|2\"\n" + " --loadFile-with-verify arg Load a bin/hex/s19 file and compare with memory\n" + " content\n" + " Example:\n" + " ./dpcmd --loadFile-with-verify d:\\xxx.bin\n" + + "SPI NAND : Optional Switches that add fine-tune ability to Basic Switches:\n" + " -v [ --verify ] verify checksum file and chip\n" + " - works with --prog/batch only\n" + " --type arg Specify a type to override auto detection\n" + " - use --list arguement to look up supported type.\n" + // " --read-id read chip id\n" + // " - return chip id only\n" + + "SPI NAND : Miscellaneous options:\n" + " -t [ --timeout ] arg (=1000) Timeout value in seconds. Default value is\n" + " 1000s.\n" + " -g [ --target ] arg (=1) Target Options\n" + " Available values:\n" + " 1, Chip 1(Default)\n" + " 2, Chip 2\n" + " 3, Socket\n" + " 0, reference card\n" + " -i [ --silent ] suppress the display of real-time timer counting\n" + " - used when integrating with 3rd-party tools\n" + " (e.g. IDE)\n" + " --vcc arg specify vcc(SF600Plus-G2 / Others)\n" + " 0, 3.3V / 3.5V\n" + " 1, 2.5V / 1.2V\n" + " 2, 1.8V / 1.8V\n" + " 3, 1.2V / 1.2V\n" + " 1200 ~ 3800, 1.2V ~ 3.8V (minimum step\n" + " 100mV)\n" + " --spi-clk arg (=2) specify SPI clock:\n" + " 2, 12MHz (Default)\n" + " 0, 25MHz\n" + " 1, 6MHz\n" + " 3, 4MHz\n" + " 4, 2MHz\n" + " 5, 1MHz\n" + " 6, 800KHz\n" + " 7, 400KHz\n" + " -i [ --silent ] suppress the display of real-time timer counting\n" + " - used when integrating with 3rd-party tools\n" + " (e.g. IDE)\n" + " --set-io1 arg (=0) specify Level of IO1(SF100) or GPIO1(SF600/S\n" + " F600Plus):\n" + " 0, Low(Default)\n" + " 1, High\n" + " --set-io4 arg (=1) specify Level of IO4(SF100) or GPIO2(SF600/S\n" + " F600Plus):\n" + " 0, Low\n" + " 1, High(Default)\n" + " --nand-BlockIndex arg (=0) Decimal starting address Decimal(e.g. 512),\n" + " - defaults to 0, if omitted.\n" + " --nand-BlockCount arg (=0) Decimal starting address Decimal(e.g. 200),\n" + " - defaults to whole file if omitted.\n" + " --nand-SpareAreaUseFile arg (=0) specify if the Spare Area use file:\n" + " 0, Unuse(Default)\n" + " 1, True\n" + " --nand-skip-bad-block arg (=0) specify if the Bad Block(s) are skipped:\n" + " 0, Skip(Default)\n" + " 1, No management\n" + " --nand-file-offset arg (=0) specify the file offset number\n" + " --nand-internal-ecc arg (=0) specify if the Internal ECC enable:\n" + " 0, Enable(Default)\n" + " 1, Disable\n" "Environment variables:\n" " Specify DPCMD_USB_BUSNUM and DPCMD_USB_DEVNUM to ensure the tool touches only said device. Numbers can be found with tools such as lsusb and others.\n" " - DPCMD_USB_BUSNUM Number of USB bus where device is\n" " - DPCMD_USB_DEVNUM Number of device in USB bus\n" - "\n\n\n"); } @@ -1109,10 +1374,20 @@ void sin_handler(int sig) } } +void FillNANDContext(void) +{ + g_NANDContext.realSpareAreaSize = ( g_bNandInternalECC==true? (g_ChipInfo.SpareSizeInByte & 0xFFFF):((g_ChipInfo.SpareSizeInByte>>16) & 0xFFFF)); + g_NANDContext.realPageSize = g_NANDContext.realSpareAreaSize+g_ChipInfo.PageSizeInByte; + g_NANDContext.realBlockSize = g_ChipInfo.BlockSizeInByte/g_ChipInfo.PageSizeInByte*g_NANDContext.realPageSize; + g_NANDContext.realChipSize = g_NANDContext.realBlockSize*g_ChipInfo.ChipSizeInByte/g_ChipInfo.BlockSizeInByte; + memcpy(&g_NANDContext.EraseCmd,&g_ChipInfo.EraseCmd, sizeof(unsigned int)); + memcpy(&g_NANDContext.ReadCmd,&g_ChipInfo.ReadCmd, sizeof(unsigned int)); + memcpy(&g_NANDContext.ProgramCmd,&g_ChipInfo.ProgramCmd, sizeof(unsigned int)); +} + int Handler(void) { if (Is_usbworking(0) == true) { - //if (Is_usbworking(g_uiDevNum - 1) == true) { #if 0 if(m_vm.count("fix-device")) { @@ -1190,11 +1465,11 @@ if (Is_usbworking(0) == true) { SetVppVoltage(0,i); if (strlen(g_parameter_type) > 0) { - if (Dedi_Search_Chip_Db_ByTypeName(g_parameter_type, &Chip_Info)) { - printf("Chip Type %s is applied manually.\n", Chip_Info.TypeName); - printf("%s chip size is %zd bytes.\n\n", Chip_Info.TypeName, Chip_Info.ChipSizeInByte); - ProjectInitWithID(Chip_Info, i); - if (!strcmp(Chip_Info.Class, "N25Qxxx_Large")) + if (Dedi_Search_Chip_Db_ByTypeName(g_parameter_type, &g_ChipInfo)) { + printf("Chip Type %s is applied manually.\n", g_ChipInfo.TypeName); + printf("%s chip size is %zd bytes.\n\n", g_ChipInfo.TypeName, g_ChipInfo.ChipSizeInByte); + ProjectInitWithID(g_ChipInfo, i); + if (!strcmp(g_ChipInfo.Class, "N25Qxxx_Large")) isSendFFsequence = true; } else { printf("Chip Type Unknow is applied manually.\n"); @@ -1214,10 +1489,10 @@ if (Is_usbworking(0) == true) { SetVppVoltage(0,g_uiDevNum - 1); if (strlen(g_parameter_type) > 0) { - if (Dedi_Search_Chip_Db_ByTypeName(g_parameter_type, &Chip_Info)) { - printf("Chip Type %s is applied manually.\n", Chip_Info.TypeName); - printf("%s chip size is %zd bytes.\n\n", Chip_Info.TypeName, Chip_Info.ChipSizeInByte); - ProjectInitWithID(Chip_Info, g_uiDevNum - 1); + if (Dedi_Search_Chip_Db_ByTypeName(g_parameter_type, &g_ChipInfo)) { + printf("Chip Type %s is applied manually.\n", g_ChipInfo.TypeName); + printf("%s chip size is %zd bytes.\n\n", g_ChipInfo.TypeName, g_ChipInfo.ChipSizeInByte); + ProjectInitWithID(g_ChipInfo, g_uiDevNum - 1); } else { printf("Chip Type Unknow is applied manually.\n"); return false; @@ -1245,20 +1520,20 @@ void CloseProject(void) bool DetectChip(void) { int dev_cnt = get_usb_dev_cnt(); - Chip_Info = GetFirstDetectionMatch(strTypeName, 0); + g_ChipInfo = GetFirstDetectionMatch(strTypeName, 0); if (g_uiDevNum == 0) { for (int i = 0; i < dev_cnt; i++) { if (!Is_usbworking(i)) { printf("%s", msg_err_communication); return false; } - if (0 == Chip_Info.UniqueID) { + if (0 == g_ChipInfo.UniqueID) { printf("%s", msg_err_identifychip); return false; } printf("By reading the chip ID, the chip applies to [ %s ]\n\n", strTypeName); - printf("%s parameters to be applied by default\n", Chip_Info.TypeName); - printf("%s chip size is %zd bytes.\n\n", Chip_Info.TypeName, Chip_Info.ChipSizeInByte); + printf("%s parameters to be applied by default\n", g_ChipInfo.TypeName); + printf("%s chip size is %zd bytes.\n\n", g_ChipInfo.TypeName, g_ChipInfo.ChipSizeInByte); RawInstructions(i); } @@ -1267,13 +1542,13 @@ bool DetectChip(void) printf("%s", msg_err_communication); return false; } - if (0 == Chip_Info.UniqueID) { + if (0 == g_ChipInfo.UniqueID) { printf("%s", msg_err_identifychip); return false; } - printf("By reading the chip ID, the chip applies to [ %s ]\n\n", Chip_Info.TypeName); - printf("%s parameters to be applied by default\n", Chip_Info.TypeName); - printf("%s chip size is %zd bytes.\n\n", Chip_Info.TypeName, Chip_Info.ChipSizeInByte); + printf("By reading the chip ID, the chip applies to [ %s ]\n\n", g_ChipInfo.TypeName); + printf("%s parameters to be applied by default\n", g_ChipInfo.TypeName); + printf("%s chip size is %zd bytes.\n\n", g_ChipInfo.TypeName, g_ChipInfo.ChipSizeInByte); RawInstructions(g_uiDevNum - 1); @@ -1566,6 +1841,15 @@ void do_BlankCheck(void) Wait(msg_info_chipblank, msg_info_chipnotblank); } +void do_NANDSpecialErase(void) +{ + printf("%s \n", msg_info_erasing); + Run(NAND_SPECIAL_ERASE, g_uiDevNum); + + Wait(msg_info_eraseOK, msg_info_erasefail); +} + + void do_Erase(void) { printf("%s \n", msg_info_erasing); @@ -1578,6 +1862,7 @@ void do_Program(void) { if (!do_loadFile()) return; + SaveProgContextChanges(); printf("%s\n", msg_info_programming); @@ -1808,6 +2093,130 @@ void do_RawInstructions(int Index) } } +void do_ScanBB() +{ + if(g_bIsNANDFlash == false) + return; + + printf("%s\n", msg_info_scanning); + Run(NAND_SCAN_BB, g_uiDevNum); + Wait( msg_info_scanBBOK, msg_info_scanBBfail) ; +} +#if 0 +bool do_loadFileWithPartitionTable() +{ + if(g_bIsNANDFlash == false) + { + return false; + } + + char* filename = NULL; + if (g_ucOperation & SPECIAL_PROGRAM) + filename = g_parameter_special_program; + else if (g_ucOperation & BATCH) { + switch (g_BatchIndex) { + case 1: + filename = g_parameter_batch; + break; + case 2: + default: + filename = g_parameter_auto; + break; + } + } else if (g_ucOperation & FSUM) + filename = g_parameter_fsum; + printf("%s", msg_info_loading); + printf("(%s)\n", filename); + + { + string s(m_vm["sp"].as()); + split(fileOut, s/*one_sequence*/,is_any_of("|"), token_compress_on); + } + + if(fileOut.size() == 0) + return false; + + if(fileOut.size() == 1) + return do_loadFile(); + + m_proj->analysisPartitionTable(m_vm["nand-SpareAreaUseFile"].as()!=0, fileOut.at(0)); + m_proj->get_context().file.nand_PartitionTableFilePath.assign(fileOut.at(1).begin(), fileOut.at(1).end()); + if(m_vm.count("device")) + m_proj->ChecknFitPartitionTable(bDeviceArray[m_vm["device"].as()]); + else if(m_vm.count("device-SN")) + m_proj->ChecknFitPartitionTable(DeviceNum); + else + m_proj->ChecknFitPartitionTable(0); + + return do_NANDloadFile(fileOut.at(1)); + return true; + +} + +void do_NANDSpecialProgram() +{ + SaveProgContextChanges(); + do_ScanBB(); + + if(!do_loadFileWithPartitionTable()) + { + m_status_result=false; + return; + } + + if( (IsAthenticated==FALSE) && (m_DetectedDeviceNum>1) ) + { + if( TrialCntProgram>0 ) + { + wcout << L"\nProgram trail count:#"<< 99 - TrialCntProgram << L" (Max trial count=99).\n"; + TrialCntProgram--; + } + else + { + wcout << L"\nProgram trial count runs out, please buy the production license.\n"; + return; + } + } + + cout << msg_info_programming; + do_SaveAllLog((CString)msg_info_programming.c_str()); + if(m_vm.count("device")) + { + if(bDeviceArray[m_vm["device"].as()]==0xff) + { + outMsg="The number of programmer is not defined!"; + OutputFormatedMsg(outMsg); + do_SaveAllLog((CString)outMsg.c_str()); + return; + } + //SiteChoosen=m_vm["device"].as()-1; + m_proj->RunSingle(CProject::NAND_SPECIAL_PROGRAM,m_vm["device"].as()-1); + } + else if(m_vm.count("device-SN")) + { + if(DeviceNum==0xffffffff) + { + OutputFormatedMsg("The number of programmer is not defined!"); + return; + } + //SiteChoosen=bReDeviceArray[DeviceNum]-1; + m_proj->RunSingle(CProject::NAND_SPECIAL_PROGRAM,bReDeviceArray[DeviceNum]-1); + } + else + m_proj->RunMulti(CProject::NAND_SPECIAL_PROGRAM); + + if( Wait( msg_info_progOK, msg_info_progfail ) ) + { + wcout << L"\nChecksum(whole file): " << m_proj->getImageFileInfo(DediVersion::IMAGEFILE_ATTRIBUTE_CRC); + wcout << L"\nChecksum(Written part of file): " << m_proj->getImageFileInfo(DediVersion::IMAGEFILE_ATTRIBUTE_CRC_OF_WRITTEN_PART); + } + if(m_proj->boFileSizeFailed) + { + wcout << L"\nError: File is invalid.\n" ; + } +} +#endif + void RawInstructions(int Index) { if (strlen(g_parameter_raw) > 0) { @@ -1824,10 +2233,36 @@ bool BlankCheck(void) return g_bStatus; } +bool SpecialErase() +{ + if (g_ucOperation & SPECIAL_ERASE) { + + g_bNandForceErase = false; + do_NANDSpecialErase(); + if(g_bStatus) + do_ScanBB(); + } + + + return g_bStatus; +} + bool Erase(void) { - if (g_ucOperation & ERASE) + if (g_ucOperation & ERASE) { do_Erase(); + if(g_bStatus) + do_ScanBB(); + } + + + return g_bStatus; +} + +bool SpecialProgram(void) +{ +// if (g_ucOperation & SPECIAL_PROGRAM) +// do_SpecialProgram(); return g_bStatus; } @@ -1896,7 +2331,7 @@ bool CalChecksum(void) else printf("\nDevice %d (DP%06d):", i + 1, dwUID); - printf("Checksum of the whole chip(address starting from: 0x%X, 0x%zX bytes in total): %08X\n", g_uiAddr, Chip_Info.ChipSizeInByte, CRC32(pBufferForLastReadData[i], Chip_Info.ChipSizeInByte)); + printf("Checksum of the whole chip(address starting from: 0x%X, 0x%zX bytes in total): %08X\n", g_uiAddr, g_ChipInfo.ChipSizeInByte, CRC32(pBufferForLastReadData[i], g_ChipInfo.ChipSizeInByte)); } else { if (is_SF700_Or_SF600PG2(i)) { if (g_bIsSF700[i] == true) @@ -1910,7 +2345,7 @@ bool CalChecksum(void) else printf("\nDevice %d (DP%06d):", i + 1, ReadUID(i)); - printf("Checksum(address starting from: 0x%X, 0x%zX bytes in total): %08X\n", g_uiAddr, g_uiLen, CRC32(pBufferForLastReadData[i], min(g_uiLen, Chip_Info.ChipSizeInByte))); + printf("Checksum(address starting from: 0x%X, 0x%zX bytes in total): %08X\n", g_uiAddr, g_uiLen, CRC32(pBufferForLastReadData[i], min(g_uiLen, g_ChipInfo.ChipSizeInByte))); } } } else if (g_uiDevNum != 0) { @@ -1928,7 +2363,7 @@ bool CalChecksum(void) else printf("\nDevice %d (DP%06d):", g_uiDevNum, ReadUID(g_uiDevNum - 1)); - printf("Checksum of the whole chip(address starting from: 0x%X, 0x%zX bytes in total): %08X\n", g_uiAddr, Chip_Info.ChipSizeInByte, CRC32(pBufferForLastReadData[g_uiDevNum - 1], Chip_Info.ChipSizeInByte)); + printf("Checksum of the whole chip(address starting from: 0x%X, 0x%zX bytes in total): %08X\n", g_uiAddr, g_ChipInfo.ChipSizeInByte, CRC32(pBufferForLastReadData[g_uiDevNum - 1], g_ChipInfo.ChipSizeInByte)); } else { if (is_SF700_Or_SF600PG2(g_uiDevNum - 1)) { if (g_bIsSF700[g_uiDevNum - 1] == true) @@ -1941,7 +2376,7 @@ bool CalChecksum(void) printf("\nDevice %d (SF%06d):", g_uiDevNum, ReadUID(g_uiDevNum - 1)); else printf("\nDevice %d (DP%06d):", g_uiDevNum, ReadUID(g_uiDevNum - 1)); - printf("Checksum(address starting from: 0x%X, 0x%zX bytes in total): %08X\n", g_uiAddr, g_uiLen, CRC32(pBufferForLastReadData[g_uiDevNum - 1], min(g_uiLen, Chip_Info.ChipSizeInByte))); + printf("Checksum(address starting from: 0x%X, 0x%zX bytes in total): %08X\n", g_uiAddr, g_uiLen, CRC32(pBufferForLastReadData[g_uiDevNum - 1], min(g_uiLen, g_ChipInfo.ChipSizeInByte))); } } else printf("The number of programmer is not defined!\n"); @@ -2112,3 +2547,15 @@ int FlashIdentifier(CHIP_INFO* Chip_Info, int search_all, int Index) } return rc; } + +bool ScanBB(void) +{ + if(g_bIsNANDFlash == false) + return true; + if(g_iNandBadBlockManagement == 1) + return true; + + do_ScanBB(); + return g_bStatus; +} + diff --git a/dpcmd.h b/dpcmd.h index dafe9ad..9b8b8f0 100755 --- a/dpcmd.h +++ b/dpcmd.h @@ -21,27 +21,6 @@ enum ErrorCode { EXCODE_FAIL_OTHERS, }; -enum { // value dedicated by the spec - STARTUP_APPLI_SF_1 = 0, - STARTUP_APPLI_CARD = 1, - STARTUP_APPLI_SF_2 = 2, - STARTUP_APPLI_SF_SKT = 3, - - STARTUP_SPECIFY_LATER = 0xFE, - STARTUP_PREVIOUS = 0xFF -}; - -enum { - clk_24M = 0x00, - clk_8M = 0x01, - clk_12M = 0x02, - clk_3M = 0x03, - clk_2180K = 0x04, - clk_1500K = 0x05, - clk_750K = 0x06, - clk_375K = 0x07, -}; - int Sequence(); void cli_classic_usage(bool IsShowExample); bool InitProject(void); @@ -84,5 +63,11 @@ bool Wait(const char* strOK, const char* strFail); void ExitProgram(void); int FirmwareUpdate(); void sin_handler(int sig); +void FillNANDContext(void); +bool ScanBB(void); +void do_ScanBB(void); +void do_NANDSpecialErase(void); +bool SpecialErase(void); + #endif diff --git a/parse.c b/parse.c index cd18c77..f073fcb 100755 --- a/parse.c +++ b/parse.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #ifdef __FreeBSD__ #include #endif @@ -17,18 +19,18 @@ //using namespace pugi; //xml_document doc; - -#if defined(__linux__) -FILE* openChipInfoDb(void) +#if 1 + bool GetChipDbPath(char *Path) { FILE* fp = NULL; - char Path[pathbufsize]; - memset(Path, 0, pathbufsize); + if(Path == NULL) + return false; + + memset(Path, 0, linebufsize); if (readlink("/proc/self/exe", Path, 512) != -1) { dirname(Path); strcat(Path, "/ChipInfoDb.dedicfg"); - // printf("%s\n",Path); if ((fp = fopen(Path, "rt")) == NULL) { // ChipInfoDb.dedicfg not in program directory dirname(Path); @@ -36,46 +38,651 @@ FILE* openChipInfoDb(void) strcat(Path, "/share/DediProg/ChipInfoDb.dedicfg"); // printf("%s\n",Path); if ((fp = fopen(Path, "rt")) == NULL) + { fprintf(stderr, "Error opening file: %s\n", Path); + return false; + } } + if(fp) + fclose(fp); + //printf("\r\n%s\r\n", Path); + return true; + } + return false; +} + + +int Dedi_Search_Chip_Db(char* chTypeName, long RDIDCommand, + long UniqueID, + CHIP_INFO* Chip_Info, + int search_all) +{ + int found_flag = 0; + char file_path[linebufsize]; + int detectICNum = 0; + char strTypeName[32][100]; + CHIP_INFO Chip_Info_temp; + xmlDocPtr doc; + xmlNodePtr cur_node; + xmlChar *chip_attribute; + + for (int i = 0; i < 32; i++) + memset(strTypeName[i], '\0', 100); + + memset(chTypeName, '\0', 1024); + + memset(Chip_Info->TypeName, '\0', sizeof(Chip_Info->TypeName)); //strlen(Chip_Info->TypeName)=0 + + if (GetChipDbPath(file_path) == false) + { + return 1; } - //xml_parse_result result = doc.load_file( Path ); - //if ( result.status != xml_parse_status::status_ok ) - // return; + doc = xmlParseFile(file_path); + cur_node = xmlDocGetRootElement(doc); // DediProgChipDatabase + cur_node = cur_node->children->next; //Portofolio + cur_node = cur_node->children->next; //Chip + //printf("UniqueID=0x%08X\n", UniqueID); + while (cur_node != NULL) { + if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"Chip"))) { + + if (found_flag == 1) { + found_flag = 0; - return fp; + if (strlen(Chip_Info->TypeName) == 0) + *Chip_Info = Chip_Info_temp; //first chip info + detectICNum++; + memset(&Chip_Info_temp, 0, sizeof(CHIP_INFO)); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"TypeName"); + if(chip_attribute){ + + strcpy(Chip_Info_temp.TypeName, (char*)chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ICType"); + if(chip_attribute){ + + strcpy(Chip_Info_temp.ICType, (char*)chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"Class"); + if(chip_attribute){ + strcpy(Chip_Info_temp.Class, (char*)chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"Manufacturer"); + if(chip_attribute){ + strcpy(Chip_Info_temp.Manufacturer, (char*)chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"UniqueID"); + if(chip_attribute){ + Chip_Info_temp.UniqueID = strtol((char*)chip_attribute, NULL, 16);; + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"Voltage"); + if(chip_attribute){ + strcpy(Chip_Info_temp.Voltage, (char*)chip_attribute); + if (strstr((char *)chip_attribute, "3.3V") != NULL) + Chip_Info_temp.VoltageInMv = 3300; + else if (strstr((char *)chip_attribute, "2.5V") != NULL) + Chip_Info_temp.VoltageInMv = 2500; + else if (strstr((char *)chip_attribute, "1.8V") != NULL) + Chip_Info_temp.VoltageInMv = 1800; + else + Chip_Info_temp.VoltageInMv = 3300; + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"JedecDeviceID"); + if(chip_attribute){ + Chip_Info_temp.JedecDeviceID = strtol((char*)chip_attribute, NULL, 16); + if ((UniqueID == Chip_Info_temp.JedecDeviceID)) { + found_flag = 1; + + strcpy(strTypeName[detectICNum], Chip_Info_temp.TypeName); + strcat(chTypeName, " "); + strcat(chTypeName, strTypeName[detectICNum]); + } + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ChipSizeInKByte"); + if(chip_attribute){ + Chip_Info_temp.ChipSizeInByte = strtol((char*)chip_attribute, NULL, 10) * 1024; + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"SectorSizeInByte"); + if(chip_attribute){ + Chip_Info_temp.SectorSizeInByte = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"BlockSizeInByte"); + if(chip_attribute){ + Chip_Info_temp.BlockSizeInByte = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"PageSizeInByte"); + if(chip_attribute){ + Chip_Info_temp.PageSizeInByte = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"AddrWidth"); + if(chip_attribute){ + Chip_Info_temp.AddrWidth = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ReadDummyLen"); + if(chip_attribute){ + Chip_Info_temp.ReadDummyLen = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ReadDummyLen"); + if(chip_attribute){ + Chip_Info_temp.ReadDummyLen = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"IDNumber"); + if(chip_attribute){ + Chip_Info_temp.IDNumber = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"VppSupport"); + if(chip_attribute){ + Chip_Info_temp.VppSupport = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"RDIDCommand"); + if(chip_attribute){ + Chip_Info_temp.RDIDCommand = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"Timeout"); + if(chip_attribute){ + Chip_Info_temp.Timeout = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"MXIC_WPmode"); + if(chip_attribute){ + if (strstr((char*)chip_attribute, "true") != NULL) + Chip_Info_temp.MXIC_WPmode = true; + else + Chip_Info_temp.MXIC_WPmode = false; + } + //SPI NAND + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"SpareSizeInByte"); + if(chip_attribute){ + Chip_Info_temp.SpareSizeInByte = (strtol((char*)chip_attribute, NULL, 16)/*&0xFFFF*/); + //printf("SpareSizeInByte=%ld\n",Chip_Info_temp.SpareSizeInByte); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"nCA_Rd"); + if(chip_attribute){ + Chip_Info_temp.nCA_Rd = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"nCA_Wr"); + if(chip_attribute){ + Chip_Info_temp.nCA_Wr = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ReadDummyLen"); + if(chip_attribute){ + Chip_Info_temp.ReadDummyLen = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"DefaultDataUnitSize"); + if(chip_attribute){ + Chip_Info_temp.DefaultDataUnitSize = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"DefaultErrorBits"); + if(chip_attribute){ + Chip_Info_temp.DefaultErrorBits = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"BBMark"); + if(chip_attribute){ + Chip_Info_temp.BBMark = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"SupportedProduct"); + if(chip_attribute){ + Chip_Info_temp.SupportedProduct = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ECCParityGroup"); + if(chip_attribute){ + Chip_Info_temp.ECCParityGroup = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ECCProtectStartAddr"); + if(chip_attribute){ + Chip_Info_temp.ECCProtectStartAddr = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ECCProtectDis"); + if(chip_attribute){ + Chip_Info_temp.ECCProtectDis = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ECCProtectLength"); + if(chip_attribute){ + Chip_Info_temp.ECCProtectLength = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ECCEnable"); + if(chip_attribute){ + if (strstr((char*)chip_attribute, "true") != NULL) + Chip_Info_temp.ECCEnable = true; + else + Chip_Info_temp.ECCEnable = false; + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"QPIEnable"); + if(chip_attribute){ + if (strstr((char*)chip_attribute, "true") != NULL) + Chip_Info_temp.QPIEnable = true; + else + Chip_Info_temp.QPIEnable = false; + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ChipEraseTime"); + if(chip_attribute){ + Chip_Info_temp.ChipEraseTime = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"EraseCmd"); + if(chip_attribute){ + Chip_Info_temp.EraseCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ProgramCmd"); + if(chip_attribute){ + Chip_Info_temp.ProgramCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ReadCmd"); + if(chip_attribute){ + Chip_Info_temp.ReadCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ProtectBlockMask"); + if(chip_attribute){ + Chip_Info_temp.ProtectBlockMask = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"UnlockCmd"); + if(chip_attribute){ + Chip_Info_temp.UnlockCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"RDSRCnt"); + if(chip_attribute){ + Chip_Info_temp.RDSRCnt = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"WRSRCnt"); + if(chip_attribute){ + Chip_Info_temp.WRSRCnt = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"WRSRCmd"); + if(chip_attribute){ + Chip_Info_temp.WRSRCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"WRCRCmd"); + if(chip_attribute){ + Chip_Info_temp.WRCRCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"RDSRCmd"); + if(chip_attribute){ + Chip_Info_temp.RDSRCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"RDCRCmd"); + if(chip_attribute){ + Chip_Info_temp.RDCRCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"QEbitAddr"); + if(chip_attribute){ + Chip_Info_temp.QEbitAddr = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ChipIDMask"); + if(chip_attribute){ + Chip_Info_temp.ChipIDMask = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"SupportLUT"); + if(chip_attribute){ + if (strstr((char*)chip_attribute, "true") != NULL) + Chip_Info_temp.SupportLUT = true; + else + Chip_Info_temp.SupportLUT = false; + } + + xmlFree(chip_attribute); + } + cur_node = cur_node->next; + } + + xmlFreeDoc(doc); + if(detectICNum) + found_flag=1; + Chip_Info->MaxErasableSegmentInByte = max(Chip_Info->SectorSizeInByte, Chip_Info->BlockSizeInByte); + /*Read into the buffer contents within thr file stream*/ + return found_flag; } -#endif + +int Dedi_Search_Chip_Db_ByTypeName(char* TypeName, CHIP_INFO* Chip_Info) +{ + int found_flag = 0; + char file_path[linebufsize]; + CHIP_INFO Chip_Info_temp; + xmlDocPtr doc; + xmlNodePtr cur_node; + xmlChar *chip_attribute; + + if (GetChipDbPath(file_path) == false) + { + return 1; + } + + + doc = xmlParseFile(file_path); + cur_node = xmlDocGetRootElement(doc); // DediProgChipDatabase + cur_node = cur_node->children->next; //Portofolio + cur_node = cur_node->children->next; //C + // data_temp = file_buf; + /*Read into the buffer contents within thr file stream*/ + while (cur_node != NULL) { + if (found_flag == 1) { + if (strlen(Chip_Info->TypeName) == 0) + *Chip_Info = Chip_Info_temp; //first chip info -#if defined(__APPLE__) || defined(__FreeBSD__) + break; + } + + if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"Chip"))) { + + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"TypeName"); + + if(chip_attribute){ + + if (!xmlStrcmp(chip_attribute, (const xmlChar *)TypeName)) { + found_flag = 1; + //printf("chip name=%s\n",chip_attribute); + } else + found_flag = 0; + memset(&Chip_Info_temp, 0, sizeof(CHIP_INFO)); + strcpy(Chip_Info_temp.TypeName, (char*)chip_attribute); + + } + } + if(found_flag == 0) + { + cur_node = cur_node->next; + continue; + }else { + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"Class"); + if(chip_attribute){ + strcpy(Chip_Info_temp.Class, (char*)chip_attribute); + //printf("Class: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"Manufacturer"); + if(chip_attribute){ + strcpy(Chip_Info_temp.Manufacturer, (char*)chip_attribute); + //printf("Manufacturer: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"UniqueID"); + if(chip_attribute){ + Chip_Info_temp.UniqueID = strtol((char*)chip_attribute, NULL, 16);; + //printf("UniqueID: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"Voltage"); + if(chip_attribute){ + //printf("Voltage: %s\n", chip_attribute); + if (strstr((char *)chip_attribute, "3.3V") == 0) + Chip_Info_temp.VoltageInMv = 3300; + else if (strstr((char *)chip_attribute, "2.5V") == 0) + Chip_Info_temp.VoltageInMv = 2500; + else if (strstr((char *)chip_attribute, "1.8V") == 0) + Chip_Info_temp.VoltageInMv = 1800; + else + Chip_Info_temp.VoltageInMv = 3300; + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"JedecDeviceID"); + if(chip_attribute){ + Chip_Info_temp.JedecDeviceID = strtol((char*)chip_attribute, NULL, 16); + //printf("JedecDeviceID: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ChipSizeInKByte"); + if(chip_attribute){ + Chip_Info_temp.ChipSizeInByte = strtol((char*)chip_attribute, NULL, 10) * 1024; + //printf("ChipSizeInKByte: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"SectorSizeInByte"); + if(chip_attribute){ + Chip_Info_temp.SectorSizeInByte = strtol((char*)chip_attribute, NULL, 10); + //printf("SectorSizeInKByte: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"BlockSizeInByte"); + if(chip_attribute){ + Chip_Info_temp.BlockSizeInByte = strtol((char*)chip_attribute, NULL, 10); + //printf("BlockSizeInByte: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"PageSizeInByte"); + if(chip_attribute){ + Chip_Info_temp.PageSizeInByte = strtol((char*)chip_attribute, NULL, 10); + //printf("PageSizeInByte: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"AddrWidth"); + if(chip_attribute){ + Chip_Info_temp.AddrWidth = strtol((char*)chip_attribute, NULL, 10); + //printf("AddrWidth: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ReadDummyLen"); + if(chip_attribute){ + Chip_Info_temp.ReadDummyLen = strtol((char*)chip_attribute, NULL, 10); + //printf("ReadDummyLen: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ReadDummyLen"); + if(chip_attribute){ + Chip_Info_temp.ReadDummyLen = strtol((char*)chip_attribute, NULL, 10); + //printf("ReadDummyLen: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"IDNumber"); + if(chip_attribute){ + Chip_Info_temp.IDNumber = strtol((char*)chip_attribute, NULL, 10); + //printf("IDNumber: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"VppSupport"); + if(chip_attribute){ + Chip_Info_temp.VppSupport = strtol((char*)chip_attribute, NULL, 10); + //printf("VppSupport: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"RDIDCommand"); + if(chip_attribute){ + Chip_Info_temp.RDIDCommand = strtol((char*)chip_attribute, NULL, 16); + //printf("RDIDCommand: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"Timeout"); + if(chip_attribute){ + Chip_Info_temp.Timeout = strtol((char*)chip_attribute, NULL, 16); + //printf("Timeout: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"MXIC_WPmode"); + if(chip_attribute){ + if (strstr((char*)chip_attribute, "true") != NULL) + Chip_Info_temp.MXIC_WPmode = true; + else + Chip_Info_temp.MXIC_WPmode = false; + //printf("MXIC_WPmode: %s\n", chip_attribute); + } + //SPI NAND + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"SpareSizeInByte"); + if(chip_attribute){ + Chip_Info_temp.SpareSizeInByte = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"nCA_Rd"); + if(chip_attribute){ + Chip_Info_temp.nCA_Rd = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"nCA_Wr"); + if(chip_attribute){ + Chip_Info_temp.nCA_Wr = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ReadDummyLen"); + if(chip_attribute){ + Chip_Info_temp.ReadDummyLen = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"DefaultDataUnitSize"); + if(chip_attribute){ + Chip_Info_temp.DefaultDataUnitSize = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"DefaultErrorBits"); + if(chip_attribute){ + Chip_Info_temp.DefaultErrorBits = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"BBMark"); + if(chip_attribute){ + Chip_Info_temp.BBMark = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"SupportedProduct"); + if(chip_attribute){ + Chip_Info_temp.SupportedProduct = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ECCParityGroup"); + if(chip_attribute){ + Chip_Info_temp.ECCParityGroup = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ECCProtectStartAddr"); + if(chip_attribute){ + Chip_Info_temp.ECCProtectStartAddr = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ECCProtectDis"); + if(chip_attribute){ + Chip_Info_temp.ECCProtectDis = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ECCProtectLength"); + if(chip_attribute){ + Chip_Info_temp.ECCProtectLength = strtol((char*)chip_attribute, NULL, 10); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ECCEnable"); + if(chip_attribute){ + if (strstr((char*)chip_attribute, "true") != NULL) + Chip_Info_temp.ECCEnable = true; + else + Chip_Info_temp.ECCEnable = false; + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"QPIEnable"); + if(chip_attribute){ + if (strstr((char*)chip_attribute, "true") != NULL) + Chip_Info_temp.QPIEnable = true; + else + Chip_Info_temp.QPIEnable = false; + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ChipEraseTime"); + if(chip_attribute){ + Chip_Info_temp.ChipEraseTime = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"EraseCmd"); + if(chip_attribute){ + Chip_Info_temp.EraseCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ProgramCmd"); + if(chip_attribute){ + Chip_Info_temp.ProgramCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ReadCmd"); + if(chip_attribute){ + Chip_Info_temp.ReadCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"ProtectBlockMask"); + if(chip_attribute){ + Chip_Info_temp.ProtectBlockMask = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"UnlockCmd"); + if(chip_attribute){ + Chip_Info_temp.UnlockCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"RDSRCnt"); + if(chip_attribute){ + Chip_Info_temp.RDSRCnt = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"WRSRCnt"); + if(chip_attribute){ + Chip_Info_temp.WRSRCnt = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"WRSRCmd"); + if(chip_attribute){ + Chip_Info_temp.WRSRCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"WRCRCmd"); + if(chip_attribute){ + Chip_Info_temp.WRCRCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"RDSRCmd"); + if(chip_attribute){ + Chip_Info_temp.RDSRCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"RDCRCmd"); + if(chip_attribute){ + Chip_Info_temp.RDCRCmd = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"QEbitAddr"); + if(chip_attribute){ + Chip_Info_temp.QEbitAddr = strtol((char*)chip_attribute, NULL, 16); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"SupportLUT"); + if(chip_attribute){ + if (strstr((char*)chip_attribute, "true") != NULL) + Chip_Info_temp.SupportLUT = true; + else + Chip_Info_temp.SupportLUT = false; + } + } + xmlFree(chip_attribute); + } + + xmlFreeDoc(doc); + Chip_Info->MaxErasableSegmentInByte = max(Chip_Info->SectorSizeInByte, Chip_Info->BlockSizeInByte); + + if (found_flag == 0) { + Chip_Info->TypeName[0] = 0; + Chip_Info->UniqueID = 0; + } + return found_flag; /*Executed without errors*/ +} + + +bool Dedi_List_AllChip(void) +{ + char file_path[linebufsize]; + char Type[256] = { 0 }; + xmlDocPtr doc; + xmlNodePtr cur_node; + xmlChar *chip_attribute; + + if (GetChipDbPath(file_path) == false) + { + return 1; + } + + doc = xmlParseFile(file_path); + cur_node = xmlDocGetRootElement(doc); // DediProgChipDatabase + cur_node = cur_node->children->next; //Portofolio + cur_node = cur_node->children->next; //C + // data_temp = file_buf; + /*Read into the buffer contents within thr file stream*/ + while (cur_node != NULL) { + if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"Chip"))) { + + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"TypeName"); + if(chip_attribute){ + strcpy(Type, (char*)chip_attribute); + //printf("TypeName: %s\n", chip_attribute); + } + chip_attribute = xmlGetProp(cur_node, (const xmlChar *)"Manufacturer"); + if(chip_attribute){ + printf("%s\t\tby %s\n", Type, (char*)chip_attribute); + } + xmlFree(chip_attribute); + } + cur_node = cur_node->next; + } + + xmlFreeDoc(doc); + + return true; + +} + + #else FILE* openChipInfoDb(void) { FILE* fp = NULL; - char Path[pathbufsize]; - uint32_t size = sizeof(Path); - - memset(Path, 0, pathbufsize); -#if defined(__APPLE__) - if (_NSGetExecutablePath(Path, &size) == 0) { -#else - if (elf_aux_info(AT_EXECPATH, Path, size) == 0) { -#endif - strcpy(Path, dirname(Path)); + char Path[linebufsize]; + + memset(Path, 0, linebufsize); + if (readlink("/proc/self/exe", Path, 512) != -1) { + dirname(Path); strcat(Path, "/ChipInfoDb.dedicfg"); + // printf("%s\n",Path); if ((fp = fopen(Path, "rt")) == NULL) { // ChipInfoDb.dedicfg not in program directory - strcpy(Path, dirname(Path)); - strcpy(Path, dirname(Path)); + dirname(Path); + dirname(Path); strcat(Path, "/share/DediProg/ChipInfoDb.dedicfg"); + // printf("%s\n",Path); if ((fp = fopen(Path, "rt")) == NULL) fprintf(stderr, "Error opening file: %s\n", Path); } } + //xml_parse_result result = doc.load_file( Path ); + //if ( result.status != xml_parse_status::status_ok ) + // return; + return fp; } -#endif long fsize(FILE* fp) { @@ -619,6 +1226,7 @@ bool Dedi_List_AllChip(void) } /*End main*/ +#endif /***********************PARSE.TXT (CONTENT)**********************/ /* "Move each word to the next line" */ /***********************PARSE.EXE (OUTPUT)***********************/ diff --git a/project.c b/project.c index 3b31633..bbb64bd 100755 --- a/project.c +++ b/project.c @@ -20,8 +20,10 @@ unsigned long g_ulFileSize = 0; unsigned int g_uiFileChecksum = 0; unsigned char g_BatchIndex = 2; unsigned int CompleteCnt = 0; +unsigned short g_usFileBlockCount = 0; // bool m_bOperationResult[16]; bool bAuto[16] = { false }; +struct BadBlockTable g_BBT[16]; extern unsigned int g_ucFill; extern int m_boEnReadQuadIO; extern int m_boEnWriteQuadIO; @@ -42,7 +44,7 @@ extern unsigned char mcode_Program; extern unsigned char mcode_ProgramCode_4Adr; extern unsigned char mcode_Read; extern unsigned char mcode_ReadCode; -extern CHIP_INFO Chip_Info; +extern CHIP_INFO g_ChipInfo; extern int g_StartupMode; extern int g_CurrentSeriase; extern struct CAddressRange DownloadAddrRange; @@ -57,6 +59,14 @@ extern size_t g_uiLen; extern bool g_bEnableVpp; extern unsigned int g_uiDevNum; extern char strTypeName[1024]; +extern bool g_bIsNANDFlash; +extern bool g_bSpareAreaUseFile; +extern struct CNANDContext g_NANDContext; +extern bool g_bNandInternalECC; +extern bool g_iNandBadBlockManagement; +extern int g_iNandBlockIndex; +extern int g_iNandBlockCount; +extern char* g_parameter_file_offset; #if 0 extern int FlashIdentifier(CHIP_INFO* Chip_Info, int search_all, int Index); #else @@ -121,7 +131,7 @@ static unsigned int crc32_tab[] = { void TurnONVpp(int Index) { if (g_bEnableVpp == true) - dediprog_set_vpp_voltage(Chip_Info.VppSupport, Index); + dediprog_set_vpp_voltage(g_ChipInfo.VppSupport, Index); } void TurnOFFVpp(int Index) @@ -152,6 +162,103 @@ unsigned int CRC32(unsigned char* v, unsigned long size) return dwCrc32; // & 0xFFFF; } +int ReadBINFileForNAND(const char* filename) +{ + FILE* pFile;//, *pFileFroWrite; + DWORD lSize, file_size; + size_t result; + size_t read_size = 0, temp_size; + unsigned char *pTemp; + unsigned char ucTemp[g_NANDContext.realPageSize]; + DWORD temp = 0; + unsigned short tepmCount = 0; + temp =strtol((char*)g_parameter_file_offset, NULL, 10); + + pFile = fopen(filename, "rb"); + //pFileFroWrite = fopen("read.bin", "wb"); + if (pFile == NULL) { + printf("Open %s failed\n", filename); + fputs("File error\n", stderr); + return 0; + } + g_usFileBlockCount = 0; + // obtain file size: + fseek(pFile, 0, SEEK_END); + file_size = ftell(pFile) - temp; + lSize = g_NANDContext.realChipSize; + tepmCount = (g_NANDContext.realChipSize/g_NANDContext.realBlockSize)+(((g_NANDContext.realChipSize%g_NANDContext.realBlockSize)==0)? 0:1); + if(file_size > lSize) + { + printf("%s file size is bigger than chip size\n", filename); + fclose(pFile); + return false; + } + if(temp == 0) + rewind(pFile); + else + fseek(pFile, temp, SEEK_SET); + // allocate memory to contain the whole file: + if (pBufferforLoadedFile != NULL) + free(pBufferforLoadedFile); + + pBufferforLoadedFile = (unsigned char*)malloc(lSize); + + if (pBufferforLoadedFile == NULL) { + fputs("Memory error\n", stderr); + fclose(pFile); + return 0; + } + + pTemp = pBufferforLoadedFile; + + memset(pBufferforLoadedFile, 0xFF, lSize); + + if(g_bSpareAreaUseFile == true) + { + read_size = g_NANDContext.realPageSize; + g_usFileBlockCount = (file_size/g_NANDContext.realBlockSize)+(((file_size%g_NANDContext.realBlockSize)==0)? 0:1); + } + else + { + read_size = g_ChipInfo.PageSizeInByte; + g_usFileBlockCount = (file_size/g_ChipInfo.BlockSizeInByte)+(((file_size%g_ChipInfo.BlockSizeInByte)==0)? 0:1); + } + + if(g_iNandBlockCount != 0) + { + if(g_iNandBlockCount > tepmCount ) + g_usFileBlockCount = tepmCount; + else + g_usFileBlockCount = g_iNandBlockCount; + } + + g_ulFileSize = file_size; + + do + { + memset(ucTemp, 0xFF, sizeof(ucTemp)); + temp_size = min(read_size,file_size); + result = fread(ucTemp, 1, temp_size, pFile); + if(result != temp_size) + break; + + memcpy(pTemp, ucTemp, temp_size); + pTemp += (g_NANDContext.realPageSize); + file_size -= temp_size; + }while(file_size>0); + + + DownloadAddrRange.start = (g_iNandBlockIndex * g_NANDContext.realBlockSize); + DownloadAddrRange.end = (DownloadAddrRange.start + (g_usFileBlockCount * g_NANDContext.realBlockSize)); + DownloadAddrRange.length = DownloadAddrRange.end-DownloadAddrRange.start; + //fwrite(pBufferforLoadedFile , 1, lSize, pFileFroWrite); + + fclose(pFile); + //fclose(pFileFroWrite); + return 1; + +} + int ReadBINFile(const char* filename, unsigned char* buf, unsigned long* size) { FILE* pFile; @@ -250,6 +357,8 @@ int GetFileFormatFromExt(const char* csPath) bool ReadFile(const char* csPath, unsigned char* buffer, unsigned long* FileSize, unsigned char PaddingByte) { + if(g_bIsNANDFlash == true) + return ReadBINFileForNAND(csPath); switch (GetFileFormatFromExt(csPath)) { case HEX: return HexFileToBin(csPath, buffer, FileSize, PaddingByte); @@ -290,12 +399,12 @@ bool IdentifyChipBeforeOperation(int Index) binfo.UniqueID = 0; int Found = 0; - if (strstr(Chip_Info.Class, SUPPORT_FREESCALE_MCF) != NULL || strstr(Chip_Info.Class, SUPPORT_SILICONBLUE_iCE65) != NULL) + if (strstr(g_ChipInfo.Class, SUPPORT_FREESCALE_MCF) != NULL || strstr(g_ChipInfo.Class, SUPPORT_SILICONBLUE_iCE65) != NULL) return true; Found = FlashIdentifier(&binfo, 0, Index); - if (Found && (binfo.UniqueID == Chip_Info.UniqueID || binfo.UniqueID == Chip_Info.JedecDeviceID)) + if (Found && (binfo.UniqueID == g_ChipInfo.UniqueID || binfo.UniqueID == g_ChipInfo.JedecDeviceID)) result = true; return result; } @@ -319,7 +428,7 @@ bool ValidateProgramParameters(int Index) PrepareProgramParameters(Index); /// special treatment for AT45DBxxxD - if (strstr(Chip_Info.Class, SUPPORT_ATMEL_45DBxxxB) != NULL) { + if (strstr(g_ChipInfo.Class, SUPPORT_ATMEL_45DBxxxB) != NULL) { size_t pagesize = 264; size_t mask = (1 << 9) - 1; return (mask & DownloadAddrRange.start) <= (mask & pagesize); @@ -327,14 +436,14 @@ bool ValidateProgramParameters(int Index) /// if file size exceeds memory size, it's an error /// if user-specified length exceeds, just ignore - if (DownloadAddrRange.start > Chip_Info.ChipSizeInByte - 1) + if (DownloadAddrRange.start > g_ChipInfo.ChipSizeInByte - 1) return false; size_t size = DownloadAddrRange.length; if (size > g_ulFileSize && g_ucFill == 0xFF) return false; - if (DownloadAddrRange.end > Chip_Info.ChipSizeInByte) + if (DownloadAddrRange.end > g_ChipInfo.ChipSizeInByte) return false; return true; } @@ -362,6 +471,42 @@ bool ProgramChip(int Index) return result; } +bool ProgramNANDChip(int Index) +{ + bool bIsBadBlock=false; + DWORD usFileOffset = 0; + bool result = true; + //threadScanBB(Index); + //printf("\nProgramming, please wait ...\n"); + TurnONVcc(Index); + if(!SPINAND_ProtectBlock(false,Index)) + return false; + if(!SPINAND_EnableInternalECC(g_bNandInternalECC,Index)) + return false; + + for(unsigned short i=0; i addr.start) - addr.length = Chip_Info.ChipSizeInByte - addr.start; + if (0 == addr.length && g_ChipInfo.ChipSizeInByte > addr.start) + addr.length = g_ChipInfo.ChipSizeInByte - addr.start; addr.end = addr.length + addr.start; - if (addr.start >= Chip_Info.ChipSizeInByte) { + if (addr.start >= g_ChipInfo.ChipSizeInByte) { result = false; } else if (0 == addr.start && (0 == addr.length)) { result = threadReadChip(Index); @@ -578,12 +746,18 @@ bool threadProgram(int Index) int pthread_mutex_destroy(pthread_mutex_t * mutex); + if(result && g_bIsNANDFlash == true) + { + result = ProgramNANDChip(Index); + goto exit; + } + if (result && ProgramChip(Index)) { result = true; } else { result = false; } - + exit: g_is_operation_successful[Index] = result; return result; } @@ -610,13 +784,22 @@ bool threadCompareFileAndChip(int Index) result = false; if (result) { - ReadChip(DownloadAddrRange, Index); - - size_t offset = min(DownloadAddrRange.length, g_ulFileSize); - unsigned int crcFile = CRC32(pBufferforLoadedFile, offset); - unsigned int crcChip = CRC32(pBufferForLastReadData[Index], offset); + if(g_bIsNANDFlash == true){ + + DownloadAddrRange.start = (g_iNandBlockIndex * g_NANDContext.realBlockSize); + DownloadAddrRange.end = (DownloadAddrRange.start + (g_usFileBlockCount * g_NANDContext.realBlockSize)); + DownloadAddrRange.length = DownloadAddrRange.end-DownloadAddrRange.start; + //printf("ReadBINFileForNAND(), DownloadAddrRange.start=%ld, DownloadAddrRange.end=%ld, DownloadAddrRange.length=%ld\n", DownloadAddrRange.start, DownloadAddrRange.end,DownloadAddrRange.length); + result = SPINAND_RangeVerify(&DownloadAddrRange,Index); + } + else{ + ReadChip(DownloadAddrRange, Index); + size_t offset = min(DownloadAddrRange.length, g_ulFileSize); + unsigned int crcFile = CRC32(pBufferforLoadedFile, offset); + unsigned int crcChip = CRC32(pBufferForLastReadData[Index], offset); - result = (crcChip == crcFile); + result = (crcChip == crcFile); + } } g_is_operation_successful[Index] = result; @@ -624,6 +807,38 @@ bool threadCompareFileAndChip(int Index) return result; } +bool threadScanBB(int Index) +{ + bool result = true; + if (strstr(g_ChipInfo.ICType, "SPI_NAND") == NULL) + return result; + + printf("\nScanning blocks...\n\n"); + g_BBT[Index].cnt=0; + SetIOMode(false, Index); + SetSPIClockDefault(Index); + SPINAND_ScanBadBlock(g_BBT[Index].bbt,&g_BBT[Index].cnt,Index); + if(g_BBT[Index].cnt > 0) + { + if(g_BBT[Index].cnt==1) + printf("There is 1 bad block: %d\n", g_BBT[Index].bbt[0]); + else + { + printf("There are %d bad blocks: ", g_BBT[Index].cnt); + for(unsigned short i=0; i 0) { offsetOfRealStartAddrOffset = LockAddrrange.start - effectiveRange.start; memcpy(pBufferforLoadedFile + offsetOfRealStartAddrOffset, pBufferForLastReadData[Index] + offsetOfRealStartAddrOffset, LockAddrrange.length); - Leng = GenerateDiff(addrs, vc, DownloadAddrRange.length, pBufferforLoadedFile, g_ulFileSize, DownloadAddrRange.start, Chip_Info.MaxErasableSegmentInByte); + Leng = GenerateDiff(addrs, vc, DownloadAddrRange.length, pBufferforLoadedFile, g_ulFileSize, DownloadAddrRange.start, g_ChipInfo.MaxErasableSegmentInByte); } else { offsetOfRealStartAddrOffset = DownloadAddrRange.start - effectiveRange.start; -Leng = GenerateDiff(addrs, vc + offsetOfRealStartAddrOffset, DownloadAddrRange.length, pBufferforLoadedFile, g_ulFileSize, DownloadAddrRange.start, Chip_Info.MaxErasableSegmentInByte); +Leng = GenerateDiff(addrs, vc + offsetOfRealStartAddrOffset, DownloadAddrRange.length, pBufferforLoadedFile, g_ulFileSize, DownloadAddrRange.start, g_ChipInfo.MaxErasableSegmentInByte); } if (Leng == 0) // speed optimisation @@ -714,14 +929,14 @@ Leng = GenerateDiff(addrs, vc + offsetOfRealStartAddrOffset, DownloadAddrRange.l else { uintptr_t* condensed_addr = (size_t*)malloc(min(DownloadAddrRange.length, g_ulFileSize)); size_t condensed_size; - condensed_size = Condense(condensed_addr, vc, addrs, Leng, effectiveRange.start, Chip_Info.MaxErasableSegmentInByte); + condensed_size = Condense(condensed_addr, vc, addrs, Leng, effectiveRange.start, g_ChipInfo.MaxErasableSegmentInByte); - if (strstr(Chip_Info.Class, SUPPORT_WINBOND_W25Mxx_Large) != NULL) + if (strstr(g_ChipInfo.Class, SUPPORT_WINBOND_W25Mxx_Large) != NULL) SerialFlash_batchErase_W25Mxx_Large(condensed_addr, condensed_size, Index); else SerialFlash_batchErase(condensed_addr, condensed_size, Index); - if (strstr(Chip_Info.Class, SUPPORT_MACRONIX_MX25Lxxx) != NULL) { + if (strstr(g_ChipInfo.Class, SUPPORT_MACRONIX_MX25Lxxx) != NULL) { TurnOFFVcc(Index); Sleep(100); TurnONVcc(Index); @@ -734,7 +949,7 @@ Leng = GenerateDiff(addrs, vc + offsetOfRealStartAddrOffset, DownloadAddrRange.l size_t idx_in_vc = addrs[i] - effectiveRange.start; struct CAddressRange addr_range; addr_range.start = addrs[i]; - addr_range.end = addrs[i] + Chip_Info.MaxErasableSegmentInByte; + addr_range.end = addrs[i] + g_ChipInfo.MaxErasableSegmentInByte; addr_range.length = addr_range.end - addr_range.start; if (SerialFlash_rangeProgram(&addr_range, vc + idx_in_vc, Index) == 0) { @@ -763,7 +978,7 @@ bool RangeUpdateThruSectorErase(int Index) bool RangeUpdateThruChipErase(int Index) { - unsigned char* vc = (unsigned char*)malloc(Chip_Info.ChipSizeInByte); + unsigned char* vc = (unsigned char*)malloc(g_ChipInfo.ChipSizeInByte); unsigned int i = 0; bool boIsBlank = true; struct CAddressRange addr; @@ -773,9 +988,9 @@ bool RangeUpdateThruChipErase(int Index) if (!threadReadChip(Index)) return false; - memcpy(vc, pBufferForLastReadData, Chip_Info.ChipSizeInByte); + memcpy(vc, pBufferForLastReadData, g_ChipInfo.ChipSizeInByte); - for (i = 0; i < Chip_Info.ChipSizeInByte; i++) { + for (i = 0; i < g_ChipInfo.ChipSizeInByte; i++) { if (vc[i] != 0xFF) { boIsBlank = false; break; @@ -785,20 +1000,20 @@ bool RangeUpdateThruChipErase(int Index) if (threadEraseWholeChip(Index) == false) return false; - if (strstr(Chip_Info.Class, SUPPORT_MACRONIX_MX25Lxxx) != NULL || strstr(Chip_Info.Class, SUPPORT_ATMEL_45DBxxxD) != NULL) { + if (strstr(g_ChipInfo.Class, SUPPORT_MACRONIX_MX25Lxxx) != NULL || strstr(g_ChipInfo.Class, SUPPORT_ATMEL_45DBxxxD) != NULL) { TurnOFFVcc(Index); Sleep(100); TurnONVcc(Index); } } - memset(vc + DownloadAddrRange.start, g_ucFill, min(DownloadAddrRange.length, Chip_Info.ChipSizeInByte)); + memset(vc + DownloadAddrRange.start, g_ucFill, min(DownloadAddrRange.length, g_ChipInfo.ChipSizeInByte)); memcpy(vc + DownloadAddrRange.start, pBufferforLoadedFile, min(g_ulFileSize, DownloadAddrRange.length)); SetIOMode(true, Index); addr.start = 0; - addr.end = Chip_Info.ChipSizeInByte; - addr.length = Chip_Info.ChipSizeInByte; + addr.end = g_ChipInfo.ChipSizeInByte; + addr.length = g_ChipInfo.ChipSizeInByte; return SerialFlash_rangeProgram(&addr, vc, Index); @@ -806,7 +1021,7 @@ bool RangeUpdateThruChipErase(int Index) bool RangeUpdate(int Index) { - bool fast_load = (Chip_Info.ChipSizeInByte > (1 << 16)); + bool fast_load = (g_ChipInfo.ChipSizeInByte > (1 << 16)); return ((mcode_SegmentErase != 0) && fast_load) ? RangeUpdateThruSectorErase(Index) @@ -822,6 +1037,41 @@ bool ReplaceChipContentThruChipErase(int Index) return threadProgram(Index); } +bool threadPredefinedNandBatchSequences(int Index) +{ + bool result = true; + + if(pBufferforLoadedFile == NULL || g_usFileBlockCount == 0 || g_ulFileSize == 0) result = false; + if(result) + { + if(!threadScanBB(Index)) + result=false; + } + if( result ) + { + switch(g_BatchIndex) + { + case 1: + if(!threadBlankCheck(Index))//not blank + { + if(!threadEraseWholeChip(Index)) + result=false; + } + if(result == true) + result=threadScanBB(Index); + if(result == true) + result = threadProgram( Index); + break; + case 2: //special auto + break; + default: + result = false; + break; + } + } + return result; +} + bool threadPredefinedBatchSequences(int Index) { bool result = true; @@ -846,6 +1096,21 @@ bool threadPredefinedBatchSequences(int Index) return result; } +bool threadSpecialEraseWholeChip(int SiteIndex) +{ + bool result = true; + if(SiteIndex == -1 || SiteIndex >= 128) + return false; + + if(bAuto[SiteIndex] ==false) + result = SPINand_SpecialErase(0, g_NANDContext.realChipSize/g_NANDContext.realBlockSize, SiteIndex); + else + result = SPINand_SpecialErase(g_iNandBlockIndex, g_iNandBlockCount, SiteIndex); + + g_is_operation_successful[SiteIndex] = result; + return result; +} + void threadRun(void* Type) { THREAD_STRUCT* thread_data = (THREAD_STRUCT*)Type; @@ -857,17 +1122,17 @@ void threadRun(void* Type) int dwUID = ReadUID(Index); if (g_uiAddr == 0 && g_uiLen == 0) { - if(is_SF700_Or_SF600PG2(Index)){ - if (g_bIsSF700[Index] == true) + if(is_SF700_Or_SF600PG2(Index)){ + if (g_bIsSF700[Index] == true) printf("\nDevice %d (SF7%05d):", Index + 1, dwUID); - else if (g_bIsSF600PG2[Index] == true) + else if (g_bIsSF600PG2[Index] == true) printf("\nDevice %d (S6B%05d):", Index + 1, dwUID); - } + } else { - if ((dwUID / 600000) == 0) - printf("\nDevice %d (DP%06d):", Index + 1, dwUID); - else - printf("\nDevice %d (SF%06d):", Index + 1, dwUID); + if ((dwUID / 600000) == 0) + printf("\nDevice %d (DP%06d):", Index + 1, dwUID); + else + printf("\nDevice %d (SF%06d):", Index + 1, dwUID); } } @@ -905,7 +1170,6 @@ void threadRun(void* Type) break; case PROGRAM_CHIP: - TurnONVpp(Index); threadProgram(Index); TurnOFFVpp(Index); @@ -926,10 +1190,20 @@ void threadRun(void* Type) case AUTO: TurnONVpp(Index); bAuto[Index] = true; - threadPredefinedBatchSequences(Index); + if(g_bIsNANDFlash) + threadPredefinedNandBatchSequences(Index); + else + threadPredefinedBatchSequences(Index); TurnOFFVpp(Index); break; + + case NAND_SCAN_BB: + TurnONVpp(Index); + threadScanBB(Index); + break; + case NAND_SPECIAL_ERASE: + threadSpecialEraseWholeChip(Index); default: break; } @@ -1137,24 +1411,37 @@ CHIP_INFO GetFirstDetectionMatch(char* TypeName, int Index) { CHIP_INFO binfo; binfo.UniqueID = 0; - unsigned int g_Vcc_temp = 0; - //char TypeName[1024]; - - // memset(TypeName, '\0', 1024); + // unsigned int g_Vcc_temp = 0; int Found = 0; int i = 0; int Loop = 3; if (strcmp(g_parameter_vcc, "NO") != 0) //g_parameter_vcc!=NO + { Loop = 1; + } - if (strlen(TypeName) != 0) - g_Vcc_temp = g_Vcc; +// if (strlen(TypeName) != 0) +// g_Vcc_temp = g_Vcc; for (i = 0; i < Loop; i++) { if (Found == 1) { - if (strlen(TypeName) != 0) - g_Vcc = g_Vcc_temp; + if (strcmp(g_parameter_vcc, "NO") == 0) + { + switch(binfo.VoltageInMv) + { + case 1800: + g_Vcc = vcc1_8V; + break; + case 2500: + g_Vcc = vcc2_5V; + break; + case 3300: + g_Vcc = vcc3_5V; + break; + } + + } break; } if (Loop != 1) @@ -1228,23 +1515,23 @@ void SetProgReadCommand(int Index) mcode_ProgramCode_4Adr = 0xFF; mcode_ReadCode = 0xFF; - if (strcmp(Chip_Info.Class, SUPPORT_SST_25xFxx) == 0) { + if (strcmp(g_ChipInfo.Class, SUPPORT_SST_25xFxx) == 0) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = 0x60; mcode_Read = BULK_NORM_READ; - if (strstr(Chip_Info.TypeName, "B") != NULL || strstr(Chip_Info.TypeName, "W") != NULL) + if (strstr(g_ChipInfo.TypeName, "B") != NULL || strstr(g_ChipInfo.TypeName, "W") != NULL) mcode_Program = AAI_2_BYTE; else mcode_Program = AAI_1_BYTE; - } else if (strstr(Chip_Info.Class, SUPPORT_SST_25xFxxA) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_SST_25xFxxA) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = 0x60; mcode_Read = BULK_NORM_READ; mcode_Program = AAI_1_BYTE; - } else if (strstr(Chip_Info.Class, SUPPORT_SST_25xFxxB) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_SST_25xFxxB) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = 0x60; @@ -1252,7 +1539,7 @@ void SetProgReadCommand(int Index) mcode_Program = AAI_2_BYTE; mcode_SegmentErase = 0xD8; mcode_WRDI = WRDI; - } else if (strstr(Chip_Info.Class, SUPPORT_SST_25xFxxC) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_SST_25xFxxC) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = 0x60; @@ -1260,52 +1547,52 @@ void SetProgReadCommand(int Index) mcode_Program = PAGE_PROGRAM; mcode_SegmentErase = 0xD8; mcode_WREN = WREN; - } else if (strstr(Chip_Info.Class, SUPPORT_ATMEL_AT25FSxxx) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_ATMEL_AT25FSxxx) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; mcode_Read = BULK_NORM_READ; mcode_Program = PP_128BYTE; mcode_SegmentErase = 0xD8; - } else if (strstr(Chip_Info.Class, SUPPORT_ATMEL_AT25Fxxx) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_ATMEL_AT25Fxxx) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; mcode_Read = BULK_NORM_READ; mcode_Program = PP_128BYTE; mcode_SegmentErase = 0x52; - } else if (strstr(Chip_Info.Class, SUPPORT_ATMEL_AT26xxx) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_ATMEL_AT26xxx) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; mcode_Read = BULK_FAST_READ; mcode_SegmentErase = 0xD8; - if (AT26DF041 == Chip_Info.UniqueID) { + if (AT26DF041 == g_ChipInfo.UniqueID) { mcode_Program = PP_AT26DF041; - } else if (AT26DF004 == Chip_Info.UniqueID) { + } else if (AT26DF004 == g_ChipInfo.UniqueID) { mcode_Program = AAI_1_BYTE; } else { mcode_Program = PAGE_PROGRAM; } - } else if (strstr(Chip_Info.Class, SUPPORT_ESMT_F25Lxx) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_ESMT_F25Lxx) != NULL) { const unsigned int F25L04UA = 0x8C8C8C; mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; mcode_Read = BULK_FAST_READ; mcode_SegmentErase = 0xD8; - if (F25L04UA == Chip_Info.UniqueID) + if (F25L04UA == g_ChipInfo.UniqueID) mcode_Program = AAI_1_BYTE; else mcode_Program = AAI_2_BYTE; // PAGE_PROGRAM; - } else if (strstr(Chip_Info.Class, SUPPORT_NUMONYX_Alverstone) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_Alverstone) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; mcode_Read = BULK_NORM_READ; mcode_Program = MODE_NUMONYX_PCM; mcode_SegmentErase = 0xD8; - } else if (strstr(Chip_Info.Class, SUPPORT_EON_EN25QHxx_Large) != NULL || strstr(Chip_Info.Class, SUPPORT_MACRONIX_MX25Lxxx_Large) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_EON_EN25QHxx_Large) != NULL || strstr(g_ChipInfo.Class, SUPPORT_MACRONIX_MX25Lxxx_Large) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; @@ -1314,7 +1601,7 @@ void SetProgReadCommand(int Index) mcode_SegmentErase = 0xD8; mcode_ProgramCode_4Adr = 0x02; mcode_ReadCode = 0x0B; - } else if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S25FLxx_Large) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S25FLxx_Large) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; @@ -1323,34 +1610,34 @@ void SetProgReadCommand(int Index) mcode_SegmentErase = 0xD8; mcode_ProgramCode_4Adr = 0x12; mcode_ReadCode = 0x0C; - }else if (strstr(Chip_Info.Class, SUPPORT_SPANSION_S25FLxxS_Large) != NULL) { + }else if (strstr(g_ChipInfo.Class, SUPPORT_SPANSION_S25FLxxS_Large) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; - if(strstr(Chip_Info.TypeName, "S25FS256T") != NULL) + if(strstr(g_ChipInfo.TypeName, "S25FS256T") != NULL) mcode_Read = BULK_NORM_READ; else - mcode_Read = BULK_4BYTE_FAST_READ; + mcode_Read = BULK_4BYTE_FAST_READ; if(g_bIsSF600[Index] == true || g_bIsSF700[Index] == true || g_bIsSF600PG2[Index] == true) mcode_Program = PP_PROGRAM_ANYSIZE_PAGESIZE; else mcode_Program = PP_4ADR_256BYTE; mcode_SegmentErase = 0xD8; mcode_ProgramCode_4Adr = 0x12; - if (strstr(Chip_Info.TypeName, "S25HL01GT") != NULL - || strstr(Chip_Info.TypeName, "S25HL512T") != NULL - || strstr(Chip_Info.TypeName, "S25HL256T") != NULL - || strstr(Chip_Info.TypeName, "S25FS256T") != NULL - || strstr(Chip_Info.TypeName, "S35HL256T") != NULL) + if (strstr(g_ChipInfo.TypeName, "S25HL01GT") != NULL + || strstr(g_ChipInfo.TypeName, "S25HL512T") != NULL + || strstr(g_ChipInfo.TypeName, "S25HL256T") != NULL + || strstr(g_ChipInfo.TypeName, "S25FS256T") != NULL + || strstr(g_ChipInfo.TypeName, "S35HL256T") != NULL) mcode_ReadCode = 0x0B; else mcode_ReadCode = 0x0C; - } else if (strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large_2Die) != NULL ) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large_2Die) != NULL ) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = 0xC4; mcode_Program = PP_4ADDR_256BYTE_MICROM; - if (strstr(Chip_Info.TypeName, "N25Q512") != NULL) + if (strstr(g_ChipInfo.TypeName, "N25Q512") != NULL) mcode_SegmentErase = 0xD4; else mcode_SegmentErase = 0xD8; @@ -1364,7 +1651,7 @@ void SetProgReadCommand(int Index) mcode_Read = BULK_4BYTE_FAST_READ_MICRON; } - } else if (strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large_4Die) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = 0xC4; @@ -1374,27 +1661,27 @@ void SetProgReadCommand(int Index) mcode_ReadCode = 0x03; mcode_Read = BULK_NORM_READ; - } else if (strstr(Chip_Info.Class, SUPPORT_NUMONYX_N25Qxxx_Large) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_NUMONYX_N25Qxxx_Large) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; mcode_Read = BULK_4BYTE_FAST_READ_MICRON; mcode_Program = PP_4ADDR_256BYTE_MICROM; - if (strstr(Chip_Info.TypeName, "N25Q512") != NULL) + if (strstr(g_ChipInfo.TypeName, "N25Q512") != NULL) mcode_SegmentErase = 0xD4; else mcode_SegmentErase = 0xD8; mcode_ProgramCode_4Adr = 0x02; mcode_ReadCode = 0x0B; - } else if (strstr(Chip_Info.Class, SUPPORT_MACRONIX_MX25Lxxx_PP32) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_MACRONIX_MX25Lxxx_PP32) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; mcode_Read = BULK_FAST_READ; mcode_Program = PP_32BYTE; mcode_SegmentErase = 0xD8; - } else if (strstr(Chip_Info.Class, SUPPORT_WINBOND_W25Pxx_Large) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_WINBOND_W25Pxx_Large) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; @@ -1403,11 +1690,11 @@ void SetProgReadCommand(int Index) mcode_SegmentErase = SE; mcode_ProgramCode_4Adr = 0x02; mcode_ReadCode = 0x0C; - } else if (strstr(Chip_Info.Class, SUPPORT_WINBOND_W25Mxx_Large) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_WINBOND_W25Mxx_Large) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; - if (strstr(g_board_type, "SF100") != NULL) // is sf100 + if (strstr(g_board_type, "SF100") != NULL) // is sf100 mcode_Program = PP_4ADDR_256BYTE_12; else mcode_Program = PP_4ADR_256BYTE; @@ -1415,7 +1702,7 @@ void SetProgReadCommand(int Index) mcode_SegmentErase = 0xDC; mcode_ProgramCode_4Adr = 0x12; mcode_ReadCode = 0x0C; - }else if (strstr(Chip_Info.Class, SUPPORT_WINBOND_W25Pxx) != NULL) { + }else if (strstr(g_ChipInfo.Class, SUPPORT_WINBOND_W25Pxx) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; @@ -1424,19 +1711,19 @@ void SetProgReadCommand(int Index) mcode_SegmentErase = SE; mcode_ProgramCode_4Adr = 0x02; mcode_ReadCode = 0x0B; - } else if (strstr(Chip_Info.Class, SUPPORT_ST_M25Pxx_Large) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_ST_M25Pxx_Large) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; mcode_Program = PP_4ADR_256BYTE; mcode_Read = BULK_4BYTE_FAST_READ; mcode_SegmentErase = SE; - if (strstr(Chip_Info.TypeName, "GD25LB256E") != NULL) + if (strstr(g_ChipInfo.TypeName, "GD25LB256E") != NULL) mcode_ProgramCode_4Adr = 0x12; else mcode_ProgramCode_4Adr = 0x02; mcode_ReadCode = 0x0C; - } else if (strstr(Chip_Info.Class, SUPPORT_WINBOND_W25Qxx_Large) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_WINBOND_W25Qxx_Large) != NULL) { mcode_RDSR = RDSR; mcode_WRSR = WRSR; mcode_ChipErase = CHIP_ERASE; @@ -1445,7 +1732,7 @@ void SetProgReadCommand(int Index) mcode_SegmentErase = SE; mcode_ProgramCode_4Adr = 0x02; mcode_ReadCode = 0x0B; - } else if (strstr(Chip_Info.Class, SUPPORT_ATMEL_45DBxxxB) != NULL) { + } else if (strstr(g_ChipInfo.Class, SUPPORT_ATMEL_45DBxxxB) != NULL) { mcode_RDSR = 0xD7; mcode_WRSR = 0; mcode_Read = BULK_AT45xx_READ; @@ -1453,9 +1740,9 @@ void SetProgReadCommand(int Index) mcode_SegmentErase = 0; CHIP_INFO mem_id; SetPageSize(&mem_id, 0); - Chip_Info.ChipSizeInByte = GetChipSize(); - Chip_Info.PageSizeInByte = GetPageSize(); - } else if (strstr(Chip_Info.Class, SUPPORT_ATMEL_45DBxxxD) != NULL) { + g_ChipInfo.ChipSizeInByte = GetChipSize(); + g_ChipInfo.PageSizeInByte = GetPageSize(); + } else if (strstr(g_ChipInfo.Class, SUPPORT_ATMEL_45DBxxxD) != NULL) { mcode_RDSR = 0xD7; mcode_WRSR = 0; mcode_Read = BULK_AT45xx_READ; @@ -1463,20 +1750,26 @@ void SetProgReadCommand(int Index) mcode_SegmentErase = 0; CHIP_INFO mem_id; SetPageSize(&mem_id, 0); - Chip_Info.ChipSizeInByte = GetChipSize(); - Chip_Info.PageSizeInByte = GetPageSize(); + g_ChipInfo.ChipSizeInByte = GetChipSize(); + g_ChipInfo.PageSizeInByte = GetPageSize(); } + else if(strstr(g_ChipInfo.Class, SUPPORT_GIGADEVICE_GD5F1GQ4xCx) != NULL){ + mcode_Program = PAGE_PROGRAM; + mcode_Read = BULK_NORM_READ; + mcode_ProgramCode_4Adr = 0x02; + mcode_ReadCode = 0x0B; + } } bool ProjectInitWithID(CHIP_INFO chipinfo, int Index) // by designated ID { DownloadAddrRange.start = 0; - DownloadAddrRange.end = Chip_Info.ChipSizeInByte; + DownloadAddrRange.end = g_ChipInfo.ChipSizeInByte; InitLED(Index); // SetTargetFlash(g_StartupMode,Index); //for SF600 Freescale issue SetProgReadCommand(Index); if (strcmp(g_parameter_vcc, "NO") == 0) { - switch (Chip_Info.VoltageInMv) { + switch (g_ChipInfo.VoltageInMv) { case 1800: g_Vcc = vcc1_8V; break; @@ -1494,9 +1787,205 @@ bool ProjectInitWithID(CHIP_INFO chipinfo, int Index) // by designated ID bool ProjectInit(int Index) // by designated ID { - Chip_Info = GetFirstDetectionMatch(strTypeName, Index); - if (Chip_Info.UniqueID == 0) { + g_ChipInfo = GetFirstDetectionMatch(strTypeName, Index); + if (g_ChipInfo.UniqueID == 0) { return false; } - return ProjectInitWithID(Chip_Info, Index); + return ProjectInitWithID(g_ChipInfo, Index); } + +#if 0 + bool analysisPartitionTable(bool SpareUseFile, char *strTblPath) + { + wstring wstr; + Context::CFileContext::NAND_PTN_TBL ptn_tbl; + + wstr.assign(strTblPath.begin(), strTblPath.end()); + m_context.file.nand_PartitionTablePath = wstr; + + boost::filesystem::wpath p(wstr); + wstring fmt(p.extension()); + boost::to_upper(fmt); + + if(fmt == L".CSV") + ptn_tbl = Context::CFileContext::PTN_CSV; + else if(fmt == L".MBN") + ptn_tbl = Context::CFileContext::PTN_MBN; + if(fmt == L".DEF") + ptn_tbl = Context::CFileContext::PTN_DEF; + if(fmt == L".DPMBN") + ptn_tbl = Context::CFileContext::PTN_DPMBN; + + + switch(ptn_tbl) + { + case Context::CFileContext::PTN_CSV://excel + { + CFile file; + CStringArray saData; + int nLen=0; + CString sFileName, str; + sFileName = m_context.file.nand_PartitionTablePath.c_str(); + CStdioFile readFile; + CString strLine; + vector vecstrLine; + CFileException fileException; + if(readFile.Open(sFileName, CFile::modeRead|CFile::shareDenyNone, &fileException)) + { + m_context.file.nand_BlockIndex.resize(0); + m_context.file.nand_EndBlock.resize(0); + m_context.file.nand_BlockCount.resize(0); + m_context.file.nand_MaxBlockCount.resize(0); + m_context.file.nand_SpareAreaUseFile.resize(0); + + + while (readFile.ReadString(strLine)) + { + vecstrLine.push_back(strLine); + CString token; + int position =0; + + m_context.file.nand_BlockIndex.push_back(_ttoi(vecstrLine[nLen].Tokenize(_T(";"),position))); + m_context.file.nand_EndBlock.push_back(_ttoi(vecstrLine[nLen].Tokenize(_T(";"),position))); + m_context.file.nand_BlockCount.push_back(_ttoi(vecstrLine[nLen].Tokenize(_T(";"),position))); + m_context.file.nand_MaxBlockCount.push_back(m_context.file.nand_BlockCount.back()); + m_context.file.nand_SpareAreaUseFile.push_back(SpareUseFile); + nLen++; + } + m_context.file.nand_ptnTable_ImageCount=nLen; + } + else + { + return false; + } + readFile.Close(); + } + break; + case Context::CFileContext::PTN_DEF://def + { + std::vector buffer; + bool bWrongFormat=false; + std::ifstream in(m_context.file.nand_PartitionTablePath.c_str(), std::ios::in|std::ios::binary) ; + in.seekg(0, in.end); + unsigned int FileLen = in.tellg(); + if((FileLen%16)!=0) + return false; + + char * buf = new char [FileLen]; + in.seekg(0, in.beg); + in.read(buf,FileLen); + + buffer.resize((FileLen)/sizeof(DWORD)); + memcpy((DWORD*)&buffer[0],&buf[0],FileLen); + + delete [] buf; + in.close(); + + if((buffer[0]==0x554f5247)&&(buffer[1]==0x45442050)&&(buffer[2]==0x454e4946)&&(buffer[3]==0x00000032))//group define2 + { + buffer.erase(buffer.begin(),buffer.begin()+4); + m_context.file.nand_BlockIndex.resize(0); + m_context.file.nand_EndBlock.resize(0); + m_context.file.nand_BlockCount.resize(0); + m_context.file.nand_MaxBlockCount.resize(0); + m_context.file.nand_SpareAreaUseFile.resize(0); + for(unsigned int i=0;i<((buffer.size()-4)/4);i++) + { + if(buffer[i*4+1]!=0xffffffff) + m_context.file.nand_BlockIndex.push_back(buffer[i*4+1]); + else + return false; + if(buffer[i*4+2]!=0xffffffff) + m_context.file.nand_EndBlock.push_back(buffer[i*4+2]); + else + return false; + if(buffer[i*4+3]!=0xffffffff) + { + m_context.file.nand_BlockCount.push_back(buffer[i*4+3]); + m_context.file.nand_MaxBlockCount.push_back(m_context.file.nand_BlockCount.back()); + } + else + return false; + m_context.file.nand_ptnTable_ImageCount=(buffer.size()-4)/4; + m_context.file.nand_SpareAreaUseFile.push_back(SpareUseFile); + } + if(((buffer[buffer.size()-3])!=0xffffffff) + &&((buffer[buffer.size()-2])!=0xffffffff) + &&((buffer[buffer.size()-1])!=0xffffffff)) + { + m_context.file.nand_BlockIndex.push_back(buffer[buffer.size()-3]); + m_context.file.nand_EndBlock.push_back(buffer[buffer.size()-2]); + m_context.file.nand_BlockCount.push_back(buffer[buffer.size()-1]); + m_context.file.nand_MaxBlockCount.push_back(m_context.file.nand_BlockCount.back()); + m_context.file.nand_ptnTable_ImageCount+=1; + m_context.file.nand_SpareAreaUseFile.push_back(SpareUseFile); + } + } + } + break; + case Context::CFileContext::PTN_MBN://mbn + case Context::CFileContext::PTN_DPMBN://dpmbn + { + std::vector buffer; + std::ifstream in(m_context.file.nand_PartitionTablePath.c_str(), std::ios::in|std::ios::binary) ; + in.seekg(0, in.end); + unsigned int FileLen = in.tellg(); + if((FileLen%16)!=0) + return false; + + char * buf = new char [FileLen]; + in.seekg(0, in.beg); + in.read(buf,FileLen); + buffer.resize(FileLen/sizeof(DWORD)); + memcpy((DWORD*)&buffer[0],&buf[0],FileLen); + delete [] buf; + in.close(); + + m_context.file.nand_BlockIndex.resize(0); + m_context.file.nand_EndBlock.resize(0); + m_context.file.nand_BlockCount.resize(0); + m_context.file.nand_MaxBlockCount.resize(0); + m_context.file.nand_FileOffset.clear(); + m_context.file.nand_SpareAreaUseFile.resize(0); + + if(!((buffer[buffer.size()-1]==0xffffffff) + ||(buffer[buffer.size()-2]==0xffffffff) + ||(buffer[buffer.size()-3]==0xffffffff))) + return false; + unsigned int i=0; + for( i=0;i<(buffer.size()-4)/4;i++) + { + if(buffer[i*4] == 0xffffffff && buffer[i*4+1] == 0xffffffff && buffer[i*4+2] == 0xffffffff && buffer[i*4+3] == 0xffffffff) + break; + if(buffer[i*4]!=0xffffffff) + m_context.file.nand_BlockIndex.push_back(buffer[i*4]); + else + return false; + + if(buffer[i*4+1]!=0xffffffff) + m_context.file.nand_EndBlock.push_back(buffer[i*4+1]); + else + return false; + if(buffer[i*4+2]!=0xffffffff) + { + m_context.file.nand_BlockCount.push_back(buffer[i*4+2]); + m_context.file.nand_MaxBlockCount.push_back(m_context.file.nand_BlockCount.back()); + } + else + return false; + + if(ptn_tbl == Context::CFileContext::PTN_DPMBN) + m_context.file.nand_FileOffset.push_back( + i==0? 0:m_context.file.nand_BlockIndex[i]-m_context.file.nand_BlockIndex[0]); + m_context.file.nand_SpareAreaUseFile.push_back(SpareUseFile); + } + m_context.file.nand_ptnTable_ImageCount=i;//(buffer.size()-4)/4; + } + break; + } + get_context().file.nand_UsePartitionFile = true; + m_context.file.nand_FileOverBBcnt.resize(m_context.file.nand_ptnTable_ImageCount); + m_context.file.nand_FileOverBBcnt_BC.resize(m_context.file.nand_ptnTable_ImageCount); + return true; + } +#endif diff --git a/project.h b/project.h index 1b2a020..a89bc28 100755 --- a/project.h +++ b/project.h @@ -27,6 +27,11 @@ typedef enum { // 07.03.2009 UPDATE_FIRMWARE, AUTO_UPDATE_FIRMWARE, + BLINK_SITE, + NAND_SCAN_BB, + NAND_SPECIAL_PROGRAM, + NAND_SPECIAL_ERASE, + NAND_SPECIAL_AUTO, } OPERATION_TYPE; @@ -70,6 +75,10 @@ bool threadReadRangeChip(struct CAddressRange range, int Index); bool threadConfiguredReadChip(int Index); bool threadCompareFileAndChip(int Index); bool threadReadChip(int Index); +bool threadScanBB(int Index); +bool threadPredefinedNandBatchSequences(int Index); + + int ReadBINFile(const char* filename, unsigned char* buf, unsigned long* size); int WriteBINFile(const char* filename, unsigned char* buf, unsigned long size); bool LoadFile(char* filename); diff --git a/usbdriver.c b/usbdriver.c index 13e5e37..dd0d003 100755 --- a/usbdriver.c +++ b/usbdriver.c @@ -16,7 +16,7 @@ extern volatile bool g_bIsSF600PG2[16]; extern int g_CurrentSeriase; extern char g_board_type[8]; extern int g_firmversion; -extern CHIP_INFO Chip_Info; +extern CHIP_INFO g_ChipInfo; extern unsigned int g_uiDevNum; extern bool isSendFFsequence; @@ -626,3 +626,17 @@ long flash_ReadId(unsigned int read_id_code, unsigned int out_data_size, int Ind // printf("\n(Simon)Flash ID 0x%x (0x%x, %d)\n",rc, read_id_code, out_data_size); return rc; } + +int BulkPipeReadEx(unsigned char* pBuff, unsigned int cnRead, unsigned int timeOut, int Index) +{ + int ret, actual_length; + if (Index == -1) + Index = DevIndex; + + //unsigned long cnTemp = cnRead; + ret = libusb_bulk_transfer(dediprog_handle[Index], 2 | LIBUSB_ENDPOINT_IN, pBuff, cnRead, &actual_length, DEFAULT_TIMEOUT); + if (ret != 0) //libusb_bulk_transfer return false + return 0; + return cnRead; +} + diff --git a/usbdriver.h b/usbdriver.h index 1553f50..43c7547 100755 --- a/usbdriver.h +++ b/usbdriver.h @@ -72,5 +72,7 @@ int dediprog_set_vpp_voltage(int volt, int Index); long flash_ReadId(unsigned int read_id_code, unsigned int out_data_size, int Index); int BulkPipeWrite(unsigned char* pBuff, unsigned int size, unsigned int timeOut, int Index); +int BulkPipeReadEx(unsigned char* pBuff, unsigned int cnRead, unsigned int timeOut, int Index); + #endif //DEDI_USB_DRIVER From fef1f8e6d0a29589b66041615232cb499551b17d Mon Sep 17 00:00:00 2001 From: Benwang217 Date: Wed, 26 Feb 2025 10:39:15 +0800 Subject: [PATCH 20/26] Update chip database Newest chip database from Windows --- ChipInfoDb.dedicfg | Bin 686599 -> 3859198 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ChipInfoDb.dedicfg b/ChipInfoDb.dedicfg index 0aee655929a390de9361b2337c2696951e83fa78..e4b15e59de5b6702a9bb30be6cc32ee3a0a6d2d0 100644 GIT binary patch literal 3859198 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

)9-3EJj~D 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

RITnZN zQwtVbyjWww7B4pK7WHc87cYV_TLbULD3*^uAGt_1`v7o;BtoX%ZZU$*78 z#c8lOR1-6fqyAtV^&mz4Ezk6uUu=G{`Nf9C7B8NkcyXxy)^gTOqAbsN4Jd3mO}EFDAO1S*oo2*tad*ZBSnP9$}@NHH_$a}T^wX&+XOR$3I2XAB+ zjI!K}Jq%YT*1oY%z(Mefvr)wAr+C*IUg2GMjWfK*>-X-sJzPEK_$y}V4o98f-;)75 zptJjro*ieMx#H3#s`wt}Oy9V>vE$w&S1U*E<8yXLIs@I|c=q+=dCC#&T_|_+JI;`! zu?{dlRV+O{imz}baz*Un)8w;+aT#}v)Fb|cqvfutl4jhoM>vXSG1~Kp_d(8;&po?r zjn;tDd$5dZn5aUmt!&*3==c@f6qg2kI%a=F}&5oxJKByvKKh zWCgQ7@Y*M=2mcOMu6lv9yuujcx

#thQYZY^nYw_Obr;JwAi8E`N>bNa;UI)(pGi z-C&MRaHiuvKis9#KS42lDrMf~e2d2)3|?Yp&fLAv*E)NRS!50H*Qf!mb--hLPD#D% z(YsHZK+Ys(Wo%h>M|cvrF3UT6vO+mOeKR`;R@CNtjjyIHPb=@BRzN>S<+@|(9ztGuxbNKX9;ctqHOL)s1$Xcnx|#B7xa-{F$>%=t1$Xrv=Owkq zxvNRHvVXa&<_bJ_D{ukNf?&!5cE1aEMW1nuN09IMA9r@{5DSIRbJgYmrn!U!MnGangNR{4MM_fvd-bXPF$$ZhQMdh~b{%a6;WIUl37&!r=q z+`+?251*f*BY1%|2JVx5U1ntUyq&!{>x`I z!+-HnCS?Pb=bjB1&lH$#K)%4(0Qx`129Sp^Hh_CA*Ms`>v&sf6qmKGAFmpBI{K#NR zH?}+*@Hxl^5L?o)0h8hXR>q>m;lCa|4g8nSYKH&9w3Xw3oc}NQZ~nje|94=yjq&&V zy)pjg|M!XUuk!!%)?3*B58;2T|KAn-->ilIdh|5#Up}iY{%;~i5w5EyR%$u>zl1o9 z>E!ik*mq1PBgz`h@s_?Gljj76<7Zw`P>lBJ1XNp|)Hokd}$O9ISFN;oFhw54H#AO-ejG$j3!owIo^&&pH zE$C77{NpqL8k?8c5&hFsJagO7c^u;BF7_4aD1JZq8Gl*D-ws{Op8F5gUX1MXcj{|+ zez)$K4f*bJz9Gz(qsk)k+)I<;NwX+>*e13Sn%c7siP?_|3|tfFlX zDyQM`ct-Ql71OZTu-IE4@?6%(V%Aj?jIY9CIiehkSIskamRgFgn3h34iXDc=hQ?H> zr&Opj+P9VQA@OQ+VW!l^X0C_y*)}w;i^j|FV#E6Q{(HLX&KqxzuC$PicTQD9+|bp~ zRXy1)_@ZRDU&C`1)s6YO3-G8VQ*6)W{#`=jAeo4qHHo1e;Rt3il9$X!c=C!6LswBy zzsG!*u@ss$GkhfZT+X)qeH(lV(ZhJ>y-Z8k)YoMcc+#%Zg2u)>8}IBbQ;PvhhAlOx z76Y~z@IpbUF?lxjJE%auU}dqc!WUO7*Qf9cY4BJrQeU}6>JCUwWD)U3 zYi3B!!3+0<9^=li@&oHF@mhB=i*>bJtddf!98uJe6=%Rlz>5(^#y581xls9~v5vkf zzx+B9HJoTrv}Q@!{I{hQ`{3rYnO00InXrn<9==)8gzH3dwW)$w8*oDQi zi`f_JtBbJ$vp3Xplo*0XdhUT$mFUdgDB2r!?FXvbL-7TvRv6|qmSOu@MPOsNpbXT*4od`8JbL^CGiHMp;_?hd)8{2Iu|qkWIOqP>v! zLXFSZbNNinIJ(4_RO00mLdIn}_QekDi*76Z#QOAptD_t^fMEHnlWW(oc=BLhukDtS~S&1eY^OLd?^AQCRtW~aI7-!`f*H^owS`LImGep$qWGhbHWUNJE~szEIYM@)zLGGblK zUk9dy`r1hRC4~3l6K%Vzngy2OAtMxwf^Xo?$Qo&m^!eyTd#Il#3c8je)LGpZr zNBYVRjYs$*b39rH zEbsZy2CULJEICwfVhw~c4C`3~KRN5_BhMw^&CxuVcp62nYp+B}7n-gzFK%M_MvA@xH><##d-&a|=& zlnv(3xN3OQLF_(6u0J@!2g_3Sc#L(R`kQ(_~hukG+>w^J87WYF@t^ z)Y=hibs6Rx@?IarcPQ6KVzPO9T+5pG67as?okt=lspMtfH zcrTi$^!vyKOv@@5jy4R>d0SBjLFHz(2239?SxuupFa+eD)zi%D0P-h4CsBH8x61hK$?GV$!8tIuBwdF=i49Fdm9R8;1ity5!;bFs zUKox}#MU)z-mAZ&5N|c56~YngS|Q}_weEX4tHBC=zr3c^NM zAE!w)5Bn~&n{|)n`L$|>R8+B^H?8>DvH}Eke3nG|=ti4-MExp=#rmz76vfJFr?eVoM`vMH1G_<-ft9(;kS(vvXXnTiU7O5m@O`2ujbY437y9+tOiy&^6$v2 zydJ`O;Jkz)AL1{C_y(=F%zO^6S^0xJS zR&4ML#T%#xn)RCQzFwlgl^fD(B&Joju^)`YBzjA|Lh=+}kr&DwjxYFm=5XsVxWGDH z7-G9D5cliWU=DKz9I-BEK-3TQaugk52=ygmF-u*Q+R#smx+yNoP?eRDuP9K=9h9-Z zV->Tm^)0@R3l&`V2EW1Xq~}o79ENbecs7RnY5Oot9+_y4``zalrma^X;~@PRyBntn z=UjN5$v)!A`&qpS;)vEiXjaWxF_Sxu=_bjje#T5NW_XE+;mzPX{`Ves1S5zGK>9Z0 z6sfZ?sDWSpx zgjXmcdTfTqJlPjT3u!)?g(GMmX1CJAv@MHuMA%mF%^K)@k~HSgrGAcK%YtVAE+jwg;Xovt!I{pd4`CGTJIAi4hY9)A8>hF@zIMd%0ad+wfB{gApve!Pi4vg{UES=ESyWLn#?+TNLvV+Ey`yd5T@|AEKzG z-79|6aJ?qkWvVJUrOctsYelW=b}xoT6qlp;2L6;2Ev0AMSpiHLsJ@rBMkAF zJuiHKVYXWSsZ<1p+3%h0EcKLVL6al&5iDB$w^@~Za)tef59lgM;n&MPrL2FRQx~m% zA9MkR*-d&q7-r}DL6OI&&OhX7%MsPS_FKdp){w{)pV+64g{yOyrq_$5g z=3Ofn)y)$W3Z|m2I`pzmgqM?(>s}V}$_n2dp*}sxi2YZaI7IQ^(sr zH%_~luinfv9DnRv?7kQ7_|ITA?@(js->8)Ec<{}AJ;J{1^-X*~s4}I_O{!<@;WySa7a#ZzTKaR;{1j#3 z8qQpfKgVEVWQ_7DVsz z3e3C*WHfl}B-f33M*OhgE zGtIC0{L@qH>@ePD65NjM1i?H=t?B$4Pcv&R@@}zfquen*^OxED>HYVygEPExiWwZP zzfJy9&LkyoAgk^OcY#kw`JAa;y_uZ@fAXr1@Kk@n7pvNE{hZ?J`2?Nf?~Lu}_0eUFou-|1fp_j+`H(@*D_NhfCRb{-NFkvx5HlXCS}Z zjXnXgs~W;{e=>x>f)!v0FMAjFo}xuCuGfXT3d_+OU+SeY^dAfML+|CbUe`8Izr z0DJI}pFpprBOgGks476lK1Ee|3>{|w6n*&}&OamhCn2xsOJ@fhVg{GNK|FCBL=nfU zb^86se$(lkAHPPqip9aJGCV2mlUVR?#!2c{`WT9}%6oBhZ@okn7(oRsOlY%dz|= z@@9C%__-O)%=-!W{}rEl4X@@qINX0$yt_%R9?wN{w~Cp1u^D&mRL>t)07y=$SlNE= zi?v;sp~qpbWL{H~jy%-P7c+*6_WE$AEoW!Q$Eu& zS544Rs*3O)g|U#xNp3fm;eLrRU&5wlt{(H$US_#!@=1Ko`(B?+=_&-+&2-0TMKuw+bcVI#Ay$QNW2O9czAp(VVU z=OfH+sB1S+87KQux!s_v_B&?(%+(|r&o?kzU>Eift)hGP^)q~(Blw2DI`7x)h{^1T z(TGG0|FGIJ|1f-3{u=YU*S+(Z={KjU^4~o>Ving$uEzKW?%J=xdK`>Yj4JX%#Qjm< zw0?Erd9x$LY8tg8gqiYwrr8mjQB{YQdum6Jxsh5zDftJE*u;(qFg}*Dw@~>^n;jucy4ew&0an3dgoxGu%G64E zHAmeX1KmSBA7OTcT28_;_>KU)ALV?6*%9|(6Eu#|#Ew{p`XQu$koqej{eyJ=mCD3o znHc{tncXm~sR*+Vd|KMjJQUBwU)8)Z4pPPU5f~ok0CKj&Re9N?OO9lHxvD+}rgON2 zwu<$aHC`dveDbex4pOt0402Z(2RV<2R6NA?4iZ87?7gDeVMXZhC3b+Oh^{e!dG1dBxu{Wri zx2PyJ)Sqs2VV+T6IoormG4~9?e4{?I$JkZoKc#%kuqu089fg>B$z~_y`xP@gB2@7} zyqjuv;4LgA_Ac7V)Cxo_V+Xt+t&CuusKU4v&mKFL9bwrK$})_r^FRC95%X+6lqnUa zmno6YlzayT+ZSMVzMB&FILnmy3m{bqeya z5UveAqh(zbB?6)&*0mwFz(RyND9h_%9>TIFe4pguSVIb%!qkr4wka%Yg8gI7rnp2U z8R_!P^(u8<+EYH3@et|vbPoc3>uaz*Hq8U$NHpQei1$C7ny@XiWA)dmrDN<)) z4%;P`O)>5Ik@u+7@Ei*N8)QLP)dq`cbb){HUSPZRBV*VHSrL{^aptPpesp=C5}Kg?5`2B_aZ!%@E1520yubeek;papMAF%0ZSWK959#eNX?DbktKZ3e z{~R@)nA;|mbg0o7pM4tc8&Mqdk;}-rMD8ia9N#@cly%|WPs1pk0{Pi5K%W2M97>&a zshP>MZ<0Ofvp34v{!NT4wKb@ek)!@Ed+)Z~HkLFC^ZI`Z#azuqOuHpf$1nDc4(@L6 zwtQ0C?*1nx6td*6t!T;iNLJhKhx#69Kghn`nJ6qTfFytgaDfEC423LNBtZ~|l~q|; zSvJSx4f0=`^5L8^j?)Pr{*f-I67xr@ZJ)(WTt%$RTjZOc3o)ycfr{x<99cK#foD=P z9$w%|dk^;_;;UU914;@307TJ{cfSZS;JJcE5wQX`|6;&WrT6^^&MatqY$CG zP@UJoN#YTvF>uU@3)SFU~mk0RzX9#Oe66gwCzSD!am-%lcW9_3i5ZdbQZ zU8pWp_m0J4;HUZX7*m#&t1DN(0wa121XHeVy)diC5_LQqTc6~MjZxt2y zob23_pL6|Mp>=i6S$~F_n%gd?S>A$wqC??XZd&{C=r_CrqvrgyI=`ROE3fs_^}WJw z^{YQ|RBmxpxCWRD*pq~#8&bWUXNu9(bKHmK!0r?yzWTFBe;@JiP9b2*WmVUQov{-E zO$`#Oy6(2vq`JPH)_db%`*ymvC}UT~u8dt7``Uc3=wvyYpuZPTr8o^|4Lo|9$9qGyghfQrR3m`&lL*8*cv22_@s8t~aZkodI1Q zj}E~8{FLOP)$?+^{>-%DvG{Q!9k*DYAK$|(t6b#jVeU5gFkUla$meIsg}E^%?JA!p z;t6wa(2vvwA2?yIcZ3PAgfpY-Yp;2C(4JW_(Yd%9UI*9=*%gXuqLwrBQD}GDX5q8JT@_A)Vnd?mda`;Ug({bh0+j^+J zoo-J#d{GWRPFWL&{bd?Vq3o;{+}qa97@(Uw2$#dtFW%t|C#bGUt;}EMTpl?xtJYwIcid)7g77^LMs-9a% zo8kc<4~WTc<{I0)ZeQgZTQ}zylV6VYyWjfDEh13PKdFLq&i`k~fBS~^^XB}=_{@vW z`}18>UCsQfbaKl4`^Do6=@*OiRPK=bi&e8%w;QLhlx6i!CE=bWq!-fr*)KwRQw;mg zcQ*q@NKe1>RqSY&I`0cG#m$y!n$vG3D*kv#?|3@Z@r&#Dwq^|4X|8?$K zzH<6oXuPgQe?c|z2-D>bq1k8VLwzavcFt2}HgpPY=tq1JaryXVs?)f{->J4RuRqo; zjMsE-79a4q*n4I`*En|0Lq1zW=g}>5kr&p-!1_(7_TpvrThOD)!^WZbydE~H)%T6P zSFK*PdQ&L~?ahtQaWdwpl1FLPCP+nh@*KbRokL)Rr;`z){ zd3~L{UK)KW|5&Lv1>j+_{x~&%mu9$2ljpN~)-gk-xN{mkr?*dc+x-j5PyYS;G@YNE-&xUQ}?~P@9%Jx@R}LAJN-1je~M3ji<(UN&H3#*H&+`tNP|td0%ZVe&<_XdMv+Nx5XxYx0@+591rW2 zgA410^}>2;&HR_s-g=e%WCmS5AFfJIF9$qz&QS>&lAW)iKlKV3?mOhUzWyKTmlK-T zJ7i`};2i4B`((~GxwU&_0914ye^X{sFV9uOCR6_h&zOFkv)RnmrU}+>MD@knQC^R; zC9D_L3+sjTYj9n?0;BU5Dsn06c}GZNM}^TmSl@h(%|0UUn0k6*z4Cfty|7+bFRT~V zA0d~uu0iSPKxC!28YaN^kIsPD)Pf}xa*GZO?FR0tMbE~VzV1njn6nh*?oC-&rU+F z%kEiO|E-^M4qQ}JjKRNHzXU5@oMd*Ftl#VcrMmJldPVtVTl@--E-F9xtg}Sx;e4l# zF_ZByd1byc{b8aNXSdA}>WhX=*$E`ac>kl+QGt3Ad)5tE{ivYh>uS`Vs)a` znNqu#s?tnt6V@k}jRWL&+tlw?`n-PW^RgJs)vMSAj~(-~`sLg0X}`ewN;h~n=dD^} z$5-%^6lv`8Tdc3K+sD3`A7i|%UEVehhdmNHtqt=edD{#*Yp?5MH#vK@30jY#+TkkE zG;`0#Z(W^3V=JNateK82HHT)%XkFLeX12S{|KKhOakp8uIDi%T-DC}k6$eOv=kxK| zae#96;X2&ajRNFt^Ec#0R=rnWoz+`h-skwXGt_sCt^1s~=4(z3V}i#x7N7Am@9M)x zy3|)!C+83At8-hdpY!h~{e!%^%CO#|fnPAa;UhTNC%E$1E5a+&^Tgy1){)O1Af`GV z{UeDVRIM+n)`#Lf86r1HNDTet_tGTES>2s6#Eo?8VxeME~bLX04do@oVj_sNyAB&||)?PNPM#wH?r?;N6 zb}~+6QOBbP_IsBn!f;WKS|T=tnf z?i=_TVv*SrHqtejmr`zj`^o4#L>Q0Y7q~WZ^W@gRORqt%u?Eb`&yqU@?!3UW z4^WxU&WK~wQQYrl$QSBT%P6KhZ2NA2axN6N$B5E2dq%izJ=el*;WpRJc|7Pyk1NhdDV2d#rV%}MMrkG#b$MM(`?1i$vLkU)zFoX3)h9~!u7v_@3i$*`Zzz) z#pTI&=;`Fl){ozGu8dLoT0?gz9B;0S+hP-3rvjeGITo%fV^_wmjGcE>UMatN(_+Q6 zi)o)^+P8z5_C6}#x1(q5Zi`KjeGmM3JY?TN#e!Q?&aRwYIlFRpt_9-am9zhmDEO4K z*PR91JZI<3n0V^AF;or8*_E>^XIIYt1-e`Fmlm=M*$vslePr`|e5mIP@48T}o6Cmd zG3RcJ&GKv0lf+=o>4U2LS|}_O777c6voqLvJ*Xx=^!%FLdvR6lZj1GieGeM;c+5Gs zrTkjRE@T(73)zM2^w@CzcT}+r9oZev9WQ5hTda@l>`vQ{RukVv#3E!DvJ2UT>_T=S zyO5n-g%?ng-zQTtIj_>3d(7+2F*(H(*XKd@?aG{eGwn?;_i?9h4Sn3Xx6-=JuXS_2 z;c{=6dprH0??zTvyn+r#tB~+6Q-6q54G{jfS%DLUr%$+8ouZ)a!LnUF!9C zuI)ng5Aeq_PwKowmOR^)t1DOkluij8nnRpWJqD^9XC5P0XI!evx^i_}XUIFA!2O9H zP@HjkHu@EnnX(BhoXX4E%^7Apls!+VE>st)3)Q+7SBVt^F9!Y^%8Iwi>N;#Ucjf9aa`h_D*LtX~y1H_8Lm3xdizN)USy811m zvHA*lPIGHkSKmlF3CWelVBj}Xy{8oL?JMBfao~>k(da9t9Prw?!`E5P`Qmu=8)gp@ zXY;k`hj>19)o*90kjQQxh=7|>;73D4t@vgKksEByO3STo{t1Hqh&f4qAwTcHM*Wy9|OEcWW~5@2vb#s z>_YZsAbU(6UK3iXl<=0#Ij%mNC;nWJDHip&xjdASlyY{<#fb&(*q%YL_iK`IKTh-L z9k3b7*`Fcqeh3ZYIhdDga1_&Q4)OH}nRXtDcY(hxTiIOBXjt-+k4{`3)Fd_GsnOB_K~ zSuXK+ZpW?F>*+)qcej7QwSPhE_XTtqCU1y*#G-<|C@HP`J>P_eskS-(X>=@JQnV2F^ah(+-*mAPpkaBz;$yD zoIS=BMBd;l?uWPF4v4sR53?U?u~@!^J6CynT{I_(^wnj~eAr{U%yEl#UFLQWk5*4{ zBT9rJ`mh|~h3H?tt<+>?`-kYfa%1Y^gydO{-Jv*t3dt=i7m{1{!)Pj;aTk&sD^Eso z1NTxBB;QM3SEhfjlbdfVHwWIm1IIqEPENTw_4%K0B?$W$PEJ)*aiv^HE+k(Tl3P_L z4w5^LP4#l+ac9vsYoVUxEFCJ79A6@O_w8SYP8=r&G@)^Rj`j zF~0d5?iT1YM=7n1*NME&@4)CSIyHS#rn zdyW6UPVN!YMf1Mno$vLP{d0X4%Py9^4AB_{jL|vz6a1TqHOIK-?{L-MCRIpRK_mM$ z9=*cj=IC@X`VM!+BPg`iM*jj2vIeaBKKZ$s{@fb<8-G2*mY*U5pdB($JYcJr*<@WSX?Bxaa zn0jBw&@lqyWIy5}x!YnBjl1DhEF@Rgnv`*6PO)O)m9u+~8smKPXyAI#@-8=w8t6}{ zZZ)f`jNxz0OqUtttE5{#-!*R$C?6$bE*9RHgEi#nbYoZpD{v3~fH^#`J~~~~7lS!^ zot)g^E_ne)x%cT-KH;}!o^fuAb&;I?=T(kz;mSB}O-L>z7n0L;glj3+jZ-jmj)mtc zAtV=)XT9Uja7A$1!rkaIYSFjpm6P{d8u|n_b*s(Wt;Tw~u>&!3@?AuUs;3LdyMyFy z&1I>pb)T%O3(@Cua#wCn*C@t{%FWNA#$#3dI*Etg;rA09o0}vm`ilR(Mm_u!I*3`1 z_jUc)*}3a7ie4TP= zPm;Si>zL>I(Yu21%Gu4+n%sGeSuH|%Aw2#6sJRPAcwf&SF22(%&bYAob9Ump6mi0L z)~1RluBwhM_Fe4zYOwE|K(~Vox?1~gs(0qQZ;}lApUAKuBToN}pZUrI9}$*+MXkmV z`wYj+Dt*NASWfPS<*KBMe;1akl0L0yQ&#SEYO8_eJ{xAeskn3}v zF~}SUlwB*kp6wCS@9f(8ykd2nQ5(W7*44D}ReWt#c5VITySuTb@hL_P{qHWE0v-ruZ z)2lC4N5{BEVoXM(dlDx=zsG*D^8GB)lF~JaD_nk`+L~zY=C9b4mbNr*o45yfFKj0F zfYrEv$7essC#EMAb+lB@3h$?{xEOeUh@9dO$Nw-n{;n6jOY=~<>hgZg=GfU|G5OeV z^Y2hDo#@innz&V>V`4qG*bM7!O)6v3!?Au?lUIcDLV3$6xccT%JG(YpUdr`IC~s;T zn@-|A;oKaD7l<8;9Kp8}-jDeLkG6kixQ~obet4Z~Liudxc{7yX{gyArLHWHwIlBtw zh4Mmq>nYns7D~>FIoM$aiCKv`0y}YouVwqb3gw0JUFucqN-n>PySCb4CN!7lig=tv z;$rOQo!BDAzKq#_iuwe*PwP%h7h_M)%ZI3*oTD%3dS=yxS@g6^s8F6=Qum3!DjnUJ z6fCtFtM)FUsyWQcMu;OOYq1co&^8R+1u*)e<6MR;?#RUO&;_ zXXDGy?>CV{x(TweP~Mme;kq<7C-H%WYSuzi^W~saTqE6?0T}I#E zkuKl2F1a@I{dj$Nbe~l{-{tbY!_C$8EWhE}>YgK>UmbXw45xhGbu@5oP`>{OxdS_P zxn3&YH*LOW5SrBU_fwuZR=)o*$qXvuc5qq zo!mX4lV;{+_46!>XA!f!{_++1rd@K*IMeP1Qtb6#P%4!<3Q z-x#sOzS{pbwD)cdd>2>m&|6$R@8DQ9`#c&ckKeD<ZUJUMSCer1Pievt6fYkK>8!x7Y;bcOp996Xn%ICzKb;3+2BcTk~J)qEiUD?9xQUbah!9QV%{TcEdJeZu|8%~F>hU3 zF*5UAa1O$3VRjpsE&g5nyZHB^@b8}YcF1~{cwt^)8c_eeZMvnT+k=*1FR28?!g!m- zB)z=!@>0^>A`kf;6}5Ayc*MSQH5dDC{W4jXy47Ugvwi1vaXvgR56io|g~`mjtq(m8 zCW|XqMVvgA^~>^Ji`A*Fyjyv<@^0nbj}hm7#=4T%`~4Gt2}9~dXxqDm@q6ewi|0ne zu6O0#;?~>1_`IT5ZZzssSD(7gQ_7>AMc3VTqv6cV^+0v|D_+WZ-CU?HR2Qnx;}0`mu3j}`y$-7Hs0%HUKa5aas4i3|i`Z{>S26H) zC$5TtXD&Z)u3n{a4@Y&@*TulAt{z|Ep4SA3ffobcm&q(bb)kAQFW32Ub*u5msH+pz z#lQ>Ih3ay06$38@UJU$l82Ak+ovWs;)ydU0IXzZCdNl)2j%G9U`j-m+7&YkYMCEFjlpR3VF}< z>D~e6Wd{j&X1eG6^Hx(O&|U2aYhXU=*hLJugZP9>qT3_lS0!QdgMlF_}k8y=hXh zyL+R375f(Y+IZC!qxv}Md#ma<_t~NP(&kmL@1${}dd(+iJgO$%{hGL+kFpLX&zz!G z-HFxB#_Be74>Tcy+25Nn>4qn3qn{Cfaz0AG zde4npi8Be!lyBT({oZpsm+|m@LwfcKJ-c&>u}-!ugZp!i!xhG>^W062n(R@d*AMU6 z=eXN!^*cbme3`oH+S;amituRbYhZq1k$W5q&d>a(G9^LUgyqx`@8} zZBNSbb?#}oJDi=1F&xEyOjep<es&UoM8zyFbE?&F7JhSy?xSMdu5+ z>XmhOCGqECvi>7vpGSB%iW85F_lRVVc1-gS%)ARv%UeU_HbGn~u zD^9VckND#Ax!PW)6YekZcW%dVwCgFyF&!gtORBP4m7NSoSe<e$%X6nyT0Y6Ka)Ytg!HU9rP^J?DTL=+#n zPBH>w{U?3kAL3|@@x6|3o(JLotK>MmN@A9L>|&7$j}qDZY0btqj^Yk*s!iTMd;*)} z2~JvK{P8fYY2I8^WB8Ix zkl?2ra;1S$1iutT{0(T(hj}t$5&l2illJw$a1UFax`x>0E53~>I0H9q`dYFG>~G+G z9EU~NM)v}@riww4%8%Vy#@o2FBb?{;()LuEKC%em)q_bEVbOS>J-V}%{~NgOxiXZi z{TE#)c!)L9-cvk5KM-DaxXnI=KCwau(^AuV1H?rV)jHyS6!62|UVf)2-d8$kJzJ>gn z>Z%RXY8o*L#))yg>PNgGMxhR)umQ~=wFFhTA6`3<>z+gN*{C0m_@;9zuNGMJz{$b% zYt)2VckHv?JaPfBYi`KQ{|;FHuImTXHCWeG*Kq>s8l0zVkO*Jp^;5?c;9(Li45MOT zagA4MWi#;hdklo|npXP(s-!=XPNaU#wOcgvFN9}*QH(rXz5r#~z&hGLi>qVy7I2I8 zdkeOa#aH|OFjuTn|Iv$gEKR^SMt*h6^42b5m(rO+($3L-Q*sP$r*5qbvXk=dE=jpI|=Hc{BiQhg!96AtE!wpr+NW~ z-~$w^^K|^>^HO;R@8hU4Iv38bkBn>SOKm_n?`HID2lWI9=f8l7Hny2cy{0&Cojh@H zUXy;jUVnCVK>2*L&VJ$iITW0>LK4}8^V!M+`3m8D*SUT2lAhaFKA-Q;W7J;Vzt) z;yEG*N;)9x0=83 zz6kH>1jGo=^_XRQ1@eA>s?_HhfUMh0H~IU%Y4x&4bhc8jtNuN7=i^s*{d-iA_ZfWF zU6*SgopbM!s@@fPjz0l&S>27~JU zh?C3ji?J7DpZf8{)$56|mnz>+oGe^CN6R6#b?ycZ__EM`94xr)#)3os(R5(T~^iiBWB{P ziivM8NBMDjyxp^;q|dKeC!=2xaUVfZ_8KeP4c0d2li&SZyn9M|)0^|()o{J*g9ENK z_FiM}`_&lVEK6bU_aanZADYoqFA_JScUx?h(O1pF3D4-amC@shbttadI`3cUal-aeoAs~=9Dck;Zu z17FRxTg-hInR|!I%yiDt`+q;;8g>Dsy+;M6iH6Q?u?fyo%Mc6aca+U5o5vO02F`b% zw^!Hu`?P-ST;*NeKuY;f>6AxJs;N7{zFk+G_Of}$u*XArx5c_B&xy3Ieh?#@--W(V zPIu+myqxYHP1N1Jz8IkskXHY#nL{4#z$zIop#ON!Qjhwuz zRyIqP)7@>tb6%#dLzl?Jn2-5s#HL631#WFOII17;xDcInOQ$2OH;1-eOqbIgodwI( zdeyV;!z=iV2E^@`M+3GxyXQ!&H=I~NIlpp#V>=WfoT8KM2(hP&j2MwlMhJ`So1;RK z`_NC7-9B)Ydmk%fm!jU`uT*xtu41X|@>s6=yXx;*W`Pv|b+@a#-BkI1f77wM>-7YP>s^`3)%>7+HbHqba`tO*L{&tLN6;z7Y-O_o0zfF0Nc$ z8abi7)5i(rRZ%yD$@Ar2oyM5BPG5VmGd%SR^uyrHS8g?o9Vcoz4Otx3y5C}5JsbC9 zr?NYZP8Ixozu)EUpTN1bs{ecsN9zP@45z8nHSRIc_A`FwyYZU&$@zU~ z!(+zQ>p1w%yVj<#G{N_3XZJezF131`d|RlV_mUH;Gp@7A7gRwB)fu()q24W2cTBoR zR7NtzIkr&!2$A5ts9wdR*F$yb&V}o3@aV#I;d(a5HC9QuPB#_ur{mEBe7{O~fmdMe zK4PNDee#pMvhfDS6uwS0;nam^Re^N)rf10>z7O$DL7sgkO zn(yHqmYuEpeHe1KzK8R;ot&9st$H0?-%~#s?w5DqkHo@@g}()R*q#nfEWGmdeyP(v zrq;>Vi|gShh-q9soKXl_`*(;({QC?UyLV9`t#We@$L=xW0OjQ6*lm%LdromLxVZNI zaqZok+*0lgljk{Rd&7_)rLQAn{KGWP=QB-H@d0b+4b&akF7QQE&igQ-MI5_0_GW&r z^Ht8P`o_cYd{=mmNYG)mSDZN?DD#J69O|AUJkMiFvCmunc~ZowcCOm_Cqz03J1-D`qmBW^al>huZTYJL7zIB$yMxwAy_KkG(`K>TL8hag{vBURuo1 zhU)zY*P_h|oJaK@cY5lqBXEWs@;W^d&(d|T=&ac_%VU=B3(r>-i63KJ*;X^O`!WCg zM>qrI`^fNdA}p_nr`YCG?8{kFe|(MKUnghBUdii*PN4qEqB^!;nl~N~_qB-Jd0_Q+pa=gcF(aNN~r5|<@r!|63Hif%w}N@ zufn6GAFy7p*)gg@Z*wct&$#l7q6+`HrtyjEFniHrU^KmySRH;3>>^&5@#V#Nc-9>} zJPV(7bcN{C-s^dmBNoH%(40So=%zPgY#>CpUW~ekZs?T7^H?~3kRX3d9OoA6;y88d z)EjdBFGli^{P}en{RqhoOJk_ils|t$d_f$yjF?%eVy!L6M%FA!C)`)30mq+IOMSV?VI*CxG3H8s+_cb~GJdbS5 z{rkYQD=+^5o~~|QZn)InNFi?C&q$$3-p^{gn{8MYDO6|vFR&d}7vfmG#BWI#Xv_KRVOw9&WdazJY%8y^i;rhic*2VRnfu zoPKZ@_@X|7{S(yv(G!l^thh`(*ID+^ld+A%#QQDQ&D{-=O`lYZ$j)iDtg22#W?Udd zj)lln8B!Nx%>HCOJ&QE&G$r84DMn4DLj&#zdstk(KQVj?oP*bI@Y6>FwWFGpnRtAxn$5INh4 zGTrT!MH=PFWvaI9ks1~zcb&UlynejUpBDHq9+I!)MFZi}9I$5X6acd^SAMRBqRGVD|D zsCVUEEWSE4A6^z7+j)waFLR5{@YrI5Vmvmiufk&@i1KB_&=@sj##sBP0tl6b%Ck{f zjJ3JJaf+#RR`nxe7Dl(L^ZFOAhc&F8-zPse)1O3V#D z|NkBTdk9_kqtOBU(D?XE{QL#~XBYPOc-24fTdaz8e7>ApY=-|;ZfTo1mPDcQe4Moy z;eR~*ubw61^vd?0Qg*X{YTAcI73+0Gk;F${CyP{et77e#xDQ}j&GC$9g6BaQde<{_ zL&caGI=5ICp}BhTNb#B}&d|3481qx0IMs5yKxwOx55q;=*bDFVT;xSO>2Xq)qdQkZ z$E|0#nRgMjezv_*_WV`a6>YVOCSInV+n=rza+N*Cd5z&tTI3);kAmBO`nL6Aj6nHi zoJqBdII-|Kj-7K6e_qo?oPODcsSihQk{N^t=n}m|P0dx)s3GY)>e|tC9aGcSUzetO zSvSly>he4+3U@a<*YkXVxH#))!j939Dcgn@ZTgw;tk|A}I-k+!{7>9#7ZY`B*XI=G zjJAnBK=+DR2=BI7AK|I>-mgS>yAR89a3VartH)p|xatVsi)L}VerbyViqXBgyV|20 zkNBc+I*wb}Fj4&!sD7G3b)J{dxgduNKy>GAR6dW>A{qO45gpP*@vd}Zm7zG#X8XBw z_b{A2D_IQZ$`pp-J2+w|X?#krlE>K2XZ(DHpV!DKZF(6WsXuR<5rW%~`4QYy*>w=S zZYQ?)^3S{V@ro**07hhQ(xFY>oKAtfX3KK-YIglJahMUZ^GLd!++(ea_buznKBpMj ztE=mIWbba)Uaz0pf2y{#aXF7==W8z-&v$x)=c}8QPa=9~R!*H&n~3iBBNWl=Aa>lk zH<7tX-P@44s#BXjq(qbQoSWx^oVs#uA@kdm`?Z>ckogOEttyV(BO`N({`2LwW)$<~ zLS{cNn;xOv&$T@w5)FzcZ3>yG#NkLGhr z%fY2cD^{fWW2HQNk(#tcaOr(Oc*a`1OU0#g(sT%uzSm;b?f0RLoZHYcW}TZ`tXt=% zoB1B{WL|Z}Z1^}J=YEOjFjLq-y_H*2ox7;cZMlfU|6(@0YOcrQRKa$JO6oJ5L)Voi zgr7!ut0nyjeabByPR>zdV@3MW=n3j=x6qo|ywEPq`^akGct3?!%c(i!^NW2Pk_}D-c@ExiqkHGh?jq*KYWxZqn=l>G3vz=pQJz_=r zHOrbgTh7+(P)^;yA{M^8E!M~PJyfZU-!H~@H`AmncPGA6okyGztM1TyzIu0vPTiqA z*YxhzyVf`Fy-1~c*O8l9UZ_&tW{t7yo5+zx@;o+AcXgNdbQj_E81KS$rVdWqD`Mg_x7ZA) zt2|Qc;k4#?#nPn-r!7C`y6qyLGu+R=;=bO7cJ)j0C7fO)XYMQX>!{}&a{0N}lPF8g zD}5m5nULKbExK^p=Ah^G(oMB%ZYHR3`hR^}-PXVoe#N)t%xB4@QLcVu%XiW!BTha| zf3_c!s6~u<5o2yuF^4>5j5#~)%KN?@S}C9I65FkO+T7BF)5Z<(?#!~}tZ~ts{tjJI ztk@Wbknfeu_fFYr-Ti6T%BRb^yco4M$)`8LQ8-w|I+s&Ols=jkHo9}kFm)mmoZcn>jlme~$JogSVy$}tWvDo}Vxc&VQ0>;N)}@@`%llo_^fxQ7hcLs&FT@<}xofW#p=GoAU)LXPOz- z_nBd;aA$p7RN*f6U6~K3V^+A;-)$VWaN4{*T}OqKXdjZg)dl|b4!pwYKJ|dB!mSGT zIs8b!Jd9h4732A;o;2gqjAz+>X~w-jsA}BV zNnop|87H#FMd}S9bw!O^%(s|tG2b>fOBuDaXzJ~9YNs;I_#SG?%zDZ)YU|Rj>cOVM zS^0FV&MrDGZKW|3`zK6e%D8&6yUDnAd8e)cvS*BEA_Unt<(?KP{}!_6eOSb*OQ*(Fs2?8aW%ch#B#)2s zt|OZ7^a`l?5nf{V$xr6{7H=32_!`IaDEZFTDA;Gelk^I2K!IT_37=^-?d&sI&7i9X z9me<@-_buaub&pm&tDO5g7S1u-^UlvOC6l+SiY zb+d9l%$~E|WX0b`q`!?7->zQv!LZNe2pQK6zRr<%<-O0Ghsz>z_&&I!E+&WX1G+OJ z7zcKrwVB0d_hZO;Jbg{8T+r*}@tQm)hMr#ItRy(STb%je-A8!M7+ogL_r*_DSv=PU z&yw?ah^u#3MS1^Ovn-yDFflQH8ypY!SE}|RRlBnIe0HAa;ENUT-N*QOv-s}0#wdel zewSsr--4~MsWX@OJA09cSez#5^heY4O_af3jQ&Wg>&oCKU0&Klcbj5Xt+5N|=(kmg zS0%oc3_c$Pbd#l54zC3r!Vq> zV4JSn_99s4&cl=UcKeIdn(8{(^ON-o!V};A}_S>o$;d8MbuCCw~=!FN!9&D za!(ddCwH2-b=;Huop-SM=}r-gk%6cFJgbI1#FQ$ofQ-+`z3->@-uz5HyTgS2R-<1J zQsQmmNra5zD^K!kck91Fy?~kza&*72g)Jq=q zqASC*EqVTa`lyYQ{E*DGMf>^Zi|^;rZg+nA5$@n4T)RifJ>>fEkCSWm26w_^oM&@p zv2|hbIX|7SjB&|2TN^{?ClI?_4DYgXyI(cDKpDc_fJO)ZB270BGic*$kjhb#C4YVoz$NX zTkUr5IKtUgfo$)DpG2AUT-|8S;o)xQD!LbS1E_otYaUWmXu|jrFLMsJD8i8@@ zc~eIp(3NO{m9Q#bKFfou)B)rjwt$q1Cd%~ziYA7{J#;0Sm`8Ki{-k+D5^;J46-f*u zlIUNgz*+B>1IJ+4mD4T7`hNK>?dlum=S~DVl!of&Gw7IG3-j&fat26V^A$Z zwTQgFaaPn|$_Dlsdd8s4|6ms1;9ptIH888@^NV{QS3}vry39JXzdRO>hmZ=gn^T6e zdIFv=DH|AT-zVC3GK=?#3ci`oVN;#tPDGs~`3xx=6it}gY!#{&?J66ZM-!}E)OAHx zM6r$z??ZekqUaC%5bBF8t)#havjdZ{SM?0zCJ_ZA0NZ{Xc0x+YDt2NQ>=e(Zi#oEs zePun7>bmG&*9FgG%pT2$New={M^l`{{7#Gy5kovoA_#S6s(#Uh`UN8&*L|`4&P@6! z#?wgdtA3Hee(!VOW~nfam(pPuVx-pH{IB zjO=-hmMbagOh6xlA^Ad?JJE7{p@=NbMYf!AFb<=>6O@m6va6A)&$*HxBi`(ew^QE5 zO4FJY4NU4!`!I1?v4HQe4E1#)va}fq`27ft1nTrxnwL^c_JCWgi}W^^u}b||2kAG3 z^xrB69!Z<92SWP1e^b^uNH{N?7tWj8Ykqz~Uvvh3VgmD&V%=i9DDU@T=onw+wp0h> zE$<&jCuAGBJfkYhzRhW&SV16+?;FN5Q!^%=XE@)*Fw3QRQUTCJM<}Nxrz1SXvF~nY zg0gs*#d}=s7rGaFEn2?bzYL$w&HUndC{_^GLw`FK!vBxZC2=0_9eixE8NPM4R_h0a z{zCuizC@wF(7$gE2BAF!*1zakd}iTqv8Gn3{9IJ=C!TqMS7bZ<+#H_%VYRXGmR-lf zYRye{I6NDxm8&mvPQo!}t6q=VQsK>;tJm%K6H*JQ`-Rkf&C~me?Up&m!gguu%CVh& z8jKX(v&6&a)p94vl%ylf0(uQ5n{&-C5lgdz*!^1jyx1-to_B^<;lIZ@x7xA&{VjN{ zOWZk=Rd(y=7Z2YLFTuXz`|x=94XCy^(uue+@P8Modf~rA_Sw08XrG>V_&oaOqXcQ~ zq_vxj0;H+u)bIXi?bd_3>zup5KM@&HcXu-S4r+@>sBNx|{x$l7e>b2o=g-ab=ho=o zh!IalPr=)h#s3vQPwmR_d$9VK~ z^i%Tq!(>}8Fr%JPXkW8@tN#|Gyvs|=JLiZ>JPTs*nQ_PKhN(2!n0eOIH3;u&^&)DLD@H`ntvJ* z-XiLLkE;8xV8P0m_u~4z7`{8c-&G4Oi@2YM%PAny_ zRL;*^zPX|Ny&`|NdCV>fDAwTZq({A+ou>=tv!pJ0_PMj@3ct%FN^zhBINU% z&g{#_QDn)FuorpN+b(kR9q{PnHxDy>I(v?ea71tLm7nmti2R*8yzb}kroa(D&ub{e z-_|hY=fb)>>+M|iW>wt(&;KRwo~^f+)z*s?c0PZ$b62MZZ?A~S(Q}J+IeK=ySG(7S zBm5SsX_~?3&}BA9zky?JXWu=q4ClA8in=b%Dztx$we@yHwM|pJKSqV>E$)n~(O>xa z2$^?&iVxRzzd!!-T2{K%>T`M1Ni8M?^HLk z*hM5z)xlRMuGm&wfmqf&@;vTlopcme+#|aj%CsG>Z84|u4KJR^MheS`EsU*GY(ccm zvqO1}93OXjd0yAAfYcw6W!xt}$+KBMrNua}6IN-GS)x932V2?0_aVNy9X|7Pii6^H zv4O8KzWH1JnR)DEM)d*FgH^|}h|X74#THr3e@r%EXt4lUhH9licr>t!%s?zdRW!gm zhF7tBUT9V?mSG;XK@2wl&*QXRe^_)>Fviu$YqDt#B71awK9jBID-s}@zJ*%SIHpUW zEbBtVVAD=oC$!5PKHzbCR4l_}BoGn<43S^hPdMI1@C*K(>hcTZQg_pSr(*SCcub*L zzS&rzh+$AnF&u_rC{BXy#}xHd4OwntQB{mXaMqgQAHe91EKqX_aqgtWS`6DVkt^$M0Z(&v7iKtMlym zH9j{~2SN2_Rv}qe2hn~s(M^V82S=ZueI4Ii1zlC+IJru1pkjFpR^ffZBUo0&u6HsE zl5vr1`qk^=oDqICwjq==LeUvAT*uKO;c{vt)<$_S2_wNZ* zy7EJ~LGQp*9E-QeJl`SrG*=+`8M^BJD)|`-=bdhG9S9!MGfAY+sur7cJ&seH>mN#+ z4zY^muak?relE@TEt>DETzt5$MT=Gswm&nlo7_Bm6ircZ*ja9#+Iiuz!{gAIzU^k- zHZj=Zg3#Q%xI@vh+cr_ZIWylZXD9z_{ULF3_HFqafh8~NQB*Y0EE*6qpLH@4GcRWT z4h#@kv3_oWzS9~z!iA9U9{m&Au%? z{a!#nez;O^7uc_S-eu~u_4MK1KFa6w`FtK*y4g7=ymtN8jyZ_o%M+5d3$Klb=?7j* zNxwGwU*9<0HAEa=@ok*?8Db3Uw_$EKPFc5NzI`)Q*Ohm*b7f*z`@1?&sPoI7p{an=QvoNBRNFqhP38ceqNBIT96+h(vdllx zxes-9RylaTGT(BZ^;w0$9aK?IoG=8(`L_QS8}2zOo;x ztFM!T+u9wIGv^lT_q22RZPa_^y_`ZP*! zjvgS2f0eAIU7e-FtS+P@T`2A6>@`K{%}V84olM;NcaSWF`oXhRr>ULS-kXa<$5<^d>M8N<86K_BW_MPIs8_2WnE5v>V5B1S3TWLz4x_j z)@F-c;)U_^Vf-#?>D35dT}wYnG+cBJ+}4b_Z%W14c|83*LvfxO#9e5CTvz*~a&8BY zy+lpx4F2Op1oma{Y&Dq+a|~6=+uYQwe8+r#U;JmwDt^A;liAlX_Mz|dg};`F-e2%)-n&7H|r z>1OZ4w7D&;1k&8qb+mOV|25o?yu(i5#6SfeJJ=qN4zT9^gx^n~1Utb!^*1@=JikAyfacjQgX|IR3ZiRXOx$@fnjOpaqc6U6SzmardBr(@`)FQwdTUv~ zxuJQ}`R~>JY~gr5R(77EX&Ii^$`C**%Hd z8As2N@hEPz;I>#d_h)vq9VPpJf$fk-Q1)+Fy{KrRC_lBm5CcGWsmnB@X%;aQ9bp$W zJizwZch4gpliOzwz^_nlf6}?Ou4`>Ix6f(=Kjmz9+U(KosyD42%NMvFX2%PhPd83x z)OFXDZXaym>azJ4-_$F{Q81qGLcBo7V7Dis@j}srx{Z-V2Vu1YM#%0JacT*Ei}m9P zYX7R{(%M~EUQKw7b&t`%;t50YvUoze0GnZB4iArzB|aJ5BNu#wb-p{(ZHCM|s5_vK z%!70R-sL`ChVc%43lgup6%#h z-GrZxSDxwU*hlF4q0u}KUmlEFVLLd;CUbLxIMbs{6F)UCRuyi zINqgtz9CC7k~2!+wOGZ#Gb0}w|8Ae$_dpljvy-S>hU6P*6jz;-m(QD-g*7}+P5Sbx zbL_oAciP3T$}_GtEL6wcvb^;k;+l2mU>(2n?r_!oE@AX)&yUU5=)-eu;?44Sb)sU- z8Ly`E;}+{?;~UtItu$UNMsaegRVe-n**Nc)9r@K`wJ5{z&}^J2P}EnSRf??!Zs*zC z@T@v}q}tZe_0+oCwQq58H=O6*G5;@(jIW;k!KYgzw}Ijo&!I z{S<>U7rwXWkSBa!6k{%YH}9KJf4nyF-S5M2@qHipyIpfJ(4BgEq5ERc{Z%?o){gh^ zdG~qn-5)Du@UyjTLUiqkflszpCr=p#0-BA{r9LAEuS#=it`O)AIoO zt4rvxOnt?xVm6}ZkEA&H_Ec`pYaq+KuO=%`ABZqkK6Y1HmY4T?5t_Fbcek5zvJP)= zU1l+Pdv38l>N6Uva=x#J`pWDbo_kDnnpbmpu!zq+OQ@g6AWgRkoo*x4?|vm-sPAXl z^b_^_hw5bOP4^cglNVc`&CzFLdZ^Z}I*<1pv@&`2#~mk5bc~x^ymW@#;a9L#+vsEc zl6?JuE;@T&e2qM{rqrb#;5*#8P9FBI=ZpEp{GPYMd2_JugXV7djD6hPos506+?}ti z(%g~NCz6yi_FUV<*jMAc@jMQR$})F1@od_qMr{2@bpPJMuk;f%eN`AQw*DN9{xyym zW1u`!5{s?hPt`cwUQz9K6)>E2ORfR!GW6ro14NXsl6QKQbk65H=zYb874oCxJ6lU% zMAh9YxFH<IQ^m%Mj=Un$4WQF@~=FTE;e@MA|w@|;2sJ;hGH>bQ}jy@dK$A~CZ zcXxUDY>wXIIrkjp?&ruV?~qqA+5MW8vS$(UPBcc;lL zCW{xE(=pbR$n0`I!Aio(RJU*xoG*v(ADXk?9uv#e9p^Riv#~r@hVCoK#{Ek-&$(}^ zwtMCLmlW@adR8Ull`=G3-vO?7eM+2g-6`qVrxn7@(}U&`xV(mH!v((REO-u04d>@_ z#>*zQ64U>klhRy8Iu>v4wpgDx-^adG^{l&Vs+>2c{znf@7DT`}ik z&P|QeeM~0v!gZnDig`bB?J!K{XJPgKJN)|qmEBhf5))yvSo|;OTGxPI-zPse)1OBXKmbSH)SlkJ)<1siAiqun=0e;R>o~+jztXW zR##=bJTYHLfqo6iL23n@QmrldEHo#d0l*`C(U*MvtB*N?Nw5dlfvB)xh#hdRk#b` zS?wabHm%E6247Vn=XEF!eesjl+=PvG^YuO`+`an?uf<|txh>?#=BPvsI{Q|xz@cB` zHAU5Lx4l0T$Lc&DI(9rP*Y?QCY<{^|Y&!HRK7BLI#zS&#O>l`-kk)`wi}gr#KdGv39*n7zD0e@{3tDzZl`W!}npc>D!6> zk*$AmGI+Pex@6SGY zBect_%Q<$BD9XR*&A)lo8P-e7me*UU(%lty-F(6vewtE?YB;KOj=(eA;EVZ(pWZbu z>;4woyTrD$-elZnAF!E-#5=m(I(Q$jIW+q=JXst4oL0lxKlT{c)o1*Cg`d}m+|Ivs zmW5TyvwF66r=;82j#)$J7VF|WIiG5Vy$-(b$n_;s1}==3n(Z3v7+J}#R?vmu@QMHw z0Vo2P^m$j7pJ%-Cxo%$=c&}e0?iBOy-HQPFi12itshX);C(D-WJO^GG}&JxuGE2Vj)DSZ z=~2TKr5xqyHsER&(&Npm$75`~DNP=5OYSpWuGbf9@8l_G75tDcxV|#(VSccCEuysd ziEjg?4H;viG`Cn6rHQ{g0UmJ{KZc;RbCeZM7vZ$I0J(gE$mpFE}eHYay&g#c?s^8tfW9Hga8!#u1 zlQqjHE*3W~JQf~*!lbVvJnl*_oAPGohGWW~X>I$E^X4#qyWPCm?L%nZT%=QXIC=3U`11LubH!jhJg+ zvF5x@B=`FeisYe4P3>6RjN5IoE(6YvGQKue#_g2p;=hadZ>uFZG#CG!?~pke{hE0G zo{e6Qly58Fww0;h3bf(o+a4i@h|=^*jf>K5i*-?&`E)#1oEWXHFo(d(r=5S{RWccY zIqzA5!e#i|4o-XS;VjL&A3&$Z{G02`v(zIh8#5iE=E+Kt_0n#qtkW}O@E_nOW!+xW zE@PZzb%1Xw0d33K=dYf}y7Fn|)213wKFz75=IcuAuZz@tt?S(?u3(Q-%~_G6j2Zc3 zVD!f5NA#L(q3U*&tW(8V^}*-~R!pvCvo&?M$qLEGE|RtJJ=o1JSm)h3Ui`|Jc>ZUUUaKVfdpf8nTn5AQyHJ%H*Yzs(1D2RcT6pX`le4$YgFQ!BVq8{!<|b8(Mu(|J=| zkGH@_a9@0#@h*8qmbdng6(ND^f!s~kcZc$G;?dNnVQi>phOpCp?R+@p40^N=i7VH2a89S zpL^CbO;PkaUSsDjyKjcGZkwlg4)^5K$enfWgZXS(9PMMRX-sy#OULPPvN|sPL7yb* zrZ?DgyNWF* z(^*l-dz_O4Jn{mM^Yd8*;r{wM-ADUtNY9*qFZzjI!Lf?_d51l?p85XOQINljLgFAh z?sejz=QxV|{LjJBoZ_2TPPtpGk1xs`VQfzh)9u+a=To-XReg%Pf!F2RZ+GM)9O-Q2 zXxAu@o9zRC@>8AS%KL~f-k-dFE)j$BE}Hg{v%4be2z!>qt9Lk)pOe?y)sknsrq$`$ zE;6@jxpjnl{c~==r`I{B&ft~FyPA&Y)z0Z-xUjOziz}R0qCLj_^9G;y9BZF>SHHt^ zIDLq^)LT5tV^mzdHgBL5KK-7}kiOcf zWk1=EDx}{O(x-SNq!-c)>A7|Z=`EfM(Xczb9xBqaPl*V*g)d$k%uvj4xEazDZ(%vgr>FVie?)pPo6M4OGn zr{mdoIKCf~ITXs<=gZq&22M^PG;epWVGeMIt6f>U%gL0rGlSx^7XDnvPa=S;(=Rq_ zH-8LH33E}vqOe_SKIHcud=72wb+XNQS`aAtzOR?(fp|nXa=hQ9<8Wf~snNC`&+` z@l}B3u>@{~5047?iuII{pC>YK@gP^KDlMRY&-&2;6#`XV^i86J??(SWj>IFx9{dF2 z4R{n3CtN4hctc;S=XblBV0$_|6@iNf6ekQr|F1ZKT>#6A6WkQ->NtUw1U`FFF+%?R z>c$6FO|VQR4tt<#!s6HiqF0xhgZR~iY-CZ!7;v^$(Q{X^lAw4%{ead>xSW2#D&8Qp zAFwOc1UDb8Iv#N90{4o=aR$w*3EN-`V(ATC@8AJYimS0$0v?6cW(n%V1QwUZRU9^R z32?6(9#dd7&PkrY{;Fz1zp4q2Q|3>uG+lQIh!qudr26*B zSW$n%bYxxZSI{Sq!9I2@@_rj)WH6gKaFvE-a0l7@M-GF=0EGDt@vQO7e%dP+?Nv~( zUy;70Tln5f6=;*bL!nAUB1{*Qh;BYjcwE3TTyh%h8B@b6haE+BVMH7g)giO92N zN`qD44zlZ-$NskC0HJ|ii7UN2fN8SQ71mwjS?U5uHjc$eBj=*NqpdPhvM1-_l5gW>}9wOZo?e$86U2) z(@_yO&_ypp=N>xm3%Ipm>`_EC8?gAu0r2 zJ#VtR(EWWG8o_L|oJaI&=U~f87y~E*;8Ac9fYYpWJp!0kLFZ=^hE@T((qDK`y9&Tp z#E1a66@GE0s_Gr^?^!Wi%a`1h=j{fxG&`Uc(ASEc{+*slt}qzOHf#kpwIu^D%|({KePhSl^Eb4?G3LJ12{H*4YiKNcn5GVjdQ3U18k0Vqg4Rp z9Z;PAPe;ea{s3fTy4DA{4PGmY-w!bx^c;P>*U){_e_4G1UGD=}W(|P&<$N|&10Y8c z8UygG@ymYND;Mn(P)`L=6;B=tFf_U%MPY{{8A>KPv$C*^05>K1oppU3*V2fMqfr}c=oT!JcHs_zQpsdlUKikp79e{w*P{g;`gJ^ z$=8F?&BQhz;2k*O{QG2Y4n~*wx*fg7`(5JI?~*N9TvV;{=TX>(zSUjtmfd@e*)Q1Y zO`0p4-lDpvc5<87*#A3xG2iCVU?lw#znzVq;*)&Bqu0qNIU0S%XTQa}@!4mIe#Gf; zjz_=Y`kc<#slI!g(=Yyv=lK;Yzc2oCO>4NAtsJ9c_$a-uh==y9C!>2DgEx2|JI7Xg znuV9{-nsgA4V)!s{~2D-dipHR!CfC`ID`4;Wn+^N1)N=LvySc=KFf7_l%L^v|2}cd zvPX>GTXr>6XS~El=6H2fZ>QLoGu%mT&W^nc?_ypH{)*+DbT|4VIp>^6vyZdEd+0e7 zkmkeYu6$k~Uz>zt}wUggFZea(18{>N&-~6oZna9cX zdV{;b=3{ePwjOXU9*^<|T**a!KiPOEoVT~>veKACeH}Z!w!x(9cd5K zBhP0RojX?>wR7a3nLl@v@k3}GVLW;@;v7TH*xAHN`3Aqcwekmiavq;|_!}|$5}Q8|k?6+41~>ZQH$Hr1i^hu^G-+EB(2z zWjOybIgSqJ`D~&5$BdHP-M9WO5y}hYzhF%yA1IXPD(hA}9uxN^lwT~$XS4bKqrCex z%R_qJ-EooLZLvPmlXFwJL+Gkr!R+#=s;I=j#ECb4q+MIik{WS;z5$2UJ+7xQ^zR_y4nVn%=Q zjl*C($WYsQG|DVm)H%5l`VN3weHQ5kei*c9$zs0)o0ok}JzCS!V*v3=`_O7>HG$JfELuon!O3-pFgySz#=M# z^I2BhxEDnP{p0vUb%Nyh*MP4-j=lrNJ_3Ku2;lMP02u!hem?;}dji(~1uCDs_J@e+ z)h<4vn9eG;Fx_Fb&xV^Y`@-`s)bSUM=VJM@EdL_%{XW$1S3TdKtl)PY-Kk-So3Xns z*3H;CRc9Yxj9unu^r^%VzL(>>a`wwnzqEQ)7~efczX_i|)a<=VpQr47xY>KT-@o{L zhg55*Qhdd?MF3~0Ntlvm7ja5e?_QOD-&OmmSp0GHcf=Y0om5QL@b7z6KGyJFREPgV zTt8|@SJ1@H#|z}O^vh@Y^ZVmJ+cb|#z19%4{Z;V-W9^t6zc_&`C*V|n{3(85vC6-G z==;0Q4iI(YvIB05b=iRp+(Bdr%Gm+u{ZX#?)ytcA^cDRxo3f1pXW27!U ztH4)x>6sR;xQ4%j6?cs9F01-1&g1>MikiMjjz3h>XSl;kz4fC~$Nw0)=V$!PcPR1^ z_Fmp13uCu)nAVSZt<4<@)%}I)`iR=b%*WF8xh>X>19%K~E8_s`0IZ4vr27x);;*Co zpLYM7?B&nnSo^yF$vvu$75d-NUv!M6`_Fqhc2)O31eKpf2-5wVA4RzCzuXacadiUA z`a|Ob>i$h}8!J9=TdW%&Q1@S@AqbBSq#^Knevh149)S6d-Q|ui$g&H0Z=FdjE@uN4 z(G@tkNB%PwF$u$u4w%)&tO?Ak`>)##DD{A?-Hu`ClDp5UM+KA2K`8&9j|!H{85H*w z^fhKMDDGZ0DOYrp^ zS8IsPCKv|DL3q-^SPDZq2=iW>WEeuV35HF5)F!Y}5Yv;8$|u`mliGvT?uz>t!{Y=x z6evz8=Mh3H50lEqWvdeM`{OwhRUI^GfO@YxXur6c$8sZ7CxT-iHEF<@p#H=Oybp?M z4tr@{9;#EIH$mK3!ELdAtU%6=pRG7nurpPzVzjtT9gXy@d=J%h(IlTZal{y!_}!#; zglDdO{lcOm1DiM%Yobt<{*cEmroup+fVvKCo>S3Op)GVEt*#bv66-@%2j)0v2y-&G z>!2~{p-9dCfVfEQwpbUbIXTeH+$zTE5Z}QQY>7PwQWaLI3PbaHIS(42bb>x1H$`&z zPQt?bEZ#3d9U$ky{y7tcGXJrBg>4RCof?1k6><6o{1)q@JmUlFhbu;Td%P?of0<(Z zSnh+!kIP(y=;bV&@6)8sUojAW2t9_2^BQ)O_sCpzca9*BhxPw+ zKgpTjC0PNT+&&>gpv#>p2Y<{s5Kv3Aj_03Xwf+k~m!%J+=LPpWlp)~MVS7cK*nz8? zZLx0bz{sI$)=+rlAaCQi!7pRIKnh@rgAj+Wb_m zyl;=8>jPvquM#ZlZmbYm1IYUpFSqlsf02Q?7FN~y>%|7YBC`A6h*iuBQ9T4jJp_sp z)MLne!lnrS4llKHOh}zpSkj%6h`ESpp^M%Gi;fm}ym=hD>~FZb%!1toO%((Eix&33 zW&LD8&cTq}r<0LC;kR3GDA{?)N9ig-*UPKXfAEay$Nd)T@(5%gwktagL!*U#++~`8 zR8@lrcP|o?&<7@=D>aCDJdqV8tYh-XVe+LYp}U;I1v*tepu*rh4x4cbsyEb+6GAEu zrnfBDD$p5XOK}3S#Hu)fIU=)3_dK~AT6YSgf&R!uGg56 zyP}36DIBeya6Vd=OM#*V#uirDv#P51M0^j88}GP2sTCe3IfYv@UfvFX&zEIo)Q7=096?x4gsTDHJf#QVW&roQq3Zc%&Z0BQao}tPkxer~CiX2uY zaxk4i%*erSu?eeScTaKLV0y*!dW3mR$RRmfX_zlw$U6P430|<$;@dvu{=!8s2D*pLb)5#KCUI>CEK0e+>c5G`S7r=N$cxa z!@bBl#JrA3oI^U!@@yW#J@I3rdA&pD@L6uQ`|;>E=&`sj`TnOWyq{D}`p-99 z#GiG1scrKw`RWN>pBaYC8ypf7QPss~-G9?+9;C*>#T&BQo*4e|LsqVhHT zPSwj>+*ORFFYp`J=P*XWa6M-Iz;Cf`q+p$oRTYE~PT_UxzbIv5l`=7|Kf)qo1#t?- z**H$2D{2FA3+51H?7Qg{S<7_p@%6QeeNY^%I=7JTg0!O%R!_*fFt*(V85$FCZH?)w zxCcCL=Bmh;U@PS{i|Y&_{K4ylKNw?cj0#MV_$%&8#!B)}is7F$nZ1ik;6$Zo@EaoU z{&q&)2_IAgG%cm>2{4Ez?GFa}#V7To*T(ZP%4?&6je9Vj{& zf(B91fy2vHs5K}$xK0p{UAm^8>Y^j_(4vFA=+S}SV*Th~3=FS|4(#!wj)YyX1&_fT zP+|aj z*Wx+ib*^dc<@H2K=ZD&A4Ku;4Buf+F^cbEpTJ0>}9)j5+FT(gY-*e|M z#w+Zyod)FW!Z4hC7O}!QL8cjhUg-|KY>V}~3;aG7bqnkv+OXMMyz1>)lYWF2=e6%t zn8%=}=%t`Cr!LN0G|*N}pBf#0h4u?fIu13#_UfJich&W|PoPZy=dhig#@)tt?kVrq zb~^*dqX$?!UM26;)fq{|ix6ZtY$0Bn&Xp+N2j?N?x17PtvmFQP{T7>GJrSDwQq1O8 z(}Qby0mY$-ApM04<9x&)>~)L8#8vw>*CjMfFKe zz?h}GgfA%Lo^226XYy4(0r~x@&ilLM3lt~s?|#fcPM>ju#WJ_h4^=Do6f@kU&I_(9 zpbs&_q8x(yzyp}pH6&&*l$<#`|jS|7F59@XT!tN~_mKl|Pgv7*dTtZoget-O#okuP%oBK0BK!sC>Pw z2fv!*?>=^0ryb98yLJ0+I{KD%(h*(SLumH4yLv*XJ5P~Pk6J38!7!yBGi>*Yco=S5 ztc&566 z>jTffC~ZJD;|6k=tELSYM^*P*6w*u^u$Achx%S108MX(N^|zt;+W<47xZzEr%D28? zUVVM(3z*gi45>$85&eI3yyO{YL}A?`AK-#=165|56N84)7r?#|9=lcK7bfF`b+G;+ zdVsbygj~(tp3Kia)X@y?CcR(w3Ll@l3Eal0@k+TG{RiEP`HsXRWcmK}b-4z<*2OTf z;)WlSD_foYMV_Xg{MPH%@`fyjN3@qm^(-gi; zw!*k>SgOKhvkiIm|MKI8{Qf9zXg_YC%9>GN^#sF7M}oReLyK@DAph^amJ>fzsT$}s z)O9z4MRg(cqdMVpecmUOHKB1+&jP1W)tzPawG zI$<$jIM1LsAdD7`|W64e%#b6xk!)W{Ztc8PT>^H!t^!A z>O}dB;;P8N)j7KCYfK#w?{Hq5PV=8V7L$*iC0?C(n3nfBx!Y~7bDlAKg-7yphWg=V zw2l=fM7`K<-=yD*P;Q_a^@*RXX%TICMrUIemA_8A;t;o}nvmaOUDV&ly=A?8#h7o8 zS0Vnv$Phn{Qqg1c@-W}d&~hA&8IuzCchglNkNYQ?*ySu)F|IIK<1H|MItu8PhVcm3 zJ>v(i$h`hd<4*s%eoaL1*JqvM-&SPtYjQk^AoZM-=)&+E=i>~x%X!C59G5xKf@iXr zd+_MXwaU)>A|nj{{_DuMjF)UP+StMR-gO?r&V-$dqKM;5a<+K%9s(uYnae)ASq#z- zZi47feEwh?YONlshX8c~JLID*rXJ|z*`8jdS{ z+wbr<-a$pK3l8DwRm|swM;Y!F@uCddVv{JNidnG7!=j8aW=``+41rltl;N-cE8Gd8 zog4n%$!1BmW+}>OLk+1YqpT-Wk%e_sEHkp`54+K&$bvaTy~x79B35MKwpcf^Adlkw zev26lH$$pCx?pY2IE;sbi7u8|x8O>^{whXldH%wWJy=MnPf+7R${!i3GPLOD)$@|k&00j_j; ztz%d%V+;m&4LH05&fz<71&>f;=RD=dz@$^K5R4ce;`=G~@V8`5t>Oz@S5G)!;9e1q z>UEtJ9GBtViO2gW`OY52CQ-n+vX0^2vpfng7FF5>hdMsb&UQrD{q3GpoU>DRM(wj= zfFrQ%ufez9V0E|z&p~9*S8KzRjODS@5GxFejse>4cyPFrjW103kX-}WW$_m5@FmvA z>G@3EuQ2T4&Y#5j>?fIgY&o?AcP{voReA2!GGl1G)Ca#0>tO zV#W-{Y?s9hhMwgygLO=bZ*W|~e0)Q3r(}8F%vxs9n1xK5~7g3hY%aqPYVuZ{IE&smS=zb7iFn;Cg-Geu)xVurSP2J)T5@0(CZ zWs_<{+Z~ndG7X_~Az5wUI%8}9w9m7zMl_iVN$r7qhq5TZ`g+2m05J#e68)^l)oj(l ze7y{-?RmwO2Soy651K~;i=7Ug&nQFL1NSPa4or2hs7PQ~{6T*s0cQ1eBY|dm1^-U* z_ybO)B$CC89Hd%Q?9kO&QRVDQ7gY<29gM}ApGD|HKcr%Z)nXAmqPMMA@b45ScGySE zW2{EZ$l(-9Q?eNk@wJ}nV5DD|%|e7~AB!1?6CCMn)UvkLQy0xnY@pz{5MDw=$o zu5c{gqjECc|4@G1+KM6!2Nzw7SS$n4{aQpjQAFOY{S+PiAMr)^G_J1o=Sfjx$1le^ zyIz27b#U^rX3EETSqM5h>|mwmD%GCyv6;i8`6S$e38tqVyCAL;ea}1meuDEt4fQQ5 ziae6#T@W69>!=dyvI^z(1-B1Px*D8sYZ=y?0;R0JK;B%AjJ#UPRR(oDnVB(+aa2tg zI;8%_)m9wN>xWc5lfm)!boF#t(cBNoZ;c9e)ef5BHrLrjp!U4pNBOh8Z0(`p3Ng8# z9Sf%5YnuUJbY<@phXF9B=IZK!UC&{0fpiCDwF9~@hi3i5jSI4#hl~-*dKp)}Z$VLn z`4QXnWipCYT130Q`rY%ms3>B--2c}k)^U+Ud%3^Y0J=Q=4ooMr`j22&jODZGddyDy z8AUL+UrZF?-ziQMLFTI}hNxC9nwFdUX0hlHY6fjMGS-P8$TaVQU9jsa&n&nZ8>}3# zcJMf<82k=S%-D_k9Sp~~6XUopaz&vVaKC3mWRGz6__keLFzjGP#WPtwW18O0O*IPg zY@T*hI0Bn@ge%zGtX&*(jEcYwzP{p4dyA?R@ygbRtdnn6g`Dkl;W>5gC-c`9=%v;N zj$$#Dh0y525UQWi1!FVA=y^B_yI#v{6z-ks)+ly>Q+7?3RVcWkmGKZhiWm+L(MA*z z%0VnPg77MdY?afh<}qV}n01L&K>0;`AoM{)Ae3jWz$j)u4&e*3$3^G|`i$~L%7nv_ z&3&$;NT?eHl%qZKb#Adf+V7^(Z!EO`J8~F$x!i*ndYjI36o=puHQW6t^pEACDD-!{ zys^MBbO@`8{;?H=i^}qa|5fTjIze8cQbE;W6YsYJ}f?nkt-9GA7UjM zW|w~dYUPXU+K;2CYpZ&mS0PRxmm%rqgyxGub8+fj=*gc{&c*G@H*D-@4ZI514bRFH zZ`-ISaGt7k^W`1+p*8RPiV>=rKf^gN{X5x{CjS3b>iPVBc}AgKrQGs5^|DO+WMtru zwIYJ%-TtduWsj?*XKrRI3w2WMdGyTN?cXhponcmAmGsW3KU_&)uAw^wcJLaiuc32Y z9L2nV)y2c&2i4GHu=RPIR{X#|UApj{CG!XKo&KNj*gfj??bhiPJ#?XFznIwq-B;x= zDqigx4 zL!C~2MGe+TWRbvXvks=Ar>7r}hWhuNzYIIze@KoAXRn-&UVvwttRhsq1KIlLy7H&D z@DSdI_Kw}{-&YLLWX6DE2p?mxbFdlfu!q-GDfh=ICsxcmoF;t`T;Jx?>_15&D&~>Q zF^L;@X*M}4(t3&KT_>^DJE&(qL7DeoU|qf+eNMg}U<-Uzerwd+++fQOu2ZNyYj$_9`DaZ!~j)V1YT2%tTQYE<=dG75Vy8K|4$x!UWx5h7P`q39N-f( zN4-tfWP1E@1Q;YLktji`a5-?}EVm86eRV^fH@P|hc~>)oP-Y;5r}uC1@hHN`BNxWV3EcXyoQs=G_#lX6V6=hyfBtJWgyAttd& z7`%fm=X!#>;RbHsybrk7&h_yakxBj$t4p0E(Oq#Zf%noiK4%-%g!1F2Sb*m*fBgM) z)NF=cUvr>Xz$OwivT!T8Vu9&cz%o*1KFwl*9UyRIXCrd)0v6rVZ@#E* zvw_@}IsN1_nJfGJpee#{_88xd1B{99++q`auj*FdJfSLlr=u*NqijD;wx3;F#QeVo z*T$Kim*4@Wv(l%i_>gZn$C@JM{|oBrR^xt-j$oU+=IUBJc8f=NU+G^=t-lXd0H^U* z6<~H1z;e!}aRJe&znQ<~bul9YZm~&ZV0%(r2XLB!vdrIcT#5|hLG!mDDDC1123RhfJ`10 z+p}WruF{fXn_4Xycdh3f!Dw;UhBhhII^qL zXJAE@!!|kvR52jq7t_UXIhuf9ac8)Dqi(OjbLcS7l4|U0{Pr69{(20-VMXQOOR{gq z=X2lYttDhD1BdCFL5-p5N!gck10;Blx{p;ZvhS~2!hKppcX?I2{K33lMfr0*sRzjF zN%>5w;hQN3_JaBZ+OH6}{fO5ou!+0#2>hPwAgPW8_zH`Osn2F-ZC-a_E8KJk!Q?wp z;W7RCX0bzcZ-Jp`dF;SBLy8?@sR{RRP3@-&4lxP+WfBxSD0W~k%_VwmSPSw|lQ}H> z0)5O4>O>##xYOVD!|AYF(F4(^U422D(SvdMi-;cVonl50)mp{s=)rpG6+I|=pk7s- zi7vZV^q}Zr_|d}~U$w%Guy=|BD?RVOrI00Ep@x5(XIIllk=GViFNWZ zxSr4WnV&7mN7&(d3qFYcDr<1yyvA>LaJ(b0L2o?z$bH5C=!Hioyfxgh>o_mw!qi4p z!*cuZ$fCM>!7bLWQtYGhRONYKvBd0H;RGw&HjccVj~{UCiCFWg9=%V_MLK<$+njx@ zs{9b?duaasZd)NPh;76P^u4nC+$kcniiy1cQ68P^R4KC9)--mA6Aic?*=f$fse2Zw zUl=Chj}aU4EEjb@E+6q@puDl1Wm-p}e7~kBkAXTN4u@@{JY$;J7{3iHG#7|{Afv5< zv#~4N)!?34g!9u|t&8^)WiCN2xxCEzTYLax|?KsvyYZXdVT`e<(+pg zZUeWe?-Xvcx+>geZorB&j|M$aPr-aT4I;0~(C);8G5Jssm{BpHXVcaF{G=Lck@#>;pwY$Z8;CqZ9MBmXITM{c%Dz6 zo`gdlrT!FxY-d5;u7V#rpOG&f*$;6~aU#)SvNpIp{y6c-z5(z080*ISB&M?aZt;GE zR;A$;)h-9$O=Rafm-ifYc*-MET-!Ho8CQFA-fDw`cY6|w?A+Tw6V7*X)`IEts%I4J zWA*3tu#r}3XJc6w_4x{S?aZ1{kl$k6yq#+Gaa6<~3QONctPq;%D^lPUKZG7cs!BbN?IL}NW5)z`7dfP#j?4PsPOz#mfib|7F+nI}-*!yU7GqD&J{<8w*m}Rk zx`@9Cymxa3%9whKI?8i=Ti3Xr3^~Jh6Bnv8eBRZLKT&?)-|oM8P+R%EO;IK4S5F(R zX70P6-!DdC*R||^Hj;C#45_^nIoiza{eH}!+na)|PHt}udd%FOTda@t+dv~@Cd!b$ zOs#JUyysvD=n^n=q<3?ftC3!P{>smV^s9#SJ%Fwrq_3iQVMvv7}MWbo9Q z#!=J@(|r%sF%%(3=`~3Ght)NoBs!)ySnqABtUH6#eQ$OweRtz~oOSlVmCgHG^$NQ% zozsj~hp88)cMsF)PVD;iLi6|P{G1qVHF87svd%aEy!u$pc*pqjVyt$o@~m3=GrW2m zt3B(+KSe<2XV94bmNNCT>kq!u?HxMxK4IePe}QfI9zXA)mZft6b@o>y-^qTJ_=dm5 zO7Q^CdWUaD5wm;b+CX&YZ&J<5n?8hlm#@CtQGSk3@Fm%IY3Yxl%Dqlh(e9|8AyVMA zXh*4S=b9$U`KEffD%Cu%m)W^?zLzRiwjHBu-QvK0Yv72+Joc-_rQ4Z1z}-j0D4x)> zhkKD)aVp2$issRqkA~FQH@@lTiLHFUDxVs@SFz6Bsvp((JGu9>u_&u^=PTURFiYp2 z-(oYQHgqaRYR3VTAvLesQ(-kGqH|6>qXp-M&F<20tY+1Q?o{sD=CJS+~#9+xSDKkF!mqfbBF3P{vOGNXAoK zNuOe^X0&e8J3oMd>0`!zjJFiPS$QwOc+`l=Md^F7oN3qi}lf(3ic{~eKXA>%h7rZP7qvw=Ic}&BERl( z@OR*bK7!l08vOdVap|+UbYAg1e${b;i}$2{%U6QMrC0Tz zEjliUp@6eoso${xQHsZY6%}xKWcRgc9*<&I*fyud`+b>h*b+iV^)ewy`ZlpEK`gZvl_9a(?Cf%K6_y z3vrotMY^LwexVO;ul=Z*6aV6K@pW>3m+3ftA*LqdeT~WZ>8T$TVlUawr_H%w1&s4h^emAS|LjHatzi}7y=Knj&|CRp(r*6^xvv@C>p?1fq=6{pU zId#r8%Ku|cXJ2Oi&kC@MmGYGVpN}(+Dy|IlJ^#-hfjIfU-(r*ezp7Wh+SP_LU{%+j zSN$hXn@e;fkO>@ORlhj{a3lsm-2W&R_P3+MufqTs+tUpDHxL)#tmbvP@4lPUV8il# zx=382KHaQJ(SBF+e?h^XB|J=&jh3?q7U=@ACfG zz5d2B_Pf82EAt}se|?Syj0JEWWKER+mN9jU39zX%bt(XM1mZ*l{+Kq42&%XMH|eMME1?6O_`+`e-ToVTyvO^FN5?#)wy zpFdW1@3z=1ySFR74EaM8e&qXK3iojxPEWzJ<5%t2SBCl74z{i%{FVCrFtO(Zc=8GJ zk;!flR~VxWSKl9-3$S}eeE)Q(OCJCDxcL6P1Wmi*^iww?VAZ`FTmU09di4=u$|3@* zXOwdR>iD0x*N-u(X5y;bPpbdEI{lGL;9ACGi&NrwcmQ?Liqqc zB{&uz;I`O=4_F@=wwIy5#VS?kuUh|nwSJ+$bO9IW_3Iz{$L0ctq6=t066jhLz|LG) zAAqUU6bbMuS#~7AiGTcx!vkpMUl9{v_eXVQK(WBEV}W^80Y5`Tkt0pi?c$nll>MNM;D_~4K4~tN)qqnVpMWlV3#NBu3+{;!pk4L|a4rlb}`})Tb zy8KK9=X~0^?jJ+-a+KDaIMdRe^#oHcZ!oosnqG_O`Tl%-@)29>PZ0etYpy`~acjT- zz|hlpx@S0EAK(B>1?mlsS6l^R*I9n4_zE;yrV^H055T-DEsfZw1?Sm z&}PkSBOcsFBxyMVpJ`Fy2gEZsh-%(vV#pX(1?dVxxq@L<6?~Rnx2CY{i2{A)1oppm z))wmvH`9!;tZqQulDnYKuYW-fe1ka6*3(cnU_0${rtX$qi+9QE)oJ)K;U3Pv)fJC% ze6EvY<2aTx^zv;2r=A15zJLv}XFLEt@tHjS&u~OJjiso|oUgVhIG?vqGbLlZ(*eHM zQ$0@p`LXl-?oSjH@_$NsF}r@UOkDQr;Z>M@jMuE)<)4umuMYAXAJD9~U=zo%OOu2w zVy)9zV4pswo{(FtoAnd-tNIG)Ai!(33is7lAlzRb<3C*7zew)B7%D<#{O`eHwB;y7 zh1(>y$H)Ets{@4lar+3G;=ZB!y!pN+2^IAagme8a<5a$%ou(qDpJ*c79|N=3@y(;* z>i)-x7Uc$5{uo@2Da?&~J;nbozz{K$F5-CNIteZY_xsHB^LVpUfM;;^^8M_mkCX5F zE!NHV=_$OE=JRF9ACmEp)gMsUAKy#`ZSk3>GoQ&>GJF=1Jpau1>3iAV^Y~7r3h@=*#Ix3*Exy9GCTsX7_*B>U`xPE} z1cv)5e*S>Jux9cOzthi?vr29e4RX)egZO8nJ$}*YP>F7T;F?q;G!wj!U6Iwl`m)oQ)fHuC5m zs?#ItbgN!(O4d4&fPMZr`Mas~xy8EqyF~(3%>72H)UApHRIyhiu*@z!MFP|g5|xQE z&!Gc*1V-sSGMhKZZ)W)`$5QDl5^&1g56CVpS6)mcFmKkrjjP4x%4~oInasr}^ZU@O zy^a&0A_3m5%Z>!h>!-Sl->PC&k${{4i>mlO)34(4#S09(XKxFzA^?DCs-6vRy(lIR~;vaGnma87&F7j(DkBa)ki-gR-dgqRs~^r6$C{J&P|F; zb{Y8#t1r8%@eu0$Vh-M-`cB@8ReH`ppY2OCD^dt|5T33g#EccP`!T;aV1J{9 z?I3T!&}iXF!feVJaMA~eSDRIF6fMvjA>WzSXBS~()(zF#bp%*7PGJZR!mAl6*qOUP zP0Ks~F<;sW(gwDT`+h$bjr*+QSWFbFn&7rrS69HkfUR_2Vz2}+h5LwzsZf0j-vsXg zWO36xm|w1WH~vA6z|+1!<;Sgkr=a?Afmj5w2=SGOUDF>}q@0fp=sFqFHNeQgxd2Ue z4K(Wz=xg52Xo}xl|I6?@ObsCPp3U*w@tp^~vx+xiHD`m#!|xK2qVwDJx;*Iu=`Gxa z{{F?}?0xR<_j>lG{r%H9ekh)^XOUfl>;&}v2#e0-iN0|&dAG&7nLHi+syYQXk?RwE z%BuZTv#C>XzBphTSB1s5s`3x7%72R3SnyyCw!84{Gw@8Xxtc&}mKdWK@=r2^?o=mW&@#dY|y>DV(W0$R$e!+30vssfVJ@eGwyYJH%8|7_{?Y9q5 zKTtk<=A55hY|p;%%-!YflR0}l$G-leH~a3aB2Zk959Q(2onO?Q@9x^_n*1^m{1}y~ zej|8Rx6r;;Zn3_)UDweo4>x}vvGL5KtGn!GvGLjNwkkfp2-TY@>iUh~)wA)!^6yi5 zRZEpzL36}|sDxFJ{3rFxrG$M>Pb%`tY}*0yKsC)JZ`{j)7v z^ZGdFIXp|-9y+Nu->+6*+wR|I{vP$d*4E9frYfIzz0+k~>U6DBm->A9{2sd0_tmF9 zqi!&a%6jvR{vxS!JxA1NlerH@m-v!f%{r<~tVKCS{usTyU2&@+q8pR<|JZxC=D3X| zXmEZC!!LVI#IYn^MV|N~Hh7UN9gDhA7VUju&?0SdEmAT`*^>YKZe|xs-Iy7m8<-vt zn5ke;7Y+u*;L@3ul~pxgOdo!~8u50ut8gRk^ee)b7`aK^x_tgzooCsvhI?$I?XRLr zhtE^Bwy#^nxPaBI8yB#NwwLgxyg*ltb39S+kt02G+~x@LW!rNBn{6*=QM2|#iSE1L z0)5N6OJv!^WoKM~_RHCUR8J7`tvq_ zuU@y+bvg3_x6mHgHA`ae19(AS<2%&d**Sa*J+7Fi-79)sv40Kck?n&CF-m8jt}>RZ zVw}U9zbIb4W#kQV?aGP(wd%AvHIte^-uZO?IA+frG*b(R%6ZiS-D5koK=K}S3_-St zsRiZ)oX!tYoq*NcAk1_d6R2VW;aTb88xtT))^0}R&+K@9<5cGmMkXjY6-80XC=p9Ww1M=x}<_WmRHYxzs5aLN4_RDh_ z!+!G&81|cIz&r!i?VgdDMojZ{4-VfkU_2nNU!V;SpkH7ExrsbHzl)xSJcPde z4`O9HfS=;;J-BFY@b^7GK5%3RTwj~mec zCkjfgT!QYgT`obcQXMx)^AVV%&~gcuOIXHSg82w+N>7uDL(3oBef}VfLaVWVz35I* z?IU;%jb+n3gcaQdQ>zJ>%aQor{DU8$&xsnh>^+G3?jO|JLH=zVpv&1lv(^zvt>`Lh zMOUGSOBUJp3Jj}Cd2Kmum%Ru1FRoI4%W_x2CLBOl#t*1WWzLLBd#aaEy0HIPbmsaG zjwr1cq3R9O6n@^pe7%XnFP|Y-6wkBEJ+_JBwWhre$pv9zNN$e6*`jzu^2PN4EN)Gp zp|_&9tm)+34FB1T%M`91bid;Y(BEGEhTn?c(wl9*(f6#{IcFr& zadmgvxv22%>hM?Lh?j{Ld31BpteffPa{M`UbMCQC=x{np4#(8?%`L?8*-0N#%+t-Ity`jD3%S=4I@e0a{koW&RfMLO&xYJQR`cKiq5^}JLiNq)60j_x3-%J z_QTi9r5{l{y?iaZUM@_ciO*b)Kc`;KJ+{-!B|}pkb*mFShTW!@8+KdNoj>X}ui7wr z&Ub^|!&l4=yT{}1w%DyMwAr!S6m!FF!*0Xw$!RZ~V7-oS_Jp9W#QC#FZc=TzQh3dd!7MG||lE_;YIJ++#b~R7bMY(r@s)7rHym%$v&C>cAC8OGTaDxEMK|v1c>HHP!4k7Sg?C!FV`L?B z=1xY>M=y}~qE0ehgSd8a*h}=K`DL_Qv)xa~w0v;ezDI?^E%fXELWQ`Gzdw(@x;c~Q z=eCwv%{q3!j#mJ#qi(jI-HL+&ZONEY4>moRqqQyO?*Y^=eti^Y;MXJR6!V zKfp78iLb9v0?+Z3bG?zQANyak|J6r4;Z@Ht6~vw52|mJ}KH-bo^BF%w|37vvIK$7m zAMTm801rko8U78{g-dMr5w9z5%PKlw9ew!mx8@afh2@z|)zPib`6YT&60dmHr2l*@ z2G_c9#pLH$VR+|q4=+)9wuzpX+Ox*6n-x#`Y|Asx^+xeMTuFW`@d4|!W=i_xoO8>9 zGqT^plhSwewr(vc{xz%l9*?=(c57j`JR(bV%pI>A`x)phY|3!EEpA)Ix8e3Q+_tED z7`ScDb90`LcP}TdQiZt~)pa*-TQ#;C?T|`L;W5-j+|-`9jUjhiF`nTKv^sISRHvI1qzwTi#e!rR#C-3NA_M1$eS7qAVZ~8(wd+!>#QRein z@Na&KeVm_9_~|)*euKl`fMeJ%I3Ag$Y$aFZS9c7O zdlB|_P+Tkjiaev?_3V1?m~dY`U-Y$$2je-;+%?Y90ewG(%T@)`fz-NV9g%Fp#%yu$9K9`E~Eb5`!U#?AmK6=Z@m^iD|~8K2pG z{BOnOa)}k!SPOaH;x%DZjSujYss=qBS;DAVb!J&vCZp=|9^2G}Z5MY$wH~hBTBhUi zCDxoxxIhlDA0oFz0kcNehsA!TpP?A`UN}?=ooKv1eMDZ(HI%!a*5e32i{YFpG!20OKiJ8Kq%l^o}=5w;sudiW8cIzX-*`*NrNRr&OKBolUFDm)c+Qvn_o>ZEF15|xy9-fN20+K_q+6Cy_PK{+{GIQLa+2cikBSxElu0MOE7(W&s2_Rz^R5%eD_s1rW79 zodc{D`hGqRAbV`b0mMaB#{p!E7zdE3c4!iWY~;Aa=}d)fxIIpBj6sJGlEsP!sS@%7=dh2&j?<*`{cn$I?S0raF*US z#tDoQ%%%%``Sx6!OVAtwMD9r!C>`=!!1j5v0lLpqT=?s70@Aa0h}y3`c=O)ie=CTa zp8-#fMo;kXLul`ZuG8r+j*V0~_2|7LrfHQ~9F@o45l3adgN#Vl=}Fgqd5`T-Ij+^$ zq4Htj+E-MT?vBfi%Hn@eH+dNOr*)h&R30WOOROqaKdox+6`t=C7Z)AFWq<6R^;E@v zuW-j!_mx$~ZOClMe0Ru9eB|`BC+NaWEF+%YxJu~@=x?|1z*Bjn&!mjXMC$MHRQv>F zKEV5qfXlCe*t@{$YQ&~`KvWkb{|Vc^!T-O<_kCbG_rh8hJ&tJ({B%6`?mN*fX2L^>g-=sv@qBSiyn(O@#$8%OJY=GtR{9FEg5%TYb=vI-Z-Qkr@k)3Pj z^X05~Z|cTpE#r{=_|&esrpF_E#qW)x)-}!u_zv#7F2d*Ump!&&1nUXi?jE{hh%*8r zoaydXlc#--maQ+2@d4ul$_K1M|J~>h7q<%^NLAp6?aZfFp(z&-MR0a5;MoQD*oF&i z6h~jJ4y4uRQ|%`gFtz`?qS`S<9oPg9=DlOufN2A!_Lsd~)~#ne=cOHMhSd$P85bzm z=`&M$g)WxtFtq};K6K~u=j_;1J}c6d;TrE_k1l2fKDfFTcIr9AUbL%T*uh8g5qzB) z3Fad{yLW$&f3pXlcJ$HLU%A)MkVANZe{otV|I|!E+de--<`EB|af@P5%_CGZiE9d4 zv9{b<2C^yP2C+Ur)FE}|r7;O(5{tnkL|KtP&Fe2-f9L@iJq)zpHfYQfMQ3F0qkq7?}K=F|$f$2MGGqsX6EYX!}?fH@MrE7(=s zkzj1V*nrg^`bk5Jc=kn5U0Bi zxH5))2X*cOE5g`u@W`R(&-nWgIZAdbYSWkSLD7344Y`>==O@UA+UF(Qmm(5xpU|W(J6RX`Klr3j8tX8GKjW z3H9ELqq}wsQ0MsUad~-<&C#88Yr-_@;_?)g{w?;StYx`XdO2J1T>mOGdh1NMIL^Oa zR}mr^yR=@zN6_iC*D!G~wa@T2q7!ak)n`~`6SxJyU!K6u+DzD}{|g^Kau{!ZMz0MES|+U`cq@qt!GDmzqfX%FWPY~)HgLgy#t}) z{$hFjy2Je)!+mH4=U^XaSW7=UCh`^ipY0-l^Xj~0kXLS zi&Xd59Sc}B7SKx;pmony?Ux?+hf@gHOYj-=rN8laxu+msA**ZNRZv;TimRz7Z%pkH zn2zb%S1%u?%O2Zdy6BJ9aeZ1hVPd*wDNN0$x)t->Q)NA#;4Ov4o1I#S4}FnkFfnIwm!$Z$8)CiMjb%C-7h*q zif+rTp1YXoS9dHj-HX4UuaCc?)uJ3P0jo(=$u>WO-v@O6Zzlz+4H zt@II)sN(LT`ethWeEay!Tg{j0zUk=y5UVFw(R}DHdu)gPvToO*zi4FBJ@#60NAy=V zYv`YX{#Lhdntr=nzM+3V(ch}|+vW1-+qq}n=>N!Jc@y-PcjQEW?y(*E3%1vxf2xy@ z_4ek|PuKJ5e6)&t)AQT7`Ap9@2JqJ5PG95yR6ReeuOF_Oui7U)uAiM_cDAm(tebC# z=-Y)qyc*GYWvD*H;&~sRT0EZ;&kwI+Ubx>hEnhN1hw#`eYq$RHwEVs~^LGmt@9XBq zvqh`OTUmu2*U&I;e}Y;J=GShJjiwGSwGQR#iE@sb`82H_=ib_2c^9?u&9r>Mjg`@l zs3Dn;M{nK{y+pC`h+h2kvUNO~PwAKQ&^>!?BKhqZd*yf?U#_3I^V1{wMM8dMvWEOz zk>^{J*S9F%kY94=R$H$+ep7G${IQ=$QQnMWPo5*vF8vA3Xu%*`K@8P_WZB*6ffBELD zc?Cvd75dax8DX=p`#*32K85PK2S+SdJ*nyQv$f04xN}71a#hZt({exDp8W_O6tz=B z?UBcRM_a(cZG7+HoA(ple@FP9^!svd{W`wcf2F)-xknPafBFjjrfguouDY}D2p=+6zq$J7*@15ds8q)VK)kL`s`=v#z?}UOC-82FGXU?Lu?xSnY~@+3l@(Xlzsn0;|7ARO}K&PR&%)oserV}6KuhE{?IX-I(49~>hC%BunEPC zHGesr0zboz__I5r>CEXTsC^%tR`(u?#w{vc{|gR!A5I&7-GhF2>%JKkyvP6FfmdGQ zb>j6dG`};v{}^iF8Mb@x_9NF~@0-3=r6q3RbJFdk>b}(U`&xR{3ymL`V}N(td>sS* z=Ld04K;}^I9+Z_;>-#6wYtKO>^Qv3+slT5_f}uk&{3N_r!q@J`J=jIofLe4~Pv31+ z#IvXFQ=ozGx$_(|bYA2Ceu@sy-2rkve>s0L^FIgQ@;L02%Gcw#{K%mfGa#wB%y;N@ zyBPh63{v@bm-pB_X5Ye*#Cq&%#n|+iJ;Y_nDbAL^H(VyJTR)!hF7PkFz}Q>s6nyH! zX?O=>+g4(i{reH9z?K8rHWhAXSY$XtId zZg0|W-*8zSzsrKlyy7Xn_BmarJ6xtKmN=M>%j%<*b$Sw)%X@5t%Q|(XE?yRH5W{83 zxf?3$v!-YfuJ}Ke+&oq%&wQ5E$+xMKw|Lpd%KVqb%lCjS{m!p<9WP7t+az8VWq7($ z8^+@4@iO<=2A5T3$$`uAY#1^dGMkbuu{bC0#=LHA=g}E58#3P(Y7aHGS?l1tQL+$0x<4M9ebz%&_?qs%VoOGizAa;nI{l!hC4v zL-UwUw#?cm?|vYczbWQ$%5>IPMVd#iA^6aEw2Pl}CIyc+Q+Iz`>~du)T%Yth~@^;6w6>#ThfEQU^xp>3+0soNGqGkWt= zm6a5!M2z=J!U4G z-uYIMWs_51qSoyrT-1^wD0iGTr}kni+worPix5AvtH-!@ZSgbD2$o^H1NZ zF(jkDmL+}`%xw}sORa3q_?dfb7e5Qfs6%OaKI&1L9lkAoZW=$c7vWA(k7pTZ%RqCz zO6`dn>w~sWT*QvczcI?|UsrM@bUTTD6 zCur2+v>fepoc_i2BRK%xY>l2|LF$*N`u$}jy-lW{p{kxFpHLV6)%j`85tm&A-AFFb z>yA;{7yRrK`jC8boVL6EB*Nt46<5`|_e*!4U*QvcamT)oPx=YmlN|I0y}!f!)&b7n zo_i9?5vlK;5;Azdp7XcUBSExaHGypP9B1_s6NOkyOm-`E^3!IQX*K`yy11$0v1_l# z+n9^{70$EPS2gWk{t#D)zp1)=xg3ui6aSR0r}Z$s#nok31#ZFlWBU``t7YERCfqZd zxVz+z=9Y4&u-g?-h1D=}(EeVbM{2w~`Q#)zR!i0O zF_$a%4*dmuAM^AIE8+=rU^2;!JxYJVo_Lp@j=mo~!#@AU&tAH}xiYouVj3Qg?|ZU` zC*cNrXLozz;&m}sRGyCN{wJxbI-ek}wN#M!yiG^Bu%3(W;FeW&*5y4m=K-9dA+ESO z9w6&S9S?Yn&%}!DC!-v_$rh6d$XSeY0X_ldBVYFV>sk20Ue^1#}uCM%y+ru6>sNnd83u-u(j4Ebd`n8Zo-HDreT z>2uHf*3I0IpL%JzpDA%%dXnZue!s^y$iIzfl!#P^{CvG0_oa{IVq^+L@A0*~VJEe4 zDq@pP=9-U*<39b155MU)O|twa(9cf6I@s@1I7a?l0u|&Oxr8n`fIlnq?vN_=!rC#p z+)?!@x-K8$%CKKPy@gcMIZdgpAAZ?XfOy7$T`u>*uO)k;dO@Fhm~SBBTSgT?t{vC1 zHaP>qmZ7Ksg6vIH0ExVFWecbRaF5No0H@uGhEdH0?8X{dFN2&tUdb@NN18wRyM^a%UTiXAD123aeAqdr0sSxZMic%qbpovmZ=iYDbYot=aJ+@IQwhK3QHP?{HJ%wwS zQej*}S9eB}rc~sd87J|%L}qCjky*G#x3v?Y_Moos`r3)`9XY&_i=b9?#WiMiNQBoe zUnPZcjdA86Dnw4M;rG~_Ydi!?iOrDJjBh>LVB~HU6jfY9*Uz{^!nz-}!3)-RZ>D%xmN)0omSYgJd^d+9IL6pH@f0iW z%IG;f&#&?K<6`}N@7M^t_|RkW75_WNwsb_N@`u!H1+i563+Cbny2s}HfSEMG!|H4W zJ8s0PEMDO=Sr>-)xMQj`1gow*#Mxo*(vRqIa^f_Cx?aYnBDC+)WGce&R0OHd;X1oq zT^K~aZkuTk)S0J_;3pWR@__1YO z9=^$5juBPMOh@hCC|AV)TxUJzNB(L38i(DBiB9yqy_ozSn`8bajwV(|p&X|^pJ2V4 z>$L(=_hp-~$3wZwk$jGI+p=|f9znLBM+b&&sHu`~k{-QW1I963o_oGN{)(dg^6CVF zhO%O&IT9DOM}u*JTbB_WMknVqCZJAcy4L8hr*2*549X4U323kTk9TtJZ)ZkP-*WLgT6Tn%139ug2nX}nC38^f9Su* zpsW5*-DnO?nZ|hjfm4c7ra4XP|1>`p!XMS_xripcphPo}n#?@B!|$;j?~tRf^DGE6 zsb?NUq{ZmwAdz$4zL4tsh*v!@MzI;qR`sx`Q>Aj}DCB9a^Cb2^N3opUBIU}Bvjy)F zpqf!XrMc`?SjTk0b-bs4Sqf1Zn&=X#lc3WkMo=4SGYOg#CU*)=ypA8p=Zo`$XN6aD z*u5g>!4EX=5X({+JFuF_S*jG4O-(R%a9#8uFVB)KW2DT5y@!?lt;-?2h4cCooClxX z-}LZH{zQBfbRSI47tNiu$juJ=o3&`d4kXsk$qxJ;o2v)(tB8_O%?{Rzyhc4cAg-Bu zP?fdNXCcN8q%YZ|gQ1J*(+5~RhV54f&(gfB6W2z&(961;HQo0r26HF~!cs-$^SfMi z3-X!UDgo?GAeD(!^255ss(M6K7XEToROQ)C+T-W{#h!fTNxBg*j+V7Jk8&?H1l(hD z>}59s;Q`gyE5}-oyw-FF%S)da}qWDXm;!d=VK{b>(LomNURYpMk94k=V zjUib7qu-ICJw>;*s@c=V5YicfXr{&x=m}T^&j91@l|4(c=$JLXKovWXH7w2zSe2muj3)UC(I%|t!3XG;TqpHRpSZm3 z#i+XHv`tu88Fe=^+FS+ZDk$p(9*5NfaO3)@ve)b_+yLyS$|rgooZ_^ zhTg}cx(>)M@O;x5bo%Wn7bG_HCLTX3R=Qm{p3ZQVcvduGmTWy)x!jrEp?7YdfcP(l z9odVQge$}{It1Uf^a%{Bv#~_$O_+jIkL6?v++!Q2u#<%;yf&WjEvEENy^trY8&9wa z2#zV5pD;I1ScD9~vhoB~K0hFme>eKWFt6#Z?ALAAbbDuHzfYTF^m>H~aT7rDa_<|226=Y8uaXn4;4 z?UOi7?KcI_{dUdqd<(hZScRczYV~MtJ&83xJUy0AuP`ik{cWQ8pNxEmT*)sq&)&zT z9hZ;Je^#q7oOd??K?kk8F-0J^A`s6U^uNN;dJ?x$1g7;Q?r$d{iSN@g2f_^U_8}%G z;U1fE4bHI89+-97K{eZW1y2F5)nhOgu7*cW^C8mB<}r8*KM0TLgVS24XIOqh##DS@ z@3HMIGR^KAfr+ST&(l z6Skd!w1az_&s&w7Kwf)^=kXDqhf_EXKH#~c)1d4!XU*PZce%Ttg($k^u-ya8S~)1! zZWnhP*Yaz3|IzJ7pDt&oso!O_s2eSN2Dh9W@X6>OcYjxRB%W^t0i9t|$B?}{L{}=j0xO~?Wym4psJssKg(Z6{NfqeA2nAL;u^uwdkT)9sd*~_ZTbqf zNBn(v<*N|?i+cto7LWM{=feSV`2QCH_o>Y3s;!yvP?Z~h?F3%hQ>=G4h+x?LSMnw0 zYc$zGxNp6MixmI=upLBpnkogS0(9d$@v-eWr?mwsAxF}Y~W@tAyjWHCAG(8eqOQZ@SOn*DKv zGAyTBV_2?vCRI6ocHE+Jo)d{u*g5_k^kK%kM^O6yaoX?|CYF75sVR<(*`eupChlb@oiWa^YSJ>0za_+GmmP@aI>bP9`_)hPp=T}a$ zjxCGJfne?9a>i2h*hPV2wp??~|#7?vBBcaP;%U-=X-SBIThu$<_@C}4>B z@>DcWkIdVnxu8cLG`Gmy(A*;PSZ93mzR`_TH7!RlVc4E`Lv!te<9%mjH`U&^;i0*Y z&E-zc8JlyD?P7Cr%GaT}aF1Bdd>y_%%bCxD=3E0fVbfysX%$x%oA1E$$a|x|PIjNO z=bbDWWk22SvT$f?&tBFs)z86O1Z3BWVT;pKk)22~)HppA+0*0ncF4X3ERm-t53*aF zZpdzN`tru{X^(uYskL%$jc*YWyrQ zyLFYhgj4Uu##tW?f}GHy|Fji_v5K;j{-%EU(Uf zeTL+-AbEAa*l{PfWZtbq+~mag@iVnpp7;8muy@}f&eZow^?kX!#I{5B;q`v?NSvy_ zYu>x6_iK5N?XX=GgX$=~3AS5i-LTy<>+{R38@3N`j+|k;p8}KWnj0Rr``o(Jhv&?# zbB}GXT`SS^VEZ%6tbzy!CEIS1`!YoCWeuHcASaJ~b}k`y z75$BtP`cX9G-t^PQ~ z*z?ivz((mf$C*`!qZfEqR?zq09`?2}Qr%(&-4di5=X+QCe(sdNYjpKr!F0O|JWKq! z9KrX+F^tb;V`R&IIe)o6*OU0mE2*<%<5O3;ZTOBn81MJkJbouK$5CD?w_+&2HhPHb zz%yo*Z|y4Ics15>m&+BYuYHp?%Ked5>*yTscJ^95>J0EZV!__%WhY zbIlD|c{dz49KQm;WZ#Kt^Ipt*)MKOO5U&be#v5V0^&K-G$oW&j-9=saDb<;EI(hM0rZ-CkzYL+9K9+;guo zJLq`Nbvc*SFx@b{4%3-O-?(%4+^qWhd{AAS?~M1GqPqCiCBu^o)n%%+{K;OITuIC& zH-DF$VfqEC-LK$bjrX5hPE23CPIR(znOknM$Fe%ZPvIb!_<)}AbvVYk9=}B-!C2z6 z`}-rjKcbh*`8-BN#=iRwyYDlq-f|AGRm2^ltaHnwi7h2kq|Q#%9^cYXzFmD=``BGj zK0eP)u72G6zKv@hqWr3%d}r=CLwQ5_zSq84EN`*Ap?vo!&n&%U{d2_fJ8(i-?9QHH z^N-zmo=uHUiQM~E#ctJY-(l4eWg$M1-Qsn|+R}BeJQHb{@w#Q&FGhbtMVYLYpCwwS z$`X&(rE)qJt#f9s^`n`^6VDo$ox;IbU#D&;o~pkaiVr!rE^E`URd<`wTJB3jhgrNc z&3Ffz?<+dcJa?Hmef1RCg$rcm&JpDt;!oDsNN*bYzpnAxDPCPcyea?tgl;wbm;Cf8 za(awsuZ#Y0+zXv!FOgOLH~#JW+Z+OkKe*rZJzl$yUOCJ>Ux9CZMih4&{3iCBJHxBH zc;yyH!z1D`{)OMOGJ1nQFOeCMW6*wdT-~esQsX! zY=c+l7FUmF?gsniO7T0+F0TR4=?bpQ8(csB{Rux4Mc4d)#!|RGT)+`}?beTz(a(5( z>+10i-4^?B=$WhET>X-XE-TN*QpTq*4^wH7K00YEMbKqY@p=={XdJI)i+9sf9IL@&RCv!Zgq9MSN5SIv10BKqRIAIe8cy}$M@NC z_=fL>@59IUw8*-RuDi&%9h>C720Z5HuaCp&6|gvbHk{u4mc_6f{kY<{7*Y6aDBX9@ zyv>V|3N-qaxMEu8_-#xjOG9O;O4lhdG8^VC-doPDhY@!<3-2@N(&hCxm!H4H9yaj( z2de#KU(7HubARKmP<1X`u3(c`T;kt&H(ISGtm;PVqkHbLT`Vph)w*1G$|N{qx^Lv_|=Su}6MUDLd6`syOM+==3b zyTsk}O0_MZ&|xui^*{LcGsL`qj<2M~*T=|1$^=$_6ywuZ#i=g-XjTTk183uv zYl7yYM(0Fx?y)(VuY%>o9cuh^FOpPkey@k7U6I@=r4E6bIaWU{5 z>UQB?%bj7VsgZZ4MAFaTrGAF{@7nc^lKp>07X2Fc;|;z}O3K{9=odsClijC$+`o?q zq?{jQcaQ@d^?otG@2UGAw|ed(mS3G?jQf-on6Hn&qIwbi;q!8Tm(Rq!J!xF2$>Qa? zk@)I&=UlkNXMEx6X1IoYEY9XEYWN<`8L#Xscq2qLT=ZFNaV+1*bGMHxAZMnZF|^gJ z`Ib;uQdl|+rW-nNe@vJjGEjaC@|J=v$W&e3q zHe7nn&o*(DoL>5~H^uUoF57hj?Lm45l_Rf17YRsbUskrW2MyPUy3Dvgj;0JiI>^S{ zZo;zD7(m!Rb`iS7&w~L7PVk20eon{`bb3Q_QRn!lD0Sp@hU9nccr&%$tM#d~+ZHpDpC6Jx zjH>dIDXovmrFLrZX1dG+$*JbZIgQ8Vb z6JpE9(^ZbXPyO7yv!PAQ?`sUp`T0qY!#XNwh{xUJ^R;%&^7-0{eha!*-}CwGDZPyD zJaM?Np64TSSbr3=t5X?*JcD%T^;hdB3+Ec1CvQ(yFMDjN+OOdmcv!fss$>0G7{a1; znwbw{AZHLvkIir|BXoVuTNw8mW0+S5*hOUw%jN(S)KOpGBx5tiu&9$_J!25BYi>`! zxCF$DnAg?sk^kfjU zofc$<5+=fqHD4`2SzQ6?oz% za34eOzdL_m=s$YxsyR46e7x>s9eURT+#wI}H_r*Tlskp;|{#VhnvbhVzU=@?%w|hS+KD7csK26wrR@TF64*>7Zx=MTT z(aBnuR-YHXBcCe3I=eRYdF(hVk!~H9$K8BKPT%A-c%CuC@-mjE#{7J$*YUi`6`3CM zYi>r)^n5&fdGLE46?y*C&mV<%oz|9$!l6^&<2;`#bLW@wH(r6)fBco44zDx0qUzTn z(;0v51k8^;i@b|_vR1ZSS1xt0hQD?AORl_HR5PdHZ}^Tp`0MxBRF$WfJ|0WU3RE9S zOMEeW^qq(5o{GLHwecbTcs-cUdK)B;W$DXDv^-h*>1TP~h~I6Ve%Vy_IO_L5Prm`A zv8Y?~^s_|W7hp}lgEw);s`eE8fc}Kx3|Bv4RwuZYyX>UTi1l4^b<7d4^9Pqk7K_@=b8Va z1JQj{LGtS!;;K-)=KrZ4-gif+T};?-=?w3E@Afkfc0pg4cGHRF^vif2i|@P0>X(nm z7{&qaxDU9u&fMR;HyO3DRx0#ThTTz{DEmzrMyM$q-Jz<_E@U4Nxk_E}bX}inK0Pb! zRlXN!@7?M8bqwPX_&IwWX5#JosZ3%GYvLNN z;>I^kKgT4x6mQ`47@Ft3%)iRLB&xdj#gvNj5gCu@H;=eWhrsZ;1ic9J@d%Eu78)7T zt;2PL=5U5WG^ai+m{)G>|n9@{XDb+`XKOk-K=62{jO ztx@#Ytg|_UK?*a7DHvs(?}LI-J|h3=!dz_rE(Uk!O*{ghWVPsYe%H4gi76P~!?=p; zR_{!#Q!tEmETcQZScmEx$~wkfH0AiUZ7)P&KTWv`-?bT?RwO>;YF*?By6p4Q{eX_i zMB&+Vk#cm;{Y__d!^o~|;QXfgH>mBh0!NjqKCqMVV={iyTp5{XuZ6|tCpoGmVw~g= zRBC?pdFCM3X?|(cs+oo`Mi_ssonMm^ch`GgFTsBDDH9V`fgV2qkHSvMGE+FEe=^T# zTz`#bdSw3eG^)Jd;%dqT|K5tX38*~dE-!PAV$loqMAgQTW>zE zXnG{f>r>`JWu{n_>F5ff=UpA)-KlLf0mEF0+xzWmSjW^Rx*Gb7y*2T=`pG4@B8Co0kKjDJMCTiL;IDxjpWqe|^q_h!*hCcRU!O$J z2zG0bu3hxcJvLj4{hA7C-3WvP9zwWUq@{1NAzW(;k!zVba`Luwte$BPBof7b_ z7nPE!$X|}S?;7{ZM`NhppXx~VZaYHUqkRuOx8U<@U6-16UFv`T1*>LQ%=n*}oj3m1 zJvLpzssa619J5L|Aggtn*<+IJ^>wAh^z;94>uCTVvmKWeY!ab$r z1>}tEeN&*qjD1)QUq(yK?|al7_W|%c>sH}D%Ps)xa7^Zx(=jl-4#(}0{+)Z8b141s z?#A=>3y6=c+&Q_7^HQa){S7A7l`X7D>-g@oXP~R@#*3x%6K%Lo_&x~w`FwmYy-Yaw zpxjI8F;;eVr+n}BaE?AYtT|;rCU($a{~T%sUS*igGw=m>Ap0AfVxOtKlgHmNJrWKx z1?n=Z?}(ts(1s~cr;IU$n0w$gu7u1%FsAScex_+TgY>CM#uSVx3}+UCv4tG2fUelW zVr2p**}^km{@=j)a-C&gxWccExq^R3F0P<^Y{L~;RS@F}u|ABiacz_<96|l3gtP`$eSzlTln!lA>*-#qp!@3d*GR%eCSFtIe>dGqMBH^fSCjzQk2rC9e88 z@)pDIxyb&_lKbGF;uzB$$Fv^KqRUd_rVoUe8)g^7jOF+`QO4;uJr~WJSY{bMYry-t zx=um54fyOuU-by~H|Hlw>utcT^LiZp9-A`?W>I1~gfNaOZ-X+5HP^35P>z4H6VjIq z?4tjk$MF?I{RLze@4x~DoHC-*E_xf{pf$8m2B&(Z}}xOQ_QnsAKqHPbSeSe63w?qs7X9tf7A4 z2dEb-qkmx?rJDZl5px}km%m598va~9G3Q0|HL}S|XgKF!ljVuge!kQT$2U1Gg~~kD z7j8}d{SN_a0#oZ972yKvj6#1RF1Rqbmc-6aa~nBmoVi**^}fjMu@0=Fe{%HekxaBC>%ll!eDG%F-3YvjMBN^wpNaj8b|g%X3(+ z!^oM*2#;jeDvUOnjGT3vqDi#t)5J-$!ei^|G>KHxc?2i1aPmUFF3opap_%H7D5GpW zlaN?l&^|U9sys=0Qf;W7S(MHu%6aUr7(&jv%ly-u=85~`(-D?^Zlp|as;j;fpPf1r z%FNZeHB0p&W0ZdSBj0_?o-~dBH=*&&5A)kpUZ%Md)<)VpnMcpQ!=H<6#V!7IJtdF8 z)w;f-Quo+A&%m0{*pz8H^>_@`sDAiuo|5D&sw*URN6(QZ;ohcy_Uj_={s**-C(tl{ zhq_U{b-W)l_d^`zelBrtwaT_h2ZlX&tk)esS+*wEqF`AlkFn*em@0FL+&?A@u$b!$0FWyTw+g z`17>5n{K~3wD|08;>hJwmES|mzjnEzJ)Fl|92K{gE$I>4M+NB>_9?Dpz82;tWD8CZ zqj&ihSK|k_H#)PqtwdY86@L%8B^_jRTFCF>=U07Y+Lq7ojw@VY)=YDs^iJ~}P22Ve zTk%+KN4wC+&hRfeiZ6JN9*fq)ma)Wp;ppg;&(A9*TRq1azQj2=FZL*?#Mj4Pktal^ zrd{CLe1#L8U1IrZC3h+Fns{9ME<4B0A;05}_~>$Ud$)_l z2FUZFKRqsvQJ(u3MShichIFtEf4^{0|GOsZO{V>RUT@}Ds_y*o87g<3o;>GdxpMC1 zc+1;Yb*a`W6Y{4ceDm|a#?_E3_7T_WvN(Tw{r%*obG&j^TvvTnateFJk;L7QatEfk zAysc+4|=ZtRp(4s0d*hf{hFSGkb8D^S3<}nbj=EnI-V8vQ9hsR4cyyLM*p~L#I@%y z+=tBF^IGZo=Oj;F!#Kvuy~5st@{Z{^6Yg8P7Ra5Y>yKaCC)Z-F8oa<=#NI&a4ADE4 zM_Ps0<>PCE*bj^KtvU)%MQnNl46zNd4Y9Ret1pPHd}kc9_2-7#l6x2mYKtfN0eGY0 zeOQ}VSMzW;s6C$ltiok#xy^7{-_a#5D`!ftT*h-^xNNv=xXigs z7EN>Io<}r2G+d@iN6mJ-P@t-CnR%0DxUBE!D=y3NHN|DB0C9zzaXZh}bcLIG;-O=1 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 Ssz=n}JHyHF&*9AoZv1~vN|BiW From a1558fb6beabe8ec584a01b183752aee9ed6764c Mon Sep 17 00:00:00 2001 From: Benwang217 Date: Wed, 26 Feb 2025 11:19:40 +0800 Subject: [PATCH 21/26] Correct F50L2G41XA parameters in ChipInfoDb.dedicfg --- ChipInfoDb.dedicfg | Bin 3859198 -> 3859190 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ChipInfoDb.dedicfg b/ChipInfoDb.dedicfg index e4b15e59de5b6702a9bb30be6cc32ee3a0a6d2d0..899fe638028757cf7cd4b80fe8e5b4b39cd14088 100644 GIT binary patch delta 255 zcmWN=HwwZ47=Td{dvCFq#2$OEcndG$5iarXkAz{SZ?{2sjDmv%n%tEVDwL2CJ;G&IX%ou}za5cG+W}0}eUjm=jJpx delta 248 zcmWN=Ne;mP7=Y2Lnbur0MX7lnOPs_d9KqsGZ0&3v!9vmlh|93I6yHnU_x17ocoL7O z;uW9xB_KfwNmwEh744y)3PD@36i3;)^{la1-AlN0Q?JK^aX)LO&KToNFv%3t%+O$# zIp$elktLQ{VU;Fptg}IjO}1#W%?`WlvCjdA9C6GEr<`%l1(#fL%?%w_Gq>;O9}@;V AFaQ7m From 135655bcff28d2bce209efde2220322cbaf448c3 Mon Sep 17 00:00:00 2001 From: Benwang217 Date: Wed, 30 Apr 2025 17:31:30 +0800 Subject: [PATCH 22/26] Update chip database --- ChipInfoDb.dedicfg | Bin 3859190 -> 3898332 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ChipInfoDb.dedicfg b/ChipInfoDb.dedicfg index 899fe638028757cf7cd4b80fe8e5b4b39cd14088..466b3c9390204edc2bf641758676a9c44749424c 100644 GIT binary patch delta 1982 zcmaKse{56N6~}#_U!G0kAJ0FMI3W#=V~l^{8pqh!Lg|ZJEGSkmv?Ei+s9{yds;Iaf zv{HX;4ze&q{Sj)GZxlM}OluWYQR`Bc+c8ubTG*5^=4Gf_yS8#shNiXKT)NR8L){KB z(5Yzq^3?RF!(&7h^-8-Fi)5L{G}MWVeLrcaN+ne2Z9cxpa0>ACB%>&mAt%mQGbr{(u^Q8UT?9O1=#1KDJZE` z(u~LGbYRnDj|-XanH?;_Py9=cF;q93++4YPl_K!+&swaER}k1C@a*lzC%lbJbAxS; zVz$r)`>n=i{@}mO5yoqCi~Ry>PU(G=kGb#RwPE!HgMEX#A9X`qME#R?32P(mHk6*z z=aJE>Nm$X?jMA6peW-m$60xhd#g6jBZQWeiZQR1~&>CwuD*s&d7vvH~EuUU4Z#O|m zF(=9&8J%nmKe5P6=goXe@N(sgm{s8QdwkQRaD#ddwUT@Ux!;;3F5ez8_JO-_aZmzO`w*PCCEco5l4qjgN>DR z+!!gG9g_LkA=9OwH(a@B(>al5X73IDgZ#fAbhs3+{@FOkFuGfM0m1p``wa_n9mahq zt4$)GHJNA6T@BZ6abon8*^Nym|7~1(#A0JSchIH?jYy@JRvrMDKTfs+!4h@5Uwb2XZGq(fx|H(Cs z@|Ttn>_eSzLO$&5!r33&-b5nNccCZ`cj2ec*`|2;kXvRbowo+C>*bDq%ud>-aPXz} z6kh*{O~UE*_Ao~6eyJc9ZA1srNh~J1h?|IRVhLd1P5WW=>kd$UG8| z3On`(h?|KZv4RK@eSF9M@U;J`)(tuuKDWr7$UPm_u{7^l6SXkp4q3cBlZ>XC8vRw; zY}Gb}R4eIPwzV!@jPO&E71Z2N(GnczBvpx*G z*6PDQ#zR5uFb3H9jf3C}r4;3lLA{a4RmvLnzB&cDp87io< zrWDFUdXWv_fnMgh5>{*)P_3YoA>%yr%_^&aCXere)TpR%Vt<1yM9fL^wEwG*nPcMMxNY@NJ?5eGUe- zHAplBpEVXiI5{*FI7p7sCPnAci-zCu9z0&@`&0Mz^r1@-9jPPrL?8`BB#lH*48%y9 zNb{}f{fcUN6W8)BD<`b@C<%OPL8{vL;kNYZW<@)SqjM?C*~O11%4~0e94k9zJxd&0 z)U%95V8*z#%x)HC5y}5QD6Pvmna6kK2P+MyWFAf_)jPK5P(;47YA(F|{fIQ;Z3PRo zK|6Hth}XKAWAde2pjyQWozMl{&;z~D2mN3JI}CsWoG=JO;Nn_k_`bxG&u(F!7L*Yf z Date: Mon, 9 Jun 2025 19:20:19 +0000 Subject: [PATCH 23/26] dpcmd: Don't crash when an invalid long option is supplied getopt_long requires a zero-filled terminating entry in the list of options. This was missing. --- dpcmd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dpcmd.c b/dpcmd.c index f5ba1d7..c558b0c 100644 --- a/dpcmd.c +++ b/dpcmd.c @@ -222,6 +222,7 @@ struct option long_options[] = { { "set-io1", 1, NULL, '1' }, { "set-io4", 1, NULL, '4' }, + { }, }; int OpenUSB(void); From 8e613e03c3cd5b008309ea3608a71e777a9f8566 Mon Sep 17 00:00:00 2001 From: Benwang217 Date: Thu, 17 Jul 2025 12:00:35 +0800 Subject: [PATCH 24/26] Fix W25Q256FV read issue --- dpcmd.c | 1 - project.c | 23 +++++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/dpcmd.c b/dpcmd.c index f5ba1d7..7080548 100644 --- a/dpcmd.c +++ b/dpcmd.c @@ -2473,7 +2473,6 @@ int FlashIdentifier(CHIP_INFO* Chip_Info, int search_all, int Index) UniqueID = 0; rc = 0; UniqueID = flash_ReadId(0x9f, 3, Index); - if (UniqueID != 0) { rc = Dedi_Search_Chip_Db(TypeName, 0x9f, UniqueID, Chip_Info, search_all); strcpy(strTypeName, TypeName); diff --git a/project.c b/project.c index bbb64bd..6515e1b 100755 --- a/project.c +++ b/project.c @@ -1507,13 +1507,24 @@ void SetProgReadCommand(int Index) mcode_WREN = WREN; mcode_RDSR = RDSR; mcode_WRSR = WRSR; + mcode_WRDI = 0x04; mcode_ChipErase = CHIP_ERASE; - mcode_Program = PAGE_PROGRAM; - mcode_Read = BULK_FAST_READ; - mcode_SegmentErase = SE; - mcode_WRDI = 0x04; - mcode_ProgramCode_4Adr = 0xFF; - mcode_ReadCode = 0xFF; + mcode_SegmentErase = SE; + + if(strstr(g_ChipInfo.Class,"_Large") == NULL) + { + mcode_Program = PAGE_PROGRAM; + mcode_Read = BULK_FAST_READ; + mcode_ProgramCode_4Adr = 0xFF; + mcode_ReadCode = 0xFF; + } + else + { + mcode_Program = PP_4ADR_256BYTE; + mcode_Read = BULK_4BYTE_FAST_READ; + mcode_ProgramCode_4Adr = (g_ChipInfo.ProgramCmd & 0x000000FF);// single program cmd + mcode_ReadCode = (g_ChipInfo.ReadCmd & 0x000000FF); // single read cmd + } if (strcmp(g_ChipInfo.Class, SUPPORT_SST_25xFxx) == 0) { mcode_RDSR = RDSR; From eb4641e408156a34511581709f2b771addc60a9d Mon Sep 17 00:00:00 2001 From: Benwang217 Date: Tue, 22 Jul 2025 15:34:35 +0800 Subject: [PATCH 25/26] Update chip database --- ChipInfoDb.dedicfg | Bin 3898332 -> 3935638 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ChipInfoDb.dedicfg b/ChipInfoDb.dedicfg index 466b3c9390204edc2bf641758676a9c44749424c..036281cbd2624c5bc317267fbc36cbe2b4164a48 100644 GIT binary patch delta 2201 zcmZ{leQZT zErksghmIK0tg{IC>F5U@Lr^ibH6i2-)O98+j7_vM&~9V`&Ft%s!B(@ejg^Y+fVXPW zv_F2ny2tmP=e*~6&U>%@{f{L5YLTSc=RL{|a9vz87aHr^-A8u!@u&KP?NOxWxg<0d5V~&vkN*oEOc%6KbIJsqN_Q5f0Ph$Lixm<>j_< ztssXTeqkHeLKi%u`5Ku_J)xz_cEv-GU8tMJ)xFAMWLg9ll$Vq}#D}xznj2L?&d2#M zc3xTpd0?p?MSp{Y@b}e5#CnK`7ebo4e?N294WLu3c3hB7K? zg%Gz4&BuJp)g9a*GjSbiu2%Hm!)%2{J;H70o@FD;Y{nOnI8o)G#Vfqb&-_(aL1=zD z;39}LmLEm-_idr{Ux=vg;-2F+avL$+78*ouOz${Qc(|+^b9^K6VWEz#?a~&q6w0?H zk^by?$3K(kF6!_eMp z2aRmC@cd*>6$bO-eHz~yD6-{zugnAe9IwT#akB}TL%MGwrV$+K0N2Wem^UH#EXhdgqihdIZI+PJ}7%SCCk%c47Zg_3X@g#iBxHx&Jb>Z|dC04yr}c zfn{q$4JZt%J4wfZ1&-F_&{{P^!2 z4aR>cg%Go7B~0y8hmuBF$Iw%wY}njFi*d4&K<=t8Lv+-<81WIl?LdSbk;rj=2$?UL z2cYyCQi6{QV|dGw+EO5LR)ZG4HHHGB*U1hV*)C1+@ZK=KOLG@1-X@6OmJ7&_7$nGR zjpH=iYk2x{>5O;Q%SvgE*jHsOv$=VV;l}5)i2q|${9Vb7=s#2<Fn%1|n7U`|^~2$b8-GS;G3P;%B;Pmnq8bkoG3GfL8**t)2E$GL+?vDdT#g{k^H zluc^w!=R+k*;m4}!s%wyi-Mo)z^0#?S{|rM#1Hbfg{{eL1t-JBXkfS*jdWYVbE^_{ zpV{h=O-dGI?s;T%RV`pCx#GD`Qv(J!lbd!IX9k5qpsW(umYys#L2fo^;Cao! z#@;bIkZE^{$p6wK!E(*!fV`QtiHEmuj@tss*gX%UiQ#25Gkgp`jok~(xMBQIvZe0^ z?4%zxqpIb|?eyhoan?G;(|B)qhINnB{0-R9RX>45M?*VOV^)zJA@aJ-jQ&ZB9&Js* z6#IMxG5kqj72Xh<+G&L&cq@hYkE-m5AMz{e)$9xJZL8LEIp@~Ww>95vf!OIC>@cf?LWtBnG-O58As8}Q z^3lV?%IFVCAQ2=HVVV689r73wGCVvytkoeph{Y}%bcp^x_&r%_vihH2tUBCrS1L+3 zr0dd6DKAaWne!%_Hy!Jy^ImRo+2+_Bca|1}vG1fDjr~LAr=X2?aeNMPd>A*s%7qs~ zwpwT_Jxtr^5tOa=59^?~om{M#9kdfyOjj|pX#4!I`9|$o(_LW(Wj}9&<;Q9Wrf#z# z*zougP`l=sgzuVr99JK>{%(s}UZHM!lzM0v^->>IsUK_kz^#6)E(JbMgR&OjF#9oJ z;3F2C>=PrYAU#Hp(-SmAPg0F`(=a_ndvGKbsb}EgT;!4{79v Date: Wed, 26 Nov 2025 09:20:14 +0800 Subject: [PATCH 26/26] 1. Update chip database 2. Fix -d issue and modify strTypeName[1024] to g_strTypeName[64] --- ChipInfoDb.dedicfg | Bin 3935638 -> 3981024 bytes dpcmd.c | 45 +++++++++++++++++++++++---------------------- project.c | 7 +++++-- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/ChipInfoDb.dedicfg b/ChipInfoDb.dedicfg index 036281cbd2624c5bc317267fbc36cbe2b4164a48..984067165dfb071db8a6c1bc5109a7e878de460c 100644 GIT binary patch delta 2571 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 Z=Zh)GxH)W6<&hjCCs7XYh*AFf<{z(?&42&^ diff --git a/dpcmd.c b/dpcmd.c index 7080548..8e452b7 100644 --- a/dpcmd.c +++ b/dpcmd.c @@ -45,7 +45,7 @@ unsigned int g_uiDevNum = 0; unsigned int g_uiDeviceID = 0; unsigned int g_IO1Select = 0; unsigned int g_IO4Select = 1; -char strTypeName[1024] = "\0"; +char g_strTypeName[64] = "\0"; bool g_bEnableVpp = false; int g_StartupMode = STARTUP_APPLI_SF_1; @@ -906,11 +906,11 @@ int main(int argc, char* argv[]) } int dwUID = ReadUID(g_uiDevNum - 1); if (is_SF700_Or_SF600PG2(g_uiDevNum - 1)) { - if (g_bIsSF700[g_uiDevNum - 1] == true) { + if (g_bIsSF700[g_uiDevNum - 1] == true) { printf("\nDevice %d (SF7%05d):\tdetecting chip\n", g_uiDevNum, dwUID); } else if (g_bIsSF600PG2[g_uiDevNum - 1] == true) { printf("\nDevice %d (S6B%05d):\tdetecting chip\n", g_uiDevNum, dwUID); - } + } } else if ((g_bIsSF600[g_uiDevNum - 1] == true) && (dwUID / 600000) > 0) { printf("\nDevice %d (SF%06d):\tdetecting chip\n", g_uiDevNum, dwUID); } else if ((dwUID / 100000) > 0) { @@ -919,10 +919,10 @@ int main(int argc, char* argv[]) printf("\nDevice %d (DP%06d):\tdetecting chip\n", g_uiDevNum, dwUID); } WriteLog(iExitCode, true); - g_ChipInfo = GetFirstDetectionMatch(strTypeName, g_uiDevNum - 1); + g_ChipInfo = GetFirstDetectionMatch(g_strTypeName, g_uiDevNum - 1); if (g_ChipInfo.UniqueID != 0) { - if (strlen(strTypeName)) { - printf("By reading the chip ID, the chip applies to [ %s ]\n\n", strTypeName); + if (strlen(g_strTypeName)) { + printf("By reading the chip ID, the chip applies to [ %s ]\n\n", g_strTypeName); printf("%s chip size is %zd bytes.\n", g_ChipInfo.TypeName, g_ChipInfo.ChipSizeInByte); } else { printf("%s", msg_err_identifychip); @@ -951,10 +951,11 @@ int main(int argc, char* argv[]) printf("\nDevice %d (DP%06d):\tdetecting chip\n", i + 1, dwUID); } WriteLog(iExitCode, true); - g_ChipInfo = GetFirstDetectionMatch(strTypeName, i); + g_ChipInfo = GetFirstDetectionMatch(g_strTypeName, i); + printf("type = %s\n\r",g_ChipInfo.ICType); if (g_ChipInfo.UniqueID != 0) { - if (strlen(strTypeName)) { - printf("By reading the chip ID, the chip applies to [ %s ]\n", strTypeName); + if (strlen(g_ChipInfo.TypeName/* g_strTypeName*/)) { + printf("By reading the chip ID, the chip applies to [ %s ]\n", g_strTypeName); printf("%s chip size is %zd bytes.\n", g_ChipInfo.TypeName, g_ChipInfo.ChipSizeInByte); } else { printf("%s", msg_err_identifychip); @@ -969,12 +970,12 @@ int main(int argc, char* argv[]) } else if (g_uiDevNum != 0) { WriteLog(iExitCode, true); printf("%d,\tdetecting chip\n", g_uiDevNum); - g_ChipInfo = GetFirstDetectionMatch(strTypeName, g_uiDevNum - 1); + g_ChipInfo = GetFirstDetectionMatch(g_strTypeName, g_uiDevNum - 1); if (g_ChipInfo.UniqueID != 0) { - //printf("strlen(strTypeName)=%ld\n",strlen(strTypeName)); - if (strlen(strTypeName)) { - printf(" \tBy reading the chip ID, the chip applies to [ %s ]\n\n", strTypeName); + //printf("strlen(g_strTypeName)=%ld\n",strlen(g_strTypeName)); + if (strlen(g_strTypeName)) { + printf(" \tBy reading the chip ID, the chip applies to [ %s ]\n\n", g_strTypeName); printf(" \t%s chip size is %zd bytes.\n", g_ChipInfo.TypeName, g_ChipInfo.ChipSizeInByte); } else { printf("%s", msg_err_identifychip); @@ -1446,7 +1447,7 @@ bool InitProject(void) { //printf("bool InitProject(void)\n"); int dev_cnt = get_usb_dev_cnt(); -if (Is_usbworking(0) == true) { + if (Is_usbworking(0) == true) { // if (Is_usbworking(g_uiDevNum-1)) { int targets[4] = { STARTUP_APPLI_CARD, @@ -1462,7 +1463,7 @@ if (Is_usbworking(0) == true) { SetSPIIOMode(i); SetSPIClock(i); SetVcc(i); - SetVppVoltage(0,i); + SetVppVoltage(0,i); if (strlen(g_parameter_type) > 0) { if (Dedi_Search_Chip_Db_ByTypeName(g_parameter_type, &g_ChipInfo)) { @@ -1482,11 +1483,11 @@ if (Is_usbworking(0) == true) { } } else if (g_uiDevNum <= dev_cnt) { g_StartupMode = targets[g_ucTarget]; - SetTargetFlash((unsigned char)targets[g_ucTarget], g_uiDevNum - 1); - SetSPIIOMode(g_uiDevNum - 1); + SetTargetFlash((unsigned char)targets[g_ucTarget], g_uiDevNum - 1); + SetSPIIOMode(g_uiDevNum - 1); SetSPIClock(g_uiDevNum - 1); SetVcc(g_uiDevNum - 1); - SetVppVoltage(0,g_uiDevNum - 1); + SetVppVoltage(0,g_uiDevNum - 1); if (strlen(g_parameter_type) > 0) { if (Dedi_Search_Chip_Db_ByTypeName(g_parameter_type, &g_ChipInfo)) { @@ -1502,7 +1503,7 @@ if (Is_usbworking(0) == true) { ProjectInit(g_uiDevNum - 1); } } else - printf("Error: Did not find the programmer.\n"); + printf("Error: Did not find the programmer.\n"); return true; } @@ -1520,7 +1521,7 @@ void CloseProject(void) bool DetectChip(void) { int dev_cnt = get_usb_dev_cnt(); - g_ChipInfo = GetFirstDetectionMatch(strTypeName, 0); + g_ChipInfo = GetFirstDetectionMatch(g_strTypeName, ((g_uiDevNum>0)? (g_uiDevNum-1):0)); if (g_uiDevNum == 0) { for (int i = 0; i < dev_cnt; i++) { if (!Is_usbworking(i)) { @@ -1531,7 +1532,7 @@ bool DetectChip(void) printf("%s", msg_err_identifychip); return false; } - printf("By reading the chip ID, the chip applies to [ %s ]\n\n", strTypeName); + printf("By reading the chip ID, the chip applies to [ %s ]\n\n", g_strTypeName); printf("%s parameters to be applied by default\n", g_ChipInfo.TypeName); printf("%s chip size is %zd bytes.\n\n", g_ChipInfo.TypeName, g_ChipInfo.ChipSizeInByte); @@ -2475,7 +2476,7 @@ int FlashIdentifier(CHIP_INFO* Chip_Info, int search_all, int Index) UniqueID = flash_ReadId(0x9f, 3, Index); if (UniqueID != 0) { rc = Dedi_Search_Chip_Db(TypeName, 0x9f, UniqueID, Chip_Info, search_all); - strcpy(strTypeName, TypeName); + strcpy(g_strTypeName, TypeName); if (rc && (search_all == 0)) { if (c == 1) isSendFFsequence = true; diff --git a/project.c b/project.c index 6515e1b..148d0bc 100755 --- a/project.c +++ b/project.c @@ -58,7 +58,7 @@ extern unsigned int g_uiAddr; extern size_t g_uiLen; extern bool g_bEnableVpp; extern unsigned int g_uiDevNum; -extern char strTypeName[1024]; +extern char g_strTypeName[64]; extern bool g_bIsNANDFlash; extern bool g_bSpareAreaUseFile; extern struct CNANDContext g_NANDContext; @@ -1484,7 +1484,10 @@ CHIP_INFO GetFirstDetectionMatch(char* TypeName, int Index) if (Found == 0) { binfo.UniqueID = 0; binfo.TypeName[0] = '\0'; + TypeName[0] = '\0'; } + else + memcpy(TypeName,binfo.TypeName, sizeof(binfo.TypeName)); return binfo; //*TypeName; } @@ -1798,7 +1801,7 @@ bool ProjectInitWithID(CHIP_INFO chipinfo, int Index) // by designated ID bool ProjectInit(int Index) // by designated ID { - g_ChipInfo = GetFirstDetectionMatch(strTypeName, Index); + g_ChipInfo = GetFirstDetectionMatch(g_strTypeName, Index); if (g_ChipInfo.UniqueID == 0) { return false; }