blob: 876b0e3538c41b7ee01c5b56f23ed18be71f995b [file] [log] [blame]
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// hammerd - A daemon to update the firmware of Hammer
#include <stdlib.h>
#include <string>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/message_loop/message_loop.h>
#include <base/strings/stringprintf.h>
#include <brillo/flag_helper.h>
#include <brillo/syslog_logging.h>
#include "hammerd/hammer_updater.h"
#include "hammerd/process_lock.h"
namespace {
// The lock file used to prevent multiple hammerd be invoked at the same time.
constexpr char kLockFile[] = "/run/lock/hammerd.lock";
} // namespace
int main(int argc, const char* argv[]) {
// hammerd should be triggered by upstart job.
// The default value of arguments are stored in `/etc/init/hammerd.conf`, and
// each board should override values in `/etc/init/hammerd.override`.
DEFINE_string(ec_image_path, "", "Path to the EC firmware image file");
DEFINE_string(touchpad_image_path, "", "Path to the touchpad image file");
// TODO(b/65534217): Define a flag about touchpad version that is expected
// to be computed by init script.
DEFINE_int32(vendor_id, -1, "USB vendor ID of the device");
DEFINE_int32(product_id, -1, "USB product ID of the device");
DEFINE_int32(usb_bus, -1, "USB bus to search");
DEFINE_int32(usb_port, -1, "USB port to search");
DEFINE_int32(autosuspend_delay_ms, -1, "USB autosuspend delay time (ms)");
DEFINE_bool(at_boot, false,
"Invoke proecess at boot time. "
"Exit if RW is up-to-date (no pairing)");
brillo::FlagHelper::Init(argc, argv, "Hammer EC firmware updater daemon");
brillo::InitLog(brillo::kLogToSyslog | brillo::kLogHeader |
brillo::kLogToStderrIfTty);
base::FilePath file_path(FILE_PATH_LITERAL(kLockFile));
hammerd::ProcessLock lock(file_path);
if (!lock.Acquire()) {
LOG(INFO) << "Other hammerd process is running, exit.";
return EXIT_SUCCESS;
}
if (FLAGS_vendor_id < 0 || FLAGS_product_id < 0 ||
FLAGS_usb_bus < 0 || FLAGS_usb_port < 0) {
LOG(ERROR) << "Must specify USB vendor/product ID and bus/port number.";
return EXIT_FAILURE;
}
std::string ec_image;
if (!base::ReadFileToString(base::FilePath(FLAGS_ec_image_path), &ec_image)) {
LOG(ERROR) << "EC image file is not found: " << FLAGS_ec_image_path;
return EXIT_FAILURE;
}
std::string touchpad_image;
std::string touchpad_product_id;
std::string touchpad_fw_ver;
if (!FLAGS_touchpad_image_path.size()) {
LOG(INFO) << "Touchpad image is not assigned. " <<
"Proceeding without updating touchpad.";
} else if (!base::ReadFileToString(base::FilePath(FLAGS_touchpad_image_path),
&touchpad_image)) {
LOG(ERROR) << "Touchpad image is not found with path ["
<< FLAGS_touchpad_image_path << "]. Abort.";
return EXIT_FAILURE;
} else if (!hammerd::HammerUpdater::ParseTouchpadInfoFromFilename(
FLAGS_touchpad_image_path, &touchpad_product_id, &touchpad_fw_ver)) {
LOG(ERROR) << "Not able to get version info from filename. "
<< "Check if [" << FLAGS_touchpad_image_path << "] follows "
<< "<product_id>_<fw_version>.bin format (applied to symbolic "
<< "link as well).";
return EXIT_FAILURE;
}
// The message loop registers a task runner with the current thread, which
// is used by DBusWrapper to send signals.
base::MessageLoop message_loop;
hammerd::HammerUpdater updater(
ec_image, touchpad_image, touchpad_product_id, touchpad_fw_ver,
FLAGS_vendor_id, FLAGS_product_id,
FLAGS_usb_bus, FLAGS_usb_port, FLAGS_at_boot);
bool ret = updater.Run();
if (ret && FLAGS_autosuspend_delay_ms >= 0) {
LOG(INFO) << "Enable USB autosuspend with delay "
<< FLAGS_autosuspend_delay_ms << " ms.";
base::FilePath base_path =
hammerd::GetUsbSysfsPath(FLAGS_usb_bus, FLAGS_usb_port);
constexpr char kPowerLevelPath[] = "power/level";
constexpr char kAutosuspendDelayMsPath[] = "power/autosuspend_delay_ms";
constexpr char kPowerLevel[] = "auto";
std::string delay_ms = base::StringPrintf("%d", FLAGS_autosuspend_delay_ms);
base::WriteFile(base_path.Append(base::FilePath(kPowerLevelPath)),
kPowerLevel, sizeof(kPowerLevel) - 1);
base::WriteFile(base_path.Append(base::FilePath(kAutosuspendDelayMsPath)),
delay_ms.data(), delay_ms.size());
}
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
}