Home | History | Annotate | Download | only in rmihidtool
      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 
     52 static int report_attn = 0;
     53 static RMIDevice * g_device = NULL;
     54 
     55 void 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 
     72 void 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 
     82 int 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 
    111 void 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 
    187 static 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 
    198 int 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