blob: 97497d62c02b5125f031768155face4e9694dd42 [file] [log] [blame]
#!/bin/sh
#
# Copyright 2021 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'
TRACKPOINT_PATH="/sys/bus/serio/devices/serio1/"
# Parse command line.
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
# Actually trigger a firmware update by running the ELAN update tool in minijail
# to limit the syscalls it can access.
update_firmware() {
local fw_link="$1"
local fw_version="$2"
local cmd_log=
local ret=
cmd_log="$(
minijail0 -u fwupdate-serio -g fwupdate-serio \
-G -I -N -n -p -v --uts \
-S /opt/google/touch/policies/eps2pstiap.update.policy -- \
/usr/sbin/epstps2_updater ${fw_link} -u 2>&1
)"
ret="$?"
if [ "${ret}" -ne 0 ]; then
report_update_result "${TRACKPOINT_PATH}" "${REPORT_RESULT_FAILURE}" \
"${fw_version}"
remove_serio_node
die "Exit status ${ret} updating trackpoint firmware: ${cmd_log}"
fi
return "${ret}"
}
# The on-disk firmware version is determined by parsing the filename of the
# actual firmware file passed as $1, after resolving any symlinks. The filename
# should be in the format format "{module_id}_{rank}_{fw_ver}.bin"
# e.g "13.0_a_129.0.bin". The 0x prefix is preserved, e.g. if the file is named
# "13.0_a_129.0.bin" the function will print "0x129" to stdout.
get_fw_version_from_disk() {
local fw_link="$1"
local fw_filepath=
local fw_filename=
local fw_ver=
[ -L "${fw_link}" ] || return
fw_filepath="$(realpath -e "${fw_link}")" || return
[ -n "${fw_filepath}" ] || return
fw_filename="$(basename "${fw_filepath}")"
fw_ver="${fw_filename##*_}"
fw_ver="${fw_ver%%.*}"
printf '0x%X\n' "${fw_ver}"
}
# Create serio raw driver
create_serio_node() {
local serio_raw=
chown root:fwupdate-serio ${TRACKPOINT_PATH}drvctl
chmod g+w ${TRACKPOINT_PATH}drvctl
echo -n "serio_raw" > ${TRACKPOINT_PATH}drvctl
trap remove_serio_node EXIT
serio_raw=$(ls ${TRACKPOINT_PATH}misc/)
if [ -e "${TRACKPOINT_PATH}misc/${serio_raw}" ]; then
chown root:fwupdate-serio "/dev/${serio_raw}"
chmod g+rw "/dev/${serio_raw}"
fi
}
# Remove serio raw driver, rebind psmouse driver
remove_serio_node() {
echo -n "rescan" > ${TRACKPOINT_PATH}drvctl
}
# Query the trackpoint controller for information about its firmware or hardware.
get_active_info() {
local description="$1"
local output=
local ret=
output="$(
minijail0 -u fwupdate-serio -g fwupdate-serio \
-G -I -N -n -p -v --uts \
-S /opt/google/touch/policies/eps2pstiap.query.policy -- \
/usr/sbin/epstps2_updater "$@" 2>&1
)"
ret="$?"
if [ "${ret}" -eq 0 ]; then
if [ "${output}" = "-1" ]; then
printf '0xFFFFFFFF\n'
else
printf '0x%X\n' "0x${output}"
fi
else
log_msg 1>&2 "Exit status ${ret} retrieving trackpoint ${description}: ${output}"
fi
return "${ret}"
}
# Query the trackpoint controller for its current firmware version.
get_active_fw_version() {
get_active_info "firmware version" -g
}
# Query the trackpoint controller for its hardware module identifier.
get_device_module_id() {
get_active_info "module ID" -m
}
main() {
local active_fw_ver=
local new_fw_ver=
local update_type=
local update_needed=
local fw_link_a=
local fw_link_b=
local fw_link_c=
local fw_link=
local device_module_id=
local chassis_id=
local board_rev=
chassis_id="$(get_chassis_id)"
log_msg "Chassis identifier detected as: ${chassis_id}"
board_rev="$(get_platform_ver)"
log_msg "Platform version detected as: ${board_rev}"
create_serio_node
device_module_id="$(get_device_module_id)"
[ -n "${device_module_id}" ] || die \
"Unable to determine hardware module of the trackpoint device."
log_msg "Hardware module of the trackpoint device: ${device_module_id}"
active_fw_ver="$(get_active_fw_version)"
[ -n "${active_fw_ver}" ] || die \
"Unable to determine active firmware version."
log_msg "Active firmware version: ${active_fw_ver}"
report_initial_version "${TRACKPOINT_PATH}" "Elan Trackpoint PS2" \
"${active_fw_ver}"
module_id=$((device_module_id))
remove_serio_node
fw_basename_a="elan_ps2_a_${module_id}.0.bin"
fw_basename_b="elan_ps2_b_${module_id}.0.bin"
fw_basename_c="elan_ps2_c_${module_id}.0.bin"
fw_link_a="$(find_fw_link_path "${fw_basename_a}")"
[ -n "${fw_link_a}" ] || die "Unable to determine path of on-disk firmware."
log_msg "Attempting to load on-disk firmware: ${fw_link_a}"
fw_link_b="$(find_fw_link_path "${fw_basename_b}")"
[ -n "${fw_link_b}" ] || die "Unable to determine path of on-disk firmware."
log_msg "Attempting to load on-disk firmware: ${fw_link_b}"
fw_link_c="$(find_fw_link_path "${fw_basename_c}")"
[ -n "${fw_link_c}" ] || die "Unable to determine path of on-disk firmware."
log_msg "Attempting to load on-disk firmware: ${fw_link_c}"
new_fw_ver="$(get_fw_version_from_disk "${fw_link_a}")"
log_msg "On-disk firmware version: ${new_fw_ver}"
[ -n "${new_fw_ver}" ] || die \
"Unable to determine version of on-disk firmware."
if [ "$(( ${active_fw_ver} == 0xFFFFFFFF ))" -gt 0 ]; then
log_msg "Active firmware appears to be corrupt, will update firmware."
update_needed="${FLAGS_TRUE}"
else
update_type="$(compare_multipart_version "${active_fw_ver}" \
"${new_fw_ver}")"
log_update_type "${update_type}"
update_needed="$(is_update_needed "${update_type}")"
fi
if [ "${update_needed}" -eq "${FLAGS_TRUE}" ]; then
log_msg "Updating firmware to ${new_fw_ver}"
fw_link="-a ${fw_link_a} -b ${fw_link_b} -c ${fw_link_c}"
create_serio_node
chromeos-boot-alert update_trackpoint_firmware
run_cmd_and_block_powerd update_firmware "${fw_link}" "${new_fw_ver}"
# Check if update was successful
active_fw_ver="$(get_active_fw_version)"
update_type="$(compare_multipart_version "${active_fw_ver}" \
"${new_fw_ver}")"
remove_serio_node
if [ "${update_type}" -ne "${UPDATE_NOT_NEEDED_UP_TO_DATE}" ]; then
report_update_result "${TRACKPOINT_PATH}" "${REPORT_RESULT_FAILURE}" \
"${new_fw_ver}"
die "Firmware update failed. Current firmware version: ${active_fw_ver}"
fi
log_msg "Updating firmware succeded. Firmware version is now: " \
"${active_fw_ver}"
report_update_result "${TRACKPOINT_PATH}" "${REPORT_RESULT_SUCCESS}" \
"${active_fw_ver}"
fi
}
main "$@"