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.
378 lines
9.3 KiB
378 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;
|
|
}
|