Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
19008bda
cloud-kernel
项目概览
openanolis
/
cloud-kernel
1 年多 前同步成功
通知
160
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看板
提交
19008bda
编写于
5月 20, 2010
作者:
T
Takashi Iwai
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'topic/hda' into for-linus
上级
9ce3db4e
fbc25669
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
502 addition
and
138 deletion
+502
-138
Documentation/sound/alsa/HD-Audio.txt
Documentation/sound/alsa/HD-Audio.txt
+3
-1
sound/pci/hda/Kconfig
sound/pci/hda/Kconfig
+1
-0
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.c
+63
-13
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_codec.h
+3
-0
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_intel.c
+63
-46
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_analog.c
+17
-4
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_conexant.c
+152
-5
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_hdmi.c
+4
-6
sound/pci/hda/patch_intelhdmi.c
sound/pci/hda/patch_intelhdmi.c
+12
-9
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_realtek.c
+184
-54
未找到文件。
Documentation/sound/alsa/HD-Audio.txt
浏览文件 @
19008bda
...
...
@@ -204,7 +204,6 @@ generic parser regardless of the codec. Usually the codec-specific
parser is much better than the generic parser (as now). Thus this
option is more about the debugging purpose.
Speaker and Headphone Output
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
One of the most frequent (and obvious) bugs with HD-audio is the
...
...
@@ -600,6 +599,9 @@ probing, the proc file is available, so you can get the raw codec
information before modified by the driver. Of course, the driver
isn't usable with `probe_only=1`. But you can continue the
configuration via hwdep sysfs file if hda-reconfig option is enabled.
Using `probe_only` mask 2 skips the reset of HDA codecs (use
`probe_only=3` as module option). The hwdep interface can be used
to determine the BIOS codec initialization.
hda-verb
...
...
sound/pci/hda/Kconfig
浏览文件 @
19008bda
...
...
@@ -145,6 +145,7 @@ config SND_HDA_CODEC_NVHDMI
config SND_HDA_CODEC_INTELHDMI
bool "Build INTEL HDMI HD-audio codec support"
select SND_DYNAMIC_MINORS
default y
help
Say Y here to include INTEL HDMI HD-audio codec support in
...
...
sound/pci/hda/hda_codec.c
浏览文件 @
19008bda
...
...
@@ -1209,8 +1209,7 @@ static void free_hda_cache(struct hda_cache_rec *cache)
}
/* query the hash. allocate an entry if not found. */
static
struct
hda_cache_head
*
get_alloc_hash
(
struct
hda_cache_rec
*
cache
,
u32
key
)
static
struct
hda_cache_head
*
get_hash
(
struct
hda_cache_rec
*
cache
,
u32
key
)
{
u16
idx
=
key
%
(
u16
)
ARRAY_SIZE
(
cache
->
hash
);
u16
cur
=
cache
->
hash
[
idx
];
...
...
@@ -1222,17 +1221,27 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache,
return
info
;
cur
=
info
->
next
;
}
return
NULL
;
}
/* add a new hash entry */
info
=
snd_array_new
(
&
cache
->
buf
);
if
(
!
info
)
return
NULL
;
cur
=
snd_array_index
(
&
cache
->
buf
,
info
);
info
->
key
=
key
;
info
->
val
=
0
;
info
->
next
=
cache
->
hash
[
idx
];
cache
->
hash
[
idx
]
=
cur
;
/* query the hash. allocate an entry if not found. */
static
struct
hda_cache_head
*
get_alloc_hash
(
struct
hda_cache_rec
*
cache
,
u32
key
)
{
struct
hda_cache_head
*
info
=
get_hash
(
cache
,
key
);
if
(
!
info
)
{
u16
idx
,
cur
;
/* add a new hash entry */
info
=
snd_array_new
(
&
cache
->
buf
);
if
(
!
info
)
return
NULL
;
cur
=
snd_array_index
(
&
cache
->
buf
,
info
);
info
->
key
=
key
;
info
->
val
=
0
;
idx
=
key
%
(
u16
)
ARRAY_SIZE
(
cache
->
hash
);
info
->
next
=
cache
->
hash
[
idx
];
cache
->
hash
[
idx
]
=
cur
;
}
return
info
;
}
...
...
@@ -1461,6 +1470,8 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
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
)
...
...
@@ -1486,6 +1497,9 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
int
direction
,
int
idx
,
int
mask
,
int
val
)
{
int
ch
,
ret
=
0
;
if
(
snd_BUG_ON
(
mask
&
~
0xff
))
mask
&=
0xff
;
for
(
ch
=
0
;
ch
<
2
;
ch
++
)
ret
|=
snd_hda_codec_amp_update
(
codec
,
nid
,
ch
,
direction
,
idx
,
mask
,
val
);
...
...
@@ -2716,6 +2730,41 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_HDA
(
snd_hda_codec_write_cache
);
/**
* snd_hda_codec_update_cache - check cache and write the cmd only when needed
* @codec: the HDA codec
* @nid: NID to send the command
* @direct: direct flag
* @verb: the verb to send
* @parm: the parameter for the verb
*
* This function works like snd_hda_codec_write_cache(), but it doesn't send
* command if the parameter is already identical with the cached value.
* If not, it sends the command and refreshes the cache.
*
* Returns 0 if successful, or a negative error code.
*/
int
snd_hda_codec_update_cache
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
direct
,
unsigned
int
verb
,
unsigned
int
parm
)
{
struct
hda_cache_head
*
c
;
u32
key
;
/* parm may contain the verb stuff for get/set amp */
verb
=
verb
|
(
parm
>>
8
);
parm
&=
0xff
;
key
=
build_cmd_cache_key
(
nid
,
verb
);
mutex_lock
(
&
codec
->
bus
->
cmd_mutex
);
c
=
get_hash
(
&
codec
->
cmd_cache
,
key
);
if
(
c
&&
c
->
val
==
parm
)
{
mutex_unlock
(
&
codec
->
bus
->
cmd_mutex
);
return
0
;
}
mutex_unlock
(
&
codec
->
bus
->
cmd_mutex
);
return
snd_hda_codec_write_cache
(
codec
,
nid
,
direct
,
verb
,
parm
);
}
EXPORT_SYMBOL_HDA
(
snd_hda_codec_update_cache
);
/**
* snd_hda_codec_resume_cache - Resume the all commands from the cache
* @codec: HD-audio codec
...
...
@@ -4218,7 +4267,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
break
;
case
AC_JACK_MIC_IN
:
{
int
preferred
,
alt
;
if
(
loc
==
AC_JACK_LOC_FRONT
)
{
if
(
loc
==
AC_JACK_LOC_FRONT
||
(
loc
&
0x30
)
==
AC_JACK_LOC_INTERNAL
)
{
preferred
=
AUTO_PIN_FRONT_MIC
;
alt
=
AUTO_PIN_MIC
;
}
else
{
...
...
sound/pci/hda/hda_codec.h
浏览文件 @
19008bda
...
...
@@ -885,9 +885,12 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
int
direct
,
unsigned
int
verb
,
unsigned
int
parm
);
void
snd_hda_sequence_write_cache
(
struct
hda_codec
*
codec
,
const
struct
hda_verb
*
seq
);
int
snd_hda_codec_update_cache
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
direct
,
unsigned
int
verb
,
unsigned
int
parm
);
void
snd_hda_codec_resume_cache
(
struct
hda_codec
*
codec
);
#else
#define snd_hda_codec_write_cache snd_hda_codec_write
#define snd_hda_codec_update_cache snd_hda_codec_write
#define snd_hda_sequence_write_cache snd_hda_sequence_write
#endif
...
...
sound/pci/hda/hda_intel.c
浏览文件 @
19008bda
...
...
@@ -84,7 +84,7 @@ module_param_array(bdl_pos_adj, int, NULL, 0644);
MODULE_PARM_DESC
(
bdl_pos_adj
,
"BDL position adjustment offset."
);
module_param_array
(
probe_mask
,
int
,
NULL
,
0444
);
MODULE_PARM_DESC
(
probe_mask
,
"Bitmask to probe codecs (default = -1)."
);
module_param_array
(
probe_only
,
bool
,
NULL
,
0444
);
module_param_array
(
probe_only
,
int
,
NULL
,
0444
);
MODULE_PARM_DESC
(
probe_only
,
"Only probing and no codec initialization."
);
module_param
(
single_cmd
,
bool
,
0444
);
MODULE_PARM_DESC
(
single_cmd
,
"Use single command to communicate with codecs "
...
...
@@ -174,7 +174,7 @@ MODULE_DESCRIPTION("Intel HDA driver");
#define ICH6_GSTS_FSTS (1 << 1)
/* flush status */
#define ICH6_REG_INTCTL 0x20
#define ICH6_REG_INTSTS 0x24
#define ICH6_REG_WAL
CLK 0x30
#define ICH6_REG_WAL
LCLK 0x30
/* 24Mhz source */
#define ICH6_REG_SYNC 0x34
#define ICH6_REG_CORBLBASE 0x40
#define ICH6_REG_CORBUBASE 0x44
...
...
@@ -340,8 +340,8 @@ struct azx_dev {
unsigned
int
period_bytes
;
/* size of the period in bytes */
unsigned
int
frags
;
/* number for period in the play buffer */
unsigned
int
fifo_size
;
/* FIFO size */
unsigned
long
start_
jiffies
;
/* start + minimum jiffies
*/
unsigned
long
min_jiffies
;
/* minimum jiffies before position is vali
d */
unsigned
long
start_
wallclk
;
/* start + minimum wallclk
*/
unsigned
long
period_wallclk
;
/* wallclk for perio
d */
void
__iomem
*
sd_addr
;
/* stream descriptor pointer */
...
...
@@ -361,7 +361,6 @@ struct azx_dev {
unsigned
int
opened
:
1
;
unsigned
int
running
:
1
;
unsigned
int
irq_pending
:
1
;
unsigned
int
start_flag
:
1
;
/* stream full start flag */
/*
* For VIA:
* A flag to ensure DMA position is 0
...
...
@@ -425,7 +424,7 @@ struct azx {
struct
snd_dma_buffer
posbuf
;
/* flags */
int
position_fix
;
int
position_fix
[
2
];
/* for both playback/capture streams */
int
poll_count
;
unsigned
int
running
:
1
;
unsigned
int
initialized
:
1
;
...
...
@@ -858,10 +857,13 @@ static void azx_power_notify(struct hda_bus *bus);
#endif
/* reset codec link */
static
int
azx_reset
(
struct
azx
*
chip
)
static
int
azx_reset
(
struct
azx
*
chip
,
int
full_reset
)
{
int
count
;
if
(
!
full_reset
)
goto
__skip
;
/* clear STATESTS */
azx_writeb
(
chip
,
STATESTS
,
STATESTS_INT_MASK
);
...
...
@@ -887,6 +889,7 @@ static int azx_reset(struct azx *chip)
/* Brent Chartrand said to wait >= 540us for codecs to initialize */
msleep
(
1
);
__skip:
/* check to see if controller is ready */
if
(
!
azx_readb
(
chip
,
GCTL
))
{
snd_printd
(
SFX
"azx_reset: controller not ready!
\n
"
);
...
...
@@ -998,13 +1001,13 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
/*
* reset and start the controller registers
*/
static
void
azx_init_chip
(
struct
azx
*
chip
)
static
void
azx_init_chip
(
struct
azx
*
chip
,
int
full_reset
)
{
if
(
chip
->
initialized
)
return
;
/* reset controller */
azx_reset
(
chip
);
azx_reset
(
chip
,
full_reset
);
/* initialize interrupts */
azx_int_clear
(
chip
);
...
...
@@ -1302,8 +1305,10 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
azx_sd_writel
(
azx_dev
,
SD_BDLPU
,
upper_32_bits
(
azx_dev
->
bdl
.
addr
));
/* enable the position buffer */
if
(
chip
->
position_fix
==
POS_FIX_POSBUF
||
chip
->
position_fix
==
POS_FIX_AUTO
||
if
(
chip
->
position_fix
[
0
]
==
POS_FIX_POSBUF
||
chip
->
position_fix
[
0
]
==
POS_FIX_AUTO
||
chip
->
position_fix
[
1
]
==
POS_FIX_POSBUF
||
chip
->
position_fix
[
1
]
==
POS_FIX_AUTO
||
chip
->
via_dmapos_patch
)
{
if
(
!
(
azx_readl
(
chip
,
DPLBASE
)
&
ICH6_DPLBASE_ENABLE
))
azx_writel
(
chip
,
DPLBASE
,
...
...
@@ -1348,7 +1353,7 @@ static void azx_bus_reset(struct hda_bus *bus)
bus
->
in_reset
=
1
;
azx_stop_chip
(
chip
);
azx_init_chip
(
chip
);
azx_init_chip
(
chip
,
1
);
#ifdef CONFIG_PM
if
(
chip
->
initialized
)
{
int
i
;
...
...
@@ -1422,7 +1427,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
* get back to the sanity state.
*/
azx_stop_chip
(
chip
);
azx_init_chip
(
chip
);
azx_init_chip
(
chip
,
1
);
}
}
}
...
...
@@ -1670,8 +1675,9 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
return
err
;
}
azx_dev
->
min_jiffies
=
(
runtime
->
period_size
*
HZ
)
/
(
runtime
->
rate
*
2
);
/* wallclk has 24Mhz clock source */
azx_dev
->
period_wallclk
=
(((
runtime
->
period_size
*
24000
)
/
runtime
->
rate
)
*
1000
);
azx_setup_controller
(
chip
,
azx_dev
);
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
azx_dev
->
fifo_size
=
azx_sd_readw
(
azx_dev
,
SD_FIFOSIZE
)
+
1
;
...
...
@@ -1725,14 +1731,15 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
if
(
s
->
pcm
->
card
!=
substream
->
pcm
->
card
)
continue
;
azx_dev
=
get_azx_dev
(
s
);
if
(
r
start
)
{
azx_dev
->
start_
flag
=
1
;
azx_dev
->
start_jiffies
=
jiffies
+
azx_dev
->
min_jiffies
;
}
if
(
start
)
if
(
start
)
{
azx_dev
->
start_
wallclk
=
azx_readl
(
chip
,
WALLCLK
)
;
if
(
!
rstart
)
azx_dev
->
start_wallclk
-=
azx_dev
->
period_wallclk
;
azx_stream_start
(
chip
,
azx_dev
);
else
}
else
{
azx_stream_stop
(
chip
,
azx_dev
);
}
azx_dev
->
running
=
start
;
}
spin_unlock
(
&
chip
->
reg_lock
);
...
...
@@ -1843,13 +1850,16 @@ static unsigned int azx_get_position(struct azx *chip,
if
(
chip
->
via_dmapos_patch
)
pos
=
azx_via_get_position
(
chip
,
azx_dev
);
else
if
(
chip
->
position_fix
==
POS_FIX_POSBUF
||
chip
->
position_fix
==
POS_FIX_AUTO
)
{
/* use the position buffer */
pos
=
le32_to_cpu
(
*
azx_dev
->
posbuf
);
}
else
{
/* read LPIB */
pos
=
azx_sd_readl
(
azx_dev
,
SD_LPIB
);
else
{
int
stream
=
azx_dev
->
substream
->
stream
;
if
(
chip
->
position_fix
[
stream
]
==
POS_FIX_POSBUF
||
chip
->
position_fix
[
stream
]
==
POS_FIX_AUTO
)
{
/* use the position buffer */
pos
=
le32_to_cpu
(
*
azx_dev
->
posbuf
);
}
else
{
/* read LPIB */
pos
=
azx_sd_readl
(
azx_dev
,
SD_LPIB
);
}
}
if
(
pos
>=
azx_dev
->
bufsize
)
pos
=
0
;
...
...
@@ -1876,32 +1886,35 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
*/
static
int
azx_position_ok
(
struct
azx
*
chip
,
struct
azx_dev
*
azx_dev
)
{
u32
wallclk
;
unsigned
int
pos
;
int
stream
;
if
(
azx_dev
->
start_flag
&&
time_before_eq
(
jiffies
,
azx_dev
->
start_jiffies
)
)
wallclk
=
azx_readl
(
chip
,
WALLCLK
)
-
azx_dev
->
start_wallclk
;
if
(
wallclk
<
(
azx_dev
->
period_wallclk
*
2
)
/
3
)
return
-
1
;
/* bogus (too early) interrupt */
azx_dev
->
start_flag
=
0
;
stream
=
azx_dev
->
substream
->
stream
;
pos
=
azx_get_position
(
chip
,
azx_dev
);
if
(
chip
->
position_fix
==
POS_FIX_AUTO
)
{
if
(
chip
->
position_fix
[
stream
]
==
POS_FIX_AUTO
)
{
if
(
!
pos
)
{
printk
(
KERN_WARNING
"hda-intel: Invalid position buffer, "
"using LPIB read method instead.
\n
"
);
chip
->
position_fix
=
POS_FIX_LPIB
;
chip
->
position_fix
[
stream
]
=
POS_FIX_LPIB
;
pos
=
azx_get_position
(
chip
,
azx_dev
);
}
else
chip
->
position_fix
=
POS_FIX_POSBUF
;
chip
->
position_fix
[
stream
]
=
POS_FIX_POSBUF
;
}
if
(
!
bdl_pos_adj
[
chip
->
dev_index
])
return
1
;
/* no delayed ack */
if
(
WARN_ONCE
(
!
azx_dev
->
period_bytes
,
"hda-intel: zero azx_dev->period_bytes"
))
return
0
;
/* this shouldn't happen! */
if
(
pos
%
azx_dev
->
period_bytes
>
azx_dev
->
period_bytes
/
2
)
return
0
;
/* NG - it's below the period boundary */
return
-
1
;
/* this shouldn't happen! */
if
(
wallclk
<=
azx_dev
->
period_wallclk
&&
pos
%
azx_dev
->
period_bytes
>
azx_dev
->
period_bytes
/
2
)
/* NG - it's below the first next period boundary */
return
bdl_pos_adj
[
chip
->
dev_index
]
?
0
:
-
1
;
azx_dev
->
start_wallclk
=
wallclk
;
return
1
;
/* OK, it's fine */
}
...
...
@@ -1911,7 +1924,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
static
void
azx_irq_pending_work
(
struct
work_struct
*
work
)
{
struct
azx
*
chip
=
container_of
(
work
,
struct
azx
,
irq_pending_work
);
int
i
,
pending
;
int
i
,
pending
,
ok
;
if
(
!
chip
->
irq_pending_warned
)
{
printk
(
KERN_WARNING
...
...
@@ -1930,11 +1943,14 @@ static void azx_irq_pending_work(struct work_struct *work)
!
azx_dev
->
substream
||
!
azx_dev
->
running
)
continue
;
if
(
azx_position_ok
(
chip
,
azx_dev
))
{
ok
=
azx_position_ok
(
chip
,
azx_dev
);
if
(
ok
>
0
)
{
azx_dev
->
irq_pending
=
0
;
spin_unlock
(
&
chip
->
reg_lock
);
snd_pcm_period_elapsed
(
azx_dev
->
substream
);
spin_lock
(
&
chip
->
reg_lock
);
}
else
if
(
ok
<
0
)
{
pending
=
0
;
/* too early */
}
else
pending
++
;
}
...
...
@@ -2112,7 +2128,7 @@ static void azx_power_notify(struct hda_bus *bus)
}
}
if
(
power_on
)
azx_init_chip
(
chip
);
azx_init_chip
(
chip
,
1
);
else
if
(
chip
->
running
&&
power_save_controller
&&
!
bus
->
power_keep_link_on
)
azx_stop_chip
(
chip
);
...
...
@@ -2182,7 +2198,7 @@ static int azx_resume(struct pci_dev *pci)
azx_init_pci
(
chip
);
if
(
snd_hda_codecs_inuse
(
chip
->
bus
))
azx_init_chip
(
chip
);
azx_init_chip
(
chip
,
1
);
snd_hda_resume
(
chip
->
bus
);
snd_power_change_state
(
card
,
SNDRV_CTL_POWER_D0
);
...
...
@@ -2431,7 +2447,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
chip
->
dev_index
=
dev
;
INIT_WORK
(
&
chip
->
irq_pending_work
,
azx_irq_pending_work
);
chip
->
position_fix
=
check_position_fix
(
chip
,
position_fix
[
dev
]);
chip
->
position_fix
[
0
]
=
chip
->
position_fix
[
1
]
=
check_position_fix
(
chip
,
position_fix
[
dev
]);
check_probe_mask
(
chip
,
dev
);
chip
->
single_cmd
=
single_cmd
;
...
...
@@ -2577,7 +2594,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
/* initialize chip */
azx_init_pci
(
chip
);
azx_init_chip
(
chip
);
azx_init_chip
(
chip
,
(
probe_only
[
dev
]
&
2
)
==
0
);
/* codec detection */
if
(
!
chip
->
codec_mask
)
{
...
...
@@ -2666,7 +2683,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
goto
out_free
;
}
#endif
if
(
!
probe_only
[
dev
]
)
{
if
(
(
probe_only
[
dev
]
&
1
)
==
0
)
{
err
=
azx_codec_configure
(
chip
);
if
(
err
<
0
)
goto
out_free
;
...
...
sound/pci/hda/patch_analog.c
浏览文件 @
19008bda
...
...
@@ -71,9 +71,10 @@ struct ad198x_spec {
struct
hda_input_mux
private_imux
;
hda_nid_t
private_dac_nids
[
AUTO_CFG_MAX_OUTS
];
unsigned
int
jack_present
:
1
;
unsigned
int
inv_jack_detect
:
1
;
/* inverted jack-detection */
unsigned
int
inv_eapd
:
1
;
/* inverted EAPD implementation */
unsigned
int
jack_present
:
1
;
unsigned
int
inv_jack_detect
:
1
;
/* inverted jack-detection */
unsigned
int
inv_eapd
:
1
;
/* inverted EAPD implementation */
unsigned
int
analog_beep
:
1
;
/* analog beep input present */
#ifdef CONFIG_SND_HDA_POWER_SAVE
struct
hda_loopback_check
loopback
;
...
...
@@ -165,6 +166,12 @@ static struct snd_kcontrol_new ad_beep_mixer[] = {
{
}
/* end */
};
static
struct
snd_kcontrol_new
ad_beep2_mixer
[]
=
{
HDA_CODEC_VOLUME
(
"Digital Beep Playback Volume"
,
0
,
0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_BEEP
(
"Digital Beep Playback Switch"
,
0
,
0
,
HDA_OUTPUT
),
{
}
/* end */
};
#define set_beep_amp(spec, nid, idx, dir) \
((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir))
/* mono */
#else
...
...
@@ -203,7 +210,8 @@ static int ad198x_build_controls(struct hda_codec *codec)
#ifdef CONFIG_SND_HDA_INPUT_BEEP
if
(
spec
->
beep_amp
)
{
struct
snd_kcontrol_new
*
knew
;
for
(
knew
=
ad_beep_mixer
;
knew
->
name
;
knew
++
)
{
knew
=
spec
->
analog_beep
?
ad_beep2_mixer
:
ad_beep_mixer
;
for
(
;
knew
->
name
;
knew
++
)
{
struct
snd_kcontrol
*
kctl
;
kctl
=
snd_ctl_new1
(
knew
,
codec
);
if
(
!
kctl
)
...
...
@@ -3481,6 +3489,8 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Internal Mic Playback Volume"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Internal Mic Playback Switch"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Beep Playback Volume"
,
0x20
,
0x03
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Beep Playback Switch"
,
0x20
,
0x03
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Docking Mic Playback Volume"
,
0x20
,
0x04
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Docking Mic Playback Switch"
,
0x20
,
0x04
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost"
,
0x14
,
0x0
,
HDA_INPUT
),
...
...
@@ -3522,6 +3532,8 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = {
{
0x1c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* docking mic boost */
{
0x25
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
/* Analog PC Beeper - allow firmware/ACPI beeps */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
3
)
|
0x1a
},
/* Analog mixer - docking mic; mute as default */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
4
)},
/* enable EAPD bit */
...
...
@@ -3654,6 +3666,7 @@ static int patch_ad1984(struct hda_codec *codec)
spec
->
input_mux
=
&
ad1984_thinkpad_capture_source
;
spec
->
mixers
[
0
]
=
ad1984_thinkpad_mixers
;
spec
->
init_verbs
[
spec
->
num_init_verbs
++
]
=
ad1984_thinkpad_init_verbs
;
spec
->
analog_beep
=
1
;
break
;
case
AD1984_DELL_DESKTOP
:
spec
->
multiout
.
dig_out_nid
=
0
;
...
...
sound/pci/hda/patch_conexant.c
浏览文件 @
19008bda
...
...
@@ -115,6 +115,7 @@ struct conexant_spec {
unsigned
int
port_d_mode
;
unsigned
int
dell_vostro
:
1
;
unsigned
int
ideapad
:
1
;
unsigned
int
thinkpad
:
1
;
unsigned
int
ext_mic_present
;
unsigned
int
recording
;
...
...
@@ -1784,6 +1785,7 @@ static struct hda_verb cxt5051_init_verbs[] = {
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)
|
0x44
},
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)
|
0x44
},
/* SPDIF route: PCM */
{
0x1c
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x1c
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* EAPD */
{
0x1a
,
AC_VERB_SET_EAPD_BTLENABLE
,
0x2
},
/* default on */
...
...
@@ -1840,6 +1842,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)
|
0x44
},
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)
|
0x44
},
/* SPDIF route: PCM */
{
0x1c
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
/* needed for W500 Advanced Mini Dock 250410 */
{
0x1c
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* EAPD */
{
0x1a
,
AC_VERB_SET_EAPD_BTLENABLE
,
0x2
},
/* default on */
...
...
@@ -1911,7 +1914,7 @@ enum {
CXT5051_LAPTOP
,
/* Laptops w/ EAPD support */
CXT5051_HP
,
/* no docking */
CXT5051_HP_DV6736
,
/* HP without mic switch */
CXT5051_LENOVO_X200
,
/* Lenovo X200 laptop */
CXT5051_LENOVO_X200
,
/* Lenovo X200 laptop
, also used for Advanced Mini Dock 250410
*/
CXT5051_F700
,
/* HP Compaq Presario F700 */
CXT5051_TOSHIBA
,
/* Toshiba M300 & co */
CXT5051_MODELS
...
...
@@ -2033,6 +2036,9 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
/* Port D (HP/LO) */
pinctl
=
((
spec
->
hp_present
&
2
)
&&
spec
->
cur_eapd
)
?
spec
->
port_d_mode
:
0
;
/* Mute if Port A is connected on Thinkpad */
if
(
spec
->
thinkpad
&&
(
spec
->
hp_present
&
1
))
pinctl
=
0
;
snd_hda_codec_write
(
codec
,
0x1c
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
pinctl
);
...
...
@@ -2213,6 +2219,50 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec)
}
}
/* toggle input of built-in digital mic and mic jack appropriately
order is: external mic -> dock mic -> interal mic */
static
void
cxt5066_thinkpad_automic
(
struct
hda_codec
*
codec
)
{
unsigned
int
ext_present
,
dock_present
;
static
struct
hda_verb
ext_mic_present
[]
=
{
{
0x14
,
AC_VERB_SET_CONNECT_SEL
,
0
},
{
0x17
,
AC_VERB_SET_CONNECT_SEL
,
1
},
{
0x1b
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x23
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
},
{
0x1a
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
},
{}
};
static
struct
hda_verb
dock_mic_present
[]
=
{
{
0x14
,
AC_VERB_SET_CONNECT_SEL
,
0
},
{
0x17
,
AC_VERB_SET_CONNECT_SEL
,
0
},
{
0x1a
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x23
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
},
{
0x1b
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
},
{}
};
static
struct
hda_verb
ext_mic_absent
[]
=
{
{
0x14
,
AC_VERB_SET_CONNECT_SEL
,
2
},
{
0x23
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
{
0x1b
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
},
{
0x1a
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
},
{}
};
ext_present
=
snd_hda_jack_detect
(
codec
,
0x1b
);
dock_present
=
snd_hda_jack_detect
(
codec
,
0x1a
);
if
(
ext_present
)
{
snd_printdd
(
"CXT5066: external microphone detected
\n
"
);
snd_hda_sequence_write
(
codec
,
ext_mic_present
);
}
else
if
(
dock_present
)
{
snd_printdd
(
"CXT5066: dock microphone detected
\n
"
);
snd_hda_sequence_write
(
codec
,
dock_mic_present
);
}
else
{
snd_printdd
(
"CXT5066: external microphone absent
\n
"
);
snd_hda_sequence_write
(
codec
,
ext_mic_absent
);
}
}
/* mute internal speaker if HP is plugged */
static
void
cxt5066_hp_automute
(
struct
hda_codec
*
codec
)
{
...
...
@@ -2225,7 +2275,8 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
/* Port D */
portD
=
snd_hda_jack_detect
(
codec
,
0x1c
);
spec
->
hp_present
=
!!
(
portA
|
portD
);
spec
->
hp_present
=
!!
(
portA
);
spec
->
hp_present
|=
portD
?
2
:
0
;
snd_printdd
(
"CXT5066: hp automute portA=%x portD=%x present=%d
\n
"
,
portA
,
portD
,
spec
->
hp_present
);
cxt5066_update_speaker
(
codec
);
...
...
@@ -2276,6 +2327,20 @@ static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res)
}
}
/* unsolicited event for jack sensing */
static
void
cxt5066_thinkpad_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
snd_printdd
(
"CXT5066_thinkpad: unsol event %x (%x)
\n
"
,
res
,
res
>>
26
);
switch
(
res
>>
26
)
{
case
CONEXANT_HP_EVENT
:
cxt5066_hp_automute
(
codec
);
break
;
case
CONEXANT_MIC_EVENT
:
cxt5066_thinkpad_automic
(
codec
);
break
;
}
}
static
const
struct
hda_input_mux
cxt5066_analog_mic_boost
=
{
.
num_items
=
5
,
.
items
=
{
...
...
@@ -2294,7 +2359,7 @@ static void cxt5066_set_mic_boost(struct hda_codec *codec)
AC_VERB_SET_AMP_GAIN_MUTE
,
AC_AMP_SET_RIGHT
|
AC_AMP_SET_LEFT
|
AC_AMP_SET_OUTPUT
|
cxt5066_analog_mic_boost
.
items
[
spec
->
mic_boost
].
index
);
if
(
spec
->
ideapad
)
{
if
(
spec
->
ideapad
||
spec
->
thinkpad
)
{
/* adjust the internal mic as well...it is not through 0x17 */
snd_hda_codec_write_cache
(
codec
,
0x23
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
...
...
@@ -2782,6 +2847,64 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = {
{
}
/* end */
};
static
struct
hda_verb
cxt5066_init_verbs_thinkpad
[]
=
{
{
0x1e
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
/* Port F */
{
0x1d
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
/* Port E */
/* Port G: internal speakers */
{
0x1f
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x1f
,
AC_VERB_SET_CONNECT_SEL
,
0x00
},
/* DAC1 */
/* Port A: HP, Amp */
{
0x19
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
},
{
0x19
,
AC_VERB_SET_CONNECT_SEL
,
0x00
},
/* DAC1 */
/* Port B: Mic Dock */
{
0x1a
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
},
/* Port C: Mic */
{
0x1b
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
},
/* Port D: HP Dock, Amp */
{
0x1c
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
},
{
0x1c
,
AC_VERB_SET_CONNECT_SEL
,
0x00
},
/* DAC1 */
/* DAC1 */
{
0x10
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
/* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)
|
0x50
},
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
2
)
|
0x50
},
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
3
)},
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
4
)},
{
0x14
,
AC_VERB_SET_CONNECT_SEL
,
2
},
/* default to internal mic */
/* Audio input selector */
{
0x17
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
|
0x2
},
{
0x17
,
AC_VERB_SET_CONNECT_SEL
,
1
},
/* route ext mic */
/* SPDIF route: PCM */
{
0x20
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
{
0x22
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
{
0x20
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x22
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
/* internal microphone */
{
0x23
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
/* enable int mic */
/* EAPD */
{
0x1d
,
AC_VERB_SET_EAPD_BTLENABLE
,
0x2
},
/* default on */
/* enable unsolicited events for Port A, B, C and D */
{
0x19
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
CONEXANT_HP_EVENT
},
{
0x1c
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
CONEXANT_HP_EVENT
},
{
0x1a
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
CONEXANT_MIC_EVENT
},
{
0x1b
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
CONEXANT_MIC_EVENT
},
{
}
/* end */
};
static
struct
hda_verb
cxt5066_init_verbs_portd_lo
[]
=
{
{
0x1c
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
}
/* end */
...
...
@@ -2800,6 +2923,8 @@ static int cxt5066_init(struct hda_codec *codec)
cxt5066_vostro_automic
(
codec
);
else
if
(
spec
->
ideapad
)
cxt5066_ideapad_automic
(
codec
);
else
if
(
spec
->
thinkpad
)
cxt5066_thinkpad_automic
(
codec
);
}
cxt5066_set_mic_boost
(
codec
);
return
0
;
...
...
@@ -2821,20 +2946,22 @@ static int cxt5066_olpc_init(struct hda_codec *codec)
}
enum
{
CXT5066_LAPTOP
,
/* Laptops w/ EAPD support */
CXT5066_LAPTOP
,
/* Laptops w/ EAPD support */
CXT5066_DELL_LAPTOP
,
/* Dell Laptop */
CXT5066_OLPC_XO_1_5
,
/* OLPC XO 1.5 */
CXT5066_DELL_VOSTO
,
/* Dell Vostro 1015i */
CXT5066_IDEAPAD
,
/* Lenovo IdeaPad U150 */
CXT5066_THINKPAD
,
/* Lenovo ThinkPad T410s, others? */
CXT5066_MODELS
};
static
const
char
*
cxt5066_models
[
CXT5066_MODELS
]
=
{
[
CXT5066_LAPTOP
]
=
"laptop"
,
[
CXT5066_LAPTOP
]
=
"laptop"
,
[
CXT5066_DELL_LAPTOP
]
=
"dell-laptop"
,
[
CXT5066_OLPC_XO_1_5
]
=
"olpc-xo-1_5"
,
[
CXT5066_DELL_VOSTO
]
=
"dell-vostro"
,
[
CXT5066_IDEAPAD
]
=
"ideapad"
,
[
CXT5066_THINKPAD
]
=
"thinkpad"
,
};
static
struct
snd_pci_quirk
cxt5066_cfg_tbl
[]
=
{
...
...
@@ -2849,6 +2976,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
SND_PCI_QUIRK
(
0x1179
,
0xffe0
,
"Toshiba Satellite Pro T130-15F"
,
CXT5066_OLPC_XO_1_5
),
SND_PCI_QUIRK
(
0x17aa
,
0x21b2
,
"Thinkpad X100e"
,
CXT5066_IDEAPAD
),
SND_PCI_QUIRK
(
0x17aa
,
0x3a0d
,
"ideapad"
,
CXT5066_IDEAPAD
),
SND_PCI_QUIRK
(
0x17aa
,
0x215e
,
"Lenovo Thinkpad"
,
CXT5066_THINKPAD
),
{}
};
...
...
@@ -2953,6 +3081,22 @@ static int patch_cxt5066(struct hda_codec *codec)
/* no S/PDIF out */
spec
->
multiout
.
dig_out_nid
=
0
;
/* input source automatically selected */
spec
->
input_mux
=
NULL
;
break
;
case
CXT5066_THINKPAD
:
codec
->
patch_ops
.
init
=
cxt5066_init
;
codec
->
patch_ops
.
unsol_event
=
cxt5066_thinkpad_event
;
spec
->
mixers
[
spec
->
num_mixers
++
]
=
cxt5066_mixer_master
;
spec
->
mixers
[
spec
->
num_mixers
++
]
=
cxt5066_mixers
;
spec
->
init_verbs
[
0
]
=
cxt5066_init_verbs_thinkpad
;
spec
->
thinkpad
=
1
;
spec
->
port_d_mode
=
PIN_OUT
;
spec
->
mic_boost
=
2
;
/* default 20dB gain */
/* no S/PDIF out */
spec
->
multiout
.
dig_out_nid
=
0
;
/* input source automatically selected */
spec
->
input_mux
=
NULL
;
break
;
...
...
@@ -2975,6 +3119,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
.
patch
=
patch_cxt5066
},
{
.
id
=
0x14f15067
,
.
name
=
"CX20583 (Pebble HSF)"
,
.
patch
=
patch_cxt5066
},
{
.
id
=
0x14f15069
,
.
name
=
"CX20585"
,
.
patch
=
patch_cxt5066
},
{}
/* terminator */
};
...
...
@@ -2983,6 +3129,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15047");
MODULE_ALIAS
(
"snd-hda-codec-id:14f15051"
);
MODULE_ALIAS
(
"snd-hda-codec-id:14f15066"
);
MODULE_ALIAS
(
"snd-hda-codec-id:14f15067"
);
MODULE_ALIAS
(
"snd-hda-codec-id:14f15069"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_DESCRIPTION
(
"Conexant HD-audio codec"
);
...
...
sound/pci/hda/patch_hdmi.c
浏览文件 @
19008bda
...
...
@@ -766,7 +766,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
if
(
spec
->
num_pins
>=
MAX_HDMI_PINS
)
{
snd_printk
(
KERN_WARNING
"HDMI: no space for pin %d
\n
"
,
pin_nid
);
return
-
E
INVAL
;
return
-
E
2BIG
;
}
hdmi_present_sense
(
codec
,
pin_nid
,
&
spec
->
sink_eld
[
spec
->
num_pins
]);
...
...
@@ -788,7 +788,7 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid)
if
(
spec
->
num_cvts
>=
MAX_HDMI_CVTS
)
{
snd_printk
(
KERN_WARNING
"HDMI: no space for converter %d
\n
"
,
nid
);
return
-
E
INVAL
;
return
-
E
2BIG
;
}
spec
->
cvt
[
spec
->
num_cvts
]
=
nid
;
...
...
@@ -820,15 +820,13 @@ static int hdmi_parse_codec(struct hda_codec *codec)
switch
(
type
)
{
case
AC_WID_AUD_OUT
:
if
(
hdmi_add_cvt
(
codec
,
nid
)
<
0
)
return
-
EINVAL
;
hdmi_add_cvt
(
codec
,
nid
);
break
;
case
AC_WID_PIN
:
caps
=
snd_hda_param_read
(
codec
,
nid
,
AC_PAR_PIN_CAP
);
if
(
!
(
caps
&
(
AC_PINCAP_HDMI
|
AC_PINCAP_DP
)))
continue
;
if
(
hdmi_add_pin
(
codec
,
nid
)
<
0
)
return
-
EINVAL
;
hdmi_add_pin
(
codec
,
nid
);
break
;
}
}
...
...
sound/pci/hda/patch_intelhdmi.c
浏览文件 @
19008bda
...
...
@@ -40,7 +40,7 @@
*
* The HDA correspondence of pipes/ports are converter/pin nodes.
*/
#define MAX_HDMI_CVTS
2
#define MAX_HDMI_CVTS
3
#define MAX_HDMI_PINS 3
#include "patch_hdmi.c"
...
...
@@ -48,6 +48,7 @@
static
char
*
intel_hdmi_pcm_names
[
MAX_HDMI_CVTS
]
=
{
"INTEL HDMI 0"
,
"INTEL HDMI 1"
,
"INTEL HDMI 2"
,
};
/*
...
...
@@ -185,14 +186,15 @@ static int patch_intel_hdmi(struct hda_codec *codec)
}
static
struct
hda_codec_preset
snd_hda_preset_intelhdmi
[]
=
{
{
.
id
=
0x808629fb
,
.
name
=
"G45 DEVCL"
,
.
patch
=
patch_intel_hdmi
},
{
.
id
=
0x80862801
,
.
name
=
"G45 DEVBLC"
,
.
patch
=
patch_intel_hdmi
},
{
.
id
=
0x80862802
,
.
name
=
"G45 DEVCTG"
,
.
patch
=
patch_intel_hdmi
},
{
.
id
=
0x80862803
,
.
name
=
"G45 DEVELK"
,
.
patch
=
patch_intel_hdmi
},
{
.
id
=
0x80862804
,
.
name
=
"G45 DEVIBX"
,
.
patch
=
patch_intel_hdmi
},
{
.
id
=
0x80860054
,
.
name
=
"Q57 DEVIBX"
,
.
patch
=
patch_intel_hdmi
},
{
.
id
=
0x10951392
,
.
name
=
"SiI1392 HDMI"
,
.
patch
=
patch_intel_hdmi
},
{}
/* terminator */
{
.
id
=
0x808629fb
,
.
name
=
"Crestline HDMI"
,
.
patch
=
patch_intel_hdmi
},
{
.
id
=
0x80862801
,
.
name
=
"Bearlake HDMI"
,
.
patch
=
patch_intel_hdmi
},
{
.
id
=
0x80862802
,
.
name
=
"Cantiga HDMI"
,
.
patch
=
patch_intel_hdmi
},
{
.
id
=
0x80862803
,
.
name
=
"Eaglelake HDMI"
,
.
patch
=
patch_intel_hdmi
},
{
.
id
=
0x80862804
,
.
name
=
"IbexPeak HDMI"
,
.
patch
=
patch_intel_hdmi
},
{
.
id
=
0x80860054
,
.
name
=
"IbexPeak HDMI"
,
.
patch
=
patch_intel_hdmi
},
{
.
id
=
0x80862805
,
.
name
=
"CougarPoint HDMI"
,
.
patch
=
patch_intel_hdmi
},
{
.
id
=
0x10951392
,
.
name
=
"SiI1392 HDMI"
,
.
patch
=
patch_intel_hdmi
},
{}
/* terminator */
};
MODULE_ALIAS
(
"snd-hda-codec-id:808629fb"
);
...
...
@@ -200,6 +202,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862801");
MODULE_ALIAS
(
"snd-hda-codec-id:80862802"
);
MODULE_ALIAS
(
"snd-hda-codec-id:80862803"
);
MODULE_ALIAS
(
"snd-hda-codec-id:80862804"
);
MODULE_ALIAS
(
"snd-hda-codec-id:80862805"
);
MODULE_ALIAS
(
"snd-hda-codec-id:80860054"
);
MODULE_ALIAS
(
"snd-hda-codec-id:10951392"
);
...
...
sound/pci/hda/patch_realtek.c
浏览文件 @
19008bda
...
...
@@ -276,6 +276,18 @@ struct alc_mic_route {
#define MUX_IDX_UNDEF ((unsigned char)-1)
struct alc_customize_define {
unsigned int sku_cfg;
unsigned char port_connectivity;
unsigned char check_sum;
unsigned char customization;
unsigned char external_amp;
unsigned int enable_pcbeep:1;
unsigned int platform_type:1;
unsigned int swap:1;
unsigned int override:1;
};
struct alc_spec {
/* codec parameterization */
struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
...
...
@@ -333,6 +345,7 @@ struct alc_spec {
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
struct alc_customize_define cdefine;
struct snd_array kctls;
struct hda_input_mux private_imux[3];
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
...
...
@@ -1248,6 +1261,62 @@ static void alc_init_auto_mic(struct hda_codec *codec)
spec->unsol_event = alc_sku_unsol_event;
}
static int alc_auto_parse_customize_define(struct hda_codec *codec)
{
unsigned int ass, tmp, i;
unsigned nid = 0;
struct alc_spec *spec = codec->spec;
ass = codec->subsystem_id & 0xffff;
if (ass != codec->bus->pci->subsystem_device && (ass & 1))
goto do_sku;
nid = 0x1d;
if (codec->vendor_id == 0x10ec0260)
nid = 0x17;
ass = snd_hda_codec_get_pincfg(codec, nid);
if (!(ass & 1)) {
printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
codec->chip_name, ass);
return -1;
}
/* check sum */
tmp = 0;
for (i = 1; i < 16; i++) {
if ((ass >> i) & 1)
tmp++;
}
if (((ass >> 16) & 0xf) != tmp)
return -1;
spec->cdefine.port_connectivity = ass >> 30;
spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
spec->cdefine.check_sum = (ass >> 16) & 0xf;
spec->cdefine.customization = ass >> 8;
do_sku:
spec->cdefine.sku_cfg = ass;
spec->cdefine.external_amp = (ass & 0x38) >> 3;
spec->cdefine.platform_type = (ass & 0x4) >> 2;
spec->cdefine.swap = (ass & 0x2) >> 1;
spec->cdefine.override = ass & 0x1;
snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
nid, spec->cdefine.sku_cfg);
snd_printd("SKU: port_connectivity=0x%x\n",
spec->cdefine.port_connectivity);
snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
return 0;
}
/* check subsystem ID and set up device-specific initialization;
* return 1 if initialized, 0 if invalid SSID
*/
...
...
@@ -3415,6 +3484,10 @@ static int alc_init(struct hda_codec *codec)
if (spec->init_hook)
spec->init_hook(codec);
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (codec->patch_ops.check_power_status)
codec->patch_ops.check_power_status(codec, 0x01);
#endif
return 0;
}
...
...
@@ -3775,6 +3848,10 @@ static int alc_resume(struct hda_codec *codec)
codec->patch_ops.init(codec);
snd_hda_codec_resume_amp(codec);
snd_hda_codec_resume_cache(codec);
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (codec->patch_ops.check_power_status)
codec->patch_ops.check_power_status(codec, 0x01);
#endif
return 0;
}
#endif
...
...
@@ -3797,6 +3874,17 @@ static struct hda_codec_ops alc_patch_ops = {
.reboot_notify = alc_shutup,
};
/* replace the codec chip_name with the given string */
static int alc_codec_rename(struct hda_codec *codec, const char *name)
{
kfree(codec->chip_name);
codec->chip_name = kstrdup(name, GFP_KERNEL);
if (!codec->chip_name) {
alc_free(codec);
return -ENOMEM;
}
return 0;
}
/*
* Test configuration for debugging
...
...
@@ -10189,21 +10277,20 @@ static int alc882_auto_create_input_ctls(struct hda_codec *codec,
static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
hda_nid_t nid, int pin_type,
int dac_idx
)
hda_nid_t dac
)
{
/* set as output */
struct alc_spec *spec = codec->spec;
int idx;
/* set as output */
alc_set_pin_output(codec, nid, pin_type);
if (dac_idx >= spec->multiout.num_dacs)
return;
if (spec->multiout.dac_nids[dac_idx] == 0x25)
if (dac == 0x25)
idx = 4;
else if (dac >= 0x02 && dac <= 0x05)
idx = dac - 2;
else
idx = spec->multiout.dac_nids[dac_idx] - 2
;
return
;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
}
static void alc882_auto_init_multi_out(struct hda_codec *codec)
...
...
@@ -10216,22 +10303,29 @@ static void alc882_auto_init_multi_out(struct hda_codec *codec)
int pin_type = get_pin_type(spec->autocfg.line_out_type);
if (nid)
alc882_auto_set_output_and_unmute(codec, nid, pin_type,
i
);
spec->multiout.dac_nids[i]
);
}
}
static void alc882_auto_init_hp_out(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
hda_nid_t pin;
hda_nid_t pin
, dac
;
pin = spec->autocfg.hp_pins[0];
if (pin) /* connect to front */
/* use dac 0 */
alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
if (pin) {
dac = spec->multiout.hp_nid;
if (!dac)
dac = spec->multiout.dac_nids[0]; /* to front */
alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
}
pin = spec->autocfg.speaker_pins[0];
if (pin)
alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
if (pin) {
dac = spec->multiout.extra_out_nid[0];
if (!dac)
dac = spec->multiout.dac_nids[0]; /* to front */
alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
}
}
static void alc882_auto_init_analog_input(struct hda_codec *codec)
...
...
@@ -10345,6 +10439,10 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
if (err < 0)
return err;
err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
if (err < 0)
return err;
err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
"Headphone");
if (err < 0)
return err;
err = alc880_auto_create_extra_out(spec,
...
...
@@ -10352,10 +10450,6 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
"Speaker");
if (err < 0)
return err;
err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
"Headphone");
if (err < 0)
return err;
err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
if (err < 0)
return err;
...
...
@@ -10425,6 +10519,8 @@ static int patch_alc882(struct hda_codec *codec)
codec->spec = spec;
alc_auto_parse_customize_define(codec);
switch (codec->vendor_id) {
case 0x10ec0882:
case 0x10ec0885:
...
...
@@ -10484,9 +10580,6 @@ static int patch_alc882(struct hda_codec *codec)
spec->stream_digital_playback = &alc882_pcm_digital_playback;
spec->stream_digital_capture = &alc882_pcm_digital_capture;
if (codec->vendor_id == 0x10ec0888)
spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
if (!spec->adc_nids && spec->input_mux) {
int i, j;
spec->num_adc_nids = 0;
...
...
@@ -10521,7 +10614,9 @@ static int patch_alc882(struct hda_codec *codec)
}
set_capture_mixer(codec);
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
if (spec->cdefine.enable_pcbeep)
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
if (board_config == ALC882_AUTO)
alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0);
...
...
@@ -12308,6 +12403,7 @@ static int patch_alc262(struct hda_codec *codec)
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
}
#endif
alc_auto_parse_customize_define(codec);
alc_fix_pll_init(codec, 0x20, 0x0a, 10);
...
...
@@ -12386,7 +12482,7 @@ static int patch_alc262(struct hda_codec *codec)
}
if (!spec->cap_mixer && !spec->no_analog)
set_capture_mixer(codec);
if (!spec->no_analog)
if (!spec->no_analog
&& spec->cdefine.enable_pcbeep
)
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
spec->vmaster_nid = 0x0c;
...
...
@@ -14005,6 +14101,35 @@ static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
/* NID is set in alc_build_pcms */
};
#ifdef CONFIG_SND_HDA_POWER_SAVE
static int alc269_mic2_for_mute_led(struct hda_codec *codec)
{
switch (codec->subsystem_id) {
case 0x103c1586:
return 1;
}
return 0;
}
static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
{
/* update mute-LED according to the speaker mute state */
if (nid == 0x01 || nid == 0x14) {
int pinval;
if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
HDA_AMP_MUTE)
pinval = 0x24;
else
pinval = 0x20;
/* mic2 vref pin is used for mute LED control */
snd_hda_codec_update_cache(codec, 0x19, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
pinval);
}
return alc_check_power_status(codec, nid);
}
#endif /* CONFIG_SND_HDA_POWER_SAVE */
/*
* BIOS auto configuration
*/
...
...
@@ -14082,7 +14207,7 @@ enum {
ALC269_FIXUP_SONY_VAIO,
};
const static
struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
static const
struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
{}
};
...
...
@@ -14290,17 +14415,17 @@ static int patch_alc269(struct hda_codec *codec)
codec->spec = spec;
alc_
fix_pll_init(codec, 0x20, 0x04, 15
);
alc_
auto_parse_customize_define(codec
);
if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
kfree(codec->chip_name);
codec->chip_name = kstrdup("ALC259", GFP_KERNEL);
if (!codec->chip_name) {
alc_free(codec);
return -ENOMEM;
}
if (codec->bus->pci->subsystem_vendor == 0x1025 &&
spec->cdefine.platform_type == 1)
alc_codec_rename(codec, "ALC271X");
else
alc_codec_rename(codec, "ALC259");
is_alc269vb = 1;
}
} else
alc_fix_pll_init(codec, 0x20, 0x04, 15);
board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
alc269_models,
...
...
@@ -14365,7 +14490,8 @@ static int patch_alc269(struct hda_codec *codec)
if (!spec->cap_mixer)
set_capture_mixer(codec);
set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
if (spec->cdefine.enable_pcbeep)
set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
if (board_config == ALC269_AUTO)
alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0);
...
...
@@ -14378,6 +14504,8 @@ static int patch_alc269(struct hda_codec *codec)
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (!spec->loopback.amplist)
spec->loopback.amplist = alc269_loopbacks;
if (alc269_mic2_for_mute_led(codec))
codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
#endif
return 0;
...
...
@@ -18525,16 +18653,16 @@ static int patch_alc662(struct hda_codec *codec)
codec->spec = spec;
alc_auto_parse_customize_define(codec);
alc_fix_pll_init(codec, 0x20, 0x04, 15);
if (alc_read_coef_idx(codec, 0)==0x8020){
kfree(codec->chip_name);
codec->chip_name = kstrdup("ALC661", GFP_KERNEL);
if (!codec->chip_name) {
alc_free(codec);
return -ENOMEM;
}
}
if (alc_read_coef_idx(codec, 0) == 0x8020)
alc_codec_rename(codec, "ALC661");
else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) &&
codec->bus->pci->subsystem_vendor == 0x1025 &&
spec->cdefine.platform_type == 1)
alc_codec_rename(codec, "ALC272X");
board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
alc662_models,
...
...
@@ -18584,18 +18712,20 @@ static int patch_alc662(struct hda_codec *codec)
if (!spec->cap_mixer)
set_capture_mixer(codec);
switch (codec->vendor_id) {
case 0x10ec0662:
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
break;
case 0x10ec0272:
case 0x10ec0663:
case 0x10ec0665:
set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
break;
case 0x10ec0273:
set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
break;
if (spec->cdefine.enable_pcbeep) {
switch (codec->vendor_id) {
case 0x10ec0662:
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
break;
case 0x10ec0272:
case 0x10ec0663:
case 0x10ec0665:
set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
break;
case 0x10ec0273:
set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
break;
}
}
spec->vmaster_nid = 0x02;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录