diff --git a/src/add-ons/kernel/drivers/audio/hda/driver.c b/src/add-ons/kernel/drivers/audio/hda/driver.c index 750208375a..c65ed8b0b6 100644 --- a/src/add-ons/kernel/drivers/audio/hda/driver.c +++ b/src/add-ons/kernel/drivers/audio/hda/driver.c @@ -12,7 +12,7 @@ int32 api_version = B_CUR_DRIVER_API_VERSION; -hda_controller gCards[MAXCARDS]; +hda_controller gCards[MAX_CARDS]; uint32 gNumCards; pci_module_info* gPci; @@ -51,7 +51,8 @@ init_driver(void) gNumCards = 0; - for (i = 0; gPci->get_nth_pci_info(i, &info) == B_OK; i++) { + for (i = 0; gPci->get_nth_pci_info(i, &info) == B_OK + && gNumCards < MAX_CARDS; i++) { if (info.class_base == PCI_multimedia && info.class_sub == PCI_hd_audio) { gCards[gNumCards].pci_info = info; @@ -93,7 +94,7 @@ uninit_driver(void) const char** publish_devices(void) { - static const char* devs[MAXCARDS+1]; + static const char* devs[MAX_CARDS + 1]; long i; dprintf("IRA: %s\n", __func__); diff --git a/src/add-ons/kernel/drivers/audio/hda/driver.h b/src/add-ons/kernel/drivers/audio/hda/driver.h index db97afe9ed..642659fdb5 100644 --- a/src/add-ons/kernel/drivers/audio/hda/driver.h +++ b/src/add-ons/kernel/drivers/audio/hda/driver.h @@ -8,48 +8,48 @@ #ifndef _HDA_H_ #define _HDA_H_ -#include -#include -#include +#include +#include +#include #include #include #ifndef HAIKU_TARGET_PLATFORM_HAIKU - #define DEVFS_PATH_FORMAT "audio/multi/hda/%lu" - #include +# define DEVFS_PATH_FORMAT "audio/multi/hda/%lu" +# include #else - #define DEVFS_PATH_FORMAT "audio/hmulti/hda/%lu" - #include +# define DEVFS_PATH_FORMAT "audio/hmulti/hda/%lu" +# include #endif #include "hda_controller_defs.h" #include "hda_codec_defs.h" -#define MAXCARDS 4 +#define MAX_CARDS 4 /* values for the class_sub field for class_base = 0x04 (multimedia device) */ -#define PCI_hd_audio 3 +#define PCI_hd_audio 3 -#define HDA_MAXAFGS 15 -#define HDA_MAXCODECS 15 -#define HDA_MAXSTREAMS 16 -#define MAX_CODEC_RESPONSES 10 -#define MAXINPUTS 32 +#define HDA_MAX_AUDIO_GROUPS 15 +#define HDA_MAX_CODECS 15 +#define HDA_MAX_STREAMS 16 +#define MAX_CODEC_RESPONSES 10 +#define MAX_INPUTS 32 /* FIXME: Find out why we need so much! */ -#define DEFAULT_FRAMESPERBUF 4096 +#define DEFAULT_FRAMES_PER_BUFFER 4096 -typedef struct hda_controller_s hda_controller; -typedef struct hda_codec_s hda_codec; -typedef struct hda_afg_s hda_afg; +typedef struct hda_controller hda_controller; +typedef struct hda_codec hda_codec; +typedef struct hda_audio_group hda_audio_group; -#define STRMAXBUF 10 -#define STRMINBUF 2 +#define STREAM_MAX_BUFFERS 10 +#define STREAM_MIN_BUFFERS 2 enum { - STRM_PLAYBACK, - STRM_RECORD + STREAM_PLAYBACK, + STREAM_RECORD }; /* hda_stream_info @@ -58,24 +58,26 @@ enum { * which is can have multiple channels (for stereo or better). */ -typedef struct hda_stream_info_s { - uint32 id; /* HDA controller stream # */ +typedef struct hda_stream_info { + uint32 id; /* HDA controller stream # */ uint32 off; /* HDA I/O/B descriptor offset */ bool running; /* Is this stream active? */ spinlock lock; /* Write lock */ - uint32 pin_wid; /* PIN Widget ID */ - uint32 io_wid; /* Input/Output Converter Widget ID */ + uint32 pin_widget; /* PIN Widget ID */ + uint32 io_widget; /* Input/Output Converter Widget ID */ - uint32 samplerate; - uint32 sampleformat; + uint32 sample_rate; + uint32 sample_format; uint32 num_buffers; uint32 num_channels; - uint32 buffer_length; /* size of buffer in samples */ + uint32 buffer_length; /* size of buffer in samples */ uint32 sample_size; - void* buffers[STRMAXBUF]; /* Virtual addresses for buffer */ - uint32 buffers_pa[STRMAXBUF]; /* Physical addresses for buffer */ + void* buffers[STREAM_MAX_BUFFERS]; + /* Virtual addresses for buffer */ + uint32 physical_buffers[STREAM_MAX_BUFFERS]; + /* Physical addresses for buffer */ sem_id buffer_ready_sem; bigtime_t real_time; uint32 frames_count; @@ -84,38 +86,36 @@ typedef struct hda_stream_info_s { uint32 rate, bps; /* Samplerate & bits per sample */ area_id buffer_area; - area_id bdl_area; - uint32 bdl_pa; /* BDL physical address */ + area_id buffer_descriptors_area; + uint32 physical_buffer_descriptors; /* BDL physical address */ } hda_stream; -/* hda_afg +/* hda_audio_group * * This structure describes a single Audio Function Group. An afg * is a group of audio widgets which can be used to configure multiple * streams of audio either from the HDA Link to an output device (= playback) * or from an input device to the HDA link (= recording). */ - -struct hda_afg_s { - hda_codec* codec; +struct hda_audio_group { + hda_codec* codec; /* Multi Audio API data */ - hda_stream* playback_stream; - hda_stream* record_stream; + hda_stream* playback_stream; + hda_stream* record_stream; - - uint32 root_nid, - wid_start, - wid_count; - - uint32 deffmts, - defrates, - defpm; + uint32 root_node_id; + uint32 widget_start; + uint32 widget_count; + + uint32 supported_formats; + uint32 supported_rates; + uint32 supported_pm; struct { uint32 num_inputs; int32 active_input; - uint32 inputs[MAXINPUTS]; + uint32 inputs[MAX_INPUTS]; uint32 flags; hda_widget_type type; @@ -133,9 +133,9 @@ struct hda_afg_s { struct { } mixer; struct { - uint32 output; - uint32 input; - pin_dev_type device; + uint32 output; + uint32 input; + pin_dev_type device; } pin; } d; } *widgets; @@ -150,22 +150,21 @@ struct hda_afg_s { * * NOTE: Atm, only Audio Function Groups are supported. */ +struct hda_codec { + uint16 vendor_id; + uint16 product_id; + uint8 revision; + uint16 stepping; + uint8 addr; -struct hda_codec_s { - uint16 vendor_id; - uint16 product_id; - uint8 hda_rev; - uint16 rev_stepping; - uint8 addr; + sem_id response_sem; + uint32 responses[MAX_CODEC_RESPONSES]; + uint32 response_count; - sem_id response_sem; - uint32 responses[MAX_CODEC_RESPONSES]; - uint32 response_count; + hda_audio_group* audio_groups[HDA_MAX_AUDIO_GROUPS]; + uint32 num_audio_groups; - hda_afg* afgs[HDA_MAXAFGS]; - uint32 num_afgs; - - struct hda_controller_s* controller; + struct hda_controller* controller; }; /* hda_controller @@ -175,61 +174,61 @@ struct hda_codec_s { * for use by the codecs contained, and the messaging queue * (verb/response) buffers for communication. */ - -struct hda_controller_s { +struct hda_controller { struct pci_info pci_info; - vuint32 opened; - const char* devfs_path; - - area_id regs_area; - vuint8* regs; - uint32 irq; + vuint32 opened; + const char* devfs_path; - uint16 codecsts; - uint32 num_input_streams; - uint32 num_output_streams; - uint32 num_bidir_streams; - - uint32 corblen; - uint32 rirblen; - uint32 rirbrp; - uint32 corbwp; - area_id rb_area; - corb_t* corb; - rirb_t* rirb; + area_id regs_area; + vuint8* regs; + uint32 irq; - hda_codec* codecs[HDA_MAXCODECS]; + uint16 codecsts; + uint32 num_input_streams; + uint32 num_output_streams; + uint32 num_bidir_streams; + + uint32 corb_length; + uint32 rirb_length; + uint32 rirbrp; + uint32 corbwp; + area_id rb_area; + corb_t* corb; + rirb_t* rirb; + + hda_codec* codecs[HDA_MAX_CODECS]; hda_codec* active_codec; uint32 num_codecs; - hda_stream* streams[HDA_MAXSTREAMS]; + hda_stream* streams[HDA_MAX_STREAMS]; }; /* driver.c */ extern device_hooks gDriverHooks; extern pci_module_info* gPci; -extern hda_controller gCards[MAXCARDS]; +extern hda_controller gCards[MAX_CARDS]; extern uint32 gNumCards; /* hda_codec.c */ hda_codec* hda_codec_new(hda_controller* controller, uint32 cad); -void hda_codec_delete(hda_codec*); +void hda_codec_delete(hda_codec* codec); /* hda_multi_audio.c */ -status_t multi_audio_control(void* cookie, uint32 op, void* arg, size_t len); +status_t multi_audio_control(void* cookie, uint32 op, void* arg, size_t length); /* hda_controller.c: Basic controller support */ status_t hda_hw_init(hda_controller* controller); void hda_hw_stop(hda_controller* controller); void hda_hw_uninit(hda_controller* controller); -status_t hda_send_verbs(hda_codec* codec, corb_t* verbs, uint32* responses, int count); +status_t hda_send_verbs(hda_codec* codec, corb_t* verbs, uint32* responses, + int count); /* hda_controller.c: Stream support */ hda_stream* hda_stream_new(hda_controller* controller, int type); -void hda_stream_delete(hda_stream* s); -status_t hda_stream_setup_buffers(hda_afg* afg, hda_stream* s, const char* desc); -status_t hda_stream_start(hda_controller* controller, hda_stream* s); -status_t hda_stream_stop(hda_controller* controller, hda_stream* s); -status_t hda_stream_check_intr(hda_controller* controller, hda_stream* s); +void hda_stream_delete(hda_stream* stream); +status_t hda_stream_setup_buffers(hda_audio_group* audioGroup, + hda_stream* stream, const char* desc); +status_t hda_stream_start(hda_controller* controller, hda_stream* stream); +status_t hda_stream_stop(hda_controller* controller, hda_stream* stream); -#endif /* _HDA_H_ */ +#endif /* _HDA_H_ */ diff --git a/src/add-ons/kernel/drivers/audio/hda/hda_codec.c b/src/add-ons/kernel/drivers/audio/hda/hda_codec.c index dae6f30c71..f31ad97375 100644 --- a/src/add-ons/kernel/drivers/audio/hda/hda_codec.c +++ b/src/add-ons/kernel/drivers/audio/hda/hda_codec.c @@ -34,9 +34,9 @@ static const char* kJackColor[] = { static status_t -hda_widget_get_pm_support(hda_codec* codec, uint32 nid, uint32* pm) +hda_widget_get_pm_support(hda_codec* codec, uint32 nodeID, uint32* pm) { - corb_t verb = MAKE_VERB(codec->addr, nid, VID_GET_PARAM, + corb_t verb = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAM, PID_POWERSTATE_SUPPORT); status_t rc; uint32 resp; @@ -56,72 +56,77 @@ hda_widget_get_pm_support(hda_codec* codec, uint32 nid, uint32* pm) static status_t -hda_widget_get_stream_support(hda_codec* codec, uint32 nid, uint32* fmts, +hda_widget_get_stream_support(hda_codec* codec, uint32 nodeID, uint32* formats, uint32* rates) { corb_t verbs[2]; uint32 resp[2]; - status_t rc; + status_t status; - verbs[0] = MAKE_VERB(codec->addr,nid,VID_GET_PARAM,PID_STREAM_SUPPORT); - verbs[1] = MAKE_VERB(codec->addr,nid,VID_GET_PARAM,PID_PCM_SUPPORT); - if ((rc = hda_send_verbs(codec, verbs, resp, 2)) == B_OK) { - *fmts = 0; *rates = 0; + verbs[0] = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAM, PID_STREAM_SUPPORT); + verbs[1] = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAM, PID_PCM_SUPPORT); - if (resp[2] & (1 << 0)) { - if (resp[1] & (1 << 0)) - *rates |= B_SR_8000; - if (resp[1] & (1 << 1)) - *rates |= B_SR_11025; - if (resp[1] & (1 << 2)) - *rates |= B_SR_16000; - if (resp[1] & (1 << 3)) - *rates |= B_SR_22050; - if (resp[1] & (1 << 4)) - *rates |= B_SR_32000; - if (resp[1] & (1 << 5)) - *rates |= B_SR_44100; - if (resp[1] & (1 << 6)) - *rates |= B_SR_48000; - if (resp[1] & (1 << 7)) - *rates |= B_SR_88200; - if (resp[1] & (1 << 8)) - *rates |= B_SR_96000; - if (resp[1] & (1 << 9)) - *rates |= B_SR_176400; - if (resp[1] & (1 << 10)) - *rates |= B_SR_192000; - if (resp[1] & (1 << 11)) - *rates |= B_SR_384000; + status = hda_send_verbs(codec, verbs, resp, 2); + if (status != B_OK) + return status; - if (resp[1] & (1 << 16)) - *fmts |= B_FMT_8BIT_S; - if (resp[1] & (1 << 17)) - *fmts |= B_FMT_16BIT; - if (resp[1] & (1 << 18)) - *fmts |= B_FMT_18BIT; - if (resp[1] & (1 << 19)) - *fmts |= B_FMT_24BIT; - if (resp[1] & (1 << 20)) - *fmts |= B_FMT_32BIT; - } + *formats = 0; + *rates = 0; -//FIXME: if (resp[0] & (1 << 1)) *fmts |= B_FMT_FLOAT; -//FIXME: if (resp[0] & (1 << 2)) /* Sort out how to handle AC3 */; + if ((resp[0] & (STREAM_FLOAT | STREAM_PCM)) != 0) { + if (resp[1] & (1 << 0)) + *rates |= B_SR_8000; + if (resp[1] & (1 << 1)) + *rates |= B_SR_11025; + if (resp[1] & (1 << 2)) + *rates |= B_SR_16000; + if (resp[1] & (1 << 3)) + *rates |= B_SR_22050; + if (resp[1] & (1 << 4)) + *rates |= B_SR_32000; + if (resp[1] & (1 << 5)) + *rates |= B_SR_44100; + if (resp[1] & (1 << 6)) + *rates |= B_SR_48000; + if (resp[1] & (1 << 7)) + *rates |= B_SR_88200; + if (resp[1] & (1 << 8)) + *rates |= B_SR_96000; + if (resp[1] & (1 << 9)) + *rates |= B_SR_176400; + if (resp[1] & (1 << 10)) + *rates |= B_SR_192000; + if (resp[1] & (1 << 11)) + *rates |= B_SR_384000; + + if (resp[1] & PCM_8_BIT) + *formats |= B_FMT_8BIT_S; + if (resp[1] & PCM_16_BIT) + *formats |= B_FMT_16BIT; + if (resp[1] & PCM_20_BIT) + *formats |= B_FMT_20BIT; + if (resp[1] & PCM_24_BIT) + *formats |= B_FMT_24BIT; + if (resp[1] & PCM_32_BIT) + *formats |= B_FMT_32BIT; } + if ((resp[0] & STREAM_FLOAT) != 0) + *formats |= B_FMT_FLOAT; - return rc; +//FIXME: if (resp[0] & (1 << 2)) /* Sort out how to handle AC3 */; + + return B_OK; } static status_t -hda_widget_get_amplifier_capabilities(hda_codec* codec, uint32 nid) +hda_widget_get_amplifier_capabilities(hda_codec* codec, uint32 nodeID) { status_t rc; corb_t verb; uint32 resp; - verb = MAKE_VERB(codec->addr, nid, VID_GET_PARAM, PID_OUTPUT_AMP_CAP); + verb = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAM, PID_OUTPUT_AMP_CAP); rc = hda_send_verbs(codec, &verb, &resp, 1); if (rc == B_OK && resp != 0) { dprintf("\tAMP: Mute: %s, step size: %ld, # steps: %ld, offset: %ld\n", @@ -136,202 +141,207 @@ hda_widget_get_amplifier_capabilities(hda_codec* codec, uint32 nid) static status_t -hda_codec_parse_afg(hda_afg* afg) +hda_codec_parse_audio_group(hda_audio_group* audioGroup) { corb_t verbs[6]; uint32 resp[6]; uint32 widx; - hda_widget_get_stream_support(afg->codec, afg->root_nid, &afg->deffmts, - &afg->defrates); - hda_widget_get_pm_support(afg->codec, afg->root_nid, &afg->defpm); + hda_widget_get_stream_support(audioGroup->codec, audioGroup->root_node_id, + &audioGroup->supported_formats, &audioGroup->supported_rates); + hda_widget_get_pm_support(audioGroup->codec, audioGroup->root_node_id, + &audioGroup->supported_pm); - verbs[0] = MAKE_VERB(afg->codec->addr, afg->root_nid, VID_GET_PARAM, - PID_AUDIO_FG_CAP); - verbs[1] = MAKE_VERB(afg->codec->addr, afg->root_nid, VID_GET_PARAM, - PID_GPIO_COUNT); - verbs[2] = MAKE_VERB(afg->codec->addr, afg->root_nid, VID_GET_PARAM, - PID_SUBORD_NODE_COUNT); + verbs[0] = MAKE_VERB(audioGroup->codec->addr, audioGroup->root_node_id, + VID_GET_PARAM, PID_AUDIO_FG_CAP); + verbs[1] = MAKE_VERB(audioGroup->codec->addr, audioGroup->root_node_id, + VID_GET_PARAM, PID_GPIO_COUNT); + verbs[2] = MAKE_VERB(audioGroup->codec->addr, audioGroup->root_node_id, + VID_GET_PARAM, PID_SUBORD_NODE_COUNT); - if (hda_send_verbs(afg->codec, verbs, resp, 3) == B_OK) { - dprintf("%s: Output delay: %ld samples, Input delay: %ld samples, " - "Beep Generator: %s\n", __func__, resp[0] & 0xf, - (resp[0] >> 8) & 0xf, (resp[0] & (1 << 16)) ? "yes" : "no"); + if (hda_send_verbs(audioGroup->codec, verbs, resp, 3) != B_OK) + return B_ERROR; - dprintf("%s: #GPIO: %ld, #GPO: %ld, #GPI: %ld, unsol: %s, wake: %s\n", - __func__, resp[4] & 0xFF, (resp[1] >> 8) & 0xFF, - (resp[1] >> 16) & 0xFF, (resp[1] & (1 << 30)) ? "yes" : "no", - (resp[1] & (1 << 31)) ? "yes" : "no"); + dprintf("%s: Output delay: %ld samples, Input delay: %ld samples, " + "Beep Generator: %s\n", __func__, resp[0] & 0xf, + (resp[0] >> 8) & 0xf, (resp[0] & (1 << 16)) ? "yes" : "no"); - afg->wid_start = resp[2] >> 16; - afg->wid_count = resp[2] & 0xFF; + dprintf("%s: #GPIO: %ld, #GPO: %ld, #GPI: %ld, unsol: %s, wake: %s\n", + __func__, resp[4] & 0xFF, (resp[1] >> 8) & 0xFF, + (resp[1] >> 16) & 0xFF, (resp[1] & (1 << 30)) ? "yes" : "no", + (resp[1] & (1 << 31)) ? "yes" : "no"); - afg->widgets = calloc(afg->wid_count, sizeof(*afg->widgets)); - if (afg->widgets == NULL) { - dprintf("ERROR: Not enough memory!\n"); - return B_NO_MEMORY; + audioGroup->widget_start = resp[2] >> 16; + audioGroup->widget_count = resp[2] & 0xFF; + + audioGroup->widgets = calloc(audioGroup->widget_count, + sizeof(*audioGroup->widgets)); + if (audioGroup->widgets == NULL) { + dprintf("ERROR: Not enough memory!\n"); + return B_NO_MEMORY; + } + + /* Iterate over all Widgets and collect info */ + for (widx = 0; widx < audioGroup->widget_count; widx++) { + uint32 wid = audioGroup->widget_start + widx; + char buf[256]; + int off; + + verbs[0] = MAKE_VERB(audioGroup->codec->addr, wid, VID_GET_PARAM, + PID_AUDIO_WIDGET_CAP); + verbs[1] = MAKE_VERB(audioGroup->codec->addr, wid, VID_GET_PARAM, + PID_CONNLIST_LEN); + hda_send_verbs(audioGroup->codec, verbs, resp, 2); + + audioGroup->widgets[widx].type = resp[0] >> 20; + audioGroup->widgets[widx].num_inputs = resp[1] & 0x7F; + + off = 0; + if (resp[0] & (1 << 11)) + off += sprintf(buf + off, "[L-R Swap] "); + + if (resp[0] & (1 << 10)) { + corb_t verb; + uint32 resp; + + off += sprintf(buf+off, "[Power] "); + + /* We support power; switch us on! */ + verb = MAKE_VERB(audioGroup->codec->addr, wid, + VID_SET_POWERSTATE, 0); + hda_send_verbs(audioGroup->codec, &verb, &resp, 1); } - /* Iterate over all Widgets and collect info */ - for (widx = 0; widx < afg->wid_count; widx++) { - uint32 wid = afg->wid_start + widx; - char buf[256]; - int off; + if (resp[0] & (1 << 9)) + off += sprintf(buf + off, "[Digital] "); + if (resp[0] & (1 << 7)) + off += sprintf(buf + off, "[Unsol Capable] "); + if (resp[0] & (1 << 6)) + off += sprintf(buf + off, "[Proc Widget] "); + if (resp[0] & (1 << 5)) + off += sprintf(buf + off, "[Stripe] "); + if (resp[0] & (1 << 4)) + off += sprintf(buf + off, "[Format Override] "); + if (resp[0] & (1 << 3)) + off += sprintf(buf + off, "[Amp Param Override] "); + if (resp[0] & (1 << 2)) + off += sprintf(buf + off, "[Out Amp] "); + if (resp[0] & (1 << 1)) + off += sprintf(buf + off, "[In Amp] "); + if (resp[0] & (1 << 0)) + off += sprintf(buf + off, "[Stereo] "); - verbs[0] = MAKE_VERB(afg->codec->addr, wid, VID_GET_PARAM, - PID_AUDIO_WIDGET_CAP); - verbs[1] = MAKE_VERB(afg->codec->addr, wid, VID_GET_PARAM, - PID_CONNLIST_LEN); - hda_send_verbs(afg->codec, verbs, resp, 2); + switch (audioGroup->widgets[widx].type) { + case WT_AUDIO_OUTPUT: + dprintf("%ld:\tAudio Output\n", wid); + hda_widget_get_stream_support(audioGroup->codec, wid, + &audioGroup->widgets[widx].d.input.formats, + &audioGroup->widgets[widx].d.input.rates); + hda_widget_get_amplifier_capabilities(audioGroup->codec, wid); + break; + case WT_AUDIO_INPUT: + dprintf("%ld:\tAudio Input\n", wid); + hda_widget_get_stream_support(audioGroup->codec, wid, + &audioGroup->widgets[widx].d.input.formats, + &audioGroup->widgets[widx].d.input.rates); + hda_widget_get_amplifier_capabilities(audioGroup->codec, wid); + break; + case WT_AUDIO_MIXER: + dprintf("%ld:\tAudio Mixer\n", wid); + hda_widget_get_amplifier_capabilities(audioGroup->codec, wid); + break; + case WT_AUDIO_SELECTOR: + dprintf("%ld:\tAudio Selector\n", wid); + hda_widget_get_amplifier_capabilities(audioGroup->codec, wid); + break; + case WT_PIN_COMPLEX: + dprintf("%ld:\tPin Complex\n", wid); + verbs[0] = MAKE_VERB(audioGroup->codec->addr, wid, VID_GET_PARAM, + PID_PIN_CAP); + if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) { + audioGroup->widgets[widx].d.pin.input = resp[0] & (1 << 5); + audioGroup->widgets[widx].d.pin.output = resp[0] & (1 << 4); - afg->widgets[widx].type = resp[0] >> 20; - afg->widgets[widx].num_inputs = resp[1] & 0x7F; - - off = 0; - if (resp[0] & (1 << 11)) - off += sprintf(buf + off, "[L-R Swap] "); - - if (resp[0] & (1 << 10)) { - corb_t verb; - uint32 resp; - - off += sprintf(buf+off, "[Power] "); - - /* We support power; switch us on! */ - verb = MAKE_VERB(afg->codec->addr, wid, VID_SET_POWERSTATE, 0); - hda_send_verbs(afg->codec, &verb, &resp, 1); - } - - if (resp[0] & (1 << 9)) - off += sprintf(buf + off, "[Digital] "); - if (resp[0] & (1 << 7)) - off += sprintf(buf + off, "[Unsol Capable] "); - if (resp[0] & (1 << 6)) - off += sprintf(buf + off, "[Proc Widget] "); - if (resp[0] & (1 << 5)) - off += sprintf(buf + off, "[Stripe] "); - if (resp[0] & (1 << 4)) - off += sprintf(buf + off, "[Format Override] "); - if (resp[0] & (1 << 3)) - off += sprintf(buf + off, "[Amp Param Override] "); - if (resp[0] & (1 << 2)) - off += sprintf(buf + off, "[Out Amp] "); - if (resp[0] & (1 << 1)) - off += sprintf(buf + off, "[In Amp] "); - if (resp[0] & (1 << 0)) - off += sprintf(buf + off, "[Stereo] "); - - switch (afg->widgets[widx].type) { - case WT_AUDIO_OUTPUT: - dprintf("%ld:\tAudio Output\n", wid); - hda_widget_get_stream_support(afg->codec, wid, - &afg->widgets[widx].d.input.formats, - &afg->widgets[widx].d.input.rates); - hda_widget_get_amplifier_capabilities(afg->codec, wid); - break; - case WT_AUDIO_INPUT: - dprintf("%ld:\tAudio Input\n", wid); - hda_widget_get_stream_support(afg->codec, wid, - &afg->widgets[widx].d.input.formats, - &afg->widgets[widx].d.input.rates); - hda_widget_get_amplifier_capabilities(afg->codec, wid); - break; - case WT_AUDIO_MIXER: - dprintf("%ld:\tAudio Mixer\n", wid); - hda_widget_get_amplifier_capabilities(afg->codec, wid); - break; - case WT_AUDIO_SELECTOR: - dprintf("%ld:\tAudio Selector\n", wid); - hda_widget_get_amplifier_capabilities(afg->codec, wid); - break; - case WT_PIN_COMPLEX: - dprintf("%ld:\tPin Complex\n", wid); - verbs[0] = MAKE_VERB(afg->codec->addr, wid, VID_GET_PARAM, - PID_PIN_CAP); - 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.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); - if (hda_send_verbs(afg->codec, verbs, resp, 1) == B_OK) { - afg->widgets[widx].d.pin.device = (resp[0] >> 20) & 0xF; - dprintf("\t%s, %s, %s, %s\n", - kPortConnector[resp[0] >> 30], - kDefaultDevice[afg->widgets[widx].d.pin.device], - kConnectionType[(resp[0] >> 16) & 0xF], - kJackColor[(resp[0] >> 12) & 0xF]); - } - - hda_widget_get_amplifier_capabilities(afg->codec, wid); - break; - case WT_POWER: - dprintf("%ld:\tPower\n", wid); - break; - case WT_VOLUME_KNOB: - dprintf("%ld:\tVolume Knob\n", wid); - break; - case WT_BEEP_GENERATOR: - dprintf("%ld:\tBeep Generator\n", wid); - break; - case WT_VENDOR_DEFINED: - dprintf("%ld:\tVendor Defined\n", wid); - break; - default: /* Reserved */ - break; - } - - dprintf("\t%s\n", buf); - - hda_widget_get_pm_support(afg->codec, wid, &afg->widgets[widx].pm); - - if (afg->widgets[widx].num_inputs) { - int idx; - - off = 0; - - if (afg->widgets[widx].num_inputs > 1) { - verbs[0] = MAKE_VERB(afg->codec->addr, wid, VID_GET_CONNSEL, - 0); - if (hda_send_verbs(afg->codec, verbs, resp, 1) == B_OK) - afg->widgets[widx].active_input = resp[0] & 0xFF; - else - afg->widgets[widx].active_input = -1; - } else - afg->widgets[widx].active_input = -1; - - for (idx = 0; idx < afg->widgets[widx].num_inputs; idx ++) { - if (!(idx % 4)) { - verbs[0] = MAKE_VERB(afg->codec->addr, wid, - VID_GET_CONNLENTRY, idx); - if (hda_send_verbs(afg->codec, verbs, resp, 1) != B_OK) { - dprintf("%s: Error parsing inputs for widget %ld!\n", - __func__, wid); - break; - } - } - - if (idx != afg->widgets[widx].active_input) { - off += sprintf(buf + off, "%ld ", - (resp[0] >> (8*(idx%4))) & 0xFF); - } else { - off += sprintf(buf + off, "(%ld) ", - (resp[0] >> (8*(idx%4))) & 0xFF); - } - - afg->widgets[widx].inputs[idx] = (resp[0] >> (8*(idx%4))) - & 0xFF; + dprintf("\t%s%s\n", + audioGroup->widgets[widx].d.pin.input ? "[Input] " : "", + audioGroup->widgets[widx].d.pin.input ? "[Output]" : ""); + } else { + dprintf("%s: Error getting Pin Complex IO\n", __func__); } - dprintf("\t[ %s]\n", buf); + verbs[0] = MAKE_VERB(audioGroup->codec->addr, wid, + VID_GET_CFGDEFAULT, 0); + if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) { + audioGroup->widgets[widx].d.pin.device = (resp[0] >> 20) & 0xF; + dprintf("\t%s, %s, %s, %s\n", + kPortConnector[resp[0] >> 30], + kDefaultDevice[audioGroup->widgets[widx].d.pin.device], + kConnectionType[(resp[0] >> 16) & 0xF], + kJackColor[(resp[0] >> 12) & 0xF]); + } + + hda_widget_get_amplifier_capabilities(audioGroup->codec, wid); + break; + case WT_POWER: + dprintf("%ld:\tPower\n", wid); + break; + case WT_VOLUME_KNOB: + dprintf("%ld:\tVolume Knob\n", wid); + break; + case WT_BEEP_GENERATOR: + dprintf("%ld:\tBeep Generator\n", wid); + break; + case WT_VENDOR_DEFINED: + dprintf("%ld:\tVendor Defined\n", wid); + break; + default: /* Reserved */ + break; + } + + dprintf("\t%s\n", buf); + + hda_widget_get_pm_support(audioGroup->codec, wid, + &audioGroup->widgets[widx].pm); + + if (audioGroup->widgets[widx].num_inputs) { + int idx; + + off = 0; + + if (audioGroup->widgets[widx].num_inputs > 1) { + verbs[0] = MAKE_VERB(audioGroup->codec->addr, wid, + VID_GET_CONNSEL, 0); + if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) + audioGroup->widgets[widx].active_input = resp[0] & 0xFF; + else + audioGroup->widgets[widx].active_input = -1; + } else + audioGroup->widgets[widx].active_input = -1; + + for (idx = 0; idx < audioGroup->widgets[widx].num_inputs; idx ++) { + if (!(idx % 4)) { + verbs[0] = MAKE_VERB(audioGroup->codec->addr, wid, + VID_GET_CONNLENTRY, idx); + if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) != B_OK) { + dprintf("%s: Error parsing inputs for widget %ld!\n", + __func__, wid); + break; + } + } + + if (idx != audioGroup->widgets[widx].active_input) { + off += sprintf(buf + off, "%ld ", + (resp[0] >> (8 * (idx % 4))) & 0xff); + } else { + off += sprintf(buf + off, "(%ld) ", + (resp[0] >> (8 * (idx % 4))) & 0xff); + } + + audioGroup->widgets[widx].inputs[idx] + = (resp[0] >> (8 * (idx % 4))) & 0xff; } + + dprintf("\t[ %s]\n", buf); } } @@ -343,38 +353,42 @@ hda_codec_parse_afg(hda_afg* afg) * Returns 0 if not found. */ static uint32 -hda_codec_afg_find_path(hda_afg* afg, uint32 wid, uint32 wtype, uint32 depth) +hda_codec_audio_group_find_path(hda_audio_group* audioGroup, uint32 widget, + uint32 widgetType, uint32 depth) { - int widx = wid - afg->wid_start; + int widx = widget - audioGroup->widget_start; int idx; - switch (afg->widgets[widx].type) { + switch (audioGroup->widgets[widx].type) { case WT_AUDIO_MIXER: - for (idx = 0; idx < afg->widgets[widx].num_inputs; idx++) { - if (hda_codec_afg_find_path(afg, afg->widgets[widx].inputs[idx], wtype, depth +1)) { - if (afg->widgets[widx].active_input == -1) - afg->widgets[widx].active_input = idx; + for (idx = 0; idx < audioGroup->widgets[widx].num_inputs; idx++) { + if (hda_codec_audio_group_find_path(audioGroup, + audioGroup->widgets[widx].inputs[idx], widgetType, + depth + 1)) { + if (audioGroup->widgets[widx].active_input == -1) + audioGroup->widgets[widx].active_input = idx; - return afg->widgets[widx].inputs[idx]; + return audioGroup->widgets[widx].inputs[idx]; } } break; case WT_AUDIO_SELECTOR: { - int idx = afg->widgets[widx].active_input; + int idx = audioGroup->widgets[widx].active_input; if (idx != -1) { - uint32 wid = afg->widgets[widx].inputs[idx]; - if (hda_codec_afg_find_path(afg, wid, wtype, depth + 1)) { - return wid; + widget = audioGroup->widgets[widx].inputs[idx]; + if (hda_codec_audio_group_find_path(audioGroup, widget, + widgetType, depth + 1)) { + return widget; } } break; } default: - if (afg->widgets[widx].type == wtype) - return wid; + if (audioGroup->widgets[widx].type == widgetType) + return widget; break; } @@ -384,69 +398,68 @@ hda_codec_afg_find_path(hda_afg* afg, uint32 wid, uint32 wtype, uint32 depth) static void -hda_afg_delete(hda_afg* afg) +hda_codec_delete_audio_group(hda_audio_group* audioGroup) { - if (afg != NULL) { - if (afg->playback_stream != NULL) - hda_stream_delete(afg->playback_stream); + if (audioGroup == NULL) + return; - if (afg->record_stream != NULL) - hda_stream_delete(afg->record_stream); + if (audioGroup->playback_stream != NULL) + hda_stream_delete(audioGroup->playback_stream); - if (afg->widgets) - free(afg->widgets); - - free(afg); - } + if (audioGroup->record_stream != NULL) + hda_stream_delete(audioGroup->record_stream); + + free(audioGroup->widgets); + free(audioGroup); } static status_t -hda_codec_afg_new(hda_codec* codec, uint32 afg_nid) +hda_codec_new_audio_group(hda_codec* codec, uint32 audioGroupNodeID) { - hda_afg* afg; + hda_audio_group* audioGroup; status_t rc; uint32 idx; - if ((afg = calloc(1, sizeof(hda_afg))) == NULL) { + if ((audioGroup = calloc(1, sizeof(hda_audio_group))) == NULL) { rc = B_NO_MEMORY; goto done; } /* Setup minimal info needed by hda_codec_parse_afg */ - afg->root_nid = afg_nid; - afg->codec = codec; + audioGroup->root_node_id = audioGroupNodeID; + audioGroup->codec = codec; /* Parse all widgets in Audio Function Group */ - rc = hda_codec_parse_afg(afg); + rc = hda_codec_parse_audio_group(audioGroup); if (rc != B_OK) - goto free_afg; + goto free_audio_group; /* Setup for worst-case scenario; we cannot find any output Pin Widgets */ rc = ENODEV; /* Try to locate all input/output channels */ - for (idx = 0; idx < afg->wid_count; idx++) { - uint32 output_wid = 0, input_wid = 0; + for (idx = 0; idx < audioGroup->widget_count; idx++) { + uint32 outputWidget = 0, inputWidget = 0; int32 iidx; - if (afg->playback_stream == NULL - && afg->widgets[idx].type == WT_PIN_COMPLEX - && afg->widgets[idx].d.pin.output) { - if (afg->widgets[idx].d.pin.device == PIN_DEV_HP_OUT - || 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; + if (audioGroup->playback_stream == NULL + && audioGroup->widgets[idx].type == WT_PIN_COMPLEX + && audioGroup->widgets[idx].d.pin.output) { + if (audioGroup->widgets[idx].d.pin.device == PIN_DEV_HP_OUT + || audioGroup->widgets[idx].d.pin.device == PIN_DEV_SPEAKER + || audioGroup->widgets[idx].d.pin.device == PIN_DEV_LINE_OUT) { + iidx = audioGroup->widgets[idx].active_input; if (iidx != -1) { - output_wid = hda_codec_afg_find_path(afg, - afg->widgets[idx].inputs[iidx], WT_AUDIO_OUTPUT, 0); + outputWidget = hda_codec_audio_group_find_path(audioGroup, + audioGroup->widgets[idx].inputs[iidx], WT_AUDIO_OUTPUT, 0); } else { - for (iidx = 0; iidx < afg->widgets[idx].num_inputs; iidx++) { - output_wid = hda_codec_afg_find_path(afg, - afg->widgets[idx].inputs[iidx], WT_AUDIO_OUTPUT, 0); - if (output_wid) { + for (iidx = 0; iidx < audioGroup->widgets[idx].num_inputs; iidx++) { + outputWidget = hda_codec_audio_group_find_path(audioGroup, + audioGroup->widgets[idx].inputs[iidx], WT_AUDIO_OUTPUT, 0); + if (outputWidget) { corb_t verb = MAKE_VERB(codec->addr, - idx + afg->wid_start, VID_SET_CONNSEL, iidx); + idx + audioGroup->widget_start, VID_SET_CONNSEL, iidx); if (hda_send_verbs(codec, &verb, NULL, 1) != B_OK) dprintf("%s: Setting output selector failed!\n", __func__); break; @@ -454,48 +467,50 @@ hda_codec_afg_new(hda_codec* codec, uint32 afg_nid) } } - if (output_wid) { - if (!afg->playback_stream) { + if (outputWidget) { + if (!audioGroup->playback_stream) { corb_t verb[2]; /* Setup playback/record streams for Multi Audio API */ - afg->playback_stream = hda_stream_new( - afg->codec->controller, STRM_PLAYBACK); - afg->record_stream = hda_stream_new( - afg->codec->controller, STRM_RECORD); + audioGroup->playback_stream = hda_stream_new( + audioGroup->codec->controller, STREAM_PLAYBACK); + audioGroup->record_stream = hda_stream_new( + audioGroup->codec->controller, STREAM_RECORD); - afg->playback_stream->pin_wid = idx + afg->wid_start; - afg->playback_stream->io_wid = output_wid; + audioGroup->playback_stream->pin_widget = idx + + audioGroup->widget_start; + audioGroup->playback_stream->io_widget = outputWidget; /* FIXME: Force Pin Widget to unmute; enable hp/output */ verb[0] = MAKE_VERB(codec->addr, - afg->playback_stream->pin_wid, VID_SET_AMPGAINMUTE, + audioGroup->playback_stream->pin_widget, VID_SET_AMPGAINMUTE, (1 << 15) | (1 << 13) | (1 << 12)); verb[1] = MAKE_VERB(codec->addr, - afg->playback_stream->pin_wid, VID_SET_PINWCTRL, + audioGroup->playback_stream->pin_widget, VID_SET_PINWCTRL, (1 << 7) | (1 << 6)); hda_send_verbs(codec, verb, NULL, 2); dprintf("%s: Found output PIN (%s) connected to output " "CONV wid:%ld\n", __func__, - kDefaultDevice[afg->widgets[idx].d.pin.device], output_wid); + kDefaultDevice[audioGroup->widgets[idx].d.pin.device], outputWidget); } } } } - if (afg->widgets[idx].type == WT_AUDIO_INPUT) { - iidx = afg->widgets[idx].active_input; + if (audioGroup->widgets[idx].type == WT_AUDIO_INPUT) { + iidx = audioGroup->widgets[idx].active_input; if (iidx != -1) { - input_wid = hda_codec_afg_find_path(afg, - afg->widgets[idx].inputs[iidx], WT_PIN_COMPLEX, 0); + inputWidget = hda_codec_audio_group_find_path(audioGroup, + audioGroup->widgets[idx].inputs[iidx], WT_PIN_COMPLEX, 0); } else { - 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); - if (input_wid) { + for (iidx = 0; iidx < audioGroup->widgets[idx].num_inputs; iidx++) { + inputWidget = hda_codec_audio_group_find_path(audioGroup, + audioGroup->widgets[idx].inputs[iidx], WT_PIN_COMPLEX, 0); + if (inputWidget) { corb_t verb = MAKE_VERB(codec->addr, - idx + afg->wid_start, VID_SET_CONNSEL, iidx); + idx + audioGroup->widget_start, VID_SET_CONNSEL, + iidx); if (hda_send_verbs(codec, &verb, NULL, 1) != B_OK) { dprintf("%s: Setting input selector failed!\n", __func__); @@ -505,59 +520,64 @@ hda_codec_afg_new(hda_codec* codec, uint32 afg_nid) } } - if (input_wid) { - if (!afg->record_stream) { + if (inputWidget) { + if (!audioGroup->record_stream) { corb_t verb; /* Setup playback/record streams for Multi Audio API */ - afg->record_stream = hda_stream_new(afg->codec->controller, - STRM_RECORD); + audioGroup->record_stream = hda_stream_new( + audioGroup->codec->controller, STREAM_RECORD); - afg->record_stream->pin_wid = input_wid; - afg->record_stream->io_wid = idx + afg->wid_start; + audioGroup->record_stream->pin_widget = inputWidget; + audioGroup->record_stream->io_widget = idx + + audioGroup->widget_start; /* FIXME: Force Pin Widget to unmute */ - verb = MAKE_VERB(codec->addr, afg->record_stream->pin_wid, + verb = MAKE_VERB(codec->addr, + audioGroup->record_stream->pin_widget, 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__, kDefaultDevice[afg->widgets[ - input_wid-afg->wid_start].d.pin.device], - idx + afg->wid_start); + "wid:%ld\n", __func__, kDefaultDevice[audioGroup->widgets[ + inputWidget - audioGroup->widget_start].d.pin.device], + idx + audioGroup->widget_start); } } } /* If we found any valid output channels, we're in the clear */ - if (afg && afg->playback_stream) { - codec->afgs[codec->num_afgs++] = afg; + if (audioGroup && audioGroup->playback_stream) { + codec->audio_groups[codec->num_audio_groups++] = audioGroup; rc = B_OK; goto done; } -free_afg: - free(afg); +free_audio_group: + free(audioGroup); done: return rc; } +// #pragma mark - + + void hda_codec_delete(hda_codec* codec) { - if (codec != NULL) { + if (codec == NULL) { uint32 idx; - + delete_sem(codec->response_sem); - for (idx = 0; idx < codec->num_afgs; idx++) { - hda_afg_delete(codec->afgs[idx]); - codec->afgs[idx] = NULL; + for (idx = 0; idx < codec->num_audio_groups; idx++) { + hda_codec_delete_audio_group(codec->audio_groups[idx]); + codec->audio_groups[idx] = NULL; } - + free(codec); } } @@ -569,7 +589,7 @@ hda_codec_new(hda_controller* controller, uint32 cad) hda_codec* codec = calloc(1, sizeof(hda_codec)); uint32 responses[3]; corb_t verbs[3]; - uint32 nid; + uint32 nodeID; if (codec == NULL) goto exit_new; @@ -587,19 +607,19 @@ hda_codec_new(hda_controller* controller, uint32 cad) goto cmd_failed; dprintf("Codec %ld Vendor: %04lx Product: %04lx\n", - cad, responses[0] >> 16, responses[0] & 0xFFFF); + cad, responses[0] >> 16, responses[0] & 0xffff); - for (nid = responses[2] >> 16; - nid < (responses[2] >> 16) + (responses[2] & 0xFF); nid++) { + for (nodeID = responses[2] >> 16; + nodeID < (responses[2] >> 16) + (responses[2] & 0xff); nodeID++) { uint32 resp; - verbs[0] = MAKE_VERB(cad, nid, VID_GET_PARAM, PID_FUNCGRP_TYPE); + verbs[0] = MAKE_VERB(cad, nodeID, VID_GET_PARAM, PID_FUNCGRP_TYPE); if (hda_send_verbs(codec, verbs, &resp, 1) != B_OK) goto cmd_failed; - if ((resp & 0xFF) == 1) { + if ((resp & 0xff) == 1) { /* Found an Audio Function Group! */ - status_t rc = hda_codec_afg_new(codec, nid); + status_t rc = hda_codec_new_audio_group(codec, nodeID); if (rc != B_OK) { dprintf("%s: Failed to setup new audio function group (%s)!\n", __func__, strerror(rc)); diff --git a/src/add-ons/kernel/drivers/audio/hda/hda_codec_defs.h b/src/add-ons/kernel/drivers/audio/hda/hda_codec_defs.h index 8ed150a35b..1f4ff165c7 100644 --- a/src/add-ons/kernel/drivers/audio/hda/hda_codec_defs.h +++ b/src/add-ons/kernel/drivers/audio/hda/hda_codec_defs.h @@ -134,4 +134,16 @@ typedef enum { #define PID_OUTPUT_AMP_CAP 0x12 #define PID_VOLUMEKNOB_CAP 0x13 +/* PCM support */ +#define PCM_8_BIT (1L << 16) +#define PCM_16_BIT (1L << 17) +#define PCM_20_BIT (1L << 18) +#define PCM_24_BIT (1L << 19) +#define PCM_32_BIT (1L << 20) + +/* stream support */ +#define STREAM_AC3 0x00000004 +#define STREAM_FLOAT 0x00000002 +#define STREAM_PCM 0x00000001 + #endif /* HDA_CODEC_H */ diff --git a/src/add-ons/kernel/drivers/audio/hda/hda_controller.c b/src/add-ons/kernel/drivers/audio/hda/hda_controller.c index 97d6df47bf..1354f0bb14 100644 --- a/src/add-ons/kernel/drivers/audio/hda/hda_controller.c +++ b/src/add-ons/kernel/drivers/audio/hda/hda_controller.c @@ -21,8 +21,8 @@ hda_stream_delete(hda_stream* stream) if (stream->buffer_area >= B_OK) delete_area(stream->buffer_area); - if (stream->bdl_area >= B_OK) - delete_area(stream->bdl_area); + if (stream->buffer_descriptors_area >= B_OK) + delete_area(stream->buffer_descriptors_area); free(stream); } @@ -36,19 +36,19 @@ hda_stream_new(hda_controller* controller, int type) return NULL; stream->buffer_area = B_ERROR; - stream->bdl_area = B_ERROR; + stream->buffer_descriptors_area = B_ERROR; switch (type) { - case STRM_PLAYBACK: + case STREAM_PLAYBACK: stream->buffer_ready_sem = create_sem(0, "hda_playback_sem"); stream->id = 1; stream->off = (controller->num_input_streams * HDAC_SDSIZE); controller->streams[controller->num_input_streams] = stream; break; - - case STRM_RECORD: + + case STREAM_RECORD: stream->buffer_area = B_ERROR; - stream->bdl_area = B_ERROR; + stream->buffer_descriptors_area = B_ERROR; stream->buffer_ready_sem = create_sem(0, "hda_record_sem"); stream->id = 2; stream->off = 0; @@ -80,31 +80,35 @@ hda_stream_start(hda_controller* controller, hda_stream* stream) } -status_t +//! Called with interrupts off +static void hda_stream_check_intr(hda_controller* controller, hda_stream* stream) { - if (stream->running) { - uint8 sts = OREG8(controller, stream->off, STS); - if (sts) { - cpu_status status; + uint8 status; - OREG8(controller, stream->off, STS) = sts; - status = disable_interrupts(); - acquire_spinlock(&stream->lock); + if (!stream->running) + return; - stream->real_time = system_time(); - stream->frames_count += stream->buffer_length; - stream->buffer_cycle = (stream->buffer_cycle + 1) - % stream->num_buffers; + status = OREG8(controller, stream->off, STS); + if (status == 0) + return; - release_spinlock(&stream->lock); - restore_interrupts(status); + OREG8(controller, stream->off, STS) = status; - release_sem_etc(stream->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE); - } - } + if ((status & STS_BCIS) != 0) { + // Buffer Completed Interrupt + acquire_spinlock(&stream->lock); - return B_OK; + stream->real_time = system_time(); + stream->frames_count += stream->buffer_length; + stream->buffer_cycle = (stream->buffer_cycle + 1) + % stream->num_buffers; + + release_spinlock(&stream->lock); + + release_sem_etc(stream->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE); + } else + dprintf("HDA: stream status %x\n", status); } @@ -123,12 +127,13 @@ hda_stream_stop(hda_controller* controller, hda_stream* stream) status_t -hda_stream_setup_buffers(hda_afg* afg, hda_stream* stream, const char* desc) +hda_stream_setup_buffers(hda_audio_group* audioGroup, hda_stream* stream, + const char* desc) { uint32 bufferSize, bufferPhysicalAddress, alloc; uint32 response[2], index; physical_entry pe; - bdl_entry_t* bdl; + bdl_entry_t* bufferDescriptors; corb_t verb[2]; uint8* buffer; status_t rc; @@ -140,22 +145,24 @@ hda_stream_setup_buffers(hda_afg* afg, hda_stream* stream, const char* desc) stream->buffer_area = B_ERROR; } - if (stream->bdl_area >= B_OK) { - delete_area(stream->bdl_area); - stream->bdl_area = B_ERROR; + if (stream->buffer_descriptors_area >= B_OK) { + delete_area(stream->buffer_descriptors_area); + stream->buffer_descriptors_area = B_ERROR; } /* Calculate size of buffer (aligned to 128 bytes) */ bufferSize = stream->sample_size * stream->num_channels * stream->buffer_length; bufferSize = (bufferSize + 127) & (~127); - +dprintf("HDA: sample size %ld, num channels %ld, buffer length %ld ****************\n", + stream->sample_size, stream->num_channels, stream->buffer_length); + /* Calculate total size of all buffers (aligned to size of B_PAGE_SIZE) */ alloc = bufferSize * stream->num_buffers; alloc = (alloc + B_PAGE_SIZE - 1) & (~(B_PAGE_SIZE -1)); /* Allocate memory for buffers */ - stream->buffer_area = create_area("hda_buffers", (void**)&buffer, + stream->buffer_area = create_area("hda buffers", (void**)&buffer, B_ANY_KERNEL_ADDRESS, alloc, B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA); if (stream->buffer_area < B_OK) return stream->buffer_area; @@ -175,55 +182,58 @@ hda_stream_setup_buffers(hda_afg* afg, hda_stream* stream, const char* desc) /* Store pointers (both virtual/physical) */ for (index = 0; index < stream->num_buffers; index++) { stream->buffers[index] = buffer + (index * bufferSize); - stream->buffers_pa[index] = bufferPhysicalAddress + (index * bufferSize); + stream->physical_buffers[index] = bufferPhysicalAddress + + (index * bufferSize); } /* Now allocate BDL for buffer range */ alloc = stream->num_buffers * sizeof(bdl_entry_t); alloc = (alloc + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); - stream->bdl_area = create_area("hda_bdl", (void**)&bdl, - B_ANY_KERNEL_ADDRESS, alloc, B_CONTIGUOUS, 0); - if (stream->bdl_area < B_OK) { + stream->buffer_descriptors_area = create_area("hda buffer descriptors", + (void**)&bufferDescriptors, B_ANY_KERNEL_ADDRESS, alloc, + B_CONTIGUOUS, 0); + if (stream->buffer_descriptors_area < B_OK) { delete_area(stream->buffer_area); - return stream->bdl_area; + return stream->buffer_descriptors_area; } /* Get the physical address of memory */ - rc = get_memory_map(bdl, alloc, &pe, 1); + rc = get_memory_map(bufferDescriptors, alloc, &pe, 1); if (rc != B_OK) { delete_area(stream->buffer_area); - delete_area(stream->bdl_area); + delete_area(stream->buffer_descriptors_area); return rc; } - stream->bdl_pa = (uint32)pe.address; + stream->physical_buffer_descriptors = (uint32)pe.address; dprintf("%s(%s): Allocated %ld bytes for %ld BDLEs\n", __func__, desc, alloc, stream->num_buffers); /* Setup BDL entries */ - for (index = 0; index < stream->num_buffers; index++, bdl++) { - bdl->address = stream->buffers_pa[index]; - bdl->length = bufferSize; - bdl->ioc = 1; + for (index = 0; index < stream->num_buffers; index++, bufferDescriptors++) { + bufferDescriptors->address = stream->physical_buffers[index]; + bufferDescriptors->length = bufferSize; + bufferDescriptors->ioc = 1; } /* Configure stream registers */ - wfmt = stream->num_channels -1; - switch (stream->sampleformat) { + wfmt = stream->num_channels - 1; + switch (stream->sample_format) { case B_FMT_8BIT_S: wfmt |= (0 << 4); stream->bps = 8; break; case B_FMT_16BIT: wfmt |= (1 << 4); stream->bps = 16; break; + case B_FMT_20BIT: wfmt |= (2 << 4); stream->bps = 20; break; case B_FMT_24BIT: wfmt |= (3 << 4); stream->bps = 24; break; case B_FMT_32BIT: wfmt |= (4 << 4); stream->bps = 32; break; default: dprintf("%s: Invalid sample format: 0x%lx\n", __func__, - stream->sampleformat); + stream->sample_format); break; } - switch (stream->samplerate) { + switch (stream->sample_rate) { case B_SR_8000: wfmt |= (0 << 14) | (0 << 11) | (5 << 8); stream->rate = 8000; @@ -271,29 +281,32 @@ hda_stream_setup_buffers(hda_afg* afg, hda_stream* stream, const char* desc) default: dprintf("%s: Invalid sample rate: 0x%lx\n", __func__, - stream->samplerate); + stream->sample_rate); break; } dprintf("IRA: %s: setup stream %ld: SR=%ld, SF=%ld\n", __func__, stream->id, stream->rate, stream->bps); - OREG16(afg->codec->controller, stream->off, FMT) = wfmt; - OREG32(afg->codec->controller, stream->off, BDPL) = stream->bdl_pa; - OREG32(afg->codec->controller, stream->off, BDPU) = 0; - OREG16(afg->codec->controller, stream->off, LVI) = stream->num_buffers -1; + OREG16(audioGroup->codec->controller, stream->off, FMT) = wfmt; + OREG32(audioGroup->codec->controller, stream->off, BDPL) + = stream->physical_buffer_descriptors; + OREG32(audioGroup->codec->controller, stream->off, BDPU) = 0; + OREG16(audioGroup->codec->controller, stream->off, LVI) + = stream->num_buffers - 1; /* total cyclic buffer size in _bytes_ */ - OREG32(afg->codec->controller, stream->off, CBL) = stream->sample_size - * stream->num_channels * stream->num_buffers * stream->buffer_length; - OREG8(afg->codec->controller, stream->off, CTL0) + OREG32(audioGroup->codec->controller, stream->off, CBL) + = stream->sample_size * stream->num_channels * stream->num_buffers + * stream->buffer_length; + OREG8(audioGroup->codec->controller, stream->off, CTL0) = CTL0_IOCE | CTL0_FEIE | CTL0_DEIE; - OREG8(afg->codec->controller, stream->off, CTL2) = stream->id << 4; + OREG8(audioGroup->codec->controller, stream->off, CTL2) = stream->id << 4; - verb[0] = MAKE_VERB(afg->codec->addr, stream->io_wid, VID_SET_CONVFORMAT, - wfmt); - verb[1] = MAKE_VERB(afg->codec->addr, stream->io_wid, VID_SET_CVTSTRCHN, - stream->id << 4); - rc = hda_send_verbs(afg->codec, verb, response, 2); + verb[0] = MAKE_VERB(audioGroup->codec->addr, stream->io_widget, + VID_SET_CONVFORMAT, wfmt); + verb[1] = MAKE_VERB(audioGroup->codec->addr, stream->io_widget, + VID_SET_CVTSTRCHN, stream->id << 4); + rc = hda_send_verbs(audioGroup->codec, verb, response, 2); return rc; } @@ -353,7 +366,7 @@ hda_interrupt_handler(hda_controller* controller) while (controller->rirbrp <= rirbwp) { uint32 resp_ex = controller->rirb[controller->rirbrp].resp_ex; - uint32 cad = resp_ex & HDA_MAXCODECS; + uint32 cad = resp_ex & HDA_MAX_CODECS; hda_codec* codec = controller->codecs[cad]; if (resp_ex & RESP_EX_UNSOL) { @@ -394,7 +407,7 @@ hda_interrupt_handler(hda_controller* controller) if (intsts & ~(INTSTS_CIS | INTSTS_GIS)) { int index; - for (index = 0; index < HDA_MAXSTREAMS; index++) { + for (index = 0; index < HDA_MAX_STREAMS; index++) { if ((intsts & (1 << index)) != 0) { if (controller->streams[index]) hda_stream_check_intr(controller, controller->streams[index]); @@ -431,59 +444,59 @@ hda_hw_start(hda_controller* controller) static status_t hda_hw_corb_rirb_init(hda_controller* controller) { - uint32 memsz, rirboff; - uint8 corbsz, rirbsz; + uint32 memSize, rirbOffset; + uint8 corbSize, rirbSize; status_t rc = B_OK; physical_entry pe; /* Determine and set size of CORB */ - corbsz = REG8(controller, CORBSIZE); - if (corbsz & CORBSIZE_CAP_256E) { - controller->corblen = 256; + corbSize = REG8(controller, CORBSIZE); + if (corbSize & CORBSIZE_CAP_256E) { + controller->corb_length = 256; REG8(controller, CORBSIZE) = CORBSIZE_SZ_256E; - } else if (corbsz & CORBSIZE_CAP_16E) { - controller->corblen = 16; + } else if (corbSize & CORBSIZE_CAP_16E) { + controller->corb_length = 16; REG8(controller, CORBSIZE) = CORBSIZE_SZ_16E; - } else if (corbsz & CORBSIZE_CAP_2E) { - controller->corblen = 2; + } else if (corbSize & CORBSIZE_CAP_2E) { + controller->corb_length = 2; REG8(controller, CORBSIZE) = CORBSIZE_SZ_2E; } /* Determine and set size of RIRB */ - rirbsz = REG8(controller, RIRBSIZE); - if (rirbsz & RIRBSIZE_CAP_256E) { - controller->rirblen = 256; + rirbSize = REG8(controller, RIRBSIZE); + if (rirbSize & RIRBSIZE_CAP_256E) { + controller->rirb_length = 256; REG8(controller, RIRBSIZE) = RIRBSIZE_SZ_256E; - } else if (rirbsz & RIRBSIZE_CAP_16E) { - controller->rirblen = 16; + } else if (rirbSize & RIRBSIZE_CAP_16E) { + controller->rirb_length = 16; REG8(controller, RIRBSIZE) = RIRBSIZE_SZ_16E; - } else if (rirbsz & RIRBSIZE_CAP_2E) { - controller->rirblen = 2; + } else if (rirbSize & RIRBSIZE_CAP_2E) { + controller->rirb_length = 2; REG8(controller, RIRBSIZE) = RIRBSIZE_SZ_2E; } /* Determine rirb offset in memory and total size of corb+alignment+rirb */ - rirboff = (controller->corblen * sizeof(corb_t) + 0x7f) & ~0x7f; - memsz = (rirboff + controller->rirblen * sizeof(rirb_t) + B_PAGE_SIZE - 1) - & ~(B_PAGE_SIZE - 1); + rirbOffset = (controller->corb_length * sizeof(corb_t) + 0x7f) & ~0x7f; + memSize = (rirbOffset + controller->rirb_length * sizeof(rirb_t) + + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); /* Allocate memory area */ controller->rb_area = create_area("hda_corb_rirb", (void**)&controller->corb, - B_ANY_KERNEL_ADDRESS, memsz, B_CONTIGUOUS, 0); + B_ANY_KERNEL_ADDRESS, memSize, B_CONTIGUOUS, 0); if (controller->rb_area < 0) return controller->rb_area; /* Rirb is after corb+aligment */ - controller->rirb = (rirb_t*)(((uint8*)controller->corb) + rirboff); + controller->rirb = (rirb_t*)(((uint8*)controller->corb) + rirbOffset); - if ((rc = get_memory_map(controller->corb, memsz, &pe, 1)) != B_OK) { + if ((rc = get_memory_map(controller->corb, memSize, &pe, 1)) != B_OK) { delete_area(controller->rb_area); return rc; } /* Program CORB/RIRB for these locations */ REG32(controller, CORBLBASE) = (uint32)pe.address; - REG32(controller, RIRBLBASE) = (uint32)pe.address + rirboff; + REG32(controller, RIRBLBASE) = (uint32)pe.address + rirbOffset; /* Reset CORB read pointer */ /* NOTE: See HDA011 for corrected procedure! */ @@ -574,13 +587,14 @@ hda_hw_init(hda_controller* controller) goto corb_rirb_failed; } - for (index = 0; index < HDA_MAXCODECS; index++) { + for (index = 0; index < HDA_MAX_CODECS; index++) { if ((controller->codecsts & (1 << index)) != 0) hda_codec_new(controller, index); } - for (index = 0; index < HDA_MAXCODECS; index++) { - if (controller->codecs[index] && controller->codecs[index]->num_afgs) { + for (index = 0; index < HDA_MAX_CODECS; index++) { + if (controller->codecs[index] + && controller->codecs[index]->num_audio_groups > 0) { controller->active_codec = controller->codecs[index]; break; } @@ -617,7 +631,7 @@ hda_hw_stop(hda_controller* controller) int index; /* Stop all audio streams */ - for (index = 0; index < HDA_MAXSTREAMS; index++) + for (index = 0; index < HDA_MAX_STREAMS; index++) if (controller->streams[index] && controller->streams[index]->running) hda_stream_stop(controller, controller->streams[index]); } @@ -661,7 +675,7 @@ hda_hw_uninit(hda_controller* controller) } /* Now delete all codecs */ - for (index = 0; index < HDA_MAXCODECS; index++) { + for (index = 0; index < HDA_MAX_CODECS; index++) { if (controller->codecs[index] != NULL) hda_codec_delete(controller->codecs[index]); } diff --git a/src/add-ons/kernel/drivers/audio/hda/hda_multi_audio.c b/src/add-ons/kernel/drivers/audio/hda/hda_multi_audio.c index 569c6b3214..d456744a83 100644 --- a/src/add-ons/kernel/drivers/audio/hda/hda_multi_audio.c +++ b/src/add-ons/kernel/drivers/audio/hda/hda_multi_audio.c @@ -11,15 +11,30 @@ #include "driver.h" +#ifdef TRACE +# undef TRACE +#endif + +#ifdef TRACE_MULTI_AUDIO +# define TRACE(a...) dprintf("\33[34mhda:\33[0m " a) +#else +# define TRACE(a...) ; +#endif + + static multi_channel_info sChannels[] = { - { 0, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 }, - { 1, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 }, - { 2, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 }, - { 3, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 }, - { 4, B_MULTI_OUTPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO }, - { 5, B_MULTI_OUTPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO }, - { 6, B_MULTI_INPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO }, - { 7, B_MULTI_INPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO }, + { 0, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 }, + { 1, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 }, + { 2, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 }, + { 3, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 }, + { 4, B_MULTI_OUTPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, + B_CHANNEL_MINI_JACK_STEREO }, + { 5, B_MULTI_OUTPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, + B_CHANNEL_MINI_JACK_STEREO }, + { 6, B_MULTI_INPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, + B_CHANNEL_MINI_JACK_STEREO }, + { 7, B_MULTI_INPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, + B_CHANNEL_MINI_JACK_STEREO }, }; @@ -34,10 +49,8 @@ format2size(uint32 format) case B_FMT_18BIT: case B_FMT_24BIT: case B_FMT_32BIT: - return 4; - case B_FMT_FLOAT: - return 8; + return 4; default: return -1; @@ -46,7 +59,7 @@ format2size(uint32 format) static status_t -get_description(hda_afg* afg, multi_description* data) +get_description(hda_audio_group* audioGroup, multi_description* data) { data->interface_version = B_CURRENT_INTERFACE_VERSION; data->interface_minimum = B_CURRENT_INTERFACE_VERSION; @@ -69,8 +82,8 @@ get_description(hda_afg* afg, multi_description* data) } /* determine output/input rates */ - data->output_rates = afg->defrates; - data->input_rates = afg->defrates; + data->output_rates = audioGroup->supported_rates; + data->input_rates = audioGroup->supported_rates; /* force existance of 48kHz if variable rates are not supported */ if (data->output_rates == 0) @@ -81,8 +94,8 @@ get_description(hda_afg* afg, multi_description* data) data->max_cvsr_rate = 0; data->min_cvsr_rate = 0; - data->output_formats = afg->deffmts; - data->input_formats = afg->deffmts; + data->output_formats = audioGroup->supported_formats; + data->input_formats = audioGroup->supported_formats; data->lock_sources = B_MULTI_LOCK_INTERNAL; data->timecode_sources = 0; data->interface_flags = B_MULTI_INTERFACE_PLAYBACK /* | B_MULTI_INTERFACE_RECORD */; @@ -95,7 +108,7 @@ get_description(hda_afg* afg, multi_description* data) static status_t -get_enabled_channels(hda_afg* afg, multi_channel_enable* data) +get_enabled_channels(hda_audio_group* audioGroup, multi_channel_enable* data) { B_SET_CHANNEL(data->enable_bits, 0, true); B_SET_CHANNEL(data->enable_bits, 1, true); @@ -108,39 +121,41 @@ get_enabled_channels(hda_afg* afg, multi_channel_enable* data) static status_t -get_global_format(hda_afg* afg, multi_format_info* data) +get_global_format(hda_audio_group* audioGroup, multi_format_info* data) { data->output_latency = 0; data->input_latency = 0; data->timecode_kind = 0; - data->output.format = afg->playback_stream->sampleformat; - data->output.rate = afg->playback_stream->samplerate; + data->output.format = audioGroup->playback_stream->sample_format; + data->output.rate = audioGroup->playback_stream->sample_rate; - data->input.format = afg->record_stream->sampleformat; - data->input.rate = afg->record_stream->sampleformat; + data->input.format = audioGroup->record_stream->sample_format; + data->input.rate = audioGroup->record_stream->sample_format; return B_OK; } static status_t -set_global_format(hda_afg* afg, multi_format_info* data) +set_global_format(hda_audio_group* audioGroup, multi_format_info* data) { - afg->playback_stream->sampleformat = data->output.format; - afg->playback_stream->samplerate = data->output.rate; - afg->playback_stream->sample_size = format2size(afg->playback_stream->sampleformat); + audioGroup->playback_stream->sample_format = data->output.format; + audioGroup->playback_stream->sample_rate = data->output.rate; + audioGroup->playback_stream->sample_size = format2size( + audioGroup->playback_stream->sample_format); - afg->record_stream->samplerate = data->input.rate; - afg->record_stream->sampleformat = data->input.format; - afg->record_stream->sample_size = format2size(afg->record_stream->sampleformat); + audioGroup->record_stream->sample_rate = data->input.rate; + audioGroup->record_stream->sample_format = data->input.format; + audioGroup->record_stream->sample_size = format2size( + audioGroup->record_stream->sample_format); return B_OK; } static status_t -list_mix_controls(hda_afg* afg, multi_mix_control_info * data) +list_mix_controls(hda_audio_group* audioGroup, multi_mix_control_info* data) { data->control_count = 0; return B_OK; @@ -148,7 +163,8 @@ list_mix_controls(hda_afg* afg, multi_mix_control_info * data) static status_t -list_mix_connections(hda_afg* afg, multi_mix_connection_info * data) +list_mix_connections(hda_audio_group* audioGroup, + multi_mix_connection_info* data) { data->actual_count = 0; return B_OK; @@ -156,89 +172,102 @@ list_mix_connections(hda_afg* afg, multi_mix_connection_info * data) static status_t -list_mix_channels(hda_afg* afg, multi_mix_channel_info *data) +list_mix_channels(hda_audio_group* audioGroup, multi_mix_channel_info *data) { return B_OK; } static status_t -get_buffers(hda_afg* afg, multi_buffer_list* data) +get_buffers(hda_audio_group* audioGroup, multi_buffer_list* data) { - uint32 playback_sample_size = afg->playback_stream->sample_size; - uint32 record_sample_size = afg->record_stream->sample_size; + uint32 playback_sample_size = audioGroup->playback_stream->sample_size; + uint32 record_sample_size = audioGroup->record_stream->sample_size; uint32 cidx, bidx; - status_t rc; + status_t status; - dprintf("%s: playback: %ld buffers, %ld channels, %ld samples\n", __func__, - data->request_playback_buffers, data->request_playback_channels, data->request_playback_buffer_size); - dprintf("%s: record: %ld buffers, %ld channels, %ld samples\n", __func__, - data->request_record_buffers, data->request_record_channels, data->request_record_buffer_size); + TRACE("playback: %ld buffers, %ld channels, %ld samples\n", + data->request_playback_buffers, data->request_playback_channels, + data->request_playback_buffer_size); + TRACE("record: %ld buffers, %ld channels, %ld samples\n", + data->request_record_buffers, data->request_record_channels, + data->request_record_buffer_size); - /* Workaround for Haiku multi_audio API, since it prefers to let the driver pick - values, while the BeOS multi_audio actually gives the user's defaults. */ - if (data->request_playback_buffers > STRMAXBUF || - data->request_playback_buffers < STRMINBUF) { - data->request_playback_buffers = STRMINBUF; - } - - if (data->request_record_buffers > STRMAXBUF || - data->request_record_buffers < STRMINBUF) { - data->request_record_buffers = STRMINBUF; - } + /* Determine what buffers we return given the request */ - if (data->request_playback_buffer_size == 0) - data->request_playback_buffer_size = DEFAULT_FRAMESPERBUF; - - if (data->request_record_buffer_size == 0) - data->request_record_buffer_size = DEFAULT_FRAMESPERBUF; - - /* ... from here on, we can assume again that a reasonable request is being made */ - - data->flags = B_MULTI_BUFFER_PLAYBACK; - - /* Copy the requested settings into the streams */ - afg->playback_stream->num_buffers = data->request_playback_buffers; - afg->playback_stream->num_channels = data->request_playback_channels; - afg->playback_stream->buffer_length = data->request_playback_buffer_size; - if ((rc=hda_stream_setup_buffers(afg, afg->playback_stream, "Playback")) != B_OK) { - dprintf("%s: Error setting up playback buffers (%s)\n", __func__, strerror(rc)); - return rc; - } - - afg->record_stream->num_buffers = data->request_record_buffers; - afg->record_stream->num_channels = data->request_record_channels; - afg->record_stream->buffer_length = data->request_record_buffer_size; - if ((rc=hda_stream_setup_buffers(afg, afg->record_stream, "Recording")) != B_OK) { - dprintf("%s: Error setting up recording buffers (%s)\n", __func__, strerror(rc)); - return rc; - } - - /* Setup data structure for multi_audio API... */ data->return_playback_buffers = data->request_playback_buffers; data->return_playback_channels = data->request_playback_channels; data->return_playback_buffer_size = data->request_playback_buffer_size; - /* frames */ + data->return_record_buffers = data->request_record_buffers; + data->return_record_channels = data->request_record_channels; + data->return_record_buffer_size = data->request_record_buffer_size; + + /* Workaround for Haiku multi_audio API, since it prefers to let the + driver pick values, while the BeOS multi_audio actually gives the + user's defaults. */ + if (data->return_playback_buffers > STREAM_MAX_BUFFERS + || data->return_playback_buffers < STREAM_MIN_BUFFERS) + data->return_playback_buffers = STREAM_MIN_BUFFERS; + + if (data->return_record_buffers > STREAM_MAX_BUFFERS + || data->return_record_buffers < STREAM_MIN_BUFFERS) + data->return_record_buffers = STREAM_MIN_BUFFERS; + + if (data->return_playback_buffer_size == 0) + data->return_playback_buffer_size = DEFAULT_FRAMES_PER_BUFFER; + + if (data->return_record_buffer_size == 0) + data->return_record_buffer_size = DEFAULT_FRAMES_PER_BUFFER; + + /* ... from here on, we can assume again that a reasonable request is + being made */ + + data->flags = B_MULTI_BUFFER_PLAYBACK; + + /* Copy the settings into the streams */ + audioGroup->playback_stream->num_buffers = data->return_playback_buffers; + audioGroup->playback_stream->num_channels = data->return_playback_channels; + audioGroup->playback_stream->buffer_length + = data->return_playback_buffer_size; + + status = hda_stream_setup_buffers(audioGroup, audioGroup->playback_stream, + "Playback"); + if (status != B_OK) { + dprintf("hda: Error setting up playback buffers: %s\n", + strerror(status)); + return status; + } + + audioGroup->record_stream->num_buffers = data->return_record_buffers; + audioGroup->record_stream->num_channels = data->return_record_channels; + audioGroup->record_stream->buffer_length + = data->return_record_buffer_size; + + status = hda_stream_setup_buffers(audioGroup, audioGroup->record_stream, + "Recording"); + if (status != B_OK) { + dprintf("hda: Error setting up recording buffers: %s\n", + strerror(status)); + return status; + } + + /* Setup data structure for multi_audio API... */ for (bidx = 0; bidx < data->return_playback_buffers; bidx++) { for (cidx = 0; cidx < data->return_playback_channels; cidx++) { data->playback_buffers[bidx][cidx].base - = afg->playback_stream->buffers[bidx] + = audioGroup->playback_stream->buffers[bidx] + (playback_sample_size * cidx); data->playback_buffers[bidx][cidx].stride = playback_sample_size * data->return_playback_channels; } } - data->return_record_buffers = data->request_record_buffers; - data->return_record_channels = data->request_record_channels; - data->return_record_buffer_size = data->request_record_buffer_size; - /* frames */ - for (bidx = 0; bidx < data->return_record_buffers; bidx++) { for (cidx = 0; cidx < data->return_record_channels; cidx++) { data->record_buffers[bidx][cidx].base - = afg->record_stream->buffers[bidx] + (record_sample_size * cidx); + = audioGroup->record_stream->buffers[bidx] + + (record_sample_size * cidx); data->record_buffers[bidx][cidx].stride = record_sample_size * data->return_record_channels; } @@ -247,20 +276,22 @@ get_buffers(hda_afg* afg, multi_buffer_list* data) return B_OK; } -/* playback_buffer_cycle is the buffer we want to have played */ +/*! playback_buffer_cycle is the buffer we want to have played */ static status_t -buffer_exchange(hda_afg* afg, multi_buffer_info* data) +buffer_exchange(hda_audio_group* audioGroup, multi_buffer_info* data) { static int debug_buffers_exchanged = 0; cpu_status status; status_t rc; - if (!afg->playback_stream->running) - hda_stream_start(afg->codec->controller, afg->playback_stream); + if (!audioGroup->playback_stream->running) { + hda_stream_start(audioGroup->codec->controller, + audioGroup->playback_stream); + } /* do playback */ - rc=acquire_sem(afg->playback_stream->buffer_ready_sem); + rc = acquire_sem(audioGroup->playback_stream->buffer_ready_sem); if (rc != B_OK) { dprintf("%s: Error waiting for playback buffer to finish (%s)!\n", __func__, strerror(rc)); @@ -268,13 +299,13 @@ buffer_exchange(hda_afg* afg, multi_buffer_info* data) } status = disable_interrupts(); - acquire_spinlock(&afg->playback_stream->lock); + acquire_spinlock(&audioGroup->playback_stream->lock); - data->playback_buffer_cycle = afg->playback_stream->buffer_cycle; - data->played_real_time = afg->playback_stream->real_time; - data->played_frames_count = afg->playback_stream->frames_count; + data->playback_buffer_cycle = audioGroup->playback_stream->buffer_cycle; + data->played_real_time = audioGroup->playback_stream->real_time; + data->played_frames_count = audioGroup->playback_stream->frames_count; - release_spinlock(&afg->playback_stream->lock); + release_spinlock(&audioGroup->playback_stream->lock); restore_interrupts(status); debug_buffers_exchanged++; @@ -285,57 +316,59 @@ buffer_exchange(hda_afg* afg, multi_buffer_info* data) return B_OK; } -static status_t -buffer_force_stop(hda_afg* afg) -{ - hda_stream_stop(afg->codec->controller, afg->playback_stream); - //hda_stream_stop(afg->codec->controller, afg->record_stream); - delete_sem(afg->playback_stream->buffer_ready_sem); -// delete_sem(afg->record_stream->buffer_ready_sem); +static status_t +buffer_force_stop(hda_audio_group* audioGroup) +{ + hda_stream_stop(audioGroup->codec->controller, audioGroup->playback_stream); + //hda_stream_stop(audioGroup->codec->controller, audioGroup->record_stream); + + delete_sem(audioGroup->playback_stream->buffer_ready_sem); +// delete_sem(audioGroup->record_stream->buffer_ready_sem); return B_OK; } + status_t multi_audio_control(void* cookie, uint32 op, void* arg, size_t len) { hda_codec* codec = (hda_codec*)cookie; - hda_afg* afg; + hda_audio_group* audioGroup; - /* FIXME: We should simply pass the afg into here... */ - if (!codec || codec->num_afgs == 0) + /* FIXME: We should simply pass the audioGroup into here... */ + if (!codec || codec->num_audio_groups == 0) return ENODEV; - afg = codec->afgs[0]; + audioGroup = codec->audio_groups[0]; switch (op) { case B_MULTI_GET_DESCRIPTION: - return get_description(afg, arg); + return get_description(audioGroup, arg); case B_MULTI_GET_ENABLED_CHANNELS: - return get_enabled_channels(afg, arg); + return get_enabled_channels(audioGroup, arg); case B_MULTI_SET_ENABLED_CHANNELS: return B_OK; case B_MULTI_GET_GLOBAL_FORMAT: - return get_global_format(afg, arg); + return get_global_format(audioGroup, arg); case B_MULTI_SET_GLOBAL_FORMAT: - return set_global_format(afg, arg); + return set_global_format(audioGroup, arg); case B_MULTI_LIST_MIX_CHANNELS: - return list_mix_channels(afg, arg); + return list_mix_channels(audioGroup, arg); case B_MULTI_LIST_MIX_CONTROLS: - return list_mix_controls(afg, arg); + return list_mix_controls(audioGroup, arg); case B_MULTI_LIST_MIX_CONNECTIONS: - return list_mix_connections(afg, arg); + return list_mix_connections(audioGroup, arg); case B_MULTI_GET_BUFFERS: - return get_buffers(afg, arg); + return get_buffers(audioGroup, arg); case B_MULTI_BUFFER_EXCHANGE: - return buffer_exchange(afg, arg); + return buffer_exchange(audioGroup, arg); case B_MULTI_BUFFER_FORCE_STOP: - return buffer_force_stop(afg); + return buffer_force_stop(audioGroup); case B_MULTI_GET_EVENT_INFO: case B_MULTI_SET_EVENT_INFO: