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