blob: d4922791427d8142226ce3540fbeaa943b822c19 [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' '' "device_name" 'd'
DEFINE_string 'device_path' '' "device path" 'p'
FW_LINK_BASE="wacom_firmware.hex"
FW_LINK_BASE_V2="wacom2_firmware.hex"
WACOMFLASH="/usr/sbin/wacom_flash"
GET_ACTIVE_FIRMVER="-a"
GET_TOUCH_HWID="-h"
GET_BOARD_SPECIFIC_HWID="/opt/google/touch/scripts/get_board_specific_wacom_hwid.sh"
# Parse command line.
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
update_firmware() {
# Actually trigger a firmware update by running the Wacom update tool
# in minijail to limit the syscalls it can access.
local fw_link="$1"
local new_fw_ver="$2"
local cmd_log=""
cmd_log="$(
minijail0 -S /opt/google/touch/policies/wacom_flash.update.policy \
"${WACOMFLASH}" "${fw_link}" ${FLAGS_recovery} ${FLAGS_device} 2>&1
)"
if [ "$?" -ne 0 ]; then
report_update_result "${FLAGS_device_path}" "${REPORT_RESULT_FAILURE}" \
"${new_fw_ver}"
die "Error updating touch firmware: ${cmd_log}"
fi
}
get_fw_version_from_disk() {
# The on-disk FW version is determined by reading the filename which
# is in the format "wacom_FWVERSION.hex". 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##*_}"
fw_ver="${fw_ver%.*}"
echo "${fw_ver}"
}
get_hardware_id() {
# Query the touchscreen and get the hardware id.
local hardware_id=""
hardware_id="$(
minijail0 -S /opt/google/touch/policies/wacom_flash.query.policy \
"${WACOMFLASH}" "dummy_unused_argument" "${GET_TOUCH_HWID}" \
"${FLAGS_device}"
)"
if [ "${hardware_id}" != "0000_0000" ]; then
echo "${hardware_id}"
fi
}
get_active_fw_version() {
# Query the touchscreen and see what the current FW version it's running.
local active_fw_ver=""
active_fw_ver="$(
minijail0 -S /opt/google/touch/policies/wacom_flash.query.policy \
"${WACOMFLASH}" "dummy_unused_argument" "${GET_ACTIVE_FIRMVER}" \
"${FLAGS_device}"
)"
if [ "$?" -eq 0 ]; then
echo "${active_fw_ver}"
fi
}
get_product_id() {
# Query the touchscreen and get the product id
local product_id=""
local cmd_log=""
cmd_log="$(
minijail0 -S /opt/google/touch/policies/wacom_flash.query.policy \
"${WACOMFLASH}" "dummy_unused_argument" "${GET_ACTIVE_FIRMVER}" \
"${FLAGS_device}" 2>&1
)"
product_id="${cmd_log#*PID:0x}"
product_id="${product_id%% *}"
if [ "$?" -eq 0 ]; then
echo "${product_id}"
fi
}
wacom_rebind_driver() {
# Unbind and then bind the driver for this touchpad incase the recent FW
# update changed the way it talks to the OS.
local touch_device_path="$1"
local bus_id="$(basename ${touch_device_path})"
local driver_path="$(readlink -f ${touch_device_path}/driver)"
log_msg "Attempting to re-bind '${bus_id}' to driver '${driver_path}'"
echo "${bus_id}" > "${driver_path}/unbind"
if [ "$?" -ne "0" ]; then
log_msg "Unable to unbind."
else
local retry_cnt=1
echo "${bus_id}" > "${driver_path}/bind"
# For some boards, the device will be powered off when the kernel driver
# unbind. Bind the driver immediately after powering off will fail.
while [ "$?" -ne "0" ] && [ $retry_cnt -le 4 ]; do
retry_cnt="$((retry_cnt + 1))"
log_msg "Fail to bind driver, will retry"
sleep "$retry_cnt"
echo "${bus_id}" > "${driver_path}/bind"
done
if [ "$?" -ne "0" ]; then
log_msg "Unable to bind the device back to the driver."
return 1
else
log_msg "Success."
return 0
fi
fi
}
main() {
# This script runs early at bootup, so if the touch driver is mistakenly
# included as a module (as opposed to being compiled directly in) the i2c
# device may not be present yet. Pause long enough for for people to notice
# and fix the kernel config.
check_i2c_chardev_driver
local active_fw_ver=""
local new_fw_ver=""
local update_type=""
local update_needed=""
local fw_link=""
local product_id=""
local hardware_id=""
local active_product_id=""
local chassis_id="$(get_chassis_id)"
local board_rev="$(get_platform_ver)"
# if there is hardware id implemented, try it as first priority.
# if no, try GET_BOARD_SPECIFIC_HWID as second choice.
hardware_id="$(get_hardware_id)"
if [ -z "${hardware_id}" ]; then
if [ -x "${GET_BOARD_SPECIFIC_HWID}" ]; then
hardware_id="$(${GET_BOARD_SPECIFIC_HWID} -d ${FLAGS_device})"
fi
fi
if [ -z "${hardware_id}" ]; then
product_id="$(get_product_id)"
else
product_id="${hardware_id#*_}"
fi
log_msg "Chassis identifier detected as: ${chassis_id}"
log_msg "Platform version detected as: ${board_rev}"
log_msg "Wacom device hardware ID dectected as: ${hardware_id}"
log_msg "Device product id detected as: ${product_id}"
if [ "${chassis_id}" = "SORAKA" ] && [ "${board_rev}" -lt "5" ] && \
[ "${product_id}" = "4876" -o "${product_id}" = "94" ]; then
# Special case: Soraka < rev5 with Laibao panel (pid = 4876) cannot
# handle latest fw. Also PID will be 94 if fw is corrupted and no
# hwid is supported. So default that case also to the same laibao fw
# since no way to determine correct pid.
log_msg "Soraka legacy (Laibao) special case"
fw_link="/lib/firmware/wacom2_firmware_4876_evt2_or_below.hex"
log_msg "Attempting to find special FW: ${fw_link}"
elif [ -z "${hardware_id}" ]; then
fw_link="$(find_fw_link_path "${FW_LINK_BASE_V2}" "${product_id}")"
log_msg "Attempting to find FW_V2: ${fw_link}"
if [ -L "${fw_link}" ]; then
log_msg "Wacom fw v2 found."
else
log_msg "Wacom fw v2 not found. Will use v1."
fw_link="$(find_fw_link_path "${FW_LINK_BASE}" "${chassis_id}")"
log_msg "Attempting to Load FW: '${fw_link}'"
fi
else
fw_link="$(find_fw_link_path "${FW_LINK_BASE_V2}" "${hardware_id}" \
"${product_id}")"
log_msg "Attempting to find FW_V2: ${fw_link}"
if [ -L "${fw_link}" ]; then
log_msg "Wacom fw v2 found."
else
log_msg "Wacom fw v2 not found. Will use v1."
fw_link="$(find_fw_link_path "${FW_LINK_BASE}" "${hardware_id}" \
"${product_id}")"
log_msg "Attempting to Load FW: '${fw_link}'"
fi
fi
active_fw_ver="$(get_active_fw_version)"
new_fw_ver="$(get_fw_version_from_disk "${fw_link}")"
log_msg "Active firmware version: ${active_fw_ver}"
log_msg "New firmware version: ${new_fw_ver}"
if [ -z "${active_fw_ver}" ]; then
die "Unable to determine active FW version."
fi
report_initial_version "${FLAGS_device_path}" "Wacom" "${active_fw_ver}"
if [ -z "${new_fw_ver}" ]; then
die "Unable to find new FW version on disk."
fi
update_type="$(compare_multipart_version "${active_fw_ver}" "${new_fw_ver}")"
log_update_type "${update_type}"
update_needed="$(is_update_needed "${update_type}")"
if [ "${chassis_id}" = "ARCADA" ] || [ "${chassis_id}" = "ARCADA_SIGNED" ]; then
# Special case: Arcada, if pid not match then force update
active_product_id="$(get_product_id)"
if [ "${product_id}" != "${active_product_id}" ]; then
update_needed="${FLAGS_TRUE}"
fi
fi
if [ "${update_needed}" -eq "${FLAGS_TRUE}" ]; then
log_msg "Update FW to ${new_fw_ver}"
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}")"
if [ "${update_type}" -ne "${UPDATE_NOT_NEEDED_UP_TO_DATE}" ]; then
report_update_result "${FLAGS_device_path}" "${REPORT_RESULT_FAILURE}" \
"${new_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}" \
"${active_fw_ver}"
wacom_rebind_driver "${FLAGS_device_path}"
fi
exit 0
}
main "$@"