1 /*
2  * Copyright (C) 2014 Andrew Duggan
3  * Copyright (C) 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 <string.h>
20 #include <errno.h>
21 #include <getopt.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <dirent.h>
26 #include <unistd.h>
27 #include <time.h>
28 #include <string>
29 #include <sstream>
30 
31 #include "hiddevice.h"
32 #include "rmi4update.h"
33 
34 #define VERSION_MAJOR		1
35 #define VERSION_MINOR		2
36 #define VERSION_SUBMINOR	0
37 
38 #define RMI4UPDATE_GETOPTS	"hfd:plv"
39 
printHelp(const char * prog_name)40 void printHelp(const char *prog_name)
41 {
42 	fprintf(stdout, "Usage: %s [OPTIONS] FIRMWAREFILE\n", prog_name);
43 	fprintf(stdout, "\t-h, --help\tPrint this message\n");
44 	fprintf(stdout, "\t-f, --force\tForce updating firmware even it the image provided is older\n\t\t\tthen the current firmware on the device.\n");
45 	fprintf(stdout, "\t-d, --device\thidraw device file associated with the device being updated.\n");
46 	fprintf(stdout, "\t-p, --fw-props\tPrint the firmware properties.\n");
47 	fprintf(stdout, "\t-l, --lockdown\tPerform lockdown.\n");
48 	fprintf(stdout, "\t-v, --version\tPrint version number.\n");
49 }
50 
printVersion()51 void printVersion()
52 {
53 	fprintf(stdout, "rmi4update version %d.%d.%d\n",
54 		VERSION_MAJOR, VERSION_MINOR, VERSION_SUBMINOR);
55 }
56 
UpdateDevice(FirmwareImage & image,bool force,bool performLockdown,const char * deviceFile)57 int UpdateDevice(FirmwareImage & image, bool force, bool performLockdown, const char * deviceFile)
58 {
59 	HIDDevice rmidevice;
60 	int rc;
61 
62 	rc = rmidevice.Open(deviceFile);
63 	if (rc)
64 		return rc;
65 
66 	RMI4Update update(rmidevice, image);
67 	rc = update.UpdateFirmware(force, performLockdown);
68 	if (rc != UPDATE_SUCCESS)
69 		return rc;
70 
71 	return rc;
72 }
73 
GetFirmwareProps(const char * deviceFile,std::string & props)74 int GetFirmwareProps(const char * deviceFile, std::string &props)
75 {
76 	HIDDevice rmidevice;
77 	int rc = UPDATE_SUCCESS;
78 	std::stringstream ss;
79 
80 	rc = rmidevice.Open(deviceFile);
81 	if (rc)
82 		return rc;
83 
84 	rmidevice.ScanPDT(0x1);
85 	rmidevice.QueryBasicProperties();
86 
87 	ss << rmidevice.GetFirmwareVersionMajor() << "."
88 		<< rmidevice.GetFirmwareVersionMinor() << "."
89 		<< std::hex << rmidevice.GetFirmwareID();
90 
91 	if (rmidevice.InBootloader())
92 		ss << " bootloader";
93 
94 	props = ss.str();
95 
96 	return rc;
97 }
98 
main(int argc,char ** argv)99 int main(int argc, char **argv)
100 {
101 	int rc;
102 	FirmwareImage image;
103 	int opt;
104 	int index;
105 	char *deviceName = NULL;
106 	const char *firmwareName = NULL;
107 	bool force = false;
108 	static struct option long_options[] = {
109 		{"help", 0, NULL, 'h'},
110 		{"force", 0, NULL, 'f'},
111 		{"device", 1, NULL, 'd'},
112 		{"fw-props", 0, NULL, 'p'},
113 		{"lockdown", 0, NULL, 'l'},
114 		{"version", 0, NULL, 'v'},
115 		{0, 0, 0, 0},
116 	};
117 	struct dirent * devDirEntry;
118 	DIR * devDir;
119 	bool printFirmwareProps = false;
120 	bool performLockdown = false;
121 
122 	while ((opt = getopt_long(argc, argv, RMI4UPDATE_GETOPTS, long_options, &index)) != -1) {
123 		switch (opt) {
124 			case 'h':
125 				printHelp(argv[0]);
126 				return 0;
127 			case 'f':
128 				force = true;
129 				break;
130 			case 'd':
131 				deviceName = optarg;
132 				break;
133 			case 'p':
134 				printFirmwareProps = true;
135 				break;
136 			case 'l':
137 				performLockdown = true;
138 				break;
139 			case 'v':
140 				printVersion();
141 				return 0;
142 			default:
143 				break;
144 
145 		}
146 	}
147 
148 	if (printFirmwareProps) {
149 		std::string props;
150 
151 		if (!deviceName) {
152 			fprintf(stderr, "Specifiy which device to query\n");
153 			return 1;
154 		}
155 		rc = GetFirmwareProps(deviceName, props);
156 		if (rc) {
157 			fprintf(stderr, "Failed to read properties from device: %s\n", update_err_to_string(rc));
158 			return 1;
159 		}
160 		fprintf(stdout, "%s\n", props.c_str());
161 		return 0;
162 	}
163 
164 	if (optind < argc) {
165 		firmwareName = argv[optind];
166 	} else {
167 		printHelp(argv[0]);
168 		return -1;
169 	}
170 
171 	rc = image.Initialize(firmwareName);
172 	if (rc != UPDATE_SUCCESS) {
173 		fprintf(stderr, "Failed to initialize the firmware image: %s\n", update_err_to_string(rc));
174 		return 1;
175 	}
176 
177 	if (deviceName) {
178 		rc = UpdateDevice(image, force, performLockdown, deviceName);
179 
180 		return rc;
181 	} else {
182 		char deviceFile[PATH_MAX];
183 		bool found = false;
184 
185 		devDir = opendir("/dev");
186 		if (!devDir)
187 			return -1;
188 
189 		while ((devDirEntry = readdir(devDir)) != NULL) {
190 			if (strstr(devDirEntry->d_name, "hidraw")) {
191 				char rawDevice[PATH_MAX];
192 				strncpy(rawDevice, devDirEntry->d_name, PATH_MAX);
193 				snprintf(deviceFile, PATH_MAX, "/dev/%s", devDirEntry->d_name);
194 				rc = UpdateDevice(image, force, performLockdown, deviceFile);
195 				if (rc != 0) {
196 					continue;
197 				} else {
198 					found = true;
199 					break;
200 				}
201 			}
202 		}
203 		closedir(devDir);
204 
205 		if (!found)
206 			return rc;
207 	}
208 
209 	return 0;
210 }
211