| # Copyright 2018 The ChromiumOS Authors | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| """Common constant and device related information.""" | |
| from __future__ import print_function | |
| import atexit | |
| import os | |
| import subprocess | |
| import time | |
| import hammerd_api # pylint: disable=import-error | |
| def cros_config(path, key, check=True): | |
| cmd = ["cros_config", path, key] | |
| proc = subprocess.run( | |
| cmd, encoding="utf-8", check=check, capture_output=True | |
| ) | |
| return None if proc.returncode else proc.stdout | |
| # The root path of the hammertests. | |
| ROOT_DIR = os.path.dirname(os.path.realpath(__file__)) | |
| IMAGE_DIR = os.path.join(ROOT_DIR, "images") | |
| UDEV_RULES_PATH = "/lib/udev/rules.d/99-hammerd.rules" | |
| BASE_TABLE = { | |
| "coachz": "zed", | |
| "poppy": "hammer", | |
| "soraka": "staff", | |
| "nocturne": "whiskers", | |
| "kodama": "magnemite", | |
| "krane": "masterball", | |
| "kakadu": "moonball", | |
| "katsu": "don", | |
| "homestar": "star", | |
| "wormdingler": "eel", | |
| "quackingstick": "duck", | |
| "starmie": "jewel", | |
| "ciri": "kelpie", | |
| } | |
| BOARD_NAME = cros_config("/", "name") | |
| BASE_NAME = BASE_TABLE[BOARD_NAME.rstrip()] | |
| BASE_USB_PATH = None | |
| BASE_I2C_PATH = None | |
| # Device-dependent information. | |
| # Deprecated, new devices should use cros_config instead. | |
| # (b/188625010) | |
| if BASE_NAME == "staff": | |
| BASE_VENDOR_ID = 0x18D1 | |
| BASE_PRODUCT_ID = 0x502B | |
| BASE_USB_PATH = "1-2" | |
| BASE_CONN_GPIO = "PP3300_DX_BASE" | |
| TP = f"/lib/firmware/{BASE_NAME}-touchpad.fw" | |
| elif BASE_NAME == "whiskers": | |
| BASE_VENDOR_ID = 0x18D1 | |
| BASE_PRODUCT_ID = 0x5030 | |
| BASE_USB_PATH = "1-7" | |
| BASE_CONN_GPIO = "BASE_PWR_EN" | |
| TP = f"/lib/firmware/{BASE_NAME}-touchpad.fw" | |
| elif BASE_NAME == "hammer": | |
| BASE_VENDOR_ID = 0x18D1 | |
| BASE_PRODUCT_ID = 0x5022 | |
| BASE_USB_PATH = "1-3" | |
| BASE_CONN_GPIO = "PP3300_DX_BASE" | |
| TP = f"/lib/firmware/{BASE_NAME}-touchpad.fw" | |
| elif BASE_NAME == "magnemite": | |
| BASE_VENDOR_ID = 0x18D1 | |
| BASE_PRODUCT_ID = 0x503D | |
| BASE_USB_PATH = "1-1.1" | |
| BASE_CONN_GPIO = "EN_PP3300_POGO" | |
| TP = f"/lib/firmware/{BASE_NAME}-touch.fw" | |
| elif BASE_NAME == "masterball": | |
| BASE_VENDOR_ID = 0x18D1 | |
| BASE_PRODUCT_ID = 0x503C | |
| BASE_USB_PATH = "1-1.1" | |
| BASE_CONN_GPIO = "EN_PP3300_POGO" | |
| TP = f"/lib/firmware/{BASE_NAME}-touch.fw" | |
| elif BASE_NAME == "moonball": | |
| BASE_VENDOR_ID = 0x18D1 | |
| BASE_PRODUCT_ID = 0x5044 | |
| BASE_USB_PATH = "1-1.1" | |
| BASE_CONN_GPIO = "EN_PP3300_POGO" | |
| TP = f"/lib/firmware/{BASE_NAME}-touch.fw" | |
| elif BASE_NAME == "zed": | |
| BASE_VENDOR_ID = 0x18D1 | |
| BASE_PRODUCT_ID = 0x504C | |
| BASE_USB_PATH = "1-1.4" | |
| BASE_CONN_GPIO = "EN_BASE" | |
| TP = f"/lib/firmware/{BASE_NAME}-touch.fw" | |
| elif BASE_NAME == "don": | |
| BASE_VENDOR_ID = 0x18D1 | |
| BASE_PRODUCT_ID = 0x5050 | |
| BASE_USB_PATH = "1-1.1" | |
| BASE_CONN_GPIO = "EN_PP3300_POGO" | |
| TP = f"/lib/firmware/{BASE_NAME}-touch.fw" | |
| else: | |
| BASE_VENDOR_ID = int(cros_config("/detachable-base", "vendor-id")) | |
| BASE_PRODUCT_ID = int(cros_config("/detachable-base", "product-id")) | |
| BASE_USB_PATH = cros_config("/detachable-base", "usb-path", check=False) | |
| BASE_I2C_PATH = cros_config("/detachable-base", "i2c-path", check=False) | |
| BASE_CONN_GPIO = None | |
| TP = os.path.join( | |
| "/lib/firmware/", cros_config("/detachable-base", "touch-image-name") | |
| ) | |
| assert (BASE_USB_PATH is not None) ^ (BASE_I2C_PATH is not None) | |
| # Status of flash protect. | |
| EC_FLASH_PROTECT_RO_AT_BOOT = 1 << 0 | |
| EC_FLASH_PROTECT_RO_NOW = 1 << 1 | |
| EC_FLASH_PROTECT_ALL_NOW = 1 << 2 | |
| EC_FLASH_PROTECT_GPIO_ASSERTED = 1 << 3 | |
| EC_FLASH_PROTECT_ERROR_STUCK = 1 << 4 | |
| EC_FLASH_PROTECT_ERROR_INCONSISTENT = 1 << 5 | |
| EC_FLASH_PROTECT_ALL_AT_BOOT = 1 << 6 | |
| EC_FLASH_PROTECT_RW_AT_BOOT = 1 << 7 | |
| EC_FLASH_PROTECT_RW_NOW = 1 << 8 | |
| EC_FLASH_PROTECT_ROLLBACK_AT_BOOT = 1 << 9 | |
| EC_FLASH_PROTECT_ROLLBACK_NOW = 1 << 10 | |
| # Path of testing image files. | |
| IMAGE = os.path.join(IMAGE_DIR, f"{BASE_NAME}.bin") | |
| RW_DEV = os.path.join(IMAGE_DIR, f"{BASE_NAME}.dev") | |
| RW_CORRUPT_FIRST_BYTE = os.path.join( | |
| IMAGE_DIR, f"{BASE_NAME}_corrupt_first_byte.bin" | |
| ) | |
| RW_CORRUPT_LAST_BYTE = os.path.join( | |
| IMAGE_DIR, f"{BASE_NAME}_corrupt_last_byte.bin" | |
| ) | |
| RW_VALID = os.path.join(IMAGE_DIR, f"{BASE_NAME}.bin") | |
| OLDER_IMAGE = os.path.join(IMAGE_DIR, f"{BASE_NAME}_older.bin") | |
| NEWER_IMAGE = os.path.join(IMAGE_DIR, f"{BASE_NAME}.bin") | |
| # Image should not update RW | |
| RB_LOWER = os.path.join(IMAGE_DIR, f"{BASE_NAME}.dev.rb0") | |
| # Initial DUT image | |
| RB_INITIAL = os.path.join(IMAGE_DIR, f"{BASE_NAME}.dev.rb1") | |
| # Image should update RW and RB regions region | |
| RB_HIGHER = os.path.join(IMAGE_DIR, f"{BASE_NAME}.dev.rb9") | |
| # Time to wait to ensure the base keyboard jumps from RO to RW in seconds. | |
| # Since there are various factor affecting the test to interacting with the RW | |
| # firmware, the wait time here is choose to be far greater than the jump time to | |
| # ensure the test code interacts with the RW section. | |
| WAIT_TIME_JUMP_FROM_RO_TO_RW = 4 | |
| # Common function. | |
| def connect_usb(updater): | |
| updater.TryConnectUsb() | |
| assert updater.SendFirstPdu() is True, "Error sending first PDU" | |
| updater.SendDone() | |
| def sim_disconnect_connect(updater): | |
| print("Simulate hammer disconnect/ reconnect to reset base") | |
| if BASE_CONN_GPIO: | |
| subprocess.call(["ectool", "gpioset", BASE_CONN_GPIO, "0"]) | |
| subprocess.call(["ectool", "gpioset", BASE_CONN_GPIO, "1"]) | |
| else: | |
| subprocess.call(["ectool", "basestate", "detach"]) | |
| subprocess.call(["ectool", "basestate", "attach"]) | |
| updater.CloseUsb() | |
| # Need to give base time to be visible to lid | |
| time.sleep(3) | |
| def disable_hammerd(): | |
| print("Disabling hammerd") | |
| if os.path.ismount(UDEV_RULES_PATH): | |
| return | |
| subprocess.call(["mount", "--bind", "/dev/null", UDEV_RULES_PATH]) | |
| subprocess.call(["initctl", "restart", "udev"]) | |
| atexit.register(enable_hammerd) | |
| def enable_hammerd(): | |
| print("Enabling hammerd") | |
| subprocess.call(["umount", UDEV_RULES_PATH]) | |
| subprocess.call(["initctl", "restart", "udev"]) | |
| def reset_stay_ro(updater): | |
| # Send immediate reset | |
| updater.SendSubcommand(hammerd_api.UpdateExtraCommand.ImmediateReset) | |
| updater.CloseUsb() | |
| # Wait for base to reappear and send StayInRO | |
| time.sleep(0.5) | |
| updater.TryConnectUsb() | |
| updater.SendSubcommand(hammerd_api.UpdateExtraCommand.StayInRO) | |
| updater.SendFirstPdu() | |
| updater.SendDone() | |
| # Wait to stay in RO | |
| time.sleep(5) | |
| print(f"Current section after StayInRO cmd: {updater.CurrentSection()}") | |
| assert updater.CurrentSection() == 0, "Running section should be 0 (RO)" | |
| def get_firmware_updater(): | |
| return hammerd_api.FirmwareUpdater( | |
| BASE_VENDOR_ID, | |
| BASE_PRODUCT_ID, | |
| usb_path=BASE_USB_PATH, | |
| i2c_path=BASE_I2C_PATH, | |
| ) |