Home | History | Annotate | Download | only in rmidevice
      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 
     58 int 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 
     74 int 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 
    193 void 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 
    212 int 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 
    233 bool 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 
    246 void 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 
    260 int 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 
    309 bool 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 
    325 long 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 
    333 int 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 
    354 void 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