blob: 0d4fc195867f51b32789b12f4e16c20c4756e6bf [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>
22
23#include "rmidevice.h"
24
25#define RMI_DEVICE_PDT_ENTRY_SIZE 6
26#define RMI_DEVICE_PAGE_SELECT_REGISTER 0xFF
27#define RMI_DEVICE_MAX_PAGE 0xFF
28#define RMI_DEVICE_PAGE_SIZE 0x100
29#define RMI_DEVICE_PAGE_SCAN_START 0x00e9
30#define RMI_DEVICE_PAGE_SCAN_END 0x0005
31#define RMI_DEVICE_F01_BASIC_QUERY_LEN 21
32#define RMI_DEVICE_F01_PRODUCTINFO_MASK 0x7f
33#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);
67 if (rc < 0) {
68 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
83 if (GetFunction(f01, 1)) {
84 queryAddr = f01.GetQueryBase();
85
86 rc = Read(queryAddr, basicQuery, RMI_DEVICE_F01_BASIC_QUERY_LEN);
87 if (rc < 0) {
88 fprintf(stderr, "Failed to read the basic query: %s\n", strerror(errno));
89 return rc;
90 }
91 m_manufacturerID = basicQuery[0];
92 m_hasLTS = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_LTS;
93 m_hasSensorID = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_SENSOR_ID;
94 m_hasAdjustableDoze = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_ADJ_DOZE;
95 m_hasAdjustableDozeHoldoff = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_ADJ_DOZE_HOFF;
96 m_hasQuery42 = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_PROPS_2;
97 m_productInfo = ((basicQuery[2] & RMI_DEVICE_F01_PRODUCTINFO_MASK) << 7) |
98 (basicQuery[3] & RMI_DEVICE_F01_PRODUCTINFO_MASK);
99
100 snprintf(m_dom, sizeof(m_dom), "20%02d/%02d/%02d",
101 basicQuery[5] & RMI_DEVICE_F01_QRY5_YEAR_MASK,
102 basicQuery[6] & RMI_DEVICE_F01_QRY6_MONTH_MASK,
103 basicQuery[7] & RMI_DEVICE_F01_QRY7_DAY_MASK);
104
105 memcpy(m_productID, &basicQuery[11], RMI_PRODUCT_ID_LENGTH);
106 m_productID[RMI_PRODUCT_ID_LENGTH] = '\0';
107
108 queryAddr += 11;
109 prodInfoAddr = queryAddr + 6;
110 queryAddr += 10;
111
112 if (m_hasLTS)
113 ++queryAddr;
114
115 if (m_hasSensorID) {
116 rc = Read(queryAddr++, &m_sensorID, 1);
117 if (rc < 0) {
118 fprintf(stderr, "Failed to read sensor id: %s\n", strerror(errno));
119 return rc;
120 }
121 }
122
123 if (m_hasLTS)
124 queryAddr += RMI_DEVICE_F01_LTS_RESERVED_SIZE;
125
126 if (m_hasQuery42) {
127 rc = Read(queryAddr++, infoBuf, 1);
128 if (rc < 0) {
129 fprintf(stderr, "Failed to read query 42: %s\n", strerror(errno));
130 return rc;
131 }
132
133 m_hasDS4Queries = infoBuf[0] & RMI_DEVICE_F01_QRY42_DS4_QUERIES;
134 m_hasMultiPhysical = infoBuf[0] & RMI_DEVICE_F01_QRY42_MULTI_PHYS;
135 }
136
137 if (m_hasDS4Queries) {
138 rc = Read(queryAddr++, &m_ds4QueryLength, 1);
139 if (rc < 0) {
140 fprintf(stderr, "Failed to read DS4 query length: %s\n", strerror(errno));
141 return rc;
142 }
143 }
144
145 for (int i = 1; i <= m_ds4QueryLength; ++i) {
146 unsigned char val;
147 rc = Read(queryAddr++, &val, 1);
148 if (rc < 0) {
149 fprintf(stderr, "Failed to read F01 Query43.%02d: %s\n", i, strerror(errno));
150 continue;
151 }
152
153 switch(i) {
154 case 1:
155 m_hasPackageIDQuery = val & RMI_DEVICE_F01_QRY43_01_PACKAGE_ID;
156 m_hasBuildIDQuery = val & RMI_DEVICE_F01_QRY43_01_BUILD_ID;
157 break;
158 case 2:
159 case 3:
160 default:
161 break;
162 }
163 }
164
165 if (m_hasPackageIDQuery) {
166 rc = Read(prodInfoAddr++, infoBuf, PACKAGE_ID_BYTES);
167 if (rc > 0) {
168 unsigned short *val = (unsigned short *)infoBuf;
169 m_packageID = *val;
170 val = (unsigned short *)(infoBuf + 2);
171 m_packageRev = *val;
172 }
173 }
174
175 if (m_hasBuildIDQuery) {
176 rc = Read(prodInfoAddr, infoBuf, BUILD_ID_BYTES);
177 if (rc > 0) {
178 unsigned short *val = (unsigned short *)infoBuf;
179 m_buildID = *val;
180 m_buildID += infoBuf[2] * 65536;
181 }
182 }
183 }
184 return 0;
185}
186
187void RMIDevice::PrintProperties()
188{
189 fprintf(stdout, "manufacturerID:\t\t%d\n", m_manufacturerID);
190 fprintf(stdout, "Has LTS?:\t\t%d\n", m_hasLTS);
191 fprintf(stdout, "Has Sensor ID?:\t\t%d\n", m_hasSensorID);
192 fprintf(stdout, "Has Adjustable Doze?:\t%d\n", m_hasAdjustableDoze);
193 fprintf(stdout, "Has Query 42?:\t\t%d\n", m_hasQuery42);
194 fprintf(stdout, "Date of Manufacturer:\t%s\n", m_dom);
195 fprintf(stdout, "Product ID:\t\t%s\n", m_productID);
196 fprintf(stdout, "Product Info:\t\t%d\n", m_productInfo);
197 fprintf(stdout, "Package ID:\t\t%d\n", m_packageID);
198 fprintf(stdout, "Package Rev:\t\t%d\n", m_packageRev);
199 fprintf(stdout, "Build ID:\t\t%ld\n", m_buildID);
200 fprintf(stdout, "Sensor ID:\t\t%d\n", m_sensorID);
201 fprintf(stdout, "Has DS4 Queries?:\t%d\n", m_hasDS4Queries);
202 fprintf(stdout, "Has Multi Phys?:\t%d\n", m_hasMultiPhysical);
203 fprintf(stdout, "\n");
204}
205
206int RMIDevice::Reset()
207{
208 int rc;
209 RMIFunction f01;
Andrew Duggan4e811252014-04-03 15:17:57 -0700210 const unsigned char deviceReset = RMI_F01_CMD_DEVICE_RESET;
211
212 if (!GetFunction(f01, 1))
213 return -1;
214
215 fprintf(stdout, "Resetting...\n");
216 rc = Write(f01.GetCommandBase(), &deviceReset, 1);
217 if (rc < 0)
218 return rc;
219
Andrew Duggan5d477502014-04-07 10:44:40 -0700220 rc = Sleep(RMI_F01_DEFAULT_RESET_DELAY_MS);
221 if (rc < 0)
222 return -1;
Andrew Duggan4e811252014-04-03 15:17:57 -0700223 fprintf(stdout, "Reset completed.\n");
224 return 0;
225}
226
227bool RMIDevice::GetFunction(RMIFunction &func, int functionNumber)
228{
229 std::vector<RMIFunction>::iterator funcIter;
230
231 for (funcIter = m_functionList.begin(); funcIter != m_functionList.end(); ++funcIter) {
232 if (funcIter->GetFunctionNumber() == functionNumber) {
233 func = *funcIter;
234 return true;
235 }
236 }
237 return false;
238}
239
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700240void RMIDevice::PrintFunctions()
241{
242 std::vector<RMIFunction>::iterator funcIter;
243
244 for (funcIter = m_functionList.begin(); funcIter != m_functionList.end(); ++funcIter)
245 fprintf(stdout, "0x%02x (%d) (%d): 0x%02x 0x%02x 0x%02x 0x%02x\n",
246 funcIter->GetFunctionNumber(), funcIter->GetFunctionVersion(),
247 funcIter->GetInterruptSourceCount(), funcIter->GetDataBase(),
248 funcIter->GetControlBase(), funcIter->GetCommandBase(),
249 funcIter->GetQueryBase());
250}
251
Andrew Duggan4e811252014-04-03 15:17:57 -0700252int RMIDevice::ScanPDT()
253{
254 int rc;
255 unsigned int page;
256 unsigned int addr;
257 unsigned char entry[RMI_DEVICE_PDT_ENTRY_SIZE];
258
259 m_functionList.clear();
260
261 for (page = 0; page < RMI_DEVICE_MAX_PAGE; ++page) {
262 unsigned int page_start = RMI_DEVICE_PAGE_SIZE * page;
263 unsigned int pdt_start = page_start + RMI_DEVICE_PAGE_SCAN_START;
264 unsigned int pdt_end = page_start + RMI_DEVICE_PAGE_SCAN_END;
265 bool found = false;
266
267 SetRMIPage(page);
268
269 for (addr = pdt_start; addr >= pdt_end; addr -= RMI_DEVICE_PDT_ENTRY_SIZE) {
270 rc = Read(addr, entry, RMI_DEVICE_PDT_ENTRY_SIZE);
271 if (rc < 0) {
272 fprintf(stderr, "Failed to read PDT entry at address (0x%04x)\n", addr);
273 return rc;
274 }
275
276 RMIFunction func(entry);
277 if (func.GetFunctionNumber() == 0)
278 break;
279
280 m_functionList.push_back(func);
281 found = true;
282 }
283
284 if (!found)
285 break;
286 }
287
288 return 0;
Andrew Duggan65e55532014-04-04 16:59:54 -0700289}
290
291long long diff_time(struct timespec *start, struct timespec *end)
292{
293 long long diff;
294 diff = (end->tv_sec - start->tv_sec) * 1000 * 1000;
295 diff += (end->tv_nsec - start->tv_nsec) / 1000;
296 return diff;
Andrew Duggan5d477502014-04-07 10:44:40 -0700297}
298
299int Sleep(int ms)
300{
301 struct timespec ts;
302 struct timespec rem;
303
304 ts.tv_sec = ms / 1000;
305 ts.tv_nsec = (ms % 1000) * 1000 * 1000;
306 for (;;) {
307 if (nanosleep(&ts, &rem) == 0) {
308 break;
309 } else {
310 if (errno == EINTR) {
311 ts = rem;
312 continue;
313 }
314 return -1;
315 }
316 }
317 return 0;
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700318}
319
320void print_buffer(const unsigned char *buf, unsigned int len)
321{
322 for (unsigned int i = 0; i < len; ++i) {
323 fprintf(stdout, "0x%02X ", buf[i]);
324 if (i % 8 == 7)
325 fprintf(stdout, "\n");
326 }
327 fprintf(stdout, "\n");
Andrew Duggan4e811252014-04-03 15:17:57 -0700328}