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:
Jérôme Duval
2004-01-06 10:34:05 +00:00
parent b855ae3d39
commit 5adb129ea3
19 changed files with 5922 additions and 2659 deletions
@@ -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