blob: 71bafa030b39570d37e40a7cde1a23f12404731b [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 <stdio.h>
19#include <time.h>
20#include <string.h>
21#include <errno.h>
Andrew Duggan777d0122014-08-05 13:59:55 -070022#include <stdlib.h>
Andrew Duggan4e811252014-04-03 15:17:57 -070023
24#include "rmidevice.h"
25
26#define RMI_DEVICE_PDT_ENTRY_SIZE 6
27#define RMI_DEVICE_PAGE_SELECT_REGISTER 0xFF
28#define RMI_DEVICE_MAX_PAGE 0xFF
29#define RMI_DEVICE_PAGE_SIZE 0x100
30#define RMI_DEVICE_PAGE_SCAN_START 0x00e9
31#define RMI_DEVICE_PAGE_SCAN_END 0x0005
Andrew Dugganfc17a652014-05-06 15:11:20 -070032#define RMI_DEVICE_F01_BASIC_QUERY_LEN 11
Andrew Duggan4e811252014-04-03 15:17:57 -070033#define RMI_DEVICE_F01_QRY5_YEAR_MASK 0x1f
34#define RMI_DEVICE_F01_QRY6_MONTH_MASK 0x0f
35#define RMI_DEVICE_F01_QRY7_DAY_MASK 0x1f
36
37#define RMI_DEVICE_F01_QRY1_HAS_LTS (1 << 2)
38#define RMI_DEVICE_F01_QRY1_HAS_SENSOR_ID (1 << 3)
39#define RMI_DEVICE_F01_QRY1_HAS_CHARGER_INP (1 << 4)
40#define RMI_DEVICE_F01_QRY1_HAS_ADJ_DOZE (1 << 5)
41#define RMI_DEVICE_F01_QRY1_HAS_ADJ_DOZE_HOFF (1 << 6)
42#define RMI_DEVICE_F01_QRY1_HAS_PROPS_2 (1 << 7)
43
44#define RMI_DEVICE_F01_LTS_RESERVED_SIZE 19
45
46#define RMI_DEVICE_F01_QRY42_DS4_QUERIES (1 << 0)
47#define RMI_DEVICE_F01_QRY42_MULTI_PHYS (1 << 1)
48
49#define RMI_DEVICE_F01_QRY43_01_PACKAGE_ID (1 << 0)
50#define RMI_DEVICE_F01_QRY43_01_BUILD_ID (1 << 1)
51
52#define PACKAGE_ID_BYTES 4
53#define BUILD_ID_BYTES 3
54
55#define RMI_F01_CMD_DEVICE_RESET 1
56#define RMI_F01_DEFAULT_RESET_DELAY_MS 100
57
58int RMIDevice::SetRMIPage(unsigned char page)
59{
Andrew Duggan5d477502014-04-07 10:44:40 -070060 int rc;
61
62 if (m_page == page)
63 return 0;
64
65 m_page = page;
66 rc = Write(RMI_DEVICE_PAGE_SELECT_REGISTER, &page, 1);
Andrew de los Reyesb2191d02015-09-04 15:26:41 -070067 if (rc < 0 || rc < 1) {
Andrew Duggan5d477502014-04-07 10:44:40 -070068 m_page = -1;
69 return rc;
70 }
71 return 0;
Andrew Duggan4e811252014-04-03 15:17:57 -070072}
73
74int RMIDevice::QueryBasicProperties()
75{
76 int rc;
77 unsigned char basicQuery[RMI_DEVICE_F01_BASIC_QUERY_LEN];
78 unsigned short queryAddr;
79 unsigned char infoBuf[4];
80 unsigned short prodInfoAddr;
81 RMIFunction f01;
82
Andrew Duggand8f08962014-09-16 15:46:49 -070083 SetRMIPage(0x00);
84
Andrew Duggan4e811252014-04-03 15:17:57 -070085 if (GetFunction(f01, 1)) {
86 queryAddr = f01.GetQueryBase();
87
88 rc = Read(queryAddr, basicQuery, RMI_DEVICE_F01_BASIC_QUERY_LEN);
Andrew de los Reyesb2191d02015-09-04 15:26:41 -070089 if (rc < 0 || rc < RMI_DEVICE_F01_BASIC_QUERY_LEN) {
Andrew Duggan4e811252014-04-03 15:17:57 -070090 fprintf(stderr, "Failed to read the basic query: %s\n", strerror(errno));
91 return rc;
92 }
93 m_manufacturerID = basicQuery[0];
94 m_hasLTS = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_LTS;
95 m_hasSensorID = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_SENSOR_ID;
96 m_hasAdjustableDoze = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_ADJ_DOZE;
97 m_hasAdjustableDozeHoldoff = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_ADJ_DOZE_HOFF;
98 m_hasQuery42 = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_PROPS_2;
Andrew Duggan777d0122014-08-05 13:59:55 -070099 m_firmwareVersionMajor = basicQuery[2];
100 m_firmwareVersionMinor = basicQuery[3];
Andrew Duggan4e811252014-04-03 15:17:57 -0700101
102 snprintf(m_dom, sizeof(m_dom), "20%02d/%02d/%02d",
103 basicQuery[5] & RMI_DEVICE_F01_QRY5_YEAR_MASK,
104 basicQuery[6] & RMI_DEVICE_F01_QRY6_MONTH_MASK,
105 basicQuery[7] & RMI_DEVICE_F01_QRY7_DAY_MASK);
106
Andrew Dugganfc17a652014-05-06 15:11:20 -0700107 queryAddr += 11;
108 rc = Read(queryAddr, m_productID, RMI_PRODUCT_ID_LENGTH);
Andrew de los Reyesb2191d02015-09-04 15:26:41 -0700109 if (rc < 0 || rc < RMI_PRODUCT_ID_LENGTH) {
Andrew Dugganfc17a652014-05-06 15:11:20 -0700110 fprintf(stderr, "Failed to read the product id: %s\n", strerror(errno));
111 return rc;
112 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700113 m_productID[RMI_PRODUCT_ID_LENGTH] = '\0';
114
Andrew Duggan4e811252014-04-03 15:17:57 -0700115 prodInfoAddr = queryAddr + 6;
116 queryAddr += 10;
117
118 if (m_hasLTS)
119 ++queryAddr;
120
121 if (m_hasSensorID) {
122 rc = Read(queryAddr++, &m_sensorID, 1);
Andrew de los Reyesb2191d02015-09-04 15:26:41 -0700123 if (rc < 0 || rc < 1) {
Andrew Duggan4e811252014-04-03 15:17:57 -0700124 fprintf(stderr, "Failed to read sensor id: %s\n", strerror(errno));
125 return rc;
126 }
127 }
128
129 if (m_hasLTS)
130 queryAddr += RMI_DEVICE_F01_LTS_RESERVED_SIZE;
131
132 if (m_hasQuery42) {
133 rc = Read(queryAddr++, infoBuf, 1);
Andrew de los Reyesb2191d02015-09-04 15:26:41 -0700134 if (rc < 0 || rc < 1) {
Andrew Duggan4e811252014-04-03 15:17:57 -0700135 fprintf(stderr, "Failed to read query 42: %s\n", strerror(errno));
136 return rc;
137 }
138
139 m_hasDS4Queries = infoBuf[0] & RMI_DEVICE_F01_QRY42_DS4_QUERIES;
140 m_hasMultiPhysical = infoBuf[0] & RMI_DEVICE_F01_QRY42_MULTI_PHYS;
141 }
142
143 if (m_hasDS4Queries) {
144 rc = Read(queryAddr++, &m_ds4QueryLength, 1);
Andrew de los Reyesb2191d02015-09-04 15:26:41 -0700145 if (rc < 0 || rc < 1) {
Andrew Duggan4e811252014-04-03 15:17:57 -0700146 fprintf(stderr, "Failed to read DS4 query length: %s\n", strerror(errno));
147 return rc;
148 }
149 }
150
151 for (int i = 1; i <= m_ds4QueryLength; ++i) {
152 unsigned char val;
153 rc = Read(queryAddr++, &val, 1);
Andrew de los Reyesb2191d02015-09-04 15:26:41 -0700154 if (rc < 0 || rc < 1) {
Andrew Duggan4e811252014-04-03 15:17:57 -0700155 fprintf(stderr, "Failed to read F01 Query43.%02d: %s\n", i, strerror(errno));
156 continue;
157 }
158
159 switch(i) {
160 case 1:
161 m_hasPackageIDQuery = val & RMI_DEVICE_F01_QRY43_01_PACKAGE_ID;
162 m_hasBuildIDQuery = val & RMI_DEVICE_F01_QRY43_01_BUILD_ID;
163 break;
164 case 2:
165 case 3:
166 default:
167 break;
168 }
169 }
170
171 if (m_hasPackageIDQuery) {
172 rc = Read(prodInfoAddr++, infoBuf, PACKAGE_ID_BYTES);
Andrew de los Reyesb2191d02015-09-04 15:26:41 -0700173 if (rc >= PACKAGE_ID_BYTES) {
Andrew Duggan4e811252014-04-03 15:17:57 -0700174 unsigned short *val = (unsigned short *)infoBuf;
175 m_packageID = *val;
176 val = (unsigned short *)(infoBuf + 2);
177 m_packageRev = *val;
178 }
179 }
180
181 if (m_hasBuildIDQuery) {
182 rc = Read(prodInfoAddr, infoBuf, BUILD_ID_BYTES);
Andrew de los Reyesb2191d02015-09-04 15:26:41 -0700183 if (rc >= BUILD_ID_BYTES) {
Andrew Duggan4e811252014-04-03 15:17:57 -0700184 unsigned short *val = (unsigned short *)infoBuf;
185 m_buildID = *val;
186 m_buildID += infoBuf[2] * 65536;
187 }
188 }
189 }
190 return 0;
191}
192
193void RMIDevice::PrintProperties()
194{
195 fprintf(stdout, "manufacturerID:\t\t%d\n", m_manufacturerID);
196 fprintf(stdout, "Has LTS?:\t\t%d\n", m_hasLTS);
197 fprintf(stdout, "Has Sensor ID?:\t\t%d\n", m_hasSensorID);
198 fprintf(stdout, "Has Adjustable Doze?:\t%d\n", m_hasAdjustableDoze);
199 fprintf(stdout, "Has Query 42?:\t\t%d\n", m_hasQuery42);
200 fprintf(stdout, "Date of Manufacturer:\t%s\n", m_dom);
201 fprintf(stdout, "Product ID:\t\t%s\n", m_productID);
Andrew Duggan777d0122014-08-05 13:59:55 -0700202 fprintf(stdout, "Firmware Version:\t%d.%d\n", m_firmwareVersionMajor, m_firmwareVersionMinor);
Andrew Duggan4e811252014-04-03 15:17:57 -0700203 fprintf(stdout, "Package ID:\t\t%d\n", m_packageID);
204 fprintf(stdout, "Package Rev:\t\t%d\n", m_packageRev);
205 fprintf(stdout, "Build ID:\t\t%ld\n", m_buildID);
206 fprintf(stdout, "Sensor ID:\t\t%d\n", m_sensorID);
207 fprintf(stdout, "Has DS4 Queries?:\t%d\n", m_hasDS4Queries);
208 fprintf(stdout, "Has Multi Phys?:\t%d\n", m_hasMultiPhysical);
209 fprintf(stdout, "\n");
210}
211
212int RMIDevice::Reset()
213{
214 int rc;
215 RMIFunction f01;
Andrew Duggan4e811252014-04-03 15:17:57 -0700216 const unsigned char deviceReset = RMI_F01_CMD_DEVICE_RESET;
217
218 if (!GetFunction(f01, 1))
219 return -1;
220
221 fprintf(stdout, "Resetting...\n");
222 rc = Write(f01.GetCommandBase(), &deviceReset, 1);
Andrew de los Reyesb2191d02015-09-04 15:26:41 -0700223 if (rc < 0 || rc < 1)
Andrew Duggan4e811252014-04-03 15:17:57 -0700224 return rc;
225
Andrew Duggan5d477502014-04-07 10:44:40 -0700226 rc = Sleep(RMI_F01_DEFAULT_RESET_DELAY_MS);
227 if (rc < 0)
228 return -1;
Andrew Duggan4e811252014-04-03 15:17:57 -0700229 fprintf(stdout, "Reset completed.\n");
230 return 0;
231}
232
233bool RMIDevice::GetFunction(RMIFunction &func, int functionNumber)
234{
235 std::vector<RMIFunction>::iterator funcIter;
236
237 for (funcIter = m_functionList.begin(); funcIter != m_functionList.end(); ++funcIter) {
238 if (funcIter->GetFunctionNumber() == functionNumber) {
239 func = *funcIter;
240 return true;
241 }
242 }
243 return false;
244}
245
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700246void RMIDevice::PrintFunctions()
247{
248 std::vector<RMIFunction>::iterator funcIter;
249
250 for (funcIter = m_functionList.begin(); funcIter != m_functionList.end(); ++funcIter)
Andrew Dugganbcdd7c62014-11-09 11:23:30 -0800251 fprintf(stdout, "0x%02x (%d) (%d) (0x%x): 0x%02x 0x%02x 0x%02x 0x%02x\n",
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700252 funcIter->GetFunctionNumber(), funcIter->GetFunctionVersion(),
Andrew Dugganbcdd7c62014-11-09 11:23:30 -0800253 funcIter->GetInterruptSourceCount(),
254 funcIter->GetInterruptMask(),
255 funcIter->GetDataBase(),
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700256 funcIter->GetControlBase(), funcIter->GetCommandBase(),
257 funcIter->GetQueryBase());
258}
259
Satoshi Noguchibaf6bba2014-09-29 02:43:37 -0700260int RMIDevice::ScanPDT(int endFunc, int endPage)
Andrew Duggan4e811252014-04-03 15:17:57 -0700261{
262 int rc;
263 unsigned int page;
Satoshi Noguchibaf6bba2014-09-29 02:43:37 -0700264 unsigned int maxPage;
Andrew Duggan4e811252014-04-03 15:17:57 -0700265 unsigned int addr;
266 unsigned char entry[RMI_DEVICE_PDT_ENTRY_SIZE];
Satoshi Noguchi3020cbb2014-09-29 02:47:25 -0700267 unsigned int interruptCount = 0;
Andrew Duggan4e811252014-04-03 15:17:57 -0700268
Satoshi Noguchibaf6bba2014-09-29 02:43:37 -0700269 maxPage = (unsigned int)((endPage < 0) ? RMI_DEVICE_MAX_PAGE : endPage);
270
Andrew Duggan4e811252014-04-03 15:17:57 -0700271 m_functionList.clear();
272
Satoshi Noguchibaf6bba2014-09-29 02:43:37 -0700273 for (page = 0; page < maxPage; ++page) {
Andrew Duggan4e811252014-04-03 15:17:57 -0700274 unsigned int page_start = RMI_DEVICE_PAGE_SIZE * page;
275 unsigned int pdt_start = page_start + RMI_DEVICE_PAGE_SCAN_START;
276 unsigned int pdt_end = page_start + RMI_DEVICE_PAGE_SCAN_END;
277 bool found = false;
278
279 SetRMIPage(page);
280
281 for (addr = pdt_start; addr >= pdt_end; addr -= RMI_DEVICE_PDT_ENTRY_SIZE) {
282 rc = Read(addr, entry, RMI_DEVICE_PDT_ENTRY_SIZE);
Andrew de los Reyesb2191d02015-09-04 15:26:41 -0700283 if (rc < 0 || rc < RMI_DEVICE_PDT_ENTRY_SIZE) {
Andrew Duggan4e811252014-04-03 15:17:57 -0700284 fprintf(stderr, "Failed to read PDT entry at address (0x%04x)\n", addr);
285 return rc;
286 }
287
Satoshi Noguchi3020cbb2014-09-29 02:47:25 -0700288 RMIFunction func(entry, page_start, interruptCount);
Andrew Duggan4e811252014-04-03 15:17:57 -0700289 if (func.GetFunctionNumber() == 0)
290 break;
291
292 m_functionList.push_back(func);
Satoshi Noguchi3020cbb2014-09-29 02:47:25 -0700293 interruptCount += func.GetInterruptSourceCount();
Andrew Duggan4e811252014-04-03 15:17:57 -0700294 found = true;
Andrew Dugganc14ec9c2014-08-13 14:42:37 -0700295
296 if (func.GetFunctionNumber() == endFunc)
297 return 0;
Andrew Duggan4e811252014-04-03 15:17:57 -0700298 }
299
Satoshi Noguchibaf6bba2014-09-29 02:43:37 -0700300 if (!found && (endPage < 0))
Andrew Duggan4e811252014-04-03 15:17:57 -0700301 break;
302 }
303
Satoshi Noguchi3020cbb2014-09-29 02:47:25 -0700304 m_numInterruptRegs = (interruptCount + 7) / 8;
305
Andrew Duggan4e811252014-04-03 15:17:57 -0700306 return 0;
Andrew Duggan65e55532014-04-04 16:59:54 -0700307}
308
Andrew Duggan2f5c0c02014-08-08 13:30:49 -0700309bool RMIDevice::InBootloader()
310{
311 RMIFunction f01;
312 if (GetFunction(f01, 0x01)) {
313 int rc;
314 unsigned char status;
315
316 rc = Read(f01.GetDataBase(), &status, 1);
Andrew de los Reyesb2191d02015-09-04 15:26:41 -0700317 if (rc < 0 || rc < 1)
Andrew Duggan2f5c0c02014-08-08 13:30:49 -0700318 return true;
319
320 return !!(status & 0x40);
321 }
322 return true;
323}
324
Andrew Duggan65e55532014-04-04 16:59:54 -0700325long long diff_time(struct timespec *start, struct timespec *end)
326{
327 long long diff;
328 diff = (end->tv_sec - start->tv_sec) * 1000 * 1000;
329 diff += (end->tv_nsec - start->tv_nsec) / 1000;
330 return diff;
Andrew Duggan5d477502014-04-07 10:44:40 -0700331}
332
333int Sleep(int ms)
334{
335 struct timespec ts;
336 struct timespec rem;
337
338 ts.tv_sec = ms / 1000;
339 ts.tv_nsec = (ms % 1000) * 1000 * 1000;
340 for (;;) {
341 if (nanosleep(&ts, &rem) == 0) {
342 break;
343 } else {
344 if (errno == EINTR) {
345 ts = rem;
346 continue;
347 }
348 return -1;
349 }
350 }
351 return 0;
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700352}
353
354void print_buffer(const unsigned char *buf, unsigned int len)
355{
356 for (unsigned int i = 0; i < len; ++i) {
357 fprintf(stdout, "0x%02X ", buf[i]);
358 if (i % 8 == 7)
359 fprintf(stdout, "\n");
360 }
361 fprintf(stdout, "\n");
Andrew de los Reyesb2191d02015-09-04 15:26:41 -0700362}