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
58int 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
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	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
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);
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
212int 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
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
246void 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
260int 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
309bool 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
325long 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
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;
352}
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");
362}
363