Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/hda_codec.c
Show First 20 Lines • Show All 394 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct hda_codec_softc *sc = NULL; | struct hda_codec_softc *sc = NULL; | ||||
struct hda_codec_stream *st = NULL; | struct hda_codec_stream *st = NULL; | ||||
int err; | int err; | ||||
if (!(play || rec)) | if (!(play || rec)) | ||||
return (-1); | return (-1); | ||||
DPRINTF("cad: 0x%x opts: %s\n", hci->cad, opts); | DPRINTF("cad: 0x%x opts: %s\n\r", hci->cad, opts); | ||||
sc = calloc(1, sizeof(*sc)); | sc = calloc(1, sizeof(*sc)); | ||||
if (!sc) | if (!sc) | ||||
return (-1); | return (-1); | ||||
if (play && rec) | if (play && rec) | ||||
sc->get_parameters = hda_codec_duplex_parameters; | sc->get_parameters = hda_codec_duplex_parameters; | ||||
else { | else { | ||||
if (play) | if (play) | ||||
sc->get_parameters = hda_codec_output_parameters; | sc->get_parameters = hda_codec_output_parameters; | ||||
else | else | ||||
sc->get_parameters = hda_codec_input_parameters; | sc->get_parameters = hda_codec_input_parameters; | ||||
} | } | ||||
sc->subsystem_id = HDA_CODEC_SUBSYSTEM_ID; | sc->subsystem_id = HDA_CODEC_SUBSYSTEM_ID; | ||||
sc->no_nodes = HDA_CODEC_NODES_COUNT; | sc->no_nodes = HDA_CODEC_NODES_COUNT; | ||||
sc->conn_list = hda_codec_conn_list; | sc->conn_list = hda_codec_conn_list; | ||||
sc->conf_default = hda_codec_conf_default; | sc->conf_default = hda_codec_conf_default; | ||||
sc->pin_ctrl_default = hda_codec_pin_ctrl_default; | sc->pin_ctrl_default = hda_codec_pin_ctrl_default; | ||||
sc->verb_handlers = hda_codec_verb_handlers; | sc->verb_handlers = hda_codec_verb_handlers; | ||||
DPRINTF("HDA Codec nodes: %d\n", sc->no_nodes); | DPRINTF("HDA Codec nodes: %d\n\r", sc->no_nodes); | ||||
/* | /* | ||||
* Initialize the Audio Output stream | * Initialize the Audio Output stream | ||||
*/ | */ | ||||
if (play) { | if (play) { | ||||
st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; | st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; | ||||
err = hda_audio_ctxt_init(&st->actx, "hda-audio-output", | err = hda_audio_ctxt_init(&st->actx, "hda-audio-output", | ||||
hda_codec_audio_output_do_transfer, | hda_codec_audio_output_do_transfer, | ||||
hda_codec_audio_output_do_setup, sc); | hda_codec_audio_output_do_setup, sc); | ||||
assert(!err); | assert(!err); | ||||
st->aud = audio_init(play, 1); | st->aud = audio_init(play, 1); | ||||
if (!st->aud) { | if (!st->aud) { | ||||
DPRINTF("Fail to init the output audio player\n"); | DPRINTF("Fail to init the output audio player\n\r"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Initialize the Audio Input stream | * Initialize the Audio Input stream | ||||
*/ | */ | ||||
if (rec) { | if (rec) { | ||||
st = &sc->streams[HDA_CODEC_STREAM_INPUT]; | st = &sc->streams[HDA_CODEC_STREAM_INPUT]; | ||||
err = hda_audio_ctxt_init(&st->actx, "hda-audio-input", | err = hda_audio_ctxt_init(&st->actx, "hda-audio-input", | ||||
hda_codec_audio_input_do_transfer, | hda_codec_audio_input_do_transfer, | ||||
hda_codec_audio_input_do_setup, sc); | hda_codec_audio_input_do_setup, sc); | ||||
assert(!err); | assert(!err); | ||||
st->aud = audio_init(rec, 0); | st->aud = audio_init(rec, 0); | ||||
if (!st->aud) { | if (!st->aud) { | ||||
DPRINTF("Fail to init the input audio player\n"); | DPRINTF("Fail to init the input audio player\n\r"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
} | } | ||||
sc->hci = hci; | sc->hci = hci; | ||||
hci->priv = sc; | hci->priv = sc; | ||||
return (0); | return (0); | ||||
Show All 18 Lines | hda_codec_reset(struct hda_codec_inst *hci) | ||||
for (i = 0; i < HDA_CODEC_STREAMS_COUNT; i++) { | for (i = 0; i < HDA_CODEC_STREAMS_COUNT; i++) { | ||||
st = &sc->streams[i]; | st = &sc->streams[i]; | ||||
st->left_gain = HDA_CODEC_AMP_NUMSTEPS; | st->left_gain = HDA_CODEC_AMP_NUMSTEPS; | ||||
st->right_gain = HDA_CODEC_AMP_NUMSTEPS; | st->right_gain = HDA_CODEC_AMP_NUMSTEPS; | ||||
st->left_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; | st->left_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; | ||||
st->right_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; | st->right_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; | ||||
} | } | ||||
DPRINTF("cad: 0x%x\n", hci->cad); | DPRINTF("cad: 0x%x\n\r", hci->cad); | ||||
if (!hops->signal) { | if (!hops->signal) { | ||||
DPRINTF("The controller ops does not implement \ | DPRINTF("The controller ops does not implement \ | ||||
the signal function\n"); | the signal function\n\r"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
return (hops->signal(hci)); | return (hops->signal(hci)); | ||||
} | } | ||||
static int | static int | ||||
hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data) | hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data) | ||||
Show All 29 Lines | hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data) | ||||
sc = (struct hda_codec_softc *)hci->priv; | sc = (struct hda_codec_softc *)hci->priv; | ||||
assert(sc); | assert(sc); | ||||
assert(nid < sc->no_nodes); | assert(nid < sc->no_nodes); | ||||
if (!hops->response) { | if (!hops->response) { | ||||
DPRINTF("The controller ops does not implement \ | DPRINTF("The controller ops does not implement \ | ||||
the response function\n"); | the response function\n\r"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
switch (verb) { | switch (verb) { | ||||
case HDA_CMD_VERB_GET_PARAMETER: | case HDA_CMD_VERB_GET_PARAMETER: | ||||
res = sc->get_parameters[nid][payload]; | res = sc->get_parameters[nid][payload]; | ||||
break; | break; | ||||
case HDA_CMD_VERB_GET_CONN_LIST_ENTRY: | case HDA_CMD_VERB_GET_CONN_LIST_ENTRY: | ||||
Show All 11 Lines | hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data) | ||||
case HDA_CMD_VERB_GET_SUBSYSTEM_ID: | case HDA_CMD_VERB_GET_SUBSYSTEM_ID: | ||||
res = sc->subsystem_id; | res = sc->subsystem_id; | ||||
break; | break; | ||||
default: | default: | ||||
assert(sc->verb_handlers); | assert(sc->verb_handlers); | ||||
if (sc->verb_handlers[nid]) | if (sc->verb_handlers[nid]) | ||||
res = sc->verb_handlers[nid](sc, verb, payload); | res = sc->verb_handlers[nid](sc, verb, payload); | ||||
else | else | ||||
DPRINTF("Unknown VERB: 0x%x\n", verb); | DPRINTF("Unknown VERB: 0x%x\n\r", verb); | ||||
break; | break; | ||||
} | } | ||||
DPRINTF("cad: 0x%x nid: 0x%x verb: 0x%x payload: 0x%x response: 0x%x\n", | DPRINTF("cad: 0x%x nid: 0x%x verb: 0x%x payload: 0x%x response: 0x%x\n\r", | ||||
cad, nid, verb, payload, res); | cad, nid, verb, payload, res); | ||||
return (hops->response(hci, res, HDA_CODEC_RESPONSE_EX_SOL)); | return (hops->response(hci, res, HDA_CODEC_RESPONSE_EX_SOL)); | ||||
} | } | ||||
static int | static int | ||||
hda_codec_notify(struct hda_codec_inst *hci, uint8_t run, | hda_codec_notify(struct hda_codec_inst *hci, uint8_t run, | ||||
uint8_t stream, uint8_t dir) | uint8_t stream, uint8_t dir) | ||||
{ | { | ||||
struct hda_codec_softc *sc = NULL; | struct hda_codec_softc *sc = NULL; | ||||
struct hda_codec_stream *st = NULL; | struct hda_codec_stream *st = NULL; | ||||
struct hda_audio_ctxt *actx = NULL; | struct hda_audio_ctxt *actx = NULL; | ||||
int i; | int i; | ||||
int err; | int err; | ||||
assert(hci); | assert(hci); | ||||
assert(stream); | assert(stream); | ||||
sc = (struct hda_codec_softc *)hci->priv; | sc = (struct hda_codec_softc *)hci->priv; | ||||
assert(sc); | assert(sc); | ||||
i = dir ? HDA_CODEC_STREAM_OUTPUT : HDA_CODEC_STREAM_INPUT; | i = dir ? HDA_CODEC_STREAM_OUTPUT : HDA_CODEC_STREAM_INPUT; | ||||
st = &sc->streams[i]; | st = &sc->streams[i]; | ||||
DPRINTF("run: %d, stream: 0x%x, st->stream: 0x%x dir: %d\n", | DPRINTF("run: %d, stream: 0x%x, st->stream: 0x%x dir: %d\n\r", | ||||
run, stream, st->stream, dir); | run, stream, st->stream, dir); | ||||
if (stream != st->stream) { | if (stream != st->stream) { | ||||
DPRINTF("Stream not found\n"); | DPRINTF("Stream not found\n\r"); | ||||
return (0); | return (0); | ||||
} | } | ||||
actx = &st->actx; | actx = &st->actx; | ||||
if (run) | if (run) | ||||
err = hda_audio_ctxt_start(actx); | err = hda_audio_ctxt_start(actx); | ||||
else | else | ||||
Show All 37 Lines | case HDA_CODEC_FMT_BITS_16: | ||||
break; | break; | ||||
case HDA_CODEC_FMT_BITS_24: | case HDA_CODEC_FMT_BITS_24: | ||||
params->format = AFMT_S24_LE; | params->format = AFMT_S24_LE; | ||||
break; | break; | ||||
case HDA_CODEC_FMT_BITS_32: | case HDA_CODEC_FMT_BITS_32: | ||||
params->format = AFMT_S32_LE; | params->format = AFMT_S32_LE; | ||||
break; | break; | ||||
default: | default: | ||||
DPRINTF("Unknown format bits: 0x%x\n", | DPRINTF("Unknown format bits: 0x%x\n\r", | ||||
fmt & HDA_CODEC_FMT_BITS_MASK); | fmt & HDA_CODEC_FMT_BITS_MASK); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
/* Compute the Number of Channels */ | /* Compute the Number of Channels */ | ||||
params->channels = (fmt & HDA_CODEC_FMT_CHAN_MASK) + 1; | params->channels = (fmt & HDA_CODEC_FMT_CHAN_MASK) + 1; | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | hda_codec_audio_output_do_setup(void *arg) | ||||
st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; | st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; | ||||
aud = st->aud; | aud = st->aud; | ||||
err = hda_codec_parse_format(st->fmt, ¶ms); | err = hda_codec_parse_format(st->fmt, ¶ms); | ||||
if (err) | if (err) | ||||
return (-1); | return (-1); | ||||
DPRINTF("rate: %d, channels: %d, format: 0x%x\n", | DPRINTF("rate: %d, channels: %d, format: 0x%x\n\r", | ||||
params.rate, params.channels, params.format); | params.rate, params.channels, params.format); | ||||
return (audio_set_params(aud, ¶ms)); | return (audio_set_params(aud, ¶ms)); | ||||
} | } | ||||
static uint32_t | static uint32_t | ||||
hda_codec_audio_input_nid(struct hda_codec_softc *sc, uint16_t verb, | hda_codec_audio_input_nid(struct hda_codec_softc *sc, uint16_t verb, | ||||
uint16_t payload) | uint16_t payload) | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | hda_codec_audio_input_do_setup(void *arg) | ||||
st = &sc->streams[HDA_CODEC_STREAM_INPUT]; | st = &sc->streams[HDA_CODEC_STREAM_INPUT]; | ||||
aud = st->aud; | aud = st->aud; | ||||
err = hda_codec_parse_format(st->fmt, ¶ms); | err = hda_codec_parse_format(st->fmt, ¶ms); | ||||
if (err) | if (err) | ||||
return (-1); | return (-1); | ||||
DPRINTF("rate: %d, channels: %d, format: 0x%x\n", | DPRINTF("rate: %d, channels: %d, format: 0x%x\n\r", | ||||
params.rate, params.channels, params.format); | params.rate, params.channels, params.format); | ||||
return (audio_set_params(aud, ¶ms)); | return (audio_set_params(aud, ¶ms)); | ||||
} | } | ||||
static uint32_t | static uint32_t | ||||
hda_codec_audio_inout_nid(struct hda_codec_stream *st, uint16_t verb, | hda_codec_audio_inout_nid(struct hda_codec_stream *st, uint16_t verb, | ||||
uint16_t payload) | uint16_t payload) | ||||
{ | { | ||||
uint32_t res = 0; | uint32_t res = 0; | ||||
uint8_t mute = 0; | uint8_t mute = 0; | ||||
uint8_t gain = 0; | uint8_t gain = 0; | ||||
DPRINTF("%s verb: 0x%x, payload, 0x%x\n", st->actx.name, verb, payload); | DPRINTF("%s verb: 0x%x, payload, 0x%x\n\r", st->actx.name, verb, payload); | ||||
switch (verb) { | switch (verb) { | ||||
case HDA_CMD_VERB_GET_CONV_FMT: | case HDA_CMD_VERB_GET_CONV_FMT: | ||||
res = st->fmt; | res = st->fmt; | ||||
break; | break; | ||||
case HDA_CMD_VERB_SET_CONV_FMT: | case HDA_CMD_VERB_SET_CONV_FMT: | ||||
st->fmt = payload; | st->fmt = payload; | ||||
break; | break; | ||||
case HDA_CMD_VERB_GET_AMP_GAIN_MUTE: | case HDA_CMD_VERB_GET_AMP_GAIN_MUTE: | ||||
if (payload & HDA_CMD_GET_AMP_GAIN_MUTE_LEFT) { | if (payload & HDA_CMD_GET_AMP_GAIN_MUTE_LEFT) { | ||||
res = st->left_gain | st->left_mute; | res = st->left_gain | st->left_mute; | ||||
DPRINTF("GET_AMP_GAIN_MUTE_LEFT: 0x%x\n", res); | DPRINTF("GET_AMP_GAIN_MUTE_LEFT: 0x%x\n\r", res); | ||||
} else { | } else { | ||||
res = st->right_gain | st->right_mute; | res = st->right_gain | st->right_mute; | ||||
DPRINTF("GET_AMP_GAIN_MUTE_RIGHT: 0x%x\n", res); | DPRINTF("GET_AMP_GAIN_MUTE_RIGHT: 0x%x\n\r", res); | ||||
} | } | ||||
break; | break; | ||||
case HDA_CMD_VERB_SET_AMP_GAIN_MUTE: | case HDA_CMD_VERB_SET_AMP_GAIN_MUTE: | ||||
mute = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; | mute = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; | ||||
gain = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_GAIN_MASK; | gain = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_GAIN_MASK; | ||||
if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_LEFT) { | if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_LEFT) { | ||||
st->left_mute = mute; | st->left_mute = mute; | ||||
st->left_gain = gain; | st->left_gain = gain; | ||||
DPRINTF("SET_AMP_GAIN_MUTE_LEFT: \ | DPRINTF("SET_AMP_GAIN_MUTE_LEFT: \ | ||||
mute: 0x%x gain: 0x%x\n", mute, gain); | mute: 0x%x gain: 0x%x\n\r", mute, gain); | ||||
} | } | ||||
if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_RIGHT) { | if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_RIGHT) { | ||||
st->right_mute = mute; | st->right_mute = mute; | ||||
st->right_gain = gain; | st->right_gain = gain; | ||||
DPRINTF("SET_AMP_GAIN_MUTE_RIGHT: \ | DPRINTF("SET_AMP_GAIN_MUTE_RIGHT: \ | ||||
mute: 0x%x gain: 0x%x\n", mute, gain); | mute: 0x%x gain: 0x%x\n\r", mute, gain); | ||||
} | } | ||||
break; | break; | ||||
case HDA_CMD_VERB_GET_CONV_STREAM_CHAN: | case HDA_CMD_VERB_GET_CONV_STREAM_CHAN: | ||||
res = (st->stream << 4) | st->channel; | res = (st->stream << 4) | st->channel; | ||||
break; | break; | ||||
case HDA_CMD_VERB_SET_CONV_STREAM_CHAN: | case HDA_CMD_VERB_SET_CONV_STREAM_CHAN: | ||||
st->channel = payload & 0x0f; | st->channel = payload & 0x0f; | ||||
st->stream = (payload >> 4) & 0x0f; | st->stream = (payload >> 4) & 0x0f; | ||||
DPRINTF("st->channel: 0x%x st->stream: 0x%x\n", | DPRINTF("st->channel: 0x%x st->stream: 0x%x\n\r", | ||||
st->channel, st->stream); | st->channel, st->stream); | ||||
if (!st->stream) | if (!st->stream) | ||||
hda_audio_ctxt_stop(&st->actx); | hda_audio_ctxt_stop(&st->actx); | ||||
break; | break; | ||||
default: | default: | ||||
DPRINTF("Unknown VERB: 0x%x\n", verb); | DPRINTF("Unknown VERB: 0x%x\n\r", verb); | ||||
break; | break; | ||||
} | } | ||||
return (res); | return (res); | ||||
} | } | ||||
struct hda_codec_class hda_codec = { | struct hda_codec_class hda_codec = { | ||||
.name = "hda_codec", | .name = "hda_codec", | ||||
Show All 10 Lines | |||||
* HDA Audio Context module function definitions | * HDA Audio Context module function definitions | ||||
*/ | */ | ||||
static void * | static void * | ||||
hda_audio_ctxt_thr(void *arg) | hda_audio_ctxt_thr(void *arg) | ||||
{ | { | ||||
struct hda_audio_ctxt *actx = arg; | struct hda_audio_ctxt *actx = arg; | ||||
DPRINTF("Start Thread: %s\n", actx->name); | DPRINTF("Start Thread: %s\n\r", actx->name); | ||||
pthread_mutex_lock(&actx->mtx); | pthread_mutex_lock(&actx->mtx); | ||||
while (1) { | while (1) { | ||||
while (!actx->run) | while (!actx->run) | ||||
pthread_cond_wait(&actx->cond, &actx->mtx); | pthread_cond_wait(&actx->cond, &actx->mtx); | ||||
actx->do_transfer(actx->priv); | actx->do_transfer(actx->priv); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 74 Lines • Show Last 20 Lines |