Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
6de15b2a
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
6de15b2a
编写于
5月 21, 2012
作者:
T
Takashi Iwai
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'topic/hda' into for-linus
上级
775b2449
8a390576
变更
19
隐藏空白更改
内联
并排
Showing
19 changed file
with
1612 addition
and
1387 deletion
+1612
-1387
sound/pci/hda/Makefile
sound/pci/hda/Makefile
+1
-1
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_auto_parser.c
+760
-0
sound/pci/hda/hda_auto_parser.h
sound/pci/hda/hda_auto_parser.h
+160
-0
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.c
+282
-745
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_codec.h
+8
-7
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_intel.c
+23
-17
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_jack.c
+1
-0
sound/pci/hda/hda_jack.h
sound/pci/hda/hda_jack.h
+2
-0
sound/pci/hda/hda_local.h
sound/pci/hda/hda_local.h
+43
-79
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_analog.c
+8
-6
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_ca0110.c
+4
-4
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_ca0132.c
+4
-5
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_cirrus.c
+10
-20
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_cmedia.c
+1
-0
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_conexant.c
+116
-70
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_hdmi.c
+2
-2
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_realtek.c
+130
-335
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_sigmatel.c
+44
-76
sound/pci/hda/patch_via.c
sound/pci/hda/patch_via.c
+13
-20
未找到文件。
sound/pci/hda/Makefile
浏览文件 @
6de15b2a
snd-hda-intel-objs
:=
hda_intel.o
snd-hda-codec-y
:=
hda_codec.o hda_jack.o
snd-hda-codec-y
:=
hda_codec.o hda_jack.o
hda_auto_parser.o
snd-hda-codec-$(CONFIG_SND_HDA_GENERIC)
+=
hda_generic.o
snd-hda-codec-$(CONFIG_PROC_FS)
+=
hda_proc.o
snd-hda-codec-$(CONFIG_SND_HDA_HWDEP)
+=
hda_hwdep.o
...
...
sound/pci/hda/hda_auto_parser.c
0 → 100644
浏览文件 @
6de15b2a
/*
* BIOS auto-parser helper functions for HD-audio
*
* Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
*
* This driver is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/slab.h>
#include <linux/export.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#define SFX "hda_codec: "
/*
* Helper for automatic pin configuration
*/
static
int
is_in_nid_list
(
hda_nid_t
nid
,
const
hda_nid_t
*
list
)
{
for
(;
*
list
;
list
++
)
if
(
*
list
==
nid
)
return
1
;
return
0
;
}
/*
* Sort an associated group of pins according to their sequence numbers.
*/
static
void
sort_pins_by_sequence
(
hda_nid_t
*
pins
,
short
*
sequences
,
int
num_pins
)
{
int
i
,
j
;
short
seq
;
hda_nid_t
nid
;
for
(
i
=
0
;
i
<
num_pins
;
i
++
)
{
for
(
j
=
i
+
1
;
j
<
num_pins
;
j
++
)
{
if
(
sequences
[
i
]
>
sequences
[
j
])
{
seq
=
sequences
[
i
];
sequences
[
i
]
=
sequences
[
j
];
sequences
[
j
]
=
seq
;
nid
=
pins
[
i
];
pins
[
i
]
=
pins
[
j
];
pins
[
j
]
=
nid
;
}
}
}
}
/* add the found input-pin to the cfg->inputs[] table */
static
void
add_auto_cfg_input_pin
(
struct
auto_pin_cfg
*
cfg
,
hda_nid_t
nid
,
int
type
)
{
if
(
cfg
->
num_inputs
<
AUTO_CFG_MAX_INS
)
{
cfg
->
inputs
[
cfg
->
num_inputs
].
pin
=
nid
;
cfg
->
inputs
[
cfg
->
num_inputs
].
type
=
type
;
cfg
->
num_inputs
++
;
}
}
/* sort inputs in the order of AUTO_PIN_* type */
static
void
sort_autocfg_input_pins
(
struct
auto_pin_cfg
*
cfg
)
{
int
i
,
j
;
for
(
i
=
0
;
i
<
cfg
->
num_inputs
;
i
++
)
{
for
(
j
=
i
+
1
;
j
<
cfg
->
num_inputs
;
j
++
)
{
if
(
cfg
->
inputs
[
i
].
type
>
cfg
->
inputs
[
j
].
type
)
{
struct
auto_pin_cfg_item
tmp
;
tmp
=
cfg
->
inputs
[
i
];
cfg
->
inputs
[
i
]
=
cfg
->
inputs
[
j
];
cfg
->
inputs
[
j
]
=
tmp
;
}
}
}
}
/* Reorder the surround channels
* ALSA sequence is front/surr/clfe/side
* HDA sequence is:
* 4-ch: front/surr => OK as it is
* 6-ch: front/clfe/surr
* 8-ch: front/clfe/rear/side|fc
*/
static
void
reorder_outputs
(
unsigned
int
nums
,
hda_nid_t
*
pins
)
{
hda_nid_t
nid
;
switch
(
nums
)
{
case
3
:
case
4
:
nid
=
pins
[
1
];
pins
[
1
]
=
pins
[
2
];
pins
[
2
]
=
nid
;
break
;
}
}
/*
* Parse all pin widgets and store the useful pin nids to cfg
*
* The number of line-outs or any primary output is stored in line_outs,
* and the corresponding output pins are assigned to line_out_pins[],
* in the order of front, rear, CLFE, side, ...
*
* If more extra outputs (speaker and headphone) are found, the pins are
* assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack
* is detected, one of speaker of HP pins is assigned as the primary
* output, i.e. to line_out_pins[0]. So, line_outs is always positive
* if any analog output exists.
*
* The analog input pins are assigned to inputs array.
* The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
* respectively.
*/
int
snd_hda_parse_pin_defcfg
(
struct
hda_codec
*
codec
,
struct
auto_pin_cfg
*
cfg
,
const
hda_nid_t
*
ignore_nids
,
unsigned
int
cond_flags
)
{
hda_nid_t
nid
,
end_nid
;
short
seq
,
assoc_line_out
;
short
sequences_line_out
[
ARRAY_SIZE
(
cfg
->
line_out_pins
)];
short
sequences_speaker
[
ARRAY_SIZE
(
cfg
->
speaker_pins
)];
short
sequences_hp
[
ARRAY_SIZE
(
cfg
->
hp_pins
)];
int
i
;
memset
(
cfg
,
0
,
sizeof
(
*
cfg
));
memset
(
sequences_line_out
,
0
,
sizeof
(
sequences_line_out
));
memset
(
sequences_speaker
,
0
,
sizeof
(
sequences_speaker
));
memset
(
sequences_hp
,
0
,
sizeof
(
sequences_hp
));
assoc_line_out
=
0
;
codec
->
ignore_misc_bit
=
true
;
end_nid
=
codec
->
start_nid
+
codec
->
num_nodes
;
for
(
nid
=
codec
->
start_nid
;
nid
<
end_nid
;
nid
++
)
{
unsigned
int
wid_caps
=
get_wcaps
(
codec
,
nid
);
unsigned
int
wid_type
=
get_wcaps_type
(
wid_caps
);
unsigned
int
def_conf
;
short
assoc
,
loc
,
conn
,
dev
;
/* read all default configuration for pin complex */
if
(
wid_type
!=
AC_WID_PIN
)
continue
;
/* ignore the given nids (e.g. pc-beep returns error) */
if
(
ignore_nids
&&
is_in_nid_list
(
nid
,
ignore_nids
))
continue
;
def_conf
=
snd_hda_codec_get_pincfg
(
codec
,
nid
);
if
(
!
(
get_defcfg_misc
(
snd_hda_codec_get_pincfg
(
codec
,
nid
))
&
AC_DEFCFG_MISC_NO_PRESENCE
))
codec
->
ignore_misc_bit
=
false
;
conn
=
get_defcfg_connect
(
def_conf
);
if
(
conn
==
AC_JACK_PORT_NONE
)
continue
;
loc
=
get_defcfg_location
(
def_conf
);
dev
=
get_defcfg_device
(
def_conf
);
/* workaround for buggy BIOS setups */
if
(
dev
==
AC_JACK_LINE_OUT
)
{
if
(
conn
==
AC_JACK_PORT_FIXED
)
dev
=
AC_JACK_SPEAKER
;
}
switch
(
dev
)
{
case
AC_JACK_LINE_OUT
:
seq
=
get_defcfg_sequence
(
def_conf
);
assoc
=
get_defcfg_association
(
def_conf
);
if
(
!
(
wid_caps
&
AC_WCAP_STEREO
))
if
(
!
cfg
->
mono_out_pin
)
cfg
->
mono_out_pin
=
nid
;
if
(
!
assoc
)
continue
;
if
(
!
assoc_line_out
)
assoc_line_out
=
assoc
;
else
if
(
assoc_line_out
!=
assoc
)
continue
;
if
(
cfg
->
line_outs
>=
ARRAY_SIZE
(
cfg
->
line_out_pins
))
continue
;
cfg
->
line_out_pins
[
cfg
->
line_outs
]
=
nid
;
sequences_line_out
[
cfg
->
line_outs
]
=
seq
;
cfg
->
line_outs
++
;
break
;
case
AC_JACK_SPEAKER
:
seq
=
get_defcfg_sequence
(
def_conf
);
assoc
=
get_defcfg_association
(
def_conf
);
if
(
cfg
->
speaker_outs
>=
ARRAY_SIZE
(
cfg
->
speaker_pins
))
continue
;
cfg
->
speaker_pins
[
cfg
->
speaker_outs
]
=
nid
;
sequences_speaker
[
cfg
->
speaker_outs
]
=
(
assoc
<<
4
)
|
seq
;
cfg
->
speaker_outs
++
;
break
;
case
AC_JACK_HP_OUT
:
seq
=
get_defcfg_sequence
(
def_conf
);
assoc
=
get_defcfg_association
(
def_conf
);
if
(
cfg
->
hp_outs
>=
ARRAY_SIZE
(
cfg
->
hp_pins
))
continue
;
cfg
->
hp_pins
[
cfg
->
hp_outs
]
=
nid
;
sequences_hp
[
cfg
->
hp_outs
]
=
(
assoc
<<
4
)
|
seq
;
cfg
->
hp_outs
++
;
break
;
case
AC_JACK_MIC_IN
:
add_auto_cfg_input_pin
(
cfg
,
nid
,
AUTO_PIN_MIC
);
break
;
case
AC_JACK_LINE_IN
:
add_auto_cfg_input_pin
(
cfg
,
nid
,
AUTO_PIN_LINE_IN
);
break
;
case
AC_JACK_CD
:
add_auto_cfg_input_pin
(
cfg
,
nid
,
AUTO_PIN_CD
);
break
;
case
AC_JACK_AUX
:
add_auto_cfg_input_pin
(
cfg
,
nid
,
AUTO_PIN_AUX
);
break
;
case
AC_JACK_SPDIF_OUT
:
case
AC_JACK_DIG_OTHER_OUT
:
if
(
cfg
->
dig_outs
>=
ARRAY_SIZE
(
cfg
->
dig_out_pins
))
continue
;
cfg
->
dig_out_pins
[
cfg
->
dig_outs
]
=
nid
;
cfg
->
dig_out_type
[
cfg
->
dig_outs
]
=
(
loc
==
AC_JACK_LOC_HDMI
)
?
HDA_PCM_TYPE_HDMI
:
HDA_PCM_TYPE_SPDIF
;
cfg
->
dig_outs
++
;
break
;
case
AC_JACK_SPDIF_IN
:
case
AC_JACK_DIG_OTHER_IN
:
cfg
->
dig_in_pin
=
nid
;
if
(
loc
==
AC_JACK_LOC_HDMI
)
cfg
->
dig_in_type
=
HDA_PCM_TYPE_HDMI
;
else
cfg
->
dig_in_type
=
HDA_PCM_TYPE_SPDIF
;
break
;
}
}
/* FIX-UP:
* If no line-out is defined but multiple HPs are found,
* some of them might be the real line-outs.
*/
if
(
!
cfg
->
line_outs
&&
cfg
->
hp_outs
>
1
&&
!
(
cond_flags
&
HDA_PINCFG_NO_HP_FIXUP
))
{
int
i
=
0
;
while
(
i
<
cfg
->
hp_outs
)
{
/* The real HPs should have the sequence 0x0f */
if
((
sequences_hp
[
i
]
&
0x0f
)
==
0x0f
)
{
i
++
;
continue
;
}
/* Move it to the line-out table */
cfg
->
line_out_pins
[
cfg
->
line_outs
]
=
cfg
->
hp_pins
[
i
];
sequences_line_out
[
cfg
->
line_outs
]
=
sequences_hp
[
i
];
cfg
->
line_outs
++
;
cfg
->
hp_outs
--
;
memmove
(
cfg
->
hp_pins
+
i
,
cfg
->
hp_pins
+
i
+
1
,
sizeof
(
cfg
->
hp_pins
[
0
])
*
(
cfg
->
hp_outs
-
i
));
memmove
(
sequences_hp
+
i
,
sequences_hp
+
i
+
1
,
sizeof
(
sequences_hp
[
0
])
*
(
cfg
->
hp_outs
-
i
));
}
memset
(
cfg
->
hp_pins
+
cfg
->
hp_outs
,
0
,
sizeof
(
hda_nid_t
)
*
(
AUTO_CFG_MAX_OUTS
-
cfg
->
hp_outs
));
if
(
!
cfg
->
hp_outs
)
cfg
->
line_out_type
=
AUTO_PIN_HP_OUT
;
}
/* sort by sequence */
sort_pins_by_sequence
(
cfg
->
line_out_pins
,
sequences_line_out
,
cfg
->
line_outs
);
sort_pins_by_sequence
(
cfg
->
speaker_pins
,
sequences_speaker
,
cfg
->
speaker_outs
);
sort_pins_by_sequence
(
cfg
->
hp_pins
,
sequences_hp
,
cfg
->
hp_outs
);
/*
* FIX-UP: if no line-outs are detected, try to use speaker or HP pin
* as a primary output
*/
if
(
!
cfg
->
line_outs
&&
!
(
cond_flags
&
HDA_PINCFG_NO_LO_FIXUP
))
{
if
(
cfg
->
speaker_outs
)
{
cfg
->
line_outs
=
cfg
->
speaker_outs
;
memcpy
(
cfg
->
line_out_pins
,
cfg
->
speaker_pins
,
sizeof
(
cfg
->
speaker_pins
));
cfg
->
speaker_outs
=
0
;
memset
(
cfg
->
speaker_pins
,
0
,
sizeof
(
cfg
->
speaker_pins
));
cfg
->
line_out_type
=
AUTO_PIN_SPEAKER_OUT
;
}
else
if
(
cfg
->
hp_outs
)
{
cfg
->
line_outs
=
cfg
->
hp_outs
;
memcpy
(
cfg
->
line_out_pins
,
cfg
->
hp_pins
,
sizeof
(
cfg
->
hp_pins
));
cfg
->
hp_outs
=
0
;
memset
(
cfg
->
hp_pins
,
0
,
sizeof
(
cfg
->
hp_pins
));
cfg
->
line_out_type
=
AUTO_PIN_HP_OUT
;
}
}
reorder_outputs
(
cfg
->
line_outs
,
cfg
->
line_out_pins
);
reorder_outputs
(
cfg
->
hp_outs
,
cfg
->
hp_pins
);
reorder_outputs
(
cfg
->
speaker_outs
,
cfg
->
speaker_pins
);
sort_autocfg_input_pins
(
cfg
);
/*
* debug prints of the parsed results
*/
snd_printd
(
"autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s
\n
"
,
cfg
->
line_outs
,
cfg
->
line_out_pins
[
0
],
cfg
->
line_out_pins
[
1
],
cfg
->
line_out_pins
[
2
],
cfg
->
line_out_pins
[
3
],
cfg
->
line_out_pins
[
4
],
cfg
->
line_out_type
==
AUTO_PIN_HP_OUT
?
"hp"
:
(
cfg
->
line_out_type
==
AUTO_PIN_SPEAKER_OUT
?
"speaker"
:
"line"
));
snd_printd
(
" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)
\n
"
,
cfg
->
speaker_outs
,
cfg
->
speaker_pins
[
0
],
cfg
->
speaker_pins
[
1
],
cfg
->
speaker_pins
[
2
],
cfg
->
speaker_pins
[
3
],
cfg
->
speaker_pins
[
4
]);
snd_printd
(
" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)
\n
"
,
cfg
->
hp_outs
,
cfg
->
hp_pins
[
0
],
cfg
->
hp_pins
[
1
],
cfg
->
hp_pins
[
2
],
cfg
->
hp_pins
[
3
],
cfg
->
hp_pins
[
4
]);
snd_printd
(
" mono: mono_out=0x%x
\n
"
,
cfg
->
mono_out_pin
);
if
(
cfg
->
dig_outs
)
snd_printd
(
" dig-out=0x%x/0x%x
\n
"
,
cfg
->
dig_out_pins
[
0
],
cfg
->
dig_out_pins
[
1
]);
snd_printd
(
" inputs:"
);
for
(
i
=
0
;
i
<
cfg
->
num_inputs
;
i
++
)
{
snd_printd
(
" %s=0x%x"
,
hda_get_autocfg_input_label
(
codec
,
cfg
,
i
),
cfg
->
inputs
[
i
].
pin
);
}
snd_printd
(
"
\n
"
);
if
(
cfg
->
dig_in_pin
)
snd_printd
(
" dig-in=0x%x
\n
"
,
cfg
->
dig_in_pin
);
return
0
;
}
EXPORT_SYMBOL_HDA
(
snd_hda_parse_pin_defcfg
);
int
snd_hda_get_input_pin_attr
(
unsigned
int
def_conf
)
{
unsigned
int
loc
=
get_defcfg_location
(
def_conf
);
unsigned
int
conn
=
get_defcfg_connect
(
def_conf
);
if
(
conn
==
AC_JACK_PORT_NONE
)
return
INPUT_PIN_ATTR_UNUSED
;
/* Windows may claim the internal mic to be BOTH, too */
if
(
conn
==
AC_JACK_PORT_FIXED
||
conn
==
AC_JACK_PORT_BOTH
)
return
INPUT_PIN_ATTR_INT
;
if
((
loc
&
0x30
)
==
AC_JACK_LOC_INTERNAL
)
return
INPUT_PIN_ATTR_INT
;
if
((
loc
&
0x30
)
==
AC_JACK_LOC_SEPARATE
)
return
INPUT_PIN_ATTR_DOCK
;
if
(
loc
==
AC_JACK_LOC_REAR
)
return
INPUT_PIN_ATTR_REAR
;
if
(
loc
==
AC_JACK_LOC_FRONT
)
return
INPUT_PIN_ATTR_FRONT
;
return
INPUT_PIN_ATTR_NORMAL
;
}
EXPORT_SYMBOL_HDA
(
snd_hda_get_input_pin_attr
);
/**
* hda_get_input_pin_label - Give a label for the given input pin
*
* When check_location is true, the function checks the pin location
* for mic and line-in pins, and set an appropriate prefix like "Front",
* "Rear", "Internal".
*/
static
const
char
*
hda_get_input_pin_label
(
struct
hda_codec
*
codec
,
hda_nid_t
pin
,
bool
check_location
)
{
unsigned
int
def_conf
;
static
const
char
*
const
mic_names
[]
=
{
"Internal Mic"
,
"Dock Mic"
,
"Mic"
,
"Front Mic"
,
"Rear Mic"
,
};
int
attr
;
def_conf
=
snd_hda_codec_get_pincfg
(
codec
,
pin
);
switch
(
get_defcfg_device
(
def_conf
))
{
case
AC_JACK_MIC_IN
:
if
(
!
check_location
)
return
"Mic"
;
attr
=
snd_hda_get_input_pin_attr
(
def_conf
);
if
(
!
attr
)
return
"None"
;
return
mic_names
[
attr
-
1
];
case
AC_JACK_LINE_IN
:
if
(
!
check_location
)
return
"Line"
;
attr
=
snd_hda_get_input_pin_attr
(
def_conf
);
if
(
!
attr
)
return
"None"
;
if
(
attr
==
INPUT_PIN_ATTR_DOCK
)
return
"Dock Line"
;
return
"Line"
;
case
AC_JACK_AUX
:
return
"Aux"
;
case
AC_JACK_CD
:
return
"CD"
;
case
AC_JACK_SPDIF_IN
:
return
"SPDIF In"
;
case
AC_JACK_DIG_OTHER_IN
:
return
"Digital In"
;
default:
return
"Misc"
;
}
}
/* Check whether the location prefix needs to be added to the label.
* If all mic-jacks are in the same location (e.g. rear panel), we don't
* have to put "Front" prefix to each label. In such a case, returns false.
*/
static
int
check_mic_location_need
(
struct
hda_codec
*
codec
,
const
struct
auto_pin_cfg
*
cfg
,
int
input
)
{
unsigned
int
defc
;
int
i
,
attr
,
attr2
;
defc
=
snd_hda_codec_get_pincfg
(
codec
,
cfg
->
inputs
[
input
].
pin
);
attr
=
snd_hda_get_input_pin_attr
(
defc
);
/* for internal or docking mics, we need locations */
if
(
attr
<=
INPUT_PIN_ATTR_NORMAL
)
return
1
;
attr
=
0
;
for
(
i
=
0
;
i
<
cfg
->
num_inputs
;
i
++
)
{
defc
=
snd_hda_codec_get_pincfg
(
codec
,
cfg
->
inputs
[
i
].
pin
);
attr2
=
snd_hda_get_input_pin_attr
(
defc
);
if
(
attr2
>=
INPUT_PIN_ATTR_NORMAL
)
{
if
(
attr
&&
attr
!=
attr2
)
return
1
;
/* different locations found */
attr
=
attr2
;
}
}
return
0
;
}
/**
* hda_get_autocfg_input_label - Get a label for the given input
*
* Get a label for the given input pin defined by the autocfg item.
* Unlike hda_get_input_pin_label(), this function checks all inputs
* defined in autocfg and avoids the redundant mic/line prefix as much as
* possible.
*/
const
char
*
hda_get_autocfg_input_label
(
struct
hda_codec
*
codec
,
const
struct
auto_pin_cfg
*
cfg
,
int
input
)
{
int
type
=
cfg
->
inputs
[
input
].
type
;
int
has_multiple_pins
=
0
;
if
((
input
>
0
&&
cfg
->
inputs
[
input
-
1
].
type
==
type
)
||
(
input
<
cfg
->
num_inputs
-
1
&&
cfg
->
inputs
[
input
+
1
].
type
==
type
))
has_multiple_pins
=
1
;
if
(
has_multiple_pins
&&
type
==
AUTO_PIN_MIC
)
has_multiple_pins
&=
check_mic_location_need
(
codec
,
cfg
,
input
);
return
hda_get_input_pin_label
(
codec
,
cfg
->
inputs
[
input
].
pin
,
has_multiple_pins
);
}
EXPORT_SYMBOL_HDA
(
hda_get_autocfg_input_label
);
/* return the position of NID in the list, or -1 if not found */
static
int
find_idx_in_nid_list
(
hda_nid_t
nid
,
const
hda_nid_t
*
list
,
int
nums
)
{
int
i
;
for
(
i
=
0
;
i
<
nums
;
i
++
)
if
(
list
[
i
]
==
nid
)
return
i
;
return
-
1
;
}
/* get a unique suffix or an index number */
static
const
char
*
check_output_sfx
(
hda_nid_t
nid
,
const
hda_nid_t
*
pins
,
int
num_pins
,
int
*
indexp
)
{
static
const
char
*
const
channel_sfx
[]
=
{
" Front"
,
" Surround"
,
" CLFE"
,
" Side"
};
int
i
;
i
=
find_idx_in_nid_list
(
nid
,
pins
,
num_pins
);
if
(
i
<
0
)
return
NULL
;
if
(
num_pins
==
1
)
return
""
;
if
(
num_pins
>
ARRAY_SIZE
(
channel_sfx
))
{
if
(
indexp
)
*
indexp
=
i
;
return
""
;
}
return
channel_sfx
[
i
];
}
static
int
fill_audio_out_name
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
const
struct
auto_pin_cfg
*
cfg
,
const
char
*
name
,
char
*
label
,
int
maxlen
,
int
*
indexp
)
{
unsigned
int
def_conf
=
snd_hda_codec_get_pincfg
(
codec
,
nid
);
int
attr
=
snd_hda_get_input_pin_attr
(
def_conf
);
const
char
*
pfx
=
""
,
*
sfx
=
""
;
/* handle as a speaker if it's a fixed line-out */
if
(
!
strcmp
(
name
,
"Line Out"
)
&&
attr
==
INPUT_PIN_ATTR_INT
)
name
=
"Speaker"
;
/* check the location */
switch
(
attr
)
{
case
INPUT_PIN_ATTR_DOCK
:
pfx
=
"Dock "
;
break
;
case
INPUT_PIN_ATTR_FRONT
:
pfx
=
"Front "
;
break
;
}
if
(
cfg
)
{
/* try to give a unique suffix if needed */
sfx
=
check_output_sfx
(
nid
,
cfg
->
line_out_pins
,
cfg
->
line_outs
,
indexp
);
if
(
!
sfx
)
sfx
=
check_output_sfx
(
nid
,
cfg
->
speaker_pins
,
cfg
->
speaker_outs
,
indexp
);
if
(
!
sfx
)
{
/* don't add channel suffix for Headphone controls */
int
idx
=
find_idx_in_nid_list
(
nid
,
cfg
->
hp_pins
,
cfg
->
hp_outs
);
if
(
idx
>=
0
)
*
indexp
=
idx
;
sfx
=
""
;
}
}
snprintf
(
label
,
maxlen
,
"%s%s%s"
,
pfx
,
name
,
sfx
);
return
1
;
}
/**
* snd_hda_get_pin_label - Get a label for the given I/O pin
*
* Get a label for the given pin. This function works for both input and
* output pins. When @cfg is given as non-NULL, the function tries to get
* an optimized label using hda_get_autocfg_input_label().
*
* This function tries to give a unique label string for the pin as much as
* possible. For example, when the multiple line-outs are present, it adds
* the channel suffix like "Front", "Surround", etc (only when @cfg is given).
* If no unique name with a suffix is available and @indexp is non-NULL, the
* index number is stored in the pointer.
*/
int
snd_hda_get_pin_label
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
const
struct
auto_pin_cfg
*
cfg
,
char
*
label
,
int
maxlen
,
int
*
indexp
)
{
unsigned
int
def_conf
=
snd_hda_codec_get_pincfg
(
codec
,
nid
);
const
char
*
name
=
NULL
;
int
i
;
if
(
indexp
)
*
indexp
=
0
;
if
(
get_defcfg_connect
(
def_conf
)
==
AC_JACK_PORT_NONE
)
return
0
;
switch
(
get_defcfg_device
(
def_conf
))
{
case
AC_JACK_LINE_OUT
:
return
fill_audio_out_name
(
codec
,
nid
,
cfg
,
"Line Out"
,
label
,
maxlen
,
indexp
);
case
AC_JACK_SPEAKER
:
return
fill_audio_out_name
(
codec
,
nid
,
cfg
,
"Speaker"
,
label
,
maxlen
,
indexp
);
case
AC_JACK_HP_OUT
:
return
fill_audio_out_name
(
codec
,
nid
,
cfg
,
"Headphone"
,
label
,
maxlen
,
indexp
);
case
AC_JACK_SPDIF_OUT
:
case
AC_JACK_DIG_OTHER_OUT
:
if
(
get_defcfg_location
(
def_conf
)
==
AC_JACK_LOC_HDMI
)
name
=
"HDMI"
;
else
name
=
"SPDIF"
;
if
(
cfg
&&
indexp
)
{
i
=
find_idx_in_nid_list
(
nid
,
cfg
->
dig_out_pins
,
cfg
->
dig_outs
);
if
(
i
>=
0
)
*
indexp
=
i
;
}
break
;
default:
if
(
cfg
)
{
for
(
i
=
0
;
i
<
cfg
->
num_inputs
;
i
++
)
{
if
(
cfg
->
inputs
[
i
].
pin
!=
nid
)
continue
;
name
=
hda_get_autocfg_input_label
(
codec
,
cfg
,
i
);
if
(
name
)
break
;
}
}
if
(
!
name
)
name
=
hda_get_input_pin_label
(
codec
,
nid
,
true
);
break
;
}
if
(
!
name
)
return
0
;
strlcpy
(
label
,
name
,
maxlen
);
return
1
;
}
EXPORT_SYMBOL_HDA
(
snd_hda_get_pin_label
);
int
snd_hda_gen_add_verbs
(
struct
hda_gen_spec
*
spec
,
const
struct
hda_verb
*
list
)
{
const
struct
hda_verb
**
v
;
snd_array_init
(
&
spec
->
verbs
,
sizeof
(
struct
hda_verb
*
),
8
);
v
=
snd_array_new
(
&
spec
->
verbs
);
if
(
!
v
)
return
-
ENOMEM
;
*
v
=
list
;
return
0
;
}
EXPORT_SYMBOL_HDA
(
snd_hda_gen_add_verbs
);
void
snd_hda_gen_apply_verbs
(
struct
hda_codec
*
codec
)
{
struct
hda_gen_spec
*
spec
=
codec
->
spec
;
int
i
;
for
(
i
=
0
;
i
<
spec
->
verbs
.
used
;
i
++
)
{
struct
hda_verb
**
v
=
snd_array_elem
(
&
spec
->
verbs
,
i
);
snd_hda_sequence_write
(
codec
,
*
v
);
}
}
EXPORT_SYMBOL_HDA
(
snd_hda_gen_apply_verbs
);
void
snd_hda_apply_pincfgs
(
struct
hda_codec
*
codec
,
const
struct
hda_pintbl
*
cfg
)
{
for
(;
cfg
->
nid
;
cfg
++
)
snd_hda_codec_set_pincfg
(
codec
,
cfg
->
nid
,
cfg
->
val
);
}
EXPORT_SYMBOL_HDA
(
snd_hda_apply_pincfgs
);
void
snd_hda_apply_fixup
(
struct
hda_codec
*
codec
,
int
action
)
{
struct
hda_gen_spec
*
spec
=
codec
->
spec
;
int
id
=
spec
->
fixup_id
;
#ifdef CONFIG_SND_DEBUG_VERBOSE
const
char
*
modelname
=
spec
->
fixup_name
;
#endif
int
depth
=
0
;
if
(
!
spec
->
fixup_list
)
return
;
while
(
id
>=
0
)
{
const
struct
hda_fixup
*
fix
=
spec
->
fixup_list
+
id
;
switch
(
fix
->
type
)
{
case
HDA_FIXUP_PINS
:
if
(
action
!=
HDA_FIXUP_ACT_PRE_PROBE
||
!
fix
->
v
.
pins
)
break
;
snd_printdd
(
KERN_INFO
SFX
"%s: Apply pincfg for %s
\n
"
,
codec
->
chip_name
,
modelname
);
snd_hda_apply_pincfgs
(
codec
,
fix
->
v
.
pins
);
break
;
case
HDA_FIXUP_VERBS
:
if
(
action
!=
HDA_FIXUP_ACT_PROBE
||
!
fix
->
v
.
verbs
)
break
;
snd_printdd
(
KERN_INFO
SFX
"%s: Apply fix-verbs for %s
\n
"
,
codec
->
chip_name
,
modelname
);
snd_hda_gen_add_verbs
(
codec
->
spec
,
fix
->
v
.
verbs
);
break
;
case
HDA_FIXUP_FUNC
:
if
(
!
fix
->
v
.
func
)
break
;
snd_printdd
(
KERN_INFO
SFX
"%s: Apply fix-func for %s
\n
"
,
codec
->
chip_name
,
modelname
);
fix
->
v
.
func
(
codec
,
fix
,
action
);
break
;
default:
snd_printk
(
KERN_ERR
SFX
"%s: Invalid fixup type %d
\n
"
,
codec
->
chip_name
,
fix
->
type
);
break
;
}
if
(
!
fix
->
chained
)
break
;
if
(
++
depth
>
10
)
break
;
id
=
fix
->
chain_id
;
}
}
EXPORT_SYMBOL_HDA
(
snd_hda_apply_fixup
);
void
snd_hda_pick_fixup
(
struct
hda_codec
*
codec
,
const
struct
hda_model_fixup
*
models
,
const
struct
snd_pci_quirk
*
quirk
,
const
struct
hda_fixup
*
fixlist
)
{
struct
hda_gen_spec
*
spec
=
codec
->
spec
;
const
struct
snd_pci_quirk
*
q
;
int
id
=
-
1
;
const
char
*
name
=
NULL
;
/* when model=nofixup is given, don't pick up any fixups */
if
(
codec
->
modelname
&&
!
strcmp
(
codec
->
modelname
,
"nofixup"
))
{
spec
->
fixup_list
=
NULL
;
spec
->
fixup_id
=
-
1
;
return
;
}
if
(
codec
->
modelname
&&
models
)
{
while
(
models
->
name
)
{
if
(
!
strcmp
(
codec
->
modelname
,
models
->
name
))
{
id
=
models
->
id
;
name
=
models
->
name
;
break
;
}
models
++
;
}
}
if
(
id
<
0
)
{
q
=
snd_pci_quirk_lookup
(
codec
->
bus
->
pci
,
quirk
);
if
(
q
)
{
id
=
q
->
value
;
#ifdef CONFIG_SND_DEBUG_VERBOSE
name
=
q
->
name
;
#endif
}
}
if
(
id
<
0
)
{
for
(
q
=
quirk
;
q
->
subvendor
;
q
++
)
{
unsigned
int
vendorid
=
q
->
subdevice
|
(
q
->
subvendor
<<
16
);
if
(
vendorid
==
codec
->
subsystem_id
)
{
id
=
q
->
value
;
#ifdef CONFIG_SND_DEBUG_VERBOSE
name
=
q
->
name
;
#endif
break
;
}
}
}
spec
->
fixup_id
=
id
;
if
(
id
>=
0
)
{
spec
->
fixup_list
=
fixlist
;
spec
->
fixup_name
=
name
;
}
}
EXPORT_SYMBOL_HDA
(
snd_hda_pick_fixup
);
sound/pci/hda/hda_auto_parser.h
0 → 100644
浏览文件 @
6de15b2a
/*
* BIOS auto-parser helper functions for HD-audio
*
* Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
*
* This driver is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __SOUND_HDA_AUTO_PARSER_H
#define __SOUND_HDA_AUTO_PARSER_H
/*
* Helper for automatic pin configuration
*/
enum
{
AUTO_PIN_MIC
,
AUTO_PIN_LINE_IN
,
AUTO_PIN_CD
,
AUTO_PIN_AUX
,
AUTO_PIN_LAST
};
enum
{
AUTO_PIN_LINE_OUT
,
AUTO_PIN_SPEAKER_OUT
,
AUTO_PIN_HP_OUT
};
#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS
#define AUTO_CFG_MAX_INS 8
struct
auto_pin_cfg_item
{
hda_nid_t
pin
;
int
type
;
};
struct
auto_pin_cfg
;
const
char
*
hda_get_autocfg_input_label
(
struct
hda_codec
*
codec
,
const
struct
auto_pin_cfg
*
cfg
,
int
input
);
int
snd_hda_get_pin_label
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
const
struct
auto_pin_cfg
*
cfg
,
char
*
label
,
int
maxlen
,
int
*
indexp
);
enum
{
INPUT_PIN_ATTR_UNUSED
,
/* pin not connected */
INPUT_PIN_ATTR_INT
,
/* internal mic/line-in */
INPUT_PIN_ATTR_DOCK
,
/* docking mic/line-in */
INPUT_PIN_ATTR_NORMAL
,
/* mic/line-in jack */
INPUT_PIN_ATTR_FRONT
,
/* mic/line-in jack in front */
INPUT_PIN_ATTR_REAR
,
/* mic/line-in jack in rear */
};
int
snd_hda_get_input_pin_attr
(
unsigned
int
def_conf
);
struct
auto_pin_cfg
{
int
line_outs
;
/* sorted in the order of Front/Surr/CLFE/Side */
hda_nid_t
line_out_pins
[
AUTO_CFG_MAX_OUTS
];
int
speaker_outs
;
hda_nid_t
speaker_pins
[
AUTO_CFG_MAX_OUTS
];
int
hp_outs
;
int
line_out_type
;
/* AUTO_PIN_XXX_OUT */
hda_nid_t
hp_pins
[
AUTO_CFG_MAX_OUTS
];
int
num_inputs
;
struct
auto_pin_cfg_item
inputs
[
AUTO_CFG_MAX_INS
];
int
dig_outs
;
hda_nid_t
dig_out_pins
[
2
];
hda_nid_t
dig_in_pin
;
hda_nid_t
mono_out_pin
;
int
dig_out_type
[
2
];
/* HDA_PCM_TYPE_XXX */
int
dig_in_type
;
/* HDA_PCM_TYPE_XXX */
};
/* bit-flags for snd_hda_parse_pin_def_config() behavior */
#define HDA_PINCFG_NO_HP_FIXUP (1 << 0)
/* no HP-split */
#define HDA_PINCFG_NO_LO_FIXUP (1 << 1)
/* don't take other outs as LO */
int
snd_hda_parse_pin_defcfg
(
struct
hda_codec
*
codec
,
struct
auto_pin_cfg
*
cfg
,
const
hda_nid_t
*
ignore_nids
,
unsigned
int
cond_flags
);
/* older function */
#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
/*
*/
struct
hda_gen_spec
{
/* fix-up list */
int
fixup_id
;
const
struct
hda_fixup
*
fixup_list
;
const
char
*
fixup_name
;
/* additional init verbs */
struct
snd_array
verbs
;
};
/*
* Fix-up pin default configurations and add default verbs
*/
struct
hda_pintbl
{
hda_nid_t
nid
;
u32
val
;
};
struct
hda_model_fixup
{
const
int
id
;
const
char
*
name
;
};
struct
hda_fixup
{
int
type
;
bool
chained
;
int
chain_id
;
union
{
const
struct
hda_pintbl
*
pins
;
const
struct
hda_verb
*
verbs
;
void
(
*
func
)(
struct
hda_codec
*
codec
,
const
struct
hda_fixup
*
fix
,
int
action
);
}
v
;
};
/* fixup types */
enum
{
HDA_FIXUP_INVALID
,
HDA_FIXUP_PINS
,
HDA_FIXUP_VERBS
,
HDA_FIXUP_FUNC
,
};
/* fixup action definitions */
enum
{
HDA_FIXUP_ACT_PRE_PROBE
,
HDA_FIXUP_ACT_PROBE
,
HDA_FIXUP_ACT_INIT
,
HDA_FIXUP_ACT_BUILD
,
};
int
snd_hda_gen_add_verbs
(
struct
hda_gen_spec
*
spec
,
const
struct
hda_verb
*
list
);
void
snd_hda_gen_apply_verbs
(
struct
hda_codec
*
codec
);
void
snd_hda_apply_pincfgs
(
struct
hda_codec
*
codec
,
const
struct
hda_pintbl
*
cfg
);
void
snd_hda_apply_fixup
(
struct
hda_codec
*
codec
,
int
action
);
void
snd_hda_pick_fixup
(
struct
hda_codec
*
codec
,
const
struct
hda_model_fixup
*
models
,
const
struct
snd_pci_quirk
*
quirk
,
const
struct
hda_fixup
*
fixlist
);
#endif
/* __SOUND_HDA_AUTO_PARSER_H */
sound/pci/hda/hda_codec.c
浏览文件 @
6de15b2a
...
...
@@ -334,78 +334,67 @@ static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid)
return
NULL
;
}
/* read the connection and add to the cache */
static
int
read_and_add_raw_conns
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
hda_nid_t
list
[
HDA_MAX_CONNECTIONS
];
int
len
;
len
=
snd_hda_get_raw_connections
(
codec
,
nid
,
list
,
ARRAY_SIZE
(
list
));
if
(
len
<
0
)
return
len
;
return
snd_hda_override_conn_list
(
codec
,
nid
,
len
,
list
);
}
/**
* snd_hda_get_conn
_list - get
connection list
* snd_hda_get_conn
ections - copy
connection list
* @codec: the HDA codec
* @nid: NID to parse
* @listp: the pointer to store NID list
* @conn_list: connection list array; when NULL, checks only the size
* @max_conns: max. number of connections to store
*
* Parses the connection list of the given widget and stores the list
* of NIDs.
*
* Returns the number of connections, or a negative error code.
*/
int
snd_hda_get_conn
_list
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
const
hda_nid_t
**
listp
)
int
snd_hda_get_conn
ections
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
hda_nid_t
*
conn_list
,
int
max_conns
)
{
struct
snd_array
*
array
=
&
codec
->
conn_lists
;
int
len
,
err
;
hda_nid_t
list
[
HDA_MAX_CONNECTIONS
];
int
len
;
hda_nid_t
*
p
;
bool
added
=
false
;
again:
mutex_lock
(
&
codec
->
hash_mutex
);
len
=
-
1
;
/* if the connection-list is already cached, read it */
p
=
lookup_conn_list
(
array
,
nid
);
if
(
p
)
{
if
(
listp
)
*
listp
=
p
+
2
;
return
p
[
1
];
len
=
p
[
1
];
if
(
conn_list
&&
len
>
max_conns
)
{
snd_printk
(
KERN_ERR
"hda_codec: "
"Too many connections %d for NID 0x%x
\n
"
,
len
,
nid
);
mutex_unlock
(
&
codec
->
hash_mutex
);
return
-
EINVAL
;
}
if
(
conn_list
&&
len
)
memcpy
(
conn_list
,
p
+
2
,
len
*
sizeof
(
hda_nid_t
));
}
mutex_unlock
(
&
codec
->
hash_mutex
);
if
(
len
>=
0
)
return
len
;
if
(
snd_BUG_ON
(
added
))
return
-
EINVAL
;
/* read the connection and add to the cache */
len
=
snd_hda_get_raw_connections
(
codec
,
nid
,
list
,
HDA_MAX_CONNECTIONS
);
len
=
read_and_add_raw_conns
(
codec
,
nid
);
if
(
len
<
0
)
return
len
;
err
=
snd_hda_override_conn_list
(
codec
,
nid
,
len
,
list
);
if
(
err
<
0
)
return
err
;
added
=
true
;
goto
again
;
}
EXPORT_SYMBOL_HDA
(
snd_hda_get_conn_list
);
/**
* snd_hda_get_connections - copy connection list
* @codec: the HDA codec
* @nid: NID to parse
* @conn_list: connection list array
* @max_conns: max. number of connections to store
*
* Parses the connection list of the given widget and stores the list
* of NIDs.
*
* Returns the number of connections, or a negative error code.
*/
int
snd_hda_get_connections
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
hda_nid_t
*
conn_list
,
int
max_conns
)
{
const
hda_nid_t
*
list
;
int
len
=
snd_hda_get_conn_list
(
codec
,
nid
,
&
list
);
if
(
len
<=
0
)
return
len
;
if
(
len
>
max_conns
)
{
snd_printk
(
KERN_ERR
"hda_codec: "
"Too many connections %d for NID 0x%x
\n
"
,
len
,
nid
);
return
-
EINVAL
;
}
memcpy
(
conn_list
,
list
,
len
*
sizeof
(
hda_nid_t
));
return
len
;
}
EXPORT_SYMBOL_HDA
(
snd_hda_get_connections
);
/**
...
...
@@ -543,6 +532,7 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
hda_nid_t
*
p
;
int
i
,
old_used
;
mutex_lock
(
&
codec
->
hash_mutex
);
p
=
lookup_conn_list
(
array
,
nid
);
if
(
p
)
*
p
=
-
1
;
/* invalidate the old entry */
...
...
@@ -553,10 +543,12 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
for
(
i
=
0
;
i
<
len
;
i
++
)
if
(
!
add_conn_list
(
array
,
list
[
i
]))
goto
error_add
;
mutex_unlock
(
&
codec
->
hash_mutex
);
return
0
;
error_add:
array
->
used
=
old_used
;
mutex_unlock
(
&
codec
->
hash_mutex
);
return
-
ENOMEM
;
}
EXPORT_SYMBOL_HDA
(
snd_hda_override_conn_list
);
...
...
@@ -1255,6 +1247,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
codec
->
addr
=
codec_addr
;
mutex_init
(
&
codec
->
spdif_mutex
);
mutex_init
(
&
codec
->
control_mutex
);
mutex_init
(
&
codec
->
hash_mutex
);
init_hda_cache
(
&
codec
->
amp_cache
,
sizeof
(
struct
hda_amp_info
));
init_hda_cache
(
&
codec
->
cmd_cache
,
sizeof
(
struct
hda_cache_head
));
snd_array_init
(
&
codec
->
mixers
,
sizeof
(
struct
hda_nid_item
),
32
);
...
...
@@ -1264,15 +1257,9 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
snd_array_init
(
&
codec
->
cvt_setups
,
sizeof
(
struct
hda_cvt_setup
),
8
);
snd_array_init
(
&
codec
->
conn_lists
,
sizeof
(
hda_nid_t
),
64
);
snd_array_init
(
&
codec
->
spdif_out
,
sizeof
(
struct
hda_spdif_out
),
16
);
if
(
codec
->
bus
->
modelname
)
{
codec
->
modelname
=
kstrdup
(
codec
->
bus
->
modelname
,
GFP_KERNEL
);
if
(
!
codec
->
modelname
)
{
snd_hda_codec_free
(
codec
);
return
-
ENODEV
;
}
}
#ifdef CONFIG_SND_HDA_POWER_SAVE
spin_lock_init
(
&
codec
->
power_lock
);
INIT_DELAYED_WORK
(
&
codec
->
power_work
,
hda_power_work
);
/* snd_hda_codec_new() marks the codec as power-up, and leave it as is.
* the caller has to power down appropriatley after initialization
...
...
@@ -1281,6 +1268,14 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
hda_keep_power_on
(
codec
);
#endif
if
(
codec
->
bus
->
modelname
)
{
codec
->
modelname
=
kstrdup
(
codec
->
bus
->
modelname
,
GFP_KERNEL
);
if
(
!
codec
->
modelname
)
{
snd_hda_codec_free
(
codec
);
return
-
ENODEV
;
}
}
list_add_tail
(
&
codec
->
list
,
&
bus
->
codec_list
);
bus
->
caddr_tbl
[
codec_addr
]
=
codec
;
...
...
@@ -1603,6 +1598,60 @@ get_alloc_amp_hash(struct hda_codec *codec, u32 key)
return
(
struct
hda_amp_info
*
)
get_alloc_hash
(
&
codec
->
amp_cache
,
key
);
}
/* overwrite the value with the key in the caps hash */
static
int
write_caps_hash
(
struct
hda_codec
*
codec
,
u32
key
,
unsigned
int
val
)
{
struct
hda_amp_info
*
info
;
mutex_lock
(
&
codec
->
hash_mutex
);
info
=
get_alloc_amp_hash
(
codec
,
key
);
if
(
!
info
)
{
mutex_unlock
(
&
codec
->
hash_mutex
);
return
-
EINVAL
;
}
info
->
amp_caps
=
val
;
info
->
head
.
val
|=
INFO_AMP_CAPS
;
mutex_unlock
(
&
codec
->
hash_mutex
);
return
0
;
}
/* query the value from the caps hash; if not found, fetch the current
* value from the given function and store in the hash
*/
static
unsigned
int
query_caps_hash
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
dir
,
u32
key
,
unsigned
int
(
*
func
)(
struct
hda_codec
*
,
hda_nid_t
,
int
))
{
struct
hda_amp_info
*
info
;
unsigned
int
val
;
mutex_lock
(
&
codec
->
hash_mutex
);
info
=
get_alloc_amp_hash
(
codec
,
key
);
if
(
!
info
)
{
mutex_unlock
(
&
codec
->
hash_mutex
);
return
0
;
}
if
(
!
(
info
->
head
.
val
&
INFO_AMP_CAPS
))
{
mutex_unlock
(
&
codec
->
hash_mutex
);
/* for reentrance */
val
=
func
(
codec
,
nid
,
dir
);
write_caps_hash
(
codec
,
key
,
val
);
}
else
{
val
=
info
->
amp_caps
;
mutex_unlock
(
&
codec
->
hash_mutex
);
}
return
val
;
}
static
unsigned
int
read_amp_cap
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
direction
)
{
if
(
!
(
get_wcaps
(
codec
,
nid
)
&
AC_WCAP_AMP_OVRD
))
nid
=
codec
->
afg
;
return
snd_hda_param_read
(
codec
,
nid
,
direction
==
HDA_OUTPUT
?
AC_PAR_AMP_OUT_CAP
:
AC_PAR_AMP_IN_CAP
);
}
/**
* query_amp_caps - query AMP capabilities
* @codec: the HD-auio codec
...
...
@@ -1617,22 +1666,9 @@ get_alloc_amp_hash(struct hda_codec *codec, u32 key)
*/
u32
query_amp_caps
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
direction
)
{
struct
hda_amp_info
*
info
;
info
=
get_alloc_amp_hash
(
codec
,
HDA_HASH_KEY
(
nid
,
direction
,
0
));
if
(
!
info
)
return
0
;
if
(
!
(
info
->
head
.
val
&
INFO_AMP_CAPS
))
{
if
(
!
(
get_wcaps
(
codec
,
nid
)
&
AC_WCAP_AMP_OVRD
))
nid
=
codec
->
afg
;
info
->
amp_caps
=
snd_hda_param_read
(
codec
,
nid
,
direction
==
HDA_OUTPUT
?
AC_PAR_AMP_OUT_CAP
:
AC_PAR_AMP_IN_CAP
);
if
(
info
->
amp_caps
)
info
->
head
.
val
|=
INFO_AMP_CAPS
;
}
return
info
->
amp_caps
;
return
query_caps_hash
(
codec
,
nid
,
direction
,
HDA_HASH_KEY
(
nid
,
direction
,
0
),
read_amp_cap
);
}
EXPORT_SYMBOL_HDA
(
query_amp_caps
);
...
...
@@ -1652,34 +1688,12 @@ EXPORT_SYMBOL_HDA(query_amp_caps);
int
snd_hda_override_amp_caps
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
dir
,
unsigned
int
caps
)
{
struct
hda_amp_info
*
info
;
info
=
get_alloc_amp_hash
(
codec
,
HDA_HASH_KEY
(
nid
,
dir
,
0
));
if
(
!
info
)
return
-
EINVAL
;
info
->
amp_caps
=
caps
;
info
->
head
.
val
|=
INFO_AMP_CAPS
;
return
0
;
return
write_caps_hash
(
codec
,
HDA_HASH_KEY
(
nid
,
dir
,
0
),
caps
);
}
EXPORT_SYMBOL_HDA
(
snd_hda_override_amp_caps
);
static
unsigned
int
query_caps_hash
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
u32
key
,
unsigned
int
(
*
func
)(
struct
hda_codec
*
,
hda_nid_t
))
{
struct
hda_amp_info
*
info
;
info
=
get_alloc_amp_hash
(
codec
,
key
);
if
(
!
info
)
return
0
;
if
(
!
info
->
head
.
val
)
{
info
->
head
.
val
|=
INFO_AMP_CAPS
;
info
->
amp_caps
=
func
(
codec
,
nid
);
}
return
info
->
amp_caps
;
}
static
unsigned
int
read_pin_cap
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
static
unsigned
int
read_pin_cap
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
dir
)
{
return
snd_hda_param_read
(
codec
,
nid
,
AC_PAR_PIN_CAP
);
}
...
...
@@ -1697,7 +1711,7 @@ static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid)
*/
u32
snd_hda_query_pin_caps
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
return
query_caps_hash
(
codec
,
nid
,
HDA_HASH_PINCAP_KEY
(
nid
),
return
query_caps_hash
(
codec
,
nid
,
0
,
HDA_HASH_PINCAP_KEY
(
nid
),
read_pin_cap
);
}
EXPORT_SYMBOL_HDA
(
snd_hda_query_pin_caps
);
...
...
@@ -1715,41 +1729,47 @@ EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
int
snd_hda_override_pin_caps
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
unsigned
int
caps
)
{
struct
hda_amp_info
*
info
;
info
=
get_alloc_amp_hash
(
codec
,
HDA_HASH_PINCAP_KEY
(
nid
));
if
(
!
info
)
return
-
ENOMEM
;
info
->
amp_caps
=
caps
;
info
->
head
.
val
|=
INFO_AMP_CAPS
;
return
0
;
return
write_caps_hash
(
codec
,
HDA_HASH_PINCAP_KEY
(
nid
),
caps
);
}
EXPORT_SYMBOL_HDA
(
snd_hda_override_pin_caps
);
/*
* read the current volume to info
* if the cache exists, read the cache value.
/* read or sync the hash value with the current value;
* call within hash_mutex
*/
static
unsigned
int
get_vol_mute
(
struct
hda_codec
*
codec
,
struct
hda_amp_info
*
info
,
hda_nid_t
nid
,
int
ch
,
int
direction
,
int
index
)
static
struct
hda_amp_info
*
update_amp_hash
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
ch
,
int
direction
,
int
index
)
{
u32
val
,
parm
;
if
(
info
->
head
.
val
&
INFO_AMP_VOL
(
ch
))
return
info
->
vol
[
ch
];
struct
hda_amp_info
*
info
;
unsigned
int
parm
,
val
=
0
;
bool
val_read
=
false
;
parm
=
ch
?
AC_AMP_GET_RIGHT
:
AC_AMP_GET_LEFT
;
parm
|=
direction
==
HDA_OUTPUT
?
AC_AMP_GET_OUTPUT
:
AC_AMP_GET_INPUT
;
parm
|=
index
;
val
=
snd_hda_codec_read
(
codec
,
nid
,
0
,
retry:
info
=
get_alloc_amp_hash
(
codec
,
HDA_HASH_KEY
(
nid
,
direction
,
index
));
if
(
!
info
)
return
NULL
;
if
(
!
(
info
->
head
.
val
&
INFO_AMP_VOL
(
ch
)))
{
if
(
!
val_read
)
{
mutex_unlock
(
&
codec
->
hash_mutex
);
parm
=
ch
?
AC_AMP_GET_RIGHT
:
AC_AMP_GET_LEFT
;
parm
|=
direction
==
HDA_OUTPUT
?
AC_AMP_GET_OUTPUT
:
AC_AMP_GET_INPUT
;
parm
|=
index
;
val
=
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_AMP_GAIN_MUTE
,
parm
);
info
->
vol
[
ch
]
=
val
&
0xff
;
info
->
head
.
val
|=
INFO_AMP_VOL
(
ch
);
return
info
->
vol
[
ch
];
val
&=
0xff
;
val_read
=
true
;
mutex_lock
(
&
codec
->
hash_mutex
);
goto
retry
;
}
info
->
vol
[
ch
]
=
val
;
info
->
head
.
val
|=
INFO_AMP_VOL
(
ch
);
}
return
info
;
}
/*
* write the current volume in info to the h/w
and update the cache
* write the current volume in info to the h/w
*/
static
void
put_vol_mute
(
struct
hda_codec
*
codec
,
struct
hda_amp_info
*
info
,
hda_nid_t
nid
,
int
ch
,
int
direction
,
int
index
,
...
...
@@ -1766,7 +1786,6 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
else
parm
|=
val
;
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
parm
);
info
->
vol
[
ch
]
=
val
;
}
/**
...
...
@@ -1783,10 +1802,14 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
int
direction
,
int
index
)
{
struct
hda_amp_info
*
info
;
info
=
get_alloc_amp_hash
(
codec
,
HDA_HASH_KEY
(
nid
,
direction
,
index
));
if
(
!
info
)
return
0
;
return
get_vol_mute
(
codec
,
info
,
nid
,
ch
,
direction
,
index
);
unsigned
int
val
=
0
;
mutex_lock
(
&
codec
->
hash_mutex
);
info
=
update_amp_hash
(
codec
,
nid
,
ch
,
direction
,
index
);
if
(
info
)
val
=
info
->
vol
[
ch
];
mutex_unlock
(
&
codec
->
hash_mutex
);
return
val
;
}
EXPORT_SYMBOL_HDA
(
snd_hda_codec_amp_read
);
...
...
@@ -1808,15 +1831,23 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
{
struct
hda_amp_info
*
info
;
info
=
get_alloc_amp_hash
(
codec
,
HDA_HASH_KEY
(
nid
,
direction
,
idx
));
if
(
!
info
)
return
0
;
if
(
snd_BUG_ON
(
mask
&
~
0xff
))
mask
&=
0xff
;
val
&=
mask
;
val
|=
get_vol_mute
(
codec
,
info
,
nid
,
ch
,
direction
,
idx
)
&
~
mask
;
if
(
info
->
vol
[
ch
]
==
val
)
mutex_lock
(
&
codec
->
hash_mutex
);
info
=
update_amp_hash
(
codec
,
nid
,
ch
,
direction
,
idx
);
if
(
!
info
)
{
mutex_unlock
(
&
codec
->
hash_mutex
);
return
0
;
}
val
|=
info
->
vol
[
ch
]
&
~
mask
;
if
(
info
->
vol
[
ch
]
==
val
)
{
mutex_unlock
(
&
codec
->
hash_mutex
);
return
0
;
}
info
->
vol
[
ch
]
=
val
;
mutex_unlock
(
&
codec
->
hash_mutex
);
put_vol_mute
(
codec
,
info
,
nid
,
ch
,
direction
,
idx
,
val
);
return
1
;
}
...
...
@@ -2263,7 +2294,10 @@ int snd_hda_codec_reset(struct hda_codec *codec)
/* OK, let it free */
#ifdef CONFIG_SND_HDA_POWER_SAVE
cancel_delayed_work
(
&
codec
->
power_work
);
cancel_delayed_work_sync
(
&
codec
->
power_work
);
codec
->
power_on
=
0
;
codec
->
power_transition
=
0
;
codec
->
power_jiffies
=
jiffies
;
flush_workqueue
(
codec
->
bus
->
workq
);
#endif
snd_hda_ctls_clear
(
codec
);
...
...
@@ -2859,12 +2893,15 @@ static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol,
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
int
idx
=
kcontrol
->
private_value
;
struct
hda_spdif_out
*
spdif
=
snd_array_elem
(
&
codec
->
spdif_out
,
idx
)
;
struct
hda_spdif_out
*
spdif
;
mutex_lock
(
&
codec
->
spdif_mutex
);
spdif
=
snd_array_elem
(
&
codec
->
spdif_out
,
idx
);
ucontrol
->
value
.
iec958
.
status
[
0
]
=
spdif
->
status
&
0xff
;
ucontrol
->
value
.
iec958
.
status
[
1
]
=
(
spdif
->
status
>>
8
)
&
0xff
;
ucontrol
->
value
.
iec958
.
status
[
2
]
=
(
spdif
->
status
>>
16
)
&
0xff
;
ucontrol
->
value
.
iec958
.
status
[
3
]
=
(
spdif
->
status
>>
24
)
&
0xff
;
mutex_unlock
(
&
codec
->
spdif_mutex
);
return
0
;
}
...
...
@@ -2950,12 +2987,14 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
int
idx
=
kcontrol
->
private_value
;
struct
hda_spdif_out
*
spdif
=
snd_array_elem
(
&
codec
->
spdif_out
,
idx
)
;
hda_nid_t
nid
=
spdif
->
nid
;
struct
hda_spdif_out
*
spdif
;
hda_nid_t
nid
;
unsigned
short
val
;
int
change
;
mutex_lock
(
&
codec
->
spdif_mutex
);
spdif
=
snd_array_elem
(
&
codec
->
spdif_out
,
idx
);
nid
=
spdif
->
nid
;
spdif
->
status
=
ucontrol
->
value
.
iec958
.
status
[
0
]
|
((
unsigned
int
)
ucontrol
->
value
.
iec958
.
status
[
1
]
<<
8
)
|
((
unsigned
int
)
ucontrol
->
value
.
iec958
.
status
[
2
]
<<
16
)
|
...
...
@@ -2977,9 +3016,12 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol,
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
int
idx
=
kcontrol
->
private_value
;
struct
hda_spdif_out
*
spdif
=
snd_array_elem
(
&
codec
->
spdif_out
,
idx
)
;
struct
hda_spdif_out
*
spdif
;
mutex_lock
(
&
codec
->
spdif_mutex
);
spdif
=
snd_array_elem
(
&
codec
->
spdif_out
,
idx
);
ucontrol
->
value
.
integer
.
value
[
0
]
=
spdif
->
ctls
&
AC_DIG1_ENABLE
;
mutex_unlock
(
&
codec
->
spdif_mutex
);
return
0
;
}
...
...
@@ -2999,12 +3041,14 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
int
idx
=
kcontrol
->
private_value
;
struct
hda_spdif_out
*
spdif
=
snd_array_elem
(
&
codec
->
spdif_out
,
idx
)
;
hda_nid_t
nid
=
spdif
->
nid
;
struct
hda_spdif_out
*
spdif
;
hda_nid_t
nid
;
unsigned
short
val
;
int
change
;
mutex_lock
(
&
codec
->
spdif_mutex
);
spdif
=
snd_array_elem
(
&
codec
->
spdif_out
,
idx
);
nid
=
spdif
->
nid
;
val
=
spdif
->
ctls
&
~
AC_DIG1_ENABLE
;
if
(
ucontrol
->
value
.
integer
.
value
[
0
])
val
|=
AC_DIG1_ENABLE
;
...
...
@@ -3092,6 +3136,9 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
}
EXPORT_SYMBOL_HDA
(
snd_hda_create_spdif_out_ctls
);
/* get the hda_spdif_out entry from the given NID
* call within spdif_mutex lock
*/
struct
hda_spdif_out
*
snd_hda_spdif_out_of_nid
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
...
...
@@ -3108,9 +3155,10 @@ EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid);
void
snd_hda_spdif_ctls_unassign
(
struct
hda_codec
*
codec
,
int
idx
)
{
struct
hda_spdif_out
*
spdif
=
snd_array_elem
(
&
codec
->
spdif_out
,
idx
)
;
struct
hda_spdif_out
*
spdif
;
mutex_lock
(
&
codec
->
spdif_mutex
);
spdif
=
snd_array_elem
(
&
codec
->
spdif_out
,
idx
);
spdif
->
nid
=
(
u16
)
-
1
;
mutex_unlock
(
&
codec
->
spdif_mutex
);
}
...
...
@@ -3118,10 +3166,11 @@ EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign);
void
snd_hda_spdif_ctls_assign
(
struct
hda_codec
*
codec
,
int
idx
,
hda_nid_t
nid
)
{
struct
hda_spdif_out
*
spdif
=
snd_array_elem
(
&
codec
->
spdif_out
,
idx
)
;
struct
hda_spdif_out
*
spdif
;
unsigned
short
val
;
mutex_lock
(
&
codec
->
spdif_mutex
);
spdif
=
snd_array_elem
(
&
codec
->
spdif_out
,
idx
);
if
(
spdif
->
nid
!=
nid
)
{
spdif
->
nid
=
nid
;
val
=
spdif
->
ctls
;
...
...
@@ -3486,11 +3535,14 @@ static void hda_call_codec_suspend(struct hda_codec *codec)
codec
->
afg
?
codec
->
afg
:
codec
->
mfg
,
AC_PWRST_D3
);
#ifdef CONFIG_SND_HDA_POWER_SAVE
snd_hda_update_power_acct
(
codec
);
cancel_delayed_work
(
&
codec
->
power_work
);
spin_lock
(
&
codec
->
power_lock
);
snd_hda_update_power_acct
(
codec
);
trace_hda_power_down
(
codec
);
codec
->
power_on
=
0
;
codec
->
power_transition
=
0
;
codec
->
power_jiffies
=
jiffies
;
spin_unlock
(
&
codec
->
power_lock
);
#endif
}
...
...
@@ -3499,6 +3551,10 @@ static void hda_call_codec_suspend(struct hda_codec *codec)
*/
static
void
hda_call_codec_resume
(
struct
hda_codec
*
codec
)
{
/* set as if powered on for avoiding re-entering the resume
* in the resume / power-save sequence
*/
hda_keep_power_on
(
codec
);
hda_set_power_state
(
codec
,
codec
->
afg
?
codec
->
afg
:
codec
->
mfg
,
AC_PWRST_D0
);
...
...
@@ -3514,6 +3570,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
snd_hda_codec_resume_amp
(
codec
);
snd_hda_codec_resume_cache
(
codec
);
}
snd_hda_power_down
(
codec
);
/* flag down before returning */
}
#endif
/* CONFIG_PM */
...
...
@@ -3665,7 +3722,8 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
}
EXPORT_SYMBOL_HDA
(
snd_hda_calc_stream_format
);
static
unsigned
int
get_pcm_param
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
static
unsigned
int
get_pcm_param
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
dir
)
{
unsigned
int
val
=
0
;
if
(
nid
!=
codec
->
afg
&&
...
...
@@ -3680,11 +3738,12 @@ static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid)
static
unsigned
int
query_pcm_param
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
return
query_caps_hash
(
codec
,
nid
,
HDA_HASH_PARPCM_KEY
(
nid
),
return
query_caps_hash
(
codec
,
nid
,
0
,
HDA_HASH_PARPCM_KEY
(
nid
),
get_pcm_param
);
}
static
unsigned
int
get_stream_param
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
static
unsigned
int
get_stream_param
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
dir
)
{
unsigned
int
streams
=
snd_hda_param_read
(
codec
,
nid
,
AC_PAR_STREAM
);
if
(
!
streams
||
streams
==
-
1
)
...
...
@@ -3696,7 +3755,7 @@ static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid)
static
unsigned
int
query_stream_param
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
return
query_caps_hash
(
codec
,
nid
,
HDA_HASH_PARSTR_KEY
(
nid
),
return
query_caps_hash
(
codec
,
nid
,
0
,
HDA_HASH_PARSTR_KEY
(
nid
),
get_stream_param
);
}
...
...
@@ -3775,11 +3834,13 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
bps
=
20
;
}
}
#if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */
if (streams & AC_SUPFMT_FLOAT32) {
formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
if (!bps)
bps = 32;
}
#endif
if
(
streams
==
AC_SUPFMT_AC3
)
{
/* should be exclusive */
/* temporary hack: we have still no proper support
...
...
@@ -4283,12 +4344,18 @@ static void hda_power_work(struct work_struct *work)
container_of
(
work
,
struct
hda_codec
,
power_work
.
work
);
struct
hda_bus
*
bus
=
codec
->
bus
;
spin_lock
(
&
codec
->
power_lock
);
if
(
codec
->
power_transition
>
0
)
{
/* during power-up sequence? */
spin_unlock
(
&
codec
->
power_lock
);
return
;
}
if
(
!
codec
->
power_on
||
codec
->
power_count
)
{
codec
->
power_transition
=
0
;
spin_unlock
(
&
codec
->
power_lock
);
return
;
}
spin_unlock
(
&
codec
->
power_lock
);
trace_hda_power_down
(
codec
);
hda_call_codec_suspend
(
codec
);
if
(
bus
->
ops
.
pm_notify
)
bus
->
ops
.
pm_notify
(
bus
);
...
...
@@ -4296,9 +4363,11 @@ static void hda_power_work(struct work_struct *work)
static
void
hda_keep_power_on
(
struct
hda_codec
*
codec
)
{
spin_lock
(
&
codec
->
power_lock
);
codec
->
power_count
++
;
codec
->
power_on
=
1
;
codec
->
power_jiffies
=
jiffies
;
spin_unlock
(
&
codec
->
power_lock
);
}
/* update the power on/off account with the current jiffies */
...
...
@@ -4323,19 +4392,31 @@ void snd_hda_power_up(struct hda_codec *codec)
{
struct
hda_bus
*
bus
=
codec
->
bus
;
spin_lock
(
&
codec
->
power_lock
);
codec
->
power_count
++
;
if
(
codec
->
power_on
||
codec
->
power_transition
)
if
(
codec
->
power_on
||
codec
->
power_transition
>
0
)
{
spin_unlock
(
&
codec
->
power_lock
);
return
;
}
spin_unlock
(
&
codec
->
power_lock
);
cancel_delayed_work_sync
(
&
codec
->
power_work
);
spin_lock
(
&
codec
->
power_lock
);
trace_hda_power_up
(
codec
);
snd_hda_update_power_acct
(
codec
);
codec
->
power_on
=
1
;
codec
->
power_jiffies
=
jiffies
;
codec
->
power_transition
=
1
;
/* avoid reentrance */
spin_unlock
(
&
codec
->
power_lock
);
if
(
bus
->
ops
.
pm_notify
)
bus
->
ops
.
pm_notify
(
bus
);
hda_call_codec_resume
(
codec
);
cancel_delayed_work
(
&
codec
->
power_work
);
spin_lock
(
&
codec
->
power_lock
);
codec
->
power_transition
=
0
;
spin_unlock
(
&
codec
->
power_lock
);
}
EXPORT_SYMBOL_HDA
(
snd_hda_power_up
);
...
...
@@ -4351,14 +4432,18 @@ EXPORT_SYMBOL_HDA(snd_hda_power_up);
*/
void
snd_hda_power_down
(
struct
hda_codec
*
codec
)
{
spin_lock
(
&
codec
->
power_lock
);
--
codec
->
power_count
;
if
(
!
codec
->
power_on
||
codec
->
power_count
||
codec
->
power_transition
)
if
(
!
codec
->
power_on
||
codec
->
power_count
||
codec
->
power_transition
)
{
spin_unlock
(
&
codec
->
power_lock
);
return
;
}
if
(
power_save
(
codec
))
{
codec
->
power_transition
=
1
;
/* avoid reentrance */
codec
->
power_transition
=
-
1
;
/* avoid reentrance */
queue_delayed_work
(
codec
->
bus
->
workq
,
&
codec
->
power_work
,
msecs_to_jiffies
(
power_save
(
codec
)
*
1000
));
}
spin_unlock
(
&
codec
->
power_lock
);
}
EXPORT_SYMBOL_HDA
(
snd_hda_power_down
);
...
...
@@ -4710,11 +4795,11 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
{
const
hda_nid_t
*
nids
=
mout
->
dac_nids
;
int
chs
=
substream
->
runtime
->
channels
;
struct
hda_spdif_out
*
spdif
=
snd_hda_spdif_out_of_nid
(
codec
,
mout
->
dig_out_nid
);
struct
hda_spdif_out
*
spdif
;
int
i
;
mutex_lock
(
&
codec
->
spdif_mutex
);
spdif
=
snd_hda_spdif_out_of_nid
(
codec
,
mout
->
dig_out_nid
);
if
(
mout
->
dig_out_nid
&&
mout
->
share_spdif
&&
mout
->
dig_out_used
!=
HDA_DIG_EXCLUSIVE
)
{
if
(
chs
==
2
&&
...
...
@@ -4795,601 +4880,58 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
}
EXPORT_SYMBOL_HDA
(
snd_hda_multi_out_analog_cleanup
);
/*
* Helper for automatic pin configuration
*/
static
int
is_in_nid_list
(
hda_nid_t
nid
,
const
hda_nid_t
*
list
)
{
for
(;
*
list
;
list
++
)
if
(
*
list
==
nid
)
return
1
;
return
0
;
}
/*
* Sort an associated group of pins according to their sequence numbers.
*/
static
void
sort_pins_by_sequence
(
hda_nid_t
*
pins
,
short
*
sequences
,
int
num_pins
)
{
int
i
,
j
;
short
seq
;
hda_nid_t
nid
;
for
(
i
=
0
;
i
<
num_pins
;
i
++
)
{
for
(
j
=
i
+
1
;
j
<
num_pins
;
j
++
)
{
if
(
sequences
[
i
]
>
sequences
[
j
])
{
seq
=
sequences
[
i
];
sequences
[
i
]
=
sequences
[
j
];
sequences
[
j
]
=
seq
;
nid
=
pins
[
i
];
pins
[
i
]
=
pins
[
j
];
pins
[
j
]
=
nid
;
}
}
}
}
/* add the found input-pin to the cfg->inputs[] table */
static
void
add_auto_cfg_input_pin
(
struct
auto_pin_cfg
*
cfg
,
hda_nid_t
nid
,
int
type
)
{
if
(
cfg
->
num_inputs
<
AUTO_CFG_MAX_INS
)
{
cfg
->
inputs
[
cfg
->
num_inputs
].
pin
=
nid
;
cfg
->
inputs
[
cfg
->
num_inputs
].
type
=
type
;
cfg
->
num_inputs
++
;
}
}
/* sort inputs in the order of AUTO_PIN_* type */
static
void
sort_autocfg_input_pins
(
struct
auto_pin_cfg
*
cfg
)
{
int
i
,
j
;
for
(
i
=
0
;
i
<
cfg
->
num_inputs
;
i
++
)
{
for
(
j
=
i
+
1
;
j
<
cfg
->
num_inputs
;
j
++
)
{
if
(
cfg
->
inputs
[
i
].
type
>
cfg
->
inputs
[
j
].
type
)
{
struct
auto_pin_cfg_item
tmp
;
tmp
=
cfg
->
inputs
[
i
];
cfg
->
inputs
[
i
]
=
cfg
->
inputs
[
j
];
cfg
->
inputs
[
j
]
=
tmp
;
}
}
}
}
/* Reorder the surround channels
* ALSA sequence is front/surr/clfe/side
* HDA sequence is:
* 4-ch: front/surr => OK as it is
* 6-ch: front/clfe/surr
* 8-ch: front/clfe/rear/side|fc
*/
static
void
reorder_outputs
(
unsigned
int
nums
,
hda_nid_t
*
pins
)
{
hda_nid_t
nid
;
switch
(
nums
)
{
case
3
:
case
4
:
nid
=
pins
[
1
];
pins
[
1
]
=
pins
[
2
];
pins
[
2
]
=
nid
;
break
;
}
}
/*
* Parse all pin widgets and store the useful pin nids to cfg
*
* The number of line-outs or any primary output is stored in line_outs,
* and the corresponding output pins are assigned to line_out_pins[],
* in the order of front, rear, CLFE, side, ...
*
* If more extra outputs (speaker and headphone) are found, the pins are
* assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack
* is detected, one of speaker of HP pins is assigned as the primary
* output, i.e. to line_out_pins[0]. So, line_outs is always positive
* if any analog output exists.
*
* The analog input pins are assigned to inputs array.
* The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
* respectively.
*/
int
snd_hda_parse_pin_defcfg
(
struct
hda_codec
*
codec
,
struct
auto_pin_cfg
*
cfg
,
const
hda_nid_t
*
ignore_nids
,
unsigned
int
cond_flags
)
{
hda_nid_t
nid
,
end_nid
;
short
seq
,
assoc_line_out
;
short
sequences_line_out
[
ARRAY_SIZE
(
cfg
->
line_out_pins
)];
short
sequences_speaker
[
ARRAY_SIZE
(
cfg
->
speaker_pins
)];
short
sequences_hp
[
ARRAY_SIZE
(
cfg
->
hp_pins
)];
int
i
;
memset
(
cfg
,
0
,
sizeof
(
*
cfg
));
memset
(
sequences_line_out
,
0
,
sizeof
(
sequences_line_out
));
memset
(
sequences_speaker
,
0
,
sizeof
(
sequences_speaker
));
memset
(
sequences_hp
,
0
,
sizeof
(
sequences_hp
));
assoc_line_out
=
0
;
codec
->
ignore_misc_bit
=
true
;
end_nid
=
codec
->
start_nid
+
codec
->
num_nodes
;
for
(
nid
=
codec
->
start_nid
;
nid
<
end_nid
;
nid
++
)
{
unsigned
int
wid_caps
=
get_wcaps
(
codec
,
nid
);
unsigned
int
wid_type
=
get_wcaps_type
(
wid_caps
);
unsigned
int
def_conf
;
short
assoc
,
loc
,
conn
,
dev
;
/* read all default configuration for pin complex */
if
(
wid_type
!=
AC_WID_PIN
)
continue
;
/* ignore the given nids (e.g. pc-beep returns error) */
if
(
ignore_nids
&&
is_in_nid_list
(
nid
,
ignore_nids
))
continue
;
def_conf
=
snd_hda_codec_get_pincfg
(
codec
,
nid
);
if
(
!
(
get_defcfg_misc
(
snd_hda_codec_get_pincfg
(
codec
,
nid
))
&
AC_DEFCFG_MISC_NO_PRESENCE
))
codec
->
ignore_misc_bit
=
false
;
conn
=
get_defcfg_connect
(
def_conf
);
if
(
conn
==
AC_JACK_PORT_NONE
)
continue
;
loc
=
get_defcfg_location
(
def_conf
);
dev
=
get_defcfg_device
(
def_conf
);
/* workaround for buggy BIOS setups */
if
(
dev
==
AC_JACK_LINE_OUT
)
{
if
(
conn
==
AC_JACK_PORT_FIXED
)
dev
=
AC_JACK_SPEAKER
;
}
switch
(
dev
)
{
case
AC_JACK_LINE_OUT
:
seq
=
get_defcfg_sequence
(
def_conf
);
assoc
=
get_defcfg_association
(
def_conf
);
if
(
!
(
wid_caps
&
AC_WCAP_STEREO
))
if
(
!
cfg
->
mono_out_pin
)
cfg
->
mono_out_pin
=
nid
;
if
(
!
assoc
)
continue
;
if
(
!
assoc_line_out
)
assoc_line_out
=
assoc
;
else
if
(
assoc_line_out
!=
assoc
)
continue
;
if
(
cfg
->
line_outs
>=
ARRAY_SIZE
(
cfg
->
line_out_pins
))
continue
;
cfg
->
line_out_pins
[
cfg
->
line_outs
]
=
nid
;
sequences_line_out
[
cfg
->
line_outs
]
=
seq
;
cfg
->
line_outs
++
;
break
;
case
AC_JACK_SPEAKER
:
seq
=
get_defcfg_sequence
(
def_conf
);
assoc
=
get_defcfg_association
(
def_conf
);
if
(
cfg
->
speaker_outs
>=
ARRAY_SIZE
(
cfg
->
speaker_pins
))
continue
;
cfg
->
speaker_pins
[
cfg
->
speaker_outs
]
=
nid
;
sequences_speaker
[
cfg
->
speaker_outs
]
=
(
assoc
<<
4
)
|
seq
;
cfg
->
speaker_outs
++
;
break
;
case
AC_JACK_HP_OUT
:
seq
=
get_defcfg_sequence
(
def_conf
);
assoc
=
get_defcfg_association
(
def_conf
);
if
(
cfg
->
hp_outs
>=
ARRAY_SIZE
(
cfg
->
hp_pins
))
continue
;
cfg
->
hp_pins
[
cfg
->
hp_outs
]
=
nid
;
sequences_hp
[
cfg
->
hp_outs
]
=
(
assoc
<<
4
)
|
seq
;
cfg
->
hp_outs
++
;
break
;
case
AC_JACK_MIC_IN
:
add_auto_cfg_input_pin
(
cfg
,
nid
,
AUTO_PIN_MIC
);
break
;
case
AC_JACK_LINE_IN
:
add_auto_cfg_input_pin
(
cfg
,
nid
,
AUTO_PIN_LINE_IN
);
break
;
case
AC_JACK_CD
:
add_auto_cfg_input_pin
(
cfg
,
nid
,
AUTO_PIN_CD
);
break
;
case
AC_JACK_AUX
:
add_auto_cfg_input_pin
(
cfg
,
nid
,
AUTO_PIN_AUX
);
break
;
case
AC_JACK_SPDIF_OUT
:
case
AC_JACK_DIG_OTHER_OUT
:
if
(
cfg
->
dig_outs
>=
ARRAY_SIZE
(
cfg
->
dig_out_pins
))
continue
;
cfg
->
dig_out_pins
[
cfg
->
dig_outs
]
=
nid
;
cfg
->
dig_out_type
[
cfg
->
dig_outs
]
=
(
loc
==
AC_JACK_LOC_HDMI
)
?
HDA_PCM_TYPE_HDMI
:
HDA_PCM_TYPE_SPDIF
;
cfg
->
dig_outs
++
;
break
;
case
AC_JACK_SPDIF_IN
:
case
AC_JACK_DIG_OTHER_IN
:
cfg
->
dig_in_pin
=
nid
;
if
(
loc
==
AC_JACK_LOC_HDMI
)
cfg
->
dig_in_type
=
HDA_PCM_TYPE_HDMI
;
else
cfg
->
dig_in_type
=
HDA_PCM_TYPE_SPDIF
;
break
;
}
}
/* FIX-UP:
* If no line-out is defined but multiple HPs are found,
* some of them might be the real line-outs.
*/
if
(
!
cfg
->
line_outs
&&
cfg
->
hp_outs
>
1
&&
!
(
cond_flags
&
HDA_PINCFG_NO_HP_FIXUP
))
{
int
i
=
0
;
while
(
i
<
cfg
->
hp_outs
)
{
/* The real HPs should have the sequence 0x0f */
if
((
sequences_hp
[
i
]
&
0x0f
)
==
0x0f
)
{
i
++
;
continue
;
}
/* Move it to the line-out table */
cfg
->
line_out_pins
[
cfg
->
line_outs
]
=
cfg
->
hp_pins
[
i
];
sequences_line_out
[
cfg
->
line_outs
]
=
sequences_hp
[
i
];
cfg
->
line_outs
++
;
cfg
->
hp_outs
--
;
memmove
(
cfg
->
hp_pins
+
i
,
cfg
->
hp_pins
+
i
+
1
,
sizeof
(
cfg
->
hp_pins
[
0
])
*
(
cfg
->
hp_outs
-
i
));
memmove
(
sequences_hp
+
i
,
sequences_hp
+
i
+
1
,
sizeof
(
sequences_hp
[
0
])
*
(
cfg
->
hp_outs
-
i
));
}
memset
(
cfg
->
hp_pins
+
cfg
->
hp_outs
,
0
,
sizeof
(
hda_nid_t
)
*
(
AUTO_CFG_MAX_OUTS
-
cfg
->
hp_outs
));
if
(
!
cfg
->
hp_outs
)
cfg
->
line_out_type
=
AUTO_PIN_HP_OUT
;
}
/* sort by sequence */
sort_pins_by_sequence
(
cfg
->
line_out_pins
,
sequences_line_out
,
cfg
->
line_outs
);
sort_pins_by_sequence
(
cfg
->
speaker_pins
,
sequences_speaker
,
cfg
->
speaker_outs
);
sort_pins_by_sequence
(
cfg
->
hp_pins
,
sequences_hp
,
cfg
->
hp_outs
);
/*
* FIX-UP: if no line-outs are detected, try to use speaker or HP pin
* as a primary output
*/
if
(
!
cfg
->
line_outs
&&
!
(
cond_flags
&
HDA_PINCFG_NO_LO_FIXUP
))
{
if
(
cfg
->
speaker_outs
)
{
cfg
->
line_outs
=
cfg
->
speaker_outs
;
memcpy
(
cfg
->
line_out_pins
,
cfg
->
speaker_pins
,
sizeof
(
cfg
->
speaker_pins
));
cfg
->
speaker_outs
=
0
;
memset
(
cfg
->
speaker_pins
,
0
,
sizeof
(
cfg
->
speaker_pins
));
cfg
->
line_out_type
=
AUTO_PIN_SPEAKER_OUT
;
}
else
if
(
cfg
->
hp_outs
)
{
cfg
->
line_outs
=
cfg
->
hp_outs
;
memcpy
(
cfg
->
line_out_pins
,
cfg
->
hp_pins
,
sizeof
(
cfg
->
hp_pins
));
cfg
->
hp_outs
=
0
;
memset
(
cfg
->
hp_pins
,
0
,
sizeof
(
cfg
->
hp_pins
));
cfg
->
line_out_type
=
AUTO_PIN_HP_OUT
;
}
}
reorder_outputs
(
cfg
->
line_outs
,
cfg
->
line_out_pins
);
reorder_outputs
(
cfg
->
hp_outs
,
cfg
->
hp_pins
);
reorder_outputs
(
cfg
->
speaker_outs
,
cfg
->
speaker_pins
);
sort_autocfg_input_pins
(
cfg
);
/*
* debug prints of the parsed results
*/
snd_printd
(
"autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s
\n
"
,
cfg
->
line_outs
,
cfg
->
line_out_pins
[
0
],
cfg
->
line_out_pins
[
1
],
cfg
->
line_out_pins
[
2
],
cfg
->
line_out_pins
[
3
],
cfg
->
line_out_pins
[
4
],
cfg
->
line_out_type
==
AUTO_PIN_HP_OUT
?
"hp"
:
(
cfg
->
line_out_type
==
AUTO_PIN_SPEAKER_OUT
?
"speaker"
:
"line"
));
snd_printd
(
" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)
\n
"
,
cfg
->
speaker_outs
,
cfg
->
speaker_pins
[
0
],
cfg
->
speaker_pins
[
1
],
cfg
->
speaker_pins
[
2
],
cfg
->
speaker_pins
[
3
],
cfg
->
speaker_pins
[
4
]);
snd_printd
(
" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)
\n
"
,
cfg
->
hp_outs
,
cfg
->
hp_pins
[
0
],
cfg
->
hp_pins
[
1
],
cfg
->
hp_pins
[
2
],
cfg
->
hp_pins
[
3
],
cfg
->
hp_pins
[
4
]);
snd_printd
(
" mono: mono_out=0x%x
\n
"
,
cfg
->
mono_out_pin
);
if
(
cfg
->
dig_outs
)
snd_printd
(
" dig-out=0x%x/0x%x
\n
"
,
cfg
->
dig_out_pins
[
0
],
cfg
->
dig_out_pins
[
1
]);
snd_printd
(
" inputs:"
);
for
(
i
=
0
;
i
<
cfg
->
num_inputs
;
i
++
)
{
snd_printd
(
" %s=0x%x"
,
hda_get_autocfg_input_label
(
codec
,
cfg
,
i
),
cfg
->
inputs
[
i
].
pin
);
}
snd_printd
(
"
\n
"
);
if
(
cfg
->
dig_in_pin
)
snd_printd
(
" dig-in=0x%x
\n
"
,
cfg
->
dig_in_pin
);
return
0
;
}
EXPORT_SYMBOL_HDA
(
snd_hda_parse_pin_defcfg
);
int
snd_hda_get_input_pin_attr
(
unsigned
int
def_conf
)
{
unsigned
int
loc
=
get_defcfg_location
(
def_conf
);
unsigned
int
conn
=
get_defcfg_connect
(
def_conf
);
if
(
conn
==
AC_JACK_PORT_NONE
)
return
INPUT_PIN_ATTR_UNUSED
;
/* Windows may claim the internal mic to be BOTH, too */
if
(
conn
==
AC_JACK_PORT_FIXED
||
conn
==
AC_JACK_PORT_BOTH
)
return
INPUT_PIN_ATTR_INT
;
if
((
loc
&
0x30
)
==
AC_JACK_LOC_INTERNAL
)
return
INPUT_PIN_ATTR_INT
;
if
((
loc
&
0x30
)
==
AC_JACK_LOC_SEPARATE
)
return
INPUT_PIN_ATTR_DOCK
;
if
(
loc
==
AC_JACK_LOC_REAR
)
return
INPUT_PIN_ATTR_REAR
;
if
(
loc
==
AC_JACK_LOC_FRONT
)
return
INPUT_PIN_ATTR_FRONT
;
return
INPUT_PIN_ATTR_NORMAL
;
}
EXPORT_SYMBOL_HDA
(
snd_hda_get_input_pin_attr
);
/**
* hda_get_input_pin_label - Give a label for the given input pin
*
* When check_location is true, the function checks the pin location
* for mic and line-in pins, and set an appropriate prefix like "Front",
* "Rear", "Internal".
*/
static
const
char
*
hda_get_input_pin_label
(
struct
hda_codec
*
codec
,
hda_nid_t
pin
,
bool
check_location
)
{
unsigned
int
def_conf
;
static
const
char
*
const
mic_names
[]
=
{
"Internal Mic"
,
"Dock Mic"
,
"Mic"
,
"Front Mic"
,
"Rear Mic"
,
};
int
attr
;
def_conf
=
snd_hda_codec_get_pincfg
(
codec
,
pin
);
switch
(
get_defcfg_device
(
def_conf
))
{
case
AC_JACK_MIC_IN
:
if
(
!
check_location
)
return
"Mic"
;
attr
=
snd_hda_get_input_pin_attr
(
def_conf
);
if
(
!
attr
)
return
"None"
;
return
mic_names
[
attr
-
1
];
case
AC_JACK_LINE_IN
:
if
(
!
check_location
)
return
"Line"
;
attr
=
snd_hda_get_input_pin_attr
(
def_conf
);
if
(
!
attr
)
return
"None"
;
if
(
attr
==
INPUT_PIN_ATTR_DOCK
)
return
"Dock Line"
;
return
"Line"
;
case
AC_JACK_AUX
:
return
"Aux"
;
case
AC_JACK_CD
:
return
"CD"
;
case
AC_JACK_SPDIF_IN
:
return
"SPDIF In"
;
case
AC_JACK_DIG_OTHER_IN
:
return
"Digital In"
;
default:
return
"Misc"
;
}
}
/* Check whether the location prefix needs to be added to the label.
* If all mic-jacks are in the same location (e.g. rear panel), we don't
* have to put "Front" prefix to each label. In such a case, returns false.
*/
static
int
check_mic_location_need
(
struct
hda_codec
*
codec
,
const
struct
auto_pin_cfg
*
cfg
,
int
input
)
{
unsigned
int
defc
;
int
i
,
attr
,
attr2
;
defc
=
snd_hda_codec_get_pincfg
(
codec
,
cfg
->
inputs
[
input
].
pin
);
attr
=
snd_hda_get_input_pin_attr
(
defc
);
/* for internal or docking mics, we need locations */
if
(
attr
<=
INPUT_PIN_ATTR_NORMAL
)
return
1
;
attr
=
0
;
for
(
i
=
0
;
i
<
cfg
->
num_inputs
;
i
++
)
{
defc
=
snd_hda_codec_get_pincfg
(
codec
,
cfg
->
inputs
[
i
].
pin
);
attr2
=
snd_hda_get_input_pin_attr
(
defc
);
if
(
attr2
>=
INPUT_PIN_ATTR_NORMAL
)
{
if
(
attr
&&
attr
!=
attr2
)
return
1
;
/* different locations found */
attr
=
attr2
;
}
}
return
0
;
}
/**
*
hda_get_autocfg_input_label - Get a label for the given input
*
snd_hda_get_default_vref - Get the default (mic) VREF pin bits
*
* Get a label for the given input pin defined by the autocfg item.
* Unlike hda_get_input_pin_label(), this function checks all inputs
* defined in autocfg and avoids the redundant mic/line prefix as much as
* possible.
*/
const
char
*
hda_get_autocfg_input_label
(
struct
hda_codec
*
codec
,
const
struct
auto_pin_cfg
*
cfg
,
int
input
)
{
int
type
=
cfg
->
inputs
[
input
].
type
;
int
has_multiple_pins
=
0
;
if
((
input
>
0
&&
cfg
->
inputs
[
input
-
1
].
type
==
type
)
||
(
input
<
cfg
->
num_inputs
-
1
&&
cfg
->
inputs
[
input
+
1
].
type
==
type
))
has_multiple_pins
=
1
;
if
(
has_multiple_pins
&&
type
==
AUTO_PIN_MIC
)
has_multiple_pins
&=
check_mic_location_need
(
codec
,
cfg
,
input
);
return
hda_get_input_pin_label
(
codec
,
cfg
->
inputs
[
input
].
pin
,
has_multiple_pins
);
}
EXPORT_SYMBOL_HDA
(
hda_get_autocfg_input_label
);
/* return the position of NID in the list, or -1 if not found */
static
int
find_idx_in_nid_list
(
hda_nid_t
nid
,
const
hda_nid_t
*
list
,
int
nums
)
{
int
i
;
for
(
i
=
0
;
i
<
nums
;
i
++
)
if
(
list
[
i
]
==
nid
)
return
i
;
return
-
1
;
}
/* get a unique suffix or an index number */
static
const
char
*
check_output_sfx
(
hda_nid_t
nid
,
const
hda_nid_t
*
pins
,
int
num_pins
,
int
*
indexp
)
{
static
const
char
*
const
channel_sfx
[]
=
{
" Front"
,
" Surround"
,
" CLFE"
,
" Side"
};
int
i
;
i
=
find_idx_in_nid_list
(
nid
,
pins
,
num_pins
);
if
(
i
<
0
)
return
NULL
;
if
(
num_pins
==
1
)
return
""
;
if
(
num_pins
>
ARRAY_SIZE
(
channel_sfx
))
{
if
(
indexp
)
*
indexp
=
i
;
return
""
;
}
return
channel_sfx
[
i
];
}
static
int
fill_audio_out_name
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
const
struct
auto_pin_cfg
*
cfg
,
const
char
*
name
,
char
*
label
,
int
maxlen
,
int
*
indexp
)
{
unsigned
int
def_conf
=
snd_hda_codec_get_pincfg
(
codec
,
nid
);
int
attr
=
snd_hda_get_input_pin_attr
(
def_conf
);
const
char
*
pfx
=
""
,
*
sfx
=
""
;
/* handle as a speaker if it's a fixed line-out */
if
(
!
strcmp
(
name
,
"Line Out"
)
&&
attr
==
INPUT_PIN_ATTR_INT
)
name
=
"Speaker"
;
/* check the location */
switch
(
attr
)
{
case
INPUT_PIN_ATTR_DOCK
:
pfx
=
"Dock "
;
break
;
case
INPUT_PIN_ATTR_FRONT
:
pfx
=
"Front "
;
break
;
}
if
(
cfg
)
{
/* try to give a unique suffix if needed */
sfx
=
check_output_sfx
(
nid
,
cfg
->
line_out_pins
,
cfg
->
line_outs
,
indexp
);
if
(
!
sfx
)
sfx
=
check_output_sfx
(
nid
,
cfg
->
speaker_pins
,
cfg
->
speaker_outs
,
indexp
);
if
(
!
sfx
)
{
/* don't add channel suffix for Headphone controls */
int
idx
=
find_idx_in_nid_list
(
nid
,
cfg
->
hp_pins
,
cfg
->
hp_outs
);
if
(
idx
>=
0
)
*
indexp
=
idx
;
sfx
=
""
;
* Guess the suitable VREF pin bits to be set as the pin-control value.
* Note: the function doesn't set the AC_PINCTL_IN_EN bit.
*/
unsigned
int
snd_hda_get_default_vref
(
struct
hda_codec
*
codec
,
hda_nid_t
pin
)
{
unsigned
int
pincap
;
unsigned
int
oldval
;
oldval
=
snd_hda_codec_read
(
codec
,
pin
,
0
,
AC_VERB_GET_PIN_WIDGET_CONTROL
,
0
);
pincap
=
snd_hda_query_pin_caps
(
codec
,
pin
);
pincap
=
(
pincap
&
AC_PINCAP_VREF
)
>>
AC_PINCAP_VREF_SHIFT
;
/* Exception: if the default pin setup is vref50, we give it priority */
if
((
pincap
&
AC_PINCAP_VREF_80
)
&&
oldval
!=
PIN_VREF50
)
return
AC_PINCTL_VREF_80
;
else
if
(
pincap
&
AC_PINCAP_VREF_50
)
return
AC_PINCTL_VREF_50
;
else
if
(
pincap
&
AC_PINCAP_VREF_100
)
return
AC_PINCTL_VREF_100
;
else
if
(
pincap
&
AC_PINCAP_VREF_GRD
)
return
AC_PINCTL_VREF_GRD
;
return
AC_PINCTL_VREF_HIZ
;
}
EXPORT_SYMBOL_HDA
(
snd_hda_get_default_vref
);
int
_snd_hda_set_pin_ctl
(
struct
hda_codec
*
codec
,
hda_nid_t
pin
,
unsigned
int
val
,
bool
cached
)
{
if
(
val
)
{
unsigned
int
cap
=
snd_hda_query_pin_caps
(
codec
,
pin
);
if
(
cap
&&
(
val
&
AC_PINCTL_OUT_EN
))
{
if
(
!
(
cap
&
AC_PINCAP_OUT
))
val
&=
~
(
AC_PINCTL_OUT_EN
|
AC_PINCTL_HP_EN
);
else
if
((
val
&
AC_PINCTL_HP_EN
)
&&
!
(
cap
&
AC_PINCAP_HP_DRV
))
val
&=
~
AC_PINCTL_HP_EN
;
}
}
snprintf
(
label
,
maxlen
,
"%s%s%s"
,
pfx
,
name
,
sfx
);
return
1
;
}
/**
* snd_hda_get_pin_label - Get a label for the given I/O pin
*
* Get a label for the given pin. This function works for both input and
* output pins. When @cfg is given as non-NULL, the function tries to get
* an optimized label using hda_get_autocfg_input_label().
*
* This function tries to give a unique label string for the pin as much as
* possible. For example, when the multiple line-outs are present, it adds
* the channel suffix like "Front", "Surround", etc (only when @cfg is given).
* If no unique name with a suffix is available and @indexp is non-NULL, the
* index number is stored in the pointer.
*/
int
snd_hda_get_pin_label
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
const
struct
auto_pin_cfg
*
cfg
,
char
*
label
,
int
maxlen
,
int
*
indexp
)
{
unsigned
int
def_conf
=
snd_hda_codec_get_pincfg
(
codec
,
nid
);
const
char
*
name
=
NULL
;
int
i
;
if
(
indexp
)
*
indexp
=
0
;
if
(
get_defcfg_connect
(
def_conf
)
==
AC_JACK_PORT_NONE
)
return
0
;
switch
(
get_defcfg_device
(
def_conf
))
{
case
AC_JACK_LINE_OUT
:
return
fill_audio_out_name
(
codec
,
nid
,
cfg
,
"Line Out"
,
label
,
maxlen
,
indexp
);
case
AC_JACK_SPEAKER
:
return
fill_audio_out_name
(
codec
,
nid
,
cfg
,
"Speaker"
,
label
,
maxlen
,
indexp
);
case
AC_JACK_HP_OUT
:
return
fill_audio_out_name
(
codec
,
nid
,
cfg
,
"Headphone"
,
label
,
maxlen
,
indexp
);
case
AC_JACK_SPDIF_OUT
:
case
AC_JACK_DIG_OTHER_OUT
:
if
(
get_defcfg_location
(
def_conf
)
==
AC_JACK_LOC_HDMI
)
name
=
"HDMI"
;
else
name
=
"SPDIF"
;
if
(
cfg
&&
indexp
)
{
i
=
find_idx_in_nid_list
(
nid
,
cfg
->
dig_out_pins
,
cfg
->
dig_outs
);
if
(
i
>=
0
)
*
indexp
=
i
;
}
break
;
default:
if
(
cfg
)
{
for
(
i
=
0
;
i
<
cfg
->
num_inputs
;
i
++
)
{
if
(
cfg
->
inputs
[
i
].
pin
!=
nid
)
continue
;
name
=
hda_get_autocfg_input_label
(
codec
,
cfg
,
i
);
if
(
name
)
break
;
}
if
(
cap
&&
(
val
&
AC_PINCTL_IN_EN
))
{
if
(
!
(
cap
&
AC_PINCAP_IN
))
val
&=
~
(
AC_PINCTL_IN_EN
|
AC_PINCTL_VREFEN
);
}
if
(
!
name
)
name
=
hda_get_input_pin_label
(
codec
,
nid
,
true
);
break
;
}
if
(
!
name
)
return
0
;
strlcpy
(
label
,
name
,
maxlen
);
return
1
;
if
(
cached
)
return
snd_hda_codec_update_cache
(
codec
,
pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
val
);
else
return
snd_hda_codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
val
);
}
EXPORT_SYMBOL_HDA
(
snd_hda_get_pin_labe
l
);
EXPORT_SYMBOL_HDA
(
_snd_hda_set_pin_ct
l
);
/**
* snd_hda_add_imux_item - Add an item to input_mux
...
...
@@ -5444,8 +4986,6 @@ 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
);
if
(
codec
->
patch_ops
.
post_suspend
)
codec
->
patch_ops
.
post_suspend
(
codec
);
}
return
0
;
}
...
...
@@ -5465,10 +5005,7 @@ int snd_hda_resume(struct hda_bus *bus)
struct
hda_codec
*
codec
;
list_for_each_entry
(
codec
,
&
bus
->
codec_list
,
list
)
{
if
(
codec
->
patch_ops
.
pre_resume
)
codec
->
patch_ops
.
pre_resume
(
codec
);
if
(
snd_hda_codec_needs_resume
(
codec
))
hda_call_codec_resume
(
codec
);
hda_call_codec_resume
(
codec
);
}
return
0
;
}
...
...
sound/pci/hda/hda_codec.h
浏览文件 @
6de15b2a
...
...
@@ -704,8 +704,6 @@ struct hda_codec_ops {
unsigned
int
power_state
);
#ifdef CONFIG_PM
int
(
*
suspend
)(
struct
hda_codec
*
codec
,
pm_message_t
state
);
int
(
*
post_suspend
)(
struct
hda_codec
*
codec
);
int
(
*
pre_resume
)(
struct
hda_codec
*
codec
);
int
(
*
resume
)(
struct
hda_codec
*
codec
);
#endif
#ifdef CONFIG_SND_HDA_POWER_SAVE
...
...
@@ -829,6 +827,7 @@ struct hda_codec {
struct
mutex
spdif_mutex
;
struct
mutex
control_mutex
;
struct
mutex
hash_mutex
;
struct
snd_array
spdif_out
;
unsigned
int
spdif_in_enable
;
/* SPDIF input enable? */
const
hda_nid_t
*
slave_dig_outs
;
/* optional digital out slave widgets */
...
...
@@ -861,12 +860,13 @@ struct hda_codec {
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 */
int
power_transition
;
/* power-state in transition */
int
power_count
;
/* current (global) power refcount */
struct
delayed_work
power_work
;
/* delayed task for powerdown */
unsigned
long
power_on_acct
;
unsigned
long
power_off_acct
;
unsigned
long
power_jiffies
;
spinlock_t
power_lock
;
#endif
/* codec-specific additional proc output */
...
...
@@ -911,10 +911,13 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
hda_nid_t
*
start_id
);
int
snd_hda_get_connections
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
hda_nid_t
*
conn_list
,
int
max_conns
);
static
inline
int
snd_hda_get_num_conns
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
return
snd_hda_get_connections
(
codec
,
nid
,
NULL
,
0
);
}
int
snd_hda_get_raw_connections
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
hda_nid_t
*
conn_list
,
int
max_conns
);
int
snd_hda_get_conn_list
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
const
hda_nid_t
**
listp
);
int
snd_hda_override_conn_list
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
nums
,
const
hda_nid_t
*
list
);
int
snd_hda_get_conn_index
(
struct
hda_codec
*
codec
,
hda_nid_t
mux
,
...
...
@@ -1051,12 +1054,10 @@ const char *snd_hda_get_jack_location(u32 cfg);
#ifdef CONFIG_SND_HDA_POWER_SAVE
void
snd_hda_power_up
(
struct
hda_codec
*
codec
);
void
snd_hda_power_down
(
struct
hda_codec
*
codec
);
#define snd_hda_codec_needs_resume(codec) codec->power_count
void
snd_hda_update_power_acct
(
struct
hda_codec
*
codec
);
#else
static
inline
void
snd_hda_power_up
(
struct
hda_codec
*
codec
)
{}
static
inline
void
snd_hda_power_down
(
struct
hda_codec
*
codec
)
{}
#define snd_hda_codec_needs_resume(codec) 1
#endif
#ifdef CONFIG_SND_HDA_PATCH_LOADER
...
...
sound/pci/hda/hda_intel.c
浏览文件 @
6de15b2a
...
...
@@ -497,6 +497,7 @@ enum {
AZX_DRIVER_NVIDIA
,
AZX_DRIVER_TERA
,
AZX_DRIVER_CTX
,
AZX_DRIVER_CTHDA
,
AZX_DRIVER_GENERIC
,
AZX_NUM_DRIVERS
,
/* keep this as last entry */
};
...
...
@@ -518,6 +519,7 @@ enum {
#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 */
#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)
/* BDLE in 4k boundary */
/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
...
...
@@ -533,6 +535,9 @@ enum {
(AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\
AZX_DCAPS_ALIGN_BUFSIZE)
#define AZX_DCAPS_PRESET_CTHDA \
(AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY)
static
char
*
driver_short_names
[]
__devinitdata
=
{
[
AZX_DRIVER_ICH
]
=
"HDA Intel"
,
[
AZX_DRIVER_PCH
]
=
"HDA Intel PCH"
,
...
...
@@ -546,6 +551,7 @@ static char *driver_short_names[] __devinitdata = {
[
AZX_DRIVER_NVIDIA
]
=
"HDA NVidia"
,
[
AZX_DRIVER_TERA
]
=
"HDA Teradici"
,
[
AZX_DRIVER_CTX
]
=
"HDA Creative"
,
[
AZX_DRIVER_CTHDA
]
=
"HDA Creative"
,
[
AZX_DRIVER_GENERIC
]
=
"HD-Audio Generic"
,
};
...
...
@@ -1285,7 +1291,8 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
/*
* set up a BDL entry
*/
static
int
setup_bdle
(
struct
snd_pcm_substream
*
substream
,
static
int
setup_bdle
(
struct
azx
*
chip
,
struct
snd_pcm_substream
*
substream
,
struct
azx_dev
*
azx_dev
,
u32
**
bdlp
,
int
ofs
,
int
size
,
int
with_ioc
)
{
...
...
@@ -1304,6 +1311,12 @@ static int setup_bdle(struct snd_pcm_substream *substream,
bdl
[
1
]
=
cpu_to_le32
(
upper_32_bits
(
addr
));
/* program the size field of the BDL entry */
chunk
=
snd_pcm_sgbuf_get_chunk_size
(
substream
,
ofs
,
size
);
/* one BDLE cannot cross 4K boundary on CTHDA chips */
if
(
chip
->
driver_caps
&
AZX_DCAPS_4K_BDLE_BOUNDARY
)
{
u32
remain
=
0x1000
-
(
ofs
&
0xfff
);
if
(
chunk
>
remain
)
chunk
=
remain
;
}
bdl
[
2
]
=
cpu_to_le32
(
chunk
);
/* program the IOC to enable interrupt
* only when the whole fragment is processed
...
...
@@ -1356,7 +1369,7 @@ static int azx_setup_periods(struct azx *chip,
bdl_pos_adj
[
chip
->
dev_index
]);
pos_adj
=
0
;
}
else
{
ofs
=
setup_bdle
(
substream
,
azx_dev
,
ofs
=
setup_bdle
(
chip
,
substream
,
azx_dev
,
&
bdl
,
ofs
,
pos_adj
,
!
substream
->
runtime
->
no_period_wakeup
);
if
(
ofs
<
0
)
...
...
@@ -1366,10 +1379,10 @@ static int azx_setup_periods(struct azx *chip,
pos_adj
=
0
;
for
(
i
=
0
;
i
<
periods
;
i
++
)
{
if
(
i
==
periods
-
1
&&
pos_adj
)
ofs
=
setup_bdle
(
substream
,
azx_dev
,
&
bdl
,
ofs
,
ofs
=
setup_bdle
(
chip
,
substream
,
azx_dev
,
&
bdl
,
ofs
,
period_bytes
-
pos_adj
,
0
);
else
ofs
=
setup_bdle
(
substream
,
azx_dev
,
&
bdl
,
ofs
,
ofs
=
setup_bdle
(
chip
,
substream
,
azx_dev
,
&
bdl
,
ofs
,
period_bytes
,
!
substream
->
runtime
->
no_period_wakeup
);
if
(
ofs
<
0
)
...
...
@@ -2353,17 +2366,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
);
...
...
@@ -2410,8 +2412,7 @@ 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
);
azx_init_chip
(
chip
,
1
);
snd_hda_resume
(
chip
->
bus
);
snd_power_change_state
(
card
,
SNDRV_CTL_POWER_D0
);
...
...
@@ -3130,6 +3131,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
.
driver_data
=
AZX_DRIVER_CTX
|
AZX_DCAPS_CTX_WORKAROUND
|
AZX_DCAPS_RIRB_PRE_DELAY
|
AZX_DCAPS_POSFIX_LPIB
},
#endif
/* CTHDA chips */
{
PCI_DEVICE
(
0x1102
,
0x0010
),
.
driver_data
=
AZX_DRIVER_CTHDA
|
AZX_DCAPS_PRESET_CTHDA
},
{
PCI_DEVICE
(
0x1102
,
0x0012
),
.
driver_data
=
AZX_DRIVER_CTHDA
|
AZX_DCAPS_PRESET_CTHDA
},
/* Vortex86MX */
{
PCI_DEVICE
(
0x17f3
,
0x3010
),
.
driver_data
=
AZX_DRIVER_GENERIC
},
/* VMware HDAudio */
...
...
sound/pci/hda/hda_jack.c
浏览文件 @
6de15b2a
...
...
@@ -17,6 +17,7 @@
#include <sound/jack.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
bool
is_jack_detectable
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
...
...
sound/pci/hda/hda_jack.h
浏览文件 @
6de15b2a
...
...
@@ -12,6 +12,8 @@
#ifndef __SOUND_HDA_JACK_H
#define __SOUND_HDA_JACK_H
struct
auto_pin_cfg
;
struct
hda_jack_tbl
{
hda_nid_t
nid
;
unsigned
char
action
;
/* event action (0 = none) */
...
...
sound/pci/hda/hda_local.h
浏览文件 @
6de15b2a
...
...
@@ -262,6 +262,8 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
const
struct
hda_input_mux
*
imux
,
struct
snd_ctl_elem_value
*
ucontrol
,
hda_nid_t
nid
,
unsigned
int
*
cur_val
);
int
snd_hda_add_imux_item
(
struct
hda_input_mux
*
imux
,
const
char
*
label
,
int
index
,
int
*
type_index_ret
);
/*
* Channel mode helper
...
...
@@ -393,72 +395,7 @@ struct hda_bus_unsolicited {
struct
hda_bus
*
bus
;
};
/*
* Helper for automatic pin configuration
*/
enum
{
AUTO_PIN_MIC
,
AUTO_PIN_LINE_IN
,
AUTO_PIN_CD
,
AUTO_PIN_AUX
,
AUTO_PIN_LAST
};
enum
{
AUTO_PIN_LINE_OUT
,
AUTO_PIN_SPEAKER_OUT
,
AUTO_PIN_HP_OUT
};
#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS
#define AUTO_CFG_MAX_INS 8
struct
auto_pin_cfg_item
{
hda_nid_t
pin
;
int
type
;
};
struct
auto_pin_cfg
;
const
char
*
hda_get_autocfg_input_label
(
struct
hda_codec
*
codec
,
const
struct
auto_pin_cfg
*
cfg
,
int
input
);
int
snd_hda_get_pin_label
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
const
struct
auto_pin_cfg
*
cfg
,
char
*
label
,
int
maxlen
,
int
*
indexp
);
int
snd_hda_add_imux_item
(
struct
hda_input_mux
*
imux
,
const
char
*
label
,
int
index
,
int
*
type_index_ret
);
enum
{
INPUT_PIN_ATTR_UNUSED
,
/* pin not connected */
INPUT_PIN_ATTR_INT
,
/* internal mic/line-in */
INPUT_PIN_ATTR_DOCK
,
/* docking mic/line-in */
INPUT_PIN_ATTR_NORMAL
,
/* mic/line-in jack */
INPUT_PIN_ATTR_FRONT
,
/* mic/line-in jack in front */
INPUT_PIN_ATTR_REAR
,
/* mic/line-in jack in rear */
};
int
snd_hda_get_input_pin_attr
(
unsigned
int
def_conf
);
struct
auto_pin_cfg
{
int
line_outs
;
/* sorted in the order of Front/Surr/CLFE/Side */
hda_nid_t
line_out_pins
[
AUTO_CFG_MAX_OUTS
];
int
speaker_outs
;
hda_nid_t
speaker_pins
[
AUTO_CFG_MAX_OUTS
];
int
hp_outs
;
int
line_out_type
;
/* AUTO_PIN_XXX_OUT */
hda_nid_t
hp_pins
[
AUTO_CFG_MAX_OUTS
];
int
num_inputs
;
struct
auto_pin_cfg_item
inputs
[
AUTO_CFG_MAX_INS
];
int
dig_outs
;
hda_nid_t
dig_out_pins
[
2
];
hda_nid_t
dig_in_pin
;
hda_nid_t
mono_out_pin
;
int
dig_out_type
[
2
];
/* HDA_PCM_TYPE_XXX */
int
dig_in_type
;
/* HDA_PCM_TYPE_XXX */
};
/* helper macros to retrieve pin default-config values */
#define get_defcfg_connect(cfg) \
((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT)
#define get_defcfg_association(cfg) \
...
...
@@ -472,19 +409,6 @@ struct auto_pin_cfg {
#define get_defcfg_misc(cfg) \
((cfg & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT)
/* bit-flags for snd_hda_parse_pin_def_config() behavior */
#define HDA_PINCFG_NO_HP_FIXUP (1 << 0)
/* no HP-split */
#define HDA_PINCFG_NO_LO_FIXUP (1 << 1)
/* don't take other outs as LO */
int
snd_hda_parse_pin_defcfg
(
struct
hda_codec
*
codec
,
struct
auto_pin_cfg
*
cfg
,
const
hda_nid_t
*
ignore_nids
,
unsigned
int
cond_flags
);
/* older function */
#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
/* amp values */
#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8))
#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8))
...
...
@@ -502,6 +426,46 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
#define PIN_HP (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN)
#define PIN_HP_AMP (AC_PINCTL_HP_EN)
unsigned
int
snd_hda_get_default_vref
(
struct
hda_codec
*
codec
,
hda_nid_t
pin
);
int
_snd_hda_set_pin_ctl
(
struct
hda_codec
*
codec
,
hda_nid_t
pin
,
unsigned
int
val
,
bool
cached
);
/**
* _snd_hda_set_pin_ctl - Set a pin-control value safely
* @codec: the codec instance
* @pin: the pin NID to set the control
* @val: the pin-control value (AC_PINCTL_* bits)
*
* This function sets the pin-control value to the given pin, but
* filters out the invalid pin-control bits when the pin has no such
* capabilities. For example, when PIN_HP is passed but the pin has no
* HP-drive capability, the HP bit is omitted.
*
* The function doesn't check the input VREF capability bits, though.
* Use snd_hda_get_default_vref() to guess the right value.
* Also, this function is only for analog pins, not for HDMI pins.
*/
static
inline
int
snd_hda_set_pin_ctl
(
struct
hda_codec
*
codec
,
hda_nid_t
pin
,
unsigned
int
val
)
{
return
_snd_hda_set_pin_ctl
(
codec
,
pin
,
val
,
false
);
}
/**
* snd_hda_set_pin_ctl_cache - Set a pin-control value safely
* @codec: the codec instance
* @pin: the pin NID to set the control
* @val: the pin-control value (AC_PINCTL_* bits)
*
* Just like snd_hda_set_pin_ctl() but write to cache as well.
*/
static
inline
int
snd_hda_set_pin_ctl_cache
(
struct
hda_codec
*
codec
,
hda_nid_t
pin
,
unsigned
int
val
)
{
return
_snd_hda_set_pin_ctl
(
codec
,
pin
,
val
,
true
);
}
/*
* get widget capabilities
*/
...
...
sound/pci/hda/patch_analog.c
浏览文件 @
6de15b2a
...
...
@@ -28,6 +28,7 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_beep.h"
#include "hda_jack.h"
...
...
@@ -1742,9 +1743,7 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
if
(
!
ad198x_eapd_put
(
kcontrol
,
ucontrol
))
return
0
;
/* change speaker pin appropriately */
snd_hda_codec_write
(
codec
,
0x05
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
spec
->
cur_eapd
?
PIN_OUT
:
0
);
snd_hda_set_pin_ctl
(
codec
,
0x05
,
spec
->
cur_eapd
?
PIN_OUT
:
0
);
/* toggle HP mute appropriately */
snd_hda_codec_amp_stereo
(
codec
,
0x06
,
HDA_OUTPUT
,
0
,
HDA_AMP_MUTE
,
...
...
@@ -3103,7 +3102,7 @@ static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,
int
dac_idx
)
{
/* set as output */
snd_hda_
codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pin_type
);
snd_hda_
set_pin_ctl
(
codec
,
nid
,
pin_type
);
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
);
switch
(
nid
)
{
case
0x11
:
/* port-A - DAC 03 */
...
...
@@ -3157,6 +3156,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
for
(
i
=
0
;
i
<
cfg
->
num_inputs
;
i
++
)
{
hda_nid_t
nid
=
cfg
->
inputs
[
i
].
pin
;
int
type
=
cfg
->
inputs
[
i
].
type
;
int
val
;
switch
(
nid
)
{
case
0x15
:
/* port-C */
snd_hda_codec_write
(
codec
,
0x33
,
0
,
AC_VERB_SET_CONNECT_SEL
,
0x0
);
...
...
@@ -3165,8 +3165,10 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
snd_hda_codec_write
(
codec
,
0x34
,
0
,
AC_VERB_SET_CONNECT_SEL
,
0x0
);
break
;
}
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
type
==
AUTO_PIN_MIC
?
PIN_VREF80
:
PIN_IN
);
val
=
PIN_IN
;
if
(
type
==
AUTO_PIN_MIC
)
val
|=
snd_hda_get_default_vref
(
codec
,
nid
);
snd_hda_set_pin_ctl
(
codec
,
nid
,
val
);
if
(
nid
!=
AD1988_PIN_CD_NID
)
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
);
...
...
sound/pci/hda/patch_ca0110.c
浏览文件 @
6de15b2a
...
...
@@ -26,6 +26,7 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
/*
*/
...
...
@@ -341,8 +342,7 @@ static int ca0110_build_pcms(struct hda_codec *codec)
static
void
init_output
(
struct
hda_codec
*
codec
,
hda_nid_t
pin
,
hda_nid_t
dac
)
{
if
(
pin
)
{
snd_hda_codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
);
snd_hda_set_pin_ctl
(
codec
,
pin
,
PIN_HP
);
if
(
get_wcaps
(
codec
,
pin
)
&
AC_WCAP_OUT_AMP
)
snd_hda_codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
...
...
@@ -356,8 +356,8 @@ static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
static
void
init_input
(
struct
hda_codec
*
codec
,
hda_nid_t
pin
,
hda_nid_t
adc
)
{
if
(
pin
)
{
snd_hda_
codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
);
snd_hda_
set_pin_ctl
(
codec
,
pin
,
PIN_IN
|
snd_hda_get_default_vref
(
codec
,
pin
)
);
if
(
get_wcaps
(
codec
,
pin
)
&
AC_WCAP_IN_AMP
)
snd_hda_codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
...
...
sound/pci/hda/patch_ca0132.c
浏览文件 @
6de15b2a
...
...
@@ -30,6 +30,7 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#define WIDGET_CHIP_CTRL 0x15
#define WIDGET_DSP_CTRL 0x16
...
...
@@ -239,8 +240,7 @@ enum get_set {
static
void
init_output
(
struct
hda_codec
*
codec
,
hda_nid_t
pin
,
hda_nid_t
dac
)
{
if
(
pin
)
{
snd_hda_codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
);
snd_hda_set_pin_ctl
(
codec
,
pin
,
PIN_HP
);
if
(
get_wcaps
(
codec
,
pin
)
&
AC_WCAP_OUT_AMP
)
snd_hda_codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
...
...
@@ -254,9 +254,8 @@ static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
static
void
init_input
(
struct
hda_codec
*
codec
,
hda_nid_t
pin
,
hda_nid_t
adc
)
{
if
(
pin
)
{
snd_hda_codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
);
snd_hda_set_pin_ctl
(
codec
,
pin
,
PIN_IN
|
snd_hda_get_default_vref
(
codec
,
pin
));
if
(
get_wcaps
(
codec
,
pin
)
&
AC_WCAP_IN_AMP
)
snd_hda_codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
...
...
sound/pci/hda/patch_cirrus.c
浏览文件 @
6de15b2a
...
...
@@ -26,6 +26,7 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
#include <sound/tlv.h>
...
...
@@ -933,8 +934,7 @@ static void cs_automute(struct hda_codec *codec)
pin_ctl
=
0
;
nid
=
cfg
->
speaker_pins
[
i
];
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pin_ctl
);
snd_hda_set_pin_ctl
(
codec
,
nid
,
pin_ctl
);
}
if
(
spec
->
gpio_eapd_hp
)
{
unsigned
int
gpio
=
hp_present
?
...
...
@@ -948,16 +948,14 @@ static void cs_automute(struct hda_codec *codec)
/* mute HPs if spdif jack (SENSE_B) is present */
for
(
i
=
0
;
i
<
cfg
->
hp_outs
;
i
++
)
{
nid
=
cfg
->
hp_pins
[
i
];
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
snd_hda_set_pin_ctl
(
codec
,
nid
,
(
spdif_present
&&
spec
->
sense_b
)
?
0
:
PIN_HP
);
}
/* SPDIF TX on/off */
if
(
cfg
->
dig_outs
)
{
nid
=
cfg
->
dig_out_pins
[
0
];
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
snd_hda_set_pin_ctl
(
codec
,
nid
,
spdif_present
?
PIN_OUT
:
0
);
}
...
...
@@ -1024,13 +1022,11 @@ static void init_output(struct hda_codec *codec)
/* set appropriate pin controls */
for
(
i
=
0
;
i
<
cfg
->
line_outs
;
i
++
)
snd_hda_codec_write
(
codec
,
cfg
->
line_out_pins
[
i
],
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
);
snd_hda_set_pin_ctl
(
codec
,
cfg
->
line_out_pins
[
i
],
PIN_OUT
);
/* HP */
for
(
i
=
0
;
i
<
cfg
->
hp_outs
;
i
++
)
{
hda_nid_t
nid
=
cfg
->
hp_pins
[
i
];
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
);
snd_hda_set_pin_ctl
(
codec
,
nid
,
PIN_HP
);
if
(
!
cfg
->
speaker_outs
)
continue
;
if
(
get_wcaps
(
codec
,
nid
)
&
AC_WCAP_UNSOL_CAP
)
{
...
...
@@ -1041,8 +1037,7 @@ static void init_output(struct hda_codec *codec)
/* Speaker */
for
(
i
=
0
;
i
<
cfg
->
speaker_outs
;
i
++
)
snd_hda_codec_write
(
codec
,
cfg
->
speaker_pins
[
i
],
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
);
snd_hda_set_pin_ctl
(
codec
,
cfg
->
speaker_pins
[
i
],
PIN_OUT
);
/* SPDIF is enabled on presence detect for CS421x */
if
(
spec
->
hp_detect
||
spec
->
spdif_detect
)
...
...
@@ -1063,14 +1058,9 @@ static void init_input(struct hda_codec *codec)
continue
;
/* set appropriate pin control and mute first */
ctl
=
PIN_IN
;
if
(
cfg
->
inputs
[
i
].
type
==
AUTO_PIN_MIC
)
{
unsigned
int
caps
=
snd_hda_query_pin_caps
(
codec
,
pin
);
caps
>>=
AC_PINCAP_VREF_SHIFT
;
if
(
caps
&
AC_PINCAP_VREF_80
)
ctl
=
PIN_VREF80
;
}
snd_hda_codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
ctl
);
if
(
cfg
->
inputs
[
i
].
type
==
AUTO_PIN_MIC
)
ctl
|=
snd_hda_get_default_vref
(
codec
,
pin
);
snd_hda_set_pin_ctl
(
codec
,
pin
,
ctl
);
snd_hda_codec_write
(
codec
,
spec
->
adc_nid
[
i
],
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
spec
->
adc_idx
[
i
]));
...
...
sound/pci/hda/patch_cmedia.c
浏览文件 @
6de15b2a
...
...
@@ -29,6 +29,7 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#define NUM_PINS 11
...
...
sound/pci/hda/patch_conexant.c
浏览文件 @
6de15b2a
...
...
@@ -30,6 +30,7 @@
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_beep.h"
#include "hda_jack.h"
...
...
@@ -66,6 +67,7 @@ struct imux_info {
};
struct
conexant_spec
{
struct
hda_gen_spec
gen
;
const
struct
snd_kcontrol_new
*
mixers
[
5
];
int
num_mixers
;
...
...
@@ -141,6 +143,7 @@ struct conexant_spec {
unsigned
int
hp_laptop
:
1
;
unsigned
int
asus
:
1
;
unsigned
int
pin_eapd_ctrls
:
1
;
unsigned
int
fixup_stereo_dmic
:
1
;
unsigned
int
adc_switching
:
1
;
...
...
@@ -1601,17 +1604,13 @@ static void cxt5051_update_speaker(struct hda_codec *codec)
unsigned
int
pinctl
;
/* headphone pin */
pinctl
=
(
spec
->
hp_present
&&
spec
->
cur_eapd
)
?
PIN_HP
:
0
;
snd_hda_codec_write
(
codec
,
0x16
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pinctl
);
snd_hda_set_pin_ctl
(
codec
,
0x16
,
pinctl
);
/* speaker pin */
pinctl
=
(
!
spec
->
hp_present
&&
spec
->
cur_eapd
)
?
PIN_OUT
:
0
;
snd_hda_codec_write
(
codec
,
0x1a
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pinctl
);
snd_hda_set_pin_ctl
(
codec
,
0x1a
,
pinctl
);
/* on ideapad there is an additional speaker (subwoofer) to mute */
if
(
spec
->
ideapad
)
snd_hda_codec_write
(
codec
,
0x1b
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pinctl
);
snd_hda_set_pin_ctl
(
codec
,
0x1b
,
pinctl
);
}
/* turn on/off EAPD (+ mute HP) as a master switch */
...
...
@@ -1996,8 +1995,7 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
/* Port A (HP) */
pinctl
=
(
hp_port_a_present
(
spec
)
&&
spec
->
cur_eapd
)
?
PIN_HP
:
0
;
snd_hda_codec_write
(
codec
,
0x19
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pinctl
);
snd_hda_set_pin_ctl
(
codec
,
0x19
,
pinctl
);
/* Port D (HP/LO) */
pinctl
=
spec
->
cur_eapd
?
spec
->
port_d_mode
:
0
;
...
...
@@ -2010,13 +2008,11 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
if
(
!
hp_port_d_present
(
spec
))
pinctl
=
0
;
}
snd_hda_codec_write
(
codec
,
0x1c
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pinctl
);
snd_hda_set_pin_ctl
(
codec
,
0x1c
,
pinctl
);
/* CLASS_D AMP */
pinctl
=
(
!
spec
->
hp_present
&&
spec
->
cur_eapd
)
?
PIN_OUT
:
0
;
snd_hda_codec_write
(
codec
,
0x1f
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pinctl
);
snd_hda_set_pin_ctl
(
codec
,
0x1f
,
pinctl
);
}
/* turn on/off EAPD (+ mute HP) as a master switch */
...
...
@@ -2047,8 +2043,7 @@ static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec)
/* Even though port F is the DC input, the bias is controlled on port B.
* we also leave that port as an active input (but unselected) in DC mode
* just in case that is necessary to make the bias setting take effect. */
return
snd_hda_codec_write_cache
(
codec
,
0x1a
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
return
snd_hda_set_pin_ctl_cache
(
codec
,
0x1a
,
cxt5066_olpc_dc_bias
.
items
[
spec
->
dc_input_bias
].
index
);
}
...
...
@@ -2081,14 +2076,14 @@ static void cxt5066_olpc_select_mic(struct hda_codec *codec)
}
/* disable DC (port F) */
snd_hda_
codec_write
(
codec
,
0x1e
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
);
snd_hda_
set_pin_ctl
(
codec
,
0x1e
,
0
);
/* external mic, port B */
snd_hda_
codec_write
(
codec
,
0x1a
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
snd_hda_
set_pin_ctl
(
codec
,
0x1a
,
spec
->
ext_mic_present
?
CXT5066_OLPC_EXT_MIC_BIAS
:
0
);
/* internal mic, port C */
snd_hda_
codec_write
(
codec
,
0x1b
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
snd_hda_
set_pin_ctl
(
codec
,
0x1b
,
spec
->
ext_mic_present
?
0
:
PIN_VREF80
);
}
...
...
@@ -3357,9 +3352,7 @@ static void do_automute(struct hda_codec *codec, int num_pins,
struct
conexant_spec
*
spec
=
codec
->
spec
;
int
i
;
for
(
i
=
0
;
i
<
num_pins
;
i
++
)
snd_hda_codec_write
(
codec
,
pins
[
i
],
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
on
?
PIN_OUT
:
0
);
snd_hda_set_pin_ctl
(
codec
,
pins
[
i
],
on
?
PIN_OUT
:
0
);
if
(
spec
->
pin_eapd_ctrls
)
cx_auto_turn_eapd
(
codec
,
num_pins
,
pins
,
on
);
}
...
...
@@ -3976,8 +3969,7 @@ static void cx_auto_init_output(struct hda_codec *codec)
if
(
snd_hda_query_pin_caps
(
codec
,
cfg
->
hp_pins
[
i
])
&
AC_PINCAP_HP_DRV
)
val
|=
AC_PINCTL_HP_EN
;
snd_hda_codec_write
(
codec
,
cfg
->
hp_pins
[
i
],
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
val
);
snd_hda_set_pin_ctl
(
codec
,
cfg
->
hp_pins
[
i
],
val
);
}
mute_outputs
(
codec
,
cfg
->
hp_outs
,
cfg
->
hp_pins
);
mute_outputs
(
codec
,
cfg
->
line_outs
,
cfg
->
line_out_pins
);
...
...
@@ -4030,13 +4022,11 @@ static void cx_auto_init_input(struct hda_codec *codec)
}
for
(
i
=
0
;
i
<
cfg
->
num_inputs
;
i
++
)
{
unsigned
int
type
;
hda_nid_t
pin
=
cfg
->
inputs
[
i
].
pin
;
unsigned
int
type
=
PIN_IN
;
if
(
cfg
->
inputs
[
i
].
type
==
AUTO_PIN_MIC
)
type
=
PIN_VREF80
;
else
type
=
PIN_IN
;
snd_hda_codec_write
(
codec
,
cfg
->
inputs
[
i
].
pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
type
);
type
|=
snd_hda_get_default_vref
(
codec
,
pin
);
snd_hda_set_pin_ctl
(
codec
,
pin
,
type
);
}
if
(
spec
->
auto_mic
)
{
...
...
@@ -4063,11 +4053,9 @@ static void cx_auto_init_digital(struct hda_codec *codec)
struct
auto_pin_cfg
*
cfg
=
&
spec
->
autocfg
;
if
(
spec
->
multiout
.
dig_out_nid
)
snd_hda_codec_write
(
codec
,
cfg
->
dig_out_pins
[
0
],
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
);
snd_hda_set_pin_ctl
(
codec
,
cfg
->
dig_out_pins
[
0
],
PIN_OUT
);
if
(
spec
->
dig_in_nid
)
snd_hda_codec_write
(
codec
,
cfg
->
dig_in_pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
);
snd_hda_set_pin_ctl
(
codec
,
cfg
->
dig_in_pin
,
PIN_IN
);
}
static
int
cx_auto_init
(
struct
hda_codec
*
codec
)
...
...
@@ -4084,9 +4072,9 @@ static int cx_auto_init(struct hda_codec *codec)
static
int
cx_auto_add_volume_idx
(
struct
hda_codec
*
codec
,
const
char
*
basename
,
const
char
*
dir
,
int
cidx
,
hda_nid_t
nid
,
int
hda_dir
,
int
amp_idx
)
hda_nid_t
nid
,
int
hda_dir
,
int
amp_idx
,
int
chs
)
{
static
char
name
[
32
];
static
char
name
[
44
];
static
struct
snd_kcontrol_new
knew
[]
=
{
HDA_CODEC_VOLUME
(
name
,
0
,
0
,
0
),
HDA_CODEC_MUTE
(
name
,
0
,
0
,
0
),
...
...
@@ -4096,7 +4084,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
for
(
i
=
0
;
i
<
2
;
i
++
)
{
struct
snd_kcontrol
*
kctl
;
knew
[
i
].
private_value
=
HDA_COMPOSE_AMP_VAL
(
nid
,
3
,
amp_idx
,
knew
[
i
].
private_value
=
HDA_COMPOSE_AMP_VAL
(
nid
,
chs
,
amp_idx
,
hda_dir
);
knew
[
i
].
subdevice
=
HDA_SUBDEV_AMP_FLAG
;
knew
[
i
].
index
=
cidx
;
...
...
@@ -4115,7 +4103,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
}
#define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \
cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0)
cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0
, 3
)
#define cx_auto_add_pb_volume(codec, nid, str, idx) \
cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
...
...
@@ -4185,6 +4173,36 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
return
0
;
}
/* Returns zero if this is a normal stereo channel, and non-zero if it should
be split in two independent channels.
dest_label must be at least 44 characters. */
static
int
cx_auto_get_rightch_label
(
struct
hda_codec
*
codec
,
const
char
*
label
,
char
*
dest_label
,
int
nid
)
{
struct
conexant_spec
*
spec
=
codec
->
spec
;
int
i
;
if
(
!
spec
->
fixup_stereo_dmic
)
return
0
;
for
(
i
=
0
;
i
<
AUTO_CFG_MAX_INS
;
i
++
)
{
int
def_conf
;
if
(
spec
->
autocfg
.
inputs
[
i
].
pin
!=
nid
)
continue
;
if
(
spec
->
autocfg
.
inputs
[
i
].
type
!=
AUTO_PIN_MIC
)
return
0
;
def_conf
=
snd_hda_codec_get_pincfg
(
codec
,
nid
);
if
(
snd_hda_get_input_pin_attr
(
def_conf
)
!=
INPUT_PIN_ATTR_INT
)
return
0
;
/* Finally found the inverted internal mic! */
snprintf
(
dest_label
,
44
,
"Inverted %s"
,
label
);
return
1
;
}
return
0
;
}
static
int
cx_auto_add_capture_volume
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
const
char
*
label
,
const
char
*
pfx
,
int
cidx
)
...
...
@@ -4193,14 +4211,25 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
int
i
;
for
(
i
=
0
;
i
<
spec
->
num_adc_nids
;
i
++
)
{
char
rightch_label
[
44
];
hda_nid_t
adc_nid
=
spec
->
adc_nids
[
i
];
int
idx
=
get_input_connection
(
codec
,
adc_nid
,
nid
);
if
(
idx
<
0
)
continue
;
if
(
codec
->
single_adc_amp
)
idx
=
0
;
if
(
cx_auto_get_rightch_label
(
codec
,
label
,
rightch_label
,
nid
))
{
/* Make two independent kcontrols for left and right */
int
err
=
cx_auto_add_volume_idx
(
codec
,
label
,
pfx
,
cidx
,
adc_nid
,
HDA_INPUT
,
idx
,
1
);
if
(
err
<
0
)
return
err
;
return
cx_auto_add_volume_idx
(
codec
,
rightch_label
,
pfx
,
cidx
,
adc_nid
,
HDA_INPUT
,
idx
,
2
);
}
return
cx_auto_add_volume_idx
(
codec
,
label
,
pfx
,
cidx
,
adc_nid
,
HDA_INPUT
,
idx
);
cidx
,
adc_nid
,
HDA_INPUT
,
idx
,
3
);
}
return
0
;
}
...
...
@@ -4213,9 +4242,19 @@ static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx,
int
i
,
con
;
nid
=
spec
->
imux_info
[
idx
].
pin
;
if
(
get_wcaps
(
codec
,
nid
)
&
AC_WCAP_IN_AMP
)
if
(
get_wcaps
(
codec
,
nid
)
&
AC_WCAP_IN_AMP
)
{
char
rightch_label
[
44
];
if
(
cx_auto_get_rightch_label
(
codec
,
label
,
rightch_label
,
nid
))
{
int
err
=
cx_auto_add_volume_idx
(
codec
,
label
,
" Boost"
,
cidx
,
nid
,
HDA_INPUT
,
0
,
1
);
if
(
err
<
0
)
return
err
;
return
cx_auto_add_volume_idx
(
codec
,
rightch_label
,
" Boost"
,
cidx
,
nid
,
HDA_INPUT
,
0
,
2
);
}
return
cx_auto_add_volume
(
codec
,
label
,
" Boost"
,
cidx
,
nid
,
HDA_INPUT
);
}
con
=
__select_input_connection
(
codec
,
spec
->
imux_info
[
idx
].
adc
,
nid
,
&
mux
,
false
,
0
);
if
(
con
<
0
)
...
...
@@ -4370,37 +4409,21 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
/*
* pin fix-up
*/
struct
cxt_pincfg
{
hda_nid_t
nid
;
u32
val
;
};
static
void
apply_pincfg
(
struct
hda_codec
*
codec
,
const
struct
cxt_pincfg
*
cfg
)
{
for
(;
cfg
->
nid
;
cfg
++
)
snd_hda_codec_set_pincfg
(
codec
,
cfg
->
nid
,
cfg
->
val
);
}
static
void
apply_pin_fixup
(
struct
hda_codec
*
codec
,
const
struct
snd_pci_quirk
*
quirk
,
const
struct
cxt_pincfg
**
table
)
{
quirk
=
snd_pci_quirk_lookup
(
codec
->
bus
->
pci
,
quirk
);
if
(
quirk
)
{
snd_printdd
(
KERN_INFO
"hda_codec: applying pincfg for %s
\n
"
,
quirk
->
name
);
apply_pincfg
(
codec
,
table
[
quirk
->
value
]);
}
}
enum
{
CXT_PINCFG_LENOVO_X200
,
CXT_PINCFG_LENOVO_TP410
,
CXT_FIXUP_STEREO_DMIC
,
};
static
void
cxt_fixup_stereo_dmic
(
struct
hda_codec
*
codec
,
const
struct
hda_fixup
*
fix
,
int
action
)
{
struct
conexant_spec
*
spec
=
codec
->
spec
;
spec
->
fixup_stereo_dmic
=
1
;
}
/* ThinkPad X200 & co with cxt5051 */
static
const
struct
cxt_pincfg
cxt_pincfg_lenovo_x200
[]
=
{
static
const
struct
hda_pintbl
cxt_pincfg_lenovo_x200
[]
=
{
{
0x16
,
0x042140ff
},
/* HP (seq# overridden) */
{
0x17
,
0x21a11000
},
/* dock-mic */
{
0x19
,
0x2121103f
},
/* dock-HP */
...
...
@@ -4409,16 +4432,26 @@ static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
};
/* ThinkPad 410/420/510/520, X201 & co with cxt5066 */
static
const
struct
cxt_pincfg
cxt_pincfg_lenovo_tp410
[]
=
{
static
const
struct
hda_pintbl
cxt_pincfg_lenovo_tp410
[]
=
{
{
0x19
,
0x042110ff
},
/* HP (seq# overridden) */
{
0x1a
,
0x21a190f0
},
/* dock-mic */
{
0x1c
,
0x212140ff
},
/* dock-HP */
{}
};
static
const
struct
cxt_pincfg
*
cxt_pincfg_tbl
[]
=
{
[
CXT_PINCFG_LENOVO_X200
]
=
cxt_pincfg_lenovo_x200
,
[
CXT_PINCFG_LENOVO_TP410
]
=
cxt_pincfg_lenovo_tp410
,
static
const
struct
hda_fixup
cxt_fixups
[]
=
{
[
CXT_PINCFG_LENOVO_X200
]
=
{
.
type
=
HDA_FIXUP_PINS
,
.
v
.
pins
=
cxt_pincfg_lenovo_x200
,
},
[
CXT_PINCFG_LENOVO_TP410
]
=
{
.
type
=
HDA_FIXUP_PINS
,
.
v
.
pins
=
cxt_pincfg_lenovo_tp410
,
},
[
CXT_FIXUP_STEREO_DMIC
]
=
{
.
type
=
HDA_FIXUP_FUNC
,
.
v
.
func
=
cxt_fixup_stereo_dmic
,
},
};
static
const
struct
snd_pci_quirk
cxt5051_fixups
[]
=
{
...
...
@@ -4432,6 +4465,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK
(
0x17aa
,
0x215f
,
"Lenovo T510"
,
CXT_PINCFG_LENOVO_TP410
),
SND_PCI_QUIRK
(
0x17aa
,
0x21ce
,
"Lenovo T420"
,
CXT_PINCFG_LENOVO_TP410
),
SND_PCI_QUIRK
(
0x17aa
,
0x21cf
,
"Lenovo T520"
,
CXT_PINCFG_LENOVO_TP410
),
SND_PCI_QUIRK
(
0x17aa
,
0x3975
,
"Lenovo U300s"
,
CXT_FIXUP_STEREO_DMIC
),
{}
};
...
...
@@ -4471,13 +4505,16 @@ static int patch_conexant_auto(struct hda_codec *codec)
case
0x14f15051
:
add_cx5051_fake_mutes
(
codec
);
codec
->
pin_amp_workaround
=
1
;
apply_pin_fixup
(
codec
,
cxt5051_fixups
,
cxt_pincfg_tbl
);
snd_hda_pick_fixup
(
codec
,
NULL
,
cxt5051_fixups
,
cxt_fixups
);
break
;
default:
codec
->
pin_amp_workaround
=
1
;
apply_pin_fixup
(
codec
,
cxt5066_fixups
,
cxt_pincfg_tbl
);
snd_hda_pick_fixup
(
codec
,
NULL
,
cxt5066_fixups
,
cxt_fixups
);
break
;
}
snd_hda_apply_fixup
(
codec
,
HDA_FIXUP_ACT_PRE_PROBE
);
/* Show mute-led control only on HP laptops
* This is a sort of white-list: on HP laptops, EAPD corresponds
* only to the mute-LED without actualy amp function. Meanwhile,
...
...
@@ -4556,6 +4593,12 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = {
.
patch
=
patch_conexant_auto
},
{
.
id
=
0x14f150b9
,
.
name
=
"CX20665"
,
.
patch
=
patch_conexant_auto
},
{
.
id
=
0x14f1510f
,
.
name
=
"CX20751/2"
,
.
patch
=
patch_conexant_auto
},
{
.
id
=
0x14f15110
,
.
name
=
"CX20751/2"
,
.
patch
=
patch_conexant_auto
},
{
.
id
=
0x14f15111
,
.
name
=
"CX20753/4"
,
.
patch
=
patch_conexant_auto
},
{}
/* terminator */
};
...
...
@@ -4576,6 +4619,9 @@ MODULE_ALIAS("snd-hda-codec-id:14f150ab");
MODULE_ALIAS
(
"snd-hda-codec-id:14f150ac"
);
MODULE_ALIAS
(
"snd-hda-codec-id:14f150b8"
);
MODULE_ALIAS
(
"snd-hda-codec-id:14f150b9"
);
MODULE_ALIAS
(
"snd-hda-codec-id:14f1510f"
);
MODULE_ALIAS
(
"snd-hda-codec-id:14f15110"
);
MODULE_ALIAS
(
"snd-hda-codec-id:14f15111"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_DESCRIPTION
(
"Conexant HD-audio codec"
);
...
...
sound/pci/hda/patch_hdmi.c
浏览文件 @
6de15b2a
...
...
@@ -1592,10 +1592,10 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
unsigned
int
dataDCC2
,
channel_id
;
int
i
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hda_spdif_out
*
spdif
=
snd_hda_spdif_out_of_nid
(
codec
,
spec
->
cvts
[
0
].
cvt_nid
);
struct
hda_spdif_out
*
spdif
;
mutex_lock
(
&
codec
->
spdif_mutex
);
spdif
=
snd_hda_spdif_out_of_nid
(
codec
,
spec
->
cvts
[
0
].
cvt_nid
);
chs
=
substream
->
runtime
->
channels
;
...
...
sound/pci/hda/patch_realtek.c
浏览文件 @
6de15b2a
...
...
@@ -32,6 +32,7 @@
#include <sound/jack.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_beep.h"
#include "hda_jack.h"
...
...
@@ -66,8 +67,6 @@ struct alc_customize_define {
unsigned
int
fixup
:
1
;
/* Means that this sku is set by driver, not read from hw */
};
struct
alc_fixup
;
struct
alc_multi_io
{
hda_nid_t
pin
;
/* multi-io widget pin NID */
hda_nid_t
dac
;
/* DAC to be connected */
...
...
@@ -82,19 +81,33 @@ enum {
#define MAX_VOL_NIDS 0x40
/* make compatible with old code */
#define alc_apply_pincfgs snd_hda_apply_pincfgs
#define alc_apply_fixup snd_hda_apply_fixup
#define alc_pick_fixup snd_hda_pick_fixup
#define alc_fixup hda_fixup
#define alc_pincfg hda_pintbl
#define alc_model_fixup hda_model_fixup
#define ALC_FIXUP_PINS HDA_FIXUP_PINS
#define ALC_FIXUP_VERBS HDA_FIXUP_VERBS
#define ALC_FIXUP_FUNC HDA_FIXUP_FUNC
#define ALC_FIXUP_ACT_PRE_PROBE HDA_FIXUP_ACT_PRE_PROBE
#define ALC_FIXUP_ACT_PROBE HDA_FIXUP_ACT_PROBE
#define ALC_FIXUP_ACT_INIT HDA_FIXUP_ACT_INIT
#define ALC_FIXUP_ACT_BUILD HDA_FIXUP_ACT_BUILD
struct
alc_spec
{
struct
hda_gen_spec
gen
;
/* codec parameterization */
const
struct
snd_kcontrol_new
*
mixers
[
5
];
/* mixer arrays */
unsigned
int
num_mixers
;
const
struct
snd_kcontrol_new
*
cap_mixer
;
/* capture mixer */
unsigned
int
beep_amp
;
/* beep amp value, set via set_beep_amp() */
const
struct
hda_verb
*
init_verbs
[
10
];
/* initialization verbs
* don't forget NULL
* termination!
*/
unsigned
int
num_init_verbs
;
char
stream_name_analog
[
32
];
/* analog PCM stream */
const
struct
hda_pcm_stream
*
stream_analog_playback
;
const
struct
hda_pcm_stream
*
stream_analog_capture
;
...
...
@@ -210,11 +223,6 @@ struct alc_spec {
unsigned
int
pll_coef_idx
,
pll_coef_bit
;
unsigned
int
coef0
;
/* fix-up list */
int
fixup_id
;
const
struct
alc_fixup
*
fixup_list
;
const
char
*
fixup_name
;
/* multi-io */
int
multi_ios
;
struct
alc_multi_io
multi_io
[
4
];
...
...
@@ -319,13 +327,16 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
/* for shared I/O, change the pin-control accordingly */
if
(
spec
->
shared_mic_hp
)
{
unsigned
int
val
;
hda_nid_t
pin
=
spec
->
autocfg
.
inputs
[
1
].
pin
;
/* NOTE: this assumes that there are only two inputs, the
* first is the real internal mic and the second is HP jack.
*/
snd_hda_codec_write
(
codec
,
spec
->
autocfg
.
inputs
[
1
].
pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
spec
->
cur_mux
[
adc_idx
]
?
PIN_VREF80
:
PIN_HP
);
if
(
spec
->
cur_mux
[
adc_idx
])
val
=
snd_hda_get_default_vref
(
codec
,
pin
)
|
PIN_IN
;
else
val
=
PIN_HP
;
snd_hda_set_pin_ctl
(
codec
,
pin
,
val
);
spec
->
automute_speaker
=
!
spec
->
cur_mux
[
adc_idx
];
call_update_outputs
(
codec
);
}
...
...
@@ -338,7 +349,7 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
nid
=
get_capsrc
(
spec
,
adc_idx
);
/* no selection? */
num_conns
=
snd_hda_get_
conn_list
(
codec
,
nid
,
NULL
);
num_conns
=
snd_hda_get_
num_conns
(
codec
,
nid
);
if
(
num_conns
<=
1
)
return
1
;
...
...
@@ -376,25 +387,9 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
int
auto_pin_type
)
{
unsigned
int
val
=
PIN_IN
;
if
(
auto_pin_type
==
AUTO_PIN_MIC
)
{
unsigned
int
pincap
;
unsigned
int
oldval
;
oldval
=
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_PIN_WIDGET_CONTROL
,
0
);
pincap
=
snd_hda_query_pin_caps
(
codec
,
nid
);
pincap
=
(
pincap
&
AC_PINCAP_VREF
)
>>
AC_PINCAP_VREF_SHIFT
;
/* if the default pin setup is vref50, we give it priority */
if
((
pincap
&
AC_PINCAP_VREF_80
)
&&
oldval
!=
PIN_VREF50
)
val
=
PIN_VREF80
;
else
if
(
pincap
&
AC_PINCAP_VREF_50
)
val
=
PIN_VREF50
;
else
if
(
pincap
&
AC_PINCAP_VREF_100
)
val
=
PIN_VREF100
;
else
if
(
pincap
&
AC_PINCAP_VREF_GRD
)
val
=
PIN_VREFGRD
;
}
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
val
);
if
(
auto_pin_type
==
AUTO_PIN_MIC
)
val
|=
snd_hda_get_default_vref
(
codec
,
nid
);
snd_hda_set_pin_ctl
(
codec
,
nid
,
val
);
}
/*
...
...
@@ -409,13 +404,6 @@ static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
mix
;
}
static
void
add_verb
(
struct
alc_spec
*
spec
,
const
struct
hda_verb
*
verb
)
{
if
(
snd_BUG_ON
(
spec
->
num_init_verbs
>=
ARRAY_SIZE
(
spec
->
init_verbs
)))
return
;
spec
->
init_verbs
[
spec
->
num_init_verbs
++
]
=
verb
;
}
/*
* GPIO setup tables, used in initialization
*/
...
...
@@ -517,9 +505,7 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
}
else
val
=
0
;
val
|=
pin_bits
;
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
val
);
snd_hda_set_pin_ctl
(
codec
,
nid
,
val
);
break
;
case
ALC_AUTOMUTE_AMP
:
snd_hda_codec_amp_stereo
(
codec
,
nid
,
HDA_OUTPUT
,
0
,
...
...
@@ -1200,6 +1186,16 @@ static void alc_auto_check_switches(struct hda_codec *codec)
*/
#define ALC_FIXUP_SKU_IGNORE (2)
static
void
alc_fixup_sku_ignore
(
struct
hda_codec
*
codec
,
const
struct
hda_fixup
*
fix
,
int
action
)
{
struct
alc_spec
*
spec
=
codec
->
spec
;
if
(
action
==
HDA_FIXUP_ACT_PRE_PROBE
)
{
spec
->
cdefine
.
fixup
=
1
;
spec
->
cdefine
.
sku_cfg
=
ALC_FIXUP_SKU_IGNORE
;
}
}
static
int
alc_auto_parse_customize_define
(
struct
hda_codec
*
codec
)
{
unsigned
int
ass
,
tmp
,
i
;
...
...
@@ -1402,178 +1398,6 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
}
}
/*
* Fix-up pin default configurations and add default verbs
*/
struct
alc_pincfg
{
hda_nid_t
nid
;
u32
val
;
};
struct
alc_model_fixup
{
const
int
id
;
const
char
*
name
;
};
struct
alc_fixup
{
int
type
;
bool
chained
;
int
chain_id
;
union
{
unsigned
int
sku
;
const
struct
alc_pincfg
*
pins
;
const
struct
hda_verb
*
verbs
;
void
(
*
func
)(
struct
hda_codec
*
codec
,
const
struct
alc_fixup
*
fix
,
int
action
);
}
v
;
};
enum
{
ALC_FIXUP_INVALID
,
ALC_FIXUP_SKU
,
ALC_FIXUP_PINS
,
ALC_FIXUP_VERBS
,
ALC_FIXUP_FUNC
,
};
enum
{
ALC_FIXUP_ACT_PRE_PROBE
,
ALC_FIXUP_ACT_PROBE
,
ALC_FIXUP_ACT_INIT
,
ALC_FIXUP_ACT_BUILD
,
};
static
void
alc_apply_pincfgs
(
struct
hda_codec
*
codec
,
const
struct
alc_pincfg
*
cfg
)
{
for
(;
cfg
->
nid
;
cfg
++
)
snd_hda_codec_set_pincfg
(
codec
,
cfg
->
nid
,
cfg
->
val
);
}
static
void
alc_apply_fixup
(
struct
hda_codec
*
codec
,
int
action
)
{
struct
alc_spec
*
spec
=
codec
->
spec
;
int
id
=
spec
->
fixup_id
;
#ifdef CONFIG_SND_DEBUG_VERBOSE
const
char
*
modelname
=
spec
->
fixup_name
;
#endif
int
depth
=
0
;
if
(
!
spec
->
fixup_list
)
return
;
while
(
id
>=
0
)
{
const
struct
alc_fixup
*
fix
=
spec
->
fixup_list
+
id
;
const
struct
alc_pincfg
*
cfg
;
switch
(
fix
->
type
)
{
case
ALC_FIXUP_SKU
:
if
(
action
!=
ALC_FIXUP_ACT_PRE_PROBE
||
!
fix
->
v
.
sku
)
break
;
snd_printdd
(
KERN_INFO
"hda_codec: %s: "
"Apply sku override for %s
\n
"
,
codec
->
chip_name
,
modelname
);
spec
->
cdefine
.
sku_cfg
=
fix
->
v
.
sku
;
spec
->
cdefine
.
fixup
=
1
;
break
;
case
ALC_FIXUP_PINS
:
cfg
=
fix
->
v
.
pins
;
if
(
action
!=
ALC_FIXUP_ACT_PRE_PROBE
||
!
cfg
)
break
;
snd_printdd
(
KERN_INFO
"hda_codec: %s: "
"Apply pincfg for %s
\n
"
,
codec
->
chip_name
,
modelname
);
alc_apply_pincfgs
(
codec
,
cfg
);
break
;
case
ALC_FIXUP_VERBS
:
if
(
action
!=
ALC_FIXUP_ACT_PROBE
||
!
fix
->
v
.
verbs
)
break
;
snd_printdd
(
KERN_INFO
"hda_codec: %s: "
"Apply fix-verbs for %s
\n
"
,
codec
->
chip_name
,
modelname
);
add_verb
(
codec
->
spec
,
fix
->
v
.
verbs
);
break
;
case
ALC_FIXUP_FUNC
:
if
(
!
fix
->
v
.
func
)
break
;
snd_printdd
(
KERN_INFO
"hda_codec: %s: "
"Apply fix-func for %s
\n
"
,
codec
->
chip_name
,
modelname
);
fix
->
v
.
func
(
codec
,
fix
,
action
);
break
;
default:
snd_printk
(
KERN_ERR
"hda_codec: %s: "
"Invalid fixup type %d
\n
"
,
codec
->
chip_name
,
fix
->
type
);
break
;
}
if
(
!
fix
->
chained
)
break
;
if
(
++
depth
>
10
)
break
;
id
=
fix
->
chain_id
;
}
}
static
void
alc_pick_fixup
(
struct
hda_codec
*
codec
,
const
struct
alc_model_fixup
*
models
,
const
struct
snd_pci_quirk
*
quirk
,
const
struct
alc_fixup
*
fixlist
)
{
struct
alc_spec
*
spec
=
codec
->
spec
;
const
struct
snd_pci_quirk
*
q
;
int
id
=
-
1
;
const
char
*
name
=
NULL
;
/* when model=nofixup is given, don't pick up any fixups */
if
(
codec
->
modelname
&&
!
strcmp
(
codec
->
modelname
,
"nofixup"
))
{
spec
->
fixup_list
=
NULL
;
spec
->
fixup_id
=
-
1
;
return
;
}
if
(
codec
->
modelname
&&
models
)
{
while
(
models
->
name
)
{
if
(
!
strcmp
(
codec
->
modelname
,
models
->
name
))
{
id
=
models
->
id
;
name
=
models
->
name
;
break
;
}
models
++
;
}
}
if
(
id
<
0
)
{
q
=
snd_pci_quirk_lookup
(
codec
->
bus
->
pci
,
quirk
);
if
(
q
)
{
id
=
q
->
value
;
#ifdef CONFIG_SND_DEBUG_VERBOSE
name
=
q
->
name
;
#endif
}
}
if
(
id
<
0
)
{
for
(
q
=
quirk
;
q
->
subvendor
;
q
++
)
{
unsigned
int
vendorid
=
q
->
subdevice
|
(
q
->
subvendor
<<
16
);
if
(
vendorid
==
codec
->
subsystem_id
)
{
id
=
q
->
value
;
#ifdef CONFIG_SND_DEBUG_VERBOSE
name
=
q
->
name
;
#endif
break
;
}
}
}
spec
->
fixup_id
=
id
;
if
(
id
>=
0
)
{
spec
->
fixup_list
=
fixlist
;
spec
->
fixup_name
=
name
;
}
}
/*
* COEF access helper functions
*/
...
...
@@ -1621,8 +1445,7 @@ static void alc_auto_init_digital(struct hda_codec *codec)
pin
=
spec
->
autocfg
.
dig_out_pins
[
i
];
if
(
!
pin
)
continue
;
snd_hda_codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
);
snd_hda_set_pin_ctl
(
codec
,
pin
,
PIN_OUT
);
if
(
!
i
)
dac
=
spec
->
multiout
.
dig_out_nid
;
else
...
...
@@ -1635,9 +1458,7 @@ static void alc_auto_init_digital(struct hda_codec *codec)
}
pin
=
spec
->
autocfg
.
dig_in_pin
;
if
(
pin
)
snd_hda_codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
);
snd_hda_set_pin_ctl
(
codec
,
pin
,
PIN_IN
);
}
/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
...
...
@@ -2068,7 +1889,6 @@ static void alc_auto_init_std(struct hda_codec *codec);
static
int
alc_init
(
struct
hda_codec
*
codec
)
{
struct
alc_spec
*
spec
=
codec
->
spec
;
unsigned
int
i
;
if
(
spec
->
init_hook
)
spec
->
init_hook
(
codec
);
...
...
@@ -2076,8 +1896,6 @@ static int alc_init(struct hda_codec *codec)
alc_fix_pll
(
codec
);
alc_auto_init_amp
(
codec
,
spec
->
init_amp
);
for
(
i
=
0
;
i
<
spec
->
num_init_verbs
;
i
++
)
snd_hda_sequence_write
(
codec
,
spec
->
init_verbs
[
i
]);
alc_init_special_input_src
(
codec
);
alc_auto_init_std
(
codec
);
...
...
@@ -2725,7 +2543,6 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec)
nid
=
codec
->
start_nid
;
for
(
i
=
0
;
i
<
codec
->
num_nodes
;
i
++
,
nid
++
)
{
hda_nid_t
src
;
const
hda_nid_t
*
list
;
unsigned
int
caps
=
get_wcaps
(
codec
,
nid
);
int
type
=
get_wcaps_type
(
caps
);
...
...
@@ -2743,13 +2560,14 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec)
cap_nids
[
nums
]
=
src
;
break
;
}
n
=
snd_hda_get_
conn_list
(
codec
,
src
,
&
list
);
n
=
snd_hda_get_
num_conns
(
codec
,
src
);
if
(
n
>
1
)
{
cap_nids
[
nums
]
=
src
;
break
;
}
else
if
(
n
!=
1
)
break
;
src
=
*
list
;
if
(
snd_hda_get_connections
(
codec
,
src
,
&
src
,
1
)
!=
1
)
break
;
}
if
(
++
nums
>=
max_nums
)
break
;
...
...
@@ -2856,8 +2674,7 @@ static int alc_auto_create_shared_input(struct hda_codec *codec)
static
void
alc_set_pin_output
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
unsigned
int
pin_type
)
{
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pin_type
);
snd_hda_set_pin_ctl
(
codec
,
nid
,
pin_type
);
/* unmute pin */
if
(
nid_has_mute
(
codec
,
nid
,
HDA_OUTPUT
))
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
...
...
@@ -2891,7 +2708,7 @@ static void alc_auto_init_analog_input(struct hda_codec *codec)
/* mute all loopback inputs */
if
(
spec
->
mixer_nid
)
{
int
nums
=
snd_hda_get_
conn_list
(
codec
,
spec
->
mixer_nid
,
NULL
);
int
nums
=
snd_hda_get_
num_conns
(
codec
,
spec
->
mixer_nid
);
for
(
i
=
0
;
i
<
nums
;
i
++
)
snd_hda_codec_write
(
codec
,
spec
->
mixer_nid
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
...
...
@@ -3521,7 +3338,7 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec,
if
(
wid_type
==
AC_WID_PIN
||
wid_type
==
AC_WID_AUD_OUT
)
{
type
=
ALC_CTL_WIDGET_MUTE
;
val
=
HDA_COMPOSE_AMP_VAL
(
nid
,
chs
,
0
,
HDA_OUTPUT
);
}
else
if
(
snd_hda_get_
conn_list
(
codec
,
nid
,
NULL
)
==
1
)
{
}
else
if
(
snd_hda_get_
num_conns
(
codec
,
nid
)
==
1
)
{
type
=
ALC_CTL_WIDGET_MUTE
;
val
=
HDA_COMPOSE_AMP_VAL
(
nid
,
chs
,
0
,
HDA_INPUT
);
}
else
{
...
...
@@ -3998,9 +3815,7 @@ static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_PIN_WIDGET_CONTROL
,
0
);
if
(
output
)
{
snd_hda_codec_update_cache
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
);
snd_hda_set_pin_ctl_cache
(
codec
,
nid
,
PIN_OUT
);
if
(
get_wcaps
(
codec
,
nid
)
&
AC_WCAP_OUT_AMP
)
snd_hda_codec_amp_stereo
(
codec
,
nid
,
HDA_OUTPUT
,
0
,
HDA_AMP_MUTE
,
0
);
...
...
@@ -4009,9 +3824,8 @@ static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
if
(
get_wcaps
(
codec
,
nid
)
&
AC_WCAP_OUT_AMP
)
snd_hda_codec_amp_stereo
(
codec
,
nid
,
HDA_OUTPUT
,
0
,
HDA_AMP_MUTE
,
HDA_AMP_MUTE
);
snd_hda_codec_update_cache
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
spec
->
multi_io
[
idx
].
ctl_in
);
snd_hda_set_pin_ctl_cache
(
codec
,
nid
,
spec
->
multi_io
[
idx
].
ctl_in
);
}
return
0
;
}
...
...
@@ -4084,7 +3898,7 @@ static void alc_remove_invalid_adc_nids(struct hda_codec *codec)
nums
=
0
;
for
(
n
=
0
;
n
<
spec
->
num_adc_nids
;
n
++
)
{
hda_nid_t
cap
=
spec
->
private_capsrc_nids
[
n
];
int
num_conns
=
snd_hda_get_
conn_list
(
codec
,
cap
,
NULL
);
int
num_conns
=
snd_hda_get_
num_conns
(
codec
,
cap
);
for
(
i
=
0
;
i
<
imux
->
num_items
;
i
++
)
{
hda_nid_t
pin
=
spec
->
imux_pins
[
i
];
if
(
pin
)
{
...
...
@@ -4213,7 +4027,7 @@ static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
if
(
get_wcaps_type
(
get_wcaps
(
codec
,
cap
))
==
AC_WID_AUD_MIX
)
{
snd_hda_codec_amp_stereo
(
codec
,
cap
,
HDA_INPUT
,
idx
,
HDA_AMP_MUTE
,
0
);
}
else
if
(
snd_hda_get_
conn_list
(
codec
,
cap
,
NULL
)
>
1
)
{
}
else
if
(
snd_hda_get_
num_conns
(
codec
,
cap
)
>
1
)
{
snd_hda_codec_write_cache
(
codec
,
cap
,
0
,
AC_VERB_SET_CONNECT_SEL
,
idx
);
}
...
...
@@ -4427,6 +4241,25 @@ static int alc_parse_auto_config(struct hda_codec *codec,
return
1
;
}
/* common preparation job for alc_spec */
static
int
alc_alloc_spec
(
struct
hda_codec
*
codec
,
hda_nid_t
mixer_nid
)
{
struct
alc_spec
*
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
int
err
;
if
(
!
spec
)
return
-
ENOMEM
;
codec
->
spec
=
spec
;
spec
->
mixer_nid
=
mixer_nid
;
err
=
alc_codec_rename_from_preset
(
codec
);
if
(
err
<
0
)
{
kfree
(
spec
);
return
err
;
}
return
0
;
}
static
int
alc880_parse_auto_config
(
struct
hda_codec
*
codec
)
{
static
const
hda_nid_t
alc880_ignore
[]
=
{
0x1d
,
0
};
...
...
@@ -4808,13 +4641,11 @@ static int patch_alc880(struct hda_codec *codec)
struct
alc_spec
*
spec
;
int
err
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
spec
==
NULL
)
return
-
ENOMEM
;
codec
->
spec
=
spec
;
err
=
alc_alloc_spec
(
codec
,
0x0b
);
if
(
err
<
0
)
return
err
;
spec
->
mixer_nid
=
0x0b
;
spec
=
codec
->
spec
;
spec
->
need_dac_fix
=
1
;
alc_pick_fixup
(
codec
,
alc880_fixup_models
,
alc880_fixup_tbl
,
...
...
@@ -4890,7 +4721,7 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
spec
->
autocfg
.
hp_pins
[
0
]
=
0x0f
;
/* copy it for automute */
snd_hda_jack_detect_enable
(
codec
,
0x0f
,
ALC_HP_EVENT
);
spec
->
unsol_event
=
alc_sku_unsol_event
;
add_verb
(
codec
->
spec
,
alc_gpio1_init_verbs
);
snd_hda_gen_add_verbs
(
&
spec
->
gen
,
alc_gpio1_init_verbs
);
}
}
...
...
@@ -5001,13 +4832,11 @@ static int patch_alc260(struct hda_codec *codec)
struct
alc_spec
*
spec
;
int
err
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
spec
==
NULL
)
return
-
ENOMEM
;
codec
->
spec
=
spec
;
err
=
alc_alloc_spec
(
codec
,
0x07
);
if
(
err
<
0
)
return
err
;
spec
->
mixer_nid
=
0x07
;
spec
=
codec
->
spec
;
alc_pick_fixup
(
codec
,
NULL
,
alc260_fixup_tbl
,
alc260_fixups
);
alc_apply_fixup
(
codec
,
ALC_FIXUP_ACT_PRE_PROBE
);
...
...
@@ -5171,8 +5000,7 @@ static void alc889_fixup_mbp_vref(struct hda_codec *codec,
val
=
snd_hda_codec_read
(
codec
,
nids
[
i
],
0
,
AC_VERB_GET_PIN_WIDGET_CONTROL
,
0
);
val
|=
AC_PINCTL_VREF_80
;
snd_hda_codec_write
(
codec
,
nids
[
i
],
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
val
);
snd_hda_set_pin_ctl
(
codec
,
nids
[
i
],
val
);
spec
->
keep_vref_in_automute
=
1
;
break
;
}
...
...
@@ -5193,8 +5021,7 @@ static void alc889_fixup_imac91_vref(struct hda_codec *codec,
val
=
snd_hda_codec_read
(
codec
,
nids
[
i
],
0
,
AC_VERB_GET_PIN_WIDGET_CONTROL
,
0
);
val
|=
AC_PINCTL_VREF_50
;
snd_hda_codec_write
(
codec
,
nids
[
i
],
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
val
);
snd_hda_set_pin_ctl
(
codec
,
nids
[
i
],
val
);
}
spec
->
keep_vref_in_automute
=
1
;
}
...
...
@@ -5225,8 +5052,8 @@ static const struct alc_fixup alc882_fixups[] = {
}
},
[
ALC882_FIXUP_ACER_ASPIRE_7736
]
=
{
.
type
=
ALC_FIXUP_
SKU
,
.
v
.
sku
=
ALC_FIXUP_SKU_IGNORE
,
.
type
=
ALC_FIXUP_
FUNC
,
.
v
.
func
=
alc_fixup_sku_ignore
,
},
[
ALC882_FIXUP_ASUS_W90V
]
=
{
.
type
=
ALC_FIXUP_PINS
,
...
...
@@ -5476,13 +5303,11 @@ static int patch_alc882(struct hda_codec *codec)
struct
alc_spec
*
spec
;
int
err
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
spec
==
NULL
)
return
-
ENOMEM
;
codec
->
spec
=
spec
;
err
=
alc_alloc_spec
(
codec
,
0x0b
);
if
(
err
<
0
)
return
err
;
spec
->
mixer_nid
=
0x0b
;
spec
=
codec
->
spec
;
switch
(
codec
->
vendor_id
)
{
case
0x10ec0882
:
...
...
@@ -5494,10 +5319,6 @@ static int patch_alc882(struct hda_codec *codec)
break
;
}
err
=
alc_codec_rename_from_preset
(
codec
);
if
(
err
<
0
)
goto
error
;
alc_pick_fixup
(
codec
,
alc882_fixup_models
,
alc882_fixup_tbl
,
alc882_fixups
);
alc_apply_fixup
(
codec
,
ALC_FIXUP_ACT_PRE_PROBE
);
...
...
@@ -5621,13 +5442,11 @@ static int patch_alc262(struct hda_codec *codec)
struct
alc_spec
*
spec
;
int
err
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
spec
==
NULL
)
return
-
ENOMEM
;
codec
->
spec
=
spec
;
err
=
alc_alloc_spec
(
codec
,
0x0b
);
if
(
err
<
0
)
return
err
;
spec
->
mixer_nid
=
0x0b
;
spec
=
codec
->
spec
;
#if 0
/* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
...
...
@@ -5710,7 +5529,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
if
(
err
>
0
)
{
if
(
!
spec
->
no_analog
&&
spec
->
autocfg
.
speaker_pins
[
0
]
!=
0x1d
)
{
add_mixer
(
spec
,
alc268_beep_mixer
);
add_verb
(
spec
,
alc268_beep_init_verbs
);
snd_hda_gen_add_verbs
(
&
spec
->
gen
,
alc268_beep_init_verbs
);
}
}
return
err
;
...
...
@@ -5723,13 +5542,12 @@ static int patch_alc268(struct hda_codec *codec)
struct
alc_spec
*
spec
;
int
i
,
has_beep
,
err
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
spec
==
NULL
)
return
-
ENOMEM
;
codec
->
spec
=
spec
;
/* ALC268 has no aa-loopback mixer */
err
=
alc_alloc_spec
(
codec
,
0
);
if
(
err
<
0
)
return
err
;
spec
=
codec
->
spec
;
/* automatic parse from the BIOS config */
err
=
alc268_parse_auto_config
(
codec
);
...
...
@@ -5946,9 +5764,7 @@ static void alc269_fixup_mic2_mute_hook(void *private_data, int enabled)
{
struct
hda_codec
*
codec
=
private_data
;
unsigned
int
pinval
=
enabled
?
0x20
:
0x24
;
snd_hda_codec_update_cache
(
codec
,
0x19
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pinval
);
snd_hda_set_pin_ctl_cache
(
codec
,
0x19
,
pinval
);
}
static
void
alc269_fixup_mic2_mute
(
struct
hda_codec
*
codec
,
...
...
@@ -6015,8 +5831,8 @@ static const struct alc_fixup alc269_fixups[] = {
}
},
[
ALC269_FIXUP_SKU_IGNORE
]
=
{
.
type
=
ALC_FIXUP_
SKU
,
.
v
.
sku
=
ALC_FIXUP_SKU_IGNORE
,
.
type
=
ALC_FIXUP_
FUNC
,
.
v
.
func
=
alc_fixup_sku_ignore
,
},
[
ALC269_FIXUP_ASUS_G73JW
]
=
{
.
type
=
ALC_FIXUP_PINS
,
...
...
@@ -6242,19 +6058,13 @@ static void alc269_fill_coef(struct hda_codec *codec)
static
int
patch_alc269
(
struct
hda_codec
*
codec
)
{
struct
alc_spec
*
spec
;
int
err
=
0
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
spec
==
NULL
)
return
-
ENOMEM
;
codec
->
spec
=
spec
;
spec
->
mixer_nid
=
0x0b
;
int
err
;
err
=
alc_
codec_rename_from_preset
(
codec
);
err
=
alc_
alloc_spec
(
codec
,
0x0b
);
if
(
err
<
0
)
goto
error
;
return
err
;
spec
=
codec
->
spec
;
if
(
codec
->
vendor_id
==
0x10ec0269
)
{
spec
->
codec_variant
=
ALC269_TYPE_ALC269VA
;
...
...
@@ -6346,8 +6156,7 @@ static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
if
(
!
(
val
&
(
AC_PINCTL_IN_EN
|
AC_PINCTL_OUT_EN
)))
val
|=
AC_PINCTL_IN_EN
;
val
|=
AC_PINCTL_VREF_50
;
snd_hda_codec_write
(
codec
,
0x0f
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
val
);
snd_hda_set_pin_ctl
(
codec
,
0x0f
,
val
);
spec
->
keep_vref_in_automute
=
1
;
}
...
...
@@ -6401,13 +6210,11 @@ static int patch_alc861(struct hda_codec *codec)
struct
alc_spec
*
spec
;
int
err
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
spec
==
NULL
)
return
-
ENOMEM
;
codec
->
spec
=
spec
;
err
=
alc_alloc_spec
(
codec
,
0x15
);
if
(
err
<
0
)
return
err
;
spec
->
mixer_nid
=
0x15
;
spec
=
codec
->
spec
;
alc_pick_fixup
(
codec
,
NULL
,
alc861_fixup_tbl
,
alc861_fixups
);
alc_apply_fixup
(
codec
,
ALC_FIXUP_ACT_PRE_PROBE
);
...
...
@@ -6504,13 +6311,11 @@ static int patch_alc861vd(struct hda_codec *codec)
struct
alc_spec
*
spec
;
int
err
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
spec
==
NULL
)
return
-
ENOMEM
;
codec
->
spec
=
spec
;
err
=
alc_alloc_spec
(
codec
,
0x0b
);
if
(
err
<
0
)
return
err
;
spec
->
mixer_nid
=
0x0b
;
spec
=
codec
->
spec
;
alc_pick_fixup
(
codec
,
NULL
,
alc861vd_fixup_tbl
,
alc861vd_fixups
);
alc_apply_fixup
(
codec
,
ALC_FIXUP_ACT_PRE_PROBE
);
...
...
@@ -6522,7 +6327,7 @@ static int patch_alc861vd(struct hda_codec *codec)
if
(
codec
->
vendor_id
==
0x10ec0660
)
{
/* always turn on EAPD */
add_verb
(
spec
,
alc660vd_eapd_verbs
);
snd_hda_gen_add_verbs
(
&
spec
->
gen
,
alc660vd_eapd_verbs
);
}
if
(
!
spec
->
no_analog
)
{
...
...
@@ -6635,8 +6440,8 @@ static const struct alc_fixup alc662_fixups[] = {
}
},
[
ALC662_FIXUP_SKU_IGNORE
]
=
{
.
type
=
ALC_FIXUP_
SKU
,
.
v
.
sku
=
ALC_FIXUP_SKU_IGNORE
,
.
type
=
ALC_FIXUP_
FUNC
,
.
v
.
func
=
alc_fixup_sku_ignore
,
},
[
ALC662_FIXUP_HP_RP5800
]
=
{
.
type
=
ALC_FIXUP_PINS
,
...
...
@@ -6849,25 +6654,19 @@ static const struct alc_model_fixup alc662_fixup_models[] = {
static
int
patch_alc662
(
struct
hda_codec
*
codec
)
{
struct
alc_spec
*
spec
;
int
err
=
0
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
!
spec
)
return
-
ENOMEM
;
int
err
;
codec
->
spec
=
spec
;
err
=
alc_alloc_spec
(
codec
,
0x0b
);
if
(
err
<
0
)
return
err
;
spec
->
mixer_nid
=
0x0b
;
spec
=
codec
->
spec
;
/* handle multiple HPs as is */
spec
->
parse_flags
=
HDA_PINCFG_NO_HP_FIXUP
;
alc_fix_pll_init
(
codec
,
0x20
,
0x04
,
15
);
err
=
alc_codec_rename_from_preset
(
codec
);
if
(
err
<
0
)
goto
error
;
if
((
alc_get_coef0
(
codec
)
&
(
1
<<
14
))
&&
codec
->
bus
->
pci
->
subsystem_vendor
==
0x1025
&&
spec
->
cdefine
.
platform_type
==
1
)
{
...
...
@@ -6930,16 +6729,12 @@ static int alc680_parse_auto_config(struct hda_codec *codec)
*/
static
int
patch_alc680
(
struct
hda_codec
*
codec
)
{
struct
alc_spec
*
spec
;
int
err
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
spec
==
NULL
)
return
-
ENOMEM
;
codec
->
spec
=
spec
;
/* ALC680 has no aa-loopback mixer */
err
=
alc_alloc_spec
(
codec
,
0
);
if
(
err
<
0
)
return
err
;
/* automatic parse from the BIOS config */
err
=
alc680_parse_auto_config
(
codec
);
...
...
sound/pci/hda/patch_sigmatel.c
浏览文件 @
6de15b2a
...
...
@@ -36,6 +36,7 @@
#include <sound/tlv.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_beep.h"
#include "hda_jack.h"
...
...
@@ -221,6 +222,7 @@ struct sigmatel_spec {
unsigned
char
aloopback_shift
;
/* power management */
unsigned
int
power_map_bits
;
unsigned
int
num_pwrs
;
const
hda_nid_t
*
pwr_nids
;
const
hda_nid_t
*
dac_list
;
...
...
@@ -314,6 +316,9 @@ struct sigmatel_spec {
struct
hda_vmaster_mute_hook
vmaster_mute
;
};
#define AC_VERB_IDT_SET_POWER_MAP 0x7ec
#define AC_VERB_IDT_GET_POWER_MAP 0xfec
static
const
hda_nid_t
stac9200_adc_nids
[
1
]
=
{
0x03
,
};
...
...
@@ -681,8 +686,7 @@ static int stac_vrefout_set(struct hda_codec *codec,
pinctl
&=
~
AC_PINCTL_VREFEN
;
pinctl
|=
(
new_vref
&
AC_PINCTL_VREFEN
);
error
=
snd_hda_codec_write_cache
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pinctl
);
error
=
snd_hda_set_pin_ctl_cache
(
codec
,
nid
,
pinctl
);
if
(
error
<
0
)
return
error
;
...
...
@@ -706,8 +710,7 @@ static unsigned int stac92xx_vref_set(struct hda_codec *codec,
else
pincfg
|=
AC_PINCTL_IN_EN
;
error
=
snd_hda_codec_write_cache
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pincfg
);
error
=
snd_hda_set_pin_ctl_cache
(
codec
,
nid
,
pincfg
);
if
(
error
<
0
)
return
error
;
else
...
...
@@ -2505,27 +2508,10 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
return
0
;
}
static
unsigned
int
stac92xx_get_default_vref
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
unsigned
int
pincap
=
snd_hda_query_pin_caps
(
codec
,
nid
);
pincap
=
(
pincap
&
AC_PINCAP_VREF
)
>>
AC_PINCAP_VREF_SHIFT
;
if
(
pincap
&
AC_PINCAP_VREF_100
)
return
AC_PINCTL_VREF_100
;
if
(
pincap
&
AC_PINCAP_VREF_80
)
return
AC_PINCTL_VREF_80
;
if
(
pincap
&
AC_PINCAP_VREF_50
)
return
AC_PINCTL_VREF_50
;
if
(
pincap
&
AC_PINCAP_VREF_GRD
)
return
AC_PINCTL_VREF_GRD
;
return
0
;
}
static
void
stac92xx_auto_set_pinctl
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
pin_type
)
{
snd_hda_codec_write_cache
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pin_type
);
snd_hda_set_pin_ctl_cache
(
codec
,
nid
,
pin_type
);
}
#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
...
...
@@ -2594,7 +2580,7 @@ static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
hda_nid_t
nid
=
kcontrol
->
private_value
;
unsigned
int
vref
=
stac92xx_vref_get
(
codec
,
nid
);
if
(
vref
==
s
tac92xx
_get_default_vref
(
codec
,
nid
))
if
(
vref
==
s
nd_hda
_get_default_vref
(
codec
,
nid
))
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
0
;
else
if
(
vref
==
AC_PINCTL_VREF_GRD
)
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
1
;
...
...
@@ -2613,7 +2599,7 @@ static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
hda_nid_t
nid
=
kcontrol
->
private_value
;
if
(
ucontrol
->
value
.
enumerated
.
item
[
0
]
==
0
)
new_vref
=
s
tac92xx
_get_default_vref
(
codec
,
nid
);
new_vref
=
s
nd_hda
_get_default_vref
(
codec
,
nid
);
else
if
(
ucontrol
->
value
.
enumerated
.
item
[
0
]
==
1
)
new_vref
=
AC_PINCTL_VREF_GRD
;
else
if
(
ucontrol
->
value
.
enumerated
.
item
[
0
]
==
2
)
...
...
@@ -2679,7 +2665,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
else
{
unsigned
int
pinctl
=
AC_PINCTL_IN_EN
;
if
(
io_idx
)
/* set VREF for mic */
pinctl
|=
s
tac92xx
_get_default_vref
(
codec
,
nid
);
pinctl
|=
s
nd_hda
_get_default_vref
(
codec
,
nid
);
stac92xx_auto_set_pinctl
(
codec
,
nid
,
pinctl
);
}
...
...
@@ -2847,7 +2833,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
char
name
[
22
];
if
(
snd_hda_get_input_pin_attr
(
def_conf
)
!=
INPUT_PIN_ATTR_INT
)
{
if
(
s
tac92xx
_get_default_vref
(
codec
,
nid
)
==
AC_PINCTL_VREF_GRD
if
(
s
nd_hda
_get_default_vref
(
codec
,
nid
)
==
AC_PINCTL_VREF_GRD
&&
nid
==
spec
->
line_switch
)
control
=
STAC_CTL_WIDGET_IO_SWITCH
;
else
if
(
snd_hda_query_pin_caps
(
codec
,
nid
)
...
...
@@ -4250,13 +4236,6 @@ static void stac_store_hints(struct hda_codec *codec)
val
=
snd_hda_get_bool_hint
(
codec
,
"eapd_switch"
);
if
(
val
>=
0
)
spec
->
eapd_switch
=
val
;
get_int_hint
(
codec
,
"gpio_led_polarity"
,
&
spec
->
gpio_led_polarity
);
if
(
get_int_hint
(
codec
,
"gpio_led"
,
&
spec
->
gpio_led
))
{
spec
->
gpio_mask
|=
spec
->
gpio_led
;
spec
->
gpio_dir
|=
spec
->
gpio_led
;
if
(
spec
->
gpio_led_polarity
)
spec
->
gpio_data
|=
spec
->
gpio_led
;
}
}
static
void
stac_issue_unsol_events
(
struct
hda_codec
*
codec
,
int
num_pins
,
...
...
@@ -4354,7 +4333,7 @@ static int stac92xx_init(struct hda_codec *codec)
unsigned
int
pinctl
,
conf
;
if
(
type
==
AUTO_PIN_MIC
)
{
/* for mic pins, force to initialize */
pinctl
=
s
tac92xx
_get_default_vref
(
codec
,
nid
);
pinctl
=
s
nd_hda
_get_default_vref
(
codec
,
nid
);
pinctl
|=
AC_PINCTL_IN_EN
;
stac92xx_auto_set_pinctl
(
codec
,
nid
,
pinctl
);
}
else
{
...
...
@@ -4390,10 +4369,18 @@ static int stac92xx_init(struct hda_codec *codec)
hda_nid_t
nid
=
spec
->
pwr_nids
[
i
];
int
pinctl
,
def_conf
;
def_conf
=
snd_hda_codec_get_pincfg
(
codec
,
nid
);
def_conf
=
get_defcfg_connect
(
def_conf
);
if
(
def_conf
==
AC_JACK_PORT_NONE
)
{
/* power off unused ports */
stac_toggle_power_map
(
codec
,
nid
,
0
);
continue
;
}
/* power on when no jack detection is available */
/* or when the VREF is used for controlling LED */
if
(
!
spec
->
hp_detect
||
spec
->
vref_mute_led_nid
==
nid
)
{
spec
->
vref_mute_led_nid
==
nid
||
!
is_jack_detectable
(
codec
,
nid
))
{
stac_toggle_power_map
(
codec
,
nid
,
1
);
continue
;
}
...
...
@@ -4411,15 +4398,6 @@ static int stac92xx_init(struct hda_codec *codec)
stac_toggle_power_map
(
codec
,
nid
,
1
);
continue
;
}
def_conf
=
snd_hda_codec_get_pincfg
(
codec
,
nid
);
def_conf
=
get_defcfg_connect
(
def_conf
);
/* skip any ports that don't have jacks since presence
* detection is useless */
if
(
def_conf
!=
AC_JACK_PORT_NONE
&&
!
is_jack_detectable
(
codec
,
nid
))
{
stac_toggle_power_map
(
codec
,
nid
,
1
);
continue
;
}
if
(
enable_pin_detect
(
codec
,
nid
,
STAC_PWR_EVENT
))
{
stac_issue_unsol_event
(
codec
,
nid
);
continue
;
...
...
@@ -4432,6 +4410,12 @@ static int stac92xx_init(struct hda_codec *codec)
/* sync mute LED */
snd_hda_sync_vmaster_hook
(
&
spec
->
vmaster_mute
);
/* sync the power-map */
if
(
spec
->
num_pwrs
)
snd_hda_codec_write
(
codec
,
codec
->
afg
,
0
,
AC_VERB_IDT_SET_POWER_MAP
,
spec
->
power_map_bits
);
if
(
spec
->
dac_list
)
stac92xx_power_down
(
codec
);
return
0
;
...
...
@@ -4460,8 +4444,7 @@ static void stac92xx_shutup_pins(struct hda_codec *codec)
struct
hda_pincfg
*
pin
=
snd_array_elem
(
&
codec
->
init_pins
,
i
);
def_conf
=
snd_hda_codec_get_pincfg
(
codec
,
pin
->
nid
);
if
(
get_defcfg_connect
(
def_conf
)
!=
AC_JACK_PORT_NONE
)
snd_hda_codec_write
(
codec
,
pin
->
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
);
snd_hda_set_pin_ctl
(
codec
,
pin
->
nid
,
0
);
}
}
...
...
@@ -4517,9 +4500,7 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
pin_ctl
|=
flag
;
if
(
old_ctl
!=
pin_ctl
)
snd_hda_codec_write_cache
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pin_ctl
);
snd_hda_set_pin_ctl_cache
(
codec
,
nid
,
pin_ctl
);
}
static
void
stac92xx_reset_pinctl
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
...
...
@@ -4528,9 +4509,7 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
unsigned
int
pin_ctl
=
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_PIN_WIDGET_CONTROL
,
0x00
);
if
(
pin_ctl
&
flag
)
snd_hda_codec_write_cache
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pin_ctl
&
~
flag
);
snd_hda_set_pin_ctl_cache
(
codec
,
nid
,
pin_ctl
&
~
flag
);
}
static
inline
int
get_pin_presence
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
...
...
@@ -4682,14 +4661,18 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
idx
=
1
<<
idx
;
val
=
s
nd_hda_codec_read
(
codec
,
codec
->
afg
,
0
,
0x0fec
,
0x0
)
&
0xff
;
val
=
s
pec
->
power_map_bits
;
if
(
enable
)
val
&=
~
idx
;
else
val
|=
idx
;
/* power down unused output ports */
snd_hda_codec_write
(
codec
,
codec
->
afg
,
0
,
0x7ec
,
val
);
if
(
val
!=
spec
->
power_map_bits
)
{
spec
->
power_map_bits
=
val
;
snd_hda_codec_write
(
codec
,
codec
->
afg
,
0
,
AC_VERB_IDT_SET_POWER_MAP
,
val
);
}
}
static
void
stac92xx_pin_sense
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
...
...
@@ -4866,6 +4849,11 @@ static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity)
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
const
struct
dmi_device
*
dev
=
NULL
;
if
(
get_int_hint
(
codec
,
"gpio_led"
,
&
spec
->
gpio_led
))
{
get_int_hint
(
codec
,
"gpio_led_polarity"
,
&
spec
->
gpio_led_polarity
);
return
1
;
}
if
((
codec
->
subsystem_id
>>
16
)
==
PCI_VENDOR_ID_HP
)
{
while
((
dev
=
dmi_find_device
(
DMI_DEV_TYPE_OEM_STRING
,
NULL
,
dev
)))
{
...
...
@@ -4952,7 +4940,8 @@ static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
{
if
(
nid
==
codec
->
afg
)
snd_iprintf
(
buffer
,
"Power-Map: 0x%02x
\n
"
,
snd_hda_codec_read
(
codec
,
nid
,
0
,
0x0fec
,
0x0
));
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_IDT_GET_POWER_MAP
,
0
));
}
static
void
analog_loop_proc_hook
(
struct
snd_info_buffer
*
buffer
,
...
...
@@ -5009,20 +4998,6 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
return
0
;
}
static
int
stac92xx_pre_resume
(
struct
hda_codec
*
codec
)
{
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
/* sync mute LED */
if
(
spec
->
vref_mute_led_nid
)
stac_vrefout_set
(
codec
,
spec
->
vref_mute_led_nid
,
spec
->
vref_led
);
else
if
(
spec
->
gpio_led
)
stac_gpio_set
(
codec
,
spec
->
gpio_mask
,
spec
->
gpio_dir
,
spec
->
gpio_data
);
return
0
;
}
static
void
stac92xx_set_power_state
(
struct
hda_codec
*
codec
,
hda_nid_t
fg
,
unsigned
int
power_state
)
{
...
...
@@ -5046,7 +5021,6 @@ static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
#else
#define stac92xx_suspend NULL
#define stac92xx_resume NULL
#define stac92xx_pre_resume NULL
#define stac92xx_set_power_state NULL
#endif
/* CONFIG_PM */
...
...
@@ -5592,9 +5566,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
codec
->
patch_ops
.
set_power_state
=
stac92xx_set_power_state
;
}
#ifdef CONFIG_PM
codec
->
patch_ops
.
pre_resume
=
stac92xx_pre_resume
;
#endif
}
err
=
stac92xx_parse_auto_config
(
codec
);
...
...
@@ -5901,9 +5872,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
codec
->
patch_ops
.
set_power_state
=
stac92xx_set_power_state
;
}
#ifdef CONFIG_PM
codec
->
patch_ops
.
pre_resume
=
stac92xx_pre_resume
;
#endif
}
spec
->
multiout
.
dac_nids
=
spec
->
dac_nids
;
...
...
sound/pci/hda/patch_via.c
浏览文件 @
6de15b2a
...
...
@@ -54,6 +54,7 @@
#include <sound/asoundef.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
/* Pin Widget NID */
...
...
@@ -484,7 +485,7 @@ static void activate_output_mix(struct hda_codec *codec, struct nid_path *path,
if
(
!
path
)
return
;
num
=
snd_hda_get_
conn_list
(
codec
,
mix_nid
,
NULL
);
num
=
snd_hda_get_
num_conns
(
codec
,
mix_nid
);
for
(
i
=
0
;
i
<
num
;
i
++
)
{
if
(
i
==
idx
)
val
=
AMP_IN_UNMUTE
(
i
);
...
...
@@ -532,8 +533,7 @@ static void init_output_pin(struct hda_codec *codec, hda_nid_t pin,
{
if
(
!
pin
)
return
;
snd_hda_codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pin_type
);
snd_hda_set_pin_ctl
(
codec
,
pin
,
pin_type
);
if
(
snd_hda_query_pin_caps
(
codec
,
pin
)
&
AC_PINCAP_EAPD
)
snd_hda_codec_write
(
codec
,
pin
,
0
,
AC_VERB_SET_EAPD_BTLENABLE
,
0x02
);
...
...
@@ -662,12 +662,12 @@ static void via_auto_init_analog_input(struct hda_codec *codec)
hda_nid_t
nid
=
cfg
->
inputs
[
i
].
pin
;
if
(
spec
->
smart51_enabled
&&
is_smart51_pins
(
codec
,
nid
))
ctl
=
PIN_OUT
;
else
if
(
cfg
->
inputs
[
i
].
type
==
AUTO_PIN_MIC
)
ctl
=
PIN_VREF50
;
else
else
{
ctl
=
PIN_IN
;
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
ctl
);
if
(
cfg
->
inputs
[
i
].
type
==
AUTO_PIN_MIC
)
ctl
|=
snd_hda_get_default_vref
(
codec
,
nid
);
}
snd_hda_set_pin_ctl
(
codec
,
nid
,
ctl
);
}
/* init input-src */
...
...
@@ -1006,9 +1006,7 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
AC_VERB_GET_PIN_WIDGET_CONTROL
,
0
);
parm
&=
~
(
AC_PINCTL_IN_EN
|
AC_PINCTL_OUT_EN
);
parm
|=
out_in
;
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
parm
);
snd_hda_set_pin_ctl
(
codec
,
nid
,
parm
);
if
(
out_in
==
AC_PINCTL_OUT_EN
)
{
mute_aa_path
(
codec
,
1
);
notify_aa_path_ctls
(
codec
);
...
...
@@ -1647,8 +1645,7 @@ static void toggle_output_mutes(struct hda_codec *codec, int num_pins,
parm
&=
~
AC_PINCTL_OUT_EN
;
else
parm
|=
AC_PINCTL_OUT_EN
;
snd_hda_codec_write
(
codec
,
pins
[
i
],
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
parm
);
snd_hda_set_pin_ctl
(
codec
,
pins
[
i
],
parm
);
}
}
...
...
@@ -1709,8 +1706,7 @@ static void via_gpio_control(struct hda_codec *codec)
if
(
gpio_data
==
0x02
)
{
/* unmute line out */
snd_hda_codec_write
(
codec
,
spec
->
autocfg
.
line_out_pins
[
0
],
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
snd_hda_set_pin_ctl
(
codec
,
spec
->
autocfg
.
line_out_pins
[
0
],
PIN_OUT
);
if
(
vol_counter
&
0x20
)
{
/* decrease volume */
...
...
@@ -1728,9 +1724,7 @@ static void via_gpio_control(struct hda_codec *codec)
}
}
else
if
(
!
(
gpio_data
&
0x02
))
{
/* mute line out */
snd_hda_codec_write
(
codec
,
spec
->
autocfg
.
line_out_pins
[
0
],
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
);
snd_hda_set_pin_ctl
(
codec
,
spec
->
autocfg
.
line_out_pins
[
0
],
0
);
}
}
...
...
@@ -2757,8 +2751,7 @@ static void via_auto_init_dig_in(struct hda_codec *codec)
struct
via_spec
*
spec
=
codec
->
spec
;
if
(
!
spec
->
dig_in_nid
)
return
;
snd_hda_codec_write
(
codec
,
spec
->
autocfg
.
dig_in_pin
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
);
snd_hda_set_pin_ctl
(
codec
,
spec
->
autocfg
.
dig_in_pin
,
PIN_IN
);
}
/* initialize the unsolicited events */
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录