• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 Andrew Duggan
3  * Copyright (C) 2014 Synaptics Inc
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <alloca.h>
19 #include <time.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <linux/input.h>
28 #include "rmi4update.h"
29 
30 #define RMI_F34_QUERY_SIZE		7
31 #define RMI_F34_HAS_NEW_REG_MAP		(1 << 0)
32 #define RMI_F34_IS_UNLOCKED		(1 << 1)
33 #define RMI_F34_HAS_CONFIG_ID		(1 << 2)
34 #define RMI_F34_BLOCK_SIZE_OFFSET	1
35 #define RMI_F34_FW_BLOCKS_OFFSET	3
36 #define RMI_F34_CONFIG_BLOCKS_OFFSET	5
37 
38 #define RMI_F34_BLOCK_SIZE_V1_OFFSET	0
39 #define RMI_F34_FW_BLOCKS_V1_OFFSET	0
40 #define RMI_F34_CONFIG_BLOCKS_V1_OFFSET	2
41 
42 #define RMI_F34_BLOCK_DATA_OFFSET	2
43 #define RMI_F34_BLOCK_DATA_V1_OFFSET	1
44 
45 #define RMI_F34_COMMAND_MASK		0x0F
46 #define RMI_F34_STATUS_MASK		0x07
47 #define RMI_F34_STATUS_SHIFT		4
48 #define RMI_F34_ENABLED_MASK		0x80
49 
50 #define RMI_F34_COMMAND_V1_MASK		0x3F
51 #define RMI_F34_STATUS_V1_MASK		0x3F
52 #define RMI_F34_ENABLED_V1_MASK		0x80
53 
54 #define RMI_F34_WRITE_FW_BLOCK        0x02
55 #define RMI_F34_ERASE_ALL             0x03
56 #define RMI_F34_WRITE_LOCKDOWN_BLOCK  0x04
57 #define RMI_F34_WRITE_CONFIG_BLOCK    0x06
58 #define RMI_F34_ENABLE_FLASH_PROG     0x0f
59 
60 #define RMI_F34_ENABLE_WAIT_MS 300
61 #define RMI_F34_ERASE_WAIT_MS (5 * 1000)
62 #define RMI_F34_ERASE_V8_WAIT_MS (10000)
63 #define RMI_F34_IDLE_WAIT_MS 500
64 
65 /* Most recent device status event */
66 #define RMI_F01_STATUS_CODE(status)		((status) & 0x0f)
67 /* Indicates that flash programming is enabled (bootloader mode). */
68 #define RMI_F01_STATUS_BOOTLOADER(status)	(!!((status) & 0x40))
69 /* The device has lost its configuration for some reason. */
70 #define RMI_F01_STATUS_UNCONFIGURED(status)	(!!((status) & 0x80))
71 
72 /* Indicates that flash programming is enabled V7(bootloader mode). */
73 #define RMI_F01_STATUS_BOOTLOADER_v7(status) (!!((status) & 0x80))
74 
75 /*
76  * Sleep mode controls power management on the device and affects all
77  * functions of the device.
78  */
79 #define RMI_F01_CTRL0_SLEEP_MODE_MASK	0x03
80 
81 #define RMI_SLEEP_MODE_NORMAL		0x00
82 #define RMI_SLEEP_MODE_SENSOR_SLEEP	0x01
83 #define RMI_SLEEP_MODE_RESERVED0	0x02
84 #define RMI_SLEEP_MODE_RESERVED1	0x03
85 
86 /*
87  * This bit disables whatever sleep mode may be selected by the sleep_mode
88  * field and forces the device to run at full power without sleeping.
89  */
90 #define RMI_F01_CRTL0_NOSLEEP_BIT	(1 << 2)
91 
UpdateFirmware(bool force,bool performLockdown)92 int RMI4Update::UpdateFirmware(bool force, bool performLockdown)
93 {
94 	struct timespec start;
95 	struct timespec end;
96 	long long int duration_us = 0;
97 	int rc;
98 	const unsigned char eraseAll = RMI_F34_ERASE_ALL;
99 	rc = FindUpdateFunctions();
100 	if (rc != UPDATE_SUCCESS)
101 		return rc;
102 
103 	rc = m_device.QueryBasicProperties();
104 	if (rc < 0)
105 		return UPDATE_FAIL_QUERY_BASIC_PROPERTIES;
106 
107 	if (!force && m_firmwareImage.HasIO()) {
108 		if (m_firmwareImage.GetFirmwareID() <= m_device.GetFirmwareID()) {
109 			fprintf(stderr, "Firmware image (%ld) is not newer then the firmware on the device (%ld)\n",
110 				m_firmwareImage.GetFirmwareID(), m_device.GetFirmwareID());
111 			rc = UPDATE_FAIL_FIRMWARE_IMAGE_IS_OLDER;
112 			return rc;
113 		}
114 	}
115 
116 	fprintf(stdout, "Device Properties:\n");
117 	m_device.PrintProperties();
118 
119 	rc = DisableNonessentialInterupts();
120 	if (rc != UPDATE_SUCCESS)
121 		return rc;
122 
123 	rc = ReadF34Queries();
124 	if (rc != UPDATE_SUCCESS)
125 		return rc;
126 	rc = m_firmwareImage.VerifyImageMatchesDevice(GetFirmwareSize(), GetConfigSize());
127 	if (rc != UPDATE_SUCCESS)
128 		return rc;
129 
130 	if (m_f34.GetFunctionVersion() == 0x02) {
131 		fprintf(stdout, "Enable Flash V7+...\n");
132 		rc = EnterFlashProgrammingV7();
133 		if (rc != UPDATE_SUCCESS) {
134 			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
135 			goto reset;
136 		}
137 		fprintf(stdout, "Enable Flash done V7+...\n");
138 
139 		if (!m_IsErased){
140 			fprintf(stdout, "Erasing FW V7+...\n");
141 			rc = EraseFirmwareV7();
142 			if (rc != UPDATE_SUCCESS) {
143 				fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
144 				goto reset;
145 			}
146 			fprintf(stdout, "Erasing FW done V7+...\n");
147 		}
148 		if(m_bootloaderID[1] == 8){
149 			if (m_firmwareImage.GetFlashConfigData()) {
150 				fprintf(stdout, "Writing flash configuration V8...\n");
151 				rc = WriteFlashConfigV7();
152 				if (rc != UPDATE_SUCCESS) {
153 					fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
154 					goto reset;
155 				}
156 				fprintf(stdout, "Writing flash config done V8...\n");
157 			}
158 		}
159 		if (m_firmwareImage.GetFirmwareData()) {
160 			fprintf(stdout, "Writing firmware V7+...\n");
161 			rc = WriteFirmwareV7();
162 			if (rc != UPDATE_SUCCESS) {
163 				fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
164 				goto reset;
165 			}
166 			fprintf(stdout, "Writing firmware done V7+...\n");
167 		}
168 		if (m_firmwareImage.GetConfigData()) {
169 			fprintf(stdout, "Writing core configuration V7+...\n");
170 			rc = WriteCoreConfigV7();
171 			if (rc != UPDATE_SUCCESS) {
172 				fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
173 				goto reset;
174 			}
175 			fprintf(stdout, "Writing core config done V7+...\n");
176 			goto reset;
177 		}
178 
179 	} else {
180 		rc = EnterFlashProgramming();
181 		if (rc != UPDATE_SUCCESS) {
182 			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
183 			goto reset;
184 		}
185 	}
186 
187 	if (performLockdown && m_unlocked) {
188 		if (m_firmwareImage.GetLockdownData()) {
189 			fprintf(stdout, "Writing lockdown...\n");
190 			clock_gettime(CLOCK_MONOTONIC, &start);
191 			rc = WriteBlocks(m_firmwareImage.GetLockdownData(),
192 					m_firmwareImage.GetLockdownSize() / 0x10,
193 					RMI_F34_WRITE_LOCKDOWN_BLOCK);
194 			if (rc != UPDATE_SUCCESS) {
195 				fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
196 				goto reset;
197 			}
198 			clock_gettime(CLOCK_MONOTONIC, &end);
199 			duration_us = diff_time(&start, &end);
200 			fprintf(stdout, "Done writing lockdown, time: %lld us.\n", duration_us);
201 		}
202 
203 		rc = EnterFlashProgramming();
204 		if (rc != UPDATE_SUCCESS) {
205 			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
206 			goto reset;
207 		}
208 	}
209 
210 	rc = WriteBootloaderID();
211 	if (rc != UPDATE_SUCCESS) {
212 		fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
213 		goto reset;
214 	}
215 
216 	fprintf(stdout, "Erasing FW...\n");
217 	clock_gettime(CLOCK_MONOTONIC, &start);
218 	rc = m_device.Write(m_f34StatusAddr, &eraseAll, 1);
219 	if (rc != 1) {
220 		fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(UPDATE_FAIL_ERASE_ALL));
221 		rc = UPDATE_FAIL_ERASE_ALL;
222 		goto reset;
223 	}
224 
225 	rc = WaitForIdle(RMI_F34_ERASE_WAIT_MS);
226 	if (rc != UPDATE_SUCCESS) {
227 		fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
228 		goto reset;
229 	}
230 	clock_gettime(CLOCK_MONOTONIC, &end);
231 	duration_us = diff_time(&start, &end);
232 	fprintf(stdout, "Erase complete, time: %lld us.\n", duration_us);
233 
234 	if (m_firmwareImage.GetFirmwareData()) {
235 		fprintf(stdout, "Writing firmware...\n");
236 		clock_gettime(CLOCK_MONOTONIC, &start);
237 		rc = WriteBlocks(m_firmwareImage.GetFirmwareData(), m_fwBlockCount,
238 						RMI_F34_WRITE_FW_BLOCK);
239 		if (rc != UPDATE_SUCCESS) {
240 			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
241 			goto reset;
242 		}
243 		clock_gettime(CLOCK_MONOTONIC, &end);
244 		duration_us = diff_time(&start, &end);
245 		fprintf(stdout, "Done writing FW, time: %lld us.\n", duration_us);
246 	}
247 
248 	if (m_firmwareImage.GetConfigData()) {
249 		fprintf(stdout, "Writing configuration...\n");
250 		clock_gettime(CLOCK_MONOTONIC, &start);
251 		rc = WriteBlocks(m_firmwareImage.GetConfigData(), m_configBlockCount,
252 				RMI_F34_WRITE_CONFIG_BLOCK);
253 		if (rc != UPDATE_SUCCESS) {
254 			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
255 			goto reset;
256 		}
257 		clock_gettime(CLOCK_MONOTONIC, &end);
258 		duration_us = diff_time(&start, &end);
259 		fprintf(stdout, "Done writing config, time: %lld us.\n", duration_us);
260 	}
261 
262 reset:
263 	m_device.Reset();
264 rebind:
265 	m_device.RebindDriver();
266 	if(!m_device.CheckABSEvent())
267 	{
268 		goto rebind;
269 	}
270 
271 	// In order to print out new PR
272 	rc = FindUpdateFunctions();
273 	if (rc != UPDATE_SUCCESS)
274 		return rc;
275 
276 	rc = m_device.QueryBasicProperties();
277 	if (rc < 0)
278 		return UPDATE_FAIL_QUERY_BASIC_PROPERTIES;
279 	fprintf(stdout, "Device Properties:\n");
280 	m_device.PrintProperties();
281 
282 	return rc;
283 
284 }
285 
DisableNonessentialInterupts()286 int RMI4Update::DisableNonessentialInterupts()
287 {
288 	int rc;
289 	unsigned char interruptEnabeMask = m_f34.GetInterruptMask() | m_f01.GetInterruptMask();
290 
291 	rc = m_device.Write(m_f01.GetControlBase() + 1, &interruptEnabeMask, 1);
292 	if (rc != 1)
293 		return rc;
294 
295 	return UPDATE_SUCCESS;
296 }
297 
FindUpdateFunctions()298 int RMI4Update::FindUpdateFunctions()
299 {
300 	if (0 > m_device.ScanPDT())
301 		return UPDATE_FAIL_SCAN_PDT;
302 
303 	if (!m_device.GetFunction(m_f01, 0x01))
304 		return UPDATE_FAIL_NO_FUNCTION_01;
305 
306 	if (!m_device.GetFunction(m_f34, 0x34))
307 		return UPDATE_FAIL_NO_FUNCTION_34;
308 
309 	return UPDATE_SUCCESS;
310 }
311 
rmi4update_poll()312 int RMI4Update::rmi4update_poll()
313 {
314 	unsigned char f34_status;
315 	unsigned short dataAddr = m_f34.GetDataBase();
316 	int rc;
317 
318 	rc = m_device.Read(dataAddr, &f34_status, sizeof(unsigned char));
319 	if (rc != sizeof(unsigned char))
320 		return UPDATE_FAIL_WRITE_FLASH_COMMAND;
321 
322 	m_flashStatus = f34_status & 0x1F;
323 	m_inBLmode = f34_status & 0x80;
324 	if(!m_flashStatus)
325 		rc = m_device.Read(dataAddr + 4, &m_flashCmd, sizeof(unsigned char));
326 
327 	return 0;
328 }
329 
ReadFlashConfig()330 int RMI4Update::ReadFlashConfig()
331 {
332 	int rc;
333 	int transaction_count, remain_block;
334 	unsigned char *flash_cfg;
335 	int transfer_leng = 0;
336 	int read_leng = 0;
337 	int offset = 0;
338 	unsigned char trans_leng_buf[2];
339 	unsigned char cmd_buf[1];
340 	unsigned char off[2] = {0, 0};
341 	unsigned char partition_id = FLASH_CONFIG_PARTITION;
342 	unsigned short dataAddr = m_f34.GetDataBase();
343 	int i;
344 	int retry = 0;
345 	unsigned char *data_temp;
346 	struct partition_tbl *partition_temp;
347 
348 	flash_cfg = (unsigned char *)malloc(m_blockSize * m_flashConfigLength);
349 	memset(flash_cfg, 0, m_blockSize * m_flashConfigLength);
350 	partition_temp = (partition_tbl *)malloc(sizeof(struct partition_tbl));
351 	memset(partition_temp, 0, sizeof(struct partition_tbl));
352 	/* calculate the count */
353 	remain_block = (m_flashConfigLength % m_payloadLength);
354 	transaction_count = (m_flashConfigLength / m_payloadLength);
355 
356 	if (remain_block > 0)
357 		transaction_count++;
358 
359 	/* set partition id for bootloader 7 */
360 	rc = m_device.Write(dataAddr + 1, &partition_id, sizeof(partition_id));
361 	if (rc != sizeof(partition_id))
362 		return UPDATE_FAIL_WRITE_FLASH_COMMAND;
363 	rc = m_device.Write(dataAddr + 2, off, sizeof(off));
364 	if (rc != sizeof(off))
365 		return UPDATE_FAIL_WRITE_INITIAL_ZEROS;
366 
367 	for (i = 0; i < transaction_count; i++)
368 	{
369 		if ((i == (transaction_count -1)) && (remain_block > 0))
370 			transfer_leng = remain_block;
371 		else
372 			transfer_leng = m_payloadLength;
373 
374 		// Set Transfer Length
375 		trans_leng_buf[0] = (unsigned char)(transfer_leng & 0xFF);
376 		trans_leng_buf[1] = (unsigned char)((transfer_leng & 0xFF00) >> 8);
377 		rc = m_device.Write(dataAddr + 3, trans_leng_buf, sizeof(trans_leng_buf));
378 		if (rc != sizeof(trans_leng_buf))
379 			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
380 
381 		// Set Command to Read
382 		cmd_buf[0] = (unsigned char)CMD_V7_READ;
383 		rc = m_device.Write(dataAddr + 4, cmd_buf, sizeof(cmd_buf));
384 		if (rc != sizeof(cmd_buf))
385 			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
386 
387 		//Wait for completion
388 		do {
389 			Sleep(20);
390 			rmi4update_poll();
391 			if (m_flashStatus == SUCCESS){
392 				break;
393 			}
394 			retry++;
395 		} while(retry < 20);
396 
397 		read_leng = transfer_leng * m_blockSize;
398 		data_temp = (unsigned char *) malloc(sizeof(char) * read_leng);
399 		rc = m_device.Read(dataAddr + 5, data_temp, sizeof(char) * read_leng);
400 		if (rc != ((ssize_t)sizeof(char) * read_leng))
401 			return UPDATE_FAIL_READ_F34_QUERIES;
402 
403 		memcpy(flash_cfg + offset, data_temp, sizeof(char) * read_leng);
404 		offset += read_leng;
405 		free(data_temp);
406 	}
407 
408 	// Initialize as NULL here to avoid segmentation fault.
409 	m_partitionConfig = NULL;
410 	m_partitionCore = NULL;
411 	m_partitionGuest = NULL;
412 
413 	/* parse the config length */
414 	for (i = 2; i < m_blockSize * m_flashConfigLength; i = i + 8)
415 	{
416 		memcpy(partition_temp->data ,flash_cfg + i, sizeof(struct partition_tbl));
417 		if (partition_temp->partition_id == CORE_CONFIG_PARTITION)
418 		{
419 			m_partitionConfig = (partition_tbl *) malloc(sizeof(struct partition_tbl));
420 			memcpy(m_partitionConfig ,partition_temp, sizeof(struct partition_tbl));
421 			memset(partition_temp, 0, sizeof(struct partition_tbl));
422 			fprintf(stdout, "CORE_CONFIG_PARTITION is found\n");
423 		}
424 		else if (partition_temp->partition_id == CORE_CODE_PARTITION)
425 		{
426 			m_partitionCore = (partition_tbl *) malloc(sizeof(struct partition_tbl));
427 			memcpy(m_partitionCore ,partition_temp, sizeof(struct partition_tbl));
428 			memset(partition_temp, 0, sizeof(struct partition_tbl));
429 			fprintf(stdout, "CORE_CODE_PARTITION is found\n");
430 		}
431 		else if (partition_temp->partition_id == GUEST_CODE_PARTITION)
432 		{
433 			m_partitionGuest = (partition_tbl *) malloc(sizeof(struct partition_tbl));
434 			memcpy(m_partitionGuest ,partition_temp, sizeof(struct partition_tbl));
435 			memset(partition_temp, 0, sizeof(struct partition_tbl));
436 			fprintf(stdout, "GUEST_CODE_PARTITION is found\n");
437 		}
438 		else if (partition_temp->partition_id == NONE_PARTITION)
439 			break;
440 	}
441 
442 	if (flash_cfg)
443 		free(flash_cfg);
444 
445 	if (partition_temp)
446 		free(partition_temp);
447 
448 	m_fwBlockCount = m_partitionCore ? m_partitionCore->partition_len : 0;
449 	m_configBlockCount = m_partitionConfig ? m_partitionConfig->partition_len : 0;
450 	m_guestBlockCount = m_partitionGuest ? m_partitionGuest->partition_len : 0;
451 	fprintf(stdout, "F34 fw blocks:     %d\n", m_fwBlockCount);
452 	fprintf(stdout, "F34 config blocks: %d\n", m_configBlockCount);
453 	fprintf(stdout, "F34 guest blocks:     %d\n", m_guestBlockCount);
454 	fprintf(stdout, "\n");
455 
456 	m_guestData = (unsigned char *) malloc(m_guestBlockCount * m_blockSize);
457 	memset(m_guestData, 0, m_guestBlockCount * m_blockSize);
458 	memset(m_guestData + m_guestBlockCount * m_blockSize -4, 0, 4);
459 	return UPDATE_SUCCESS;
460 }
461 
ReadF34QueriesV7()462 int RMI4Update::ReadF34QueriesV7()
463 {
464 	int rc;
465 	struct f34_v7_query_0 query_0;
466 	struct f34_v7_query_1_7 query_1_7;
467 	unsigned char idStr[3];
468 	unsigned short queryAddr = m_f34.GetQueryBase();
469 	unsigned char offset;
470 
471 	rc = m_device.Read(queryAddr, query_0.data, sizeof(query_0.data));
472 	if (rc != sizeof(query_0.data))
473 		return UPDATE_FAIL_READ_BOOTLOADER_ID;
474 
475 	offset = query_0.subpacket_1_size + 1;
476 	rc = m_device.Read(queryAddr + offset, query_1_7.data, sizeof(query_1_7.data));
477 	if (rc != sizeof(query_1_7.data))
478 		return UPDATE_FAIL_READ_BOOTLOADER_ID;
479 
480 	m_bootloaderID[0] = query_1_7.bl_minor_revision;
481 	m_bootloaderID[1] = query_1_7.bl_major_revision;
482 	m_hasConfigID = query_0.has_config_id;
483 	m_blockSize = query_1_7.block_size_15_8 << 8 |
484 			query_1_7.block_size_7_0;
485 	m_flashConfigLength = query_1_7.flash_config_length_15_8 << 8 |
486 				query_1_7.flash_config_length_7_0;
487 	m_payloadLength = query_1_7.payload_length_15_8 << 8 |
488 			query_1_7.payload_length_7_0;
489 	m_buildID = query_1_7.bl_fw_id_7_0 |
490 			query_1_7.bl_fw_id_15_8 << 8 |
491 			query_1_7.bl_fw_id_23_16 << 16 |
492 			query_1_7.bl_fw_id_31_24 << 24;
493 
494 	idStr[0] = m_bootloaderID[0];
495 	idStr[1] = m_bootloaderID[1];
496 	idStr[2] = 0;
497 
498 	fprintf(stdout, "F34 bootloader id: %s (%#04x %#04x)\n", idStr, m_bootloaderID[0],
499 		m_bootloaderID[1]);
500 	fprintf(stdout, "F34 has config id: %d\n", m_hasConfigID);
501 	fprintf(stdout, "F34 unlocked:      %d\n", m_unlocked);
502 	fprintf(stdout, "F34 block size:    %d\n", m_blockSize);
503 	fprintf(stdout, "F34 flash cfg leng:%d\n", m_flashConfigLength);
504 	fprintf(stdout, "F34 payload length:%d\n", m_payloadLength);
505 	fprintf(stdout, "F34 build id:      %lu\n", m_buildID);
506 
507 	return ReadFlashConfig();
508 }
509 
ReadF34Queries()510 int RMI4Update::ReadF34Queries()
511 {
512 	int rc;
513 	unsigned char idStr[3];
514 	unsigned char buf[8];
515 	unsigned short queryAddr = m_f34.GetQueryBase();
516 	unsigned short f34Version = m_f34.GetFunctionVersion();
517 	unsigned short querySize;
518 
519 	if (f34Version == 0x2)
520 		return ReadF34QueriesV7();
521 	else if (f34Version == 0x1)
522 		querySize = 8;
523 	else
524 		querySize = 2;
525 
526 	rc = m_device.Read(queryAddr, m_bootloaderID, RMI_BOOTLOADER_ID_SIZE);
527 	if (rc != RMI_BOOTLOADER_ID_SIZE)
528 		return UPDATE_FAIL_READ_BOOTLOADER_ID;
529 
530 	if (f34Version == 0x1)
531 		++queryAddr;
532 	else
533 		queryAddr += querySize;
534 
535 	if (f34Version == 0x1) {
536 		rc = m_device.Read(queryAddr, buf, 1);
537 		if (rc != 1)
538 			return UPDATE_FAIL_READ_F34_QUERIES;
539 
540 		m_hasNewRegmap = buf[0] & RMI_F34_HAS_NEW_REG_MAP;
541 		m_unlocked = buf[0] & RMI_F34_IS_UNLOCKED;;
542 		m_hasConfigID = buf[0] & RMI_F34_HAS_CONFIG_ID;
543 
544 		++queryAddr;
545 
546 		rc = m_device.Read(queryAddr, buf, 2);
547 		if (rc != 2)
548 			return UPDATE_FAIL_READ_F34_QUERIES;
549 
550 		m_blockSize = extract_short(buf + RMI_F34_BLOCK_SIZE_V1_OFFSET);
551 
552 		++queryAddr;
553 
554 		rc = m_device.Read(queryAddr, buf, 8);
555 		if (rc != 8)
556 			return UPDATE_FAIL_READ_F34_QUERIES;
557 
558 		m_fwBlockCount = extract_short(buf + RMI_F34_FW_BLOCKS_V1_OFFSET);
559 		m_configBlockCount = extract_short(buf + RMI_F34_CONFIG_BLOCKS_V1_OFFSET);
560 	} else {
561 		rc = m_device.Read(queryAddr, buf, RMI_F34_QUERY_SIZE);
562 		if (rc != RMI_F34_QUERY_SIZE)
563 			return UPDATE_FAIL_READ_F34_QUERIES;
564 
565 		m_hasNewRegmap = buf[0] & RMI_F34_HAS_NEW_REG_MAP;
566 		m_unlocked = buf[0] & RMI_F34_IS_UNLOCKED;;
567 		m_hasConfigID = buf[0] & RMI_F34_HAS_CONFIG_ID;
568 		m_blockSize = extract_short(buf + RMI_F34_BLOCK_SIZE_OFFSET);
569 		m_fwBlockCount = extract_short(buf + RMI_F34_FW_BLOCKS_OFFSET);
570 		m_configBlockCount = extract_short(buf + RMI_F34_CONFIG_BLOCKS_OFFSET);
571 	}
572 
573 	idStr[0] = m_bootloaderID[0];
574 	idStr[1] = m_bootloaderID[1];
575 	idStr[2] = 0;
576 
577 	fprintf(stdout, "F34 bootloader id: %s (%#04x %#04x)\n", idStr, m_bootloaderID[0],
578 		m_bootloaderID[1]);
579 	fprintf(stdout, "F34 has config id: %d\n", m_hasConfigID);
580 	fprintf(stdout, "F34 unlocked:      %d\n", m_unlocked);
581 	fprintf(stdout, "F34 new reg map:   %d\n", m_hasNewRegmap);
582 	fprintf(stdout, "F34 block size:    %d\n", m_blockSize);
583 	fprintf(stdout, "F34 fw blocks:     %d\n", m_fwBlockCount);
584 	fprintf(stdout, "F34 config blocks: %d\n", m_configBlockCount);
585 	fprintf(stdout, "\n");
586 
587 	if (f34Version == 0x1)
588 		m_f34StatusAddr = m_f34.GetDataBase() + 2;
589 	else
590 		m_f34StatusAddr = m_f34.GetDataBase() + RMI_F34_BLOCK_DATA_OFFSET + m_blockSize;
591 
592 	return UPDATE_SUCCESS;
593 }
594 
ReadF34Controls()595 int RMI4Update::ReadF34Controls()
596 {
597 	int rc;
598 	unsigned char buf[2];
599 
600 	if (m_f34.GetFunctionVersion() == 0x1) {
601 		rc = m_device.Read(m_f34StatusAddr, buf, 2);
602 		if (rc != 2)
603 			return UPDATE_FAIL_READ_F34_CONTROLS;
604 
605 		m_f34Command = buf[0] & RMI_F34_COMMAND_V1_MASK;
606 		m_f34Status = buf[1] & RMI_F34_STATUS_V1_MASK;
607 		m_programEnabled = !!(buf[1] & RMI_F34_ENABLED_MASK);
608 
609 	} else {
610 		rc = m_device.Read(m_f34StatusAddr, buf, 1);
611 		if (rc != 1)
612 			return UPDATE_FAIL_READ_F34_CONTROLS;
613 
614 		m_f34Command = buf[0] & RMI_F34_COMMAND_MASK;
615 		m_f34Status = (buf[0] >> RMI_F34_STATUS_SHIFT) & RMI_F34_STATUS_MASK;
616 		m_programEnabled = !!(buf[0] & RMI_F34_ENABLED_MASK);
617 	}
618 
619 	return UPDATE_SUCCESS;
620 }
621 
WriteBootloaderID()622 int RMI4Update::WriteBootloaderID()
623 {
624 	int rc;
625 	int blockDataOffset = RMI_F34_BLOCK_DATA_OFFSET;
626 
627 	if (m_f34.GetFunctionVersion() == 0x1)
628 		blockDataOffset = RMI_F34_BLOCK_DATA_V1_OFFSET;
629 
630 	rc = m_device.Write(m_f34.GetDataBase() + blockDataOffset,
631 				m_bootloaderID, RMI_BOOTLOADER_ID_SIZE);
632 	if (rc != RMI_BOOTLOADER_ID_SIZE)
633 		return UPDATE_FAIL_WRITE_BOOTLOADER_ID;
634 
635 	return UPDATE_SUCCESS;
636 }
637 
WriteFirmwareV7()638 int RMI4Update::WriteFirmwareV7()
639 {
640 	int transaction_count, remain_block;
641 	int transfer_leng = 0;
642 	int offset = 0;
643 	unsigned char trans_leng_buf[2];
644 	unsigned char cmd_buf[1];
645 	unsigned char off[2] = {0, 0};
646 	unsigned char partition_id;
647 	int i;
648 	int retry = 0;
649 	unsigned char *data_temp;
650 	int rc;
651 	unsigned short left_bytes;
652 	unsigned short write_size;
653 	unsigned short max_write_size;
654 	unsigned short dataAddr = m_f34.GetDataBase();
655 
656 	/* calculate the count */
657 	partition_id = CORE_CODE_PARTITION;
658 	remain_block = (m_fwBlockCount % m_payloadLength);
659 	transaction_count = (m_fwBlockCount / m_payloadLength);
660 	if (remain_block > 0)
661 		transaction_count++;
662 
663 	/* set partition id for bootloader 7 */
664 	rc = m_device.Write(dataAddr + 1, &partition_id, sizeof(partition_id));
665 	if (rc != sizeof(partition_id))
666 		return UPDATE_FAIL_WRITE_FLASH_COMMAND;
667 
668 	rc = m_device.Write(dataAddr + 2, off, sizeof(off));
669 	if (rc != sizeof(off))
670 		return UPDATE_FAIL_WRITE_INITIAL_ZEROS;
671 
672 	for (i = 0; i < transaction_count; i++)
673 	{
674 		if ((i == (transaction_count -1)) && (remain_block > 0))
675 			transfer_leng = remain_block;
676 		else
677 			transfer_leng = m_payloadLength;
678 
679 		// Set Transfer Length
680 		trans_leng_buf[0] = (unsigned char)(transfer_leng & 0xFF);
681 		trans_leng_buf[1] = (unsigned char)((transfer_leng & 0xFF00) >> 8);
682 
683 		rc = m_device.Write(dataAddr + 3, trans_leng_buf, sizeof(trans_leng_buf));
684 		if (rc != sizeof(trans_leng_buf))
685 			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
686 
687 		// Set Command to Write
688 		cmd_buf[0] = (unsigned char)CMD_V7_WRITE;
689 		rc = m_device.Write(dataAddr + 4, cmd_buf, sizeof(cmd_buf));
690 		if (rc != sizeof(cmd_buf))
691 			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
692 
693 		max_write_size = 16;
694 		if (max_write_size >= transfer_leng * m_blockSize)
695 			max_write_size = transfer_leng * m_blockSize;
696 		else if (max_write_size > m_blockSize)
697 			max_write_size -= max_write_size % m_blockSize;
698 		else
699 			max_write_size = m_blockSize;
700 
701 		left_bytes = transfer_leng * m_blockSize;
702 		do {
703 			if (left_bytes / max_write_size)
704 				write_size = max_write_size;
705 			else
706 				write_size = left_bytes;
707 
708 			data_temp = (unsigned char *) malloc(sizeof(unsigned char) * write_size);
709 			memcpy(data_temp, m_firmwareImage.GetFirmwareData() + offset, sizeof(char) * write_size);
710 			rc = m_device.Write(dataAddr + 5, data_temp, sizeof(char) * write_size);
711 			if (rc != ((ssize_t)sizeof(char) * write_size)) {
712 				fprintf(stdout, "err write_size = %d; rc = %d\n", write_size, rc);
713 				return UPDATE_FAIL_READ_F34_QUERIES;
714 			}
715 
716 			offset += write_size;
717 			left_bytes -= write_size;
718 			free(data_temp);
719 		} while (left_bytes);
720 
721 		// Sleep 100 ms and wait for attention.
722 		Sleep(100);
723 		rc = WaitForIdle(RMI_F34_IDLE_WAIT_MS, false);
724 		if (rc != UPDATE_SUCCESS) {
725 			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
726 			return UPDATE_FAIL_TIMEOUT_WAITING_FOR_ATTN;
727 		}
728 
729 		//Wait for completion
730 		do {
731 			Sleep(20);
732 			rmi4update_poll();
733 			if (m_flashStatus == SUCCESS){
734 				break;
735 
736 			}
737 			retry++;
738 		} while(retry < 20);
739 
740 		if (m_flashStatus != SUCCESS) {
741 			fprintf(stdout, "err flash_status = %d\n", m_flashStatus);
742 			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
743 		}
744 
745 	}
746 	return UPDATE_SUCCESS;
747 }
748 
WriteCoreConfigV7()749 int RMI4Update::WriteCoreConfigV7()
750 {
751 	int transaction_count, remain_block;
752 	int transfer_leng = 0;
753 	int offset = 0;
754 	unsigned char trans_leng_buf[2];
755 	unsigned char cmd_buf[1];
756 	unsigned char off[2] = {0, 0};
757 	unsigned char partition_id;
758 	unsigned short dataAddr = m_f34.GetDataBase();
759 	unsigned short left_bytes;
760 	unsigned short write_size;
761 	unsigned short max_write_size;
762 	int rc;
763 	int i;
764 	int retry = 0;
765 	unsigned char *data_temp;
766 
767 	/* calculate the count */
768 	partition_id = CORE_CONFIG_PARTITION;
769 	remain_block = (m_configBlockCount % m_payloadLength);
770 	transaction_count = (m_configBlockCount / m_payloadLength);
771 	if (remain_block > 0)
772 		transaction_count++;
773 
774 	/* set partition id for bootloader 7 */
775 	rc = m_device.Write(dataAddr + 1, &partition_id, sizeof(partition_id));
776 	if (rc != sizeof(partition_id))
777 		return UPDATE_FAIL_WRITE_FLASH_COMMAND;
778 
779 	rc = m_device.Write(dataAddr + 2, off, sizeof(off));
780 	if (rc != sizeof(off))
781 		return UPDATE_FAIL_WRITE_INITIAL_ZEROS;
782 
783 	for (i = 0; i < transaction_count; i++)
784 	{
785 		if ((i == (transaction_count -1)) && (remain_block > 0))
786 			transfer_leng = remain_block;
787 		else
788 			transfer_leng = m_payloadLength;
789 
790 		// Set Transfer Length
791 		trans_leng_buf[0] = (unsigned char)(transfer_leng & 0xFF);
792 		trans_leng_buf[1] = (unsigned char)((transfer_leng & 0xFF00) >> 8);
793 
794 		rc = m_device.Write(dataAddr + 3, trans_leng_buf, sizeof(trans_leng_buf));
795 		if (rc != sizeof(trans_leng_buf))
796 			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
797 
798 		// Set Command to Write
799 		cmd_buf[0] = (unsigned char)CMD_V7_WRITE;
800 		rc = m_device.Write(dataAddr + 4, cmd_buf, sizeof(cmd_buf));
801 		if (rc != sizeof(cmd_buf))
802 			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
803 
804 		max_write_size = 16;
805 		if (max_write_size >= transfer_leng * m_blockSize)
806 			max_write_size = transfer_leng * m_blockSize;
807 		else if (max_write_size > m_blockSize)
808 			max_write_size -= max_write_size % m_blockSize;
809 		else
810 			max_write_size = m_blockSize;
811 
812 		left_bytes = transfer_leng * m_blockSize;
813 
814 		do {
815 			if (left_bytes / max_write_size)
816 				write_size = max_write_size;
817 			else
818 				write_size = left_bytes;
819 
820 			data_temp = (unsigned char *) malloc(sizeof(unsigned char) * write_size);
821 			memcpy(data_temp, m_firmwareImage.GetConfigData() + offset, sizeof(char) * write_size);
822 			rc = m_device.Write(dataAddr + 5, data_temp, sizeof(char) * write_size);
823 			if (rc != ((ssize_t)sizeof(char) * write_size)) {
824 				return UPDATE_FAIL_READ_F34_QUERIES;
825 			}
826 
827 			offset += write_size;
828 			left_bytes -= write_size;
829 			free(data_temp);
830 		} while (left_bytes);
831 
832 		// Wait for attention.
833 		rc = WaitForIdle(RMI_F34_IDLE_WAIT_MS, false);
834 		if (rc != UPDATE_SUCCESS) {
835 			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
836 			return UPDATE_FAIL_TIMEOUT_WAITING_FOR_ATTN;
837 		}
838 
839 		//Wait for completion
840 		do {
841 			Sleep(20);
842 			rmi4update_poll();
843 			if (m_flashStatus == SUCCESS){
844 				break;
845 			}
846 			retry++;
847 		} while(retry < 20);
848 
849 		if (m_flashStatus != SUCCESS) {
850 			fprintf(stdout, "err flash_status = %d\n", m_flashStatus);
851 			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
852 		}
853 
854 	}
855 	return UPDATE_SUCCESS;
856 }
857 
WriteFlashConfigV7()858 int RMI4Update::WriteFlashConfigV7()
859 {
860 	int transaction_count, remain_block;
861 	int transfer_leng = 0;
862 	int offset = 0;
863 	unsigned char trans_leng_buf[2];
864 	unsigned char cmd_buf[1];
865 	unsigned char off[2] = {0, 0};
866 	unsigned char partition_id;
867 	unsigned short dataAddr = m_f34.GetDataBase();
868 	unsigned short left_bytes;
869 	unsigned short write_size;
870 	unsigned short max_write_size;
871 	int rc;
872 	int i;
873 	int retry = 0;
874 	unsigned char *data_temp;
875 	unsigned short FlashConfigBlockCount;
876 
877 	/* calculate the count */
878 	partition_id = FLASH_CONFIG_PARTITION;
879 
880 	FlashConfigBlockCount = m_firmwareImage.GetFlashConfigSize() / m_blockSize;
881 
882 	remain_block = (FlashConfigBlockCount % m_payloadLength);
883 	transaction_count = (FlashConfigBlockCount / m_payloadLength);
884 	if (remain_block > 0)
885 		transaction_count++;
886 
887 	/* set partition id for bootloader 7 */
888 	rc = m_device.Write(dataAddr + 1, &partition_id, sizeof(partition_id));
889 	if (rc != sizeof(partition_id))
890 		return UPDATE_FAIL_WRITE_FLASH_COMMAND;
891 
892 	rc = m_device.Write(dataAddr + 2, off, sizeof(off));
893 	if (rc != sizeof(off))
894 		return UPDATE_FAIL_WRITE_INITIAL_ZEROS;
895 
896 	for (i = 0; i < transaction_count; i++)
897 	{
898 		if ((i == (transaction_count -1)) && (remain_block > 0))
899 			transfer_leng = remain_block;
900 		else
901 			transfer_leng = m_payloadLength;
902 
903 		// Set Transfer Length
904 		trans_leng_buf[0] = (unsigned char)(transfer_leng & 0xFF);
905 		trans_leng_buf[1] = (unsigned char)((transfer_leng & 0xFF00) >> 8);
906 
907 		rc = m_device.Write(dataAddr + 3, trans_leng_buf, sizeof(trans_leng_buf));
908 		if (rc != sizeof(trans_leng_buf))
909 			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
910 
911 		// Set Command to Write
912 		cmd_buf[0] = (unsigned char)CMD_V7_WRITE;
913 		rc = m_device.Write(dataAddr + 4, cmd_buf, sizeof(cmd_buf));
914 		if (rc != sizeof(cmd_buf))
915 			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
916 
917 		max_write_size = 16;
918 		if (max_write_size >= transfer_leng * m_blockSize)
919 			max_write_size = transfer_leng * m_blockSize;
920 		else if (max_write_size > m_blockSize)
921 			max_write_size -= max_write_size % m_blockSize;
922 		else
923 			max_write_size = m_blockSize;
924 
925 		left_bytes = transfer_leng * m_blockSize;
926 
927 		do {
928 			if (left_bytes / max_write_size)
929 				write_size = max_write_size;
930 			else
931 				write_size = left_bytes;
932 
933 			data_temp = (unsigned char *) malloc(sizeof(unsigned char) * write_size);
934 			memcpy(data_temp, m_firmwareImage.GetFlashConfigData() + offset, sizeof(char) * write_size);
935 			rc = m_device.Write(dataAddr + 5, data_temp, sizeof(char) * write_size);
936 			if (rc != ((ssize_t)sizeof(char) * write_size)) {
937 				fprintf(stdout, "err write_size = %d; rc = %d\n", write_size, rc);
938 				return UPDATE_FAIL_READ_F34_QUERIES;
939 			}
940 
941 			offset += write_size;
942 			left_bytes -= write_size;
943 			free(data_temp);
944 		} while (left_bytes);
945 
946 		// Wair for attention.
947 		rc = WaitForIdle(RMI_F34_IDLE_WAIT_MS, false);
948 		if (rc != UPDATE_SUCCESS) {
949 			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
950 			return UPDATE_FAIL_TIMEOUT_WAITING_FOR_ATTN;
951 		}
952 
953 		//Wait for completion
954 		do {
955 			Sleep(20);
956 			rmi4update_poll();
957 			if (m_flashStatus == SUCCESS){
958 				break;
959 			}
960 			retry++;
961 		} while(retry < 20);
962 
963 		if (m_flashStatus != SUCCESS) {
964 			fprintf(stdout, "err flash_status = %d\n", m_flashStatus);
965 			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
966 		}
967 
968 	}
969 	return UPDATE_SUCCESS;
970 }
971 
EraseFirmwareV7()972 int RMI4Update::EraseFirmwareV7()
973 {
974 	unsigned char erase_cmd[8] = {0, 0, 0, 0, 0, 0, 0, 0};
975 	int retry = 0;
976 	int rc;
977 
978 	/* set partition id for bootloader 7 */
979 	erase_cmd[0] = CORE_CODE_PARTITION;
980 	/* write bootloader id */
981 	erase_cmd[6] = m_bootloaderID[0];
982 	erase_cmd[7] = m_bootloaderID[1];
983 	if(m_bootloaderID[1] == 8){
984 		/* Set Command to Erase AP for BL8*/
985 		erase_cmd[5] = (unsigned char)CMD_V7_ERASE_AP;
986 	} else {
987 		/* Set Command to Erase AP for BL7*/
988 		erase_cmd[5] = (unsigned char)CMD_V7_ERASE;
989 	}
990 
991 	fprintf(stdout, "Erase command : ");
992 	for(int i = 0 ;i<8;i++){
993 		fprintf(stdout, "%d ", erase_cmd[i]);
994 	}
995 	fprintf(stdout, "\n");
996 
997 	rmi4update_poll();
998 	if (!m_inBLmode)
999 		return UPDATE_FAIL_DEVICE_NOT_IN_BOOTLOADER;
1000 	if(m_bootloaderID[1] == 8){
1001 		// For BL8 device, we need hold 1 seconds after querying
1002 		// F34 status to avoid not get attention by following giving
1003 		// erase command.
1004 		Sleep(1000);
1005 	}
1006 
1007 	rc = m_device.Write(m_f34.GetDataBase() + 1, erase_cmd, sizeof(erase_cmd));
1008 	if (rc != sizeof(erase_cmd))
1009 		return UPDATE_FAIL_WRITE_F01_CONTROL_0;
1010 
1011 	Sleep(100);
1012 
1013 	//Wait from ATTN
1014 	if(m_bootloaderID[1] == 8){
1015 		// Wait for attention for BL8 device.
1016 		rc = WaitForIdle(RMI_F34_ERASE_V8_WAIT_MS, false);
1017 		if (rc != UPDATE_SUCCESS) {
1018 			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
1019 			return UPDATE_FAIL_TIMEOUT_WAITING_FOR_ATTN;
1020 		}
1021 	}
1022 	do {
1023 		Sleep(20);
1024 		rmi4update_poll();
1025 		if (m_flashStatus == SUCCESS){
1026 			break;
1027 		}
1028 		retry++;
1029 	} while(retry < 20);
1030 
1031 	if (m_flashStatus != SUCCESS) {
1032 		fprintf(stdout, "err flash_status = %d\n", m_flashStatus);
1033 		return UPDATE_FAIL_WRITE_F01_CONTROL_0;
1034 	}
1035 
1036 	if(m_bootloaderID[1] == 7){
1037 		// For BL7, we need erase config partition.
1038 		fprintf(stdout, "Start to erase config\n");
1039 		erase_cmd[0] = CORE_CONFIG_PARTITION;
1040 		erase_cmd[6] = m_bootloaderID[0];
1041 		erase_cmd[7] = m_bootloaderID[1];
1042 		erase_cmd[5] = (unsigned char)CMD_V7_ERASE;
1043 
1044 		Sleep(100);
1045 		rmi4update_poll();
1046 		if (!m_inBLmode)
1047 		  return UPDATE_FAIL_DEVICE_NOT_IN_BOOTLOADER;
1048 
1049 		rc = m_device.Write(m_f34.GetDataBase() + 1, erase_cmd, sizeof(erase_cmd));
1050 		if (rc != sizeof(erase_cmd))
1051 			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
1052 
1053 		//Wait from ATTN
1054 		Sleep(100);
1055 
1056 		rc = WaitForIdle(RMI_F34_ERASE_WAIT_MS, true);
1057 		if (rc != UPDATE_SUCCESS) {
1058 			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
1059 			return UPDATE_FAIL_TIMEOUT_WAITING_FOR_ATTN;
1060 		}
1061 
1062 
1063 		do {
1064 			Sleep(20);
1065 			rmi4update_poll();
1066 			if (m_flashStatus == SUCCESS){
1067 				break;
1068 			}
1069 			retry++;
1070 		} while(retry < 20);
1071 
1072 		if (m_flashStatus != SUCCESS) {
1073 			fprintf(stdout, "err flash_status = %d\n", m_flashStatus);
1074 			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
1075 		}
1076 	}
1077 
1078 	return UPDATE_SUCCESS;
1079 }
1080 
EnterFlashProgrammingV7()1081 int RMI4Update::EnterFlashProgrammingV7()
1082 {
1083 	int rc;
1084 	unsigned char f34_status;
1085 	rc = m_device.Read(m_f34.GetDataBase(), &f34_status, sizeof(unsigned char));
1086 	m_inBLmode = f34_status & 0x80;
1087 	if(!m_inBLmode){
1088 		fprintf(stdout, "Not in BL mode, going to BL mode...\n");
1089 		unsigned char EnterCmd[8] = {0, 0, 0, 0, 0, 0, 0, 0};
1090 		int retry = 0;
1091 
1092 		/* set partition id for bootloader 7 */
1093 		EnterCmd[0] = BOOTLOADER_PARTITION;
1094 
1095 		/* write bootloader id */
1096 		EnterCmd[6] = m_bootloaderID[0];
1097 		EnterCmd[7] = m_bootloaderID[1];
1098 
1099 		// Set Command to EnterBL
1100 		EnterCmd[5] = (unsigned char)CMD_V7_ENTER_BL;
1101 
1102 		rc = m_device.Write(m_f34.GetDataBase() + 1, EnterCmd, sizeof(EnterCmd));
1103 		if (rc != sizeof(EnterCmd))
1104 			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
1105 
1106 		rc = WaitForIdle(RMI_F34_ENABLE_WAIT_MS, false);
1107 		if (rc != UPDATE_SUCCESS) {
1108 			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
1109 			return UPDATE_FAIL_TIMEOUT_WAITING_FOR_ATTN;
1110 		}
1111 
1112 		//Wait from ATTN
1113 		do {
1114 			Sleep(20);
1115 			rmi4update_poll();
1116 			if (m_flashStatus == SUCCESS){
1117 				break;
1118 			}
1119 			retry++;
1120 		} while(retry < 20);
1121 
1122 		if (m_flashStatus != SUCCESS) {
1123 			fprintf(stdout, "err flash_status = %d\n", m_flashStatus);
1124 			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
1125 		}
1126 
1127 		Sleep(RMI_F34_ENABLE_WAIT_MS);
1128 
1129 		fprintf(stdout, "%s\n", __func__);
1130 		rmi4update_poll();
1131 		if (!m_inBLmode)
1132 			return UPDATE_FAIL_DEVICE_NOT_IN_BOOTLOADER;
1133 
1134 	} else
1135 		fprintf(stdout, "Already in BL mode, skip...\n");
1136 
1137 	if(m_device.GetDeviceType() != RMI_DEVICE_TYPE_TOUCHPAD) {
1138 		// workaround for touchscreen only
1139 		fprintf(stdout, "Erase in BL mode\n");
1140 		rc = EraseFirmwareV7();
1141 		if (rc != UPDATE_SUCCESS) {
1142 			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
1143 			return UPDATE_FAIL_ERASE_ALL;
1144 		}
1145 		fprintf(stdout, "Erase in BL mode end\n");
1146 		m_device.RebindDriver();
1147 	}
1148 
1149 	Sleep(RMI_F34_ENABLE_WAIT_MS);
1150 
1151 	rc = FindUpdateFunctions();
1152 	if (rc != UPDATE_SUCCESS)
1153 		return rc;
1154 
1155 	rc = ReadF34Queries();
1156 	if (rc != UPDATE_SUCCESS)
1157 		return rc;
1158 
1159 	return UPDATE_SUCCESS;
1160 }
1161 
EnterFlashProgramming()1162 int RMI4Update::EnterFlashProgramming()
1163 {
1164 	int rc;
1165 	unsigned char f01Control_0;
1166 	const unsigned char enableProg = RMI_F34_ENABLE_FLASH_PROG;
1167 
1168 	rc = WriteBootloaderID();
1169 	if (rc != UPDATE_SUCCESS)
1170 		return rc;
1171 
1172 	fprintf(stdout, "Enabling flash programming.\n");
1173 	rc = m_device.Write(m_f34StatusAddr, &enableProg, 1);
1174 	if (rc != 1)
1175 		return UPDATE_FAIL_ENABLE_FLASH_PROGRAMMING;
1176 
1177 	Sleep(RMI_F34_ENABLE_WAIT_MS);
1178 	if(m_device.GetDeviceType() != RMI_DEVICE_TYPE_TOUCHPAD) {
1179 		fprintf(stdout, "not TouchPad, rebind driver here\n");
1180 		m_device.RebindDriver();
1181 	}
1182 	rc = WaitForIdle(0);
1183 	if (rc != UPDATE_SUCCESS)
1184 		return UPDATE_FAIL_NOT_IN_IDLE_STATE;
1185 
1186 	if (!m_programEnabled)
1187 		return UPDATE_FAIL_PROGRAMMING_NOT_ENABLED;
1188 
1189 	fprintf(stdout, "Programming is enabled.\n");
1190 	rc = FindUpdateFunctions();
1191 	if (rc != UPDATE_SUCCESS)
1192 		return rc;
1193 
1194 	rc = m_device.Read(m_f01.GetDataBase(), &m_deviceStatus, 1);
1195 	if (rc != 1)
1196 		return UPDATE_FAIL_READ_DEVICE_STATUS;
1197 
1198 	if(m_f34.GetFunctionVersion() > 0x1){
1199 		if (!RMI_F01_STATUS_BOOTLOADER_v7(m_deviceStatus))
1200 			return UPDATE_FAIL_DEVICE_NOT_IN_BOOTLOADER;
1201 		fprintf(stdout, "Already in BL mode V7\n");
1202 	} else {
1203 		if (!RMI_F01_STATUS_BOOTLOADER(m_deviceStatus))
1204 			return UPDATE_FAIL_DEVICE_NOT_IN_BOOTLOADER;
1205 		fprintf(stdout, "Already in BL mode\n");
1206 	}
1207 
1208 	rc = ReadF34Queries();
1209 	if (rc != UPDATE_SUCCESS)
1210 		return rc;
1211 
1212 	rc = m_device.Read(m_f01.GetControlBase(), &f01Control_0, 1);
1213 	if (rc != 1)
1214 		return UPDATE_FAIL_READ_F01_CONTROL_0;
1215 
1216 	f01Control_0 |= RMI_F01_CRTL0_NOSLEEP_BIT;
1217 	f01Control_0 = (f01Control_0 & ~RMI_F01_CTRL0_SLEEP_MODE_MASK) | RMI_SLEEP_MODE_NORMAL;
1218 
1219 	rc = m_device.Write(m_f01.GetControlBase(), &f01Control_0, 1);
1220 	if (rc != 1)
1221 		return UPDATE_FAIL_WRITE_F01_CONTROL_0;
1222 
1223 	return UPDATE_SUCCESS;
1224 }
1225 
WriteBlocks(unsigned char * block,unsigned short count,unsigned char cmd)1226 int RMI4Update::WriteBlocks(unsigned char *block, unsigned short count, unsigned char cmd)
1227 {
1228 	int blockNum;
1229 	unsigned char zeros[] = { 0, 0 };
1230 	int rc;
1231 	unsigned short addr;
1232 	unsigned char *blockWithCmd = (unsigned char *)alloca(m_blockSize + 1);
1233 
1234 	if (m_f34.GetFunctionVersion() == 0x1)
1235 		addr = m_f34.GetDataBase() + RMI_F34_BLOCK_DATA_V1_OFFSET;
1236 	else
1237 		addr = m_f34.GetDataBase() + RMI_F34_BLOCK_DATA_OFFSET;
1238 
1239 	rc = m_device.Write(m_f34.GetDataBase(), zeros, 2);
1240 	if (rc != 2)
1241 		return UPDATE_FAIL_WRITE_INITIAL_ZEROS;
1242 
1243 	for (blockNum = 0; blockNum < count; ++blockNum) {
1244 		if (m_writeBlockWithCmd) {
1245 			memcpy(blockWithCmd, block, m_blockSize);
1246 			blockWithCmd[m_blockSize] = cmd;
1247 
1248 			rc = m_device.Write(addr, blockWithCmd, m_blockSize + 1);
1249 			if (rc != m_blockSize + 1) {
1250 				fprintf(stderr, "failed to write block %d\n", blockNum);
1251 				return UPDATE_FAIL_WRITE_BLOCK;
1252 			}
1253 		} else {
1254 			rc = m_device.Write(addr, block, m_blockSize);
1255 			if (rc != m_blockSize) {
1256 				fprintf(stderr, "failed to write block %d\n", blockNum);
1257 				return UPDATE_FAIL_WRITE_BLOCK;
1258 			}
1259 
1260 			rc = m_device.Write(m_f34StatusAddr, &cmd, 1);
1261 			if (rc != 1) {
1262 				fprintf(stderr, "failed to write command for block %d\n", blockNum);
1263 				return UPDATE_FAIL_WRITE_FLASH_COMMAND;
1264 			}
1265 		}
1266 
1267 		rc = WaitForIdle(RMI_F34_IDLE_WAIT_MS, !m_writeBlockWithCmd);
1268 		if (rc != UPDATE_SUCCESS) {
1269 			fprintf(stderr, "failed to go into idle after writing block %d\n", blockNum);
1270 			return UPDATE_FAIL_NOT_IN_IDLE_STATE;
1271 		}
1272 
1273 		block += m_blockSize;
1274 	}
1275 
1276 	return UPDATE_SUCCESS;
1277 }
1278 
1279 /*
1280  * This is a limited implementation of WaitForIdle which assumes WaitForAttention is supported
1281  * this will be true for HID, but other protocols will need to revert polling. Polling
1282  * is not implemented yet.
1283  */
WaitForIdle(int timeout_ms,bool readF34OnSucess)1284 int RMI4Update::WaitForIdle(int timeout_ms, bool readF34OnSucess)
1285 {
1286 	int rc = 0;
1287 	struct timeval tv;
1288 
1289 	if (timeout_ms > 0) {
1290 		tv.tv_sec = timeout_ms / 1000;
1291 		tv.tv_usec = (timeout_ms % 1000) * 1000;
1292 
1293 		rc = m_device.WaitForAttention(&tv, m_f34.GetInterruptMask());
1294 		if (rc == -ETIMEDOUT){
1295 			/*
1296 			 * If for some reason we are not getting attention reports for HID devices
1297 			 * then we can still continue after the timeout and read F34 status
1298 			 * but if we have to wait for the timeout to ellapse everytime then this
1299 			 * will be slow. If this message shows up a lot then something is wrong
1300 			 * with receiving attention reports and that should be fixed.
1301 			 */
1302 			fprintf(stderr, "RMI4Update::WaitForIdle Timed out waiting for attn report\n");
1303 		}
1304 	}
1305 
1306 	if (rc <= 0 || readF34OnSucess) {
1307 		rc = ReadF34Controls();
1308 		if (rc != UPDATE_SUCCESS)
1309 			return rc;
1310 
1311 		if (!m_f34Status && !m_f34Command) {
1312 			if (!m_programEnabled) {
1313 				fprintf(stderr, "RMI4Update::WaitForIdle Bootloader is idle but program_enabled bit isn't set.\n");
1314 				return UPDATE_FAIL_PROGRAMMING_NOT_ENABLED;
1315 			} else {
1316 				return UPDATE_SUCCESS;
1317 			}
1318 		}
1319 		fprintf(stderr, "RMI4Update::WaitForIdle\n");
1320 		fprintf(stderr, "  ERROR: Waiting for idle status.\n");
1321 		fprintf(stderr, "  Command: %#04x\n", m_f34Command);
1322 		fprintf(stderr, "  Status:  %#04x\n", m_f34Status);
1323 		fprintf(stderr, "  Enabled: %d\n", m_programEnabled);
1324 		fprintf(stderr, "  Idle:    %d\n", !m_f34Command && !m_f34Status);
1325 
1326 		return UPDATE_FAIL_NOT_IN_IDLE_STATE;
1327 	}
1328 
1329 	return UPDATE_SUCCESS;
1330 }
1331