最近因为装了台式,加上公司有发笔记本,我自己的笔记本就显得没什么用处了,正好可以用来装 Linux 玩。
其实在去年6月刚买这台华硕灵耀 X13 (Zenbook S13 OLED) 的时候,我就尝试过装 Linux,那个时候整个 Ryzen 6000 系列在 Linux 上的键盘都是不可用的,直到两个月之后 Kernel 6.0 发布。时隔一年多再次尝试,这次遇到的问题倒是没有那么致命,只有指纹和扬声器不可用(插耳机可用),指纹是 Linux 的老大难问题了,一时半会也解决不了,而扬声器这个不仅是我这一台笔记本的问题,几乎所有华硕的笔记本都有,这里记录下如何修复。
Cirrus SmartAMP
第一次在这个笔记本上重装系统的时候我就注意到了,Windows 自动安装的声卡驱动并不能驱动扬声器,必须要到华硕的驱动页面下载一个 Cirrus SmartAMP 的驱动才行。这个 Cirrus SmartAMP 对应的设备是 CS35L41,是一个内置的音频放大器,跟应该跟华硕所谓的哈曼卡顿调音相关吧。
这也是 Linux 扬声器没有声音的问题来源,从 dmesg 日志中我们可以看到
$ dmesg | grep CSC
[ 6.381872] Serial bus multi instantiate pseudo device driver CSC3551:00: Instantiated 2 I2C devices.
[ 6.532659] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: Error: ACPI _DSD Properties are missing for HID CSC3551.
[ 6.532664] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: error -EINVAL: Platform not supported
[ 6.532696] cs35l41-hda: probe of i2c-CSC3551:00-cs35l41-hda.0 failed with error -22
[ 6.541464] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: Error: ACPI _DSD Properties are missing for HID CSC3551.
[ 6.541468] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: error -EINVAL: Platform not supported
[ 6.541503] cs35l41-hda: probe of i2c-CSC3551:00-cs35l41-hda.1 failed with error -22
从上面的报错中可以看到,Linux 并不没有这个设备的驱动程序,而是缺少了这个设备在 ACPI Table 上的一些属性。
这其实是华硕的锅,众所周知,ACPI Table 是硬件制造商提供的固件中包含的信息,华硕提供的固件里缺少了一些属性值,据说在 Windows 的驱动中,他们硬编码了相关属性值,而 Linux 这边没有这么做,为了让扬声器重新响起来,我们需要自己给 ACPI Table 打补丁。
修复 ACPI Table
Dump DSDT Table
我们这里用不到完整的 ACPI Table,只需要对 DSDT Table 进行操作即可
$ sudo cat /sys/firmware/acpi/tables/DSDT > dsdt.dat
$ iasl -d dsdt.dat
之后会多出来一个 dsdt.dsl 文件,即反编译的 dsdt table。
了解 CSC3551 在 DSDT 中的定义
在 dsdt.dsl 中搜索 CSC3551
,找到和它相关的部分以及它的上一级,在我的设备中,这部分是
Scope (_SB.I2CA)
{
Device (SPKR)
{
Name (_HID, "CSC3551") // _HID: Hardware ID
Name (_SUB, "10431F12") // _SUB: Subsystem ID
Name (_UID, One) // _UID: Unique ID
Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
Name (RBUF, ResourceTemplate ()
{
I2cSerialBusV2 (0x0040, ControllerInitiated, 0x000F4240,
AddressingMode7Bit, "\\_SB.I2CA",
0x00, ResourceConsumer, , Exclusive,
)
I2cSerialBusV2 (0x0041, ControllerInitiated, 0x000F4240,
AddressingMode7Bit, "\\_SB.I2CA",
0x00, ResourceConsumer, , Exclusive,
)
GpioIo (Exclusive, PullDown, 0x0000, 0x0000, IoRestrictionOutputOnly,
"\\_SB.GPIO", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0004
}
这里是要了解 CSC3551 这条设备挂在哪个总线下面,可以看到,我这个设备挂在 _SB.I2CA
这条线下,设备号是 SPKR
,设备硬件ID是 10431F12
。
但是除了 I2C 总线,这个设备还可能挂载在 SPI 总线之下,下面是一个 SPI 总线下的 DSDT 部分示例
Scope (_SB.PC00.SPI3)
{
Device (SPK1)
{
Name (_HID, "CSC3551") // _HID: Hardware ID
Name (_SUB, "10431CAF") // _SUB: Subsystem ID
Name (_UID, One) // _UID: Unique ID
Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
Name (SBUF, ResourceTemplate ()
{
SpiSerialBusV2 (0x0000, PolarityLow, FourWireMode, 0x08,
ControllerInitiated, 0x003D0900, ClockPolarityLow,
ClockPhaseFirst, "\\_SB.PC00.SPI3",
0x00, ResourceConsumer, , Exclusive,
)
SpiSerialBusV2 (0x0001, PolarityLow, FourWireMode, 0x08,
ControllerInitiated, 0x003D0900, ClockPolarityLow,
ClockPhaseFirst, "\\_SB.PC00.SPI3",
0x00, ResourceConsumer, , Exclusive,
)
编写 Patch
下面是示例 patch
DefinitionBlock ("", "SSDT", 1, "CUSTOM", "CSC3551", 0x00000001)
{
External (<EXTERNAL>, DeviceObj)
External (<EXTERNAL>.<SPK>, DeviceObj)
Scope (<SCOPE>.<SPK>)
{
Name (_DSD, Package () // _DSD: Device-Specific Data
{
ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package () { "cirrus,dev-index", Package () { <ADDRESS_PAIR> }},
Package () { "reset-gpios", Package () {
<SPK>, Zero, Zero, Zero,
<SPK>, Zero, Zero, Zero,
} },
Package () { "spk-id-gpios", Package () {
<SPK>, 0x02, Zero, Zero,
<SPK>, 0x02, Zero, Zero,
} },
Package () { "cirrus,speaker-position", Package () { Zero, One } },
// gpioX-func: 0 not used, 1 VPSK_SWITCH, 2: INTERRUPT, 3: SYNC
Package () { "cirrus,gpio1-func", Package () { One, One } },
Package () { "cirrus,gpio2-func", Package () { 0x02, 0x02 } },
// boost-type: 0 internal, 1 external
Package () { "cirrus,boost-type", Package () { One, One } },
},
})
}
}
其中
<EXTERNAL>
一般为_SB_
<SPK>
为前面提到的哪条总线,如I2CA
<SCOPE>
和前面提到Scope()
里的内容相同,注意这里的_SB
少一个后置的下划线<ADDRESS_PAIR>
在 I2C 设备上是0x0040, 0x0041
,在 SPI 设备上是Zero, One
对于我这台笔记本来说,patch 如下
DefinitionBlock ("", "SSDT", 1, "CUSTOM", "CSC3551", 0x000000001)
{
External (_SB_, DeviceObj)
External (_SB_.I2CA, DeviceObj)
Scope (_SB.I2CA.SPKR)
{
Name (_DSD, Package ()
{
ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package () { "cirrus,dev-index", Package () { 0x0040, 0x0041 }},
Package () { "reset-gpios", Package () {
SPKR, Zero, Zero, Zero,
SPKR, Zero, Zero, Zero,
} },
Package () { "spk-id-gpios", Package () {
SPKR, 0x02, Zero, Zero,
SPKR, 0x02, Zero, Zero,
} },
Package () { "cirrus,speaker-position", Package () { Zero, One } },
// gpioX-func: 0 not used, 1 VPSK_SWITCH, 2: INTERRUPT, 3: SYNC
Package () { "cirrus,gpio1-func", Package () { One, One } },
Package () { "cirrus,gpio2-func", Package () { 0x02, 0x02 } },
// boost-type: 0 internal, 1 external
Package () { "cirrus,boost-type", Package () { One, One } },
}
})
}
}
编译与使用 patch
使用命令编译 iasl -tc ssdt_csc3551.dsl
, 获得文件 ssdt_csc3551.aml
,将文件复制到 /boot
中
在 /etc/grub.d/01_acpi
中写入,并 chmod +x /etc/grub.d/01_acpi
添加权限
#!/bin/sh -e
#sudo cp -f 01_acpi /etc/grub.d/01_acpi
# Uncomment to load custom ACPI tables
GRUB_CUSTOM_ACPI_DIR="/boot"
# DON'T MODIFY ANYTHING BELOW THIS LINE!
prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
. "$pkgdatadir/grub-mkconfig_lib"
# Load custom ACPI tables
if [ x${GRUB_CUSTOM_ACPI_DIR} != x ] && [ -d ${GRUB_CUSTOM_ACPI_DIR} ]; then
echo "Searching for custom ACPI tables in ${GRUB_CUSTOM_ACPI_DIR}" >&2
for file in ${GRUB_CUSTOM_ACPI_DIR}/ssdt*.aml; do
if [ -f "${file}" ] && is_path_readable_by_grub "${file}"; then
echo "Found custom ACPI table: ${file}" >&2
prepare_grub_to_access_device `${grub_probe} --target=device ${file}` | sed -e "s/^/ /"
cat << EOF
acpi (\$root)`make_system_path_relative_to_its_root ${file}`
EOF
fi
done
fi
使用命令 grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg
生成新的 grub 配置,并重启电脑。
(这里的配置文件路径和发行版相关,如果是 debian 系的直接 update-grub2
就行)
重启后测试扬声器可用,查看日志
dmesg | grep CSC
[ 0.004184] ACPI: SSDT 0x00000000A8AA53DE 000143 (v01 CUSTOM CSC3551 00000001 INTL 20220331)
[ 6.393627] Serial bus multi instantiate pseudo device driver CSC3551:00: Instantiated 2 I2C devices.
[ 6.585168] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: Cirrus Logic CS35L41 (35a40), Revision: B2
[ 6.585683] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: Reset line busy, assuming shared reset
[ 6.642721] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: Cirrus Logic CS35L41 (35a40), Revision: B2
[ 6.754917] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: DSP1: Firmware version: 3
[ 6.754927] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: DSP1: cirrus/cs35l41-dsp1-spk-prot-10431f12.wmfw: Fri 27 Aug 2021 14:58:19 W. Europe Daylight Time
[ 7.213773] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: DSP1: Firmware: 400a4 vendor: 0x2 v0.43.1, 2 algorithms
[ 7.214860] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: DSP1: 0: ID cd v29.63.1 XM@94 YM@e
[ 7.214868] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: DSP1: 1: ID f20b v0.1.0 XM@176 YM@0
[ 7.214876] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: DSP1: spk-prot: C:\Users\tyang\Desktop\Product Setting\SmartAMP\ASUS\ASUS_Zenbook\UM5302\Tuning_release\220210\UM5302_L_with Rtrace_Tuning_YC_Rattle.bin
[ 7.299115] snd_hda_codec_realtek hdaudioC1D0: bound i2c-CSC3551:00-cs35l41-hda.0 (ops cs35l41_hda_comp_ops [snd_hda_scodec_cs35l41])
[ 7.302803] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: DSP1: Firmware version: 3
[ 7.302809] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: DSP1: cirrus/cs35l41-dsp1-spk-prot-10431f12.wmfw: Fri 27 Aug 2021 14:58:19 W. Europe Daylight Time
[ 7.761640] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: DSP1: Firmware: 400a4 vendor: 0x2 v0.43.1, 2 algorithms
[ 7.762715] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: DSP1: 0: ID cd v29.63.1 XM@94 YM@e
[ 7.762724] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: DSP1: 1: ID f20b v0.1.0 XM@176 YM@0
[ 7.762731] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: DSP1: spk-prot: C:\Users\tyang\Desktop\Product Setting\SmartAMP\ASUS\ASUS_Zenbook\UM5302\Tuning_release\220210\UM5302_R_Tuning_YC_Rattle.bin
[ 7.846106] snd_hda_codec_realtek hdaudioC1D0: bound i2c-CSC3551:00-cs35l41-hda.1 (ops cs35l41_hda_comp_ops [snd_hda_scodec_cs35l41])
(可选) 下载 cirrus 固件
如果你的发行版没有提供 cirrus
驱动的固件,那你需要手动下载
git clone --depth=1 https://gitlab.com/asus-linux/firmware.git
cp -r firmware/cirrus /lib/firmware
(可选) 内核版本
华硕这个不仅需要 dsdt, 固件,还要有一个内核的补丁,这里我的建议是升到最新的内核,如果没有的话开摆等着别人修吧。
0 条评论