blob: 6c267bc094f5b04105f8622d491133ed70df22ad [file] [log] [blame]
Andrew Duggan052556f2014-04-16 11:32:30 -07001/*
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
Andrew Duggan4e811252014-04-03 15:17:57 -070018#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>
Andrew Duggan62137912014-05-06 16:06:19 -070025#include <errno.h>
Andrew Duggan4e811252014-04-03 15:17:57 -070026
27#include "rmi4update.h"
28
29#define RMI_F34_QUERY_SIZE 7
30#define RMI_F34_HAS_NEW_REG_MAP (1 << 0)
31#define RMI_F34_IS_UNLOCKED (1 << 1)
32#define RMI_F34_HAS_CONFIG_ID (1 << 2)
33#define RMI_F34_BLOCK_SIZE_OFFSET 1
34#define RMI_F34_FW_BLOCKS_OFFSET 3
35#define RMI_F34_CONFIG_BLOCKS_OFFSET 5
36
Andrew Duggana90829b2014-05-23 12:34:31 -070037#define RMI_F34_BLOCK_SIZE_V1_OFFSET 0
38#define RMI_F34_FW_BLOCKS_V1_OFFSET 0
39#define RMI_F34_CONFIG_BLOCKS_V1_OFFSET 2
40
Andrew Duggan4e811252014-04-03 15:17:57 -070041#define RMI_F34_BLOCK_DATA_OFFSET 2
Andrew Duggana90829b2014-05-23 12:34:31 -070042#define RMI_F34_BLOCK_DATA_V1_OFFSET 1
Andrew Duggan4e811252014-04-03 15:17:57 -070043
44#define RMI_F34_COMMAND_MASK 0x0F
45#define RMI_F34_STATUS_MASK 0x07
46#define RMI_F34_STATUS_SHIFT 4
47#define RMI_F34_ENABLED_MASK 0x80
48
Andrew Duggana90829b2014-05-23 12:34:31 -070049#define RMI_F34_COMMAND_V1_MASK 0x3F
50#define RMI_F34_STATUS_V1_MASK 0x3F
51#define RMI_F34_ENABLED_V1_MASK 0x80
52
Andrew Duggan4e811252014-04-03 15:17:57 -070053#define RMI_F34_WRITE_FW_BLOCK 0x02
54#define RMI_F34_ERASE_ALL 0x03
55#define RMI_F34_WRITE_LOCKDOWN_BLOCK 0x04
56#define RMI_F34_WRITE_CONFIG_BLOCK 0x06
57#define RMI_F34_ENABLE_FLASH_PROG 0x0f
58
59#define RMI_F34_ENABLE_WAIT_MS 300
60#define RMI_F34_ERASE_WAIT_MS (5 * 1000)
61#define RMI_F34_IDLE_WAIT_MS 500
62
63/* Most recent device status event */
64#define RMI_F01_STATUS_CODE(status) ((status) & 0x0f)
65/* Indicates that flash programming is enabled (bootloader mode). */
66#define RMI_F01_STATUS_BOOTLOADER(status) (!!((status) & 0x40))
67/* The device has lost its configuration for some reason. */
68#define RMI_F01_STATUS_UNCONFIGURED(status) (!!((status) & 0x80))
69
70/*
71 * Sleep mode controls power management on the device and affects all
72 * functions of the device.
73 */
74#define RMI_F01_CTRL0_SLEEP_MODE_MASK 0x03
75
76#define RMI_SLEEP_MODE_NORMAL 0x00
77#define RMI_SLEEP_MODE_SENSOR_SLEEP 0x01
78#define RMI_SLEEP_MODE_RESERVED0 0x02
79#define RMI_SLEEP_MODE_RESERVED1 0x03
80
81/*
82 * This bit disables whatever sleep mode may be selected by the sleep_mode
83 * field and forces the device to run at full power without sleeping.
84 */
85#define RMI_F01_CRTL0_NOSLEEP_BIT (1 << 2)
86
Satoshi Noguchia0b675a2014-09-29 02:38:14 -070087int RMI4Update::UpdateFirmware(bool force, bool performLockdown)
Andrew Duggan4e811252014-04-03 15:17:57 -070088{
89 struct timespec start;
90 struct timespec end;
Andrew Duggan65e55532014-04-04 16:59:54 -070091 long long int duration_us = 0;
Andrew Duggan4e811252014-04-03 15:17:57 -070092 int rc;
93 const unsigned char eraseAll = RMI_F34_ERASE_ALL;
94
95 rc = FindUpdateFunctions();
96 if (rc != UPDATE_SUCCESS)
97 return rc;
98
99 rc = m_device.QueryBasicProperties();
100 if (rc < 0)
101 return UPDATE_FAIL_QUERY_BASIC_PROPERTIES;
102
Andrew de los Reyes69b31fb2015-09-08 13:34:11 -0700103 if (!force && m_firmwareImage.HasIO()) {
104 if (m_firmwareImage.GetFirmwareID() <= m_device.GetFirmwareID()) {
105 fprintf(stderr, "Firmware image (%ld) is not newer then the firmware on the device (%ld)\n",
106 m_firmwareImage.GetFirmwareID(), m_device.GetFirmwareID());
107 rc = UPDATE_FAIL_FIRMWARE_IMAGE_IS_OLDER;
108 return rc;
109 }
110 }
111
Andrew Duggan4e811252014-04-03 15:17:57 -0700112 fprintf(stdout, "Device Properties:\n");
113 m_device.PrintProperties();
114
Andrew Duggandc838552014-11-11 07:58:09 -0800115 rc = DisableNonessentialInterupts();
116 if (rc != UPDATE_SUCCESS)
117 return rc;
118
Andrew Duggan4e811252014-04-03 15:17:57 -0700119 rc = ReadF34Queries();
120 if (rc != UPDATE_SUCCESS)
121 return rc;
122
Andrew Duggan050db0e2014-07-29 12:42:49 -0700123 rc = m_firmwareImage.VerifyImageMatchesDevice(GetFirmwareSize(), GetConfigSize());
Andrew Duggan4e811252014-04-03 15:17:57 -0700124 if (rc != UPDATE_SUCCESS)
125 return rc;
126
127 rc = EnterFlashProgramming();
128 if (rc != UPDATE_SUCCESS) {
129 fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
Andrew Duggan1129d672015-06-23 15:56:49 -0700130 goto reset;
Andrew Duggan4e811252014-04-03 15:17:57 -0700131 }
132
Satoshi Noguchia0b675a2014-09-29 02:38:14 -0700133 if (performLockdown && m_unlocked) {
Andrew Duggan4e811252014-04-03 15:17:57 -0700134 if (m_firmwareImage.GetLockdownData()) {
135 fprintf(stdout, "Writing lockdown...\n");
136 clock_gettime(CLOCK_MONOTONIC, &start);
137 rc = WriteBlocks(m_firmwareImage.GetLockdownData(),
138 m_firmwareImage.GetLockdownSize() / 0x10,
139 RMI_F34_WRITE_LOCKDOWN_BLOCK);
140 if (rc != UPDATE_SUCCESS) {
141 fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
Andrew Duggan1129d672015-06-23 15:56:49 -0700142 goto reset;
Andrew Duggan4e811252014-04-03 15:17:57 -0700143 }
144 clock_gettime(CLOCK_MONOTONIC, &end);
Andrew Duggan65e55532014-04-04 16:59:54 -0700145 duration_us = diff_time(&start, &end);
146 fprintf(stdout, "Done writing lockdown, time: %lld us.\n", duration_us);
Andrew Duggan4e811252014-04-03 15:17:57 -0700147 }
148
149 rc = EnterFlashProgramming();
150 if (rc != UPDATE_SUCCESS) {
151 fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
Andrew Duggan1129d672015-06-23 15:56:49 -0700152 goto reset;
Andrew Duggan4e811252014-04-03 15:17:57 -0700153 }
154
155 }
156
157 rc = WriteBootloaderID();
158 if (rc != UPDATE_SUCCESS) {
159 fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
Andrew Duggan1129d672015-06-23 15:56:49 -0700160 goto reset;
Andrew Duggan4e811252014-04-03 15:17:57 -0700161 }
162
163 fprintf(stdout, "Erasing FW...\n");
164 clock_gettime(CLOCK_MONOTONIC, &start);
165 rc = m_device.Write(m_f34StatusAddr, &eraseAll, 1);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700166 if (rc != 1) {
Andrew Duggan4e811252014-04-03 15:17:57 -0700167 fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(UPDATE_FAIL_ERASE_ALL));
Andrew Duggan1129d672015-06-23 15:56:49 -0700168 rc = UPDATE_FAIL_ERASE_ALL;
169 goto reset;
Andrew Duggan4e811252014-04-03 15:17:57 -0700170 }
171
172 rc = WaitForIdle(RMI_F34_ERASE_WAIT_MS);
173 if (rc != UPDATE_SUCCESS) {
174 fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
Andrew Duggan1129d672015-06-23 15:56:49 -0700175 goto reset;
Andrew Duggan4e811252014-04-03 15:17:57 -0700176 }
177 clock_gettime(CLOCK_MONOTONIC, &end);
Andrew Duggan65e55532014-04-04 16:59:54 -0700178 duration_us = diff_time(&start, &end);
179 fprintf(stdout, "Erase complete, time: %lld us.\n", duration_us);
Andrew Duggan4e811252014-04-03 15:17:57 -0700180
181 if (m_firmwareImage.GetFirmwareData()) {
182 fprintf(stdout, "Writing firmware...\n");
183 clock_gettime(CLOCK_MONOTONIC, &start);
184 rc = WriteBlocks(m_firmwareImage.GetFirmwareData(), m_fwBlockCount,
185 RMI_F34_WRITE_FW_BLOCK);
186 if (rc != UPDATE_SUCCESS) {
187 fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
Andrew Duggan1129d672015-06-23 15:56:49 -0700188 goto reset;
Andrew Duggan4e811252014-04-03 15:17:57 -0700189 }
190 clock_gettime(CLOCK_MONOTONIC, &end);
Andrew Duggan65e55532014-04-04 16:59:54 -0700191 duration_us = diff_time(&start, &end);
192 fprintf(stdout, "Done writing FW, time: %lld us.\n", duration_us);
Andrew Duggan4e811252014-04-03 15:17:57 -0700193 }
194
195 if (m_firmwareImage.GetConfigData()) {
196 fprintf(stdout, "Writing configuration...\n");
197 clock_gettime(CLOCK_MONOTONIC, &start);
198 rc = WriteBlocks(m_firmwareImage.GetConfigData(), m_configBlockCount,
199 RMI_F34_WRITE_CONFIG_BLOCK);
200 if (rc != UPDATE_SUCCESS) {
201 fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
Andrew Duggan1129d672015-06-23 15:56:49 -0700202 goto reset;
Andrew Duggan4e811252014-04-03 15:17:57 -0700203 }
204 clock_gettime(CLOCK_MONOTONIC, &end);
Andrew Duggan65e55532014-04-04 16:59:54 -0700205 duration_us = diff_time(&start, &end);
206 fprintf(stdout, "Done writing config, time: %lld us.\n", duration_us);
Andrew Duggan4e811252014-04-03 15:17:57 -0700207 }
Andrew Duggan1129d672015-06-23 15:56:49 -0700208
209reset:
Andrew Duggan4e811252014-04-03 15:17:57 -0700210 m_device.Reset();
Andrew Dugganf2e021f2015-05-07 10:35:45 -0700211 m_device.RebindDriver();
Andrew Duggan1129d672015-06-23 15:56:49 -0700212 return rc;
Andrew Duggan4e811252014-04-03 15:17:57 -0700213
214}
215
Andrew Duggandc838552014-11-11 07:58:09 -0800216int RMI4Update::DisableNonessentialInterupts()
217{
218 int rc;
219 unsigned char interruptEnabeMask = m_f34.GetInterruptMask() | m_f01.GetInterruptMask();
220
221 rc = m_device.Write(m_f01.GetControlBase() + 1, &interruptEnabeMask, 1);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700222 if (rc != 1)
Andrew Duggandc838552014-11-11 07:58:09 -0800223 return rc;
224
225 return UPDATE_SUCCESS;
226}
227
Andrew Duggan4e811252014-04-03 15:17:57 -0700228int RMI4Update::FindUpdateFunctions()
229{
230 if (0 > m_device.ScanPDT())
231 return UPDATE_FAIL_SCAN_PDT;
232
233 if (!m_device.GetFunction(m_f01, 0x01))
234 return UPDATE_FAIL_NO_FUNCTION_01;
235
236 if (!m_device.GetFunction(m_f34, 0x34))
237 return UPDATE_FAIL_NO_FUNCTION_34;
238
239 return UPDATE_SUCCESS;
240}
241
242int RMI4Update::ReadF34Queries()
243{
244 int rc;
245 unsigned char idStr[3];
Andrew Duggana90829b2014-05-23 12:34:31 -0700246 unsigned char buf[8];
Andrew Duggan4e811252014-04-03 15:17:57 -0700247 unsigned short queryAddr = m_f34.GetQueryBase();
Andrew Duggana90829b2014-05-23 12:34:31 -0700248 unsigned short f34Version = m_f34.GetFunctionVersion();
249 unsigned short querySize;
250
251 if (f34Version == 0x1)
252 querySize = 8;
253 else
254 querySize = 2;
Andrew Duggan4e811252014-04-03 15:17:57 -0700255
256 rc = m_device.Read(queryAddr, m_bootloaderID, RMI_BOOTLOADER_ID_SIZE);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700257 if (rc != RMI_BOOTLOADER_ID_SIZE)
Andrew Duggan4e811252014-04-03 15:17:57 -0700258 return UPDATE_FAIL_READ_BOOTLOADER_ID;
259
Andrew Duggana90829b2014-05-23 12:34:31 -0700260 if (f34Version == 0x1)
261 ++queryAddr;
262 else
263 queryAddr += querySize;
Andrew Duggan4e811252014-04-03 15:17:57 -0700264
Andrew Duggana90829b2014-05-23 12:34:31 -0700265 if (f34Version == 0x1) {
266 rc = m_device.Read(queryAddr, buf, 1);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700267 if (rc != 1)
Andrew Duggana90829b2014-05-23 12:34:31 -0700268 return UPDATE_FAIL_READ_F34_QUERIES;
Andrew Duggan4e811252014-04-03 15:17:57 -0700269
Andrew Duggana90829b2014-05-23 12:34:31 -0700270 m_hasNewRegmap = buf[0] & RMI_F34_HAS_NEW_REG_MAP;
271 m_unlocked = buf[0] & RMI_F34_IS_UNLOCKED;;
272 m_hasConfigID = buf[0] & RMI_F34_HAS_CONFIG_ID;
273
274 ++queryAddr;
275
276 rc = m_device.Read(queryAddr, buf, 2);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700277 if (rc != 2)
Andrew Duggana90829b2014-05-23 12:34:31 -0700278 return UPDATE_FAIL_READ_F34_QUERIES;
279
280 m_blockSize = extract_short(buf + RMI_F34_BLOCK_SIZE_V1_OFFSET);
281
282 ++queryAddr;
283
284 rc = m_device.Read(queryAddr, buf, 8);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700285 if (rc != 8)
Andrew Duggana90829b2014-05-23 12:34:31 -0700286 return UPDATE_FAIL_READ_F34_QUERIES;
287
288 m_fwBlockCount = extract_short(buf + RMI_F34_FW_BLOCKS_V1_OFFSET);
289 m_configBlockCount = extract_short(buf + RMI_F34_CONFIG_BLOCKS_V1_OFFSET);
290 } else {
291 rc = m_device.Read(queryAddr, buf, RMI_F34_QUERY_SIZE);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700292 if (rc != RMI_F34_QUERY_SIZE)
Andrew Duggana90829b2014-05-23 12:34:31 -0700293 return UPDATE_FAIL_READ_F34_QUERIES;
294
295 m_hasNewRegmap = buf[0] & RMI_F34_HAS_NEW_REG_MAP;
296 m_unlocked = buf[0] & RMI_F34_IS_UNLOCKED;;
297 m_hasConfigID = buf[0] & RMI_F34_HAS_CONFIG_ID;
298 m_blockSize = extract_short(buf + RMI_F34_BLOCK_SIZE_OFFSET);
299 m_fwBlockCount = extract_short(buf + RMI_F34_FW_BLOCKS_OFFSET);
300 m_configBlockCount = extract_short(buf + RMI_F34_CONFIG_BLOCKS_OFFSET);
301 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700302
303 idStr[0] = m_bootloaderID[0];
304 idStr[1] = m_bootloaderID[1];
305 idStr[2] = 0;
306
307 fprintf(stdout, "F34 bootloader id: %s (%#04x %#04x)\n", idStr, m_bootloaderID[0],
308 m_bootloaderID[1]);
309 fprintf(stdout, "F34 has config id: %d\n", m_hasConfigID);
310 fprintf(stdout, "F34 unlocked: %d\n", m_unlocked);
311 fprintf(stdout, "F34 new reg map: %d\n", m_hasNewRegmap);
312 fprintf(stdout, "F34 block size: %d\n", m_blockSize);
313 fprintf(stdout, "F34 fw blocks: %d\n", m_fwBlockCount);
314 fprintf(stdout, "F34 config blocks: %d\n", m_configBlockCount);
315 fprintf(stdout, "\n");
316
Andrew Duggana90829b2014-05-23 12:34:31 -0700317 if (f34Version == 0x1)
318 m_f34StatusAddr = m_f34.GetDataBase() + 2;
319 else
320 m_f34StatusAddr = m_f34.GetDataBase() + RMI_F34_BLOCK_DATA_OFFSET + m_blockSize;
Andrew Duggan4e811252014-04-03 15:17:57 -0700321
322 return UPDATE_SUCCESS;
323}
324
325int RMI4Update::ReadF34Controls()
326{
327 int rc;
Andrew Duggana90829b2014-05-23 12:34:31 -0700328 unsigned char buf[2];
Andrew Duggan4e811252014-04-03 15:17:57 -0700329
Andrew Duggana90829b2014-05-23 12:34:31 -0700330 if (m_f34.GetFunctionVersion() == 0x1) {
331 rc = m_device.Read(m_f34StatusAddr, buf, 2);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700332 if (rc != 2)
Andrew Duggana90829b2014-05-23 12:34:31 -0700333 return UPDATE_FAIL_READ_F34_CONTROLS;
Andrew Duggan4e811252014-04-03 15:17:57 -0700334
Andrew Duggana90829b2014-05-23 12:34:31 -0700335 m_f34Command = buf[0] & RMI_F34_COMMAND_V1_MASK;
336 m_f34Status = buf[1] & RMI_F34_STATUS_V1_MASK;
337 m_programEnabled = !!(buf[1] & RMI_F34_ENABLED_MASK);
338
339 } else {
340 rc = m_device.Read(m_f34StatusAddr, buf, 1);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700341 if (rc != 1)
Andrew Duggana90829b2014-05-23 12:34:31 -0700342 return UPDATE_FAIL_READ_F34_CONTROLS;
343
344 m_f34Command = buf[0] & RMI_F34_COMMAND_MASK;
345 m_f34Status = (buf[0] >> RMI_F34_STATUS_SHIFT) & RMI_F34_STATUS_MASK;
346 m_programEnabled = !!(buf[0] & RMI_F34_ENABLED_MASK);
347 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700348
349 return UPDATE_SUCCESS;
350}
351
352int RMI4Update::WriteBootloaderID()
353{
354 int rc;
Andrew Duggana90829b2014-05-23 12:34:31 -0700355 int blockDataOffset = RMI_F34_BLOCK_DATA_OFFSET;
Andrew Duggan4e811252014-04-03 15:17:57 -0700356
Andrew Duggana90829b2014-05-23 12:34:31 -0700357 if (m_f34.GetFunctionVersion() == 0x1)
358 blockDataOffset = RMI_F34_BLOCK_DATA_V1_OFFSET;
359
360 rc = m_device.Write(m_f34.GetDataBase() + blockDataOffset,
Andrew Duggan4e811252014-04-03 15:17:57 -0700361 m_bootloaderID, RMI_BOOTLOADER_ID_SIZE);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700362 if (rc != RMI_BOOTLOADER_ID_SIZE)
Andrew Duggan4e811252014-04-03 15:17:57 -0700363 return UPDATE_FAIL_WRITE_BOOTLOADER_ID;
364
365 return UPDATE_SUCCESS;
366}
367
368int RMI4Update::EnterFlashProgramming()
369{
370 int rc;
371 unsigned char f01Control_0;
372 const unsigned char enableProg = RMI_F34_ENABLE_FLASH_PROG;
373
374 rc = WriteBootloaderID();
375 if (rc != UPDATE_SUCCESS)
376 return rc;
377
378 fprintf(stdout, "Enabling flash programming.\n");
379 rc = m_device.Write(m_f34StatusAddr, &enableProg, 1);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700380 if (rc != 1)
Andrew Duggan4e811252014-04-03 15:17:57 -0700381 return UPDATE_FAIL_ENABLE_FLASH_PROGRAMMING;
382
Andrew Dugganf2e021f2015-05-07 10:35:45 -0700383 Sleep(RMI_F34_ENABLE_WAIT_MS);
384 m_device.RebindDriver();
385 rc = WaitForIdle(0);
Andrew Duggan4e811252014-04-03 15:17:57 -0700386 if (rc != UPDATE_SUCCESS)
387 return UPDATE_FAIL_NOT_IN_IDLE_STATE;
388
389 if (!m_programEnabled)
390 return UPDATE_FAIL_PROGRAMMING_NOT_ENABLED;
391
Andrew Duggan62137912014-05-06 16:06:19 -0700392 fprintf(stdout, "Programming is enabled.\n");
Andrew Duggan4e811252014-04-03 15:17:57 -0700393 rc = FindUpdateFunctions();
394 if (rc != UPDATE_SUCCESS)
395 return rc;
396
397 rc = m_device.Read(m_f01.GetDataBase(), &m_deviceStatus, 1);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700398 if (rc != 1)
Andrew Duggan4e811252014-04-03 15:17:57 -0700399 return UPDATE_FAIL_READ_DEVICE_STATUS;
400
401 if (!RMI_F01_STATUS_BOOTLOADER(m_deviceStatus))
402 return UPDATE_FAIL_DEVICE_NOT_IN_BOOTLOADER;
403
404 rc = ReadF34Queries();
405 if (rc != UPDATE_SUCCESS)
406 return rc;
407
408 rc = m_device.Read(m_f01.GetControlBase(), &f01Control_0, 1);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700409 if (rc != 1)
Andrew Duggan4e811252014-04-03 15:17:57 -0700410 return UPDATE_FAIL_READ_F01_CONTROL_0;
411
412 f01Control_0 |= RMI_F01_CRTL0_NOSLEEP_BIT;
413 f01Control_0 = (f01Control_0 & ~RMI_F01_CTRL0_SLEEP_MODE_MASK) | RMI_SLEEP_MODE_NORMAL;
414
415 rc = m_device.Write(m_f01.GetControlBase(), &f01Control_0, 1);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700416 if (rc != 1)
Andrew Duggan4e811252014-04-03 15:17:57 -0700417 return UPDATE_FAIL_WRITE_F01_CONTROL_0;
418
419 return UPDATE_SUCCESS;
420}
421
422int RMI4Update::WriteBlocks(unsigned char *block, unsigned short count, unsigned char cmd)
423{
424 int blockNum;
425 unsigned char zeros[] = { 0, 0 };
426 int rc;
Andrew Duggana90829b2014-05-23 12:34:31 -0700427 unsigned short addr;
Andrew Duggan83b0e1f2015-10-12 12:23:14 -0700428 unsigned char *blockWithCmd = (unsigned char *)alloca(m_blockSize + 1);
Andrew Duggana90829b2014-05-23 12:34:31 -0700429
430 if (m_f34.GetFunctionVersion() == 0x1)
431 addr = m_f34.GetDataBase() + RMI_F34_BLOCK_DATA_V1_OFFSET;
432 else
433 addr = m_f34.GetDataBase() + RMI_F34_BLOCK_DATA_OFFSET;
Andrew Duggan4e811252014-04-03 15:17:57 -0700434
435 rc = m_device.Write(m_f34.GetDataBase(), zeros, 2);
Andrew Duggan0e21a042015-09-10 11:24:29 -0700436 if (rc != 2)
Andrew Duggan4e811252014-04-03 15:17:57 -0700437 return UPDATE_FAIL_WRITE_INITIAL_ZEROS;
438
439 for (blockNum = 0; blockNum < count; ++blockNum) {
Andrew Duggan83b0e1f2015-10-12 12:23:14 -0700440 if (m_writeBlockWithCmd) {
441 memcpy(blockWithCmd, block, m_blockSize);
442 blockWithCmd[m_blockSize] = cmd;
443
444 rc = m_device.Write(addr, blockWithCmd, m_blockSize + 1);
445 if (rc != m_blockSize + 1) {
446 fprintf(stderr, "failed to write block %d\n", blockNum);
447 return UPDATE_FAIL_WRITE_BLOCK;
448 }
449 } else {
450 rc = m_device.Write(addr, block, m_blockSize);
451 if (rc != m_blockSize) {
452 fprintf(stderr, "failed to write block %d\n", blockNum);
453 return UPDATE_FAIL_WRITE_BLOCK;
454 }
455
456 rc = m_device.Write(m_f34StatusAddr, &cmd, 1);
457 if (rc != 1) {
458 fprintf(stderr, "failed to write command for block %d\n", blockNum);
459 return UPDATE_FAIL_WRITE_FLASH_COMMAND;
460 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700461 }
462
Andrew Duggan83b0e1f2015-10-12 12:23:14 -0700463 rc = WaitForIdle(RMI_F34_IDLE_WAIT_MS, !m_writeBlockWithCmd);
Andrew Duggan4e811252014-04-03 15:17:57 -0700464 if (rc != UPDATE_SUCCESS) {
465 fprintf(stderr, "failed to go into idle after writing block %d\n", blockNum);
466 return UPDATE_FAIL_NOT_IN_IDLE_STATE;
467 }
468
469 block += m_blockSize;
470 }
471
472 return UPDATE_SUCCESS;
473}
474
475/*
476 * This is a limited implementation of WaitForIdle which assumes WaitForAttention is supported
477 * this will be true for HID, but other protocols will need to revert polling. Polling
478 * is not implemented yet.
479 */
Andrew Duggan83b0e1f2015-10-12 12:23:14 -0700480int RMI4Update::WaitForIdle(int timeout_ms, bool readF34OnSucess)
Andrew Duggan4e811252014-04-03 15:17:57 -0700481{
Andrew Dugganbfe164f2015-10-12 13:48:30 -0700482 int rc = 0;
Andrew Duggan4e811252014-04-03 15:17:57 -0700483 struct timeval tv;
484
Andrew Dugganf2e021f2015-05-07 10:35:45 -0700485 if (timeout_ms > 0) {
486 tv.tv_sec = timeout_ms / 1000;
487 tv.tv_usec = (timeout_ms % 1000) * 1000;
Andrew Duggan4e811252014-04-03 15:17:57 -0700488
Andrew Dugganf2e021f2015-05-07 10:35:45 -0700489 rc = m_device.WaitForAttention(&tv, m_f34.GetInterruptMask());
490 if (rc == -ETIMEDOUT)
491 /*
492 * If for some reason we are not getting attention reports for HID devices
493 * then we can still continue after the timeout and read F34 status
494 * but if we have to wait for the timeout to ellapse everytime then this
495 * will be slow. If this message shows up a lot then something is wrong
496 * with receiving attention reports and that should be fixed.
497 */
498 fprintf(stderr, "Timed out waiting for attn report\n");
499 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700500
Andrew Duggan83b0e1f2015-10-12 12:23:14 -0700501 if (rc <= 0 || readF34OnSucess) {
502 rc = ReadF34Controls();
503 if (rc != UPDATE_SUCCESS)
504 return rc;
Andrew Duggan62137912014-05-06 16:06:19 -0700505
Andrew Duggan83b0e1f2015-10-12 12:23:14 -0700506 if (!m_f34Status && !m_f34Command) {
507 if (!m_programEnabled) {
508 fprintf(stderr, "Bootloader is idle but program_enabled bit isn't set.\n");
509 return UPDATE_FAIL_PROGRAMMING_NOT_ENABLED;
510 } else {
511 return UPDATE_SUCCESS;
512 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700513 }
Andrew Duggan83b0e1f2015-10-12 12:23:14 -0700514
515 fprintf(stderr, "ERROR: Waiting for idle status.\n");
516 fprintf(stderr, "Command: %#04x\n", m_f34Command);
517 fprintf(stderr, "Status: %#04x\n", m_f34Status);
518 fprintf(stderr, "Enabled: %d\n", m_programEnabled);
519 fprintf(stderr, "Idle: %d\n", !m_f34Command && !m_f34Status);
520
521 return UPDATE_FAIL_NOT_IN_IDLE_STATE;
Andrew Duggan4e811252014-04-03 15:17:57 -0700522 }
Andrew Duggan62137912014-05-06 16:06:19 -0700523
Andrew Duggan83b0e1f2015-10-12 12:23:14 -0700524 return UPDATE_SUCCESS;
Andrew Duggan1129d672015-06-23 15:56:49 -0700525}