xref: /aosp_15_r20/external/rmi4utils/rmihidtool/main.cpp (revision a248dafd7653b99fc45f9d29e5f139b04f2f28bc)
1 /*
2  * Copyright (C) 2013 - 2014 Andrew Duggan
3  * Copyright (C) 2013 - 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 <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/ioctl.h>
27 #include <sys/select.h>
28 #include <getopt.h>
29 
30 #include <linux/types.h>
31 #include <linux/input.h>
32 #include <linux/hidraw.h>
33 #include <signal.h>
34 #include <stdlib.h>
35 
36 #include "hiddevice.h"
37 
38 #define RMI4UPDATE_GETOPTS      "hp:ir:w:foambd:ecnt:"
39 
40  enum rmihidtool_cmd {
41 	RMIHIDTOOL_CMD_INTERACTIVE,
42 	RMIHIDTOOL_CMD_READ,
43 	RMIHIDTOOL_CMD_WRITE,
44 	RMIHIDTOOL_CMD_FW_ID,
45 	RMIHIDTOOL_CMD_CF_ID,
46 	RMIHIDTOOL_CMD_PROPS,
47 	RMIHIDTOOL_CMD_ATTN,
48 	RMIHIDTOOL_CMD_PRINT_FUNCTIONS,
49 	RMIHIDTOOL_CMD_REBIND_DRIVER,
50 	RMIHIDTOOL_CMD_PRINT_DEVICE_INFO,
51 	RMIHIDTOOL_CMD_RESET_DEVICE,
52 };
53 
54 static int report_attn = 0;
55 static RMIDevice * g_device = NULL;
56 
print_help(const char * prog_name)57 void print_help(const char *prog_name)
58 {
59 	fprintf(stdout, "Usage: %s [OPTIONS] DEVICEFILE\n", prog_name);
60 	fprintf(stdout, "\t-h, --help\t\t\t\tPrint this message\n");
61 	fprintf(stdout, "\t-d, --device\t\t\t\thidraw device file associated with the device.\n");
62 	fprintf(stdout, "\t-p, --protocol [protocol]\t\tSet which transport prototocl to use.\n");
63 	fprintf(stdout, "\t-i, --interactive\t\t\tRun in interactive mode.\n");
64 	fprintf(stdout, "\t-r, --read [address] [length]\t\tRead registers starting at the address.\n");
65 	fprintf(stdout, "\t-w, --write [address] [length] [data]\tWrite registers starting at the address.\n");
66 	fprintf(stdout, "\t-f, --firmware-id\t\t\tPrint the firmware id\n");
67 	fprintf(stdout, "\t-c, --config-id\t\t\t\tPrint the config id\n");
68 	fprintf(stdout, "\t-o, --props\t\t\t\tPrint device properties\n");
69 	fprintf(stdout, "\t-a, --attention\t\t\t\tPrint attention reports until control + c\n");
70 	fprintf(stdout, "\t-m, --print-functions\t\t\tPrint RMI4 functions for the device.\n");
71 	fprintf(stdout, "\t-b, --rebind-driver\t\t\tRebind the driver to force an update of device properties.\n");
72 	fprintf(stdout, "\t-n, --device-info\t\t\tPrint protocol specific information about the device.\n");
73 	fprintf(stdout, "\t-e, --reset-device\t\t\tReset the device.\n");
74 	fprintf(stdout, "\t-t, --device-type\t\t\tFilter by device type [touchpad or touchscreen].\n");
75 }
76 
print_cmd_usage()77 void print_cmd_usage()
78 {
79 	fprintf(stdout, "Commands:\n");
80 	fprintf(stdout, "s [0,1,2]: Set RMIMode\n");
81 	fprintf(stdout, "r address size: read size bytes from address\n");
82 	fprintf(stdout, "w address { values }: write bytes to address\n");
83 	fprintf(stdout, "a: Wait for attention\n");
84 	fprintf(stdout, "q: quit\n");
85 }
86 
find_token(char * input,char * result,size_t result_len,char ** endpp)87 int find_token(char * input, char * result, size_t result_len, char ** endpp)
88 {
89 	int i = 0;
90 	char * start = input;
91 	char * end;
92 
93 	while (input[i] == ' ') {
94 		++start;
95 		++i;
96 	}
97 
98 	while (input[i] != '\0') {
99 		if (input[++i] == ' ')
100 			break;
101 	}
102 	end = &input[i];
103 
104 	if (start == end)
105 		return 0;
106 
107 	*endpp = end;
108 	if (static_cast<ssize_t>(result_len) < end - start + 1)
109 		return 0;
110 	strncpy(result, start, end - start);
111 	result[end - start] = '\0';
112 
113 	return 1;
114 }
115 
interactive(RMIDevice * device,unsigned char * report)116 void interactive(RMIDevice * device, unsigned char *report)
117 {
118 	char token[256];
119 	char * start;
120 	char * end;
121 	int rc;
122 
123 	for (;;) {
124 		fprintf(stdout, "\n");
125 		device->PrintDeviceInfo();
126 		fprintf(stdout, "\n");
127 		print_cmd_usage();
128 		char input[256];
129 
130 		if (fgets(input, 256, stdin)) {
131 			memset(token, 0, 256);
132 
133 			if (input[0] == 's') {
134 				start = input + 2;
135 				find_token(start, token, sizeof(token), &end);
136 				int mode = strtol(token, NULL, 0);
137 				if (mode >= 0 && mode <= 2) {
138 					if (device->SetMode(mode)) {
139 						fprintf(stderr, "Set RMI Mode to: %d\n", mode);
140 					} else {
141 						fprintf(stderr, "Set RMI Mode FAILED!\n");
142 						continue;
143 					}
144 				}
145 			} else if (input[0] == 'r') {
146 				start = input + 2;
147 				find_token(start, token, sizeof(token), &end);
148 				start = end + 1;
149 				unsigned int addr = strtol(token, NULL, 0);
150 				find_token(start, token, sizeof(token), &end);
151 				start = end + 1;
152 				unsigned int len = strtol(token, NULL, 0);
153 				fprintf(stdout, "Address = 0x%02x Length = %d\n", addr, len);
154 
155 				memset(report, 0, 256);
156 				rc = device->Read(addr, report, len);
157 				if (rc < 0)
158 					fprintf(stderr, "Failed to read report: %d\n", rc);
159 				print_buffer(report, len);
160 			} else if (input[0] == 'w') {
161 				int index = 0;
162 				start = input + 2;
163 				find_token(start, token, sizeof(token), &end);
164 				start = end + 1;
165 				unsigned int addr = strtol(token, NULL, 0);
166 				unsigned int len = 0;
167 
168 				memset(report, 0, 256);
169 				while (find_token(start, token, sizeof(token), &end)) {
170 					start = end;
171 					report[index++] = strtol(token, NULL, 0);
172 					++len;
173 				}
174 
175 				if (device->Write(addr, report, len) < 0) {
176 					fprintf(stderr, "Failed to Write Report\n");
177 					continue;
178 				}
179 			} else if (input[0] == 'a') {
180 				unsigned int bytes = 256;
181 				device->GetAttentionReport(NULL,
182 						RMI_INTERUPT_SOURCES_ALL_MASK,
183 						report, &bytes);
184 				print_buffer(report, bytes);
185 			} else if (input[0] == 'q') {
186 				return;
187 			} else {
188 				print_cmd_usage();
189 			}
190 		}
191 	}
192 }
193 
cleanup(int status)194 static void cleanup(int status)
195 {
196 	if (report_attn) {
197 		report_attn = 0;
198 		if (g_device)
199 			g_device->Cancel();
200 	} else {
201 		exit(0);
202 	}
203 }
204 
main(int argc,char ** argv)205 int main(int argc, char ** argv)
206 {
207 	int rc;
208 	struct sigaction sig_cleanup_action;
209 	int opt;
210 	int index;
211 	char *deviceName = NULL;
212 	RMIDevice *device;
213 	const char *protocol = "HID";
214 	unsigned char report[256];
215 	char token[256];
216 	enum RMIDeviceType deviceType = RMI_DEVICE_TYPE_ANY;
217 	static struct option long_options[] = {
218 		{"help", 0, NULL, 'h'},
219 		{"device", 1, NULL, 'd'},
220 		{"protocol", 1, NULL, 'p'},
221 		{"interactive", 0, NULL, 'i'},
222 		{"read", 1, NULL, 'r'},
223 		{"write", 1, NULL, 'w'},
224 		{"firmware-id", 0, NULL, 'f'},
225 		{"config-id", 0, NULL, 'c'},
226 		{"props", 0, NULL, 'o'},
227 		{"attention", 0, NULL, 'a'},
228 		{"print-functions", 0, NULL, 'm'},
229 		{"rebind-driver", 0, NULL, 'b'},
230 		{"device-info", 0, NULL, 'n'},
231 		{"reset-device", 0, NULL, 'e'},
232 		{"device-type", 1, NULL, 't'},
233 		{0, 0, 0, 0},
234 	};
235 	enum rmihidtool_cmd cmd = RMIHIDTOOL_CMD_INTERACTIVE;
236 	unsigned int addr = 0;
237 	unsigned int len = 0;
238 	char * data = NULL;
239 	char * start;
240 	char * end;
241 	int i = 0;
242 
243 	memset(&sig_cleanup_action, 0, sizeof(struct sigaction));
244 	sig_cleanup_action.sa_handler = cleanup;
245 	sig_cleanup_action.sa_flags = SA_RESTART;
246 	sigaction(SIGINT, &sig_cleanup_action, NULL);
247 
248 	while ((opt = getopt_long(argc, argv, RMI4UPDATE_GETOPTS, long_options, &index)) != -1) {
249 		switch (opt) {
250 			case 'h':
251 				print_help(argv[0]);
252 				return 0;
253 			case 'p':
254 				protocol = optarg;
255 				break;
256 			case 'd':
257 				deviceName = optarg;
258 				break;
259 			case 'i':
260 				cmd = RMIHIDTOOL_CMD_INTERACTIVE;
261 				break;
262 			case 'r':
263 				cmd = RMIHIDTOOL_CMD_READ;
264 				addr = strtol(optarg, NULL, 0);
265 				len = strtol(argv[optind++], NULL, 0);
266 				break;
267 			case 'w':
268 				cmd = RMIHIDTOOL_CMD_WRITE;
269 				addr = strtol(optarg, NULL, 0);
270 				data = argv[optind++];
271 				break;
272 			case 'f':
273 				cmd = RMIHIDTOOL_CMD_FW_ID;
274 				break;
275 			case 'c':
276 				cmd = RMIHIDTOOL_CMD_CF_ID;
277 				break;
278 			case 'o':
279 				cmd = RMIHIDTOOL_CMD_PROPS;
280 				break;
281 			case 'a':
282 				cmd = RMIHIDTOOL_CMD_ATTN;
283 				break;
284 			case 'm':
285 				cmd = RMIHIDTOOL_CMD_PRINT_FUNCTIONS;
286 				break;
287 			case 'b':
288 				cmd = RMIHIDTOOL_CMD_REBIND_DRIVER;
289 				break;
290 			case 'n':
291 				cmd = RMIHIDTOOL_CMD_PRINT_DEVICE_INFO;
292 				break;
293 			case 'e':
294 				cmd = RMIHIDTOOL_CMD_RESET_DEVICE;
295 				break;
296 			case 't':
297 				if (!strcasecmp(optarg, "touchpad"))
298 					deviceType = RMI_DEVICE_TYPE_TOUCHPAD;
299 				else if (!strcasecmp(optarg, "touchscreen"))
300 					deviceType = RMI_DEVICE_TYPE_TOUCHSCREEN;
301 				break;
302 			default:
303 				print_help(argv[0]);
304 				return 0;
305 				break;
306 
307 		}
308 	}
309 
310 	if (!strncasecmp("hid", protocol, 3)) {
311 		device = new HIDDevice();
312 	} else {
313 		fprintf(stderr, "Invalid Protocol: %s\n", protocol);
314 		return -1;
315 	}
316 
317 	if (optind != argc) {
318 		print_help(argv[0]);
319 		return -1;
320 	}
321 
322 	if (deviceName) {
323 		rc = device->Open(deviceName);
324 		if (rc) {
325 			fprintf(stderr, "%s: failed to initialize rmi device (%d): %s\n", argv[0], errno,
326 				strerror(errno));
327 			return 1;
328 		}
329 	} else {
330 		if (!device->FindDevice(deviceType))
331 			return -1;
332 	}
333 
334 	g_device = device;
335 
336 	switch (cmd) {
337 		case RMIHIDTOOL_CMD_READ:
338 			memset(report, 0, sizeof(report));
339 			rc = device->Read(addr, report, len);
340 			if (rc < 0)
341 				fprintf(stderr, "Failed to read report: %d\n", rc);
342 
343 			print_buffer(report, len);
344 			break;
345 		case RMIHIDTOOL_CMD_WRITE:
346 			i = 0;
347 			start = data;
348 			memset(report, 0, sizeof(report));
349 			while (find_token(start, token, sizeof(token), &end)) {
350 				start = end;
351 				report[i++] = (unsigned char)strtol(token, NULL, 0);
352 				++len;
353 			}
354 
355 			if (device->Write(addr, report, len) < 0) {
356 				fprintf(stderr, "Failed to Write Report\n");
357 				return -1;
358 			}
359 			break;
360 		case RMIHIDTOOL_CMD_FW_ID:
361 			device->ScanPDT();
362 			device->QueryBasicProperties();
363 			fprintf(stdout, "firmware id: %lu\n", device->GetFirmwareID());
364 			break;
365 		case RMIHIDTOOL_CMD_CF_ID:
366 			device->ScanPDT();
367 			device->QueryBasicProperties();
368 			fprintf(stdout, "config id: %08lx\n", device->GetConfigID());
369 			break;
370 		case RMIHIDTOOL_CMD_PROPS:
371 			device->ScanPDT();
372 			device->QueryBasicProperties();
373 			device->PrintProperties();
374 			break;
375 		case RMIHIDTOOL_CMD_ATTN:
376 			report_attn = 1;
377 			while(report_attn) {
378 				unsigned int bytes = 256;
379 				rc = device->GetAttentionReport(NULL,
380 						RMI_INTERUPT_SOURCES_ALL_MASK,
381 						report, &bytes);
382 				if (rc > 0) {
383 					print_buffer(report, bytes);
384 					fprintf(stdout, "\n");
385 				}
386 			}
387 			break;
388 		case RMIHIDTOOL_CMD_PRINT_FUNCTIONS:
389 			device->ScanPDT();
390 			device->PrintFunctions();
391 			break;
392 		case RMIHIDTOOL_CMD_REBIND_DRIVER:
393 			device->RebindDriver();
394 			break;
395 		case RMIHIDTOOL_CMD_PRINT_DEVICE_INFO:
396 			device->PrintDeviceInfo();
397 			break;
398 		case RMIHIDTOOL_CMD_RESET_DEVICE:
399 			device->ScanPDT();
400 			device->Reset();
401 			break;
402 		case RMIHIDTOOL_CMD_INTERACTIVE:
403 		default:
404 			interactive(device, report);
405 			break;
406 	}
407 
408 	device->Close();
409 
410 	return 0;
411 }
412