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
This commit is contained in:
@@ -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 = <kernel!drivers!dev!audio!multi>echo_24 ;
|
||||
local instDriver = <kernel!drivers!dev!audio!multi>echo24 ;
|
||||
MakeLocate $(instDriver) : $(dir) ;
|
||||
RelSymLink $(instDriver) : echo_24 ;
|
||||
RelSymLink $(instDriver) : echo24 ;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* EchoGals/Echo24 BeOS Driver for Echo audio cards
|
||||
*
|
||||
* Copyright (c) 2003, Jerome Duval ([email protected])
|
||||
*
|
||||
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
|
||||
* Copyright (c) 2002, Marcus Overhagen <[email protected]>
|
||||
*
|
||||
* 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 <KernelExport.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <OS.h>
|
||||
#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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* EchoGals/Echo24 BeOS Driver for Echo audio cards
|
||||
*
|
||||
* Copyright (c) 2003, Jerome Duval ([email protected])
|
||||
*
|
||||
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
|
||||
* Copyright (c) 2002, Marcus Overhagen <[email protected]>
|
||||
*
|
||||
* 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
|
||||
@@ -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 <KernelExport.h>
|
||||
#include <Drivers.h>
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
#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; i<stream->bufcount; 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<cnt; ix++) {
|
||||
echo_shutdown(&cards[ix]);
|
||||
}
|
||||
memset(&cards, 0, sizeof(cards));
|
||||
put_module(pci_name);
|
||||
}
|
||||
|
||||
|
||||
const char **
|
||||
publish_devices(void)
|
||||
{
|
||||
int ix = 0;
|
||||
PRINT(("publish_devices()\n"));
|
||||
|
||||
for (ix=0; names[ix]; ix++) {
|
||||
PRINT(("publish %s\n", names[ix]));
|
||||
}
|
||||
return (const char **)names;
|
||||
}
|
||||
|
||||
|
||||
device_hooks *
|
||||
find_device(const char * name)
|
||||
{
|
||||
int ix;
|
||||
|
||||
PRINT(("find_device(%s)\n", name));
|
||||
|
||||
for (ix=0; ix<num_cards; ix++) {
|
||||
if (!strcmp(cards[ix].name, name)) {
|
||||
return &multi_hooks;
|
||||
}
|
||||
}
|
||||
PRINT(("find_device(%s) failed\n", name));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32 api_version = B_CUR_DRIVER_API_VERSION;
|
||||
@@ -0,0 +1,137 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 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.
|
||||
|
||||
#ifndef _ECHO_H_
|
||||
#define _ECHO_H_
|
||||
|
||||
#include <PCI.h>
|
||||
#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_ */
|
||||
@@ -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 = <kernel!drivers!dev!audio!multi>echo_gals ;
|
||||
local instDriver = <kernel!drivers!dev!audio!multi>echogals ;
|
||||
MakeLocate $(instDriver) : $(dir) ;
|
||||
RelSymLink $(instDriver) : echo_gals ;
|
||||
RelSymLink $(instDriver) : echogals ;
|
||||
}
|
||||
|
||||
@@ -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 ****
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 ***
|
||||
|
||||
@@ -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 ****
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -47,10 +47,9 @@
|
||||
// ****************************************************************************
|
||||
|
||||
#include "CEchoGals.h"
|
||||
#include <stdarg.h>
|
||||
#include <RealtimeAlloc.h>
|
||||
#include <OS.h>
|
||||
#include <Alert.h>
|
||||
#include <KernelExport.h>
|
||||
#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 )
|
||||
|
||||
|
||||
@@ -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 <stdio.h>
|
||||
#include <endian.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <SupportDefs.h>
|
||||
#include <ByteOrder.h>
|
||||
#include "debug.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#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 <ByteOrder.h>
|
||||
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
|
||||
|
||||
@@ -0,0 +1,664 @@
|
||||
/*
|
||||
* EchoGals/Echo24 BeOS Driver for Echo audio cards
|
||||
*
|
||||
* Copyright (c) 2003, Jerome Duval ([email protected])
|
||||
*
|
||||
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
|
||||
* Copyright (c) 2002, Marcus Overhagen <[email protected]>
|
||||
*
|
||||
* 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 <OS.h>
|
||||
#include <MediaDefs.h>
|
||||
#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; i<card->multi.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; i<stream->channels; 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; i<BUFFER_COUNT; i++)
|
||||
for(j=0; j<pchannels; j++)
|
||||
echo_stream_get_nth_buffer(card->pstream, 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; i<BUFFER_COUNT; i++)
|
||||
for(j=0; j<rchannels; j++)
|
||||
echo_stream_get_nth_buffer(card->rstream, 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; ix<num_cards; ix++) {
|
||||
if (!strcmp(cards[ix].name, name)) {
|
||||
card = &cards[ix];
|
||||
}
|
||||
}
|
||||
|
||||
if(card == NULL) {
|
||||
LOG(("open() card not found %s\n", name));
|
||||
for (ix=0; ix<num_cards; ix++) {
|
||||
LOG(("open() card available %s\n", cards[ix].name));
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
LOG(("open() got card\n"));
|
||||
|
||||
if(card->pstream !=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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* EchoGals/Echo24 BeOS Driver for Echo audio cards
|
||||
*
|
||||
* Copyright (c) 2003, Jerome Duval ([email protected])
|
||||
*
|
||||
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
|
||||
* Copyright (c) 2002, Marcus Overhagen <[email protected]>
|
||||
*
|
||||
* 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
|
||||
@@ -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 [email protected] [1999-07-02] */
|
||||
|
||||
#if !defined(_MULTI_AUDIO_H)
|
||||
#define _MULTI_AUDIO_H
|
||||
|
||||
#include <Drivers.h>
|
||||
|
||||
#if !defined(ASSERT)
|
||||
#include <Debug.h>
|
||||
#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 <stdio.h>
|
||||
|
||||
#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 */
|
||||
|
||||
@@ -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_ */
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* BeOS Driver for Intel ICH AC'97 Link interface
|
||||
*
|
||||
* Copyright (c) 2002, Marcus Overhagen <[email protected]>
|
||||
*
|
||||
* 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 <Errors.h>
|
||||
#include <OS.h>
|
||||
#include <string.h>
|
||||
|
||||
//#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* BeOS Driver for Intel ICH AC'97 Link interface
|
||||
*
|
||||
* Copyright (c) 2002, Marcus Overhagen <[email protected]>
|
||||
*
|
||||
* 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 <KernelExport.h>
|
||||
|
||||
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user