diff options
author | Nicholas Sudsgaard <devel+coreboot@nsudsgaard.com> | 2024-02-14 18:10:57 +0900 |
---|---|---|
committer | Michael Niewöhner <foss@mniewoehner.de> | 2024-07-15 07:22:32 +0000 |
commit | b205f4e53ec30487ea1c219366e496664a3c20aa (patch) | |
tree | e5dcc7bc41a60691791911dac42538e95fb35a78 /util/hda-decoder/decoder | |
parent | b0fa6683de2e97c017cf73eaa409350a2f1709e3 (diff) |
util: Add hda-decoder
This tool helps take off the burden of manually decoding default
configuration registers. Using decoded values can make code more
self-documenting compared to shrouding it with magic numbers.
This is also written as a module which allows easy integration with
other tools written in Go (e.g. autoport).
Change-Id: Ib4fb652e178517b2b7aceaac8be005c5b2d3b03e
Signed-off-by: Nicholas Sudsgaard <devel+coreboot@nsudsgaard.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/80470
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Felix Singer <service+coreboot-gerrit@felixsinger.de>
Reviewed-by: Michael Niewöhner <foss@mniewoehner.de>
Diffstat (limited to 'util/hda-decoder/decoder')
-rw-r--r-- | util/hda-decoder/decoder/lib.go | 179 | ||||
-rw-r--r-- | util/hda-decoder/decoder/lib_test.go | 109 |
2 files changed, 288 insertions, 0 deletions
diff --git a/util/hda-decoder/decoder/lib.go b/util/hda-decoder/decoder/lib.go new file mode 100644 index 0000000000..834e83044c --- /dev/null +++ b/util/hda-decoder/decoder/lib.go @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +package decoder + +import ( + "fmt" + "math/bits" +) + +type Fields[T uint32 | string] struct { + PortConnectivity T + Location T + DefaultDevice T + ConnectionType T + Color T + Misc T + DefaultAssociation T + Sequence T +} + +func getField(config uint32, mask uint32) uint32 { + return (config & mask) >> bits.TrailingZeros32(mask) +} + +func Decode(config uint32) Fields[uint32] { + return Fields[uint32]{ + PortConnectivity: getField(config, 0xc0000000), + Location: getField(config, 0x3f000000), + DefaultDevice: getField(config, 0x00f00000), + ConnectionType: getField(config, 0x000f0000), + Color: getField(config, 0x0000f000), + Misc: getField(config, 0x00000f00), + DefaultAssociation: getField(config, 0x000000f0), + Sequence: getField(config, 0x0000000f), + } +} + +func PortIsConnected(config uint32) bool { + return Decode(config).PortConnectivity != 0x1 +} + +var portConnectivityDescriptions = map[uint32]string{ + 0x0: "AZALIA_JACK", + 0x1: "AZALIA_NC", + 0x2: "AZALIA_INTEGRATED", + 0x3: "AZALIA_JACK_AND_INTEGRATED", +} + +var grossLocationDescriptions = map[uint32]string{ + 0x00: "AZALIA_EXTERNAL_PRIMARY_CHASSIS", + 0x10: "AZALIA_INTERNAL", + 0x20: "AZALIA_SEPARATE_CHASSIS", + 0x30: "AZALIA_LOCATION_OTHER", +} + +var geometricLocationDescriptions = map[uint32]string{ + 0x00: "AZALIA_GEOLOCATION_NA", + 0x01: "AZALIA_REAR", + 0x02: "AZALIA_FRONT", + 0x03: "AZALIA_LEFT", + 0x04: "AZALIA_RIGHT", + 0x05: "AZALIA_TOP", + 0x06: "AZALIA_BOTTOM", + 0x07: "AZALIA_SPECIAL7", + 0x08: "AZALIA_SPECIAL8", + 0x09: "AZALIA_SPECIAL9", +} + +var specialLocationDescriptions = map[uint32]string{ + 0x00 | 0x07: "AZALIA_REAR_PANEL", + 0x00 | 0x08: "AZALIA_DRIVE_BAY", + 0x10 | 0x07: "AZALIA_RISER", + 0x10 | 0x08: "AZALIA_DIGITAL_DISPLAY", + 0x10 | 0x09: "AZALIA_ATAPI", + 0x30 | 0x07: "AZALIA_MOBILE_LID_INSIDE", + 0x30 | 0x08: "AZALIA_MOBILE_LID_OUTSIDE", +} + +var defaultDeviceDescriptions = map[uint32]string{ + 0x0: "AZALIA_LINE_OUT", + 0x1: "AZALIA_SPEAKER", + 0x2: "AZALIA_HP_OUT", + 0x3: "AZALIA_CD", + 0x4: "AZALIA_SPDIF_OUT", + 0x5: "AZALIA_DIGITAL_OTHER_OUT", + 0x6: "AZALIA_MODEM_LINE_SIDE", + 0x7: "AZALIA_MODEM_HANDSET_SIDE", + 0x8: "AZALIA_LINE_IN", + 0x9: "AZALIA_AUX", + 0xa: "AZALIA_MIC_IN", + 0xb: "AZALIA_TELEPHONY", + 0xc: "AZALIA_SPDIF_IN", + 0xd: "AZALIA_DIGITAL_OTHER_IN", + 0xf: "AZALIA_DEVICE_OTHER", +} + +var connectionTypeDescriptions = map[uint32]string{ + 0x0: "AZALIA_TYPE_UNKNOWN", + 0x1: "AZALIA_STEREO_MONO_1_8", + 0x2: "AZALIA_STEREO_MONO_1_4", + 0x3: "AZALIA_ATAPI_INTERNAL", + 0x4: "AZALIA_RCA", + 0x5: "AZALIA_OPTICAL", + 0x6: "AZALIA_OTHER_DIGITAL", + 0x7: "AZALIA_OTHER_ANALOG", + 0x8: "AZALIA_MULTICHANNEL_ANALOG", + 0x9: "AZALIA_XLR", + 0xa: "AZALIA_RJ_11", + 0xb: "AZALIA_COMBINATION", + 0xf: "AZALIA_TYPE_OTHER", +} + +var colorDescriptions = map[uint32]string{ + 0x0: "AZALIA_COLOR_UNKNOWN", + 0x1: "AZALIA_BLACK", + 0x2: "AZALIA_GREY", + 0x3: "AZALIA_BLUE", + 0x4: "AZALIA_GREEN", + 0x5: "AZALIA_RED", + 0x6: "AZALIA_ORANGE", + 0x7: "AZALIA_YELLOW", + 0x8: "AZALIA_PURPLE", + 0x9: "AZALIA_PINK", + 0xe: "AZALIA_WHITE", + 0xf: "AZALIA_COLOR_OTHER", +} + +var miscDescriptions = map[uint32]string{ + 0x0: "AZALIA_JACK_PRESENCE_DETECT", + 0x1: "AZALIA_NO_JACK_PRESENCE_DETECT", +} + +func getDescription(field uint32, descriptions map[uint32]string) string { + desc, exists := descriptions[field] + + if !exists { + return fmt.Sprintf("0x%x", field) + } + return desc +} + +func getLocationDescription(field uint32) string { + desc, isSpecialLocation := specialLocationDescriptions[field] + if isSpecialLocation { + return desc + } + + grossLocation := field & 0x30 + geometricLocation := field & 0x0f + + desc = grossLocationDescriptions[grossLocation] + if geometricLocation != 0x00 { + desc += " | " + getDescription(geometricLocation, geometricLocationDescriptions) + } + return desc +} + +func getMiscDescription(field uint32) string { + presenceBit := field & 0b0001 + reservedBits := field & 0b1110 + + desc := miscDescriptions[presenceBit] + if bits.OnesCount32(reservedBits) > 0 { + desc += fmt.Sprintf(" | 0x%x", reservedBits) + } + return desc +} + +func ToHumanReadable(fields Fields[uint32]) Fields[string] { + return Fields[string]{ + PortConnectivity: getDescription(fields.PortConnectivity, portConnectivityDescriptions), + Location: getLocationDescription(fields.Location), + DefaultDevice: getDescription(fields.DefaultDevice, defaultDeviceDescriptions), + ConnectionType: getDescription(fields.ConnectionType, connectionTypeDescriptions), + Color: getDescription(fields.Color, colorDescriptions), + Misc: getMiscDescription(fields.Misc), + DefaultAssociation: fmt.Sprintf("%d", fields.DefaultAssociation), + Sequence: fmt.Sprintf("%d", fields.Sequence), + } +} diff --git a/util/hda-decoder/decoder/lib_test.go b/util/hda-decoder/decoder/lib_test.go new file mode 100644 index 0000000000..045c0fced9 --- /dev/null +++ b/util/hda-decoder/decoder/lib_test.go @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0-only +package decoder + +import ( + "reflect" + "testing" +) + +type portIsConnectedTest struct { + arg1 uint32 + expected bool +} + +var portIsConnectedTests = []portIsConnectedTest{ + portIsConnectedTest{0x20000000, true}, + portIsConnectedTest{0xC0000000, true}, + portIsConnectedTest{0x40000000, false}, +} + +func TestPortIsConnected(t *testing.T) { + for _, test := range portIsConnectedTests { + output := PortIsConnected(test.arg1) + if output != test.expected { + t.Errorf("Expected %v, received %v", test.expected, output) + } + } +} + +type decodeTest struct { + arg1 uint32 + expected Fields[uint32] +} + +var decodeTests = []decodeTest{ + decodeTest{0xe23d1a0e, Fields[uint32]{0x3, 0x22, 0x3, 0xd, 0x1, 0xa, 0x0, 0xe}}, + decodeTest{0x66a8a2e4, Fields[uint32]{0x1, 0x26, 0xa, 0x8, 0xa, 0x2, 0xe, 0x4}}, + decodeTest{0x2e00a164, Fields[uint32]{0x0, 0x2e, 0x0, 0x0, 0xa, 0x1, 0x6, 0x4}}, + decodeTest{0x3b83dfe9, Fields[uint32]{0x0, 0x3b, 0x8, 0x3, 0xd, 0xf, 0xe, 0x9}}, + decodeTest{0x51708701, Fields[uint32]{0x1, 0x11, 0x7, 0x0, 0x8, 0x7, 0x0, 0x1}}, +} + +func TestDecode(t *testing.T) { + for _, test := range decodeTests { + output := Decode(test.arg1) + if !reflect.DeepEqual(output, test.expected) { + t.Errorf("Expected %v, received %v", test.expected, output) + } + } +} + +type toHumanReadableTest struct { + arg1 uint32 + expected Fields[string] +} + +var toHumanReadableTests = []toHumanReadableTest{ + toHumanReadableTest{0xe23d1a0e, Fields[string]{ + "AZALIA_JACK_AND_INTEGRATED", + "AZALIA_SEPARATE_CHASSIS | AZALIA_FRONT", + "AZALIA_CD", + "0xd", + "AZALIA_BLACK", + "AZALIA_JACK_PRESENCE_DETECT | 0xa", + "0", + "14", + }}, + + toHumanReadableTest{0x57708701, Fields[string]{ + "AZALIA_NC", + "AZALIA_RISER", + "AZALIA_MODEM_HANDSET_SIDE", + "AZALIA_TYPE_UNKNOWN", + "AZALIA_PURPLE", + "AZALIA_NO_JACK_PRESENCE_DETECT | 0x6", + "0", + "1", + }}, + + toHumanReadableTest{0x2e00a164, Fields[string]{ + "AZALIA_JACK", + "AZALIA_SEPARATE_CHASSIS | 0xe", + "AZALIA_LINE_OUT", + "AZALIA_TYPE_UNKNOWN", + "0xa", + "AZALIA_NO_JACK_PRESENCE_DETECT", + "6", + "4", + }}, + + toHumanReadableTest{0x80949653, Fields[string]{ + "AZALIA_INTEGRATED", + "AZALIA_EXTERNAL_PRIMARY_CHASSIS", + "AZALIA_AUX", + "AZALIA_RCA", + "AZALIA_PINK", + "AZALIA_JACK_PRESENCE_DETECT | 0x6", + "5", + "3", + }}, +} + +func TestToHumanReadable(t *testing.T) { + for _, test := range toHumanReadableTests { + output := ToHumanReadable(Decode(test.arg1)) + if output != test.expected { + t.Errorf("Expected %v, received %v", test.expected, output) + } + } +} |