boolean OTAUpdateClass::parseUpdateMD5(String* vxp_name, String* vxp_digest) {
    LFlash.begin();
    LFile update_md5 = LFlash.open(UPDATE_MD5);
    if(!update_md5) {
        DEBUG_UPDATE("OTAUpdate::parseUpdateMD5 - could not open %s\r\n", UPDATE_MD5);
        return false;
    }

    String line = "";
    while(update_md5.available()) {
        line += (char) update_md5.read();
    }
    update_md5.close();
    line.trim();

    // Warning : buffer line contain HTTP header !
    // should look for vxp name and md5 from the end of buffer

    // look for index of last word (md5 name file)
    int idx = line.lastIndexOf(" ");
    // get md4 name file from index until end of buffer
    *vxp_name = line.substring(idx);
    // get md5 from index and index - 32 bytes (lenght of md5 is constant)
    *vxp_digest = line.substring(idx - 33, idx - 1);

    vxp_name->trim();
    vxp_digest->trim();

    DEBUG_UPDATE("OTAUpdate::parseUpdateMD5 - %s [%s]\r\n", vxp_name->c_str(), vxp_digest->c_str());
    return true;
}
boolean OTAUpdateClass::copyFile(const char* src, const char* dst) {
    char buffer[DIGEST_SIZE_BUFFER];

    LFlash.begin();
    LFile fsrc = LFlash.open(src, FILE_READ);
    if(!fsrc) {
        DEBUG_UPDATE("OTAUpdate::copyFile - error opening src %s\r\n", src);
        return false;
    }
    LFile fdst = LFlash.open(dst, FILE_WRITE);
    if(!fsrc) {
        fsrc.close();
        DEBUG_UPDATE("OTAUpdate::copyFile - error opening dst %s\r\n", dst);
        return false;
    }

    fdst.seek(0);
    int size = fsrc.size();
    int done = 0;
    while(done < size) {
        int read = fsrc.read(buffer, DIGEST_SIZE_BUFFER);
        fdst.write(buffer, read);
        done += read;
    }
    fsrc.close();
    fdst.close();

    return true;
}
Beispiel #3
0
boolean OTAUpdateClass::parseUpdateMD5(String* vxp_name, String* vxp_digest) {
	LFlash.begin();
	LFile update_md5 = LFlash.open(UPDATE_MD5);
	if(!update_md5) {
		DEBUG_UPDATE("OTAUpdate::parseUpdateMD5 - could not open %s\r\n", UPDATE_MD5);
		return false;
	}

	String line = "";
	while(update_md5.available()) {		
		line += (char) update_md5.read();
	}
	update_md5.close();
	line.trim();
	
	int idx = line.indexOf(" ");
	*vxp_digest = line.substring(0, idx);	
	*vxp_name = line.substring(idx + 1);
	
	vxp_name->trim();
	vxp_digest->trim();
	
	DEBUG_UPDATE("OTAUpdate::parseUpdateMD5 - %s [%s]\r\n", vxp_name->c_str(), vxp_digest->c_str());
	return true;
}
boolean OTAUpdateClass::checkUpdate(void) {
    String vxp_name, vxp_digest;

    if(!downloadFile(UPDATE_MD5)) {
        return false;
    }

    if(!parseUpdateMD5(&vxp_name, &vxp_digest)) {
        return false;
    }

    if(checkMD5(this->firmware_name, vxp_digest.c_str())) {
        DEBUG_UPDATE("found no new firmware!\r\n");
        return false;
    }

    DEBUG_UPDATE("found a new firmware %s [%s]!\r\n", vxp_name.c_str(), vxp_digest.c_str());
    if(!downloadFile(UPDATE_VXP)) {
        return false;
    }

    if(!checkMD5("C:\\" UPDATE_VXP, vxp_digest.c_str())) {
        DEBUG_UPDATE("new firmware has a wrong md5sum!\r\n");
        return false;
    }

    DEBUG_UPDATE("new firmware is ok!\r\n");
    return true;
}
s32 init_update_proc(struct goodix_ts_data *ts)
{
    u8 flag = 0;
    struct task_struct *thread = NULL;
    s32 retry = 0;

    DEBUG_MSG("Ready to run update thread.\n");

    update_msg.fw_flag = get_ic_fw_msg(ts);
    if (fail == update_msg.fw_flag)
    {
        DEBUG_UPDATE("Try get ic msg in update mode.\n");
        for (retry = 0; retry < 5; retry++)
        {
            if (success == guitar_update_mode(ts))
            {
                break;
            }
        }
        if (retry >= 5)
        {
            update_msg.fw_flag = fail;
        }
        else
        {
            DEBUG_UPDATE("Get ic msg in update mode.\n");
            update_msg.fw_flag = get_ic_fw_msg(ts);
            update_msg.ic_fw_msg.version = 0xfff0;
            if (update_msg.force_update == 0xAA)
            {
                flag = 0xff;
            }
        }
        guitar_leave_update_mode();
    }
    else
    {
        guitar_reset(10);
    }

    if (success == update_msg.fw_flag)
    {
        update_msg.gt_loc = -1;
        thread = kthread_run(guitar_update_proc, (void*)ts, "guitar_update");
        if (IS_ERR(thread))
        {
            dev_err(&ts->client->dev, " failed to create update thread\n");
        }
        if (0xff == flag)
        {
            return 0xff;
        }
    }

    return success;
}
static u8 clear_mix_flag(struct goodix_ts_data *ts)
{
    s32 i = 0;
    u8 buf[3];
    
    buf[0] = 0x14;
    buf[1] = 0x00;
    buf[2] = 0x80;
    
    for (i = 0; i < 5; i++)
    {
        if (i2c_write_bytes(ts->client, buf, 3) > 0)
        {
            break;
        }
    }
    i2c_end_cmd(ts);

    if (i >= 5)
    {
        DEBUG_UPDATE("Clear mix flag failed!\n");
        return fail;
    }

    return success;
}
Beispiel #7
0
boolean OTAUpdateClass::downloadFile(const char* name) {
	// make some http requests to check for firmware updates
	LGPRSClient c;
	uint8_t buffer[DIGEST_SIZE_BUFFER];
	int n , size, max_millis;
	
	// download the firmware
	if(!c.connect(this->host, 80)) {
		DEBUG_UPDATE("OTAUpdate::downloadFile - error connecting to update host\r\n");
		return false;
	}
	// connected... send the get request
	DEBUG_UPDATE("OTAUpdate::downloadFile %s:80 'GET /%s/%s'\r\n", this->host, this->path, &name[4]);
	c.printf("GET /%s/%s\n", this->path, &name[4]);

	// save the result
	max_millis = millis() + 10000;
	LFlash.begin();
	LFlash.remove((char*) name);
	
	LFile ota = LFlash.open(name, FILE_WRITE);
	ota.seek(0);
	size = 0;
	
	while(c.connected()) {
		int n = c.read(buffer, 1024);
		if(n > 0) {
			max_millis = millis() + 2000;
			ota.write(buffer, n);
			size += n;
		} else {
			if(millis() > max_millis) {
				DEBUG_UPDATE("OTAUpdate::downloadFile - timed out!\r\n");
				c.stop();
				ota.close();
				return false;
			} else {
				delay(100);
			}
		}		
	}
	c.stop();
	ota.close();
	
	DEBUG_UPDATE("OTAUpdate::downloadFile - done! got %d bytes\r\n", size);
	return size > 0;
}
boolean OTAUpdateClass::checkMD5(const char* name, const char* hash) {
    char local_hash[DIGEST_SIZE_CHAR];
    DEBUG_UPDATE("OTAUpdate::checkMD5 - %s %s\r\n", name, hash);

    // calculate the md5 sum of the new firmware
    if(!md5sum(name, local_hash)) {
        DEBUG_UPDATE("OTAUpdate::checkMD5 - error calculating md5sum!\r\n");
        return false;
    }

    // check if the md5sum of the firmware matches
    if(strcmp(hash, local_hash) != 0) {
        DEBUG_UPDATE("OTAUpdate::checkMD5 - error md5sum mismatch!\r\n");
        return false;
    }

    DEBUG_UPDATE("OTAUpdate::checkMD5 - OK\r\n");
    return true;
}
boolean OTAUpdateClass::startFirmware(const char* name) {
    DEBUG_UPDATE("OTAUpdate::startFirmware - %s\r\n", name);

    // update autostart.txt for the new firmware
    LFlash.begin();
    LFile dst = LFlash.open("autostart.txt", FILE_WRITE);
    if(!dst) {
        DEBUG_UPDATE("OTAUpdate::performUpdate - error opening autostart.txt\r\n");
        return false;
    }

    dst.seek(0);
    dst.printf("[autostart]\r\nApp=%s\r\n", name);
    dst.close();

    // reset the board
    reset();
    return true;
}
boolean OTAUpdateClass::startUpdate(void) {
    String vxp_name, vxp_digest;

    // check if all required files exist
    if(!LFlash.exists((char*)OTA_FW) || !LFlash.exists((char*)UPDATE_MD5) || !LFlash.exists((char*)UPDATE_VXP)) {
        DEBUG_UPDATE("OTAUpdate::startUpdate - not all required files found\r\n");
        return false;
    }

    // check if the update files are ok
    if(!checkUpdateFiles(&vxp_name, &vxp_digest)) {
        DEBUG_UPDATE("OTAUpdate::startUpdate - check files failed\r\n");
        return false;
    }

    // if yes, start the OTA FW upgrade
    DEBUG_UPDATE("OTAUpdate::startUpdate - updating to firmware %s [%s]\r\n", vxp_name.c_str(), vxp_digest.c_str());
    return startFirmware("C:\\" OTA_FW);
}
/*
* Steps of reset guitar
*1. INT脚输出低,延时5ms
*2. RESET脚拉低100ms,转输入悬浮态
*3. I2C寻址GUITAR
*4. 延时100ms读取0xff(3、4轮询80次,直至成功)
*5. Oxff等于0x55则返回成功,否则失败
*/
static int guitar_update_mode( struct goodix_ts_data *ts )
{
    int ret = 1;
    u8 retry;
    unsigned char inbuf[3] = {0,0xff,0};

    // step 1
    GPIO_DIRECTION_OUTPUT(INT_PORT, 0);
    GPIO_SET_VALUE(INT_PORT, 0);
    msleep(5);

    //step 2
    guitar_reset(100);

    for(retry=0;retry < 80; retry++)
    {
        //step 3
        ret =i2c_write_bytes(ts->client, inbuf, 0);    //Test I2C connection.
        if (ret > 0)
        {
            DEBUG_UPDATE("<Set update mode>I2C is OK!\n");
            //step 4
            msleep(100);
            ret =i2c_read_bytes(ts->client, inbuf, 3);
            if (ret > 0)
            {
                DEBUG_UPDATE("The value of 0x00ff is 0x%02x\n", inbuf[2]);
                //step 5
                if(inbuf[2] == 0x55)
                {
                    return success;
                }
            }
        }
        msleep(10);
    }
    DEBUG_UPDATE(KERN_INFO"Detect address %0X\n", ts->client->addr);

    return fail;
}
static u8 get_ic_msg(struct goodix_ts_data *ts, u16 addr, u8* msg, s32 len)
{
    s32 i = 0;

    msg[0] = addr >> 8 & 0xff;
    msg[1] = addr & 0xff;

    for (i = 0; i < 5; i++)
    {
        if (i2c_read_bytes(ts->client, msg, ADDR_LENGTH + len) > 0)
        {
            break;
        }
    }
    i2c_end_cmd(ts);

    if (i >= 5)
    {
        DEBUG_UPDATE("Read data from 0x%02x%02x failed!\n", msg[0], msg[1]);
        return fail;
    }

    return success;
}
static u8 guitar_update_firmware(struct goodix_ts_data *ts, st_fw_head* fw_head, u8 *nvram)
{
    int retry;
    int ret;
    u32 status = 0;
    u8 buf[32];

    //Cuts the frequency
    buf[0] = 0x15;
    buf[1] = 0x22;
    buf[2] = 0x18;
    ret =  i2c_write_bytes(ts->client, buf, 3);
    if (ret <= 0)
    {
        return fail;
    }

    get_ic_msg(ts, 0x1522, buf, 1);
    DEBUG_UPDATE("IC OSC_CAL:0x%02x.\n", buf[2]);

    for (retry = 0; retry < 10; retry++)
    {
        //Write the 1st part (pid and vid)
  /*      if (!(status & 0x01))
        {
            buf[0] = UPDATE_FW_MSG_ADDR_H;
            buf[1] = UPDATE_FW_MSG_ADDR_L;
            buf[2] = fw_head->type;
            buf[3] = fw_head->version >> 8;
            buf[4] = fw_head->version & 0xff;
            ret = i2c_write_bytes(ts->client, buf, 5);
            if (ret <= 0)
            {
                continue;
            }
            else
            {
                DEBUG_UPDATE("Update pid and vid successfully!\n");
                status |= 0x01;
                msleep(1);
            }
        }
*/
        //Write the 2nd part (nvram)
        if (!(status & 0x02))
        {
            if (fail == guitar_update_nvram(ts, fw_head, nvram))
            {
                continue;
            }
            else
            {
                DEBUG_UPDATE("Update nvram successfully!\n");
                status |= 0x02;
                msleep(1);
            }
        }

        //Write the 3rd part (check sum)
        if (1)
        {
            buf[0] = 0x4f;
            buf[1] = 0xf3;
            memcpy(&buf[2], fw_head->chk_sum, sizeof(fw_head->chk_sum));
            ret = i2c_write_bytes(ts->client, buf, 5);
            if (ret <= 0)
            {
                continue;
            }
            else
            {
                DEBUG_UPDATE("Update check sum successfully!\n");
                break;
            }
        }
    }

    if (retry >= 10)
    {
        return fail;
    }
    else
    {
        for (retry = 0; retry < 10; retry++)
        {
            buf[0] = 0x00;
            buf[1] = 0xff;
            buf[2] = 0x44;
            ret = i2c_write_bytes(ts->client, buf, 3);
            if (ret > 0)
            {
                break;
            }
        }

        if (retry >= 10)
        {
            DEBUG_UPDATE("Write address at 0x00ff error!\n");
            return fail;
        }
        msleep(10);
    }

    for (retry = 0; retry < 30; retry++)
    {
        msleep(1);
        if (fail == get_ic_msg(ts, 0x00ff, buf, 1))
        {
            DEBUG_UPDATE("Read address at 0x00ff error!\t retry:%d\n", retry);
            continue;
        }

        if (0xcc == buf[ADDR_LENGTH])
        {
            return success;
        }
        else
        {
            DEBUG_UPDATE("The value of 0x00ff: 0x%02x!\t retry:%d\n", buf[ADDR_LENGTH], retry);
            continue;
        }
    }

    DEBUG_UPDATE("The value of 0x00ff error.\n");
    return fail;
}
boolean OTAUpdateClass::begin(const char* host, const char* port, const char* path) {
    DEBUG_UPDATE("OTAUpdate::begin - %s %s\r\n", host, path);

    // initialize our memory structures
    this->initialized = false;
    memset(this->firmware_name, 0, OTA_MAX_PATH_LEN);
    memset(this->firmware_digest, 0, DIGEST_SIZE_CHAR);
    memset(this->host, 0, OTA_MAX_PATH_LEN);
    memset(this->path, 0, OTA_MAX_PATH_LEN);
    memset(this->port, 0, OTA_MAX_PATH_LEN);
    strncpy(this->host, host, OTA_MAX_PATH_LEN-1);
    strncpy(this->path, path, OTA_MAX_PATH_LEN-1);
    strncpy(this->port, port, OTA_MAX_PATH_LEN-1);

    // read the firmware information
    LFlash.begin();
    LFile cfg = LFlash.open("autostart.txt", FILE_READ);
    if (!cfg) {
        DEBUG_UPDATE("OTAUpdateClass::begin - could not read autostart.txt\r\n");
        return false;
    }

    DEBUG_UPDATE("OTAUpdateClass::begin - reading autostart.txt\r\n");
    while (cfg.available()) {
        String line = "";
        char c = '\n';
        // read the setting part of the line
        while (cfg.available()) {
            c = cfg.read();
            line += c;
            if(c == '\n') {
                break;
            }
        }

        // look for = in the config line
        line.trim();
        int idx = line.indexOf("=");

        if(idx >= 0) {
            String setting = line.substring(0, idx);
            String value = line.substring(idx+1);

            setting.trim();
            value.trim();

            DEBUG_UPDATE("autostart.txt: %s=%s\r\n", setting.c_str(), value.c_str());
            if(setting == "App") {
                value.toCharArray(firmware_name, OTA_MAX_PATH_LEN);
                this->initialized = true;
                break;
            }
        }
    }
    cfg.close();

    if(this->initialized) {
        // we found the app name... calculate the md5 sum
        md5sum(this->firmware_name, this->firmware_digest);
        DEBUG_UPDATE("OTAUpdate::begin - %s [%s]\r\n", this->firmware_name, this->firmware_digest);
    } else {
        DEBUG_UPDATE("OTAUpdate::begin - could not find firmware name\r\n");
        return false;
    }

    return true;
}
static u8 get_ic_fw_msg(struct goodix_ts_data *ts)
{
    s32 ret = 0;
    s32 i = 0;
    u8 buf[32];
    
    if (fail == clear_mix_flag(ts))
    {
        return fail;
    }
    
    //Get the mask version in rom of IC
    if (fail == get_ic_msg(ts, READ_MSK_VER_ADDR_H << 8 | READ_MSK_VER_ADDR_L, buf, 4))
    {
        DEBUG_UPDATE("Read mask version failed!\n");
        return fail;
    }
    
    memcpy(update_msg.ic_fw_msg.msk_ver, &buf[ADDR_LENGTH], 4);
    DEBUG_UPDATE("IC The mask version in rom is %c%c%c%c.\n",
                 update_msg.ic_fw_msg.msk_ver[0],update_msg.ic_fw_msg.msk_ver[1],
                 update_msg.ic_fw_msg.msk_ver[2],update_msg.ic_fw_msg.msk_ver[3]);

#if 1
    //Get the firmware msg in IC, include firmware version and checksum flag
    for (i = 0; i < 2; i++)
    {
        if (fail == get_ic_msg(ts, READ_FW_MSG_ADDR_H<< 8 | READ_FW_MSG_ADDR_L, buf, 4))
        {
            DEBUG_UPDATE("Get firmware msg in IC error.\n");
            return fail;
        }
        update_msg.force_update = buf[ADDR_LENGTH];
        if (i == 0 && update_msg.force_update == 0xAA)
        {
            DEBUG_UPDATE("The check sum in ic is error.\n");
            DEBUG_UPDATE("IC will be reset.\n");
            DEBUG_UPDATE("If the check sum is still error,\n ");
            DEBUG_UPDATE("The IC will be updated by force.\n");

            guitar_reset(10);
            continue;
            //msleep(100);
        }
        break;
    }
    //ic_fw_msg.type = buf[ADDR_LENGTH + 1];
    update_msg.ic_fw_msg.version = buf[ADDR_LENGTH + 2] << 8 | buf[ADDR_LENGTH + 3];
    DEBUG_UPDATE("IC VID:0x%x\n", (int)update_msg.ic_fw_msg.version);
    DEBUG_UPDATE("IC force update:%x\n", update_msg.force_update);
#endif

    //Cuts the frequency
    buf[0] = 0x15;
    buf[1] = 0x22;
    buf[2] = 0x18;
    ret =  i2c_write_bytes(ts->client, buf, 3);
    if (ret <= 0)
    {
        return fail;
    }
    i2c_end_cmd(ts);
    
    //Get the pid at 0x4011 in nvram
    if (fail == get_ic_msg(ts, 0x4011, buf, 1))
    {
        DEBUG_UPDATE("Read pid failed!\n");
        return fail;
    }
    update_msg.ic_fw_msg.type = buf[ADDR_LENGTH];
    
    DEBUG_UPDATE("IC PID:%x\n", update_msg.ic_fw_msg.type);

//    guitar_reset(10);
    return success;
}
boolean OTAUpdateClass::downloadFile(const char* name) {
    // make some http requests to check for firmware updates
    LGPRSClient c;
    uint8_t buffer[DIGEST_SIZE_BUFFER];
    int n , size, max_millis;
    char buff[256];
    static char endofheader[5] ;
    boolean HTTPHeaderreached = false;
    char byc;

    //convert string to int
    String sthostport = this->port;
    unsigned int uinthostport = sthostport.toInt();

    // download the firmware
    if(!c.connect(this->host, uinthostport)) {
        DEBUG_UPDATE("OTAUpdate::downloadFile - error connecting to update host\r\n");
        return false;
    }
    // connected... send the get request
    DEBUG_UPDATE("OTAUpdate::downloadFile %s:%d 'GET /%s/%s'\r\n", this->host, uinthostport, this->path, &name[4]);

    sprintf(buff, "GET /%s/%s", this->path, &name[4]);
    c.print(buff);
    //c.printf("GET /%s/%s", this->path, &name[4]);
    c.println(" HTTP/1.1");
    c.print("Host: ");
    c.println(this->host);
    c.println("Connection: close");
    c.println();

    // save the result
    max_millis = millis() + 10000;
    LFlash.begin();
    LFlash.remove((char*) name);

    LFile ota = LFlash.open(name, FILE_WRITE);
    ota.seek(0);
    size = 0;

    // get data content of the file
    while(c.connected()) {
        //skip byte until end of HTTP Header
        if(HTTPHeaderreached == false) {
            // read byte
            byc = c.read();
            if(byc > 0) {
                max_millis = millis() + 2000;
                // if HTTP header is not reached, read until find double CRLF
                Serial.print(byc);

                // proceed a right shift of the  array
                for(int i = 0; i < 3; i++) {
                    endofheader[i] =  endofheader[i+1];
                }
                // add last received char at the end of the array
                endofheader[3] = byc;
                //don't forget null caracter
                endofheader[4] = '\0';
                // compare array with end of HTTP header key (double CRLF)
                if (strcmp("\r\n\r\n", endofheader ) == 0) {
                    // return true
                    DEBUG_UPDATE("OTAUpdate::downloadFile - end of HTTP header reached\r\n");
                    HTTPHeaderreached = true;
                }
                else {
                    HTTPHeaderreached = false;
                }
            }
            else {
                if(millis() > max_millis) {
                    DEBUG_UPDATE("OTAUpdate::downloadFile - timed out!\r\n");
                    c.stop();
                    ota.close();
                    return false;
                } else {
                    delay(100);
                }
            }
        }
        else {
            int n = c.read(buffer, 1024);
            if(n > 0) {
                max_millis = millis() + 2000;
                ota.write(buffer, n);
                size += n;
                DEBUG_UPDATE("size = %d\r", size);
            } else {
                if(millis() > max_millis) {
                    DEBUG_UPDATE("OTAUpdate::downloadFile - timed out!\r\n");
                    c.stop();
                    ota.close();
                    return false;
                } else {
                    delay(100);
                }
            }
        }
    }
    c.stop();
    ota.close();

    DEBUG_UPDATE("\r\nOTAUpdate::downloadFile - done! got %d bytes\r\n", size);
    return size > 0;
}
static int guitar_update_proc(void *v_ts)
{
    s32 ret;
    u32 retry = 100;
    u32 i = 0;
    struct goodix_ts_data* ts = NULL;
    u8* data = NULL;
    u8* ic_nvram = NULL;
    st_fw_head fw_head;
    u8 buf[32];

    ts = (struct goodix_ts_data*)v_ts;
    data = kzalloc(UPDATE_DATA_LENGTH, GFP_KERNEL);
    if (NULL == data)
    {
        DEBUG_UPDATE("data failed apply for memory.\n");
        return fail;
    }
    
    ic_nvram = kzalloc(UPDATE_DATA_LENGTH, GFP_KERNEL);
    if (NULL == ic_nvram)
    {
        DEBUG_UPDATE("ic_nvram failed apply for memory.\n");
        goto app_mem_failed;
    }
    DEBUG_UPDATE("Apply for memory successfully.memory size: %d.\n", UPDATE_DATA_LENGTH);

    msleep(1000);
    DEBUG_UPDATE("Updating...\n");

    if (fail == load_update_file(ts, &fw_head, &data[2], NULL))
    {
        DEBUG_UPDATE("Load file data failed!\n");
        goto load_failed;
    }
    DEBUG_UPDATE("Load file data successfully!\n");

    if (ts->use_irq)
    {
        if(!ts->irq_is_disable)
        {
            disable_irq(ts->client->irq);
        }
        ts->irq_is_disable = 2;
    }

    for (i = 0; i < 5; i++)
    {
        if (fail == guitar_update_mode(ts))
        {
            DEBUG_UPDATE("Next try![Enter update mode]\n");
            continue;
        }
        else
        {
            DEBUG_UPDATE("Set update mode successfully.\n");
            break;
        }
    }
    if (i >= 5)
    {
        DEBUG_UPDATE("Set update mode failed.\n");
        return fail;
    }
    
    retry = 0;
    while(retry++ < 5)
    {
        if (fail == guitar_update_firmware(ts, &fw_head, &data[2]))
        {
            DEBUG_UPDATE("Update firmware failed.\n");
            continue;
        }
        DEBUG_UPDATE("Update firmware successfully.\n");

        //while(1)  // simulation store operation failed
        if (fail == guitar_nvram_store(ts))
        {
            DEBUG_UPDATE("Store nvram failed.\n");
            continue;
        }

        msleep(100);

        if (fail == get_ic_msg(ts, 0x1201, buf, 1))
        {
            DEBUG_UPDATE("Read NVRCS failed.(Store)\n");
            continue;
        }
        if (buf[ADDR_LENGTH] & 0x01)
        {
            DEBUG_UPDATE("Check NVRCS(0x%02x) failed.(Store)\n", buf[ADDR_LENGTH]);
            continue;
        }

        DEBUG_UPDATE("Store nvram successfully.\n");

        if (fail == guitar_nvram_recall(ts))
        {
            DEBUG_UPDATE("Recall nvram failed.\n");
            continue;
        }
        msleep(5);
        
        if (fail == get_ic_msg(ts, 0x1201, buf, 1))
        {
            DEBUG_UPDATE("Read NVRCS failed.(Recall)\n");
            continue;
        }
        if (buf[ADDR_LENGTH] & 0x02)
        {
            DEBUG_UPDATE("Check NVRCS(0x%02x) failed.(Recall)\n", buf[ADDR_LENGTH]);
            continue;
        }
        DEBUG_UPDATE("Recall nvram successfully.\n");

        ic_nvram[0] = fw_head.st_addr[0];
        ic_nvram[1] = fw_head.st_addr[1];

        for ( i = 0; i < 10; i++)
        {
            ret = i2c_read_bytes(ts->client, ic_nvram, ADDR_LENGTH + fw_head.lenth);
            if (ret <= 0)
            {
                continue;
            }
            break;
        }

        if (i >= 10)
        {
            DEBUG_UPDATE("Read nvram failed!\n");
            continue;
        }
        DEBUG_UPDATE("Read nvram successfully!\n");

        if (false == is_equal(&data[2], &ic_nvram[2], fw_head.lenth))
        {
            DEBUG_UPDATE("Nvram not equal!\n");
            continue;
        }
        DEBUG_UPDATE("Check nvram by byte successfully!\n");
        
        if (update_msg.gt_loc > 0)
        {
            DEBUG_UPDATE("Location:%d, Ret:%d.\n", (s32)update_msg.gt_loc, (s32)ret);
            memset(buf, 0, sizeof(buf));
            ret = update_msg.file->f_op->write(update_msg.file, buf, 6, &update_msg.gt_loc);
            if (ret < 0)
            {
                DEBUG_UPDATE("Didn't clear the focre update flag in file.\n");
            }
            else
            {
                DEBUG_UPDATE("Clear the focre update flag in file.Location:%d, Ret:%d.\n", (s32)update_msg.gt_loc, (s32)ret);
            }
        }
        DEBUG_UPDATE("Update successfully!\n");
        break;
    }
    
    set_fs(update_msg.old_fs);
    filp_close(update_msg.file, NULL);
    guitar_leave_update_mode();
    DEBUG_UPDATE("Leave update mode!\n");
    
    //Reset guitar
    DEBUG_UPDATE("Reset IC and send config!\n");
    guitar_reset(10);
    for (i = 0; i < 3; i++)
    {
        if (fail == goodix_init_panel(ts, 1))
        {
            msleep(10);
            continue;
        }
        break;
    }
    if (i >= 3)
    {
        DEBUG_UPDATE("Send config data failed.\n");
    }
    
    msleep(10);
    if (ts->use_irq)
    {
        ts->irq_is_disable = 0;
        enable_irq(ts->client->irq);
    }

load_failed:
    kfree(ic_nvram);
app_mem_failed:
    kfree(data);

    if (retry < 5)
    {
        return success;
    }

    DEBUG_UPDATE("Update failed!\n");
    return fail;    
}
static u8 guitar_update_nvram(struct goodix_ts_data *ts, st_fw_head* fw_head, u8 *nvram)
{
    int length = 0;
    int ret = 0;
    int write_bytes = 0;
    int retry = 0;
    int i = 0;
    int comp = 0;
    u16 st_addr = 0;
    u8 w_buf[PACK_SIZE + ADDR_LENGTH];
    u8 r_buf[PACK_SIZE + ADDR_LENGTH];

    if (fw_head->lenth > PACK_SIZE)
    {
        write_bytes = PACK_SIZE;
    }
    else
    {
        write_bytes = fw_head->lenth;
    }

    clear_mix_flag(ts);
    st_addr = (fw_head->st_addr[0] << 8) | (fw_head->st_addr[1]&0xff);
    memcpy(&w_buf[2], &nvram[length], write_bytes);
    DEBUG_UPDATE("Total length:%d\n", (int)fw_head->lenth);
    while(length < fw_head->lenth)
    {
        w_buf[0] = st_addr >> 8;
        w_buf[1] = st_addr & 0xff;
        DEBUG_UPDATE("Write address:0x%02x%02x\tlength:%d\n", w_buf[0], w_buf[1], write_bytes);
        ret =  i2c_write_bytes(ts->client, w_buf, ADDR_LENGTH + write_bytes);
        if (ret <= 0)
        {
            if (retry++ > 10)
            {
                DEBUG_UPDATE("Write the same address 10 times.Give up!\n");
                return fail;
            }
            DEBUG_UPDATE("Write error![guitar_update_nvram]\n");
            continue;
        }
        else
        {
//            DEBUG_UPDATE("w_buf:\n");
//            DEBUG_ARRAY(w_buf, ADDR_LENGTH + write_bytes);
/*            r_buf[0] = 0x14;
            r_buf[1] = 0x00;
            r_buf[2] = 0x80;
            i2c_write_bytes(ts->client, r_buf, 3);
            r_buf[0] = 0x14;
            r_buf[1] = 0x00;
            i2c_read_bytes(ts->client, r_buf, 3);
            DEBUG_UPDATE("I2CCS:0x%x\n", r_buf[2]);//*/
            
            r_buf[0] = w_buf[0];
            r_buf[1] = w_buf[1];

            for (i = 0; i < 10; i++)
            {
                ret = i2c_read_bytes(ts->client, r_buf, ADDR_LENGTH + write_bytes);
                if (ret <= 0)
                {
                    continue;
                }
                break;
            }
            if (i >= 10)
            {
                DEBUG_UPDATE("Read error! Can't check the nvram data.\n");
                return fail;
            }
//            DEBUG_UPDATE("r_buf:\n");
//            DEBUG_ARRAY(r_buf, ADDR_LENGTH + write_bytes);
#if 0            
            if (fail == guitar_nvram_store(ts))
            {
                DEBUG_UPDATE("Store nvram failed.\n");
                //continue;
            }
            return fail;
#endif
            if (false == is_equal(r_buf, w_buf, ADDR_LENGTH + write_bytes))
            {   
                if (comp ++ > 10)
                {
                    DEBUG_UPDATE("Compare error!\n");
                    return fail;
                }
                DEBUG_UPDATE("Updating nvram: Not equal!\n");

                DEBUG_UPDATE("r_buf:\n");
                DEBUG_ARRAY(r_buf, ADDR_LENGTH + write_bytes);

                
                DEBUG_UPDATE("w_buf:\n");
//                DEBUG_ARRAY(w_buf, ADDR_LENGTH + write_bytes);
                continue;
                //return fail;
            }
        }
        comp = 0;
        retry = 0;
        length += PACK_SIZE;
        st_addr += PACK_SIZE;
        if ((length + PACK_SIZE) > fw_head->lenth)
        {
            write_bytes = fw_head->lenth - length;
        }
        memcpy(&w_buf[2], &nvram[length], write_bytes);
    }

    return success;
}
u8 load_update_file(struct goodix_ts_data *ts, st_fw_head* fw_head, u8* data, u8* path)
{
    u8 mask_num = 0;
    int ret = 0;
    int i = 0;
    u8 buf[FW_HEAD_LENGTH];

    if (path)
    {
        update_msg.file = filp_open(path, O_RDWR, 0666);
        
        if (IS_ERR(update_msg.file))
        {
            DEBUG_UPDATE("Open update file(%s) error!\n", path);
            return fail;
        }
    }
    else
    {
        //Begin to search update file
        for (i = 0; i < SEARCH_FILE_TIMES; i++)
        {
            update_msg.file = filp_open(UPDATE_FILE_PATH_1, O_RDWR, 0666);
            if (IS_ERR(update_msg.file))
            {
                update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_RDWR, 0666);//O_RDWR
                if (IS_ERR(update_msg.file))
                {
                    DEBUG_UPDATE("%3d:Searching file...\n", i);
                    msleep(3000);
                    continue;
                }
                else
                {
                    break;
                }
            }
            else
            {
                break;
            }
        }
        if (i >= 100)
        {
            DEBUG_UPDATE("Can't find update file.\n");
            return fail;
        }
        DEBUG_UPDATE("Find the update file.\n");
    }
    
    update_msg.old_fs = get_fs();
    set_fs(KERNEL_DS);

    update_msg.file->f_pos = IGNORE_LENGTH;

    //Make sure the file is the right file.(By compare the "Guitar" flag)
    ret = update_msg.file->f_op->read(update_msg.file, (char*)&buf, 6, &update_msg.file->f_pos);
    if (ret < 0)
    {
        DEBUG_UPDATE("Read \"Guitar\" flag error.\n");
        goto load_failed;
    }
    if (false == is_equal(buf, "Guitar", 6))
    {
        DEBUG_UPDATE("The flag is %s.Not equal!\n"
                     "The update file is incorrect!\n", buf);
        goto load_failed; 
    }
    DEBUG_UPDATE("The file flag is :%s.\n", buf);
    
    //Get the total number of masks
    update_msg.file->f_pos++; //ignore one byte.
    ret = update_msg.file->f_op->read(update_msg.file, &mask_num, 1, &update_msg.file->f_pos);
    if (ret < 0)
    {
        DEBUG_UPDATE("Didn't get the mask number from the file.\n");
        goto load_failed;
    }
    DEBUG_UPDATE("FILE The total number of masks is:%d.\n", mask_num);
    update_msg.file->f_pos = FILE_HEAD_LENGTH + IGNORE_LENGTH;

    //Get the correct nvram data
    //The correct conditions: 
    //1. the product id is the same
    //2. the mask id is the same
    //3. the nvram version in update file is greater than the nvram version in ic 
    //or force update flag is marked or the check sum in ic is wrong
    update_msg.gt_loc = -1;
    for ( i = 0; i < mask_num; i++)
    {        
        ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, FW_HEAD_LENGTH, &update_msg.file->f_pos);
        if (ret < 0)
        {
            DEBUG_UPDATE("Read update file head error.\n");
            goto load_failed;
        }
        memcpy(fw_head, buf, sizeof(st_fw_head));
        fw_head->version = buf[1] << 8 | buf[2];
        fw_head->lenth = buf[9] << 8 | buf[10];
        DEBUG_UPDATE("No.%d firmware\n", i);
        DEBUG_UPDATE("FILE PID:%x\n", fw_head->type);
        DEBUG_UPDATE("FILE VID:0x%x\n", fw_head->version);
        DEBUG_UPDATE("FILE mask version:%c%c%c%c.\n", fw_head->msk_ver[0],
                     fw_head->msk_ver[1],fw_head->msk_ver[2],fw_head->msk_ver[3]);
        DEBUG_UPDATE("FILE start address:0x%02x%02x.\n", fw_head->st_addr[0], fw_head->st_addr[1]);
        DEBUG_UPDATE("FILE length:%d\n", (int)fw_head->lenth);
        DEBUG_UPDATE("FILE force update flag:%s\n", fw_head->force_update);
        DEBUG_UPDATE("FILE chksum:0x%02x%02x%02x\n", fw_head->chk_sum[0], 
                                 fw_head->chk_sum[1], fw_head->chk_sum[2]);

        //First two conditions
        if (is_equal(fw_head->msk_ver, update_msg.ic_fw_msg.msk_ver, sizeof(update_msg.ic_fw_msg.msk_ver))
            && update_msg.ic_fw_msg.type == fw_head->type)
        {
            DEBUG_UPDATE("Get the same mask version and same pid.\n");
            //The third condition
            if (fw_head->version > update_msg.ic_fw_msg.version
                || is_equal(fw_head->force_update, "GOODIX", 6) 
                || update_msg.force_update == 0xAA)
            {
               // DEBUG_UPDATE("FILE read position:%d\n", file->f_pos);
               // file->f_pos = FW_HEAD_LENGTH + FILE_HEAD_LENGTH + IGNORE_LENGTH;

                if (is_equal(fw_head->force_update, "GOODIX", 6))
                {
                    update_msg.gt_loc = update_msg.file->f_pos - FW_HEAD_LENGTH + sizeof(st_fw_head) - sizeof(fw_head->force_update);
                }
                
                ret = update_msg.file->f_op->read(update_msg.file, (char*)data, fw_head->lenth, &update_msg.file->f_pos);
                if (ret <= 0)
                {
                    DEBUG_UPDATE("Read firmware data in file error.\n");
                    goto load_failed;
                }
               // DEBUG_ARRAY(data, 512);
               // set_fs(ts->old_fs);
              //  filp_close(ts->file, NULL);
                DEBUG_UPDATE("Load data from file successfully.\n");
                return success;
            }
            DEBUG_UPDATE("Don't meet the third condition.\n");
            goto load_failed;
        }

        update_msg.file->f_pos += UPDATE_DATA_LENGTH;
    }

load_failed:    
    set_fs(update_msg.old_fs);
    filp_close(update_msg.file, NULL);
    return fail;
}