switch: added ignore_hpd quirk for bad csi boards

This commit is contained in:
Maxim Devaev 2025-02-16 01:00:38 +02:00
parent 02740aef37
commit 6a08fab818
8 changed files with 64 additions and 13 deletions

View File

@ -508,6 +508,7 @@ 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"),
"ignore_hpd_on_top": Option(False, type=valid_bool),
},
},

View File

@ -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)

View File

@ -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):

View File

@ -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(

View File

@ -60,6 +60,7 @@ class Header(Packable, Unpackable):
SET_EDID = 9
CLEAR_EDID = 10
SET_COLORS = 12
SET_QUIRKS = 13
__struct = struct.Struct("<BHBB")
@ -89,6 +90,13 @@ class Nak(Unpackable):
return Nak(*cls.__struct.unpack_from(data, offset=offset))
@dataclasses.dataclass(frozen=True)
class UnitVersion:
hw: int
sw: int
sw_dev: bool
@dataclasses.dataclass(frozen=True)
class UnitFlags:
changing_busy: bool
@ -97,10 +105,14 @@ class UnitFlags:
has_hpd: bool
@dataclasses.dataclass(frozen=True)
class UnitQuirks:
ignore_hpd: bool
@dataclasses.dataclass(frozen=True)
class UnitState(Unpackable): # pylint: disable=too-many-instance-attributes
sw_version: int
hw_version: int
version: UnitVersion
flags: UnitFlags
ch: int
beacons: tuple[bool, bool, bool, bool, bool, bool]
@ -111,8 +123,9 @@ class UnitState(Unpackable): # pylint: disable=too-many-instance-attributes
video_crc: tuple[int, int, int, int]
usb_5v_sens: tuple[bool, bool, bool, bool]
atx_busy: tuple[bool, bool, bool, bool]
quirks: UnitQuirks
__struct = struct.Struct("<HHHBBHHHHHHBBBHHHHBxB30x")
__struct = struct.Struct("<HHHBBHHHHHHBBBHHHHBxBB29x")
def compare_edid(self, ch: int, edid: Optional["Edid"]) -> 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:

View File

@ -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:

Binary file not shown.

View File

@ -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) {