blob: d89d5fe8c0d870341083299fb12312c047f01433 [file] [log] [blame]
#!/bin/sh
# Copyright 2017 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.
# This file implements a watchdog, triggered by the udev rules specified in
# '99-modem-watchdog.rules', to monitor if the built-in modem (Huawei ME936) on
# Kip is successfully picked up ModemManager within a specified amount of time
# after the modem appears on USB under USB configuration 3 (i.e. MBIM mode).
# The watchdog will power cycle the modem upon timeout. This is a temporary
# workaround of an out-of-sync issue between the modem and the host
# (chromium:653979). The current implementation assumes only one Huawei ME936
# modem is connected to Kip over the internal M.2 slot, and thus doesn't work
# properly if multiple Huawei ME936 modems are found, which is considered a
# rare and unsupported scenario.
if [ "$1" = '--daemonize' ]; then
shift
setsid nohup "$0" "$@" >/dev/null 2>&1 &
exit
fi
readonly LOG_TAG='modem-watchdog'
readonly MODEM_USB_VID='12d1'
readonly MODEM_USB_PID='15bb'
readonly MODEM_USB_VID_PID="${MODEM_USB_VID}:${MODEM_USB_PID}"
readonly LOCK_FILE=/run/lock/chromeos-kip-modem-watchdog.lock
# Empirically, it takes about ~10s on average for the modem object to show up
# in ModemManager after the modeam appears on USB. The watchdog timeout is set
# for 30s to accomodate some unexpected delay.
readonly TIMEOUT_SECONDS=30
log_info() {
logger -t "${LOG_TAG}" --id="$$" -p info "$*"
echo " INFO: $*"
}
log_warning() {
logger -t "${LOG_TAG}" --id="$$" -p warn "$*"
echo "WARNING: $*"
}
log_error() {
logger -t "${LOG_TAG}" --id="$$" -p err "$*"
echo " ERROR: $*"
}
# Powers "on" or "off" the built-in modem via EC.
#
# Copied from the powerd_suspend script provided by
# chromeos-base/power_manager. As this script is only a temporary workaroud, we
# don't bother to refactor the code for sharing.
ec_power_modem() {
local op="$1"
case "${op}" in
on)
ectool wireless 0x4 0x4
;;
off)
ectool wireless 0x0 0x4
;;
*)
log_msg "Invalid operation 'ec_power_modem ${op}'"
return 1
;;
esac
if [ $? -eq 0 ]; then
log_info "Powered ${op} modem"
return 0
else
log_error "Failed to power ${op} modem"
return 1
fi
}
get_modem_devices() {
dbus-send --fixed --system --print-reply \
--dest=org.freedesktop.ModemManager1 \
/org/freedesktop/ModemManager1 \
org.freedesktop.DBus.ObjectManager.GetManagedObjects \
2>/dev/null | sed -nE 's|.*/Device (/sys/devices/.+)|\1|p'
}
match_modem_ids() {
local device="$1"
local vid="$2"
local pid="$3"
if ! grep -iqs "${vid}" "${device}/idVendor"; then
return 1
fi
if ! grep -iqs "${pid}" "${device}/idProduct"; then
return 1
fi
return 0
}
modem_watchdog() {
local seconds=0
local device
local modem_devices
log_info "Start waiting for modem to be ready"
while [ "${seconds}" -lt "${TIMEOUT_SECONDS}" ]; do
if ! lsusb -d "${MODEM_USB_VID_PID}" >/dev/null; then
log_warning "Modem is no longer on USB; exiting watchdog"
return 2
fi
modem_devices="$(get_modem_devices)"
if [ $? -ne 0 ]; then
log_warning "ModemManager isn't running? exiting watchdog"
return 2
fi
for device in ${modem_devices}; do
if match_modem_ids "${device}" "${MODEM_USB_VID}" "${MODEM_USB_PID}"; then
log_info "Found modem object for ${MODEM_USB_VID_PID}; exiting watchdog"
return
fi
done
sleep 1
: $((seconds += 1))
done
log_warning "Timed out waiting for modem to be ready; power-cycling modem"
ec_power_modem off
sleep .5
ec_power_modem on
log_info "Exiting watchdog"
return 1
}
(
# Ensure only one instance of modem watchdog is running at a time.
flock -n 9 || exit 0
modem_watchdog
) 9>"${LOCK_FILE}" || exit 0