blob: 0fc2b1acd9a2635bb364de3f56e37439d5bbec5d [file] [log] [blame]
Andrew Duggan052556f2014-04-16 11:32:30 -07001/*
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
Andrew Duggan4e811252014-04-03 15:17:57 -070018#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>
Andrew Duggan63078d52014-04-08 11:20:15 -070027#include <getopt.h>
Andrew Duggan4e811252014-04-03 15:17:57 -070028
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
Andrew Duggana0d74e02015-05-11 15:50:59 -070037#define RMI4UPDATE_GETOPTS "hp:ir:w:foambde"
Andrew Duggane9a5cd02014-04-29 13:34:42 -070038
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,
Andrew Duggan161c83c2015-05-06 18:06:03 -070047 RMIHIDTOOL_CMD_REBIND_DRIVER,
Andrew Duggan2c24adb2015-05-06 18:18:06 -070048 RMIHIDTOOL_CMD_PRINT_DEVICE_INFO,
Andrew Duggana0d74e02015-05-11 15:50:59 -070049 RMIHIDTOOL_CMD_RESET_DEVICE,
Andrew Duggane9a5cd02014-04-29 13:34:42 -070050};
Andrew Duggan63078d52014-04-08 11:20:15 -070051
Andrew Duggan4e811252014-04-03 15:17:57 -070052static int report_attn = 0;
Andrew Duggan63078d52014-04-08 11:20:15 -070053static RMIDevice * g_device = NULL;
54
Andrew Duggane9a5cd02014-04-29 13:34:42 -070055void print_help(const char *prog_name)
Andrew Duggan63078d52014-04-08 11:20:15 -070056{
Andrew Duggane9a5cd02014-04-29 13:34:42 -070057 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");
Andrew Duggan161c83c2015-05-06 18:06:03 -070067 fprintf(stdout, "\t-b, --rebind-driver\t\t\tRebind the driver to force an update of device properties.\n");
Andrew Duggan2c24adb2015-05-06 18:18:06 -070068 fprintf(stdout, "\t-d, --device-info\t\t\tPrint protocol specific information about the device.\n");
Andrew Duggana0d74e02015-05-11 15:50:59 -070069 fprintf(stdout, "\t-e, --reset-device\t\t\tReset the device.\n");
Andrew Duggan63078d52014-04-08 11:20:15 -070070}
Andrew Duggan4e811252014-04-03 15:17:57 -070071
Andrew Duggane9a5cd02014-04-29 13:34:42 -070072void print_cmd_usage()
Andrew Duggan4e811252014-04-03 15:17:57 -070073{
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
Andrew de los Reyes6f1ac592015-09-04 15:44:57 -070082int find_token(char * input, char * result, size_t result_len, char ** endpp)
Andrew Duggan4e811252014-04-03 15:17:57 -070083{
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') {
Andrew Duggan849fea32014-11-13 21:15:48 -080094 if (input[++i] == ' ')
Andrew Duggan4e811252014-04-03 15:17:57 -070095 break;
Andrew Duggan4e811252014-04-03 15:17:57 -070096 }
97 end = &input[i];
98
Andrew Duggane9a5cd02014-04-29 13:34:42 -070099 if (start == end)
Andrew Duggan4e811252014-04-03 15:17:57 -0700100 return 0;
Andrew Duggan4e811252014-04-03 15:17:57 -0700101
102 *endpp = end;
Andrew de los Reyes6f1ac592015-09-04 15:44:57 -0700103 if (static_cast<ssize_t>(result_len) < end - start + 1)
104 return 0;
Andrew Duggan4e811252014-04-03 15:17:57 -0700105 strncpy(result, start, end - start);
Andrew Duggan849fea32014-11-13 21:15:48 -0800106 result[end - start] = '\0';
Andrew Duggan4e811252014-04-03 15:17:57 -0700107
108 return 1;
109}
110
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700111void interactive(RMIDevice * device, unsigned char *report)
Andrew Duggan4e811252014-04-03 15:17:57 -0700112{
Andrew Duggan4e811252014-04-03 15:17:57 -0700113 char token[256];
114 char * start;
115 char * end;
116 int rc;
117
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700118 for (;;) {
Andrew Duggan4e811252014-04-03 15:17:57 -0700119 fprintf(stdout, "\n");
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700120 print_cmd_usage();
121 char input[256];
Andrew Duggan4e811252014-04-03 15:17:57 -0700122
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700123 if (fgets(input, 256, stdin)) {
124 memset(token, 0, 256);
Andrew Duggan4e811252014-04-03 15:17:57 -0700125
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700126 if (input[0] == 's') {
127 start = input + 2;
Andrew de los Reyes6f1ac592015-09-04 15:44:57 -0700128 find_token(start, token, sizeof(token), &end);
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700129 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 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700137 }
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700138 } else if (input[0] == 'r') {
139 start = input + 2;
Andrew de los Reyes6f1ac592015-09-04 15:44:57 -0700140 find_token(start, token, sizeof(token), &end);
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700141 start = end + 1;
142 unsigned int addr = strtol(token, NULL, 0);
Andrew de los Reyes6f1ac592015-09-04 15:44:57 -0700143 find_token(start, token, sizeof(token), &end);
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700144 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;
Andrew de los Reyes6f1ac592015-09-04 15:44:57 -0700156 find_token(start, token, sizeof(token), &end);
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700157 start = end + 1;
158 unsigned int addr = strtol(token, NULL, 0);
159 unsigned int len = 0;
160
161 memset(report, 0, 256);
Andrew de los Reyes6f1ac592015-09-04 15:44:57 -0700162 while (find_token(start, token, sizeof(token), &end)) {
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700163 start = end;
Andrew Duggan849fea32014-11-13 21:15:48 -0800164 report[index++] = strtol(token, NULL, 0);
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700165 ++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;
Andrew Dugganf73fdc72014-11-09 11:02:22 -0800174 device->GetAttentionReport(NULL,
175 RMI_INTERUPT_SOURCES_ALL_MASK,
176 report, &bytes);
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700177 print_buffer(report, bytes);
178 } else if (input[0] == 'q') {
179 return;
180 } else {
181 print_cmd_usage();
Andrew Duggan4e811252014-04-03 15:17:57 -0700182 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700183 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700184 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700185}
186
187static 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
198int main(int argc, char ** argv)
199{
200 int rc;
201 struct sigaction sig_cleanup_action;
Andrew Duggan63078d52014-04-08 11:20:15 -0700202 int opt;
203 int index;
204 RMIDevice *device;
205 const char *protocol = "HID";
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700206 unsigned char report[256];
207 char token[256];
Andrew Duggan63078d52014-04-08 11:20:15 -0700208 static struct option long_options[] = {
209 {"help", 0, NULL, 'h'},
210 {"protocol", 1, NULL, 'p'},
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700211 {"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'},
Andrew Duggan161c83c2015-05-06 18:06:03 -0700218 {"rebind-driver", 0, NULL, 'b'},
Andrew Duggan2c24adb2015-05-06 18:18:06 -0700219 {"device-info", 0, NULL, 'd'},
Andrew Duggana0d74e02015-05-11 15:50:59 -0700220 {"reset-device", 0, NULL, 'e'},
Andrew Duggan63078d52014-04-08 11:20:15 -0700221 {0, 0, 0, 0},
222 };
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700223 enum rmihidtool_cmd cmd = RMIHIDTOOL_CMD_INTERACTIVE;
Andrew Duggan8b79f312014-05-16 13:26:09 -0700224 unsigned int addr = 0;
225 unsigned int len = 0;
226 char * data = NULL;
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700227 char * start;
228 char * end;
Andrew Duggan849fea32014-11-13 21:15:48 -0800229 int i = 0;
Andrew Duggan4e811252014-04-03 15:17:57 -0700230
231 memset(&sig_cleanup_action, 0, sizeof(struct sigaction));
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700232 sig_cleanup_action.sa_handler = cleanup;
233 sig_cleanup_action.sa_flags = SA_RESTART;
234 sigaction(SIGINT, &sig_cleanup_action, NULL);
Andrew Duggan4e811252014-04-03 15:17:57 -0700235
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700236 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;
Andrew Duggan161c83c2015-05-06 18:06:03 -0700269 case 'b':
270 cmd = RMIHIDTOOL_CMD_REBIND_DRIVER;
271 break;
Andrew Duggan2c24adb2015-05-06 18:18:06 -0700272 case 'd':
273 cmd = RMIHIDTOOL_CMD_PRINT_DEVICE_INFO;
274 break;
Andrew Duggana0d74e02015-05-11 15:50:59 -0700275 case 'e':
276 cmd = RMIHIDTOOL_CMD_RESET_DEVICE;
277 break;
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700278 default:
279 print_help(argv[0]);
280 return 0;
281 break;
Andrew Duggan63078d52014-04-08 11:20:15 -0700282
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700283 }
284 }
Andrew Duggan63078d52014-04-08 11:20:15 -0700285
286 if (!strncasecmp("hid", protocol, 3)) {
287 device = new HIDDevice();
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700288 } else {
Andrew Duggan63078d52014-04-08 11:20:15 -0700289 fprintf(stderr, "Invalid Protocol: %s\n", protocol);
290 return -1;
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700291 }
Andrew Duggan63078d52014-04-08 11:20:15 -0700292
Andrew Duggan4667eb72014-04-29 13:37:42 -0700293 if (optind >= argc) {
294 print_help(argv[0]);
295 return -1;
296 }
297
Andrew Duggan63078d52014-04-08 11:20:15 -0700298 rc = device->Open(argv[optind++]);
Andrew Duggan4e811252014-04-03 15:17:57 -0700299 if (rc) {
Andrew Duggan63078d52014-04-08 11:20:15 -0700300 fprintf(stderr, "%s: failed to initialize rmi device (%d): %s\n", argv[0], errno,
301 strerror(errno));
Andrew Duggan4e811252014-04-03 15:17:57 -0700302 return 1;
303 }
304
Andrew Duggan63078d52014-04-08 11:20:15 -0700305 g_device = device;
Andrew Duggan4e811252014-04-03 15:17:57 -0700306
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700307 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);
Andrew Duggan4e811252014-04-03 15:17:57 -0700313
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700314 print_buffer(report, len);
315 break;
316 case RMIHIDTOOL_CMD_WRITE:
Andrew Duggan849fea32014-11-13 21:15:48 -0800317 i = 0;
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700318 start = data;
319 memset(report, 0, sizeof(report));
Andrew de los Reyes6f1ac592015-09-04 15:44:57 -0700320 while (find_token(start, token, sizeof(token), &end)) {
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700321 start = end;
Andrew Duggan849fea32014-11-13 21:15:48 -0800322 report[i++] = (unsigned char)strtol(token, NULL, 0);
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700323 ++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;
Andrew Dugganf73fdc72014-11-09 11:02:22 -0800345 rc = device->GetAttentionReport(NULL,
346 RMI_INTERUPT_SOURCES_ALL_MASK,
347 report, &bytes);
Andrew Dugganf6e278f2014-10-07 21:58:02 -0700348 if (rc > 0) {
349 print_buffer(report, bytes);
350 fprintf(stdout, "\n");
351 }
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700352 }
353 break;
354 case RMIHIDTOOL_CMD_PRINT_FUNCTIONS:
355 device->ScanPDT();
356 device->PrintFunctions();
357 break;
Andrew Duggan161c83c2015-05-06 18:06:03 -0700358 case RMIHIDTOOL_CMD_REBIND_DRIVER:
359 device->RebindDriver();
360 break;
Andrew Duggan2c24adb2015-05-06 18:18:06 -0700361 case RMIHIDTOOL_CMD_PRINT_DEVICE_INFO:
362 device->PrintDeviceInfo();
363 break;
Andrew Duggana0d74e02015-05-11 15:50:59 -0700364 case RMIHIDTOOL_CMD_RESET_DEVICE:
365 device->ScanPDT();
366 device->Reset();
367 break;
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700368 case RMIHIDTOOL_CMD_INTERACTIVE:
369 default:
370 interactive(device, report);
371 break;
Andrew Duggan4e811252014-04-03 15:17:57 -0700372 }
373
Andrew Duggan63078d52014-04-08 11:20:15 -0700374 device->Close();
Andrew Duggan4e811252014-04-03 15:17:57 -0700375
376 return 0;
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700377}