1052556f215226db267e5e21d090c4555bba41704Andrew Duggan/*
2052556f215226db267e5e21d090c4555bba41704Andrew Duggan * Copyright (C) 2014 Andrew Duggan
3052556f215226db267e5e21d090c4555bba41704Andrew Duggan * Copyright (C) 2014 Synaptics Inc
4052556f215226db267e5e21d090c4555bba41704Andrew Duggan *
5052556f215226db267e5e21d090c4555bba41704Andrew Duggan * Licensed under the Apache License, Version 2.0 (the "License");
6052556f215226db267e5e21d090c4555bba41704Andrew Duggan * you may not use this file except in compliance with the License.
7052556f215226db267e5e21d090c4555bba41704Andrew Duggan * You may obtain a copy of the License at
8052556f215226db267e5e21d090c4555bba41704Andrew Duggan *
9052556f215226db267e5e21d090c4555bba41704Andrew Duggan *      http://www.apache.org/licenses/LICENSE-2.0
10052556f215226db267e5e21d090c4555bba41704Andrew Duggan *
11052556f215226db267e5e21d090c4555bba41704Andrew Duggan * Unless required by applicable law or agreed to in writing, software
12052556f215226db267e5e21d090c4555bba41704Andrew Duggan * distributed under the License is distributed on an "AS IS" BASIS,
13052556f215226db267e5e21d090c4555bba41704Andrew Duggan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14052556f215226db267e5e21d090c4555bba41704Andrew Duggan * See the License for the specific language governing permissions and
15052556f215226db267e5e21d090c4555bba41704Andrew Duggan * limitations under the License.
16052556f215226db267e5e21d090c4555bba41704Andrew Duggan */
17052556f215226db267e5e21d090c4555bba41704Andrew Duggan
184e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#include <stdio.h>
194e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#include <time.h>
204e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#include <string.h>
214e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#include <errno.h>
22777d012aadce5220c1445b8923d86e95fcc60128Andrew Duggan#include <stdlib.h>
234e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
244e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#include "rmidevice.h"
254e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
264e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_PDT_ENTRY_SIZE		6
274e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_PAGE_SELECT_REGISTER		0xFF
284e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_MAX_PAGE			0xFF
294e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_PAGE_SIZE			0x100
304e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_PAGE_SCAN_START		0x00e9
314e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_PAGE_SCAN_END		0x0005
32fc17a65f3c9c3db99ab5c962bf55d109e485f9b5Andrew Duggan#define RMI_DEVICE_F01_BASIC_QUERY_LEN		11
334e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_QRY5_YEAR_MASK		0x1f
344e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_QRY6_MONTH_MASK		0x0f
354e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_QRY7_DAY_MASK		0x1f
364e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
374e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_QRY1_HAS_LTS		(1 << 2)
384e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_QRY1_HAS_SENSOR_ID	(1 << 3)
394e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_QRY1_HAS_CHARGER_INP	(1 << 4)
404e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_QRY1_HAS_ADJ_DOZE	(1 << 5)
414e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_QRY1_HAS_ADJ_DOZE_HOFF	(1 << 6)
424e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_QRY1_HAS_PROPS_2		(1 << 7)
434e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
444e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_LTS_RESERVED_SIZE	19
454e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
464e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_QRY42_DS4_QUERIES	(1 << 0)
474e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_QRY42_MULTI_PHYS		(1 << 1)
484e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
494e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_QRY43_01_PACKAGE_ID     (1 << 0)
504e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_DEVICE_F01_QRY43_01_BUILD_ID       (1 << 1)
514e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
524e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define PACKAGE_ID_BYTES			4
534e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define BUILD_ID_BYTES				3
544e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
554e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_F01_CMD_DEVICE_RESET	1
564e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan#define RMI_F01_DEFAULT_RESET_DELAY_MS	100
574e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
584e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Dugganint RMIDevice::SetRMIPage(unsigned char page)
594e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan{
605d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	int rc;
615d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan
625d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	if (m_page == page)
635d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan		return 0;
645d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan
655d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	m_page = page;
665d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	rc = Write(RMI_DEVICE_PAGE_SELECT_REGISTER, &page, 1);
67b2191d0467eaee992eff48646c40a01d1e405597Andrew de los Reyes	if (rc < 0 || rc < 1) {
685d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan		m_page = -1;
695d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan		return rc;
705d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	}
715d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	return 0;
724e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan}
734e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
744e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Dugganint RMIDevice::QueryBasicProperties()
754e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan{
764e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	int rc;
774e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	unsigned char basicQuery[RMI_DEVICE_F01_BASIC_QUERY_LEN];
784e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	unsigned short queryAddr;
794e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	unsigned char infoBuf[4];
804e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	unsigned short prodInfoAddr;
814e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	RMIFunction f01;
824e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
83d8f0896e72f336f81bf507e5344631177309ea3cAndrew Duggan	SetRMIPage(0x00);
84d8f0896e72f336f81bf507e5344631177309ea3cAndrew Duggan
854e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	if (GetFunction(f01, 1)) {
864e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		queryAddr = f01.GetQueryBase();
874e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
884e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		rc = Read(queryAddr, basicQuery, RMI_DEVICE_F01_BASIC_QUERY_LEN);
89b2191d0467eaee992eff48646c40a01d1e405597Andrew de los Reyes		if (rc < 0 || rc < RMI_DEVICE_F01_BASIC_QUERY_LEN) {
904e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			fprintf(stderr, "Failed to read the basic query: %s\n", strerror(errno));
914e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			return rc;
924e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		}
934e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		m_manufacturerID = basicQuery[0];
944e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		m_hasLTS = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_LTS;
954e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		m_hasSensorID = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_SENSOR_ID;
964e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		m_hasAdjustableDoze = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_ADJ_DOZE;
974e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		m_hasAdjustableDozeHoldoff = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_ADJ_DOZE_HOFF;
984e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		m_hasQuery42 = basicQuery[1] & RMI_DEVICE_F01_QRY1_HAS_PROPS_2;
99777d012aadce5220c1445b8923d86e95fcc60128Andrew Duggan		m_firmwareVersionMajor = basicQuery[2];
100777d012aadce5220c1445b8923d86e95fcc60128Andrew Duggan		m_firmwareVersionMinor = basicQuery[3];
1014e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
1024e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		snprintf(m_dom, sizeof(m_dom), "20%02d/%02d/%02d",
1034e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				basicQuery[5] & RMI_DEVICE_F01_QRY5_YEAR_MASK,
1044e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		 		basicQuery[6] & RMI_DEVICE_F01_QRY6_MONTH_MASK,
1054e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		 		basicQuery[7] & RMI_DEVICE_F01_QRY7_DAY_MASK);
1064e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
107fc17a65f3c9c3db99ab5c962bf55d109e485f9b5Andrew Duggan		queryAddr += 11;
108fc17a65f3c9c3db99ab5c962bf55d109e485f9b5Andrew Duggan		rc = Read(queryAddr, m_productID, RMI_PRODUCT_ID_LENGTH);
109b2191d0467eaee992eff48646c40a01d1e405597Andrew de los Reyes		if (rc < 0 || rc < RMI_PRODUCT_ID_LENGTH) {
110fc17a65f3c9c3db99ab5c962bf55d109e485f9b5Andrew Duggan			fprintf(stderr, "Failed to read the product id: %s\n", strerror(errno));
111fc17a65f3c9c3db99ab5c962bf55d109e485f9b5Andrew Duggan			return rc;
112fc17a65f3c9c3db99ab5c962bf55d109e485f9b5Andrew Duggan		}
1134e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		m_productID[RMI_PRODUCT_ID_LENGTH] = '\0';
1144e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
1154e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		prodInfoAddr = queryAddr + 6;
1164e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		queryAddr += 10;
1174e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
1184e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		if (m_hasLTS)
1194e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			++queryAddr;
1204e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
1214e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		if (m_hasSensorID) {
1224e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			rc = Read(queryAddr++, &m_sensorID, 1);
123b2191d0467eaee992eff48646c40a01d1e405597Andrew de los Reyes			if (rc < 0 || rc < 1) {
1244e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				fprintf(stderr, "Failed to read sensor id: %s\n", strerror(errno));
1254e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				return rc;
1264e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			}
1274e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		}
1284e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
1294e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		if (m_hasLTS)
1304e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			queryAddr += RMI_DEVICE_F01_LTS_RESERVED_SIZE;
1314e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
1324e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		if (m_hasQuery42) {
1334e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			rc = Read(queryAddr++, infoBuf, 1);
134b2191d0467eaee992eff48646c40a01d1e405597Andrew de los Reyes			if (rc < 0 || rc < 1) {
1354e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				fprintf(stderr, "Failed to read query 42: %s\n", strerror(errno));
1364e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				return rc;
1374e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			}
1384e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
1394e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			m_hasDS4Queries = infoBuf[0] & RMI_DEVICE_F01_QRY42_DS4_QUERIES;
1404e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			m_hasMultiPhysical = infoBuf[0] & RMI_DEVICE_F01_QRY42_MULTI_PHYS;
1414e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		}
1424e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
1434e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		if (m_hasDS4Queries) {
1444e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			rc = Read(queryAddr++, &m_ds4QueryLength, 1);
145b2191d0467eaee992eff48646c40a01d1e405597Andrew de los Reyes			if (rc < 0 || rc < 1) {
1464e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				fprintf(stderr, "Failed to read DS4 query length: %s\n", strerror(errno));
1474e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				return rc;
1484e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			}
1494e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		}
1504e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
1514e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		for (int i = 1; i <= m_ds4QueryLength; ++i) {
1524e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			unsigned char val;
1534e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			rc = Read(queryAddr++, &val, 1);
154b2191d0467eaee992eff48646c40a01d1e405597Andrew de los Reyes			if (rc < 0 || rc < 1) {
1554e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				fprintf(stderr, "Failed to read F01 Query43.%02d: %s\n", i, strerror(errno));
1564e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				continue;
1574e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			}
1584e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
1594e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			switch(i) {
1604e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				case 1:
1614e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan					m_hasPackageIDQuery = val & RMI_DEVICE_F01_QRY43_01_PACKAGE_ID;
1624e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan					m_hasBuildIDQuery = val & RMI_DEVICE_F01_QRY43_01_BUILD_ID;
1634e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan					break;
1644e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				case 2:
1654e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				case 3:
1664e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				default:
1674e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan					break;
1684e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			}
1694e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		}
1704e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
1714e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		if (m_hasPackageIDQuery) {
1724e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			rc = Read(prodInfoAddr++, infoBuf, PACKAGE_ID_BYTES);
173b2191d0467eaee992eff48646c40a01d1e405597Andrew de los Reyes			if (rc >= PACKAGE_ID_BYTES) {
1744e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				unsigned short *val = (unsigned short *)infoBuf;
1754e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				m_packageID = *val;
1764e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				val = (unsigned short *)(infoBuf + 2);
1774e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				m_packageRev = *val;
1784e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			}
1794e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		}
1804e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
1814e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		if (m_hasBuildIDQuery) {
1824e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			rc = Read(prodInfoAddr, infoBuf, BUILD_ID_BYTES);
183b2191d0467eaee992eff48646c40a01d1e405597Andrew de los Reyes			if (rc >= BUILD_ID_BYTES) {
1844e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				unsigned short *val = (unsigned short *)infoBuf;
1854e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				m_buildID = *val;
1864e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				m_buildID += infoBuf[2] * 65536;
1874e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			}
1884e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		}
1894e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	}
1904e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	return 0;
1914e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan}
1924e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
1934e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Dugganvoid RMIDevice::PrintProperties()
1944e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan{
1954e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "manufacturerID:\t\t%d\n", m_manufacturerID);
1964e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Has LTS?:\t\t%d\n", m_hasLTS);
1974e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Has Sensor ID?:\t\t%d\n", m_hasSensorID);
1984e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Has Adjustable Doze?:\t%d\n", m_hasAdjustableDoze);
1994e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Has Query 42?:\t\t%d\n", m_hasQuery42);
2004e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Date of Manufacturer:\t%s\n", m_dom);
2014e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Product ID:\t\t%s\n", m_productID);
202777d012aadce5220c1445b8923d86e95fcc60128Andrew Duggan	fprintf(stdout, "Firmware Version:\t%d.%d\n", m_firmwareVersionMajor, m_firmwareVersionMinor);
2034e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Package ID:\t\t%d\n", m_packageID);
2044e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Package Rev:\t\t%d\n", m_packageRev);
2054e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Build ID:\t\t%ld\n", m_buildID);
2064e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Sensor ID:\t\t%d\n", m_sensorID);
2074e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Has DS4 Queries?:\t%d\n", m_hasDS4Queries);
2084e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Has Multi Phys?:\t%d\n", m_hasMultiPhysical);
2094e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "\n");
2104e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan}
2114e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
2124e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Dugganint RMIDevice::Reset()
2134e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan{
2144e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	int rc;
2154e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	RMIFunction f01;
2164e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	const unsigned char deviceReset = RMI_F01_CMD_DEVICE_RESET;
2174e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
2184e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	if (!GetFunction(f01, 1))
2194e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		return -1;
2204e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
2214e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Resetting...\n");
2224e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	rc = Write(f01.GetCommandBase(), &deviceReset, 1);
223b2191d0467eaee992eff48646c40a01d1e405597Andrew de los Reyes	if (rc < 0 || rc < 1)
2244e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		return rc;
2254e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
2265d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	rc = Sleep(RMI_F01_DEFAULT_RESET_DELAY_MS);
2275d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	if (rc < 0)
2285d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan		return -1;
2294e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	fprintf(stdout, "Reset completed.\n");
2304e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	return 0;
2314e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan}
2324e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
2334e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Dugganbool RMIDevice::GetFunction(RMIFunction &func, int functionNumber)
2344e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan{
2354e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	std::vector<RMIFunction>::iterator funcIter;
2364e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
2374e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	for (funcIter = m_functionList.begin(); funcIter != m_functionList.end(); ++funcIter) {
2384e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		if (funcIter->GetFunctionNumber() == functionNumber) {
2394e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			func = *funcIter;
2404e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			return true;
2414e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		}
2424e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	}
2434e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	return false;
2444e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan}
2454e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
246e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Dugganvoid RMIDevice::PrintFunctions()
247e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan{
248e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan	std::vector<RMIFunction>::iterator funcIter;
249e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan
250e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan	for (funcIter = m_functionList.begin(); funcIter != m_functionList.end(); ++funcIter)
251bcdd7c6b1132937424c89f3ed897b6b7c9996225Andrew Duggan		fprintf(stdout, "0x%02x (%d) (%d) (0x%x): 0x%02x 0x%02x 0x%02x 0x%02x\n",
252e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan				funcIter->GetFunctionNumber(), funcIter->GetFunctionVersion(),
253bcdd7c6b1132937424c89f3ed897b6b7c9996225Andrew Duggan				funcIter->GetInterruptSourceCount(),
254bcdd7c6b1132937424c89f3ed897b6b7c9996225Andrew Duggan				funcIter->GetInterruptMask(),
255bcdd7c6b1132937424c89f3ed897b6b7c9996225Andrew Duggan				funcIter->GetDataBase(),
256e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan				funcIter->GetControlBase(), funcIter->GetCommandBase(),
257e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan				funcIter->GetQueryBase());
258e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan}
259e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan
260baf6bbac1ce5bb27f17b9c4fa9a4ab394af23542Satoshi Noguchiint RMIDevice::ScanPDT(int endFunc, int endPage)
2614e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan{
2624e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	int rc;
2634e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	unsigned int page;
264baf6bbac1ce5bb27f17b9c4fa9a4ab394af23542Satoshi Noguchi	unsigned int maxPage;
2654e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	unsigned int addr;
2664e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	unsigned char entry[RMI_DEVICE_PDT_ENTRY_SIZE];
2673020cbb062d094612429051eec89f268133799acSatoshi Noguchi	unsigned int interruptCount = 0;
2684e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
269baf6bbac1ce5bb27f17b9c4fa9a4ab394af23542Satoshi Noguchi	maxPage = (unsigned int)((endPage < 0) ? RMI_DEVICE_MAX_PAGE : endPage);
270baf6bbac1ce5bb27f17b9c4fa9a4ab394af23542Satoshi Noguchi
2714e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	m_functionList.clear();
2724e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
273baf6bbac1ce5bb27f17b9c4fa9a4ab394af23542Satoshi Noguchi	for (page = 0; page < maxPage; ++page) {
2744e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		unsigned int page_start = RMI_DEVICE_PAGE_SIZE * page;
2754e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		unsigned int pdt_start = page_start + RMI_DEVICE_PAGE_SCAN_START;
2764e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		unsigned int pdt_end = page_start + RMI_DEVICE_PAGE_SCAN_END;
2774e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		bool found = false;
2784e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
2794e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		SetRMIPage(page);
2804e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
2814e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		for (addr = pdt_start; addr >= pdt_end; addr -= RMI_DEVICE_PDT_ENTRY_SIZE) {
2824e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			rc = Read(addr, entry, RMI_DEVICE_PDT_ENTRY_SIZE);
283b2191d0467eaee992eff48646c40a01d1e405597Andrew de los Reyes			if (rc < 0 || rc < RMI_DEVICE_PDT_ENTRY_SIZE) {
2844e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				fprintf(stderr, "Failed to read PDT entry at address (0x%04x)\n", addr);
2854e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				return rc;
2864e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			}
2874e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
2883020cbb062d094612429051eec89f268133799acSatoshi Noguchi			RMIFunction func(entry, page_start, interruptCount);
2894e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			if (func.GetFunctionNumber() == 0)
2904e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan				break;
2914e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
2924e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			m_functionList.push_back(func);
2933020cbb062d094612429051eec89f268133799acSatoshi Noguchi			interruptCount += func.GetInterruptSourceCount();
2944e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			found = true;
295c14ec9ced73a2f5d243c010c9fc45cb5e4956a3aAndrew Duggan
296c14ec9ced73a2f5d243c010c9fc45cb5e4956a3aAndrew Duggan			if (func.GetFunctionNumber() == endFunc)
297c14ec9ced73a2f5d243c010c9fc45cb5e4956a3aAndrew Duggan				return 0;
2984e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan		}
2994e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
300baf6bbac1ce5bb27f17b9c4fa9a4ab394af23542Satoshi Noguchi		if (!found && (endPage < 0))
3014e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan			break;
3024e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	}
3034e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan
3043020cbb062d094612429051eec89f268133799acSatoshi Noguchi	m_numInterruptRegs = (interruptCount + 7) / 8;
3053020cbb062d094612429051eec89f268133799acSatoshi Noguchi
3064e811258783e0f1e0cdaf70e3bdb2069ce4f046Andrew Duggan	return 0;
30765e5553ace01906e5c0ac3a810afd552a2820acdAndrew Duggan}
30865e5553ace01906e5c0ac3a810afd552a2820acdAndrew Duggan
3092f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Dugganbool RMIDevice::InBootloader()
3102f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan{
3112f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan	RMIFunction f01;
3122f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan	if (GetFunction(f01, 0x01)) {
3132f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan		int rc;
3142f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan		unsigned char status;
3152f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan
3162f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan		rc = Read(f01.GetDataBase(), &status, 1);
317b2191d0467eaee992eff48646c40a01d1e405597Andrew de los Reyes		if (rc < 0 || rc < 1)
3182f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan			return true;
3192f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan
3202f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan		return !!(status & 0x40);
3212f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan	}
3222f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan	return true;
3232f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan}
3242f5c0c0f9a3164923ff7edc58e848096ae98fc18Andrew Duggan
32565e5553ace01906e5c0ac3a810afd552a2820acdAndrew Dugganlong long diff_time(struct timespec *start, struct timespec *end)
32665e5553ace01906e5c0ac3a810afd552a2820acdAndrew Duggan{
32765e5553ace01906e5c0ac3a810afd552a2820acdAndrew Duggan	long long diff;
32865e5553ace01906e5c0ac3a810afd552a2820acdAndrew Duggan	diff = (end->tv_sec - start->tv_sec) * 1000 * 1000;
32965e5553ace01906e5c0ac3a810afd552a2820acdAndrew Duggan	diff += (end->tv_nsec - start->tv_nsec) / 1000;
33065e5553ace01906e5c0ac3a810afd552a2820acdAndrew Duggan	return diff;
3315d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan}
3325d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan
3335d47750894ddaf019a016505f790c439e2eae3acAndrew Dugganint Sleep(int ms)
3345d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan{
3355d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	struct timespec ts;
3365d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	struct timespec rem;
3375d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan
3385d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	ts.tv_sec = ms / 1000;
3395d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	ts.tv_nsec = (ms % 1000) * 1000 * 1000;
3405d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	for (;;) {
3415d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan		if (nanosleep(&ts, &rem) == 0) {
3425d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan			break;
3435d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan		} else {
3445d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan			if (errno == EINTR) {
3455d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan				ts = rem;
3465d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan				continue;
3475d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan			}
3485d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan			return -1;
3495d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan		}
3505d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	}
3515d47750894ddaf019a016505f790c439e2eae3acAndrew Duggan	return 0;
352e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan}
353e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan
354e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Dugganvoid print_buffer(const unsigned char *buf, unsigned int len)
355e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan{
356e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan	for (unsigned int i = 0; i < len; ++i) {
357e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan		fprintf(stdout, "0x%02X ", buf[i]);
358e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan		if (i % 8 == 7)
359e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan			fprintf(stdout, "\n");
360e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan	}
361e9a5cd0172ce96168a9431531d259b677f331aa6Andrew Duggan	fprintf(stdout, "\n");
362b2191d0467eaee992eff48646c40a01d1e405597Andrew de los Reyes}
363