At Fri, 14 Jun 2013 23:20:29 +0800, Wang Xingchao wrote: > > ALSA side use these apis to know display audio routing map > in gfx side. And use the API to disable unused pin's audio output. Adding more and more such exported functions doesn't look scaling. Better to define an ops struct and export it. Takashi > > Signed-off-by: Wang Xingchao <xingchao.wang at linux.intel.com> > --- > sound/pci/hda/hda_i915.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++ > sound/pci/hda/hda_i915.h | 4 +++ > sound/pci/hda/patch_hdmi.c | 20 +++++++++-- > 3 files changed, 104 insertions(+), 3 deletions(-) > > diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c > index 76c13d5..7ac446f 100644 > --- a/sound/pci/hda/hda_i915.c > +++ b/sound/pci/hda/hda_i915.c > @@ -22,9 +22,73 @@ > #include <drm/i915_powerwell.h> > #include "hda_i915.h" > > +/* Haswell power well */ > static void (*get_power)(void); > static void (*put_power)(void); > > +/* Haswell audio routing */ > +static int (*get_using_pipe)(int); > +static int (*disable_unused_pipe)(int, int *); > +static int (*restore_eld)(void); > + > +#define i915_pipe_name(p) ((p) + 'A') > + > +static int busy_pins[3] = {0, 0, 0}; > + > +int hdmi_disable_unused_pipe(int pin_idx, int pipe_idx) > +{ > + busy_pins[pin_idx] = 1; > + if (disable_unused_pipe) > + disable_unused_pipe(pipe_idx, busy_pins); > + > + return 0; > +} > +EXPORT_SYMBOL(hdmi_disable_unused_pipe); > + > +void hdmi_restore_pineld(int pin_idx) > +{ > + busy_pins[pin_idx] = 0; > + if (restore_eld) > + restore_eld(); > +} > +EXPORT_SYMBOL(hdmi_restore_pineld); > + > +int hdmi_get_using_pipe(int pin_idx) > +{ > + int pipe = -1; > + > + if (get_using_pipe) > + pipe = get_using_pipe(pin_idx); > + > + if (pipe != -1) > + snd_printd("HDMI: pin %d get using pipe %c\n", pin_idx, i915_pipe_name(pipe)); > + > + return pipe; > +} > +EXPORT_SYMBOL(hdmi_get_using_pipe); > + > +static int init_audio_routing(void) > +{ > + get_using_pipe = symbol_request(i915_using_pipe); > + if (!get_using_pipe) > + return -ENODEV; > + > + disable_unused_pipe = symbol_request(i915_disable_pipe); > + if (!disable_unused_pipe) { > + get_using_pipe = NULL; > + return -ENODEV; > + } > + > + restore_eld = symbol_request(i915_restore_pineld); > + if (!restore_eld) { > + restore_eld = NULL; > + get_using_pipe = NULL; > + return -ENODEV; > + } > + > + return 0; > +} > + > void hda_display_power(bool enable) > { > if (!get_power || !put_power) > @@ -57,6 +121,10 @@ int hda_i915_init(void) > > snd_printd("HDA driver get symbol successfully from i915 module\n"); > > + err = init_audio_routing(); > + if (err < 0) > + snd_printd("HDA driver get audior routing APIs failed!\n"); > + > return err; > } > > @@ -71,5 +139,20 @@ int hda_i915_exit(void) > put_power = NULL; > } > > + if (get_using_pipe) { > + symbol_put(get_using_pipe); > + get_using_pipe = NULL; > + } > + > + if (disable_unused_pipe) { > + symbol_put(disable_unused_pipe); > + disable_unused_pipe = NULL; > + } > + > + if (restore_eld) { > + symbol_put(restore_eld); > + restore_eld = NULL; > + } > + > return 0; > } > diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h > index 5a63da2..52d6f09 100644 > --- a/sound/pci/hda/hda_i915.h > +++ b/sound/pci/hda/hda_i915.h > @@ -32,4 +32,8 @@ static inline int hda_i915_exit(void) > } > #endif > > +extern int hdmi_get_using_pipe(int pin_idx); > +extern int hdmi_disable_unused_pipe(int pin_idx, int pipe_idx); > +extern void hdmi_restore_pineld(int pin_idx); > + > #endif > diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c > index d766f40..2a1e977 100644 > --- a/sound/pci/hda/patch_hdmi.c > +++ b/sound/pci/hda/patch_hdmi.c > @@ -39,6 +39,7 @@ > #include "hda_codec.h" > #include "hda_local.h" > #include "hda_jack.h" > +#include "hda_i915.h" > > static bool static_hdmi_pcm; > module_param(static_hdmi_pcm, bool, 0644); > @@ -1131,6 +1132,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, > struct hdmi_spec_per_pin *per_pin; > struct hdmi_eld *eld; > struct hdmi_spec_per_cvt *per_cvt = NULL; > + int pipe_idx; > > /* Validate hinfo */ > pin_idx = hinfo_to_pin_index(spec, hinfo); > @@ -1139,12 +1141,21 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, > per_pin = get_pin(spec, pin_idx); > eld = &per_pin->sink_eld; > > + if (codec->vendor_id == 0x80862807) { > + hsw_verify_cvt_D0(spec, codec); > + > + pipe_idx = hdmi_get_using_pipe(pin_idx); > + if (pipe_idx < 0) > + snd_printdd("HDMI: Pin %d has no valid pipe in use\n", pin_idx); > + else { > + hdmi_disable_unused_pipe(pin_idx, pipe_idx); > + msleep(10); > + } > + } > + > if (!eld->monitor_present || !eld->eld_valid) > return -EIO; > > - if (codec->vendor_id == 0x80862807) > - hsw_verify_cvt_D0(spec, codec); > - > /* Dynamically assign converter to stream */ > for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { > per_cvt = get_cvt(spec, cvt_idx); > @@ -1514,6 +1525,9 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, > snd_hda_spdif_ctls_unassign(codec, pin_idx); > per_pin->chmap_set = false; > memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); > + > + if (codec->vendor_id == 0x80862807) > + hdmi_restore_pineld(pin_idx); > } > > return 0; > -- > 1.8.1.2 >