Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
42dc2378
Commit
42dc2378
authored
Oct 27, 2008
by
Takashi Iwai
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/hda-next' into topic/hda
parents
da74ae3e
74aeaabc
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
970 additions
and
412 deletions
+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
No files found.
include/linux/input.h
View file @
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)
...
...
include/sound/jack.h
View file @
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
{
...
...
sound/core/jack.c
View file @
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
);
...
...
sound/pci/Kconfig
View file @
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.
...
...
sound/pci/hda/hda_codec.c
View file @
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
);
if
(
!
err
&&
codec
->
patch_ops
.
unsol_event
)
err
=
init_unsol_queue
(
codec
->
bus
);
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
;
}
/**
...
...
@@ -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,6 +2050,15 @@ 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
=
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
);
...
...
@@ -1925,6 +2066,7 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus)
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
);
...
...
@@ -1933,8 +2075,6 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus)
snd_hda_power_down
(
codec
);
if
(
err
<
0
)
return
err
;
}
return
0
;
}
...
...
@@ -2235,7 +2375,7 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo,
return
0
;
}
static
int
__devinit
set_pcm_default_values
(
struct
hda_codec
*
codec
,
static
int
set_pcm_default_values
(
struct
hda_codec
*
codec
,
struct
hda_pcm_stream
*
info
)
{
/* query support PCM information from the given NID */
...
...
@@ -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
->
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
;
}
sound/pci/hda/hda_codec.h
View file @
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
*/
...
...
sound/pci/hda/hda_generic.c
View file @
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
;
}
...
...
sound/pci/hda/hda_hwdep.c
View file @
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
;
}
sound/pci/hda/hda_intel.c
View file @
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
;
...
...
sound/pci/hda/hda_local.h
View file @
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
...
...
sound/pci/hda/hda_proc.c
View file @
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
);
...
...
sound/pci/hda/patch_analog.c
View file @
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
)
snd_array_init
(
&
spec
->
kctls
,
sizeof
(
*
knew
),
32
);
knew
=
snd_array_new
(
&
spec
->
kctls
);
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
];
*
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
;
...
...
sound/pci/hda/patch_conexant.c
View file @
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
);
}
...
...
sound/pci/hda/patch_realtek.c
View file @
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
);
snd_array_init
(
&
spec
->
kctls
,
sizeof
(
*
knew
),
32
);
knew
=
snd_array_new
(
&
spec
->
kctls
);
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
];
*
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
;
...
...
sound/pci/hda/patch_sigmatel.c
View file @
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
)
snd_array_init
(
&
spec
->
kctls
,
sizeof
(
*
knew
),
32
);
knew
=
snd_array_new
(
&
spec
->
kctls
);
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
];
*
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
);
/* 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
(
struct
hda_codec
*
codec
)
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
);
}
if
(
!
spec
)
return
;
static
void
stac92xx_free_kctls
(
struct
hda_codec
*
codec
)
{
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
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
stac92xx_free
(
struct
hda_codec
*
codec
)
{
struct
sigmatel_spec
*
spec
=
codec
->
spec
;
if
(
!
spec
)
return
;
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
(
nid
)
{
if
(
spec
->
num_pwrs
>
0
)
stac92xx_pin_sense
(
codec
,
idx
);
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
)));
...
...
@@ -4393,7 +4534,10 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
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_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
;
}
...
...
@@ -4793,7 +4937,10 @@ static int patch_stac9205(struct hda_codec *codec)
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_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
;
...
...
sound/pci/hda/patch_via.c
View file @
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
);
snd_array_init
(
&
spec
->
kctls
,
sizeof
(
*
knew
),
32
);
knew
=
snd_array_new
(
&
spec
->
kctls
);
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
];
*
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
];
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment