/* * File: huawei_matebook14s_codec_fix.cpp * Author: ursul_polar * * Created on Jan 22, 2023, 5:34 AM */ #include #include #include #include #include #include #include #include #include #include #include #include #include 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); }