From 5adb129ea33d02bfa4f36bb515d6153538c6c07e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Tue, 6 Jan 2004 10:34:05 +0000 Subject: [PATCH] Echo driver : echogals and echo24 This is implemented but untested. Mixer is lacking, and multichannels support. Only 2 channels input/output currently. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5929 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/drivers/audio/echo/24/Jamfile | 102 +- src/add-ons/kernel/drivers/audio/echo/debug.c | 94 + src/add-ons/kernel/drivers/audio/echo/debug.h | 93 + .../kernel/drivers/audio/echo/echo.cpp | 681 +++++ src/add-ons/kernel/drivers/audio/echo/echo.h | 137 + .../kernel/drivers/audio/echo/gals/Jamfile | 102 +- .../echo/generic/CDarla24DspCommObject.cpp | 463 ++-- .../echo/generic/CEchoGals_transport.cpp | 2450 ++++++++--------- .../drivers/audio/echo/generic/CLayla.cpp | 658 ++--- .../echo/generic/CLaylaDspCommObject.cpp | 806 +++--- .../drivers/audio/echo/generic/MixerXface.h | 695 +++-- .../audio/echo/generic/OsSupportBeOS.cpp | 138 +- .../audio/echo/generic/OsSupportBeOS.h | 65 +- .../kernel/drivers/audio/echo/multi.cpp | 664 +++++ src/add-ons/kernel/drivers/audio/echo/multi.h | 64 + .../kernel/drivers/audio/echo/multi_audio.h | 702 +++++ src/add-ons/kernel/drivers/audio/echo/queue.h | 529 ++++ src/add-ons/kernel/drivers/audio/echo/util.c | 88 + src/add-ons/kernel/drivers/audio/echo/util.h | 50 + 19 files changed, 5922 insertions(+), 2659 deletions(-) create mode 100644 src/add-ons/kernel/drivers/audio/echo/debug.c create mode 100644 src/add-ons/kernel/drivers/audio/echo/debug.h create mode 100644 src/add-ons/kernel/drivers/audio/echo/echo.cpp create mode 100644 src/add-ons/kernel/drivers/audio/echo/echo.h create mode 100644 src/add-ons/kernel/drivers/audio/echo/multi.cpp create mode 100644 src/add-ons/kernel/drivers/audio/echo/multi.h create mode 100644 src/add-ons/kernel/drivers/audio/echo/multi_audio.h create mode 100644 src/add-ons/kernel/drivers/audio/echo/queue.h create mode 100644 src/add-ons/kernel/drivers/audio/echo/util.c create mode 100644 src/add-ons/kernel/drivers/audio/echo/util.h diff --git a/src/add-ons/kernel/drivers/audio/echo/24/Jamfile b/src/add-ons/kernel/drivers/audio/echo/24/Jamfile index b38f8ab91d..84d76fcbaa 100644 --- a/src/add-ons/kernel/drivers/audio/echo/24/Jamfile +++ b/src/add-ons/kernel/drivers/audio/echo/24/Jamfile @@ -1,34 +1,90 @@ SubDir OBOS_TOP src add-ons kernel drivers audio echo 24 ; -UsePrivateHeaders media ; +SubDirHdrs $(OBOS_TOP) src add-ons kernel drivers audio echo ; +SubDirHdrs $(OBOS_TOP) src add-ons kernel drivers audio echo generic ; +SubDirHdrs $(OBOS_TOP) src add-ons kernel drivers audio echo generic DSP ; +SubDirHdrs $(OBOS_TOP) src add-ons kernel drivers audio echo generic ASIC ; -R5KernelAddon echo_24 : kernel drivers bin : -# ac97_multi.c -# config.c -# debug.c -# ich.c -# io.c -# util.c -# ac97.c +UsePrivateHeaders [ FDirName kernel ] ; # For kernel_cpp.cpp + +# set some additional defines +{ + SubDirCcFlags -DECHO_BEOS -DECHO24_FAMILY ; + SubDirC++Flags -DECHO_BEOS -DECHO24_FAMILY ; +} + +R5KernelAddon echo24 : kernel drivers bin : + kernel_cpp.cpp + debug.c + echo.cpp + multi.cpp + util.c + CChannelMask.cpp + CDaffyDuck.cpp + CDspCommObject.cpp + CEchoGals.cpp + CEchoGals_info.cpp + CEchoGals_midi.cpp + CEchoGals_mixer.cpp + CEchoGals_power.cpp + CEchoGals_transport.cpp +# CEchoGals_WDM.cpp + CGina24.cpp + CGina24DspCommObject.cpp + CLayla24.cpp + CLayla24DspCommObject.cpp + CLineLevel.cpp + CMia.cpp + CMiaDspCommObject.cpp + CMidiInQ.cpp + CMona.cpp + CMonaDspCommObject.cpp + CMonitorCtrl.cpp + CPipeOutCtrl.cpp + OsSupportBeOS.cpp ; -# For OpenBeOS we should be building the driver objects this way. -#KernelObjects -# ac97_multi.c -# config.c -# debug.c -# ich.c -# io.c -# util.c -# ac97.c -# : -# -fno-pic -D_KERNEL_MODE -# ; +SEARCH on [ FGristFiles + CChannelMask.cpp + CDaffyDuck.cpp + CDspCommObject.cpp + CEchoGals.cpp + CEchoGals_info.cpp + CEchoGals_midi.cpp + CEchoGals_mixer.cpp + CEchoGals_power.cpp + CEchoGals_transport.cpp + CEchoGals_WDM.cpp + CGina24.cpp + CGina24DspCommObject.cpp + CLayla24.cpp + CLayla24DspCommObject.cpp + CLineLevel.cpp + CMia.cpp + CMiaDspCommObject.cpp + CMidiInQ.cpp + CMona.cpp + CMonaDspCommObject.cpp + CMonitorCtrl.cpp + CPipeOutCtrl.cpp + OsSupportBeOS.cpp + ] = [ FDirName $(OBOS_TOP) src add-ons kernel drivers audio echo generic ] ; + +SEARCH on [ FGristFiles + kernel_cpp.cpp + ] = [ FDirName $(OBOS_TOP) src kernel core util ] ; + +SEARCH on [ FGristFiles + debug.c + echo.cpp + multi.cpp + util.c + ] = [ FDirName $(OBOS_TOP) src add-ons kernel drivers audio echo ] ; # Link to kernel/drivers/dev/audio/multi { local dir = [ FDirName $(OBOS_ADDON_DIR) kernel drivers dev audio multi ] ; - local instDriver = echo_24 ; + local instDriver = echo24 ; MakeLocate $(instDriver) : $(dir) ; - RelSymLink $(instDriver) : echo_24 ; + RelSymLink $(instDriver) : echo24 ; } diff --git a/src/add-ons/kernel/drivers/audio/echo/debug.c b/src/add-ons/kernel/drivers/audio/echo/debug.c new file mode 100644 index 0000000000..6cafa2c380 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/echo/debug.c @@ -0,0 +1,94 @@ +/* + * EchoGals/Echo24 BeOS Driver for Echo audio cards + * + * Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr) + * + * Original code : BeOS Driver for Intel ICH AC'97 Link interface + * Copyright (c) 2002, Marcus Overhagen + * + * All rights reserved. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include +#include +#include +#include +#include "debug.h" + +#if DEBUG > 0 +static const char * logfile="/boot/home/"DRIVER_NAME".log"; +static sem_id loglock; +#endif + +void debug_printf(const char *text,...); +void log_printf(const char *text,...); +void log_create(); + +void debug_printf(const char *text,...) +{ + char buf[1024]; + va_list ap; + + va_start(ap,text); + vsprintf(buf,text,ap); + va_end(ap); + + dprintf(DRIVER_NAME ": %s",buf); +} + +void log_create() +{ +#if DEBUG > 0 + int fd = open(logfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); + const char *text = DRIVER_NAME ", " VERSION "\n"; + loglock = create_sem(1,"logfile sem"); + write(fd,text,strlen(text)); + close(fd); +#endif +} + +void log_printf(const char *text,...) +{ +#if DEBUG > 0 + int fd; + char buf[1024]; + va_list ap; + + va_start(ap,text); + vsprintf(buf,text,ap); + va_end(ap); + + dprintf(DRIVER_NAME ": %s",buf); + + acquire_sem(loglock); + fd = open(logfile, O_WRONLY | O_APPEND); + write(fd,buf,strlen(buf)); + close(fd); + release_sem(loglock); + + #if DEBUG > 1 + snooze(150000); + #endif +#endif +} + diff --git a/src/add-ons/kernel/drivers/audio/echo/debug.h b/src/add-ons/kernel/drivers/audio/echo/debug.h new file mode 100644 index 0000000000..1ea521bcc5 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/echo/debug.h @@ -0,0 +1,93 @@ +/* + * EchoGals/Echo24 BeOS Driver for Echo audio cards + * + * Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr) + * + * Original code : BeOS Driver for Intel ICH AC'97 Link interface + * Copyright (c) 2002, Marcus Overhagen + * + * All rights reserved. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +#ifdef ECHO24_FAMILY +#define DRIVER_NAME "echo24" +#endif +#ifdef ECHOGALS_FAMILY +#define DRIVER_NAME "echogals" +#endif +#define VERSION "0.0" + +/* + * PRINT() executes dprintf if DEBUG = 0 (disabled), or expands to LOG() when DEBUG > 0 + * TRACE() executes dprintf if DEBUG > 0 + * LOG() executes dprintf and writes to the logfile if DEBUG > 0 + */ + +/* DEBUG == 0, no debugging, PRINT writes to syslog + * DEBUG == 1, TRACE & LOG, PRINT + * DEBUG == 2, TRACE & LOG, PRINT with snooze() + */ +#ifndef DEBUG + #define DEBUG 0 +#endif + +#undef PRINT +#undef TRACE +#undef ASSERT + +#if DEBUG > 0 + #define PRINT(a) log_printf a + #define TRACE(a) debug_printf a + #define LOG(a) log_printf a + #define LOG_CREATE() log_create() + #define ASSERT(a) if (a) {} else LOG(("ASSERT failed! file = %s, line = %d\n",__FILE__,__LINE__)) +#ifdef __cplusplus +extern "C" { +#endif + + void log_create(); + void log_printf(const char *text,...); + void debug_printf(const char *text,...); +#ifdef __cplusplus +} +#endif + +#else +#ifdef __cplusplus +extern "C" { +#endif + void log_create(); + void debug_printf(const char *text,...); +#ifdef __cplusplus +} +#endif + #define PRINT(a) debug_printf a + #define TRACE(a) ((void)(0)) + #define ASSERT(a) ((void)(0)) + #define LOG(a) ((void)(0)) + #define LOG_CREATE() +#endif + +#endif diff --git a/src/add-ons/kernel/drivers/audio/echo/echo.cpp b/src/add-ons/kernel/drivers/audio/echo/echo.cpp new file mode 100644 index 0000000000..e95be7adb6 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/echo/echo.cpp @@ -0,0 +1,681 @@ +//------------------------------------------------------------------------------ +// +// EchoGals/Echo24 BeOS Driver for Echo audio cards +// +// Copyright (c) 2003, Jérôme Duval +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#include +#include +#include +#include +#include "OsSupportBeOS.h" +#include "EchoGalsXface.h" +#include "CDarla24.h" +#include "CDarla.h" +#include "CGina.h" +#include "CGina24.h" +#include "CLayla.h" +#include "CLayla24.h" +#include "CMia.h" +#include "CMona.h" +#include "echo.h" +#include "debug.h" +#include "util.h" + +static char pci_name[] = B_PCI_MODULE_NAME; +static pci_module_info *pci; +int32 num_cards; +echo_dev cards[NUM_CARDS]; +int32 num_names; +char * names[NUM_CARDS*20+1]; + +extern device_hooks multi_hooks; + +uint32 round_to_pagesize(uint32 size); +area_id map_mem(void **log, void *phy, size_t size, const char *name); +int32 echo_int(void *arg); +status_t init_hardware(void); +status_t init_driver(void); +static void make_device_names(echo_dev * card); + +static status_t echo_setup(echo_dev * card); +static void echo_shutdown(echo_dev *card); + +void uninit_driver(void); +const char ** publish_devices(void); +device_hooks * find_device(const char * name); + + +/* Echo Memory management */ + +echo_mem * +echo_mem_new(echo_dev *card, size_t size) +{ + echo_mem *mem; + + if ((mem = (echo_mem *) malloc(sizeof(*mem))) == NULL) + return (NULL); + + mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "echo buffer"); + mem->size = size; + if (mem->area < B_OK) { + free(mem); + return NULL; + } + return mem; +} + +void +echo_mem_delete(echo_mem *mem) +{ + if(mem->area > B_OK) + delete_area(mem->area); + free(mem); +} + +echo_mem * +echo_mem_alloc(echo_dev *card, size_t size) +{ + echo_mem *mem; + + mem = echo_mem_new(card, size); + if (mem == NULL) + return (NULL); + + LIST_INSERT_HEAD(&(card->mems), mem, next); + + return mem; +} + +void +echo_mem_free(echo_dev *card, void *ptr) +{ + echo_mem *mem; + + LIST_FOREACH(mem, &card->mems, next) { + if (mem->log_base != ptr) + continue; + LIST_REMOVE(mem, next); + + echo_mem_delete(mem); + break; + } +} + +/* Echo stream functions */ + +status_t +echo_stream_set_audioparms(echo_stream *stream, uint8 channels, + uint8 b16, uint32 sample_rate) +{ + int32 i; + uint8 sample_size, frame_size; + ECHOGALS_OPENAUDIOPARAMETERS open_params; + ECHOGALS_CLOSEAUDIOPARAMETERS close_params; + ECHOGALS_AUDIOFORMAT format_params; + + LOG(("echo_stream_set_audioparms\n")); + + close_params.wPipeIndex = stream->pipe; + stream->card->pEG->CloseAudio(&close_params); + + open_params.bIsCyclic = TRUE; + open_params.Pipe.nPipe = 0; + open_params.Pipe.bIsInput = stream->use == ECHO_USE_RECORD ? TRUE : FALSE; + open_params.Pipe.wInterleave = stream->channels; + + stream->card->pEG->OpenAudio(&open_params, &stream->pipe); + + if ((stream->channels == channels) && + (stream->b16 == b16) && + (stream->sample_rate == sample_rate)) + return B_OK; + + format_params.wBitsPerSample = b16 == 0 ? 8 : 16; + format_params.byDataAreBigEndian = 0; + format_params.byMonoToStereo = 0; + format_params.wDataInterleave = channels == 1 ? 1 : 2; + + if(stream->card->pEG->QueryAudioFormat(stream->pipe, &format_params)!=ECHOSTATUS_OK) { + PRINT(("echo_stream_set_audioparms : bad format when querying\n")); + return B_ERROR; + } + + /* XXXX : setting sample rate is global in this driver */ + if(stream->card->pEG->QueryAudioSampleRate(sample_rate)!=ECHOSTATUS_OK) { + PRINT(("echo_stream_set_audioparms : bad sample rate when querying\n")); + return B_ERROR; + } + + if(stream->card->pEG->SetAudioFormat(stream->pipe, &format_params)!=ECHOSTATUS_OK) { + PRINT(("echo_stream_set_audioparms : bad format when setting\n")); + return B_ERROR; + } + + /* XXXX : setting sample rate is global in this driver */ + if(stream->card->pEG->SetAudioSampleRate(sample_rate)!=ECHOSTATUS_OK) { + PRINT(("echo_stream_set_audioparms : bad sample rate when setting\n")); + return B_ERROR; + } + + if(stream->buffer) + echo_mem_free(stream->card, stream->buffer->log_base); + + stream->b16 = b16; + stream->sample_rate = sample_rate; + stream->channels = channels; + + sample_size = stream->b16 + 1; + frame_size = sample_size * stream->channels; + + stream->buffer = echo_mem_alloc(stream->card, stream->bufframes * frame_size * stream->bufcount); + + stream->trigblk = 0; /* This shouldn't be needed */ + stream->blkmod = stream->bufcount; + stream->blksize = stream->bufframes * frame_size; + + CDaffyDuck *duck = stream->card->pEG->GetDaffyDuck(stream->pipe); + if(duck == NULL) { + PRINT(("echo_stream_set_audioparms : Could not get daffy duck pointer\n")); + return B_ERROR; + } + + uint32 dwNumFreeEntries = 0; + + for(i=0; ibufcount; i++) { + duck->AddMapping(((uint32)stream->buffer->phy_base) + + i * stream->blksize, stream->blksize, 0, TRUE, dwNumFreeEntries); + } + + duck->Wrap(); + + if(stream->card->pEG->GetAudioPositionPtr(stream->pipe, stream->position)!=ECHOSTATUS_OK) { + PRINT(("echo_stream_set_audioparms : Could not get audio position ptr\n")); + return B_ERROR; + } + + return B_OK; +} + + +status_t +echo_stream_get_nth_buffer(echo_stream *stream, uint8 chan, uint8 buf, + char** buffer, size_t *stride) +{ + uint8 sample_size, frame_size; + LOG(("echo_stream_get_nth_buffer\n")); + + sample_size = stream->b16 + 1; + frame_size = sample_size * stream->channels; + + *buffer = (char*)stream->buffer->log_base + (buf * stream->bufframes * frame_size) + + chan * sample_size; + *stride = frame_size; + + return B_OK; +} + + +static uint32 +echo_stream_curaddr(echo_stream *stream) +{ + uint32 addr = *stream->position - (uint32)stream->buffer->phy_base; + TRACE(("stream_curaddr %p, phy_base %p\n", addr, (uint32)stream->buffer->phy_base)); + return addr; +} + + +void +echo_stream_start(echo_stream *stream, void (*inth) (void *), void *inthparam) +{ + LOG(("echo_stream_start\n")); + + stream->inth = inth; + stream->inthparam = inthparam; + + stream->state |= ECHO_STATE_STARTED; + + if(stream->card->pEG->Start(stream->pipe)!=ECHOSTATUS_OK) { + PRINT(("echo_stream_start : Could not start the pipe\n")); + } +} + +void +echo_stream_halt(echo_stream *stream) +{ + LOG(("echo_stream_halt\n")); + + stream->state &= ~ECHO_STATE_STARTED; + + if(stream->card->pEG->Stop(stream->pipe)!=ECHOSTATUS_OK) { + PRINT(("echo_stream_halt : Could not stop the pipe\n")); + } +} + +echo_stream * +echo_stream_new(echo_dev *card, uint8 use, uint32 bufframes, uint8 bufcount) +{ + echo_stream *stream; + cpu_status status; + LOG(("echo_stream_new\n")); + + stream = (echo_stream *) malloc(sizeof(echo_stream)); + if (stream == NULL) + return (NULL); + stream->card = card; + stream->use = use; + stream->state = !ECHO_STATE_STARTED; + stream->b16 = 0; + stream->sample_rate = 0; + stream->channels = 0; + stream->bufframes = bufframes; + stream->bufcount = bufcount; + stream->inth = NULL; + stream->inthparam = NULL; + stream->buffer = NULL; + stream->blksize = 0; + stream->trigblk = 0; + stream->blkmod = 0; + + stream->pipe = 0; + + stream->frames_count = 0; + stream->real_time = 0; + stream->update_needed = false; + + status = lock(); + LIST_INSERT_HEAD((&card->streams), stream, next); + unlock(status); + + return stream; +} + +void +echo_stream_delete(echo_stream *stream) +{ + cpu_status status; + LOG(("echo_stream_delete\n")); + + echo_stream_halt(stream); + + if(stream->buffer) + echo_mem_free(stream->card, stream->buffer->log_base); + + status = lock(); + LIST_REMOVE(stream, next); + unlock(status); + + free(stream); +} + + +uint32 round_to_pagesize(uint32 size) +{ + return (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); +} + +/* This is not the most advanced method to map physical memory for io access. + * Perhaps using B_ANY_KERNEL_ADDRESS instead of B_ANY_KERNEL_BLOCK_ADDRESS + * makes the whole offset calculation and relocation obsolete. But the code + * below does work, and I can't test if using B_ANY_KERNEL_ADDRESS also works. + */ +area_id +map_mem(void **log, void *phy, size_t size, const char *name) +{ + uint32 offset; + void *phyadr; + void *mapadr; + area_id area; + + LOG(("mapping physical address %p with %#x bytes for %s\n",phy,size,name)); + + offset = (uint32)phy & (B_PAGE_SIZE - 1); + phyadr = (void*)((uint32)phy - offset); + size = round_to_pagesize(size + offset); + area = map_physical_memory(name, phyadr, size, B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA, &mapadr); + *log = (void*) ((uint32)mapadr + offset); + + LOG(("physical = %p, logical = %p, offset = %#x, phyadr = %p, mapadr = %p, size = %#x, area = %#x\n", + phy, *log, offset, phyadr, mapadr, size, area)); + + return area; +} + + +/* Echo interrupt */ + +int32 echo_int(void *arg) +{ + echo_dev *card = (echo_dev*)arg; + BOOL midiReceived; + ECHOSTATUS err; + + echo_stream *stream; + uint32 curblk; + + err = card->pEG->ServiceIrq(midiReceived); + + if(err == ECHOSTATUS_OK) { + LIST_FOREACH(stream, &card->streams, next) { + if ((stream->use & ECHO_USE_PLAY) == 0 || + (stream->state & ECHO_STATE_STARTED) == 0 || + (stream->inth == NULL)) + continue; + + TRACE(("echo_int stream %p\n", stream)); + curblk = echo_stream_curaddr(stream) / stream->blksize; + TRACE(("echo_int at trigblk %lu\n", curblk)); + TRACE(("echo_int at stream->trigblk %lu\n", stream->trigblk)); + if (curblk == stream->trigblk) { + if(stream->inth) + stream->inth(stream->inthparam); + + stream->trigblk++; + stream->trigblk %= stream->blkmod; + } + } + + return B_HANDLED_INTERRUPT; + } else + return B_UNHANDLED_INTERRUPT; +} + +/* detect presence of our hardware */ +status_t +init_hardware(void) +{ + int ix=0; + pci_info info; + status_t err = ENODEV; + + LOG_CREATE(); + + PRINT(("init_hardware()\n")); + + if (get_module(pci_name, (module_info **)&pci)) + return ENOSYS; + + while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { + + ushort card_type = info.u.h0.subsystem_id & 0xfff0; + + if (info.vendor_id == VENDOR_ID && + ((info.device_id == DEVICE_ID_56301) + || (info.device_id == DEVICE_ID_56361)) && + (info.u.h0.subsystem_vendor_id == SUBVENDOR_ID) && + ( +#ifdef ECHOGALS_FAMILY + (card_type == DARLA) + || (card_type == GINA) + || (card_type == LAYLA) + || (card_type == DARLA24) +#endif +#ifdef ECHO24_FAMILY + (card_type == GINA24) + || (card_type == LAYLA24) + || (card_type == MONA) + || (card_type == MIA) + || (card_type == INDIGO) +#endif + )) { + err = B_OK; + } + ix++; + } + + put_module(pci_name); + + if(err!=B_OK) { + PRINT(("no card found\n")); + } + + return err; +} + + +status_t +init_driver(void) +{ + int ix=0; + + pci_info info; + num_cards = 0; + + PRINT(("init_driver()\n")); + load_driver_symbols(DRIVER_NAME); + + if (get_module(pci_name, (module_info **) &pci)) + return ENOSYS; + + while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { + ushort card_type = info.u.h0.subsystem_id & 0xfff0; + + if (info.vendor_id == VENDOR_ID && + ((info.device_id == DEVICE_ID_56301) + || (info.device_id == DEVICE_ID_56361)) && + (info.u.h0.subsystem_vendor_id == SUBVENDOR_ID) && + ( +#ifdef ECHOGALS_FAMILY + (card_type == DARLA) + || (card_type == GINA) + || (card_type == LAYLA) + || (card_type == DARLA24) +#endif +#ifdef ECHO24_FAMILY + (card_type == GINA24) + || (card_type == LAYLA24) + || (card_type == MONA) + || (card_type == MIA) + || (card_type == INDIGO) +#endif + )) { + + if (num_cards == NUM_CARDS) { + PRINT(("Too many "DRIVER_NAME" cards installed!\n")); + break; + } + memset(&cards[num_cards], 0, sizeof(echo_dev)); + cards[num_cards].info = info; + cards[num_cards].type = card_type; + if (echo_setup(&cards[num_cards])) { + PRINT(("Setup of "DRIVER_NAME" %ld failed\n", num_cards+1)); + } + else { + num_cards++; + } + } + ix++; + } + if (!num_cards) { + PRINT(("no cards\n")); + put_module(pci_name); + PRINT(("no suitable cards found\n")); + return ENODEV; + } + + return B_OK; +} + + +static void +make_device_names( + echo_dev * card) +{ + sprintf(card->name, "audio/multi/"DRIVER_NAME"/%ld", card-cards+1); + names[num_names++] = card->name; + + names[num_names] = NULL; +} + + +static status_t +echo_setup(echo_dev * card) +{ + status_t err = B_OK; + unsigned char cmd; + + PRINT(("echo_setup(%p)\n", card)); + + (*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function, + PCI_latency, 1, 0xc0 ); + + make_device_names(card); + + card->bmbar = card->info.u.h0.base_registers[0]; + card->irq = card->info.u.h0.interrupt_line; + + card->pOSS = new COsSupport(card->info.device_id); + if(card->pOSS == NULL) + return B_ERROR; + + switch (card->type) { +#ifdef ECHOGALS_FAMILY + case DARLA: + card->pEG = new CDarla(card->pOSS); + break; + case GINA: + card->pEG = new CGina(card->pOSS); + break; + case LAYLA: + card->pEG = new CLayla(card->pOSS); + break; + case DARLA24: + card->pEG = new CDarla24(card->pOSS); + break; +#endif +#ifdef ECHO24_FAMILY + case GINA24: + card->pEG = new CGina24(card->pOSS); + break; + case LAYLA24: + card->pEG = new CLayla24(card->pOSS); + break; + case MONA: + card->pEG = new CMona(card->pOSS); + break; + case MIA: + card->pEG = new CMia(card->pOSS); + break; +#endif + default: + PRINT(("card type 0x%x not supported by "DRIVER_NAME"\n", card->type)); + delete card->pOSS; + return B_ERROR; + } + + if (card->pEG == NULL) + return B_ERROR; + + card->area_bmbar = map_mem(&card->log_bmbar, (void *)card->bmbar, + card->info.u.h0.base_register_sizes[0], DRIVER_NAME" bmbar io"); + if (card->area_bmbar <= B_OK) { + LOG(("mapping of bmbar io failed, error = %#x\n",card->area_bmbar)); + return B_ERROR; + } + LOG(("mapping of bmbar: area %#x, phys %#x, log %#x\n", card->area_bmbar, card->bmbar, card->log_bmbar)); + + cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2); + PRINT(("PCI command before: %x\n", cmd)); + (*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2, cmd | PCI_command_io); + cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2); + PRINT(("PCI command after: %x\n", cmd)); + + card->pEG->AssignResources(card->log_bmbar, "no name"); + + ECHOSTATUS status; + status = card->pEG->InitHw(); + if(status != ECHOSTATUS_OK) + return B_ERROR; + + /* Init streams list */ + LIST_INIT(&(card->streams)); + + /* Init mems list */ + LIST_INIT(&(card->mems)); + + PRINT(("installing interrupt : %x\n", card->irq)); + install_io_interrupt_handler(card->irq, echo_int, card, 0); + + PRINT(("echo_setup done\n")); + + return err; +} + +static void +echo_shutdown(echo_dev *card) +{ + PRINT(("shutdown(%p)\n", card)); + remove_io_interrupt_handler(card->irq, echo_int, card); + + delete card->pEG; + delete card->pOSS; + + delete_area(card->area_bmbar); +} + + + +void +uninit_driver(void) +{ + int ix, cnt = num_cards; + num_cards = 0; + + PRINT(("uninit_driver()\n")); + + for (ix=0; ix +#include "OsSupportBeOS.h" +#include "CEchoGals.h" +#include "multi_audio.h" +#include "multi.h" +#include "queue.h" + +#define AUTHOR "Jérôme Duval" +#define DEVNAME 32 +#define NUM_CARDS 3 + +#define ECHO_USE_PLAY (1 << 0) +#define ECHO_USE_RECORD (1 << 1) +#define ECHO_STATE_STARTED (1 << 0) + + +typedef struct _echo_mem { + LIST_ENTRY(_echo_mem) next; + void *log_base; + void *phy_base; + area_id area; + size_t size; +} echo_mem; + +/* + * Streams + */ + +typedef struct _echo_stream { + struct _echo_dev *card; + uint8 use; + uint8 state; + uint8 b16; + uint32 sample_rate; + uint8 channels; + uint32 bufframes; + uint8 bufcount; + + WORD pipe; + PDWORD position; + + LIST_ENTRY(_echo_stream) next; + + void (*inth) (void *); + void *inthparam; + + echo_mem *buffer; + uint16 blksize; /* in samples */ + uint16 trigblk; /* blk on which to trigger inth */ + uint16 blkmod; /* Modulo value to wrap trigblk */ + + /* multi_audio */ + volatile int64 frames_count; // for play or record + volatile bigtime_t real_time; // for play or record + volatile int32 buffer_cycle; // for play or record + int32 first_channel; + bool update_needed; +} echo_stream; + + +typedef struct _echo_dev { + char name[DEVNAME]; /* used for resources */ + pci_info info; + + uint32 bmbar; + void * log_bmbar; + area_id area_bmbar; + uint32 irq; + uint16 type; + + PCEchoGals pEG; + PCOsSupport pOSS; + + void *ptb_log_base; + void *ptb_phy_base; + area_id ptb_area; + + sem_id buffer_ready_sem; + + LIST_HEAD(, _echo_stream) streams; + LIST_HEAD(, _echo_mem) mems; + + echo_stream *pstream; + echo_stream *rstream; + + /* multi_audio */ + multi_dev multi; +} echo_dev; + +extern int32 num_cards; +extern echo_dev cards[NUM_CARDS]; + +#ifdef __cplusplus +extern "C" { +#endif + +status_t echo_stream_set_audioparms(echo_stream *stream, uint8 channels, + uint8 b16, uint32 sample_rate); +status_t echo_stream_get_nth_buffer(echo_stream *stream, uint8 chan, uint8 buf, + char** buffer, size_t *stride); +void echo_stream_start(echo_stream *stream, void (*inth) (void *), void *inthparam); +void echo_stream_halt(echo_stream *stream); +echo_stream *echo_stream_new(echo_dev *card, uint8 use, uint32 bufframes, uint8 bufcount); +void echo_stream_delete(echo_stream *stream); + +#ifdef __cplusplus +} +#endif + + +#endif /* _ECHO_H_ */ diff --git a/src/add-ons/kernel/drivers/audio/echo/gals/Jamfile b/src/add-ons/kernel/drivers/audio/echo/gals/Jamfile index d8369552f0..9ae58392df 100644 --- a/src/add-ons/kernel/drivers/audio/echo/gals/Jamfile +++ b/src/add-ons/kernel/drivers/audio/echo/gals/Jamfile @@ -1,34 +1,92 @@ SubDir OBOS_TOP src add-ons kernel drivers audio echo gals ; -UsePrivateHeaders media ; +SubDirHdrs $(OBOS_TOP) src add-ons kernel drivers audio echo ; +SubDirHdrs $(OBOS_TOP) src add-ons kernel drivers audio echo generic ; +SubDirHdrs $(OBOS_TOP) src add-ons kernel drivers audio echo generic DSP ; +SubDirHdrs $(OBOS_TOP) src add-ons kernel drivers audio echo generic ASIC ; -R5KernelAddon echo_gals : kernel drivers bin : -# ac97_multi.c -# config.c +UsePrivateHeaders [ FDirName kernel ] ; # For kernel_cpp.cpp + +# set some additional defines +{ + SubDirCcFlags -DECHO_BEOS -DECHOGALS_FAMILY ; + SubDirC++Flags -DECHO_BEOS -DECHOGALS_FAMILY ; +} + +R5KernelAddon echogals : kernel drivers bin : + kernel_cpp.cpp debug.c -# ich.c -# io.c -# util.c -# ac97.c + echo.cpp + multi.cpp + util.c + CChannelMask.cpp + CDaffyDuck.cpp + CDarla.cpp + CDarla24.cpp + CDarla24DspCommObject.cpp + CDarlaDspCommObject.cpp + CDspCommObject.cpp + CEchoGals.cpp + CEchoGals_info.cpp + CEchoGals_midi.cpp + CEchoGals_mixer.cpp + CEchoGals_power.cpp + CEchoGals_transport.cpp +# CEchoGals_WDM.cpp + CGdDspCommObject.cpp + CGina.cpp + CGinaDspCommObject.cpp + CLayla.cpp + CLaylaDspCommObject.cpp + CLineLevel.cpp + CMidiInQ.cpp + CMonitorCtrl.cpp + CPipeOutCtrl.cpp + OsSupportBeOS.cpp ; -# For OpenBeOS we should be building the driver objects this way. -#KernelObjects -# ac97_multi.c -# config.c -# debug.c -# ich.c -# io.c -# util.c -# ac97.c -# : -# -fno-pic -D_KERNEL_MODE -# ; +SEARCH on [ FGristFiles + CChannelMask.cpp + CDaffyDuck.cpp + CDarla.cpp + CDarla24.cpp + CDarla24DspCommObject.cpp + CDarlaDspCommObject.cpp + CDspCommObject.cpp + CEchoGals.cpp + CEchoGals_info.cpp + CEchoGals_midi.cpp + CEchoGals_mixer.cpp + CEchoGals_power.cpp + CEchoGals_transport.cpp + CEchoGals_WDM.cpp + CGdDspCommObject.cpp + CGina.cpp + CGinaDspCommObject.cpp + CLayla.cpp + CLaylaDspCommObject.cpp + CLineLevel.cpp + CMidiInQ.cpp + CMonitorCtrl.cpp + CPipeOutCtrl.cpp + OsSupportBeOS.cpp + ] = [ FDirName $(OBOS_TOP) src add-ons kernel drivers audio echo generic ] ; + +SEARCH on [ FGristFiles + kernel_cpp.cpp + ] = [ FDirName $(OBOS_TOP) src kernel core util ] ; + +SEARCH on [ FGristFiles + debug.c + echo.cpp + multi.cpp + util.c + ] = [ FDirName $(OBOS_TOP) src add-ons kernel drivers audio echo ] ; # Link to kernel/drivers/dev/audio/multi { local dir = [ FDirName $(OBOS_ADDON_DIR) kernel drivers dev audio multi ] ; - local instDriver = echo_gals ; + local instDriver = echogals ; MakeLocate $(instDriver) : $(dir) ; - RelSymLink $(instDriver) : echo_gals ; + RelSymLink $(instDriver) : echogals ; } diff --git a/src/add-ons/kernel/drivers/audio/echo/generic/CDarla24DspCommObject.cpp b/src/add-ons/kernel/drivers/audio/echo/generic/CDarla24DspCommObject.cpp index cbb24b0e45..b407655ec0 100644 --- a/src/add-ons/kernel/drivers/audio/echo/generic/CDarla24DspCommObject.cpp +++ b/src/add-ons/kernel/drivers/audio/echo/generic/CDarla24DspCommObject.cpp @@ -1,232 +1,231 @@ -// **************************************************************************** -// -// CDarla24DspCommObject.cpp -// -// Implementation file for Darla24 DSP interface class. -// -// Copyright Echo Digital Audio Corporation (c) 1998 - 2002 -// All rights reserved -// www.echoaudio.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal with the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimers. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimers in the -// documentation and/or other materials provided with the distribution. -// -// - Neither the name of Echo Digital Audio, nor the names of its -// contributors may be used to endorse or promote products derived from -// this Software without specific prior written permission. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR -// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -// SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. -// -// **************************************************************************** - -#include "CEchoGals.h" -#include "CDarla24DspCommObject.h" - -#include "Darla24DSP.c" - - -/**************************************************************************** - - Magic constants for the Darla24 hardware - - ****************************************************************************/ - -#define GD24_96000 0x0 -#define GD24_48000 0x1 -#define GD24_44100 0x2 -#define GD24_32000 0x3 -#define GD24_22050 0x4 -#define GD24_16000 0x5 -#define GD24_11025 0x6 -#define GD24_8000 0x7 -#define GD24_88200 0x8 -#define GD24_EXT_SYNC 0x9 - - - - -/**************************************************************************** - - Construction and destruction - - ****************************************************************************/ - -//=========================================================================== -// -// Constructor -// -//=========================================================================== - -CDarla24DspCommObject::CDarla24DspCommObject -( - PDWORD pdwRegBase, // Virtual ptr to DSP registers - PCOsSupport pOsSupport -) : CGdDspCommObject( pdwRegBase, pOsSupport ) -{ - strcpy( m_szCardName, "Darla24" ); - m_pdwDspRegBase = pdwRegBase; // Virtual addr DSP's register base - - m_wNumPipesOut = 8; - m_wNumPipesIn = 2; - m_wNumBussesOut = 8; - m_wNumBussesIn = 2; - m_wFirstDigitalBusOut = 8; - m_wFirstDigitalBusIn = 2; - - m_fHasVmixer = FALSE; - - m_wNumMidiOut = 0; // # MIDI out channels - m_wNumMidiIn = 0; // # MIDI in channels - m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 44100 ); - // Need this in case we start with ESYNC - - m_pwDspCodeToLoad = pwDarla24DSP; - - // - // Since this card has no ASIC, mark it as loaded so everything works OK - // - m_bASICLoaded = TRUE; - -} // CDarla24DspCommObject::CDarla24DspCommObject( DWORD dwPhysRegBase ) - - -//=========================================================================== -// -// Destructor -// -//=========================================================================== - -CDarla24DspCommObject::~CDarla24DspCommObject() -{ -} // CDarla24DspCommObject::~CDarla24DspCommObject() - - - - -/**************************************************************************** - - Hardware config - - ****************************************************************************/ - -//=========================================================================== -// -// SetSampleRate -// -// Set the audio sample rate for Darla24; this is fairly simple. You -// just pick the right magic number. -// -//=========================================================================== - -DWORD CDarla24DspCommObject::SetSampleRate( DWORD dwNewSampleRate ) -{ - BYTE bClock; - - // - // Pick the magic number - // - switch ( dwNewSampleRate ) - { - case 96000 : - bClock = GD24_96000; - break; - case 88200 : - bClock = GD24_88200; - break; - case 48000 : - bClock = GD24_48000; - break; - case 44100 : - bClock = GD24_44100; - break; - case 32000 : - bClock = GD24_32000; - break; - case 22050 : - bClock = GD24_22050; - break; - case 16000 : - bClock = GD24_16000; - break; - case 11025 : - bClock = GD24_11025; - break; - case 8000 : - bClock = GD24_8000; - break; - default : - ECHO_DEBUGPRINTF( ("CDarla24DspCommObject::SetSampleRate: Error, " - "invalid sample rate 0x%lx\n", dwNewSampleRate) ); - return 0xffffffff; - } - - if ( !WaitForHandshake() ) - return 0xffffffff; - - // - // Override the sample rate if this card is set to Echo sync. - // m_pDspCommPage->wInputClock is just being used as a parameter here; - // the DSP ignores it. - // - if ( ECHO_CLOCK_ESYNC == GetInputClock() ) - bClock = GD24_EXT_SYNC; - - m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate ); - - // - // Write the audio state to the comm page - // - m_pDspCommPage->byGDClockState = bClock; - - // Send command to DSP - ClearHandshake(); - SendVector( DSP_VC_SET_GD_AUDIO_STATE ); - - ECHO_DEBUGPRINTF( ("CDarla24DspCommObject::SetSampleRate: 0x%lx " - "clocks %s\n", dwNewSampleRate) ); - - return GetSampleRate(); - -} // DWORD CDarla24DspCommObject::SetSampleRate( DWORD dwNewSampleRate ) - - -//=========================================================================== -// -// Set input clock -// -// Darla24 supports internal and Esync clock. -// -//=========================================================================== - -ECHOSTATUS CDarla24DspCommObject::SetInputClock(WORD wClock) -{ - if ( (ECHO_CLOCK_INTERNAL != wClock) && - (ECHO_CLOCK_ESYNC != wClock)) - return ECHOSTATUS_CLOCK_NOT_SUPPORTED; - - m_wInputClock = wClock; - - return SetSampleRate( GetSampleRate() ); - -} // SetInputClock - - -// **** Darla24DspCommObject.cpp **** +// **************************************************************************** +// +// CDarla24DspCommObject.cpp +// +// Implementation file for Darla24 DSP interface class. +// +// Copyright Echo Digital Audio Corporation (c) 1998 - 2002 +// All rights reserved +// www.echoaudio.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal with the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimers. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimers in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of Echo Digital Audio, nor the names of its +// contributors may be used to endorse or promote products derived from +// this Software without specific prior written permission. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR +// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. +// +// **************************************************************************** +#include "CEchoGals.h" +#include "CDarla24DspCommObject.h" + +#include "Darla24DSP.c" + + +/**************************************************************************** + + Magic constants for the Darla24 hardware + + ****************************************************************************/ + +#define GD24_96000 0x0 +#define GD24_48000 0x1 +#define GD24_44100 0x2 +#define GD24_32000 0x3 +#define GD24_22050 0x4 +#define GD24_16000 0x5 +#define GD24_11025 0x6 +#define GD24_8000 0x7 +#define GD24_88200 0x8 +#define GD24_EXT_SYNC 0x9 + + + + +/**************************************************************************** + + Construction and destruction + + ****************************************************************************/ + +//=========================================================================== +// +// Constructor +// +//=========================================================================== + +CDarla24DspCommObject::CDarla24DspCommObject +( + PDWORD pdwRegBase, // Virtual ptr to DSP registers + PCOsSupport pOsSupport +) : CGdDspCommObject( pdwRegBase, pOsSupport ) +{ + strcpy( m_szCardName, "Darla24" ); + m_pdwDspRegBase = pdwRegBase; // Virtual addr DSP's register base + + m_wNumPipesOut = 8; + m_wNumPipesIn = 2; + m_wNumBussesOut = 8; + m_wNumBussesIn = 2; + m_wFirstDigitalBusOut = 8; + m_wFirstDigitalBusIn = 2; + + m_fHasVmixer = FALSE; + + m_wNumMidiOut = 0; // # MIDI out channels + m_wNumMidiIn = 0; // # MIDI in channels + m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 44100 ); + // Need this in case we start with ESYNC + + m_pwDspCodeToLoad = pwDarla24DSP; + + // + // Since this card has no ASIC, mark it as loaded so everything works OK + // + m_bASICLoaded = TRUE; + +} // CDarla24DspCommObject::CDarla24DspCommObject( DWORD dwPhysRegBase ) + + +//=========================================================================== +// +// Destructor +// +//=========================================================================== + +CDarla24DspCommObject::~CDarla24DspCommObject() +{ +} // CDarla24DspCommObject::~CDarla24DspCommObject() + + + + +/**************************************************************************** + + Hardware config + + ****************************************************************************/ + +//=========================================================================== +// +// SetSampleRate +// +// Set the audio sample rate for Darla24; this is fairly simple. You +// just pick the right magic number. +// +//=========================================================================== + +DWORD CDarla24DspCommObject::SetSampleRate( DWORD dwNewSampleRate ) +{ + BYTE bClock; + + // + // Pick the magic number + // + switch ( dwNewSampleRate ) + { + case 96000 : + bClock = GD24_96000; + break; + case 88200 : + bClock = GD24_88200; + break; + case 48000 : + bClock = GD24_48000; + break; + case 44100 : + bClock = GD24_44100; + break; + case 32000 : + bClock = GD24_32000; + break; + case 22050 : + bClock = GD24_22050; + break; + case 16000 : + bClock = GD24_16000; + break; + case 11025 : + bClock = GD24_11025; + break; + case 8000 : + bClock = GD24_8000; + break; + default : + ECHO_DEBUGPRINTF( ("CDarla24DspCommObject::SetSampleRate: Error, " + "invalid sample rate 0x%lx\n", dwNewSampleRate) ); + return 0xffffffff; + } + + if ( !WaitForHandshake() ) + return 0xffffffff; + + // + // Override the sample rate if this card is set to Echo sync. + // m_pDspCommPage->wInputClock is just being used as a parameter here; + // the DSP ignores it. + // + if ( ECHO_CLOCK_ESYNC == GetInputClock() ) + bClock = GD24_EXT_SYNC; + + m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate ); + + // + // Write the audio state to the comm page + // + m_pDspCommPage->byGDClockState = bClock; + + // Send command to DSP + ClearHandshake(); + SendVector( DSP_VC_SET_GD_AUDIO_STATE ); + + ECHO_DEBUGPRINTF( ("CDarla24DspCommObject::SetSampleRate: 0x%lx " + "clocks %d\n", dwNewSampleRate, bClock ) ); + + return GetSampleRate(); + +} // DWORD CDarla24DspCommObject::SetSampleRate( DWORD dwNewSampleRate ) + + +//=========================================================================== +// +// Set input clock +// +// Darla24 supports internal and Esync clock. +// +//=========================================================================== + +ECHOSTATUS CDarla24DspCommObject::SetInputClock(WORD wClock) +{ + if ( (ECHO_CLOCK_INTERNAL != wClock) && + (ECHO_CLOCK_ESYNC != wClock)) + return ECHOSTATUS_CLOCK_NOT_SUPPORTED; + + m_wInputClock = wClock; + + return SetSampleRate( GetSampleRate() ); + +} // SetInputClock + + +// **** Darla24DspCommObject.cpp **** diff --git a/src/add-ons/kernel/drivers/audio/echo/generic/CEchoGals_transport.cpp b/src/add-ons/kernel/drivers/audio/echo/generic/CEchoGals_transport.cpp index 828efc0ac3..76bd507556 100644 --- a/src/add-ons/kernel/drivers/audio/echo/generic/CEchoGals_transport.cpp +++ b/src/add-ons/kernel/drivers/audio/echo/generic/CEchoGals_transport.cpp @@ -1,1225 +1,1225 @@ -// **************************************************************************** -// -// CEchoGals_transport.cpp -// -// Audio transport methods for the CEchoGals driver class. -// Set editor tabs to 3 for your viewing pleasure. -// -// Copyright Echo Digital Audio Corporation (c) 1998 - 2002 -// All rights reserved -// www.echoaudio.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal with the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimers. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimers in the -// documentation and/or other materials provided with the distribution. -// -// - Neither the name of Echo Digital Audio, nor the names of its -// contributors may be used to endorse or promote products derived from -// this Software without specific prior written permission. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR -// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -// SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. -// -// **************************************************************************** - -#include "CEchoGals.h" - -#pragma optimize("",off) - - -/****************************************************************************** - - Functions for opening and closing pipes - - ******************************************************************************/ - -//=========================================================================== -// -// OpenAudio is used to reserve audio pipes for your exclusive use. The call -// will fail if someone else has already opened the pipes. Calling OpenAudio -// is the first step if you want to play or record. -// -//=========================================================================== - -ECHOSTATUS CEchoGals::OpenAudio -( - PECHOGALS_OPENAUDIOPARAMETERS pOpenParameters, // Info on pipe - PWORD pwPipeIndex // Pipe index ptr -) -{ - CChannelMask cmMask; - WORD wPipeMax, wPipe, wPipeIndex, i, wWidth; - - ECHO_DEBUGPRINTF( ("CEchoGals::OpenAudio: %s %u " - "PipeWidth %d " - "Cyclic %u \n", - ( pOpenParameters->Pipe.bIsInput ) ? "Input" : "Output", - pOpenParameters->Pipe.nPipe, - pOpenParameters->Pipe.wInterleave, - pOpenParameters->bIsCyclic) ); - - *pwPipeIndex = (WORD) -1; // So it's never undefined - - // - // Make sure the hardware is OK - // - if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) - { - ECHO_DEBUGPRINTF( ("\tECHOSTATUS_DSP_DEAD\n") ); - return ECHOSTATUS_DSP_DEAD; - } - - // - // Make sure the DSP & ASIC are up and running - // - ECHOSTATUS Status = GetDspCommObject()->LoadFirmware(); - if ( ECHOSTATUS_OK != Status ) - return Status; - - // - // Validate the pipe number - // - wPipe = pOpenParameters->Pipe.nPipe; - wWidth = pOpenParameters->Pipe.wInterleave; - - if ( pOpenParameters->Pipe.bIsInput ) - { - wPipeIndex = wPipe + GetNumPipesOut(); - wPipeMax = GetNumPipesIn(); - } - else - { - wPipeIndex = wPipe; - wPipeMax = GetNumPipesOut(); - } - - if ( ( wPipe + wWidth ) > wPipeMax ) - { - ECHO_DEBUGPRINTF( ("\tECHOSTATUS_INVALID_CHANNEL\n") ); - return ECHOSTATUS_INVALID_CHANNEL; - } - - // - // If the width is more than two, make sure that this card - // can handle super interleave - // - if ( (0 == (m_wFlags & ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK)) && - (wWidth > 2) - ) - { - ECHO_DEBUGPRINTF( ("\tECHOSTATUS_NO_SUPER_INTERLEAVE\n") ); - return ECHOSTATUS_NO_SUPER_INTERLEAVE; - } - - // - // See if the specified pipes are already open - // - for ( i = 0; i < pOpenParameters->Pipe.wInterleave; i++ ) - { - cmMask.SetIndexInMask( wPipeIndex + i ); - } - - if ( m_cmAudioOpen.Test( &cmMask ) ) - { - ECHO_DEBUGPRINTF( ("\tECHOSTATUS_CHANNEL_ALREADY_OPEN\n") ); - return( ECHOSTATUS_CHANNEL_ALREADY_OPEN ); - } - - // - // Make a daffy duck - // - Status = MakeDaffyDuck(wPipeIndex); - if (ECHOSTATUS_OK != Status) - return Status; - - // - // Reset the 64-bit DMA position - // - ResetDmaPos(wPipeIndex); - GetDspCommObject()->ResetPipePosition(wPipeIndex); - - // - // Prep stuff - // - m_cmAudioOpen += cmMask; - if ( pOpenParameters->bIsCyclic ) - m_cmAudioCyclic += cmMask; - m_Pipes[ wPipeIndex ] = pOpenParameters->Pipe; - *pwPipeIndex = wPipeIndex; - m_ProcessId[ wPipeIndex ] = pOpenParameters->ProcessId; - Reset( wPipeIndex ); - - ECHO_DEBUGPRINTF( ("\tECHOSTATUS_OK\n") ); - return ECHOSTATUS_OK; - -} // ECHOSTATUS CEchoGals::OpenAudio - - -//=========================================================================== -// -// CloseAudio is, naturally, the inverse of OpenAudio. -// -//=========================================================================== - -ECHOSTATUS CEchoGals::CloseAudio -( - PECHOGALS_CLOSEAUDIOPARAMETERS pCloseParameters -) -{ - CChannelMask cmMask; - ECHOSTATUS Status; - WORD i; - WORD wPipeIndex; - - ECHO_DEBUGPRINTF( ("CEchoGals::CloseAudio: Pipe %u ", - pCloseParameters->wPipeIndex) ); - - Status = VerifyAudioOpen( pCloseParameters->wPipeIndex ); - if ( ECHOSTATUS_OK != Status ) - return Status; - - for ( i = 0; - i < m_Pipes[ pCloseParameters->wPipeIndex ].wInterleave; - i++ ) - { - cmMask.SetIndexInMask( pCloseParameters->wPipeIndex + i ); - } - Reset( pCloseParameters->wPipeIndex ); - - KillDaffyDuck( pCloseParameters->wPipeIndex ); - - m_cmAudioOpen -= cmMask; - m_cmAudioCyclic -= cmMask; - - wPipeIndex = pCloseParameters->wPipeIndex; - m_ProcessId[ wPipeIndex ] = NULL; - m_Pipes[ wPipeIndex ].wInterleave = 0; - - ECHO_DEBUGPRINTF( ("\tECHOSTATUS_OK\n") ); - return ECHOSTATUS_OK; - -} // ECHOSTATUS CEchoGals::CloseAudio - - -//=========================================================================== -// -// VerifyAudioOpen is a utility function; it tells you if -// a pipe is open or not. -// -//=========================================================================== - -ECHOSTATUS CEchoGals::VerifyAudioOpen -( - WORD wPipeIndex -) -{ - CChannelMask cmMask; - - if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) - { - ECHO_DEBUGPRINTF( ("\tECHOSTATUS_DSP_DEAD\n") ); - return ECHOSTATUS_DSP_DEAD; - } - - cmMask.SetIndexInMask( wPipeIndex ); - if ( !( m_cmAudioOpen.Test( &cmMask ) ) ) - { - ECHO_DEBUGPRINTF( ("\tECHOSTATUS_CHANNEL_NOT_OPEN\n") ); - return ECHOSTATUS_CHANNEL_NOT_OPEN; - } - - return ECHOSTATUS_OK; - -} // ECHOSTATUS CEchoGals::VerifyAudioOpen - - -//=========================================================================== -// -// GetActivePipes tells you which pipes are currently active; that is, which -// pipes are currently playing or recording. -// -//=========================================================================== - -ECHOSTATUS CEchoGals::GetActivePipes -( - PCChannelMask pChannelMask -) -{ - if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) - return ECHOSTATUS_DSP_DEAD; - - GetDspCommObject()->GetActivePipes( pChannelMask ); - return ECHOSTATUS_OK; -} // void CEchoGals::GetActivePipes() - - -//=========================================================================== -// -// Just like GetActivePipes, but this one tells you which pipes are currently -// open. -// -//=========================================================================== - -ECHOSTATUS CEchoGals::GetOpenPipes -( - PCChannelMask pChannelMask -) -{ - if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) - return ECHOSTATUS_DSP_DEAD; - - *pChannelMask = m_cmAudioOpen; - return ECHOSTATUS_OK; - -} // void CEchoGals::GetOpenPipes() - - - - -/****************************************************************************** - - Functions for setting audio formats and the sample rate - - ******************************************************************************/ - -//=========================================================================== -// -// Validate an audio format. -// -// For comments on audio formats, refer to the definition of -// ECHOGALS_AUDIOFORMAT. -// -//=========================================================================== - -ECHOSTATUS CEchoGals::QueryAudioFormat -( - WORD wPipeIndex, - PECHOGALS_AUDIOFORMAT pAudioFormat -) -{ - ECHOSTATUS Status = ECHOSTATUS_OK; - - ECHO_DEBUGPRINTF( ("CEchoGals::QueryAudioFormat:\n") ); - - // - // If this pipe is open, make sure that this audio format - // does not exceed the stored pipe width - // - WORD wInterleave = pAudioFormat->wDataInterleave; - WORD wStoredPipeWidth = m_Pipes[ wPipeIndex ].wInterleave; - - if (0 != wStoredPipeWidth) - { - if (wInterleave > wStoredPipeWidth) - { - ECHO_DEBUGPRINTF(("CEchoGals::QueryAudioFormat - pipe was opened " - "with a width of %d; interleave of %d invalid.\n", - wStoredPipeWidth, - pAudioFormat->wDataInterleave)); - return ECHOSTATUS_BAD_FORMAT; - } - } - - // - // Check for super interleave (i.e. interleave > 2) - // - if (wInterleave > 2) - { - // - // Make sure the card is capable of super interleave - // - if (0 == (m_wFlags & ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK)) - return ECHOSTATUS_NO_SUPER_INTERLEAVE; - - // - // Allow super interleave for 32 bit little endian data; - // the interleave factor must be even. - // - if ( (32 != pAudioFormat->wBitsPerSample) || - (0 != pAudioFormat->byDataAreBigEndian) || - (0 != (wInterleave & 1) ) - ) - return ECHOSTATUS_BAD_FORMAT; - - // - // Make sure that this interleave factor on this pipe - // does not exceed the number of pipes for the card - // - WORD wMaxPipe; - - if (wPipeIndex >= GetNumPipesOut()) - { - wMaxPipe = GetNumPipesIn(); - wPipeIndex -= GetNumPipesOut(); - } - else - { - wMaxPipe = GetNumPipesOut(); - } - - if ( (wPipeIndex + wInterleave) > wMaxPipe) - return ECHOSTATUS_BAD_FORMAT; - - return ECHOSTATUS_OK; - } - - // - // Check the interleave - // - if ( (1 != pAudioFormat->wDataInterleave) && - (2 != pAudioFormat->wDataInterleave) ) - - { - ECHO_DEBUGPRINTF( ("CEchoGals::QueryAudioFormat - interleave %d not allowed\n", - pAudioFormat->wDataInterleave)); - return ECHOSTATUS_BAD_FORMAT; - } - - // - // If the big endian flag is set, the data must be mono or stereo interleave, - // 32 bits wide, left justified data. Only the upper 24 bits are used. - // - if (pAudioFormat->byDataAreBigEndian) - { - // - // Must have 32 bits per sample - // - if (pAudioFormat->wBitsPerSample != 32) - { - ECHO_DEBUGPRINTF(("CEchoGals::QueryAudioFormat - Only 32 bits per" - " sample supported for big-endian data\n")); - return ECHOSTATUS_BAD_FORMAT; - } - - // - // Mono or stereo only - // - switch (pAudioFormat->wDataInterleave) - { - -#ifdef STEREO_BIG_ENDIAN32_SUPPORT - - case 1 : - case 2 : - break; -#else - - case 1 : - break; - -#endif - - default : - ECHO_DEBUGPRINTF(("CEchoGals::QueryAudioFormat - Interleave of %d" - " not allowed for big-endian data\n", - pAudioFormat->wDataInterleave)); - return ECHOSTATUS_BAD_FORMAT; - } - - return ECHOSTATUS_OK; - } - - // - // Check bits per sample - // - switch ( pAudioFormat->wBitsPerSample ) - { - case 8 : - case 16 : - case 32 : - break; - - default : - ECHO_DEBUGPRINTF( - ("CEchoGals::QueryAudioFormat: No valid format " - "specified, bits per sample %d\n", - pAudioFormat->wBitsPerSample) ); - Status = ECHOSTATUS_BAD_FORMAT; - break; - } - - return Status; - -} // ECHOSTATUS CEchoGals::QueryAudioFormat - - -//=========================================================================== -// -// SetAudioFormat sets the format of the audio data in host memory -// for this pipe. -// -//=========================================================================== - -ECHOSTATUS CEchoGals::SetAudioFormat -( - WORD wPipeIndex, - PECHOGALS_AUDIOFORMAT pAudioFormat -) -{ - ECHOSTATUS Status; - - ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioFormat: " - "for pipe %d\n", - wPipeIndex) ); - - // - // Make sure this pipe is open - // - Status = VerifyAudioOpen( wPipeIndex ); - if ( ECHOSTATUS_OK != Status ) - return Status; - - // - // Check the format - // - Status = QueryAudioFormat( wPipeIndex, pAudioFormat ); - if ( ECHOSTATUS_OK != Status ) - return Status; - - // - // Set the format - // - BOOL fDitherDigitalInputs; - - fDitherDigitalInputs = 0 != (m_wFlags & ECHOGALS_FLAG_SPDIF_NODITHER); - Status = - GetDspCommObject()->SetAudioFormat( wPipeIndex, - pAudioFormat, - fDitherDigitalInputs ); - return Status; - -} // ECHOSTATUS CEchoGals::SetAudioFormat - single pipe - - -//=========================================================================== -// -// This call lets you set the audio format for several pipes at once. -// -//=========================================================================== - -ECHOSTATUS CEchoGals::SetAudioFormat -( - PCChannelMask pChannelMask, - PECHOGALS_AUDIOFORMAT pAudioFormat -) -{ - WORD wPipeIndex = 0xffff; - ECHOSTATUS Status; - BOOL fDitherDigitalInputs; - - if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) - { - ECHO_DEBUGPRINTF( ("\tECHOSTATUS_DSP_DEAD\n") ); - return ECHOSTATUS_DSP_DEAD; - } - - fDitherDigitalInputs = 0 != (m_wFlags & ECHOGALS_FLAG_SPDIF_NODITHER); - for ( ; ; ) - { - wPipeIndex = pChannelMask->GetIndexFromMask( ++wPipeIndex ); - if ( (WORD) ECHO_INVALID_CHANNEL == wPipeIndex ) - break; // We be done! - - // - // See if this pipe is open - // - if ( !( m_cmAudioOpen.TestIndexInMask( wPipeIndex ) ) ) - { - ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioFormat: " - "for pipe %d failed, pipe not open\n", - wPipeIndex) ); - return ECHOSTATUS_CHANNEL_NOT_OPEN; - } - - // - // See if the format is OK - // - ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioFormat: " - "for pipe %d\n", - wPipeIndex) ); - Status = QueryAudioFormat( wPipeIndex, pAudioFormat ); - if ( ECHOSTATUS_OK != Status ) - return Status; - - // - // Set the format for this pipe - // - Status = - GetDspCommObject()->SetAudioFormat( wPipeIndex, - pAudioFormat, - fDitherDigitalInputs ); - if ( ECHOSTATUS_OK != Status ) - return Status; - - m_wBytesPerSample[ wPipeIndex ] = pAudioFormat->wBitsPerSample / 8; - m_wBytesPerSample[ wPipeIndex ] *= pAudioFormat->wDataInterleave; - } - - return ECHOSTATUS_OK; - -} // ECHOSTATUS CEchoGals::SetAudioFormat - multiple pipes - - -//=========================================================================== -// -// GetAudioFormat returns the current audio format for a pipe. -// -//=========================================================================== - -ECHOSTATUS CEchoGals::GetAudioFormat -( - WORD wPipeIndex, - PECHOGALS_AUDIOFORMAT pAudioFormat -) -{ - ECHO_DEBUGPRINTF( ("CEchoGals::GetAudioFormat: " - "for pipe %d\n", - wPipeIndex) ); - - GetDspCommObject()->GetAudioFormat( wPipeIndex, pAudioFormat ); - - return ECHOSTATUS_OK; - -} // ECHOSTATUS CEchoGals::GetAudioFormat - - -//=========================================================================== -// -// This function does exactly what you think it does. -// -// Note that if the card is not set to internal clock (that is, the hardware -// is synced to word clock or some such), this call has no effect. -// -// Note that all of the inputs and outputs on a single card share the same -// clock. -// -//=========================================================================== - -ECHOSTATUS CEchoGals::SetAudioSampleRate -( - DWORD dwSampleRate -) -{ - ECHOSTATUS Status; - - ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioSampleRate: " - "to %ld Hz\n", - dwSampleRate) ); - - // - // Check to see if the sample rate is locked - // - if ( 0 != (m_wFlags & ECHOGALS_FLAG_SAMPLE_RATE_LOCKED)) - { - return ECHOSTATUS_OK; - } - else - { - Status = QueryAudioSampleRate( dwSampleRate ); - if ( ECHOSTATUS_OK != Status ) - return Status; - - if ( dwSampleRate == GetDspCommObject()->SetSampleRate( dwSampleRate ) ) - { - m_dwSampleRate = dwSampleRate; - return ECHOSTATUS_OK; - } - } - return ECHOSTATUS_BAD_FORMAT; - -} // ECHOSTATUS CEchoGals::SetAudioSampleRate - - -//=========================================================================== -// -// GetAudioSampleRate - retrieves the current sample rate for the hardware -// -//=========================================================================== - -ECHOSTATUS CEchoGals::GetAudioSampleRate -( - PDWORD pdwSampleRate -) -{ - ECHO_DEBUGPRINTF( ("CEchoGals::GetAudioSampleRate\n")); - - *pdwSampleRate = m_dwSampleRate; - - return ECHOSTATUS_OK; - -} // ECHOSTATUS CEchoGals::GetAudioSampleRate - - - - -/****************************************************************************** - - Functions related to the scatter-gather list - - ******************************************************************************/ - -//=========================================================================== -// -// This protected method is used to create a CDaffyDuck object to -// manage a scatter-gather list for a newly opened pipe. -// -//=========================================================================== - -ECHOSTATUS CEchoGals::MakeDaffyDuck(WORD wPipeIndex) -{ - ECHOSTATUS Status = ECHOSTATUS_OK; - - //--------------------------------------------------------- - // - // Allocate the main daffy duck for this pipe - // - //--------------------------------------------------------- - - m_DaffyDucks[wPipeIndex] = new CDaffyDuck(m_pOsSupport, - GetDspCommObject(), - wPipeIndex ); - if (NULL == m_DaffyDucks[wPipeIndex]) - { - return ECHOSTATUS_NO_MEM; - } - - // - // Check the daffy duck - // - Status = m_DaffyDucks[wPipeIndex]->InitCheck(); - if (ECHOSTATUS_OK != Status) - { - return Status; - } - - // - // Put the daffy duck in the comm page - // - GetDspCommObject()-> - SetAudioDuckListPhys(wPipeIndex, - m_DaffyDucks[wPipeIndex]->GetPhysStartAddr() ); - - ECHO_DEBUGPRINTF(("CEchoGals::MakeDaffyDuck - 0x%lx for pipe index %d\n", - (DWORD) m_DaffyDucks[wPipeIndex],wPipeIndex)); - - return Status; - -} // MakeDaffyDuck - - -//=========================================================================== -// -// Daffy duck cleanup -// -//=========================================================================== - -void CEchoGals::KillDaffyDuck(WORD wPipeIndex) -{ - if (NULL != m_DaffyDucks[wPipeIndex]) - { - delete m_DaffyDucks[wPipeIndex]; - m_DaffyDucks[wPipeIndex] = NULL; - } - -} // KillDaffyDuck - - -//=========================================================================== -// -// This method returns a pointer to the daffy duck for a pipe; the caller -// can then have direct access to the daffy duck object. -// -//=========================================================================== - -CDaffyDuck *CEchoGals::GetDaffyDuck(WORD wPipeIndex) -{ - ECHO_DEBUGPRINTF(("CEchoGals::GetDaffyDuck for pipe index %d\n",wPipeIndex)); - - if (wPipeIndex >= GetNumPipes()) - return NULL; - - return m_DaffyDucks[wPipeIndex]; -} - - - -/****************************************************************************** - - Functions for starting and stopping transport - - ******************************************************************************/ - -//=========================================================================== -// -// Start transport for a single pipe -// -//=========================================================================== - -ECHOSTATUS CEchoGals::Start -( - WORD wPipeIndex -) -{ - CChannelMask cmMask; - - cmMask.SetIndexInMask( wPipeIndex ); - return Start( &cmMask ); - -} // ECHOSTATUS CEchoGals::Start - - -//=========================================================================== -// -// Start transport for a group of pipes -// -// This function includes logic to sync-start several pipes at once, -// according to the process ID specified when the pipe was opened. This is -// included to work around a limitation of the Windows wave API so that -// programs could use multiple inputs and outputs and have them start at the -// same time. -// -// If you don't want to use this feature, call CEchoGals::ClearFlags -// with ECHOGALS_FLAG_SYNCH_WAVE and the pipes will start immediately. -// -//=========================================================================== - -ECHOSTATUS CEchoGals::Start -( - PCChannelMask pChannelMask -) -{ - WORD wPipe; - CChannelMask cmStart; - PVOID ProcessId = NULL; - - if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) - return ECHOSTATUS_DSP_DEAD; - - // - // See if we are dealing with synchronized wave pipes. If the sync - // flag is set, get the process ID for this pipe to compare with - // other pipes. - // - if ( GetFlags() & ECHOGALS_FLAG_SYNCH_WAVE ) - { - wPipe = pChannelMask->GetIndexFromMask( 0 ); - ProcessId = m_ProcessId[ wPipe ]; - } - - //-------------------------------------------------------- - // Process each pipe in the mask - //-------------------------------------------------------- - - for (wPipe = 0; wPipe < GetNumPipes(); wPipe++) - { - PDWORD pdwDspCommPositions; - - // - // Skip this pipe if it's not in the mask - // - if (!pChannelMask->TestIndexInMask(wPipe)) - continue; - - // - // This pipe must have a CDaffyDuck object - // - if (NULL == m_DaffyDucks[ wPipe ]) - { - ECHO_DEBUGPRINTF(("CDaffyDuck::Start - trying to start pipe index %d " - "but there is no CDaffyDuck!\n",wPipe)); - return ECHOSTATUS_CHANNEL_NOT_OPEN; - } - - // - // If this pipe was opened in cyclic mode, make sure that the corresponding - // CDaffyDuck has been wrapped - // - if ( (0 != m_cmAudioCyclic.TestIndexInMask( wPipe ) ) && - (FALSE == m_DaffyDucks[wPipe]->Wrapped()) - ) - { - ECHO_DEBUGPRINTF(("CEchoGals::Start called for pipe index %d - " - "pipe was opened in cyclic mode, but the duck " - "has not been wrapped\n",wPipe)); - return ECHOSTATUS_DUCK_NOT_WRAPPED; - } - - - // - // Do different things to this pipe depending on the - // state - // - switch (m_byPipeState[wPipe]) - { - case PIPE_STATE_RESET : - // - // Clean up the DMA position stuff - // - pdwDspCommPositions = GetDspCommObject()->GetAudioPositionPtr(); - pdwDspCommPositions[ wPipe ] = 0; - - // - // If this pipe isn't synced or is in a reset state, - // start it up - // - if (NULL == ProcessId) - { - m_byPipeState[ wPipe ] = PIPE_STATE_STARTED; - cmStart.SetIndexInMask( wPipe ); - } - else - { - // - // This pipe is synced; upgrade to PENDING - // - m_byPipeState[ wPipe ] = PIPE_STATE_PENDING; - } - break; - - - case PIPE_STATE_STOPPED : - - if (NULL == ProcessId) - { - // - // Non-synced pipe; start 'er up! - // - m_byPipeState[ wPipe ] = PIPE_STATE_STARTED; - cmStart.SetIndexInMask( wPipe ); - } - else - { - // - // Synced pipe; if this pipe is in STOP mode, - // upgrade it to PENDING status - // - m_byPipeState[ wPipe ] = PIPE_STATE_PENDING; - } - break; - - - case PIPE_STATE_PENDING : - case PIPE_STATE_STARTED : - break; - } - } - - //----------------------------------------------------------------- - // Start the pipes - //----------------------------------------------------------------- - - // - // Don't go if all the synced pipes are not yet pending - // - BOOL fAllReady = TRUE; - for ( wPipe = 0; wPipe < GetNumPipes(); wPipe++ ) - { - if ( ( ProcessId == m_ProcessId[ wPipe ] ) && - ( PIPE_STATE_STOPPED == m_byPipeState[wPipe])) - { - ECHO_DEBUGPRINTF(("CEchoGals::Start - can't start; pipe %d " - "still set to state %d\n", - wPipe, - m_byPipeState[wPipe])); - fAllReady = FALSE; - } - } - - // - // All synced pipes are pending; time to go! - // - if (fAllReady) - { - for (wPipe = 0; wPipe < GetNumPipes(); wPipe++) - { - if ( (ProcessId == m_ProcessId[ wPipe ]) && - (PIPE_STATE_PENDING == m_byPipeState[ wPipe ])) - { - m_byPipeState[wPipe] = PIPE_STATE_STARTED; - cmStart.SetIndexInMask( wPipe ); - ECHO_DEBUGPRINTF(("CEchoGals::Start - setting pipe %d to start\n", - wPipe)); - } - } - } - - //----------------------------------------------------------------- - // Send the result of all this to the DSP - //----------------------------------------------------------------- - - if ( cmStart.IsEmpty() ) - return ECHOSTATUS_OK; - - return GetDspCommObject()->StartTransport( &cmStart, &m_cmAudioCyclic ); - -} // ECHOSTATUS CEchoGals::Start - - - -//=========================================================================== -// -// Stop a single pipe -// -//=========================================================================== - -ECHOSTATUS CEchoGals::Stop -( - WORD wPipeIndex -) -{ - CChannelMask cmMask; - - cmMask.SetIndexInMask( wPipeIndex ); - return( Stop( &cmMask ) ); - -} // ECHOSTATUS CEchoGals::Stop - - -//=========================================================================== -// -// Stop several pipes simultaneously -// -//=========================================================================== - -ECHOSTATUS CEchoGals::Stop -( - PCChannelMask pChannelMask -) -{ - int i; - ECHOSTATUS Status; - - if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) - return ECHOSTATUS_DSP_DEAD; - - Status = GetDspCommObject()->StopTransport( pChannelMask ); - if ( ECHOSTATUS_OK != Status ) - return Status; - - for ( i = 0; i < GetNumPipes(); i++ ) - { - // - // Skip channel if not in mask - // - if ( !pChannelMask->TestIndexInMask( (WORD) i ) ) - continue; - - - // - // Don't bother if it's stopped already - // - if ( PIPE_STATE_STOPPED == m_byPipeState[ i ] ) - continue; - - // - // Muck with the DMA position - // - UpdateDmaPos( (WORD) i ); - - m_byPipeState[ i ] = PIPE_STATE_STOPPED; - } - - return Status; - -} // ECHOSTATUS CEchoGals::Stop - - -//=========================================================================== -// -// Reset transport for a single pipe -// -//=========================================================================== - -ECHOSTATUS CEchoGals::Reset -( - WORD wPipeIndex -) -{ - CChannelMask cmMask; - - cmMask.SetIndexInMask( wPipeIndex ); - return Reset( &cmMask ); - -} // ECHOSTATUS CEchoGals::Reset - - -//=========================================================================== -// -// Reset transport for a group of pipes simultaneously -// -//=========================================================================== - -ECHOSTATUS CEchoGals::Reset -( - PCChannelMask pChannelMask -) -{ - WORD i; - ECHOSTATUS Status; - - if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) - return ECHOSTATUS_DSP_DEAD; - - Status = GetDspCommObject()->ResetTransport( pChannelMask ); - if ( ECHOSTATUS_OK != Status ) - return Status; - - PDWORD pdwDspCommPositions = - GetDspCommObject()->GetAudioPositionPtr(); - - for ( i = 0; i < GetNumPipes(); i++ ) - { - // - // Skip channel if not in mask - // - if ( !pChannelMask->TestIndexInMask( (WORD) i ) ) - continue; - - if ( PIPE_STATE_RESET == m_byPipeState[ i ] ) - continue; - - // - // Muck with the DMA position - // - UpdateDmaPos( i ); - m_dwLastDspPos[ i ] = 0; - GetDspCommObject()->ResetPipePosition(i); - - pdwDspCommPositions[ i ] = 0; - - m_byPipeState[ i ] = PIPE_STATE_RESET; - } - - return Status; - -} // ECHOSTATUS CEchoGals::Reset - - - - -/****************************************************************************** - - Functions for handling the current DMA position for pipes; the DMA position - is the number of bytes transported by a pipe. - - ******************************************************************************/ - -//=========================================================================== -// -// The DSP sends back a 32 bit DMA counter for each pipe of the number of bytes -// transported; this count is written by the DSP to the comm page without -// the driver doing anything. -// -// The driver then maintains a 64 bit counter based off of the DSP's counter. -// -// Call UpdateDmaPos to cause the driver to update the internal 64 bit DMA -// counter. -// -// The 64 bit DMA counter is in units of bytes, not samples. -// -//=========================================================================== - -void CEchoGals::UpdateDmaPos( WORD wPipeIndex ) -{ - DWORD dwDspPos; - DWORD dwDelta; - - // - // Get the current DSP position and find out how much it - // has moved since last time. This is necessary to avoid - // the 32 bit counter wrapping around. - // - dwDspPos = GetDspCommObject()->GetAudioPosition( wPipeIndex ); - dwDelta = dwDspPos - m_dwLastDspPos[ wPipeIndex ]; - - // - // Adjust the 64 bit position - // - m_ullDmaPos[ wPipeIndex ] += dwDelta; - m_dwLastDspPos[ wPipeIndex ] = dwDspPos; - -} // UpdateDmaPos - - -//=========================================================================== -// -// ResetDmaPos resets the 64 bit DMA counter. -// -//=========================================================================== - -void CEchoGals::ResetDmaPos(WORD wPipe) -{ - m_ullDmaPos[ wPipe ] = 0; - m_dwLastDspPos[ wPipe ] = 0; - - // - // There may still be mappings in the daffy duck; if so, - // tell them to reset their DMA positions starting at zero - // - if (NULL != m_DaffyDucks[wPipe]) - m_DaffyDucks[wPipe]->ResetStartPos(); -} - - -//=========================================================================== -// -// This is a very powerful feature; calling this function gives you a pointer -// to the memory location where the DSP writes the 32 bit DMA position for -// a pipe. The DSP is constantly updating this value as it moves data. -// -// Since the DSP is constantly updating it, you can dereference this pointer -// from anywhere and read the DMA position without calling the generic driver. -// This means that with some adroit mapping, you could read the DMA position -// from user mode without calling the kernel. -// -// Remember, Peter - with great power comes great responsibility; you should -// only read this pointer and never write to it or to anywhere around it. You -// could easily lock up your computer. -// -// Note that the DSP writes the position in little endian format; if you are -// on a big endian machine, you will need to byte swap the postion -// before you use it. -// -//=========================================================================== - -ECHOSTATUS CEchoGals::GetAudioPositionPtr -( - WORD wPipeIndex, - PDWORD & pdwPosition -) -{ - if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) - return ECHOSTATUS_DSP_DEAD; - - if (wPipeIndex >= GetNumPipes()) - { - pdwPosition = NULL; - return ECHOSTATUS_INVALID_CHANNEL; - } - - PDWORD pdwDspCommPos = GetDspCommObject()->GetAudioPositionPtr(); - - pdwPosition = pdwDspCommPos + wPipeIndex; - - return ECHOSTATUS_OK; - -} // ECHOSTATUS CEchoGals::GetAudioPositionPtr - - - +// **************************************************************************** +// +// CEchoGals_transport.cpp +// +// Audio transport methods for the CEchoGals driver class. +// Set editor tabs to 3 for your viewing pleasure. +// +// Copyright Echo Digital Audio Corporation (c) 1998 - 2002 +// All rights reserved +// www.echoaudio.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal with the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimers. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimers in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of Echo Digital Audio, nor the names of its +// contributors may be used to endorse or promote products derived from +// this Software without specific prior written permission. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR +// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. +// +// **************************************************************************** + +#include "CEchoGals.h" + +//#pragma optimize("",off) + + +/****************************************************************************** + + Functions for opening and closing pipes + + ******************************************************************************/ + +//=========================================================================== +// +// OpenAudio is used to reserve audio pipes for your exclusive use. The call +// will fail if someone else has already opened the pipes. Calling OpenAudio +// is the first step if you want to play or record. +// +//=========================================================================== + +ECHOSTATUS CEchoGals::OpenAudio +( + PECHOGALS_OPENAUDIOPARAMETERS pOpenParameters, // Info on pipe + PWORD pwPipeIndex // Pipe index ptr +) +{ + CChannelMask cmMask; + WORD wPipeMax, wPipe, wPipeIndex, i, wWidth; + + ECHO_DEBUGPRINTF( ("CEchoGals::OpenAudio: %s %u " + "PipeWidth %d " + "Cyclic %u \n", + ( pOpenParameters->Pipe.bIsInput ) ? "Input" : "Output", + pOpenParameters->Pipe.nPipe, + pOpenParameters->Pipe.wInterleave, + pOpenParameters->bIsCyclic) ); + + *pwPipeIndex = (WORD) -1; // So it's never undefined + + // + // Make sure the hardware is OK + // + if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) + { + ECHO_DEBUGPRINTF( ("\tECHOSTATUS_DSP_DEAD\n") ); + return ECHOSTATUS_DSP_DEAD; + } + + // + // Make sure the DSP & ASIC are up and running + // + ECHOSTATUS Status = GetDspCommObject()->LoadFirmware(); + if ( ECHOSTATUS_OK != Status ) + return Status; + + // + // Validate the pipe number + // + wPipe = pOpenParameters->Pipe.nPipe; + wWidth = pOpenParameters->Pipe.wInterleave; + + if ( pOpenParameters->Pipe.bIsInput ) + { + wPipeIndex = wPipe + GetNumPipesOut(); + wPipeMax = GetNumPipesIn(); + } + else + { + wPipeIndex = wPipe; + wPipeMax = GetNumPipesOut(); + } + + if ( ( wPipe + wWidth ) > wPipeMax ) + { + ECHO_DEBUGPRINTF( ("\tECHOSTATUS_INVALID_CHANNEL\n") ); + return ECHOSTATUS_INVALID_CHANNEL; + } + + // + // If the width is more than two, make sure that this card + // can handle super interleave + // + if ( (0 == (m_wFlags & ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK)) && + (wWidth > 2) + ) + { + ECHO_DEBUGPRINTF( ("\tECHOSTATUS_NO_SUPER_INTERLEAVE\n") ); + return ECHOSTATUS_NO_SUPER_INTERLEAVE; + } + + // + // See if the specified pipes are already open + // + for ( i = 0; i < pOpenParameters->Pipe.wInterleave; i++ ) + { + cmMask.SetIndexInMask( wPipeIndex + i ); + } + + if ( m_cmAudioOpen.Test( &cmMask ) ) + { + ECHO_DEBUGPRINTF( ("\tECHOSTATUS_CHANNEL_ALREADY_OPEN\n") ); + return( ECHOSTATUS_CHANNEL_ALREADY_OPEN ); + } + + // + // Make a daffy duck + // + Status = MakeDaffyDuck(wPipeIndex); + if (ECHOSTATUS_OK != Status) + return Status; + + // + // Reset the 64-bit DMA position + // + ResetDmaPos(wPipeIndex); + GetDspCommObject()->ResetPipePosition(wPipeIndex); + + // + // Prep stuff + // + m_cmAudioOpen += cmMask; + if ( pOpenParameters->bIsCyclic ) + m_cmAudioCyclic += cmMask; + m_Pipes[ wPipeIndex ] = pOpenParameters->Pipe; + *pwPipeIndex = wPipeIndex; + m_ProcessId[ wPipeIndex ] = pOpenParameters->ProcessId; + Reset( wPipeIndex ); + + ECHO_DEBUGPRINTF( ("\tECHOSTATUS_OK\n") ); + return ECHOSTATUS_OK; + +} // ECHOSTATUS CEchoGals::OpenAudio + + +//=========================================================================== +// +// CloseAudio is, naturally, the inverse of OpenAudio. +// +//=========================================================================== + +ECHOSTATUS CEchoGals::CloseAudio +( + PECHOGALS_CLOSEAUDIOPARAMETERS pCloseParameters +) +{ + CChannelMask cmMask; + ECHOSTATUS Status; + WORD i; + WORD wPipeIndex; + + ECHO_DEBUGPRINTF( ("CEchoGals::CloseAudio: Pipe %u ", + pCloseParameters->wPipeIndex) ); + + Status = VerifyAudioOpen( pCloseParameters->wPipeIndex ); + if ( ECHOSTATUS_OK != Status ) + return Status; + + for ( i = 0; + i < m_Pipes[ pCloseParameters->wPipeIndex ].wInterleave; + i++ ) + { + cmMask.SetIndexInMask( pCloseParameters->wPipeIndex + i ); + } + Reset( pCloseParameters->wPipeIndex ); + + KillDaffyDuck( pCloseParameters->wPipeIndex ); + + m_cmAudioOpen -= cmMask; + m_cmAudioCyclic -= cmMask; + + wPipeIndex = pCloseParameters->wPipeIndex; + m_ProcessId[ wPipeIndex ] = NULL; + m_Pipes[ wPipeIndex ].wInterleave = 0; + + ECHO_DEBUGPRINTF( ("\tECHOSTATUS_OK\n") ); + return ECHOSTATUS_OK; + +} // ECHOSTATUS CEchoGals::CloseAudio + + +//=========================================================================== +// +// VerifyAudioOpen is a utility function; it tells you if +// a pipe is open or not. +// +//=========================================================================== + +ECHOSTATUS CEchoGals::VerifyAudioOpen +( + WORD wPipeIndex +) +{ + CChannelMask cmMask; + + if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) + { + ECHO_DEBUGPRINTF( ("\tECHOSTATUS_DSP_DEAD\n") ); + return ECHOSTATUS_DSP_DEAD; + } + + cmMask.SetIndexInMask( wPipeIndex ); + if ( !( m_cmAudioOpen.Test( &cmMask ) ) ) + { + ECHO_DEBUGPRINTF( ("\tECHOSTATUS_CHANNEL_NOT_OPEN\n") ); + return ECHOSTATUS_CHANNEL_NOT_OPEN; + } + + return ECHOSTATUS_OK; + +} // ECHOSTATUS CEchoGals::VerifyAudioOpen + + +//=========================================================================== +// +// GetActivePipes tells you which pipes are currently active; that is, which +// pipes are currently playing or recording. +// +//=========================================================================== + +ECHOSTATUS CEchoGals::GetActivePipes +( + PCChannelMask pChannelMask +) +{ + if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) + return ECHOSTATUS_DSP_DEAD; + + GetDspCommObject()->GetActivePipes( pChannelMask ); + return ECHOSTATUS_OK; +} // void CEchoGals::GetActivePipes() + + +//=========================================================================== +// +// Just like GetActivePipes, but this one tells you which pipes are currently +// open. +// +//=========================================================================== + +ECHOSTATUS CEchoGals::GetOpenPipes +( + PCChannelMask pChannelMask +) +{ + if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) + return ECHOSTATUS_DSP_DEAD; + + *pChannelMask = m_cmAudioOpen; + return ECHOSTATUS_OK; + +} // void CEchoGals::GetOpenPipes() + + + + +/****************************************************************************** + + Functions for setting audio formats and the sample rate + + ******************************************************************************/ + +//=========================================================================== +// +// Validate an audio format. +// +// For comments on audio formats, refer to the definition of +// ECHOGALS_AUDIOFORMAT. +// +//=========================================================================== + +ECHOSTATUS CEchoGals::QueryAudioFormat +( + WORD wPipeIndex, + PECHOGALS_AUDIOFORMAT pAudioFormat +) +{ + ECHOSTATUS Status = ECHOSTATUS_OK; + + ECHO_DEBUGPRINTF( ("CEchoGals::QueryAudioFormat:\n") ); + + // + // If this pipe is open, make sure that this audio format + // does not exceed the stored pipe width + // + WORD wInterleave = pAudioFormat->wDataInterleave; + WORD wStoredPipeWidth = m_Pipes[ wPipeIndex ].wInterleave; + + if (0 != wStoredPipeWidth) + { + if (wInterleave > wStoredPipeWidth) + { + ECHO_DEBUGPRINTF(("CEchoGals::QueryAudioFormat - pipe was opened " + "with a width of %d; interleave of %d invalid.\n", + wStoredPipeWidth, + pAudioFormat->wDataInterleave)); + return ECHOSTATUS_BAD_FORMAT; + } + } + + // + // Check for super interleave (i.e. interleave > 2) + // + if (wInterleave > 2) + { + // + // Make sure the card is capable of super interleave + // + if (0 == (m_wFlags & ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK)) + return ECHOSTATUS_NO_SUPER_INTERLEAVE; + + // + // Allow super interleave for 32 bit little endian data; + // the interleave factor must be even. + // + if ( (32 != pAudioFormat->wBitsPerSample) || + (0 != pAudioFormat->byDataAreBigEndian) || + (0 != (wInterleave & 1) ) + ) + return ECHOSTATUS_BAD_FORMAT; + + // + // Make sure that this interleave factor on this pipe + // does not exceed the number of pipes for the card + // + WORD wMaxPipe; + + if (wPipeIndex >= GetNumPipesOut()) + { + wMaxPipe = GetNumPipesIn(); + wPipeIndex -= GetNumPipesOut(); + } + else + { + wMaxPipe = GetNumPipesOut(); + } + + if ( (wPipeIndex + wInterleave) > wMaxPipe) + return ECHOSTATUS_BAD_FORMAT; + + return ECHOSTATUS_OK; + } + + // + // Check the interleave + // + if ( (1 != pAudioFormat->wDataInterleave) && + (2 != pAudioFormat->wDataInterleave) ) + + { + ECHO_DEBUGPRINTF( ("CEchoGals::QueryAudioFormat - interleave %d not allowed\n", + pAudioFormat->wDataInterleave)); + return ECHOSTATUS_BAD_FORMAT; + } + + // + // If the big endian flag is set, the data must be mono or stereo interleave, + // 32 bits wide, left justified data. Only the upper 24 bits are used. + // + if (pAudioFormat->byDataAreBigEndian) + { + // + // Must have 32 bits per sample + // + if (pAudioFormat->wBitsPerSample != 32) + { + ECHO_DEBUGPRINTF(("CEchoGals::QueryAudioFormat - Only 32 bits per" + " sample supported for big-endian data\n")); + return ECHOSTATUS_BAD_FORMAT; + } + + // + // Mono or stereo only + // + switch (pAudioFormat->wDataInterleave) + { + +#ifdef STEREO_BIG_ENDIAN32_SUPPORT + + case 1 : + case 2 : + break; +#else + + case 1 : + break; + +#endif + + default : + ECHO_DEBUGPRINTF(("CEchoGals::QueryAudioFormat - Interleave of %d" + " not allowed for big-endian data\n", + pAudioFormat->wDataInterleave)); + return ECHOSTATUS_BAD_FORMAT; + } + + return ECHOSTATUS_OK; + } + + // + // Check bits per sample + // + switch ( pAudioFormat->wBitsPerSample ) + { + case 8 : + case 16 : + case 32 : + break; + + default : + ECHO_DEBUGPRINTF( + ("CEchoGals::QueryAudioFormat: No valid format " + "specified, bits per sample %d\n", + pAudioFormat->wBitsPerSample) ); + Status = ECHOSTATUS_BAD_FORMAT; + break; + } + + return Status; + +} // ECHOSTATUS CEchoGals::QueryAudioFormat + + +//=========================================================================== +// +// SetAudioFormat sets the format of the audio data in host memory +// for this pipe. +// +//=========================================================================== + +ECHOSTATUS CEchoGals::SetAudioFormat +( + WORD wPipeIndex, + PECHOGALS_AUDIOFORMAT pAudioFormat +) +{ + ECHOSTATUS Status; + + ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioFormat: " + "for pipe %d\n", + wPipeIndex) ); + + // + // Make sure this pipe is open + // + Status = VerifyAudioOpen( wPipeIndex ); + if ( ECHOSTATUS_OK != Status ) + return Status; + + // + // Check the format + // + Status = QueryAudioFormat( wPipeIndex, pAudioFormat ); + if ( ECHOSTATUS_OK != Status ) + return Status; + + // + // Set the format + // + BOOL fDitherDigitalInputs; + + fDitherDigitalInputs = 0 != (m_wFlags & ECHOGALS_FLAG_SPDIF_NODITHER); + Status = + GetDspCommObject()->SetAudioFormat( wPipeIndex, + pAudioFormat, + fDitherDigitalInputs ); + return Status; + +} // ECHOSTATUS CEchoGals::SetAudioFormat - single pipe + + +//=========================================================================== +// +// This call lets you set the audio format for several pipes at once. +// +//=========================================================================== + +ECHOSTATUS CEchoGals::SetAudioFormat +( + PCChannelMask pChannelMask, + PECHOGALS_AUDIOFORMAT pAudioFormat +) +{ + WORD wPipeIndex = 0xffff; + ECHOSTATUS Status; + BOOL fDitherDigitalInputs; + + if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) + { + ECHO_DEBUGPRINTF( ("\tECHOSTATUS_DSP_DEAD\n") ); + return ECHOSTATUS_DSP_DEAD; + } + + fDitherDigitalInputs = 0 != (m_wFlags & ECHOGALS_FLAG_SPDIF_NODITHER); + for ( ; ; ) + { + wPipeIndex = pChannelMask->GetIndexFromMask( ++wPipeIndex ); + if ( (WORD) ECHO_INVALID_CHANNEL == wPipeIndex ) + break; // We be done! + + // + // See if this pipe is open + // + if ( !( m_cmAudioOpen.TestIndexInMask( wPipeIndex ) ) ) + { + ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioFormat: " + "for pipe %d failed, pipe not open\n", + wPipeIndex) ); + return ECHOSTATUS_CHANNEL_NOT_OPEN; + } + + // + // See if the format is OK + // + ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioFormat: " + "for pipe %d\n", + wPipeIndex) ); + Status = QueryAudioFormat( wPipeIndex, pAudioFormat ); + if ( ECHOSTATUS_OK != Status ) + return Status; + + // + // Set the format for this pipe + // + Status = + GetDspCommObject()->SetAudioFormat( wPipeIndex, + pAudioFormat, + fDitherDigitalInputs ); + if ( ECHOSTATUS_OK != Status ) + return Status; + + m_wBytesPerSample[ wPipeIndex ] = pAudioFormat->wBitsPerSample / 8; + m_wBytesPerSample[ wPipeIndex ] *= pAudioFormat->wDataInterleave; + } + + return ECHOSTATUS_OK; + +} // ECHOSTATUS CEchoGals::SetAudioFormat - multiple pipes + + +//=========================================================================== +// +// GetAudioFormat returns the current audio format for a pipe. +// +//=========================================================================== + +ECHOSTATUS CEchoGals::GetAudioFormat +( + WORD wPipeIndex, + PECHOGALS_AUDIOFORMAT pAudioFormat +) +{ + ECHO_DEBUGPRINTF( ("CEchoGals::GetAudioFormat: " + "for pipe %d\n", + wPipeIndex) ); + + GetDspCommObject()->GetAudioFormat( wPipeIndex, pAudioFormat ); + + return ECHOSTATUS_OK; + +} // ECHOSTATUS CEchoGals::GetAudioFormat + + +//=========================================================================== +// +// This function does exactly what you think it does. +// +// Note that if the card is not set to internal clock (that is, the hardware +// is synced to word clock or some such), this call has no effect. +// +// Note that all of the inputs and outputs on a single card share the same +// clock. +// +//=========================================================================== + +ECHOSTATUS CEchoGals::SetAudioSampleRate +( + DWORD dwSampleRate +) +{ + ECHOSTATUS Status; + + ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioSampleRate: " + "to %ld Hz\n", + dwSampleRate) ); + + // + // Check to see if the sample rate is locked + // + if ( 0 != (m_wFlags & ECHOGALS_FLAG_SAMPLE_RATE_LOCKED)) + { + return ECHOSTATUS_OK; + } + else + { + Status = QueryAudioSampleRate( dwSampleRate ); + if ( ECHOSTATUS_OK != Status ) + return Status; + + if ( dwSampleRate == GetDspCommObject()->SetSampleRate( dwSampleRate ) ) + { + m_dwSampleRate = dwSampleRate; + return ECHOSTATUS_OK; + } + } + return ECHOSTATUS_BAD_FORMAT; + +} // ECHOSTATUS CEchoGals::SetAudioSampleRate + + +//=========================================================================== +// +// GetAudioSampleRate - retrieves the current sample rate for the hardware +// +//=========================================================================== + +ECHOSTATUS CEchoGals::GetAudioSampleRate +( + PDWORD pdwSampleRate +) +{ + ECHO_DEBUGPRINTF( ("CEchoGals::GetAudioSampleRate\n")); + + *pdwSampleRate = m_dwSampleRate; + + return ECHOSTATUS_OK; + +} // ECHOSTATUS CEchoGals::GetAudioSampleRate + + + + +/****************************************************************************** + + Functions related to the scatter-gather list + + ******************************************************************************/ + +//=========================================================================== +// +// This protected method is used to create a CDaffyDuck object to +// manage a scatter-gather list for a newly opened pipe. +// +//=========================================================================== + +ECHOSTATUS CEchoGals::MakeDaffyDuck(WORD wPipeIndex) +{ + ECHOSTATUS Status = ECHOSTATUS_OK; + + //--------------------------------------------------------- + // + // Allocate the main daffy duck for this pipe + // + //--------------------------------------------------------- + + m_DaffyDucks[wPipeIndex] = new CDaffyDuck(m_pOsSupport, + GetDspCommObject(), + wPipeIndex ); + if (NULL == m_DaffyDucks[wPipeIndex]) + { + return ECHOSTATUS_NO_MEM; + } + + // + // Check the daffy duck + // + Status = m_DaffyDucks[wPipeIndex]->InitCheck(); + if (ECHOSTATUS_OK != Status) + { + return Status; + } + + // + // Put the daffy duck in the comm page + // + GetDspCommObject()-> + SetAudioDuckListPhys(wPipeIndex, + m_DaffyDucks[wPipeIndex]->GetPhysStartAddr() ); + + ECHO_DEBUGPRINTF(("CEchoGals::MakeDaffyDuck - 0x%lx for pipe index %d\n", + (DWORD) m_DaffyDucks[wPipeIndex],wPipeIndex)); + + return Status; + +} // MakeDaffyDuck + + +//=========================================================================== +// +// Daffy duck cleanup +// +//=========================================================================== + +void CEchoGals::KillDaffyDuck(WORD wPipeIndex) +{ + if (NULL != m_DaffyDucks[wPipeIndex]) + { + delete m_DaffyDucks[wPipeIndex]; + m_DaffyDucks[wPipeIndex] = NULL; + } + +} // KillDaffyDuck + + +//=========================================================================== +// +// This method returns a pointer to the daffy duck for a pipe; the caller +// can then have direct access to the daffy duck object. +// +//=========================================================================== + +CDaffyDuck *CEchoGals::GetDaffyDuck(WORD wPipeIndex) +{ + ECHO_DEBUGPRINTF(("CEchoGals::GetDaffyDuck for pipe index %d\n",wPipeIndex)); + + if (wPipeIndex >= GetNumPipes()) + return NULL; + + return m_DaffyDucks[wPipeIndex]; +} + + + +/****************************************************************************** + + Functions for starting and stopping transport + + ******************************************************************************/ + +//=========================================================================== +// +// Start transport for a single pipe +// +//=========================================================================== + +ECHOSTATUS CEchoGals::Start +( + WORD wPipeIndex +) +{ + CChannelMask cmMask; + + cmMask.SetIndexInMask( wPipeIndex ); + return Start( &cmMask ); + +} // ECHOSTATUS CEchoGals::Start + + +//=========================================================================== +// +// Start transport for a group of pipes +// +// This function includes logic to sync-start several pipes at once, +// according to the process ID specified when the pipe was opened. This is +// included to work around a limitation of the Windows wave API so that +// programs could use multiple inputs and outputs and have them start at the +// same time. +// +// If you don't want to use this feature, call CEchoGals::ClearFlags +// with ECHOGALS_FLAG_SYNCH_WAVE and the pipes will start immediately. +// +//=========================================================================== + +ECHOSTATUS CEchoGals::Start +( + PCChannelMask pChannelMask +) +{ + WORD wPipe; + CChannelMask cmStart; + PVOID ProcessId = NULL; + + if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) + return ECHOSTATUS_DSP_DEAD; + + // + // See if we are dealing with synchronized wave pipes. If the sync + // flag is set, get the process ID for this pipe to compare with + // other pipes. + // + if ( GetFlags() & ECHOGALS_FLAG_SYNCH_WAVE ) + { + wPipe = pChannelMask->GetIndexFromMask( 0 ); + ProcessId = m_ProcessId[ wPipe ]; + } + + //-------------------------------------------------------- + // Process each pipe in the mask + //-------------------------------------------------------- + + for (wPipe = 0; wPipe < GetNumPipes(); wPipe++) + { + PDWORD pdwDspCommPositions; + + // + // Skip this pipe if it's not in the mask + // + if (!pChannelMask->TestIndexInMask(wPipe)) + continue; + + // + // This pipe must have a CDaffyDuck object + // + if (NULL == m_DaffyDucks[ wPipe ]) + { + ECHO_DEBUGPRINTF(("CDaffyDuck::Start - trying to start pipe index %d " + "but there is no CDaffyDuck!\n",wPipe)); + return ECHOSTATUS_CHANNEL_NOT_OPEN; + } + + // + // If this pipe was opened in cyclic mode, make sure that the corresponding + // CDaffyDuck has been wrapped + // + if ( (0 != m_cmAudioCyclic.TestIndexInMask( wPipe ) ) && + (FALSE == m_DaffyDucks[wPipe]->Wrapped()) + ) + { + ECHO_DEBUGPRINTF(("CEchoGals::Start called for pipe index %d - " + "pipe was opened in cyclic mode, but the duck " + "has not been wrapped\n",wPipe)); + return ECHOSTATUS_DUCK_NOT_WRAPPED; + } + + + // + // Do different things to this pipe depending on the + // state + // + switch (m_byPipeState[wPipe]) + { + case PIPE_STATE_RESET : + // + // Clean up the DMA position stuff + // + pdwDspCommPositions = GetDspCommObject()->GetAudioPositionPtr(); + pdwDspCommPositions[ wPipe ] = 0; + + // + // If this pipe isn't synced or is in a reset state, + // start it up + // + if (NULL == ProcessId) + { + m_byPipeState[ wPipe ] = PIPE_STATE_STARTED; + cmStart.SetIndexInMask( wPipe ); + } + else + { + // + // This pipe is synced; upgrade to PENDING + // + m_byPipeState[ wPipe ] = PIPE_STATE_PENDING; + } + break; + + + case PIPE_STATE_STOPPED : + + if (NULL == ProcessId) + { + // + // Non-synced pipe; start 'er up! + // + m_byPipeState[ wPipe ] = PIPE_STATE_STARTED; + cmStart.SetIndexInMask( wPipe ); + } + else + { + // + // Synced pipe; if this pipe is in STOP mode, + // upgrade it to PENDING status + // + m_byPipeState[ wPipe ] = PIPE_STATE_PENDING; + } + break; + + + case PIPE_STATE_PENDING : + case PIPE_STATE_STARTED : + break; + } + } + + //----------------------------------------------------------------- + // Start the pipes + //----------------------------------------------------------------- + + // + // Don't go if all the synced pipes are not yet pending + // + BOOL fAllReady = TRUE; + for ( wPipe = 0; wPipe < GetNumPipes(); wPipe++ ) + { + if ( ( ProcessId == m_ProcessId[ wPipe ] ) && + ( PIPE_STATE_STOPPED == m_byPipeState[wPipe])) + { + ECHO_DEBUGPRINTF(("CEchoGals::Start - can't start; pipe %d " + "still set to state %d\n", + wPipe, + m_byPipeState[wPipe])); + fAllReady = FALSE; + } + } + + // + // All synced pipes are pending; time to go! + // + if (fAllReady) + { + for (wPipe = 0; wPipe < GetNumPipes(); wPipe++) + { + if ( (ProcessId == m_ProcessId[ wPipe ]) && + (PIPE_STATE_PENDING == m_byPipeState[ wPipe ])) + { + m_byPipeState[wPipe] = PIPE_STATE_STARTED; + cmStart.SetIndexInMask( wPipe ); + ECHO_DEBUGPRINTF(("CEchoGals::Start - setting pipe %d to start\n", + wPipe)); + } + } + } + + //----------------------------------------------------------------- + // Send the result of all this to the DSP + //----------------------------------------------------------------- + + if ( cmStart.IsEmpty() ) + return ECHOSTATUS_OK; + + return GetDspCommObject()->StartTransport( &cmStart, &m_cmAudioCyclic ); + +} // ECHOSTATUS CEchoGals::Start + + + +//=========================================================================== +// +// Stop a single pipe +// +//=========================================================================== + +ECHOSTATUS CEchoGals::Stop +( + WORD wPipeIndex +) +{ + CChannelMask cmMask; + + cmMask.SetIndexInMask( wPipeIndex ); + return( Stop( &cmMask ) ); + +} // ECHOSTATUS CEchoGals::Stop + + +//=========================================================================== +// +// Stop several pipes simultaneously +// +//=========================================================================== + +ECHOSTATUS CEchoGals::Stop +( + PCChannelMask pChannelMask +) +{ + int i; + ECHOSTATUS Status; + + if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) + return ECHOSTATUS_DSP_DEAD; + + Status = GetDspCommObject()->StopTransport( pChannelMask ); + if ( ECHOSTATUS_OK != Status ) + return Status; + + for ( i = 0; i < GetNumPipes(); i++ ) + { + // + // Skip channel if not in mask + // + if ( !pChannelMask->TestIndexInMask( (WORD) i ) ) + continue; + + + // + // Don't bother if it's stopped already + // + if ( PIPE_STATE_STOPPED == m_byPipeState[ i ] ) + continue; + + // + // Muck with the DMA position + // + UpdateDmaPos( (WORD) i ); + + m_byPipeState[ i ] = PIPE_STATE_STOPPED; + } + + return Status; + +} // ECHOSTATUS CEchoGals::Stop + + +//=========================================================================== +// +// Reset transport for a single pipe +// +//=========================================================================== + +ECHOSTATUS CEchoGals::Reset +( + WORD wPipeIndex +) +{ + CChannelMask cmMask; + + cmMask.SetIndexInMask( wPipeIndex ); + return Reset( &cmMask ); + +} // ECHOSTATUS CEchoGals::Reset + + +//=========================================================================== +// +// Reset transport for a group of pipes simultaneously +// +//=========================================================================== + +ECHOSTATUS CEchoGals::Reset +( + PCChannelMask pChannelMask +) +{ + WORD i; + ECHOSTATUS Status; + + if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) + return ECHOSTATUS_DSP_DEAD; + + Status = GetDspCommObject()->ResetTransport( pChannelMask ); + if ( ECHOSTATUS_OK != Status ) + return Status; + + PDWORD pdwDspCommPositions = + GetDspCommObject()->GetAudioPositionPtr(); + + for ( i = 0; i < GetNumPipes(); i++ ) + { + // + // Skip channel if not in mask + // + if ( !pChannelMask->TestIndexInMask( (WORD) i ) ) + continue; + + if ( PIPE_STATE_RESET == m_byPipeState[ i ] ) + continue; + + // + // Muck with the DMA position + // + UpdateDmaPos( i ); + m_dwLastDspPos[ i ] = 0; + GetDspCommObject()->ResetPipePosition(i); + + pdwDspCommPositions[ i ] = 0; + + m_byPipeState[ i ] = PIPE_STATE_RESET; + } + + return Status; + +} // ECHOSTATUS CEchoGals::Reset + + + + +/****************************************************************************** + + Functions for handling the current DMA position for pipes; the DMA position + is the number of bytes transported by a pipe. + + ******************************************************************************/ + +//=========================================================================== +// +// The DSP sends back a 32 bit DMA counter for each pipe of the number of bytes +// transported; this count is written by the DSP to the comm page without +// the driver doing anything. +// +// The driver then maintains a 64 bit counter based off of the DSP's counter. +// +// Call UpdateDmaPos to cause the driver to update the internal 64 bit DMA +// counter. +// +// The 64 bit DMA counter is in units of bytes, not samples. +// +//=========================================================================== + +void CEchoGals::UpdateDmaPos( WORD wPipeIndex ) +{ + DWORD dwDspPos; + DWORD dwDelta; + + // + // Get the current DSP position and find out how much it + // has moved since last time. This is necessary to avoid + // the 32 bit counter wrapping around. + // + dwDspPos = GetDspCommObject()->GetAudioPosition( wPipeIndex ); + dwDelta = dwDspPos - m_dwLastDspPos[ wPipeIndex ]; + + // + // Adjust the 64 bit position + // + m_ullDmaPos[ wPipeIndex ] += dwDelta; + m_dwLastDspPos[ wPipeIndex ] = dwDspPos; + +} // UpdateDmaPos + + +//=========================================================================== +// +// ResetDmaPos resets the 64 bit DMA counter. +// +//=========================================================================== + +void CEchoGals::ResetDmaPos(WORD wPipe) +{ + m_ullDmaPos[ wPipe ] = 0; + m_dwLastDspPos[ wPipe ] = 0; + + // + // There may still be mappings in the daffy duck; if so, + // tell them to reset their DMA positions starting at zero + // + if (NULL != m_DaffyDucks[wPipe]) + m_DaffyDucks[wPipe]->ResetStartPos(); +} + + +//=========================================================================== +// +// This is a very powerful feature; calling this function gives you a pointer +// to the memory location where the DSP writes the 32 bit DMA position for +// a pipe. The DSP is constantly updating this value as it moves data. +// +// Since the DSP is constantly updating it, you can dereference this pointer +// from anywhere and read the DMA position without calling the generic driver. +// This means that with some adroit mapping, you could read the DMA position +// from user mode without calling the kernel. +// +// Remember, Peter - with great power comes great responsibility; you should +// only read this pointer and never write to it or to anywhere around it. You +// could easily lock up your computer. +// +// Note that the DSP writes the position in little endian format; if you are +// on a big endian machine, you will need to byte swap the postion +// before you use it. +// +//=========================================================================== + +ECHOSTATUS CEchoGals::GetAudioPositionPtr +( + WORD wPipeIndex, + PDWORD & pdwPosition +) +{ + if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) + return ECHOSTATUS_DSP_DEAD; + + if (wPipeIndex >= GetNumPipes()) + { + pdwPosition = NULL; + return ECHOSTATUS_INVALID_CHANNEL; + } + + PDWORD pdwDspCommPos = GetDspCommObject()->GetAudioPositionPtr(); + + pdwPosition = pdwDspCommPos + wPipeIndex; + + return ECHOSTATUS_OK; + +} // ECHOSTATUS CEchoGals::GetAudioPositionPtr + + + diff --git a/src/add-ons/kernel/drivers/audio/echo/generic/CLayla.cpp b/src/add-ons/kernel/drivers/audio/echo/generic/CLayla.cpp index 0fa39e4152..fed206ccc5 100644 --- a/src/add-ons/kernel/drivers/audio/echo/generic/CLayla.cpp +++ b/src/add-ons/kernel/drivers/audio/echo/generic/CLayla.cpp @@ -1,329 +1,329 @@ -// **************************************************************************** -// -// CLayla.cpp -// -// Implementation file for the CLayla driver class; this is for 20-bit -// Layla. -// -// Set editor tabs to 3 for your viewing pleasure. -// -// Copyright Echo Digital Audio Corporation (c) 1998 - 2002 -// All rights reserved -// www.echoaudio.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal with the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimers. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimers in the -// documentation and/or other materials provided with the distribution. -// -// - Neither the name of Echo Digital Audio, nor the names of its -// contributors may be used to endorse or promote products derived from -// this Software without specific prior written permission. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR -// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -// SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. -// -// **************************************************************************** - -#include "CLayla.h" - - -/**************************************************************************** - - Construction and destruction - - ****************************************************************************/ - -//=========================================================================== -// -// Overload new & delete so memory for this object is allocated -// from non-paged memory. -// -//=========================================================================== - -PVOID CLayla::operator new( size_t Size ) -{ - PVOID pMemory; - ECHOSTATUS Status; - - Status = OsAllocateNonPaged(Size,&pMemory); - - if ( (ECHOSTATUS_OK != Status) || (NULL == pMemory )) - { - ECHO_DEBUGPRINTF(("CLayla::operator new - memory allocation failed\n")); - - pMemory = NULL; - } - else - { - memset( pMemory, 0, Size ); - } - - return pMemory; - -} // PVOID CLayla::operator new( size_t Size ) - - -VOID CLayla::operator delete( PVOID pVoid ) -{ - if ( ECHOSTATUS_OK != OsFreeNonPaged( pVoid ) ) - { - ECHO_DEBUGPRINTF( ("CLayla::operator delete memory free failed\n") ); - } -} // VOID CLayla::operator delete( PVOID pVoid ) - - -//=========================================================================== -// -// Constructor and destructor -// -//=========================================================================== - -CLayla::CLayla( PCOsSupport pOsSupport ) - : CEchoGals( pOsSupport ) -{ - ECHO_DEBUGPRINTF( ( "CLayla::CLayla() is born!\n" ) ); -} // CLayla::CLayla() - - -CLayla::~CLayla() -{ - ECHO_DEBUGPRINTF( ( "CLayla::~CLayla() is toast!\n" ) ); -} // CLayla::~CLayla() - - - - -/**************************************************************************** - - Setup and hardware initialization - - ****************************************************************************/ - -//=========================================================================== -// -// Every card has an InitHw method -// -//=========================================================================== - -ECHOSTATUS CLayla::InitHw() -{ - ECHOSTATUS Status; - WORD i; - - // - // Call the base method - // - if ( ECHOSTATUS_OK != ( Status = CEchoGals::InitHw() ) ) - return Status; - - // - // Create the DSP comm object - // - ASSERT( NULL == m_pDspCommObject ); - m_pDspCommObject = new CLaylaDspCommObject( (PDWORD) m_pvSharedMemory, - m_pOsSupport ); - if (NULL == m_pDspCommObject) - { - ECHO_DEBUGPRINTF(("CLayla::InitHw - could not create DSP comm object\n")); - return ECHOSTATUS_NO_MEM; - } - - // - // Load the DSP and the external box ASIC - // - GetDspCommObject()->LoadFirmware(); - if ( GetDspCommObject()->IsBoardBad() ) - return ECHOSTATUS_DSP_DEAD; - - // - // Clear the "bad board" flag; set the flag to indicate that - // Darla24 can handle super-interleave. - // - m_wFlags &= ~ECHOGALS_FLAG_BADBOARD; - m_wFlags |= ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK; - - // - // Must call this here after DSP is init to - // init gains and mutes - // - Status = InitLineLevels(); - if ( ECHOSTATUS_OK != Status ) - return Status; - - // - // Initialize the MIDI input - // - Status = m_MidiIn.Init( this ); - if ( ECHOSTATUS_OK != Status ) - return Status; - - // - // Set defaults for +4/-10 - // - for (i = 0; i < GetFirstDigitalBusOut(); i++ ) - { - GetDspCommObject()->SetNominalLevel( i, TRUE ); // TRUE is -10 here - } - for ( i = 0; i < GetFirstDigitalBusIn(); i++ ) - { - GetDspCommObject()->SetNominalLevel( GetNumBussesOut() + i, TRUE ); - } - - // - // Set the S/PDIF output format to "professional" - // - SetProfessionalSpdif( TRUE ); - - // - // Get default sample rate from DSP - // - m_dwSampleRate = GetDspCommObject()->GetSampleRate(); - ECHO_DEBUGPRINTF( ( "CLayla::InitHw()\n" ) ); - - return Status; - -} // ECHOSTATUS CLayla::InitHw() - - - - -/**************************************************************************** - - Informational methods - - ****************************************************************************/ - -//=========================================================================== -// -// Override GetCapabilities to enumerate unique capabilties for Layla20 -// -//=========================================================================== - -ECHOSTATUS CLayla::GetCapabilities -( - PECHOGALS_CAPS pCapabilities -) -{ - ECHOSTATUS Status; - WORD i; - - Status = GetBaseCapabilities(pCapabilities); - - // - // Add input gain and nominal level to input busses - // - for (i = 0; i < GetFirstDigitalBusIn(); i++) - { - pCapabilities->dwBusInCaps[i] |= ECHOCAPS_GAIN | - ECHOCAPS_MUTE | - ECHOCAPS_NOMINAL_LEVEL; - } - - // - // Add nominal levels to output busses - // - for (i = 0; i < GetFirstDigitalBusOut(); i++) - { - pCapabilities->dwBusOutCaps[i] |= ECHOCAPS_NOMINAL_LEVEL; - } - - if ( ECHOSTATUS_OK != Status ) - return Status; - - pCapabilities->dwInClockTypes |= ECHO_CLOCK_BIT_WORD | - ECHO_CLOCK_BIT_SUPER | - ECHO_CLOCK_BIT_SPDIF; - - pCapabilities->dwOutClockTypes |= ECHO_CLOCK_BIT_WORD | - ECHO_CLOCK_BIT_SUPER; - - return Status; - -} // ECHOSTATUS CLayla::GetCapabilities - - -//=========================================================================== -// -// QueryAudioSampleRate is used to find out if this card can handle a -// given sample rate. -// -//=========================================================================== - -ECHOSTATUS CLayla::QueryAudioSampleRate -( - DWORD dwSampleRate -) -{ - if ( dwSampleRate < 8000 || - dwSampleRate > 50000 ) - { - ECHO_DEBUGPRINTF( - ("CLayla::QueryAudioSampleRate() Sample rate must be >= 8,000 Hz" - " and <= 50,000 Hz\n") ); - return ECHOSTATUS_BAD_FORMAT; - } - ECHO_DEBUGPRINTF( ( "CLayla::QueryAudioSampleRate() %d Hz OK\n", - dwSampleRate ) ); - return ECHOSTATUS_OK; - -} // ECHOSTATUS CLayla::QueryAudioSampleRate - - -//=========================================================================== -// -// GetInputClockDetect returns a bitmask consisting of all the input -// clocks currently connected to the hardware; this changes as the user -// connects and disconnects clock inputs. -// -// You should use this information to determine which clocks the user is -// allowed to select. -// -// Layla20 supports S/PDIF clock, word clock, and super clock. -// -//=========================================================================== - -ECHOSTATUS CLayla::GetInputClockDetect(DWORD &dwClockDetectBits) -{ - if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) - { - ECHO_DEBUGPRINTF( ("CLayla::GetInputClockDetect: DSP Dead!\n") ); - return ECHOSTATUS_DSP_DEAD; - } - - DWORD dwClocksFromDsp = GetDspCommObject()->GetInputClockDetect(); - - dwClockDetectBits = ECHO_CLOCK_BIT_INTERNAL; - - if (0 != (dwClocksFromDsp & GLDM_CLOCK_DETECT_BIT_SPDIF)) - dwClockDetectBits |= ECHO_CLOCK_BIT_SPDIF; - - if (0 != (dwClocksFromDsp & GLDM_CLOCK_DETECT_BIT_WORD)) - { - if (0 != (dwClocksFromDsp & GLDM_CLOCK_DETECT_BIT_SUPER)) - dwClockDetectBits |= ECHO_CLOCK_BIT_SUPER; - else - dwClockDetectBits |= ECHO_CLOCK_BIT_WORD; - } - - return ECHOSTATUS_OK; - -} // GetInputClockDetect - - -// *** CLayla.cpp *** +// **************************************************************************** +// +// CLayla.cpp +// +// Implementation file for the CLayla driver class; this is for 20-bit +// Layla. +// +// Set editor tabs to 3 for your viewing pleasure. +// +// Copyright Echo Digital Audio Corporation (c) 1998 - 2002 +// All rights reserved +// www.echoaudio.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal with the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimers. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimers in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of Echo Digital Audio, nor the names of its +// contributors may be used to endorse or promote products derived from +// this Software without specific prior written permission. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR +// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. +// +// **************************************************************************** + +#include "CLayla.h" + + +/**************************************************************************** + + Construction and destruction + + ****************************************************************************/ + +//=========================================================================== +// +// Overload new & delete so memory for this object is allocated +// from non-paged memory. +// +//=========================================================================== + +PVOID CLayla::operator new( size_t Size ) +{ + PVOID pMemory; + ECHOSTATUS Status; + + Status = OsAllocateNonPaged(Size,&pMemory); + + if ( (ECHOSTATUS_OK != Status) || (NULL == pMemory )) + { + ECHO_DEBUGPRINTF(("CLayla::operator new - memory allocation failed\n")); + + pMemory = NULL; + } + else + { + memset( pMemory, 0, Size ); + } + + return pMemory; + +} // PVOID CLayla::operator new( size_t Size ) + + +VOID CLayla::operator delete( PVOID pVoid ) +{ + if ( ECHOSTATUS_OK != OsFreeNonPaged( pVoid ) ) + { + ECHO_DEBUGPRINTF( ("CLayla::operator delete memory free failed\n") ); + } +} // VOID CLayla::operator delete( PVOID pVoid ) + + +//=========================================================================== +// +// Constructor and destructor +// +//=========================================================================== + +CLayla::CLayla( PCOsSupport pOsSupport ) + : CEchoGals( pOsSupport ) +{ + ECHO_DEBUGPRINTF( ( "CLayla::CLayla() is born!\n" ) ); +} // CLayla::CLayla() + + +CLayla::~CLayla() +{ + ECHO_DEBUGPRINTF( ( "CLayla::~CLayla() is toast!\n" ) ); +} // CLayla::~CLayla() + + + + +/**************************************************************************** + + Setup and hardware initialization + + ****************************************************************************/ + +//=========================================================================== +// +// Every card has an InitHw method +// +//=========================================================================== + +ECHOSTATUS CLayla::InitHw() +{ + ECHOSTATUS Status; + WORD i; + + // + // Call the base method + // + if ( ECHOSTATUS_OK != ( Status = CEchoGals::InitHw() ) ) + return Status; + + // + // Create the DSP comm object + // + ASSERT( NULL == m_pDspCommObject ); + m_pDspCommObject = new CLaylaDspCommObject( (PDWORD) m_pvSharedMemory, + m_pOsSupport ); + if (NULL == m_pDspCommObject) + { + ECHO_DEBUGPRINTF(("CLayla::InitHw - could not create DSP comm object\n")); + return ECHOSTATUS_NO_MEM; + } + + // + // Load the DSP and the external box ASIC + // + GetDspCommObject()->LoadFirmware(); + if ( GetDspCommObject()->IsBoardBad() ) + return ECHOSTATUS_DSP_DEAD; + + // + // Clear the "bad board" flag; set the flag to indicate that + // Darla24 can handle super-interleave. + // + m_wFlags &= ~ECHOGALS_FLAG_BADBOARD; + m_wFlags |= ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK; + + // + // Must call this here after DSP is init to + // init gains and mutes + // + Status = InitLineLevels(); + if ( ECHOSTATUS_OK != Status ) + return Status; + + // + // Initialize the MIDI input + // + Status = m_MidiIn.Init( this ); + if ( ECHOSTATUS_OK != Status ) + return Status; + + // + // Set defaults for +4/-10 + // + for (i = 0; i < GetFirstDigitalBusOut(); i++ ) + { + GetDspCommObject()->SetNominalLevel( i, TRUE ); // TRUE is -10 here + } + for ( i = 0; i < GetFirstDigitalBusIn(); i++ ) + { + GetDspCommObject()->SetNominalLevel( GetNumBussesOut() + i, TRUE ); + } + + // + // Set the S/PDIF output format to "professional" + // + SetProfessionalSpdif( TRUE ); + + // + // Get default sample rate from DSP + // + m_dwSampleRate = GetDspCommObject()->GetSampleRate(); + ECHO_DEBUGPRINTF( ( "CLayla::InitHw()\n" ) ); + + return Status; + +} // ECHOSTATUS CLayla::InitHw() + + + + +/**************************************************************************** + + Informational methods + + ****************************************************************************/ + +//=========================================================================== +// +// Override GetCapabilities to enumerate unique capabilties for Layla20 +// +//=========================================================================== + +ECHOSTATUS CLayla::GetCapabilities +( + PECHOGALS_CAPS pCapabilities +) +{ + ECHOSTATUS Status; + WORD i; + + Status = GetBaseCapabilities(pCapabilities); + + // + // Add input gain and nominal level to input busses + // + for (i = 0; i < GetFirstDigitalBusIn(); i++) + { + pCapabilities->dwBusInCaps[i] |= ECHOCAPS_GAIN | + ECHOCAPS_MUTE | + ECHOCAPS_NOMINAL_LEVEL; + } + + // + // Add nominal levels to output busses + // + for (i = 0; i < GetFirstDigitalBusOut(); i++) + { + pCapabilities->dwBusOutCaps[i] |= ECHOCAPS_NOMINAL_LEVEL; + } + + if ( ECHOSTATUS_OK != Status ) + return Status; + + pCapabilities->dwInClockTypes |= ECHO_CLOCK_BIT_WORD | + ECHO_CLOCK_BIT_SUPER | + ECHO_CLOCK_BIT_SPDIF; + + pCapabilities->dwOutClockTypes |= ECHO_CLOCK_BIT_WORD | + ECHO_CLOCK_BIT_SUPER; + + return Status; + +} // ECHOSTATUS CLayla::GetCapabilities + + +//=========================================================================== +// +// QueryAudioSampleRate is used to find out if this card can handle a +// given sample rate. +// +//=========================================================================== + +ECHOSTATUS CLayla::QueryAudioSampleRate +( + DWORD dwSampleRate +) +{ + if ( dwSampleRate < 8000 || + dwSampleRate > 50000 ) + { + ECHO_DEBUGPRINTF( + ("CLayla::QueryAudioSampleRate() Sample rate must be >= 8,000 Hz" + " and <= 50,000 Hz\n") ); + return ECHOSTATUS_BAD_FORMAT; + } + ECHO_DEBUGPRINTF( ( "CLayla::QueryAudioSampleRate() %ld Hz OK\n", + dwSampleRate ) ); + return ECHOSTATUS_OK; + +} // ECHOSTATUS CLayla::QueryAudioSampleRate + + +//=========================================================================== +// +// GetInputClockDetect returns a bitmask consisting of all the input +// clocks currently connected to the hardware; this changes as the user +// connects and disconnects clock inputs. +// +// You should use this information to determine which clocks the user is +// allowed to select. +// +// Layla20 supports S/PDIF clock, word clock, and super clock. +// +//=========================================================================== + +ECHOSTATUS CLayla::GetInputClockDetect(DWORD &dwClockDetectBits) +{ + if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) + { + ECHO_DEBUGPRINTF( ("CLayla::GetInputClockDetect: DSP Dead!\n") ); + return ECHOSTATUS_DSP_DEAD; + } + + DWORD dwClocksFromDsp = GetDspCommObject()->GetInputClockDetect(); + + dwClockDetectBits = ECHO_CLOCK_BIT_INTERNAL; + + if (0 != (dwClocksFromDsp & GLDM_CLOCK_DETECT_BIT_SPDIF)) + dwClockDetectBits |= ECHO_CLOCK_BIT_SPDIF; + + if (0 != (dwClocksFromDsp & GLDM_CLOCK_DETECT_BIT_WORD)) + { + if (0 != (dwClocksFromDsp & GLDM_CLOCK_DETECT_BIT_SUPER)) + dwClockDetectBits |= ECHO_CLOCK_BIT_SUPER; + else + dwClockDetectBits |= ECHO_CLOCK_BIT_WORD; + } + + return ECHOSTATUS_OK; + +} // GetInputClockDetect + + +// *** CLayla.cpp *** diff --git a/src/add-ons/kernel/drivers/audio/echo/generic/CLaylaDspCommObject.cpp b/src/add-ons/kernel/drivers/audio/echo/generic/CLaylaDspCommObject.cpp index 2d507afef8..4892744402 100644 --- a/src/add-ons/kernel/drivers/audio/echo/generic/CLaylaDspCommObject.cpp +++ b/src/add-ons/kernel/drivers/audio/echo/generic/CLaylaDspCommObject.cpp @@ -1,403 +1,403 @@ -// **************************************************************************** -// -// CLaylaDspCommObject.cpp -// -// Implementation file for EchoGals generic driver Layla DSP -// interface class. -// -// Copyright Echo Digital Audio Corporation (c) 1998 - 2002 -// All rights reserved -// www.echoaudio.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal with the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimers. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimers in the -// documentation and/or other materials provided with the distribution. -// -// - Neither the name of Echo Digital Audio, nor the names of its -// contributors may be used to endorse or promote products derived from -// this Software without specific prior written permission. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR -// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -// SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. -// -// **************************************************************************** - -#include "CEchoGals.h" -#include "CLaylaDspCommObject.h" - -#include "Layla20DSP.c" -#include "LaylaAsic.c" - -// -// The ASIC files for Layla20 are always this size -// -#define LAYLA_ASIC_SIZE 32385 - - -/**************************************************************************** - - Construction and destruction - - ****************************************************************************/ - -//=========================================================================== -// -// Constructor -// -//=========================================================================== - -CLaylaDspCommObject::CLaylaDspCommObject -( - PDWORD pdwRegBase, // Virtual ptr to DSP registers - PCOsSupport pOsSupport -) : CDspCommObject( pdwRegBase, pOsSupport ) -{ - strcpy( m_szCardName, "Layla" ); - m_pdwDspRegBase = pdwRegBase; // Virtual addr DSP's register base - - m_wNumPipesOut = 12; - m_wNumPipesIn = 10; - m_wNumBussesOut = 12; - m_wNumBussesIn = 10; - m_wFirstDigitalBusOut = 10; - m_wFirstDigitalBusIn = 8; - - m_fHasVmixer = FALSE; - - m_wNumMidiOut = 1; // # MIDI out channels - m_wNumMidiIn = 1; // # MIDI in channels - - m_bHasASIC = TRUE; - - m_pwDspCodeToLoad = pwLayla20DSP; - -} // CLaylaDspCommObject::CLaylaDspCommObject( DWORD dwPhysRegBase ) - - -//=========================================================================== -// -// Destructor -// -//=========================================================================== - -CLaylaDspCommObject::~CLaylaDspCommObject() -{ - ECHO_DEBUGPRINTF( ( "CLaylaDspCommObject::~CLaylaDspCommObject() is toast!\n" ) ); -} // CLaylaDspCommObject::~CLaylaDspCommObject() - - - - -/**************************************************************************** - - Hardware setup and config - - ****************************************************************************/ - -//=========================================================================== -// -// Layla20 has an ASIC in the external box -// -//=========================================================================== - -BOOL CLaylaDspCommObject::LoadASIC() -{ - if ( m_bASICLoaded == TRUE ) - return TRUE; - - if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA_ASIC, - pbLaylaASIC, - LAYLA_ASIC_SIZE ) ) - return FALSE; - // - // Check if ASIC is alive and well. - // - return( CheckAsicStatus() ); -} // BOOL CLaylaDspCommObject::LoadASIC() - - -//=========================================================================== -// -// SetSampleRate -// -// Set the sample rate for Layla -// -// Layla is simple; just send it the sampling rate (assuming that the clock -// mode is correct). -// -//=========================================================================== - -DWORD CLaylaDspCommObject::SetSampleRate( DWORD dwNewSampleRate ) -{ - // - // Only set the clock for internal mode - // Do not return failure, simply treat it as a non-event. - // - if ( GetInputClock() != ECHO_CLOCK_INTERNAL ) - { - ECHO_DEBUGPRINTF( ( "SetSampleRate: Cannot set sample rate because " - "Layla clock NOT set to CLK_CLOCKININTERNAL\n" ) ); - m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate ); - return GetSampleRate(); - } - - // - // Sanity check - check the sample rate - // - if ( ( dwNewSampleRate < 8000 ) || - ( dwNewSampleRate > 50000 ) ) - { - ECHO_DEBUGPRINTF( ( "SetSampleRate: Layla sample rate %d out of range, " - "no change made\n", - dwNewSampleRate) ); - return 0xffffffff; - } - - if ( !WaitForHandshake() ) - return 0xffffffff; - - m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate ); - - ClearHandshake(); - SendVector( DSP_VC_SET_LAYLA_SAMPLE_RATE ); - ECHO_DEBUGPRINTF( ( "SetSampleRate: Layla sample rate changed to %d\n", - dwNewSampleRate ) ); - return( dwNewSampleRate ); -} // DWORD CLaylaDspCommObject::SetSampleRate( DWORD dwNewSampleRate ) - - -//=========================================================================== -// -// Send new input clock setting to DSP -// -//=========================================================================== - -ECHOSTATUS CLaylaDspCommObject::SetInputClock(WORD wClock) -{ - BOOL bSetRate; - BOOL bWriteControlReg; - DWORD dwSampleRate; - WORD wNewClock; - - ECHO_DEBUGPRINTF( ( "CLaylaDspCommObject::SetInputClock:\n" ) ); - - bSetRate = FALSE; - - switch ( wClock ) - { - case ECHO_CLOCK_INTERNAL : - ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to INTERNAL\n" ) ); - - // If the sample rate is out of range for some reason, set it - // to a reasonable value. mattg - if ( ( GetSampleRate() < 8000 ) || - ( GetSampleRate() > 50000 ) ) - { - m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 ); - } - - bSetRate = TRUE; - wNewClock = LAYLA20_CLOCK_INTERNAL; - break; - - case ECHO_CLOCK_SPDIF: - ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to SPDIF\n" ) ); - - wNewClock = LAYLA20_CLOCK_SPDIF; - break; - - case ECHO_CLOCK_WORD: - ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to WORD\n" ) ); - - wNewClock = LAYLA20_CLOCK_WORD; - - break; - - case ECHO_CLOCK_SUPER: - ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to SUPER\n" ) ); - - wNewClock = LAYLA20_CLOCK_SUPER; - - break; - - default : - ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Layla24\n")); - ECHO_DEBUGBREAK(); - return ECHOSTATUS_CLOCK_NOT_SUPPORTED; - - } // switch (wClock) - - // - // Winner! Save the new input clock. - // - m_wInputClock = wClock; - - // - // Send the new clock to the DSP - // - m_pDspCommPage->wInputClock = SWAP(wNewClock); - ClearHandshake(); - SendVector( DSP_VC_UPDATE_CLOCKS ); - - if ( bSetRate ) - SetSampleRate(); - - return ECHOSTATUS_OK; -} // ECHOSTATUS CLaylaDspCommObject::SetInputClock() - - -//=========================================================================== -// -// Set new output clock -// -//=========================================================================== - -ECHOSTATUS CLaylaDspCommObject::SetOutputClock(WORD wClock) -{ - if (FALSE == m_bASICLoaded) - return ECHOSTATUS_ASIC_NOT_LOADED; - - if (!WaitForHandshake()) - return ECHOSTATUS_DSP_DEAD; - - ECHO_DEBUGPRINTF( ("CDspCommObject::SetOutputClock:\n") ); - - m_pDspCommPage->wOutputClock = SWAP(wClock); - m_wOutputClock = wClock; - - ClearHandshake(); - ECHOSTATUS Status = SendVector(DSP_VC_UPDATE_CLOCKS); - - return Status; -} // ECHOSTATUS CLaylaDspCommObject::SetOutputClock - - -//=========================================================================== -// -// Detect MIDI output activity -// -//=========================================================================== - -BOOL CLaylaDspCommObject::IsMidiOutActive() -{ - ULONGLONG ullCurTime; - - m_pOsSupport->OsGetSystemTime( &ullCurTime ); - return( ( ( ullCurTime - m_ullMidiOutTime ) > MIDI_ACTIVITY_TIMEOUT_USEC ) ? FALSE : TRUE ); -} // BOOL CLaylaDspCommObject::IsMidiOutActive() - - -//=========================================================================== -// -// Input bus gain - iGain is in units of .5 dB -// -//=========================================================================== - -ECHOSTATUS CLaylaDspCommObject::SetBusInGain( WORD wBusIn, int iGain) -{ - // - // Store the gain for later use - // - m_byInputTrims[wBusIn] = (BYTE) iGain; - - // - // Adjust the input gain depending on the nominal level switch - // - BYTE byMinus10; - GetNominalLevel( wBusIn + m_wNumBussesOut, &byMinus10); - - if (0 == byMinus10) - { - // - // This channel is in +4 mode; subtract 12 dB from the input gain - // (note that iGain is in units of .5 dB) - // - iGain -= 12 << 1; - } - - return CDspCommObject::SetBusInGain(wBusIn,iGain); - -} - -ECHOSTATUS CLaylaDspCommObject::GetBusInGain( WORD wBusIn, int &iGain) -{ - ECHOSTATUS Status; - - if (wBusIn > m_wNumBussesIn) - return ECHOSTATUS_INVALID_CHANNEL; - - iGain = (int) m_byInputTrims[wBusIn]; - - return ECHOSTATUS_OK; -} - - -//=========================================================================== -// -// Set the nominal level for an input or output bus -// -// Set bState to TRUE for -10, FALSE for +4 -// -// Layla20 sets the input nominal level by adjusting the -// input trim -// -//=========================================================================== - -ECHOSTATUS CLaylaDspCommObject::SetNominalLevel -( - WORD wBus, - BOOL bState -) -{ - if (wBus < m_wNumBussesOut) - { - // - // This is an output bus; call the base class routine to service it - // - return CDspCommObject::SetNominalLevel(wBus,bState); - } - - // - // Check the bus number - // - if (wBus < (m_wNumBussesOut + m_wNumBussesIn)) - { - // - // Set the nominal bit in the comm page - // - if ( bState ) - m_pDspCommPage->cmdNominalLevel.SetIndexInMask( wBus ); - else - m_pDspCommPage->cmdNominalLevel.ClearIndexInMask( wBus ); - - // - // Set the input trim, using the current gain - // - return SetBusInGain(wBus - m_wNumBussesOut,(int) m_byInputTrims[wBus]); - } - - ECHO_DEBUGPRINTF( ("CLaylaDspCommObject::SetNominalOutLineLevel Invalid " - "index %d\n", - wBus ) ); - return ECHOSTATUS_INVALID_CHANNEL; - -} // ECHOSTATUS CLaylaDspCommObject::SetNominalLevel - - -// **** LaylaDspCommObject.cpp **** +// **************************************************************************** +// +// CLaylaDspCommObject.cpp +// +// Implementation file for EchoGals generic driver Layla DSP +// interface class. +// +// Copyright Echo Digital Audio Corporation (c) 1998 - 2002 +// All rights reserved +// www.echoaudio.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal with the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimers. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimers in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of Echo Digital Audio, nor the names of its +// contributors may be used to endorse or promote products derived from +// this Software without specific prior written permission. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR +// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. +// +// **************************************************************************** + +#include "CEchoGals.h" +#include "CLaylaDspCommObject.h" + +#include "Layla20DSP.c" +#include "LaylaAsic.c" + +// +// The ASIC files for Layla20 are always this size +// +#define LAYLA_ASIC_SIZE 32385 + + +/**************************************************************************** + + Construction and destruction + + ****************************************************************************/ + +//=========================================================================== +// +// Constructor +// +//=========================================================================== + +CLaylaDspCommObject::CLaylaDspCommObject +( + PDWORD pdwRegBase, // Virtual ptr to DSP registers + PCOsSupport pOsSupport +) : CDspCommObject( pdwRegBase, pOsSupport ) +{ + strcpy( m_szCardName, "Layla" ); + m_pdwDspRegBase = pdwRegBase; // Virtual addr DSP's register base + + m_wNumPipesOut = 12; + m_wNumPipesIn = 10; + m_wNumBussesOut = 12; + m_wNumBussesIn = 10; + m_wFirstDigitalBusOut = 10; + m_wFirstDigitalBusIn = 8; + + m_fHasVmixer = FALSE; + + m_wNumMidiOut = 1; // # MIDI out channels + m_wNumMidiIn = 1; // # MIDI in channels + + m_bHasASIC = TRUE; + + m_pwDspCodeToLoad = pwLayla20DSP; + +} // CLaylaDspCommObject::CLaylaDspCommObject( DWORD dwPhysRegBase ) + + +//=========================================================================== +// +// Destructor +// +//=========================================================================== + +CLaylaDspCommObject::~CLaylaDspCommObject() +{ + ECHO_DEBUGPRINTF( ( "CLaylaDspCommObject::~CLaylaDspCommObject() is toast!\n" ) ); +} // CLaylaDspCommObject::~CLaylaDspCommObject() + + + + +/**************************************************************************** + + Hardware setup and config + + ****************************************************************************/ + +//=========================================================================== +// +// Layla20 has an ASIC in the external box +// +//=========================================================================== + +BOOL CLaylaDspCommObject::LoadASIC() +{ + if ( m_bASICLoaded == TRUE ) + return TRUE; + + if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA_ASIC, + pbLaylaASIC, + LAYLA_ASIC_SIZE ) ) + return FALSE; + // + // Check if ASIC is alive and well. + // + return( CheckAsicStatus() ); +} // BOOL CLaylaDspCommObject::LoadASIC() + + +//=========================================================================== +// +// SetSampleRate +// +// Set the sample rate for Layla +// +// Layla is simple; just send it the sampling rate (assuming that the clock +// mode is correct). +// +//=========================================================================== + +DWORD CLaylaDspCommObject::SetSampleRate( DWORD dwNewSampleRate ) +{ + // + // Only set the clock for internal mode + // Do not return failure, simply treat it as a non-event. + // + if ( GetInputClock() != ECHO_CLOCK_INTERNAL ) + { + ECHO_DEBUGPRINTF( ( "SetSampleRate: Cannot set sample rate because " + "Layla clock NOT set to CLK_CLOCKININTERNAL\n" ) ); + m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate ); + return GetSampleRate(); + } + + // + // Sanity check - check the sample rate + // + if ( ( dwNewSampleRate < 8000 ) || + ( dwNewSampleRate > 50000 ) ) + { + ECHO_DEBUGPRINTF( ( "SetSampleRate: Layla sample rate %ld out of range, " + "no change made\n", + dwNewSampleRate) ); + return 0xffffffff; + } + + if ( !WaitForHandshake() ) + return 0xffffffff; + + m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate ); + + ClearHandshake(); + SendVector( DSP_VC_SET_LAYLA_SAMPLE_RATE ); + ECHO_DEBUGPRINTF( ( "SetSampleRate: Layla sample rate changed to %ld\n", + dwNewSampleRate ) ); + return( dwNewSampleRate ); +} // DWORD CLaylaDspCommObject::SetSampleRate( DWORD dwNewSampleRate ) + + +//=========================================================================== +// +// Send new input clock setting to DSP +// +//=========================================================================== + +ECHOSTATUS CLaylaDspCommObject::SetInputClock(WORD wClock) +{ + BOOL bSetRate; + //BOOL bWriteControlReg; + //DWORD dwSampleRate; + WORD wNewClock; + + ECHO_DEBUGPRINTF( ( "CLaylaDspCommObject::SetInputClock:\n" ) ); + + bSetRate = FALSE; + + switch ( wClock ) + { + case ECHO_CLOCK_INTERNAL : + ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to INTERNAL\n" ) ); + + // If the sample rate is out of range for some reason, set it + // to a reasonable value. mattg + if ( ( GetSampleRate() < 8000 ) || + ( GetSampleRate() > 50000 ) ) + { + m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 ); + } + + bSetRate = TRUE; + wNewClock = LAYLA20_CLOCK_INTERNAL; + break; + + case ECHO_CLOCK_SPDIF: + ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to SPDIF\n" ) ); + + wNewClock = LAYLA20_CLOCK_SPDIF; + break; + + case ECHO_CLOCK_WORD: + ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to WORD\n" ) ); + + wNewClock = LAYLA20_CLOCK_WORD; + + break; + + case ECHO_CLOCK_SUPER: + ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to SUPER\n" ) ); + + wNewClock = LAYLA20_CLOCK_SUPER; + + break; + + default : + ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Layla24\n", wClock)); + ECHO_DEBUGBREAK(); + return ECHOSTATUS_CLOCK_NOT_SUPPORTED; + + } // switch (wClock) + + // + // Winner! Save the new input clock. + // + m_wInputClock = wClock; + + // + // Send the new clock to the DSP + // + m_pDspCommPage->wInputClock = SWAP(wNewClock); + ClearHandshake(); + SendVector( DSP_VC_UPDATE_CLOCKS ); + + if ( bSetRate ) + SetSampleRate(); + + return ECHOSTATUS_OK; +} // ECHOSTATUS CLaylaDspCommObject::SetInputClock() + + +//=========================================================================== +// +// Set new output clock +// +//=========================================================================== + +ECHOSTATUS CLaylaDspCommObject::SetOutputClock(WORD wClock) +{ + if (FALSE == m_bASICLoaded) + return ECHOSTATUS_ASIC_NOT_LOADED; + + if (!WaitForHandshake()) + return ECHOSTATUS_DSP_DEAD; + + ECHO_DEBUGPRINTF( ("CDspCommObject::SetOutputClock:\n") ); + + m_pDspCommPage->wOutputClock = SWAP(wClock); + m_wOutputClock = wClock; + + ClearHandshake(); + ECHOSTATUS Status = SendVector(DSP_VC_UPDATE_CLOCKS); + + return Status; +} // ECHOSTATUS CLaylaDspCommObject::SetOutputClock + + +//=========================================================================== +// +// Detect MIDI output activity +// +//=========================================================================== + +BOOL CLaylaDspCommObject::IsMidiOutActive() +{ + ULONGLONG ullCurTime; + + m_pOsSupport->OsGetSystemTime( &ullCurTime ); + return( ( ( ullCurTime - m_ullMidiOutTime ) > MIDI_ACTIVITY_TIMEOUT_USEC ) ? FALSE : TRUE ); +} // BOOL CLaylaDspCommObject::IsMidiOutActive() + + +//=========================================================================== +// +// Input bus gain - iGain is in units of .5 dB +// +//=========================================================================== + +ECHOSTATUS CLaylaDspCommObject::SetBusInGain( WORD wBusIn, int iGain) +{ + // + // Store the gain for later use + // + m_byInputTrims[wBusIn] = (BYTE) iGain; + + // + // Adjust the input gain depending on the nominal level switch + // + BYTE byMinus10; + GetNominalLevel( wBusIn + m_wNumBussesOut, &byMinus10); + + if (0 == byMinus10) + { + // + // This channel is in +4 mode; subtract 12 dB from the input gain + // (note that iGain is in units of .5 dB) + // + iGain -= 12 << 1; + } + + return CDspCommObject::SetBusInGain(wBusIn,iGain); + +} + +ECHOSTATUS CLaylaDspCommObject::GetBusInGain( WORD wBusIn, int &iGain) +{ + //ECHOSTATUS Status; + + if (wBusIn > m_wNumBussesIn) + return ECHOSTATUS_INVALID_CHANNEL; + + iGain = (int) m_byInputTrims[wBusIn]; + + return ECHOSTATUS_OK; +} + + +//=========================================================================== +// +// Set the nominal level for an input or output bus +// +// Set bState to TRUE for -10, FALSE for +4 +// +// Layla20 sets the input nominal level by adjusting the +// input trim +// +//=========================================================================== + +ECHOSTATUS CLaylaDspCommObject::SetNominalLevel +( + WORD wBus, + BOOL bState +) +{ + if (wBus < m_wNumBussesOut) + { + // + // This is an output bus; call the base class routine to service it + // + return CDspCommObject::SetNominalLevel(wBus,bState); + } + + // + // Check the bus number + // + if (wBus < (m_wNumBussesOut + m_wNumBussesIn)) + { + // + // Set the nominal bit in the comm page + // + if ( bState ) + m_pDspCommPage->cmdNominalLevel.SetIndexInMask( wBus ); + else + m_pDspCommPage->cmdNominalLevel.ClearIndexInMask( wBus ); + + // + // Set the input trim, using the current gain + // + return SetBusInGain(wBus - m_wNumBussesOut,(int) m_byInputTrims[wBus]); + } + + ECHO_DEBUGPRINTF( ("CLaylaDspCommObject::SetNominalOutLineLevel Invalid " + "index %d\n", + wBus ) ); + return ECHOSTATUS_INVALID_CHANNEL; + +} // ECHOSTATUS CLaylaDspCommObject::SetNominalLevel + + +// **** LaylaDspCommObject.cpp **** diff --git a/src/add-ons/kernel/drivers/audio/echo/generic/MixerXface.h b/src/add-ons/kernel/drivers/audio/echo/generic/MixerXface.h index d65ffec276..ebc581bcd8 100644 --- a/src/add-ons/kernel/drivers/audio/echo/generic/MixerXface.h +++ b/src/add-ons/kernel/drivers/audio/echo/generic/MixerXface.h @@ -1,348 +1,347 @@ -// **************************************************************************** -// -// MixerXface.H -// -// Include file for mixer interfacing with the EchoGals-derived classes. -// -// Set editor tabs to 3 for your viewing pleasure. -// -// ---------------------------------------------------------------------------- -// -// Copyright Echo Digital Audio Corporation (c) 1998 - 2002 -// All rights reserved -// www.echoaudio.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal with the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimers. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimers in the -// documentation and/or other materials provided with the distribution. -// -// - Neither the name of Echo Digital Audio, nor the names of its -// contributors may be used to endorse or promote products derived from -// this Software without specific prior written permission. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR -// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -// SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. -// -// **************************************************************************** - -// Prevent problems with multiple includes -#ifndef _MIXERXFACE_ -#define _MIXERXFACE_ - -#include "EchoGalsXface.h" - -// -// Gain ranges -// -#define ECHOGAIN_MUTED DSP_TO_GENERIC(-128) // Minimum possible gain -#define ECHOGAIN_MINOUT DSP_TO_GENERIC(-128) // Min output gain in dB -#define ECHOGAIN_MAXOUT DSP_TO_GENERIC(6) // Max output gain in dB -#define ECHOGAIN_MININP DSP_TO_GENERIC(-25) // Min input gain in dB -#define ECHOGAIN_MAXINP DSP_TO_GENERIC(25) // Max input gain in dB - -#define ECHOGAIN_UPDATE 0xAAAAAA // Using this value means: - // Re-set the gain - // to the DSP using the - // currently stored value. - - -//============================================================================= -// -// Most of the mixer functions have been unified into a single interface; -// you pass either a single MIXER_FUNCTION struct or an array of MIXER_FUNCTION -// structs. Each MIXER_FUNCTION is generally used to set or get one or more -// values. -// -//============================================================================= - -// -// Structure to specify a bus, pipe, or a monitor being routed from -// the input to the output -// -enum ECHO_CHANNEL_TYPES -{ - ECHO_BUS_OUT = 0, - ECHO_BUS_IN, - ECHO_PIPE_OUT, - ECHO_PIPE_IN, - ECHO_MONITOR, - ECHO_NO_CHANNEL_TYPE = 0xffff, - ECHO_CHANNEL_UNUSED = 0xffff -}; - -typedef struct tMIXER_AUDIO_CHANNEL -{ - WORD wCardId; // This field is obsolete - WORD wChannel; // channel index - DWORD dwType; // One of the above enums -} MIXER_AUDIO_CHANNEL, *PMIXER_AUDIO_CHANNEL; - - -// -// Output pipe control change -// -typedef struct -{ - WORD wBusOut; // For cards without vmixer, should - // be the same as wChannel in MIXER_AUDIO_CHANNEL - union - { - INT32 iLevel; // New gain in dB X 256 - INT32 iPan; // 0 <= new pan <= MAX_MIXER_PAN, - // 0 = full left MAX_MIXER_PAN = full right - BOOL bMuteOn; // To mute or not to mute - // MXF_GET_MONITOR_MUTE & - // MXF_SET_MONITOR_MUTE - - } Data; -} MIXER_PIPE_OUT, PMIXER_PIPE_OUT; - - -// -// The MIXER_AUDIO_CHANNEL header has the card and input channel. -// This structure has the output channel and the gain, mute or pan -// state for one monitor. -// -typedef struct tMIXER_MONITOR -{ - WORD wBusOut; - union - { - INT32 iLevel; // New gain in dB X 256 - INT32 iPan; // 0 <= new pan <= MAX_MIXER_PAN, - // 0 = full left MAX_MIXER_PAN = full right - BOOL bMuteOn; // To mute or not to mute - // MXF_GET_MONITOR_MUTE & - // MXF_SET_MONITOR_MUTE - } Data; -} MIXER_MONITOR, *PMIXER_MONITOR; - - -// -// Mixer Function Tags -// -// These codes are used to specify the mixer function you want to perform; -// they determine which field in the Data union to use -// -#define MXF_GET_CAPS 1 // Get card capabilities -#define MXF_GET_LEVEL 2 // Get level for one channel -#define MXF_SET_LEVEL 3 // Set level for one channel -#define MXF_GET_NOMINAL 4 // Get nominal level for one channel -#define MXF_SET_NOMINAL 5 // Set nominal level for one channel -#define MXF_GET_MONITOR 6 // Get monitor for one channel -#define MXF_SET_MONITOR 7 // Set monitor for one channel -#define MXF_GET_INPUT_CLOCK 8 // Get input clock -#define MXF_SET_INPUT_CLOCK 9 // Set input clock for one card -#define MXF_GET_METERS 10 // Get meters for all channels on one card -#define MXF_GET_METERS_ON 11 // Get meters on state for one card -#define MXF_SET_METERS_ON 12 // Set meters on state for one card - // Meters must only be enabled while - // driver for card exists; the meters are - // written via bus mastering directly to memory -#define MXF_GET_PROF_SPDIF 13 // Get Professional or consumer S/PDIF mode - // for one card -#define MXF_SET_PROF_SPDIF 14 // Set Professional or consumer S/PDIF mode - // for one card -#define MXF_GET_MUTE 15 // Get mute state for one channel -#define MXF_SET_MUTE 16 // Set mute state for one channel -#define MXF_GET_MONITOR_MUTE 19 // Get monitor mute state for one channel -#define MXF_SET_MONITOR_MUTE 20 // Set monitor mute state for one channel -#define MXF_GET_MONITOR_PAN 23 // Get monitor pan value for one stereo channel -#define MXF_SET_MONITOR_PAN 24 // Set monitor pan value for one stereo channel -#define MXF_GET_FLAGS 27 // Get driver flags. i.e. S/PDIF no - // dither mode -#define MXF_SET_FLAGS 28 // Set driver flag. i.e. S/PDIF no - // dither mode -#define MXF_CLEAR_FLAGS 29 // Clear driver flag. i.e. S/PDIF no - // dither mode for one card -#define MXF_GET_SAMPLERATE_LOCK 30 // Get locked sample rate for one card -#define MXF_SET_SAMPLERATE_LOCK 31 // Set locked sample rate for one card -#define MXF_GET_SAMPLERATE 32 // Get actual sample rate for one card -#define MXF_GET_MIDI_IN_ACTIVITY 35 // Get MIDI in activity state -#define MXF_GET_MIDI_OUT_ACTIVITY 36 // Get MIDI out activity state -#define MXF_GET_DIGITAL_MODE 37 // Get digital mode -#define MXF_SET_DIGITAL_MODE 38 // Get digital mode - -#define MXF_GET_PAN 39 // Get & set pan -#define MXF_SET_PAN 40 -#define MXF_GET_OUTPUT_CLOCK 41 // Get output clock -#define MXF_SET_OUTPUT_CLOCK 42 // Set output clock for one card -#define MXF_GET_CLOCK_DETECT 43 // Get the currently detected clocks -#define MXF_GET_DIG_IN_AUTO_MUTE 44 // Get the state of the digital input auto-mute -#define MXF_SET_DIG_IN_AUTO_MUTE 45 // Set the state of the digital input auto-mute - -// -// Mixer Function Data Structure -// -typedef struct tMIXER_FUNCTION -{ - MIXER_AUDIO_CHANNEL Channel; // Which channel to service - INT32 iFunction; // What function to do - ECHOSTATUS RtnStatus; // Return Result - union - { - ECHOGALS_CAPS Capabilities; // MXF_GET_CAPS - INT32 iNominal; // MXF_GET_NOMINAL & MXF_SET_NOMINAL - INT32 iLevel; // MXF_GET_LEVEL & MXF_SET_LEVEL - MIXER_MONITOR Monitor; // MXF_GET_MONITOR & MXF_SET_MONITOR - // MXF_GET_MONITOR_MUTE & MXF_SET_MONITOR_MUTE - // MXF_GET_MONITOR_PAN & MXF_SET_MONITOR_PAN - WORD wClock; // MXF_GET_INPUT_CLOCK & MXF_SET_INPUT_CLOCK - // MXF_GET_OUTPUT_CLOCK & MXF_SET_OUTPUT_CLOCK - DWORD dwClockDetectBits; - // MXF_GET_CLOCK_DETECTs - ECHOGALS_METERS Meters; // MXF_GET_METERS - BOOL bMetersOn; // MXF_GET_METERS_ON & - // MXF_SET_METERS_ON - BOOL bProfSpdif; // MXF_GET_PROF_SPDIF & - // MXF_SET_PROF_SPDIF - BOOL bMuteOn; // MXF_GET_MUTE & MXF_SET_MUTE - BOOL bNotifyOn; // MXF_GET_NOTIFY_ON & - // MXF_SET_NOTIFY_ON - WORD wFlags; // MXF_GET_FLAGS, MXF_SET_FLAGS & - // MXF_CLEAR_FLAGS (See - // ECHOGALS_FLAG_??? in file - // EchoGalsXface.h) - DWORD dwLockedSampleRate; - // MXF_GET_SAMPLERATE_LOCK & - // MXF_SET_SAMPLERATE_LOCK - DWORD dwSampleRate; // MXF_GET_SAMPLERATE - BOOL bMidiActive; // MXF_GET_MIDI_IN_ACTIVITY & - // MXF_GET_MIDI_OUT_ACTIVITY - INT32 iDigMode; // MXF_GET_DIGITAL_MODE & - // MXF_SET_DIGITAL_MODE - - MIXER_PIPE_OUT PipeOut; // MXF_GET_LEVEL & MXF_SET_LEVEL - // MXF_GET_MUTE & MXF_SET_MUTE - // MXF_GET_PAN & MXF_SET_PAN - - BOOL fDigitalInAutoMute; // MXF_GET_DIG_IN_AUTO_MUTE - // MXF_SET_DIG_IN_AUTO_MUTE - } Data; -} MIXER_FUNCTION, *PMIXER_FUNCTION; - -// -// Mixer Multifunction Interface -// -// Allow user to supply an array of commands to be performed in one call. -// Since this is a variable length structure, user beware! -// -typedef struct tMIXER_MULTI_FUNCTION -{ - INT32 iCount; - MIXER_FUNCTION MixerFunction[ 1 ]; -} MIXER_MULTI_FUNCTION, *PMIXER_MULTI_FUNCTION; - -// -// Use this macro to size the data structure -// -#define ComputeMixerMultiFunctionSize(Ct) \ - ( sizeof( MIXER_MULTI_FUNCTION ) + ( sizeof( MIXER_FUNCTION ) * ( Ct - 1 ) ) ) - - -// -// Notification -// -// Mixers allow for notification whenever a change occurs. -// Mixer notify structure contains channel and parameter(s) that -// changed. -// - -// -// Mixer Parameter Changed definitions -// -#define MXN_LEVEL 0 // Level changed -#define MXN_NOMINAL 1 // Nominal level changed -#define MXN_INPUT_CLOCK 2 // Input clock changed -#define MXN_SPDIF 3 // S/PDIF - Professional mode changed -#define MXN_MUTE 4 // Mute state changed -#define MXN_PAN 6 // Pan value changed - -#define MXN_FLAGS 12 // A driver flag changed. I.E. - // S/PDIF no dither state changed -#define MXN_DIGITAL_MODE 14 // Digital mode changed -#define MXN_OUTPUT_CLOCK 15 // Output clock changed -#define MXN_MAX 15 // Max notify parameters - -typedef struct tMIXER_NOTIFY -{ - WORD wType; // Same as enums used for MIXER_AUDIO_CHANNEL - - union - { - WORD wBusIn; - WORD wPipeIn; - WORD wPipeOut; - } u; - - WORD wBusOut; // For monitor & output pipe notifies only - WORD wParameter; // One of the above MXN_* - -} MIXER_NOTIFY, *PMIXER_NOTIFY; - - -typedef struct tMIXER_MULTI_NOTIFY -{ - DWORD dwCookie; - DWORD dwCount; // When passed to the generic driver, - // dwCount holds the size of the Notifies array. - // On returning from the driver, dwCount - // holds the number of entries in Notifies - // filled out by the generic driver. - MIXER_NOTIFY Notifies[1]; // Dynamic array; there are dwCount entries -} MIXER_MULTI_NOTIFY, *PMIXER_MULTI_NOTIFY; - -// -// Max pan value -// -#define MAX_MIXER_PAN 1000 // this is pan hard right - - -//============================================================================= -// -// After designing eighteen or nineteen consoles for this hardware, we've -// learned that it's useful to be able to get all the following stuff at -// once. Typically the console will run a timer that fetchs this periodically. -// -// dwCookie is the unique ID for the mixer client; this is obtained by calling -// CEchoGals::OpenMixer. The generic driver will maintain a separate notify -// queue for each client. -// -// Meters and dwClockDetectBits are exactly the same as you would get if you -// did each of those mixer functions separately. -// -// dwNumPendingNotifies is how many notifies are in the queue associated with -// the cookie. You can use this number to create an array of MIXER_NOTIFY -// structures and call CEchoGals::GetControlChanges. This way you only check -// for control changes if the controls have actually changed. -// -//============================================================================= - -typedef struct tECHO_POLLED_STUFF -{ - DWORD dwCookie; - ECHOGALS_METERS Meters; - DWORD dwClockDetectBits; - DWORD dwNumPendingNotifies; -} ECHO_POLLED_STUFF; - - -#endif - -// MixerXface.h +// **************************************************************************** +// +// MixerXface.H +// +// Include file for mixer interfacing with the EchoGals-derived classes. +// +// Set editor tabs to 3 for your viewing pleasure. +// +// ---------------------------------------------------------------------------- +// +// Copyright Echo Digital Audio Corporation (c) 1998 - 2002 +// All rights reserved +// www.echoaudio.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal with the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimers. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimers in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of Echo Digital Audio, nor the names of its +// contributors may be used to endorse or promote products derived from +// this Software without specific prior written permission. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR +// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. +// +// **************************************************************************** + +// Prevent problems with multiple includes +#ifndef _MIXERXFACE_ +#define _MIXERXFACE_ + +#include "EchoGalsXface.h" + +// +// Gain ranges +// +#define ECHOGAIN_MUTED DSP_TO_GENERIC(-128) // Minimum possible gain +#define ECHOGAIN_MINOUT DSP_TO_GENERIC(-128) // Min output gain in dB +#define ECHOGAIN_MAXOUT DSP_TO_GENERIC(6) // Max output gain in dB +#define ECHOGAIN_MININP DSP_TO_GENERIC(-25) // Min input gain in dB +#define ECHOGAIN_MAXINP DSP_TO_GENERIC(25) // Max input gain in dB + +#define ECHOGAIN_UPDATE 0xAAAAAA // Using this value means: + // Re-set the gain + // to the DSP using the + // currently stored value. + + +//============================================================================= +// +// Most of the mixer functions have been unified into a single interface; +// you pass either a single MIXER_FUNCTION struct or an array of MIXER_FUNCTION +// structs. Each MIXER_FUNCTION is generally used to set or get one or more +// values. +// +//============================================================================= + +// +// Structure to specify a bus, pipe, or a monitor being routed from +// the input to the output +// +enum ECHO_CHANNEL_TYPES +{ + ECHO_BUS_OUT = 0, + ECHO_BUS_IN, + ECHO_PIPE_OUT, + ECHO_PIPE_IN, + ECHO_MONITOR, + ECHO_NO_CHANNEL_TYPE = 0xffff, + ECHO_CHANNEL_UNUSED = 0xffff +}; + +typedef struct tMIXER_AUDIO_CHANNEL +{ + WORD wCardId; // This field is obsolete + WORD wChannel; // channel index + DWORD dwType; // One of the above enums +} MIXER_AUDIO_CHANNEL, *PMIXER_AUDIO_CHANNEL; + + +// +// Output pipe control change +// +typedef struct +{ + WORD wBusOut; // For cards without vmixer, should + // be the same as wChannel in MIXER_AUDIO_CHANNEL + union + { + INT32 iLevel; // New gain in dB X 256 + INT32 iPan; // 0 <= new pan <= MAX_MIXER_PAN, + // 0 = full left MAX_MIXER_PAN = full right + BOOL bMuteOn; // To mute or not to mute + // MXF_GET_MONITOR_MUTE & + // MXF_SET_MONITOR_MUTE + + } Data; +} MIXER_PIPE_OUT, PMIXER_PIPE_OUT; + + +// +// The MIXER_AUDIO_CHANNEL header has the card and input channel. +// This structure has the output channel and the gain, mute or pan +// state for one monitor. +// +typedef struct tMIXER_MONITOR +{ + WORD wBusOut; + union + { + INT32 iLevel; // New gain in dB X 256 + INT32 iPan; // 0 <= new pan <= MAX_MIXER_PAN, + // 0 = full left MAX_MIXER_PAN = full right + BOOL bMuteOn; // To mute or not to mute + // MXF_GET_MONITOR_MUTE & + // MXF_SET_MONITOR_MUTE + } Data; +} MIXER_MONITOR, *PMIXER_MONITOR; + + +// +// Mixer Function Tags +// +// These codes are used to specify the mixer function you want to perform; +// they determine which field in the Data union to use +// +#define MXF_GET_CAPS 1 // Get card capabilities +#define MXF_GET_LEVEL 2 // Get level for one channel +#define MXF_SET_LEVEL 3 // Set level for one channel +#define MXF_GET_NOMINAL 4 // Get nominal level for one channel +#define MXF_SET_NOMINAL 5 // Set nominal level for one channel +#define MXF_GET_MONITOR 6 // Get monitor for one channel +#define MXF_SET_MONITOR 7 // Set monitor for one channel +#define MXF_GET_INPUT_CLOCK 8 // Get input clock +#define MXF_SET_INPUT_CLOCK 9 // Set input clock for one card +#define MXF_GET_METERS 10 // Get meters for all channels on one card +#define MXF_GET_METERS_ON 11 // Get meters on state for one card +#define MXF_SET_METERS_ON 12 // Set meters on state for one card + // Meters must only be enabled while + // driver for card exists; the meters are + // written via bus mastering directly to memory +#define MXF_GET_PROF_SPDIF 13 // Get Professional or consumer S/PDIF mode + // for one card +#define MXF_SET_PROF_SPDIF 14 // Set Professional or consumer S/PDIF mode + // for one card +#define MXF_GET_MUTE 15 // Get mute state for one channel +#define MXF_SET_MUTE 16 // Set mute state for one channel +#define MXF_GET_MONITOR_MUTE 19 // Get monitor mute state for one channel +#define MXF_SET_MONITOR_MUTE 20 // Set monitor mute state for one channel +#define MXF_GET_MONITOR_PAN 23 // Get monitor pan value for one stereo channel +#define MXF_SET_MONITOR_PAN 24 // Set monitor pan value for one stereo channel +#define MXF_GET_FLAGS 27 // Get driver flags. i.e. S/PDIF no + // dither mode +#define MXF_SET_FLAGS 28 // Set driver flag. i.e. S/PDIF no + // dither mode +#define MXF_CLEAR_FLAGS 29 // Clear driver flag. i.e. S/PDIF no + // dither mode for one card +#define MXF_GET_SAMPLERATE_LOCK 30 // Get locked sample rate for one card +#define MXF_SET_SAMPLERATE_LOCK 31 // Set locked sample rate for one card +#define MXF_GET_SAMPLERATE 32 // Get actual sample rate for one card +#define MXF_GET_MIDI_IN_ACTIVITY 35 // Get MIDI in activity state +#define MXF_GET_MIDI_OUT_ACTIVITY 36 // Get MIDI out activity state +#define MXF_GET_DIGITAL_MODE 37 // Get digital mode +#define MXF_SET_DIGITAL_MODE 38 // Get digital mode + +#define MXF_GET_PAN 39 // Get & set pan +#define MXF_SET_PAN 40 +#define MXF_GET_OUTPUT_CLOCK 41 // Get output clock +#define MXF_SET_OUTPUT_CLOCK 42 // Set output clock for one card +#define MXF_GET_CLOCK_DETECT 43 // Get the currently detected clocks +#define MXF_GET_DIG_IN_AUTO_MUTE 44 // Get the state of the digital input auto-mute +#define MXF_SET_DIG_IN_AUTO_MUTE 45 // Set the state of the digital input auto-mute + +// +// Mixer Function Data Structure +// +typedef struct tMIXER_FUNCTION +{ + MIXER_AUDIO_CHANNEL Channel; // Which channel to service + INT32 iFunction; // What function to do + ECHOSTATUS RtnStatus; // Return Result + union + { + ECHOGALS_CAPS Capabilities; // MXF_GET_CAPS + INT32 iNominal; // MXF_GET_NOMINAL & MXF_SET_NOMINAL + INT32 iLevel; // MXF_GET_LEVEL & MXF_SET_LEVEL + MIXER_MONITOR Monitor; // MXF_GET_MONITOR & MXF_SET_MONITOR + // MXF_GET_MONITOR_MUTE & MXF_SET_MONITOR_MUTE + // MXF_GET_MONITOR_PAN & MXF_SET_MONITOR_PAN + WORD wClock; // MXF_GET_INPUT_CLOCK & MXF_SET_INPUT_CLOCK + // MXF_GET_OUTPUT_CLOCK & MXF_SET_OUTPUT_CLOCK + DWORD dwClockDetectBits; + // MXF_GET_CLOCK_DETECTs + ECHOGALS_METERS Meters; // MXF_GET_METERS + BOOL bMetersOn; // MXF_GET_METERS_ON & + // MXF_SET_METERS_ON + BOOL bProfSpdif; // MXF_GET_PROF_SPDIF & + // MXF_SET_PROF_SPDIF + BOOL bMuteOn; // MXF_GET_MUTE & MXF_SET_MUTE + BOOL bNotifyOn; // MXF_GET_NOTIFY_ON & + // MXF_SET_NOTIFY_ON + WORD wFlags; // MXF_GET_FLAGS, MXF_SET_FLAGS & + // MXF_CLEAR_FLAGS (See + // ECHOGALS_FLAG_??? in file + // EchoGalsXface.h) + DWORD dwLockedSampleRate; + // MXF_GET_SAMPLERATE_LOCK & + // MXF_SET_SAMPLERATE_LOCK + DWORD dwSampleRate; // MXF_GET_SAMPLERATE + BOOL bMidiActive; // MXF_GET_MIDI_IN_ACTIVITY & + // MXF_GET_MIDI_OUT_ACTIVITY + INT32 iDigMode; // MXF_GET_DIGITAL_MODE & + // MXF_SET_DIGITAL_MODE + + MIXER_PIPE_OUT PipeOut; // MXF_GET_LEVEL & MXF_SET_LEVEL + // MXF_GET_MUTE & MXF_SET_MUTE + // MXF_GET_PAN & MXF_SET_PAN + + BOOL fDigitalInAutoMute; // MXF_GET_DIG_IN_AUTO_MUTE + // MXF_SET_DIG_IN_AUTO_MUTE + } Data; +} MIXER_FUNCTION, *PMIXER_FUNCTION; + +// +// Mixer Multifunction Interface +// +// Allow user to supply an array of commands to be performed in one call. +// Since this is a variable length structure, user beware! +// +typedef struct tMIXER_MULTI_FUNCTION +{ + INT32 iCount; + MIXER_FUNCTION MixerFunction[ 1 ]; +} MIXER_MULTI_FUNCTION, *PMIXER_MULTI_FUNCTION; + +// +// Use this macro to size the data structure +// +#define ComputeMixerMultiFunctionSize(Ct) ( sizeof( MIXER_MULTI_FUNCTION ) + ( sizeof( MIXER_FUNCTION ) * ( Ct - 1 ) ) ) + + +// +// Notification +// +// Mixers allow for notification whenever a change occurs. +// Mixer notify structure contains channel and parameter(s) that +// changed. +// + +// +// Mixer Parameter Changed definitions +// +#define MXN_LEVEL 0 // Level changed +#define MXN_NOMINAL 1 // Nominal level changed +#define MXN_INPUT_CLOCK 2 // Input clock changed +#define MXN_SPDIF 3 // S/PDIF - Professional mode changed +#define MXN_MUTE 4 // Mute state changed +#define MXN_PAN 6 // Pan value changed + +#define MXN_FLAGS 12 // A driver flag changed. I.E. + // S/PDIF no dither state changed +#define MXN_DIGITAL_MODE 14 // Digital mode changed +#define MXN_OUTPUT_CLOCK 15 // Output clock changed +#define MXN_MAX 15 // Max notify parameters + +typedef struct tMIXER_NOTIFY +{ + WORD wType; // Same as enums used for MIXER_AUDIO_CHANNEL + + union + { + WORD wBusIn; + WORD wPipeIn; + WORD wPipeOut; + } u; + + WORD wBusOut; // For monitor & output pipe notifies only + WORD wParameter; // One of the above MXN_* + +} MIXER_NOTIFY, *PMIXER_NOTIFY; + + +typedef struct tMIXER_MULTI_NOTIFY +{ + DWORD dwCookie; + DWORD dwCount; // When passed to the generic driver, + // dwCount holds the size of the Notifies array. + // On returning from the driver, dwCount + // holds the number of entries in Notifies + // filled out by the generic driver. + MIXER_NOTIFY Notifies[1]; // Dynamic array; there are dwCount entries +} MIXER_MULTI_NOTIFY, *PMIXER_MULTI_NOTIFY; + +// +// Max pan value +// +#define MAX_MIXER_PAN 1000 // this is pan hard right + + +//============================================================================= +// +// After designing eighteen or nineteen consoles for this hardware, we've +// learned that it's useful to be able to get all the following stuff at +// once. Typically the console will run a timer that fetchs this periodically. +// +// dwCookie is the unique ID for the mixer client; this is obtained by calling +// CEchoGals::OpenMixer. The generic driver will maintain a separate notify +// queue for each client. +// +// Meters and dwClockDetectBits are exactly the same as you would get if you +// did each of those mixer functions separately. +// +// dwNumPendingNotifies is how many notifies are in the queue associated with +// the cookie. You can use this number to create an array of MIXER_NOTIFY +// structures and call CEchoGals::GetControlChanges. This way you only check +// for control changes if the controls have actually changed. +// +//============================================================================= + +typedef struct tECHO_POLLED_STUFF +{ + DWORD dwCookie; + ECHOGALS_METERS Meters; + DWORD dwClockDetectBits; + DWORD dwNumPendingNotifies; +} ECHO_POLLED_STUFF; + + +#endif + +// MixerXface.h diff --git a/src/add-ons/kernel/drivers/audio/echo/generic/OsSupportBeOS.cpp b/src/add-ons/kernel/drivers/audio/echo/generic/OsSupportBeOS.cpp index 79d6724432..81a0204636 100644 --- a/src/add-ons/kernel/drivers/audio/echo/generic/OsSupportBeOS.cpp +++ b/src/add-ons/kernel/drivers/audio/echo/generic/OsSupportBeOS.cpp @@ -47,10 +47,9 @@ // **************************************************************************** #include "CEchoGals.h" -#include -#include -#include -#include +#include +#include "queue.h" +#include "util.h" /**************************************************************************** @@ -66,18 +65,78 @@ //=========================================================================== DWORD gdwAllocNonPagedCount = 0; -rtm_pool * echo_pool = 0; + +typedef struct _echo_mem { + LIST_ENTRY(_echo_mem) next; + void *log_base; + void *phy_base; + area_id area; + size_t size; +} echo_mem; + +LIST_HEAD(, _echo_mem) mems; + + +static echo_mem * +echo_mem_new(size_t size) +{ + echo_mem *mem = NULL; + + if ((mem = (echo_mem*)malloc(sizeof(*mem))) == NULL) + return (NULL); + + mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "echo buffer"); + mem->size = size; + if (mem->area < B_OK) { + free(mem); + return NULL; + } + return mem; +} + +static void +echo_mem_delete(echo_mem *mem) +{ + if(mem->area > B_OK) + delete_area(mem->area); + free(mem); +} + +echo_mem * +echo_mem_alloc(size_t size) +{ + echo_mem *mem = NULL; + + mem = echo_mem_new(size); + if (mem == NULL) + return (NULL); + + LIST_INSERT_HEAD(&mems, mem, next); + + return mem; +} + +void +echo_mem_free(void *ptr) +{ + echo_mem *mem = NULL; + + LIST_FOREACH(mem, &mems, next) { + if (mem->log_base != ptr) + continue; + LIST_REMOVE(mem, next); + + echo_mem_delete(mem); + break; + } +} + void OsAllocateInit() { gdwAllocNonPagedCount = 0; - rtm_create_pool(&echo_pool,0xFFFF, ECHO_POOL_TAG); - if ( NULL == echo_pool ) - { - ECHO_DEBUGPRINTF( ("OsAllocateInit : Failed to create the pool\n") ); - ECHO_DEBUGBREAK(); - return; - } + /* Init mems list */ + LIST_INIT(&mems); } // OsAllocateInit @@ -108,11 +167,15 @@ ECHOSTATUS OsAllocateNonPaged PPVOID ppMemAddr // Where to return memory ptr ) { - *ppMemAddr = rtm_alloc( echo_pool, dwByteCt ); - + + + echo_mem * mem = echo_mem_alloc( dwByteCt ); + if(mem) + *ppMemAddr = mem->log_base; + if ( NULL == *ppMemAddr ) { - ECHO_DEBUGPRINTF( ("OsAllocateNonPaged : Failed on %d bytes\n", + ECHO_DEBUGPRINTF( ("OsAllocateNonPaged : Failed on %ld bytes\n", dwByteCt) ); ECHO_DEBUGBREAK(); return ECHOSTATUS_NO_MEM; @@ -121,7 +184,7 @@ ECHOSTATUS OsAllocateNonPaged OsZeroMemory( *ppMemAddr, dwByteCt ); gdwAllocNonPagedCount++; - ECHO_DEBUGPRINTF(("gdwAllocNonPagedCount %d\n",gdwAllocNonPagedCount)); + ECHO_DEBUGPRINTF(("gdwAllocNonPagedCount %ld\n",gdwAllocNonPagedCount)); return ECHOSTATUS_OK; @@ -142,10 +205,10 @@ ECHOSTATUS OsFreeNonPaged PVOID pMemAddr ) { - rtm_free( pMemAddr ); + echo_mem_free( pMemAddr ); gdwAllocNonPagedCount--; - ECHO_DEBUGPRINTF(("gdwAllocNonPagedCount %d\n",gdwAllocNonPagedCount)); + ECHO_DEBUGPRINTF(("gdwAllocNonPagedCount %ld\n",gdwAllocNonPagedCount)); return ECHOSTATUS_OK; @@ -281,21 +344,17 @@ ECHOSTATUS COsSupport::OsPageAllocate PPHYS_ADDR pPhysicalPageAddr // Where to return the physical PCI address ) { - PHYSICAL_ADDRESS LogicalAddress; - - *ppPageAddr = rtm_alloc ( echo_pool, dwPageCt ); + + echo_mem *mem = echo_mem_alloc ( dwPageCt * B_PAGE_SIZE ); + if(mem) + *ppPageAddr = mem->log_base; if (NULL != *ppPageAddr) { - physical_entry PhysTemp; - - get_memory_map(ppPageAddr, dwPageCt, &PhysTemp, 1); - - PhysTemp = MmGetPhysicalAddress(*ppPageAddr); // XXX: ? - *pPhysicalPageAddr = PhysTemp.address; + *pPhysicalPageAddr = (PHYS_ADDR) mem->phy_base; } - OsZeroMemory( *ppPageAddr, dwPageCt * PAGE_SIZE ); + OsZeroMemory( *ppPageAddr, dwPageCt * B_PAGE_SIZE ); return ECHOSTATUS_OK; @@ -316,12 +375,10 @@ ECHOSTATUS COsSupport::OsPageFree PHYS_ADDR PhysicalPageAddr // Physical PCI addr ) { - PHYSICAL_ADDRESS LogicalAddress; - if (NULL == pPageAddr) return ECHOSTATUS_OK; - rtm_free(pPageAddr); + echo_mem_free (pPageAddr); return ECHOSTATUS_OK; @@ -340,8 +397,8 @@ void COsSupport::EchoErrorMsg PCHAR pszTitle ) { - BAlert alert(pszTitle,pszMsg,"Ok",NULL,NULL,B_WIDTH_AS_USUAL,B_STOP_ALERT); - alert.Go(); + //BAlert alert(pszTitle,pszMsg,"Ok",NULL,NULL,B_WIDTH_AS_USUAL,B_STOP_ALERT); + //alert.Go(); } // void COsSupport::EchoErrorMsg( PCHAR ) @@ -355,10 +412,8 @@ void COsSupport::EchoErrorMsg PVOID COsSupport::operator new( size_t Size ) { PVOID pMemory; - - // it's probably better to not rtm alloc this - // but it does need to be resident - pMemory = rtm_alloc(NULL,Size); + + pMemory = malloc(Size); if ( NULL == pMemory ) { @@ -378,13 +433,6 @@ PVOID COsSupport::operator new( size_t Size ) VOID COsSupport::operator delete( PVOID pVoid ) { - status_t status; - status = rtm_free(pVoid); - - if (status != B_OK) { - ECHO_DEBUGPRINTF(("COsSupport::operator delete " - "memory free failed\n")); - } - + free(pVoid); } // VOID COsSupport::operator delete( PVOID pVoid ) diff --git a/src/add-ons/kernel/drivers/audio/echo/generic/OsSupportBeOS.h b/src/add-ons/kernel/drivers/audio/echo/generic/OsSupportBeOS.h index 4412d8438c..8dcfda8599 100644 --- a/src/add-ons/kernel/drivers/audio/echo/generic/OsSupportBeOS.h +++ b/src/add-ons/kernel/drivers/audio/echo/generic/OsSupportBeOS.h @@ -42,35 +42,29 @@ // // **************************************************************************** -#ifdef _DEBUG -#pragma optimize("",off) -#endif +//#ifdef _DEBUG +//#pragma optimize("",off) +//#endif // Prevent problems with multiple includes #ifndef _ECHOOSSUPPORTBEOS_ #define _ECHOOSSUPPORTBEOS_ -extern "C" -{ -#include -#include - -#ifdef _DEBUG - #include +#include +#include +#include "debug.h" -extern "C" -{ +#include +#include +#include "util/kernel_cpp.h" +#if DEBUG > 0 // BeOS debug printf macro -//#define ECHO_DEBUGPRINTF( strings ) DbgPrint##strings -#define ECHO_DEBUGPRINTF( strings ) dprintf##strings -//#define ECHO_DEBUGBREAK() +#define ECHO_DEBUGPRINTF( strings ) TRACE(strings) #define ECHO_DEBUGBREAK() kernel_debugger("echo driver debug break"); #define ECHO_DEBUG -} - #else #define ECHO_DEBUGPRINTF( strings ) @@ -82,14 +76,27 @@ extern "C" // Specify OS specific types // typedef void ** PPVOID; -typedef signed char INT8; +typedef int8 INT8; typedef int32 INT32; -typedef int32 WORD; -typedef int64 DWORD; +typedef uint16 WORD; +typedef uint16 * PWORD; +typedef uint32 DWORD; +typedef uint32 * PDWORD; typedef void * PVOID; +#define VOID void +typedef int8 BYTE; +typedef int8 * PBYTE; +typedef unsigned long ULONG; +typedef signed long long LONGLONG; typedef unsigned long long ULONGLONG; typedef unsigned long long * PULONGLONG; +typedef char CHAR; typedef char * PCHAR; +typedef bool BOOL; +typedef bool BOOLEAN; +#define CONST const + +#define PAGE_SIZE B_PAGE_SIZE // // Return Status Values @@ -100,19 +107,13 @@ typedef unsigned long ECHOSTATUS; // // Define generic byte swapping functions // -#ifdef BIG_ENDIAN -#include -WORD B_HOST_TO_LENDIAN( WORD in ) { return B_HOST_TO_LENDIAN_INT32(in); } -DWORD B_HOST_TO_LENDIAN( DWORD in ) { return B_HOST_TO_LENDIAN_INT64(in); } -#define SWAP(x) B_HOST_TO_LENDIAN( x ) -#else -#define SWAP(x) x -#endif +#define SWAP(x) B_HOST_TO_LENDIAN_INT32(x) + // // Define what a physical address is on this OS // -typedef unsigned long PHYS_ADDR; // Define physical addr type -typedef unsigned long * PPHYS_ADDR; // Define physical addr pointer type +typedef uint32 PHYS_ADDR; // Define physical addr type +typedef uint32 * PPHYS_ADDR; // Define physical addr pointer type // // Global Memory Management Functions @@ -263,7 +264,7 @@ public: // Overload new & delete so memory for this object is allocated // from non-paged memory. // - PVOID operator new( size_t Size ); + PVOID operator new( size_t Size ); VOID operator delete( PVOID pVoid ); protected: @@ -275,7 +276,7 @@ private: // Define data here. // - KIRQL m_IrqlCurrent; // Old IRQ level + //KIRQL m_IrqlCurrent; // Old IRQ level bigtime_t m_ullStartTime; // All system time relative to this time class CPtrQueue * m_pPtrQue; // Store read only ptrs so they // can be unmapped diff --git a/src/add-ons/kernel/drivers/audio/echo/multi.cpp b/src/add-ons/kernel/drivers/audio/echo/multi.cpp new file mode 100644 index 0000000000..1a0b1405b1 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/echo/multi.cpp @@ -0,0 +1,664 @@ +/* + * EchoGals/Echo24 BeOS Driver for Echo audio cards + * + * Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr) + * + * Original code : BeOS Driver for Intel ICH AC'97 Link interface + * Copyright (c) 2002, Marcus Overhagen + * + * All rights reserved. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include "debug.h" +#include "multi_audio.h" +#include "multi.h" + +//#define DEBUG 1 + +#include "echo.h" +#include "util.h" + +static status_t +echo_create_controls_list(multi_dev *multi) +{ + multi->control_count = 0; + PRINT(("multi->control_count %u\n", multi->control_count)); + return B_OK; +} + +static status_t +echo_get_mix(echo_dev *card, multi_mix_value_info * MMVI) +{ + return B_OK; +} + +static status_t +echo_set_mix(echo_dev *card, multi_mix_value_info * MMVI) +{ + return B_OK; +} + +static status_t +echo_list_mix_controls(echo_dev *card, multi_mix_control_info * MMCI) +{ + multi_mix_control *MMC; + uint32 i; + + MMC = MMCI->controls; + if(MMCI->control_count < 24) + return B_ERROR; + + if(echo_create_controls_list(&card->multi) < B_OK) + return B_ERROR; + for(i=0; imulti.control_count; i++) { + MMC[i] = card->multi.controls[i].mix_control; + } + + MMCI->control_count = card->multi.control_count; + return B_OK; +} + +static status_t +echo_list_mix_connections(echo_dev *card, multi_mix_connection_info * data) +{ + return B_ERROR; +} + +static status_t +echo_list_mix_channels(echo_dev *card, multi_mix_channel_info *data) +{ + return B_ERROR; +} + +/*multi_channel_info chans[] = { +{ 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_OUTPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 }, +{ 3, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 }, +{ 4, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 }, +{ 5, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 }, +{ 6, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 }, +{ 7, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 }, +{ 8, B_MULTI_OUTPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO }, +{ 9, B_MULTI_OUTPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO }, +{ 10, B_MULTI_INPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO }, +{ 11, B_MULTI_INPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO }, +};*/ + +/*multi_channel_info chans[] = { +{ 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_OUTPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_SURROUND_BUS, 0 }, +{ 3, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_SURROUND_BUS, 0 }, +{ 4, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_REARLEFT | B_CHANNEL_SURROUND_BUS, 0 }, +{ 5, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_REARRIGHT | B_CHANNEL_SURROUND_BUS, 0 }, +{ 6, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 }, +{ 7, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 }, +{ 8, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 }, +{ 9, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 }, +{ 10, B_MULTI_OUTPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO }, +{ 11, B_MULTI_OUTPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO }, +{ 12, B_MULTI_INPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO }, +{ 13, B_MULTI_INPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO }, +};*/ + + +static void +echo_create_channels_list(multi_dev *multi) +{ + echo_stream *stream; + int32 mode; + uint32 index, i, designations; + multi_channel_info *chans; + uint32 chan_designations[] = { + B_CHANNEL_LEFT, + B_CHANNEL_RIGHT, + B_CHANNEL_REARLEFT, + B_CHANNEL_REARRIGHT, + B_CHANNEL_CENTER, + B_CHANNEL_SUB + }; + + chans = multi->chans; + index = 0; + + for(mode=ECHO_USE_PLAY; mode!=-1; + mode = (mode == ECHO_USE_PLAY) ? ECHO_USE_RECORD : -1) { + LIST_FOREACH(stream, &((echo_dev*)multi->card)->streams, next) { + if ((stream->use & mode) == 0) + continue; + + if(stream->channels == 2) + designations = B_CHANNEL_STEREO_BUS; + else + designations = B_CHANNEL_SURROUND_BUS; + + for(i=0; ichannels; i++) { + chans[index].channel_id = index; + chans[index].kind = (mode == ECHO_USE_PLAY) ? B_MULTI_OUTPUT_CHANNEL : B_MULTI_INPUT_CHANNEL; + chans[index].designations = designations | chan_designations[i]; + chans[index].connectors = 0; + index++; + } + } + + if(mode==ECHO_USE_PLAY) { + multi->output_channel_count = index; + } else { + multi->input_channel_count = index - multi->output_channel_count; + } + } + + chans[index].channel_id = index; + chans[index].kind = B_MULTI_OUTPUT_BUS; + chans[index].designations = B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS; + chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO; + index++; + + chans[index].channel_id = index; + chans[index].kind = B_MULTI_OUTPUT_BUS; + chans[index].designations = B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS; + chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO; + index++; + + multi->output_bus_channel_count = index - multi->output_channel_count + - multi->input_channel_count; + + chans[index].channel_id = index; + chans[index].kind = B_MULTI_INPUT_BUS; + chans[index].designations = B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS; + chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO; + index++; + + chans[index].channel_id = index; + chans[index].kind = B_MULTI_INPUT_BUS; + chans[index].designations = B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS; + chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO; + index++; + + multi->input_bus_channel_count = index - multi->output_channel_count + - multi->input_channel_count - multi->output_bus_channel_count; + + multi->aux_bus_channel_count = 0; +} + + +static status_t +echo_get_description(echo_dev *card, multi_description *data) +{ + int32 size; + + data->interface_version = B_CURRENT_INTERFACE_VERSION; + data->interface_minimum = B_CURRENT_INTERFACE_VERSION; + + strncpy(data->friendly_name, card->name, 32); + strcpy(data->vendor_info, AUTHOR); + + data->output_channel_count = card->multi.output_channel_count; + data->input_channel_count = card->multi.input_channel_count; + data->output_bus_channel_count = card->multi.output_bus_channel_count; + data->input_bus_channel_count = card->multi.input_bus_channel_count; + data->aux_bus_channel_count = card->multi.aux_bus_channel_count; + + size = card->multi.output_channel_count + card->multi.input_channel_count + + card->multi.output_bus_channel_count + card->multi.input_bus_channel_count + + card->multi.aux_bus_channel_count; + + // for each channel, starting with the first output channel, + // then the second, third..., followed by the first input + // channel, second, third, ..., followed by output bus + // channels and input bus channels and finally auxillary channels, + + LOG(("request_channel_count = %d\n",data->request_channel_count)); + if (data->request_channel_count >= size) { + LOG(("copying data\n")); + memcpy(data->channels, card->multi.chans, size * sizeof(card->multi.chans[0])); + } + + data->output_rates = B_SR_48000;// | B_SR_44100 | B_SR_CVSR; + data->input_rates = B_SR_48000;// | B_SR_44100 | B_SR_CVSR; + //data->output_rates = B_SR_44100; + //data->input_rates = B_SR_44100; + data->min_cvsr_rate = 0; + data->max_cvsr_rate = 48000; + //data->max_cvsr_rate = 44100; + + data->output_formats = B_FMT_16BIT; + data->input_formats = B_FMT_16BIT; + data->lock_sources = B_MULTI_LOCK_INTERNAL; + data->timecode_sources = 0; + data->interface_flags = B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD; + data->start_latency = 3000; + + strcpy(data->control_panel,""); + + return B_OK; +} + +static status_t +echo_get_enabled_channels(echo_dev *card, multi_channel_enable *data) +{ + B_SET_CHANNEL(data->enable_bits, 0, true); + B_SET_CHANNEL(data->enable_bits, 1, true); + B_SET_CHANNEL(data->enable_bits, 2, true); + B_SET_CHANNEL(data->enable_bits, 3, true); + data->lock_source = B_MULTI_LOCK_INTERNAL; +/* + uint32 lock_source; + int32 lock_data; + uint32 timecode_source; + uint32 * connectors; +*/ + return B_OK; +} + +static status_t +echo_set_enabled_channels(echo_dev *card, multi_channel_enable *data) +{ + PRINT(("set_enabled_channels 0 : %s\n", B_TEST_CHANNEL(data->enable_bits, 0) ? "enabled": "disabled")); + PRINT(("set_enabled_channels 1 : %s\n", B_TEST_CHANNEL(data->enable_bits, 1) ? "enabled": "disabled")); + PRINT(("set_enabled_channels 2 : %s\n", B_TEST_CHANNEL(data->enable_bits, 2) ? "enabled": "disabled")); + PRINT(("set_enabled_channels 3 : %s\n", B_TEST_CHANNEL(data->enable_bits, 3) ? "enabled": "disabled")); + return B_OK; +} + +static status_t +echo_get_global_format(echo_dev *card, multi_format_info *data) +{ + data->output_latency = 0; + data->input_latency = 0; + data->timecode_kind = 0; + data->input.rate = B_SR_48000; + data->input.cvsr = 48000; + data->input.format = B_FMT_16BIT; + data->output.rate = B_SR_48000; + data->output.cvsr = 48000; + data->output.format = B_FMT_16BIT; + /*data->input.rate = B_SR_44100; + data->input.cvsr = 44100; + data->input.format = B_FMT_16BIT; + data->output.rate = B_SR_44100; + data->output.cvsr = 44100; + data->output.format = B_FMT_16BIT;*/ + return B_OK; +} + +static status_t +echo_get_buffers(echo_dev *card, multi_buffer_list *data) +{ + int32 i, j, pchannels, rchannels; + + LOG(("flags = %#x\n",data->flags)); + LOG(("request_playback_buffers = %#x\n",data->request_playback_buffers)); + LOG(("request_playback_channels = %#x\n",data->request_playback_channels)); + LOG(("request_playback_buffer_size = %#x\n",data->request_playback_buffer_size)); + LOG(("request_record_buffers = %#x\n",data->request_record_buffers)); + LOG(("request_record_channels = %#x\n",data->request_record_channels)); + LOG(("request_record_buffer_size = %#x\n",data->request_record_buffer_size)); + + pchannels = card->pstream->channels; + rchannels = card->rstream->channels; + + if (data->request_playback_buffers < BUFFER_COUNT || + data->request_playback_channels < (pchannels) || + data->request_record_buffers < BUFFER_COUNT || + data->request_record_channels < (rchannels)) { + LOG(("not enough channels/buffers\n")); + } + + ASSERT(BUFFER_COUNT == 2); + + data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD; // XXX ??? +// data->flags = 0; + + data->return_playback_buffers = BUFFER_COUNT; /* playback_buffers[b][] */ + data->return_playback_channels = pchannels; /* playback_buffers[][c] */ + data->return_playback_buffer_size = BUFFER_FRAMES; /* frames */ + + for(i=0; ipstream, j, i, + &data->playback_buffers[i][j].base, + &data->playback_buffers[i][j].stride); + + data->return_record_buffers = BUFFER_COUNT; + data->return_record_channels = rchannels; + data->return_record_buffer_size = BUFFER_FRAMES; /* frames */ + + for(i=0; irstream, j, i, + &data->record_buffers[i][j].base, + &data->record_buffers[i][j].stride); + + return B_OK; +} + + +void +echo_play_inth(void* inthparams) +{ + echo_stream *stream = (echo_stream *)inthparams; + //int32 count; + + //TRACE(("echo_play_inth\n")); + + acquire_spinlock(&slock); + stream->real_time = system_time(); + stream->frames_count += BUFFER_FRAMES; + stream->buffer_cycle = (stream->trigblk + + stream->blkmod -1) % stream->blkmod; + stream->update_needed = true; + release_spinlock(&slock); + + //get_sem_count(stream->card->buffer_ready_sem, &count); + //if (count <= 0) + release_sem_etc(stream->card->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE); +} + +void +echo_record_inth(void* inthparams) +{ + echo_stream *stream = (echo_stream *)inthparams; + //int32 count; + + //TRACE(("echo_record_inth\n")); + + acquire_spinlock(&slock); + stream->real_time = system_time(); + stream->frames_count += BUFFER_FRAMES; + stream->buffer_cycle = (stream->trigblk + + stream->blkmod -1) % stream->blkmod; + stream->update_needed = true; + release_spinlock(&slock); + + //get_sem_count(stream->card->buffer_ready_sem, &count); + //if (count <= 0) + release_sem_etc(stream->card->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE); +} + +static status_t +echo_buffer_exchange(echo_dev *card, multi_buffer_info *data) +{ + cpu_status status; + echo_stream *pstream, *rstream; + + data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD; + + if (!(card->pstream->state & ECHO_STATE_STARTED)) + echo_stream_start(card->pstream, echo_play_inth, card->pstream); + + if (!(card->rstream->state & ECHO_STATE_STARTED)) + echo_stream_start(card->rstream, echo_record_inth, card->rstream); + + if(acquire_sem_etc(card->buffer_ready_sem, 1, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT, 50000) + == B_TIMED_OUT) { + LOG(("buffer_exchange timeout ff\n")); + } + + status = lock(); + + LIST_FOREACH(pstream, &card->streams, next) { + if ((pstream->use & ECHO_USE_PLAY) == 0 || + (pstream->state & ECHO_STATE_STARTED) == 0) + continue; + if(pstream->update_needed) + break; + } + + LIST_FOREACH(rstream, &card->streams, next) { + if ((rstream->use & ECHO_USE_RECORD) == 0 || + (rstream->state & ECHO_STATE_STARTED) == 0) + continue; + if(rstream->update_needed) + break; + } + + if(!pstream) + pstream = card->pstream; + if(!rstream) + rstream = card->rstream; + + /* do playback */ + data->playback_buffer_cycle = pstream->buffer_cycle; + data->played_real_time = pstream->real_time; + data->played_frames_count = pstream->frames_count; + data->_reserved_0 = pstream->first_channel; + pstream->update_needed = false; + + /* do record */ + data->record_buffer_cycle = rstream->buffer_cycle; + data->recorded_frames_count = rstream->frames_count; + data->recorded_real_time = rstream->real_time; + data->_reserved_1 = rstream->first_channel; + rstream->update_needed = false; + unlock(status); + + //TRACE(("buffer_exchange ended\n")); + return B_OK; +} + +static status_t +echo_buffer_force_stop(echo_dev *card) +{ + //echo_voice_halt(card->pvoice); + return B_OK; +} + +static status_t +echo_multi_control(void *cookie, uint32 op, void *data, size_t length) +{ + echo_dev *card = (echo_dev *)cookie; + + switch (op) { + case B_MULTI_GET_DESCRIPTION: + LOG(("B_MULTI_GET_DESCRIPTION\n")); + return echo_get_description(card, (multi_description *)data); + case B_MULTI_GET_EVENT_INFO: + LOG(("B_MULTI_GET_EVENT_INFO\n")); + return B_ERROR; + case B_MULTI_SET_EVENT_INFO: + LOG(("B_MULTI_SET_EVENT_INFO\n")); + return B_ERROR; + case B_MULTI_GET_EVENT: + LOG(("B_MULTI_GET_EVENT\n")); + return B_ERROR; + case B_MULTI_GET_ENABLED_CHANNELS: + LOG(("B_MULTI_GET_ENABLED_CHANNELS\n")); + return echo_get_enabled_channels(card, (multi_channel_enable *)data); + case B_MULTI_SET_ENABLED_CHANNELS: + LOG(("B_MULTI_SET_ENABLED_CHANNELS\n")); + return echo_set_enabled_channels(card, (multi_channel_enable *)data); + case B_MULTI_GET_GLOBAL_FORMAT: + LOG(("B_MULTI_GET_GLOBAL_FORMAT\n")); + return echo_get_global_format(card, (multi_format_info *)data); + case B_MULTI_SET_GLOBAL_FORMAT: + LOG(("B_MULTI_SET_GLOBAL_FORMAT\n")); + return B_OK; /* XXX BUG! we *MUST* return B_OK, returning B_ERROR will prevent + * BeOS to accept the format returned in B_MULTI_GET_GLOBAL_FORMAT + */ + case B_MULTI_GET_CHANNEL_FORMATS: + LOG(("B_MULTI_GET_CHANNEL_FORMATS\n")); + return B_ERROR; + case B_MULTI_SET_CHANNEL_FORMATS: /* only implemented if possible */ + LOG(("B_MULTI_SET_CHANNEL_FORMATS\n")); + return B_ERROR; + case B_MULTI_GET_MIX: + LOG(("B_MULTI_GET_MIX\n")); + return echo_get_mix(card, (multi_mix_value_info *)data); + case B_MULTI_SET_MIX: + LOG(("B_MULTI_SET_MIX\n")); + return echo_set_mix(card, (multi_mix_value_info *)data); + case B_MULTI_LIST_MIX_CHANNELS: + LOG(("B_MULTI_LIST_MIX_CHANNELS\n")); + return echo_list_mix_channels(card, (multi_mix_channel_info *)data); + case B_MULTI_LIST_MIX_CONTROLS: + LOG(("B_MULTI_LIST_MIX_CONTROLS\n")); + return echo_list_mix_controls(card, (multi_mix_control_info *)data); + case B_MULTI_LIST_MIX_CONNECTIONS: + LOG(("B_MULTI_LIST_MIX_CONNECTIONS\n")); + return echo_list_mix_connections(card, (multi_mix_connection_info *)data); + case B_MULTI_GET_BUFFERS: /* Fill out the struct for the first time; doesn't start anything. */ + LOG(("B_MULTI_GET_BUFFERS\n")); + return echo_get_buffers(card, (multi_buffer_list*)data); + case B_MULTI_SET_BUFFERS: /* Set what buffers to use, if the driver supports soft buffers. */ + LOG(("B_MULTI_SET_BUFFERS\n")); + return B_ERROR; /* we do not support soft buffers */ + case B_MULTI_SET_START_TIME: /* When to actually start */ + LOG(("B_MULTI_SET_START_TIME\n")); + return B_ERROR; + case B_MULTI_BUFFER_EXCHANGE: /* stop and go are derived from this being called */ + //TRACE(("B_MULTI_BUFFER_EXCHANGE\n")); + return echo_buffer_exchange(card, (multi_buffer_info *)data); + case B_MULTI_BUFFER_FORCE_STOP: /* force stop of playback, nothing in data */ + LOG(("B_MULTI_BUFFER_FORCE_STOP\n")); + return echo_buffer_force_stop(card); + } + LOG(("ERROR: unknown multi_control %#x\n",op)); + return B_ERROR; +} + +static status_t echo_open(const char *name, uint32 flags, void** cookie); +static status_t echo_close(void* cookie); +static status_t echo_free(void* cookie); +static status_t echo_control(void* cookie, uint32 op, void* arg, size_t len); +static status_t echo_read(void* cookie, off_t position, void *buf, size_t* num_bytes); +static status_t echo_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes); + +device_hooks multi_hooks = { + echo_open, /* -> open entry point */ + echo_close, /* -> close entry point */ + echo_free, /* -> free cookie */ + echo_control, /* -> control entry point */ + echo_read, /* -> read entry point */ + echo_write, /* -> write entry point */ + NULL, /* start select */ + NULL, /* stop select */ + NULL, /* scatter-gather read from the device */ + NULL /* scatter-gather write to the device */ +}; + +static status_t +echo_open(const char *name, uint32 flags, void** cookie) +{ + echo_dev *card = NULL; + int ix; + + LOG(("echo_open()\n")); + + for (ix=0; ixpstream !=NULL) + return B_ERROR; + if(card->rstream !=NULL) + return B_ERROR; + + *cookie = card; + card->multi.card = card; + + LOG(("stream_new\n")); + + card->rstream = echo_stream_new(card, ECHO_USE_RECORD, BUFFER_FRAMES, BUFFER_COUNT); + card->pstream = echo_stream_new(card, ECHO_USE_PLAY, BUFFER_FRAMES, BUFFER_COUNT); + + card->buffer_ready_sem = create_sem(0, "pbuffer ready"); + + LOG(("stream_setaudio\n")); + + echo_stream_set_audioparms(card->pstream, 2, true, 48000); + echo_stream_set_audioparms(card->rstream, 2, true, 48000); + + card->pstream->first_channel = 0; + card->rstream->first_channel = 2; + + echo_create_channels_list(&card->multi); + + return B_OK; +} + +static status_t +echo_close(void* cookie) +{ + //echo_dev *card = cookie; + LOG(("close()\n")); + + return B_OK; +} + +static status_t +echo_free(void* cookie) +{ + echo_dev *card = (echo_dev *) cookie; + echo_stream *stream; + LOG(("echo_free()\n")); + + if (card->buffer_ready_sem > B_OK) + delete_sem(card->buffer_ready_sem); + + LIST_FOREACH(stream, &card->streams, next) { + echo_stream_halt(stream); + } + + while(!LIST_EMPTY(&card->streams)) { + echo_stream_delete(LIST_FIRST(&card->streams)); + } + + return B_OK; +} + +static status_t +echo_control(void* cookie, uint32 op, void* arg, size_t len) +{ + return echo_multi_control(cookie, op, arg, len); +} + +static status_t +echo_read(void* cookie, off_t position, void *buf, size_t* num_bytes) +{ + *num_bytes = 0; /* tell caller nothing was read */ + return B_IO_ERROR; +} + +static status_t +echo_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes) +{ + *num_bytes = 0; /* tell caller nothing was written */ + return B_IO_ERROR; +} + diff --git a/src/add-ons/kernel/drivers/audio/echo/multi.h b/src/add-ons/kernel/drivers/audio/echo/multi.h new file mode 100644 index 0000000000..b0d908a29c --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/echo/multi.h @@ -0,0 +1,64 @@ +/* + * EchoGals/Echo24 BeOS Driver for Echo audio cards + * + * Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr) + * + * Original code : BeOS Driver for Intel ICH AC'97 Link interface + * Copyright (c) 2002, Marcus Overhagen + * + * All rights reserved. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _MULTI_H_ +#define _MULTI_H_ + +#define BUFFER_FRAMES 512 +#define BUFFER_COUNT 2 + +typedef struct _multi_mixer_control { + struct _multi_dev *multi; + void (*get) (void *card, const void *cookie, int32 type, float *values); + void (*set) (void *card, const void *cookie, int32 type, float *values); + const void *cookie; + int32 type; + multi_mix_control mix_control; +} multi_mixer_control; + +#define EMU_MULTI_CONTROL_FIRSTID 1024 +#define EMU_MULTI_CONTROL_MASTERID 0 + +typedef struct _multi_dev { + void *card; +#define EMU_MULTICONTROLSNUM 64 + multi_mixer_control controls[EMU_MULTICONTROLSNUM]; + uint32 control_count; + +#define EMU_MULTICHANNUM 64 + multi_channel_info chans[EMU_MULTICHANNUM]; + uint32 output_channel_count; + uint32 input_channel_count; + uint32 output_bus_channel_count; + uint32 input_bus_channel_count; + uint32 aux_bus_channel_count; +} multi_dev; + +#endif diff --git a/src/add-ons/kernel/drivers/audio/echo/multi_audio.h b/src/add-ons/kernel/drivers/audio/echo/multi_audio.h new file mode 100644 index 0000000000..6802a49ba3 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/echo/multi_audio.h @@ -0,0 +1,702 @@ +/* multi_audio.h */ + +/* Interface description for drivers implementing studio-level audio I/O with */ +/* possible auxillary functions (transport, time code, etc). */ +/* Copyright © 1998-1999 Be Incorporated. All rights reserved. */ + +/* This is the first release candidate for the API. Unless we hear feedback that */ +/* forces a change before the end of August, we will try to stay binary compatible */ +/* with this interface. */ +/* Send feedback to trinity@be.com [1999-07-02] */ + +#if !defined(_MULTI_AUDIO_H) +#define _MULTI_AUDIO_H + +#include + +#if !defined(ASSERT) + #include +#endif + +#define B_MULTI_DRIVER_BASE (B_AUDIO_DRIVER_BASE+20) + +enum { /* open() modes */ + /* O_RDONLY is 0, O_WRONLY is 1, O_RDWR is 2 */ + B_MULTI_CONTROL = 3 +}; + +/* ioctl codes */ +enum { + /* multi_description */ + B_MULTI_GET_DESCRIPTION = B_MULTI_DRIVER_BASE, + /* multi_event_handling */ + B_MULTI_GET_EVENT_INFO, + B_MULTI_SET_EVENT_INFO, + B_MULTI_GET_EVENT, + /* multi_channel_enable */ + B_MULTI_GET_ENABLED_CHANNELS, + B_MULTI_SET_ENABLED_CHANNELS, + /* multi_format_info */ + B_MULTI_GET_GLOBAL_FORMAT, + B_MULTI_SET_GLOBAL_FORMAT, /* always sets for all channels, always implemented */ + /* multi_channel_formats */ + B_MULTI_GET_CHANNEL_FORMATS, + B_MULTI_SET_CHANNEL_FORMATS, /* only implemented if possible */ + /* multi_mix_value_info */ + B_MULTI_GET_MIX, + B_MULTI_SET_MIX, + /* multi_mix_channel_info */ + B_MULTI_LIST_MIX_CHANNELS, + /* multi_mix_control_info */ + B_MULTI_LIST_MIX_CONTROLS, + /* multi_mix_connection_info */ + B_MULTI_LIST_MIX_CONNECTIONS, + /* multi_buffer_list */ + B_MULTI_GET_BUFFERS, /* Fill out the struct for the first time; doesn't start anything. */ + B_MULTI_SET_BUFFERS, /* Set what buffers to use, if the driver supports soft buffers. */ + /* bigtime_t */ + B_MULTI_SET_START_TIME, /* When to actually start */ + /* multi_buffer_info */ + B_MULTI_BUFFER_EXCHANGE, /* stop and go are derived from this being called */ + B_MULTI_BUFFER_FORCE_STOP, /* force stop of playback */ + /* extension protocol */ + B_MULTI_LIST_EXTENSIONS, /* get a list of supported extensions */ + B_MULTI_GET_EXTENSION, /* get the value of an extension (or return error if not supported) */ + B_MULTI_SET_EXTENSION, /* set the value of an extension */ + /* multi_mode_list */ + B_MULTI_LIST_MODES, /* get a list of possible modes (multi_mode_list * arg) */ + B_MULTI_GET_MODE, /* get the current mode (int32 * arg) */ + B_MULTI_SET_MODE /* set a new mode (int32 * arg) */ +}; + +/* sample rate values */ +/* various fixed sample rates we support (for hard-sync clocked values) */ +#define B_SR_8000 0x1 +#define B_SR_11025 0x2 +#define B_SR_12000 0x4 +#define B_SR_16000 0x8 +#define B_SR_22050 0x10 +#define B_SR_24000 0x20 +#define B_SR_32000 0x40 +#define B_SR_44100 0x80 +#define B_SR_48000 0x100 +#define B_SR_64000 0x200 +#define B_SR_88200 0x400 +#define B_SR_96000 0x800 +#define B_SR_176400 0x1000 +#define B_SR_192000 0x2000 +#define B_SR_384000 0x4000 +#define B_SR_1536000 0x10000 +/* continuously variable sample rate (typically board-generated) */ +#define B_SR_CVSR 0x10000000UL +/* sample rate parameter global to all channels (input and output rates respectively) */ +#define B_SR_IS_GLOBAL 0x80000000UL +/* output sample rate locked to input sample rate (output_rates only; the common case!) */ +#define B_SR_SAME_AS_INPUT 0x40000000UL + + +/* format values */ +/* signed char */ +#define B_FMT_8BIT_S 0x01 +/* unsigned char -- this is special case */ +#define B_FMT_8BIT_U 0x02 +/* traditional 16 bit signed format (host endian) */ +#define B_FMT_16BIT 0x10 +/* left-adjusted in 32 bit signed word */ +#define B_FMT_18BIT 0x20 +#define B_FMT_20BIT 0x40 +#define B_FMT_24BIT 0x100 +#define B_FMT_32BIT 0x1000 +/* 32-bit floating point, -1.0 to 1.0 */ +#define B_FMT_FLOAT 0x20000 +/* 64-bit floating point, -1.0 to 1.0 */ +#define B_FMT_DOUBLE 0x40000 +/* 80-bit floating point, -1.0 to 1.0 */ +#define B_FMT_EXTENDED 0x80000 +/* bit stream */ +#define B_FMT_BITSTREAM 0x1000000 +/* format parameter global to all channels (input and output formats respectively) */ +#define B_FMT_IS_GLOBAL 0x80000000UL +/* output format locked to input format (output_formats) */ +#define B_FMT_SAME_AS_INPUT 0x40000000UL + +/* possible sample lock sources */ +#define B_MULTI_LOCK_INPUT_CHANNEL 0x0 /* lock_source_data is channel id */ +#define B_MULTI_LOCK_INTERNAL 0x1 +#define B_MULTI_LOCK_WORDCLOCK 0x2 +#define B_MULTI_LOCK_SUPERCLOCK 0x4 +#define B_MULTI_LOCK_LIGHTPIPE 0x8 +#define B_MULTI_LOCK_VIDEO 0x10 /* or blackburst */ +#define B_MULTI_LOCK_FIRST_CARD 0x20 /* if you have more than one card */ +#define B_MULTI_LOCK_MTC 0x40 +#define B_MULTI_LOCK_SPDIF 0x80 + +/* possible timecode sources */ +#define B_MULTI_TIMECODE_MTC 0x1 +#define B_MULTI_TIMECODE_VTC 0x2 +#define B_MULTI_TIMECODE_SMPTE 0x4 +#define B_MULTI_TIMECODE_SUPERCLOCK 0x8 +#define B_MULTI_TIMECODE_FIREWIRE 0x10 + +/* interface_flags values */ +/* Available functions on this device. */ +#define B_MULTI_INTERFACE_PLAYBACK 0x1 +#define B_MULTI_INTERFACE_RECORD 0x2 +#define B_MULTI_INTERFACE_TRANSPORT 0x4 +#define B_MULTI_INTERFACE_TIMECODE 0x8 +/* "Soft" buffers means you can change the pointer values and the driver will still be happy. */ +#define B_MULTI_INTERFACE_SOFT_PLAY_BUFFERS 0x10000 +#define B_MULTI_INTERFACE_SOFT_REC_BUFFERS 0x20000 +/* Whether the data stream is interrupted when changing channel enables. */ +#define B_MULTI_INTERFACE_CLICKS_WHEN_ENABLING_OUTPUTS 0x40000 +#define B_MULTI_INTERFACE_CLICKS_WHEN_ENABLING_INPUTS 0x80000 + +#define B_CURRENT_INTERFACE_VERSION 0x4502 +#define B_MINIMUM_INTERFACE_VERSION 0x4502 + +typedef struct multi_description multi_description; +typedef struct multi_channel_info multi_channel_info; +struct multi_description { + + size_t info_size; /* sizeof(multi_description) */ + uint32 interface_version; /* current version of interface that's implemented */ + uint32 interface_minimum; /* minimum version required to understand driver */ + + char friendly_name[32]; /* name displayed to user (C string) */ + char vendor_info[32]; /* name used internally by vendor (C string) */ + + int32 output_channel_count; + int32 input_channel_count; + int32 output_bus_channel_count; + int32 input_bus_channel_count; + int32 aux_bus_channel_count; + + int32 request_channel_count; /* how many channel_infos are there */ + multi_channel_info * + channels; + + uint32 output_rates; + uint32 input_rates; + float min_cvsr_rate; + float max_cvsr_rate; + uint32 output_formats; + uint32 input_formats; + uint32 lock_sources; + uint32 timecode_sources; + + uint32 interface_flags; + bigtime_t start_latency; /* how much in advance driver needs SET_START_TIME */ + + uint32 _reserved_[11]; + + char control_panel[64]; /* MIME type of control panel application */ +}; + +#if !defined(_MEDIA_DEFS_H) /* enum in MediaDefs.h */ +/* designation values */ +/* mono channels have no designation */ +#define B_CHANNEL_LEFT 0x1 +#define B_CHANNEL_RIGHT 0x2 +#define B_CHANNEL_CENTER 0x4 /* 5.1+ or fake surround */ +#define B_CHANNEL_SUB 0x8 /* 5.1+ */ +#define B_CHANNEL_REARLEFT 0x10 /* quad surround or 5.1+ */ +#define B_CHANNEL_REARRIGHT 0x20 /* quad surround or 5.1+ */ +#define B_CHANNEL_FRONT_LEFT_CENTER 0x40 +#define B_CHANNEL_FRONT_RIGHT_CENTER 0x80 +#define B_CHANNEL_BACK_CENTER 0x100 /* 6.1 or fake surround */ +#define B_CHANNEL_SIDE_LEFT 0x200 +#define B_CHANNEL_SIDE_RIGHT 0x400 +#define B_CHANNEL_TOP_CENTER 0x800 +#define B_CHANNEL_TOP_FRONT_LEFT 0x1000 +#define B_CHANNEL_TOP_FRONT_CENTER 0x2000 +#define B_CHANNEL_TOP_FRONT_RIGHT 0x4000 +#define B_CHANNEL_TOP_BACK_LEFT 0x8000 +#define B_CHANNEL_TOP_BACK_CENTER 0x10000 +#define B_CHANNEL_TOP_BACK_RIGHT 0x20000 +#endif + +#define B_CHANNEL_MONO_BUS 0x4000000 +#define B_CHANNEL_STEREO_BUS 0x2000000 /* + left/right */ +#define B_CHANNEL_SURROUND_BUS 0x1000000 /* multichannel */ + +/* If you have interactions where some inputs can not be used when some */ +/* outputs are used, mark both inputs and outputs with this flag. */ +#define B_CHANNEL_INTERACTION 0x80000000UL +/* If input channel #n is simplexed with output channel #n, they should both */ +/* have this flag set (different from the previous flag, which is more vague). */ +#define B_CHANNEL_SIMPLEX 0x40000000UL + +/* connector values */ +/* analog connectors */ +#define B_CHANNEL_RCA 0x1 +#define B_CHANNEL_XLR 0x2 +#define B_CHANNEL_TRS 0x4 +#define B_CHANNEL_QUARTER_INCH_MONO 0x8 +#define B_CHANNEL_MINI_JACK_STEREO 0x10 +#define B_CHANNEL_QUARTER_INCH_STEREO 0x20 +#define B_CHANNEL_ANALOG_HEADER 0x100 /* internal on card */ +#define B_CHANNEL_SNAKE 0x200 /* or D-sub */ +/* digital connectors (stereo) */ +#define B_CHANNEL_OPTICAL_SPDIF 0x1000 +#define B_CHANNEL_COAX_SPDIF 0x2000 +#define B_CHANNEL_COAX_EBU 0x4000 +#define B_CHANNEL_XLR_EBU 0x8000 +#define B_CHANNEL_TRS_EBU 0x10000 +#define B_CHANNEL_SPDIF_HEADER 0x20000 /* internal on card */ +/* multi-channel digital connectors */ +#define B_CHANNEL_LIGHTPIPE 0x100000 +#define B_CHANNEL_TDIF 0x200000 +#define B_CHANNEL_FIREWIRE 0x400000 +#define B_CHANNEL_USB 0x800000 +/* If you have multiple output connectors, only one of which can */ +/* be active at a time. */ +#define B_CHANNEL_EXCLUSIVE_SELECTION 0x80000000UL + + +typedef enum { + B_MULTI_NO_CHANNEL_KIND, + B_MULTI_OUTPUT_CHANNEL = 0x1, + B_MULTI_INPUT_CHANNEL = 0x2, + B_MULTI_OUTPUT_BUS = 0x4, + B_MULTI_INPUT_BUS = 0x8, + B_MULTI_AUX_BUS = 0x10 +} channel_kind; + +struct multi_channel_info { + int32 channel_id; + channel_kind kind; + uint32 designations; + uint32 connectors; + uint32 _reserved_[4]; +}; + + +/* Constants */ +#define B_MULTI_EVENT_MINMAX 16 +/* Event flags/masks */ +#define B_MULTI_EVENT_TRANSPORT 0x40000000UL +#define B_MULTI_EVENT_HAS_TIMECODE 0x80000000UL + +/* possible transport events */ +#define B_MULTI_EVENT_NONE 0x00000000UL +#define B_MULTI_EVENT_START 0x40010000UL +#define B_MULTI_EVENT_LOCATION 0x40020000UL /* location when shuttling or locating */ +#define B_MULTI_EVENT_SHUTTLING 0x40040000UL +#define B_MULTI_EVENT_STOP 0x40080000UL +#define B_MULTI_EVENT_RECORD 0x40100000UL +#define B_MULTI_EVENT_PAUSE 0x40200000UL +#define B_MULTI_EVENT_RUNNING 0x40400000UL /* location when running */ +/* possible device events */ +enum { + B_MULTI_EVENT_STARTED = 0x1, + B_MULTI_EVENT_STOPPED = 0x2, + B_MULTI_EVENT_CHANNEL_FORMAT_CHANGED= 0x4, + B_MULTI_EVENT_BUFFER_OVERRUN = 0x8, + B_MULTI_EVENT_SIGNAL_LOST = 0x10, + B_MULTI_EVENT_SIGNAL_DETECTED = 0x20, + B_MULTI_EVENT_CLOCK_LOST = 0x40, + B_MULTI_EVENT_CLOCK_DETECTED = 0x80, + B_MULTI_EVENT_NEW_MODE = 0x100, + B_MULTI_EVENT_CONTROL_CHANGED = 0x200 +}; + +typedef struct multi_get_event_info multi_get_event_info; +struct multi_get_event_info { + size_t info_size; /* sizeof(multi_get_event_info) */ + uint32 supported_mask; /* what events h/w supports */ + uint32 current_mask; /* current driver value */ + uint32 queue_size; /* current queue size */ + uint32 event_count; /* number of events currently in queue*/ + uint32 _reserved[3]; +}; + +typedef struct multi_set_event_info multi_set_event_info; +struct multi_set_event_info { + size_t info_size; /* sizeof(multi_set_event_info) */ + uint32 in_mask; /* what events to wait for */ + int32 semaphore; /* semaphore app will wait on */ + uint32 queue_size; /* minimum number of events to save */ + uint32 _reserved[4]; +}; + +typedef struct multi_get_event multi_get_event; +struct multi_get_event { + size_t info_size; /* sizeof(multi_get_event) */ + uint32 event; + bigtime_t timestamp; /* real time at which event was received */ + int32 count; /* used for configuration events */ + union { + int32 channels[100]; + uint32 clocks; + int32 mode; + int32 controls[100]; + struct { /* transport event */ + float out_rate; /* what rate it's now playing at */ + int32 out_hours; /* location at the time given */ + int32 out_minutes; + int32 out_seconds; + int32 out_frames; + }transport; + char _reserved_[400]; + #if defined(__cplusplus) + }; + #else + } u; + #endif + uint32 _reserved_1[10]; +}; + +typedef struct multi_channel_enable multi_channel_enable; +struct multi_channel_enable { + size_t info_size; /* sizeof(multi_channel_enable) */ + /* this must have bytes for all channels (see multi_description) */ + /* channel 0 is lowest bit of first byte */ + uchar * enable_bits; + + uint32 lock_source; + int32 lock_data; + uint32 timecode_source; + uint32 * connectors; /* which connector(s) is/are active, per channel */ +}; + +#include + +#if defined(__cplusplus) + inline void B_SET_CHANNEL(void * bits, int channel, bool value) + { + ASSERT(channel>=0); + (((uchar *)(bits))[((channel)&0x7fff)>>3] = + (((uchar *)(bits))[((channel)&0x7fff)>>3] & ~(1<<((channel)&0x7))) | + ((value) ? (1<<((channel)&0x7)) : 0)); + } + inline bool B_TEST_CHANNEL(const void * bits, int channel) + { + return ((((uchar *)(bits))[((channel)&0x7fff)>>3] >> ((channel)&0x7)) & 1); + } +#else + #define B_SET_CHANNEL(bits, channel, value) \ + ASSERT(channel>=0); \ + (((uchar *)(bits))[((channel)&0x7fff)>>3] = \ + (((uchar *)(bits))[((channel)&0x7fff)>>3] & ~(1<<((channel)&0x7))) | \ + ((value) ? (1<<((channel)&0x7)) : 0)) + #define B_TEST_CHANNEL(bits, channel) \ + ((((uchar *)(bits))[((channel)&0x7fff)>>3] >> ((channel)&0x7)) & 1) +#endif + +typedef struct multi_channel_formats multi_channel_formats; +typedef struct multi_format_info multi_format_info; +typedef struct _multi_format _multi_format; + +struct _multi_format { + uint32 rate; + float cvsr; + uint32 format; + uint32 _reserved_[3]; +}; +enum { /* timecode kinds */ + B_MULTI_NO_TIMECODE, + B_MULTI_TIMECODE_30, /* MIDI */ + B_MULTI_TIMECODE_30_DROP_2, /* NTSC */ + B_MULTI_TIMECODE_30_DROP_4, /* Brazil */ + B_MULTI_TIMECODE_25, /* PAL */ + B_MULTI_TIMECODE_24 /* Film */ +}; +struct multi_format_info { + size_t info_size; /* sizeof(multi_format_info) */ + bigtime_t output_latency; + bigtime_t input_latency; + int32 timecode_kind; + uint32 _reserved_[7]; + _multi_format input; + _multi_format output; +}; +struct multi_channel_formats { + size_t info_size; /* sizeof(multi_channel_formats) */ + int32 request_channel_count; + int32 request_first_channel; + int32 returned_channel_count; + int32 timecode_kind; + int32 _reserved_[4]; + _multi_format * + channels; + bigtime_t * latencies; /* DMA/hardware latencies; client calculates for buffers */ +}; + + +typedef struct multi_mix_value multi_mix_value; +struct multi_mix_value { + int32 id; + union { + float gain; + uint32 mux; /* bitmask of mux points */ + bool enable; + uint32 _reserved_[2]; +#if defined(__cplusplus) + }; +#else + } u; +#endif + int32 ramp; + uint32 _reserved_2[2]; +}; + +typedef struct multi_mix_value_info multi_mix_value_info; +struct multi_mix_value_info { + size_t info_size; /* sizeof(multi_mix_value_info) */ + int32 item_count; + multi_mix_value * + values; + int32 at_frame; /* time at which to start the change */ +}; + +// only one of these should be set +#define B_MULTI_MIX_JUNCTION 0x1 +#define B_MULTI_MIX_GAIN 0x2 +#define B_MULTI_MIX_MUX 0x4 +#define B_MULTI_MIX_ENABLE 0x8 +#define B_MULTI_MIX_GROUP 0x10 +#define B_MULTI_MIX_KIND_MASK 0xffff + +#define B_MULTI_MIX_MUX_VALUE 0x0104 +// any combination of these can be set +#define B_MULTI_MIX_RAMP 0x10000 + +enum strind_id { + S_null = 0, S_OUTPUT, S_INPUT, S_SETUP, S_TONE_CONTROL, S_EXTENDED_SETUP, + S_ENHANDED_SETUP, S_MASTER, S_BEEP, S_PHONE, S_MIC, S_LINE, S_CD, S_VIDEO, + S_AUX, S_WAVE, S_GAIN, S_LEVEL, S_VOLUME, S_MUTE, S_ENABLE, S_STEREO_MIX, + S_MONO_MIX, S_OUTPUT_STEREO_MIX, S_OUTPUT_MONO_MIX, S_OUTPUT_BASS, + S_OUTPUT_TREBLE, S_OUTPUT_3D_CENTER, S_OUTPUT_3D_DEPTH, + S_USERID = 1000000 +}; + +typedef struct multi_mix_control multi_mix_control; +struct multi_mix_control { + int32 id; /* unique for device -- not same id as any channel/bus ! */ + uint32 flags; /* including kind */ + int32 master; /* or 0 if it's not slaved */ + union { + struct { + float min_gain; /* dB */ + float max_gain; /* dB */ + float granularity; /* dB */ + } gain; + struct { + uint32 _reserved; + } mux; + struct { + uint32 _reserved; + } enable; + uint32 _reserved[12]; +#if defined(__cplusplus) + }; +#else + } u; +#endif + enum strind_id string; /* string id (S_null : use name) */ + int32 parent; /* parent id */ + char name[48]; +}; + +typedef struct multi_mix_channel_info multi_mix_channel_info; +struct multi_mix_channel_info { + size_t info_size; /* sizeof(multi_mix_channel_info) */ + int32 channel_count; + int32 * channels; /* allocated by caller, lists requested channels */ + int32 max_count; /* in: control ids per channel */ + int32 actual_count; /* out: actual max # controls for any individual requested channel */ + int32 ** controls; +}; + +typedef struct multi_mix_control_info multi_mix_control_info; +struct multi_mix_control_info { + size_t info_size; /* sizeof(multi_mix_control_info) */ + int32 control_count; /* in: number of controls */ + multi_mix_control * + controls; /* allocated by caller, returns control description for each */ +}; + +typedef struct multi_mix_connection multi_mix_connection; +struct multi_mix_connection { + int32 from; + int32 to; + uint32 _reserved_[2]; +}; + +typedef struct multi_mix_connection_info multi_mix_connection_info; +struct multi_mix_connection_info { + size_t info_size; + int32 max_count; /* in: available space */ + int32 actual_count; /* out: actual count */ + multi_mix_connection * + connections; /* allocated by caller, returns connections */ +}; + + +/* possible flags values for what is available (in and out) */ +#define B_MULTI_BUFFER_PLAYBACK 0x1 +#define B_MULTI_BUFFER_RECORD 0x2 +#define B_MULTI_BUFFER_METERING 0x4 +#define B_MULTI_BUFFER_TIMECODE 0x40000 + +typedef struct multi_buffer_list multi_buffer_list; +typedef struct buffer_desc buffer_desc; +/* This struct is used to query the driver about what buffers it will use, */ +/* and to tell it what buffers to use if it supports soft buffers. */ +struct multi_buffer_list { + + size_t info_size; /* sizeof(multi_buffer_list) */ + uint32 flags; + + int32 request_playback_buffers; + int32 request_playback_channels; + uint32 request_playback_buffer_size; /* frames per buffer */ + int32 return_playback_buffers; /* playback_buffers[b][] */ + int32 return_playback_channels; /* playback_buffers[][c] */ + uint32 return_playback_buffer_size; /* frames */ + buffer_desc ** playback_buffers; + void * _reserved_1; + + int32 request_record_buffers; + int32 request_record_channels; + uint32 request_record_buffer_size; /* frames per buffer */ + int32 return_record_buffers; + int32 return_record_channels; + uint32 return_record_buffer_size; /* frames */ + buffer_desc ** record_buffers; + void * _reserved_2; + +}; + +struct buffer_desc { + char * base; /* pointer to first sample for channel for buffer */ + size_t stride; /* offset to next sample */ + uint32 _reserved_[2]; +}; + + +/* This struct is used when actually queuing data to be played, and/or */ +/* receiving data from a recorder. */ +typedef struct multi_buffer_info multi_buffer_info; +struct multi_buffer_info { + + size_t info_size; /* sizeof(multi_buffer_info) */ + uint32 flags; + + bigtime_t played_real_time; + bigtime_t played_frames_count; + int32 _reserved_0; + int32 playback_buffer_cycle; + + bigtime_t recorded_real_time; + bigtime_t recorded_frames_count; + int32 _reserved_1; + int32 record_buffer_cycle; + + int32 meter_channel_count; + char * meters_peak; /* in the same format as the data; allocated by caller */ + char * meters_average; /* in the same format as the data; allocated by caller */ + + /* timecode sent and received at buffer swap */ + int32 hours; + int32 minutes; + int32 seconds; + int32 tc_frames; /* for timecode frames as opposed to sample frames */ + int32 at_frame_delta; /* how far into buffer (or before buffer for negative) */ + +}; + + +typedef struct multi_mode_info multi_mode_info; +typedef struct multi_mode_list multi_mode_list; + +struct multi_mode_list { + size_t info_size; /* sizeof(multi_mode_list) */ + int32 in_request_count; + int32 out_actual_count; + int32 out_current_mode; + multi_mode_info * + io_modes; +}; + +struct multi_mode_info { + int32 mode_id; + uint32 flags; + char mode_name[64]; + int32 input_channel_count; + int32 output_channel_count; + float best_frame_rate_in; + float best_frame_rate_out; + uint32 sample_formats_in; + uint32 sample_formats_out; + char _reserved[160]; +}; + + +/* This extension protocol can grow however much you want. */ +/* Good extensions should be put into this header; really */ +/* good extensions should become part of the regular API. */ +/* For developer-developed extensions, use all lowercase */ +/* and digits (no upper case). If we then bless a third- */ +/* party extension, we can just upper-case the selector. */ + +typedef struct multi_extension_list multi_extension_list; +typedef struct multi_extension_info multi_extension_info; +struct multi_extension_info { + uint32 code; + uint32 flags; + char name[24]; +}; + +#define B_MULTI_MAX_EXTENSION_COUNT 31 +struct multi_extension_list { /* MULTI_LIST_EXTENSIONS */ + size_t info_size; /* sizeof(multi_extension_list) */ + uint32 max_count; + int32 actual_count; /* return # of actual extensions */ + multi_extension_info * + extensions; /* allocated by caller */ +}; + +typedef struct multi_extension_cmd multi_extension_cmd; +struct multi_extension_cmd { /* MULTI_GET_EXTENSION and MULTI_SET_EXTENSION */ + size_t info_size; /* sizeof(multi_extension_cmd) */ + uint32 code; + uint32 _reserved_1; + void * in_data; + size_t in_size; + void * out_data; + size_t out_size; +}; + +enum { + B_MULTI_EX_CLOCK_GENERATION = 'CLGE', + B_MULTI_EX_DIGITAL_FORMAT = 'DIFO', + B_MULTI_EX_OUTPUT_NOMINAL = 'OUNO', + B_MULTI_EX_INPUT_NOMINAL = 'INNO' +}; + +typedef struct multi_ex_clock_generation multi_ex_clock_generation; +struct multi_ex_clock_generation { + int32 channel; /* if specific, or -1 for all */ + uint32 clock; /* WORDCLOCK or SUPERCLOCK, typically */ +}; + +typedef struct multi_ex_digital_format multi_ex_digital_format; +struct multi_ex_digital_format { + int32 channel; /* if specific, or -1 for all */ + uint32 format; /* B_CHANNEL_*_SPDIF or B_CHANNEL_*_EBU */ +}; + +enum { + B_MULTI_NOMINAL_MINUS_10 = 1, + B_MULTI_NOMINAL_PLUS_4 +}; + +typedef struct multi_ex_nominal_level multi_ex_nominal_level; +struct multi_ex_nominal_level { + int32 channel; /* if specific, or -1 for all */ + int32 level; +}; + +#endif /* _MULTI_AUDIO_H */ + diff --git a/src/add-ons/kernel/drivers/audio/echo/queue.h b/src/add-ons/kernel/drivers/audio/echo/queue.h new file mode 100644 index 0000000000..396c70fb2e --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/echo/queue.h @@ -0,0 +1,529 @@ +/* $NetBSD: queue.h,v 1.31 2002/06/01 23:51:05 lukem Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The + * elements are singly linked for minimum space and pointer manipulation + * overhead at the expense of O(n) removal for arbitrary elements. New + * elements can be added to the list after an existing element or at the + * head of the list. Elements being removed from the head of the list + * should use the explicit macro for this purpose for optimum + * efficiency. A singly-linked list may only be traversed in the forward + * direction. Singly-linked lists are ideal for applications with large + * datasets and few or no removals or for implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so only elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#if defined(_KERNEL) && defined(QUEUEDEBUG) +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \ + if ((head)->lh_first && \ + (head)->lh_first->field.le_prev != &(head)->lh_first) \ + panic("LIST_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_OP(elm, field) \ + if ((elm)->field.le_next && \ + (elm)->field.le_next->field.le_prev != \ + &(elm)->field.le_next) \ + panic("LIST_* forw %p %s:%d", (elm), __FILE__, __LINE__);\ + if (*(elm)->field.le_prev != (elm)) \ + panic("LIST_* back %p %s:%d", (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \ + (elm)->field.le_next = (void *)1L; \ + (elm)->field.le_prev = (void *)1L; +#else +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_LIST_OP(elm, field) +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) +#endif + +#define LIST_INIT(head) do { \ + (head)->lh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (/*CONSTCOND*/0) + +#define LIST_REMOVE(elm, field) do { \ + QUEUEDEBUG_LIST_OP((elm), field) \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ +} while (/*CONSTCOND*/0) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var); \ + (var) = ((var)->field.le_next)) + +/* + * List access methods. + */ +#define LIST_EMPTY(head) ((head)->lh_first == NULL) +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) + +#define SLIST_INIT(head) do { \ + (head)->slh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while(curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (/*CONSTCOND*/0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + SIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var); \ + (var) = ((var)->field.sqe_next)) + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * Tail queue functions. + */ +#if defined(_KERNEL) && defined(QUEUEDEBUG) +#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \ + if ((head)->tqh_first && \ + (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \ + panic("TAILQ_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \ + if (*(head)->tqh_last != NULL) \ + panic("TAILQ_INSERT_TAIL %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_OP(elm, field) \ + if ((elm)->field.tqe_next && \ + (elm)->field.tqe_next->field.tqe_prev != \ + &(elm)->field.tqe_next) \ + panic("TAILQ_* forw %p %s:%d", (elm), __FILE__, __LINE__);\ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("TAILQ_* back %p %s:%d", (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \ + (elm)->field.tqe_next = (void *)1L; \ + (elm)->field.tqe_prev = (void *)1L; +#else +#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) +#define QUEUEDEBUG_TAILQ_OP(elm, field) +#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) +#endif + +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QUEUEDEBUG_TAILQ_OP((listelm), field) \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_TAILQ_OP((listelm), field) \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_OP((elm), field) \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ +} while (/*CONSTCOND*/0) + +/* + * Tail queue access methods. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var); \ + (var) = ((var)->field.tqe_next)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ + (var); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&head, (void *)&head } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != (void *)(head); \ + (var) = ((var)->field.cqe_next)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != (void *)(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#endif /* !_SYS_QUEUE_H_ */ diff --git a/src/add-ons/kernel/drivers/audio/echo/util.c b/src/add-ons/kernel/drivers/audio/echo/util.c new file mode 100644 index 0000000000..d71521def3 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/echo/util.c @@ -0,0 +1,88 @@ +/* + * BeOS Driver for Intel ICH AC'97 Link interface + * + * Copyright (c) 2002, Marcus Overhagen + * + * All rights reserved. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include +#include + +//#define DEBUG 2 + +#include "debug.h" +#include "util.h" + +spinlock slock = 0; + +uint32 round_to_pagesize(uint32 size); + +cpu_status lock(void) +{ + cpu_status status = disable_interrupts(); + acquire_spinlock(&slock); + return status; +} + +void unlock(cpu_status status) +{ + release_spinlock(&slock); + restore_interrupts(status); +} + +uint32 round_to_pagesize(uint32 size) +{ + return (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); +} + +area_id alloc_mem(void **phy, void **log, size_t size, const char *name) +{ + physical_entry pe; + void * logadr; + area_id areaid; + status_t rv; + + LOG(("allocating %d bytes for %s\n",size,name)); + + size = round_to_pagesize(size); + areaid = create_area(name, &logadr, B_ANY_KERNEL_ADDRESS,size,B_FULL_LOCK | B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA); + if (areaid < B_OK) { + PRINT(("couldn't allocate area %s\n",name)); + return B_ERROR; + } + rv = get_memory_map(logadr,size,&pe,1); + if (rv < B_OK) { + delete_area(areaid); + PRINT(("couldn't map %s\n",name)); + return B_ERROR; + } + memset(logadr,0,size); + if (log) + *log = logadr; + if (phy) + *phy = pe.address; + LOG(("area = %d, size = %d, log = %#08X, phy = %#08X\n",areaid,size,logadr,pe.address)); + return areaid; +} + diff --git a/src/add-ons/kernel/drivers/audio/echo/util.h b/src/add-ons/kernel/drivers/audio/echo/util.h new file mode 100644 index 0000000000..02fb99225f --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/echo/util.h @@ -0,0 +1,50 @@ +/* + * BeOS Driver for Intel ICH AC'97 Link interface + * + * Copyright (c) 2002, Marcus Overhagen + * + * All rights reserved. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + + + +area_id alloc_mem(void **phy, void **log, size_t size, const char *name); + +cpu_status lock(void); +void unlock(cpu_status status); + +extern spinlock slock; + +#ifdef __cplusplus +} +#endif + +#endif