184659b24SMichael Zeller /*-
2*32640292SAndy Fiddaman * SPDX-License-Identifier: BSD-2-Clause
384659b24SMichael Zeller *
484659b24SMichael Zeller * Copyright (c) 2016 Alex Teaca <iateaca@FreeBSD.org>
584659b24SMichael Zeller * All rights reserved.
684659b24SMichael Zeller *
784659b24SMichael Zeller * Redistribution and use in source and binary forms, with or without
884659b24SMichael Zeller * modification, are permitted provided that the following conditions
984659b24SMichael Zeller * are met:
1084659b24SMichael Zeller * 1. Redistributions of source code must retain the above copyright
1184659b24SMichael Zeller * notice, this list of conditions and the following disclaimer.
1284659b24SMichael Zeller * 2. Redistributions in binary form must reproduce the above copyright
1384659b24SMichael Zeller * notice, this list of conditions and the following disclaimer in the
1484659b24SMichael Zeller * documentation and/or other materials provided with the distribution.
1584659b24SMichael Zeller *
1684659b24SMichael Zeller * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
1784659b24SMichael Zeller * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1884659b24SMichael Zeller * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1984659b24SMichael Zeller * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2084659b24SMichael Zeller * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2184659b24SMichael Zeller * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2284659b24SMichael Zeller * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2384659b24SMichael Zeller * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2484659b24SMichael Zeller * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2584659b24SMichael Zeller * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2684659b24SMichael Zeller * SUCH DAMAGE.
2784659b24SMichael Zeller *
2884659b24SMichael Zeller */
2984659b24SMichael Zeller
3084659b24SMichael Zeller #include <sys/cdefs.h>
3184659b24SMichael Zeller
3284659b24SMichael Zeller #include <pthread.h>
3384659b24SMichael Zeller #include <pthread_np.h>
3484659b24SMichael Zeller #include <unistd.h>
3584659b24SMichael Zeller
3684659b24SMichael Zeller #include "pci_hda.h"
3784659b24SMichael Zeller #include "audio.h"
3884659b24SMichael Zeller
3984659b24SMichael Zeller /*
4084659b24SMichael Zeller * HDA Codec defines
4184659b24SMichael Zeller */
4284659b24SMichael Zeller #define INTEL_VENDORID 0x8086
4384659b24SMichael Zeller
4484659b24SMichael Zeller #define HDA_CODEC_SUBSYSTEM_ID ((INTEL_VENDORID << 16) | 0x01)
4584659b24SMichael Zeller #define HDA_CODEC_ROOT_NID 0x00
4684659b24SMichael Zeller #define HDA_CODEC_FG_NID 0x01
4784659b24SMichael Zeller #define HDA_CODEC_AUDIO_OUTPUT_NID 0x02
4884659b24SMichael Zeller #define HDA_CODEC_PIN_OUTPUT_NID 0x03
4984659b24SMichael Zeller #define HDA_CODEC_AUDIO_INPUT_NID 0x04
5084659b24SMichael Zeller #define HDA_CODEC_PIN_INPUT_NID 0x05
5184659b24SMichael Zeller
5284659b24SMichael Zeller #define HDA_CODEC_STREAMS_COUNT 0x02
5384659b24SMichael Zeller #define HDA_CODEC_STREAM_OUTPUT 0x00
5484659b24SMichael Zeller #define HDA_CODEC_STREAM_INPUT 0x01
5584659b24SMichael Zeller
5684659b24SMichael Zeller #define HDA_CODEC_PARAMS_COUNT 0x14
5784659b24SMichael Zeller #define HDA_CODEC_CONN_LIST_COUNT 0x01
5884659b24SMichael Zeller #define HDA_CODEC_RESPONSE_EX_UNSOL 0x10
5984659b24SMichael Zeller #define HDA_CODEC_RESPONSE_EX_SOL 0x00
6084659b24SMichael Zeller #define HDA_CODEC_AMP_NUMSTEPS 0x4a
6184659b24SMichael Zeller
6284659b24SMichael Zeller #define HDA_CODEC_SUPP_STREAM_FORMATS_PCM \
6384659b24SMichael Zeller (1 << HDA_PARAM_SUPP_STREAM_FORMATS_PCM_SHIFT)
6484659b24SMichael Zeller
6584659b24SMichael Zeller #define HDA_CODEC_FMT_BASE_MASK (0x01 << 14)
6684659b24SMichael Zeller
6784659b24SMichael Zeller #define HDA_CODEC_FMT_MULT_MASK (0x07 << 11)
6884659b24SMichael Zeller #define HDA_CODEC_FMT_MULT_2 (0x01 << 11)
6984659b24SMichael Zeller #define HDA_CODEC_FMT_MULT_3 (0x02 << 11)
7084659b24SMichael Zeller #define HDA_CODEC_FMT_MULT_4 (0x03 << 11)
7184659b24SMichael Zeller
7284659b24SMichael Zeller #define HDA_CODEC_FMT_DIV_MASK 0x07
7384659b24SMichael Zeller #define HDA_CODEC_FMT_DIV_SHIFT 8
7484659b24SMichael Zeller
7584659b24SMichael Zeller #define HDA_CODEC_FMT_BITS_MASK (0x07 << 4)
7684659b24SMichael Zeller #define HDA_CODEC_FMT_BITS_8 (0x00 << 4)
7784659b24SMichael Zeller #define HDA_CODEC_FMT_BITS_16 (0x01 << 4)
7884659b24SMichael Zeller #define HDA_CODEC_FMT_BITS_24 (0x03 << 4)
7984659b24SMichael Zeller #define HDA_CODEC_FMT_BITS_32 (0x04 << 4)
8084659b24SMichael Zeller
8184659b24SMichael Zeller #define HDA_CODEC_FMT_CHAN_MASK (0x0f << 0)
8284659b24SMichael Zeller
8384659b24SMichael Zeller #define HDA_CODEC_AUDIO_WCAP_OUTPUT \
8484659b24SMichael Zeller (0x00 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT)
8584659b24SMichael Zeller #define HDA_CODEC_AUDIO_WCAP_INPUT \
8684659b24SMichael Zeller (0x01 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT)
8784659b24SMichael Zeller #define HDA_CODEC_AUDIO_WCAP_PIN \
8884659b24SMichael Zeller (0x04 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT)
8984659b24SMichael Zeller #define HDA_CODEC_AUDIO_WCAP_CONN_LIST \
9084659b24SMichael Zeller (1 << HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_SHIFT)
9184659b24SMichael Zeller #define HDA_CODEC_AUDIO_WCAP_FORMAT_OVR \
9284659b24SMichael Zeller (1 << HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_SHIFT)
9384659b24SMichael Zeller #define HDA_CODEC_AUDIO_WCAP_AMP_OVR \
9484659b24SMichael Zeller (1 << HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_SHIFT)
9584659b24SMichael Zeller #define HDA_CODEC_AUDIO_WCAP_OUT_AMP \
9684659b24SMichael Zeller (1 << HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_SHIFT)
9784659b24SMichael Zeller #define HDA_CODEC_AUDIO_WCAP_IN_AMP \
9884659b24SMichael Zeller (1 << HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_SHIFT)
9984659b24SMichael Zeller #define HDA_CODEC_AUDIO_WCAP_STEREO \
10084659b24SMichael Zeller (1 << HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT)
10184659b24SMichael Zeller
10284659b24SMichael Zeller #define HDA_CODEC_PIN_CAP_OUTPUT \
10384659b24SMichael Zeller (1 << HDA_PARAM_PIN_CAP_OUTPUT_CAP_SHIFT)
10484659b24SMichael Zeller #define HDA_CODEC_PIN_CAP_INPUT \
10584659b24SMichael Zeller (1 << HDA_PARAM_PIN_CAP_INPUT_CAP_SHIFT)
10684659b24SMichael Zeller #define HDA_CODEC_PIN_CAP_PRESENCE_DETECT \
10784659b24SMichael Zeller (1 << HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT)
10884659b24SMichael Zeller
10984659b24SMichael Zeller #define HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP \
11084659b24SMichael Zeller (1 << HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_SHIFT)
11184659b24SMichael Zeller #define HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE \
11284659b24SMichael Zeller (0x03 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT)
11384659b24SMichael Zeller #define HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS \
11484659b24SMichael Zeller (HDA_CODEC_AMP_NUMSTEPS << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT)
11584659b24SMichael Zeller #define HDA_CODEC_OUTPUT_AMP_CAP_OFFSET \
11684659b24SMichael Zeller (HDA_CODEC_AMP_NUMSTEPS << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT)
11784659b24SMichael Zeller
11884659b24SMichael Zeller #define HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE 0x80
11984659b24SMichael Zeller #define HDA_CODEC_SET_AMP_GAIN_MUTE_GAIN_MASK 0x7f
12084659b24SMichael Zeller
12184659b24SMichael Zeller #define HDA_CODEC_PIN_SENSE_PRESENCE_PLUGGED (1 << 31)
12284659b24SMichael Zeller #define HDA_CODEC_PIN_WIDGET_CTRL_OUT_ENABLE \
12384659b24SMichael Zeller (1 << HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_SHIFT)
12484659b24SMichael Zeller #define HDA_CODEC_PIN_WIDGET_CTRL_IN_ENABLE \
12584659b24SMichael Zeller (1 << HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_SHIFT)
12684659b24SMichael Zeller
12784659b24SMichael Zeller #define HDA_CONFIG_DEFAULTCONF_COLOR_BLACK \
12884659b24SMichael Zeller (0x01 << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT)
12984659b24SMichael Zeller #define HDA_CONFIG_DEFAULTCONF_COLOR_RED \
13084659b24SMichael Zeller (0x05 << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT)
13184659b24SMichael Zeller
13284659b24SMichael Zeller #define HDA_CODEC_BUF_SIZE HDA_FIFO_SIZE
13384659b24SMichael Zeller
13484659b24SMichael Zeller #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
13584659b24SMichael Zeller
13684659b24SMichael Zeller
13784659b24SMichael Zeller /*
13884659b24SMichael Zeller * HDA Audio Context data structures
13984659b24SMichael Zeller */
14084659b24SMichael Zeller
14184659b24SMichael Zeller typedef void (*transfer_func_t)(void *arg);
14284659b24SMichael Zeller typedef int (*setup_func_t)(void *arg);
14384659b24SMichael Zeller
14484659b24SMichael Zeller struct hda_audio_ctxt {
14584659b24SMichael Zeller char name[64];
14684659b24SMichael Zeller uint8_t run;
14784659b24SMichael Zeller uint8_t started;
14884659b24SMichael Zeller void *priv;
14984659b24SMichael Zeller pthread_t tid;
15084659b24SMichael Zeller pthread_mutex_t mtx;
15184659b24SMichael Zeller pthread_cond_t cond;
15284659b24SMichael Zeller setup_func_t do_setup;
15384659b24SMichael Zeller transfer_func_t do_transfer;
15484659b24SMichael Zeller };
15584659b24SMichael Zeller
15684659b24SMichael Zeller /*
15784659b24SMichael Zeller * HDA Audio Context module function declarations
15884659b24SMichael Zeller */
15984659b24SMichael Zeller
16084659b24SMichael Zeller static void *hda_audio_ctxt_thr(void *arg);
16184659b24SMichael Zeller static int hda_audio_ctxt_init(struct hda_audio_ctxt *actx, const char *tname,
16284659b24SMichael Zeller transfer_func_t do_transfer, setup_func_t do_setup, void *priv);
16384659b24SMichael Zeller static int hda_audio_ctxt_start(struct hda_audio_ctxt *actx);
16484659b24SMichael Zeller static int hda_audio_ctxt_stop(struct hda_audio_ctxt *actx);
16584659b24SMichael Zeller
16684659b24SMichael Zeller /*
16784659b24SMichael Zeller * HDA Codec data structures
16884659b24SMichael Zeller */
16984659b24SMichael Zeller
17084659b24SMichael Zeller struct hda_codec_softc;
17184659b24SMichael Zeller
17284659b24SMichael Zeller typedef uint32_t (*verb_func_t)(struct hda_codec_softc *sc, uint16_t verb,
17384659b24SMichael Zeller uint16_t payload);
17484659b24SMichael Zeller
17584659b24SMichael Zeller struct hda_codec_stream {
17684659b24SMichael Zeller uint8_t buf[HDA_CODEC_BUF_SIZE];
17784659b24SMichael Zeller uint8_t channel;
17884659b24SMichael Zeller uint16_t fmt;
17984659b24SMichael Zeller uint8_t stream;
18084659b24SMichael Zeller
18184659b24SMichael Zeller uint8_t left_gain;
18284659b24SMichael Zeller uint8_t right_gain;
18384659b24SMichael Zeller uint8_t left_mute;
18484659b24SMichael Zeller uint8_t right_mute;
18584659b24SMichael Zeller
18684659b24SMichael Zeller struct audio *aud;
18784659b24SMichael Zeller struct hda_audio_ctxt actx;
18884659b24SMichael Zeller };
18984659b24SMichael Zeller
19084659b24SMichael Zeller struct hda_codec_softc {
19184659b24SMichael Zeller uint32_t no_nodes;
19284659b24SMichael Zeller uint32_t subsystem_id;
19384659b24SMichael Zeller const uint32_t (*get_parameters)[HDA_CODEC_PARAMS_COUNT];
19484659b24SMichael Zeller const uint8_t (*conn_list)[HDA_CODEC_CONN_LIST_COUNT];
19584659b24SMichael Zeller const uint32_t *conf_default;
19684659b24SMichael Zeller const uint8_t *pin_ctrl_default;
19784659b24SMichael Zeller const verb_func_t *verb_handlers;
19884659b24SMichael Zeller
19984659b24SMichael Zeller struct hda_codec_inst *hci;
20084659b24SMichael Zeller struct hda_codec_stream streams[HDA_CODEC_STREAMS_COUNT];
20184659b24SMichael Zeller };
20284659b24SMichael Zeller
20384659b24SMichael Zeller /*
20484659b24SMichael Zeller * HDA Codec module function declarations
20584659b24SMichael Zeller */
20684659b24SMichael Zeller static int hda_codec_init(struct hda_codec_inst *hci, const char *play,
2072b948146SAndy Fiddaman const char *rec);
20884659b24SMichael Zeller static int hda_codec_reset(struct hda_codec_inst *hci);
20984659b24SMichael Zeller static int hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data);
21084659b24SMichael Zeller static int hda_codec_notify(struct hda_codec_inst *hci, uint8_t run,
21184659b24SMichael Zeller uint8_t stream, uint8_t dir);
21284659b24SMichael Zeller
21384659b24SMichael Zeller static int hda_codec_parse_format(uint16_t fmt, struct audio_params *params);
21484659b24SMichael Zeller
21584659b24SMichael Zeller static uint32_t hda_codec_audio_output_nid(struct hda_codec_softc *sc,
21684659b24SMichael Zeller uint16_t verb, uint16_t payload);
21784659b24SMichael Zeller static void hda_codec_audio_output_do_transfer(void *arg);
21884659b24SMichael Zeller static int hda_codec_audio_output_do_setup(void *arg);
21984659b24SMichael Zeller static uint32_t hda_codec_audio_input_nid(struct hda_codec_softc *sc,
22084659b24SMichael Zeller uint16_t verb, uint16_t payload);
22184659b24SMichael Zeller static void hda_codec_audio_input_do_transfer(void *arg);
22284659b24SMichael Zeller static int hda_codec_audio_input_do_setup(void *arg);
22384659b24SMichael Zeller
22484659b24SMichael Zeller static uint32_t hda_codec_audio_inout_nid(struct hda_codec_stream *st,
22584659b24SMichael Zeller uint16_t verb, uint16_t payload);
22684659b24SMichael Zeller
22784659b24SMichael Zeller /*
22884659b24SMichael Zeller * HDA Codec global data
22984659b24SMichael Zeller */
23084659b24SMichael Zeller
23184659b24SMichael Zeller #define HDA_CODEC_ROOT_DESC \
23284659b24SMichael Zeller [HDA_CODEC_ROOT_NID] = { \
23384659b24SMichael Zeller [HDA_PARAM_VENDOR_ID] = INTEL_VENDORID, \
23484659b24SMichael Zeller [HDA_PARAM_REVISION_ID] = 0xffff, \
23584659b24SMichael Zeller /* 1 Subnode, StartNid = 1 */ \
23684659b24SMichael Zeller [HDA_PARAM_SUB_NODE_COUNT] = 0x00010001, \
23784659b24SMichael Zeller }, \
23884659b24SMichael Zeller
23984659b24SMichael Zeller #define HDA_CODEC_FG_COMMON_DESC \
24084659b24SMichael Zeller [HDA_PARAM_FCT_GRP_TYPE] = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO,\
24184659b24SMichael Zeller /* B8 - B32, 8.0 - 192.0kHz */ \
24284659b24SMichael Zeller [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x1f << 16) | 0x7ff, \
24384659b24SMichael Zeller [HDA_PARAM_SUPP_STREAM_FORMATS] = HDA_CODEC_SUPP_STREAM_FORMATS_PCM,\
24484659b24SMichael Zeller [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \
24584659b24SMichael Zeller [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \
24684659b24SMichael Zeller [HDA_PARAM_GPIO_COUNT] = 0x00, \
24784659b24SMichael Zeller
24884659b24SMichael Zeller #define HDA_CODEC_FG_OUTPUT_DESC \
24984659b24SMichael Zeller [HDA_CODEC_FG_NID] = { \
25084659b24SMichael Zeller /* 2 Subnodes, StartNid = 2 */ \
25184659b24SMichael Zeller [HDA_PARAM_SUB_NODE_COUNT] = 0x00020002, \
25284659b24SMichael Zeller HDA_CODEC_FG_COMMON_DESC \
25384659b24SMichael Zeller }, \
25484659b24SMichael Zeller
25584659b24SMichael Zeller #define HDA_CODEC_FG_INPUT_DESC \
25684659b24SMichael Zeller [HDA_CODEC_FG_NID] = { \
25784659b24SMichael Zeller /* 2 Subnodes, StartNid = 4 */ \
25884659b24SMichael Zeller [HDA_PARAM_SUB_NODE_COUNT] = 0x00040002, \
25984659b24SMichael Zeller HDA_CODEC_FG_COMMON_DESC \
26084659b24SMichael Zeller }, \
26184659b24SMichael Zeller
26284659b24SMichael Zeller #define HDA_CODEC_FG_DUPLEX_DESC \
26384659b24SMichael Zeller [HDA_CODEC_FG_NID] = { \
26484659b24SMichael Zeller /* 4 Subnodes, StartNid = 2 */ \
26584659b24SMichael Zeller [HDA_PARAM_SUB_NODE_COUNT] = 0x00020004, \
26684659b24SMichael Zeller HDA_CODEC_FG_COMMON_DESC \
26784659b24SMichael Zeller }, \
26884659b24SMichael Zeller
26984659b24SMichael Zeller #define HDA_CODEC_OUTPUT_DESC \
27084659b24SMichael Zeller [HDA_CODEC_AUDIO_OUTPUT_NID] = { \
27184659b24SMichael Zeller [HDA_PARAM_AUDIO_WIDGET_CAP] = \
27284659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_OUTPUT | \
27384659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_FORMAT_OVR | \
27484659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_AMP_OVR | \
27584659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_OUT_AMP | \
27684659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_STEREO, \
27784659b24SMichael Zeller /* B16, 16.0 - 192.0kHz */ \
27884659b24SMichael Zeller [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x02 << 16) | 0x7fc, \
27984659b24SMichael Zeller [HDA_PARAM_SUPP_STREAM_FORMATS] = \
28084659b24SMichael Zeller HDA_CODEC_SUPP_STREAM_FORMATS_PCM, \
28184659b24SMichael Zeller [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \
28284659b24SMichael Zeller [HDA_PARAM_CONN_LIST_LENGTH] = 0x00, \
28384659b24SMichael Zeller [HDA_PARAM_OUTPUT_AMP_CAP] = \
28484659b24SMichael Zeller HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP | \
28584659b24SMichael Zeller HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE | \
28684659b24SMichael Zeller HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS | \
28784659b24SMichael Zeller HDA_CODEC_OUTPUT_AMP_CAP_OFFSET, \
28884659b24SMichael Zeller }, \
28984659b24SMichael Zeller [HDA_CODEC_PIN_OUTPUT_NID] = { \
29084659b24SMichael Zeller [HDA_PARAM_AUDIO_WIDGET_CAP] = \
29184659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_PIN | \
29284659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_CONN_LIST | \
29384659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_STEREO, \
29484659b24SMichael Zeller [HDA_PARAM_PIN_CAP] = HDA_CODEC_PIN_CAP_OUTPUT | \
29584659b24SMichael Zeller HDA_CODEC_PIN_CAP_PRESENCE_DETECT,\
29684659b24SMichael Zeller [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \
29784659b24SMichael Zeller [HDA_PARAM_CONN_LIST_LENGTH] = 0x01, \
29884659b24SMichael Zeller [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \
29984659b24SMichael Zeller }, \
30084659b24SMichael Zeller
30184659b24SMichael Zeller #define HDA_CODEC_INPUT_DESC \
30284659b24SMichael Zeller [HDA_CODEC_AUDIO_INPUT_NID] = { \
30384659b24SMichael Zeller [HDA_PARAM_AUDIO_WIDGET_CAP] = \
30484659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_INPUT | \
30584659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_CONN_LIST | \
30684659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_FORMAT_OVR | \
30784659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_AMP_OVR | \
30884659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_IN_AMP | \
30984659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_STEREO, \
31084659b24SMichael Zeller /* B16, 16.0 - 192.0kHz */ \
31184659b24SMichael Zeller [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x02 << 16) | 0x7fc, \
31284659b24SMichael Zeller [HDA_PARAM_SUPP_STREAM_FORMATS] = \
31384659b24SMichael Zeller HDA_CODEC_SUPP_STREAM_FORMATS_PCM, \
31484659b24SMichael Zeller [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \
31584659b24SMichael Zeller [HDA_PARAM_CONN_LIST_LENGTH] = 0x01, \
31684659b24SMichael Zeller [HDA_PARAM_INPUT_AMP_CAP] = \
31784659b24SMichael Zeller HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP | \
31884659b24SMichael Zeller HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE | \
31984659b24SMichael Zeller HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS | \
32084659b24SMichael Zeller HDA_CODEC_OUTPUT_AMP_CAP_OFFSET, \
32184659b24SMichael Zeller }, \
32284659b24SMichael Zeller [HDA_CODEC_PIN_INPUT_NID] = { \
32384659b24SMichael Zeller [HDA_PARAM_AUDIO_WIDGET_CAP] = \
32484659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_PIN | \
32584659b24SMichael Zeller HDA_CODEC_AUDIO_WCAP_STEREO, \
32684659b24SMichael Zeller [HDA_PARAM_PIN_CAP] = HDA_CODEC_PIN_CAP_INPUT | \
32784659b24SMichael Zeller HDA_CODEC_PIN_CAP_PRESENCE_DETECT, \
32884659b24SMichael Zeller [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \
32984659b24SMichael Zeller [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \
33084659b24SMichael Zeller }, \
33184659b24SMichael Zeller
33284659b24SMichael Zeller static const uint32_t
33384659b24SMichael Zeller hda_codec_output_parameters[][HDA_CODEC_PARAMS_COUNT] = {
33484659b24SMichael Zeller HDA_CODEC_ROOT_DESC
33584659b24SMichael Zeller HDA_CODEC_FG_OUTPUT_DESC
33684659b24SMichael Zeller HDA_CODEC_OUTPUT_DESC
33784659b24SMichael Zeller };
33884659b24SMichael Zeller
33984659b24SMichael Zeller static const uint32_t
34084659b24SMichael Zeller hda_codec_input_parameters[][HDA_CODEC_PARAMS_COUNT] = {
34184659b24SMichael Zeller HDA_CODEC_ROOT_DESC
34284659b24SMichael Zeller HDA_CODEC_FG_INPUT_DESC
34384659b24SMichael Zeller HDA_CODEC_INPUT_DESC
34484659b24SMichael Zeller };
34584659b24SMichael Zeller
34684659b24SMichael Zeller static const uint32_t
34784659b24SMichael Zeller hda_codec_duplex_parameters[][HDA_CODEC_PARAMS_COUNT] = {
34884659b24SMichael Zeller HDA_CODEC_ROOT_DESC
34984659b24SMichael Zeller HDA_CODEC_FG_DUPLEX_DESC
35084659b24SMichael Zeller HDA_CODEC_OUTPUT_DESC
35184659b24SMichael Zeller HDA_CODEC_INPUT_DESC
35284659b24SMichael Zeller };
35384659b24SMichael Zeller
35484659b24SMichael Zeller #define HDA_CODEC_NODES_COUNT (ARRAY_SIZE(hda_codec_duplex_parameters))
35584659b24SMichael Zeller
35684659b24SMichael Zeller static const uint8_t
35784659b24SMichael Zeller hda_codec_conn_list[HDA_CODEC_NODES_COUNT][HDA_CODEC_CONN_LIST_COUNT] = {
35884659b24SMichael Zeller [HDA_CODEC_PIN_OUTPUT_NID] = {HDA_CODEC_AUDIO_OUTPUT_NID},
35984659b24SMichael Zeller [HDA_CODEC_AUDIO_INPUT_NID] = {HDA_CODEC_PIN_INPUT_NID},
36084659b24SMichael Zeller };
36184659b24SMichael Zeller
36284659b24SMichael Zeller static const uint32_t
36384659b24SMichael Zeller hda_codec_conf_default[HDA_CODEC_NODES_COUNT] = {
36484659b24SMichael Zeller [HDA_CODEC_PIN_OUTPUT_NID] = \
36584659b24SMichael Zeller HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK |
36684659b24SMichael Zeller HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT |
36784659b24SMichael Zeller HDA_CONFIG_DEFAULTCONF_COLOR_BLACK |
36884659b24SMichael Zeller (0x01 << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT),
36984659b24SMichael Zeller [HDA_CODEC_PIN_INPUT_NID] = HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK |
37084659b24SMichael Zeller HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN |
37184659b24SMichael Zeller HDA_CONFIG_DEFAULTCONF_COLOR_RED |
37284659b24SMichael Zeller (0x02 << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT),
37384659b24SMichael Zeller };
37484659b24SMichael Zeller
37584659b24SMichael Zeller static const uint8_t
37684659b24SMichael Zeller hda_codec_pin_ctrl_default[HDA_CODEC_NODES_COUNT] = {
37784659b24SMichael Zeller [HDA_CODEC_PIN_OUTPUT_NID] = HDA_CODEC_PIN_WIDGET_CTRL_OUT_ENABLE,
37884659b24SMichael Zeller [HDA_CODEC_PIN_INPUT_NID] = HDA_CODEC_PIN_WIDGET_CTRL_IN_ENABLE,
37984659b24SMichael Zeller };
38084659b24SMichael Zeller
38184659b24SMichael Zeller static const
38284659b24SMichael Zeller verb_func_t hda_codec_verb_handlers[HDA_CODEC_NODES_COUNT] = {
38384659b24SMichael Zeller [HDA_CODEC_AUDIO_OUTPUT_NID] = hda_codec_audio_output_nid,
38484659b24SMichael Zeller [HDA_CODEC_AUDIO_INPUT_NID] = hda_codec_audio_input_nid,
38584659b24SMichael Zeller };
38684659b24SMichael Zeller
38784659b24SMichael Zeller /*
38884659b24SMichael Zeller * HDA Codec module function definitions
38984659b24SMichael Zeller */
39084659b24SMichael Zeller
39184659b24SMichael Zeller static int
hda_codec_init(struct hda_codec_inst * hci,const char * play,const char * rec)39284659b24SMichael Zeller hda_codec_init(struct hda_codec_inst *hci, const char *play,
3932b948146SAndy Fiddaman const char *rec)
39484659b24SMichael Zeller {
39584659b24SMichael Zeller struct hda_codec_softc *sc = NULL;
39684659b24SMichael Zeller struct hda_codec_stream *st = NULL;
39784659b24SMichael Zeller int err;
39884659b24SMichael Zeller
39984659b24SMichael Zeller if (!(play || rec))
40084659b24SMichael Zeller return (-1);
40184659b24SMichael Zeller
40284659b24SMichael Zeller sc = calloc(1, sizeof(*sc));
40384659b24SMichael Zeller if (!sc)
40484659b24SMichael Zeller return (-1);
40584659b24SMichael Zeller
40684659b24SMichael Zeller if (play && rec)
40784659b24SMichael Zeller sc->get_parameters = hda_codec_duplex_parameters;
40884659b24SMichael Zeller else {
40984659b24SMichael Zeller if (play)
41084659b24SMichael Zeller sc->get_parameters = hda_codec_output_parameters;
41184659b24SMichael Zeller else
41284659b24SMichael Zeller sc->get_parameters = hda_codec_input_parameters;
41384659b24SMichael Zeller }
41484659b24SMichael Zeller sc->subsystem_id = HDA_CODEC_SUBSYSTEM_ID;
41584659b24SMichael Zeller sc->no_nodes = HDA_CODEC_NODES_COUNT;
41684659b24SMichael Zeller sc->conn_list = hda_codec_conn_list;
41784659b24SMichael Zeller sc->conf_default = hda_codec_conf_default;
41884659b24SMichael Zeller sc->pin_ctrl_default = hda_codec_pin_ctrl_default;
41984659b24SMichael Zeller sc->verb_handlers = hda_codec_verb_handlers;
420154972afSPatrick Mooney DPRINTF("HDA Codec nodes: %d", sc->no_nodes);
42184659b24SMichael Zeller
42284659b24SMichael Zeller /*
42384659b24SMichael Zeller * Initialize the Audio Output stream
42484659b24SMichael Zeller */
42584659b24SMichael Zeller if (play) {
42684659b24SMichael Zeller st = &sc->streams[HDA_CODEC_STREAM_OUTPUT];
42784659b24SMichael Zeller
42884659b24SMichael Zeller err = hda_audio_ctxt_init(&st->actx, "hda-audio-output",
42984659b24SMichael Zeller hda_codec_audio_output_do_transfer,
43084659b24SMichael Zeller hda_codec_audio_output_do_setup, sc);
43184659b24SMichael Zeller assert(!err);
43284659b24SMichael Zeller
43384659b24SMichael Zeller st->aud = audio_init(play, 1);
43484659b24SMichael Zeller if (!st->aud) {
435154972afSPatrick Mooney DPRINTF("Fail to init the output audio player");
43684659b24SMichael Zeller return (-1);
43784659b24SMichael Zeller }
43884659b24SMichael Zeller }
43984659b24SMichael Zeller
44084659b24SMichael Zeller /*
44184659b24SMichael Zeller * Initialize the Audio Input stream
44284659b24SMichael Zeller */
44384659b24SMichael Zeller if (rec) {
44484659b24SMichael Zeller st = &sc->streams[HDA_CODEC_STREAM_INPUT];
44584659b24SMichael Zeller
44684659b24SMichael Zeller err = hda_audio_ctxt_init(&st->actx, "hda-audio-input",
44784659b24SMichael Zeller hda_codec_audio_input_do_transfer,
44884659b24SMichael Zeller hda_codec_audio_input_do_setup, sc);
44984659b24SMichael Zeller assert(!err);
45084659b24SMichael Zeller
45184659b24SMichael Zeller st->aud = audio_init(rec, 0);
45284659b24SMichael Zeller if (!st->aud) {
453154972afSPatrick Mooney DPRINTF("Fail to init the input audio player");
45484659b24SMichael Zeller return (-1);
45584659b24SMichael Zeller }
45684659b24SMichael Zeller }
45784659b24SMichael Zeller
45884659b24SMichael Zeller sc->hci = hci;
45984659b24SMichael Zeller hci->priv = sc;
46084659b24SMichael Zeller
46184659b24SMichael Zeller return (0);
46284659b24SMichael Zeller }
46384659b24SMichael Zeller
46484659b24SMichael Zeller static int
hda_codec_reset(struct hda_codec_inst * hci)46584659b24SMichael Zeller hda_codec_reset(struct hda_codec_inst *hci)
46684659b24SMichael Zeller {
46759d65d31SAndy Fiddaman const struct hda_ops *hops = NULL;
46884659b24SMichael Zeller struct hda_codec_softc *sc = NULL;
46984659b24SMichael Zeller struct hda_codec_stream *st = NULL;
47084659b24SMichael Zeller int i;
47184659b24SMichael Zeller
47284659b24SMichael Zeller assert(hci);
47384659b24SMichael Zeller
47484659b24SMichael Zeller hops = hci->hops;
47584659b24SMichael Zeller assert(hops);
47684659b24SMichael Zeller
47784659b24SMichael Zeller sc = (struct hda_codec_softc *)hci->priv;
47884659b24SMichael Zeller assert(sc);
47984659b24SMichael Zeller
48084659b24SMichael Zeller for (i = 0; i < HDA_CODEC_STREAMS_COUNT; i++) {
48184659b24SMichael Zeller st = &sc->streams[i];
48284659b24SMichael Zeller st->left_gain = HDA_CODEC_AMP_NUMSTEPS;
48384659b24SMichael Zeller st->right_gain = HDA_CODEC_AMP_NUMSTEPS;
48484659b24SMichael Zeller st->left_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE;
48584659b24SMichael Zeller st->right_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE;
48684659b24SMichael Zeller }
48784659b24SMichael Zeller
488154972afSPatrick Mooney DPRINTF("cad: 0x%x", hci->cad);
48984659b24SMichael Zeller
49084659b24SMichael Zeller if (!hops->signal) {
49184659b24SMichael Zeller DPRINTF("The controller ops does not implement \
492154972afSPatrick Mooney the signal function");
49384659b24SMichael Zeller return (-1);
49484659b24SMichael Zeller }
49584659b24SMichael Zeller
49684659b24SMichael Zeller return (hops->signal(hci));
49784659b24SMichael Zeller }
49884659b24SMichael Zeller
49984659b24SMichael Zeller static int
hda_codec_command(struct hda_codec_inst * hci,uint32_t cmd_data)50084659b24SMichael Zeller hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data)
50184659b24SMichael Zeller {
50259d65d31SAndy Fiddaman const struct hda_ops *hops = NULL;
50384659b24SMichael Zeller struct hda_codec_softc *sc = NULL;
50484659b24SMichael Zeller uint8_t cad = 0, nid = 0;
50584659b24SMichael Zeller uint16_t verb = 0, payload = 0;
50684659b24SMichael Zeller uint32_t res = 0;
50784659b24SMichael Zeller
50884659b24SMichael Zeller /* 4 bits */
50984659b24SMichael Zeller cad = (cmd_data >> HDA_CMD_CAD_SHIFT) & 0x0f;
51084659b24SMichael Zeller /* 8 bits */
51184659b24SMichael Zeller nid = (cmd_data >> HDA_CMD_NID_SHIFT) & 0xff;
51284659b24SMichael Zeller
51384659b24SMichael Zeller if ((cmd_data & 0x70000) == 0x70000) {
51484659b24SMichael Zeller /* 12 bits */
51584659b24SMichael Zeller verb = (cmd_data >> HDA_CMD_VERB_12BIT_SHIFT) & 0x0fff;
51684659b24SMichael Zeller /* 8 bits */
51784659b24SMichael Zeller payload = cmd_data & 0xff;
51884659b24SMichael Zeller } else {
51984659b24SMichael Zeller /* 4 bits */
52084659b24SMichael Zeller verb = (cmd_data >> HDA_CMD_VERB_4BIT_SHIFT) & 0x0f;
52184659b24SMichael Zeller /* 16 bits */
52284659b24SMichael Zeller payload = cmd_data & 0xffff;
52384659b24SMichael Zeller }
52484659b24SMichael Zeller
52584659b24SMichael Zeller assert(cad == hci->cad);
52684659b24SMichael Zeller assert(hci);
52784659b24SMichael Zeller
52884659b24SMichael Zeller hops = hci->hops;
52984659b24SMichael Zeller assert(hops);
53084659b24SMichael Zeller
53184659b24SMichael Zeller sc = (struct hda_codec_softc *)hci->priv;
53284659b24SMichael Zeller assert(sc);
53384659b24SMichael Zeller
53484659b24SMichael Zeller assert(nid < sc->no_nodes);
53584659b24SMichael Zeller
53684659b24SMichael Zeller if (!hops->response) {
53784659b24SMichael Zeller DPRINTF("The controller ops does not implement \
538154972afSPatrick Mooney the response function");
53984659b24SMichael Zeller return (-1);
54084659b24SMichael Zeller }
54184659b24SMichael Zeller
54284659b24SMichael Zeller switch (verb) {
54384659b24SMichael Zeller case HDA_CMD_VERB_GET_PARAMETER:
54484659b24SMichael Zeller res = sc->get_parameters[nid][payload];
54584659b24SMichael Zeller break;
54684659b24SMichael Zeller case HDA_CMD_VERB_GET_CONN_LIST_ENTRY:
54784659b24SMichael Zeller res = sc->conn_list[nid][0];
54884659b24SMichael Zeller break;
54984659b24SMichael Zeller case HDA_CMD_VERB_GET_PIN_WIDGET_CTRL:
55084659b24SMichael Zeller res = sc->pin_ctrl_default[nid];
55184659b24SMichael Zeller break;
55284659b24SMichael Zeller case HDA_CMD_VERB_GET_PIN_SENSE:
55384659b24SMichael Zeller res = HDA_CODEC_PIN_SENSE_PRESENCE_PLUGGED;
55484659b24SMichael Zeller break;
55584659b24SMichael Zeller case HDA_CMD_VERB_GET_CONFIGURATION_DEFAULT:
55684659b24SMichael Zeller res = sc->conf_default[nid];
55784659b24SMichael Zeller break;
55884659b24SMichael Zeller case HDA_CMD_VERB_GET_SUBSYSTEM_ID:
55984659b24SMichael Zeller res = sc->subsystem_id;
56084659b24SMichael Zeller break;
56184659b24SMichael Zeller default:
56284659b24SMichael Zeller assert(sc->verb_handlers);
56384659b24SMichael Zeller if (sc->verb_handlers[nid])
56484659b24SMichael Zeller res = sc->verb_handlers[nid](sc, verb, payload);
56584659b24SMichael Zeller else
566154972afSPatrick Mooney DPRINTF("Unknown VERB: 0x%x", verb);
56784659b24SMichael Zeller break;
56884659b24SMichael Zeller }
56984659b24SMichael Zeller
570154972afSPatrick Mooney DPRINTF("cad: 0x%x nid: 0x%x verb: 0x%x payload: 0x%x response: 0x%x",
57184659b24SMichael Zeller cad, nid, verb, payload, res);
57284659b24SMichael Zeller
57384659b24SMichael Zeller return (hops->response(hci, res, HDA_CODEC_RESPONSE_EX_SOL));
57484659b24SMichael Zeller }
57584659b24SMichael Zeller
57684659b24SMichael Zeller static int
hda_codec_notify(struct hda_codec_inst * hci,uint8_t run,uint8_t stream,uint8_t dir)57784659b24SMichael Zeller hda_codec_notify(struct hda_codec_inst *hci, uint8_t run,
57884659b24SMichael Zeller uint8_t stream, uint8_t dir)
57984659b24SMichael Zeller {
58084659b24SMichael Zeller struct hda_codec_softc *sc = NULL;
58184659b24SMichael Zeller struct hda_codec_stream *st = NULL;
58284659b24SMichael Zeller struct hda_audio_ctxt *actx = NULL;
58384659b24SMichael Zeller int i;
58484659b24SMichael Zeller int err;
58584659b24SMichael Zeller
58684659b24SMichael Zeller assert(hci);
58784659b24SMichael Zeller assert(stream);
58884659b24SMichael Zeller
58984659b24SMichael Zeller sc = (struct hda_codec_softc *)hci->priv;
59084659b24SMichael Zeller assert(sc);
59184659b24SMichael Zeller
59284659b24SMichael Zeller i = dir ? HDA_CODEC_STREAM_OUTPUT : HDA_CODEC_STREAM_INPUT;
59384659b24SMichael Zeller st = &sc->streams[i];
59484659b24SMichael Zeller
595154972afSPatrick Mooney DPRINTF("run: %d, stream: 0x%x, st->stream: 0x%x dir: %d",
59684659b24SMichael Zeller run, stream, st->stream, dir);
59784659b24SMichael Zeller
59884659b24SMichael Zeller if (stream != st->stream) {
599154972afSPatrick Mooney DPRINTF("Stream not found");
60084659b24SMichael Zeller return (0);
60184659b24SMichael Zeller }
60284659b24SMichael Zeller
60384659b24SMichael Zeller actx = &st->actx;
60484659b24SMichael Zeller
60584659b24SMichael Zeller if (run)
60684659b24SMichael Zeller err = hda_audio_ctxt_start(actx);
60784659b24SMichael Zeller else
60884659b24SMichael Zeller err = hda_audio_ctxt_stop(actx);
60984659b24SMichael Zeller
61084659b24SMichael Zeller return (err);
61184659b24SMichael Zeller }
61284659b24SMichael Zeller
61384659b24SMichael Zeller static int
hda_codec_parse_format(uint16_t fmt,struct audio_params * params)61484659b24SMichael Zeller hda_codec_parse_format(uint16_t fmt, struct audio_params *params)
61584659b24SMichael Zeller {
61684659b24SMichael Zeller uint8_t div = 0;
61784659b24SMichael Zeller
61884659b24SMichael Zeller assert(params);
61984659b24SMichael Zeller
62084659b24SMichael Zeller /* Compute the Sample Rate */
62184659b24SMichael Zeller params->rate = (fmt & HDA_CODEC_FMT_BASE_MASK) ? 44100 : 48000;
62284659b24SMichael Zeller
62384659b24SMichael Zeller switch (fmt & HDA_CODEC_FMT_MULT_MASK) {
62484659b24SMichael Zeller case HDA_CODEC_FMT_MULT_2:
62584659b24SMichael Zeller params->rate *= 2;
62684659b24SMichael Zeller break;
62784659b24SMichael Zeller case HDA_CODEC_FMT_MULT_3:
62884659b24SMichael Zeller params->rate *= 3;
62984659b24SMichael Zeller break;
63084659b24SMichael Zeller case HDA_CODEC_FMT_MULT_4:
63184659b24SMichael Zeller params->rate *= 4;
63284659b24SMichael Zeller break;
63384659b24SMichael Zeller }
63484659b24SMichael Zeller
63584659b24SMichael Zeller div = (fmt >> HDA_CODEC_FMT_DIV_SHIFT) & HDA_CODEC_FMT_DIV_MASK;
63684659b24SMichael Zeller params->rate /= (div + 1);
63784659b24SMichael Zeller
63884659b24SMichael Zeller /* Compute the Bits per Sample */
63984659b24SMichael Zeller switch (fmt & HDA_CODEC_FMT_BITS_MASK) {
64084659b24SMichael Zeller case HDA_CODEC_FMT_BITS_8:
64184659b24SMichael Zeller params->format = AFMT_U8;
64284659b24SMichael Zeller break;
64384659b24SMichael Zeller case HDA_CODEC_FMT_BITS_16:
64484659b24SMichael Zeller params->format = AFMT_S16_LE;
64584659b24SMichael Zeller break;
64684659b24SMichael Zeller case HDA_CODEC_FMT_BITS_24:
64784659b24SMichael Zeller params->format = AFMT_S24_LE;
64884659b24SMichael Zeller break;
64984659b24SMichael Zeller case HDA_CODEC_FMT_BITS_32:
65084659b24SMichael Zeller params->format = AFMT_S32_LE;
65184659b24SMichael Zeller break;
65284659b24SMichael Zeller default:
653154972afSPatrick Mooney DPRINTF("Unknown format bits: 0x%x",
65484659b24SMichael Zeller fmt & HDA_CODEC_FMT_BITS_MASK);
65584659b24SMichael Zeller return (-1);
65684659b24SMichael Zeller }
65784659b24SMichael Zeller
65884659b24SMichael Zeller /* Compute the Number of Channels */
65984659b24SMichael Zeller params->channels = (fmt & HDA_CODEC_FMT_CHAN_MASK) + 1;
66084659b24SMichael Zeller
66184659b24SMichael Zeller return (0);
66284659b24SMichael Zeller }
66384659b24SMichael Zeller
66484659b24SMichael Zeller static uint32_t
hda_codec_audio_output_nid(struct hda_codec_softc * sc,uint16_t verb,uint16_t payload)66584659b24SMichael Zeller hda_codec_audio_output_nid(struct hda_codec_softc *sc, uint16_t verb,
66684659b24SMichael Zeller uint16_t payload)
66784659b24SMichael Zeller {
66884659b24SMichael Zeller struct hda_codec_stream *st = &sc->streams[HDA_CODEC_STREAM_OUTPUT];
66984659b24SMichael Zeller int res;
67084659b24SMichael Zeller
67184659b24SMichael Zeller res = hda_codec_audio_inout_nid(st, verb, payload);
67284659b24SMichael Zeller
67384659b24SMichael Zeller return (res);
67484659b24SMichael Zeller }
67584659b24SMichael Zeller
67684659b24SMichael Zeller static void
hda_codec_audio_output_do_transfer(void * arg)67784659b24SMichael Zeller hda_codec_audio_output_do_transfer(void *arg)
67884659b24SMichael Zeller {
67959d65d31SAndy Fiddaman const struct hda_ops *hops = NULL;
68084659b24SMichael Zeller struct hda_codec_softc *sc = (struct hda_codec_softc *)arg;
68184659b24SMichael Zeller struct hda_codec_inst *hci = NULL;
68284659b24SMichael Zeller struct hda_codec_stream *st = NULL;
68384659b24SMichael Zeller struct audio *aud = NULL;
68484659b24SMichael Zeller int err;
68584659b24SMichael Zeller
68684659b24SMichael Zeller hci = sc->hci;
68784659b24SMichael Zeller assert(hci);
68884659b24SMichael Zeller
68984659b24SMichael Zeller hops = hci->hops;
69084659b24SMichael Zeller assert(hops);
69184659b24SMichael Zeller
69284659b24SMichael Zeller st = &sc->streams[HDA_CODEC_STREAM_OUTPUT];
69384659b24SMichael Zeller aud = st->aud;
69484659b24SMichael Zeller
69584659b24SMichael Zeller err = hops->transfer(hci, st->stream, 1, st->buf, sizeof(st->buf));
69684659b24SMichael Zeller if (err)
69784659b24SMichael Zeller return;
69884659b24SMichael Zeller
69984659b24SMichael Zeller err = audio_playback(aud, st->buf, sizeof(st->buf));
70084659b24SMichael Zeller assert(!err);
70184659b24SMichael Zeller }
70284659b24SMichael Zeller
70384659b24SMichael Zeller static int
hda_codec_audio_output_do_setup(void * arg)70484659b24SMichael Zeller hda_codec_audio_output_do_setup(void *arg)
70584659b24SMichael Zeller {
70684659b24SMichael Zeller struct hda_codec_softc *sc = (struct hda_codec_softc *)arg;
70784659b24SMichael Zeller struct hda_codec_stream *st = NULL;
70884659b24SMichael Zeller struct audio *aud = NULL;
70984659b24SMichael Zeller struct audio_params params;
71084659b24SMichael Zeller int err;
71184659b24SMichael Zeller
71284659b24SMichael Zeller st = &sc->streams[HDA_CODEC_STREAM_OUTPUT];
71384659b24SMichael Zeller aud = st->aud;
71484659b24SMichael Zeller
71584659b24SMichael Zeller err = hda_codec_parse_format(st->fmt, ¶ms);
71684659b24SMichael Zeller if (err)
71784659b24SMichael Zeller return (-1);
71884659b24SMichael Zeller
719154972afSPatrick Mooney DPRINTF("rate: %d, channels: %d, format: 0x%x",
72084659b24SMichael Zeller params.rate, params.channels, params.format);
72184659b24SMichael Zeller
72284659b24SMichael Zeller return (audio_set_params(aud, ¶ms));
72384659b24SMichael Zeller }
72484659b24SMichael Zeller
72584659b24SMichael Zeller static uint32_t
hda_codec_audio_input_nid(struct hda_codec_softc * sc,uint16_t verb,uint16_t payload)72684659b24SMichael Zeller hda_codec_audio_input_nid(struct hda_codec_softc *sc, uint16_t verb,
72784659b24SMichael Zeller uint16_t payload)
72884659b24SMichael Zeller {
72984659b24SMichael Zeller struct hda_codec_stream *st = &sc->streams[HDA_CODEC_STREAM_INPUT];
73084659b24SMichael Zeller int res;
73184659b24SMichael Zeller
73284659b24SMichael Zeller res = hda_codec_audio_inout_nid(st, verb, payload);
73384659b24SMichael Zeller
73484659b24SMichael Zeller return (res);
73584659b24SMichael Zeller }
73684659b24SMichael Zeller
73784659b24SMichael Zeller static void
hda_codec_audio_input_do_transfer(void * arg)73884659b24SMichael Zeller hda_codec_audio_input_do_transfer(void *arg)
73984659b24SMichael Zeller {
74059d65d31SAndy Fiddaman const struct hda_ops *hops = NULL;
74184659b24SMichael Zeller struct hda_codec_softc *sc = (struct hda_codec_softc *)arg;
74284659b24SMichael Zeller struct hda_codec_inst *hci = NULL;
74384659b24SMichael Zeller struct hda_codec_stream *st = NULL;
74484659b24SMichael Zeller struct audio *aud = NULL;
74584659b24SMichael Zeller int err;
74684659b24SMichael Zeller
74784659b24SMichael Zeller hci = sc->hci;
74884659b24SMichael Zeller assert(hci);
74984659b24SMichael Zeller
75084659b24SMichael Zeller hops = hci->hops;
75184659b24SMichael Zeller assert(hops);
75284659b24SMichael Zeller
75384659b24SMichael Zeller st = &sc->streams[HDA_CODEC_STREAM_INPUT];
75484659b24SMichael Zeller aud = st->aud;
75584659b24SMichael Zeller
75684659b24SMichael Zeller err = audio_record(aud, st->buf, sizeof(st->buf));
75784659b24SMichael Zeller assert(!err);
75884659b24SMichael Zeller
75984659b24SMichael Zeller hops->transfer(hci, st->stream, 0, st->buf, sizeof(st->buf));
76084659b24SMichael Zeller }
76184659b24SMichael Zeller
76284659b24SMichael Zeller static int
hda_codec_audio_input_do_setup(void * arg)76384659b24SMichael Zeller hda_codec_audio_input_do_setup(void *arg)
76484659b24SMichael Zeller {
76584659b24SMichael Zeller struct hda_codec_softc *sc = (struct hda_codec_softc *)arg;
76684659b24SMichael Zeller struct hda_codec_stream *st = NULL;
76784659b24SMichael Zeller struct audio *aud = NULL;
76884659b24SMichael Zeller struct audio_params params;
76984659b24SMichael Zeller int err;
77084659b24SMichael Zeller
77184659b24SMichael Zeller st = &sc->streams[HDA_CODEC_STREAM_INPUT];
77284659b24SMichael Zeller aud = st->aud;
77384659b24SMichael Zeller
77484659b24SMichael Zeller err = hda_codec_parse_format(st->fmt, ¶ms);
77584659b24SMichael Zeller if (err)
77684659b24SMichael Zeller return (-1);
77784659b24SMichael Zeller
778154972afSPatrick Mooney DPRINTF("rate: %d, channels: %d, format: 0x%x",
77984659b24SMichael Zeller params.rate, params.channels, params.format);
78084659b24SMichael Zeller
78184659b24SMichael Zeller return (audio_set_params(aud, ¶ms));
78284659b24SMichael Zeller }
78384659b24SMichael Zeller
78484659b24SMichael Zeller static uint32_t
hda_codec_audio_inout_nid(struct hda_codec_stream * st,uint16_t verb,uint16_t payload)78584659b24SMichael Zeller hda_codec_audio_inout_nid(struct hda_codec_stream *st, uint16_t verb,
78684659b24SMichael Zeller uint16_t payload)
78784659b24SMichael Zeller {
78884659b24SMichael Zeller uint32_t res = 0;
78984659b24SMichael Zeller uint8_t mute = 0;
79084659b24SMichael Zeller uint8_t gain = 0;
79184659b24SMichael Zeller
792154972afSPatrick Mooney DPRINTF("%s verb: 0x%x, payload, 0x%x", st->actx.name, verb, payload);
79384659b24SMichael Zeller
79484659b24SMichael Zeller switch (verb) {
79584659b24SMichael Zeller case HDA_CMD_VERB_GET_CONV_FMT:
79684659b24SMichael Zeller res = st->fmt;
79784659b24SMichael Zeller break;
79884659b24SMichael Zeller case HDA_CMD_VERB_SET_CONV_FMT:
79984659b24SMichael Zeller st->fmt = payload;
80084659b24SMichael Zeller break;
80184659b24SMichael Zeller case HDA_CMD_VERB_GET_AMP_GAIN_MUTE:
80284659b24SMichael Zeller if (payload & HDA_CMD_GET_AMP_GAIN_MUTE_LEFT) {
80384659b24SMichael Zeller res = st->left_gain | st->left_mute;
804154972afSPatrick Mooney DPRINTF("GET_AMP_GAIN_MUTE_LEFT: 0x%x", res);
80584659b24SMichael Zeller } else {
80684659b24SMichael Zeller res = st->right_gain | st->right_mute;
807154972afSPatrick Mooney DPRINTF("GET_AMP_GAIN_MUTE_RIGHT: 0x%x", res);
80884659b24SMichael Zeller }
80984659b24SMichael Zeller break;
81084659b24SMichael Zeller case HDA_CMD_VERB_SET_AMP_GAIN_MUTE:
81184659b24SMichael Zeller mute = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE;
81284659b24SMichael Zeller gain = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_GAIN_MASK;
81384659b24SMichael Zeller
81484659b24SMichael Zeller if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_LEFT) {
81584659b24SMichael Zeller st->left_mute = mute;
81684659b24SMichael Zeller st->left_gain = gain;
81784659b24SMichael Zeller DPRINTF("SET_AMP_GAIN_MUTE_LEFT: \
818154972afSPatrick Mooney mute: 0x%x gain: 0x%x", mute, gain);
81984659b24SMichael Zeller }
82084659b24SMichael Zeller
82184659b24SMichael Zeller if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_RIGHT) {
82284659b24SMichael Zeller st->right_mute = mute;
82384659b24SMichael Zeller st->right_gain = gain;
82484659b24SMichael Zeller DPRINTF("SET_AMP_GAIN_MUTE_RIGHT: \
825154972afSPatrick Mooney mute: 0x%x gain: 0x%x", mute, gain);
82684659b24SMichael Zeller }
82784659b24SMichael Zeller break;
82884659b24SMichael Zeller case HDA_CMD_VERB_GET_CONV_STREAM_CHAN:
82984659b24SMichael Zeller res = (st->stream << 4) | st->channel;
83084659b24SMichael Zeller break;
83184659b24SMichael Zeller case HDA_CMD_VERB_SET_CONV_STREAM_CHAN:
83284659b24SMichael Zeller st->channel = payload & 0x0f;
83384659b24SMichael Zeller st->stream = (payload >> 4) & 0x0f;
834154972afSPatrick Mooney DPRINTF("st->channel: 0x%x st->stream: 0x%x",
83584659b24SMichael Zeller st->channel, st->stream);
83684659b24SMichael Zeller if (!st->stream)
83784659b24SMichael Zeller hda_audio_ctxt_stop(&st->actx);
83884659b24SMichael Zeller break;
83984659b24SMichael Zeller default:
840154972afSPatrick Mooney DPRINTF("Unknown VERB: 0x%x", verb);
84184659b24SMichael Zeller break;
84284659b24SMichael Zeller }
84384659b24SMichael Zeller
84484659b24SMichael Zeller return (res);
84584659b24SMichael Zeller }
84684659b24SMichael Zeller
8474f3f3e9aSAndy Fiddaman static const struct hda_codec_class hda_codec = {
84884659b24SMichael Zeller .name = "hda_codec",
84984659b24SMichael Zeller .init = hda_codec_init,
85084659b24SMichael Zeller .reset = hda_codec_reset,
85184659b24SMichael Zeller .command = hda_codec_command,
85284659b24SMichael Zeller .notify = hda_codec_notify,
85384659b24SMichael Zeller };
85484659b24SMichael Zeller HDA_EMUL_SET(hda_codec);
85584659b24SMichael Zeller
85684659b24SMichael Zeller /*
85784659b24SMichael Zeller * HDA Audio Context module function definitions
85884659b24SMichael Zeller */
85984659b24SMichael Zeller
86084659b24SMichael Zeller static void *
hda_audio_ctxt_thr(void * arg)86184659b24SMichael Zeller hda_audio_ctxt_thr(void *arg)
86284659b24SMichael Zeller {
86384659b24SMichael Zeller struct hda_audio_ctxt *actx = arg;
86484659b24SMichael Zeller
865154972afSPatrick Mooney DPRINTF("Start Thread: %s", actx->name);
86684659b24SMichael Zeller
86784659b24SMichael Zeller pthread_mutex_lock(&actx->mtx);
86884659b24SMichael Zeller while (1) {
86984659b24SMichael Zeller while (!actx->run)
87084659b24SMichael Zeller pthread_cond_wait(&actx->cond, &actx->mtx);
87184659b24SMichael Zeller
87284659b24SMichael Zeller actx->do_transfer(actx->priv);
87384659b24SMichael Zeller }
87484659b24SMichael Zeller pthread_mutex_unlock(&actx->mtx);
87584659b24SMichael Zeller
87684659b24SMichael Zeller pthread_exit(NULL);
87784659b24SMichael Zeller return (NULL);
87884659b24SMichael Zeller }
87984659b24SMichael Zeller
88084659b24SMichael Zeller static int
hda_audio_ctxt_init(struct hda_audio_ctxt * actx,const char * tname,transfer_func_t do_transfer,setup_func_t do_setup,void * priv)88184659b24SMichael Zeller hda_audio_ctxt_init(struct hda_audio_ctxt *actx, const char *tname,
88284659b24SMichael Zeller transfer_func_t do_transfer, setup_func_t do_setup, void *priv)
88384659b24SMichael Zeller {
88484659b24SMichael Zeller int err;
88584659b24SMichael Zeller
88684659b24SMichael Zeller assert(actx);
88784659b24SMichael Zeller assert(tname);
88884659b24SMichael Zeller assert(do_transfer);
88984659b24SMichael Zeller assert(do_setup);
89084659b24SMichael Zeller assert(priv);
89184659b24SMichael Zeller
89284659b24SMichael Zeller memset(actx, 0, sizeof(*actx));
89384659b24SMichael Zeller
89484659b24SMichael Zeller actx->run = 0;
89584659b24SMichael Zeller actx->do_transfer = do_transfer;
89684659b24SMichael Zeller actx->do_setup = do_setup;
89784659b24SMichael Zeller actx->priv = priv;
89884659b24SMichael Zeller if (strlen(tname) < sizeof(actx->name))
89984659b24SMichael Zeller memcpy(actx->name, tname, strlen(tname) + 1);
90084659b24SMichael Zeller else
90184659b24SMichael Zeller strcpy(actx->name, "unknown");
90284659b24SMichael Zeller
90384659b24SMichael Zeller err = pthread_mutex_init(&actx->mtx, NULL);
90484659b24SMichael Zeller assert(!err);
90584659b24SMichael Zeller
90684659b24SMichael Zeller err = pthread_cond_init(&actx->cond, NULL);
90784659b24SMichael Zeller assert(!err);
90884659b24SMichael Zeller
90984659b24SMichael Zeller err = pthread_create(&actx->tid, NULL, hda_audio_ctxt_thr, actx);
91084659b24SMichael Zeller assert(!err);
91184659b24SMichael Zeller
91284659b24SMichael Zeller pthread_set_name_np(actx->tid, tname);
91384659b24SMichael Zeller
91484659b24SMichael Zeller actx->started = 1;
91584659b24SMichael Zeller
91684659b24SMichael Zeller return (0);
91784659b24SMichael Zeller }
91884659b24SMichael Zeller
91984659b24SMichael Zeller static int
hda_audio_ctxt_start(struct hda_audio_ctxt * actx)92084659b24SMichael Zeller hda_audio_ctxt_start(struct hda_audio_ctxt *actx)
92184659b24SMichael Zeller {
92284659b24SMichael Zeller int err = 0;
92384659b24SMichael Zeller
92484659b24SMichael Zeller assert(actx);
92584659b24SMichael Zeller assert(actx->started);
92684659b24SMichael Zeller
92784659b24SMichael Zeller /* The stream is supposed to be stopped */
92884659b24SMichael Zeller if (actx->run)
92984659b24SMichael Zeller return (-1);
93084659b24SMichael Zeller
93184659b24SMichael Zeller pthread_mutex_lock(&actx->mtx);
93284659b24SMichael Zeller err = (* actx->do_setup)(actx->priv);
93384659b24SMichael Zeller if (!err) {
93484659b24SMichael Zeller actx->run = 1;
93584659b24SMichael Zeller pthread_cond_signal(&actx->cond);
93684659b24SMichael Zeller }
93784659b24SMichael Zeller pthread_mutex_unlock(&actx->mtx);
93884659b24SMichael Zeller
93984659b24SMichael Zeller return (err);
94084659b24SMichael Zeller }
94184659b24SMichael Zeller
94284659b24SMichael Zeller static int
hda_audio_ctxt_stop(struct hda_audio_ctxt * actx)94384659b24SMichael Zeller hda_audio_ctxt_stop(struct hda_audio_ctxt *actx)
94484659b24SMichael Zeller {
94584659b24SMichael Zeller actx->run = 0;
94684659b24SMichael Zeller return (0);
94784659b24SMichael Zeller }
948