Emuxki BeOS Driver for Creative Labs SBLive!/Audigy series.

Written by Jerome Duval.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2936 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper
2003-03-17 22:32:45 +00:00
parent 49fa1748f5
commit 30ace1d7c5
19 changed files with 7941 additions and 0 deletions
@@ -0,0 +1,19 @@
SubDir OBOS_TOP src add-ons kernel drivers audio emuxki ;
R5KernelAddon emuxki : kernel drivers bin :
ac97.c
debug.c
emuxki.c
io.c
midi.c
multi.c
util.c
;
# 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>emuxki ;
MakeLocate $(instDriver) : $(dir) ;
RelSymLink $(instDriver) : emuxki ;
}
@@ -0,0 +1,292 @@
/*
* Emuxki BeOS Driver for Creative Labs SBLive!/Audigy series
*
* Copyright (c) 2002, 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 <stdio.h>
#include <MediaDefs.h>
#include "ac97.h"
#define REVERSE_EAMP_POLARITY 0
#include "debug.h"
#include "io.h"
#define B_UTF8_REGISTERED "\xC2\xAE"
const char * stereo_enhancement_technique[] =
{
"No 3D Stereo Enhancement",
"Analog Devices",
"Creative Technology",
"National Semiconductor",
"Yamaha",
"BBE Sound",
"Crystal Semiconductor",
"Qsound Labs",
"Spatializer Audio Laboratories",
"SRS Labs",
"Platform Tech",
"AKM Semiconductor",
"Aureal",
"Aztech Labs",
"Binaura",
"ESS Technology",
"Harman International",
"Nvidea",
"Philips",
"Texas Instruments",
"VLSI Technology",
"TriTech",
"Realtek",
"Samsung",
"Wolfson Microelectronics",
"Delta Integration",
"SigmaTel",
"KS Waves",
"Rockwell",
"Unknown (29)",
"Unknown (30)",
"Unknown (31)"
};
typedef void (* codec_init)(device_config *);
typedef void (* codec_amp_enable)(device_config *, bool);
typedef struct codec_ops_tag
{
codec_init init;
codec_amp_enable amp_enable;
} codec_ops;
typedef struct codec_table_tag
{
uint32 id;
uint32 mask;
codec_ops *ops;
const char *info;
} codec_table;
void default_init(device_config *);
void ad1886_init(device_config *);
void default_amp_enable(device_config *, bool);
void cs4299_amp_enable(device_config *, bool);
codec_ops default_ops = { default_init, default_amp_enable };
codec_ops ad1886_ops = { ad1886_init, default_amp_enable };
codec_ops cs4299_ops = { default_init, cs4299_amp_enable };
codec_table codecs[] =
{
/* Vendor ID and description imported from FreeBSD src/sys/dev/sound/pcm/ac97.c */
{ 0x414b4d00, 0xffffffff, &default_ops, "Asahi Kasei AK4540" },
{ 0x414b4d01, 0xffffffff, &default_ops, "Asahi Kasei AK4542" },
{ 0x414b4d02, 0xffffffff, &default_ops, "Asahi Kasei AK4543" },
{ 0x43525900, 0xffffffff, &default_ops, "Cirrus Logic CS4297" },
{ 0x43525903, 0xffffffff, &default_ops, "Cirrus Logic CS4297" },
{ 0x43525913, 0xffffffff, &default_ops, "Cirrus Logic CS4297A" },
{ 0x43525914, 0xffffffff, &default_ops, "Cirrus Logic CS4297B" },
{ 0x43525923, 0xffffffff, &default_ops, "Cirrus Logic CS4294C" },
{ 0x4352592b, 0xffffffff, &default_ops, "Cirrus Logic CS4298C" },
{ 0x43525931, 0xffffffff, &cs4299_ops, "Cirrus Logic CS4299A" },
{ 0x43525933, 0xffffffff, &cs4299_ops, "Cirrus Logic CS4299C" },
{ 0x43525934, 0xffffffff, &cs4299_ops, "Cirrus Logic CS4299D" },
{ 0x43525941, 0xffffffff, &default_ops, "Cirrus Logic CS4201A" },
{ 0x43525951, 0xffffffff, &default_ops, "Cirrus Logic CS4205A" },
{ 0x43525961, 0xffffffff, &default_ops, "Cirrus Logic CS4291A" },
{ 0x45838308, 0xffffffff, &default_ops, "ESS Technology ES1921" },
{ 0x49434511, 0xffffffff, &default_ops, "ICEnsemble ICE1232" },
{ 0x4e534331, 0xffffffff, &default_ops, "National Semiconductor LM4549" },
{ 0x83847600, 0xffffffff, &default_ops, "SigmaTel STAC9700/9783/9784" },
{ 0x83847604, 0xffffffff, &default_ops, "SigmaTel STAC9701/9703/9704/9705" },
{ 0x83847605, 0xffffffff, &default_ops, "SigmaTel STAC9704" },
{ 0x83847608, 0xffffffff, &default_ops, "SigmaTel STAC9708/9711" },
{ 0x83847609, 0xffffffff, &default_ops, "SigmaTel STAC9721/9723" },
{ 0x83847644, 0xffffffff, &default_ops, "SigmaTel STAC9744" },
{ 0x83847656, 0xffffffff, &default_ops, "SigmaTel STAC9756/9757" },
{ 0x53494c22, 0xffffffff, &default_ops, "Silicon Laboratory Si3036" },
{ 0x53494c23, 0xffffffff, &default_ops, "Silicon Laboratory Si3038" },
{ 0x54524103, 0xffffffff, &default_ops, "TriTech TR?????" },
{ 0x54524106, 0xffffffff, &default_ops, "TriTech TR28026" },
{ 0x54524108, 0xffffffff, &default_ops, "TriTech TR28028" },
{ 0x54524123, 0xffffffff, &default_ops, "TriTech TR28602" },
{ 0x574d4c00, 0xffffffff, &default_ops, "Wolfson WM9701A" },
{ 0x574d4c03, 0xffffffff, &default_ops, "Wolfson WM9703/9704" },
{ 0x574d4c04, 0xffffffff, &default_ops, "Wolfson WM9704 (quad)" },
/* Assembled from datasheets: */
{ 0x41445303, 0xffffffff, &default_ops, "Analog Devices AD1819B SoundPort"B_UTF8_REGISTERED },
{ 0x41445340, 0xffffffff, &default_ops, "Analog Devices AD1881 SoundMAX"B_UTF8_REGISTERED },
{ 0x41445348, 0xffffffff, &default_ops, "Analog Devices AD1881A SoundMAX"B_UTF8_REGISTERED },
{ 0x41445360, 0xffffffff, &default_ops, "Analog Devices AD1885 SoundMAX"B_UTF8_REGISTERED },
{ 0x41445361, 0xffffffff, &ad1886_ops, "Analog Devices AD1886 SoundMAX"B_UTF8_REGISTERED },
{ 0x41445362, 0xffffffff, &default_ops, "Analog Devices AD1887 SoundMAX"B_UTF8_REGISTERED },
{ 0x41445363, 0xffffffff, &default_ops, "Analog Devices AD1886A SoundMAX"B_UTF8_REGISTERED },
{ 0x41445371, 0xffffffff, &default_ops, "Analog Devices AD1981A SoundMAX"B_UTF8_REGISTERED },
{ 0x41445372, 0xffffffff, &default_ops, "Analog Devices AD1981A SoundMAX"B_UTF8_REGISTERED },
{ 0x414c4320, 0xfffffff0, &default_ops, "Avance Logic (Realtek) ALC100/ALC100P, RL5383/RL5522" },
{ 0x414c4730, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC101" },
#if 0
{ 0x414c4710, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC200/ALC200A" }, /* datasheet says id2 = 4710 */
{ 0x414c4710, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC201/ALC201A" }, /* 4710 or 4720 */
{ 0x414c4720, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC650" }, /* datasheet says id2 = 4720 */
#else
{ 0x414c4710, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC200/ALC200A or ALC201/ALC201A" },
{ 0x414c4720, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC650 or ALC201/ALC201A" },
#endif
{ 0x414c4740, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC202/ALC202A" },
/* Vendors only: */
{ 0x41445300, 0xffffff00, &default_ops, "Analog Devices" },
{ 0x414b4d00, 0xffffff00, &default_ops, "Asahi Kasei" },
{ 0x414c4700, 0xffffff00, &default_ops, "Avance Logic (Realtek)" },
{ 0x43525900, 0xffffff00, &default_ops, "Cirrus Logic" },
{ 0x45838300, 0xffffff00, &default_ops, "ESS Technology" },
{ 0x49434500, 0xffffff00, &default_ops, "ICEnsemble" },
{ 0x4e534300, 0xffffff00, &default_ops, "National Semiconductor" },
{ 0x83847600, 0xffffff00, &default_ops, "SigmaTel" },
{ 0x53494c00, 0xffffff00, &default_ops, "Silicon Laboratory" },
{ 0x54524100, 0xffffff00, &default_ops, "TriTech" },
{ 0x574d4c00, 0xffffff00, &default_ops, "Wolfson" },
{ 0x00000000, 0x00000000, &default_ops, "Unknown" } /* must be last one, matches every codec */
};
codec_table *
find_codec_table(uint32 codecid)
{
codec_table *codec;
for (codec = codecs; codec->id; codec++)
if ((codec->id & codec->mask) == (codecid & codec->mask))
break;
return codec;
}
const char *
ac97_get_3d_stereo_enhancement(device_config *config)
{
uint16 data;
data = emuxki_codec_read(config, AC97_RESET);
data = (data >> 10) & 31;
return stereo_enhancement_technique[data];
}
const char *
ac97_get_vendor_id_description()
{
uint32 id = ac97_get_vendor_id();
codec_table *codec = find_codec_table(id);
char f = (id >> 24) & 0xff;
char s = (id >> 16) & 0xff;
char t = (id >> 8) & 0xff;
if (f == 0) f = '?';
if (s == 0) s = '?';
if (t == 0) t = '?';
LOG(("codec %c%c%c %u\n",f,s,t,id & 0xff));
LOG(("info: %s\n",codec->info));
return codec->info;
}
uint32
ac97_get_vendor_id(device_config *config)
{
uint16 data1;
uint16 data2;
data1 = emuxki_codec_read(config, AC97_VENDOR_ID1);
data2 = emuxki_codec_read(config, AC97_VENDOR_ID2);
return (((uint32)data1) << 16) | data2;
}
void
ac97_amp_enable(device_config *config, bool yesno)
{
codec_table *codec;
LOG(("ac97_amp_enable\n"));
codec = find_codec_table(ac97_get_vendor_id(config));
codec->ops->amp_enable(config, yesno);
}
void
ac97_init(device_config *config)
{
codec_table *codec;
LOG(("ac97_init\n"));
codec = find_codec_table(ac97_get_vendor_id(config));
codec->ops->init(config);
}
void default_init(device_config *config)
{
LOG(("default_init\n"));
}
void ad1886_init(device_config *config)
{
LOG(("ad1886_init\n"));
emuxki_codec_write(config, 0x72, 0x0010);
}
void default_amp_enable(device_config *config, bool yesno)
{
LOG(("default_amp_enable\n"));
LOG(("powerdown register was = %#04x\n",emuxki_codec_read(config, AC97_POWERDOWN)));
#if REVERSE_EAMP_POLARITY
yesno = !yesno;
LOG(("using reverse eamp polarity\n"));
#endif
if (yesno)
emuxki_codec_write(config, AC97_POWERDOWN, emuxki_codec_read(config, AC97_POWERDOWN) & ~0x8000); /* switch on (low active) */
else
emuxki_codec_write(config, AC97_POWERDOWN, emuxki_codec_read(config, AC97_POWERDOWN) | 0x8000); /* switch off */
LOG(("powerdown register is = %#04x\n", emuxki_codec_read(config, AC97_POWERDOWN)));
}
void cs4299_amp_enable(device_config *config, bool yesno)
{
LOG(("cs4299_amp_enable\n"));
if (yesno)
emuxki_codec_write(config, 0x68, 0x8004);
else
emuxki_codec_write(config, 0x68, 0);
}
const ac97_source_info source_info[] = {
{ "Record", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO|B_MIX_RECORDMUX, 100, AC97_RECORD_GAIN, 0x8000, 4, 0, 1, 0, 0.0, 22.5, 1.5 },
{ "Master", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 101, AC97_MASTER_VOLUME, 0x8000, 5, 0, 1, 1,-46.5, 0.0, 1.5 },
//{ "Bass/Trebble", B_MIX_GAIN|B_MIX_STEREO, 102, AC97_MASTER_TONE, 0x0f0f, 4, 0, 1, 1,-12.0, 10.5, 1.5 },
//{ "Aux Out", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 103, AC97_AUX_OUT_VOLUME, 0x8000, 5, 0, 1, 1,-46.5, 0.0, 1.5 },
{ "PCM Out", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 104, AC97_PCM_OUT_VOLUME, 0x8808, 5, 0, 1, 1,-34.5, 12.0, 1.5 },
{ "CD", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 105, AC97_CD_VOLUME, 0x8808, 5, 0, 1, 1,-34.5, 12.0, 1.5 },
{ "Aux In", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 106, AC97_AUX_IN_VOLUME, 0x8808, 5, 0, 1, 1,-34.5, 12.0, 1.5 },
{ "TAD", B_MIX_GAIN|B_MIX_MUTE|B_MIX_MONO, 107, AC97_PHONE_VOLUME, 0x8008, 5, 0, 1, 1,-34.5, 12.0, 1.5 },
{ "Mic", B_MIX_GAIN|B_MIX_MUTE|B_MIX_MONO|B_MIX_MICBOOST, 108, AC97_MIC_VOLUME, 0x8008, 5, 0, 1, 1,-34.5, 12.0, 1.5 },
{ "Line In", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 109, AC97_LINE_IN_VOLUME, 0x8808, 5, 0, 1, 1,-34.5, 12.0, 1.5 },
//{ "Center/Lfe", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 111, AC97_CENTER_LFE_VOLUME, 0x8080, 5, 0, 1, 1,-46.5, 0.0, 1.5 },
{ "Center/Lfe" /* should be "Surround" but no */, B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 110, AC97_SURROUND_VOLUME, 0x8080, 5, 0, 1, 1,-46.5, 0.0, 1.5 }
};
const int32 source_info_size = (sizeof(source_info)/sizeof(source_info[0]));
@@ -0,0 +1,107 @@
/*
* Emuxki BeOS Driver for Creative Labs SBLive!/Audigy series
*
* Copyright (c) 2002, 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 _AC97_H_
#define _AC97_H_
#include "config.h"
enum AC97_REGISTER {
AC97_RESET = 0x00,
AC97_MASTER_VOLUME = 0x02,
AC97_AUX_OUT_VOLUME = 0x04,
AC97_MONO_VOLUME = 0x06,
AC97_MASTER_TONE = 0x08,
AC97_PC_BEEP_VOLUME = 0x0A,
AC97_PHONE_VOLUME = 0x0C,
AC97_MIC_VOLUME = 0x0E,
AC97_LINE_IN_VOLUME = 0x10,
AC97_CD_VOLUME = 0x12,
AC97_VIDEO_VOLUME = 0x14,
AC97_AUX_IN_VOLUME = 0x16,
AC97_PCM_OUT_VOLUME = 0x18,
AC97_RECORD_SELECT = 0x1A,
AC97_RECORD_GAIN = 0x1C,
AC97_RECORD_GAIN_MIC = 0x1E,
AC97_GENERAL_PURPOSE = 0x20,
AC97_3D_CONTROL = 0x22,
AC97_PAGING = 0x24,
AC97_POWERDOWN = 0x26,
AC97_EXTENDED_AUDIO_ID = 0x28,
AC97_EXTENDED_AUDIO_STATUS = 0x2A,
AC97_PCM_FRONT_DAC_RATE = 0x2C,
AC97_PCM_SURR_DAC_RATE = 0x2E,
AC97_PCM_LFE_DAC_RATE = 0x30,
AC97_PCM_LR_ADC_RATE = 0x32,
AC97_MIC_ADC_RATE = 0x34,
AC97_CENTER_LFE_VOLUME = 0x36,
AC97_SURROUND_VOLUME = 0x38,
AC97_SPDIF_CONTROL = 0x3A,
AC97_VENDOR_ID1 = 0x7C,
AC97_VENDOR_ID2 = 0x7E
};
const char * ac97_get_3d_stereo_enhancement();
const char * ac97_get_vendor_id_description();
uint32 ac97_get_vendor_id();
void ac97_init();
void ac97_amp_enable(device_config *config, bool yesno);
typedef enum {
B_MIX_GAIN = 1 << 0,
B_MIX_MUTE = 1 << 1,
B_MIX_MONO = 1 << 2,
B_MIX_STEREO = 1 << 3,
B_MIX_MUX = 1 << 4,
B_MIX_MICBOOST = 1 << 5,
B_MIX_RECORDMUX = 1 << 6
} ac97_mixer_type;
typedef struct _ac97_source_info {
const char *name;
ac97_mixer_type type;
int32 id;
uint8 reg;
uint16 default_value;
uint8 bits:3;
uint8 ofs:4;
uint8 mute:1;
uint8 polarity:1; // max_gain -> 0
float min_gain;
float max_gain;
float granularity;
} ac97_source_info;
extern const ac97_source_info source_info[];
extern const int32 source_info_size;
#endif
@@ -0,0 +1,57 @@
/*
* Emuxki BeOS Driver for Creative Labs SBLive!/Audigy series
*
* Copyright (c) 2002, 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 _CONFIG_H_
#define _CONFIG_H_
#include <PCI.h>
#define NUM_CARDS 3
#define DEVNAME 32
typedef struct
{
const char *name;
uint32 nambar;
uint32 nabmbar;
uint32 irq;
int sample_size;
bool swap_reg;
uint32 type;
} device_config;
#define TYPE_AUDIGY 0x01
#define TYPE_AUDIGY2 0x02
#define TYPE_LIVE_5_1 0x04
#define IS_AUDIGY(x) ((x)->type & TYPE_AUDIGY)
#define IS_AUDIGY2(x) ((x)->type & TYPE_AUDIGY2)
#define IS_LIVE_5_1(x) ((x)->type & TYPE_LIVE_5_1)
#endif
@@ -0,0 +1,95 @@
/*
* Emuxki BeOS Driver for Creative Labs SBLive!/Audigy series
*
* Copyright (c) 2002, 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"
#include "emuxki.h"
#if DEBUG > 0
static const char * logfile="/boot/home/emuxki.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,70 @@
/*
* Emuxki BeOS Driver for Creative Labs SBLive!/Audigy series
*
* Copyright (c) 2002, 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_
/*
* 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__))
void log_create();
void log_printf(const char *text,...);
void debug_printf(const char *text,...);
#else
void debug_printf(const char *text,...);
#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
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,391 @@
/*
* Emuxki BeOS Driver for Creative Labs SBLive!/Audigy series
*
* Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr)
*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Yannick Montulet.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#if !defined(_EMUXKI_H)
#define _EMUXKI_H
#include <Drivers.h>
#include <SupportDefs.h>
#include <OS.h>
#include "emuxkireg.h"
#include "config.h"
#include "queue.h"
#include "multi_audio.h"
#include "multi.h"
#define CREATIVELABS_VENDOR_ID 0x1102 /* Creative Labs */
#define CREATIVELABS_SBLIVE_DEVICE_ID 0x0002 /* Creative Labs SoundBlaster Live */
#define CREATIVELABS_AUDIGY_DEVICE_ID 0x0004 /* Creative Labs Audigy and Audigy 2 */
#define AUDIGY 1 // Audigy is not tested for now, but Audigy 2 is
#define VERSION "Version alpha 4, Copyright (c) 2002 Jérôme Duval, compiled on " ## __DATE__ ## " " ## __TIME__
#define DRIVER_NAME "emuxki"
#define FRIENDLY_NAME "Emuxki"
#define FRIENDLY_NAME_LIVE FRIENDLY_NAME" SB Live"
#define FRIENDLY_NAME_LIVE_5_1 FRIENDLY_NAME_LIVE" 5.1"
#define FRIENDLY_NAME_AUDIGY FRIENDLY_NAME" Audigy"
#define FRIENDLY_NAME_AUDIGY2 FRIENDLY_NAME_AUDIGY" 2"
#define AUTHOR "Jérôme Duval"
/*
* Emu10k1 midi
*/
typedef struct _midi_dev {
struct _emuxki_dev *
card;
void * driver;
void * cookie;
int32 count;
char name[64];
} midi_dev;
/*
* Emu10k1 hardware limits
*/
#define EMU_PTESIZE 4096
#define EMU_MAXPTE ((EMU_CHAN_PSST_LOOPSTARTADDR_MASK + 1) / \
EMU_PTESIZE)
#define EMU_NUMCHAN 64
#define EMU_NUMRECSRCS 3
#define EMU_DMA_ALIGN 4096
#define EMU_DMAMEM_NSEG 1
/*
* Emu10k1 memory managment
*/
typedef struct _emuxki_mem {
LIST_ENTRY(_emuxki_mem) next;
uint16 ptbidx;
void *log_base;
void *phy_base;
area_id area;
size_t size;
#define EMU_RMEM 0xffff /* recording memory */
} emuxki_mem;
/*
* Emu10k1 play channel params
*/
typedef struct _emuxki_chanparms_fxsend {
struct {
uint8 level, dest;
} a, b, c, d, e, f, g, h;
} emuxki_chanparms_fxsend;
typedef struct _emuxki_chanparms_pitch {
uint16 intial; /* 4 bits of octave, 12 bits of fractional
* octave */
uint16 current;/* 0x4000 == unity pitch shift */
uint16 target; /* 0x4000 == unity pitch shift */
uint8 envelope_amount; /* Signed 2's complement, +/-
* one octave peak extremes */
} emuxki_chanparms_pitch;
typedef struct _emuxki_chanparms_envelope {
uint16 current_state; /* 0x8000-n == 666*n usec delay */
uint8 hold_time; /* 127-n == n*(volume ? 88.2 :
* 42)msec */
uint8 attack_time; /* 0 = infinite, 1 = (volume ? 11 :
* 10.9) msec, 0x7f = 5.5msec */
uint8 sustain_level; /* 127 = full, 0 = off, 0.75dB
* increments */
uint8 decay_time; /* 0 = 43.7msec, 1 = 21.8msec, 0x7f =
* 22msec */
} emuxki_chanparms_envelope;
typedef struct _emuxki_chanparms_volume {
uint16 current;
uint16 target;
emuxki_chanparms_envelope envelope;
} emuxki_chanparms_volume;
typedef struct _emuxki_chanparms_filter {
uint16 initial_cutoff_frequency;
/*
* 6 most significant bits are semitones, 2 least significant bits
* are fractions
*/
uint16 current_cutoff_frequency;
uint16 target_cutoff_frequency;
uint8 lowpass_resonance_height;
uint8 interpolation_ROM; /* 1 = full band, 7 = low
* pass */
uint8 envelope_amount; /* Signed 2's complement, +/-
* six octaves peak extremes */
uint8 LFO_modulation_depth; /* Signed 2's complement, +/-
* three octave extremes */
} emuxki_chanparms_filter;
typedef struct _emuxki_chanparms_loop {
uint32 start; /* index in the PTB (in samples) */
uint32 end; /* index in the PTB (in samples) */
} emuxki_chanparms_loop;
typedef struct _emuxki_chanparms_modulation {
emuxki_chanparms_envelope envelope;
uint16 LFO_state; /* 0x8000-n = 666*n usec delay */
} emuxki_chanparms_modulation;
typedef struct _emuxki_chanparms_vibrato_LFO {
uint16 state; /* 0x8000-n == 666*n usec delay */
uint8 modulation_depth; /* Signed 2's complement, +/-
* one octave extremes */
uint8 vibrato_depth; /* Signed 2's complement, +/- one
* octave extremes */
uint8 frequency; /* 0.039Hz steps, maximum of 9.85 Hz */
} emuxki_chanparms_vibrato_LFO;
typedef struct _emuxki_channel {
uint8 num; /* voice number */
struct _emuxki_voice *voice;
emuxki_chanparms_fxsend fxsend;
emuxki_chanparms_pitch pitch;
uint16 initial_attenuation; /* 0.375dB steps */
emuxki_chanparms_volume volume;
emuxki_chanparms_filter filter;
emuxki_chanparms_loop loop;
emuxki_chanparms_modulation modulation;
emuxki_chanparms_vibrato_LFO vibrato_LFO;
uint8 tremolo_depth;
} emuxki_channel;
typedef struct _emuxki_recparams {
uint32 efx_voices[2];
} emuxki_recparams;
/*
* Voices
*/
typedef enum {
EMU_RECSRC_MIC = 0,
EMU_RECSRC_ADC,
EMU_RECSRC_FX,
EMU_RECSRC_NOTSET
} emuxki_recsrc_t;
#define EMU_USE_PLAY (1 << 0)
#define EMU_USE_RECORD (1 << 1)
#define EMU_STATE_STARTED (1 << 0)
#define EMU_STEREO_NOTSET 0xFF
typedef struct _emuxki_voice {
struct _emuxki_stream *stream;
uint8 use;
uint8 voicenum;
uint8 state;
uint8 stereo;
uint8 b16;
uint32 sample_rate;
union {
emuxki_channel *chan[2];
emuxki_recsrc_t source;
} dataloc;
emuxki_recparams recparams;
emuxki_mem *buffer;
uint16 blksize;/* in samples */
uint16 trigblk;/* blk on which to trigger inth */
uint16 blkmod; /* Modulo value to wrap trigblk */
uint16 timerate;
LIST_ENTRY(_emuxki_voice) next;
} emuxki_voice;
/*
* Streams
*/
typedef struct _emuxki_stream {
struct _emuxki_dev *card;
uint8 use;
uint8 state;
uint8 stereo;
uint8 b16;
uint32 sample_rate;
uint8 nmono;
uint8 nstereo;
uint32 bufframes;
uint8 bufcount;
LIST_HEAD(, _emuxki_voice) voices;
emuxki_voice *first_voice;
LIST_ENTRY(_emuxki_stream) next;
void (*inth) (void *);
void *inthparam;
/* 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;
} emuxki_stream;
/*
* Mixer controls gpr
*/
#define EMU_GPR_FIRST_MIX 16
typedef enum {
EMU_MIX_GAIN = 1 << 0,
EMU_MIX_MONO = 1 << 1,
EMU_MIX_STEREO = 1 << 2,
EMU_MIX_TMP = 1 << 3,
EMU_MIX_MUTE = 1 << 4,
EMU_MIX_PLAYBACK = 1 << 5,
EMU_MIX_RECORD = 1 << 6
} emuxki_gpr_type;
typedef struct _emuxki_gpr {
char name[32];
emuxki_gpr_type type;
uint16 gpr;
float default_value;
float min_gain;
float max_gain;
float granularity;
float current[2];
bool mute;
} emuxki_gpr;
typedef enum {
EMU_DIGITAL_MODE = 1 << 0,
EMU_AUDIO_MODE = 1 << 1
} emuxki_parameter_type;
/*
* Devices
*/
typedef struct _emuxki_dev {
char name[DEVNAME]; /* used for resources */
pci_info info;
device_config config;
void *ptb_log_base;
void *ptb_phy_base;
area_id ptb_area;
void *silentpage_log_base;
void *silentpage_phy_base;
area_id silentpage_area;
emuxki_channel *channel[EMU_NUMCHAN];
emuxki_voice *recsrc[EMU_NUMRECSRCS];
LIST_HEAD(, _emuxki_mem) mem;
LIST_HEAD(, _emuxki_stream) streams;
uint8 timerstate;
uint16 timerate;
#define EMU_TIMER_STATE_ENABLED 1
uint8 play_mode; // number of channels to be played : 2, 4, 6
bool digital_enabled; // if digital is enabled and analog is disabled
emuxki_stream *pstream;
emuxki_stream *pstream2;
emuxki_stream *rstream;
emuxki_stream *rstream2;
sem_id buffer_ready_sem;
midi_dev midi;
/* mixer controls */
emuxki_gpr gpr[256];
uint32 gpr_count;
/* multi_audio */
multi_dev multi;
} emuxki_dev;
extern int32 num_cards;
extern emuxki_dev cards[NUM_CARDS];
void emuxki_mem_free(emuxki_dev *card, void *ptr);
void * emuxki_pmem_alloc(emuxki_dev *card, size_t size);
void * emuxki_rmem_alloc(emuxki_dev *card, size_t size);
status_t emuxki_voice_commit_parms(emuxki_voice *voice);
status_t emuxki_voice_set_audioparms(emuxki_voice *voice, uint8 stereo,
uint8 b16, uint32 srate);
status_t emuxki_voice_set_recparms(emuxki_voice *voice, emuxki_recsrc_t recsrc,
emuxki_recparams *recparams);
status_t emuxki_voice_set_bufparms(emuxki_voice *voice, void *ptr,
uint32 bufsize, uint16 blksize);
void emuxki_voice_start(emuxki_voice *voice);
void emuxki_voice_halt(emuxki_voice *voice);
emuxki_voice *emuxki_voice_new(emuxki_stream *stream, uint8 use, uint8 voicenum);
void emuxki_voice_delete(emuxki_voice *voice);
status_t emuxki_stream_set_audioparms(emuxki_stream *stream, bool stereo, uint8 channels,
uint8 b16, uint32 sample_rate);
status_t emuxki_stream_set_recparms(emuxki_stream *stream, emuxki_recsrc_t recsrc,
emuxki_recparams *recparams);
status_t emuxki_stream_commit_parms(emuxki_stream *stream);
status_t emuxki_stream_get_nth_buffer(emuxki_stream *stream, uint8 chan, uint8 buf,
char** buffer, size_t *stride);
void emuxki_stream_start(emuxki_stream *stream, void (*inth) (void *), void *inthparam);
void emuxki_stream_halt(emuxki_stream *stream);
emuxki_stream *emuxki_stream_new(emuxki_dev *card, uint8 use, uint32 bufframes, uint8 bufcount);
void emuxki_stream_delete(emuxki_stream *stream);
void emuxki_dump_fx(emuxki_dev * card);
void emuxki_gpr_dump(emuxki_dev * card, uint16 count);
void emuxki_gpr_set(emuxki_dev *card, emuxki_gpr *gpr, int32 type, float *values);
void emuxki_gpr_get(emuxki_dev *card, emuxki_gpr *gpr, int32 type, float *values);
void emuxki_parameter_set(emuxki_dev *card, const void*, int32 type, int32 *value);
void emuxki_parameter_get(emuxki_dev *card, const void*, int32 type, int32 *value);
extern void midi_interrupt_op(int32 op, void * data);
extern bool midi_interrupt(emuxki_dev *card);
#endif
@@ -0,0 +1,702 @@
/*
* Emuxki BeOS Driver for Creative Labs SBLive!/Audigy series
*
* Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr)
*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Yannick Montulet.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 _DEV_PCI_EMUXKIREG_H_
#define _DEV_PCI_EMUXKIREG_H_
/*
* Register values for Creative EMU10000. The register values have been
* taken from GPLed SBLive! header file published by Creative. The comments
* have been stripped to avoid GPL pollution in kernel. The Creative version
* including comments is available in Linux 2.4.* kernel as file
* drivers/sound/emu10k1/8010.h
*/
// Audigy specific registers contain a 'A_'
// Audigy(2) specific registers contain a 'A2_'
#define EMU_MKSUBREG(sz, idx, reg) (((sz) << 24) | ((idx) << 16) | (reg))
#define EMU_PTR 0x00
#define EMU_PTR_CHNO_MASK 0x0000003f
#define EMU_PTR_ADDR_MASK 0x07ff0000
#define EMU_A_PTR_ADDR_MASK 0x0fff0000
#define EMU_DATA 0x04
#define EMU_IPR 0x08
#define EMU_IPR_A_MIDITRANSBUFE2 0x10000000
#define EMU_IPR_A_MIDIRECVBUFE2 0x08000000
#define EMU_IPR_RATETRCHANGE 0x01000000
#define EMU_IPR_FXDSP 0x00800000
#define EMU_IPR_FORCEINT 0x00400000
#define EMU_PCIERROR 0x00200000
#define EMU_IPR_VOLINCR 0x00100000
#define EMU_IPR_VOLDECR 0x00080000
#define EMU_IPR_MUTE 0x00040000
#define EMU_IPR_MICBUFFULL 0x00020000
#define EMU_IPR_MICBUFHALFFULL 0x00010000
#define EMU_IPR_ADCBUFFULL 0x00008000
#define EMU_IPR_ADCBUFHALFFULL 0x00004000
#define EMU_IPR_EFXBUFFULL 0x00002000
#define EMU_IPR_EFXBUFHALFFULL 0x00001000
#define EMU_IPR_GPSPDIFSTCHANGE 0x00000800
#define EMU_IPR_CDROMSTCHANGE 0x00000400
#define EMU_IPR_INTERVALTIMER 0x00000200
#define EMU_IPR_MIDITRANSBUFE 0x00000100
#define EMU_IPR_MIDIRECVBUFE 0x00000080
#define EMU_IPR_CHANNELLOOP 0x00000040
#define EMU_IPR_CHNOMASK 0x0000003f
#define EMU_INTE 0x0c
#define EMU_INTE_VSB_MASK 0xc0000000
#define EMU_INTE_VSB_220 0x00000000
#define EMU_INTE_VSB_240 0x40000000
#define EMU_INTE_VSB_260 0x80000000
#define EMU_INTE_VSB_280 0xc0000000
#define EMU_INTE_VMPU_MASK 0x30000000
#define EMU_INTE_VMPU_300 0x00000000
#define EMU_INTE_VMPU_310 0x10000000
#define EMU_INTE_VMPU_320 0x20000000
#define EMU_INTE_VMPU_330 0x30000000
#define EMU_INTE_MDMAENABLE 0x08000000
#define EMU_INTE_SDMAENABLE 0x04000000
#define EMU_INTE_MPICENABLE 0x02000000
#define EMU_INTE_SPICENABLE 0x01000000
#define EMU_INTE_VSBENABLE 0x00800000
#define EMU_INTE_ADLIBENABLE 0x00400000
#define EMU_INTE_MPUENABLE 0x00200000
#define EMU_INTE_FORCEINT 0x00100000
#define EMU_INTE_MRHANDENABLE 0x00080000
#define EMU_INTE_SAMPLERATER 0x00002000
#define EMU_INTE_FXDSPENABLE 0x00001000
#define EMU_INTE_PCIERRENABLE 0x00000800
#define EMU_INTE_VOLINCRENABLE 0x00000400
#define EMU_INTE_VOLDECRENABLE 0x00000200
#define EMU_INTE_MUTEENABLE 0x00000100
#define EMU_INTE_MICBUFENABLE 0x00000080
#define EMU_INTE_ADCBUFENABLE 0x00000040
#define EMU_INTE_EFXBUFENABLE 0x00000020
#define EMU_INTE_GPSPDIFENABLE 0x00000010
#define EMU_INTE_CDSPDIFENABLE 0x00000008
#define EMU_INTE_INTERTIMERENB 0x00000004
#define EMU_INTE_MIDITXENABLE 0x00000002
#define EMU_INTE_MIDIRXENABLE 0x00000001
#define EMU_INTE_A_MIDITXENABLE2 0x00020000
#define EMU_INTE_A_MIDIRXENABLE2 0x00010000
#define EMU_WC 0x10
#define EMU_WC_SAMPLECOUNTER_MASK 0x03FFFFC0
#define EMU_WC_SAMPLECOUNTER EMU_MKSUBREG(20, 6, EMU_WC)
#define EMU_WC_CURRENTCHANNEL 0x0000003F
#define EMU_HCFG 0x14
#define EMU_HCFG_LEGACYFUNC_MASK 0xe0000000
#define EMU_HCFG_LEGACYFUNC_MPU 0x00000000
#define EMU_HCFG_LEGACYFUNC_SB 0x40000000
#define EMU_HCFG_LEGACYFUNC_AD 0x60000000
#define EMU_HCFG_LEGACYFUNC_MPIC 0x80000000
#define EMU_HCFG_LEGACYFUNC_MDMA 0xa0000000
#define EMU_HCFG_LEGACYFUNC_SPCI 0xc0000000
#define EMU_HCFG_LEGACYFUNC_SDMA 0xe0000000
#define EMU_HCFG_IOCAPTUREADDR 0x1f000000
#define EMU_HCFG_LEGACYWRITE 0x00800000
#define EMU_HCFG_LEGACYWORD 0x00400000
#define EMU_HCFG_LEGACYINT 0x00200000
#define EMU_HCFG_CODECFMT_MASK 0x00070000
#define EMU_HCFG_CODECFMT_AC97 0x00000000
#define EMU_HCFG_CODECFMT_I2S 0x00010000
#define EMU_HCFG_GPINPUT0 0x00004000
#define EMU_HCFG_GPINPUT1 0x00002000
#define EMU_HCFG_GPOUTPUT_MASK 0x00001c00
#define EMU_HCFG_GPOUTPUT0 0x00001000
#define EMU_HCFG_JOYENABLE 0x00000200
#define EMU_HCFG_PHASETRACKENABLE 0x00000100
#define EMU_HCFG_AC3ENABLE_MASK 0x000000e0
#define EMU_HCFG_AC3ENABLE_ZVIDEO 0x00000080
#define EMU_HCFG_AC3ENABLE_CDSPDIF 0x00000040
#define EMU_HCFG_AC3ENABLE_GPSPDIF 0x00000020
#define EMU_HCFG_AUTOMUTE 0x00000010
#define EMU_HCFG_LOCKSOUNDCACHE 0x00000008
#define EMU_HCFG_LOCKTANKCACHE_MASK 0x00000004
#define EMU_HCFG_LOCKTANKCACHE EMU_MKSUBREG(1, 2, EMU_HCFG)
#define EMU_HCFG_MUTEBUTTONENABLE 0x00000002
#define EMU_HCFG_AUDIOENABLE 0x00000001
#define EMU_MUDATA 0x18
#define EMU_MUCMD 0x19
#define EMU_MUCMD_RESET 0xff
#define EMU_MUCMD_ENTERUARTMODE 0x3f
#define EMU_MUSTAT EMU_MUCMD
#define EMU_MUSTAT_IRDYN 0x80
#define EMU_MUSTAT_ORDYN 0x40
#define EMU_A_IOCFG 0x18
#define EMU_A_GPINPUT_MASK 0xff00
#define EMU_A_GPOUTPUT_MASK 0x00ff
#define EMU_A_IOCFG_GPOUT0 0x0040
#define EMU_A_IOCFG_GPOUT1 0x0004
#define EMU_TIMER 0x1a
#define EMU_TIMER_RATE_MASK 0x000003ff
#define EMU_TIMER_RATE EMU_MKSUBREG(10, 0, EMU_TIMER)
#define EMU_AC97DATA 0x1c
#define EMU_AC97ADDR 0x1e
#define EMU_AC97ADDR_RDY 0x80
#define EMU_AC97ADDR_ADDR 0x7f
#define EMU_A2_PTR 0x20
#define EMU_A2_DATA 0x24
#define EMU_A2_SRCSEL 0x600000
#define EMU_A2_SRCSEL_ENABLE_SPDIF 0x00000004
#define EMU_A2_SRCSEL_ENABLE_SRCMULTI 0x00000010
#define EMU_A2_SRCMULTI 0x6e0000
#define EMU_A2_SRCMULTI_ENABLE_INPUT 0xff00ff00
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
#define EMU_CHAN_CPF 0x00
#define EMU_CHAN_CPF_PITCH_MASK 0xffff0000
#define EMU_CHAN_CPF_PITCH EMU_MKSUBREG(16, 16, EMU_CHAN_CPF)
#define EMU_CHAN_CPF_STEREO_MASK 0x00008000
#define EMU_CHAN_CPF_STEREO EMU_MKSUBREG(1, 15, EMU_CHAN_CPF)
#define EMU_CHAN_CPF_STOP_MASK 0x00004000
#define EMU_CHAN_CPF_FRACADDRESS_MASK 0x00003fff
#define EMU_CHAN_PTRX 0x01
#define EMU_CHAN_PTRX_PITCHTARGET_MASK 0xffff0000
#define EMU_CHAN_PTRX_PITCHTARGET EMU_MKSUBREG(16, 16, EMU_CHAN_PTRX)
#define EMU_CHAN_PTRX_FXSENDAMOUNT_A_MASK 0x0000ff00
#define EMU_CHAN_PTRX_FXSENDAMOUNT_A EMU_MKSUBREG(8, 8, EMU_CHAN_PTRX)
#define EMU_CHAN_PTRX_FXSENDAMOUNT_B_MASK 0x000000ff
#define EMU_CHAN_PTRX_FXSENDAMOUNT_B EMU_MKSUBREG(8, 0, EMU_CHAN_PTRX)
#define EMU_CHAN_CVCF 0x02
#define EMU_CHAN_CVCF_CURRVOL_MASK 0xffff0000
#define EMU_CHAN_CVCF_CURRVOL EMU_MKSUBREG(16, 16, EMU_CHAN_CVCF)
#define EMU_CHAN_CVCF_CURRFILTER_MASK 0x0000ffff
#define EMU_CHAN_CVCF_CURRFILTER EMU_MKSUBREG(16, 0, EMU_CHAN_CVCF)
#define EMU_CHAN_VTFT 0x03
#define EMU_CHAN_VTFT_VOLUMETARGET_MASK 0xffff0000
#define EMU_CHAN_VTFT_VOLUMETARGET EMU_MKSUBREG(16, 16, EMU_CHAN_VTFT)
#define EMU_CHAN_VTFT_FILTERTARGET_MASK 0x0000ffff
#define EMU_CHAN_VTFT_FILTERTARGET EMU_MKSUBREG(16, 0, EMU_CHAN_VTFT)
#define EMU_CHAN_Z1 0x05
#define EMU_CHAN_Z2 0x04
#define EMU_CHAN_PSST 0x06
#define EMU_CHAN_PSST_FXSENDAMOUNT_C_MASK 0xff000000
#define EMU_CHAN_PSST_FXSENDAMOUNT_C EMU_MKSUBREG(8, 24, EMU_CHAN_PSST)
#define EMU_CHAN_PSST_LOOPSTARTADDR_MASK 0x00ffffff
#define EMU_CHAN_PSST_LOOPSTARTADDR EMU_MKSUBREG(24, 0, EMU_CHAN_PSST)
#define EMU_CHAN_DSL 0x07
#define EMU_CHAN_DSL_FXSENDAMOUNT_D_MASK 0xff000000
#define EMU_CHAN_DSL_FXSENDAMOUNT_D EMU_MKSUBREG(8, 24, EMU_CHAN_DSL)
#define EMU_CHAN_DSL_LOOPENDADDR_MASK 0x00ffffff
#define EMU_CHAN_DSL_LOOPENDADDR EMU_MKSUBREG(24, 0, EMU_CHAN_DSL)
#define EMU_CHAN_CCCA 0x08
#define EMU_CHAN_CCCA_RESONANCE 0xf0000000
#define EMU_CHAN_CCCA_INTERPROMMASK 0x0e000000
#define EMU_CHAN_CCCA_INTERPROM_0 0x00000000
#define EMU_CHAN_CCCA_INTERPROM_1 0x02000000
#define EMU_CHAN_CCCA_INTERPROM_2 0x04000000
#define EMU_CHAN_CCCA_INTERPROM_3 0x06000000
#define EMU_CHAN_CCCA_INTERPROM_4 0x08000000
#define EMU_CHAN_CCCA_INTERPROM_5 0x0a000000
#define EMU_CHAN_CCCA_INTERPROM_6 0x0c000000
#define EMU_CHAN_CCCA_INTERPROM_7 0x0e000000
#define EMU_CHAN_CCCA_8BITSELECT 0x01000000
#define EMU_CHAN_CCCA_CURRADDR_MASK 0x00ffffff
#define EMU_CHAN_CCCA_CURRADDR EMU_MKSUBREG(24, 0, EMU_CHAN_CCCA)
#define EMU_CHAN_CCR 0x09
#define EMU_CHAN_CCR_CACHEINVALIDSIZE_MASK 0xfe000000
#define EMU_CHAN_CCR_CACHEINVALIDSIZE EMU_MKSUBREG(7, 25, EMU_CHAN_CCR)
#define EMU_CHAN_CCR_CACHELOOPFLAG 0x01000000
#define EMU_CHAN_CCR_INTERLEAVEDSAMPLES 0x00800000
#define EMU_CHAN_CCR_WORDSIZEDSAMPLES 0x00400000
#define EMU_CHAN_CCR_READADDRESS_MASK 0x003f0000
#define EMU_CHAN_CCR_READADDRESS EMU_MKSUBREG(6, 16, EMU_CHAN_CCR)
#define EMU_CHAN_CCR_LOOPINVALSIZE 0x0000fe00
#define EMU_CHAN_CCR_LOOPFLAG 0x00000100
#define EMU_CHAN_CCR_CACHELOOPADDRHI 0x000000ff
#define EMU_CHAN_CLP 0x0a
#define EMU_CHAN_CLP_CACHELOOPADDR 0x0000ffff
#define EMU_CHAN_FXRT 0x0b
#define EMU_CHAN_FXRT_CHANNELA 0x000f0000
#define EMU_CHAN_FXRT_CHANNELB 0x00f00000
#define EMU_CHAN_FXRT_CHANNELC 0x0f000000
#define EMU_CHAN_FXRT_CHANNELD 0xf0000000
#define EMU_CHAN_MAPA 0x0c
#define EMU_CHAN_MAPB 0x0d
#define EMU_CHAN_MAP_PTE_MASK 0xffffe000
#define EMU_CHAN_MAP_PTI_MASK 0x00001fff
#define EMU_CHAN_ENVVOL 0x10
#define EMU_CHAN_ENVVOL_MASK 0x0000ffff
#define EMU_CHAN_ATKHLDV 0x11
#define EMU_CHAN_ATKHLDV_PHASE0 0x00008000
#define EMU_CHAN_ATKHLDV_HOLDTIME_MASK 0x00007f00
#define EMU_CHAN_ATKHLDV_ATTACKTIME_MASK 0x0000007f
#define EMU_CHAN_DCYSUSV 0x12
#define EMU_CHAN_DCYSUSV_PHASE1_MASK 0x00008000
#define EMU_CHAN_DCYSUSV_SUSTAINLEVEL_MASK 0x00007f00
#define EMU_CHAN_DCYSUSV_CHANNELENABLE_MASK 0x00000080
#define EMU_CHAN_DCYSUSV_DECAYTIME_MASK 0x0000007f
#define EMU_CHAN_LFOVAL1 0x13
#define EMU_CHAN_LFOVAL_MASK 0x0000ffff
#define EMU_CHAN_ENVVAL 0x14
#define EMU_CHAN_ENVVAL_MASK 0x0000ffff
#define EMU_CHAN_ATKHLDM 0x15
#define EMU_CHAN_ATKHLDM_PHASE0 0x00008000
#define EMU_CHAN_ATKHLDM_HOLDTIME 0x00007f00
#define EMU_CHAN_ATKHLDM_ATTACKTIME 0x0000007f
#define EMU_CHAN_DCYSUSM 0x16
#define EMU_CHAN_DCYSUSM_PHASE1_MASK 0x00008000
#define EMU_CHAN_DCYSUSM_SUSTAINLEVEL_MASK 0x00007f00
#define EMU_CHAN_DCYSUSM_DECAYTIME_MASK 0x0000007f
#define EMU_CHAN_LFOVAL2 0x17
#define EMU_CHAN_LFOVAL2_MASK 0x0000ffff
#define EMU_CHAN_IP 0x18
#define EMU_CHAN_IP_MASK 0x0000ffff
#define EMU_CHAN_IP_UNITY 0x0000e000
#define EMU_CHAN_IFATN 0x19
#define EMU_CHAN_IFATN_FILTERCUTOFF_MASK 0x0000ff00
#define EMU_CHAN_IFATN_FILTERCUTOFF EMU_MKSUBREG(8, 8, EMU_CHAN_IFATN)
#define EMU_CHAN_IFATN_ATTENUATION_MASK 0x000000ff
#define EMU_CHAN_IFATN_ATTENUATION EMU_MKSUBREG(8, 0, EMU_CHAN_IFATN)
#define EMU_CHAN_PEFE 0x1a
#define EMU_CHAN_PEFE_PITCHAMOUNT_MASK 0x0000ff00
#define EMU_CHAN_PEFE_PITCHAMOUNT EMU_MKSUBREG(8, 8, EMU_CHAN_PEFE)
#define EMU_CHAN_PEFE_FILTERAMOUNT_MASK 0x000000ff
#define EMU_CHAN_PEFE_FILTERAMOUNT EMU_MKSUBREG(8, 0, EMU_CHAN_PEFE)
#define EMU_CHAN_FMMOD 0x1b
#define EMU_CHAN_FMMOD_MODVIBRATO 0x0000ff00
#define EMU_CHAN_FMMOD_MOFILTER 0x000000ff
#define EMU_CHAN_TREMFRQ 0x1c
#define EMU_CHAN_TREMFRQ_DEPTH 0x0000ff00
#define EMU_CHAN_FM2FRQ2 0x1d
#define EMU_CHAN_FM2FRQ2_DEPTH 0x0000ff00
#define EMU_CHAN_FM2FRQ2_FREQUENCY 0x000000ff
#define EMU_CHAN_TEMPENV 0x1e
#define EMU_CHAN_TEMPENV_MASK 0x0000ffff
#define EMU_CHAN_CD0 0x20
#define EMU_CHAN_CD1 0x21
#define EMU_CHAN_CD2 0x22
#define EMU_CHAN_CD3 0x23
#define EMU_CHAN_CD4 0x24
#define EMU_CHAN_CD5 0x25
#define EMU_CHAN_CD6 0x26
#define EMU_CHAN_CD7 0x27
#define EMU_CHAN_CD8 0x28
#define EMU_CHAN_CD9 0x29
#define EMU_CHAN_CDA 0x2a
#define EMU_CHAN_CDB 0x2b
#define EMU_CHAN_CDC 0x2c
#define EMU_CHAN_CDD 0x2d
#define EMU_CHAN_CDE 0x2e
#define EMU_CHAN_CDF 0x2f
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
#define EMU_PTB 0x40
#define EMU_PTB_MASK 0xfffff000
#define EMU_TCB 0x41
#define EMU_TCB_MASK 0xfffff000
#define EMU_ADCCR 0x42
#define EMU_ADCCR_RCHANENABLE 0x00000010
#define EMU_ADCCR_LCHANENABLE 0x00000008
#define EMU_ADCCR_SAMPLERATE_MASK 0x00000007
#define EMU_A_ADCCR_RCHANENABLE 0x00000020
#define EMU_A_ADCCR_LCHANENABLE 0x00000010
#define EMU_A_ADCCR_SAMPLERATE_MASK 0x0000000F
#define EMU_ADCCR_SAMPLERATE_48 0x00000000
#define EMU_ADCCR_SAMPLERATE_44 0x00000001
#define EMU_ADCCR_SAMPLERATE_32 0x00000002
#define EMU_ADCCR_SAMPLERATE_24 0x00000003
#define EMU_ADCCR_SAMPLERATE_22 0x00000004
#define EMU_ADCCR_SAMPLERATE_16 0x00000005
#define EMU_ADCCR_SAMPLERATE_11 0x00000006
#define EMU_ADCCR_SAMPLERATE_8 0x00000007
#define EMU_A_ADCCR_SAMPLERATE_12 0x00000006
#define EMU_A_ADCCR_SAMPLERATE_11 0x00000007
#define EMU_A_ADCCR_SAMPLERATE_8 0x00000008
#define EMU_FXWC 0x43
#define EMU_TCBS 0x44
#define EMU_TCBS_MASK 0x00000007
#define EMU_TCBS_BUFFSIZE_16K 0x00000000
#define EMU_TCBS_BUFFSIZE_32K 0x00000001
#define EMU_TCBS_BUFFSIZE_64K 0x00000002
#define EMU_TCBS_BUFFSIZE_128K 0x00000003
#define EMU_TCBS_BUFFSIZE_256K 0x00000004
#define EMU_TCBS_BUFFSIZE_512K 0x00000005
#define EMU_TCBS_BUFFSIZE_1024K 0x00000006
#define EMU_TCBS_BUFFSIZE_2048K 0x00000007
#define EMU_MICBA 0x45
#define EMU_ADCBA 0x46
#define EMU_FXBA 0x47
#define EMU_RECBA_MASK 0xfffff000
#define EMU_MICBS 0x49
#define EMU_ADCBS 0x4a
#define EMU_FXBS 0x4b
#define EMU_RECBS_BUFSIZE_NONE 0x00000000
#define EMU_RECBS_BUFSIZE_384 0x00000001
#define EMU_RECBS_BUFSIZE_448 0x00000002
#define EMU_RECBS_BUFSIZE_512 0x00000003
#define EMU_RECBS_BUFSIZE_640 0x00000004
#define EMU_RECBS_BUFSIZE_768 0x00000005
#define EMU_RECBS_BUFSIZE_896 0x00000006
#define EMU_RECBS_BUFSIZE_1024 0x00000007
#define EMU_RECBS_BUFSIZE_1280 0x00000008
#define EMU_RECBS_BUFSIZE_1536 0x00000009
#define EMU_RECBS_BUFSIZE_1792 0x0000000a
#define EMU_RECBS_BUFSIZE_2048 0x0000000b
#define EMU_RECBS_BUFSIZE_2560 0x0000000c
#define EMU_RECBS_BUFSIZE_3072 0x0000000d
#define EMU_RECBS_BUFSIZE_3584 0x0000000e
#define EMU_RECBS_BUFSIZE_4096 0x0000000f
#define EMU_RECBS_BUFSIZE_5120 0x00000010
#define EMU_RECBS_BUFSIZE_6144 0x00000011
#define EMU_RECBS_BUFSIZE_7168 0x00000012
#define EMU_RECBS_BUFSIZE_8192 0x00000013
#define EMU_RECBS_BUFSIZE_10240 0x00000014
#define EMU_RECBS_BUFSIZE_12288 0x00000015
#define EMU_RECBS_BUFSIZE_14366 0x00000016
#define EMU_RECBS_BUFSIZE_16384 0x00000017
#define EMU_RECBS_BUFSIZE_20480 0x00000018
#define EMU_RECBS_BUFSIZE_24576 0x00000019
#define EMU_RECBS_BUFSIZE_28672 0x0000001a
#define EMU_RECBS_BUFSIZE_32768 0x0000001b
#define EMU_RECBS_BUFSIZE_40960 0x0000001c
#define EMU_RECBS_BUFSIZE_49152 0x0000001d
#define EMU_RECBS_BUFSIZE_57344 0x0000001e
#define EMU_RECBS_BUFSIZE_65536 0x0000001f
#define EMU_CDCS 0x50
#define EMU_GPSCS 0x51
#define EMU_DBG 0x52
#define EMU_DBG_ZC 0x80000000
#define EMU_DBG_SATURATION_OCCURED 0x02000000
#define EMU_DBG_SATURATION_ADDR 0x01ff0000
#define EMU_DBG_SINGLE_STEP 0x00008000
#define EMU_DBG_STEP 0x00004000
#define EMU_DBG_CONDITION_CODE 0x00003e00
#define EMU_DBG_SINGLE_STEP_ADDR 0x000001ff
#define EMU_REG53 0x53
#define EMU_A_DBG 0x53
#define EMU_A_DBG_SINGLE_STEP 0x00020000
#define EMU_A_DBG_ZC 0x40000000
#define EMU_A_DBG_STEP_ADDR 0x000003ff
#define EMU_A_DBG_SATURATION_OCCRD 0x20000000
#define EMU_A_DBG_SATURATION_ADDR 0x0ffc0000
#define EMU_SPCS0 0x54
#define EMU_SPCS1 0x55
#define EMU_SPCS2 0x56
#define EMU_SPCS_CLKACCYMASK 0x30000000
#define EMU_SPCS_CLKACCY_1000PPM 0x00000000
#define EMU_SPCS_CLKACCY_50PPM 0x10000000
#define EMU_SPCS_CLKACCY_VARIABLE 0x20000000
#define EMU_SPCS_SAMPLERATEMASK 0x0f000000
#define EMU_SPCS_SAMPLERATE_44 0x00000000
#define EMU_SPCS_SAMPLERATE_48 0x02000000
#define EMU_SPCS_SAMPLERATE_32 0x03000000
#define EMU_SPCS_CHANNELNUMMASK 0x00f00000
#define EMU_SPCS_CHANNELNUM_UNSPEC 0x00000000
#define EMU_SPCS_CHANNELNUM_LEFT 0x00100000
#define EMU_SPCS_CHANNELNUM_RIGHT 0x00200000
#define EMU_SPCS_SOURCENUMMASK 0x000f0000
#define EMU_SPCS_SOURCENUM_UNSPEC 0x00000000
#define EMU_SPCS_GENERATIONSTATUS 0x00008000
#define EMU_SPCS_CATEGORYCODEMASK 0x00007f00
#define EMU_SPCS_MODEMASK 0x000000c0
#define EMU_SPCS_EMPHASISMASK 0x00000038
#define EMU_SPCS_EMPHASIS_NONE 0x00000000
#define EMU_SPCS_EMPHASIS_50_15 0x00000008
#define EMU_SPCS_COPYRIGHT 0x00000004
#define EMU_SPCS_NOTAUDIODATA 0x00000002
#define EMU_SPCS_PROFESSIONAL 0x00000001
#define EMU_CLIEL 0x58
#define EMU_CLIEH 0x59
#define EMU_CLIPL 0x5a
#define EMU_CLIPH 0x5b
#define EMU_SOLEL 0x5c
#define EMU_SOLEH 0x5d
#define EMU_SPBYPASS 0x5e
#define EMU_SPBYPASS_ENABLE 0x00000001
#define EMU_AC97SLOT 0x5f
#define EMU_AC97SLOT_CENTER 0x00000010
#define EMU_AC97SLOT_LFE 0x00000020
#define EMU_CDSRCS 0x60
#define EMU_GPSRCS 0x61
#define EMU_ZVSRCS 0x62
#define EMU_SRCS_SPDIFLOCKED 0x02000000
#define EMU_SRCS_RATELOCKED 0x01000000
#define EMU_SRCS_ESTSAMPLERATE 0x0007ffff
#define EMU_MICIDX 0x63
#define EMU_A_MICIDX 0x64
#define EMU_ADCIDX 0x64
#define EMU_A_ADCIDX 0x63
#define EMU_FXIDX 0x65
#define EMU_RECIDX_MASK 0x0000ffff
#define EMU_RECIDX(idxreg) (0x10000000|(idxreg))
#define EMU_A_MUDATA1 0x70
#define EMU_A_MUCMD1 0x71
#define EMU_A_MUSTAT1 EMU_A_MUCMD1
#define EMU_A_MUDATA2 0x72
#define EMU_A_MUCMD2 0x73
#define EMU_A_MUSTAT2 EMU_A_MUCMD2
#define EMU_A_FXWC1 0x74
#define EMU_A_FXWC2 0x75
#define EMU_A_SPDIF_SAMPLERATE 0x76
#define EMU_A_SPDIF_48000 0x00000080
#define EMU_A_SPDIF_44100 0x00000000
#define EMU_A_SPDIF_96000 0x00000040
#define EMU_A2_SPDIF_SAMPLERATE EMU_MKSUBREG(3, 9, EMU_A_SPDIF_SAMPLERATE)
#define EMU_A2_SPDIF_MASK 0x00000e00
#define EMU_A2_SPDIF_UNKNOWN 0x2
#define EMU_A_CHAN_FXRT2 0x7c
#define EMU_A_CHAN_FXRT_CHANNELE 0x0000003f
#define EMU_A_CHAN_FXRT_CHANNELF 0x00003f00
#define EMU_A_CHAN_FXRT_CHANNELG 0x003f0000
#define EMU_A_CHAN_FXRT_CHANNELH 0x3f000000
#define EMU_A_CHAN_SENDAMOUNTS 0x7d
#define EMU_A_CHAN_FXSENDAMOUNTS_E_MASK 0xff000000
#define EMU_A_CHAN_FXSENDAMOUNTS_F_MASK 0x00ff0000
#define EMU_A_CHAN_FXSENDAMOUNTS_G_MASK 0x0000ff00
#define EMU_A_CHAN_FXSENDAMOUNTS_H_MASK 0x000000ff
#define EMU_A_CHAN_FXRT1 0x7e
#define EMU_A_CHAN_FXRT_CHANNELA 0x0000003f
#define EMU_A_CHAN_FXRT_CHANNELB 0x00003f00
#define EMU_A_CHAN_FXRT_CHANNELC 0x003f0000
#define EMU_A_CHAN_FXRT_CHANNELD 0x3f000000
#define EMU_FXGPREGBASE 0x100
#define EMU_A_FXGPREGBASE 0x400
#define EMU_TANKMEMDATAREGBASE 0x200
#define EMU_TANKMEMDATAREG_MASK 0x000fffff
#define EMU_TANKMEMADDRREGBASE 0x300
#define EMU_TANKMEMADDRREG_ADDR_MASK 0x000fffff
#define EMU_TANKMEMADDRREG_CLEAR 0x00800000
#define EMU_TANKMEMADDRREG_ALIGN 0x00400000
#define EMU_TANKMEMADDRREG_WRITE 0x00200000
#define EMU_TANKMEMADDRREG_READ 0x00100000
#define EMU_MICROCODEBASE 0x400
#define EMU_DSP_LOWORD_OPX_MASK 0x000ffc00
#define EMU_DSP_LOWORD_OPY_MASK 0x000003ff
#define EMU_DSP_HIWORD_OPCODE_MASK 0x00f00000
#define EMU_DSP_HIWORD_RESULT_MASK 0x000ffc00
#define EMU_DSP_HIWORD_OPA_MASK 0x000003ff
#define EMU_A_MICROCODEBASE 0x600
#define EMU_A_DSP_LOWORD_OPX_MASK 0x007ff000
#define EMU_A_DSP_LOWORD_OPY_MASK 0x000007ff
#define EMU_A_DSP_HIWORD_OPCODE_MASK 0x0f000000
#define EMU_A_DSP_HIWORD_RESULT_MASK 0x007ff000
#define EMU_A_DSP_HIWORD_OPA_MASK 0x000007ff
#define EMU_DSP_OP_MACS 0x0
#define EMU_DSP_OP_MACS1 0x1
#define EMU_DSP_OP_MACW 0x2
#define EMU_DSP_OP_MACW1 0x3
#define EMU_DSP_OP_MACINTS 0x4
#define EMU_DSP_OP_MACINTW 0x5
#define EMU_DSP_OP_ACC3 0x6
#define EMU_DSP_OP_MACMV 0x7
#define EMU_DSP_OP_ANDXOR 0x8
#define EMU_DSP_OP_TSTNEG 0x9
#define EMU_DSP_OP_LIMIT 0xa
#define EMU_DSP_OP_LIMIT1 0xb
#define EMU_DSP_OP_LOG 0xc
#define EMU_DSP_OP_EXP 0xd
#define EMU_DSP_OP_INTERP 0xe
#define EMU_DSP_OP_SKIP 0xf
#define EMU_DSP_FX(num) (num)
#define EMU_DSP_IOL(base, num) (base + (num << 1))
#define EMU_DSP_IOR(base, num) (EMU_DSP_IOL(base, num) + 1)
#define EMU_DSP_INL_BASE 0x010
#define EMU_DSP_INL(num) (EMU_DSP_IOL(EMU_DSP_INL_BASE, num))
#define EMU_DSP_INR(num) (EMU_DSP_IOR(EMU_DSP_INL_BASE, num))
#define EMU_DSP_IN_AC97 0
#define EMU_DSP_IN_CDSPDIF 1
#define EMU_DSP_IN_ZOOM 2
#define EMU_DSP_IN_TOSOPT 3
#define EMU_DSP_IN_LVDLM1 4
#define EMU_DSP_IN_LVDCOS 5
#define EMU_DSP_IN_LVDLM2 6
#define EMU_DSP_IN_UNKOWN 7
#define EMU_A_DSP_INL_BASE 0x040
#define EMU_A_DSP_INL(num) (EMU_DSP_IOL(EMU_A_DSP_INL_BASE, num))
#define EMU_A_DSP_INR(num) (EMU_DSP_IOR(EMU_A_DSP_INL_BASE, num))
#define EMU_DSP_OUTL_BASE 0x020
#define EMU_DSP_OUTL(num) (EMU_DSP_IOL(EMU_DSP_OUTL_BASE, num))
#define EMU_DSP_OUTR(num) (EMU_DSP_IOR(EMU_DSP_OUTL_BASE, num))
#define EMU_DSP_OUT_A_FRONT 0
#define EMU_DSP_OUT_D_FRONT 1 // not tested
#define EMU_DSP_OUT_D_CENTER 2 // not tested
#define EMU_DSP_OUT_DRIVE_HP 3 // not tested
#define EMU_DSP_OUT_AD_REAR 4
#define EMU_DSP_OUT_ADC 5
#define EMU_DSP_OUTL_MIC 6
#define EMU_DSP_OUT_A_CENTER (EMU_DSP_IOR(EMU_DSP_OUTL_BASE, 8)) // Live 5.1 only
#define EMU_DSP_OUT_A_SUB (EMU_DSP_IOL(EMU_DSP_OUTL_BASE, 9)) // Live 5.1 only
#define EMU_A_DSP_OUTL_BASE 0x060
#define EMU_A_DSP_OUTL(num) (EMU_DSP_IOL(EMU_A_DSP_OUTL_BASE, num))
#define EMU_A_DSP_OUTR(num) (EMU_DSP_IOR(EMU_A_DSP_OUTL_BASE, num))
#define EMU_A_DSP_OUT_D_FRONT 0 // not tested
#define EMU_A_DSP_OUT_D_CENTER 1 // not tested
#define EMU_A_DSP_OUT_DRIVE_HP 2 // not tested
#define EMU_A_DSP_OUT_D_REAR 3 // not tested
#define EMU_A_DSP_OUT_A_FRONT 4
#define EMU_A_DSP_OUT_A_CENTER 5
#define EMU_A_DSP_OUT_A_REAR 7
#define EMU_A_DSP_OUT_ADC 11
#define EMU_DSP_CST_BASE 0x40
#define EMU_A_DSP_CST_BASE 0xc0
#define EMU_DSP_CST(num) (EMU_DSP_CST_BASE + num)
#define EMU_A_DSP_CST(num) (EMU_A_DSP_CST_BASE + num)
/*
00 = 0x00000000
01 = 0x00000001
02 = 0x00000002
03 = 0x00000003
04 = 0x00000004
05 = 0x00000008
06 = 0x00000010
07 = 0x00000020
08 = 0x00000100
09 = 0x00010000
0A = 0x00080000
0B = 0x10000000
0C = 0x20000000
0D = 0x40000000
0E = 0x80000000
0F = 0x7FFFFFFF
10 = 0xFFFFFFFF
11 = 0xFFFFFFFE
12 = 0xC0000000
13 = 0x4F1BBCDC
14 = 0x5A7EF9DB
15 = 0x00100000
*/
#define EMU_DSP_HWR_ACC 0x056
#define EMU_DSP_HWR_CCR 0x057
#define EMU_DSP_HWR_CCR_S 0x04
#define EMU_DSP_HWR_CCR_Z 0x03
#define EMU_DSP_HWR_CCR_M 0x02
#define EMU_DSP_HWR_CCR_N 0x01
#define EMU_DSP_HWR_CCR_B 0x00
#define EMU_DSP_HWR_NOISE0 0x058
#define EMU_DSP_HWR_NOISE1 0x059
#define EMU_DSP_HWR_INTR 0x05A
#define EMU_DSP_HWR_DBAC 0x05B
#define EMU_DSP_GPR(num) (EMU_FXGPREGBASE + num)
#define EMU_A_DSP_GPR(num) (EMU_A_FXGPREGBASE + num)
#endif /* _DEV_PCI_EMUXKIREG_H_ */
@@ -0,0 +1,236 @@
/*
* Emuxki BeOS Driver for Creative Labs SBLive!/Audigy series
*
* Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr)
*
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
* Copyright (c) 2002, Marcus Overhagen <marcus@overhagen.de>
*
* 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 <OS.h>
#include "io.h"
#include "emuxkireg.h"
/*
* from BeOS R3 KernelExport.h
* should be replaced by PCI bus manager functions
*/
uint8 read_io_8(int mapped_io_addr);
void write_io_8(int mapped_io_addr, uint8 value);
uint16 read_io_16(int mapped_io_addr);
void write_io_16(int mapped_io_addr, uint16 value);
uint32 read_io_32(int mapped_io_addr);
void write_io_32(int mapped_io_addr, uint32 value);
uint8
emuxki_reg_read_8(device_config *config, int regno)
{
return read_io_8(config->nabmbar + regno);
}
uint16
emuxki_reg_read_16(device_config *config, int regno)
{
return read_io_16(config->nabmbar + regno);
}
uint32
emuxki_reg_read_32(device_config *config, int regno)
{
return read_io_32(config->nabmbar + regno);
}
void
emuxki_reg_write_8(device_config *config, int regno, uint8 value)
{
write_io_8(config->nabmbar + regno, value);
}
void
emuxki_reg_write_16(device_config *config, int regno, uint16 value)
{
write_io_16(config->nabmbar + regno, value);
}
void
emuxki_reg_write_32(device_config *config, int regno, uint32 value)
{
write_io_32(config->nabmbar + regno, value);
}
/* Emu10k1 Low level */
uint32
emuxki_chan_read(device_config *config, uint16 chano, uint32 reg)
{
uint32 ptr, mask = 0xFFFFFFFF;
uint8 size, offset = 0;
ptr = ((((uint32) reg) << 16) &
(IS_AUDIGY(config) ? EMU_A_PTR_ADDR_MASK : EMU_PTR_ADDR_MASK)) |
(chano & EMU_PTR_CHNO_MASK);
if (reg & 0xff000000) {
size = (reg >> 24) & 0x3f;
offset = (reg >> 16) & 0x1f;
mask = ((1 << size) - 1) << offset;
}
write_io_32(config->nabmbar + EMU_PTR, ptr);
ptr = (read_io_32(config->nabmbar + EMU_DATA) & mask) >> offset;
return ptr;
}
void
emuxki_chan_write(device_config *config, uint16 chano,
uint32 reg, uint32 data)
{
uint32 ptr, mask;
uint8 size, offset;
ptr = ((((uint32) reg) << 16) &
(IS_AUDIGY(config) ? EMU_A_PTR_ADDR_MASK : EMU_PTR_ADDR_MASK)) |
(chano & EMU_PTR_CHNO_MASK);
if (reg & 0xff000000) {
size = (reg >> 24) & 0x3f;
offset = (reg >> 16) & 0x1f;
mask = ((1 << size) - 1) << offset;
data = ((data << offset) & mask) |
(emuxki_chan_read(config, chano, reg & 0xFFFF) & ~mask);
}
write_io_32(config->nabmbar + EMU_PTR, ptr);
write_io_32(config->nabmbar + EMU_DATA, data);
}
/* Microcode */
void
emuxki_write_micro(device_config *config, uint32 pc, uint32 data)
{
emuxki_chan_write(config, 0, (IS_AUDIGY(config) ? EMU_A_MICROCODEBASE :
EMU_MICROCODEBASE ) + pc, data);
}
uint32
emuxki_read_micro(device_config *config, uint32 pc)
{
return emuxki_chan_read(config, 0, (IS_AUDIGY(config) ? EMU_A_MICROCODEBASE :
EMU_MICROCODEBASE ) + pc);
}
void
emuxki_dsp_addop(device_config *config, uint16 *pc, uint8 op,
uint16 r, uint16 a, uint16 x, uint16 y)
{
if(IS_AUDIGY(config)) {
emuxki_write_micro(config, *pc << 1,
((x << 12) & EMU_A_DSP_LOWORD_OPX_MASK) |
(y & EMU_A_DSP_LOWORD_OPY_MASK));
emuxki_write_micro(config, (*pc << 1) + 1,
((op << 24) & EMU_A_DSP_HIWORD_OPCODE_MASK) |
((r << 12) & EMU_A_DSP_HIWORD_RESULT_MASK) |
(a & EMU_A_DSP_HIWORD_OPA_MASK));
} else {
emuxki_write_micro(config, *pc << 1,
((x << 10) & EMU_DSP_LOWORD_OPX_MASK) |
(y & EMU_DSP_LOWORD_OPY_MASK));
emuxki_write_micro(config, (*pc << 1) + 1,
((op << 20) & EMU_DSP_HIWORD_OPCODE_MASK) |
((r << 10) & EMU_DSP_HIWORD_RESULT_MASK) |
(a & EMU_DSP_HIWORD_OPA_MASK));
}
(*pc)++;
}
void
emuxki_dsp_getop(device_config *config, uint16 *pc, uint8 *op,
uint16 *r, uint16 *a, uint16 *x, uint16 *y)
{
uint32 value;
if(IS_AUDIGY(config)) {
value = emuxki_read_micro(config, *pc << 1);
*x = (value & EMU_A_DSP_LOWORD_OPX_MASK) >> 12;
*y = value & EMU_A_DSP_LOWORD_OPY_MASK;
value = emuxki_read_micro(config, (*pc << 1) + 1);
*op = (value & EMU_A_DSP_HIWORD_OPCODE_MASK) >> 24;
*r = (value & EMU_A_DSP_HIWORD_RESULT_MASK) >> 12;
*a = value & EMU_A_DSP_HIWORD_OPA_MASK;
} else {
value = emuxki_read_micro(config, *pc << 1);
*x = (value & EMU_DSP_LOWORD_OPX_MASK) >> 10;
*y = value & EMU_DSP_LOWORD_OPY_MASK;
value = emuxki_read_micro(config, (*pc << 1) + 1);
*op = (value & EMU_DSP_HIWORD_OPCODE_MASK) >> 20;
*r = (value & EMU_DSP_HIWORD_RESULT_MASK) >> 10;
*a = value & EMU_DSP_HIWORD_OPA_MASK;
}
(*pc)++;
}
/* Gpr */
void
emuxki_write_gpr(device_config *config, uint32 pc, uint32 data)
{
emuxki_chan_write(config, 0, IS_AUDIGY(config) ? EMU_A_DSP_GPR(pc) :
EMU_DSP_GPR(pc), data);
}
uint32
emuxki_read_gpr(device_config *config, uint32 pc)
{
return emuxki_chan_read(config, 0, IS_AUDIGY(config) ? EMU_A_DSP_GPR(pc) :
EMU_DSP_GPR(pc));
}
/* codec */
uint16
emuxki_codec_read(device_config *config, int regno)
{
write_io_8(config->nabmbar + EMU_AC97ADDR, regno);
return read_io_16(config->nabmbar + EMU_AC97DATA);
}
void
emuxki_codec_write(device_config *config, int regno, uint16 value)
{
write_io_8(config->nabmbar + EMU_AC97ADDR, regno);
write_io_16(config->nabmbar + EMU_AC97DATA, value);
}
/* inte */
void
emuxki_inte_enable(device_config *config, uint32 value)
{
emuxki_reg_write_32(config, EMU_INTE,
emuxki_reg_read_32(config, EMU_INTE) | value);
}
void
emuxki_inte_disable(device_config *config, uint32 value)
{
emuxki_reg_write_32(config, EMU_INTE,
emuxki_reg_read_32(config, EMU_INTE) & ~value);
}
@@ -0,0 +1,61 @@
/*
* Emuxki BeOS Driver for Creative Labs SBLive!/Audigy series
*
* Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr)
*
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
* Copyright (c) 2002, Marcus Overhagen <marcus@overhagen.de>
*
* 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 _IO_H_
#define _IO_H_
#include "config.h"
uint8 emuxki_reg_read_8(device_config *config, int regno);
uint16 emuxki_reg_read_16(device_config *config, int regno);
uint32 emuxki_reg_read_32(device_config *config, int regno);
void emuxki_reg_write_8(device_config *config, int regno, uint8 value);
void emuxki_reg_write_16(device_config *config, int regno, uint16 value);
void emuxki_reg_write_32(device_config *config, int regno, uint32 value);
uint32 emuxki_chan_read(device_config *config, uint16 chano, uint32 reg);
void emuxki_chan_write(device_config *config, uint16 chano, uint32 reg, uint32 data);
void emuxki_dsp_addop(device_config *config, uint16 *pc, uint8 op,
uint16 r, uint16 a, uint16 x, uint16 y);
void emuxki_dsp_getop(device_config *config, uint16 *pc, uint8 *op,
uint16 *r, uint16 *a, uint16 *x, uint16 *y);
void emuxki_write_gpr(device_config *config, uint32 pc, uint32 data);
uint32 emuxki_read_gpr(device_config *config, uint32 pc);
uint16 emuxki_codec_read(device_config *config, int regno);
void emuxki_codec_write(device_config *config, int regno, uint16 value);
void emuxki_inte_enable(device_config *config, uint32 value);
void emuxki_inte_disable(device_config *config, uint32 value);
#endif
@@ -0,0 +1,226 @@
/*
* Emuxki BeOS Driver for Creative Labs SBLive!/Audigy series
*
* Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr)
*
* 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.
*
*
* Original code : Copyright 1999, Be Incorporated. All Rights Reserved.
* This file may be used under the terms of the Be Sample Code License.
*/
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include "emuxki.h"
#include "io.h"
#include "debug.h"
#include "midi_driver.h"
#include "util.h"
extern generic_mpu401_module * mpu401;
void
midi_interrupt_op(
int32 op,
void * data)
{
// dprint seems to be disabled here, will have to enable it to trace
midi_dev * port = (midi_dev *)data;
TRACE(("port = %p\n", port));
if (op == B_MPU_401_ENABLE_CARD_INT) {
// sample code
/*cpu_status cp;
ddprintf(("sonic_vibes: B_MPU_401_ENABLE_CARD_INT\n"));
cp = disable_interrupts();
acquire_spinlock(&port->card->hardware);
increment_interrupt_handler(port->card);
set_direct(port->card, 0x01, 0x00, 0x80);
set_indirect(port->card, 0x2A, 0x04, 0xff);
release_spinlock(&port->card->hardware);
restore_interrupts(cp);*/
//real code
cpu_status status;
status = lock();
emuxki_reg_write_32(&(port->card->config), EMU_INTE,
emuxki_reg_read_32(&(port->card->config), EMU_INTE) |
EMU_INTE_MIDITXENABLE | EMU_INTE_MIDIRXENABLE );
unlock(status);
}
else if (op == B_MPU_401_DISABLE_CARD_INT) {
// sample code
/* turn off MPU interrupts */
/*cpu_status cp;
ddprintf(("sonic_vibes: B_MPU_401_DISABLE_CARD_INT\n"));
cp = disable_interrupts();
acquire_spinlock(&port->card->hardware);
set_direct(port->card, 0x01, 0x80, 0x80);*/
/* remove interrupt handler if necessary */
/*decrement_interrupt_handler(port->card);
release_spinlock(&port->card->hardware);
restore_interrupts(cp);*/
//real code
cpu_status status;
status = lock();
emuxki_reg_write_32(&port->card->config, EMU_INTE,
emuxki_reg_read_32(&port->card->config, EMU_INTE) &
~ (EMU_INTE_MIDITXENABLE | EMU_INTE_MIDIRXENABLE ) );
unlock(status);
}
TRACE(("midi_interrupt_op() done\n"));
}
static status_t midi_open(const char *name, uint32 flags, void **cookie);
static status_t midi_close(void *cookie);
static status_t midi_free(void *cookie);
static status_t midi_control(void *cookie, uint32 op, void *data, size_t len);
static status_t midi_read(void *cookie, off_t pos, void *data, size_t *len);
static status_t midi_write(void *cookie, off_t pos, const void *data, size_t *len);
device_hooks midi_hooks = {
&midi_open,
&midi_close,
&midi_free,
&midi_control,
&midi_read,
&midi_write,
NULL, /* select */
NULL, /* deselect */
NULL, /* readv */
NULL /* writev */
};
static status_t
midi_open(
const char * name,
uint32 flags,
void ** cookie)
{
int ix;
int ret;
LOG(("midi_open()\n"));
*cookie = NULL;
for (ix=0; ix<num_cards; ix++) {
if (!strcmp(name, cards[ix].midi.name)) {
break;
}
}
if (ix >= num_cards) {
LOG(("bad device\n"));
return ENODEV;
}
LOG(("mpu401: %p open(): %p driver: %p\n", mpu401, mpu401->open_hook, cards[ix].midi.driver));
ret = (*mpu401->open_hook)(cards[ix].midi.driver, flags, cookie);
if (ret >= B_OK) {
cards[ix].midi.cookie = *cookie;
atomic_add(&cards[ix].midi.count, 1);
}
LOG(("mpu401: open returns %x / %p\n", ret, *cookie));
return ret;
}
static status_t
midi_close(
void * cookie)
{
LOG(("midi_close()\n"));
return (*mpu401->close_hook)(cookie);
}
static status_t
midi_free(
void * cookie)
{
int ix;
status_t f;
LOG(("midi_free()\n"));
f = (*mpu401->free_hook)(cookie);
for (ix=0; ix<num_cards; ix++) {
if (cards[ix].midi.cookie == cookie) {
if (atomic_add(&cards[ix].midi.count, -1) == 1) {
cards[ix].midi.cookie = NULL;
LOG(("cleared %p card %d\n", cookie, ix));
}
break;
}
}
LOG(("midi_free() done\n"));
return f;
}
static status_t
midi_control(
void * cookie,
uint32 iop,
void * data,
size_t len)
{
return (*mpu401->control_hook)(cookie, iop, data, len);
}
static status_t
midi_read(
void * cookie,
off_t pos,
void * ptr,
size_t * nread)
{
return (*mpu401->read_hook)(cookie, pos, ptr, nread);
}
static status_t
midi_write(
void * cookie,
off_t pos,
const void * ptr,
size_t * nwritten)
{
return (*mpu401->write_hook)(cookie, pos, ptr, nwritten);
}
bool
midi_interrupt(emuxki_dev *card)
{
TRACE(("midi_interrupt\n"));
if (!card->midi.driver) {
// kprintf("aiigh\n");
return false;
}
return (*mpu401->interrupt_hook)(card->midi.driver);
}
@@ -0,0 +1,118 @@
/* ++++++++++
FILE: midi_driver.h
REVS: $Revision: 1.1 $
NAME: herold
DATE: Tue Jun 4 15:23:29 PDT 1996
Interface to /dev/midi, the midi driver
+++++ */
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#ifndef _MIDI_DRIVER_H
#define _MIDI_DRIVER_H
#include <Drivers.h>
#include <module.h>
/* -----
ioctl codes
----- */
/* the old opcodes are deprecated, and may or may not work
in newer drivers */
enum {
B_MIDI_GET_READ_TIMEOUT = B_MIDI_DRIVER_BASE,
B_MIDI_SET_READ_TIMEOUT,
B_MIDI_TIMED_READ,
B_MIDI_TIMED_WRITE,
B_MIDI_WRITE_SYNC,
B_MIDI_WRITE_CLEAR,
B_MIDI_GET_READ_TIMEOUT_OLD = B_DEVICE_OP_CODES_END + 1,
B_MIDI_SET_READ_TIMEOUT_OLD
};
/* the default timeout when you open a midi driver */
#define B_MIDI_DEFAULT_TIMEOUT 1000000000000000LL
/* Usage:
To read, set "data" to a pointer to your buffer, and "size" to the
maximum size of this buffer. On return, "when" will contain the time
at which the data was received (first byte) and "size" will contain
the actual amount of data read.
Call ioctl(fd, B_MIDI_TIMED_READ, &midi_timed_data, sizeof(midi_timed_data));
To write, set "when" to when you want the first byte to go out the
wire, set "data" to point to your data, and set "size" to the size
of your data.
Call ioctl(fd, B_MIDI_TIMED_WRITE, &midi_timed_data, sizeof(midi_timed_data));
*/
typedef struct {
bigtime_t when;
size_t size;
unsigned char * data;
} midi_timed_data;
/* The MIDI parser returns the number of bytes that a message contains, given the */
/* initial byte. For some messages, this is not known until the second byte is seen. */
/* For such messages, a state > 0 is returned as well as some count > 0. When state */
/* is > 0, you should call (*parse) for the next byte as well, which might modify */
/* the returned message size. Message size will always be returned with the current */
/* byte being counted as byte 1. A return of 0 means that the byte initiates a new */
/* message. SysX is handled by returning max_size until the end or next initial message */
/* is seen. So your loop looks something like: */
/*
uint32 state = 0; // Only set this to 0 the first time you call the parser.
// preserve the 'state' between invocations of your read() hook.
int todo = 0;
unsigned char * end = in_buf+buf_size
unsigned char * out_buf = in_buf;
while (true) {
uchar byte = read_midi();
if (!todo || state) {
todo = (*parser->parse)(&state, byte, end-out_buf);
}
if (todo < 1) {
unput_midi(byte);
} else {
*(out_buf++) = byte;
todo--;
}
if (todo < 1 || out_buf >= end) {
received_midi_message(in_buf, out_buf-in_buf);
todo = 0;
}
}
*/
#define B_MIDI_PARSER_MODULE_NAME "media/midiparser/v1"
typedef struct _midi_parser_module_info {
module_info minfo;
int (*parse)(uint32 * state, uchar byte, size_t max_size);
int _reserved_;
} midi_parser_module_info;
#define B_MPU_401_MODULE_NAME "generic/mpu401/v1"
enum {
B_MPU_401_ENABLE_CARD_INT = 1,
B_MPU_401_DISABLE_CARD_INT
};
typedef struct _generic_mpu401_module {
module_info minfo;
status_t (*create_device)(int port, void ** out_storage, uint32 workarounds, void (*interrupt_op)(int32 op, void * card), void * card);
status_t (*delete_device)(void * storage);
status_t (*open_hook)(void * storage, uint32 flags, void ** out_cookie);
status_t (*close_hook)(void * cookie);
status_t (*free_hook)(void * cookie);
status_t (*control_hook)(void * cookie, uint32 op, void * data, size_t len);
status_t (*read_hook)(void * cookie, off_t pos, void * data, size_t * len);
status_t (*write_hook)(void * cookie, off_t pos, const void * data, size_t * len);
bool (*interrupt_hook)(void * cookie);
int _reserved_;
} generic_mpu401_module;
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,65 @@
/*
* BeOS Driver for Creative Labs SBLive! series
*
* Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr)
*
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
* Copyright (c) 2002, Marcus Overhagen <marcus@overhagen.de>
*
* 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_FRAMES 32 // this is the minimum which works
#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,699 @@
/* 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>
#include <Debug.h>
#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 <marcus@overhagen.de>
*
* 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,40 @@
/*
* BeOS Driver for Intel ICH AC'97 Link interface
*
* Copyright (c) 2002, Marcus Overhagen <marcus@overhagen.de>
*
* 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_
#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;
#endif