aboutsummaryrefslogtreecommitdiff
path: root/huawei_matebook14s_codec_fix.cpp
diff options
context:
space:
mode:
authorAlexander Kiryukhin <i@neonxp.dev>2023-01-29 07:21:38 +0300
committerAlexander Kiryukhin <i@neonxp.dev>2023-01-29 07:21:38 +0300
commitfb1e31fd1968433ebbf5c34be0c78b4d33891af1 (patch)
tree9288a5d3cf7390299136df80aaa909bc0484bbe7 /huawei_matebook14s_codec_fix.cpp
initialHEADmaster
Diffstat (limited to 'huawei_matebook14s_codec_fix.cpp')
-rw-r--r--huawei_matebook14s_codec_fix.cpp164
1 files changed, 164 insertions, 0 deletions
diff --git a/huawei_matebook14s_codec_fix.cpp b/huawei_matebook14s_codec_fix.cpp
new file mode 100644
index 0000000..9d8c57e
--- /dev/null
+++ b/huawei_matebook14s_codec_fix.cpp
@@ -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);
+}