This commit is contained in:
Alexander Kiryukhin 2023-01-29 07:21:38 +03:00
commit fb1e31fd19
5 changed files with 214 additions and 0 deletions

18
Makefile Normal file
View file

@ -0,0 +1,18 @@
huawei-sound-fix:
@gcc huawei_matebook14s_codec_fix.cpp -o huawei-sound-fix
@echo "Now run sudo make install"
.PHONY:
install: huawei-sound-fix
@cp huawei-sound-fix /usr/local/bin/
@chmod +x /usr/local/bin/huawei-sound-fix
@cp *.service /etc/systemd/system/
@systemctl daemon-reload
@systemctl enable huawei-codec-fix.service
@systemctl enable restart-huawei-codec-fix.service
@systemctl start huawei-codec-fix.service
@echo "Now reboot required"
.PHONY:
clear:
@rm huawei-sound-fix

10
README.md Normal file
View file

@ -0,0 +1,10 @@
# Fix sound on Huawei laptops on modern linux
Recipe from https://github.com/thesofproject/linux/issues/3350#issuecomment-1399427143
```
git clone https://github.com/neonxp/fix-huawei-sound.git
make
sudo make install
reboot
```

12
huawei-codec-fix.service Normal file
View file

@ -0,0 +1,12 @@
[Unit]
Description=huawei-codec-fix
Before=sleep.target
StopWhenUnneeded=yes
[Service]
Type=idle
ExecStart=/usr/local/bin/huawei-sound-fix
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target suspend.target hibernate.target hybrid-sleep.target sleep.target

View file

@ -0,0 +1,164 @@
/*
* File: huawei_matebook14s_codec_fix.cpp
* Author: ursul_polar
*
* Created on Jan 22, 2023, 5:34 AM
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/io.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <syslog.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/stat.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#define HDA_VERB(nid,verb,param) ((nid)<<24 | (verb)<<8 | (param))
#define HDA_IOCTL_VERB_WRITE _IOWR('H', 0x11, struct hda_verb_ioctl)
#define GET_VARIABLE_NAME(Variable) (void(Variable),#Variable)
// Struct to contain HDA_VERBS properties
struct hda_verb_ioctl {
u32 verb; /* HDA_VERB() */
u32 res; /* response */
}state_check;
// Derivate struct to handle conn and EAPD separately
struct verbs_enable{
struct hda_verb_ioctl conn;
struct hda_verb_ioctl eapd;
}speaker_enable, headphone_enable;
bool done = false;
// If TERM Signal is sent will cause the loop to exit
void trpsig(int)
{
done = true;
}
int get_conn_state(int fd){
// Set standard verb to get status for HP connection
state_check.verb = HDA_VERB(0x16, 0x0f09, 0x0);
// Check connection status
if (ioctl(fd, HDA_IOCTL_VERB_WRITE, &state_check) < 0)
syslog(LOG_ERR, "Failed to read connection state verb.");
return state_check.res >> 28;
}
int get_snd_device(){
int fd;
// Check that we can RW with regards to the sound card
fd = open("/dev/snd/hwC0D0", O_RDWR|O_NOCTTY);
if (fd < 0) {
syslog(LOG_ERR, "Failed to open snd device.");
exit(EXIT_FAILURE);
}
return fd;
}
void clear_pin(int fd, const char* type){
struct hda_verb_ioctl clear_pins;
int array[]={0x715, 0x716, 0x717};
for(int i=0; i<3; i++){
if(type == "headphone" && array[i] != 0x715)
clear_pins.verb = HDA_VERB(0x1, array[i], 0x2);
else if( type =="headphone" && array[i] == 0x715)
clear_pins.verb = HDA_VERB(0x1, array[i], 0x0);
if(type == "spkr" && array[i] == 0x715)
clear_pins.verb = HDA_VERB(0x1, array[i], 0x2);
else if( type =="spkr" && array[i] != 0x715)
continue;
if (clear_pins.verb > 0){
if (ioctl(fd, HDA_IOCTL_VERB_WRITE, &clear_pins) < 0)
syslog(LOG_ERR, "Failed to write clear pin hda verb.");
else
syslog(LOG_INFO, "Written data to hda verb %.8x", clear_pins.verb);
}
}
}
void enable_verb(int fd, struct hda_verb_ioctl conn, struct hda_verb_ioctl eapd, const char* type){
// Enable speakers with hda verbs
if (ioctl(fd, HDA_IOCTL_VERB_WRITE, &conn) < 0)
syslog(LOG_ERR, "Failed to write connection slector hda verb.");
if (ioctl(fd, HDA_IOCTL_VERB_WRITE, &eapd) < 0)
syslog(LOG_ERR, "Failed to write EAPD hda verb.");
clear_pin(fd, type);
}
int main(int argc, char** argv) {
// TERM Signal check
signal(SIGTERM, &trpsig);
// Sound card file descriptor and connection state vars
int fd, state;
// Check connection status
state = 0;
// Set standard verbs to enable connections and EAPD for speaker
speaker_enable.conn.verb = HDA_VERB(0x16, 0x701, 0x0001);
speaker_enable.eapd.verb = HDA_VERB(0x17, 0x70c, 0x0002);
// Set standard verbs to enable connections and EAPD for headphones
headphone_enable.conn.verb = HDA_VERB(0x16, 0x701, 0x0000);
headphone_enable.eapd.verb = HDA_VERB(0x17, 0x70c, 0x0000);
// Write to syslog
syslog(LOG_INFO, "Daemon started.");
// Check that we can RW with regards to the sound card
fd = get_snd_device();
// Enable Speaker on startup so that there's no need to have a audio jack inserted
// to trigger the switch
enable_verb(fd, speaker_enable.conn, speaker_enable.eapd, "spkr");
syslog(LOG_INFO, "Enabled speaker output");
// Enter loop to detect connection changes
while (!done)
{
sleep(1);
if (state != get_conn_state(fd) && state == 8){
//Enable speaker
enable_verb(fd, speaker_enable.conn, speaker_enable.eapd, "spkr");
syslog(LOG_INFO, "Enabled speaker output");
}
if(state != get_conn_state(fd) && state == 0){
//Enable headphones
enable_verb(fd, headphone_enable.conn, headphone_enable.eapd, "headphone");
syslog(LOG_INFO, "Enabled headphone output");
}
state = get_conn_state(fd);
}
// Close and exit
close(fd);
syslog(LOG_INFO, "Daemon stopped.");
exit(EXIT_SUCCESS);
}

View file

@ -0,0 +1,10 @@
[Unit]
Description=Restart huawei codec fix after resume
After=suspend.target
[Service]
Type=simple
ExecStart=/usr/bin/systemctl --no-block restart huawei-codec-fix.service
[Install]
WantedBy=suspend.target