diff --git a/src/add-ons/kernel/drivers/audio/hda/driver.c b/src/add-ons/kernel/drivers/audio/hda/driver.c index e6b31380ed..750208375a 100644 --- a/src/add-ons/kernel/drivers/audio/hda/driver.c +++ b/src/add-ons/kernel/drivers/audio/hda/driver.c @@ -1,110 +1,114 @@ +/* + * Copyright 2007-2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ithamar Adema, ithamar AT unet DOT nl + */ + + #include "driver.h" -hda_controller cards[MAXCARDS]; -uint32 num_cards; int32 api_version = B_CUR_DRIVER_API_VERSION; -pci_module_info* pci; +hda_controller gCards[MAXCARDS]; +uint32 gNumCards; +pci_module_info* gPci; -const char** publish_devices(void); /* Just to silence compiler */ status_t init_hardware(void) { - pci_info pcii; - status_t rc; + pci_info info; long i; - if ((rc=get_module(B_PCI_MODULE_NAME, (module_info**)&pci)) == B_OK) { - for (i=0; pci->get_nth_pci_info(i,&pcii) == B_OK; i++) { - if (pcii.class_base == PCI_multimedia && pcii.class_sub == PCI_hd_audio) { - put_module(B_PCI_MODULE_NAME); - pci = NULL; - return B_OK; - } - } + if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPci) != B_OK) + return ENODEV; - put_module(B_PCI_MODULE_NAME); + for (i = 0; gPci->get_nth_pci_info(i, &info) == B_OK; i++) { + if (info.class_base == PCI_multimedia + && info.class_sub == PCI_hd_audio) { + put_module(B_PCI_MODULE_NAME); + return B_OK; + } } - pci = NULL; - + put_module(B_PCI_MODULE_NAME); return ENODEV; } + status_t -init_driver (void) +init_driver(void) { char path[B_PATH_NAME_LENGTH]; - pci_info pcii; - status_t rc; + pci_info info; long i; - num_cards = 0; + if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPci) != B_OK) + return ENODEV; - if ((rc=get_module(B_PCI_MODULE_NAME, (module_info**)&pci)) == B_OK) { - for (i=0; pci->get_nth_pci_info(i,&pcii) == B_OK; i++) { - if (pcii.class_base == PCI_multimedia && pcii.class_sub == PCI_hd_audio) { - cards[num_cards].pcii = pcii; - cards[num_cards].opened = 0; - sprintf(path, DEVFS_PATH_FORMAT, num_cards); - cards[num_cards++].devfs_path = strdup(path); - - dprintf("HDA: Detected controller @ PCI:%d:%d:%d, IRQ:%d, type %04x/%04x\n", - pcii.bus, pcii.device, pcii.function, - pcii.u.h0.interrupt_line, - pcii.vendor_id, pcii.device_id); - } + gNumCards = 0; + + for (i = 0; gPci->get_nth_pci_info(i, &info) == B_OK; i++) { + if (info.class_base == PCI_multimedia + && info.class_sub == PCI_hd_audio) { + gCards[gNumCards].pci_info = info; + gCards[gNumCards].opened = 0; + sprintf(path, DEVFS_PATH_FORMAT, gNumCards); + gCards[gNumCards++].devfs_path = strdup(path); + + dprintf("HDA: Detected controller @ PCI:%d:%d:%d, IRQ:%d, type %04x/%04x\n", + info.bus, info.device, info.function, + info.u.h0.interrupt_line, + info.vendor_id, info.device_id); } - } else { - return rc; } - if (num_cards == 0) { + if (gNumCards == 0) { put_module(B_PCI_MODULE_NAME); - pci = NULL; - return ENODEV; } return B_OK; } + void -uninit_driver (void) +uninit_driver(void) { long i; dprintf("IRA: %s\n", __func__); - for (i=0; i < num_cards; i++) { - free((void*)cards[i].devfs_path); - cards[i].devfs_path = NULL; + + for (i = 0; i < gNumCards; i++) { + free((void*)gCards[i].devfs_path); + gCards[i].devfs_path = NULL; } - if (pci != NULL) { - put_module(B_PCI_MODULE_NAME); - pci = NULL; - } + put_module(B_PCI_MODULE_NAME); } + const char** publish_devices(void) { static const char* devs[MAXCARDS+1]; long i; - + dprintf("IRA: %s\n", __func__); - for (i=0; i < num_cards; i++) - devs[i] = cards[i].devfs_path; + for (i = 0; i < gNumCards; i++) + devs[i] = gCards[i].devfs_path; devs[i] = NULL; return devs; } + device_hooks* find_device(const char* name) { dprintf("IRA: %s\n", __func__); - return &driver_hooks; + return &gDriverHooks; } diff --git a/src/add-ons/kernel/drivers/audio/hda/driver.h b/src/add-ons/kernel/drivers/audio/hda/driver.h index 897ad0e918..db97afe9ed 100644 --- a/src/add-ons/kernel/drivers/audio/hda/driver.h +++ b/src/add-ons/kernel/drivers/audio/hda/driver.h @@ -1,3 +1,10 @@ +/* + * Copyright 2007-2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ithamar Adema, ithamar AT unet DOT nl + */ #ifndef _HDA_H_ #define _HDA_H_ @@ -158,7 +165,7 @@ struct hda_codec_s { hda_afg* afgs[HDA_MAXAFGS]; uint32 num_afgs; - struct hda_controller_s* ctrlr; + struct hda_controller_s* controller; }; /* hda_controller @@ -170,7 +177,7 @@ struct hda_codec_s { */ struct hda_controller_s { - pci_info pcii; + struct pci_info pci_info; vuint32 opened; const char* devfs_path; @@ -199,30 +206,30 @@ struct hda_controller_s { }; /* driver.c */ -extern device_hooks driver_hooks; -extern pci_module_info* pci; -extern hda_controller cards[MAXCARDS]; -extern uint32 num_cards; +extern device_hooks gDriverHooks; +extern pci_module_info* gPci; +extern hda_controller gCards[MAXCARDS]; +extern uint32 gNumCards; /* hda_codec.c */ -hda_codec* hda_codec_new(hda_controller* ctrlr, uint32 cad); +hda_codec* hda_codec_new(hda_controller* controller, uint32 cad); void hda_codec_delete(hda_codec*); /* hda_multi_audio.c */ status_t multi_audio_control(void* cookie, uint32 op, void* arg, size_t len); /* hda_controller.c: Basic controller support */ -status_t hda_hw_init(hda_controller* ctrlr); -void hda_hw_stop(hda_controller* ctrlr); -void hda_hw_uninit(hda_controller* ctrlr); +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); /* hda_controller.c: Stream support */ -hda_stream* hda_stream_new(hda_controller* ctrlr, int type); +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* ctrlr, hda_stream* s); -status_t hda_stream_stop(hda_controller* ctrlr, hda_stream* s); -status_t hda_stream_check_intr(hda_controller* ctrlr, hda_stream* s); +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); #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 651670fed9..dae6f30c71 100644 --- a/src/add-ons/kernel/drivers/audio/hda/hda_codec.c +++ b/src/add-ons/kernel/drivers/audio/hda/hda_codec.c @@ -1,34 +1,47 @@ +/* + * Copyright 2007-2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ithamar Adema, ithamar AT unet DOT nl + */ + + #include "driver.h" #include "hda_codec_defs.h" -const char* portcon[] = { + +static const char* kPortConnector[] = { "Jack", "None", "Fixed", "Dual" }; -const char* defdev[] = { - "Line Out", "Speaker", "HP Out", "CD", "SPDIF out", "Digital Other Out", "Modem Line Side", - "Modem Hand Side", "Line In", "AUX", "Mic In", "Telephony", "SPDIF In", "Digital Other In", - "Reserved", "Other" +static const char* kDefaultDevice[] = { + "Line Out", "Speaker", "HP Out", "CD", "SPDIF out", "Digital Other Out", + "Modem Line Side", "Modem Hand Side", "Line In", "AUX", "Mic In", + "Telephony", "SPDIF In", "Digital Other In", "Reserved", "Other" }; -const char* conntype[] = { - "N/A", "1/8\"", "1/4\"", "ATAPI internal", "RCA", "Optical", "Other Digital", "Other Analog", - "Multichannel Analog (DIN)", "XLR/Professional", "RJ-11 (Modem)", "Combination", "-", "-", "-", "Other" +static const char* kConnectionType[] = { + "N/A", "1/8\"", "1/4\"", "ATAPI internal", "RCA", "Optical", + "Other Digital", "Other Analog", "Multichannel Analog (DIN)", + "XLR/Professional", "RJ-11 (Modem)", "Combination", "-", "-", "-", "Other" }; -const char* jcolor[] = { - "N/A", "Black", "Grey", "Blue", "Green", "Red", "Orange", "Yellow", "Purple", "Pink", - "-", "-", "-", "-", "White", "Other" +static const char* kJackColor[] = { + "N/A", "Black", "Grey", "Blue", "Green", "Red", "Orange", "Yellow", + "Purple", "Pink", "-", "-", "-", "-", "White", "Other" }; + static status_t hda_widget_get_pm_support(hda_codec* codec, uint32 nid, uint32* pm) { - corb_t verb = MAKE_VERB(codec->addr,nid,VID_GET_PARAM,PID_POWERSTATE_SUPPORT); + corb_t verb = MAKE_VERB(codec->addr, nid, VID_GET_PARAM, + PID_POWERSTATE_SUPPORT); status_t rc; uint32 resp; - - if ((rc=hda_send_verbs(codec, &verb, &resp, 1)) == B_OK) { + + if ((rc = hda_send_verbs(codec, &verb, &resp, 1)) == B_OK) { *pm = 0; /* FIXME: Define constants for powermanagement modes */ @@ -37,12 +50,14 @@ hda_widget_get_pm_support(hda_codec* codec, uint32 nid, uint32* pm) if (resp & (1 << 2)) ; if (resp & (1 << 3)) ; } - + return rc; } + static status_t -hda_widget_get_stream_support(hda_codec* codec, uint32 nid, uint32* fmts, uint32* rates) +hda_widget_get_stream_support(hda_codec* codec, uint32 nid, uint32* fmts, + uint32* rates) { corb_t verbs[2]; uint32 resp[2]; @@ -50,56 +65,76 @@ hda_widget_get_stream_support(hda_codec* codec, uint32 nid, uint32* fmts, uint32 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) { + if ((rc = hda_send_verbs(codec, verbs, resp, 2)) == B_OK) { *fmts = 0; *rates = 0; 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; - - 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; + 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] & (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; } -//FIXME: if (resp[0] & (1 << 1)) *fmts |= B_FMT_FLOAT; -//FIXME: if (resp[0] & (1 << 2)) /* Sort out how to handle AC3 */; +//FIXME: if (resp[0] & (1 << 1)) *fmts |= B_FMT_FLOAT; +//FIXME: if (resp[0] & (1 << 2)) /* Sort out how to handle AC3 */; } - + return rc; } + static status_t hda_widget_get_amplifier_capabilities(hda_codec* codec, uint32 nid) { status_t rc; corb_t verb; uint32 resp; - - verb = MAKE_VERB(codec->addr,nid,VID_GET_PARAM,PID_OUTPUT_AMP_CAP); - if ((rc=hda_send_verbs(codec, &verb, &resp, 1)) == B_OK && resp != 0) { + + verb = MAKE_VERB(codec->addr, nid, 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", (resp & (1 << 31)) ? "supported" : "N/A", (resp >> 16) & 0x7F, (resp >> 8) & 0x7F, resp & 0x7F); } - + return rc; } + static status_t hda_codec_parse_afg(hda_afg* afg) { @@ -107,20 +142,25 @@ hda_codec_parse_afg(hda_afg* afg) uint32 resp[6]; uint32 widx; - hda_widget_get_stream_support(afg->codec, afg->root_nid, &afg->deffmts, &afg->defrates); + 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); - 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(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); 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"); + 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"); - 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", + 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->wid_start = resp[2] >> 16; @@ -133,20 +173,24 @@ hda_codec_parse_afg(hda_afg* afg) } /* Iterate over all Widgets and collect info */ - for (widx=0; widx < afg->wid_count; widx++) { + for (widx = 0; widx < afg->wid_count; widx++) { uint32 wid = afg->wid_start + widx; char buf[256]; int off; - - 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); + + 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); - + 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 << 11)) + off += sprintf(buf + off, "[L-R Swap] "); + if (resp[0] & (1 << 10)) { corb_t verb; uint32 resp; @@ -154,21 +198,30 @@ hda_codec_parse_afg(hda_afg* afg) off += sprintf(buf+off, "[Power] "); /* We support power; switch us on! */ - verb = MAKE_VERB(afg->codec->addr,wid,VID_SET_POWERSTATE,0); + 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] "); + 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) { + switch (afg->widgets[widx].type) { case WT_AUDIO_OUTPUT: dprintf("%ld:\tAudio Output\n", wid); hda_widget_get_stream_support(afg->codec, wid, @@ -193,11 +246,12 @@ hda_codec_parse_afg(hda_afg* afg) 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); + 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]" : ""); @@ -205,16 +259,17 @@ hda_codec_parse_afg(hda_afg* afg) 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); 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", - portcon[resp[0] >> 30], - defdev[afg->widgets[widx].d.pin.device], - conntype[(resp[0] >> 16) & 0xF], - jcolor[(resp[0] >> 12) & 0xF]); + 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: @@ -236,61 +291,66 @@ hda_codec_parse_afg(hda_afg* afg) 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); + 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 ++) { + + 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); + 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); + 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); + 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; + afg->widgets[widx].inputs[idx] = (resp[0] >> (8*(idx%4))) + & 0xFF; } - + dprintf("\t[ %s]\n", buf); } } } - + return B_OK; } -/* hda_codec_afg_find_path - * - * Find path from 'wid' to a widget of type 'wtype', returning its widget id. + +/*! Find path from 'wid' to a widget of type 'wtype', returning its widget id. * Returns 0 if not found. */ - static uint32 hda_codec_afg_find_path(hda_afg* afg, uint32 wid, uint32 wtype, uint32 depth) { int widx = wid - afg->wid_start; int idx; - switch(afg->widgets[widx].type) { + switch (afg->widgets[widx].type) { 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_path(afg, afg->widgets[widx].inputs[idx], wtype, depth +1)) { if (afg->widgets[widx].active_input == -1) afg->widgets[widx].active_input = idx; @@ -301,16 +361,16 @@ hda_codec_afg_find_path(hda_afg* afg, uint32 wid, uint32 wtype, uint32 depth) break; case WT_AUDIO_SELECTOR: - { - int idx = afg->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; - } + { + int idx = afg->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; } } break; + } default: if (afg->widgets[widx].type == wtype) @@ -322,6 +382,7 @@ hda_codec_afg_find_path(hda_afg* afg, uint32 wid, uint32 wtype, uint32 depth) return 0; } + static void hda_afg_delete(hda_afg* afg) { @@ -339,6 +400,7 @@ hda_afg_delete(hda_afg* afg) } } + static status_t hda_codec_afg_new(hda_codec* codec, uint32 afg_nid) { @@ -346,7 +408,7 @@ hda_codec_afg_new(hda_codec* codec, uint32 afg_nid) status_t rc; uint32 idx; - if ((afg=calloc(1, sizeof(hda_afg))) == NULL) { + if ((afg = calloc(1, sizeof(hda_afg))) == NULL) { rc = B_NO_MEMORY; goto done; } @@ -360,94 +422,110 @@ hda_codec_afg_new(hda_codec* codec, uint32 afg_nid) if (rc != B_OK) goto free_afg; - /* Setup for worst-case scenario; - we cannot find any output Pin Widgets */ + /* 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++) { + for (idx = 0; idx < afg->wid_count; idx++) { uint32 output_wid = 0, input_wid = 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 (iidx != -1) { - output_wid = hda_codec_afg_find_path(afg, afg->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) { - 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: Setting output selector failed!\n", __func__); - break; + 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 (iidx != -1) { + output_wid = hda_codec_afg_find_path(afg, + afg->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) { + 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: Setting output selector failed!\n", __func__); + break; + } } } - } - - if (output_wid) { - if (!afg->playback_stream) { - corb_t verb[2]; - - /* 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; enable hp/output */ - verb[0] = MAKE_VERB(codec->addr, afg->playback_stream->pin_wid, - VID_SET_AMPGAINMUTE, (1 << 15) | (1 << 13) | (1 << 12)); - verb[1] = MAKE_VERB(codec->addr, afg->playback_stream->pin_wid, - 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__, defdev[afg->widgets[idx].d.pin.device], output_wid); - } + if (output_wid) { + if (!afg->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); + + afg->playback_stream->pin_wid = idx + afg->wid_start; + afg->playback_stream->io_wid = output_wid; + + /* FIXME: Force Pin Widget to unmute; enable hp/output */ + verb[0] = MAKE_VERB(codec->addr, + afg->playback_stream->pin_wid, VID_SET_AMPGAINMUTE, + (1 << 15) | (1 << 13) | (1 << 12)); + verb[1] = MAKE_VERB(codec->addr, + afg->playback_stream->pin_wid, 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); + } + } } - } } if (afg->widgets[idx].type == WT_AUDIO_INPUT) { iidx = afg->widgets[idx].active_input; if (iidx != -1) { - input_wid = hda_codec_afg_find_path(afg, afg->widgets[idx].inputs[iidx], WT_PIN_COMPLEX, 0); + input_wid = hda_codec_afg_find_path(afg, + afg->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); + 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) { - 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: Setting input selector failed!\n", __func__); + 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: Setting input selector failed!\n", + __func__); + } break; } } } - + if (input_wid) { if (!afg->record_stream) { corb_t verb; - + /* Setup playback/record streams for Multi Audio API */ - afg->record_stream = hda_stream_new(afg->codec->ctrlr, STRM_RECORD); - + afg->record_stream = hda_stream_new(afg->codec->controller, + 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); + + 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); } } } @@ -466,6 +544,7 @@ done: return rc; } + void hda_codec_delete(hda_codec* codec) { @@ -474,7 +553,7 @@ hda_codec_delete(hda_codec* codec) delete_sem(codec->response_sem); - for (idx=0; idx < codec->num_afgs; idx++) { + for (idx = 0; idx < codec->num_afgs; idx++) { hda_afg_delete(codec->afgs[idx]); codec->afgs[idx] = NULL; } @@ -483,44 +562,45 @@ hda_codec_delete(hda_codec* codec) } } + hda_codec* -hda_codec_new(hda_controller* ctrlr, uint32 cad) +hda_codec_new(hda_controller* controller, uint32 cad) { hda_codec* codec = calloc(1, sizeof(hda_codec)); uint32 responses[3]; corb_t verbs[3]; - status_t rc; uint32 nid; - if (codec == NULL) goto exit_new; + if (codec == NULL) + goto exit_new; - codec->ctrlr = ctrlr; + codec->controller = controller; codec->addr = cad; 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); + controller->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) 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++) { + + 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) + verbs[0] = MAKE_VERB(cad, nid, 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! */ - if ((rc=hda_codec_afg_new(codec, nid)) != B_OK) { + status_t rc = hda_codec_afg_new(codec, nid); + if (rc != B_OK) { dprintf("%s: Failed to setup new audio function group (%s)!\n", __func__, strerror(rc)); goto cmd_failed; @@ -531,7 +611,7 @@ hda_codec_new(hda_controller* ctrlr, uint32 cad) goto exit_new; cmd_failed: - ctrlr->codecs[cad] = NULL; + controller->codecs[cad] = NULL; hda_codec_delete(codec); codec = NULL; 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 f4ab1ae992..8ed150a35b 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 @@ -1,3 +1,10 @@ +/* + * Copyright 2007-2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ithamar Adema, ithamar AT unet DOT nl + */ #ifndef HDA_CODEC_H #define 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 6fabae034f..97d6df47bf 100644 --- a/src/add-ons/kernel/drivers/audio/hda/hda_controller.c +++ b/src/add-ons/kernel/drivers/audio/hda/hda_controller.c @@ -1,117 +1,132 @@ +/* + * Copyright 2007-2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ithamar Adema, ithamar AT unet DOT nl + */ + + #include "driver.h" #include "hda_controller_defs.h" #include "hda_codec_defs.h" -#include "driver.h" void -hda_stream_delete(hda_stream* s) +hda_stream_delete(hda_stream* stream) { - if (s->buffer_ready_sem >= B_OK) - delete_sem(s->buffer_ready_sem); - - if (s->buffer_area >= B_OK) - delete_area(s->buffer_area); - - if (s->bdl_area >= B_OK) - delete_area(s->bdl_area); + if (stream->buffer_ready_sem >= B_OK) + delete_sem(stream->buffer_ready_sem); - free(s); + if (stream->buffer_area >= B_OK) + delete_area(stream->buffer_area); + + if (stream->bdl_area >= B_OK) + delete_area(stream->bdl_area); + + free(stream); } + hda_stream* -hda_stream_new(hda_controller* ctrlr, int type) +hda_stream_new(hda_controller* controller, int type) { - hda_stream* s = calloc(1, sizeof(hda_stream)); - if (s != NULL) { - s->buffer_area = B_ERROR; - s->bdl_area = B_ERROR; - - switch(type) { - case STRM_PLAYBACK: - s->buffer_ready_sem = create_sem(0, "hda_playback_sem"); - s->id = 1; - s->off = (ctrlr->num_input_streams * HDAC_SDSIZE); - ctrlr->streams[ctrlr->num_input_streams] = s; - break; - - case STRM_RECORD: - s->buffer_area = B_ERROR; - s->bdl_area = B_ERROR; - s->buffer_ready_sem = create_sem(0, "hda_record_sem"); - s->id = 2; - s->off = 0; - ctrlr->streams[0] = s; - break; + hda_stream* stream = calloc(1, sizeof(hda_stream)); + if (stream == NULL) + return NULL; - default: - dprintf("%s: Unknown stream type %d!\n", __func__, type); - free(s); - s = NULL; - break; - } + stream->buffer_area = B_ERROR; + stream->bdl_area = B_ERROR; + + switch (type) { + case STRM_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: + stream->buffer_area = B_ERROR; + stream->bdl_area = B_ERROR; + stream->buffer_ready_sem = create_sem(0, "hda_record_sem"); + stream->id = 2; + stream->off = 0; + controller->streams[0] = stream; + break; + + default: + dprintf("%s: Unknown stream type %d!\n", __func__, type); + free(stream); + stream = NULL; + break; } - return s; + return stream; } -status_t -hda_stream_start(hda_controller* ctrlr, hda_stream* s) -{ - OREG8(ctrlr,s->off,CTL0) |= CTL0_RUN; - while (!(OREG8(ctrlr,s->off,CTL0) & CTL0_RUN)) +status_t +hda_stream_start(hda_controller* controller, hda_stream* stream) +{ + OREG8(controller, stream->off, CTL0) |= CTL0_RUN; + + while (!(OREG8(controller, stream->off, CTL0) & CTL0_RUN)) snooze(1); - s->running = true; + stream->running = true; return B_OK; } + status_t -hda_stream_check_intr(hda_controller* ctrlr, hda_stream* s) +hda_stream_check_intr(hda_controller* controller, hda_stream* stream) { - if (s->running) { - uint8 sts = OREG8(ctrlr,s->off,STS); + if (stream->running) { + uint8 sts = OREG8(controller, stream->off, STS); if (sts) { cpu_status status; - OREG8(ctrlr,s->off,STS) = sts; + OREG8(controller, stream->off, STS) = sts; status = disable_interrupts(); - acquire_spinlock(&s->lock); + acquire_spinlock(&stream->lock); - s->real_time = system_time(); - s->frames_count += s->buffer_length; - s->buffer_cycle = (s->buffer_cycle +1) % s->num_buffers; + stream->real_time = system_time(); + stream->frames_count += stream->buffer_length; + stream->buffer_cycle = (stream->buffer_cycle + 1) + % stream->num_buffers; - release_spinlock(&s->lock); + release_spinlock(&stream->lock); restore_interrupts(status); - release_sem_etc(s->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE); + release_sem_etc(stream->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE); } } return B_OK; } -status_t -hda_stream_stop(hda_controller* ctrlr, hda_stream* s) -{ - OREG8(ctrlr,s->off,CTL0) &= ~CTL0_RUN; - while (OREG8(ctrlr,s->off,CTL0) & CTL0_RUN) +status_t +hda_stream_stop(hda_controller* controller, hda_stream* stream) +{ + OREG8(controller, stream->off, CTL0) &= ~CTL0_RUN; + + while ((OREG8(controller, stream->off, CTL0) & CTL0_RUN) != 0) snooze(1); - s->running = false; + stream->running = false; return B_OK; } + status_t -hda_stream_setup_buffers(hda_afg* afg, hda_stream* s, const char* desc) +hda_stream_setup_buffers(hda_afg* afg, hda_stream* stream, const char* desc) { - uint32 buffer_size, buffer_pa, alloc; - uint32 response[2], idx; + uint32 bufferSize, bufferPhysicalAddress, alloc; + uint32 response[2], index; physical_entry pe; bdl_entry_t* bdl; corb_t verb[2]; @@ -120,237 +135,301 @@ hda_stream_setup_buffers(hda_afg* afg, hda_stream* s, const char* desc) uint16 wfmt; /* Clear previously allocated memory */ - if (s->buffer_area >= B_OK) { - delete_area(s->buffer_area); - s->buffer_area = B_ERROR; + if (stream->buffer_area >= B_OK) { + delete_area(stream->buffer_area); + stream->buffer_area = B_ERROR; } - if (s->bdl_area >= B_OK) { - delete_area(s->bdl_area); - s->bdl_area = B_ERROR; + if (stream->bdl_area >= B_OK) { + delete_area(stream->bdl_area); + stream->bdl_area = B_ERROR; } /* Calculate size of buffer (aligned to 128 bytes) */ - buffer_size = s->sample_size * s->num_channels * s->buffer_length; - buffer_size = (buffer_size + 127) & (~127); + bufferSize = stream->sample_size * stream->num_channels + * stream->buffer_length; + bufferSize = (bufferSize + 127) & (~127); /* Calculate total size of all buffers (aligned to size of B_PAGE_SIZE) */ - alloc = buffer_size * s->num_buffers; + alloc = bufferSize * stream->num_buffers; alloc = (alloc + B_PAGE_SIZE - 1) & (~(B_PAGE_SIZE -1)); /* Allocate memory for buffers */ - s->buffer_area = create_area("hda_buffers", (void**)&buffer, B_ANY_KERNEL_ADDRESS, alloc, B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA); - if (s->buffer_area < B_OK) - return s->buffer_area; + 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; /* Get the physical address of memory */ rc = get_memory_map(buffer, alloc, &pe, 1); if (rc != B_OK) { - delete_area(s->buffer_area); + delete_area(stream->buffer_area); return rc; } - buffer_pa = (uint32)pe.address; + bufferPhysicalAddress = (uint32)pe.address; dprintf("%s(%s): Allocated %lu bytes for %ld buffers\n", __func__, desc, - alloc, s->num_buffers); + alloc, stream->num_buffers); /* Store pointers (both virtual/physical) */ - for (idx=0; idx < s->num_buffers; idx++) { - s->buffers[idx] = buffer + (idx*buffer_size); - s->buffers_pa[idx] = buffer_pa + (idx*buffer_size); + for (index = 0; index < stream->num_buffers; index++) { + stream->buffers[index] = buffer + (index * bufferSize); + stream->buffers_pa[index] = bufferPhysicalAddress + (index * bufferSize); } /* Now allocate BDL for buffer range */ - alloc = s->num_buffers * sizeof(bdl_entry_t); - alloc = (alloc + B_PAGE_SIZE - 1) & (~(B_PAGE_SIZE -1)); - - s->bdl_area = create_area("hda_bdl", (void**)&bdl, B_ANY_KERNEL_ADDRESS, alloc, B_CONTIGUOUS, 0); - if (s->bdl_area < B_OK) { - delete_area(s->buffer_area); - return s->bdl_area; + 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) { + delete_area(stream->buffer_area); + return stream->bdl_area; } /* Get the physical address of memory */ rc = get_memory_map(bdl, alloc, &pe, 1); if (rc != B_OK) { - delete_area(s->buffer_area); - delete_area(s->bdl_area); + delete_area(stream->buffer_area); + delete_area(stream->bdl_area); return rc; } - - s->bdl_pa = (uint32)pe.address; + + stream->bdl_pa = (uint32)pe.address; dprintf("%s(%s): Allocated %ld bytes for %ld BDLEs\n", __func__, desc, - alloc, s->num_buffers); + alloc, stream->num_buffers); /* Setup BDL entries */ - for (idx=0; idx < s->num_buffers; idx++, bdl++) { - bdl->address = s->buffers_pa[idx]; - bdl->length = buffer_size; + for (index = 0; index < stream->num_buffers; index++, bdl++) { + bdl->address = stream->buffers_pa[index]; + bdl->length = bufferSize; bdl->ioc = 1; } /* Configure stream registers */ - wfmt = s->num_channels -1; - switch(s->sampleformat) { - case B_FMT_8BIT_S: wfmt |= (0 << 4); s->bps = 8; break; - case B_FMT_16BIT: wfmt |= (1 << 4); s->bps = 16; break; - case B_FMT_24BIT: wfmt |= (3 << 4); s->bps = 24; break; - case B_FMT_32BIT: wfmt |= (4 << 4); s->bps = 32; break; - default: dprintf("%s: Invalid sample format: 0x%lx\n", __func__, s->sampleformat); break; + wfmt = stream->num_channels -1; + switch (stream->sampleformat) { + 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_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); + break; } - switch(s->samplerate) { - case B_SR_8000: wfmt |= (0 << 14) | (0 << 11) | (5 << 8); s->rate=8000; break; - case B_SR_11025: wfmt |= (1 << 14) | (0 << 11) | (3 << 8); s->rate=11025; break; - case B_SR_16000: wfmt |= (0 << 14) | (0 << 11) | (2 << 8); s->rate=16000; break; - case B_SR_22050: wfmt |= (1 << 14) | (0 << 11) | (1 << 8); s->rate=22050; break; - case B_SR_32000: wfmt |= (0 << 14) | (1 << 11) | (2 << 8); s->rate=32000; break; - case B_SR_44100: wfmt |= (1 << 14) | (0 << 11) | (0 << 8); s->rate=44100; break; - case B_SR_48000: wfmt |= (0 << 14) | (0 << 11) | (0 << 8); s->rate=48000; break; - case B_SR_88200: wfmt |= (1 << 14) | (1 << 11) | (0 << 8); s->rate=88200; break; - case B_SR_96000: wfmt |= (0 << 14) | (2 << 11) | (0 << 8); s->rate=96000; break; - case B_SR_176400: wfmt |= (1 << 14) | (3 << 11) | (0 << 8); s->rate=176400; break; - case B_SR_192000: wfmt |= (0 << 14) | (3 << 11) | (0 << 8); s->rate=192000; break; - default: dprintf("%s: Invalid sample rate: 0x%lx\n", __func__, s->samplerate); break; + switch (stream->samplerate) { + case B_SR_8000: + wfmt |= (0 << 14) | (0 << 11) | (5 << 8); + stream->rate = 8000; + break; + case B_SR_11025: + wfmt |= (1 << 14) | (0 << 11) | (3 << 8); + stream->rate = 11025; + break; + case B_SR_16000: + wfmt |= (0 << 14) | (0 << 11) | (2 << 8); + stream->rate = 16000; + break; + case B_SR_22050: + wfmt |= (1 << 14) | (0 << 11) | (1 << 8); + stream->rate = 22050; + break; + case B_SR_32000: + wfmt |= (0 << 14) | (1 << 11) | (2 << 8); + stream->rate = 32000; + break; + case B_SR_44100: + wfmt |= (1 << 14) | (0 << 11) | (0 << 8); + stream->rate = 44100; + break; + case B_SR_48000: + wfmt |= (0 << 14) | (0 << 11) | (0 << 8); + stream->rate = 48000; + break; + case B_SR_88200: + wfmt |= (1 << 14) | (1 << 11) | (0 << 8); + stream->rate = 88200; + break; + case B_SR_96000: + wfmt |= (0 << 14) | (2 << 11) | (0 << 8); + stream->rate = 96000; + break; + case B_SR_176400: + wfmt |= (1 << 14) | (3 << 11) | (0 << 8); + stream->rate = 176400; + break; + case B_SR_192000: + wfmt |= (0 << 14) | (3 << 11) | (0 << 8); + stream->rate = 192000; + break; + + default: + dprintf("%s: Invalid sample rate: 0x%lx\n", __func__, + stream->samplerate); + break; } - dprintf("IRA: %s: setup stream %ld: SR=%ld, SF=%ld\n", __func__, s->id, s->rate, s->bps); + dprintf("IRA: %s: setup stream %ld: SR=%ld, SF=%ld\n", __func__, stream->id, + stream->rate, stream->bps); - OREG16(afg->codec->ctrlr,s->off,FMT) = wfmt; - OREG32(afg->codec->ctrlr,s->off,BDPL) = s->bdl_pa; - OREG32(afg->codec->ctrlr,s->off,BDPU) = 0; - OREG16(afg->codec->ctrlr,s->off,LVI) = s->num_buffers -1; - OREG32(afg->codec->ctrlr,s->off,CBL) = s->sample_size * s->num_channels * s->num_buffers * s->buffer_length; /* total cyclic buffer size in _bytes_ */ - OREG8(afg->codec->ctrlr,s->off,CTL0) = CTL0_IOCE | CTL0_FEIE | CTL0_DEIE; - OREG8(afg->codec->ctrlr,s->off,CTL2) = s->id << 4; + 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; + /* 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) + = CTL0_IOCE | CTL0_FEIE | CTL0_DEIE; + OREG8(afg->codec->controller, stream->off, CTL2) = stream->id << 4; - verb[0] = MAKE_VERB(afg->codec->addr, s->io_wid, VID_SET_CONVFORMAT, wfmt); - verb[1] = MAKE_VERB(afg->codec->addr, s->io_wid, VID_SET_CVTSTRCHN, s->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); return rc; } -//#pragma mark - + +// #pragma mark - + status_t hda_send_verbs(hda_codec* codec, corb_t* verbs, uint32* responses, int count) { - corb_t* corb = codec->ctrlr->corb; + corb_t* corb = codec->controller->corb; status_t rc; codec->response_count = 0; - memcpy(corb+(codec->ctrlr->corbwp +1), verbs, sizeof(corb_t)*count); - REG16(codec->ctrlr,CORBWP) = (codec->ctrlr->corbwp += count); + memcpy(corb + (codec->controller->corbwp + 1), verbs, + sizeof(corb_t) * count); + REG16(codec->controller, CORBWP) = (codec->controller->corbwp += count); - rc = acquire_sem_etc(codec->response_sem, count, B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, 1000ULL * 50); + rc = acquire_sem_etc(codec->response_sem, count, /*B_CAN_INTERRUPT | */ + B_RELATIVE_TIMEOUT, 1000ULL * 50); if (rc == B_OK && responses != NULL) - memcpy(responses, codec->responses, count*sizeof(uint32)); + memcpy(responses, codec->responses, count * sizeof(uint32)); return rc; } + static int32 -hda_interrupt_handler(hda_controller* ctrlr) +hda_interrupt_handler(hda_controller* controller) { - int32 rc = B_UNHANDLED_INTERRUPT; - + int32 rc = B_HANDLED_INTERRUPT; + /* Check if this interrupt is ours */ - uint32 intsts = REG32(ctrlr, INTSTS); - if (intsts & INTSTS_GIS) { - rc = B_HANDLED_INTERRUPT; + uint32 intsts = REG32(controller, INTSTS); + if ((intsts & INTSTS_GIS) == 0) + return B_UNHANDLED_INTERRUPT; - /* Controller or stream related? */ - if (intsts & INTSTS_CIS) { - uint32 statests = REG16(ctrlr,STATESTS); - uint8 rirbsts = REG8(ctrlr,RIRBSTS); - uint8 corbsts = REG8(ctrlr,CORBSTS); + /* Controller or stream related? */ + if (intsts & INTSTS_CIS) { + uint32 statests = REG16(controller, STATESTS); + uint8 rirbsts = REG8(controller, RIRBSTS); + uint8 corbsts = REG8(controller, CORBSTS); - if (statests) { - /* Detected Codec state change */ - REG16(ctrlr,STATESTS) = statests; - ctrlr->codecsts = statests; - } - - /* Check for incoming responses */ - if (rirbsts) { - REG8(ctrlr,RIRBSTS) = rirbsts; - - if (rirbsts & RIRBSTS_RINTFL) { - uint16 rirbwp = REG16(ctrlr,RIRBWP); - while (ctrlr->rirbrp <= rirbwp) { - uint32 resp_ex = ctrlr->rirb[ctrlr->rirbrp].resp_ex; - uint32 cad = resp_ex & HDA_MAXCODECS; - hda_codec* codec = ctrlr->codecs[cad]; - - if (resp_ex & RESP_EX_UNSOL) { - dprintf("%s: Usolicited response: %08lx/%08lx\n", __func__, - ctrlr->rirb[ctrlr->rirbrp].response, resp_ex); - } else if (codec) { - /* Store responses in codec */ - codec->responses[codec->response_count++] = ctrlr->rirb[ctrlr->rirbrp].response; - release_sem_etc(codec->response_sem, 1, B_DO_NOT_RESCHEDULE); - rc = B_INVOKE_SCHEDULER; - } else { - dprintf("%s: Response for unknown codec %ld: %08lx/%08lx\n", __func__, cad, - ctrlr->rirb[ctrlr->rirbrp].response, resp_ex); - } - - - ++ctrlr->rirbrp; - } - } - - if (rirbsts & RIRBSTS_OIS) - dprintf("%s: RIRB Overflow\n", __func__); - } - - /* Check for sending errors */ - if (corbsts) { - REG8(ctrlr,CORBSTS) = corbsts; - - if (corbsts & CORBSTS_MEI) - dprintf("%s: CORB Memory Error!\n", __func__); - } + if (statests) { + /* Detected Codec state change */ + REG16(controller, STATESTS) = statests; + controller->codecsts = statests; } - if (intsts & ~(INTSTS_CIS|INTSTS_GIS)) { - int idx; - for (idx=0; idx < HDA_MAXSTREAMS; idx++) { - if (intsts & (1 << idx)) { - if (ctrlr->streams[idx]) - hda_stream_check_intr(ctrlr, ctrlr->streams[idx]); - else - dprintf("%s: Stream interrupt for unconfigured stream %d!\n", __func__, idx); - } + /* Check for incoming responses */ + if (rirbsts) { + REG8(controller, RIRBSTS) = rirbsts; + + if (rirbsts & RIRBSTS_RINTFL) { + uint16 rirbwp = REG16(controller, RIRBWP); + while (controller->rirbrp <= rirbwp) { + uint32 resp_ex + = controller->rirb[controller->rirbrp].resp_ex; + uint32 cad = resp_ex & HDA_MAXCODECS; + hda_codec* codec = controller->codecs[cad]; + + if (resp_ex & RESP_EX_UNSOL) { + dprintf("%s: Unsolicited response: %08lx/%08lx\n", + __func__, + controller->rirb[controller->rirbrp].response, + resp_ex); + } else if (codec) { + /* Store responses in codec */ + codec->responses[codec->response_count++] + = controller->rirb[controller->rirbrp].response; + release_sem_etc(codec->response_sem, 1, + B_DO_NOT_RESCHEDULE); + rc = B_INVOKE_SCHEDULER; + } else { + dprintf("%s: Response for unknown codec %ld: " + "%08lx/%08lx\n", __func__, cad, + controller->rirb[controller->rirbrp].response, + resp_ex); + } + + ++controller->rirbrp; + } } + + if (rirbsts & RIRBSTS_OIS) + dprintf("%s: RIRB Overflow\n", __func__); + } + + /* Check for sending errors */ + if (corbsts) { + REG8(controller, CORBSTS) = corbsts; + + if (corbsts & CORBSTS_MEI) + dprintf("%s: CORB Memory Error!\n", __func__); } - - /* NOTE: See HDA001 => CIS/GIS cannot be cleared! */ } + if (intsts & ~(INTSTS_CIS | INTSTS_GIS)) { + int index; + for (index = 0; index < HDA_MAXSTREAMS; index++) { + if ((intsts & (1 << index)) != 0) { + if (controller->streams[index]) + hda_stream_check_intr(controller, controller->streams[index]); + else { + dprintf("%s: Stream interrupt for unconfigured stream " + "%d!\n", __func__, index); + } + } + } + } + + /* NOTE: See HDA001 => CIS/GIS cannot be cleared! */ + return rc; } + static status_t -hda_hw_start(hda_controller* ctrlr) +hda_hw_start(hda_controller* controller) { int timeout = 10; /* Put controller out of reset mode */ - REG32(ctrlr,GCTL) |= GCTL_CRST; - + REG32(controller, GCTL) |= GCTL_CRST; + do { snooze(100); - } while (--timeout && !(REG32(ctrlr,GCTL) & GCTL_CRST)); - + } while (--timeout && !(REG32(controller, GCTL) & GCTL_CRST)); + return timeout ? B_OK : B_TIMED_OUT; } + static status_t -hda_hw_corb_rirb_init(hda_controller* ctrlr) +hda_hw_corb_rirb_init(hda_controller* controller) { uint32 memsz, rirboff; uint8 corbsz, rirbsz; @@ -358,174 +437,171 @@ hda_hw_corb_rirb_init(hda_controller* ctrlr) physical_entry pe; /* Determine and set size of CORB */ - corbsz = REG8(ctrlr,CORBSIZE); + corbsz = REG8(controller, CORBSIZE); if (corbsz & CORBSIZE_CAP_256E) { - ctrlr->corblen = 256; - REG8(ctrlr,CORBSIZE) = CORBSIZE_SZ_256E; + controller->corblen = 256; + REG8(controller, CORBSIZE) = CORBSIZE_SZ_256E; } else if (corbsz & CORBSIZE_CAP_16E) { - ctrlr->corblen = 16; - REG8(ctrlr,CORBSIZE) = CORBSIZE_SZ_16E; + controller->corblen = 16; + REG8(controller, CORBSIZE) = CORBSIZE_SZ_16E; } else if (corbsz & CORBSIZE_CAP_2E) { - ctrlr->corblen = 2; - REG8(ctrlr,CORBSIZE) = CORBSIZE_SZ_2E; + controller->corblen = 2; + REG8(controller, CORBSIZE) = CORBSIZE_SZ_2E; } /* Determine and set size of RIRB */ - rirbsz = REG8(ctrlr,RIRBSIZE); + rirbsz = REG8(controller, RIRBSIZE); if (rirbsz & RIRBSIZE_CAP_256E) { - ctrlr->rirblen = 256; - REG8(ctrlr,RIRBSIZE) = RIRBSIZE_SZ_256E; + controller->rirblen = 256; + REG8(controller, RIRBSIZE) = RIRBSIZE_SZ_256E; } else if (rirbsz & RIRBSIZE_CAP_16E) { - ctrlr->rirblen = 16; - REG8(ctrlr,RIRBSIZE) = RIRBSIZE_SZ_16E; + controller->rirblen = 16; + REG8(controller, RIRBSIZE) = RIRBSIZE_SZ_16E; } else if (rirbsz & RIRBSIZE_CAP_2E) { - ctrlr->rirblen = 2; - REG8(ctrlr,RIRBSIZE) = RIRBSIZE_SZ_2E; + controller->rirblen = 2; + REG8(controller, RIRBSIZE) = RIRBSIZE_SZ_2E; } /* Determine rirb offset in memory and total size of corb+alignment+rirb */ - rirboff = (ctrlr->corblen * sizeof(corb_t) + 0x7f) & ~0x7f; - memsz = ((B_PAGE_SIZE -1) + - rirboff + - (ctrlr->rirblen * sizeof(rirb_t))) & ~(B_PAGE_SIZE-1); + rirboff = (controller->corblen * sizeof(corb_t) + 0x7f) & ~0x7f; + memsz = (rirboff + controller->rirblen * sizeof(rirb_t) + B_PAGE_SIZE - 1) + & ~(B_PAGE_SIZE - 1); /* Allocate memory area */ - ctrlr->rb_area = create_area("hda_corb_rirb", - (void**)&ctrlr->corb, B_ANY_KERNEL_ADDRESS, memsz, B_CONTIGUOUS, 0); - if (ctrlr->rb_area < 0) { - return ctrlr->rb_area; - } + controller->rb_area = create_area("hda_corb_rirb", (void**)&controller->corb, + B_ANY_KERNEL_ADDRESS, memsz, B_CONTIGUOUS, 0); + if (controller->rb_area < 0) + return controller->rb_area; /* Rirb is after corb+aligment */ - ctrlr->rirb = (rirb_t*)(((uint8*)ctrlr->corb)+rirboff); - - if ((rc=get_memory_map(ctrlr->corb, memsz, &pe, 1)) != B_OK) { - delete_area(ctrlr->rb_area); + controller->rirb = (rirb_t*)(((uint8*)controller->corb) + rirboff); + + if ((rc = get_memory_map(controller->corb, memsz, &pe, 1)) != B_OK) { + delete_area(controller->rb_area); return rc; } - + /* Program CORB/RIRB for these locations */ - REG32(ctrlr,CORBLBASE) = (uint32)pe.address; - REG32(ctrlr,RIRBLBASE) = (uint32)pe.address + rirboff; - + REG32(controller, CORBLBASE) = (uint32)pe.address; + REG32(controller, RIRBLBASE) = (uint32)pe.address + rirboff; + /* Reset CORB read pointer */ /* NOTE: See HDA011 for corrected procedure! */ - REG16(ctrlr,CORBRP) = CORBRP_RST; + REG16(controller, CORBRP) = CORBRP_RST; do { snooze(10); - } while ( !(REG16(ctrlr,CORBRP) & CORBRP_RST) ); - REG16(ctrlr,CORBRP) = 0; - + } while ( !(REG16(controller, CORBRP) & CORBRP_RST) ); + REG16(controller, CORBRP) = 0; + /* Reset RIRB write pointer */ - REG16(ctrlr,RIRBWP) = RIRBWP_RST; - + REG16(controller, RIRBWP) = RIRBWP_RST; + /* Generate interrupt for every response */ - REG16(ctrlr,RINTCNT) = 1; + REG16(controller, RINTCNT) = 1; /* Setup cached read/write indices */ - ctrlr->rirbrp = 1; - ctrlr->corbwp = 0; - + controller->rirbrp = 1; + controller->corbwp = 0; + /* Gentlemen, start your engines... */ - REG8(ctrlr,CORBCTL) = CORBCTL_RUN | CORBCTL_MEIE; - REG8(ctrlr,RIRBCTL) = RIRBCTL_DMAEN | RIRBCTL_OIC | RIRBCTL_RINTCTL; + REG8(controller, CORBCTL) = CORBCTL_RUN | CORBCTL_MEIE; + REG8(controller, RIRBCTL) = RIRBCTL_DMAEN | RIRBCTL_OIC | RIRBCTL_RINTCTL; return B_OK; } +// #pragma mark - -//#pragma mark - -/* Setup hardware for use; detect codecs; etc */ +/*! Setup hardware for use; detect codecs; etc */ status_t -hda_hw_init(hda_controller* ctrlr) +hda_hw_init(hda_controller* controller) { status_t rc; uint16 gcap; - uint32 idx; + uint32 index; /* Map MMIO registers */ - ctrlr->regs_area = - map_physical_memory("hda_hw_regs", (void*)ctrlr->pcii.u.h0.base_registers[0], - ctrlr->pcii.u.h0.base_register_sizes[0], B_ANY_KERNEL_ADDRESS, 0, - (void**)&ctrlr->regs); - - if (ctrlr->regs_area < B_OK) { - rc = ctrlr->regs_area; + controller->regs_area = map_physical_memory("hda_hw_regs", + (void*)controller->pci_info.u.h0.base_registers[0], + controller->pci_info.u.h0.base_register_sizes[0], B_ANY_KERNEL_ADDRESS, + 0, (void**)&controller->regs); + if (controller->regs_area < B_OK) { + rc = controller->regs_area; goto error; } /* Absolute minimum hw is online; we can now install interrupt handler */ - ctrlr->irq = ctrlr->pcii.u.h0.interrupt_line; - rc = install_io_interrupt_handler(ctrlr->irq, - (interrupt_handler)hda_interrupt_handler, ctrlr, 0); + controller->irq = controller->pci_info.u.h0.interrupt_line; + rc = install_io_interrupt_handler(controller->irq, + (interrupt_handler)hda_interrupt_handler, controller, 0); if (rc != B_OK) goto no_irq; /* show some hw features */ - gcap = REG16(ctrlr,GCAP); + gcap = REG16(controller, GCAP); dprintf("HDA: HDA v%d.%d, O:%d/I:%d/B:%d, #SDO:%d, 64bit:%s\n", - REG8(ctrlr,VMAJ), REG8(ctrlr,VMIN), + REG8(controller, VMAJ), REG8(controller, VMIN), GCAP_OSS(gcap), GCAP_ISS(gcap), GCAP_BSS(gcap), GCAP_NSDO(gcap) ? GCAP_NSDO(gcap) *2 : 1, gcap & GCAP_64OK ? "yes" : "no" ); - ctrlr->num_input_streams = GCAP_OSS(gcap); - ctrlr->num_output_streams = GCAP_ISS(gcap); - ctrlr->num_bidir_streams = GCAP_BSS(gcap); + controller->num_input_streams = GCAP_OSS(gcap); + controller->num_output_streams = GCAP_ISS(gcap); + controller->num_bidir_streams = GCAP_BSS(gcap); /* Get controller into valid state */ - rc = hda_hw_start(ctrlr); + rc = hda_hw_start(controller); if (rc != B_OK) goto reset_failed; /* Setup CORB/RIRB */ - rc = hda_hw_corb_rirb_init(ctrlr); + rc = hda_hw_corb_rirb_init(controller); if (rc != B_OK) goto corb_rirb_failed; - REG16(ctrlr,WAKEEN) = 0x7fff; + REG16(controller, WAKEEN) = 0x7fff; /* Enable controller interrupts */ - REG32(ctrlr,INTCTL) = INTCTL_GIE | INTCTL_CIE | 0xffff; + REG32(controller, INTCTL) = INTCTL_GIE | INTCTL_CIE | 0xffff; /* Wait for codecs to warm up */ snooze(1000); - if (!ctrlr->codecsts) { + if (!controller->codecsts) { rc = ENODEV; goto corb_rirb_failed; } - for (idx=0; idx < HDA_MAXCODECS; idx++) - if (ctrlr->codecsts & (1 << idx)) - hda_codec_new(ctrlr, idx); + for (index = 0; index < HDA_MAXCODECS; index++) { + if ((controller->codecsts & (1 << index)) != 0) + hda_codec_new(controller, index); + } - for (idx=0; idx < HDA_MAXCODECS; idx++) { - if (ctrlr->codecs[idx] && ctrlr->codecs[idx]->num_afgs) { - ctrlr->active_codec = ctrlr->codecs[idx]; + for (index = 0; index < HDA_MAXCODECS; index++) { + if (controller->codecs[index] && controller->codecs[index]->num_afgs) { + controller->active_codec = controller->codecs[index]; break; } } - if (ctrlr->active_codec != NULL) + if (controller->active_codec != NULL) return B_OK; - else - rc = ENODEV; + + rc = ENODEV; corb_rirb_failed: - REG32(ctrlr,INTCTL) = 0; + REG32(controller, INTCTL) = 0; reset_failed: - remove_io_interrupt_handler(ctrlr->irq, - (interrupt_handler)hda_interrupt_handler, - ctrlr); + remove_io_interrupt_handler(controller->irq, + (interrupt_handler)hda_interrupt_handler, controller); no_irq: - delete_area(ctrlr->regs_area); - ctrlr->regs_area = B_ERROR; - ctrlr->regs = NULL; + delete_area(controller->regs_area); + controller->regs_area = B_ERROR; + controller->regs = NULL; error: dprintf("ERROR: %s(%ld)\n", strerror(rc), rc); @@ -533,57 +609,61 @@ error: return rc; } -/* Stop any activity */ + +/*! Stop any activity */ void -hda_hw_stop(hda_controller* ctrlr) +hda_hw_stop(hda_controller* controller) { - int idx; - + int index; + /* Stop all audio streams */ - for (idx=0; idx < HDA_MAXSTREAMS; idx++) - if (ctrlr->streams[idx] && ctrlr->streams[idx]->running) - hda_stream_stop(ctrlr, ctrlr->streams[idx]); + for (index = 0; index < HDA_MAXSTREAMS; index++) + if (controller->streams[index] && controller->streams[index]->running) + hda_stream_stop(controller, controller->streams[index]); } -/* Free resources */ + +/*! Free resources */ void -hda_hw_uninit(hda_controller* ctrlr) +hda_hw_uninit(hda_controller* controller) { - if (ctrlr != NULL) { - uint32 idx; + uint32 index; - /* Stop all audio streams */ - hda_hw_stop(ctrlr); - - /* Stop CORB/RIRB */ - REG8(ctrlr,CORBCTL) = 0; - REG8(ctrlr,RIRBCTL) = 0; + if (controller == NULL) + return; - /* Disable interrupts and remove interrupt handler */ - REG32(ctrlr,INTCTL) = 0; - REG32(ctrlr,GCTL) &= ~GCTL_CRST; - remove_io_interrupt_handler(ctrlr->irq, - (interrupt_handler)hda_interrupt_handler, - ctrlr); + /* Stop all audio streams */ + hda_hw_stop(controller); - /* Delete corb/rirb area */ - if (ctrlr->rb_area >= 0) { - delete_area(ctrlr->rb_area); - ctrlr->rb_area = B_ERROR; - ctrlr->corb = NULL; - ctrlr->rirb = NULL; - } - - /* Unmap registers */ - if (ctrlr->regs_area >= 0) { - delete_area(ctrlr->regs_area); - ctrlr->regs_area = B_ERROR; - ctrlr->regs = NULL; - } - - /* Now delete all codecs */ - for (idx=0; idx < HDA_MAXCODECS; idx++) - if (ctrlr->codecs[idx] != NULL) - hda_codec_delete(ctrlr->codecs[idx]); + /* Stop CORB/RIRB */ + REG8(controller, CORBCTL) = 0; + REG8(controller, RIRBCTL) = 0; + + /* Disable interrupts and remove interrupt handler */ + REG32(controller, INTCTL) = 0; + REG32(controller, GCTL) &= ~GCTL_CRST; + remove_io_interrupt_handler(controller->irq, + (interrupt_handler)hda_interrupt_handler, controller); + + /* Delete corb/rirb area */ + if (controller->rb_area >= 0) { + delete_area(controller->rb_area); + controller->rb_area = B_ERROR; + controller->corb = NULL; + controller->rirb = NULL; + } + + /* Unmap registers */ + if (controller->regs_area >= 0) { + delete_area(controller->regs_area); + controller->regs_area = B_ERROR; + controller->regs = NULL; + } + + /* Now delete all codecs */ + for (index = 0; index < HDA_MAXCODECS; index++) { + if (controller->codecs[index] != NULL) + hda_codec_delete(controller->codecs[index]); } } + diff --git a/src/add-ons/kernel/drivers/audio/hda/hda_controller_defs.h b/src/add-ons/kernel/drivers/audio/hda/hda_controller_defs.h index 38d963eaa2..5dda6bdbf4 100644 --- a/src/add-ons/kernel/drivers/audio/hda/hda_controller_defs.h +++ b/src/add-ons/kernel/drivers/audio/hda/hda_controller_defs.h @@ -1,16 +1,26 @@ +/* + * Copyright 2007-2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ithamar Adema, ithamar AT unet DOT nl + */ #ifndef HDAC_REGS_H #define HDAC_REGS_H #include /* Accessors for HDA controller registers */ -#define REG32(ctrlr,reg) (*(vuint32*)((ctrlr)->regs + HDAC_##reg)) -#define REG16(ctrlr,reg) (*(vuint16*)((ctrlr)->regs + HDAC_##reg)) -#define REG8(ctrlr,reg) (*((ctrlr)->regs + HDAC_##reg)) +#define REG32(controller, reg) (*(vuint32*)((controller)->regs + HDAC_##reg)) +#define REG16(controller, reg) (*(vuint16*)((controller)->regs + HDAC_##reg)) +#define REG8(controller, reg) (*((controller)->regs + HDAC_##reg)) -#define OREG32(ctrlr,s,reg) (*(vuint32*)((ctrlr)->regs + HDAC_SDBASE + (s) + HDAC_SD_##reg)) -#define OREG16(ctrlr,s,reg) (*(vuint16*)((ctrlr)->regs + HDAC_SDBASE + (s) + HDAC_SD_##reg)) -#define OREG8(ctrlr,s,reg) (*((ctrlr)->regs + HDAC_SDBASE + (s) + HDAC_SD_##reg)) +#define OREG32(controller, stream, reg) \ + (*(vuint32*)((controller)->regs + HDAC_SDBASE + (stream) + HDAC_SD_##reg)) +#define OREG16(controller, stream, reg) \ + (*(vuint16*)((controller)->regs + HDAC_SDBASE + (stream) + HDAC_SD_##reg)) +#define OREG8(controller, stream, reg) \ + (*((controller)->regs + HDAC_SDBASE + (stream) + HDAC_SD_##reg)) /* Register definitions */ #define HDAC_GCAP 0x00 /* 16bits */ 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 87786238b8..569c6b3214 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 @@ -1,7 +1,17 @@ +/* + * Copyright 2007-2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ithamar Adema, ithamar AT unet DOT nl + */ + + #include "multi_audio.h" #include "driver.h" -multi_channel_info chans[] = { + +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 }, @@ -12,10 +22,11 @@ multi_channel_info chans[] = { { 7, B_MULTI_INPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO }, }; + static int32 format2size(uint32 format) { - switch(format) { + switch (format) { case B_FMT_8BIT_S: case B_FMT_16BIT: return 2; @@ -27,20 +38,21 @@ format2size(uint32 format) case B_FMT_FLOAT: return 8; - + default: return -1; } } + static status_t get_description(hda_afg* afg, multi_description* data) { data->interface_version = B_CURRENT_INTERFACE_VERSION; data->interface_minimum = B_CURRENT_INTERFACE_VERSION; - strcpy(data->friendly_name,"HD Audio"); - strcpy(data->vendor_info,"Haiku"); + strcpy(data->friendly_name, "HD Audio"); + strcpy(data->vendor_info, "Haiku"); data->output_channel_count = 2; data->input_channel_count = 2; @@ -48,10 +60,12 @@ get_description(hda_afg* afg, multi_description* data) data->input_bus_channel_count = 2; data->aux_bus_channel_count = 0; - dprintf("%s: request_channel_count: %ld\n", __func__, data->request_channel_count); + dprintf("%s: request_channel_count: %ld\n", __func__, + data->request_channel_count); - if (data->request_channel_count >= (int)(sizeof(chans) / sizeof(chans[0]))) { - memcpy(data->channels,&chans,sizeof(chans)); + if (data->request_channel_count >= (int)(sizeof(sChannels) + / sizeof(sChannels[0]))) { + memcpy(data->channels, &sChannels, sizeof(sChannels)); } /* determine output/input rates */ @@ -74,11 +88,12 @@ get_description(hda_afg* afg, multi_description* data) data->interface_flags = B_MULTI_INTERFACE_PLAYBACK /* | B_MULTI_INTERFACE_RECORD */; data->start_latency = 30000; - strcpy(data->control_panel,""); + strcpy(data->control_panel, ""); return B_OK; } + static status_t get_enabled_channels(hda_afg* afg, multi_channel_enable* data) { @@ -91,6 +106,7 @@ get_enabled_channels(hda_afg* afg, multi_channel_enable* data) return B_OK; } + static status_t get_global_format(hda_afg* afg, multi_format_info* data) { @@ -107,6 +123,7 @@ get_global_format(hda_afg* afg, multi_format_info* data) return B_OK; } + static status_t set_global_format(hda_afg* afg, multi_format_info* data) { @@ -121,6 +138,7 @@ set_global_format(hda_afg* afg, multi_format_info* data) return B_OK; } + static status_t list_mix_controls(hda_afg* afg, multi_mix_control_info * data) { @@ -128,6 +146,7 @@ list_mix_controls(hda_afg* afg, multi_mix_control_info * data) return B_OK; } + static status_t list_mix_connections(hda_afg* afg, multi_mix_connection_info * data) { @@ -135,12 +154,14 @@ list_mix_connections(hda_afg* afg, multi_mix_connection_info * data) return B_OK; } + static status_t list_mix_channels(hda_afg* afg, multi_mix_channel_info *data) { return B_OK; } + static status_t get_buffers(hda_afg* afg, multi_buffer_list* data) { @@ -196,23 +217,30 @@ get_buffers(hda_afg* afg, multi_buffer_list* data) /* 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_playback_buffer_size = data->request_playback_buffer_size; + /* frames */ - 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] + (playback_sample_size * cidx); - data->playback_buffers[bidx][cidx].stride = playback_sample_size * data->return_playback_channels; + 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] + + (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 */ + 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); - data->record_buffers[bidx][cidx].stride = record_sample_size * data->return_record_channels; + 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); + data->record_buffers[bidx][cidx].stride + = record_sample_size * data->return_record_channels; } } @@ -229,7 +257,7 @@ buffer_exchange(hda_afg* afg, multi_buffer_info* data) status_t rc; if (!afg->playback_stream->running) - hda_stream_start(afg->codec->ctrlr, afg->playback_stream); + hda_stream_start(afg->codec->controller, afg->playback_stream); /* do playback */ rc=acquire_sem(afg->playback_stream->buffer_ready_sem); @@ -260,8 +288,8 @@ buffer_exchange(hda_afg* afg, multi_buffer_info* data) static status_t buffer_force_stop(hda_afg* afg) { - hda_stream_stop(afg->codec->ctrlr, afg->playback_stream); - //hda_stream_stop(afg->codec->ctrlr, afg->record_stream); + 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); @@ -281,27 +309,44 @@ multi_audio_control(void* cookie, uint32 op, void* arg, size_t len) afg = codec->afgs[0]; - switch(op) { - case B_MULTI_GET_DESCRIPTION: return get_description(afg, arg); - case B_MULTI_GET_EVENT_INFO: return B_ERROR; - case B_MULTI_SET_EVENT_INFO: return B_ERROR; - case B_MULTI_GET_EVENT: return B_ERROR; - case B_MULTI_GET_ENABLED_CHANNELS: return get_enabled_channels(afg, arg); - case B_MULTI_SET_ENABLED_CHANNELS: return B_OK; - case B_MULTI_GET_GLOBAL_FORMAT: return get_global_format(afg, arg); - case B_MULTI_SET_GLOBAL_FORMAT: return set_global_format(afg, arg); - case B_MULTI_GET_CHANNEL_FORMATS: return B_ERROR; - case B_MULTI_SET_CHANNEL_FORMATS: return B_ERROR; - case B_MULTI_GET_MIX: return B_ERROR; - case B_MULTI_SET_MIX: return B_ERROR; - case B_MULTI_LIST_MIX_CHANNELS: return list_mix_channels(afg, arg); - case B_MULTI_LIST_MIX_CONTROLS: return list_mix_controls(afg, arg); - case B_MULTI_LIST_MIX_CONNECTIONS: return list_mix_connections(afg, arg); - case B_MULTI_GET_BUFFERS: return get_buffers(afg, arg); - case B_MULTI_SET_BUFFERS: return B_ERROR; - case B_MULTI_SET_START_TIME: return B_ERROR; - case B_MULTI_BUFFER_EXCHANGE: return buffer_exchange(afg, arg); - case B_MULTI_BUFFER_FORCE_STOP: return buffer_force_stop(afg); + switch (op) { + case B_MULTI_GET_DESCRIPTION: + return get_description(afg, arg); + + case B_MULTI_GET_ENABLED_CHANNELS: + return get_enabled_channels(afg, arg); + case B_MULTI_SET_ENABLED_CHANNELS: + return B_OK; + + case B_MULTI_GET_GLOBAL_FORMAT: + return get_global_format(afg, arg); + case B_MULTI_SET_GLOBAL_FORMAT: + return set_global_format(afg, arg); + + case B_MULTI_LIST_MIX_CHANNELS: + return list_mix_channels(afg, arg); + case B_MULTI_LIST_MIX_CONTROLS: + return list_mix_controls(afg, arg); + case B_MULTI_LIST_MIX_CONNECTIONS: + return list_mix_connections(afg, arg); + case B_MULTI_GET_BUFFERS: + return get_buffers(afg, arg); + + case B_MULTI_BUFFER_EXCHANGE: + return buffer_exchange(afg, arg); + case B_MULTI_BUFFER_FORCE_STOP: + return buffer_force_stop(afg); + + case B_MULTI_GET_EVENT_INFO: + case B_MULTI_SET_EVENT_INFO: + case B_MULTI_GET_EVENT: + case B_MULTI_GET_CHANNEL_FORMATS: + case B_MULTI_SET_CHANNEL_FORMATS: + case B_MULTI_GET_MIX: + case B_MULTI_SET_MIX: + case B_MULTI_SET_BUFFERS: + case B_MULTI_SET_START_TIME: + return B_ERROR; } return B_BAD_VALUE; diff --git a/src/add-ons/kernel/drivers/audio/hda/hooks.c b/src/add-ons/kernel/drivers/audio/hda/hooks.c index add8b58a46..c12f7bc5b2 100644 --- a/src/add-ons/kernel/drivers/audio/hda/hooks.c +++ b/src/add-ons/kernel/drivers/audio/hda/hooks.c @@ -1,82 +1,101 @@ +/* + * Copyright 2007-2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ithamar Adema, ithamar AT unet DOT nl + */ + + #include "driver.h" + static status_t -hda_open (const char *name, uint32 flags, void** cookie) +hda_open(const char *name, uint32 flags, void** cookie) { - hda_controller* hc = NULL; + hda_controller* controller = NULL; status_t rc = B_OK; long i; - for(i=0; i < num_cards; i++) { - if (strcmp(cards[i].devfs_path, name) == 0) { - hc = &cards[i]; + for (i = 0; i < gNumCards; i++) { + if (strcmp(gCards[i].devfs_path, name) == 0) { + controller = &gCards[i]; + break; } } - - if (hc == NULL) + + if (controller == NULL) return ENODEV; - - if (hc->opened) + + if (controller->opened) return B_BUSY; - rc = hda_hw_init(hc); + rc = hda_hw_init(controller); if (rc != B_OK) return rc; - hc->opened++; + controller->opened++; - *cookie = hc; + *cookie = controller; return B_OK; } + static status_t -hda_read (void* cookie, off_t position, void *buf, size_t* num_bytes) +hda_read(void* cookie, off_t position, void *buf, size_t* numBytes) { - *num_bytes = 0; /* tell caller nothing was read */ + *numBytes = 0; + /* tell caller nothing was read */ return B_IO_ERROR; } + static status_t -hda_write (void* cookie, off_t position, const void* buffer, size_t* num_bytes) +hda_write(void* cookie, off_t position, const void* buffer, size_t* numBytes) { - *num_bytes = 0; /* tell caller nothing was written */ + *numBytes = 0; + /* tell caller nothing was written */ return B_IO_ERROR; } + static status_t -hda_control (void* cookie, uint32 op, void* arg, size_t len) +hda_control(void* cookie, uint32 op, void* arg, size_t length) { - hda_controller* hc = (hda_controller*)cookie; - if (hc->active_codec) - return multi_audio_control(hc->active_codec, op, arg, len); + hda_controller* controller = (hda_controller*)cookie; + if (controller->active_codec) + return multi_audio_control(controller->active_codec, op, arg, length); return B_BAD_VALUE; } + static status_t -hda_close (void* cookie) +hda_close(void* cookie) { - hda_controller* hc = (hda_controller*)cookie; - hda_hw_stop(hc); - --hc->opened; + hda_controller* controller = (hda_controller*)cookie; + hda_hw_stop(controller); + --controller->opened; return B_OK; } + static status_t -hda_free (void* cookie) +hda_free(void* cookie) { - hda_controller* hc = (hda_controller*)cookie; - hda_hw_uninit(hc); + hda_controller* controller = (hda_controller*)cookie; + hda_hw_uninit(controller); return B_OK; } -device_hooks driver_hooks = { + +device_hooks gDriverHooks = { hda_open, /* -> open entry point */ hda_close, /* -> close entry point */ hda_free, /* -> free cookie */ - hda_control, /* -> control entry point */ + hda_control, /* -> control entry point */ hda_read, /* -> read entry point */ hda_write /* -> write entry point */ };