blob: 2d2240e976b808cbffc696559c1849d89279d212 [file] [log] [blame]
// Copyright 2018 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.
#include <base/logging.h>
#include <brillo/flag_helper.h>
#include <brillo/syslog_logging.h>
#include <iostream>
#include <string>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>
#include <fcntl.h>
#include <linux/hidraw.h>
#include <sys/socket.h>
#include <signal.h> // sigaction()
#include <unistd.h> // alarm()
#include "base/files/file.h"
#include "composite_device.h"
#include "utilities.h"
#include "audio_device.h"
#include "version.h"
namespace {
// PTZ Pro 2 pid.
const char kLogiPtzPro2Pid[] = "0x85f";
// MeetUp pids
const char kLogiMeetUpAudioPid[] = "0x0867";
const char kLogiMeetUpAudioDfuPid[] = "0x0859";
const char kLogiMeetUpVideoPid[] = "0x0866";
// PTZ Pro pid
const char kLogiPtzProVideoPid[] = "0x0853";
// Tap pids.
const char kLogiTapHdmiPid[] = "0x0876";
const char kLogiTapMcuPid[] = "0x0872";
// Rally pid
const char kLogiRallyTableHubPid[] = "0x088f";
const char kLogiRallyVideoPid[] = "0x0881";
const char kLogiRallyAudioPid[] = "0x0885";
const char kLogiRallyAudioDfuPid[] = "0x0886";
// These device names are used where real device name cannot be queried from
// the device, for example, querying image info, checking if device is present,
// etc...
const char kLogiPtzPro2Name[] = "PTZ Pro 2";
const char kLogiMeetUpName[] = "MeetUp";
const char kLogiPtzProName[] = "PTZ Pro";
const char kLogiTapName[] = "Tap";
const char kLogiRallyName[] = "Rally";
// PTZ Pro 2 binary image paths.
const char kLogiPtzPro2VideoImagePath[] =
"/lib/firmware/logitech/ptzpro2/ptzpro2_video.bin";
const char kLogiPtzPro2EepromImagePath[] =
"/lib/firmware/logitech/ptzpro2/ptzpro2_eeprom.s19";
const char kLogiPtzPro2Mcu2ImagePath[] =
"/lib/firmware/logitech/ptzpro2/ptzpro2_mcu2.bin";
// MeetUp binary image paths.
const char kLogiMeetUpVideoImagePath[] =
"/lib/firmware/logitech/meetup/meetup_video.bin";
const char kLogiMeetUpEepromImagePath[] =
"/lib/firmware/logitech/meetup/meetup_eeprom.s19";
const char kLogiMeetUpAudioImagePath[] =
"/lib/firmware/logitech/meetup/meetup_audio.bin";
const char kLogiMeetUpCodecImagePath[] =
"/lib/firmware/logitech/meetup/meetup_codec.bin";
const char kLogiMeetUpBleImagePath[] =
"/lib/firmware/logitech/meetup/meetup_ble.bin";
const char kLogiMeetUpAudioLogicoolImagePath[] =
"/lib/firmware/logitech/meetup/meetup_audio_logicool.bin";
const char kLogiMeetUpEepromLogicoolImagePath[] =
"/lib/firmware/logitech/meetup/meetup_eeprom_logicool.s19";
// PTZ Pro binary image paths.
const char kLogiPtzProVideoImagePath[] =
"/lib/firmware/logitech/ptzpro/ptzpro_video.bin";
const char kLogiPtzProEepromImagePath[] =
"/lib/firmware/logitech/ptzpro/ptzpro_eeprom.s19";
// Tap binary image paths.
const char kLogiTapHdmiImagePath[] = "/lib/firmware/logitech/tap/tap_hdmi.bin";
const char kLogiTapHdmiVersionFilePath[] =
"/lib/firmware/logitech/tap/tap_hdmi_version.bin";
// Rally binaries image path.
const char kLogiRallyImagePath[] = "/lib/firmware/logitech/rally/tablehub.bin";
// Rally binary versions path.
const char kLogiRallyVersionsPath[] =
"/lib/firmware/logitech/rally/versions.bin";
// Note DEVICES_BEGIN/DEVICES_END are used for range check
// Add new device(s) in-between
enum {
DEVICES_BEGIN = 0,
kLogiDeviceTypePTZPro2 = 1,
kLogiDeviceTypePTZPro = 2,
kLogiDeviceTypeMeetUpDfu = 3,
kLogiDeviceTypeMeetUpAudio = 4,
kLogiDeviceTypeRally = 5,
kLogiDeviceTypeTapSensor = 6,
kLogiDeviceTypeTapHDMI = 7,
DEVICES_END
};
// Timeout for this process to wait, for another instance to finish
constexpr int kLogiProcessWaitMaxTime =
(kLogiPollingSleep / 1000) * kLogiPollingMaxTimeout;
// Timeout handler function
void TimeoutHandler(int signum) {
if (signum == SIGALRM) {
LOG(INFO) << "Checking for logitech-updater running status.";
int error = CheckUpdater();
if (error != kLogiErrorNoError) {
LOG(ERROR)
<< "Another logitech-updater still running. Exiting now. Error="
<< error;
exit(1);
}
// This process has already acquired the file lock
LOG(INFO) << "logitech-updater running normally. Timeout ignored.";
}
return;
}
/**
* @brief Prints version info from info map.
* @param info_map The map containing versions.
*/
void PrintVersions(std::map<int, std::string> info_map) {
if (info_map.find(kLogiDeviceVideo) != info_map.end())
LOG(INFO) << "Video version: " << info_map[kLogiDeviceVideo].c_str();
if (info_map.find(kLogiDeviceEeprom) != info_map.end())
LOG(INFO) << "Eeprom version: " << info_map[kLogiDeviceEeprom].c_str();
if (info_map.find(kLogiDeviceMcu2) != info_map.end())
LOG(INFO) << "Mcu2 version: " << info_map[kLogiDeviceMcu2].c_str();
if (info_map.find(kLogiDeviceAudio) != info_map.end())
LOG(INFO) << "Audio version: " << info_map[kLogiDeviceAudio].c_str();
if (info_map.find(kLogiDeviceCodec) != info_map.end())
LOG(INFO) << "Codec version: " << info_map[kLogiDeviceCodec].c_str();
if (info_map.find(kLogiDeviceBle) != info_map.end())
LOG(INFO) << "BLE version: " << info_map[kLogiDeviceBle].c_str();
if (info_map.find(kLogiDeviceHdmi) != info_map.end())
LOG(INFO) << "HDMI version: " << info_map[kLogiDeviceHdmi].c_str();
if (info_map.find(kLogiDeviceVideoBle) != info_map.end())
LOG(INFO) << "Video BLE version: "
<< info_map[kLogiDeviceVideoBle].c_str();
if (info_map.find(kLogiDeviceTableHub) != info_map.end())
LOG(INFO) << "Table Hub version: "
<< info_map[kLogiDeviceTableHub].c_str();
if (info_map.find(kLogiDeviceMicPod) != info_map.end())
LOG(INFO) << "Mic Pod version: " << info_map[kLogiDeviceMicPod].c_str();
if (info_map.find(kLogiDeviceSplitter) != info_map.end())
LOG(INFO) << "Mic Pod Hub version: "
<< info_map[kLogiDeviceSplitter].c_str();
std::cout << std::endl;
}
/**
* @brief Checks and prints the device version info.
* @param device The composite device to check.
*/
void CheckDeviceVersion(std::shared_ptr<CompositeDevice> device) {
if (!device->IsDevicePresent())
return;
std::string name;
device->GetDeviceName(name);
std::map<int, std::string> info_map;
int error;
if (name.find(kLogiRallyName) != std::string::npos) {
error = device->GetDevicesVersionFromAudio(info_map);
name = name.substr(0, 10);
} else {
error = device->GetDevicesVersion(info_map);
}
if (error) {
LOG(ERROR) << "Failed to read " << name.c_str() << " versions.";
} else {
LOG(INFO) << "Device name: " << name.c_str();
PrintVersions(info_map);
}
}
/**
* @brief Checks and prints the image version info.
* @param device The composite device to check image for.
* @param image_name Name of the image to print for clearer log message.
*/
void CheckImageVersion(std::shared_ptr<CompositeDevice> device,
const char* image_name) {
std::map<int, std::string> info_map;
int error;
if (strcmp(image_name, kLogiRallyName) == 0) {
error = device->GetImagesVersionFromFile(info_map);
} else {
error = device->GetImagesVersion(info_map);
}
if (error) {
LOG(ERROR) << "Failed to read " << image_name << " image versions.";
} else {
LOG(INFO) << image_name << " Versions:";
PrintVersions(info_map);
}
}
/**
* @brief Applies PTZ Pro 2 firmwares.
* @param test_sig If true, validate payload with test key and test sig,
* otherwise validate it with live key and live sig.
* @param device PTZ Pro 2 composite device.
*/
int ApplyPTZPro2Firmware(std::shared_ptr<CompositeDevice> device,
bool test_sig) {
// Validate signatures.
bool validated = ValidateSignature(test_sig, kLogiPtzPro2VideoImagePath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiPtzPro2Name
<< " video firmware signature.";
return kLogiErrorSignatureValidationFailed;
}
validated = ValidateSignature(test_sig, kLogiPtzPro2EepromImagePath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiPtzPro2Name
<< " eeprom firmware signature.";
return kLogiErrorSignatureValidationFailed;
}
validated = ValidateSignature(test_sig, kLogiPtzPro2Mcu2ImagePath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiPtzPro2Name
<< " mcu2 firmware signature.";
return kLogiErrorSignatureValidationFailed;
}
device->SetImageBuffer(kLogiDeviceVideo,
ReadBinaryFileContent(kLogiPtzPro2VideoImagePath));
device->SetImageBuffer(kLogiDeviceEeprom,
ReadBinaryFileContent(kLogiPtzPro2EepromImagePath));
device->SetImageBuffer(kLogiDeviceMcu2,
ReadBinaryFileContent(kLogiPtzPro2Mcu2ImagePath));
return kLogiErrorNoError;
}
/**
* @brief Checks brand and applies firmware for MeetUp device.
* @param device MeetUp device to check and apply firmware.
* @return kLogiErrorNoError if checked ok, error code otherwise.
*/
int ApplyMeetUpFirmware(std::shared_ptr<CompositeDevice> device,
bool test_sig) {
// Validates signatures.
bool validated = ValidateSignature(test_sig, kLogiMeetUpVideoImagePath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiMeetUpName
<< " video firmware signature.";
return kLogiErrorSignatureValidationFailed;
}
validated = ValidateSignature(test_sig, kLogiMeetUpCodecImagePath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiMeetUpName
<< " codec firmware signature.";
return kLogiErrorSignatureValidationFailed;
}
validated = ValidateSignature(test_sig, kLogiMeetUpBleImagePath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiMeetUpName
<< " ble firmware signature.";
return kLogiErrorSignatureValidationFailed;
}
validated = ValidateSignature(test_sig, kLogiMeetUpEepromImagePath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiMeetUpName
<< " eeprom firmware signature.";
return kLogiErrorSignatureValidationFailed;
}
validated = ValidateSignature(test_sig, kLogiMeetUpEepromLogicoolImagePath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiMeetUpName
<< " Logicool eeprom firmware signature.";
return kLogiErrorSignatureValidationFailed;
}
validated = ValidateSignature(test_sig, kLogiMeetUpAudioImagePath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiMeetUpName
<< " audio firmware signature.";
return kLogiErrorSignatureValidationFailed;
}
validated = ValidateSignature(test_sig, kLogiMeetUpAudioLogicoolImagePath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiMeetUpName
<< " Logicool audio firmware signature.";
return kLogiErrorSignatureValidationFailed;
}
bool logicool = false;
if (device->IsDevicePresent()) {
int error = device->IsLogicool(true, false, logicool);
if (error)
return error;
}
device->SetImageBuffer(kLogiDeviceVideo,
ReadBinaryFileContent(kLogiMeetUpVideoImagePath));
device->SetImageBuffer(kLogiDeviceCodec,
ReadBinaryFileContent(kLogiMeetUpCodecImagePath));
device->SetImageBuffer(kLogiDeviceBle,
ReadBinaryFileContent(kLogiMeetUpBleImagePath));
std::string eeprom_image_path = kLogiMeetUpEepromImagePath;
std::string audio_image_path = kLogiMeetUpAudioImagePath;
if (logicool) {
eeprom_image_path = kLogiMeetUpEepromLogicoolImagePath;
audio_image_path = kLogiMeetUpAudioLogicoolImagePath;
}
device->SetImageBuffer(kLogiDeviceEeprom,
ReadBinaryFileContent(eeprom_image_path));
device->SetImageBuffer(kLogiDeviceAudio,
ReadBinaryFileContent(audio_image_path));
return kLogiErrorNoError;
}
/**
* @brief Applies PTZ Pro firmwares.
* @param device PTZ Pro composite device.
*/
int ApplyPTZProFirmware(std::shared_ptr<CompositeDevice> device,
bool test_sig) {
// Validates signatures.
bool validated = ValidateSignature(test_sig, kLogiPtzProVideoImagePath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiPtzProName
<< " video firmware signature.";
return kLogiErrorSignatureValidationFailed;
}
validated = ValidateSignature(test_sig, kLogiPtzProEepromImagePath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiPtzProName
<< " eeprom firmware signature.";
return kLogiErrorSignatureValidationFailed;
}
device->SetImageBuffer(kLogiDeviceVideo,
ReadBinaryFileContent(kLogiPtzProVideoImagePath));
device->SetImageBuffer(kLogiDeviceEeprom,
ReadBinaryFileContent(kLogiPtzProEepromImagePath));
return kLogiErrorNoError;
}
/**
* @brief Applies Tap firmwares.
* @param device Tap composite device.
* @param test_sig True if using test signature.
*/
int ApplyTapFirmware(std::shared_ptr<CompositeDevice> device, bool test_sig) {
// Validates signatures.
std::vector<std::string> binpaths = {kLogiTapHdmiImagePath,
kLogiTapHdmiVersionFilePath};
for (const auto& binpath : binpaths) {
if (!ValidateSignature(test_sig, binpath)) {
LOG(ERROR) << "Failed to validate " << kLogiTapName
<< " binary signature " << binpath.c_str();
return kLogiErrorSignatureValidationFailed;
}
}
device->SetImageBuffer(kLogiDeviceHdmi,
ReadBinaryFileContent(kLogiTapHdmiImagePath));
device->SetVersionFile(kLogiDeviceHdmi, kLogiTapHdmiVersionFilePath);
return kLogiErrorNoError;
}
/**
* @brief Applies Rally firmwares.
* @param device Rally composite device.
*/
int ApplyRallyFirmware(std::shared_ptr<CompositeDevice> device, bool test_sig) {
bool validated = ValidateSignature(test_sig, kLogiRallyImagePath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiRallyName
<< " firmware signature.";
return kLogiErrorSignatureValidationFailed;
}
validated = ValidateSignature(test_sig, kLogiRallyVersionsPath);
if (!validated) {
LOG(ERROR) << "Failed to validate " << kLogiRallyName
<< " firmware versions signature.";
return kLogiErrorSignatureValidationFailed;
}
device->SetImageBuffer(kLogiDeviceTableHub,
ReadBinaryFileContent(kLogiRallyImagePath));
device->SetImageBuffer(kLogiDeviceAudio,
ReadBinaryFileContent(kLogiRallyImagePath));
device->SetImageBuffer(kLogiDeviceVideo,
ReadBinaryFileContent(kLogiRallyImagePath));
return kLogiErrorNoError;
}
/**
* @brief Configures the logging system.
* @param log_file Specifies the log file to redirect to or stdout for console
* output.
*/
void ConfigureLogging(std::string log_file) {
if (log_file.empty()) {
// Default log to syslog.
brillo::InitLog(brillo::InitFlags::kLogToSyslog |
brillo::InitFlags::kLogToStderrIfTty);
} else if (log_file == "stdout") {
logging::LoggingSettings logging_settings;
logging::InitLogging(logging_settings);
} else {
// Logs to file.
logging::LoggingSettings logging_settings;
logging_settings.logging_dest = logging::LOG_TO_FILE;
logging_settings.log_file_path = log_file.c_str();
logging_settings.lock_log = logging::DONT_LOCK_LOG_FILE;
logging::InitLogging(logging_settings);
}
}
/**
* @brief Ensure image(s) exist, check version if requested
* @param device The composite device to check
* @param name Name of composite device
* @param check_version Check and print version
* @param set_force_update Setup device for force upgrade
*/
int CheckForImage(std::shared_ptr<CompositeDevice> device,
const char* name,
bool check_version,
bool set_force_update) {
if (!device->AreImagesPresent()) {
LOG(ERROR) << name << " image not found.";
return kLogiErrorImageVersionNotFound;
}
if (check_version) {
CheckImageVersion(device, name);
LOG(INFO) << "Exiting updater with code: " << kLogiErrorNoError;
return kLogiErrorNoError; // Done here. Rest is N/A
}
device->SetForceUpdate(set_force_update);
return kLogiErrorNoError;
}
} // namespace
/**
* main
*/
int main(int argc, char** argv) {
// Parse the flags
DEFINE_bool(binary_version, false, "Show this binary version.");
DEFINE_bool(device_version, false, "Show device versions.");
DEFINE_bool(image_version, false, "Show image versions.");
// Performs composite device components one at a time. This method is
// to integrate with Udev since updating audio devices requires reboot and
// causing udev issues on changing user and group that prevents read and write
// to device. This method updates component device, then reboots device. Udev
// can keep calling the updater with this method to update all components when
// device reboots and mounts back.
DEFINE_bool(update_components, false,
"Perform firmware update on one component at a time. This "
"option is used to integrate with Udev.");
// Performs firmware update on audio device when it is in DFU mode.
DEFINE_bool(update_dfu_audio, false,
"Perform audio firmware update when audio device is in DFU mode. "
"This option is used to integrate with Udev.");
DEFINE_bool(lock, false,
"Check and lock the firmware updater with lock file at "
"/tmp/logitech-updater.lock. When run with this option, only 1 "
"instance of updater can be run at the time during the updating "
"process. This option is used to integrate with Udev.");
DEFINE_bool(force, false, "Force firmware update.");
DEFINE_bool(
test_sig, false,
"If set, validate firmware payload with test key and test sig. "
"Otherwise, validate firmware payload with live key and live sig.");
// When run under Udev, device can still be booting up or calibrating and
// fails to update until it is ready. Use this to delay the update process.
DEFINE_uint64(delay, 0,
"Delay this executable when it starts. This option is used to "
"integrate Udev.");
// Process specified device only
DEFINE_uint64(id, 0,
"Device type. PTZPro2=1, PtzPro=2, MeetUpDfu=3, "
"MeetUpAudio=4, Rally=5, TapSensor=6, TapHDMI=7.");
DEFINE_string(log_to, "", "Specify log file to write messages to.");
brillo::FlagHelper::Init(argc, argv, "logitech-updater");
// Configures log file.
ConfigureLogging(FLAGS_log_to);
LOG(INFO) << "Logitech updater instance invoked. ID=" << FLAGS_id;
if (FLAGS_lock) {
// LockUpdater is blocking call.
// Setup alarm/SIGALRM to terminate this instance,
// if timeout occurs and other instance still running
struct sigaction action, old_action;
unsigned int old_timeout;
// Cancel any existing alarm
old_timeout = alarm(0);
// Establish signal handler
action.sa_handler = TimeoutHandler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_RESTART;
sigaction(SIGALRM, &action, &old_action);
alarm(kLogiProcessWaitMaxTime);
if (!LockUpdater()) {
LOG(ERROR)
<< "There is another logitech-updater running. Exiting now. ID="
<< FLAGS_id;
return kLogiErrorProcessAlreadyRunning;
}
// Reset the signal handler and alarm
sigaction(SIGALRM, &old_action, NULL);
alarm(old_timeout);
}
if (FLAGS_delay > 0) {
LOG(INFO) << "Delaying " << FLAGS_delay << " seconds. ID=" << FLAGS_id;
sleep(FLAGS_delay);
}
int error = kLogiErrorNoError;
if (FLAGS_binary_version) {
LOG(INFO) << "Binary version: " << kLogiBinaryVersion;
LOG(INFO) << "Exiting updater with code: " << kLogiErrorNoError;
return kLogiErrorNoError; // Done here. Rest is N/A
}
if ((FLAGS_id <= DEVICES_BEGIN) || ((FLAGS_id >= DEVICES_END))) {
LOG(ERROR) << "Unsupported device type: " << FLAGS_id;
return kLogiErrorDeviceNotPresent;
}
std::shared_ptr<CompositeDevice> composite_device = nullptr;
bool did_update = false;
switch (FLAGS_id) {
// PTZ Pro 2 device.
case kLogiDeviceTypePTZPro2:
composite_device = std::make_shared<CompositeDevice>(
kLogiPtzPro2Pid, kLogiPtzPro2Pid, kLogiPtzPro2Pid);
if (FLAGS_device_version) {
CheckDeviceVersion(composite_device);
LOG(INFO) << "Exiting updater with code: " << kLogiErrorNoError;
return kLogiErrorNoError; // Done here. Rest is N/A
}
// Images must exist for subsequent operations
error = ApplyPTZPro2Firmware(composite_device, FLAGS_test_sig);
if (error) {
LOG(ERROR) << "Exiting updater with code: " << error;
return error;
}
// Ensure image(s) exist, setup for upgrade, if requested
error = CheckForImage(composite_device, kLogiPtzPro2Name,
FLAGS_image_version, FLAGS_force);
if (error || FLAGS_image_version)
return error; // Done here. Rest is N/A
if (FLAGS_update_components && composite_device->IsDevicePresent())
error = composite_device->PerformComponentUpdate(&did_update);
LOG(INFO) << "Exiting updater with code: " << error;
break;
case kLogiDeviceTypePTZPro:
// PTZ Pro device.
composite_device = std::make_shared<CompositeDevice>();
composite_device->AddDevice(kLogiDeviceVideo, kLogiPtzProVideoPid);
composite_device->AddDevice(kLogiDeviceEeprom, kLogiPtzProVideoPid);
if (FLAGS_device_version) {
CheckDeviceVersion(composite_device);
LOG(INFO) << "Exiting updater with code: " << kLogiErrorNoError;
return kLogiErrorNoError; // Done here. Rest is N/A
}
// Images must exist for subsequent operations
error = ApplyPTZProFirmware(composite_device, FLAGS_test_sig);
if (error) {
LOG(ERROR) << "Exiting updater with code: " << error;
return error;
}
// Ensure image(s) exist, setup for upgrade, if requested
error = CheckForImage(composite_device, kLogiPtzProName,
FLAGS_image_version, FLAGS_force);
if (error || FLAGS_image_version)
return error; // Done here. Rest is N/A
if (FLAGS_update_components && composite_device->IsDevicePresent())
error = composite_device->PerformComponentUpdate(&did_update);
LOG(INFO) << "Exiting updater with code: " << error;
break;
case kLogiDeviceTypeMeetUpDfu:
case kLogiDeviceTypeMeetUpAudio:
// MeetUp device.
composite_device = std::make_shared<CompositeDevice>();
composite_device->AddDevice(kLogiDeviceVideo, kLogiMeetUpVideoPid);
composite_device->AddDevice(kLogiDeviceEeprom, kLogiMeetUpVideoPid);
composite_device->AddDevice(kLogiDeviceAudio, kLogiMeetUpAudioPid,
kLogiMeetUpAudioDfuPid);
composite_device->AddDevice(kLogiDeviceCodec, kLogiMeetUpAudioPid);
composite_device->AddDevice(kLogiDeviceBle, kLogiMeetUpAudioPid);
composite_device->SetSupportBle(true);
if (FLAGS_device_version) {
CheckDeviceVersion(composite_device);
LOG(INFO) << "Exiting updater with code: " << kLogiErrorNoError;
return kLogiErrorNoError; // Done here. Rest is N/A
}
// Images must exist for subsequent operations
error = ApplyMeetUpFirmware(composite_device, FLAGS_test_sig);
if (error) {
LOG(ERROR) << "Exiting updater with code: " << error;
return error;
}
// Ensure image(s) exist, setup for upgrade, if requested
error = CheckForImage(composite_device, kLogiMeetUpName,
FLAGS_image_version, FLAGS_force);
if (error || FLAGS_image_version)
return error; // Done here. Rest is N/A
if (FLAGS_update_components || FLAGS_update_dfu_audio) {
if (composite_device->IsDevicePresent()) {
if (FLAGS_update_components)
error = composite_device->PerformComponentUpdate(&did_update);
if (FLAGS_update_dfu_audio)
error = composite_device->PerformDfuAudioUpdate();
}
}
LOG(INFO) << "Exiting updater with code: " << error;
break;
case kLogiDeviceTypeRally:
// Rally system.
composite_device = std::make_shared<CompositeDevice>();
composite_device->AddDevice(kLogiDeviceAudio, kLogiRallyAudioPid,
kLogiRallyAudioDfuPid);
composite_device->AddDevice(kLogiDeviceVideo, kLogiRallyVideoPid);
composite_device->AddDevice(kLogiDeviceTableHub, kLogiRallyTableHubPid);
if (FLAGS_device_version) {
CheckDeviceVersion(composite_device);
LOG(INFO) << "Exiting updater with code: " << kLogiErrorNoError;
return kLogiErrorNoError; // Done here. Rest is N/A
}
// Images must exist for subsequent operations
error = ApplyRallyFirmware(composite_device, FLAGS_test_sig);
if (error) {
LOG(ERROR) << "Exiting updater with code: " << error;
return error;
}
// Ensure image(s) exist, setup for upgrade, if requested
error = CheckForImage(composite_device, kLogiRallyName,
FLAGS_image_version, FLAGS_force);
if (error || FLAGS_image_version)
return error; // Done here. Rest is N/A
if (FLAGS_update_components || FLAGS_update_dfu_audio) {
if (composite_device->IsDevicePresent(kLogiDeviceTableHub))
error = composite_device->PerformSystemUpdate();
}
LOG(INFO) << "Exiting updater with code: " << error;
break;
case kLogiDeviceTypeTapSensor:
case kLogiDeviceTypeTapHDMI:
// Tap device.
composite_device = std::make_shared<CompositeDevice>();
composite_device->AddDevice(kLogiDeviceHdmi, kLogiTapHdmiPid);
if (FLAGS_device_version) {
CheckDeviceVersion(composite_device);
LOG(INFO) << "Exiting updater with code: " << kLogiErrorNoError;
return kLogiErrorNoError; // Done here. Rest is N/A
}
// Images must exist for subsequent operations
error = ApplyTapFirmware(composite_device, FLAGS_test_sig);
if (error) {
LOG(ERROR) << "Exiting updater with code: " << error;
return error;
}
// Ensure image(s) exist, setup for upgrade, if requested
error = CheckForImage(composite_device, kLogiTapName, FLAGS_image_version,
FLAGS_force);
if (error || FLAGS_image_version)
return error; // Done here. Rest is N/A
if (FLAGS_update_components || FLAGS_update_dfu_audio) {
error = composite_device->PerformComponentUpdate(&did_update);
if (did_update)
composite_device->PowerCycleTDEMode(kLogiTapMcuPid);
}
break;
default:
LOG(ERROR) << "Unsupported device type: " << FLAGS_id;
break;
}
return error;
}