Commit dbf117cb authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/hda' into for-linus

parents 25dc16f6 350eba43
......@@ -860,7 +860,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
[Multiple options for each card instance]
model - force the model name
position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF)
position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF,
3 = VIACOMBO, 4 = COMBO)
probe_mask - Bitmask to probe codecs (default = -1, meaning all slots)
When the bit 8 (0x100) is set, the lower 8 bits are used
as the "fixed" codec slots; i.e. the driver probes the
......@@ -925,6 +926,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
(Usually SD_LPIB register is more accurate than the
position buffer.)
position_fix=3 is specific to VIA devices. The position
of the capture stream is checked from both LPIB and POSBUF
values. position_fix=4 is a combination mode, using LPIB
for playback and POSBUF for capture.
NB: If you get many "azx_get_response timeout" messages at
loading, it's likely a problem of interrupts (e.g. ACPI irq
routing). Try to boot with options like "pci=noacpi". Also, you
......
......@@ -8,37 +8,10 @@ ALC880
5stack-digout 5-jack in back, 2-jack in front, a SPDIF out
6stack 6-jack in back, 2-jack in front
6stack-digout 6-jack with a SPDIF out
w810 3-jack
z71v 3-jack (HP shared SPDIF)
asus 3-jack (ASUS Mobo)
asus-w1v ASUS W1V
asus-dig ASUS with SPDIF out
asus-dig2 ASUS with SPDIF out (using GPIO2)
uniwill 3-jack
fujitsu Fujitsu Laptops (Pi1536)
F1734 2-jack
lg LG laptop (m1 express dual)
lg-lw LG LW20/LW25 laptop
tcl TCL S700
clevo Clevo laptops (m520G, m665n)
medion Medion Rim 2150
test for testing/debugging purpose, almost all controls can be
adjusted. Appearing only when compiled with
$CONFIG_SND_DEBUG=y
auto auto-config reading BIOS (default)
ALC260
======
fujitsu Fujitsu S7020
acer Acer TravelMate
will Will laptops (PB V7900)
replacer Replacer 672V
favorit100 Maxdata Favorit 100XS
basic fixed pin assignment (old default model)
test for testing/debugging purpose, almost all controls can
adjusted. Appearing only when compiled with
$CONFIG_SND_DEBUG=y
auto auto-config reading BIOS (default)
N/A
ALC262
======
......@@ -70,55 +43,7 @@ ALC680
ALC882/883/885/888/889
======================
3stack-dig 3-jack with SPDIF I/O
6stack-dig 6-jack digital with SPDIF I/O
arima Arima W820Di1
targa Targa T8, MSI-1049 T8
asus-a7j ASUS A7J
asus-a7m ASUS A7M
macpro MacPro support
mb5 Macbook 5,1
macmini3 Macmini 3,1
mba21 Macbook Air 2,1
mbp3 Macbook Pro rev3
imac24 iMac 24'' with jack detection
imac91 iMac 9,1
w2jc ASUS W2JC
3stack-2ch-dig 3-jack with SPDIF I/O (ALC883)
alc883-6stack-dig 6-jack digital with SPDIF I/O (ALC883)
3stack-6ch 3-jack 6-channel
3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
6stack-dig-demo 6-jack digital for Intel demo board
acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
acer-aspire Acer Aspire 9810
acer-aspire-4930g Acer Aspire 4930G
acer-aspire-6530g Acer Aspire 6530G
acer-aspire-7730g Acer Aspire 7730G
acer-aspire-8930g Acer Aspire 8930G
medion Medion Laptops
targa-dig Targa/MSI
targa-2ch-dig Targa/MSI with 2-channel
targa-8ch-dig Targa/MSI with 8-channel (MSI GX620)
laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
lenovo-101e Lenovo 101E
lenovo-nb0763 Lenovo NB0763
lenovo-ms7195-dig Lenovo MS7195
lenovo-sky Lenovo Sky
haier-w66 Haier W66
3stack-hp HP machines with 3stack (Lucknow, Samba boards)
6stack-dell Dell machines with 6stack (Inspiron 530)
mitac Mitac 8252D
clevo-m540r Clevo M540R (6ch + digital)
clevo-m720 Clevo M720 laptop series
fujitsu-pi2515 Fujitsu AMILO Pi2515
fujitsu-xa3530 Fujitsu AMILO XA3530
3stack-6ch-intel Intel DG33* boards
intel-alc889a Intel IbexPeak with ALC889A
intel-x58 Intel DX58 with ALC889
asus-p5q ASUS P5Q-EM boards
mb31 MacBook 3,1
sony-vaio-tt Sony VAIO TT
auto auto-config reading BIOS (default)
N/A
ALC861/660
==========
......
......@@ -59,7 +59,12 @@ a case, you can change the default method via `position_fix` option.
`position_fix=1` means to use LPIB method explicitly.
`position_fix=2` means to use the position-buffer.
`position_fix=3` means to use a combination of both methods, needed
for some VIA and ATI controllers. 0 is the default value for all other
for some VIA controllers. The capture stream position is corrected
by comparing both LPIB and position-buffer values.
`position_fix=4` is another combination available for all controllers,
and uses LPIB for the playback and the position-buffer for the capture
streams.
0 is the default value for all other
controllers, the automatic check and fallback to LPIB as described in
the above. If you get a problem of repeated sounds, this option might
help.
......
......@@ -227,6 +227,11 @@ snd_ctl_add_slave_uncached(struct snd_kcontrol *master,
return _snd_ctl_add_slave(master, slave, SND_CTL_SLAVE_NEED_UPDATE);
}
int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kctl,
void (*hook)(void *private_data, int),
void *private_data);
void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kctl);
/*
* Helper functions for jack-detection controls
*/
......
......@@ -37,6 +37,8 @@ struct link_master {
struct link_ctl_info info;
int val; /* the master value */
unsigned int tlv[4];
void (*hook)(void *private_data, int);
void *hook_private_data;
};
/*
......@@ -126,7 +128,9 @@ static int master_init(struct link_master *master)
master->info.count = 1; /* always mono */
/* set full volume as default (= no attenuation) */
master->val = master->info.max_val;
return 0;
if (master->hook)
master->hook(master->hook_private_data, master->val);
return 1;
}
return -ENOENT;
}
......@@ -329,6 +333,8 @@ static int master_put(struct snd_kcontrol *kcontrol,
slave_put_val(slave, uval);
}
kfree(uval);
if (master->hook && !err)
master->hook(master->hook_private_data, master->val);
return 1;
}
......@@ -408,3 +414,41 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
return kctl;
}
EXPORT_SYMBOL(snd_ctl_make_virtual_master);
/**
* snd_ctl_add_vmaster_hook - Add a hook to a vmaster control
* @kcontrol: vmaster kctl element
* @hook: the hook function
*
* Adds the given hook to the vmaster control element so that it's called
* at each time when the value is changed.
*/
int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol,
void (*hook)(void *private_data, int),
void *private_data)
{
struct link_master *master = snd_kcontrol_chip(kcontrol);
master->hook = hook;
master->hook_private_data = private_data;
return 0;
}
EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook);
/**
* snd_ctl_sync_vmaster_hook - Sync the vmaster hook
* @kcontrol: vmaster kctl element
*
* Call the hook function to synchronize with the current value of the given
* vmaster element. NOP when NULL is passed to @kcontrol or the hook doesn't
* exist.
*/
void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kcontrol)
{
struct link_master *master;
if (!kcontrol)
return;
master = snd_kcontrol_chip(kcontrol);
if (master->hook)
master->hook(master->hook_private_data, master->val);
}
EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster_hook);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -19,6 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
......@@ -2304,7 +2305,7 @@ typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *);
/* apply the function to all matching slave ctls in the mixer list */
static int map_slaves(struct hda_codec *codec, const char * const *slaves,
map_slave_func_t func, void *data)
const char *suffix, map_slave_func_t func, void *data)
{
struct hda_nid_item *items;
const char * const *s;
......@@ -2317,7 +2318,14 @@ static int map_slaves(struct hda_codec *codec, const char * const *slaves,
sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER)
continue;
for (s = slaves; *s; s++) {
if (!strcmp(sctl->id.name, *s)) {
char tmpname[sizeof(sctl->id.name)];
const char *name = *s;
if (suffix) {
snprintf(tmpname, sizeof(tmpname), "%s %s",
name, suffix);
name = tmpname;
}
if (!strcmp(sctl->id.name, name)) {
err = func(data, sctl);
if (err)
return err;
......@@ -2333,12 +2341,65 @@ static int check_slave_present(void *data, struct snd_kcontrol *sctl)
return 1;
}
/* guess the value corresponding to 0dB */
static int get_kctl_0dB_offset(struct snd_kcontrol *kctl)
{
int _tlv[4];
const int *tlv = NULL;
int val = -1;
if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
/* FIXME: set_fs() hack for obtaining user-space TLV data */
mm_segment_t fs = get_fs();
set_fs(get_ds());
if (!kctl->tlv.c(kctl, 0, sizeof(_tlv), _tlv))
tlv = _tlv;
set_fs(fs);
} else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ)
tlv = kctl->tlv.p;
if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE)
val = -tlv[2] / tlv[3];
return val;
}
/* call kctl->put with the given value(s) */
static int put_kctl_with_value(struct snd_kcontrol *kctl, int val)
{
struct snd_ctl_elem_value *ucontrol;
ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL);
if (!ucontrol)
return -ENOMEM;
ucontrol->value.integer.value[0] = val;
ucontrol->value.integer.value[1] = val;
kctl->put(kctl, ucontrol);
kfree(ucontrol);
return 0;
}
/* initialize the slave volume with 0dB */
static int init_slave_0dB(void *data, struct snd_kcontrol *slave)
{
int offset = get_kctl_0dB_offset(slave);
if (offset > 0)
put_kctl_with_value(slave, offset);
return 0;
}
/* unmute the slave */
static int init_slave_unmute(void *data, struct snd_kcontrol *slave)
{
return put_kctl_with_value(slave, 1);
}
/**
* snd_hda_add_vmaster - create a virtual master control and add slaves
* @codec: HD-audio codec
* @name: vmaster control name
* @tlv: TLV data (optional)
* @slaves: slave control names (optional)
* @suffix: suffix string to each slave name (optional)
* @init_slave_vol: initialize slaves to unmute/0dB
* @ctl_ret: store the vmaster kcontrol in return
*
* Create a virtual master control with the given name. The TLV data
* must be either NULL or a valid data.
......@@ -2349,13 +2410,18 @@ static int check_slave_present(void *data, struct snd_kcontrol *sctl)
*
* This function returns zero if successful or a negative error code.
*/
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char * const *slaves)
int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char * const *slaves,
const char *suffix, bool init_slave_vol,
struct snd_kcontrol **ctl_ret)
{
struct snd_kcontrol *kctl;
int err;
err = map_slaves(codec, slaves, check_slave_present, NULL);
if (ctl_ret)
*ctl_ret = NULL;
err = map_slaves(codec, slaves, suffix, check_slave_present, NULL);
if (err != 1) {
snd_printdd("No slave found for %s\n", name);
return 0;
......@@ -2367,13 +2433,119 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
if (err < 0)
return err;
err = map_slaves(codec, slaves, (map_slave_func_t)snd_ctl_add_slave,
kctl);
err = map_slaves(codec, slaves, suffix,
(map_slave_func_t)snd_ctl_add_slave, kctl);
if (err < 0)
return err;
/* init with master mute & zero volume */
put_kctl_with_value(kctl, 0);
if (init_slave_vol)
map_slaves(codec, slaves, suffix,
tlv ? init_slave_0dB : init_slave_unmute, kctl);
if (ctl_ret)
*ctl_ret = kctl;
return 0;
}
EXPORT_SYMBOL_HDA(__snd_hda_add_vmaster);
/*
* mute-LED control using vmaster
*/
static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
static const char * const texts[] = {
"Off", "On", "Follow Master"
};
unsigned int index;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = 3;
index = uinfo->value.enumerated.item;
if (index >= 3)
index = 2;
strcpy(uinfo->value.enumerated.name, texts[index]);
return 0;
}
static int vmaster_mute_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol);
ucontrol->value.enumerated.item[0] = hook->mute_mode;
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_add_vmaster);
static int vmaster_mute_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol);
unsigned int old_mode = hook->mute_mode;
hook->mute_mode = ucontrol->value.enumerated.item[0];
if (hook->mute_mode > HDA_VMUTE_FOLLOW_MASTER)
hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
if (old_mode == hook->mute_mode)
return 0;
snd_hda_sync_vmaster_hook(hook);
return 1;
}
static struct snd_kcontrol_new vmaster_mute_mode = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Mute-LED Mode",
.info = vmaster_mute_mode_info,
.get = vmaster_mute_mode_get,
.put = vmaster_mute_mode_put,
};
/*
* Add a mute-LED hook with the given vmaster switch kctl
* "Mute-LED Mode" control is automatically created and associated with
* the given hook.
*/
int snd_hda_add_vmaster_hook(struct hda_codec *codec,
struct hda_vmaster_mute_hook *hook,
bool expose_enum_ctl)
{
struct snd_kcontrol *kctl;
if (!hook->hook || !hook->sw_kctl)
return 0;
snd_ctl_add_vmaster_hook(hook->sw_kctl, hook->hook, codec);
hook->codec = codec;
hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
if (!expose_enum_ctl)
return 0;
kctl = snd_ctl_new1(&vmaster_mute_mode, hook);
if (!kctl)
return -ENOMEM;
return snd_hda_ctl_add(codec, 0, kctl);
}
EXPORT_SYMBOL_HDA(snd_hda_add_vmaster_hook);
/*
* Call the hook with the current value for synchronization
* Should be called in init callback
*/
void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook)
{
if (!hook->hook || !hook->codec)
return;
switch (hook->mute_mode) {
case HDA_VMUTE_FOLLOW_MASTER:
snd_ctl_sync_vmaster_hook(hook->sw_kctl);
break;
default:
hook->hook(hook->codec, hook->mute_mode);
break;
}
}
EXPORT_SYMBOL_HDA(snd_hda_sync_vmaster_hook);
/**
* snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch
......@@ -5272,6 +5444,10 @@ int snd_hda_suspend(struct hda_bus *bus)
list_for_each_entry(codec, &bus->codec_list, list) {
if (hda_codec_is_power_on(codec))
hda_call_codec_suspend(codec);
else /* forcibly change the power to D3 even if not used */
hda_set_power_state(codec,
codec->afg ? codec->afg : codec->mfg,
AC_PWRST_D3);
if (codec->patch_ops.post_suspend)
codec->patch_ops.post_suspend(codec);
}
......
......@@ -855,6 +855,7 @@ struct hda_codec {
unsigned int pins_shutup:1; /* pins are shut up */
unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */
unsigned int no_jack_detect:1; /* Machine has no jack-detection */
#ifdef CONFIG_SND_HDA_POWER_SAVE
unsigned int power_on :1; /* current (global) power-state */
unsigned int power_transition :1; /* power-state in transition */
......
......@@ -84,7 +84,7 @@ module_param_array(model, charp, NULL, 0444);
MODULE_PARM_DESC(model, "Use the given board model.");
module_param_array(position_fix, int, NULL, 0444);
MODULE_PARM_DESC(position_fix, "DMA pointer read method."
"(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO).");
"(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO).");
module_param_array(bdl_pos_adj, int, NULL, 0644);
MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
module_param_array(probe_mask, int, NULL, 0444);
......@@ -94,7 +94,7 @@ MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization.");
module_param(single_cmd, bool, 0444);
MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
"(for debugging only).");
module_param(enable_msi, int, 0444);
module_param(enable_msi, bint, 0444);
MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
#ifdef CONFIG_SND_HDA_PATCH_LOADER
module_param_array(patch, charp, NULL, 0444);
......@@ -121,8 +121,8 @@ module_param(power_save_controller, bool, 0644);
MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
#endif
static bool align_buffer_size = 1;
module_param(align_buffer_size, bool, 0644);
static int align_buffer_size = -1;
module_param(align_buffer_size, bint, 0644);
MODULE_PARM_DESC(align_buffer_size,
"Force buffer and period sizes to be multiple of 128 bytes.");
......@@ -148,6 +148,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{Intel, PCH},"
"{Intel, CPT},"
"{Intel, PPT},"
"{Intel, LPT},"
"{Intel, PBG},"
"{Intel, SCH},"
"{ATI, SB450},"
......@@ -329,6 +330,7 @@ enum {
POS_FIX_LPIB,
POS_FIX_POSBUF,
POS_FIX_VIACOMBO,
POS_FIX_COMBO,
};
/* Defines for ATI HD Audio support in SB450 south bridge */
......@@ -515,6 +517,7 @@ enum {
#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */
#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */
#define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */
#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */
/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
......@@ -527,7 +530,8 @@ enum {
/* quirks for Nvidia */
#define AZX_DCAPS_PRESET_NVIDIA \
(AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI)
(AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\
AZX_DCAPS_ALIGN_BUFSIZE)
static char *driver_short_names[] __devinitdata = {
[AZX_DRIVER_ICH] = "HDA Intel",
......@@ -2347,17 +2351,6 @@ static void azx_power_notify(struct hda_bus *bus)
* power management
*/
static int snd_hda_codecs_inuse(struct hda_bus *bus)
{
struct hda_codec *codec;
list_for_each_entry(codec, &bus->codec_list, list) {
if (snd_hda_codec_needs_resume(codec))
return 1;
}
return 0;
}
static int azx_suspend(struct pci_dev *pci, pm_message_t state)
{
struct snd_card *card = pci_get_drvdata(pci);
......@@ -2404,7 +2397,6 @@ static int azx_resume(struct pci_dev *pci)
return -EIO;
azx_init_pci(chip);
if (snd_hda_codecs_inuse(chip->bus))
azx_init_chip(chip, 1);
snd_hda_resume(chip->bus);
......@@ -2517,6 +2509,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
case POS_FIX_LPIB:
case POS_FIX_POSBUF:
case POS_FIX_VIACOMBO:
case POS_FIX_COMBO:
return fix;
}
......@@ -2696,6 +2689,12 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
chip->position_fix[0] = chip->position_fix[1] =
check_position_fix(chip, position_fix[dev]);
/* combo mode uses LPIB for playback */
if (chip->position_fix[0] == POS_FIX_COMBO) {
chip->position_fix[0] = POS_FIX_LPIB;
chip->position_fix[1] = POS_FIX_AUTO;
}
check_probe_mask(chip, dev);
chip->single_cmd = single_cmd;
......@@ -2774,9 +2773,16 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
}
/* disable buffer size rounding to 128-byte multiples if supported */
chip->align_buffer_size = align_buffer_size;
if (align_buffer_size >= 0)
chip->align_buffer_size = !!align_buffer_size;
else {
if (chip->driver_caps & AZX_DCAPS_BUFSIZE)
chip->align_buffer_size = 0;
else if (chip->driver_caps & AZX_DCAPS_ALIGN_BUFSIZE)
chip->align_buffer_size = 1;
else
chip->align_buffer_size = 1;
}
/* allow 64bit DMA address if supported by H/W */
if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
......@@ -2992,6 +2998,10 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
{ PCI_DEVICE(0x8086, 0x1e20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
AZX_DCAPS_BUFSIZE},
/* Lynx Point */
{ PCI_DEVICE(0x8086, 0x8c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
AZX_DCAPS_BUFSIZE},
/* SCH */
{ PCI_DEVICE(0x8086, 0x811b),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
......
......@@ -19,6 +19,22 @@
#include "hda_local.h"
#include "hda_jack.h"
bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
{
if (codec->no_jack_detect)
return false;
if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
return false;
if (!codec->ignore_misc_bit &&
(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
AC_DEFCFG_MISC_NO_PRESENCE))
return false;
if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
return false;
return true;
}
EXPORT_SYMBOL_HDA(is_jack_detectable);
/* execute pin sense measurement */
static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
{
......
......@@ -62,18 +62,7 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
{
if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
return false;
if (!codec->ignore_misc_bit &&
(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
AC_DEFCFG_MISC_NO_PRESENCE))
return false;
if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
return false;
return true;
}
bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
const char *name, int idx);
......
......@@ -139,10 +139,36 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int *tlv);
struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
const char *name);
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char * const *slaves);
int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char * const *slaves,
const char *suffix, bool init_slave_vol,
struct snd_kcontrol **ctl_ret);
#define snd_hda_add_vmaster(codec, name, tlv, slaves, suffix) \
__snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL)
int snd_hda_codec_reset(struct hda_codec *codec);
enum {
HDA_VMUTE_OFF,
HDA_VMUTE_ON,
HDA_VMUTE_FOLLOW_MASTER,
};
struct hda_vmaster_mute_hook {
/* below two fields must be filled by the caller of
* snd_hda_add_vmaster_hook() beforehand
*/
struct snd_kcontrol *sw_kctl;
void (*hook)(void *, int);
/* below are initialized automatically */
unsigned int mute_mode; /* HDA_VMUTE_XXX */
struct hda_codec *codec;
};
int snd_hda_add_vmaster_hook(struct hda_codec *codec,
struct hda_vmaster_mute_hook *hook,
bool expose_enum_ctl);
void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook);
/* amp value bits */
#define HDA_AMP_MUTE 0x80
#define HDA_AMP_UNMUTE 0x00
......
......@@ -82,6 +82,7 @@ struct ad198x_spec {
unsigned int inv_jack_detect: 1;/* inverted jack-detection */
unsigned int inv_eapd: 1; /* inverted EAPD implementation */
unsigned int analog_beep: 1; /* analog beep input present */
unsigned int avoid_init_slave_vol:1;
#ifdef CONFIG_SND_HDA_POWER_SAVE
struct hda_loopback_check loopback;
......@@ -137,51 +138,17 @@ static int ad198x_init(struct hda_codec *codec)
return 0;
}
static const char * const ad_slave_vols[] = {
"Front Playback Volume",
"Surround Playback Volume",
"Center Playback Volume",
"LFE Playback Volume",
"Side Playback Volume",
"Headphone Playback Volume",
"Mono Playback Volume",
"Speaker Playback Volume",
"IEC958 Playback Volume",
static const char * const ad_slave_pfxs[] = {
"Front", "Surround", "Center", "LFE", "Side",
"Headphone", "Mono", "Speaker", "IEC958",
NULL
};
static const char * const ad_slave_sws[] = {
"Front Playback Switch",
"Surround Playback Switch",
"Center Playback Switch",
"LFE Playback Switch",
"Side Playback Switch",
"Headphone Playback Switch",
"Mono Playback Switch",
"Speaker Playback Switch",
"IEC958 Playback Switch",
static const char * const ad1988_6stack_fp_slave_pfxs[] = {
"Front", "Surround", "Center", "LFE", "Side", "IEC958",
NULL
};
static const char * const ad1988_6stack_fp_slave_vols[] = {
"Front Playback Volume",
"Surround Playback Volume",
"Center Playback Volume",
"LFE Playback Volume",
"Side Playback Volume",
"IEC958 Playback Volume",
NULL
};
static const char * const ad1988_6stack_fp_slave_sws[] = {
"Front Playback Switch",
"Surround Playback Switch",
"Center Playback Switch",
"LFE Playback Switch",
"Side Playback Switch",
"IEC958 Playback Switch",
NULL
};
static void ad198x_free_kctls(struct hda_codec *codec);
#ifdef CONFIG_SND_HDA_INPUT_BEEP
......@@ -257,10 +224,12 @@ static int ad198x_build_controls(struct hda_codec *codec)
unsigned int vmaster_tlv[4];
snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
HDA_OUTPUT, vmaster_tlv);
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
err = __snd_hda_add_vmaster(codec, "Master Playback Volume",
vmaster_tlv,
(spec->slave_vols ?
spec->slave_vols : ad_slave_vols));
spec->slave_vols : ad_slave_pfxs),
"Playback Volume",
!spec->avoid_init_slave_vol, NULL);
if (err < 0)
return err;
}
......@@ -268,7 +237,8 @@ static int ad198x_build_controls(struct hda_codec *codec)
err = snd_hda_add_vmaster(codec, "Master Playback Switch",
NULL,
(spec->slave_sws ?
spec->slave_sws : ad_slave_sws));
spec->slave_sws : ad_slave_pfxs),
"Playback Switch");
if (err < 0)
return err;
}
......@@ -3385,8 +3355,8 @@ static int patch_ad1988(struct hda_codec *codec)
if (spec->autocfg.hp_pins[0]) {
spec->mixers[spec->num_mixers++] = ad1988_hp_mixers;
spec->slave_vols = ad1988_6stack_fp_slave_vols;
spec->slave_sws = ad1988_6stack_fp_slave_sws;
spec->slave_vols = ad1988_6stack_fp_slave_pfxs;
spec->slave_sws = ad1988_6stack_fp_slave_pfxs;
spec->alt_dac_nid = ad1988_alt_dac_nid;
spec->stream_analog_alt_playback =
&ad198x_pcm_analog_alt_playback;
......@@ -3594,16 +3564,8 @@ static const struct hda_amp_list ad1884_loopbacks[] = {
#endif
static const char * const ad1884_slave_vols[] = {
"PCM Playback Volume",
"Mic Playback Volume",
"Mono Playback Volume",
"Front Mic Playback Volume",
"Mic Playback Volume",
"CD Playback Volume",
"Internal Mic Playback Volume",
"Docking Mic Playback Volume",
/* "Beep Playback Volume", */
"IEC958 Playback Volume",
"PCM", "Mic", "Mono", "Front Mic", "Mic", "CD",
"Internal Mic", "Docking Mic", /* "Beep", */ "IEC958",
NULL
};
......@@ -3644,6 +3606,8 @@ static int patch_ad1884(struct hda_codec *codec)
spec->vmaster_nid = 0x04;
/* we need to cover all playback volumes */
spec->slave_vols = ad1884_slave_vols;
/* slaves may contain input volumes, so we can't raise to 0dB blindly */
spec->avoid_init_slave_vol = 1;
codec->patch_ops = ad198x_patch_ops;
......
This diff is collapsed.
......@@ -1912,6 +1912,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
{ .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi },
{ .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_generic_hdmi },
{ .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi },
{ .id = 0x80862880, .name = "CedarTrail HDMI", .patch = patch_generic_hdmi },
{ .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi },
{} /* terminator */
};
......@@ -1958,6 +1959,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862803");
MODULE_ALIAS("snd-hda-codec-id:80862804");
MODULE_ALIAS("snd-hda-codec-id:80862805");
MODULE_ALIAS("snd-hda-codec-id:80862806");
MODULE_ALIAS("snd-hda-codec-id:80862880");
MODULE_ALIAS("snd-hda-codec-id:808629fb");
MODULE_LICENSE("GPL");
......
This diff is collapsed.
This diff is collapsed.
......@@ -550,7 +550,10 @@ static void via_auto_init_output(struct hda_codec *codec,
pin = path->path[path->depth - 1];
init_output_pin(codec, pin, pin_type);
if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
caps = query_amp_caps(codec, pin, HDA_OUTPUT);
else
caps = 0;
if (caps & AC_AMPCAP_MUTE) {
unsigned int val;
val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
......@@ -645,6 +648,10 @@ static void via_auto_init_analog_input(struct hda_codec *codec)
/* init ADCs */
for (i = 0; i < spec->num_adc_nids; i++) {
hda_nid_t nid = spec->adc_nids[i];
if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP) ||
!(query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE))
continue;
snd_hda_codec_write(codec, spec->adc_nids[i], 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_UNMUTE(0));
......@@ -1445,25 +1452,9 @@ static const struct hda_pcm_stream via_pcm_digital_capture = {
/*
* slave controls for virtual master
*/
static const char * const via_slave_vols[] = {
"Front Playback Volume",
"Surround Playback Volume",
"Center Playback Volume",
"LFE Playback Volume",
"Side Playback Volume",
"Headphone Playback Volume",
"Speaker Playback Volume",
NULL,
};
static const char * const via_slave_sws[] = {
"Front Playback Switch",
"Surround Playback Switch",
"Center Playback Switch",
"LFE Playback Switch",
"Side Playback Switch",
"Headphone Playback Switch",
"Speaker Playback Switch",
static const char * const via_slave_pfxs[] = {
"Front", "Surround", "Center", "LFE", "Side",
"Headphone", "Speaker",
NULL,
};
......@@ -1508,13 +1499,15 @@ static int via_build_controls(struct hda_codec *codec)
snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
HDA_OUTPUT, vmaster_tlv);
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
vmaster_tlv, via_slave_vols);
vmaster_tlv, via_slave_pfxs,
"Playback Volume");
if (err < 0)
return err;
}
if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
err = snd_hda_add_vmaster(codec, "Master Playback Switch",
NULL, via_slave_sws);
NULL, via_slave_pfxs,
"Playback Switch");
if (err < 0)
return err;
}
......@@ -1522,6 +1515,8 @@ static int via_build_controls(struct hda_codec *codec)
/* assign Capture Source enums to NID */
kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
for (i = 0; kctl && i < kctl->count; i++) {
if (!spec->mux_nids[i])
continue;
err = snd_hda_add_nid(codec, kctl, i, spec->mux_nids[i]);
if (err < 0)
return err;
......@@ -2488,6 +2483,8 @@ static int create_mic_boost_ctls(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
const struct auto_pin_cfg *cfg = &spec->autocfg;
const char *prev_label = NULL;
int type_idx = 0;
int i, err;
for (i = 0; i < cfg->num_inputs; i++) {
......@@ -2502,8 +2499,13 @@ static int create_mic_boost_ctls(struct hda_codec *codec)
if (caps == -1 || !(caps & AC_AMPCAP_NUM_STEPS))
continue;
label = hda_get_autocfg_input_label(codec, cfg, i);
if (prev_label && !strcmp(label, prev_label))
type_idx++;
else
type_idx = 0;
prev_label = label;
snprintf(name, sizeof(name), "%s Boost Volume", label);
err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx,
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT));
if (err < 0)
return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment