blob: 89b85c8cce5cac38ef1539bb628415fedc30bbf4 [file] [log] [blame]
#!/bin/sh
# Copyright (c) 2013 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.
I2C_DEVICES_PATH="/sys/bus/i2c/devices"
# Find touchscreen/pad path in i2c devices given it's device name and a list
# of the sysfs entries it is expect to have (this can help skip over some
# bogus devices that have already been disconnected)
# The required sysfs filenames could be supplied as a space-delimited string
find_i2c_device_by_name() {
local dev=""
local name_to_find="$1"
local required_sysfs="$2"
for dev in "${I2C_DEVICES_PATH}"/*/name; do
local dev_name="$(cat "${dev}")"
if [ "${name_to_find}" = "${dev_name}" ]; then
local missing_sysfs_entry=0
local path="${dev%/name}"
for sysfs in $required_sysfs; do
if [ ! -e "${path}/${sysfs}" ]; then
missing_sysfs_entry=1
fi
done
if [ "${missing_sysfs_entry}" -eq 0 ]; then
echo "${path}"
return 0
fi
fi
done
return 1
}
find_i2c_hid_device() {
local dev=""
local path=""
local vid="${1%_*}"
local pid="${1#*_}"
for dev in "${I2C_DEVICES_PATH}"/*/; do
local driver_name="$(readlink -f ${dev}/driver | xargs basename)"
if [ "i2c_hid" = "${driver_name}" ]; then
local hid_path=$(echo ${dev}/*:${vid}:${pid}.*)
if [ -d "${hid_path}" ]; then
local hidraw_sysfs_path=$(echo ${hid_path}/hidraw/hidraw*)
path="/dev/${hidraw_sysfs_path##*/}"
break
fi
fi
done
echo "${path}"
}
find_fw_link_path() {
# Given a hardware version (or product ID depending on the device)
# determine which fw symlink in /lib/firmware it should try to load
local hw_version="$1"
local fw_link_name="$2"
local specific_fw_link_path=""
local generic_fw_link_path=""
local fw_link_name_extension="`expr "$fw_link_name" : ".*\(\..*\)"`"
local fw_link_name_base="${fw_link_name%$fw_link_name_extension}"
case ${fw_link_name_base} in
/*) fw_link_path="${fw_link_name_base}" ;;
*) fw_link_path="/lib/firmware/${fw_link_name_base}" ;;
esac
specific_fw_link_path="${fw_link_path}_${hw_version}${fw_link_name_extension}"
generic_fw_link_path="${fw_link_path}${fw_link_name_extension}"
if [ -e "${specific_fw_link_path}" ]; then
echo "${specific_fw_link_path}"
else
echo "${generic_fw_link_path}"
fi
}
standard_update_firmware() {
# Update a touch device by piping a "1" into a sysfs entry called update_fw
# This is a common method for triggering a FW update, and it used by several
# different touch vendors.
local touch_device_path="$1"
local i=""
local ret=""
for i in $(seq 5); do
printf 1 > "${touch_device_path}/update_fw"
ret=$?
if [ ${ret} -eq 0 ]; then
return 0
fi
log_msg "update_firmware try #${i} failed... retrying."
done
die "Error updating touch firmware. ${ret}"
}
get_active_firmware_version_from_sysfs() {
local sysfs_name="$1"
local touch_device_path="$2"
local fw_version_sysfs_path="${touch_device_path}/${sysfs_name}"
if [ -e "${fw_version_sysfs_path}" ]; then
cat "${fw_version_sysfs_path}"
else
die "No firmware version sysfs at ${fw_version_sysfs_path}."
fi
}
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
echo "${bus_id}" > "${driver_path}/bind"
if [ "$?" -ne "0" ]; then
log_msg "Unable to bind the device back to the driver."
else
log_msg "Success."
fi
fi
}
hex_to_decimal() {
printf "%d" "0x""$1"
}
log_msg() {
local script_filename="$(basename $0)"
logger -t "${script_filename%.*}[${PPID}]-${FLAGS_device}" "$@"
echo "$@"
}
die() {
log_msg "error: $*"
exit 1
}
# These flags can be used as "update types" to indicate updater state
UPDATE_NEEDED_OUT_OF_DATE="1"
UPDATE_NEEDED_RECOVERY="2"
UPDATE_NOT_NEEDED_UP_TO_DATE="3"
UPDATE_NOT_NEEDED_AHEAD_OF_DATE="4"
log_update_type() {
# Given the update type, print a corresponding message into the logs.
local update_type="$1"
if [ "${update_type}" -eq "${UPDATE_NEEDED_OUT_OF_DATE}" ]; then
log_msg "Update needed, firmware out of date."
elif [ "${update_type}" -eq "${UPDATE_NEEDED_RECOVERY}" ]; then
log_msg "Recovery firmware update. Rolling back."
elif [ "${update_type}" -eq "${UPDATE_NOT_NEEDED_UP_TO_DATE}" ]; then
log_msg "Firmware up to date."
elif [ "${update_type}" -eq "${UPDATE_NOT_NEEDED_AHEAD_OF_DATE}" ]; then
log_msg "Active firmware is ahead of updater, no update needed."
else
log_msg "Unknow update type '${update_type}'."
fi
}
is_update_needed() {
# Given an update type, this function returns a boolean indicating if the
# updater should trigger an update at all.
local update_type="$1"
if [ "${update_type}" -eq "${UPDATE_NEEDED_OUT_OF_DATE}" ] ||
[ "${update_type}" -eq "${UPDATE_NEEDED_RECOVERY}" ]; then
echo ${FLAGS_TRUE}
else
echo ${FLAGS_FALSE}
fi
}
compare_multipart_version() {
# Compare firmware versions that are of the form A.B...Y.Z
# The numbers must all be devimal integers for this to work, so
# do your conversions before calling the function.
# To call this function interleave the two version strings by
# importance, starting with the active FW version.
# eg: If your active version is A.B.C and the fw updater is X.Y.Z
# you should call compare_multipart_version A X B Y C Z
local update_type=""
local num_parts="$(($# / 2))"
# Starting with the most significant values, compare them one
# by one until we find a difference or run out of values.
for i in `seq "$num_parts"`; do
local active_component="$1"
local updater_component="$2"
if [ -z "${update_type}" ]; then
if [ "${active_component}" -lt "${updater_component}" ]; then
update_type="${UPDATE_NEEDED_OUT_OF_DATE}"
elif [ "${active_component}" -gt "${updater_component}" ]; then
update_type="${UPDATE_NOT_NEEDED_AHEAD_OF_DATE}"
fi
fi
shift
shift
done
if [ -z "${update_type}" ]; then
update_type="${UPDATE_NOT_NEEDED_UP_TO_DATE}"
elif [ "${FLAGS_recovery}" -eq "${FLAGS_TRUE}" ] &&
[ "${update_type}" = "${UPDATE_NOT_NEEDED_AHEAD_OF_DATE}" ]; then
update_type="${UPDATE_NEEDED_RECOVERY}"
fi
echo "${update_type}"
}
get_customization_id() {
# Get the "customization id" from the Chromebook's VPD. This ID is
# mandatory for Zerg systems (where 2 different devices use the same build)
# and can be used to differentiate them. If the entry doesn't exist, this
# will simply not print anything. Note that is is only required to remain
# constant *after* a machine has reached MP -- if you don't know what you're
# doing you're probably better off using get_board_name which wraps this.
vpd_get_value customization_id
}
get_board_name_from_vpd() {
# Get the name of this specific board. This is done to differentiate which
# board is being used, and the board name is determined by looking at the
# customization_id in VPD which is supposed to be of the format:
# "${OEM_NAME}-${BOARD_NAME}" By stripping off the OEM name we allow the
# customization_id to change to mask the OEM name during early stages of
# development without having to modify the firmware filenames.
local customization_id="$(get_customization_id)"
if [ -z "${customization_id}" ]; then
echo ""
fi
echo "${customization_id##*-}"
}