blob: f30df21da621008b9c48b4814cfcab846a10a476 [file] [log] [blame]
#!/bin/sh
# Copyright 2016 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.
. /usr/share/misc/shflags
. /opt/google/touch/scripts/chromeos-touch-common.sh
DEFINE_boolean 'recovery' ${FLAGS_FALSE} "Recovery. Allows for rollback" 'r'
DEFINE_string 'device_path' '' "device path" 'p'
# Parse command line
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
FW_LINK="/lib/firmware/google_touchpad.bin"
# Sysfs entry created by cros_ec driver.
CROS_TP_SYSFS="/sys/class/chromeos/cros_tp"
# Flashrom programmer argument, we are type "tp"
PROGRAMMER="ec:type=tp"
extract_numerical_fw_version() {
# FW version string has the following format:
# rose_v1.1.6371-3fc259f2c
# This function extract the "numerical" part, which is "1.1.6371"
echo $1 | sed -n "s/^.*_v\(.*\)-.*$/\1/p"
}
get_minor_version() {
local major_minor=${1%.*}
echo ${major_minor#*.}
}
compare_fw_versions() {
# FW version string has the following format:
# rose_v1.1.6371-3fc259f2c
# We only need to compare the numeric part of the version string.
local active_fw_ver_raw="$1"
local updater_fw_ver_raw="$2"
local active_fw_ver="$(extract_numerical_fw_version "${active_fw_ver_raw}")"
local updater_fw_ver="$(extract_numerical_fw_version "${updater_fw_ver_raw}")"
local active_fw_ver_major="${active_fw_ver%%.*}"
local active_fw_ver_minor="$(get_minor_version "${active_fw_ver}")"
local active_fw_ver_revision="${active_fw_ver##*.}"
local updater_fw_ver_major="${updater_fw_ver%%.*}"
local updater_fw_ver_minor="$(get_minor_version "${updater_fw_ver}")"
local updater_fw_ver_revision="${updater_fw_ver##*.}"
compare_multipart_version "${active_fw_ver_major}" "${updater_fw_ver_major}" \
"${active_fw_ver_minor}" "${updater_fw_ver_minor}" \
"${active_fw_ver_revision}" "${updater_fw_ver_revision}"
}
get_fw_version_from_disk() {
# The on-disk FW version is determined by reading the filename which
# is in the format "FWVERSION.hex" where the fw version is a hex
# number preceeded by 0x and using lower case letters. We follow the fw's
# link to the actual file then strip away everything in the FW's filename
# but the FW version.
local fw_link="$1"
local fw_filepath=""
local fw_filename=""
local fw_ver=""
if [ ! -L "${fw_link}" ]; then
return
fi
fw_filepath="$(readlink -f "${fw_link}")"
if [ ! -e "${fw_filepath}" ]; then
return
fi
fw_filename="$(basename "${fw_filepath}")"
fw_ver="${fw_filename%.*}"
echo "${fw_ver}"
}
real_get_active_fw_version() {
local fw_copy=$(cat "${CROS_TP_SYSFS}"/version | awk 'NR==3 { print $3 }')
# If TP firmware is still in RO, wait 1 second for it to jump to RW.
if [ "${fw_copy}" = "RO" ]; then
sleep 1
fw_copy=$(cat "${CROS_TP_SYSFS}"/version | awk 'NR==3 { print $3 }')
fi
cat "${CROS_TP_SYSFS}"/version | grep ${fw_copy} | awk 'NR==1 { print $3 }'
}
get_active_fw_version() {
local active_fw_ver
# If we check the touchpad during RWSIG jump, we may get an empty version
# number. In this case, retry after 1 seconds and we should get the correct
# version number.
for i in $(seq 0 10); do
active_fw_ver="$(real_get_active_fw_version)"
if [ -n "${active_fw_ver}" ]; then
echo ${active_fw_ver}
return
fi
sleep 1
done
}
display_splash() {
chromeos-boot-alert update_touchpad_firmware
}
main() {
local ret
# Active firmware version (RW version)
local active_fw_ver="$(get_active_fw_version)"
local updater_fw_ver="$(get_fw_version_from_disk "${FW_LINK}")"
log_msg "Current active fw version is: '${active_fw_ver}'"
log_msg "Current updater fw version is: '${updater_fw_ver}'"
if [ -z "${active_fw_ver}" ]; then
die "Unable to detect the active FW version."
fi
report_initial_version "${FLAGS_device_path}" "Google" \
"$(extract_numerical_fw_version "${active_fw_ver}")"
if [ -z "${updater_fw_ver}" ]; then
die "Unable to detect the updater's FW version on disk."
fi
update_type="$(compare_fw_versions "${active_fw_ver}" "${updater_fw_ver}")"
log_update_type "${update_type}"
update_needed="$(is_update_needed "${update_type}")"
if [ "${update_needed}" -eq "${FLAGS_TRUE}" ]; then
log_msg "Update FW to ${updater_fw_ver}"
display_splash
# Determine if WP is enabled
local extra_flashrom_arg=""
local wp_status="$(flashrom -p "${PROGRAMMER}" --wp-status | \
sed -n 's/WP: status: \(.*\)/\1/p' 2>/dev/null)"
# Only update RW section if WP is enabled
if [ "${wp_status}" != "0x00" ]; then
extra_flashrom_arg="-i EC_RW"
fi
# Run the actual firmware update
flashrom -p "${PROGRAMMER}" ${extra_flashrom_arg} -w "${FW_LINK}"
# Check if update was successful
active_fw_ver="$(get_active_fw_version)"
update_type="$(compare_fw_versions "${active_fw_ver}" "${updater_fw_ver}")"
if [ "${update_type}" -ne "${UPDATE_NOT_NEEDED_UP_TO_DATE}" ]; then
report_update_result "${FLAGS_device_path}" "${REPORT_RESULT_FAILURE}" \
"$(extract_numerical_fw_version "${updater_fw_ver}")"
die "Firmware update failed. Current Firmware: ${active_fw_ver}"
fi
log_msg "Update FW succeeded. Current Firmware: ${active_fw_ver}"
report_update_result "${FLAGS_device_path}" "${REPORT_RESULT_SUCCESS}" \
"$(extract_numerical_fw_version "${active_fw_ver}")"
rebind_driver "${FLAGS_device_path}"
if [ "$?" -ne "0" ]; then
log_msg "Driver rebind failed, doing a reboot to reload driver."
reboot
exit 0
fi
else
# Force rebind driver to reload RW HID descriptor
rebind_driver "${FLAGS_device_path}"
fi
# Try to read the FW version again after driver rebinding.
#
# The act of reading the FW version is used to turn on CrOS specific features
# of the touchpad (e.g., hovering). We do this because:
#
# 1. Some features like hovering are only supported on CrOS.
# 2. CrOS EC host commands serve as a reliable way to tell if we are running
# CrOS since it isn't used by any other OS for now.
# 3. Getting FW version is the only host command that we can send without
# using the ectool which is unavailable on a normal image.
local final_fw_ver="$(get_active_fw_version)"
if [ -z "${final_fw_ver}" ]; then
log_msg "Can't read FW version. CrOS-specific feature may not be enabled."
fi
}
main "$@"