• 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 <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 BUILD_ID_BYTES				3
54 
55 #define RMI_F01_CMD_DEVICE_RESET	1
56 #define RMI_F01_DEFAULT_RESET_DELAY_MS	100
57 
SetRMIPage(unsigned char page)58 int RMIDevice::SetRMIPage(unsigned char page)
59 {
60 	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 || 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 short queryAddr;
79 	unsigned char infoBuf[4];
80 	unsigned short prodInfoAddr;
81 	RMIFunction f01;
82 
83 	SetRMIPage(0x00);
84 
85 	if (GetFunction(f01, 1)) {
86 		queryAddr = f01.GetQueryBase();
87 
88 		rc = Read(queryAddr, basicQuery, RMI_DEVICE_F01_BASIC_QUERY_LEN);
89 		if (rc < 0 || rc < RMI_DEVICE_F01_BASIC_QUERY_LEN) {
90 			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;
99 		m_firmwareVersionMajor = basicQuery[2];
100 		m_firmwareVersionMinor = basicQuery[3];
101 
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 
107 		queryAddr += 11;
108 		rc = Read(queryAddr, m_productID, RMI_PRODUCT_ID_LENGTH);
109 		if (rc < 0 || rc < RMI_PRODUCT_ID_LENGTH) {
110 			fprintf(stderr, "Failed to read the product id: %s\n", strerror(errno));
111 			return rc;
112 		}
113 		m_productID[RMI_PRODUCT_ID_LENGTH] = '\0';
114 
115 		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);
123 			if (rc < 0 || rc < 1) {
124 				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);
134 			if (rc < 0 || rc < 1) {
135 				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);
145 			if (rc < 0 || rc < 1) {
146 				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);
154 			if (rc < 0 || rc < 1) {
155 				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);
173 			if (rc >= PACKAGE_ID_BYTES) {
174 				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);
183 			if (rc >= BUILD_ID_BYTES) {
184 				unsigned short *val = (unsigned short *)infoBuf;
185 				m_buildID = *val;
186 				m_buildID += infoBuf[2] * 65536;
187 			}
188 		}
189 	}
190 	return 0;
191 }
192 
PrintProperties()193 void 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);
202 	fprintf(stdout, "Firmware Version:\t%d.%d\n", m_firmwareVersionMajor, m_firmwareVersionMinor);
203 	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 
Reset()212 int RMIDevice::Reset()
213 {
214 	int rc;
215 	RMIFunction f01;
216 	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);
223 	if (rc < 0 || rc < 1)
224 		return rc;
225 
226 	rc = Sleep(RMI_F01_DEFAULT_RESET_DELAY_MS);
227 	if (rc < 0)
228 		return -1;
229 	fprintf(stdout, "Reset completed.\n");
230 	return 0;
231 }
232 
GetFunction(RMIFunction & func,int functionNumber)233 bool 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 
PrintFunctions()246 void RMIDevice::PrintFunctions()
247 {
248 	std::vector<RMIFunction>::iterator funcIter;
249 
250 	for (funcIter = m_functionList.begin(); funcIter != m_functionList.end(); ++funcIter)
251 		fprintf(stdout, "0x%02x (%d) (%d) (0x%x): 0x%02x 0x%02x 0x%02x 0x%02x\n",
252 				funcIter->GetFunctionNumber(), funcIter->GetFunctionVersion(),
253 				funcIter->GetInterruptSourceCount(),
254 				funcIter->GetInterruptMask(),
255 				funcIter->GetDataBase(),
256 				funcIter->GetControlBase(), funcIter->GetCommandBase(),
257 				funcIter->GetQueryBase());
258 }
259 
ScanPDT(int endFunc,int endPage)260 int RMIDevice::ScanPDT(int endFunc, int endPage)
261 {
262 	int rc;
263 	unsigned int page;
264 	unsigned int maxPage;
265 	unsigned int addr;
266 	unsigned char entry[RMI_DEVICE_PDT_ENTRY_SIZE];
267 	unsigned int interruptCount = 0;
268 
269 	maxPage = (unsigned int)((endPage < 0) ? RMI_DEVICE_MAX_PAGE : endPage);
270 
271 	m_functionList.clear();
272 
273 	for (page = 0; page < maxPage; ++page) {
274 		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);
283 			if (rc < 0 || rc < RMI_DEVICE_PDT_ENTRY_SIZE) {
284 				fprintf(stderr, "Failed to read PDT entry at address (0x%04x)\n", addr);
285 				return rc;
286 			}
287 
288 			RMIFunction func(entry, page_start, interruptCount);
289 			if (func.GetFunctionNumber() == 0)
290 				break;
291 
292 			m_functionList.push_back(func);
293 			interruptCount += func.GetInterruptSourceCount();
294 			found = true;
295 
296 			if (func.GetFunctionNumber() == endFunc)
297 				return 0;
298 		}
299 
300 		if (!found && (endPage < 0))
301 			break;
302 	}
303 
304 	m_numInterruptRegs = (interruptCount + 7) / 8;
305 
306 	return 0;
307 }
308 
InBootloader()309 bool 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);
317 		if (rc < 0 || rc < 1)
318 			return true;
319 
320 		return !!(status & 0x40);
321 	}
322 	return true;
323 }
324 
diff_time(struct timespec * start,struct timespec * end)325 long 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;
331 }
332 
Sleep(int ms)333 int 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;
352 }
353 
print_buffer(const unsigned char * buf,unsigned int len)354 void 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");
362 }
363