Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
42dc2378
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
42dc2378
编写于
16年前
作者:
T
Takashi Iwai
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'topic/hda-next' into topic/hda
上级
da74ae3e
74aeaabc
变更
16
隐藏空白更改
内联
并排
Showing
16 changed file
with
970 addition
and
412 deletion
+970
-412
include/linux/input.h
include/linux/input.h
+1
-0
include/sound/jack.h
include/sound/jack.h
+1
-0
sound/core/jack.c
sound/core/jack.c
+8
-1
sound/pci/Kconfig
sound/pci/Kconfig
+1
-0
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.c
+333
-95
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_codec.h
+41
-5
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.c
+12
-8
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_hwdep.c
+228
-0
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_intel.c
+35
-86
sound/pci/hda/hda_local.h
sound/pci/hda/hda_local.h
+10
-0
sound/pci/hda/hda_proc.c
sound/pci/hda/hda_proc.c
+5
-39
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_analog.c
+27
-29
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_conexant.c
+0
-11
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_realtek.c
+40
-46
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_sigmatel.c
+198
-51
sound/pci/hda/patch_via.c
sound/pci/hda/patch_via.c
+30
-41
未找到文件。
include/linux/input.h
浏览文件 @
42dc2378
...
...
@@ -644,6 +644,7 @@ struct input_absinfo {
#define SW_RADIO SW_RFKILL_ALL
/* deprecated */
#define SW_MICROPHONE_INSERT 0x04
/* set = inserted */
#define SW_DOCK 0x05
/* set = plugged into dock */
#define SW_LINEOUT_INSERT 0x06
/* set = inserted */
#define SW_MAX 0x0f
#define SW_CNT (SW_MAX+1)
...
...
This diff is collapsed.
Click to expand it.
include/sound/jack.h
浏览文件 @
42dc2378
...
...
@@ -35,6 +35,7 @@ enum snd_jack_types {
SND_JACK_HEADPHONE
=
0x0001
,
SND_JACK_MICROPHONE
=
0x0002
,
SND_JACK_HEADSET
=
SND_JACK_HEADPHONE
|
SND_JACK_MICROPHONE
,
SND_JACK_LINEOUT
=
0x0004
,
};
struct
snd_jack
{
...
...
This diff is collapsed.
Click to expand it.
sound/core/jack.c
浏览文件 @
42dc2378
...
...
@@ -34,6 +34,7 @@ static int snd_jack_dev_free(struct snd_device *device)
else
input_free_device
(
jack
->
input_dev
);
kfree
(
jack
->
id
);
kfree
(
jack
);
return
0
;
...
...
@@ -87,7 +88,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
if
(
jack
==
NULL
)
return
-
ENOMEM
;
jack
->
id
=
id
;
jack
->
id
=
kstrdup
(
id
,
GFP_KERNEL
)
;
jack
->
input_dev
=
input_allocate_device
();
if
(
jack
->
input_dev
==
NULL
)
{
...
...
@@ -102,6 +103,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
if
(
type
&
SND_JACK_HEADPHONE
)
input_set_capability
(
jack
->
input_dev
,
EV_SW
,
SW_HEADPHONE_INSERT
);
if
(
type
&
SND_JACK_LINEOUT
)
input_set_capability
(
jack
->
input_dev
,
EV_SW
,
SW_LINEOUT_INSERT
);
if
(
type
&
SND_JACK_MICROPHONE
)
input_set_capability
(
jack
->
input_dev
,
EV_SW
,
SW_MICROPHONE_INSERT
);
...
...
@@ -150,6 +154,9 @@ void snd_jack_report(struct snd_jack *jack, int status)
if
(
jack
->
type
&
SND_JACK_HEADPHONE
)
input_report_switch
(
jack
->
input_dev
,
SW_HEADPHONE_INSERT
,
status
&
SND_JACK_HEADPHONE
);
if
(
jack
->
type
&
SND_JACK_LINEOUT
)
input_report_switch
(
jack
->
input_dev
,
SW_LINEOUT_INSERT
,
status
&
SND_JACK_LINEOUT
);
if
(
jack
->
type
&
SND_JACK_MICROPHONE
)
input_report_switch
(
jack
->
input_dev
,
SW_MICROPHONE_INSERT
,
status
&
SND_JACK_MICROPHONE
);
...
...
This diff is collapsed.
Click to expand it.
sound/pci/Kconfig
浏览文件 @
42dc2378
...
...
@@ -501,6 +501,7 @@ config SND_HDA_INTEL
tristate "Intel HD Audio"
select SND_PCM
select SND_VMASTER
select SND_JACK if INPUT=y || INPUT=SND
help
Say Y here to include support for Intel "High Definition
Audio" (Azalia) motherboard devices.
...
...
This diff is collapsed.
Click to expand it.
sound/pci/hda/hda_codec.c
浏览文件 @
42dc2378
...
...
@@ -107,6 +107,52 @@ static void hda_keep_power_on(struct hda_codec *codec);
static
inline
void
hda_keep_power_on
(
struct
hda_codec
*
codec
)
{}
#endif
const
char
*
snd_hda_get_jack_location
(
u32
cfg
)
{
static
char
*
bases
[
7
]
=
{
"N/A"
,
"Rear"
,
"Front"
,
"Left"
,
"Right"
,
"Top"
,
"Bottom"
,
};
static
unsigned
char
specials_idx
[]
=
{
0x07
,
0x08
,
0x17
,
0x18
,
0x19
,
0x37
,
0x38
};
static
char
*
specials
[]
=
{
"Rear Panel"
,
"Drive Bar"
,
"Riser"
,
"HDMI"
,
"ATAPI"
,
"Mobile-In"
,
"Mobile-Out"
};
int
i
;
cfg
=
(
cfg
&
AC_DEFCFG_LOCATION
)
>>
AC_DEFCFG_LOCATION_SHIFT
;
if
((
cfg
&
0x0f
)
<
7
)
return
bases
[
cfg
&
0x0f
];
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
specials_idx
);
i
++
)
{
if
(
cfg
==
specials_idx
[
i
])
return
specials
[
i
];
}
return
"UNKNOWN"
;
}
const
char
*
snd_hda_get_jack_connectivity
(
u32
cfg
)
{
static
char
*
jack_locations
[
4
]
=
{
"Ext"
,
"Int"
,
"Sep"
,
"Oth"
};
return
jack_locations
[(
cfg
>>
(
AC_DEFCFG_LOCATION_SHIFT
+
4
))
&
3
];
}
const
char
*
snd_hda_get_jack_type
(
u32
cfg
)
{
static
char
*
jack_types
[
16
]
=
{
"Line Out"
,
"Speaker"
,
"HP Out"
,
"CD"
,
"SPDIF Out"
,
"Digital Out"
,
"Modem Line"
,
"Modem Hand"
,
"Line In"
,
"Aux"
,
"Mic"
,
"Telephony"
,
"SPDIF In"
,
"Digitial In"
,
"Reserved"
,
"Other"
};
return
jack_types
[(
cfg
&
AC_DEFCFG_DEVICE
)
>>
AC_DEFCFG_DEVICE_SHIFT
];
}
/**
* snd_hda_codec_read - send a command and get the response
* @codec: the HDA codec
...
...
@@ -344,7 +390,7 @@ static void process_unsol_events(struct work_struct *work)
/*
* initialize unsolicited queue
*/
static
int
__devinit
init_unsol_queue
(
struct
hda_bus
*
bus
)
static
int
init_unsol_queue
(
struct
hda_bus
*
bus
)
{
struct
hda_bus_unsolicited
*
unsol
;
...
...
@@ -393,6 +439,20 @@ static int snd_hda_bus_dev_free(struct snd_device *device)
return
snd_hda_bus_free
(
bus
);
}
#ifdef CONFIG_SND_HDA_HWDEP
static
int
snd_hda_bus_dev_register
(
struct
snd_device
*
device
)
{
struct
hda_bus
*
bus
=
device
->
device_data
;
struct
hda_codec
*
codec
;
list_for_each_entry
(
codec
,
&
bus
->
codec_list
,
list
)
{
snd_hda_hwdep_add_sysfs
(
codec
);
}
return
0
;
}
#else
#define snd_hda_bus_dev_register NULL
#endif
/**
* snd_hda_bus_new - create a HDA bus
* @card: the card entry
...
...
@@ -408,6 +468,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
struct
hda_bus
*
bus
;
int
err
;
static
struct
snd_device_ops
dev_ops
=
{
.
dev_register
=
snd_hda_bus_dev_register
,
.
dev_free
=
snd_hda_bus_dev_free
,
};
...
...
@@ -446,7 +507,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
#ifdef CONFIG_SND_HDA_GENERIC
#define is_generic_config(codec) \
(codec->
bus->modelname && !strcmp(codec->bus
->modelname, "generic"))
(codec->
modelname && !strcmp(codec
->modelname, "generic"))
#else
#define is_generic_config(codec) 0
#endif
...
...
@@ -454,7 +515,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
/*
* find a matching codec preset
*/
static
const
struct
hda_codec_preset
__devinit
*
static
const
struct
hda_codec_preset
*
find_codec_preset
(
struct
hda_codec
*
codec
)
{
const
struct
hda_codec_preset
**
tbl
,
*
preset
;
...
...
@@ -481,15 +542,14 @@ find_codec_preset(struct hda_codec *codec)
}
/*
*
snd_hda_
get_codec_name - store the codec name
* get_codec_name - store the codec name
*/
void
snd_hda_get_codec_name
(
struct
hda_codec
*
codec
,
char
*
name
,
int
namelen
)
static
int
get_codec_name
(
struct
hda_codec
*
codec
)
{
const
struct
hda_vendor_id
*
c
;
const
char
*
vendor
=
NULL
;
u16
vendor_id
=
codec
->
vendor_id
>>
16
;
char
tmp
[
16
];
char
tmp
[
16
]
,
name
[
32
]
;
for
(
c
=
hda_vendor_ids
;
c
->
id
;
c
++
)
{
if
(
c
->
id
==
vendor_id
)
{
...
...
@@ -502,10 +562,15 @@ void snd_hda_get_codec_name(struct hda_codec *codec,
vendor
=
tmp
;
}
if
(
codec
->
preset
&&
codec
->
preset
->
name
)
snprintf
(
name
,
namelen
,
"%s %s"
,
vendor
,
codec
->
preset
->
name
);
snprintf
(
name
,
sizeof
(
name
),
"%s %s"
,
vendor
,
codec
->
preset
->
name
);
else
snprintf
(
name
,
namelen
,
"%s ID %x"
,
vendor
,
snprintf
(
name
,
sizeof
(
name
)
,
"%s ID %x"
,
vendor
,
codec
->
vendor_id
&
0xffff
);
codec
->
name
=
kstrdup
(
name
,
GFP_KERNEL
);
if
(
!
codec
->
name
)
return
-
ENOMEM
;
return
0
;
}
/*
...
...
@@ -570,11 +635,14 @@ static void snd_hda_codec_free(struct hda_codec *codec)
flush_scheduled_work
();
#endif
list_del
(
&
codec
->
list
);
snd_array_free
(
&
codec
->
mixers
);
codec
->
bus
->
caddr_tbl
[
codec
->
addr
]
=
NULL
;
if
(
codec
->
patch_ops
.
free
)
codec
->
patch_ops
.
free
(
codec
);
free_hda_cache
(
&
codec
->
amp_cache
);
free_hda_cache
(
&
codec
->
cmd_cache
);
kfree
(
codec
->
name
);
kfree
(
codec
->
modelname
);
kfree
(
codec
->
wcaps
);
kfree
(
codec
);
}
...
...
@@ -616,6 +684,14 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
mutex_init
(
&
codec
->
spdif_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
snd_kcontrol
*
),
32
);
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
INIT_DELAYED_WORK
(
&
codec
->
power_work
,
hda_power_work
);
...
...
@@ -661,12 +737,41 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_SUBSYSTEM_ID
,
0
);
}
if
(
bus
->
modelname
)
codec
->
modelname
=
kstrdup
(
bus
->
modelname
,
GFP_KERNEL
);
err
=
snd_hda_codec_configure
(
codec
);
if
(
err
<
0
)
{
snd_hda_codec_free
(
codec
);
return
err
;
}
snd_hda_codec_proc_new
(
codec
);
snd_hda_create_hwdep
(
codec
);
sprintf
(
component
,
"HDA:%08x,%08x,%08x"
,
codec
->
vendor_id
,
codec
->
subsystem_id
,
codec
->
revision_id
);
snd_component_add
(
codec
->
bus
->
card
,
component
);
if
(
codecp
)
*
codecp
=
codec
;
return
0
;
}
int
snd_hda_codec_configure
(
struct
hda_codec
*
codec
)
{
int
err
;
codec
->
preset
=
find_codec_preset
(
codec
);
if
(
!
codec
->
name
)
{
err
=
get_codec_name
(
codec
);
if
(
err
<
0
)
return
err
;
}
/* audio codec should override the mixer name */
if
(
codec
->
afg
||
!*
bus
->
card
->
mixername
)
s
nd_hda_get_codec_name
(
codec
,
bus
->
card
->
mixer
name
,
sizeof
(
bus
->
card
->
mixername
));
if
(
codec
->
afg
||
!*
codec
->
bus
->
card
->
mixername
)
s
trlcpy
(
codec
->
bus
->
card
->
mixername
,
codec
->
name
,
sizeof
(
codec
->
bus
->
card
->
mixername
));
if
(
is_generic_config
(
codec
))
{
err
=
snd_hda_parse_generic_codec
(
codec
);
...
...
@@ -683,25 +788,9 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
printk
(
KERN_ERR
"hda-codec: No codec parser is available
\n
"
);
patched:
if
(
err
<
0
)
{
snd_hda_codec_free
(
codec
);
return
err
;
}
if
(
codec
->
patch_ops
.
unsol_event
)
init_unsol_queue
(
bus
);
snd_hda_codec_proc_new
(
codec
);
#ifdef CONFIG_SND_HDA_HWDEP
snd_hda_create_hwdep
(
codec
);
#endif
sprintf
(
component
,
"HDA:%08x,%08x,%08x"
,
codec
->
vendor_id
,
codec
->
subsystem_id
,
codec
->
revision_id
);
snd_component_add
(
codec
->
bus
->
card
,
component
);
if
(
codecp
)
*
codecp
=
codec
;
return
0
;
if
(
!
err
&&
codec
->
patch_ops
.
unsol_event
)
err
=
init_unsol_queue
(
codec
->
bus
);
return
err
;
}
/**
...
...
@@ -756,12 +845,12 @@ static void __devinit init_hda_cache(struct hda_cache_rec *cache,
{
memset
(
cache
,
0
,
sizeof
(
*
cache
));
memset
(
cache
->
hash
,
0xff
,
sizeof
(
cache
->
hash
));
cache
->
record_size
=
record_size
;
snd_array_init
(
&
cache
->
buf
,
record_size
,
64
)
;
}
static
void
free_hda_cache
(
struct
hda_cache_rec
*
cache
)
{
kfree
(
cache
->
buffer
);
snd_array_free
(
&
cache
->
buf
);
}
/* query the hash. allocate an entry if not found. */
...
...
@@ -770,38 +859,18 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache,
{
u16
idx
=
key
%
(
u16
)
ARRAY_SIZE
(
cache
->
hash
);
u16
cur
=
cache
->
hash
[
idx
];
struct
hda_cache_head
*
info_head
=
cache
->
buf
.
list
;
struct
hda_cache_head
*
info
;
while
(
cur
!=
0xffff
)
{
info
=
(
struct
hda_cache_head
*
)(
cache
->
buffer
+
cur
*
cache
->
record_size
);
info
=
&
info_head
[
cur
];
if
(
info
->
key
==
key
)
return
info
;
cur
=
info
->
next
;
}
/* add a new hash entry */
if
(
cache
->
num_entries
>=
cache
->
size
)
{
/* reallocate the array */
unsigned
int
new_size
=
cache
->
size
+
64
;
void
*
new_buffer
;
new_buffer
=
kcalloc
(
new_size
,
cache
->
record_size
,
GFP_KERNEL
);
if
(
!
new_buffer
)
{
snd_printk
(
KERN_ERR
"hda_codec: "
"can't malloc amp_info
\n
"
);
return
NULL
;
}
if
(
cache
->
buffer
)
{
memcpy
(
new_buffer
,
cache
->
buffer
,
cache
->
size
*
cache
->
record_size
);
kfree
(
cache
->
buffer
);
}
cache
->
size
=
new_size
;
cache
->
buffer
=
new_buffer
;
}
cur
=
cache
->
num_entries
++
;
info
=
(
struct
hda_cache_head
*
)(
cache
->
buffer
+
cur
*
cache
->
record_size
);
info
=
snd_array_new
(
&
cache
->
buf
);
info
->
key
=
key
;
info
->
val
=
0
;
info
->
next
=
cache
->
hash
[
idx
];
...
...
@@ -942,10 +1011,10 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
/* resume the all amp commands from the cache */
void
snd_hda_codec_resume_amp
(
struct
hda_codec
*
codec
)
{
struct
hda_amp_info
*
buffer
=
codec
->
amp_cache
.
buf
fer
;
struct
hda_amp_info
*
buffer
=
codec
->
amp_cache
.
buf
.
list
;
int
i
;
for
(
i
=
0
;
i
<
codec
->
amp_cache
.
size
;
i
++
,
buffer
++
)
{
for
(
i
=
0
;
i
<
codec
->
amp_cache
.
buf
.
used
;
i
++
,
buffer
++
)
{
u32
key
=
buffer
->
head
.
key
;
hda_nid_t
nid
;
unsigned
int
idx
,
dir
,
ch
;
...
...
@@ -1097,6 +1166,57 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
return
_snd_hda_find_mixer_ctl
(
codec
,
name
,
0
);
}
/* Add a control element and assign to the codec */
int
snd_hda_ctl_add
(
struct
hda_codec
*
codec
,
struct
snd_kcontrol
*
kctl
)
{
int
err
;
struct
snd_kcontrol
**
knewp
;
err
=
snd_ctl_add
(
codec
->
bus
->
card
,
kctl
);
if
(
err
<
0
)
return
err
;
knewp
=
snd_array_new
(
&
codec
->
mixers
);
if
(
!
knewp
)
return
-
ENOMEM
;
*
knewp
=
kctl
;
return
0
;
}
/* Clear all controls assigned to the given codec */
void
snd_hda_ctls_clear
(
struct
hda_codec
*
codec
)
{
int
i
;
struct
snd_kcontrol
**
kctls
=
codec
->
mixers
.
list
;
for
(
i
=
0
;
i
<
codec
->
mixers
.
used
;
i
++
)
snd_ctl_remove
(
codec
->
bus
->
card
,
kctls
[
i
]);
snd_array_free
(
&
codec
->
mixers
);
}
void
snd_hda_codec_reset
(
struct
hda_codec
*
codec
)
{
int
i
;
#ifdef CONFIG_SND_HDA_POWER_SAVE
cancel_delayed_work
(
&
codec
->
power_work
);
flush_scheduled_work
();
#endif
snd_hda_ctls_clear
(
codec
);
/* relase PCMs */
for
(
i
=
0
;
i
<
codec
->
num_pcms
;
i
++
)
{
if
(
codec
->
pcm_info
[
i
].
pcm
)
snd_device_free
(
codec
->
bus
->
card
,
codec
->
pcm_info
[
i
].
pcm
);
}
if
(
codec
->
patch_ops
.
free
)
codec
->
patch_ops
.
free
(
codec
);
codec
->
spec
=
NULL
;
free_hda_cache
(
&
codec
->
amp_cache
);
free_hda_cache
(
&
codec
->
cmd_cache
);
codec
->
num_pcms
=
0
;
codec
->
pcm_info
=
NULL
;
codec
->
preset
=
NULL
;
}
/* create a virtual master control and add slaves */
int
snd_hda_add_vmaster
(
struct
hda_codec
*
codec
,
char
*
name
,
unsigned
int
*
tlv
,
const
char
**
slaves
)
...
...
@@ -1114,7 +1234,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
kctl
=
snd_ctl_make_virtual_master
(
name
,
tlv
);
if
(
!
kctl
)
return
-
ENOMEM
;
err
=
snd_
ctl_add
(
codec
->
bus
->
card
,
kctl
);
err
=
snd_
hda_ctl_add
(
codec
,
kctl
);
if
(
err
<
0
)
return
err
;
...
...
@@ -1578,7 +1698,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
kctl
=
snd_ctl_new1
(
dig_mix
,
codec
);
kctl
->
id
.
index
=
idx
;
kctl
->
private_value
=
nid
;
err
=
snd_
ctl_add
(
codec
->
bus
->
card
,
kctl
);
err
=
snd_
hda_ctl_add
(
codec
,
kctl
);
if
(
err
<
0
)
return
err
;
}
...
...
@@ -1622,7 +1742,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
if
(
!
mout
->
dig_out_nid
)
return
0
;
/* ATTENTION: here mout is passed as private_data, instead of codec */
return
snd_
ctl_add
(
codec
->
bus
->
card
,
return
snd_
hda_ctl_add
(
codec
,
snd_ctl_new1
(
&
spdif_share_sw
,
mout
));
}
...
...
@@ -1724,7 +1844,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
for
(
dig_mix
=
dig_in_ctls
;
dig_mix
->
name
;
dig_mix
++
)
{
kctl
=
snd_ctl_new1
(
dig_mix
,
codec
);
kctl
->
private_value
=
nid
;
err
=
snd_
ctl_add
(
codec
->
bus
->
card
,
kctl
);
err
=
snd_
hda_ctl_add
(
codec
,
kctl
);
if
(
err
<
0
)
return
err
;
}
...
...
@@ -1779,10 +1899,10 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
/* resume the all commands from the cache */
void
snd_hda_codec_resume_cache
(
struct
hda_codec
*
codec
)
{
struct
hda_cache_head
*
buffer
=
codec
->
cmd_cache
.
buf
fer
;
struct
hda_cache_head
*
buffer
=
codec
->
cmd_cache
.
buf
.
list
;
int
i
;
for
(
i
=
0
;
i
<
codec
->
cmd_cache
.
size
;
i
++
,
buffer
++
)
{
for
(
i
=
0
;
i
<
codec
->
cmd_cache
.
buf
.
used
;
i
++
,
buffer
++
)
{
u32
key
=
buffer
->
key
;
if
(
!
key
)
continue
;
...
...
@@ -1867,6 +1987,17 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
}
}
#ifdef CONFIG_SND_HDA_HWDEP
/* execute additional init verbs */
static
void
hda_exec_init_verbs
(
struct
hda_codec
*
codec
)
{
if
(
codec
->
init_verbs
.
list
)
snd_hda_sequence_write
(
codec
,
codec
->
init_verbs
.
list
);
}
#else
static
inline
void
hda_exec_init_verbs
(
struct
hda_codec
*
codec
)
{}
#endif
#ifdef SND_HDA_NEEDS_RESUME
/*
* call suspend and power-down; used both from PM and power-save
...
...
@@ -1893,6 +2024,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
hda_set_power_state
(
codec
,
codec
->
afg
?
codec
->
afg
:
codec
->
mfg
,
AC_PWRST_D0
);
hda_exec_init_verbs
(
codec
);
if
(
codec
->
patch_ops
.
resume
)
codec
->
patch_ops
.
resume
(
codec
);
else
{
...
...
@@ -1918,23 +2050,31 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus)
struct
hda_codec
*
codec
;
list_for_each_entry
(
codec
,
&
bus
->
codec_list
,
list
)
{
int
err
=
0
;
/* fake as if already powered-on */
hda_keep_power_on
(
codec
);
/* then fire up */
hda_set_power_state
(
codec
,
codec
->
afg
?
codec
->
afg
:
codec
->
mfg
,
AC_PWRST_D0
);
/* continue to initialize... */
if
(
codec
->
patch_ops
.
init
)
err
=
codec
->
patch_ops
.
init
(
codec
);
if
(
!
err
&&
codec
->
patch_ops
.
build_controls
)
err
=
codec
->
patch_ops
.
build_controls
(
codec
);
snd_hda_power_down
(
codec
);
int
err
=
snd_hda_codec_build_controls
(
codec
);
if
(
err
<
0
)
return
err
;
}
return
0
;
}
int
snd_hda_codec_build_controls
(
struct
hda_codec
*
codec
)
{
int
err
=
0
;
/* fake as if already powered-on */
hda_keep_power_on
(
codec
);
/* then fire up */
hda_set_power_state
(
codec
,
codec
->
afg
?
codec
->
afg
:
codec
->
mfg
,
AC_PWRST_D0
);
hda_exec_init_verbs
(
codec
);
/* continue to initialize... */
if
(
codec
->
patch_ops
.
init
)
err
=
codec
->
patch_ops
.
init
(
codec
);
if
(
!
err
&&
codec
->
patch_ops
.
build_controls
)
err
=
codec
->
patch_ops
.
build_controls
(
codec
);
snd_hda_power_down
(
codec
);
if
(
err
<
0
)
return
err
;
return
0
;
}
...
...
@@ -2235,8 +2375,8 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo,
return
0
;
}
static
int
__devinit
set_pcm_default_values
(
struct
hda_codec
*
codec
,
struct
hda_pcm_stream
*
info
)
static
int
set_pcm_default_values
(
struct
hda_codec
*
codec
,
struct
hda_pcm_stream
*
info
)
{
/* query support PCM information from the given NID */
if
(
info
->
nid
&&
(
!
info
->
rates
||
!
info
->
formats
))
{
...
...
@@ -2262,6 +2402,28 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec,
return
0
;
}
/*
* attach a new PCM stream
*/
static
int
__devinit
snd_hda_attach_pcm
(
struct
hda_codec
*
codec
,
struct
hda_pcm
*
pcm
)
{
struct
hda_pcm_stream
*
info
;
int
stream
,
err
;
if
(
!
pcm
->
name
)
return
-
EINVAL
;
for
(
stream
=
0
;
stream
<
2
;
stream
++
)
{
info
=
&
pcm
->
stream
[
stream
];
if
(
info
->
substreams
)
{
err
=
set_pcm_default_values
(
codec
,
info
);
if
(
err
<
0
)
return
err
;
}
}
return
codec
->
bus
->
ops
.
attach_pcm
(
codec
,
pcm
);
}
/**
* snd_hda_build_pcms - build PCM information
* @bus: the BUS
...
...
@@ -2288,25 +2450,67 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec,
*
* This function returns 0 if successfull, or a negative error code.
*/
int
__devinit
snd_hda_build_pcms
(
struct
hda_bus
*
bus
)
int
snd_hda_build_pcms
(
struct
hda_bus
*
bus
)
{
static
const
char
*
dev_name
[
HDA_PCM_NTYPES
]
=
{
"Audio"
,
"SPDIF"
,
"HDMI"
,
"Modem"
};
/* starting device index for each PCM type */
static
int
dev_idx
[
HDA_PCM_NTYPES
]
=
{
[
HDA_PCM_TYPE_AUDIO
]
=
0
,
[
HDA_PCM_TYPE_SPDIF
]
=
1
,
[
HDA_PCM_TYPE_HDMI
]
=
3
,
[
HDA_PCM_TYPE_MODEM
]
=
6
};
/* normal audio device indices; not linear to keep compatibility */
static
int
audio_idx
[
4
]
=
{
0
,
2
,
4
,
5
};
struct
hda_codec
*
codec
;
int
num_devs
[
HDA_PCM_NTYPES
];
memset
(
num_devs
,
0
,
sizeof
(
num_devs
));
list_for_each_entry
(
codec
,
&
bus
->
codec_list
,
list
)
{
unsigned
int
pcm
,
s
;
unsigned
int
pcm
;
int
err
;
if
(
!
codec
->
patch_ops
.
build_pcms
)
continue
;
err
=
codec
->
patch_ops
.
build_pcms
(
codec
);
if
(
err
<
0
)
return
err
;
if
(
!
codec
->
num_pcms
)
{
if
(
!
codec
->
patch_ops
.
build_pcms
)
continue
;
err
=
codec
->
patch_ops
.
build_pcms
(
codec
);
if
(
err
<
0
)
return
err
;
}
for
(
pcm
=
0
;
pcm
<
codec
->
num_pcms
;
pcm
++
)
{
for
(
s
=
0
;
s
<
2
;
s
++
)
{
struct
hda_pcm_stream
*
info
;
info
=
&
codec
->
pcm_info
[
pcm
].
stream
[
s
];
if
(
!
info
->
substreams
)
struct
hda_pcm
*
cpcm
=
&
codec
->
pcm_info
[
pcm
];
int
type
=
cpcm
->
pcm_type
;
int
dev
;
switch
(
type
)
{
case
HDA_PCM_TYPE_AUDIO
:
if
(
num_devs
[
type
]
>=
ARRAY_SIZE
(
audio_idx
))
{
snd_printk
(
KERN_WARNING
"Too many audio devices
\n
"
);
continue
;
err
=
set_pcm_default_values
(
codec
,
info
);
}
dev
=
audio_idx
[
num_devs
[
type
]];
break
;
case
HDA_PCM_TYPE_SPDIF
:
case
HDA_PCM_TYPE_HDMI
:
case
HDA_PCM_TYPE_MODEM
:
if
(
num_devs
[
type
])
{
snd_printk
(
KERN_WARNING
"%s already defined
\n
"
,
dev_name
[
type
]);
continue
;
}
dev
=
dev_idx
[
type
];
break
;
default:
snd_printk
(
KERN_WARNING
"Invalid PCM type %d
\n
"
,
type
);
continue
;
}
num_devs
[
type
]
++
;
if
(
!
cpcm
->
pcm
)
{
cpcm
->
device
=
dev
;
err
=
snd_hda_attach_pcm
(
codec
,
cpcm
);
if
(
err
<
0
)
return
err
;
}
...
...
@@ -2332,11 +2536,11 @@ int snd_hda_check_board_config(struct hda_codec *codec,
int
num_configs
,
const
char
**
models
,
const
struct
snd_pci_quirk
*
tbl
)
{
if
(
codec
->
bus
->
modelname
&&
models
)
{
if
(
codec
->
modelname
&&
models
)
{
int
i
;
for
(
i
=
0
;
i
<
num_configs
;
i
++
)
{
if
(
models
[
i
]
&&
!
strcmp
(
codec
->
bus
->
modelname
,
models
[
i
]))
{
!
strcmp
(
codec
->
modelname
,
models
[
i
]))
{
snd_printd
(
KERN_INFO
"hda_codec: model '%s' is "
"selected
\n
"
,
models
[
i
]);
return
i
;
...
...
@@ -2389,7 +2593,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
kctl
=
snd_ctl_new1
(
knew
,
codec
);
if
(
!
kctl
)
return
-
ENOMEM
;
err
=
snd_
ctl_add
(
codec
->
bus
->
card
,
kctl
);
err
=
snd_
hda_ctl_add
(
codec
,
kctl
);
if
(
err
<
0
)
{
if
(
!
codec
->
addr
)
return
err
;
...
...
@@ -2397,7 +2601,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
if
(
!
kctl
)
return
-
ENOMEM
;
kctl
->
id
.
device
=
codec
->
addr
;
err
=
snd_
ctl_add
(
codec
->
bus
->
card
,
kctl
);
err
=
snd_
hda_ctl_add
(
codec
,
kctl
);
if
(
err
<
0
)
return
err
;
}
...
...
@@ -3138,3 +3342,37 @@ int snd_hda_codecs_inuse(struct hda_bus *bus)
}
#endif
#endif
/*
* generic arrays
*/
/* get a new element from the given array
* if it exceeds the pre-allocated array size, re-allocate the array
*/
void
*
snd_array_new
(
struct
snd_array
*
array
)
{
if
(
array
->
used
>=
array
->
alloced
)
{
int
num
=
array
->
alloced
+
array
->
alloc_align
;
void
*
nlist
=
kcalloc
(
num
+
1
,
array
->
elem_size
,
GFP_KERNEL
);
if
(
!
nlist
)
return
NULL
;
if
(
array
->
list
)
{
memcpy
(
nlist
,
array
->
list
,
array
->
elem_size
*
array
->
alloced
);
kfree
(
array
->
list
);
}
array
->
list
=
nlist
;
array
->
alloced
=
num
;
}
return
array
->
list
+
(
array
->
used
++
*
array
->
elem_size
);
}
/* free the given array elements */
void
snd_array_free
(
struct
snd_array
*
array
)
{
kfree
(
array
->
list
);
array
->
used
=
0
;
array
->
alloced
=
0
;
array
->
list
=
NULL
;
}
This diff is collapsed.
Click to expand it.
sound/pci/hda/hda_codec.h
浏览文件 @
42dc2378
...
...
@@ -519,6 +519,26 @@ enum {
/* max. codec address */
#define HDA_MAX_CODEC_ADDRESS 0x0f
/*
* generic arrays
*/
struct
snd_array
{
unsigned
int
used
;
unsigned
int
alloced
;
unsigned
int
elem_size
;
unsigned
int
alloc_align
;
void
*
list
;
};
void
*
snd_array_new
(
struct
snd_array
*
array
);
void
snd_array_free
(
struct
snd_array
*
array
);
static
inline
void
snd_array_init
(
struct
snd_array
*
array
,
unsigned
int
size
,
unsigned
int
align
)
{
array
->
elem_size
=
size
;
array
->
alloc_align
=
align
;
}
/*
* Structures
*/
...
...
@@ -542,6 +562,8 @@ struct hda_bus_ops {
unsigned
int
(
*
get_response
)(
struct
hda_codec
*
codec
);
/* free the private data */
void
(
*
private_free
)(
struct
hda_bus
*
);
/* attach a PCM stream */
int
(
*
attach_pcm
)(
struct
hda_codec
*
codec
,
struct
hda_pcm
*
pcm
);
#ifdef CONFIG_SND_HDA_POWER_SAVE
/* notify power-up/down from codec to controller */
void
(
*
pm_notify
)(
struct
hda_codec
*
codec
);
...
...
@@ -635,10 +657,7 @@ struct hda_amp_info {
struct
hda_cache_rec
{
u16
hash
[
64
];
/* hash table for index */
unsigned
int
num_entries
;
/* number of assigned entries */
unsigned
int
size
;
/* allocated size */
unsigned
int
record_size
;
/* record size (including header) */
void
*
buffer
;
/* hash table entries */
struct
snd_array
buf
;
/* record entries */
};
/* PCM callbacks */
...
...
@@ -680,7 +699,8 @@ struct hda_pcm {
char
*
name
;
struct
hda_pcm_stream
stream
[
2
];
unsigned
int
pcm_type
;
/* HDA_PCM_TYPE_XXX */
int
device
;
/* assigned device number */
int
device
;
/* device number to assign */
struct
snd_pcm
*
pcm
;
/* assigned PCM instance */
};
/* codec information */
...
...
@@ -699,6 +719,8 @@ struct hda_codec {
/* detected preset */
const
struct
hda_codec_preset
*
preset
;
const
char
*
name
;
/* codec name */
const
char
*
modelname
;
/* model name for preset */
/* set by patch */
struct
hda_codec_ops
patch_ops
;
...
...
@@ -718,6 +740,8 @@ struct hda_codec {
hda_nid_t
start_nid
;
u32
*
wcaps
;
struct
snd_array
mixers
;
/* list of assigned mixer elements */
struct
hda_cache_rec
amp_cache
;
/* cache for amp access */
struct
hda_cache_rec
cmd_cache
;
/* cache for other commands */
...
...
@@ -727,7 +751,11 @@ struct hda_codec {
unsigned
int
spdif_in_enable
;
/* SPDIF input enable? */
hda_nid_t
*
slave_dig_outs
;
/* optional digital out slave widgets */
#ifdef CONFIG_SND_HDA_HWDEP
struct
snd_hwdep
*
hwdep
;
/* assigned hwdep device */
struct
snd_array
init_verbs
;
/* additional init verbs */
struct
snd_array
hints
;
/* additional hints */
#endif
/* misc flags */
unsigned
int
spdif_status_reset
:
1
;
/* needs to toggle SPDIF for each
...
...
@@ -799,6 +827,7 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec);
* Mixer
*/
int
snd_hda_build_controls
(
struct
hda_bus
*
bus
);
int
snd_hda_codec_build_controls
(
struct
hda_codec
*
codec
);
/*
* PCM
...
...
@@ -830,6 +859,13 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state);
int
snd_hda_resume
(
struct
hda_bus
*
bus
);
#endif
/*
* get widget information
*/
const
char
*
snd_hda_get_jack_connectivity
(
u32
cfg
);
const
char
*
snd_hda_get_jack_type
(
u32
cfg
);
const
char
*
snd_hda_get_jack_location
(
u32
cfg
);
/*
* power saving
*/
...
...
This diff is collapsed.
Click to expand it.
sound/pci/hda/hda_generic.c
浏览文件 @
42dc2378
...
...
@@ -723,7 +723,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
if
(
is_loopback
)
add_input_loopback
(
codec
,
node
->
nid
,
HDA_INPUT
,
index
);
snd_printdd
(
"[%s] NID=0x%x, DIR=IN, IDX=0x%x
\n
"
,
name
,
node
->
nid
,
index
);
if
((
err
=
snd_ctl_add
(
codec
->
bus
->
card
,
snd_ctl_new1
(
&
knew
,
codec
)))
<
0
)
err
=
snd_hda_ctl_add
(
codec
,
snd_ctl_new1
(
&
knew
,
codec
));
if
(
err
<
0
)
return
err
;
created
=
1
;
}
else
if
((
node
->
wid_caps
&
AC_WCAP_OUT_AMP
)
&&
...
...
@@ -732,7 +733,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
if
(
is_loopback
)
add_input_loopback
(
codec
,
node
->
nid
,
HDA_OUTPUT
,
0
);
snd_printdd
(
"[%s] NID=0x%x, DIR=OUT
\n
"
,
name
,
node
->
nid
);
if
((
err
=
snd_ctl_add
(
codec
->
bus
->
card
,
snd_ctl_new1
(
&
knew
,
codec
)))
<
0
)
err
=
snd_hda_ctl_add
(
codec
,
snd_ctl_new1
(
&
knew
,
codec
));
if
(
err
<
0
)
return
err
;
created
=
1
;
}
...
...
@@ -745,14 +747,16 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
(
node
->
amp_in_caps
&
AC_AMPCAP_NUM_STEPS
))
{
knew
=
(
struct
snd_kcontrol_new
)
HDA_CODEC_VOLUME
(
name
,
node
->
nid
,
index
,
HDA_INPUT
);
snd_printdd
(
"[%s] NID=0x%x, DIR=IN, IDX=0x%x
\n
"
,
name
,
node
->
nid
,
index
);
if
((
err
=
snd_ctl_add
(
codec
->
bus
->
card
,
snd_ctl_new1
(
&
knew
,
codec
)))
<
0
)
err
=
snd_hda_ctl_add
(
codec
,
snd_ctl_new1
(
&
knew
,
codec
));
if
(
err
<
0
)
return
err
;
created
=
1
;
}
else
if
((
node
->
wid_caps
&
AC_WCAP_OUT_AMP
)
&&
(
node
->
amp_out_caps
&
AC_AMPCAP_NUM_STEPS
))
{
knew
=
(
struct
snd_kcontrol_new
)
HDA_CODEC_VOLUME
(
name
,
node
->
nid
,
0
,
HDA_OUTPUT
);
snd_printdd
(
"[%s] NID=0x%x, DIR=OUT
\n
"
,
name
,
node
->
nid
);
if
((
err
=
snd_ctl_add
(
codec
->
bus
->
card
,
snd_ctl_new1
(
&
knew
,
codec
)))
<
0
)
err
=
snd_hda_ctl_add
(
codec
,
snd_ctl_new1
(
&
knew
,
codec
));
if
(
err
<
0
)
return
err
;
created
=
1
;
}
...
...
@@ -849,8 +853,8 @@ static int build_input_controls(struct hda_codec *codec)
}
/* create input MUX if multiple sources are available */
if
((
err
=
snd_ctl_add
(
codec
->
bus
->
card
,
snd_ctl_new1
(
&
cap_sel
,
codec
)))
<
0
)
err
=
snd_hda_ctl_add
(
codec
,
snd_ctl_new1
(
&
cap_sel
,
codec
));
if
(
err
<
0
)
return
err
;
/* no volume control? */
...
...
@@ -867,8 +871,8 @@ static int build_input_controls(struct hda_codec *codec)
HDA_CODEC_VOLUME
(
name
,
adc_node
->
nid
,
spec
->
input_mux
.
items
[
i
].
index
,
HDA_INPUT
);
if
((
err
=
snd_ctl_add
(
codec
->
bus
->
card
,
snd_ctl_new1
(
&
knew
,
codec
)))
<
0
)
err
=
snd_hda_ctl_add
(
codec
,
snd_ctl_new1
(
&
knew
,
codec
));
if
(
err
<
0
)
return
err
;
}
...
...
This diff is collapsed.
Click to expand it.
sound/pci/hda/hda_hwdep.c
浏览文件 @
42dc2378
...
...
@@ -23,10 +23,12 @@
#include <linux/pci.h>
#include <linux/compat.h>
#include <linux/mutex.h>
#include <linux/ctype.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
#include <sound/hda_hwdep.h>
#include <sound/minors.h>
/*
* write/read an out-of-bound verb
...
...
@@ -95,6 +97,25 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
return
0
;
}
static
void
clear_hwdep_elements
(
struct
hda_codec
*
codec
)
{
char
**
head
;
int
i
;
/* clear init verbs */
snd_array_free
(
&
codec
->
init_verbs
);
/* clear hints */
head
=
codec
->
hints
.
list
;
for
(
i
=
0
;
i
<
codec
->
hints
.
used
;
i
++
,
head
++
)
kfree
(
*
head
);
snd_array_free
(
&
codec
->
hints
);
}
static
void
hwdep_free
(
struct
snd_hwdep
*
hwdep
)
{
clear_hwdep_elements
(
hwdep
->
private_data
);
}
int
__devinit
snd_hda_create_hwdep
(
struct
hda_codec
*
codec
)
{
char
hwname
[
16
];
...
...
@@ -109,6 +130,7 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
sprintf
(
hwdep
->
name
,
"HDA Codec %d"
,
codec
->
addr
);
hwdep
->
iface
=
SNDRV_HWDEP_IFACE_HDA
;
hwdep
->
private_data
=
codec
;
hwdep
->
private_free
=
hwdep_free
;
hwdep
->
exclusive
=
1
;
hwdep
->
ops
.
open
=
hda_hwdep_open
;
...
...
@@ -117,5 +139,211 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
hwdep
->
ops
.
ioctl_compat
=
hda_hwdep_ioctl_compat
;
#endif
snd_array_init
(
&
codec
->
init_verbs
,
sizeof
(
struct
hda_verb
),
32
);
snd_array_init
(
&
codec
->
hints
,
sizeof
(
char
*
),
32
);
return
0
;
}
/*
* sysfs interface
*/
static
int
clear_codec
(
struct
hda_codec
*
codec
)
{
snd_hda_codec_reset
(
codec
);
clear_hwdep_elements
(
codec
);
return
0
;
}
static
int
reconfig_codec
(
struct
hda_codec
*
codec
)
{
int
err
;
snd_printk
(
KERN_INFO
"hda-codec: reconfiguring
\n
"
);
snd_hda_codec_reset
(
codec
);
err
=
snd_hda_codec_configure
(
codec
);
if
(
err
<
0
)
return
err
;
/* rebuild PCMs */
err
=
snd_hda_build_pcms
(
codec
->
bus
);
if
(
err
<
0
)
return
err
;
/* rebuild mixers */
err
=
snd_hda_codec_build_controls
(
codec
);
if
(
err
<
0
)
return
err
;
return
0
;
}
/*
* allocate a string at most len chars, and remove the trailing EOL
*/
static
char
*
kstrndup_noeol
(
const
char
*
src
,
size_t
len
)
{
char
*
s
=
kstrndup
(
src
,
len
,
GFP_KERNEL
);
char
*
p
;
if
(
!
s
)
return
NULL
;
p
=
strchr
(
s
,
'\n'
);
if
(
p
)
*
p
=
0
;
return
s
;
}
#define CODEC_INFO_SHOW(type) \
static ssize_t type##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
struct hda_codec *codec = hwdep->private_data; \
return sprintf(buf, "0x%x\n", codec->type); \
}
#define CODEC_INFO_STR_SHOW(type) \
static ssize_t type##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
struct hda_codec *codec = hwdep->private_data; \
return sprintf(buf, "%s\n", \
codec->type ? codec->type : ""); \
}
CODEC_INFO_SHOW
(
vendor_id
);
CODEC_INFO_SHOW
(
subsystem_id
);
CODEC_INFO_SHOW
(
revision_id
);
CODEC_INFO_SHOW
(
afg
);
CODEC_INFO_SHOW
(
mfg
);
CODEC_INFO_STR_SHOW
(
name
);
CODEC_INFO_STR_SHOW
(
modelname
);
#define CODEC_INFO_STORE(type) \
static ssize_t type##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
struct hda_codec *codec = hwdep->private_data; \
char *after; \
codec->type = simple_strtoul(buf, &after, 0); \
return count; \
}
#define CODEC_INFO_STR_STORE(type) \
static ssize_t type##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
struct hda_codec *codec = hwdep->private_data; \
char *s = kstrndup_noeol(buf, 64); \
if (!s) \
return -ENOMEM; \
kfree(codec->type); \
codec->type = s; \
return count; \
}
CODEC_INFO_STORE
(
vendor_id
);
CODEC_INFO_STORE
(
subsystem_id
);
CODEC_INFO_STORE
(
revision_id
);
CODEC_INFO_STR_STORE
(
name
);
CODEC_INFO_STR_STORE
(
modelname
);
#define CODEC_ACTION_STORE(type) \
static ssize_t type##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
struct hda_codec *codec = hwdep->private_data; \
int err = 0; \
if (*buf) \
err = type##_codec(codec); \
return err < 0 ? err : count; \
}
CODEC_ACTION_STORE
(
reconfig
);
CODEC_ACTION_STORE
(
clear
);
static
ssize_t
init_verbs_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
snd_hwdep
*
hwdep
=
dev_get_drvdata
(
dev
);
struct
hda_codec
*
codec
=
hwdep
->
private_data
;
char
*
p
;
struct
hda_verb
verb
,
*
v
;
verb
.
nid
=
simple_strtoul
(
buf
,
&
p
,
0
);
verb
.
verb
=
simple_strtoul
(
p
,
&
p
,
0
);
verb
.
param
=
simple_strtoul
(
p
,
&
p
,
0
);
if
(
!
verb
.
nid
||
!
verb
.
verb
||
!
verb
.
param
)
return
-
EINVAL
;
v
=
snd_array_new
(
&
codec
->
init_verbs
);
if
(
!
v
)
return
-
ENOMEM
;
*
v
=
verb
;
return
count
;
}
static
ssize_t
hints_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
snd_hwdep
*
hwdep
=
dev_get_drvdata
(
dev
);
struct
hda_codec
*
codec
=
hwdep
->
private_data
;
char
*
p
;
char
**
hint
;
if
(
!*
buf
||
isspace
(
*
buf
)
||
*
buf
==
'#'
||
*
buf
==
'\n'
)
return
count
;
p
=
kstrndup_noeol
(
buf
,
1024
);
if
(
!
p
)
return
-
ENOMEM
;
hint
=
snd_array_new
(
&
codec
->
hints
);
if
(
!
hint
)
{
kfree
(
p
);
return
-
ENOMEM
;
}
*
hint
=
p
;
return
count
;
}
#define CODEC_ATTR_RW(type) \
__ATTR(type, 0644, type##_show, type##_store)
#define CODEC_ATTR_RO(type) \
__ATTR_RO(type)
#define CODEC_ATTR_WO(type) \
__ATTR(type, 0200, NULL, type##_store)
static
struct
device_attribute
codec_attrs
[]
=
{
CODEC_ATTR_RW
(
vendor_id
),
CODEC_ATTR_RW
(
subsystem_id
),
CODEC_ATTR_RW
(
revision_id
),
CODEC_ATTR_RO
(
afg
),
CODEC_ATTR_RO
(
mfg
),
CODEC_ATTR_RW
(
name
),
CODEC_ATTR_RW
(
modelname
),
CODEC_ATTR_WO
(
init_verbs
),
CODEC_ATTR_WO
(
hints
),
CODEC_ATTR_WO
(
reconfig
),
CODEC_ATTR_WO
(
clear
),
};
/*
* create sysfs files on hwdep directory
*/
int
snd_hda_hwdep_add_sysfs
(
struct
hda_codec
*
codec
)
{
struct
snd_hwdep
*
hwdep
=
codec
->
hwdep
;
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
codec_attrs
);
i
++
)
snd_add_device_sysfs_file
(
SNDRV_DEVICE_TYPE_HWDEP
,
hwdep
->
card
,
hwdep
->
device
,
&
codec_attrs
[
i
]);
return
0
;
}
This diff is collapsed.
Click to expand it.
sound/pci/hda/hda_intel.c
浏览文件 @
42dc2378
...
...
@@ -1180,6 +1180,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
return
0
;
}
static
int
azx_attach_pcm_stream
(
struct
hda_codec
*
codec
,
struct
hda_pcm
*
cpcm
);
/*
* Codec initialization
...
...
@@ -1212,6 +1213,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
bus_temp
.
pci
=
chip
->
pci
;
bus_temp
.
ops
.
command
=
azx_send_cmd
;
bus_temp
.
ops
.
get_response
=
azx_get_response
;
bus_temp
.
ops
.
attach_pcm
=
azx_attach_pcm_stream
;
#ifdef CONFIG_SND_HDA_POWER_SAVE
bus_temp
.
ops
.
pm_notify
=
azx_power_notify
;
#endif
...
...
@@ -1718,111 +1720,58 @@ static struct snd_pcm_ops azx_pcm_ops = {
static
void
azx_pcm_free
(
struct
snd_pcm
*
pcm
)
{
kfree
(
pcm
->
private_data
);
struct
azx_pcm
*
apcm
=
pcm
->
private_data
;
if
(
apcm
)
{
apcm
->
chip
->
pcm
[
pcm
->
device
]
=
NULL
;
kfree
(
apcm
);
}
}
static
int
__devinit
create_codec_pcm
(
struct
azx
*
chip
,
struct
hda_codec
*
codec
,
struct
hda_pcm
*
cpcm
)
static
int
azx_attach_pcm_stream
(
struct
hda_codec
*
codec
,
struct
hda_pcm
*
cpcm
)
{
int
err
;
struct
azx
*
chip
=
codec
->
bus
->
private_data
;
struct
snd_pcm
*
pcm
;
struct
azx_pcm
*
apcm
;
int
pcm_dev
=
cpcm
->
device
;
int
s
,
err
;
/* if no substreams are defined for both playback and capture,
* it's just a placeholder. ignore it.
*/
if
(
!
cpcm
->
stream
[
0
].
substreams
&&
!
cpcm
->
stream
[
1
].
substreams
)
return
0
;
if
(
snd_BUG_ON
(
!
cpcm
->
name
))
if
(
pcm_dev
>=
AZX_MAX_PCMS
)
{
snd_printk
(
KERN_ERR
SFX
"Invalid PCM device number %d
\n
"
,
pcm_dev
);
return
-
EINVAL
;
err
=
snd_pcm_new
(
chip
->
card
,
cpcm
->
name
,
cpcm
->
device
,
cpcm
->
stream
[
0
].
substreams
,
cpcm
->
stream
[
1
].
substreams
,
}
if
(
chip
->
pcm
[
pcm_dev
])
{
snd_printk
(
KERN_ERR
SFX
"PCM %d already exists
\n
"
,
pcm_dev
);
return
-
EBUSY
;
}
err
=
snd_pcm_new
(
chip
->
card
,
cpcm
->
name
,
pcm_dev
,
cpcm
->
stream
[
SNDRV_PCM_STREAM_PLAYBACK
].
substreams
,
cpcm
->
stream
[
SNDRV_PCM_STREAM_CAPTURE
].
substreams
,
&
pcm
);
if
(
err
<
0
)
return
err
;
strcpy
(
pcm
->
name
,
cpcm
->
name
);
apcm
=
k
m
alloc
(
sizeof
(
*
apcm
),
GFP_KERNEL
);
apcm
=
k
z
alloc
(
sizeof
(
*
apcm
),
GFP_KERNEL
);
if
(
apcm
==
NULL
)
return
-
ENOMEM
;
apcm
->
chip
=
chip
;
apcm
->
codec
=
codec
;
apcm
->
hinfo
[
0
]
=
&
cpcm
->
stream
[
0
];
apcm
->
hinfo
[
1
]
=
&
cpcm
->
stream
[
1
];
pcm
->
private_data
=
apcm
;
pcm
->
private_free
=
azx_pcm_free
;
if
(
cpcm
->
stream
[
0
].
substreams
)
snd_pcm_set_ops
(
pcm
,
SNDRV_PCM_STREAM_PLAYBACK
,
&
azx_pcm_ops
);
if
(
cpcm
->
stream
[
1
].
substreams
)
snd_pcm_set_ops
(
pcm
,
SNDRV_PCM_STREAM_CAPTURE
,
&
azx_pcm_ops
);
if
(
cpcm
->
pcm_type
==
HDA_PCM_TYPE_MODEM
)
pcm
->
dev_class
=
SNDRV_PCM_CLASS_MODEM
;
chip
->
pcm
[
pcm_dev
]
=
pcm
;
cpcm
->
pcm
=
pcm
;
for
(
s
=
0
;
s
<
2
;
s
++
)
{
apcm
->
hinfo
[
s
]
=
&
cpcm
->
stream
[
s
];
if
(
cpcm
->
stream
[
s
].
substreams
)
snd_pcm_set_ops
(
pcm
,
s
,
&
azx_pcm_ops
);
}
/* buffer pre-allocation */
snd_pcm_lib_preallocate_pages_for_all
(
pcm
,
SNDRV_DMA_TYPE_DEV_SG
,
snd_dma_pci_data
(
chip
->
pci
),
1024
*
64
,
32
*
1024
*
1024
);
chip
->
pcm
[
cpcm
->
device
]
=
pcm
;
return
0
;
}
static
int
__devinit
azx_pcm_create
(
struct
azx
*
chip
)
{
static
const
char
*
dev_name
[
HDA_PCM_NTYPES
]
=
{
"Audio"
,
"SPDIF"
,
"HDMI"
,
"Modem"
};
/* starting device index for each PCM type */
static
int
dev_idx
[
HDA_PCM_NTYPES
]
=
{
[
HDA_PCM_TYPE_AUDIO
]
=
0
,
[
HDA_PCM_TYPE_SPDIF
]
=
1
,
[
HDA_PCM_TYPE_HDMI
]
=
3
,
[
HDA_PCM_TYPE_MODEM
]
=
6
};
/* normal audio device indices; not linear to keep compatibility */
static
int
audio_idx
[
4
]
=
{
0
,
2
,
4
,
5
};
struct
hda_codec
*
codec
;
int
c
,
err
;
int
num_devs
[
HDA_PCM_NTYPES
];
err
=
snd_hda_build_pcms
(
chip
->
bus
);
if
(
err
<
0
)
return
err
;
/* create audio PCMs */
memset
(
num_devs
,
0
,
sizeof
(
num_devs
));
list_for_each_entry
(
codec
,
&
chip
->
bus
->
codec_list
,
list
)
{
for
(
c
=
0
;
c
<
codec
->
num_pcms
;
c
++
)
{
struct
hda_pcm
*
cpcm
=
&
codec
->
pcm_info
[
c
];
int
type
=
cpcm
->
pcm_type
;
switch
(
type
)
{
case
HDA_PCM_TYPE_AUDIO
:
if
(
num_devs
[
type
]
>=
ARRAY_SIZE
(
audio_idx
))
{
snd_printk
(
KERN_WARNING
"Too many audio devices
\n
"
);
continue
;
}
cpcm
->
device
=
audio_idx
[
num_devs
[
type
]];
break
;
case
HDA_PCM_TYPE_SPDIF
:
case
HDA_PCM_TYPE_HDMI
:
case
HDA_PCM_TYPE_MODEM
:
if
(
num_devs
[
type
])
{
snd_printk
(
KERN_WARNING
"%s already defined
\n
"
,
dev_name
[
type
]);
continue
;
}
cpcm
->
device
=
dev_idx
[
type
];
break
;
default:
snd_printk
(
KERN_WARNING
"Invalid PCM type %d
\n
"
,
type
);
continue
;
}
num_devs
[
type
]
++
;
err
=
create_codec_pcm
(
chip
,
codec
,
cpcm
);
if
(
err
<
0
)
return
err
;
}
}
return
0
;
}
...
...
@@ -2324,7 +2273,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
}
/* create PCM streams */
err
=
azx_pcm_create
(
chip
);
err
=
snd_hda_build_pcms
(
chip
->
bus
);
if
(
err
<
0
)
{
snd_card_free
(
card
);
return
err
;
...
...
This diff is collapsed.
Click to expand it.
sound/pci/hda/hda_local.h
浏览文件 @
42dc2378
...
...
@@ -96,6 +96,8 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
const
char
*
name
);
int
snd_hda_add_vmaster
(
struct
hda_codec
*
codec
,
char
*
name
,
unsigned
int
*
tlv
,
const
char
**
slaves
);
void
snd_hda_codec_reset
(
struct
hda_codec
*
codec
);
int
snd_hda_codec_configure
(
struct
hda_codec
*
codec
);
/* amp value bits */
#define HDA_AMP_MUTE 0x80
...
...
@@ -393,10 +395,18 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
int
snd_hda_override_amp_caps
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
dir
,
unsigned
int
caps
);
int
snd_hda_ctl_add
(
struct
hda_codec
*
codec
,
struct
snd_kcontrol
*
kctl
);
void
snd_hda_ctls_clear
(
struct
hda_codec
*
codec
);
/*
* hwdep interface
*/
#ifdef CONFIG_SND_HDA_HWDEP
int
snd_hda_create_hwdep
(
struct
hda_codec
*
codec
);
int
snd_hda_hwdep_add_sysfs
(
struct
hda_codec
*
codec
);
#else
static
inline
int
snd_hda_create_hwdep
(
struct
hda_codec
*
codec
)
{
return
0
;
}
#endif
/*
* power-management
...
...
This diff is collapsed.
Click to expand it.
sound/pci/hda/hda_proc.c
浏览文件 @
42dc2378
...
...
@@ -145,32 +145,6 @@ static void print_pcm_caps(struct snd_info_buffer *buffer,
print_pcm_formats
(
buffer
,
stream
);
}
static
const
char
*
get_jack_location
(
u32
cfg
)
{
static
char
*
bases
[
7
]
=
{
"N/A"
,
"Rear"
,
"Front"
,
"Left"
,
"Right"
,
"Top"
,
"Bottom"
,
};
static
unsigned
char
specials_idx
[]
=
{
0x07
,
0x08
,
0x17
,
0x18
,
0x19
,
0x37
,
0x38
};
static
char
*
specials
[]
=
{
"Rear Panel"
,
"Drive Bar"
,
"Riser"
,
"HDMI"
,
"ATAPI"
,
"Mobile-In"
,
"Mobile-Out"
};
int
i
;
cfg
=
(
cfg
&
AC_DEFCFG_LOCATION
)
>>
AC_DEFCFG_LOCATION_SHIFT
;
if
((
cfg
&
0x0f
)
<
7
)
return
bases
[
cfg
&
0x0f
];
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
specials_idx
);
i
++
)
{
if
(
cfg
==
specials_idx
[
i
])
return
specials
[
i
];
}
return
"UNKNOWN"
;
}
static
const
char
*
get_jack_connection
(
u32
cfg
)
{
static
char
*
names
[
16
]
=
{
...
...
@@ -206,13 +180,6 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
int
*
supports_vref
)
{
static
char
*
jack_conns
[
4
]
=
{
"Jack"
,
"N/A"
,
"Fixed"
,
"Both"
};
static
char
*
jack_types
[
16
]
=
{
"Line Out"
,
"Speaker"
,
"HP Out"
,
"CD"
,
"SPDIF Out"
,
"Digital Out"
,
"Modem Line"
,
"Modem Hand"
,
"Line In"
,
"Aux"
,
"Mic"
,
"Telephony"
,
"SPDIF In"
,
"Digitial In"
,
"Reserved"
,
"Other"
};
static
char
*
jack_locations
[
4
]
=
{
"Ext"
,
"Int"
,
"Sep"
,
"Oth"
};
unsigned
int
caps
,
val
;
caps
=
snd_hda_param_read
(
codec
,
nid
,
AC_PAR_PIN_CAP
);
...
...
@@ -274,9 +241,9 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
caps
=
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_CONFIG_DEFAULT
,
0
);
snd_iprintf
(
buffer
,
" Pin Default 0x%08x: [%s] %s at %s %s
\n
"
,
caps
,
jack_conns
[(
caps
&
AC_DEFCFG_PORT_CONN
)
>>
AC_DEFCFG_PORT_CONN_SHIFT
],
jack_types
[(
caps
&
AC_DEFCFG_DEVICE
)
>>
AC_DEFCFG_DEVICE_SHIFT
]
,
jack_locations
[(
caps
>>
(
AC_DEFCFG_LOCATION_SHIFT
+
4
))
&
3
]
,
get_jack_location
(
caps
));
snd_hda_get_jack_type
(
caps
)
,
snd_hda_get_jack_connectivity
(
caps
)
,
snd_hda_
get_jack_location
(
caps
));
snd_iprintf
(
buffer
,
" Conn = %s, Color = %s
\n
"
,
get_jack_connection
(
caps
),
get_jack_color
(
caps
));
...
...
@@ -511,12 +478,11 @@ static void print_codec_info(struct snd_info_entry *entry,
struct
snd_info_buffer
*
buffer
)
{
struct
hda_codec
*
codec
=
entry
->
private_data
;
char
buf
[
32
];
hda_nid_t
nid
;
int
i
,
nodes
;
snd_
hda_get_codec_name
(
codec
,
buf
,
sizeof
(
buf
));
snd_iprintf
(
buffer
,
"Codec: %s
\n
"
,
buf
);
snd_
iprintf
(
buffer
,
"Codec: %s
\n
"
,
codec
->
name
?
codec
->
name
:
"Not Set"
);
snd_iprintf
(
buffer
,
"Address: %d
\n
"
,
codec
->
addr
);
snd_iprintf
(
buffer
,
"Vendor Id: 0x%x
\n
"
,
codec
->
vendor_id
);
snd_iprintf
(
buffer
,
"Subsystem Id: 0x%x
\n
"
,
codec
->
subsystem_id
);
...
...
This diff is collapsed.
Click to expand it.
sound/pci/hda/patch_analog.c
浏览文件 @
42dc2378
...
...
@@ -67,8 +67,7 @@ struct ad198x_spec {
/* dynamic controls, init_verbs and input_mux */
struct
auto_pin_cfg
autocfg
;
unsigned
int
num_kctl_alloc
,
num_kctl_used
;
struct
snd_kcontrol_new
*
kctl_alloc
;
struct
snd_array
kctls
;
struct
hda_input_mux
private_imux
;
hda_nid_t
private_dac_nids
[
AUTO_CFG_MAX_OUTS
];
...
...
@@ -154,6 +153,8 @@ static const char *ad_slave_sws[] = {
NULL
};
static
void
ad198x_free_kctls
(
struct
hda_codec
*
codec
);
static
int
ad198x_build_controls
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
...
...
@@ -202,6 +203,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
return
err
;
}
ad198x_free_kctls
(
codec
);
/* no longer needed */
return
0
;
}
...
...
@@ -375,16 +377,27 @@ static int ad198x_build_pcms(struct hda_codec *codec)
return
0
;
}
static
void
ad198x_free
(
struct
hda_codec
*
codec
)
static
void
ad198x_free
_kctls
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
unsigned
int
i
;
if
(
spec
->
kctl_alloc
)
{
for
(
i
=
0
;
i
<
spec
->
num_kctl_used
;
i
++
)
kfree
(
spec
->
kctl_alloc
[
i
].
name
);
kfree
(
spec
->
kctl_alloc
);
if
(
spec
->
kctls
.
list
)
{
struct
snd_kcontrol_new
*
kctl
=
spec
->
kctls
.
list
;
int
i
;
for
(
i
=
0
;
i
<
spec
->
kctls
.
used
;
i
++
)
kfree
(
kctl
[
i
].
name
);
}
snd_array_free
(
&
spec
->
kctls
);
}
static
void
ad198x_free
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
if
(
!
spec
)
return
;
ad198x_free_kctls
(
codec
);
kfree
(
codec
->
spec
);
}
...
...
@@ -2452,9 +2465,6 @@ static struct hda_amp_list ad1988_loopbacks[] = {
* Automatic parse of I/O pins from the BIOS configuration
*/
#define NUM_CONTROL_ALLOC 32
#define NUM_VERB_ALLOC 32
enum
{
AD_CTL_WIDGET_VOL
,
AD_CTL_WIDGET_MUTE
,
...
...
@@ -2472,27 +2482,15 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name,
{
struct
snd_kcontrol_new
*
knew
;
if
(
spec
->
num_kctl_used
>=
spec
->
num_kctl_alloc
)
{
int
num
=
spec
->
num_kctl_alloc
+
NUM_CONTROL_ALLOC
;
knew
=
kcalloc
(
num
+
1
,
sizeof
(
*
knew
),
GFP_KERNEL
);
/* array + terminator */
if
(
!
knew
)
return
-
ENOMEM
;
if
(
spec
->
kctl_alloc
)
{
memcpy
(
knew
,
spec
->
kctl_alloc
,
sizeof
(
*
knew
)
*
spec
->
num_kctl_alloc
);
kfree
(
spec
->
kctl_alloc
);
}
spec
->
kctl_alloc
=
knew
;
spec
->
num_kctl_alloc
=
num
;
}
knew
=
&
spec
->
kctl_alloc
[
spec
->
num_kctl_used
];
snd_array_init
(
&
spec
->
kctls
,
sizeof
(
*
knew
),
32
);
knew
=
snd_array_new
(
&
spec
->
kctls
);
if
(
!
knew
)
return
-
ENOMEM
;
*
knew
=
ad1988_control_templates
[
type
];
knew
->
name
=
kstrdup
(
name
,
GFP_KERNEL
);
if
(
!
knew
->
name
)
return
-
ENOMEM
;
knew
->
private_value
=
val
;
spec
->
num_kctl_used
++
;
return
0
;
}
...
...
@@ -2846,8 +2844,8 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
if
(
spec
->
autocfg
.
dig_in_pin
)
spec
->
dig_in_nid
=
AD1988_SPDIF_IN
;
if
(
spec
->
kctl
_alloc
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
_alloc
;
if
(
spec
->
kctl
s
.
list
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
s
.
list
;
spec
->
init_verbs
[
spec
->
num_init_verbs
++
]
=
ad1988_6stack_init_verbs
;
...
...
This diff is collapsed.
Click to expand it.
sound/pci/hda/patch_conexant.c
浏览文件 @
42dc2378
...
...
@@ -86,8 +86,6 @@ struct conexant_spec {
/* dynamic controls, init_verbs and input_mux */
struct
auto_pin_cfg
autocfg
;
unsigned
int
num_kctl_alloc
,
num_kctl_used
;
struct
snd_kcontrol_new
*
kctl_alloc
;
struct
hda_input_mux
private_imux
;
hda_nid_t
private_dac_nids
[
AUTO_CFG_MAX_OUTS
];
...
...
@@ -344,15 +342,6 @@ static int conexant_init(struct hda_codec *codec)
static
void
conexant_free
(
struct
hda_codec
*
codec
)
{
struct
conexant_spec
*
spec
=
codec
->
spec
;
unsigned
int
i
;
if
(
spec
->
kctl_alloc
)
{
for
(
i
=
0
;
i
<
spec
->
num_kctl_used
;
i
++
)
kfree
(
spec
->
kctl_alloc
[
i
].
name
);
kfree
(
spec
->
kctl_alloc
);
}
kfree
(
codec
->
spec
);
}
...
...
This diff is collapsed.
Click to expand it.
sound/pci/hda/patch_realtek.c
浏览文件 @
42dc2378
...
...
@@ -284,8 +284,7 @@ struct alc_spec {
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
unsigned int num_kctl_alloc, num_kctl_used;
struct snd_kcontrol_new *kctl_alloc;
struct snd_array kctls;
struct hda_input_mux private_imux;
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
...
...
@@ -1625,6 +1624,9 @@ static const char *alc_slave_sws[] = {
/*
* build control elements
*/
static void alc_free_kctls(struct hda_codec *codec);
static int alc_build_controls(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
...
...
@@ -1671,6 +1673,7 @@ static int alc_build_controls(struct hda_codec *codec)
return err;
}
alc_free_kctls(codec); /* no longer needed */
return 0;
}
...
...
@@ -2761,19 +2764,27 @@ static int alc_build_pcms(struct hda_codec *codec)
return 0;
}
static void alc_free_kctls(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
if (spec->kctls.list) {
struct snd_kcontrol_new *kctl = spec->kctls.list;
int i;
for (i = 0; i < spec->kctls.used; i++)
kfree(kctl[i].name);
}
snd_array_free(&spec->kctls);
}
static void alc_free(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
unsigned int i;
if (!spec)
return;
if (spec->kctl_alloc) {
for (i = 0; i < spec->num_kctl_used; i++)
kfree(spec->kctl_alloc[i].name);
kfree(spec->kctl_alloc);
}
alc_free_kctls(codec);
kfree(spec);
codec->spec = NULL; /* to be sure */
}
...
...
@@ -3458,9 +3469,6 @@ static struct alc_config_preset alc880_presets[] = {
* Automatic parse of I/O pins from the BIOS configuration
*/
#define NUM_CONTROL_ALLOC 32
#define NUM_VERB_ALLOC 32
enum {
ALC_CTL_WIDGET_VOL,
ALC_CTL_WIDGET_MUTE,
...
...
@@ -3478,29 +3486,15 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
{
struct snd_kcontrol_new *knew;
if (spec->num_kctl_used >= spec->num_kctl_alloc) {
int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
/* array + terminator */
knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
if (!knew)
return -ENOMEM;
if (spec->kctl_alloc) {
memcpy(knew, spec->kctl_alloc,
sizeof(*knew) * spec->num_kctl_alloc);
kfree(spec->kctl_alloc);
}
spec->kctl_alloc = knew;
spec->num_kctl_alloc = num;
}
knew = &spec->kctl_alloc[spec->num_kctl_used];
snd_array_init(&spec->kctls, sizeof(*knew), 32);
knew = snd_array_new(&spec->kctls);
if (!knew)
return -ENOMEM;
*knew = alc880_control_templates[type];
knew->name = kstrdup(name, GFP_KERNEL);
if (!knew->name)
return -ENOMEM;
knew->private_value = val;
spec->num_kctl_used++;
return 0;
}
...
...
@@ -3824,8 +3818,8 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = ALC880_DIGIN_NID;
if (spec->kctl
_alloc
)
spec->mixers[spec->num_mixers++] = spec->kctl
_alloc
;
if (spec->kctl
s.list
)
spec->mixers[spec->num_mixers++] = spec->kctl
s.list
;
spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
...
...
@@ -5218,7 +5212,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
if (err < 0)
return err;
if (!spec->kctl
_alloc
)
if (!spec->kctl
s.list
)
return 0; /* can't find valid BIOS pin config */
err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
if (err < 0)
...
...
@@ -5228,8 +5222,8 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
if (spec->kctl
_alloc
)
spec->mixers[spec->num_mixers++] = spec->kctl
_alloc
;
if (spec->kctl
s.list
)
spec->mixers[spec->num_mixers++] = spec->kctl
s.list
;
spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
...
...
@@ -10302,8 +10296,8 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = ALC262_DIGIN_NID;
if (spec->kctl
_alloc
)
spec->mixers[spec->num_mixers++] = spec->kctl
_alloc
;
if (spec->kctl
s.list
)
spec->mixers[spec->num_mixers++] = spec->kctl
s.list
;
spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
spec->num_mux_defs = 1;
...
...
@@ -11433,8 +11427,8 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
if (spec->kctl
_alloc
)
spec->mixers[spec->num_mixers++] = spec->kctl
_alloc
;
if (spec->kctl
s.list
)
spec->mixers[spec->num_mixers++] = spec->kctl
s.list
;
if (spec->autocfg.speaker_pins[0] != 0x1d)
spec->mixers[spec->num_mixers++] = alc268_beep_mixer;
...
...
@@ -12205,8 +12199,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
if (spec->kctl
_alloc
)
spec->mixers[spec->num_mixers++] = spec->kctl
_alloc
;
if (spec->kctl
s.list
)
spec->mixers[spec->num_mixers++] = spec->kctl
s.list
;
/* create a beep mixer control if the pin 0x1d isn't assigned */
for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
...
...
@@ -13303,8 +13297,8 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
if (spec->kctl
_alloc
)
spec->mixers[spec->num_mixers++] = spec->kctl
_alloc
;
if (spec->kctl
s.list
)
spec->mixers[spec->num_mixers++] = spec->kctl
s.list
;
spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
...
...
@@ -14414,8 +14408,8 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
if (spec->kctl
_alloc
)
spec->mixers[spec->num_mixers++] = spec->kctl
_alloc
;
if (spec->kctl
s.list
)
spec->mixers[spec->num_mixers++] = spec->kctl
s.list
;
spec->init_verbs[spec->num_init_verbs++]
= alc861vd_volume_init_verbs;
...
...
@@ -16241,8 +16235,8 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
if (spec->kctl
_alloc
)
spec->mixers[spec->num_mixers++] = spec->kctl
_alloc
;
if (spec->kctl
s.list
)
spec->mixers[spec->num_mixers++] = spec->kctl
s.list
;
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
...
...
This diff is collapsed.
Click to expand it.
sound/pci/hda/patch_sigmatel.c
浏览文件 @
42dc2378
...
...
@@ -30,12 +30,13 @@
#include <linux/pci.h>
#include <sound/core.h>
#include <sound/asoundef.h>
#include <sound/jack.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_patch.h"
#include "hda_beep.h"
#define
NUM_CONTROL_ALLOC 32
#define
STAC_INSERT_EVENT 0x10
#define STAC_PWR_EVENT 0x20
#define STAC_HP_EVENT 0x30
#define STAC_VREF_EVENT 0x40
...
...
@@ -129,6 +130,17 @@ enum {
STAC_927X_MODELS
};
struct
sigmatel_event
{
hda_nid_t
nid
;
int
data
;
};
struct
sigmatel_jack
{
hda_nid_t
nid
;
int
type
;
struct
snd_jack
*
jack
;
};
struct
sigmatel_spec
{
struct
snd_kcontrol_new
*
mixers
[
4
];
unsigned
int
num_mixers
;
...
...
@@ -161,6 +173,12 @@ struct sigmatel_spec {
hda_nid_t
*
pwr_nids
;
hda_nid_t
*
dac_list
;
/* jack detection */
struct
snd_array
jacks
;
/* events */
struct
snd_array
events
;
/* playback */
struct
hda_input_mux
*
mono_mux
;
struct
hda_input_mux
*
amp_mux
;
...
...
@@ -218,8 +236,7 @@ struct sigmatel_spec {
/* dynamic controls and input_mux */
struct
auto_pin_cfg
autocfg
;
unsigned
int
num_kctl_alloc
,
num_kctl_used
;
struct
snd_kcontrol_new
*
kctl_alloc
;
struct
snd_array
kctls
;
struct
hda_input_mux
private_dimux
;
struct
hda_input_mux
private_imux
;
struct
hda_input_mux
private_smux
;
...
...
@@ -1233,6 +1250,8 @@ static const char *slave_sws[] = {
NULL
};
static
void
stac92xx_free_kctls
(
struct
hda_codec
*
codec
);
static
int
stac92xx_build_controls
(
struct
hda_codec
*
codec
)
{
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
...
...
@@ -1250,7 +1269,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
}
if
(
spec
->
num_dmuxes
>
0
)
{
stac_dmux_mixer
.
count
=
spec
->
num_dmuxes
;
err
=
snd_
ctl_add
(
codec
->
bus
->
card
,
err
=
snd_
hda_ctl_add
(
codec
,
snd_ctl_new1
(
&
stac_dmux_mixer
,
codec
));
if
(
err
<
0
)
return
err
;
...
...
@@ -1305,6 +1324,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
return
err
;
}
stac92xx_free_kctls
(
codec
);
/* no longer needed */
return
0
;
}
...
...
@@ -2453,13 +2473,15 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
struct
auto_pin_cfg
*
cfg
=
&
spec
->
autocfg
;
int
nid
=
cfg
->
hp_pins
[
cfg
->
hp_outs
-
1
];
spec
->
hp_switch
=
ucontrol
->
value
.
integer
.
value
[
0
];
/* check to be sure that the ports are upto date with
* switch changes
*/
codec
->
patch_ops
.
unsol_event
(
codec
,
STAC_HP_EVENT
<<
26
);
codec
->
patch_ops
.
unsol_event
(
codec
,
(
STAC_HP_EVENT
|
nid
)
<<
26
);
return
1
;
}
...
...
@@ -2499,7 +2521,8 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
* appropriately according to the pin direction
*/
if
(
spec
->
hp_detect
)
codec
->
patch_ops
.
unsol_event
(
codec
,
STAC_HP_EVENT
<<
26
);
codec
->
patch_ops
.
unsol_event
(
codec
,
(
STAC_HP_EVENT
|
nid
)
<<
26
);
return
1
;
}
...
...
@@ -2592,28 +2615,16 @@ static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
{
struct
snd_kcontrol_new
*
knew
;
if
(
spec
->
num_kctl_used
>=
spec
->
num_kctl_alloc
)
{
int
num
=
spec
->
num_kctl_alloc
+
NUM_CONTROL_ALLOC
;
knew
=
kcalloc
(
num
+
1
,
sizeof
(
*
knew
),
GFP_KERNEL
);
/* array + terminator */
if
(
!
knew
)
return
-
ENOMEM
;
if
(
spec
->
kctl_alloc
)
{
memcpy
(
knew
,
spec
->
kctl_alloc
,
sizeof
(
*
knew
)
*
spec
->
num_kctl_alloc
);
kfree
(
spec
->
kctl_alloc
);
}
spec
->
kctl_alloc
=
knew
;
spec
->
num_kctl_alloc
=
num
;
}
knew
=
&
spec
->
kctl_alloc
[
spec
->
num_kctl_used
];
snd_array_init
(
&
spec
->
kctls
,
sizeof
(
*
knew
),
32
);
knew
=
snd_array_new
(
&
spec
->
kctls
);
if
(
!
knew
)
return
-
ENOMEM
;
*
knew
=
stac92xx_control_templates
[
type
];
knew
->
index
=
idx
;
knew
->
name
=
kstrdup
(
name
,
GFP_KERNEL
);
if
(
!
knew
->
name
)
return
-
ENOMEM
;
knew
->
private_value
=
val
;
spec
->
num_kctl_used
++
;
return
0
;
}
...
...
@@ -3434,8 +3445,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
if
(
dig_in
&&
spec
->
autocfg
.
dig_in_pin
)
spec
->
dig_in_nid
=
dig_in
;
if
(
spec
->
kctl
_alloc
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
_alloc
;
if
(
spec
->
kctl
s
.
list
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
s
.
list
;
spec
->
input_mux
=
&
spec
->
private_imux
;
spec
->
dinput_mux
=
&
spec
->
private_dimux
;
...
...
@@ -3536,8 +3547,8 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
if
(
spec
->
autocfg
.
dig_in_pin
)
spec
->
dig_in_nid
=
0x04
;
if
(
spec
->
kctl
_alloc
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
_alloc
;
if
(
spec
->
kctl
s
.
list
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
s
.
list
;
spec
->
input_mux
=
&
spec
->
private_imux
;
spec
->
dinput_mux
=
&
spec
->
private_dimux
;
...
...
@@ -3581,13 +3592,70 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
AC_VERB_SET_GPIO_DATA
,
gpiostate
);
/* sync */
}
static
int
stac92xx_add_jack
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
type
)
{
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
struct
sigmatel_jack
*
jack
;
int
def_conf
=
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_CONFIG_DEFAULT
,
0
);
int
connectivity
=
get_defcfg_connect
(
def_conf
);
char
name
[
32
];
if
(
connectivity
&&
connectivity
!=
AC_JACK_PORT_FIXED
)
return
0
;
snd_array_init
(
&
spec
->
jacks
,
sizeof
(
*
jack
),
32
);
jack
=
snd_array_new
(
&
spec
->
jacks
);
if
(
!
jack
)
return
-
ENOMEM
;
jack
->
nid
=
nid
;
jack
->
type
=
type
;
sprintf
(
name
,
"%s at %s %s Jack"
,
snd_hda_get_jack_type
(
def_conf
),
snd_hda_get_jack_connectivity
(
def_conf
),
snd_hda_get_jack_location
(
def_conf
));
return
snd_jack_new
(
codec
->
bus
->
card
,
name
,
type
,
&
jack
->
jack
);
}
static
int
stac92xx_add_event
(
struct
sigmatel_spec
*
spec
,
hda_nid_t
nid
,
int
data
)
{
struct
sigmatel_event
*
event
;
snd_array_init
(
&
spec
->
events
,
sizeof
(
*
event
),
32
);
event
=
snd_array_new
(
&
spec
->
events
);
if
(
!
event
)
return
-
ENOMEM
;
event
->
nid
=
nid
;
event
->
data
=
data
;
return
0
;
}
static
int
stac92xx_event_data
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
struct
sigmatel_event
*
events
=
spec
->
events
.
list
;
if
(
events
)
{
int
i
;
for
(
i
=
0
;
i
<
spec
->
events
.
used
;
i
++
)
if
(
events
[
i
].
nid
==
nid
)
return
events
[
i
].
data
;
}
return
0
;
}
static
void
enable_pin_detect
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
unsigned
int
event
)
{
if
(
get_wcaps
(
codec
,
nid
)
&
AC_WCAP_UNSOL_CAP
)
if
(
get_wcaps
(
codec
,
nid
)
&
AC_WCAP_UNSOL_CAP
)
{
snd_hda_codec_write_cache
(
codec
,
nid
,
0
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
(
AC_USRSP_EN
|
event
));
(
AC_USRSP_EN
|
event
|
nid
));
}
}
static
int
is_nid_hp_pin
(
struct
auto_pin_cfg
*
cfg
,
hda_nid_t
nid
)
...
...
@@ -3617,7 +3685,7 @@ static int stac92xx_init(struct hda_codec *codec)
{
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
struct
auto_pin_cfg
*
cfg
=
&
spec
->
autocfg
;
int
i
;
int
i
,
err
;
snd_hda_sequence_write
(
codec
,
spec
->
init
);
...
...
@@ -3630,21 +3698,36 @@ static int stac92xx_init(struct hda_codec *codec)
/* set up pins */
if
(
spec
->
hp_detect
)
{
/* Enable unsolicited responses on the HP widget */
for
(
i
=
0
;
i
<
cfg
->
hp_outs
;
i
++
)
enable_pin_detect
(
codec
,
cfg
->
hp_pins
[
i
],
STAC_HP_EVENT
);
for
(
i
=
0
;
i
<
cfg
->
hp_outs
;
i
++
)
{
int
type
=
SND_JACK_HEADPHONE
;
hda_nid_t
nid
=
cfg
->
hp_pins
[
i
];
enable_pin_detect
(
codec
,
nid
,
STAC_HP_EVENT
|
nid
);
/* jack detection */
if
(
cfg
->
hp_outs
==
i
)
type
|=
SND_JACK_LINEOUT
;
err
=
stac92xx_add_jack
(
codec
,
nid
,
type
);
if
(
err
<
0
)
return
err
;
}
/* force to enable the first line-out; the others are set up
* in unsol_event
*/
stac92xx_auto_set_pinctl
(
codec
,
spec
->
autocfg
.
line_out_pins
[
0
],
AC_PINCTL_OUT_EN
);
stac92xx_auto_init_hp_out
(
codec
);
AC_PINCTL_OUT_EN
);
/* fake event to set up pins */
codec
->
patch_ops
.
unsol_event
(
codec
,
STAC_HP_EVENT
<<
26
);
codec
->
patch_ops
.
unsol_event
(
codec
,
(
STAC_HP_EVENT
|
spec
->
autocfg
.
hp_pins
[
0
])
<<
26
);
}
else
{
stac92xx_auto_init_multi_out
(
codec
);
stac92xx_auto_init_hp_out
(
codec
);
}
for
(
i
=
0
;
i
<
cfg
->
line_outs
;
i
++
)
{
err
=
stac92xx_add_jack
(
codec
,
cfg
->
line_out_pins
[
i
],
SND_JACK_LINEOUT
);
if
(
err
<
0
)
return
err
;
}
for
(
i
=
0
;
i
<
AUTO_PIN_LAST
;
i
++
)
{
hda_nid_t
nid
=
cfg
->
input_pins
[
i
];
if
(
nid
)
{
...
...
@@ -3657,6 +3740,11 @@ static int stac92xx_init(struct hda_codec *codec)
if
(
i
==
AUTO_PIN_MIC
||
i
==
AUTO_PIN_FRONT_MIC
)
pinctl
|=
stac92xx_get_vref
(
codec
,
nid
);
stac92xx_auto_set_pinctl
(
codec
,
nid
,
pinctl
);
err
=
stac92xx_add_jack
(
codec
,
nid
,
SND_JACK_MICROPHONE
);
if
(
err
<
0
)
return
err
;
enable_pin_detect
(
codec
,
nid
,
STAC_INSERT_EVENT
|
nid
);
}
}
for
(
i
=
0
;
i
<
spec
->
num_dmics
;
i
++
)
...
...
@@ -3698,22 +3786,42 @@ static int stac92xx_init(struct hda_codec *codec)
return
0
;
}
static
void
stac92xx_free_jacks
(
struct
hda_codec
*
codec
)
{
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
if
(
spec
->
jacks
.
list
)
{
struct
sigmatel_jack
*
jacks
=
spec
->
jacks
.
list
;
int
i
;
for
(
i
=
0
;
i
<
spec
->
jacks
.
used
;
i
++
)
snd_device_free
(
codec
->
bus
->
card
,
&
jacks
[
i
].
jack
);
}
snd_array_free
(
&
spec
->
jacks
);
}
static
void
stac92xx_free_kctls
(
struct
hda_codec
*
codec
)
{
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
if
(
spec
->
kctls
.
list
)
{
struct
snd_kcontrol_new
*
kctl
=
spec
->
kctls
.
list
;
int
i
;
for
(
i
=
0
;
i
<
spec
->
kctls
.
used
;
i
++
)
kfree
(
kctl
[
i
].
name
);
}
snd_array_free
(
&
spec
->
kctls
);
}
static
void
stac92xx_free
(
struct
hda_codec
*
codec
)
{
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
int
i
;
if
(
!
spec
)
return
;
if
(
spec
->
kctl_alloc
)
{
for
(
i
=
0
;
i
<
spec
->
num_kctl_used
;
i
++
)
kfree
(
spec
->
kctl_alloc
[
i
].
name
);
kfree
(
spec
->
kctl_alloc
);
}
if
(
spec
->
bios_pin_configs
)
kfree
(
spec
->
bios_pin_configs
);
stac92xx_free_jacks
(
codec
);
snd_array_free
(
&
spec
->
events
);
kfree
(
spec
);
snd_hda_detach_beep_device
(
codec
);
...
...
@@ -3852,24 +3960,57 @@ static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
/* power down unused output ports */
snd_hda_codec_write
(
codec
,
codec
->
afg
,
0
,
0x7ec
,
val
);
};
}
static
void
stac92xx_report_jack
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
struct
sigmatel_jack
*
jacks
=
spec
->
jacks
.
list
;
if
(
jacks
)
{
int
i
;
for
(
i
=
0
;
i
<
spec
->
jacks
.
used
;
i
++
)
{
if
(
jacks
->
nid
==
nid
)
{
unsigned
int
pin_ctl
=
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_PIN_WIDGET_CONTROL
,
0x00
);
int
type
=
jacks
->
type
;
if
(
type
==
(
SND_JACK_LINEOUT
|
SND_JACK_HEADPHONE
))
type
=
(
pin_ctl
&
AC_PINCTL_HP_EN
)
?
SND_JACK_HEADPHONE
:
SND_JACK_LINEOUT
;
snd_jack_report
(
jacks
->
jack
,
get_hp_pin_presence
(
codec
,
nid
)
?
type
:
0
);
}
jacks
++
;
}
}
}
static
void
stac92xx_unsol_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
int
idx
=
res
>>
26
&
0x0f
;
int
event
=
(
res
>>
26
)
&
0x70
;
int
nid
=
res
>>
26
&
0x0f
;
switch
(
(
res
>>
26
)
&
0x70
)
{
switch
(
event
)
{
case
STAC_HP_EVENT
:
stac92xx_hp_detect
(
codec
,
res
);
/* fallthru */
case
STAC_INSERT_EVENT
:
case
STAC_PWR_EVENT
:
if
(
spec
->
num_pwrs
>
0
)
stac92xx_pin_sense
(
codec
,
idx
);
if
(
nid
)
{
if
(
spec
->
num_pwrs
>
0
)
stac92xx_pin_sense
(
codec
,
nid
);
stac92xx_report_jack
(
codec
,
nid
);
}
break
;
case
STAC_VREF_EVENT
:
{
int
data
=
snd_hda_codec_read
(
codec
,
codec
->
afg
,
0
,
AC_VERB_GET_GPIO_DATA
,
0
);
int
idx
=
stac92xx_event_data
(
codec
,
nid
);
/* toggle VREF state based on GPIOx status */
snd_hda_codec_write
(
codec
,
codec
->
afg
,
0
,
0x7e0
,
!!
(
data
&
(
1
<<
idx
)));
...
...
@@ -4392,8 +4533,11 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
snd_hda_codec_write
(
codec
,
codec
->
afg
,
0
,
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK
,
0x02
);
snd_hda_codec_write_cache
(
codec
,
codec
->
afg
,
0
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
(
AC_USRSP_EN
|
STAC_VREF_EVENT
|
0x01
));
AC_VERB_SET_UNSOLICITED_ENABLE
,
(
AC_USRSP_EN
|
STAC_VREF_EVENT
|
codec
->
afg
));
err
=
stac92xx_add_event
(
spec
,
codec
->
afg
,
0x02
);
if
(
err
<
0
)
return
err
;
spec
->
gpio_mask
|=
0x02
;
break
;
}
...
...
@@ -4792,8 +4936,11 @@ static int patch_stac9205(struct hda_codec *codec)
snd_hda_codec_write
(
codec
,
codec
->
afg
,
0
,
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK
,
0x10
);
snd_hda_codec_write_cache
(
codec
,
codec
->
afg
,
0
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
(
AC_USRSP_EN
|
STAC_HP_EVENT
));
AC_VERB_SET_UNSOLICITED_ENABLE
,
(
AC_USRSP_EN
|
STAC_VREF_EVENT
|
codec
->
afg
));
err
=
stac92xx_add_event
(
spec
,
codec
->
afg
,
0x01
);
if
(
err
<
0
)
return
err
;
spec
->
gpio_dir
=
0x0b
;
spec
->
eapd_mask
=
0x01
;
...
...
This diff is collapsed.
Click to expand it.
sound/pci/hda/patch_via.c
浏览文件 @
42dc2378
...
...
@@ -53,9 +53,6 @@
#define AMP_VAL_IDX_SHIFT 19
#define AMP_VAL_IDX_MASK (0x0f<<19)
#define NUM_CONTROL_ALLOC 32
#define NUM_VERB_ALLOC 32
/* Pin Widget NID */
#define VT1708_HP_NID 0x13
#define VT1708_DIGOUT_NID 0x14
...
...
@@ -227,8 +224,7 @@ struct via_spec {
/* dynamic controls, init_verbs and input_mux */
struct
auto_pin_cfg
autocfg
;
unsigned
int
num_kctl_alloc
,
num_kctl_used
;
struct
snd_kcontrol_new
*
kctl_alloc
;
struct
snd_array
kctls
;
struct
hda_input_mux
private_imux
[
2
];
hda_nid_t
private_dac_nids
[
AUTO_CFG_MAX_OUTS
];
...
...
@@ -272,33 +268,31 @@ static int via_add_control(struct via_spec *spec, int type, const char *name,
{
struct
snd_kcontrol_new
*
knew
;
if
(
spec
->
num_kctl_used
>=
spec
->
num_kctl_alloc
)
{
int
num
=
spec
->
num_kctl_alloc
+
NUM_CONTROL_ALLOC
;
/* array + terminator */
knew
=
kcalloc
(
num
+
1
,
sizeof
(
*
knew
),
GFP_KERNEL
);
if
(
!
knew
)
return
-
ENOMEM
;
if
(
spec
->
kctl_alloc
)
{
memcpy
(
knew
,
spec
->
kctl_alloc
,
sizeof
(
*
knew
)
*
spec
->
num_kctl_alloc
);
kfree
(
spec
->
kctl_alloc
);
}
spec
->
kctl_alloc
=
knew
;
spec
->
num_kctl_alloc
=
num
;
}
knew
=
&
spec
->
kctl_alloc
[
spec
->
num_kctl_used
];
snd_array_init
(
&
spec
->
kctls
,
sizeof
(
*
knew
),
32
);
knew
=
snd_array_new
(
&
spec
->
kctls
);
if
(
!
knew
)
return
-
ENOMEM
;
*
knew
=
vt1708_control_templates
[
type
];
knew
->
name
=
kstrdup
(
name
,
GFP_KERNEL
);
if
(
!
knew
->
name
)
return
-
ENOMEM
;
knew
->
private_value
=
val
;
spec
->
num_kctl_used
++
;
return
0
;
}
static
void
via_free_kctls
(
struct
hda_codec
*
codec
)
{
struct
via_spec
*
spec
=
codec
->
spec
;
if
(
spec
->
kctls
.
list
)
{
struct
snd_kcontrol_new
*
kctl
=
spec
->
kctls
.
list
;
int
i
;
for
(
i
=
0
;
i
<
spec
->
kctls
.
used
;
i
++
)
kfree
(
kctl
[
i
].
name
);
}
snd_array_free
(
&
spec
->
kctls
);
}
/* create input playback/capture controls for the given pin */
static
int
via_new_analog_input
(
struct
via_spec
*
spec
,
hda_nid_t
pin
,
const
char
*
ctlname
,
int
idx
,
int
mix_nid
)
...
...
@@ -896,6 +890,7 @@ static int via_build_controls(struct hda_codec *codec)
if
(
err
<
0
)
return
err
;
}
via_free_kctls
(
codec
);
/* no longer needed */
return
0
;
}
...
...
@@ -941,17 +936,11 @@ static int via_build_pcms(struct hda_codec *codec)
static
void
via_free
(
struct
hda_codec
*
codec
)
{
struct
via_spec
*
spec
=
codec
->
spec
;
unsigned
int
i
;
if
(
!
spec
)
return
;
if
(
spec
->
kctl_alloc
)
{
for
(
i
=
0
;
i
<
spec
->
num_kctl_used
;
i
++
)
kfree
(
spec
->
kctl_alloc
[
i
].
name
);
kfree
(
spec
->
kctl_alloc
);
}
via_free_kctls
(
codec
);
kfree
(
codec
->
spec
);
}
...
...
@@ -1373,8 +1362,8 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
if
(
spec
->
autocfg
.
dig_in_pin
)
spec
->
dig_in_nid
=
VT1708_DIGIN_NID
;
if
(
spec
->
kctl
_alloc
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
_alloc
;
if
(
spec
->
kctl
s
.
list
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
s
.
list
;
spec
->
init_verbs
[
spec
->
num_iverbs
++
]
=
vt1708_volume_init_verbs
;
...
...
@@ -1846,8 +1835,8 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
if
(
spec
->
autocfg
.
dig_in_pin
)
spec
->
dig_in_nid
=
VT1709_DIGIN_NID
;
if
(
spec
->
kctl
_alloc
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
_alloc
;
if
(
spec
->
kctl
s
.
list
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
s
.
list
;
spec
->
input_mux
=
&
spec
->
private_imux
[
0
];
...
...
@@ -2390,8 +2379,8 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
if
(
spec
->
autocfg
.
dig_in_pin
)
spec
->
dig_in_nid
=
VT1708B_DIGIN_NID
;
if
(
spec
->
kctl
_alloc
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
_alloc
;
if
(
spec
->
kctl
s
.
list
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
s
.
list
;
spec
->
input_mux
=
&
spec
->
private_imux
[
0
];
...
...
@@ -2855,8 +2844,8 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
spec
->
extra_dig_out_nid
=
0x15
;
if
(
spec
->
kctl
_alloc
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
_alloc
;
if
(
spec
->
kctl
s
.
list
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
s
.
list
;
spec
->
input_mux
=
&
spec
->
private_imux
[
0
];
...
...
@@ -3174,8 +3163,8 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
spec
->
extra_dig_out_nid
=
0x1B
;
if
(
spec
->
kctl
_alloc
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
_alloc
;
if
(
spec
->
kctl
s
.
list
)
spec
->
mixers
[
spec
->
num_mixers
++
]
=
spec
->
kctl
s
.
list
;
spec
->
input_mux
=
&
spec
->
private_imux
[
0
];
...
...
This diff is collapsed.
Click to expand it.
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录
反馈
建议
客服
返回
顶部