Tue Jul 18 13:35:57 2023 UTC ()
hdafg(4): Do hotplug detection in kthread, not callout.

This can sometimes take a while (~1ms), and the logic to suspend the
callout on device suspend/resume was racy (PR kern/57322).

XXX pullup-8
XXX pullup-9
XXX pullup-10


(riastradh)
diff -r1.29 -r1.30 src/sys/dev/hdaudio/hdafg.c

cvs diff -r1.29 -r1.30 src/sys/dev/hdaudio/hdafg.c (expand / switch to unified diff)

--- src/sys/dev/hdaudio/hdafg.c 2023/01/05 09:57:39 1.29
+++ src/sys/dev/hdaudio/hdafg.c 2023/07/18 13:35:57 1.30
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: hdafg.c,v 1.29 2023/01/05 09:57:39 kardel Exp $ */ 1/* $NetBSD: hdafg.c,v 1.30 2023/07/18 13:35:57 riastradh Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2009 Precedence Technologies Ltd <support@precedence.co.uk> 4 * Copyright (c) 2009 Precedence Technologies Ltd <support@precedence.co.uk>
5 * Copyright (c) 2009-2011 Jared D. McNeill <jmcneill@invisible.ca> 5 * Copyright (c) 2009-2011 Jared D. McNeill <jmcneill@invisible.ca>
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * This code is derived from software contributed to The NetBSD Foundation 8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Precedence Technologies Ltd 9 * by Precedence Technologies Ltd
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -50,37 +50,40 @@ @@ -50,37 +50,40 @@
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE. 59 * SUCH DAMAGE.
60 */ 60 */
61 61
62#include <sys/cdefs.h> 62#include <sys/cdefs.h>
63__KERNEL_RCSID(0, "$NetBSD: hdafg.c,v 1.29 2023/01/05 09:57:39 kardel Exp $"); 63__KERNEL_RCSID(0, "$NetBSD: hdafg.c,v 1.30 2023/07/18 13:35:57 riastradh Exp $");
64 64
65#include <sys/types.h> 65#include <sys/types.h>
66#include <sys/param.h> 66#include <sys/param.h>
67#include <sys/systm.h> 67#include <sys/systm.h>
68#include <sys/kernel.h> 68#include <sys/kernel.h>
69#include <sys/device.h> 69#include <sys/device.h>
70#include <sys/conf.h> 70#include <sys/conf.h>
71#include <sys/bus.h> 71#include <sys/bus.h>
72#include <sys/kmem.h> 72#include <sys/kmem.h>
73#include <sys/module.h> 73#include <sys/module.h>
 74#include <sys/condvar.h>
 75#include <sys/kthread.h>
 76#include <sys/mutex.h>
74 77
75#include <sys/audioio.h> 78#include <sys/audioio.h>
76#include <dev/audio/audio_if.h> 79#include <dev/audio/audio_if.h>
77 80
78#ifdef _KERNEL_OPT 81#ifdef _KERNEL_OPT
79#include "opt_hdaudio.h" 82#include "opt_hdaudio.h"
80#endif 83#endif
81 84
82#include "hdaudiovar.h" 85#include "hdaudiovar.h"
83#include "hdaudioreg.h" 86#include "hdaudioreg.h"
84#include "hdaudio_mixer.h" 87#include "hdaudio_mixer.h"
85#include "hdaudioio.h" 88#include "hdaudioio.h"
86#include "hdaudio_verbose.h" 89#include "hdaudio_verbose.h"
@@ -301,28 +304,32 @@ struct hdafg_softc { @@ -301,28 +304,32 @@ struct hdafg_softc {
301 int sc_nwidgets; 304 int sc_nwidgets;
302 struct hdaudio_widget *sc_widgets; 305 struct hdaudio_widget *sc_widgets;
303 int sc_nassocs; 306 int sc_nassocs;
304 struct hdaudio_assoc *sc_assocs; 307 struct hdaudio_assoc *sc_assocs;
305 int sc_nctls; 308 int sc_nctls;
306 struct hdaudio_control *sc_ctls; 309 struct hdaudio_control *sc_ctls;
307 int sc_nmixers; 310 int sc_nmixers;
308 struct hdaudio_mixer *sc_mixers; 311 struct hdaudio_mixer *sc_mixers;
309 bool sc_has_beepgen; 312 bool sc_has_beepgen;
310 313
311 int sc_pchan, sc_rchan; 314 int sc_pchan, sc_rchan;
312 audio_params_t sc_pparam, sc_rparam; 315 audio_params_t sc_pparam, sc_rparam;
313 316
314 struct callout sc_jack_callout; 317 kmutex_t sc_jack_lock;
 318 kcondvar_t sc_jack_cv;
 319 struct lwp *sc_jack_thread;
315 bool sc_jack_polling; 320 bool sc_jack_polling;
 321 bool sc_jack_suspended;
 322 bool sc_jack_dying;
316 323
317 struct { 324 struct {
318 uint32_t afg_cap; 325 uint32_t afg_cap;
319 uint32_t pcm_size_rate; 326 uint32_t pcm_size_rate;
320 uint32_t stream_format; 327 uint32_t stream_format;
321 uint32_t outamp_cap; 328 uint32_t outamp_cap;
322 uint32_t inamp_cap; 329 uint32_t inamp_cap;
323 uint32_t power_states; 330 uint32_t power_states;
324 uint32_t gpio_cnt; 331 uint32_t gpio_cnt;
325 } sc_p; 332 } sc_p;
326 333
327 struct hdaudio_audiodev sc_audiodev; 334 struct hdaudio_audiodev sc_audiodev;
328 335
@@ -3502,36 +3509,38 @@ hdafg_configure_encodings(struct hdafg_s @@ -3502,36 +3509,38 @@ hdafg_configure_encodings(struct hdafg_s
3502 f.channels = 2; 3509 f.channels = 2;
3503 f.channel_mask = AUFMT_STEREO; 3510 f.channel_mask = AUFMT_STEREO;
3504 f.frequency_type = 0; 3511 f.frequency_type = 0;
3505 f.frequency[0] = f.frequency[1] = sc->sc_fixed_rate ? 3512 f.frequency[0] = f.frequency[1] = sc->sc_fixed_rate ?
3506 sc->sc_fixed_rate : 48000; 3513 sc->sc_fixed_rate : 48000;
3507 f.mode = AUMODE_PLAY|AUMODE_RECORD; 3514 f.mode = AUMODE_PLAY|AUMODE_RECORD;
3508 hdafg_append_formats(&sc->sc_audiodev, &f); 3515 hdafg_append_formats(&sc->sc_audiodev, &f);
3509 } 3516 }
3510 3517
3511 hda_print1(sc, "\n"); 3518 hda_print1(sc, "\n");
3512} 3519}
3513 3520
3514static void 3521static void
3515hdafg_hp_switch_handler(void *opaque) 3522hdafg_hp_switch_handler(struct hdafg_softc *sc)
3516{ 3523{
3517 struct hdafg_softc *sc = opaque; 
3518 struct hdaudio_assoc *as = sc->sc_assocs; 3524 struct hdaudio_assoc *as = sc->sc_assocs;
3519 struct hdaudio_widget *w; 3525 struct hdaudio_widget *w;
3520 uint32_t res = 0; 3526 uint32_t res = 0;
3521 int i, j; 3527 int i, j;
3522 3528
 3529 KASSERT(sc->sc_jack_polling);
 3530 KASSERT(mutex_owned(&sc->sc_jack_lock));
 3531
3523 if (!device_is_active(sc->sc_dev)) 3532 if (!device_is_active(sc->sc_dev))
3524 goto resched; 3533 return;
3525 3534
3526 for (i = 0; i < sc->sc_nassocs; i++) { 3535 for (i = 0; i < sc->sc_nassocs; i++) {
3527 if (as[i].as_digital != HDAFG_AS_ANALOG && 3536 if (as[i].as_digital != HDAFG_AS_ANALOG &&
3528 as[i].as_digital != HDAFG_AS_SPDIF) 3537 as[i].as_digital != HDAFG_AS_SPDIF)
3529 continue; 3538 continue;
3530 for (j = 0; j < HDAUDIO_MAXPINS; j++) { 3539 for (j = 0; j < HDAUDIO_MAXPINS; j++) {
3531 if (as[i].as_pins[j] == 0) 3540 if (as[i].as_pins[j] == 0)
3532 continue; 3541 continue;
3533 w = hdafg_widget_lookup(sc, as[i].as_pins[j]); 3542 w = hdafg_widget_lookup(sc, as[i].as_pins[j]);
3534 if (w == NULL || w->w_enable == false) 3543 if (w == NULL || w->w_enable == false)
3535 continue; 3544 continue;
3536 if (w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX) 3545 if (w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
3537 continue; 3546 continue;
@@ -3570,38 +3579,58 @@ hdafg_hp_switch_handler(void *opaque) @@ -3570,38 +3579,58 @@ hdafg_hp_switch_handler(void *opaque)
3570 case COP_DEVICE_AUX: 3579 case COP_DEVICE_AUX:
3571 if (res & COP_GET_PIN_SENSE_PRESENSE_DETECT) 3580 if (res & COP_GET_PIN_SENSE_PRESENSE_DETECT)
3572 w->w_pin.ctrl &= ~COP_PWC_OUT_ENABLE; 3581 w->w_pin.ctrl &= ~COP_PWC_OUT_ENABLE;
3573 else 3582 else
3574 w->w_pin.ctrl |= COP_PWC_OUT_ENABLE; 3583 w->w_pin.ctrl |= COP_PWC_OUT_ENABLE;
3575 hdaudio_command(sc->sc_codec, w->w_nid, 3584 hdaudio_command(sc->sc_codec, w->w_nid,
3576 CORB_SET_PIN_WIDGET_CONTROL, w->w_pin.ctrl); 3585 CORB_SET_PIN_WIDGET_CONTROL, w->w_pin.ctrl);
3577 break; 3586 break;
3578 default: 3587 default:
3579 break; 3588 break;
3580 } 3589 }
3581 } 3590 }
3582 } 3591 }
 3592}
 3593
 3594static void
 3595hdafg_hp_switch_thread(void *opaque)
 3596{
 3597 struct hdafg_softc *sc = opaque;
 3598
 3599 KASSERT(sc->sc_jack_polling);
 3600
 3601 mutex_enter(&sc->sc_jack_lock);
 3602 while (!sc->sc_jack_dying) {
 3603 if (sc->sc_jack_suspended) {
 3604 cv_wait(&sc->sc_jack_cv, &sc->sc_jack_lock);
 3605 continue;
 3606 }
 3607 hdafg_hp_switch_handler(sc);
 3608 (void)cv_timedwait(&sc->sc_jack_cv, &sc->sc_jack_lock,
 3609 HDAUDIO_HP_SENSE_PERIOD);
 3610 }
 3611 mutex_exit(&sc->sc_jack_lock);
3583 3612
3584resched: 3613 kthread_exit(0);
3585 callout_schedule(&sc->sc_jack_callout, HDAUDIO_HP_SENSE_PERIOD); 
3586} 3614}
3587 3615
3588static void 3616static void
3589hdafg_hp_switch_init(struct hdafg_softc *sc) 3617hdafg_hp_switch_init(struct hdafg_softc *sc)
3590{ 3618{
3591 struct hdaudio_assoc *as = sc->sc_assocs; 3619 struct hdaudio_assoc *as = sc->sc_assocs;
3592 struct hdaudio_widget *w; 3620 struct hdaudio_widget *w;
3593 bool enable = false; 3621 bool enable = false;
3594 int i, j; 3622 int i, j;
 3623 int error;
3595 3624
3596 for (i = 0; i < sc->sc_nassocs; i++) { 3625 for (i = 0; i < sc->sc_nassocs; i++) {
3597 if (as[i].as_hpredir < 0 && as[i].as_displaydev == false) 3626 if (as[i].as_hpredir < 0 && as[i].as_displaydev == false)
3598 continue; 3627 continue;
3599 if (as[i].as_displaydev == false) 3628 if (as[i].as_displaydev == false)
3600 w = hdafg_widget_lookup(sc, as[i].as_pins[15]); 3629 w = hdafg_widget_lookup(sc, as[i].as_pins[15]);
3601 else { 3630 else {
3602 w = NULL; 3631 w = NULL;
3603 for (j = 0; j < HDAUDIO_MAXPINS; j++) { 3632 for (j = 0; j < HDAUDIO_MAXPINS; j++) {
3604 if (as[i].as_pins[j] == 0) 3633 if (as[i].as_pins[j] == 0)
3605 continue; 3634 continue;
3606 w = hdafg_widget_lookup(sc, as[i].as_pins[j]); 3635 w = hdafg_widget_lookup(sc, as[i].as_pins[j]);
3607 if (w && w->w_enable && 3636 if (w && w->w_enable &&
@@ -3640,55 +3669,64 @@ hdafg_hp_switch_init(struct hdafg_softc  @@ -3640,55 +3669,64 @@ hdafg_hp_switch_init(struct hdafg_softc
3640 } 3669 }
3641 3670
3642 hda_trace(sc, "presence detect [pin=%02X,%s", 3671 hda_trace(sc, "presence detect [pin=%02X,%s",
3643 w->w_nid, 3672 w->w_nid,
3644 (w->w_p.aw_cap & COP_AWCAP_UNSOL_CAPABLE) ? 3673 (w->w_p.aw_cap & COP_AWCAP_UNSOL_CAPABLE) ?
3645 "unsol" : "poll" 3674 "unsol" : "poll"
3646 ); 3675 );
3647 if (w->w_pin.cap & COP_PINCAP_HDMI) 3676 if (w->w_pin.cap & COP_PINCAP_HDMI)
3648 hda_trace1(sc, ",hdmi"); 3677 hda_trace1(sc, ",hdmi");
3649 if (w->w_pin.cap & COP_PINCAP_DP) 3678 if (w->w_pin.cap & COP_PINCAP_DP)
3650 hda_trace1(sc, ",displayport"); 3679 hda_trace1(sc, ",displayport");
3651 hda_trace1(sc, "]\n"); 3680 hda_trace1(sc, "]\n");
3652 } 3681 }
3653 if (enable) { 3682 if (!enable) {
3654 sc->sc_jack_polling = true; 
3655 hdafg_hp_switch_handler(sc); 
3656 } else 
3657 hda_trace(sc, "jack detect not enabled\n"); 3683 hda_trace(sc, "jack detect not enabled\n");
 3684 return;
 3685 }
 3686
 3687 mutex_init(&sc->sc_jack_lock, MUTEX_DEFAULT, IPL_NONE);
 3688 cv_init(&sc->sc_jack_cv, "hdafghp");
 3689 sc->sc_jack_polling = true;
 3690 error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, /*ci*/NULL,
 3691 hdafg_hp_switch_thread, sc, &sc->sc_jack_thread,
 3692 "%s hotplug detect", device_xname(sc->sc_dev));
 3693 if (error) {
 3694 aprint_error_dev(sc->sc_dev, "failed to create hotplug thread:"
 3695 " %d", error);
 3696 sc->sc_jack_polling = false;
 3697 cv_destroy(&sc->sc_jack_cv);
 3698 mutex_destroy(&sc->sc_jack_lock);
 3699 }
3658} 3700}
3659 3701
3660static void 3702static void
3661hdafg_attach(device_t parent, device_t self, void *opaque) 3703hdafg_attach(device_t parent, device_t self, void *opaque)
3662{ 3704{
3663 struct hdafg_softc *sc = device_private(self); 3705 struct hdafg_softc *sc = device_private(self);
3664 audio_params_t defparams; 3706 audio_params_t defparams;
3665 prop_dictionary_t args = opaque; 3707 prop_dictionary_t args = opaque;
3666 uint64_t fgptr = 0; 3708 uint64_t fgptr = 0;
3667 uint32_t astype = 0; 3709 uint32_t astype = 0;
3668 uint8_t nid = 0; 3710 uint8_t nid = 0;
3669 int i; 3711 int i;
3670 bool rv; 3712 bool rv;
3671 3713
3672 aprint_naive("\n"); 3714 aprint_naive("\n");
3673 sc->sc_dev = self; 3715 sc->sc_dev = self;
3674 3716
3675 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 3717 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
3676 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); 3718 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
3677 3719
3678 callout_init(&sc->sc_jack_callout, 0); 
3679 callout_setfunc(&sc->sc_jack_callout, 
3680 hdafg_hp_switch_handler, sc); 
3681 
3682 if (!pmf_device_register(self, hdafg_suspend, hdafg_resume)) 3720 if (!pmf_device_register(self, hdafg_suspend, hdafg_resume))
3683 aprint_error_dev(self, "couldn't establish power handler\n"); 3721 aprint_error_dev(self, "couldn't establish power handler\n");
3684 3722
3685 sc->sc_config = prop_dictionary_get(args, "pin-config"); 3723 sc->sc_config = prop_dictionary_get(args, "pin-config");
3686 if (sc->sc_config && prop_object_type(sc->sc_config) != PROP_TYPE_ARRAY) 3724 if (sc->sc_config && prop_object_type(sc->sc_config) != PROP_TYPE_ARRAY)
3687 sc->sc_config = NULL; 3725 sc->sc_config = NULL;
3688 3726
3689 prop_dictionary_get_uint16(args, "vendor-id", &sc->sc_vendor); 3727 prop_dictionary_get_uint16(args, "vendor-id", &sc->sc_vendor);
3690 prop_dictionary_get_uint16(args, "product-id", &sc->sc_product); 3728 prop_dictionary_get_uint16(args, "product-id", &sc->sc_product);
3691 hdaudio_findvendor(sc->sc_name, sizeof(sc->sc_name), sc->sc_vendor); 3729 hdaudio_findvendor(sc->sc_name, sizeof(sc->sc_name), sc->sc_vendor);
3692 hdaudio_findproduct(sc->sc_version, sizeof(sc->sc_version), sc->sc_vendor, 3730 hdaudio_findproduct(sc->sc_version, sizeof(sc->sc_version), sc->sc_vendor,
3693 sc->sc_product); 3731 sc->sc_product);
3694 hda_print1(sc, ": %s %s%s\n", sc->sc_name, sc->sc_version, 3732 hda_print1(sc, ": %s %s%s\n", sc->sc_name, sc->sc_version,
@@ -3815,28 +3853,36 @@ hdafg_attach(device_t parent, device_t s @@ -3815,28 +3853,36 @@ hdafg_attach(device_t parent, device_t s
3815 &sc->sc_audiodev, self); 3853 &sc->sc_audiodev, self);
3816} 3854}
3817 3855
3818static int 3856static int
3819hdafg_detach(device_t self, int flags) 3857hdafg_detach(device_t self, int flags)
3820{ 3858{
3821 struct hdafg_softc *sc = device_private(self); 3859 struct hdafg_softc *sc = device_private(self);
3822 struct hdaudio_widget *wl, *w = sc->sc_widgets; 3860 struct hdaudio_widget *wl, *w = sc->sc_widgets;
3823 struct hdaudio_assoc *as = sc->sc_assocs; 3861 struct hdaudio_assoc *as = sc->sc_assocs;
3824 struct hdaudio_control *ctl = sc->sc_ctls; 3862 struct hdaudio_control *ctl = sc->sc_ctls;
3825 struct hdaudio_mixer *mx = sc->sc_mixers; 3863 struct hdaudio_mixer *mx = sc->sc_mixers;
3826 int nid; 3864 int nid;
3827 3865
3828 callout_halt(&sc->sc_jack_callout, NULL); 3866 if (sc->sc_jack_polling) {
3829 callout_destroy(&sc->sc_jack_callout); 3867 int error __diagused;
 3868
 3869 mutex_enter(&sc->sc_jack_lock);
 3870 sc->sc_jack_dying = true;
 3871 cv_broadcast(&sc->sc_jack_cv);
 3872 mutex_exit(&sc->sc_jack_lock);
 3873 error = kthread_join(sc->sc_jack_thread);
 3874 KASSERTMSG(error == 0, "error=%d", error);
 3875 }
3830 3876
3831 if (sc->sc_config) 3877 if (sc->sc_config)
3832 prop_object_release(sc->sc_config); 3878 prop_object_release(sc->sc_config);
3833 if (sc->sc_audiodev.ad_audiodev) 3879 if (sc->sc_audiodev.ad_audiodev)
3834 config_detach(sc->sc_audiodev.ad_audiodev, flags); 3880 config_detach(sc->sc_audiodev.ad_audiodev, flags);
3835 if (sc->sc_audiodev.ad_playback) 3881 if (sc->sc_audiodev.ad_playback)
3836 hdaudio_stream_disestablish(sc->sc_audiodev.ad_playback); 3882 hdaudio_stream_disestablish(sc->sc_audiodev.ad_playback);
3837 if (sc->sc_audiodev.ad_capture) 3883 if (sc->sc_audiodev.ad_capture)
3838 hdaudio_stream_disestablish(sc->sc_audiodev.ad_capture); 3884 hdaudio_stream_disestablish(sc->sc_audiodev.ad_capture);
3839 3885
3840 /* restore bios pin widget configuration */ 3886 /* restore bios pin widget configuration */
3841 for (nid = sc->sc_startnode; nid < sc->sc_endnode; nid++) { 3887 for (nid = sc->sc_startnode; nid < sc->sc_endnode; nid++) {
3842 wl = hdafg_widget_lookup(sc, nid); 3888 wl = hdafg_widget_lookup(sc, nid);
@@ -3866,27 +3912,32 @@ static void @@ -3866,27 +3912,32 @@ static void
3866hdafg_childdet(device_t self, device_t child) 3912hdafg_childdet(device_t self, device_t child)
3867{ 3913{
3868 struct hdafg_softc *sc = device_private(self); 3914 struct hdafg_softc *sc = device_private(self);
3869 3915
3870 if (child == sc->sc_audiodev.ad_audiodev) 3916 if (child == sc->sc_audiodev.ad_audiodev)
3871 sc->sc_audiodev.ad_audiodev = NULL; 3917 sc->sc_audiodev.ad_audiodev = NULL;
3872} 3918}
3873 3919
3874static bool 3920static bool
3875hdafg_suspend(device_t self, const pmf_qual_t *qual) 3921hdafg_suspend(device_t self, const pmf_qual_t *qual)
3876{ 3922{
3877 struct hdafg_softc *sc = device_private(self); 3923 struct hdafg_softc *sc = device_private(self);
3878 3924
3879 callout_halt(&sc->sc_jack_callout, NULL); 3925 if (sc->sc_jack_polling) {
 3926 mutex_enter(&sc->sc_jack_lock);
 3927 KASSERT(!sc->sc_jack_suspended);
 3928 sc->sc_jack_suspended = true;
 3929 mutex_exit(&sc->sc_jack_lock);
 3930 }
3880 3931
3881 return true; 3932 return true;
3882} 3933}
3883 3934
3884static bool 3935static bool
3885hdafg_resume(device_t self, const pmf_qual_t *qual) 3936hdafg_resume(device_t self, const pmf_qual_t *qual)
3886{ 3937{
3887 struct hdafg_softc *sc = device_private(self); 3938 struct hdafg_softc *sc = device_private(self);
3888 struct hdaudio_widget *w; 3939 struct hdaudio_widget *w;
3889 int nid; 3940 int nid;
3890 3941
3891 hdaudio_command(sc->sc_codec, sc->sc_nid, 3942 hdaudio_command(sc->sc_codec, sc->sc_nid,
3892 CORB_SET_POWER_STATE, COP_POWER_STATE_D0); 3943 CORB_SET_POWER_STATE, COP_POWER_STATE_D0);
@@ -3897,28 +3948,33 @@ hdafg_resume(device_t self, const pmf_qu @@ -3897,28 +3948,33 @@ hdafg_resume(device_t self, const pmf_qu
3897 w = hdafg_widget_lookup(sc, nid); 3948 w = hdafg_widget_lookup(sc, nid);
3898 3949
3899 /* restore pin widget configuration */ 3950 /* restore pin widget configuration */
3900 if (w == NULL || w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX) 3951 if (w == NULL || w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
3901 continue; 3952 continue;
3902 hdafg_widget_setconfig(w, w->w_pin.config); 3953 hdafg_widget_setconfig(w, w->w_pin.config);
3903 } 3954 }
3904 hda_delay(1000); 3955 hda_delay(1000);
3905 3956
3906 hdafg_commit(sc); 3957 hdafg_commit(sc);
3907 hdafg_stream_connect(sc, AUMODE_PLAY); 3958 hdafg_stream_connect(sc, AUMODE_PLAY);
3908 hdafg_stream_connect(sc, AUMODE_RECORD); 3959 hdafg_stream_connect(sc, AUMODE_RECORD);
3909 3960
3910 if (sc->sc_jack_polling) 3961 if (sc->sc_jack_polling) {
3911 hdafg_hp_switch_handler(sc); 3962 mutex_enter(&sc->sc_jack_lock);
 3963 KASSERT(sc->sc_jack_suspended);
 3964 sc->sc_jack_suspended = false;
 3965 cv_broadcast(&sc->sc_jack_cv);
 3966 mutex_exit(&sc->sc_jack_lock);
 3967 }
3912 3968
3913 return true; 3969 return true;
3914} 3970}
3915 3971
3916static int 3972static int
3917hdafg_query_format(void *opaque, audio_format_query_t *afp) 3973hdafg_query_format(void *opaque, audio_format_query_t *afp)
3918{ 3974{
3919 struct hdaudio_audiodev *ad = opaque; 3975 struct hdaudio_audiodev *ad = opaque;
3920 3976
3921 return audio_query_format(ad->ad_formats, ad->ad_nformats, afp); 3977 return audio_query_format(ad->ad_formats, ad->ad_nformats, afp);
3922} 3978}
3923 3979
3924static int 3980static int