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 }