| /* |
| * Copyright (C) 2013 - 2014 Andrew Duggan |
| * Copyright (C) 2013 - 2014 Synaptics Inc |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <stdio.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <sys/ioctl.h> |
| #include <sys/select.h> |
| #include <getopt.h> |
| |
| #include <linux/types.h> |
| #include <linux/input.h> |
| #include <linux/hidraw.h> |
| #include <signal.h> |
| #include <stdlib.h> |
| |
| #include "hiddevice.h" |
| |
| #define RMI4UPDATE_GETOPTS "hp:ir:w:foambde" |
| |
| enum rmihidtool_cmd { |
| RMIHIDTOOL_CMD_INTERACTIVE, |
| RMIHIDTOOL_CMD_READ, |
| RMIHIDTOOL_CMD_WRITE, |
| RMIHIDTOOL_CMD_FW_ID, |
| RMIHIDTOOL_CMD_PROPS, |
| RMIHIDTOOL_CMD_ATTN, |
| RMIHIDTOOL_CMD_PRINT_FUNCTIONS, |
| RMIHIDTOOL_CMD_REBIND_DRIVER, |
| RMIHIDTOOL_CMD_PRINT_DEVICE_INFO, |
| RMIHIDTOOL_CMD_RESET_DEVICE, |
| }; |
| |
| static int report_attn = 0; |
| static RMIDevice * g_device = NULL; |
| |
| void print_help(const char *prog_name) |
| { |
| fprintf(stdout, "Usage: %s [OPTIONS] DEVICEFILE\n", prog_name); |
| fprintf(stdout, "\t-h, --help\t\t\t\tPrint this message\n"); |
| fprintf(stdout, "\t-p, --protocol [protocol]\t\tSet which transport prototocl to use.\n"); |
| fprintf(stdout, "\t-i, --interactive\t\t\tRun in interactive mode.\n"); |
| fprintf(stdout, "\t-r, --read [address] [length]\t\tRead registers starting at the address.\n"); |
| fprintf(stdout, "\t-r, --write [address] [length] [data]\tWrite registers starting at the address.\n"); |
| fprintf(stdout, "\t-f, --firmware-id\t\t\tPrint the firmware id\n"); |
| fprintf(stdout, "\t-o, --props\t\t\t\tPrint device properties\n"); |
| fprintf(stdout, "\t-a, --attention\t\t\t\tPrint attention reports until control + c\n"); |
| fprintf(stdout, "\t-m, --print-functions\t\t\tPrint RMI4 functions for the device.\n"); |
| fprintf(stdout, "\t-b, --rebind-driver\t\t\tRebind the driver to force an update of device properties.\n"); |
| fprintf(stdout, "\t-d, --device-info\t\t\tPrint protocol specific information about the device.\n"); |
| fprintf(stdout, "\t-e, --reset-device\t\t\tReset the device.\n"); |
| } |
| |
| void print_cmd_usage() |
| { |
| fprintf(stdout, "Commands:\n"); |
| fprintf(stdout, "s [0,1,2]: Set RMIMode\n"); |
| fprintf(stdout, "r address size: read size bytes from address\n"); |
| fprintf(stdout, "w address { values }: write bytes to address\n"); |
| fprintf(stdout, "a: Wait for attention\n"); |
| fprintf(stdout, "q: quit\n"); |
| } |
| |
| int find_token(char * input, char * result, size_t result_len, char ** endpp) |
| { |
| int i = 0; |
| char * start = input; |
| char * end; |
| |
| while (input[i] == ' ') { |
| ++start; |
| ++i; |
| } |
| |
| while (input[i] != '\0') { |
| if (input[++i] == ' ') |
| break; |
| } |
| end = &input[i]; |
| |
| if (start == end) |
| return 0; |
| |
| *endpp = end; |
| if (static_cast<ssize_t>(result_len) < end - start + 1) |
| return 0; |
| strncpy(result, start, end - start); |
| result[end - start] = '\0'; |
| |
| return 1; |
| } |
| |
| void interactive(RMIDevice * device, unsigned char *report) |
| { |
| char token[256]; |
| char * start; |
| char * end; |
| int rc; |
| |
| for (;;) { |
| fprintf(stdout, "\n"); |
| print_cmd_usage(); |
| char input[256]; |
| |
| if (fgets(input, 256, stdin)) { |
| memset(token, 0, 256); |
| |
| if (input[0] == 's') { |
| start = input + 2; |
| find_token(start, token, sizeof(token), &end); |
| int mode = strtol(token, NULL, 0); |
| if (mode >= 0 && mode <= 2) { |
| if (device->SetMode(mode)) { |
| fprintf(stderr, "Set RMI Mode to: %d\n", mode); |
| } else { |
| fprintf(stderr, "Set RMI Mode FAILED!\n"); |
| continue; |
| } |
| } |
| } else if (input[0] == 'r') { |
| start = input + 2; |
| find_token(start, token, sizeof(token), &end); |
| start = end + 1; |
| unsigned int addr = strtol(token, NULL, 0); |
| find_token(start, token, sizeof(token), &end); |
| start = end + 1; |
| unsigned int len = strtol(token, NULL, 0); |
| fprintf(stdout, "Address = 0x%02x Length = %d\n", addr, len); |
| |
| memset(report, 0, 256); |
| rc = device->Read(addr, report, len); |
| if (rc < 0) |
| fprintf(stderr, "Failed to read report: %d\n", rc); |
| print_buffer(report, len); |
| } else if (input[0] == 'w') { |
| int index = 0; |
| start = input + 2; |
| find_token(start, token, sizeof(token), &end); |
| start = end + 1; |
| unsigned int addr = strtol(token, NULL, 0); |
| unsigned int len = 0; |
| |
| memset(report, 0, 256); |
| while (find_token(start, token, sizeof(token), &end)) { |
| start = end; |
| report[index++] = strtol(token, NULL, 0); |
| ++len; |
| } |
| |
| if (device->Write(addr, report, len) < 0) { |
| fprintf(stderr, "Failed to Write Report\n"); |
| continue; |
| } |
| } else if (input[0] == 'a') { |
| unsigned int bytes = 256; |
| device->GetAttentionReport(NULL, |
| RMI_INTERUPT_SOURCES_ALL_MASK, |
| report, &bytes); |
| print_buffer(report, bytes); |
| } else if (input[0] == 'q') { |
| return; |
| } else { |
| print_cmd_usage(); |
| } |
| } |
| } |
| } |
| |
| static void cleanup(int status) |
| { |
| if (report_attn) { |
| report_attn = 0; |
| if (g_device) |
| g_device->Cancel(); |
| } else { |
| exit(0); |
| } |
| } |
| |
| int main(int argc, char ** argv) |
| { |
| int rc; |
| struct sigaction sig_cleanup_action; |
| int opt; |
| int index; |
| RMIDevice *device; |
| const char *protocol = "HID"; |
| unsigned char report[256]; |
| char token[256]; |
| static struct option long_options[] = { |
| {"help", 0, NULL, 'h'}, |
| {"protocol", 1, NULL, 'p'}, |
| {"interactive", 0, NULL, 'i'}, |
| {"read", 1, NULL, 'r'}, |
| {"write", 1, NULL, 'w'}, |
| {"firmware-id", 0, NULL, 'f'}, |
| {"props", 0, NULL, 'o'}, |
| {"attention", 0, NULL, 'a'}, |
| {"print-functions", 0, NULL, 'm'}, |
| {"rebind-driver", 0, NULL, 'b'}, |
| {"device-info", 0, NULL, 'd'}, |
| {"reset-device", 0, NULL, 'e'}, |
| {0, 0, 0, 0}, |
| }; |
| enum rmihidtool_cmd cmd = RMIHIDTOOL_CMD_INTERACTIVE; |
| unsigned int addr = 0; |
| unsigned int len = 0; |
| char * data = NULL; |
| char * start; |
| char * end; |
| int i = 0; |
| |
| memset(&sig_cleanup_action, 0, sizeof(struct sigaction)); |
| sig_cleanup_action.sa_handler = cleanup; |
| sig_cleanup_action.sa_flags = SA_RESTART; |
| sigaction(SIGINT, &sig_cleanup_action, NULL); |
| |
| while ((opt = getopt_long(argc, argv, RMI4UPDATE_GETOPTS, long_options, &index)) != -1) { |
| switch (opt) { |
| case 'h': |
| print_help(argv[0]); |
| return 0; |
| case 'p': |
| protocol = optarg; |
| break; |
| case 'i': |
| cmd = RMIHIDTOOL_CMD_INTERACTIVE; |
| break; |
| case 'r': |
| cmd = RMIHIDTOOL_CMD_READ; |
| addr = strtol(optarg, NULL, 0); |
| len = strtol(argv[optind++], NULL, 0); |
| break; |
| case 'w': |
| cmd = RMIHIDTOOL_CMD_WRITE; |
| addr = strtol(optarg, NULL, 0); |
| data = argv[optind++]; |
| break; |
| case 'f': |
| cmd = RMIHIDTOOL_CMD_FW_ID; |
| break; |
| case 'o': |
| cmd = RMIHIDTOOL_CMD_PROPS; |
| break; |
| case 'a': |
| cmd = RMIHIDTOOL_CMD_ATTN; |
| break; |
| case 'm': |
| cmd = RMIHIDTOOL_CMD_PRINT_FUNCTIONS; |
| break; |
| case 'b': |
| cmd = RMIHIDTOOL_CMD_REBIND_DRIVER; |
| break; |
| case 'd': |
| cmd = RMIHIDTOOL_CMD_PRINT_DEVICE_INFO; |
| break; |
| case 'e': |
| cmd = RMIHIDTOOL_CMD_RESET_DEVICE; |
| break; |
| default: |
| print_help(argv[0]); |
| return 0; |
| break; |
| |
| } |
| } |
| |
| if (!strncasecmp("hid", protocol, 3)) { |
| device = new HIDDevice(); |
| } else { |
| fprintf(stderr, "Invalid Protocol: %s\n", protocol); |
| return -1; |
| } |
| |
| if (optind >= argc) { |
| print_help(argv[0]); |
| return -1; |
| } |
| |
| rc = device->Open(argv[optind++]); |
| if (rc) { |
| fprintf(stderr, "%s: failed to initialize rmi device (%d): %s\n", argv[0], errno, |
| strerror(errno)); |
| return 1; |
| } |
| |
| g_device = device; |
| |
| switch (cmd) { |
| case RMIHIDTOOL_CMD_READ: |
| memset(report, 0, sizeof(report)); |
| rc = device->Read(addr, report, len); |
| if (rc < 0) |
| fprintf(stderr, "Failed to read report: %d\n", rc); |
| |
| print_buffer(report, len); |
| break; |
| case RMIHIDTOOL_CMD_WRITE: |
| i = 0; |
| start = data; |
| memset(report, 0, sizeof(report)); |
| while (find_token(start, token, sizeof(token), &end)) { |
| start = end; |
| report[i++] = (unsigned char)strtol(token, NULL, 0); |
| ++len; |
| } |
| |
| if (device->Write(addr, report, len) < 0) { |
| fprintf(stderr, "Failed to Write Report\n"); |
| return -1; |
| } |
| break; |
| case RMIHIDTOOL_CMD_FW_ID: |
| device->ScanPDT(); |
| device->QueryBasicProperties(); |
| fprintf(stdout, "firmware id: %lu\n", device->GetFirmwareID()); |
| break; |
| case RMIHIDTOOL_CMD_PROPS: |
| device->ScanPDT(); |
| device->QueryBasicProperties(); |
| device->PrintProperties(); |
| break; |
| case RMIHIDTOOL_CMD_ATTN: |
| report_attn = 1; |
| while(report_attn) { |
| unsigned int bytes = 256; |
| rc = device->GetAttentionReport(NULL, |
| RMI_INTERUPT_SOURCES_ALL_MASK, |
| report, &bytes); |
| if (rc > 0) { |
| print_buffer(report, bytes); |
| fprintf(stdout, "\n"); |
| } |
| } |
| break; |
| case RMIHIDTOOL_CMD_PRINT_FUNCTIONS: |
| device->ScanPDT(); |
| device->PrintFunctions(); |
| break; |
| case RMIHIDTOOL_CMD_REBIND_DRIVER: |
| device->RebindDriver(); |
| break; |
| case RMIHIDTOOL_CMD_PRINT_DEVICE_INFO: |
| device->PrintDeviceInfo(); |
| break; |
| case RMIHIDTOOL_CMD_RESET_DEVICE: |
| device->ScanPDT(); |
| device->Reset(); |
| break; |
| case RMIHIDTOOL_CMD_INTERACTIVE: |
| default: |
| interactive(device, report); |
| break; |
| } |
| |
| device->Close(); |
| |
| return 0; |
| } |