* Fix some bad error handling
* Plug some leaks * Initial code for input/output bus discovery git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21174 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
bdf8a2e1e7
commit
641541a4f3
|
@ -105,7 +105,7 @@ struct hda_afg_s {
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint32 num_inputs;
|
uint32 num_inputs;
|
||||||
uint32 active_input;
|
int32 active_input;
|
||||||
uint32 inputs[MAXINPUTS];
|
uint32 inputs[MAXINPUTS];
|
||||||
uint32 flags;
|
uint32 flags;
|
||||||
|
|
||||||
|
@ -124,8 +124,8 @@ struct hda_afg_s {
|
||||||
struct {
|
struct {
|
||||||
} mixer;
|
} mixer;
|
||||||
struct {
|
struct {
|
||||||
uint32 output : 1;
|
uint32 output;
|
||||||
uint32 input : 1;
|
uint32 input;
|
||||||
pin_dev_type device;
|
pin_dev_type device;
|
||||||
} pin;
|
} pin;
|
||||||
} d;
|
} d;
|
||||||
|
|
|
@ -126,7 +126,7 @@ hda_codec_parse_afg(hda_afg* afg)
|
||||||
afg->wid_start = resp[2] >> 16;
|
afg->wid_start = resp[2] >> 16;
|
||||||
afg->wid_count = resp[2] & 0xFF;
|
afg->wid_count = resp[2] & 0xFF;
|
||||||
|
|
||||||
afg->widgets = calloc(sizeof(*afg->widgets), afg->wid_count);
|
afg->widgets = calloc(afg->wid_count, sizeof(*afg->widgets));
|
||||||
if (afg->widgets == NULL) {
|
if (afg->widgets == NULL) {
|
||||||
dprintf("ERROR: Not enough memory!\n");
|
dprintf("ERROR: Not enough memory!\n");
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
@ -187,6 +187,12 @@ hda_codec_parse_afg(hda_afg* afg)
|
||||||
if (hda_send_verbs(afg->codec, verbs, resp, 1) == B_OK) {
|
if (hda_send_verbs(afg->codec, verbs, resp, 1) == B_OK) {
|
||||||
afg->widgets[widx].d.pin.input = resp[0] & (1 << 5);
|
afg->widgets[widx].d.pin.input = resp[0] & (1 << 5);
|
||||||
afg->widgets[widx].d.pin.output = resp[0] & (1 << 4);
|
afg->widgets[widx].d.pin.output = resp[0] & (1 << 4);
|
||||||
|
|
||||||
|
dprintf("\t%s%s\n",
|
||||||
|
afg->widgets[widx].d.pin.input ? "[Input] " : "",
|
||||||
|
afg->widgets[widx].d.pin.input ? "[Output]" : "");
|
||||||
|
} else {
|
||||||
|
dprintf("%s: Error getting Pin Complex IO\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
verbs[0] = MAKE_VERB(afg->codec->addr,wid,VID_GET_CFGDEFAULT,0);
|
verbs[0] = MAKE_VERB(afg->codec->addr,wid,VID_GET_CFGDEFAULT,0);
|
||||||
|
@ -260,19 +266,22 @@ hda_codec_parse_afg(hda_afg* afg)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* hda_codec_afg_find_path
|
||||||
|
*
|
||||||
|
* Find path from 'wid' to a widget of type 'wtype', returning its widget id.
|
||||||
|
* Returns 0 if not found.
|
||||||
|
*/
|
||||||
|
|
||||||
static uint32
|
static uint32
|
||||||
hda_codec_afg_find_dac_path(hda_afg* afg, uint32 wid, uint32 depth)
|
hda_codec_afg_find_path(hda_afg* afg, uint32 wid, uint32 wtype, uint32 depth)
|
||||||
{
|
{
|
||||||
int widx = wid - afg->wid_start;
|
int widx = wid - afg->wid_start;
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
switch(afg->widgets[widx].type) {
|
switch(afg->widgets[widx].type) {
|
||||||
case WT_AUDIO_OUTPUT:
|
|
||||||
return wid;
|
|
||||||
|
|
||||||
case WT_AUDIO_MIXER:
|
case WT_AUDIO_MIXER:
|
||||||
for (idx=0; idx < afg->widgets[widx].num_inputs; idx++) {
|
for (idx=0; idx < afg->widgets[widx].num_inputs; idx++) {
|
||||||
if (hda_codec_afg_find_dac_path(afg, afg->widgets[widx].inputs[idx], depth +1)) {
|
if (hda_codec_afg_find_path(afg, afg->widgets[widx].inputs[idx], wtype, depth +1)) {
|
||||||
if (afg->widgets[widx].active_input == -1)
|
if (afg->widgets[widx].active_input == -1)
|
||||||
afg->widgets[widx].active_input = idx;
|
afg->widgets[widx].active_input = idx;
|
||||||
|
|
||||||
|
@ -286,7 +295,7 @@ hda_codec_afg_find_dac_path(hda_afg* afg, uint32 wid, uint32 depth)
|
||||||
int idx = afg->widgets[widx].active_input;
|
int idx = afg->widgets[widx].active_input;
|
||||||
if (idx != -1) {
|
if (idx != -1) {
|
||||||
uint32 wid = afg->widgets[widx].inputs[idx];
|
uint32 wid = afg->widgets[widx].inputs[idx];
|
||||||
if (hda_codec_afg_find_dac_path(afg, wid, depth +1)) {
|
if (hda_codec_afg_find_path(afg, wid, wtype, depth +1)) {
|
||||||
return wid;
|
return wid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,6 +303,9 @@ hda_codec_afg_find_dac_path(hda_afg* afg, uint32 wid, uint32 depth)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
if (afg->widgets[widx].type == wtype)
|
||||||
|
return wid;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,7 +322,9 @@ hda_afg_delete(hda_afg* afg)
|
||||||
if (afg->record_stream != NULL)
|
if (afg->record_stream != NULL)
|
||||||
hda_stream_delete(afg->record_stream);
|
hda_stream_delete(afg->record_stream);
|
||||||
|
|
||||||
free(afg->widgets);
|
if (afg->widgets)
|
||||||
|
free(afg->widgets);
|
||||||
|
|
||||||
free(afg);
|
free(afg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,60 +354,99 @@ hda_codec_afg_new(hda_codec* codec, uint32 afg_nid)
|
||||||
we cannot find any output Pin Widgets */
|
we cannot find any output Pin Widgets */
|
||||||
rc = ENODEV;
|
rc = ENODEV;
|
||||||
|
|
||||||
/* Try to locate all output channels */
|
dprintf("%s: Scanning all %ld widgets for outputs/inputs....\n",
|
||||||
|
__func__, afg->wid_count);
|
||||||
|
|
||||||
|
/* Try to locate all input/output channels */
|
||||||
for (idx=0; idx < afg->wid_count; idx++) {
|
for (idx=0; idx < afg->wid_count; idx++) {
|
||||||
uint32 iidx, output_wid = 0;
|
uint32 output_wid = 0, input_wid = 0;
|
||||||
|
int32 iidx;
|
||||||
|
|
||||||
if (afg->widgets[idx].type != WT_PIN_COMPLEX)
|
if (afg->widgets[idx].type == WT_PIN_COMPLEX && afg->widgets[idx].d.pin.output) {
|
||||||
continue;
|
if (afg->widgets[idx].d.pin.device != PIN_DEV_HP_OUT &&
|
||||||
if (afg->widgets[idx].d.pin.output)
|
afg->widgets[idx].d.pin.device != PIN_DEV_SPEAKER &&
|
||||||
continue;
|
afg->widgets[idx].d.pin.device != PIN_DEV_LINE_OUT)
|
||||||
if (afg->widgets[idx].d.pin.device != PIN_DEV_HP_OUT &&
|
continue;
|
||||||
afg->widgets[idx].d.pin.device != PIN_DEV_SPEAKER &&
|
|
||||||
afg->widgets[idx].d.pin.device != PIN_DEV_LINE_OUT)
|
iidx = afg->widgets[idx].active_input;
|
||||||
continue;
|
if (iidx != -1) {
|
||||||
|
output_wid = hda_codec_afg_find_path(afg, afg->widgets[idx].inputs[iidx], WT_AUDIO_OUTPUT, 0);
|
||||||
iidx = afg->widgets[idx].active_input;
|
} else {
|
||||||
if (iidx != -1) {
|
for (iidx=0; iidx < afg->widgets[idx].num_inputs; iidx++) {
|
||||||
output_wid = hda_codec_afg_find_dac_path(afg, afg->widgets[idx].inputs[iidx], 0);
|
output_wid = hda_codec_afg_find_path(afg, afg->widgets[idx].inputs[iidx], WT_AUDIO_OUTPUT, 0);
|
||||||
} else {
|
if (output_wid) {
|
||||||
for (iidx=0; iidx < afg->widgets[idx].num_inputs; iidx++) {
|
corb_t verb = MAKE_VERB(codec->addr,idx+afg->wid_start,VID_SET_CONNSEL,iidx);
|
||||||
output_wid = hda_codec_afg_find_dac_path(afg, afg->widgets[idx].inputs[iidx], 0);
|
if (hda_send_verbs(codec, &verb, NULL, 1) != B_OK)
|
||||||
if (output_wid) {
|
dprintf("%s: Setting output selector failed!\n", __func__);
|
||||||
corb_t verb = MAKE_VERB(codec->addr,idx+afg->wid_start,VID_SET_CONNSEL,iidx);
|
break;
|
||||||
if (hda_send_verbs(codec, &verb, NULL, 1) != B_OK)
|
}
|
||||||
dprintf("%s: Setting output selector failed!\n", __func__);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (output_wid) {
|
||||||
|
if (!afg->playback_stream) {
|
||||||
|
corb_t verb;
|
||||||
|
|
||||||
|
/* Setup playback/record streams for Multi Audio API */
|
||||||
|
afg->playback_stream = hda_stream_new(afg->codec->ctrlr, STRM_PLAYBACK);
|
||||||
|
afg->record_stream = hda_stream_new(afg->codec->ctrlr, STRM_RECORD);
|
||||||
|
|
||||||
|
afg->playback_stream->pin_wid = idx + afg->wid_start;
|
||||||
|
afg->playback_stream->io_wid = output_wid;
|
||||||
|
|
||||||
|
/* FIXME: Force Pin Widget to unmute */
|
||||||
|
verb = MAKE_VERB(codec->addr, afg->playback_stream->pin_wid,
|
||||||
|
VID_SET_AMPGAINMUTE, (1 << 15) | (1 << 13) | (1 << 12));
|
||||||
|
hda_send_verbs(codec, &verb, NULL, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("%s: Found output PIN (%s) connected to output CONV wid:%ld\n",
|
||||||
|
__func__, defdev[afg->widgets[idx].d.pin.device], output_wid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (output_wid) {
|
if (afg->widgets[idx].type == WT_AUDIO_INPUT) {
|
||||||
corb_t verb;
|
iidx = afg->widgets[idx].active_input;
|
||||||
|
if (iidx != -1) {
|
||||||
/* Setup playback/record streams for Multi Audio API */
|
input_wid = hda_codec_afg_find_path(afg, afg->widgets[idx].inputs[iidx], WT_PIN_COMPLEX, 0);
|
||||||
afg->playback_stream = hda_stream_new(afg->codec->ctrlr, STRM_PLAYBACK);
|
} else {
|
||||||
afg->record_stream = hda_stream_new(afg->codec->ctrlr, STRM_RECORD);
|
for (iidx=0; iidx < afg->widgets[idx].num_inputs; iidx++) {
|
||||||
|
input_wid = hda_codec_afg_find_path(afg, afg->widgets[idx].inputs[iidx], WT_PIN_COMPLEX, 0);
|
||||||
afg->playback_stream->pin_wid = idx + afg->wid_start;
|
if (input_wid) {
|
||||||
afg->playback_stream->io_wid = output_wid;
|
corb_t verb = MAKE_VERB(codec->addr,idx+afg->wid_start,VID_SET_CONNSEL,iidx);
|
||||||
|
if (hda_send_verbs(codec, &verb, NULL, 1) != B_OK)
|
||||||
dprintf("%s: Found output PIN (%s) connected to output CONV wid:%ld\n",
|
dprintf("%s: Setting input selector failed!\n", __func__);
|
||||||
__func__, defdev[afg->widgets[idx].d.pin.device], output_wid);
|
break;
|
||||||
|
}
|
||||||
/* FIXME: Force Pin Widget to unmute */
|
}
|
||||||
verb = MAKE_VERB(codec->addr, afg->playback_stream->pin_wid,
|
}
|
||||||
VID_SET_AMPGAINMUTE, (1 << 15) | (1 << 13) | (1 << 12));
|
|
||||||
hda_send_verbs(codec, &verb, NULL, 1);
|
if (input_wid) {
|
||||||
|
if (!afg->record_stream) {
|
||||||
rc = B_OK;
|
corb_t verb;
|
||||||
break;
|
|
||||||
|
/* Setup playback/record streams for Multi Audio API */
|
||||||
|
afg->record_stream = hda_stream_new(afg->codec->ctrlr, STRM_RECORD);
|
||||||
|
|
||||||
|
afg->record_stream->pin_wid = input_wid;
|
||||||
|
afg->record_stream->io_wid = idx + afg->wid_start;
|
||||||
|
|
||||||
|
/* FIXME: Force Pin Widget to unmute */
|
||||||
|
verb = MAKE_VERB(codec->addr, afg->record_stream->pin_wid,
|
||||||
|
VID_SET_AMPGAINMUTE, (1 << 15) | (1 << 13) | (1 << 12));
|
||||||
|
hda_send_verbs(codec, &verb, NULL, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("%s: Found input PIN (%s) connected to input CONV wid:%ld\n",
|
||||||
|
__func__, defdev[afg->widgets[input_wid-afg->wid_start].d.pin.device], idx+afg->wid_start);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we found any valid output channels, we're in the clear */
|
/* If we found any valid output channels, we're in the clear */
|
||||||
if (rc == B_OK) {
|
if (afg && afg->playback_stream) {
|
||||||
codec->afgs[codec->num_afgs++] = afg;
|
codec->afgs[codec->num_afgs++] = afg;
|
||||||
|
rc = B_OK;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,42 +478,54 @@ hda_codec*
|
||||||
hda_codec_new(hda_controller* ctrlr, uint32 cad)
|
hda_codec_new(hda_controller* ctrlr, uint32 cad)
|
||||||
{
|
{
|
||||||
hda_codec* codec = calloc(1, sizeof(hda_codec));
|
hda_codec* codec = calloc(1, sizeof(hda_codec));
|
||||||
if (codec) {
|
uint32 responses[3];
|
||||||
uint32 responses[3];
|
corb_t verbs[3];
|
||||||
corb_t verbs[3];
|
status_t rc;
|
||||||
status_t rc;
|
uint32 nid;
|
||||||
uint32 nid;
|
|
||||||
|
|
||||||
codec->ctrlr = ctrlr;
|
|
||||||
codec->addr = cad;
|
|
||||||
codec->response_count = 0;
|
|
||||||
codec->response_sem = create_sem(0, "hda_codec_response_sem");
|
|
||||||
ctrlr->codecs[cad] = codec;
|
|
||||||
|
|
||||||
verbs[0] = MAKE_VERB(cad,0,VID_GET_PARAM,PID_VENDORID);
|
|
||||||
verbs[1] = MAKE_VERB(cad,0,VID_GET_PARAM,PID_REVISIONID);
|
|
||||||
verbs[2] = MAKE_VERB(cad,0,VID_GET_PARAM,PID_SUBORD_NODE_COUNT);
|
|
||||||
|
|
||||||
if (hda_send_verbs(codec, verbs, responses, 3) == B_OK) {
|
if (codec == NULL) goto exit_new;
|
||||||
dprintf("Codec %ld Vendor: %04lx Product: %04lx\n",
|
|
||||||
cad, responses[0] >> 16, responses[0] & 0xFFFF);
|
codec->ctrlr = ctrlr;
|
||||||
|
codec->addr = cad;
|
||||||
|
codec->response_sem = create_sem(0, "hda_codec_response_sem");
|
||||||
|
ctrlr->codecs[cad] = codec;
|
||||||
|
|
||||||
for (nid=responses[2] >> 16;
|
verbs[0] = MAKE_VERB(cad,0,VID_GET_PARAM,PID_VENDORID);
|
||||||
nid < (responses[2] >> 16) + (responses[2] & 0xFF);
|
verbs[1] = MAKE_VERB(cad,0,VID_GET_PARAM,PID_REVISIONID);
|
||||||
nid++) {
|
verbs[2] = MAKE_VERB(cad,0,VID_GET_PARAM,PID_SUBORD_NODE_COUNT);
|
||||||
uint32 resp;
|
|
||||||
verbs[0] = MAKE_VERB(cad,nid,VID_GET_PARAM,PID_FUNCGRP_TYPE);
|
if (hda_send_verbs(codec, verbs, responses, 3) != B_OK)
|
||||||
|
goto cmd_failed;
|
||||||
|
|
||||||
|
dprintf("Codec %ld Vendor: %04lx Product: %04lx\n",
|
||||||
|
cad, responses[0] >> 16, responses[0] & 0xFFFF);
|
||||||
|
|
||||||
|
for (nid=responses[2] >> 16;
|
||||||
|
nid < (responses[2] >> 16) + (responses[2] & 0xFF);
|
||||||
|
nid++) {
|
||||||
|
uint32 resp;
|
||||||
|
verbs[0] = MAKE_VERB(cad,nid,VID_GET_PARAM,PID_FUNCGRP_TYPE);
|
||||||
|
|
||||||
if ((rc=hda_send_verbs(codec, verbs, &resp, 1)) == B_OK &&
|
if ((rc=hda_send_verbs(codec, verbs, &resp, 1)) != B_OK)
|
||||||
(resp&0xFF) == 1 &&
|
goto cmd_failed;
|
||||||
(rc=hda_codec_afg_new(codec, nid)) == B_OK) {
|
|
||||||
/* Found an Audio Function Group! */
|
if ((resp&0xFF) == 1) {
|
||||||
} else {
|
/* Found an Audio Function Group! */
|
||||||
dprintf("%s: FG %ld: %s\n", __func__, nid, strerror(rc));
|
if ((rc=hda_codec_afg_new(codec, nid)) != B_OK) {
|
||||||
}
|
dprintf("%s: Failed to setup new audio function group (%s)!\n",
|
||||||
}
|
__func__, strerror(rc));
|
||||||
|
goto cmd_failed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goto exit_new;
|
||||||
|
|
||||||
|
cmd_failed:
|
||||||
|
ctrlr->codecs[cad] = NULL;
|
||||||
|
hda_codec_delete(codec);
|
||||||
|
codec = NULL;
|
||||||
|
|
||||||
|
exit_new:
|
||||||
return codec;
|
return codec;
|
||||||
}
|
}
|
||||||
|
|
|
@ -498,8 +498,11 @@ hda_hw_init(hda_controller* ctrlr)
|
||||||
for (idx=0; idx < HDA_MAXCODECS; idx++)
|
for (idx=0; idx < HDA_MAXCODECS; idx++)
|
||||||
if (ctrlr->codecsts & (1 << idx))
|
if (ctrlr->codecsts & (1 << idx))
|
||||||
hda_codec_new(ctrlr, idx);
|
hda_codec_new(ctrlr, idx);
|
||||||
|
|
||||||
return B_OK;
|
if (ctrlr->codecs[0] != NULL)
|
||||||
|
return B_OK;
|
||||||
|
else
|
||||||
|
rc = ENODEV;
|
||||||
|
|
||||||
corb_rirb_failed:
|
corb_rirb_failed:
|
||||||
REG32(ctrlr,INTCTL) = 0;
|
REG32(ctrlr,INTCTL) = 0;
|
||||||
|
|
Loading…
Reference in New Issue