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