You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
377 lines
9.3 KiB
377 lines
9.3 KiB
/* |
|
* 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; |
|
}
|
|
|