Blame hdajackretask/sysfs-pin-configs.c

Packit 427e91
/* Copyright 2011 David Henningsson, Canonical Ltd.
Packit 427e91
   License: GPLv2+ 
Packit 427e91
*/
Packit 427e91
Packit 427e91
#include <stdlib.h>
Packit 427e91
#include <string.h>
Packit 427e91
#include "sysfs-pin-configs.h"
Packit 427e91
#include "apply-changes.h"
Packit 427e91
Packit 427e91
const gchar *hint_names[25] = {
Packit 427e91
"jack_detect",  "inv_jack_detect", "trigger_sense", "inv_eapd",
Packit 427e91
"pcm_format_first", "sticky_stream", "spdif_status_reset",
Packit 427e91
"pin_amp_workaround", "single_adc_amp", "auto_mute", "auto_mic",
Packit 427e91
"line_in_auto_switch", "auto_mute_via_amp", "need_dac_fix", "primary_hp",
Packit 427e91
"multi_io", "multi_cap_vol", "inv_dmic_split", "indep_hp",
Packit 427e91
"add_stereo_mix_input", "add_jack_modes", "power_down_unused", "add_hp_mic",
Packit 427e91
"hp_mic_detect", NULL };
Packit 427e91
Packit 427e91
const gchar** get_standard_hint_names()
Packit 427e91
{
Packit 427e91
    return hint_names;
Packit 427e91
}
Packit 427e91
Packit 427e91
Packit 427e91
int get_codec_name_list(codec_name_t* names, int entries)
Packit 427e91
{
Packit 427e91
    GDir* sysdir = g_dir_open("/sys/class/sound", 0, NULL);
Packit 427e91
    int count = 0;
Packit 427e91
    if (!sysdir)
Packit 427e91
        return 0;
Packit 427e91
  
Packit 427e91
    while (entries > 1) {
Packit 427e91
        gchar** cd = NULL;
Packit 427e91
        gboolean ok;
Packit 427e91
        const gchar* dirname = g_dir_read_name(sysdir);
Packit 427e91
        if (!dirname)
Packit 427e91
            break;
Packit 427e91
        /* Split e g "hwC0D1" into "hw", "0" and "1" */
Packit 427e91
        cd = g_strsplit_set(dirname, "CD", 9);
Packit 427e91
        ok = g_strv_length(cd) == 3;
Packit 427e91
        ok &= strcmp(cd[0], "hw") == 0;
Packit 427e91
        if (ok) {
Packit 427e91
            gchar* filetest = g_strdup_printf("/sys/class/sound/%s/init_pin_configs", dirname);
Packit 427e91
            ok = g_file_test(filetest, G_FILE_TEST_IS_REGULAR);
Packit 427e91
            g_free(filetest);
Packit 427e91
        }
Packit 427e91
Packit 427e91
        if (ok) {
Packit 427e91
            gchar* chip_name = NULL, *vendor_name = NULL;
Packit 427e91
            gchar* chip_file = g_strdup_printf("/sys/class/sound/%s/chip_name", dirname);
Packit 427e91
            gchar* vendor_file = g_strdup_printf("/sys/class/sound/%s/vendor_name", dirname);
Packit 427e91
            ok = g_file_get_contents(chip_file, &chip_name, NULL, NULL);
Packit 427e91
            ok &= g_file_get_contents(vendor_file, &vendor_name, NULL, NULL);
Packit 427e91
            if (ok) {
Packit 427e91
                names->name = g_strdup_printf("%s %s", g_strchomp(vendor_name), g_strchomp(chip_name));
Packit 427e91
            }
Packit 427e91
            g_free(chip_name);
Packit 427e91
            g_free(vendor_name);
Packit 427e91
            g_free(chip_file);
Packit 427e91
            g_free(vendor_file);
Packit 427e91
        }
Packit 427e91
Packit 427e91
        if (ok) {
Packit 427e91
            names->card = atoi(cd[1]);
Packit 427e91
            names->device = atoi(cd[2]); 
Packit 427e91
Packit 427e91
            names++; 
Packit 427e91
            count++;
Packit 427e91
            entries--;
Packit 427e91
        }
Packit 427e91
        g_strfreev(cd);
Packit 427e91
    }
Packit 427e91
    if (entries) {
Packit 427e91
        names->name = NULL;
Packit 427e91
        names->card = -1;
Packit 427e91
    }
Packit 427e91
    g_dir_close(sysdir);
Packit 427e91
    return count;
Packit 427e91
}
Packit 427e91
Packit 427e91
static unsigned long read_header_value(gchar* contents, gchar* key)
Packit 427e91
{
Packit 427e91
    gchar* s = strstr(contents, key);
Packit 427e91
    s += strlen(key);
Packit 427e91
    return g_ascii_strtoull(s, NULL, 0);
Packit 427e91
}
Packit 427e91
Packit 427e91
void get_codec_header(int card, int device, unsigned int* address, 
Packit 427e91
    unsigned int* codec_vendorid, unsigned int* codec_ssid)
Packit 427e91
{
Packit 427e91
    gchar* filename = g_strdup_printf("/proc/asound/card%d/codec#%d", card, device);
Packit 427e91
    gchar* contents = NULL;
Packit 427e91
    int ok = g_file_get_contents(filename, &contents, NULL, NULL);
Packit 427e91
    g_free(filename);
Packit 427e91
    if (!ok)
Packit 427e91
        return;
Packit 427e91
    *address = read_header_value(contents, "Address: ");
Packit 427e91
    *codec_vendorid = read_header_value(contents, "Vendor Id: ");
Packit 427e91
    *codec_ssid = read_header_value(contents, "Subsystem Id: ");
Packit 427e91
Packit 427e91
    g_free(contents);
Packit 427e91
}
Packit 427e91
Packit 427e91
static void get_pin_caps(pin_configs_t* pins, int entries, int card, int device)
Packit 427e91
{
Packit 427e91
    gchar* filename = g_strdup_printf("/proc/asound/card%d/codec#%d", card, device);
Packit 427e91
    gchar* contents = NULL;
Packit 427e91
    int ok = g_file_get_contents(filename, &contents, NULL, NULL);
Packit 427e91
    g_free(filename);
Packit 427e91
    if (!ok) 
Packit 427e91
        return;
Packit 427e91
Packit 427e91
    for (; entries; entries--, pins++) {
Packit 427e91
        gchar* nodestr = g_strdup_printf("Node 0x%02x [", pins->nid);
Packit 427e91
        gchar* q = strstr(contents, nodestr);
Packit 427e91
        g_free(nodestr);
Packit 427e91
        if (!q) 
Packit 427e91
            continue;
Packit 427e91
Packit 427e91
        q = strstr(q, "wcaps 0x");
Packit 427e91
        if (!q) 
Packit 427e91
            continue;
Packit 427e91
        q += strlen("wcaps ");
Packit 427e91
        pins->wid_caps = g_ascii_strtoull(q, NULL, 0);
Packit 427e91
Packit 427e91
        q = strstr(q, "Pincap 0x");
Packit 427e91
        if (!q) 
Packit 427e91
            continue;
Packit 427e91
        q += strlen("Pincap ");
Packit 427e91
        pins->pin_caps = g_ascii_strtoull(q, NULL, 0);
Packit 427e91
    }
Packit 427e91
    g_free(contents);
Packit 427e91
}
Packit 427e91
Packit 427e91
gchar *get_hint_overrides(int card, int device)
Packit 427e91
{
Packit 427e91
    gchar* filename = g_strdup_printf("/sys/class/sound/hwC%dD%d/hints", card, device);
Packit 427e91
    gchar* contents = NULL;
Packit 427e91
    int ok = g_file_get_contents(filename, &contents, NULL, NULL);
Packit 427e91
    g_free(filename);
Packit 427e91
    if (!ok)
Packit 427e91
        return NULL;
Packit 427e91
    return contents;
Packit 427e91
}
Packit 427e91
Packit 427e91
static void read_pin_overrides(pin_configs_t* pins, int entries, int card, int device, gboolean is_user)
Packit 427e91
{
Packit 427e91
    gchar* filename = g_strdup_printf("/sys/class/sound/hwC%dD%d/%s_pin_configs", card, device, is_user ? "user" : "driver");
Packit 427e91
    gchar* contents = NULL;
Packit 427e91
    gchar** lines = NULL, **line_iterator;
Packit 427e91
    int count = 0;
Packit 427e91
    int ok = g_file_get_contents(filename, &contents, NULL, NULL);
Packit 427e91
    g_free(filename);
Packit 427e91
    if (!ok)
Packit 427e91
        return;
Packit 427e91
    line_iterator = lines = g_strsplit(contents, "\n", entries);
Packit 427e91
    while (count < entries && *line_iterator) {
Packit 427e91
        gchar** line = g_strsplit(*line_iterator, " ", 0);
Packit 427e91
        line_iterator++;
Packit 427e91
        if (g_strv_length(line) == 2) {
Packit 427e91
            int nid = g_ascii_strtoull(line[0], NULL, 0) & 0xff;
Packit 427e91
            unsigned long config = g_ascii_strtoull(line[1], NULL, 0);
Packit 427e91
            int i;
Packit 427e91
            for (i=0; i < entries; i++)
Packit 427e91
                if (nid == pins[i].nid) {
Packit 427e91
                    if (is_user) {
Packit 427e91
                        pins[i].user_override = FALSE;
Packit 427e91
                        pins[i].user_override = config != actual_pin_config(&pins[i]);
Packit 427e91
                        pins[i].user_pin_config = config;
Packit 427e91
                    } else {
Packit 427e91
                        pins[i].driver_override = config != pins[i].init_pin_config;
Packit 427e91
                        pins[i].driver_pin_config = config;
Packit 427e91
                    }
Packit 427e91
                }
Packit 427e91
        }
Packit 427e91
        g_strfreev(line); 
Packit 427e91
    }    
Packit 427e91
    g_strfreev(lines);
Packit 427e91
    g_free(contents);
Packit 427e91
}
Packit 427e91
Packit 427e91
int get_pin_configs_list(pin_configs_t* pins, int entries, int card, int device)
Packit 427e91
{
Packit 427e91
    gchar* filename = g_strdup_printf("/sys/class/sound/hwC%dD%d/init_pin_configs", card, device);
Packit 427e91
    gchar* contents = NULL;
Packit 427e91
    gchar** lines = NULL, **line_iterator;
Packit 427e91
    int count = 0;
Packit 427e91
    int ok = g_file_get_contents(filename, &contents, NULL, NULL);
Packit 427e91
    g_free(filename);
Packit 427e91
    if (!ok) 
Packit 427e91
        return 0;
Packit 427e91
    line_iterator = lines = g_strsplit(contents, "\n", entries);
Packit 427e91
    g_free(contents);
Packit 427e91
    while (count < entries && *line_iterator) {
Packit 427e91
        gchar** line = g_strsplit(*line_iterator, " ", 0);
Packit 427e91
        line_iterator++;
Packit 427e91
        if (g_strv_length(line) == 2) {
Packit 427e91
            pins[count].nid = g_ascii_strtoull(line[0], NULL, 0);
Packit 427e91
            pins[count].init_pin_config = g_ascii_strtoull(line[1], NULL, 0) & 0xffffffff;
Packit 427e91
            pins[count].driver_override = FALSE;
Packit 427e91
            pins[count].user_override = FALSE;
Packit 427e91
            count++;
Packit 427e91
        }
Packit 427e91
        g_strfreev(line); 
Packit 427e91
    }    
Packit 427e91
    g_strfreev(lines);
Packit 427e91
Packit 427e91
    read_pin_overrides(pins, count, card, device, FALSE);
Packit 427e91
    read_pin_overrides(pins, count, card, device, TRUE);
Packit 427e91
    get_pin_caps(pins, count, card, device);
Packit 427e91
Packit 427e91
    return count;
Packit 427e91
}
Packit 427e91
Packit 427e91
unsigned long actual_pin_config(pin_configs_t* pins)
Packit 427e91
{
Packit 427e91
    if (pins->user_override)
Packit 427e91
        return pins->user_pin_config;
Packit 427e91
    if (pins->driver_override)
Packit 427e91
        return pins->driver_pin_config;
Packit 427e91
    return pins->init_pin_config;
Packit 427e91
}
Packit 427e91
Packit 427e91
/*** Code below taken from sound/pci/hda/hda_proc.c and hda_codec.h, (C) Takashi Iwai, GPLv2+. ****/
Packit 427e91
Packit 427e91
#define u32 unsigned long
Packit 427e91
Packit 427e91
#define AC_WCAP_STEREO                  (1<<0)  /* stereo I/O */
Packit 427e91
#define AC_WCAP_IN_AMP                  (1<<1)  /* AMP-in present */
Packit 427e91
#define AC_WCAP_OUT_AMP                 (1<<2)  /* AMP-out present */
Packit 427e91
#define AC_WCAP_AMP_OVRD                (1<<3)  /* AMP-parameter override */
Packit 427e91
#define AC_WCAP_FORMAT_OVRD             (1<<4)  /* format override */
Packit 427e91
#define AC_WCAP_STRIPE                  (1<<5)  /* stripe */
Packit 427e91
#define AC_WCAP_PROC_WID                (1<<6)  /* Proc Widget */
Packit 427e91
#define AC_WCAP_UNSOL_CAP               (1<<7)  /* Unsol capable */
Packit 427e91
#define AC_WCAP_CONN_LIST               (1<<8)  /* connection list */
Packit 427e91
#define AC_WCAP_DIGITAL                 (1<<9)  /* digital I/O */
Packit 427e91
#define AC_WCAP_POWER                   (1<<10) /* power control */
Packit 427e91
#define AC_WCAP_LR_SWAP                 (1<<11) /* L/R swap */
Packit 427e91
#define AC_WCAP_CP_CAPS                 (1<<12) /* content protection */
Packit 427e91
#define AC_WCAP_CHAN_CNT_EXT            (7<<13) /* channel count ext */
Packit 427e91
#define AC_WCAP_DELAY                   (0xf<<16)
Packit 427e91
#define AC_WCAP_DELAY_SHIFT             16
Packit 427e91
#define AC_WCAP_TYPE                    (0xf<<20)
Packit 427e91
#define AC_WCAP_TYPE_SHIFT              20
Packit 427e91
Packit 427e91
#define AC_PINCAP_IMP_SENSE		(1<<0)	/* impedance sense capable */
Packit 427e91
#define AC_PINCAP_TRIG_REQ		(1<<1)	/* trigger required */
Packit 427e91
#define AC_PINCAP_PRES_DETECT		(1<<2)	/* presence detect capable */
Packit 427e91
#define AC_PINCAP_HP_DRV		(1<<3)	/* headphone drive capable */
Packit 427e91
#define AC_PINCAP_OUT			(1<<4)	/* output capable */
Packit 427e91
#define AC_PINCAP_IN			(1<<5)	/* input capable */
Packit 427e91
#define AC_PINCAP_BALANCE		(1<<6)	/* balanced I/O capable */
Packit 427e91
/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification,
Packit 427e91
 *       but is marked reserved in the Intel HDA specification.
Packit 427e91
 */
Packit 427e91
#define AC_PINCAP_LR_SWAP		(1<<7)	/* L/R swap */
Packit 427e91
/* Note: The same bit as LR_SWAP is newly defined as HDMI capability
Packit 427e91
 *       in HD-audio specification
Packit 427e91
 */
Packit 427e91
#define AC_PINCAP_HDMI			(1<<7)	/* HDMI pin */
Packit 427e91
#define AC_PINCAP_DP			(1<<24)	/* DisplayPort pin, can
Packit 427e91
						 * coexist with AC_PINCAP_HDMI
Packit 427e91
						 */
Packit 427e91
#define AC_PINCAP_VREF			(0x37<<8)
Packit 427e91
#define AC_PINCAP_VREF_SHIFT		8
Packit 427e91
#define AC_PINCAP_EAPD			(1<<16)	/* EAPD capable */
Packit 427e91
#define AC_PINCAP_HBR			(1<<27)	/* High Bit Rate */
Packit 427e91
/* Vref status (used in pin cap) */
Packit 427e91
#define AC_PINCAP_VREF_HIZ		(1<<0)	/* Hi-Z */
Packit 427e91
#define AC_PINCAP_VREF_50		(1<<1)	/* 50% */
Packit 427e91
#define AC_PINCAP_VREF_GRD		(1<<2)	/* ground */
Packit 427e91
#define AC_PINCAP_VREF_80		(1<<4)	/* 80% */
Packit 427e91
#define AC_PINCAP_VREF_100		(1<<5)	/* 100% */
Packit 427e91
Packit 427e91
Packit 427e91
/* configuration default - 32bit */
Packit 427e91
#define AC_DEFCFG_SEQUENCE		(0xf<<0)
Packit 427e91
#define AC_DEFCFG_DEF_ASSOC		(0xf<<4)
Packit 427e91
#define AC_DEFCFG_ASSOC_SHIFT		4
Packit 427e91
#define AC_DEFCFG_MISC			(0xf<<8)
Packit 427e91
#define AC_DEFCFG_MISC_SHIFT		8
Packit 427e91
#define AC_DEFCFG_MISC_NO_PRESENCE	(1<<0)
Packit 427e91
#define AC_DEFCFG_COLOR			(0xf<<12)
Packit 427e91
#define AC_DEFCFG_COLOR_SHIFT		12
Packit 427e91
#define AC_DEFCFG_CONN_TYPE		(0xf<<16)
Packit 427e91
#define AC_DEFCFG_CONN_TYPE_SHIFT	16
Packit 427e91
#define AC_DEFCFG_DEVICE		(0xf<<20)
Packit 427e91
#define AC_DEFCFG_DEVICE_SHIFT		20
Packit 427e91
#define AC_DEFCFG_LOCATION		(0x3f<<24)
Packit 427e91
#define AC_DEFCFG_LOCATION_SHIFT	24
Packit 427e91
#define AC_DEFCFG_GROSSLOC		(0x3<<28)
Packit 427e91
#define AC_DEFCFG_GROSSLOC_SHIFT	28
Packit 427e91
#define AC_DEFCFG_PORT_CONN		(0x3<<30)
Packit 427e91
#define AC_DEFCFG_PORT_CONN_SHIFT	30
Packit 427e91
Packit 427e91
static const char *get_jack_color(u32 cfg)
Packit 427e91
{
Packit 427e91
	static char *names[16] = {
Packit 427e91
		"", "Black", "Grey", "Blue",
Packit 427e91
		"Green", "Red", "Orange", "Yellow",
Packit 427e91
		"Purple", "Pink", NULL, NULL,
Packit 427e91
		NULL, NULL, "White", "Other",
Packit 427e91
	};
Packit 427e91
	cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT;
Packit 427e91
	if (names[cfg])
Packit 427e91
		return names[cfg];
Packit 427e91
	else
Packit 427e91
		return "UNKNOWN";
Packit 427e91
}
Packit 427e91
Packit 427e91
static const char *get_jack_type(u32 cfg)
Packit 427e91
{
Packit 427e91
	static char *jack_types[16] = {
Packit 427e91
		"Line Out", "Speaker", "Headphone", "CD",
Packit 427e91
		"SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
Packit 427e91
		"Line In", "Aux", "Mic", "Telephony",
Packit 427e91
		"SPDIF In", "Digital In", "Reserved", "Other"
Packit 427e91
	};
Packit 427e91
Packit 427e91
	return jack_types[(cfg & AC_DEFCFG_DEVICE)
Packit 427e91
				>> AC_DEFCFG_DEVICE_SHIFT];
Packit 427e91
}
Packit 427e91
Packit 427e91
static const char *get_jack_location(u32 cfg)
Packit 427e91
{
Packit 427e91
	static char *bases[7] = {
Packit 427e91
		"", ", Rear side", ", Front side", ", Left side", ", Right side", ", Top", ", Bottom",
Packit 427e91
	};
Packit 427e91
	static unsigned char specials_idx[] = {
Packit 427e91
		0x07, 0x08,
Packit 427e91
		0x17, 0x18, 0x19,
Packit 427e91
		0x37, 0x38
Packit 427e91
	};
Packit 427e91
	static char *specials[] = {
Packit 427e91
		", Rear Panel", ", Drive Bar",
Packit 427e91
		", Riser", ", HDMI", ", ATAPI",
Packit 427e91
		", Mobile-In", ", Mobile-Out"
Packit 427e91
	};
Packit 427e91
	int i;
Packit 427e91
	cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
Packit 427e91
	if ((cfg & 0x0f) < 7)
Packit 427e91
		return bases[cfg & 0x0f];
Packit 427e91
	for (i = 0; i < 7; i++) {
Packit 427e91
		if (cfg == specials_idx[i])
Packit 427e91
			return specials[i];
Packit 427e91
	}
Packit 427e91
	return "UNKNOWN";
Packit 427e91
}
Packit 427e91
Packit 427e91
Packit 427e91
/**** Borrowed code end *****/
Packit 427e91
Packit 427e91
static free_override_t pc_arr[] = {
Packit 427e91
    {"Not connected", 1 << AC_DEFCFG_PORT_CONN_SHIFT},
Packit 427e91
    {"Jack", 0},
Packit 427e91
    {"Internal", 2 << AC_DEFCFG_PORT_CONN_SHIFT},
Packit 427e91
    {"Both", 3 << AC_DEFCFG_PORT_CONN_SHIFT},
Packit 427e91
    {}
Packit 427e91
};
Packit 427e91
Packit 427e91
static free_override_t location_arr[] = {
Packit 427e91
    {"External", 0},
Packit 427e91
    {"Rear", 1 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Front", 2 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Left", 3 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Right", 4 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Top", 5 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Bottom", 6 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Rear panel", 7 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Drive bay", 8 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
Packit 427e91
    {"Internal", 16 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Internal riser", (16+7) << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Internal display", (16+8) << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Internal ATAPI", (16+9) << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
Packit 427e91
    {"Dock", 32 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Dock Rear", 33 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Dock Front", 34 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Dock Left", 35 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Dock Right", 36 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Dock Top", 37 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Dock Bottom", 38 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
Packit 427e91
    {"Other", 48 << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Other bottom", (48+7) << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Inside mobile lid", (48+8) << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
    {"Outside mobile lid", (48+9) << AC_DEFCFG_LOCATION_SHIFT},
Packit 427e91
Packit 427e91
    {}
Packit 427e91
};
Packit 427e91
Packit 427e91
static free_override_t device_arr[] = {
Packit 427e91
    {"Line Out", 0},
Packit 427e91
    {"Speaker", 1 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {"Headphone", 2 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {"CD", 3 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {"SPDIF Out", 4 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {"Digital Out", 5 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {"Modem (Line side)", 6 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {"Modem (Handset side)", 7 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {"Line In", 8 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {"Aux", 9 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {"Microphone", 10 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {"Telephony", 11 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {"SPDIF In", 12 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {"Other Digital In", 13 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {"Other", 15 << AC_DEFCFG_DEVICE_SHIFT},
Packit 427e91
    {}
Packit 427e91
};
Packit 427e91
Packit 427e91
static free_override_t jack_arr[] = {
Packit 427e91
    {"Unknown", 0},
Packit 427e91
    {"3.5 mm", 1 << AC_DEFCFG_CONN_TYPE_SHIFT},
Packit 427e91
    {"6.3 mm", 2 << AC_DEFCFG_CONN_TYPE_SHIFT},
Packit 427e91
    {"ATAPI", 3 << AC_DEFCFG_CONN_TYPE_SHIFT},
Packit 427e91
    {"RCA", 4 << AC_DEFCFG_CONN_TYPE_SHIFT},
Packit 427e91
    {"Optical", 5 << AC_DEFCFG_CONN_TYPE_SHIFT},
Packit 427e91
    {"Other Digital", 6 << AC_DEFCFG_CONN_TYPE_SHIFT},
Packit 427e91
    {"Other Analog", 7 << AC_DEFCFG_CONN_TYPE_SHIFT},
Packit 427e91
    {"DIN", 8 << AC_DEFCFG_CONN_TYPE_SHIFT},
Packit 427e91
    {"XLR", 9 << AC_DEFCFG_CONN_TYPE_SHIFT},
Packit 427e91
    {"RJ-11 (Modem)", 10 << AC_DEFCFG_CONN_TYPE_SHIFT},
Packit 427e91
    {"Combination", 11 << AC_DEFCFG_CONN_TYPE_SHIFT},
Packit 427e91
    {"Other", 15 << AC_DEFCFG_CONN_TYPE_SHIFT},
Packit 427e91
    {}
Packit 427e91
};
Packit 427e91
Packit 427e91
static free_override_t color_arr[] = {
Packit 427e91
    {"Unknown", 0},
Packit 427e91
    {"Black", 1 << AC_DEFCFG_COLOR_SHIFT},
Packit 427e91
    {"Grey", 2 << AC_DEFCFG_COLOR_SHIFT},
Packit 427e91
    {"Blue", 3 << AC_DEFCFG_COLOR_SHIFT},
Packit 427e91
    {"Green", 4 << AC_DEFCFG_COLOR_SHIFT},
Packit 427e91
    {"Red", 5 << AC_DEFCFG_COLOR_SHIFT},
Packit 427e91
    {"Orange", 6 << AC_DEFCFG_COLOR_SHIFT},
Packit 427e91
    {"Yellow", 7 << AC_DEFCFG_COLOR_SHIFT},
Packit 427e91
    {"Purple", 8 << AC_DEFCFG_COLOR_SHIFT},
Packit 427e91
    {"Pink", 9 << AC_DEFCFG_COLOR_SHIFT},
Packit 427e91
    {"White", 14 << AC_DEFCFG_COLOR_SHIFT},
Packit 427e91
    {"Other", 15 << AC_DEFCFG_COLOR_SHIFT},
Packit 427e91
    {}
Packit 427e91
};
Packit 427e91
Packit 427e91
static free_override_t no_presence_arr[] = {
Packit 427e91
    {"Present", 0},
Packit 427e91
    {"Not present", 1 << AC_DEFCFG_MISC_SHIFT},
Packit 427e91
    {}
Packit 427e91
};
Packit 427e91
Packit 427e91
static free_override_t group_nr_arr[] = {
Packit 427e91
    {"1", 1 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"2", 2 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"3", 3 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"4", 4 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"5", 5 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"6", 6 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"7", 7 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"8", 8 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"9", 9 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"10", 10 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"11", 11 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"12", 12 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"13", 13 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"14", 14 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {"15", 15 << AC_DEFCFG_ASSOC_SHIFT},
Packit 427e91
    {}
Packit 427e91
};
Packit 427e91
Packit 427e91
static free_override_t channel_arr[] = {
Packit 427e91
    {"Front", 0},
Packit 427e91
    {"Center/LFE", 1},
Packit 427e91
    {"Back", 2},
Packit 427e91
    {"Side", 3},
Packit 427e91
    {"Channel 8 & 9", 4},
Packit 427e91
    {"Channel 10 & 11", 5},
Packit 427e91
    {"Channel 12 & 13", 6},
Packit 427e91
    {"Channel 14 & 15", 7},
Packit 427e91
    {"Channel 16 & 17", 8},
Packit 427e91
    {"Channel 18 & 19", 9},
Packit 427e91
    {"Channel 20 & 21", 10},
Packit 427e91
    {"Channel 22 & 23", 11},
Packit 427e91
    {"Channel 24 & 25", 12},
Packit 427e91
    {"Channel 26 & 27", 13},
Packit 427e91
    {"Channel 28 & 29", 14},
Packit 427e91
    {"Channel 30 & 31", 15},
Packit 427e91
    {}
Packit 427e91
};
Packit 427e91
Packit 427e91
Packit 427e91
static free_override_t* type_order[FREE_OVERRIDES_COUNT] = {
Packit 427e91
    pc_arr, location_arr, device_arr, jack_arr,
Packit 427e91
    color_arr, no_presence_arr, group_nr_arr, channel_arr
Packit 427e91
};
Packit 427e91
Packit 427e91
unsigned long get_free_override_mask(int type)
Packit 427e91
{
Packit 427e91
    static unsigned long masks[FREE_OVERRIDES_COUNT] = {
Packit 427e91
        AC_DEFCFG_PORT_CONN,
Packit 427e91
        AC_DEFCFG_LOCATION,
Packit 427e91
        AC_DEFCFG_DEVICE,
Packit 427e91
        AC_DEFCFG_CONN_TYPE,
Packit 427e91
        AC_DEFCFG_COLOR,
Packit 427e91
        AC_DEFCFG_MISC & (AC_DEFCFG_MISC_NO_PRESENCE << AC_DEFCFG_MISC_SHIFT),
Packit 427e91
        AC_DEFCFG_DEF_ASSOC,
Packit 427e91
        AC_DEFCFG_SEQUENCE,
Packit 427e91
    };
Packit 427e91
Packit 427e91
    return masks[type];
Packit 427e91
}
Packit 427e91
Packit 427e91
free_override_t* get_free_override_list(int type)
Packit 427e91
{
Packit 427e91
    return type_order[type];
Packit 427e91
}
Packit 427e91
Packit 427e91
Packit 427e91
int get_port_conn(unsigned long config)
Packit 427e91
{
Packit 427e91
    return (config & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT;
Packit 427e91
}
Packit 427e91
Packit 427e91
gchar* get_config_description(unsigned long config)
Packit 427e91
{
Packit 427e91
    int port_conn = get_port_conn(config);
Packit 427e91
    if (port_conn == 1)
Packit 427e91
        return g_strdup("Not connected");
Packit 427e91
    return g_strdup_printf("%s %s%s%s", port_conn == 2 ? "Internal" : get_jack_color(config), 
Packit 427e91
        get_jack_type(config), 
Packit 427e91
        ((config >> (AC_DEFCFG_LOCATION_SHIFT+4)) & 3) == 2 ? ", Docking station" : "",
Packit 427e91
        get_jack_location(config));
Packit 427e91
}
Packit 427e91
Packit 427e91
/*
Packit 427e91
gchar* get_caps_description(unsigned long pin_caps)
Packit 427e91
{
Packit 427e91
    int vref = (pin_caps & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Packit 427e91
    gboolean linein = (pin_caps & AC_PINCAP_IN) && (vref & AC_PINCAP_VREF_HIZ);
Packit 427e91
    gboolean lineout = pin_caps & AC_PINCAP_OUT;
Packit 427e91
    gboolean hp = pin_caps & AC_PINCAP_HP_DRV;
Packit 427e91
    gboolean mic = (pin_caps & AC_PINCAP_IN) && (vref & AC_PINCAP_VREF_50 || vref & AC_PINCAP_VREF_80);
Packit 427e91
    return g_strjoin("", 
Packit 427e91
            lineout ? ", Line out": "", 
Packit 427e91
            hp ? ", Headphone": "", 
Packit 427e91
            linein ? ", Line in": "", 
Packit 427e91
            mic ? ", Microphone": "", NULL);
Packit 427e91
Packit 427e91
}
Packit 427e91
*/
Packit 427e91
Packit 427e91
static gboolean extmic_caps(unsigned long pin_caps, unsigned long wid_caps)
Packit 427e91
{
Packit 427e91
    int vref = (pin_caps & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Packit 427e91
    return (pin_caps & AC_PINCAP_IN) && (vref & AC_PINCAP_VREF_50 || vref & AC_PINCAP_VREF_80);
Packit 427e91
}
Packit 427e91
Packit 427e91
static gboolean headphone_caps(unsigned long pin_caps, unsigned long wid_caps)
Packit 427e91
{
Packit 427e91
    return pin_caps & AC_PINCAP_HP_DRV;
Packit 427e91
}
Packit 427e91
Packit 427e91
static gboolean lineout_caps(unsigned long pin_caps, unsigned long wid_caps)
Packit 427e91
{
Packit 427e91
    return (pin_caps & AC_PINCAP_OUT) && !(wid_caps & AC_WCAP_DIGITAL);
Packit 427e91
}
Packit 427e91
Packit 427e91
static gboolean spdifout_caps(unsigned long pin_caps, unsigned long wid_caps)
Packit 427e91
{
Packit 427e91
    return (pin_caps & AC_PINCAP_OUT) && (wid_caps & AC_WCAP_DIGITAL) && !(pin_caps & AC_PINCAP_HDMI);
Packit 427e91
}
Packit 427e91
Packit 427e91
static gboolean hdmi_caps(unsigned long pin_caps, unsigned long wid_caps)
Packit 427e91
{
Packit 427e91
    return pin_caps & AC_PINCAP_HDMI;
Packit 427e91
}
Packit 427e91
Packit 427e91
static gboolean intmic_caps(unsigned long pin_caps, unsigned long wid_caps)
Packit 427e91
{
Packit 427e91
    return (pin_caps & AC_PINCAP_IN) && !(wid_caps & AC_WCAP_DIGITAL);
Packit 427e91
}
Packit 427e91
Packit 427e91
static gboolean spdifin_caps(unsigned long pin_caps, unsigned long wid_caps)
Packit 427e91
{
Packit 427e91
    return (pin_caps & AC_PINCAP_IN) && (wid_caps & AC_WCAP_DIGITAL);
Packit 427e91
}
Packit 427e91
Packit 427e91
static gboolean linein_caps(unsigned long pin_caps, unsigned long wid_caps)
Packit 427e91
{
Packit 427e91
    int vref = (pin_caps & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Packit 427e91
    return (pin_caps & AC_PINCAP_IN) && (vref & AC_PINCAP_VREF_HIZ);
Packit 427e91
}
Packit 427e91
Packit 427e91
static gboolean disabled_caps(unsigned long pin_caps, unsigned long wid_caps)
Packit 427e91
{
Packit 427e91
    return TRUE;
Packit 427e91
}
Packit 427e91
Packit 427e91
#define DEFAULT_MASK (AC_DEFCFG_PORT_CONN | AC_DEFCFG_GROSSLOC | AC_DEFCFG_DEVICE)
Packit 427e91
Packit 427e91
static typical_pins_t simple_typical_pins[] = {
Packit 427e91
    {"Headphone", headphone_caps, 0x0321403f, DEFAULT_MASK, },
Packit 427e91
    {"Microphone", extmic_caps, 0x03a19020, DEFAULT_MASK,},
Packit 427e91
    {"Line out (Front)", lineout_caps, 0x01014010, DEFAULT_MASK | AC_DEFCFG_SEQUENCE,},
Packit 427e91
    {"Line out (Center/LFE)", lineout_caps, 0x01014011, DEFAULT_MASK | AC_DEFCFG_SEQUENCE,},
Packit 427e91
    {"Line out (Back)", lineout_caps, 0x01014012, DEFAULT_MASK | AC_DEFCFG_SEQUENCE,},
Packit 427e91
    {"Line out (Side)", lineout_caps, 0x01014013, DEFAULT_MASK | AC_DEFCFG_SEQUENCE,},
Packit 427e91
    {"Line in", linein_caps, 0x0181304f, DEFAULT_MASK,},
Packit 427e91
    {"Internal speaker", lineout_caps, 0x90170150, DEFAULT_MASK | AC_DEFCFG_SEQUENCE, },
Packit 427e91
    {"Internal speaker (LFE)", lineout_caps, 0x90170151, DEFAULT_MASK | AC_DEFCFG_SEQUENCE, },
Packit 427e91
    {"Internal speaker (Back)", lineout_caps, 0x90170152, DEFAULT_MASK | AC_DEFCFG_SEQUENCE, },
Packit 427e91
    {"Internal mic", intmic_caps, 0x90a60160, DEFAULT_MASK,},
Packit 427e91
    {"HDMI / DisplayPort", hdmi_caps, 0x18560070, AC_DEFCFG_PORT_CONN | AC_DEFCFG_LOCATION,},
Packit 427e91
    {"SPDIF out", spdifout_caps, 0x014b1180, AC_DEFCFG_PORT_CONN | AC_DEFCFG_DEVICE,},
Packit 427e91
    {"SPDIF in", spdifin_caps, 0x01cb6190, AC_DEFCFG_PORT_CONN | AC_DEFCFG_DEVICE,},
Packit 427e91
    {"Dock Headphone", headphone_caps, 0x222140af, DEFAULT_MASK, },
Packit 427e91
    {"Dock Microphone", extmic_caps, 0x22a190a0, DEFAULT_MASK,},
Packit 427e91
    {"Dock Line out", lineout_caps, 0x220140b0, DEFAULT_MASK | AC_DEFCFG_SEQUENCE,},
Packit 427e91
    {"Dock Line in", linein_caps, 0x228130bf, DEFAULT_MASK,},
Packit 427e91
    {"Not connected", disabled_caps, 0x40f000f0, AC_DEFCFG_PORT_CONN,},
Packit 427e91
    {}
Packit 427e91
};
Packit 427e91
Packit 427e91
Packit 427e91
Packit 427e91
int get_typical_pins(typical_pins_t* result, int entries, pin_configs_t* pin_cfg, int caps_limit)
Packit 427e91
{
Packit 427e91
    int count = 0;
Packit 427e91
    int index = -1;
Packit 427e91
    unsigned long actual = actual_pin_config(pin_cfg);
Packit 427e91
    typical_pins_t* src;
Packit 427e91
    for (src = simple_typical_pins; src->name && entries; src++) {
Packit 427e91
        if (caps_limit && !src->caps_limit(pin_cfg->pin_caps, pin_cfg->wid_caps))
Packit 427e91
            continue;         
Packit 427e91
        if ((actual & src->match_mask) == (src->pin_set & src->match_mask))
Packit 427e91
            index = count;
Packit 427e91
        *result = *src;
Packit 427e91
        result++;
Packit 427e91
        count++;
Packit 427e91
        entries--;
Packit 427e91
    }
Packit 427e91
    if (entries) {
Packit 427e91
        result->name = NULL;
Packit 427e91
    }
Packit 427e91
    return index;
Packit 427e91
}
Packit 427e91
Packit 427e91
gboolean find_pin_channel_match(pin_configs_t* pins, int count, unsigned long pinval)
Packit 427e91
{
Packit 427e91
    int i;
Packit 427e91
    pinval &= (AC_DEFCFG_DEF_ASSOC + AC_DEFCFG_SEQUENCE);
Packit 427e91
    for (i = 0; i < count; i++, pins++) {
Packit 427e91
        unsigned long val2 = actual_pin_config(pins);
Packit 427e91
        if (get_port_conn(val2) == 1)
Packit 427e91
            continue;
Packit 427e91
        if (pinval == (val2 & (AC_DEFCFG_DEF_ASSOC + AC_DEFCFG_SEQUENCE)))
Packit 427e91
            return TRUE;
Packit 427e91
    }
Packit 427e91
    return FALSE;
Packit 427e91
}
Packit 427e91
Packit 427e91