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