| @@ -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 | |
3514 | static void | | 3521 | static void |
3515 | hdafg_hp_switch_handler(void *opaque) | | 3522 | hdafg_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 | |
| | | 3594 | static void |
| | | 3595 | hdafg_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 | |
3584 | resched: | | 3613 | kthread_exit(0); |
3585 | callout_schedule(&sc->sc_jack_callout, HDAUDIO_HP_SENSE_PERIOD); | | | |
3586 | } | | 3614 | } |
3587 | | | 3615 | |
3588 | static void | | 3616 | static void |
3589 | hdafg_hp_switch_init(struct hdafg_softc *sc) | | 3617 | hdafg_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 | |
3660 | static void | | 3702 | static void |
3661 | hdafg_attach(device_t parent, device_t self, void *opaque) | | 3703 | hdafg_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 | |
3818 | static int | | 3856 | static int |
3819 | hdafg_detach(device_t self, int flags) | | 3857 | hdafg_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 |
3866 | hdafg_childdet(device_t self, device_t child) | | 3912 | hdafg_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 | |
3874 | static bool | | 3920 | static bool |
3875 | hdafg_suspend(device_t self, const pmf_qual_t *qual) | | 3921 | hdafg_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 | |
3884 | static bool | | 3935 | static bool |
3885 | hdafg_resume(device_t self, const pmf_qual_t *qual) | | 3936 | hdafg_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 | |
3916 | static int | | 3972 | static int |
3917 | hdafg_query_format(void *opaque, audio_format_query_t *afp) | | 3973 | hdafg_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 | |
3924 | static int | | 3980 | static int |