blob: f8a177046cd7591c765eae2745b8f05bf0e783ec [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 Duggane9a5cd02014-04-29 13:34:42 -070037#define RMI4UPDATE_GETOPTS "hp:ir:w:foam"
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};
Andrew Duggan63078d52014-04-08 11:20:15 -070048
Andrew Duggan4e811252014-04-03 15:17:57 -070049static int report_attn = 0;
Andrew Duggan63078d52014-04-08 11:20:15 -070050static RMIDevice * g_device = NULL;
51
Andrew Duggane9a5cd02014-04-29 13:34:42 -070052void print_help(const char *prog_name)
Andrew Duggan63078d52014-04-08 11:20:15 -070053{
Andrew Duggane9a5cd02014-04-29 13:34:42 -070054 fprintf(stdout, "Usage: %s [OPTIONS] DEVICEFILE\n", prog_name);
55 fprintf(stdout, "\t-h, --help\t\t\t\tPrint this message\n");
56 fprintf(stdout, "\t-p, --protocol [protocol]\t\tSet which transport prototocl to use.\n");
57 fprintf(stdout, "\t-i, --interactive\t\t\tRun in interactive mode.\n");
58 fprintf(stdout, "\t-r, --read [address] [length]\t\tRead registers starting at the address.\n");
59 fprintf(stdout, "\t-r, --write [address] [length] [data]\tWrite registers starting at the address.\n");
60 fprintf(stdout, "\t-f, --firmware-id\t\t\tPrint the firmware id\n");
61 fprintf(stdout, "\t-o, --props\t\t\t\tPrint device properties\n");
62 fprintf(stdout, "\t-a, --attention\t\t\t\tPrint attention reports until control + c\n");
63 fprintf(stdout, "\t-m, --print-functions\t\t\tPrint RMI4 functions for the device.\n");
Andrew Duggan63078d52014-04-08 11:20:15 -070064}
Andrew Duggan4e811252014-04-03 15:17:57 -070065
Andrew Duggane9a5cd02014-04-29 13:34:42 -070066void print_cmd_usage()
Andrew Duggan4e811252014-04-03 15:17:57 -070067{
68 fprintf(stdout, "Commands:\n");
69 fprintf(stdout, "s [0,1,2]: Set RMIMode\n");
70 fprintf(stdout, "r address size: read size bytes from address\n");
71 fprintf(stdout, "w address { values }: write bytes to address\n");
72 fprintf(stdout, "a: Wait for attention\n");
73 fprintf(stdout, "q: quit\n");
74}
75
76int find_token(char * input, char * result, char ** endpp)
77{
78 int i = 0;
79 char * start = input;
80 char * end;
81
82 while (input[i] == ' ') {
83 ++start;
84 ++i;
85 }
86
87 while (input[i] != '\0') {
88 ++i;
89 if (input[i] == ' ') {
90 break;
91 }
92 }
93 end = &input[i];
94
Andrew Duggane9a5cd02014-04-29 13:34:42 -070095 if (start == end)
Andrew Duggan4e811252014-04-03 15:17:57 -070096 return 0;
Andrew Duggan4e811252014-04-03 15:17:57 -070097
98 *endpp = end;
99 strncpy(result, start, end - start);
100 result[end - start + 1] = '\0';
101
102 return 1;
103}
104
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700105
106
107void interactive(RMIDevice * device, unsigned char *report)
Andrew Duggan4e811252014-04-03 15:17:57 -0700108{
Andrew Duggan4e811252014-04-03 15:17:57 -0700109 char token[256];
110 char * start;
111 char * end;
112 int rc;
113
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700114 for (;;) {
Andrew Duggan4e811252014-04-03 15:17:57 -0700115 fprintf(stdout, "\n");
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700116 print_cmd_usage();
117 char input[256];
Andrew Duggan4e811252014-04-03 15:17:57 -0700118
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700119 if (fgets(input, 256, stdin)) {
120 memset(token, 0, 256);
Andrew Duggan4e811252014-04-03 15:17:57 -0700121
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700122 if (input[0] == 's') {
123 start = input + 2;
124 find_token(start, token, &end);
125 int mode = strtol(token, NULL, 0);
126 if (mode >= 0 && mode <= 2) {
127 if (device->SetMode(mode)) {
128 fprintf(stderr, "Set RMI Mode to: %d\n", mode);
129 } else {
130 fprintf(stderr, "Set RMI Mode FAILED!\n");
131 continue;
132 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700133 }
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700134 } else if (input[0] == 'r') {
135 start = input + 2;
136 find_token(start, token, &end);
137 start = end + 1;
138 unsigned int addr = strtol(token, NULL, 0);
139 find_token(start, token, &end);
140 start = end + 1;
141 unsigned int len = strtol(token, NULL, 0);
142 fprintf(stdout, "Address = 0x%02x Length = %d\n", addr, len);
143
144 memset(report, 0, 256);
145 rc = device->Read(addr, report, len);
146 if (rc < 0)
147 fprintf(stderr, "Failed to read report: %d\n", rc);
148 print_buffer(report, len);
149 } else if (input[0] == 'w') {
150 int index = 0;
151 start = input + 2;
152 find_token(start, token, &end);
153 start = end + 1;
154 unsigned int addr = strtol(token, NULL, 0);
155 unsigned int len = 0;
156
157 memset(report, 0, 256);
158 while (find_token(start, token, &end)) {
159 start = end;
160 report[index] = strtol(token, NULL, 0);
161 ++index;
162 ++len;
163 }
164
165 if (device->Write(addr, report, len) < 0) {
166 fprintf(stderr, "Failed to Write Report\n");
167 continue;
168 }
169 } else if (input[0] == 'a') {
170 unsigned int bytes = 256;
171 device->GetAttentionReport(NULL, NULL, report, &bytes);
172 print_buffer(report, bytes);
173 } else if (input[0] == 'q') {
174 return;
175 } else {
176 print_cmd_usage();
Andrew Duggan4e811252014-04-03 15:17:57 -0700177 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700178 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700179 }
Andrew Duggan4e811252014-04-03 15:17:57 -0700180}
181
182static void cleanup(int status)
183{
184 if (report_attn) {
185 report_attn = 0;
186 if (g_device)
187 g_device->Cancel();
188 } else {
189 exit(0);
190 }
191}
192
193int main(int argc, char ** argv)
194{
195 int rc;
196 struct sigaction sig_cleanup_action;
Andrew Duggan63078d52014-04-08 11:20:15 -0700197 int opt;
198 int index;
199 RMIDevice *device;
200 const char *protocol = "HID";
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700201 unsigned char report[256];
202 char token[256];
Andrew Duggan63078d52014-04-08 11:20:15 -0700203 static struct option long_options[] = {
204 {"help", 0, NULL, 'h'},
205 {"protocol", 1, NULL, 'p'},
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700206 {"interactive", 0, NULL, 'i'},
207 {"read", 1, NULL, 'r'},
208 {"write", 1, NULL, 'w'},
209 {"firmware-id", 0, NULL, 'f'},
210 {"props", 0, NULL, 'o'},
211 {"attention", 0, NULL, 'a'},
212 {"print-functions", 0, NULL, 'm'},
Andrew Duggan63078d52014-04-08 11:20:15 -0700213 {0, 0, 0, 0},
214 };
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700215 enum rmihidtool_cmd cmd = RMIHIDTOOL_CMD_INTERACTIVE;
Andrew Duggan8b79f312014-05-16 13:26:09 -0700216 unsigned int addr = 0;
217 unsigned int len = 0;
218 char * data = NULL;
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700219 char * start;
220 char * end;
Andrew Duggan4e811252014-04-03 15:17:57 -0700221
222 memset(&sig_cleanup_action, 0, sizeof(struct sigaction));
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700223 sig_cleanup_action.sa_handler = cleanup;
224 sig_cleanup_action.sa_flags = SA_RESTART;
225 sigaction(SIGINT, &sig_cleanup_action, NULL);
Andrew Duggan4e811252014-04-03 15:17:57 -0700226
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700227 while ((opt = getopt_long(argc, argv, RMI4UPDATE_GETOPTS, long_options, &index)) != -1) {
228 switch (opt) {
229 case 'h':
230 print_help(argv[0]);
231 return 0;
232 case 'p':
233 protocol = optarg;
234 break;
235 case 'i':
236 cmd = RMIHIDTOOL_CMD_INTERACTIVE;
237 break;
238 case 'r':
239 cmd = RMIHIDTOOL_CMD_READ;
240 addr = strtol(optarg, NULL, 0);
241 len = strtol(argv[optind++], NULL, 0);
242 break;
243 case 'w':
244 cmd = RMIHIDTOOL_CMD_WRITE;
245 addr = strtol(optarg, NULL, 0);
246 data = argv[optind++];
247 break;
248 case 'f':
249 cmd = RMIHIDTOOL_CMD_FW_ID;
250 break;
251 case 'o':
252 cmd = RMIHIDTOOL_CMD_PROPS;
253 break;
254 case 'a':
255 cmd = RMIHIDTOOL_CMD_ATTN;
256 break;
257 case 'm':
258 cmd = RMIHIDTOOL_CMD_PRINT_FUNCTIONS;
259 break;
260 default:
261 print_help(argv[0]);
262 return 0;
263 break;
Andrew Duggan63078d52014-04-08 11:20:15 -0700264
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700265 }
266 }
Andrew Duggan63078d52014-04-08 11:20:15 -0700267
268 if (!strncasecmp("hid", protocol, 3)) {
269 device = new HIDDevice();
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700270 } else {
Andrew Duggan63078d52014-04-08 11:20:15 -0700271 fprintf(stderr, "Invalid Protocol: %s\n", protocol);
272 return -1;
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700273 }
Andrew Duggan63078d52014-04-08 11:20:15 -0700274
Andrew Duggan4667eb72014-04-29 13:37:42 -0700275 if (optind >= argc) {
276 print_help(argv[0]);
277 return -1;
278 }
279
Andrew Duggan63078d52014-04-08 11:20:15 -0700280 rc = device->Open(argv[optind++]);
Andrew Duggan4e811252014-04-03 15:17:57 -0700281 if (rc) {
Andrew Duggan63078d52014-04-08 11:20:15 -0700282 fprintf(stderr, "%s: failed to initialize rmi device (%d): %s\n", argv[0], errno,
283 strerror(errno));
Andrew Duggan4e811252014-04-03 15:17:57 -0700284 return 1;
285 }
286
Andrew Duggan63078d52014-04-08 11:20:15 -0700287 g_device = device;
Andrew Duggan4e811252014-04-03 15:17:57 -0700288
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700289 switch (cmd) {
290 case RMIHIDTOOL_CMD_READ:
291 memset(report, 0, sizeof(report));
292 rc = device->Read(addr, report, len);
293 if (rc < 0)
294 fprintf(stderr, "Failed to read report: %d\n", rc);
Andrew Duggan4e811252014-04-03 15:17:57 -0700295
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700296 print_buffer(report, len);
297 break;
298 case RMIHIDTOOL_CMD_WRITE:
299 start = data;
300 memset(report, 0, sizeof(report));
301 while (find_token(start, token, &end)) {
302 start = end;
303 report[index++] = (unsigned char)strtol(token, NULL, 0);
304 ++len;
305 }
306
307 if (device->Write(addr, report, len) < 0) {
308 fprintf(stderr, "Failed to Write Report\n");
309 return -1;
310 }
311 break;
312 case RMIHIDTOOL_CMD_FW_ID:
313 device->ScanPDT();
314 device->QueryBasicProperties();
315 fprintf(stdout, "firmware id: %lu\n", device->GetFirmwareID());
316 break;
317 case RMIHIDTOOL_CMD_PROPS:
318 device->ScanPDT();
319 device->QueryBasicProperties();
320 device->PrintProperties();
321 break;
322 case RMIHIDTOOL_CMD_ATTN:
323 report_attn = 1;
324 while(report_attn) {
325 unsigned int bytes = 256;
Andrew Dugganf6e278f2014-10-07 21:58:02 -0700326 rc = device->GetAttentionReport(NULL, NULL, report, &bytes);
327 if (rc > 0) {
328 print_buffer(report, bytes);
329 fprintf(stdout, "\n");
330 }
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700331 }
332 break;
333 case RMIHIDTOOL_CMD_PRINT_FUNCTIONS:
334 device->ScanPDT();
335 device->PrintFunctions();
336 break;
337 case RMIHIDTOOL_CMD_INTERACTIVE:
338 default:
339 interactive(device, report);
340 break;
Andrew Duggan4e811252014-04-03 15:17:57 -0700341 }
342
Andrew Duggan63078d52014-04-08 11:20:15 -0700343 device->Close();
Andrew Duggan4e811252014-04-03 15:17:57 -0700344
345 return 0;
Andrew Duggane9a5cd02014-04-29 13:34:42 -0700346}