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