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
Kirill Smelkov
linux
Commits
f1cf9a66
Commit
f1cf9a66
authored
Mar 08, 2010
by
Takashi Iwai
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/hda' into for-linus
parents
6679ee18
2abbf439
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1141 additions
and
904 deletions
+1141
-904
sound/pci/hda/Kconfig
sound/pci/hda/Kconfig
+1
-1
sound/pci/hda/Makefile
sound/pci/hda/Makefile
+2
-2
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.c
+38
-31
sound/pci/hda/hda_eld.c
sound/pci/hda/hda_eld.c
+6
-0
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_intel.c
+7
-2
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_hdmi.c
+849
-0
sound/pci/hda/patch_intelhdmi.c
sound/pci/hda/patch_intelhdmi.c
+13
-808
sound/pci/hda/patch_nvhdmi.c
sound/pci/hda/patch_nvhdmi.c
+216
-59
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_realtek.c
+9
-1
No files found.
sound/pci/hda/Kconfig
View file @
f1cf9a66
...
...
@@ -157,7 +157,7 @@ config SND_HDA_CODEC_INTELHDMI
config SND_HDA_ELD
def_bool y
depends on SND_HDA_CODEC_INTELHDMI
depends on SND_HDA_CODEC_INTELHDMI
|| SND_HDA_CODEC_NVHDMI
config SND_HDA_CODEC_CIRRUS
bool "Build Cirrus Logic codec support"
...
...
sound/pci/hda/Makefile
View file @
f1cf9a66
...
...
@@ -3,7 +3,7 @@ snd-hda-intel-objs := hda_intel.o
snd-hda-codec-y
:=
hda_codec.o
snd-hda-codec-$(CONFIG_SND_HDA_GENERIC)
+=
hda_generic.o
snd-hda-codec-$(CONFIG_PROC_FS)
+=
hda_proc.o
#
snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o
snd-hda-codec-$(CONFIG_SND_HDA_ELD)
+=
hda_eld.o
snd-hda-codec-$(CONFIG_SND_HDA_HWDEP)
+=
hda_hwdep.o
snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP)
+=
hda_beep.o
...
...
@@ -18,7 +18,7 @@ snd-hda-codec-ca0110-objs := patch_ca0110.o
snd-hda-codec-conexant-objs
:=
patch_conexant.o
snd-hda-codec-via-objs
:=
patch_via.o
snd-hda-codec-nvhdmi-objs
:=
patch_nvhdmi.o
snd-hda-codec-intelhdmi-objs
:=
patch_intelhdmi.o
hda_eld.o
snd-hda-codec-intelhdmi-objs
:=
patch_intelhdmi.o
# common driver
obj-$(CONFIG_SND_HDA_INTEL)
:=
snd-hda-codec.o
...
...
sound/pci/hda/hda_codec.c
View file @
f1cf9a66
...
...
@@ -978,8 +978,9 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
*
* Returns 0 if successful, or a negative error code.
*/
int
/*__devinit*/
snd_hda_codec_new
(
struct
hda_bus
*
bus
,
unsigned
int
codec_addr
,
struct
hda_codec
**
codecp
)
int
/*__devinit*/
snd_hda_codec_new
(
struct
hda_bus
*
bus
,
unsigned
int
codec_addr
,
struct
hda_codec
**
codecp
)
{
struct
hda_codec
*
codec
;
char
component
[
31
];
...
...
@@ -1186,7 +1187,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream);
*/
/* FIXME: more better hash key? */
#define HDA_HASH_KEY(nid,
dir,
idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
#define HDA_HASH_KEY(nid,
dir,
idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
#define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24))
#define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24))
#define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24))
...
...
@@ -1356,7 +1357,8 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
if
(
!
codec
->
no_trigger_sense
)
{
pincap
=
snd_hda_query_pin_caps
(
codec
,
nid
);
if
(
pincap
&
AC_PINCAP_TRIG_REQ
)
/* need trigger? */
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_SENSE
,
0
);
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_SET_PIN_SENSE
,
0
);
}
return
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_PIN_SENSE
,
0
);
...
...
@@ -1372,8 +1374,8 @@ EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
*/
int
snd_hda_jack_detect
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
u32
sense
=
snd_hda_pin_sense
(
codec
,
nid
);
return
!!
(
sense
&
AC_PINSENSE_PRESENCE
);
u32
sense
=
snd_hda_pin_sense
(
codec
,
nid
);
return
!!
(
sense
&
AC_PINSENSE_PRESENCE
);
}
EXPORT_SYMBOL_HDA
(
snd_hda_jack_detect
);
...
...
@@ -1952,7 +1954,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
err
=
snd_hda_ctl_add
(
codec
,
0
,
kctl
);
if
(
err
<
0
)
return
err
;
for
(
s
=
slaves
;
*
s
;
s
++
)
{
struct
snd_kcontrol
*
sctl
;
int
i
=
0
;
...
...
@@ -2439,27 +2441,27 @@ static struct snd_kcontrol_new dig_mixes[] = {
{
.
access
=
SNDRV_CTL_ELEM_ACCESS_READ
,
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
CON_MASK
),
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
CON_MASK
),
.
info
=
snd_hda_spdif_mask_info
,
.
get
=
snd_hda_spdif_cmask_get
,
},
{
.
access
=
SNDRV_CTL_ELEM_ACCESS_READ
,
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
PRO_MASK
),
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
PRO_MASK
),
.
info
=
snd_hda_spdif_mask_info
,
.
get
=
snd_hda_spdif_pmask_get
,
},
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
DEFAULT
),
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
DEFAULT
),
.
info
=
snd_hda_spdif_mask_info
,
.
get
=
snd_hda_spdif_default_get
,
.
put
=
snd_hda_spdif_default_put
,
},
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
SWITCH
),
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
SWITCH
),
.
info
=
snd_hda_spdif_out_switch_info
,
.
get
=
snd_hda_spdif_out_switch_get
,
.
put
=
snd_hda_spdif_out_switch_put
,
...
...
@@ -2610,7 +2612,7 @@ static int snd_hda_spdif_in_status_get(struct snd_kcontrol *kcontrol,
static
struct
snd_kcontrol_new
dig_in_ctls
[]
=
{
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
CAPTURE
,
SWITCH
),
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
CAPTURE
,
SWITCH
),
.
info
=
snd_hda_spdif_in_switch_info
,
.
get
=
snd_hda_spdif_in_switch_get
,
.
put
=
snd_hda_spdif_in_switch_put
,
...
...
@@ -2618,7 +2620,7 @@ static struct snd_kcontrol_new dig_in_ctls[] = {
{
.
access
=
SNDRV_CTL_ELEM_ACCESS_READ
,
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
CAPTURE
,
DEFAULT
),
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
CAPTURE
,
DEFAULT
),
.
info
=
snd_hda_spdif_mask_info
,
.
get
=
snd_hda_spdif_in_status_get
,
},
...
...
@@ -2883,7 +2885,7 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus)
int
err
=
snd_hda_codec_build_controls
(
codec
);
if
(
err
<
0
)
{
printk
(
KERN_ERR
"hda_codec: cannot build controls"
"for #%d (error %d)
\n
"
,
codec
->
addr
,
err
);
"for #%d (error %d)
\n
"
,
codec
->
addr
,
err
);
err
=
snd_hda_codec_reset
(
codec
);
if
(
err
<
0
)
{
printk
(
KERN_ERR
...
...
@@ -2979,8 +2981,12 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
val
|=
channels
-
1
;
switch
(
snd_pcm_format_width
(
format
))
{
case
8
:
val
|=
0x00
;
break
;
case
16
:
val
|=
0x10
;
break
;
case
8
:
val
|=
0x00
;
break
;
case
16
:
val
|=
0x10
;
break
;
case
20
:
case
24
:
case
32
:
...
...
@@ -3298,7 +3304,8 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type)
if
(
!
test_and_set_bit
(
audio_idx
[
type
][
i
],
bus
->
pcm_dev_bits
))
return
audio_idx
[
type
][
i
];
snd_printk
(
KERN_WARNING
"Too many %s devices
\n
"
,
snd_hda_pcm_type_name
[
type
]);
snd_printk
(
KERN_WARNING
"Too many %s devices
\n
"
,
snd_hda_pcm_type_name
[
type
]);
return
-
EAGAIN
;
}
...
...
@@ -3336,7 +3343,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec)
err
=
codec
->
patch_ops
.
build_pcms
(
codec
);
if
(
err
<
0
)
{
printk
(
KERN_ERR
"hda_codec: cannot build PCMs"
"for #%d (error %d)
\n
"
,
codec
->
addr
,
err
);
"for #%d (error %d)
\n
"
,
codec
->
addr
,
err
);
err
=
snd_hda_codec_reset
(
codec
);
if
(
err
<
0
)
{
printk
(
KERN_ERR
...
...
@@ -3466,8 +3473,8 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_config);
/**
* snd_hda_check_board_codec_sid_config - compare the current codec
subsystem ID with the
config table
subsystem ID with the
config table
This is important for Gateway notebooks with SB450 HDA Audio
where the vendor ID of the PCI device is:
...
...
@@ -3607,7 +3614,7 @@ void snd_hda_update_power_acct(struct hda_codec *codec)
*
* Increment the power-up counter and power up the hardware really when
* not turned on yet.
*/
*/
void
snd_hda_power_up
(
struct
hda_codec
*
codec
)
{
struct
hda_bus
*
bus
=
codec
->
bus
;
...
...
@@ -3636,7 +3643,7 @@ EXPORT_SYMBOL_HDA(snd_hda_power_up);
*
* Decrement the power-up counter and schedules the power-off work if
* the counter rearches to zero.
*/
*/
void
snd_hda_power_down
(
struct
hda_codec
*
codec
)
{
--
codec
->
power_count
;
...
...
@@ -3662,7 +3669,7 @@ EXPORT_SYMBOL_HDA(snd_hda_power_down);
*
* This function is supposed to be set or called from the check_power_status
* patch ops.
*/
*/
int
snd_hda_check_amp_list_power
(
struct
hda_codec
*
codec
,
struct
hda_loopback_check
*
check
,
hda_nid_t
nid
)
...
...
@@ -3830,7 +3837,7 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
{
/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
if
(
codec
->
spdif_status_reset
&&
(
codec
->
spdif_ctls
&
AC_DIG1_ENABLE
))
set_dig_out_convert
(
codec
,
nid
,
set_dig_out_convert
(
codec
,
nid
,
codec
->
spdif_ctls
&
~
AC_DIG1_ENABLE
&
0xff
,
-
1
);
snd_hda_codec_setup_stream
(
codec
,
nid
,
stream_tag
,
0
,
format
);
...
...
@@ -4089,13 +4096,13 @@ static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list)
/*
* Sort an associated group of pins according to their sequence numbers.
*/
static
void
sort_pins_by_sequence
(
hda_nid_t
*
pins
,
short
*
sequences
,
static
void
sort_pins_by_sequence
(
hda_nid_t
*
pins
,
short
*
sequences
,
int
num_pins
)
{
int
i
,
j
;
short
seq
;
hda_nid_t
nid
;
for
(
i
=
0
;
i
<
num_pins
;
i
++
)
{
for
(
j
=
i
+
1
;
j
<
num_pins
;
j
++
)
{
if
(
sequences
[
i
]
>
sequences
[
j
])
{
...
...
@@ -4123,7 +4130,7 @@ static void sort_pins_by_sequence(hda_nid_t * pins, short * sequences,
* is detected, one of speaker of HP pins is assigned as the primary
* output, i.e. to line_out_pins[0]. So, line_outs is always positive
* if any analog output exists.
*
*
* The analog input pins are assigned to input_pins array.
* The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
* respectively.
...
...
@@ -4186,9 +4193,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
case
AC_JACK_SPEAKER
:
seq
=
get_defcfg_sequence
(
def_conf
);
assoc
=
get_defcfg_association
(
def_conf
);
if
(
!
assoc
)
if
(
!
assoc
)
continue
;
if
(
!
assoc_speaker
)
if
(
!
assoc_speaker
)
assoc_speaker
=
assoc
;
else
if
(
assoc_speaker
!=
assoc
)
continue
;
...
...
@@ -4286,7 +4293,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
cfg
->
speaker_outs
);
sort_pins_by_sequence
(
cfg
->
hp_pins
,
sequences_hp
,
cfg
->
hp_outs
);
/* if we have only one mic, make it AUTO_PIN_MIC */
if
(
!
cfg
->
input_pins
[
AUTO_PIN_MIC
]
&&
cfg
->
input_pins
[
AUTO_PIN_FRONT_MIC
])
{
...
...
@@ -4436,7 +4443,7 @@ EXPORT_SYMBOL_HDA(snd_hda_resume);
/**
* snd_array_new - get a new element from the given array
* @array: the array object
*
*
* Get a new element from the given array. If it exceeds the
* pre-allocated array size, re-allocate the array.
*
...
...
sound/pci/hda/hda_eld.c
View file @
f1cf9a66
...
...
@@ -331,6 +331,7 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
return
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_HDMI_DIP_SIZE
,
AC_DIPSIZE_ELD_BUF
);
}
EXPORT_SYMBOL_HDA
(
snd_hdmi_get_eld_size
);
int
snd_hdmi_get_eld
(
struct
hdmi_eld
*
eld
,
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
...
...
@@ -366,6 +367,7 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
kfree
(
buf
);
return
ret
;
}
EXPORT_SYMBOL_HDA
(
snd_hdmi_get_eld
);
static
void
hdmi_show_short_audio_desc
(
struct
cea_sad
*
a
)
{
...
...
@@ -404,6 +406,7 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
}
buf
[
j
]
=
'\0'
;
/* necessary when j == 0 */
}
EXPORT_SYMBOL_HDA
(
snd_print_channel_allocation
);
void
snd_hdmi_show_eld
(
struct
hdmi_eld
*
e
)
{
...
...
@@ -422,6 +425,7 @@ void snd_hdmi_show_eld(struct hdmi_eld *e)
for
(
i
=
0
;
i
<
e
->
sad_count
;
i
++
)
hdmi_show_short_audio_desc
(
e
->
sad
+
i
);
}
EXPORT_SYMBOL_HDA
(
snd_hdmi_show_eld
);
#ifdef CONFIG_PROC_FS
...
...
@@ -580,6 +584,7 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
return
0
;
}
EXPORT_SYMBOL_HDA
(
snd_hda_eld_proc_new
);
void
snd_hda_eld_proc_free
(
struct
hda_codec
*
codec
,
struct
hdmi_eld
*
eld
)
{
...
...
@@ -588,5 +593,6 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
eld
->
proc_entry
=
NULL
;
}
}
EXPORT_SYMBOL_HDA
(
snd_hda_eld_proc_free
);
#endif
/* CONFIG_PROC_FS */
sound/pci/hda/hda_intel.c
View file @
f1cf9a66
...
...
@@ -267,7 +267,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define RIRB_INT_MASK 0x05
/* STATESTS int mask: S3,SD2,SD1,SD0 */
#define AZX_MAX_CODECS 4
#define AZX_MAX_CODECS 8
#define AZX_DEFAULT_CODECS 4
#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1)
/* SD_CTL bits */
...
...
@@ -1367,6 +1368,7 @@ static void azx_bus_reset(struct hda_bus *bus)
/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
static
unsigned
int
azx_max_codecs
[
AZX_NUM_DRIVERS
]
__devinitdata
=
{
[
AZX_DRIVER_NVIDIA
]
=
8
,
[
AZX_DRIVER_TERA
]
=
1
,
};
...
...
@@ -1399,7 +1401,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
codecs
=
0
;
max_slots
=
azx_max_codecs
[
chip
->
driver_type
];
if
(
!
max_slots
)
max_slots
=
AZX_
MAX
_CODECS
;
max_slots
=
AZX_
DEFAULT
_CODECS
;
/* First try to probe all given codec slots */
for
(
c
=
0
;
c
<
max_slots
;
c
++
)
{
...
...
@@ -2263,10 +2265,12 @@ static int azx_dev_free(struct snd_device *device)
static
struct
snd_pci_quirk
position_fix_list
[]
__devinitdata
=
{
SND_PCI_QUIRK
(
0x1028
,
0x01cc
,
"Dell D820"
,
POS_FIX_LPIB
),
SND_PCI_QUIRK
(
0x1028
,
0x01de
,
"Dell Precision 390"
,
POS_FIX_LPIB
),
SND_PCI_QUIRK
(
0x1028
,
0x01f6
,
"Dell Latitude 131L"
,
POS_FIX_LPIB
),
SND_PCI_QUIRK
(
0x103c
,
0x306d
,
"HP dv3"
,
POS_FIX_LPIB
),
SND_PCI_QUIRK
(
0x1106
,
0x3288
,
"ASUS M2V-MX SE"
,
POS_FIX_LPIB
),
SND_PCI_QUIRK
(
0x1043
,
0x813d
,
"ASUS P5AD2"
,
POS_FIX_LPIB
),
SND_PCI_QUIRK
(
0x1462
,
0x1002
,
"MSI Wind U115"
,
POS_FIX_LPIB
),
SND_PCI_QUIRK
(
0x1565
,
0x820f
,
"Biostar Microtech"
,
POS_FIX_LPIB
),
{}
};
...
...
@@ -2354,6 +2358,7 @@ static void __devinit check_probe_mask(struct azx *chip, int dev)
static
struct
snd_pci_quirk
msi_black_list
[]
__devinitdata
=
{
SND_PCI_QUIRK
(
0x1043
,
0x81f2
,
"ASUS"
,
0
),
/* Athlon64 X2 + nvidia */
SND_PCI_QUIRK
(
0x1043
,
0x81f6
,
"ASUS"
,
0
),
/* nvidia */
SND_PCI_QUIRK
(
0x1849
,
0x0888
,
"ASRock"
,
0
),
/* Athlon64 X2 + nvidia */
{}
};
...
...
sound/pci/hda/patch_hdmi.c
0 → 100644
View file @
f1cf9a66
/*
*
* patch_hdmi.c - routines for HDMI/DisplayPort codecs
*
* Copyright(c) 2008-2010 Intel Corporation. All rights reserved.
*
* Authors:
* Wu Fengguang <wfg@linux.intel.com>
*
* Maintained by:
* Wu Fengguang <wfg@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
struct
hdmi_spec
{
int
num_cvts
;
int
num_pins
;
hda_nid_t
cvt
[
MAX_HDMI_CVTS
+
1
];
/* audio sources */
hda_nid_t
pin
[
MAX_HDMI_PINS
+
1
];
/* audio sinks */
/*
* source connection for each pin
*/
hda_nid_t
pin_cvt
[
MAX_HDMI_PINS
+
1
];
/*
* HDMI sink attached to each pin
*/
struct
hdmi_eld
sink_eld
[
MAX_HDMI_PINS
];
/*
* export one pcm per pipe
*/
struct
hda_pcm
pcm_rec
[
MAX_HDMI_CVTS
];
/*
* nvhdmi specific
*/
struct
hda_multi_out
multiout
;
unsigned
int
codec_type
;
};
struct
hdmi_audio_infoframe
{
u8
type
;
/* 0x84 */
u8
ver
;
/* 0x01 */
u8
len
;
/* 0x0a */
u8
checksum
;
/* PB0 */
u8
CC02_CT47
;
/* CC in bits 0:2, CT in 4:7 */
u8
SS01_SF24
;
u8
CXT04
;
u8
CA
;
u8
LFEPBL01_LSV36_DM_INH7
;
u8
reserved
[
5
];
/* PB6 - PB10 */
};
/*
* CEA speaker placement:
*
* FLH FCH FRH
* FLW FL FLC FC FRC FR FRW
*
* LFE
* TC
*
* RL RLC RC RRC RR
*
* The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to
* CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC.
*/
enum
cea_speaker_placement
{
FL
=
(
1
<<
0
),
/* Front Left */
FC
=
(
1
<<
1
),
/* Front Center */
FR
=
(
1
<<
2
),
/* Front Right */
FLC
=
(
1
<<
3
),
/* Front Left Center */
FRC
=
(
1
<<
4
),
/* Front Right Center */
RL
=
(
1
<<
5
),
/* Rear Left */
RC
=
(
1
<<
6
),
/* Rear Center */
RR
=
(
1
<<
7
),
/* Rear Right */
RLC
=
(
1
<<
8
),
/* Rear Left Center */
RRC
=
(
1
<<
9
),
/* Rear Right Center */
LFE
=
(
1
<<
10
),
/* Low Frequency Effect */
FLW
=
(
1
<<
11
),
/* Front Left Wide */
FRW
=
(
1
<<
12
),
/* Front Right Wide */
FLH
=
(
1
<<
13
),
/* Front Left High */
FCH
=
(
1
<<
14
),
/* Front Center High */
FRH
=
(
1
<<
15
),
/* Front Right High */
TC
=
(
1
<<
16
),
/* Top Center */
};
/*
* ELD SA bits in the CEA Speaker Allocation data block
*/
static
int
eld_speaker_allocation_bits
[]
=
{
[
0
]
=
FL
|
FR
,
[
1
]
=
LFE
,
[
2
]
=
FC
,
[
3
]
=
RL
|
RR
,
[
4
]
=
RC
,
[
5
]
=
FLC
|
FRC
,
[
6
]
=
RLC
|
RRC
,
/* the following are not defined in ELD yet */
[
7
]
=
FLW
|
FRW
,
[
8
]
=
FLH
|
FRH
,
[
9
]
=
TC
,
[
10
]
=
FCH
,
};
struct
cea_channel_speaker_allocation
{
int
ca_index
;
int
speakers
[
8
];
/* derived values, just for convenience */
int
channels
;
int
spk_mask
;
};
/*
* ALSA sequence is:
*
* surround40 surround41 surround50 surround51 surround71
* ch0 front left = = = =
* ch1 front right = = = =
* ch2 rear left = = = =
* ch3 rear right = = = =
* ch4 LFE center center center
* ch5 LFE LFE
* ch6 side left
* ch7 side right
*
* surround71 = {FL, FR, RLC, RRC, FC, LFE, RL, RR}
*/
static
int
hdmi_channel_mapping
[
0x32
][
8
]
=
{
/* stereo */
[
0x00
]
=
{
0x00
,
0x11
,
0xf2
,
0xf3
,
0xf4
,
0xf5
,
0xf6
,
0xf7
},
/* 2.1 */
[
0x01
]
=
{
0x00
,
0x11
,
0x22
,
0xf3
,
0xf4
,
0xf5
,
0xf6
,
0xf7
},
/* Dolby Surround */
[
0x02
]
=
{
0x00
,
0x11
,
0x23
,
0xf2
,
0xf4
,
0xf5
,
0xf6
,
0xf7
},
/* surround40 */
[
0x08
]
=
{
0x00
,
0x11
,
0x24
,
0x35
,
0xf3
,
0xf2
,
0xf6
,
0xf7
},
/* 4ch */
[
0x03
]
=
{
0x00
,
0x11
,
0x23
,
0x32
,
0x44
,
0xf5
,
0xf6
,
0xf7
},
/* surround41 */
[
0x09
]
=
{
0x00
,
0x11
,
0x24
,
0x34
,
0x43
,
0xf2
,
0xf6
,
0xf7
},
/* surround50 */
[
0x0a
]
=
{
0x00
,
0x11
,
0x24
,
0x35
,
0x43
,
0xf2
,
0xf6
,
0xf7
},
/* surround51 */
[
0x0b
]
=
{
0x00
,
0x11
,
0x24
,
0x35
,
0x43
,
0x52
,
0xf6
,
0xf7
},
/* 7.1 */
[
0x13
]
=
{
0x00
,
0x11
,
0x26
,
0x37
,
0x43
,
0x52
,
0x64
,
0x75
},
};
/*
* This is an ordered list!
*
* The preceding ones have better chances to be selected by
* hdmi_setup_channel_allocation().
*/
static
struct
cea_channel_speaker_allocation
channel_allocations
[]
=
{
/* channel: 7 6 5 4 3 2 1 0 */
{
.
ca_index
=
0x00
,
.
speakers
=
{
0
,
0
,
0
,
0
,
0
,
0
,
FR
,
FL
}
},
/* 2.1 */
{
.
ca_index
=
0x01
,
.
speakers
=
{
0
,
0
,
0
,
0
,
0
,
LFE
,
FR
,
FL
}
},
/* Dolby Surround */
{
.
ca_index
=
0x02
,
.
speakers
=
{
0
,
0
,
0
,
0
,
FC
,
0
,
FR
,
FL
}
},
/* surround40 */
{
.
ca_index
=
0x08
,
.
speakers
=
{
0
,
0
,
RR
,
RL
,
0
,
0
,
FR
,
FL
}
},
/* surround41 */
{
.
ca_index
=
0x09
,
.
speakers
=
{
0
,
0
,
RR
,
RL
,
0
,
LFE
,
FR
,
FL
}
},
/* surround50 */
{
.
ca_index
=
0x0a
,
.
speakers
=
{
0
,
0
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
/* surround51 */
{
.
ca_index
=
0x0b
,
.
speakers
=
{
0
,
0
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
/* 6.1 */
{
.
ca_index
=
0x0f
,
.
speakers
=
{
0
,
RC
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
/* surround71 */
{
.
ca_index
=
0x13
,
.
speakers
=
{
RRC
,
RLC
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x03
,
.
speakers
=
{
0
,
0
,
0
,
0
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x04
,
.
speakers
=
{
0
,
0
,
0
,
RC
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x05
,
.
speakers
=
{
0
,
0
,
0
,
RC
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x06
,
.
speakers
=
{
0
,
0
,
0
,
RC
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x07
,
.
speakers
=
{
0
,
0
,
0
,
RC
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x0c
,
.
speakers
=
{
0
,
RC
,
RR
,
RL
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x0d
,
.
speakers
=
{
0
,
RC
,
RR
,
RL
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x0e
,
.
speakers
=
{
0
,
RC
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x10
,
.
speakers
=
{
RRC
,
RLC
,
RR
,
RL
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x11
,
.
speakers
=
{
RRC
,
RLC
,
RR
,
RL
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x12
,
.
speakers
=
{
RRC
,
RLC
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x14
,
.
speakers
=
{
FRC
,
FLC
,
0
,
0
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x15
,
.
speakers
=
{
FRC
,
FLC
,
0
,
0
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x16
,
.
speakers
=
{
FRC
,
FLC
,
0
,
0
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x17
,
.
speakers
=
{
FRC
,
FLC
,
0
,
0
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x18
,
.
speakers
=
{
FRC
,
FLC
,
0
,
RC
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x19
,
.
speakers
=
{
FRC
,
FLC
,
0
,
RC
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x1a
,
.
speakers
=
{
FRC
,
FLC
,
0
,
RC
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x1b
,
.
speakers
=
{
FRC
,
FLC
,
0
,
RC
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x1c
,
.
speakers
=
{
FRC
,
FLC
,
RR
,
RL
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x1d
,
.
speakers
=
{
FRC
,
FLC
,
RR
,
RL
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x1e
,
.
speakers
=
{
FRC
,
FLC
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x1f
,
.
speakers
=
{
FRC
,
FLC
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x20
,
.
speakers
=
{
0
,
FCH
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x21
,
.
speakers
=
{
0
,
FCH
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x22
,
.
speakers
=
{
TC
,
0
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x23
,
.
speakers
=
{
TC
,
0
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x24
,
.
speakers
=
{
FRH
,
FLH
,
RR
,
RL
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x25
,
.
speakers
=
{
FRH
,
FLH
,
RR
,
RL
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x26
,
.
speakers
=
{
FRW
,
FLW
,
RR
,
RL
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x27
,
.
speakers
=
{
FRW
,
FLW
,
RR
,
RL
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x28
,
.
speakers
=
{
TC
,
RC
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x29
,
.
speakers
=
{
TC
,
RC
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x2a
,
.
speakers
=
{
FCH
,
RC
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x2b
,
.
speakers
=
{
FCH
,
RC
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x2c
,
.
speakers
=
{
TC
,
FCH
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x2d
,
.
speakers
=
{
TC
,
FCH
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x2e
,
.
speakers
=
{
FRH
,
FLH
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x2f
,
.
speakers
=
{
FRH
,
FLH
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x30
,
.
speakers
=
{
FRW
,
FLW
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x31
,
.
speakers
=
{
FRW
,
FLW
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
};
/*
* HDMI routines
*/
static
int
hda_node_index
(
hda_nid_t
*
nids
,
hda_nid_t
nid
)
{
int
i
;
for
(
i
=
0
;
nids
[
i
];
i
++
)
if
(
nids
[
i
]
==
nid
)
return
i
;
snd_printk
(
KERN_WARNING
"HDMI: nid %d not registered
\n
"
,
nid
);
return
-
EINVAL
;
}
static
void
hdmi_get_show_eld
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
struct
hdmi_eld
*
eld
)
{
if
(
!
snd_hdmi_get_eld
(
eld
,
codec
,
pin_nid
))
snd_hdmi_show_eld
(
eld
);
}
#ifdef BE_PARANOID
static
void
hdmi_get_dip_index
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
int
*
packet_index
,
int
*
byte_index
)
{
int
val
;
val
=
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_HDMI_DIP_INDEX
,
0
);
*
packet_index
=
val
>>
5
;
*
byte_index
=
val
&
0x1f
;
}
#endif
static
void
hdmi_set_dip_index
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
int
packet_index
,
int
byte_index
)
{
int
val
;
val
=
(
packet_index
<<
5
)
|
(
byte_index
&
0x1f
);
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_HDMI_DIP_INDEX
,
val
);
}
static
void
hdmi_write_dip_byte
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
unsigned
char
val
)
{
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_HDMI_DIP_DATA
,
val
);
}
static
void
hdmi_enable_output
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
/* Unmute */
if
(
get_wcaps
(
codec
,
pin_nid
)
&
AC_WCAP_OUT_AMP
)
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
);
/* Enable pin out */
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
);
}
static
int
hdmi_get_channel_count
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
return
1
+
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_CVT_CHAN_COUNT
,
0
);
}
static
void
hdmi_set_channel_count
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
chs
)
{
if
(
chs
!=
hdmi_get_channel_count
(
codec
,
nid
))
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_CVT_CHAN_COUNT
,
chs
-
1
);
}
/*
* Channel mapping routines
*/
/*
* Compute derived values in channel_allocations[].
*/
static
void
init_channel_allocations
(
void
)
{
int
i
,
j
;
struct
cea_channel_speaker_allocation
*
p
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
channel_allocations
);
i
++
)
{
p
=
channel_allocations
+
i
;
p
->
channels
=
0
;
p
->
spk_mask
=
0
;
for
(
j
=
0
;
j
<
ARRAY_SIZE
(
p
->
speakers
);
j
++
)
if
(
p
->
speakers
[
j
])
{
p
->
channels
++
;
p
->
spk_mask
|=
p
->
speakers
[
j
];
}
}
}
/*
* The transformation takes two steps:
*
* eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
* spk_mask => (channel_allocations[]) => ai->CA
*
* TODO: it could select the wrong CA from multiple candidates.
*/
static
int
hdmi_setup_channel_allocation
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
struct
hdmi_audio_infoframe
*
ai
)
{
struct
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hdmi_eld
*
eld
;
int
i
;
int
spk_mask
=
0
;
int
channels
=
1
+
(
ai
->
CC02_CT47
&
0x7
);
char
buf
[
SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE
];
/*
* CA defaults to 0 for basic stereo audio
*/
if
(
channels
<=
2
)
return
0
;
i
=
hda_node_index
(
spec
->
pin_cvt
,
nid
);
if
(
i
<
0
)
return
0
;
eld
=
&
spec
->
sink_eld
[
i
];
/*
* HDMI sink's ELD info cannot always be retrieved for now, e.g.
* in console or for audio devices. Assume the highest speakers
* configuration, to _not_ prohibit multi-channel audio playback.
*/
if
(
!
eld
->
spk_alloc
)
eld
->
spk_alloc
=
0xffff
;
/*
* expand ELD's speaker allocation mask
*
* ELD tells the speaker mask in a compact(paired) form,
* expand ELD's notions to match the ones used by Audio InfoFrame.
*/
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
eld_speaker_allocation_bits
);
i
++
)
{
if
(
eld
->
spk_alloc
&
(
1
<<
i
))
spk_mask
|=
eld_speaker_allocation_bits
[
i
];
}
/* search for the first working match in the CA table */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
channel_allocations
);
i
++
)
{
if
(
channels
==
channel_allocations
[
i
].
channels
&&
(
spk_mask
&
channel_allocations
[
i
].
spk_mask
)
==
channel_allocations
[
i
].
spk_mask
)
{
ai
->
CA
=
channel_allocations
[
i
].
ca_index
;
break
;
}
}
snd_print_channel_allocation
(
eld
->
spk_alloc
,
buf
,
sizeof
(
buf
));
snd_printdd
(
"HDMI: select CA 0x%x for %d-channel allocation: %s
\n
"
,
ai
->
CA
,
channels
,
buf
);
return
ai
->
CA
;
}
static
void
hdmi_debug_channel_mapping
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
#ifdef CONFIG_SND_DEBUG_VERBOSE
int
i
;
int
slot
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
slot
=
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_HDMI_CHAN_SLOT
,
i
);
printk
(
KERN_DEBUG
"HDMI: ASP channel %d => slot %d
\n
"
,
slot
>>
4
,
slot
&
0xf
);
}
#endif
}
static
void
hdmi_setup_channel_mapping
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
struct
hdmi_audio_infoframe
*
ai
)
{
int
i
;
int
ca
=
ai
->
CA
;
int
err
;
if
(
hdmi_channel_mapping
[
ca
][
1
]
==
0
)
{
for
(
i
=
0
;
i
<
channel_allocations
[
ca
].
channels
;
i
++
)
hdmi_channel_mapping
[
ca
][
i
]
=
i
|
(
i
<<
4
);
for
(;
i
<
8
;
i
++
)
hdmi_channel_mapping
[
ca
][
i
]
=
0xf
|
(
i
<<
4
);
}
for
(
i
=
0
;
i
<
8
;
i
++
)
{
err
=
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_HDMI_CHAN_SLOT
,
hdmi_channel_mapping
[
ca
][
i
]);
if
(
err
)
{
snd_printdd
(
KERN_NOTICE
"HDMI: channel mapping failed
\n
"
);
break
;
}
}
hdmi_debug_channel_mapping
(
codec
,
pin_nid
);
}
/*
* Audio InfoFrame routines
*/
/*
* Enable Audio InfoFrame Transmission
*/
static
void
hdmi_start_infoframe_trans
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
hdmi_set_dip_index
(
codec
,
pin_nid
,
0x0
,
0x0
);
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_HDMI_DIP_XMIT
,
AC_DIPXMIT_BEST
);
}
/*
* Disable Audio InfoFrame Transmission
*/
static
void
hdmi_stop_infoframe_trans
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
hdmi_set_dip_index
(
codec
,
pin_nid
,
0x0
,
0x0
);
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_HDMI_DIP_XMIT
,
AC_DIPXMIT_DISABLE
);
}
static
void
hdmi_debug_dip_size
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
#ifdef CONFIG_SND_DEBUG_VERBOSE
int
i
;
int
size
;
size
=
snd_hdmi_get_eld_size
(
codec
,
pin_nid
);
printk
(
KERN_DEBUG
"HDMI: ELD buf size is %d
\n
"
,
size
);
for
(
i
=
0
;
i
<
8
;
i
++
)
{
size
=
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_HDMI_DIP_SIZE
,
i
);
printk
(
KERN_DEBUG
"HDMI: DIP GP[%d] buf size is %d
\n
"
,
i
,
size
);
}
#endif
}
static
void
hdmi_clear_dip_buffers
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
#ifdef BE_PARANOID
int
i
,
j
;
int
size
;
int
pi
,
bi
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
size
=
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_HDMI_DIP_SIZE
,
i
);
if
(
size
==
0
)
continue
;
hdmi_set_dip_index
(
codec
,
pin_nid
,
i
,
0x0
);
for
(
j
=
1
;
j
<
1000
;
j
++
)
{
hdmi_write_dip_byte
(
codec
,
pin_nid
,
0x0
);
hdmi_get_dip_index
(
codec
,
pin_nid
,
&
pi
,
&
bi
);
if
(
pi
!=
i
)
snd_printd
(
KERN_INFO
"dip index %d: %d != %d
\n
"
,
bi
,
pi
,
i
);
if
(
bi
==
0
)
/* byte index wrapped around */
break
;
}
snd_printd
(
KERN_INFO
"HDMI: DIP GP[%d] buf reported size=%d, written=%d
\n
"
,
i
,
size
,
j
);
}
#endif
}
static
void
hdmi_checksum_audio_infoframe
(
struct
hdmi_audio_infoframe
*
ai
)
{
u8
*
bytes
=
(
u8
*
)
ai
;
u8
sum
=
0
;
int
i
;
ai
->
checksum
=
0
;
for
(
i
=
0
;
i
<
sizeof
(
*
ai
);
i
++
)
sum
+=
bytes
[
i
];
ai
->
checksum
=
-
sum
;
}
static
void
hdmi_fill_audio_infoframe
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
struct
hdmi_audio_infoframe
*
ai
)
{
u8
*
bytes
=
(
u8
*
)
ai
;
int
i
;
hdmi_debug_dip_size
(
codec
,
pin_nid
);
hdmi_clear_dip_buffers
(
codec
,
pin_nid
);
/* be paranoid */
hdmi_checksum_audio_infoframe
(
ai
);
hdmi_set_dip_index
(
codec
,
pin_nid
,
0x0
,
0x0
);
for
(
i
=
0
;
i
<
sizeof
(
*
ai
);
i
++
)
hdmi_write_dip_byte
(
codec
,
pin_nid
,
bytes
[
i
]);
}
static
bool
hdmi_infoframe_uptodate
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
struct
hdmi_audio_infoframe
*
ai
)
{
u8
*
bytes
=
(
u8
*
)
ai
;
u8
val
;
int
i
;
if
(
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_HDMI_DIP_XMIT
,
0
)
!=
AC_DIPXMIT_BEST
)
return
false
;
hdmi_set_dip_index
(
codec
,
pin_nid
,
0x0
,
0x0
);
for
(
i
=
0
;
i
<
sizeof
(
*
ai
);
i
++
)
{
val
=
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_HDMI_DIP_DATA
,
0
);
if
(
val
!=
bytes
[
i
])
return
false
;
}
return
true
;
}
static
void
hdmi_setup_audio_infoframe
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
struct
snd_pcm_substream
*
substream
)
{
struct
hdmi_spec
*
spec
=
codec
->
spec
;
hda_nid_t
pin_nid
;
int
i
;
struct
hdmi_audio_infoframe
ai
=
{
.
type
=
0x84
,
.
ver
=
0x01
,
.
len
=
0x0a
,
.
CC02_CT47
=
substream
->
runtime
->
channels
-
1
,
};
hdmi_setup_channel_allocation
(
codec
,
nid
,
&
ai
);
for
(
i
=
0
;
i
<
spec
->
num_pins
;
i
++
)
{
if
(
spec
->
pin_cvt
[
i
]
!=
nid
)
continue
;
if
(
!
spec
->
sink_eld
[
i
].
monitor_present
)
continue
;
pin_nid
=
spec
->
pin
[
i
];
if
(
!
hdmi_infoframe_uptodate
(
codec
,
pin_nid
,
&
ai
))
{
snd_printdd
(
"hdmi_setup_audio_infoframe: "
"cvt=%d pin=%d channels=%d
\n
"
,
nid
,
pin_nid
,
substream
->
runtime
->
channels
);
hdmi_setup_channel_mapping
(
codec
,
pin_nid
,
&
ai
);
hdmi_stop_infoframe_trans
(
codec
,
pin_nid
);
hdmi_fill_audio_infoframe
(
codec
,
pin_nid
,
&
ai
);
hdmi_start_infoframe_trans
(
codec
,
pin_nid
);
}
}
}
/*
* Unsolicited events
*/
static
void
hdmi_intrinsic_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
struct
hdmi_spec
*
spec
=
codec
->
spec
;
int
tag
=
res
>>
AC_UNSOL_RES_TAG_SHIFT
;
int
pind
=
!!
(
res
&
AC_UNSOL_RES_PD
);
int
eldv
=
!!
(
res
&
AC_UNSOL_RES_ELDV
);
int
index
;
printk
(
KERN_INFO
"HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d
\n
"
,
tag
,
pind
,
eldv
);
index
=
hda_node_index
(
spec
->
pin
,
tag
);
if
(
index
<
0
)
return
;
spec
->
sink_eld
[
index
].
monitor_present
=
pind
;
spec
->
sink_eld
[
index
].
eld_valid
=
eldv
;
if
(
pind
&&
eldv
)
{
hdmi_get_show_eld
(
codec
,
spec
->
pin
[
index
],
&
spec
->
sink_eld
[
index
]);
/* TODO: do real things about ELD */
}
}
static
void
hdmi_non_intrinsic_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
int
tag
=
res
>>
AC_UNSOL_RES_TAG_SHIFT
;
int
subtag
=
(
res
&
AC_UNSOL_RES_SUBTAG
)
>>
AC_UNSOL_RES_SUBTAG_SHIFT
;
int
cp_state
=
!!
(
res
&
AC_UNSOL_RES_CP_STATE
);
int
cp_ready
=
!!
(
res
&
AC_UNSOL_RES_CP_READY
);
printk
(
KERN_INFO
"HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d
\n
"
,
tag
,
subtag
,
cp_state
,
cp_ready
);
/* TODO */
if
(
cp_state
)
;
if
(
cp_ready
)
;
}
static
void
hdmi_unsol_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
struct
hdmi_spec
*
spec
=
codec
->
spec
;
int
tag
=
res
>>
AC_UNSOL_RES_TAG_SHIFT
;
int
subtag
=
(
res
&
AC_UNSOL_RES_SUBTAG
)
>>
AC_UNSOL_RES_SUBTAG_SHIFT
;
if
(
hda_node_index
(
spec
->
pin
,
tag
)
<
0
)
{
snd_printd
(
KERN_INFO
"Unexpected HDMI event tag 0x%x
\n
"
,
tag
);
return
;
}
if
(
subtag
==
0
)
hdmi_intrinsic_event
(
codec
,
res
);
else
hdmi_non_intrinsic_event
(
codec
,
res
);
}
/*
* Callbacks
*/
static
void
hdmi_setup_stream
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
u32
stream_tag
,
int
format
)
{
int
tag
;
int
fmt
;
tag
=
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_CONV
,
0
)
>>
4
;
fmt
=
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_STREAM_FORMAT
,
0
);
snd_printdd
(
"hdmi_setup_stream: "
"NID=0x%x, %sstream=0x%x, %sformat=0x%x
\n
"
,
nid
,
tag
==
stream_tag
?
""
:
"new-"
,
stream_tag
,
fmt
==
format
?
""
:
"new-"
,
format
);
if
(
tag
!=
stream_tag
)
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_CHANNEL_STREAMID
,
stream_tag
<<
4
);
if
(
fmt
!=
format
)
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_STREAM_FORMAT
,
format
);
}
/*
* HDA/HDMI auto parsing
*/
static
int
hdmi_read_pin_conn
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
struct
hdmi_spec
*
spec
=
codec
->
spec
;
hda_nid_t
conn_list
[
HDA_MAX_CONNECTIONS
];
int
conn_len
,
curr
;
int
index
;
if
(
!
(
get_wcaps
(
codec
,
pin_nid
)
&
AC_WCAP_CONN_LIST
))
{
snd_printk
(
KERN_WARNING
"HDMI: pin %d wcaps %#x "
"does not support connection list
\n
"
,
pin_nid
,
get_wcaps
(
codec
,
pin_nid
));
return
-
EINVAL
;
}
conn_len
=
snd_hda_get_connections
(
codec
,
pin_nid
,
conn_list
,
HDA_MAX_CONNECTIONS
);
if
(
conn_len
>
1
)
curr
=
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_CONNECT_SEL
,
0
);
else
curr
=
0
;
index
=
hda_node_index
(
spec
->
pin
,
pin_nid
);
if
(
index
<
0
)
return
-
EINVAL
;
spec
->
pin_cvt
[
index
]
=
conn_list
[
curr
];
return
0
;
}
static
void
hdmi_present_sense
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
struct
hdmi_eld
*
eld
)
{
int
present
=
snd_hda_pin_sense
(
codec
,
pin_nid
);
eld
->
monitor_present
=
!!
(
present
&
AC_PINSENSE_PRESENCE
);
eld
->
eld_valid
=
!!
(
present
&
AC_PINSENSE_ELDV
);
if
(
present
&
AC_PINSENSE_ELDV
)
hdmi_get_show_eld
(
codec
,
pin_nid
,
eld
);
}
static
int
hdmi_add_pin
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
struct
hdmi_spec
*
spec
=
codec
->
spec
;
if
(
spec
->
num_pins
>=
MAX_HDMI_PINS
)
{
snd_printk
(
KERN_WARNING
"HDMI: no space for pin %d
\n
"
,
pin_nid
);
return
-
EINVAL
;
}
hdmi_present_sense
(
codec
,
pin_nid
,
&
spec
->
sink_eld
[
spec
->
num_pins
]);
spec
->
pin
[
spec
->
num_pins
]
=
pin_nid
;
spec
->
num_pins
++
;
/*
* It is assumed that converter nodes come first in the node list and
* hence have been registered and usable now.
*/
return
hdmi_read_pin_conn
(
codec
,
pin_nid
);
}
static
int
hdmi_add_cvt
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
struct
hdmi_spec
*
spec
=
codec
->
spec
;
if
(
spec
->
num_cvts
>=
MAX_HDMI_CVTS
)
{
snd_printk
(
KERN_WARNING
"HDMI: no space for converter %d
\n
"
,
nid
);
return
-
EINVAL
;
}
spec
->
cvt
[
spec
->
num_cvts
]
=
nid
;
spec
->
num_cvts
++
;
return
0
;
}
static
int
hdmi_parse_codec
(
struct
hda_codec
*
codec
)
{
hda_nid_t
nid
;
int
i
,
nodes
;
nodes
=
snd_hda_get_sub_nodes
(
codec
,
codec
->
afg
,
&
nid
);
if
(
!
nid
||
nodes
<
0
)
{
snd_printk
(
KERN_WARNING
"HDMI: failed to get afg sub nodes
\n
"
);
return
-
EINVAL
;
}
for
(
i
=
0
;
i
<
nodes
;
i
++
,
nid
++
)
{
unsigned
int
caps
;
unsigned
int
type
;
caps
=
snd_hda_param_read
(
codec
,
nid
,
AC_PAR_AUDIO_WIDGET_CAP
);
type
=
get_wcaps_type
(
caps
);
if
(
!
(
caps
&
AC_WCAP_DIGITAL
))
continue
;
switch
(
type
)
{
case
AC_WID_AUD_OUT
:
if
(
hdmi_add_cvt
(
codec
,
nid
)
<
0
)
return
-
EINVAL
;
break
;
case
AC_WID_PIN
:
caps
=
snd_hda_param_read
(
codec
,
nid
,
AC_PAR_PIN_CAP
);
if
(
!
(
caps
&
(
AC_PINCAP_HDMI
|
AC_PINCAP_DP
)))
continue
;
if
(
hdmi_add_pin
(
codec
,
nid
)
<
0
)
return
-
EINVAL
;
break
;
}
}
/*
* G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event
* can be lost and presence sense verb will become inaccurate if the
* HDA link is powered off at hot plug or hw initialization time.
*/
#ifdef CONFIG_SND_HDA_POWER_SAVE
if
(
!
(
snd_hda_param_read
(
codec
,
codec
->
afg
,
AC_PAR_POWER_STATE
)
&
AC_PWRST_EPSS
))
codec
->
bus
->
power_keep_link_on
=
1
;
#endif
return
0
;
}
sound/pci/hda/patch_intelhdmi.c
View file @
f1cf9a66
...
...
@@ -40,815 +40,20 @@
*
* The HDA correspondence of pipes/ports are converter/pin nodes.
*/
#define
INTEL
_HDMI_CVTS 2
#define
INTEL
_HDMI_PINS 3
#define
MAX
_HDMI_CVTS 2
#define
MAX
_HDMI_PINS 3
static
char
*
intel_hdmi_pcm_names
[
INTEL_HDMI_CVTS
]
=
{
#include "patch_hdmi.c"
static
char
*
intel_hdmi_pcm_names
[
MAX_HDMI_CVTS
]
=
{
"INTEL HDMI 0"
,
"INTEL HDMI 1"
,
};
struct
intel_hdmi_spec
{
int
num_cvts
;
int
num_pins
;
hda_nid_t
cvt
[
INTEL_HDMI_CVTS
+
1
];
/* audio sources */
hda_nid_t
pin
[
INTEL_HDMI_PINS
+
1
];
/* audio sinks */
/*
* source connection for each pin
*/
hda_nid_t
pin_cvt
[
INTEL_HDMI_PINS
+
1
];
/*
* HDMI sink attached to each pin
*/
struct
hdmi_eld
sink_eld
[
INTEL_HDMI_PINS
];
/*
* export one pcm per pipe
*/
struct
hda_pcm
pcm_rec
[
INTEL_HDMI_CVTS
];
};
struct
hdmi_audio_infoframe
{
u8
type
;
/* 0x84 */
u8
ver
;
/* 0x01 */
u8
len
;
/* 0x0a */
u8
checksum
;
/* PB0 */
u8
CC02_CT47
;
/* CC in bits 0:2, CT in 4:7 */
u8
SS01_SF24
;
u8
CXT04
;
u8
CA
;
u8
LFEPBL01_LSV36_DM_INH7
;
u8
reserved
[
5
];
/* PB6 - PB10 */
};
/*
* CEA speaker placement:
*
* FLH FCH FRH
* FLW FL FLC FC FRC FR FRW
*
* LFE
* TC
*
* RL RLC RC RRC RR
*
* The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to
* CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC.
*/
enum
cea_speaker_placement
{
FL
=
(
1
<<
0
),
/* Front Left */
FC
=
(
1
<<
1
),
/* Front Center */
FR
=
(
1
<<
2
),
/* Front Right */
FLC
=
(
1
<<
3
),
/* Front Left Center */
FRC
=
(
1
<<
4
),
/* Front Right Center */
RL
=
(
1
<<
5
),
/* Rear Left */
RC
=
(
1
<<
6
),
/* Rear Center */
RR
=
(
1
<<
7
),
/* Rear Right */
RLC
=
(
1
<<
8
),
/* Rear Left Center */
RRC
=
(
1
<<
9
),
/* Rear Right Center */
LFE
=
(
1
<<
10
),
/* Low Frequency Effect */
FLW
=
(
1
<<
11
),
/* Front Left Wide */
FRW
=
(
1
<<
12
),
/* Front Right Wide */
FLH
=
(
1
<<
13
),
/* Front Left High */
FCH
=
(
1
<<
14
),
/* Front Center High */
FRH
=
(
1
<<
15
),
/* Front Right High */
TC
=
(
1
<<
16
),
/* Top Center */
};
/*
* ELD SA bits in the CEA Speaker Allocation data block
*/
static
int
eld_speaker_allocation_bits
[]
=
{
[
0
]
=
FL
|
FR
,
[
1
]
=
LFE
,
[
2
]
=
FC
,
[
3
]
=
RL
|
RR
,
[
4
]
=
RC
,
[
5
]
=
FLC
|
FRC
,
[
6
]
=
RLC
|
RRC
,
/* the following are not defined in ELD yet */
[
7
]
=
FLW
|
FRW
,
[
8
]
=
FLH
|
FRH
,
[
9
]
=
TC
,
[
10
]
=
FCH
,
};
struct
cea_channel_speaker_allocation
{
int
ca_index
;
int
speakers
[
8
];
/* derived values, just for convenience */
int
channels
;
int
spk_mask
;
};
/*
* ALSA sequence is:
*
* surround40 surround41 surround50 surround51 surround71
* ch0 front left = = = =
* ch1 front right = = = =
* ch2 rear left = = = =
* ch3 rear right = = = =
* ch4 LFE center center center
* ch5 LFE LFE
* ch6 side left
* ch7 side right
*
* surround71 = {FL, FR, RLC, RRC, FC, LFE, RL, RR}
*/
static
int
hdmi_channel_mapping
[
0x32
][
8
]
=
{
/* stereo */
[
0x00
]
=
{
0x00
,
0x11
,
0xf2
,
0xf3
,
0xf4
,
0xf5
,
0xf6
,
0xf7
},
/* 2.1 */
[
0x01
]
=
{
0x00
,
0x11
,
0x22
,
0xf3
,
0xf4
,
0xf5
,
0xf6
,
0xf7
},
/* Dolby Surround */
[
0x02
]
=
{
0x00
,
0x11
,
0x23
,
0xf2
,
0xf4
,
0xf5
,
0xf6
,
0xf7
},
/* surround40 */
[
0x08
]
=
{
0x00
,
0x11
,
0x24
,
0x35
,
0xf3
,
0xf2
,
0xf6
,
0xf7
},
/* 4ch */
[
0x03
]
=
{
0x00
,
0x11
,
0x23
,
0x32
,
0x44
,
0xf5
,
0xf6
,
0xf7
},
/* surround41 */
[
0x09
]
=
{
0x00
,
0x11
,
0x24
,
0x34
,
0x43
,
0xf2
,
0xf6
,
0xf7
},
/* surround50 */
[
0x0a
]
=
{
0x00
,
0x11
,
0x24
,
0x35
,
0x43
,
0xf2
,
0xf6
,
0xf7
},
/* surround51 */
[
0x0b
]
=
{
0x00
,
0x11
,
0x24
,
0x35
,
0x43
,
0x52
,
0xf6
,
0xf7
},
/* 7.1 */
[
0x13
]
=
{
0x00
,
0x11
,
0x26
,
0x37
,
0x43
,
0x52
,
0x64
,
0x75
},
};
/*
* This is an ordered list!
*
* The preceding ones have better chances to be selected by
* hdmi_setup_channel_allocation().
*/
static
struct
cea_channel_speaker_allocation
channel_allocations
[]
=
{
/* channel: 7 6 5 4 3 2 1 0 */
{
.
ca_index
=
0x00
,
.
speakers
=
{
0
,
0
,
0
,
0
,
0
,
0
,
FR
,
FL
}
},
/* 2.1 */
{
.
ca_index
=
0x01
,
.
speakers
=
{
0
,
0
,
0
,
0
,
0
,
LFE
,
FR
,
FL
}
},
/* Dolby Surround */
{
.
ca_index
=
0x02
,
.
speakers
=
{
0
,
0
,
0
,
0
,
FC
,
0
,
FR
,
FL
}
},
/* surround40 */
{
.
ca_index
=
0x08
,
.
speakers
=
{
0
,
0
,
RR
,
RL
,
0
,
0
,
FR
,
FL
}
},
/* surround41 */
{
.
ca_index
=
0x09
,
.
speakers
=
{
0
,
0
,
RR
,
RL
,
0
,
LFE
,
FR
,
FL
}
},
/* surround50 */
{
.
ca_index
=
0x0a
,
.
speakers
=
{
0
,
0
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
/* surround51 */
{
.
ca_index
=
0x0b
,
.
speakers
=
{
0
,
0
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
/* 6.1 */
{
.
ca_index
=
0x0f
,
.
speakers
=
{
0
,
RC
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
/* surround71 */
{
.
ca_index
=
0x13
,
.
speakers
=
{
RRC
,
RLC
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x03
,
.
speakers
=
{
0
,
0
,
0
,
0
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x04
,
.
speakers
=
{
0
,
0
,
0
,
RC
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x05
,
.
speakers
=
{
0
,
0
,
0
,
RC
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x06
,
.
speakers
=
{
0
,
0
,
0
,
RC
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x07
,
.
speakers
=
{
0
,
0
,
0
,
RC
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x0c
,
.
speakers
=
{
0
,
RC
,
RR
,
RL
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x0d
,
.
speakers
=
{
0
,
RC
,
RR
,
RL
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x0e
,
.
speakers
=
{
0
,
RC
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x10
,
.
speakers
=
{
RRC
,
RLC
,
RR
,
RL
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x11
,
.
speakers
=
{
RRC
,
RLC
,
RR
,
RL
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x12
,
.
speakers
=
{
RRC
,
RLC
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x14
,
.
speakers
=
{
FRC
,
FLC
,
0
,
0
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x15
,
.
speakers
=
{
FRC
,
FLC
,
0
,
0
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x16
,
.
speakers
=
{
FRC
,
FLC
,
0
,
0
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x17
,
.
speakers
=
{
FRC
,
FLC
,
0
,
0
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x18
,
.
speakers
=
{
FRC
,
FLC
,
0
,
RC
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x19
,
.
speakers
=
{
FRC
,
FLC
,
0
,
RC
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x1a
,
.
speakers
=
{
FRC
,
FLC
,
0
,
RC
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x1b
,
.
speakers
=
{
FRC
,
FLC
,
0
,
RC
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x1c
,
.
speakers
=
{
FRC
,
FLC
,
RR
,
RL
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x1d
,
.
speakers
=
{
FRC
,
FLC
,
RR
,
RL
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x1e
,
.
speakers
=
{
FRC
,
FLC
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x1f
,
.
speakers
=
{
FRC
,
FLC
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x20
,
.
speakers
=
{
0
,
FCH
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x21
,
.
speakers
=
{
0
,
FCH
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x22
,
.
speakers
=
{
TC
,
0
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x23
,
.
speakers
=
{
TC
,
0
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x24
,
.
speakers
=
{
FRH
,
FLH
,
RR
,
RL
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x25
,
.
speakers
=
{
FRH
,
FLH
,
RR
,
RL
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x26
,
.
speakers
=
{
FRW
,
FLW
,
RR
,
RL
,
0
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x27
,
.
speakers
=
{
FRW
,
FLW
,
RR
,
RL
,
0
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x28
,
.
speakers
=
{
TC
,
RC
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x29
,
.
speakers
=
{
TC
,
RC
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x2a
,
.
speakers
=
{
FCH
,
RC
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x2b
,
.
speakers
=
{
FCH
,
RC
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x2c
,
.
speakers
=
{
TC
,
FCH
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x2d
,
.
speakers
=
{
TC
,
FCH
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x2e
,
.
speakers
=
{
FRH
,
FLH
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x2f
,
.
speakers
=
{
FRH
,
FLH
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
{
.
ca_index
=
0x30
,
.
speakers
=
{
FRW
,
FLW
,
RR
,
RL
,
FC
,
0
,
FR
,
FL
}
},
{
.
ca_index
=
0x31
,
.
speakers
=
{
FRW
,
FLW
,
RR
,
RL
,
FC
,
LFE
,
FR
,
FL
}
},
};
/*
* HDA/HDMI auto parsing
*/
static
int
hda_node_index
(
hda_nid_t
*
nids
,
hda_nid_t
nid
)
{
int
i
;
for
(
i
=
0
;
nids
[
i
];
i
++
)
if
(
nids
[
i
]
==
nid
)
return
i
;
snd_printk
(
KERN_WARNING
"HDMI: nid %d not registered
\n
"
,
nid
);
return
-
EINVAL
;
}
static
int
intel_hdmi_read_pin_conn
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
struct
intel_hdmi_spec
*
spec
=
codec
->
spec
;
hda_nid_t
conn_list
[
HDA_MAX_CONNECTIONS
];
int
conn_len
,
curr
;
int
index
;
if
(
!
(
get_wcaps
(
codec
,
pin_nid
)
&
AC_WCAP_CONN_LIST
))
{
snd_printk
(
KERN_WARNING
"HDMI: pin %d wcaps %#x "
"does not support connection list
\n
"
,
pin_nid
,
get_wcaps
(
codec
,
pin_nid
));
return
-
EINVAL
;
}
conn_len
=
snd_hda_get_connections
(
codec
,
pin_nid
,
conn_list
,
HDA_MAX_CONNECTIONS
);
if
(
conn_len
>
1
)
curr
=
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_CONNECT_SEL
,
0
);
else
curr
=
0
;
index
=
hda_node_index
(
spec
->
pin
,
pin_nid
);
if
(
index
<
0
)
return
-
EINVAL
;
spec
->
pin_cvt
[
index
]
=
conn_list
[
curr
];
return
0
;
}
static
void
hdmi_get_show_eld
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
struct
hdmi_eld
*
eld
)
{
if
(
!
snd_hdmi_get_eld
(
eld
,
codec
,
pin_nid
))
snd_hdmi_show_eld
(
eld
);
}
static
void
hdmi_present_sense
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
struct
hdmi_eld
*
eld
)
{
int
present
=
snd_hda_pin_sense
(
codec
,
pin_nid
);
eld
->
monitor_present
=
!!
(
present
&
AC_PINSENSE_PRESENCE
);
eld
->
eld_valid
=
!!
(
present
&
AC_PINSENSE_ELDV
);
if
(
present
&
AC_PINSENSE_ELDV
)
hdmi_get_show_eld
(
codec
,
pin_nid
,
eld
);
}
static
int
intel_hdmi_add_pin
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
struct
intel_hdmi_spec
*
spec
=
codec
->
spec
;
if
(
spec
->
num_pins
>=
INTEL_HDMI_PINS
)
{
snd_printk
(
KERN_WARNING
"HDMI: no space for pin %d
\n
"
,
pin_nid
);
return
-
EINVAL
;
}
hdmi_present_sense
(
codec
,
pin_nid
,
&
spec
->
sink_eld
[
spec
->
num_pins
]);
spec
->
pin
[
spec
->
num_pins
]
=
pin_nid
;
spec
->
num_pins
++
;
/*
* It is assumed that converter nodes come first in the node list and
* hence have been registered and usable now.
*/
return
intel_hdmi_read_pin_conn
(
codec
,
pin_nid
);
}
static
int
intel_hdmi_add_cvt
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
struct
intel_hdmi_spec
*
spec
=
codec
->
spec
;
if
(
spec
->
num_cvts
>=
INTEL_HDMI_CVTS
)
{
snd_printk
(
KERN_WARNING
"HDMI: no space for converter %d
\n
"
,
nid
);
return
-
EINVAL
;
}
spec
->
cvt
[
spec
->
num_cvts
]
=
nid
;
spec
->
num_cvts
++
;
return
0
;
}
static
int
intel_hdmi_parse_codec
(
struct
hda_codec
*
codec
)
{
hda_nid_t
nid
;
int
i
,
nodes
;
nodes
=
snd_hda_get_sub_nodes
(
codec
,
codec
->
afg
,
&
nid
);
if
(
!
nid
||
nodes
<
0
)
{
snd_printk
(
KERN_WARNING
"HDMI: failed to get afg sub nodes
\n
"
);
return
-
EINVAL
;
}
for
(
i
=
0
;
i
<
nodes
;
i
++
,
nid
++
)
{
unsigned
int
caps
;
unsigned
int
type
;
caps
=
snd_hda_param_read
(
codec
,
nid
,
AC_PAR_AUDIO_WIDGET_CAP
);
type
=
get_wcaps_type
(
caps
);
if
(
!
(
caps
&
AC_WCAP_DIGITAL
))
continue
;
switch
(
type
)
{
case
AC_WID_AUD_OUT
:
if
(
intel_hdmi_add_cvt
(
codec
,
nid
)
<
0
)
return
-
EINVAL
;
break
;
case
AC_WID_PIN
:
caps
=
snd_hda_param_read
(
codec
,
nid
,
AC_PAR_PIN_CAP
);
if
(
!
(
caps
&
(
AC_PINCAP_HDMI
|
AC_PINCAP_DP
)))
continue
;
if
(
intel_hdmi_add_pin
(
codec
,
nid
)
<
0
)
return
-
EINVAL
;
break
;
}
}
/*
* G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event
* can be lost and presence sense verb will become inaccurate if the
* HDA link is powered off at hot plug or hw initialization time.
*/
#ifdef CONFIG_SND_HDA_POWER_SAVE
if
(
!
(
snd_hda_param_read
(
codec
,
codec
->
afg
,
AC_PAR_POWER_STATE
)
&
AC_PWRST_EPSS
))
codec
->
bus
->
power_keep_link_on
=
1
;
#endif
return
0
;
}
/*
* HDMI routines
*/
#ifdef BE_PARANOID
static
void
hdmi_get_dip_index
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
int
*
packet_index
,
int
*
byte_index
)
{
int
val
;
val
=
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_HDMI_DIP_INDEX
,
0
);
*
packet_index
=
val
>>
5
;
*
byte_index
=
val
&
0x1f
;
}
#endif
static
void
hdmi_set_dip_index
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
int
packet_index
,
int
byte_index
)
{
int
val
;
val
=
(
packet_index
<<
5
)
|
(
byte_index
&
0x1f
);
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_HDMI_DIP_INDEX
,
val
);
}
static
void
hdmi_write_dip_byte
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
unsigned
char
val
)
{
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_HDMI_DIP_DATA
,
val
);
}
static
void
hdmi_enable_output
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
/* Unmute */
if
(
get_wcaps
(
codec
,
pin_nid
)
&
AC_WCAP_OUT_AMP
)
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
);
/* Enable pin out */
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
);
}
/*
* Enable Audio InfoFrame Transmission
*/
static
void
hdmi_start_infoframe_trans
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
hdmi_set_dip_index
(
codec
,
pin_nid
,
0x0
,
0x0
);
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_HDMI_DIP_XMIT
,
AC_DIPXMIT_BEST
);
}
/*
* Disable Audio InfoFrame Transmission
*/
static
void
hdmi_stop_infoframe_trans
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
hdmi_set_dip_index
(
codec
,
pin_nid
,
0x0
,
0x0
);
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_HDMI_DIP_XMIT
,
AC_DIPXMIT_DISABLE
);
}
static
int
hdmi_get_channel_count
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
return
1
+
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_CVT_CHAN_COUNT
,
0
);
}
static
void
hdmi_set_channel_count
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
int
chs
)
{
if
(
chs
!=
hdmi_get_channel_count
(
codec
,
nid
))
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_CVT_CHAN_COUNT
,
chs
-
1
);
}
static
void
hdmi_debug_channel_mapping
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
#ifdef CONFIG_SND_DEBUG_VERBOSE
int
i
;
int
slot
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
slot
=
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_HDMI_CHAN_SLOT
,
i
);
printk
(
KERN_DEBUG
"HDMI: ASP channel %d => slot %d
\n
"
,
slot
>>
4
,
slot
&
0xf
);
}
#endif
}
/*
* Audio InfoFrame routines
*/
static
void
hdmi_debug_dip_size
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
#ifdef CONFIG_SND_DEBUG_VERBOSE
int
i
;
int
size
;
size
=
snd_hdmi_get_eld_size
(
codec
,
pin_nid
);
printk
(
KERN_DEBUG
"HDMI: ELD buf size is %d
\n
"
,
size
);
for
(
i
=
0
;
i
<
8
;
i
++
)
{
size
=
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_HDMI_DIP_SIZE
,
i
);
printk
(
KERN_DEBUG
"HDMI: DIP GP[%d] buf size is %d
\n
"
,
i
,
size
);
}
#endif
}
static
void
hdmi_clear_dip_buffers
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
)
{
#ifdef BE_PARANOID
int
i
,
j
;
int
size
;
int
pi
,
bi
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
size
=
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_HDMI_DIP_SIZE
,
i
);
if
(
size
==
0
)
continue
;
hdmi_set_dip_index
(
codec
,
pin_nid
,
i
,
0x0
);
for
(
j
=
1
;
j
<
1000
;
j
++
)
{
hdmi_write_dip_byte
(
codec
,
pin_nid
,
0x0
);
hdmi_get_dip_index
(
codec
,
pin_nid
,
&
pi
,
&
bi
);
if
(
pi
!=
i
)
snd_printd
(
KERN_INFO
"dip index %d: %d != %d
\n
"
,
bi
,
pi
,
i
);
if
(
bi
==
0
)
/* byte index wrapped around */
break
;
}
snd_printd
(
KERN_INFO
"HDMI: DIP GP[%d] buf reported size=%d, written=%d
\n
"
,
i
,
size
,
j
);
}
#endif
}
static
void
hdmi_checksum_audio_infoframe
(
struct
hdmi_audio_infoframe
*
ai
)
{
u8
*
bytes
=
(
u8
*
)
ai
;
u8
sum
=
0
;
int
i
;
ai
->
checksum
=
0
;
for
(
i
=
0
;
i
<
sizeof
(
*
ai
);
i
++
)
sum
+=
bytes
[
i
];
ai
->
checksum
=
-
sum
;
}
static
void
hdmi_fill_audio_infoframe
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
struct
hdmi_audio_infoframe
*
ai
)
{
u8
*
bytes
=
(
u8
*
)
ai
;
int
i
;
hdmi_debug_dip_size
(
codec
,
pin_nid
);
hdmi_clear_dip_buffers
(
codec
,
pin_nid
);
/* be paranoid */
hdmi_checksum_audio_infoframe
(
ai
);
hdmi_set_dip_index
(
codec
,
pin_nid
,
0x0
,
0x0
);
for
(
i
=
0
;
i
<
sizeof
(
*
ai
);
i
++
)
hdmi_write_dip_byte
(
codec
,
pin_nid
,
bytes
[
i
]);
}
/*
* Compute derived values in channel_allocations[].
*/
static
void
init_channel_allocations
(
void
)
{
int
i
,
j
;
struct
cea_channel_speaker_allocation
*
p
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
channel_allocations
);
i
++
)
{
p
=
channel_allocations
+
i
;
p
->
channels
=
0
;
p
->
spk_mask
=
0
;
for
(
j
=
0
;
j
<
ARRAY_SIZE
(
p
->
speakers
);
j
++
)
if
(
p
->
speakers
[
j
])
{
p
->
channels
++
;
p
->
spk_mask
|=
p
->
speakers
[
j
];
}
}
}
/*
* The transformation takes two steps:
*
* eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
* spk_mask => (channel_allocations[]) => ai->CA
*
* TODO: it could select the wrong CA from multiple candidates.
*/
static
int
hdmi_setup_channel_allocation
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
struct
hdmi_audio_infoframe
*
ai
)
{
struct
intel_hdmi_spec
*
spec
=
codec
->
spec
;
struct
hdmi_eld
*
eld
;
int
i
;
int
spk_mask
=
0
;
int
channels
=
1
+
(
ai
->
CC02_CT47
&
0x7
);
char
buf
[
SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE
];
/*
* CA defaults to 0 for basic stereo audio
*/
if
(
channels
<=
2
)
return
0
;
i
=
hda_node_index
(
spec
->
pin_cvt
,
nid
);
if
(
i
<
0
)
return
0
;
eld
=
&
spec
->
sink_eld
[
i
];
/*
* HDMI sink's ELD info cannot always be retrieved for now, e.g.
* in console or for audio devices. Assume the highest speakers
* configuration, to _not_ prohibit multi-channel audio playback.
*/
if
(
!
eld
->
spk_alloc
)
eld
->
spk_alloc
=
0xffff
;
/*
* expand ELD's speaker allocation mask
*
* ELD tells the speaker mask in a compact(paired) form,
* expand ELD's notions to match the ones used by Audio InfoFrame.
*/
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
eld_speaker_allocation_bits
);
i
++
)
{
if
(
eld
->
spk_alloc
&
(
1
<<
i
))
spk_mask
|=
eld_speaker_allocation_bits
[
i
];
}
/* search for the first working match in the CA table */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
channel_allocations
);
i
++
)
{
if
(
channels
==
channel_allocations
[
i
].
channels
&&
(
spk_mask
&
channel_allocations
[
i
].
spk_mask
)
==
channel_allocations
[
i
].
spk_mask
)
{
ai
->
CA
=
channel_allocations
[
i
].
ca_index
;
break
;
}
}
snd_print_channel_allocation
(
eld
->
spk_alloc
,
buf
,
sizeof
(
buf
));
snd_printdd
(
KERN_INFO
"HDMI: select CA 0x%x for %d-channel allocation: %s
\n
"
,
ai
->
CA
,
channels
,
buf
);
return
ai
->
CA
;
}
static
void
hdmi_setup_channel_mapping
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
struct
hdmi_audio_infoframe
*
ai
)
{
int
i
;
int
ca
=
ai
->
CA
;
int
err
;
if
(
hdmi_channel_mapping
[
ca
][
1
]
==
0
)
{
for
(
i
=
0
;
i
<
channel_allocations
[
ca
].
channels
;
i
++
)
hdmi_channel_mapping
[
ca
][
i
]
=
i
|
(
i
<<
4
);
for
(;
i
<
8
;
i
++
)
hdmi_channel_mapping
[
ca
][
i
]
=
0xf
|
(
i
<<
4
);
}
for
(
i
=
0
;
i
<
8
;
i
++
)
{
err
=
snd_hda_codec_write
(
codec
,
pin_nid
,
0
,
AC_VERB_SET_HDMI_CHAN_SLOT
,
hdmi_channel_mapping
[
ca
][
i
]);
if
(
err
)
{
snd_printdd
(
KERN_INFO
"HDMI: channel mapping failed
\n
"
);
break
;
}
}
hdmi_debug_channel_mapping
(
codec
,
pin_nid
);
}
static
bool
hdmi_infoframe_uptodate
(
struct
hda_codec
*
codec
,
hda_nid_t
pin_nid
,
struct
hdmi_audio_infoframe
*
ai
)
{
u8
*
bytes
=
(
u8
*
)
ai
;
u8
val
;
int
i
;
if
(
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_HDMI_DIP_XMIT
,
0
)
!=
AC_DIPXMIT_BEST
)
return
false
;
hdmi_set_dip_index
(
codec
,
pin_nid
,
0x0
,
0x0
);
for
(
i
=
0
;
i
<
sizeof
(
*
ai
);
i
++
)
{
val
=
snd_hda_codec_read
(
codec
,
pin_nid
,
0
,
AC_VERB_GET_HDMI_DIP_DATA
,
0
);
if
(
val
!=
bytes
[
i
])
return
false
;
}
return
true
;
}
static
void
hdmi_setup_audio_infoframe
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
struct
snd_pcm_substream
*
substream
)
{
struct
intel_hdmi_spec
*
spec
=
codec
->
spec
;
hda_nid_t
pin_nid
;
int
i
;
struct
hdmi_audio_infoframe
ai
=
{
.
type
=
0x84
,
.
ver
=
0x01
,
.
len
=
0x0a
,
.
CC02_CT47
=
substream
->
runtime
->
channels
-
1
,
};
hdmi_setup_channel_allocation
(
codec
,
nid
,
&
ai
);
for
(
i
=
0
;
i
<
spec
->
num_pins
;
i
++
)
{
if
(
spec
->
pin_cvt
[
i
]
!=
nid
)
continue
;
if
(
!
spec
->
sink_eld
[
i
].
monitor_present
)
continue
;
pin_nid
=
spec
->
pin
[
i
];
if
(
!
hdmi_infoframe_uptodate
(
codec
,
pin_nid
,
&
ai
))
{
hdmi_setup_channel_mapping
(
codec
,
pin_nid
,
&
ai
);
hdmi_stop_infoframe_trans
(
codec
,
pin_nid
);
hdmi_fill_audio_infoframe
(
codec
,
pin_nid
,
&
ai
);
hdmi_start_infoframe_trans
(
codec
,
pin_nid
);
}
}
}
/*
*
Unsolicited event
s
*
HDMI callback
s
*/
static
void
hdmi_intrinsic_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
struct
intel_hdmi_spec
*
spec
=
codec
->
spec
;
int
tag
=
res
>>
AC_UNSOL_RES_TAG_SHIFT
;
int
pind
=
!!
(
res
&
AC_UNSOL_RES_PD
);
int
eldv
=
!!
(
res
&
AC_UNSOL_RES_ELDV
);
int
index
;
printk
(
KERN_INFO
"HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d
\n
"
,
tag
,
pind
,
eldv
);
index
=
hda_node_index
(
spec
->
pin
,
tag
);
if
(
index
<
0
)
return
;
spec
->
sink_eld
[
index
].
monitor_present
=
pind
;
spec
->
sink_eld
[
index
].
eld_valid
=
eldv
;
if
(
pind
&&
eldv
)
{
hdmi_get_show_eld
(
codec
,
spec
->
pin
[
index
],
&
spec
->
sink_eld
[
index
]);
/* TODO: do real things about ELD */
}
}
static
void
hdmi_non_intrinsic_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
int
tag
=
res
>>
AC_UNSOL_RES_TAG_SHIFT
;
int
subtag
=
(
res
&
AC_UNSOL_RES_SUBTAG
)
>>
AC_UNSOL_RES_SUBTAG_SHIFT
;
int
cp_state
=
!!
(
res
&
AC_UNSOL_RES_CP_STATE
);
int
cp_ready
=
!!
(
res
&
AC_UNSOL_RES_CP_READY
);
printk
(
KERN_INFO
"HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d
\n
"
,
tag
,
subtag
,
cp_state
,
cp_ready
);
/* TODO */
if
(
cp_state
)
;
if
(
cp_ready
)
;
}
static
void
intel_hdmi_unsol_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
struct
intel_hdmi_spec
*
spec
=
codec
->
spec
;
int
tag
=
res
>>
AC_UNSOL_RES_TAG_SHIFT
;
int
subtag
=
(
res
&
AC_UNSOL_RES_SUBTAG
)
>>
AC_UNSOL_RES_SUBTAG_SHIFT
;
if
(
hda_node_index
(
spec
->
pin
,
tag
)
<
0
)
{
snd_printd
(
KERN_INFO
"Unexpected HDMI event tag 0x%x
\n
"
,
tag
);
return
;
}
if
(
subtag
==
0
)
hdmi_intrinsic_event
(
codec
,
res
);
else
hdmi_non_intrinsic_event
(
codec
,
res
);
}
/*
* Callbacks
*/
static
void
hdmi_setup_stream
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
,
u32
stream_tag
,
int
format
)
{
int
tag
;
int
fmt
;
tag
=
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_CONV
,
0
)
>>
4
;
fmt
=
snd_hda_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_STREAM_FORMAT
,
0
);
snd_printdd
(
"hdmi_setup_stream: "
"NID=0x%x, %sstream=0x%x, %sformat=0x%x
\n
"
,
nid
,
tag
==
stream_tag
?
""
:
"new-"
,
stream_tag
,
fmt
==
format
?
""
:
"new-"
,
format
);
if
(
tag
!=
stream_tag
)
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_CHANNEL_STREAMID
,
stream_tag
<<
4
);
if
(
fmt
!=
format
)
snd_hda_codec_write
(
codec
,
nid
,
0
,
AC_VERB_SET_STREAM_FORMAT
,
format
);
}
static
int
intel_hdmi_playback_pcm_prepare
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
unsigned
int
stream_tag
,
...
...
@@ -882,7 +87,7 @@ static struct hda_pcm_stream intel_hdmi_pcm_playback = {
static
int
intel_hdmi_build_pcms
(
struct
hda_codec
*
codec
)
{
struct
intel_
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hda_pcm
*
info
=
spec
->
pcm_rec
;
int
i
;
...
...
@@ -908,7 +113,7 @@ static int intel_hdmi_build_pcms(struct hda_codec *codec)
static
int
intel_hdmi_build_controls
(
struct
hda_codec
*
codec
)
{
struct
intel_
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
int
err
;
int
i
;
...
...
@@ -923,7 +128,7 @@ static int intel_hdmi_build_controls(struct hda_codec *codec)
static
int
intel_hdmi_init
(
struct
hda_codec
*
codec
)
{
struct
intel_
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
int
i
;
for
(
i
=
0
;
spec
->
pin
[
i
];
i
++
)
{
...
...
@@ -937,7 +142,7 @@ static int intel_hdmi_init(struct hda_codec *codec)
static
void
intel_hdmi_free
(
struct
hda_codec
*
codec
)
{
struct
intel_
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
int
i
;
for
(
i
=
0
;
i
<
spec
->
num_pins
;
i
++
)
...
...
@@ -951,12 +156,12 @@ static struct hda_codec_ops intel_hdmi_patch_ops = {
.
free
=
intel_hdmi_free
,
.
build_pcms
=
intel_hdmi_build_pcms
,
.
build_controls
=
intel_hdmi_build_controls
,
.
unsol_event
=
intel_
hdmi_unsol_event
,
.
unsol_event
=
hdmi_unsol_event
,
};
static
int
patch_intel_hdmi
(
struct
hda_codec
*
codec
)
{
struct
intel_
hdmi_spec
*
spec
;
struct
hdmi_spec
*
spec
;
int
i
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
...
...
@@ -964,7 +169,7 @@ static int patch_intel_hdmi(struct hda_codec *codec)
return
-
ENOMEM
;
codec
->
spec
=
spec
;
if
(
intel_
hdmi_parse_codec
(
codec
)
<
0
)
{
if
(
hdmi_parse_codec
(
codec
)
<
0
)
{
codec
->
spec
=
NULL
;
kfree
(
spec
);
return
-
EINVAL
;
...
...
sound/pci/hda/patch_nvhdmi.c
View file @
f1cf9a66
...
...
@@ -29,13 +29,23 @@
#include "hda_codec.h"
#include "hda_local.h"
#define MAX_HDMI_CVTS 1
#define MAX_HDMI_PINS 1
#include "patch_hdmi.c"
static
char
*
nvhdmi_pcm_names
[
MAX_HDMI_CVTS
]
=
{
"NVIDIA HDMI"
,
};
/* define below to restrict the supported rates and formats */
/* #define LIMITED_RATE_FMT_SUPPORT */
struct
nvhdmi_spec
{
struct
hda_multi_out
multiout
;
struct
hda_pcm
pcm_rec
;
enum
HDACodec
{
HDA_CODEC_NVIDIA_MCP7X
,
HDA_CODEC_NVIDIA_MCP89
,
HDA_CODEC_NVIDIA_GT21X
,
HDA_CODEC_INVALID
};
#define Nv_VERB_SET_Channel_Allocation 0xF79
...
...
@@ -43,15 +53,18 @@ struct nvhdmi_spec {
#define Nv_VERB_SET_Audio_Protection_On 0xF98
#define Nv_VERB_SET_Audio_Protection_Off 0xF99
#define
Nv_Master_Convert_nid
0x04
#define
Nv_Master_Pin_nid
0x05
#define
nvhdmi_master_con_nid_7x
0x04
#define
nvhdmi_master_pin_nid_7x
0x05
static
hda_nid_t
nvhdmi_convert_nids
[
4
]
=
{
#define nvhdmi_master_con_nid_89 0x04
#define nvhdmi_master_pin_nid_89 0x05
static
hda_nid_t
nvhdmi_con_nids_7x
[
4
]
=
{
/*front, rear, clfe, rear_surr */
0x6
,
0x8
,
0xa
,
0xc
,
};
static
struct
hda_verb
nvhdmi_basic_init
[]
=
{
static
struct
hda_verb
nvhdmi_basic_init
_7x
[]
=
{
/* set audio protect on */
{
0x1
,
Nv_VERB_SET_Audio_Protection_On
,
0x1
},
/* enable digital output on pin widget */
...
...
@@ -84,22 +97,60 @@ static struct hda_verb nvhdmi_basic_init[] = {
*/
static
int
nvhdmi_build_controls
(
struct
hda_codec
*
codec
)
{
struct
nv
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
int
err
;
int
i
;
err
=
snd_hda_create_spdif_out_ctls
(
codec
,
spec
->
multiout
.
dig_out_nid
);
if
(
err
<
0
)
return
err
;
if
((
spec
->
codec_type
==
HDA_CODEC_NVIDIA_MCP89
)
||
(
spec
->
codec_type
==
HDA_CODEC_NVIDIA_GT21X
))
{
for
(
i
=
0
;
i
<
codec
->
num_pcms
;
i
++
)
{
err
=
snd_hda_create_spdif_out_ctls
(
codec
,
spec
->
cvt
[
i
]);
if
(
err
<
0
)
return
err
;
}
}
else
{
err
=
snd_hda_create_spdif_out_ctls
(
codec
,
spec
->
multiout
.
dig_out_nid
);
if
(
err
<
0
)
return
err
;
}
return
0
;
}
static
int
nvhdmi_init
(
struct
hda_codec
*
codec
)
{
snd_hda_sequence_write
(
codec
,
nvhdmi_basic_init
);
struct
hdmi_spec
*
spec
=
codec
->
spec
;
int
i
;
if
((
spec
->
codec_type
==
HDA_CODEC_NVIDIA_MCP89
)
||
(
spec
->
codec_type
==
HDA_CODEC_NVIDIA_GT21X
))
{
for
(
i
=
0
;
spec
->
pin
[
i
];
i
++
)
{
hdmi_enable_output
(
codec
,
spec
->
pin
[
i
]);
snd_hda_codec_write
(
codec
,
spec
->
pin
[
i
],
0
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
spec
->
pin
[
i
]);
}
}
else
{
snd_hda_sequence_write
(
codec
,
nvhdmi_basic_init_7x
);
}
return
0
;
}
static
void
nvhdmi_free
(
struct
hda_codec
*
codec
)
{
struct
hdmi_spec
*
spec
=
codec
->
spec
;
int
i
;
if
((
spec
->
codec_type
==
HDA_CODEC_NVIDIA_MCP89
)
||
(
spec
->
codec_type
==
HDA_CODEC_NVIDIA_GT21X
))
{
for
(
i
=
0
;
i
<
spec
->
num_pins
;
i
++
)
snd_hda_eld_proc_free
(
codec
,
&
spec
->
sink_eld
[
i
]);
}
kfree
(
spec
);
}
/*
* Digital out
*/
...
...
@@ -107,25 +158,25 @@ static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct
hda_codec
*
codec
,
struct
snd_pcm_substream
*
substream
)
{
struct
nv
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
return
snd_hda_multi_out_dig_open
(
codec
,
&
spec
->
multiout
);
}
static
int
nvhdmi_dig_playback_pcm_close_8ch
(
struct
hda_pcm_stream
*
hinfo
,
static
int
nvhdmi_dig_playback_pcm_close_8ch
_7x
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
struct
snd_pcm_substream
*
substream
)
{
struct
nv
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
int
i
;
snd_hda_codec_write
(
codec
,
Nv_Master_Convert_nid
,
snd_hda_codec_write
(
codec
,
nvhdmi_master_con_nid_7x
,
0
,
AC_VERB_SET_CHANNEL_STREAMID
,
0
);
for
(
i
=
0
;
i
<
4
;
i
++
)
{
/* set the stream id */
snd_hda_codec_write
(
codec
,
nvhdmi_con
vert_nids
[
i
],
0
,
snd_hda_codec_write
(
codec
,
nvhdmi_con
_nids_7x
[
i
],
0
,
AC_VERB_SET_CHANNEL_STREAMID
,
0
);
/* set the stream format */
snd_hda_codec_write
(
codec
,
nvhdmi_con
vert_nids
[
i
],
0
,
snd_hda_codec_write
(
codec
,
nvhdmi_con
_nids_7x
[
i
],
0
,
AC_VERB_SET_STREAM_FORMAT
,
0
);
}
...
...
@@ -136,10 +187,25 @@ static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo,
struct
hda_codec
*
codec
,
struct
snd_pcm_substream
*
substream
)
{
struct
nv
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
return
snd_hda_multi_out_dig_close
(
codec
,
&
spec
->
multiout
);
}
static
int
nvhdmi_dig_playback_pcm_prepare_8ch_89
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
unsigned
int
stream_tag
,
unsigned
int
format
,
struct
snd_pcm_substream
*
substream
)
{
hdmi_set_channel_count
(
codec
,
hinfo
->
nid
,
substream
->
runtime
->
channels
);
hdmi_setup_audio_infoframe
(
codec
,
hinfo
->
nid
,
substream
);
hdmi_setup_stream
(
codec
,
hinfo
->
nid
,
stream_tag
,
format
);
return
0
;
}
static
int
nvhdmi_dig_playback_pcm_prepare_8ch
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
unsigned
int
stream_tag
,
...
...
@@ -181,29 +247,29 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
if
(
codec
->
spdif_status_reset
&&
(
codec
->
spdif_ctls
&
AC_DIG1_ENABLE
))
snd_hda_codec_write
(
codec
,
Nv_Master_Convert_nid
,
nvhdmi_master_con_nid_7x
,
0
,
AC_VERB_SET_DIGI_CONVERT_1
,
codec
->
spdif_ctls
&
~
AC_DIG1_ENABLE
&
0xff
);
/* set the stream id */
snd_hda_codec_write
(
codec
,
Nv_Master_Convert_nid
,
0
,
snd_hda_codec_write
(
codec
,
nvhdmi_master_con_nid_7x
,
0
,
AC_VERB_SET_CHANNEL_STREAMID
,
(
stream_tag
<<
4
)
|
0x0
);
/* set the stream format */
snd_hda_codec_write
(
codec
,
Nv_Master_Convert_nid
,
0
,
snd_hda_codec_write
(
codec
,
nvhdmi_master_con_nid_7x
,
0
,
AC_VERB_SET_STREAM_FORMAT
,
format
);
/* turn on again (if needed) */
/* enable and set the channel status audio/data flag */
if
(
codec
->
spdif_status_reset
&&
(
codec
->
spdif_ctls
&
AC_DIG1_ENABLE
))
{
snd_hda_codec_write
(
codec
,
Nv_Master_Convert_nid
,
nvhdmi_master_con_nid_7x
,
0
,
AC_VERB_SET_DIGI_CONVERT_1
,
codec
->
spdif_ctls
&
0xff
);
snd_hda_codec_write
(
codec
,
Nv_Master_Convert_nid
,
nvhdmi_master_con_nid_7x
,
0
,
AC_VERB_SET_DIGI_CONVERT_2
,
dataDCC2
);
}
...
...
@@ -220,19 +286,19 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
if
(
codec
->
spdif_status_reset
&&
(
codec
->
spdif_ctls
&
AC_DIG1_ENABLE
))
snd_hda_codec_write
(
codec
,
nvhdmi_con
vert_nids
[
i
],
nvhdmi_con
_nids_7x
[
i
],
0
,
AC_VERB_SET_DIGI_CONVERT_1
,
codec
->
spdif_ctls
&
~
AC_DIG1_ENABLE
&
0xff
);
/* set the stream id */
snd_hda_codec_write
(
codec
,
nvhdmi_con
vert_nids
[
i
],
nvhdmi_con
_nids_7x
[
i
],
0
,
AC_VERB_SET_CHANNEL_STREAMID
,
(
stream_tag
<<
4
)
|
channel_id
);
/* set the stream format */
snd_hda_codec_write
(
codec
,
nvhdmi_con
vert_nids
[
i
],
nvhdmi_con
_nids_7x
[
i
],
0
,
AC_VERB_SET_STREAM_FORMAT
,
format
);
...
...
@@ -241,12 +307,12 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
if
(
codec
->
spdif_status_reset
&&
(
codec
->
spdif_ctls
&
AC_DIG1_ENABLE
))
{
snd_hda_codec_write
(
codec
,
nvhdmi_con
vert_nids
[
i
],
nvhdmi_con
_nids_7x
[
i
],
0
,
AC_VERB_SET_DIGI_CONVERT_1
,
codec
->
spdif_ctls
&
0xff
);
snd_hda_codec_write
(
codec
,
nvhdmi_con
vert_nids
[
i
],
nvhdmi_con
_nids_7x
[
i
],
0
,
AC_VERB_SET_DIGI_CONVERT_2
,
dataDCC2
);
}
...
...
@@ -261,28 +327,47 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
return
0
;
}
static
int
nvhdmi_playback_pcm_cleanup
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
struct
snd_pcm_substream
*
substream
)
{
return
0
;
}
static
int
nvhdmi_dig_playback_pcm_prepare_2ch
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
unsigned
int
stream_tag
,
unsigned
int
format
,
struct
snd_pcm_substream
*
substream
)
{
struct
nv
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
return
snd_hda_multi_out_dig_prepare
(
codec
,
&
spec
->
multiout
,
stream_tag
,
format
,
substream
);
}
static
struct
hda_pcm_stream
nvhdmi_pcm_digital_playback_8ch
=
{
static
struct
hda_pcm_stream
nvhdmi_pcm_digital_playback_8ch_89
=
{
.
substreams
=
1
,
.
channels_min
=
2
,
.
rates
=
SUPPORTED_RATES
,
.
maxbps
=
SUPPORTED_MAXBPS
,
.
formats
=
SUPPORTED_FORMATS
,
.
ops
=
{
.
prepare
=
nvhdmi_dig_playback_pcm_prepare_8ch_89
,
.
cleanup
=
nvhdmi_playback_pcm_cleanup
,
},
};
static
struct
hda_pcm_stream
nvhdmi_pcm_digital_playback_8ch_7x
=
{
.
substreams
=
1
,
.
channels_min
=
2
,
.
channels_max
=
8
,
.
nid
=
Nv_Master_Convert_nid
,
.
nid
=
nvhdmi_master_con_nid_7x
,
.
rates
=
SUPPORTED_RATES
,
.
maxbps
=
SUPPORTED_MAXBPS
,
.
formats
=
SUPPORTED_FORMATS
,
.
ops
=
{
.
open
=
nvhdmi_dig_playback_pcm_open
,
.
close
=
nvhdmi_dig_playback_pcm_close_8ch
,
.
close
=
nvhdmi_dig_playback_pcm_close_8ch
_7x
,
.
prepare
=
nvhdmi_dig_playback_pcm_prepare_8ch
},
};
...
...
@@ -291,7 +376,7 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = {
.
substreams
=
1
,
.
channels_min
=
2
,
.
channels_max
=
2
,
.
nid
=
Nv_Master_Convert_nid
,
.
nid
=
nvhdmi_master_con_nid_7x
,
.
rates
=
SUPPORTED_RATES
,
.
maxbps
=
SUPPORTED_MAXBPS
,
.
formats
=
SUPPORTED_FORMATS
,
...
...
@@ -302,10 +387,36 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = {
},
};
static
int
nvhdmi_build_pcms_8ch
(
struct
hda_codec
*
codec
)
static
int
nvhdmi_build_pcms_8ch_89
(
struct
hda_codec
*
codec
)
{
struct
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hda_pcm
*
info
=
spec
->
pcm_rec
;
int
i
;
codec
->
num_pcms
=
spec
->
num_cvts
;
codec
->
pcm_info
=
info
;
for
(
i
=
0
;
i
<
codec
->
num_pcms
;
i
++
,
info
++
)
{
unsigned
int
chans
;
chans
=
get_wcaps
(
codec
,
spec
->
cvt
[
i
]);
chans
=
get_wcaps_channels
(
chans
);
info
->
name
=
nvhdmi_pcm_names
[
i
];
info
->
pcm_type
=
HDA_PCM_TYPE_HDMI
;
info
->
stream
[
SNDRV_PCM_STREAM_PLAYBACK
]
=
nvhdmi_pcm_digital_playback_8ch_89
;
info
->
stream
[
SNDRV_PCM_STREAM_PLAYBACK
].
nid
=
spec
->
cvt
[
i
];
info
->
stream
[
SNDRV_PCM_STREAM_PLAYBACK
].
channels_max
=
chans
;
}
return
0
;
}
static
int
nvhdmi_build_pcms_8ch_7x
(
struct
hda_codec
*
codec
)
{
struct
nv
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hda_pcm
*
info
=
&
spec
->
pcm_rec
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hda_pcm
*
info
=
spec
->
pcm_rec
;
codec
->
num_pcms
=
1
;
codec
->
pcm_info
=
info
;
...
...
@@ -313,15 +424,15 @@ static int nvhdmi_build_pcms_8ch(struct hda_codec *codec)
info
->
name
=
"NVIDIA HDMI"
;
info
->
pcm_type
=
HDA_PCM_TYPE_HDMI
;
info
->
stream
[
SNDRV_PCM_STREAM_PLAYBACK
]
=
nvhdmi_pcm_digital_playback_8ch
;
=
nvhdmi_pcm_digital_playback_8ch
_7x
;
return
0
;
}
static
int
nvhdmi_build_pcms_2ch
(
struct
hda_codec
*
codec
)
{
struct
nv
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hda_pcm
*
info
=
&
spec
->
pcm_rec
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hda_pcm
*
info
=
spec
->
pcm_rec
;
codec
->
num_pcms
=
1
;
codec
->
pcm_info
=
info
;
...
...
@@ -334,14 +445,17 @@ static int nvhdmi_build_pcms_2ch(struct hda_codec *codec)
return
0
;
}
static
void
nvhdmi_free
(
struct
hda_codec
*
codec
)
{
kfree
(
codec
->
spec
);
}
static
struct
hda_codec_ops
nvhdmi_patch_ops_8ch_89
=
{
.
build_controls
=
nvhdmi_build_controls
,
.
build_pcms
=
nvhdmi_build_pcms_8ch_89
,
.
init
=
nvhdmi_init
,
.
free
=
nvhdmi_free
,
.
unsol_event
=
hdmi_unsol_event
,
};
static
struct
hda_codec_ops
nvhdmi_patch_ops_8ch
=
{
static
struct
hda_codec_ops
nvhdmi_patch_ops_8ch
_7x
=
{
.
build_controls
=
nvhdmi_build_controls
,
.
build_pcms
=
nvhdmi_build_pcms_8ch
,
.
build_pcms
=
nvhdmi_build_pcms_8ch
_7x
,
.
init
=
nvhdmi_init
,
.
free
=
nvhdmi_free
,
};
...
...
@@ -353,9 +467,36 @@ static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
.
free
=
nvhdmi_free
,
};
static
int
patch_nvhdmi_8ch
(
struct
hda_codec
*
codec
)
static
int
patch_nvhdmi_8ch_89
(
struct
hda_codec
*
codec
)
{
struct
hdmi_spec
*
spec
;
int
i
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
spec
==
NULL
)
return
-
ENOMEM
;
codec
->
spec
=
spec
;
spec
->
codec_type
=
HDA_CODEC_NVIDIA_MCP89
;
if
(
hdmi_parse_codec
(
codec
)
<
0
)
{
codec
->
spec
=
NULL
;
kfree
(
spec
);
return
-
EINVAL
;
}
codec
->
patch_ops
=
nvhdmi_patch_ops_8ch_89
;
for
(
i
=
0
;
i
<
spec
->
num_pins
;
i
++
)
snd_hda_eld_proc_new
(
codec
,
&
spec
->
sink_eld
[
i
],
i
);
init_channel_allocations
();
return
0
;
}
static
int
patch_nvhdmi_8ch_7x
(
struct
hda_codec
*
codec
)
{
struct
nv
hdmi_spec
*
spec
;
struct
hdmi_spec
*
spec
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
spec
==
NULL
)
...
...
@@ -365,16 +506,17 @@ static int patch_nvhdmi_8ch(struct hda_codec *codec)
spec
->
multiout
.
num_dacs
=
0
;
/* no analog */
spec
->
multiout
.
max_channels
=
8
;
spec
->
multiout
.
dig_out_nid
=
Nv_Master_Convert_nid
;
spec
->
multiout
.
dig_out_nid
=
nvhdmi_master_con_nid_7x
;
spec
->
codec_type
=
HDA_CODEC_NVIDIA_MCP7X
;
codec
->
patch_ops
=
nvhdmi_patch_ops_8ch
;
codec
->
patch_ops
=
nvhdmi_patch_ops_8ch
_7x
;
return
0
;
}
static
int
patch_nvhdmi_2ch
(
struct
hda_codec
*
codec
)
{
struct
nv
hdmi_spec
*
spec
;
struct
hdmi_spec
*
spec
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
spec
==
NULL
)
...
...
@@ -384,7 +526,8 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
spec
->
multiout
.
num_dacs
=
0
;
/* no analog */
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
dig_out_nid
=
Nv_Master_Convert_nid
;
spec
->
multiout
.
dig_out_nid
=
nvhdmi_master_con_nid_7x
;
spec
->
codec_type
=
HDA_CODEC_NVIDIA_MCP7X
;
codec
->
patch_ops
=
nvhdmi_patch_ops_2ch
;
...
...
@@ -395,13 +538,24 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
* patch entries
*/
static
struct
hda_codec_preset
snd_hda_preset_nvhdmi
[]
=
{
{
.
id
=
0x10de0002
,
.
name
=
"MCP78 HDMI"
,
.
patch
=
patch_nvhdmi_8ch
},
{
.
id
=
0x10de0003
,
.
name
=
"MCP78 HDMI"
,
.
patch
=
patch_nvhdmi_8ch
},
{
.
id
=
0x10de0005
,
.
name
=
"MCP78 HDMI"
,
.
patch
=
patch_nvhdmi_8ch
},
{
.
id
=
0x10de0006
,
.
name
=
"MCP78 HDMI"
,
.
patch
=
patch_nvhdmi_8ch
},
{
.
id
=
0x10de0007
,
.
name
=
"MCP7A HDMI"
,
.
patch
=
patch_nvhdmi_8ch
},
{
.
id
=
0x10de0067
,
.
name
=
"MCP67 HDMI"
,
.
patch
=
patch_nvhdmi_2ch
},
{
.
id
=
0x10de8001
,
.
name
=
"MCP73 HDMI"
,
.
patch
=
patch_nvhdmi_2ch
},
{
.
id
=
0x10de0002
,
.
name
=
"MCP77/78 HDMI"
,
.
patch
=
patch_nvhdmi_8ch_7x
},
{
.
id
=
0x10de0003
,
.
name
=
"MCP77/78 HDMI"
,
.
patch
=
patch_nvhdmi_8ch_7x
},
{
.
id
=
0x10de0005
,
.
name
=
"MCP77/78 HDMI"
,
.
patch
=
patch_nvhdmi_8ch_7x
},
{
.
id
=
0x10de0006
,
.
name
=
"MCP77/78 HDMI"
,
.
patch
=
patch_nvhdmi_8ch_7x
},
{
.
id
=
0x10de0007
,
.
name
=
"MCP79/7A HDMI"
,
.
patch
=
patch_nvhdmi_8ch_7x
},
{
.
id
=
0x10de000c
,
.
name
=
"MCP89 HDMI"
,
.
patch
=
patch_nvhdmi_8ch_89
},
{
.
id
=
0x10de000b
,
.
name
=
"GT21x HDMI"
,
.
patch
=
patch_nvhdmi_8ch_89
},
{
.
id
=
0x10de000d
,
.
name
=
"GT240 HDMI"
,
.
patch
=
patch_nvhdmi_8ch_89
},
{}
/* terminator */
};
...
...
@@ -412,9 +566,12 @@ MODULE_ALIAS("snd-hda-codec-id:10de0006");
MODULE_ALIAS
(
"snd-hda-codec-id:10de0007"
);
MODULE_ALIAS
(
"snd-hda-codec-id:10de0067"
);
MODULE_ALIAS
(
"snd-hda-codec-id:10de8001"
);
MODULE_ALIAS
(
"snd-hda-codec-id:10de000c"
);
MODULE_ALIAS
(
"snd-hda-codec-id:10de000b"
);
MODULE_ALIAS
(
"snd-hda-codec-id:10de000d"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_DESCRIPTION
(
"N
vidia
HDMI HD-audio codec"
);
MODULE_DESCRIPTION
(
"N
VIDIA
HDMI HD-audio codec"
);
static
struct
hda_codec_preset_list
nvhdmi_list
=
{
.
preset
=
snd_hda_preset_nvhdmi
,
...
...
sound/pci/hda/patch_realtek.c
View file @
f1cf9a66
...
...
@@ -4915,7 +4915,7 @@ static void fixup_automic_adc(struct hda_codec *codec)
static
void
fixup_single_adc
(
struct
hda_codec
*
codec
)
{
struct
alc_spec
*
spec
=
codec
->
spec
;
hda_nid_t
pin
;
hda_nid_t
pin
=
0
;
int
i
;
/* search for the input pin; there must be only one */
...
...
@@ -13561,6 +13561,8 @@ static void alc269_lifebook_unsol_event(struct hda_codec *codec,
static
void
alc269_quanta_fl1_setup
(
struct
hda_codec
*
codec
)
{
struct
alc_spec
*
spec
=
codec
->
spec
;
spec
->
autocfg
.
hp_pins
[
0
]
=
0x15
;
spec
->
autocfg
.
speaker_pins
[
0
]
=
0x14
;
spec
->
ext_mic
.
pin
=
0x18
;
spec
->
ext_mic
.
mux_idx
=
0
;
spec
->
int_mic
.
pin
=
0x19
;
...
...
@@ -13656,6 +13658,8 @@ static void alc269_laptop_unsol_event(struct hda_codec *codec,
static
void
alc269_laptop_dmic_setup
(
struct
hda_codec
*
codec
)
{
struct
alc_spec
*
spec
=
codec
->
spec
;
spec
->
autocfg
.
hp_pins
[
0
]
=
0x15
;
spec
->
autocfg
.
speaker_pins
[
0
]
=
0x14
;
spec
->
ext_mic
.
pin
=
0x18
;
spec
->
ext_mic
.
mux_idx
=
0
;
spec
->
int_mic
.
pin
=
0x12
;
...
...
@@ -13666,6 +13670,8 @@ static void alc269_laptop_dmic_setup(struct hda_codec *codec)
static
void
alc269vb_laptop_dmic_setup
(
struct
hda_codec
*
codec
)
{
struct
alc_spec
*
spec
=
codec
->
spec
;
spec
->
autocfg
.
hp_pins
[
0
]
=
0x15
;
spec
->
autocfg
.
speaker_pins
[
0
]
=
0x14
;
spec
->
ext_mic
.
pin
=
0x18
;
spec
->
ext_mic
.
mux_idx
=
0
;
spec
->
int_mic
.
pin
=
0x12
;
...
...
@@ -13676,6 +13682,8 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
static
void
alc269_laptop_amic_setup
(
struct
hda_codec
*
codec
)
{
struct
alc_spec
*
spec
=
codec
->
spec
;
spec
->
autocfg
.
hp_pins
[
0
]
=
0x15
;
spec
->
autocfg
.
speaker_pins
[
0
]
=
0x14
;
spec
->
ext_mic
.
pin
=
0x18
;
spec
->
ext_mic
.
mux_idx
=
0
;
spec
->
int_mic
.
pin
=
0x19
;
...
...
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