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 52static int report_attn = 0; 53static RMIDevice * g_device = NULL; 54 55void 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 72void 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 82int 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 111void 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 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; 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