blob: a2d0643a09e99a464125b61a8ce8bd64db622c20 [file] [log] [blame] [edit]
/*
* 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 <dirent.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:foambd:ecnt:"
enum rmihidtool_cmd {
RMIHIDTOOL_CMD_INTERACTIVE,
RMIHIDTOOL_CMD_READ,
RMIHIDTOOL_CMD_WRITE,
RMIHIDTOOL_CMD_FW_ID,
RMIHIDTOOL_CMD_CF_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-d, --device\t\t\t\thidraw device file associated with the device.\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-w, --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-c, --config-id\t\t\t\tPrint the config 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-n, --device-info\t\t\tPrint protocol specific information about the device.\n");
fprintf(stdout, "\t-e, --reset-device\t\t\tReset the device.\n");
fprintf(stdout, "\t-t, --device-type\t\t\tFilter by device type [touchpad or touchscreen].\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");
device->PrintDeviceInfo();
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;
char *deviceName = NULL;
RMIDevice *device;
const char *protocol = "HID";
unsigned char report[256];
char token[256];
enum RMIDeviceType deviceType = RMI_DEVICE_TYPE_ANY;
static struct option long_options[] = {
{"help", 0, NULL, 'h'},
{"device", 1, NULL, 'd'},
{"protocol", 1, NULL, 'p'},
{"interactive", 0, NULL, 'i'},
{"read", 1, NULL, 'r'},
{"write", 1, NULL, 'w'},
{"firmware-id", 0, NULL, 'f'},
{"config-id", 0, NULL, 'c'},
{"props", 0, NULL, 'o'},
{"attention", 0, NULL, 'a'},
{"print-functions", 0, NULL, 'm'},
{"rebind-driver", 0, NULL, 'b'},
{"device-info", 0, NULL, 'n'},
{"reset-device", 0, NULL, 'e'},
{"device-type", 1, NULL, 't'},
{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 'd':
deviceName = 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 'c':
cmd = RMIHIDTOOL_CMD_CF_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 'n':
cmd = RMIHIDTOOL_CMD_PRINT_DEVICE_INFO;
break;
case 'e':
cmd = RMIHIDTOOL_CMD_RESET_DEVICE;
break;
case 't':
if (!strcasecmp(optarg, "touchpad"))
deviceType = RMI_DEVICE_TYPE_TOUCHPAD;
else if (!strcasecmp(optarg, "touchscreen"))
deviceType = RMI_DEVICE_TYPE_TOUCHSCREEN;
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;
}
if (deviceName) {
rc = device->Open(deviceName);
if (rc) {
fprintf(stderr, "%s: failed to initialize rmi device (%d): %s\n", argv[0], errno,
strerror(errno));
return 1;
}
} else {
if (!device->FindDevice(deviceType))
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_CF_ID:
device->ScanPDT();
device->QueryBasicProperties();
fprintf(stdout, "config id: %08lx\n", device->GetConfigID());
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;
}