Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci/hdaudio PR# kern/45701: hdaudio stops working af...



details:   https://anonhg.NetBSD.org/src/rev/5ff30f07d250
branches:  trunk
changeset: 771955:5ff30f07d250
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sun Dec 11 15:13:58 2011 +0000

description:
PR# kern/45701: hdaudio stops working after suspend/resume and then detach/reattach

restore BIOS pin widget config on detach, and selected pin widget config on
resume

diffstat:

 sys/dev/pci/hdaudio/hdafg.c |  58 ++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 55 insertions(+), 3 deletions(-)

diffs (128 lines):

diff -r 3c4b71e1a537 -r 5ff30f07d250 sys/dev/pci/hdaudio/hdafg.c
--- a/sys/dev/pci/hdaudio/hdafg.c       Sun Dec 11 14:59:24 2011 +0000
+++ b/sys/dev/pci/hdaudio/hdafg.c       Sun Dec 11 15:13:58 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: hdafg.c,v 1.11 2011/11/23 23:07:36 jmcneill Exp $ */
+/* $NetBSD: hdafg.c,v 1.12 2011/12/11 15:13:58 jmcneill Exp $ */
 
 /*
  * Copyright (c) 2009 Precedence Technologies Ltd <support%precedence.co.uk@localhost>
@@ -60,7 +60,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hdafg.c,v 1.11 2011/11/23 23:07:36 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hdafg.c,v 1.12 2011/12/11 15:13:58 jmcneill Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -241,6 +241,7 @@
        } w_p;
        struct {
                uint32_t                config;
+               uint32_t                biosconfig;
                uint32_t                cap;
                uint32_t                ctrl;
        } w_pin;
@@ -552,6 +553,36 @@
        }
 }
 
+static void
+hdafg_widget_setconfig(struct hdaudio_widget *w)
+{
+       struct hdafg_softc *sc = w->w_afg;
+
+       hdaudio_command(sc->sc_codec, w->w_nid,
+           CORB_SET_CONFIGURATION_DEFAULT_1, w->w_pin.config & 0xff);
+       hdaudio_command(sc->sc_codec, w->w_nid,
+           CORB_SET_CONFIGURATION_DEFAULT_2, (w->w_pin.config >> 8) & 0xff);
+       hdaudio_command(sc->sc_codec, w->w_nid,
+           CORB_SET_CONFIGURATION_DEFAULT_3, (w->w_pin.config >> 16) & 0xff);
+       hdaudio_command(sc->sc_codec, w->w_nid,
+           CORB_SET_CONFIGURATION_DEFAULT_4, (w->w_pin.config >> 24) & 0xff);
+}
+
+static void
+hdafg_widget_setbiosconfig(struct hdaudio_widget *w)
+{
+       struct hdafg_softc *sc = w->w_afg;
+
+       hdaudio_command(sc->sc_codec, w->w_nid,
+           CORB_SET_CONFIGURATION_DEFAULT_1, w->w_pin.biosconfig & 0xff);
+       hdaudio_command(sc->sc_codec, w->w_nid,
+           CORB_SET_CONFIGURATION_DEFAULT_2, (w->w_pin.biosconfig >> 8) & 0xff);
+       hdaudio_command(sc->sc_codec, w->w_nid,
+           CORB_SET_CONFIGURATION_DEFAULT_3, (w->w_pin.biosconfig >> 16) & 0xff);
+       hdaudio_command(sc->sc_codec, w->w_nid,
+           CORB_SET_CONFIGURATION_DEFAULT_4, (w->w_pin.biosconfig >> 24) & 0xff);
+}
+
 static uint32_t
 hdafg_widget_getconfig(struct hdaudio_widget *w)
 {
@@ -593,6 +624,8 @@
 
        w->w_pin.cap = hda_get_wparam(w, PIN_CAPABILITIES);
        w->w_pin.config = hdafg_widget_getconfig(w);
+       w->w_pin.biosconfig = hdaudio_command(sc->sc_codec, w->w_nid,
+           CORB_GET_CONFIGURATION_DEFAULT, 0);
        w->w_pin.ctrl = hdaudio_command(sc->sc_codec, w->w_nid,
            CORB_GET_PIN_WIDGET_CONTROL, 0);
 
@@ -732,6 +765,7 @@
                break;
        case COP_AWCAP_TYPE_PIN_COMPLEX:
                hdafg_widget_pin_parse(w);
+               hdafg_widget_setconfig(w);
                break;
        }
 }
@@ -3698,6 +3732,7 @@
        struct hdaudio_assoc *as = sc->sc_assocs;
        struct hdaudio_control *ctl = sc->sc_ctls;
        struct hdaudio_mixer *mx = sc->sc_mixers;
+       int nid;
 
        callout_halt(&sc->sc_jack_callout, NULL);
        callout_destroy(&sc->sc_jack_callout);
@@ -3712,6 +3747,15 @@
                hdaudio_stream_disestablish(sc->sc_audiodev.ad_playback);
        if (sc->sc_audiodev.ad_capture)
                hdaudio_stream_disestablish(sc->sc_audiodev.ad_capture);
+
+       /* restore bios pin widget configuration */
+       for (nid = sc->sc_startnode; nid < sc->sc_endnode; nid++) {
+               w = hdafg_widget_lookup(sc, nid);               
+               if (w == NULL || w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
+                       continue;
+               hdafg_widget_setbiosconfig(w);
+       }
+
        if (w)
                kmem_free(w, sc->sc_nwidgets * sizeof(*w));
        if (as)
@@ -3752,14 +3796,22 @@
 hdafg_resume(device_t self, const pmf_qual_t *qual)
 {
        struct hdafg_softc *sc = device_private(self);
+       struct hdaudio_widget *w;
        int nid;
 
        hdaudio_command(sc->sc_codec, sc->sc_nid,
            CORB_SET_POWER_STATE, COP_POWER_STATE_D0);
        hda_delay(100);
-       for (nid = sc->sc_startnode; nid < sc->sc_endnode; nid++)
+       for (nid = sc->sc_startnode; nid < sc->sc_endnode; nid++) {
                hdaudio_command(sc->sc_codec, nid,
                    CORB_SET_POWER_STATE, COP_POWER_STATE_D0);
+               w = hdafg_widget_lookup(sc, nid);               
+
+               /* restore pin widget configuration */
+               if (w == NULL || w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
+                       continue;
+               hdafg_widget_setconfig(w);
+       }
        hda_delay(1000);
 
        hdafg_commit(sc);



Home | Main Index | Thread Index | Old Index