Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
128bc4ba
cloud-kernel
项目概览
openanolis
/
cloud-kernel
1 年多 前同步成功
通知
161
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
128bc4ba
编写于
5月 07, 2012
作者:
T
Takashi Iwai
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
ALSA: hda - Move BIOS pin-parser code to hda_auto_parser.c
Just code shuffles. Signed-off-by:
N
Takashi Iwai
<
tiwai@suse.de
>
上级
23d30f28
变更
13
隐藏空白更改
内联
并排
Showing
13 changed file
with
690 addition
and
675 deletion
+690
-675
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_auto_parser.c
+597
-0
sound/pci/hda/hda_auto_parser.h
sound/pci/hda/hda_auto_parser.h
+80
-0
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.c
+0
-596
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
+3
-79
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_analog.c
+1
-0
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_ca0110.c
+1
-0
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_ca0132.c
+1
-0
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_cirrus.c
+1
-0
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_cmedia.c
+1
-0
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_sigmatel.c
+1
-0
sound/pci/hda/patch_via.c
sound/pci/hda/patch_via.c
+1
-0
未找到文件。
sound/pci/hda/hda_auto_parser.c
浏览文件 @
128bc4ba
...
...
@@ -13,10 +13,607 @@
#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
)
{
...
...
sound/pci/hda/hda_auto_parser.h
浏览文件 @
128bc4ba
...
...
@@ -12,6 +12,86 @@
#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
;
...
...
sound/pci/hda/hda_codec.c
浏览文件 @
128bc4ba
...
...
@@ -4877,602 +4877,6 @@ int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
}
EXPORT_SYMBOL_HDA
(
_snd_hda_set_pin_ctl
);
/*
* 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
);
/**
* snd_hda_add_imux_item - Add an item to input_mux
*
...
...
sound/pci/hda/hda_jack.c
浏览文件 @
128bc4ba
...
...
@@ -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
浏览文件 @
128bc4ba
...
...
@@ -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
浏览文件 @
128bc4ba
...
...
@@ -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))
...
...
sound/pci/hda/patch_analog.c
浏览文件 @
128bc4ba
...
...
@@ -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"
...
...
sound/pci/hda/patch_ca0110.c
浏览文件 @
128bc4ba
...
...
@@ -26,6 +26,7 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
/*
*/
...
...
sound/pci/hda/patch_ca0132.c
浏览文件 @
128bc4ba
...
...
@@ -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
...
...
sound/pci/hda/patch_cirrus.c
浏览文件 @
128bc4ba
...
...
@@ -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>
...
...
sound/pci/hda/patch_cmedia.c
浏览文件 @
128bc4ba
...
...
@@ -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_sigmatel.c
浏览文件 @
128bc4ba
...
...
@@ -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"
...
...
sound/pci/hda/patch_via.c
浏览文件 @
128bc4ba
...
...
@@ -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 */
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录