diff --git a/kvmd/apps/__init__.py b/kvmd/apps/__init__.py index e48079a5..ef258044 100644 --- a/kvmd/apps/__init__.py +++ b/kvmd/apps/__init__.py @@ -506,8 +506,9 @@ def _get_config_scheme() -> dict: }, "switch": { - "device": Option("/dev/kvmd-switch", type=valid_abs_path, unpack_as="device_path"), - "default_edid": Option("/etc/kvmd/switch-edid.hex", type=valid_abs_path, unpack_as="default_edid_path"), + "device": Option("/dev/kvmd-switch", type=valid_abs_path, unpack_as="device_path"), + "default_edid": Option("/etc/kvmd/switch-edid.hex", type=valid_abs_path, unpack_as="default_edid_path"), + "ignore_hpd_on_top": Option(False, type=valid_bool), }, }, diff --git a/kvmd/apps/kvmd/switch/__init__.py b/kvmd/apps/kvmd/switch/__init__.py index 49bfbd7d..f0cc98f2 100644 --- a/kvmd/apps/kvmd/switch/__init__.py +++ b/kvmd/apps/kvmd/switch/__init__.py @@ -84,11 +84,12 @@ class Switch: # pylint: disable=too-many-public-methods device_path: str, default_edid_path: str, pst_unix_path: str, + ignore_hpd_on_top: bool, ) -> None: self.__default_edid_path = default_edid_path - self.__chain = Chain(device_path) + self.__chain = Chain(device_path, ignore_hpd_on_top) self.__cache = StateCache() self.__storage = Storage(pst_unix_path) diff --git a/kvmd/apps/kvmd/switch/chain.py b/kvmd/apps/kvmd/switch/chain.py index 8e4d94eb..7137f5b9 100644 --- a/kvmd/apps/kvmd/switch/chain.py +++ b/kvmd/apps/kvmd/switch/chain.py @@ -177,8 +177,14 @@ class UnitAtxLedsEvent(BaseEvent): # ===== class Chain: # pylint: disable=too-many-instance-attributes - def __init__(self, device_path: str) -> None: + def __init__( + self, + device_path: str, + ignore_hpd_on_top: bool, + ) -> None: + self.__device = Device(device_path) + self.__ignore_hpd_on_top = ignore_hpd_on_top self.__actual = False @@ -293,6 +299,7 @@ class Chain: # pylint: disable=too-many-instance-attributes if self.__select(): for resp in self.__device.read_all(): self.__update_units(resp) + self.__adjust_quirks() self.__adjust_start_port() self.__finish_changing_request(resp) self.__consume_commands() @@ -364,6 +371,15 @@ class Chain: # pylint: disable=too-many-instance-attributes self.__units[resp.header.unit].atx_leds = resp.body self.__queue_event(UnitAtxLedsEvent(resp.header.unit, resp.body)) + def __adjust_quirks(self) -> None: + for (unit, ctx) in enumerate(self.__units): + if ctx.state is not None and (ctx.state.version.sw_dev or ctx.state.version.sw >= 7): + ignore_hpd = (unit == 0 and self.__ignore_hpd_on_top) + if ctx.state.quirks.ignore_hpd != ignore_hpd: + get_logger().info("Applying quirk ignore_hpd=%s to [%d] ...", + ignore_hpd, unit) + self.__device.request_set_quirks(unit, ignore_hpd) + def __adjust_start_port(self) -> None: if self.__active_port < 0: for (unit, ctx) in enumerate(self.__units): diff --git a/kvmd/apps/kvmd/switch/device.py b/kvmd/apps/kvmd/switch/device.py index b56cc406..a057a50d 100644 --- a/kvmd/apps/kvmd/switch/device.py +++ b/kvmd/apps/kvmd/switch/device.py @@ -42,6 +42,7 @@ from .proto import BodyAtxClick from .proto import BodySetEdid from .proto import BodyClearEdid from .proto import BodySetColors +from .proto import BodySetQuirks # ===== @@ -166,6 +167,9 @@ class Device: def request_set_colors(self, unit: int, ch: int, colors: Colors) -> int: return self.__send_request(Header.SET_COLORS, unit, BodySetColors(ch, colors)) + def request_set_quirks(self, unit: int, ignore_hpd: bool) -> int: + return self.__send_request(Header.SET_QUIRKS, unit, BodySetQuirks(ignore_hpd)) + def __send_request(self, op: int, unit: int, body: (Packable | None)) -> int: assert self.__tty is not None req = Request(Header( diff --git a/kvmd/apps/kvmd/switch/proto.py b/kvmd/apps/kvmd/switch/proto.py index 43da118f..2081a4b6 100644 --- a/kvmd/apps/kvmd/switch/proto.py +++ b/kvmd/apps/kvmd/switch/proto.py @@ -60,6 +60,7 @@ class Header(Packable, Unpackable): SET_EDID = 9 CLEAR_EDID = 10 SET_COLORS = 12 + SET_QUIRKS = 13 __struct = struct.Struct(" bool: if edid is None: @@ -129,11 +142,14 @@ class UnitState(Unpackable): # pylint: disable=too-many-instance-attributes sw_version, hw_version, flags, ch, beacons, nc0, nc1, nc2, nc3, nc4, nc5, video_5v_sens, video_hpd, video_edid, vc0, vc1, vc2, vc3, - usb_5v_sens, atx_busy, + usb_5v_sens, atx_busy, quirks, ) = cls.__struct.unpack_from(data, offset=offset) return UnitState( - sw_version, - hw_version, + version=UnitVersion( + hw=hw_version, + sw=(sw_version & 0x7FFF), + sw_dev=bool(sw_version & 0x8000), + ), flags=UnitFlags( changing_busy=bool(flags & 0x80), flashing_busy=bool(flags & 0x40), @@ -149,6 +165,7 @@ class UnitState(Unpackable): # pylint: disable=too-many-instance-attributes video_crc=(vc0, vc1, vc2, vc3), usb_5v_sens=cls.__make_flags4(usb_5v_sens), atx_busy=cls.__make_flags4(atx_busy), + quirks=UnitQuirks(ignore_hpd=bool(quirks & 0x01)), ) @classmethod @@ -265,6 +282,14 @@ class BodySetColors(Packable): return self.ch.to_bytes() + self.colors.pack() +@dataclasses.dataclass(frozen=True) +class BodySetQuirks(Packable): + ignore_hpd: bool + + def pack(self) -> bytes: + return self.ignore_hpd.to_bytes() + + # ===== @dataclasses.dataclass(frozen=True) class Request: diff --git a/kvmd/apps/kvmd/switch/state.py b/kvmd/apps/kvmd/switch/state.py index 5b06db0a..84f01cfd 100644 --- a/kvmd/apps/kvmd/switch/state.py +++ b/kvmd/apps/kvmd/switch/state.py @@ -49,7 +49,7 @@ class _UnitInfo: # ===== class StateCache: # pylint: disable=too-many-instance-attributes - __FW_VERSION = 6 + __FW_VERSION = 7 __FULL = 0xFFFF __SUMMARY = 0x01 @@ -195,7 +195,10 @@ class StateCache: # pylint: disable=too-many-instance-attributes assert ui.state is not None assert ui.atx_leds is not None if x_model: - state["model"]["units"].append({"firmware": {"version": ui.state.sw_version}}) + state["model"]["units"].append({"firmware": { + "version": ui.state.version.sw, + "devbuild": ui.state.version.sw_dev, + }}) if x_video: state["video"]["links"].extend(ui.state.video_5v_sens[:4]) if x_usb: diff --git a/switch/switch.uf2 b/switch/switch.uf2 index c6581ab9..e5a1725e 100644 Binary files a/switch/switch.uf2 and b/switch/switch.uf2 differ diff --git a/web/share/js/kvm/switch.js b/web/share/js/kvm/switch.js index e54307f2..a33e2fd0 100644 --- a/web/share/js/kvm/switch.js +++ b/web/share/js/kvm/switch.js @@ -408,7 +408,8 @@ export function Switch() { $("switch-chain").innerHTML = content; if (model.units.length > 0) { - tools.hidden.setVisible($("switch-message-update"), (model.firmware.version > model.units[0].firmware.version)); + let fw = model.units[0].firmware; + tools.hidden.setVisible($("switch-message-update"), (fw.devbuild || fw.version < model.firmware.version)); } for (let unit = 0; unit < model.units.length; ++unit) {