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 <stdio.h>
19 #include <time.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <stdlib.h>
23
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
32 #define RMI_DEVICE_F01_BASIC_QUERY_LEN 11
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 CONFIG_ID_BYTES 4
54 #define BUILD_ID_BYTES 3
55
56 #define RMI_F01_CMD_DEVICE_RESET 1
57 #define RMI_F01_DEFAULT_RESET_DELAY_MS 100
58
SetRMIPage(unsigned char page)59 int RMIDevice::SetRMIPage(unsigned char page)
60 {
61 int rc;
62
63 if (m_page == page)
64 return 0;
65 m_page = page;
66 rc = Write(RMI_DEVICE_PAGE_SELECT_REGISTER, &page, 1);
67 if (rc < 0 || rc < 1) {
68 m_page = -1;
69 return rc;
70 }
71 return 0;
72 }
73
QueryBasicProperties()74 int RMIDevice::QueryBasicProperties()
75 {
76 int rc;
77 unsigned char basicQuery[RMI_DEVICE_F01_BASIC_QUERY_LEN];
78 unsigned char configid[CONFIG_ID_BYTES];
79 unsigned short queryAddr;
80 unsigned short controlAddr;
81 unsigned char infoBuf[4];
82 unsigned short prodInfoAddr;
83 RMIFunction f01;
84 RMIFunction f34;
85
86 SetRMIPage(0x00);
87
88 if (GetFunction(f01, 1)) {
89 queryAddr = f01.GetQueryBase();
90
91 rc = Read(queryAddr, basicQuery, RMI_DEVICE_F01_BASIC_QUERY_LEN);
92 if (rc < 0 || rc < RMI_DEVICE_F01_BASIC_QUERY_LEN) {
93 fprintf(stderr, "Failed to read the basic query: %s\n", strerror(errno));
94 return rc;
95 }
96 m_manufacturerID = basicQuery[0];
97 m_hasLTS = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_LTS;
98 m_hasSensorID = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_SENSOR_ID;
99 m_hasAdjustableDoze = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_ADJ_DOZE;
100 m_hasAdjustableDozeHoldoff = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_ADJ_DOZE_HOFF;
101 m_hasQuery42 = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_PROPS_2;
102 m_firmwareVersionMajor = basicQuery[2];
103 m_firmwareVersionMinor = basicQuery[3];
104
105 snprintf(m_dom, sizeof(m_dom), "20%02d/%02d/%02d",
106 basicQuery[5] & RMI_DEVICE_F01_QRY5_YEAR_MASK,
107 basicQuery[6] & RMI_DEVICE_F01_QRY6_MONTH_MASK,
108 basicQuery[7] & RMI_DEVICE_F01_QRY7_DAY_MASK);
109
110 queryAddr += 11;
111 rc = Read(queryAddr, m_productID, RMI_PRODUCT_ID_LENGTH);
112 if (rc < 0 || rc < RMI_PRODUCT_ID_LENGTH) {
113 fprintf(stderr, "Failed to read the product id: %s\n", strerror(errno));
114 return rc;
115 }
116 m_productID[RMI_PRODUCT_ID_LENGTH] = '\0';
117
118 prodInfoAddr = queryAddr + 6;
119 queryAddr += 10;
120
121 if (m_hasLTS)
122 ++queryAddr;
123
124 if (m_hasSensorID) {
125 rc = Read(queryAddr++, &m_sensorID, 1);
126 if (rc < 0 || rc < 1) {
127 fprintf(stderr, "Failed to read sensor id: %s\n", strerror(errno));
128 return rc;
129 }
130 }
131
132 if (m_hasLTS)
133 queryAddr += RMI_DEVICE_F01_LTS_RESERVED_SIZE;
134
135 if (m_hasQuery42) {
136 rc = Read(queryAddr++, infoBuf, 1);
137 if (rc < 0 || rc < 1) {
138 fprintf(stderr, "Failed to read query 42: %s\n", strerror(errno));
139 return rc;
140 }
141
142 m_hasDS4Queries = infoBuf[0] & RMI_DEVICE_F01_QRY42_DS4_QUERIES;
143 m_hasMultiPhysical = infoBuf[0] & RMI_DEVICE_F01_QRY42_MULTI_PHYS;
144 }
145
146 if (m_hasDS4Queries) {
147 rc = Read(queryAddr++, &m_ds4QueryLength, 1);
148 if (rc < 0 || rc < 1) {
149 fprintf(stderr, "Failed to read DS4 query length: %s\n", strerror(errno));
150 return rc;
151 }
152 }
153
154 for (int i = 1; i <= m_ds4QueryLength; ++i) {
155 unsigned char val;
156 rc = Read(queryAddr++, &val, 1);
157 if (rc < 0 || rc < 1) {
158 fprintf(stderr, "Failed to read F01 Query43.%02d: %s\n", i, strerror(errno));
159 continue;
160 }
161
162 switch(i) {
163 case 1:
164 m_hasPackageIDQuery = val & RMI_DEVICE_F01_QRY43_01_PACKAGE_ID;
165 m_hasBuildIDQuery = val & RMI_DEVICE_F01_QRY43_01_BUILD_ID;
166 break;
167 case 2:
168 case 3:
169 default:
170 break;
171 }
172 }
173
174 if (m_hasPackageIDQuery) {
175 rc = Read(prodInfoAddr++, infoBuf, PACKAGE_ID_BYTES);
176 if (rc >= PACKAGE_ID_BYTES) {
177 unsigned short *val = (unsigned short *)infoBuf;
178 m_packageID = *val;
179 val = (unsigned short *)(infoBuf + 2);
180 m_packageRev = *val;
181 }
182 }
183
184 if (m_hasBuildIDQuery) {
185 rc = Read(prodInfoAddr, infoBuf, BUILD_ID_BYTES);
186 if (rc >= BUILD_ID_BYTES) {
187 unsigned short *val = (unsigned short *)infoBuf;
188 m_buildID = *val;
189 m_buildID += infoBuf[2] * 65536;
190 }
191 }
192 }
193
194 if (GetFunction(f34, 0x34)) {
195 controlAddr = f34.GetControlBase();
196 rc = Read(controlAddr, configid, CONFIG_ID_BYTES);
197 if (rc < 0 || rc < CONFIG_ID_BYTES) {
198 fprintf(stderr, "Failed to read the config id: %s\n", strerror(errno));
199 return rc;
200 }
201 m_configID = (configid[0] << 24 | configid[1] << 16
202 | configid[2] << 8 | configid[3]) & 0xFFFFFFFF;
203 }
204
205 return 0;
206 }
207
Close()208 void RMIDevice::Close()
209 {
210 m_functionList.clear();
211 m_bCancel = false;
212 m_bytesPerReadRequest = 0;
213 m_page = -1;
214 m_deviceType = RMI_DEVICE_TYPE_ANY;
215 }
216
PrintProperties()217 void RMIDevice::PrintProperties()
218 {
219 fprintf(stdout, "manufacturerID:\t\t%d\n", m_manufacturerID);
220 fprintf(stdout, "Has LTS?:\t\t%d\n", m_hasLTS);
221 fprintf(stdout, "Has Sensor ID?:\t\t%d\n", m_hasSensorID);
222 fprintf(stdout, "Has Adjustable Doze?:\t%d\n", m_hasAdjustableDoze);
223 fprintf(stdout, "Has Query 42?:\t\t%d\n", m_hasQuery42);
224 fprintf(stdout, "Date of Manufacturer:\t%s\n", m_dom);
225 fprintf(stdout, "Product ID:\t\t%s\n", m_productID);
226 fprintf(stdout, "Firmware Version:\t%d.%d\n", m_firmwareVersionMajor, m_firmwareVersionMinor);
227 fprintf(stdout, "Package ID:\t\t%d\n", m_packageID);
228 fprintf(stdout, "Package Rev:\t\t%d\n", m_packageRev);
229 fprintf(stdout, "Build ID:\t\t%ld\n", m_buildID);
230 fprintf(stdout, "Sensor ID:\t\t%d\n", m_sensorID);
231 fprintf(stdout, "Has DS4 Queries?:\t%d\n", m_hasDS4Queries);
232 fprintf(stdout, "Has Multi Phys?:\t%d\n", m_hasMultiPhysical);
233 fprintf(stdout, "\n");
234 }
235
Reset()236 int RMIDevice::Reset()
237 {
238 int rc;
239 RMIFunction f01;
240 const unsigned char deviceReset = RMI_F01_CMD_DEVICE_RESET;
241
242 if (!GetFunction(f01, 1))
243 return -1;
244
245 fprintf(stdout, "Resetting...\n");
246 rc = Write(f01.GetCommandBase(), &deviceReset, 1);
247 if (rc < 0 || rc < 1)
248 return rc;
249
250 rc = Sleep(RMI_F01_DEFAULT_RESET_DELAY_MS);
251 if (rc < 0)
252 return -1;
253 fprintf(stdout, "Reset completed.\n");
254 return 0;
255 }
256
GetFunction(RMIFunction & func,int functionNumber)257 bool RMIDevice::GetFunction(RMIFunction &func, int functionNumber)
258 {
259 std::vector<RMIFunction>::iterator funcIter;
260
261 for (funcIter = m_functionList.begin(); funcIter != m_functionList.end(); ++funcIter) {
262 if (funcIter->GetFunctionNumber() == functionNumber) {
263 func = *funcIter;
264 return true;
265 }
266 }
267 return false;
268 }
269
PrintFunctions()270 void RMIDevice::PrintFunctions()
271 {
272 std::vector<RMIFunction>::iterator funcIter;
273
274 for (funcIter = m_functionList.begin(); funcIter != m_functionList.end(); ++funcIter)
275 fprintf(stdout, "0x%02x (%d) (%d) (0x%x): 0x%02x 0x%02x 0x%02x 0x%02x\n",
276 funcIter->GetFunctionNumber(), funcIter->GetFunctionVersion(),
277 funcIter->GetInterruptSourceCount(),
278 funcIter->GetInterruptMask(),
279 funcIter->GetDataBase(),
280 funcIter->GetControlBase(), funcIter->GetCommandBase(),
281 funcIter->GetQueryBase());
282 }
283
ScanPDT(int endFunc,int endPage)284 int RMIDevice::ScanPDT(int endFunc, int endPage)
285 {
286 int rc;
287 unsigned int page;
288 unsigned int maxPage;
289 unsigned int addr;
290 unsigned char entry[RMI_DEVICE_PDT_ENTRY_SIZE];
291 unsigned int interruptCount = 0;
292
293 maxPage = (unsigned int)((endPage < 0) ? RMI_DEVICE_MAX_PAGE : endPage);
294
295 m_functionList.clear();
296
297 for (page = 0; page < maxPage; ++page) {
298 unsigned int page_start = RMI_DEVICE_PAGE_SIZE * page;
299 unsigned int pdt_start = page_start + RMI_DEVICE_PAGE_SCAN_START;
300 unsigned int pdt_end = page_start + RMI_DEVICE_PAGE_SCAN_END;
301 bool found = false;
302
303 SetRMIPage(page);
304
305 for (addr = pdt_start; addr >= pdt_end; addr -= RMI_DEVICE_PDT_ENTRY_SIZE) {
306 rc = Read(addr, entry, RMI_DEVICE_PDT_ENTRY_SIZE);
307 if (rc < 0 || rc < RMI_DEVICE_PDT_ENTRY_SIZE) {
308 fprintf(stderr, "Failed to read PDT entry at address (0x%04x)\n", addr);
309 return rc;
310 }
311
312 RMIFunction func(entry, page_start, interruptCount);
313 if (func.GetFunctionNumber() == 0)
314 break;
315
316 m_functionList.push_back(func);
317 interruptCount += func.GetInterruptSourceCount();
318 found = true;
319
320 if (func.GetFunctionNumber() == endFunc)
321 return 0;
322 }
323
324 if (!found && (endPage < 0))
325 break;
326 }
327
328 m_numInterruptRegs = (interruptCount + 7) / 8;
329
330 return 0;
331 }
332
InBootloader()333 bool RMIDevice::InBootloader()
334 {
335 RMIFunction f01;
336 if (GetFunction(f01, 0x01)) {
337 int rc;
338 unsigned char status;
339
340 rc = Read(f01.GetDataBase(), &status, 1);
341 if (rc < 0 || rc < 1)
342 return true;
343
344 return !!(status & 0x40);
345 }
346 return true;
347 }