Auvia driver for Via audio chipsets VT82C686 and VT8233/35

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3063 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval
2003-04-12 00:27:14 +00:00
parent 8959b6dde2
commit 822fd93938
17 changed files with 4371 additions and 0 deletions
@@ -0,0 +1,18 @@
SubDir OBOS_TOP src add-ons kernel drivers audio ac97 auvia ;
R5KernelAddon auvia : kernel drivers bin :
ac97.c
debug.c
auvia.c
io.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>auvia ;
MakeLocate $(instDriver) : $(dir) ;
RelSymLink $(instDriver) : auvia ;
}
@@ -0,0 +1,292 @@
/*
* Auvia BeOS Driver for Via VT82xx Southbridge audio
*
* Copyright (c) 2003, Jerome Duval ([email protected])
*
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
* Copyright (c) 2002, Marcus Overhagen <[email protected]>
*
* All rights reserved.
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <OS.h>
#include <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 = auvia_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 = auvia_codec_read(config, AC97_VENDOR_ID1);
data2 = auvia_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"));
auvia_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",auvia_codec_read(config, AC97_POWERDOWN)));
#if REVERSE_EAMP_POLARITY
yesno = !yesno;
LOG(("using reverse eamp polarity\n"));
#endif
if (yesno)
auvia_codec_write(config, AC97_POWERDOWN, auvia_codec_read(config, AC97_POWERDOWN) & ~0x8000); /* switch on (low active) */
else
auvia_codec_write(config, AC97_POWERDOWN, auvia_codec_read(config, AC97_POWERDOWN) | 0x8000); /* switch off */
LOG(("powerdown register is = %#04x\n", auvia_codec_read(config, AC97_POWERDOWN)));
}
void cs4299_amp_enable(device_config *config, bool yesno)
{
LOG(("cs4299_amp_enable\n"));
if (yesno)
auvia_codec_write(config, 0x68, 0x8004);
else
auvia_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 @@
/*
* Auvia BeOS Driver for Via VT82xx Southbridge audio
*
* Copyright (c) 2003, Jerome Duval ([email protected])
*
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
* Copyright (c) 2002, Marcus Overhagen <[email protected]>
*
* All rights reserved.
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _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,670 @@
/*
* Auvia BeOS Driver for Via VT82xx Southbridge audio
*
* Copyright (c) 2003, Jerome Duval ([email protected])
* This code is derived from software contributed to The NetBSD Foundation
* by Tyler C. Sarna
*
* 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.
*/
#include <KernelExport.h>
#include <PCI.h>
#include <string.h>
#include <stdio.h>
#include "auvia.h"
#include "debug.h"
#include "config.h"
#include "util.h"
#include "io.h"
#include <fcntl.h>
#include <unistd.h>
#include <malloc.h>
#include "ac97.h"
status_t init_hardware(void);
status_t init_driver(void);
void uninit_driver(void);
const char ** publish_devices(void);
device_hooks * find_device(const char *);
static char pci_name[] = B_PCI_MODULE_NAME;
static pci_module_info *pci;
int32 num_cards;
auvia_dev cards[NUM_CARDS];
int32 num_names;
char * names[NUM_CARDS*20+1];
extern device_hooks multi_hooks;
/* Auvia Memory management */
static auvia_mem *
auvia_mem_new(auvia_dev *card, size_t size)
{
auvia_mem *mem;
if ((mem = malloc(sizeof(*mem))) == NULL)
return (NULL);
mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "auvia buffer");
mem->size = size;
if (mem->area < B_OK) {
free(mem);
return NULL;
}
return mem;
}
static void
auvia_mem_delete(auvia_mem *mem)
{
if(mem->area > B_OK)
delete_area(mem->area);
free(mem);
}
void *
auvia_mem_alloc(auvia_dev *card, size_t size)
{
auvia_mem *mem;
mem = auvia_mem_new(card, size);
if (mem == NULL)
return (NULL);
LIST_INSERT_HEAD(&(card->mems), mem, next);
return mem;
}
void
auvia_mem_free(auvia_dev *card, void *ptr)
{
auvia_mem *mem;
LIST_FOREACH(mem, &card->mems, next) {
if (mem->log_base != ptr)
continue;
LIST_REMOVE(mem, next);
auvia_mem_delete(mem);
break;
}
}
/* Auvia stream functions */
status_t
auvia_stream_set_audioparms(auvia_stream *stream, uint8 channels,
uint8 b16, uint32 sample_rate)
{
uint8 sample_size, frame_size;
LOG(("auvia_stream_set_audioparms\n"));
if ((stream->channels == channels) &&
(stream->b16 == b16) &&
(stream->sample_rate == sample_rate))
return B_OK;
if(stream->buffer)
auvia_mem_free(stream->card, stream->buffer->log_base);
stream->b16 = b16;
stream->sample_rate = sample_rate;
stream->channels = channels;
sample_size = stream->b16 + 1;
frame_size = sample_size * stream->channels;
stream->buffer = auvia_mem_alloc(stream->card, stream->bufframes * frame_size * stream->bufcount);
stream->trigblk = 0; /* This shouldn't be needed */
stream->blkmod = stream->bufcount;
stream->blksize = stream->bufframes * frame_size;
return B_OK;
}
status_t
auvia_stream_commit_parms(auvia_stream *stream)
{
int i;
uint32 *page;
uint32 value;
LOG(("auvia_stream_commit_parms\n"));
page = stream->dmaops_log_base;
for(i=0; i<stream->bufcount; i++) {
page[2*i] = ((uint32)stream->buffer->phy_base) +
i * stream->blksize;
page[2*i + 1] = AUVIA_DMAOP_FLAG | stream->blksize;
}
page[2*stream->bufcount - 1] &= ~AUVIA_DMAOP_FLAG;
page[2*stream->bufcount - 1] |= AUVIA_DMAOP_EOL;
auvia_reg_write_32(&stream->card->config, stream->base + AUVIA_RP_DMAOPS_BASE,
(uint32)stream->dmaops_phy_base);
if(stream->use & AUVIA_USE_RECORD)
auvia_codec_write(&stream->card->config, AC97_PCM_LR_ADC_RATE, (uint16)stream->sample_rate);
else
auvia_codec_write(&stream->card->config, AC97_PCM_FRONT_DAC_RATE, (uint16)stream->sample_rate);
if(IS_8233(&stream->card->config)) {
if(stream->base != AUVIA_8233_MP_BASE) {
value = auvia_reg_read_32(&stream->card->config, stream->base + AUVIA_8233_RP_RATEFMT);
value &= ~(AUVIA_8233_RATEFMT_48K | AUVIA_8233_RATEFMT_STEREO | AUVIA_8233_RATEFMT_16BIT);
if(stream->use & AUVIA_USE_PLAY)
value |= AUVIA_8233_RATEFMT_48K * (stream->sample_rate / 20) / (48000 / 20);
value |= (stream->channels == 2 ? AUVIA_8233_RATEFMT_STEREO : 0)
| (stream->b16 ? AUVIA_8233_RATEFMT_16BIT : 0);
auvia_reg_write_32(&stream->card->config, stream->base + AUVIA_8233_RP_RATEFMT, value);
} else {
static const uint32 slottab[7] = {0, 0xff000011, 0xff000021, 0xff000521,
0xff004321, 0xff054321, 0xff654321};
value = (stream->b16 ? AUVIA_8233_MP_FORMAT_16BIT : AUVIA_8233_MP_FORMAT_8BIT)
| ((stream->channels << 4) & AUVIA_8233_MP_FORMAT_CHANNEL_MASK) ;
auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_8233_OFF_MP_FORMAT, value);
auvia_reg_write_32(&stream->card->config, stream->base + AUVIA_8233_OFF_MP_STOP,
slottab[stream->channels]);
}
}
//auvia_codec_write(&stream->card->config, AC97_SPDIF_CONTROL, (uint16)stream->sample_rate);
return B_OK;
}
status_t
auvia_stream_get_nth_buffer(auvia_stream *stream, uint8 chan, uint8 buf,
char** buffer, size_t *stride)
{
uint8 sample_size, frame_size;
LOG(("auvia_stream_get_nth_buffer\n"));
sample_size = stream->b16 + 1;
frame_size = sample_size * stream->channels;
*buffer = stream->buffer->log_base + (buf * stream->bufframes * frame_size)
+ chan * sample_size;
*stride = frame_size;
return B_OK;
}
static uint32
auvia_stream_curaddr(auvia_stream *stream)
{
uint32 addr;
if(IS_8233(&stream->card->config)) {
addr = auvia_reg_read_32(&stream->card->config, stream->base + AUVIA_RP_DMAOPS_BASE);
//TRACE(("auvia_stream_curaddr %p\n", addr));
//TRACE(("auvia_stream_curaddr %p\n", (uint32)stream->dmaops_phy_base));
return (addr - (uint32)stream->dmaops_phy_base - 4) / 8;
} else {
addr = auvia_reg_read_32(&stream->card->config, stream->base + AUVIA_RP_DMAOPS_BASE);
return (addr - (uint32)stream->dmaops_phy_base - 8) / 8;
}
}
void
auvia_stream_start(auvia_stream *stream, void (*inth) (void *), void *inthparam)
{
LOG(("auvia_stream_start\n"));
stream->inth = inth;
stream->inthparam = inthparam;
stream->state |= AUVIA_STATE_STARTED;
if(IS_8233(&stream->card->config)) {
if(stream->base != AUVIA_8233_MP_BASE) {
auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_8233_RP_DXS_LVOL, 0);
auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_8233_RP_DXS_RVOL, 0);
}
auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_RP_CONTROL,
AUVIA_RPCTRL_START | AUVIA_RPCTRL_AUTOSTART | AUVIA_RPCTRL_STOP
| AUVIA_RPCTRL_EOL | AUVIA_RPCTRL_FLAG);
} else {
uint8 regvalue = (stream->channels > 1 ? AUVIA_RPMODE_STEREO : 0)
| (stream->b16 == 1 ? AUVIA_RPMODE_16BIT : 0)
| AUVIA_RPMODE_INTR_FLAG | AUVIA_RPMODE_INTR_EOL | AUVIA_RPMODE_AUTOSTART;
auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_RP_MODE, regvalue);
auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_RP_CONTROL, AUVIA_RPCTRL_START);
}
}
void
auvia_stream_halt(auvia_stream *stream)
{
LOG(("auvia_stream_halt\n"));
stream->state &= ~AUVIA_STATE_STARTED;
auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_RP_CONTROL, AUVIA_RPCTRL_TERMINATE);
}
auvia_stream *
auvia_stream_new(auvia_dev *card, uint8 use, uint32 bufframes, uint8 bufcount)
{
auvia_stream *stream;
cpu_status status;
LOG(("auvia_stream_new\n"));
stream = malloc(sizeof(auvia_stream));
if (stream == NULL)
return (NULL);
stream->card = card;
stream->use = use;
stream->state = !AUVIA_STATE_STARTED;
stream->b16 = 0;
stream->sample_rate = 0;
stream->channels = 0;
stream->bufframes = bufframes;
stream->bufcount = bufcount;
stream->inth = NULL;
stream->inthparam = NULL;
stream->buffer = NULL;
stream->blksize = 0;
stream->trigblk = 0;
stream->blkmod = 0;
if(use & AUVIA_USE_PLAY) {
if(IS_8233(&card->config))
stream->base = AUVIA_8233_MP_BASE;
//stream->base = AUVIA_PLAY_BASE;
else
stream->base = AUVIA_PLAY_BASE;
} else {
if(IS_8233(&card->config))
stream->base = AUVIA_8233_RECORD_BASE;
else
stream->base = AUVIA_RECORD_BASE;
}
stream->frames_count = 0;
stream->real_time = 0;
stream->update_needed = false;
/* allocate memory for our dma ops */
stream->dmaops_area = alloc_mem(&stream->dmaops_phy_base, &stream->dmaops_log_base,
VIA_TABLE_SIZE, "auvia dmaops");
if (stream->dmaops_area < B_OK) {
PRINT(("couldn't allocate memory\n"));
free(stream);
return NULL;
}
status = lock();
LIST_INSERT_HEAD((&card->streams), stream, next);
unlock(status);
return stream;
}
void
auvia_stream_delete(auvia_stream *stream)
{
cpu_status status;
LOG(("auvia_stream_delete\n"));
auvia_stream_halt(stream);
auvia_reg_write_32(&stream->card->config, stream->base + AUVIA_RP_DMAOPS_BASE, 0);
if (stream->dmaops_area > B_OK)
delete_area(stream->dmaops_area);
if(stream->buffer)
auvia_mem_free(stream->card, stream->buffer->log_base);
status = lock();
LIST_REMOVE(stream, next);
unlock(status);
free(stream);
}
/* Auvia interrupt */
int32 auvia_int(void *arg)
{
auvia_dev *card = arg;
bool gotone = false;
uint32 curblk;
auvia_stream *stream;
if(auvia_reg_read_32(&card->config, AUVIA_SGD_SHADOW)
& card->interrupt_mask) {
LIST_FOREACH(stream, &card->streams, next)
if(auvia_reg_read_8(&card->config, stream->base + AUVIA_RP_STAT) & AUVIA_RPSTAT_INTR) {
gotone = true;
//TRACE(("interrupt\n"));
curblk = auvia_stream_curaddr(stream);
//TRACE(("AUVIA_RPSTAT_INTR at trigblk %lu\n", curblk));
//TRACE(("AUVIA_RPSTAT_INTR at stream->trigblk %lu\n", stream->trigblk));
if (curblk == stream->trigblk) {
//TRACE(("AUVIA_RPSTAT_INTR at trigblk %lu\n", curblk));
if(stream->inth)
stream->inth(stream->inthparam);
stream->trigblk++;
stream->trigblk %= stream->blkmod;
}
auvia_reg_write_8(&card->config, stream->base + AUVIA_RP_STAT, AUVIA_RPSTAT_INTR);
}
} else {
TRACE(("AUVIA_SGD_SHADOW %x %x\n", card->interrupt_mask, auvia_reg_read_32(&card->config, AUVIA_SGD_SHADOW)));
}
if(gotone)
return B_HANDLED_INTERRUPT;
TRACE(("Got unhandled interrupt\n"));
return B_UNHANDLED_INTERRUPT;
}
/* Auvia driver functions */
/* detect presence of our hardware */
status_t
init_hardware(void)
{
int ix=0;
pci_info info;
status_t err = ENODEV;
LOG_CREATE();
PRINT(("init_hardware()\n"));
if (get_module(pci_name, (module_info **)&pci))
return ENOSYS;
while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
if (info.vendor_id == VIATECH_VENDOR_ID &&
(info.device_id == VIATECH_82C686_AC97_DEVICE_ID
|| info.device_id == VIATECH_8233_AC97_DEVICE_ID
)) {
err = B_OK;
}
ix++;
}
put_module(pci_name);
return err;
}
static void
make_device_names(
auvia_dev * card)
{
sprintf(card->name, "audio/multi/auvia/%ld", card-cards+1);
names[num_names++] = card->name;
names[num_names] = NULL;
}
status_t
auvia_init(auvia_dev * card)
{
uint32 pr;
pr = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, AUVIA_PCICONF_JUNK, 4);
PRINT(("AUVIA_PCICONF_JUNK before: %x\n", pr));
pr &= ~AUVIA_PCICONF_ENABLES;
pr |= AUVIA_PCICONF_ACLINKENAB | AUVIA_PCICONF_ACNOTRST | AUVIA_PCICONF_ACVSR | AUVIA_PCICONF_ACSGD;
pr &= ~(AUVIA_PCICONF_ACFM | AUVIA_PCICONF_ACSB);
(*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function, AUVIA_PCICONF_JUNK, 4, pr );
snooze(100);
pr = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, AUVIA_PCICONF_JUNK, 4);
PRINT(("AUVIA_PCICONF_JUNK after: %x\n", pr));
if(IS_8233(&card->config)) {
card->interrupt_mask =
AUVIA_8233_SGD_STAT_FLAG_EOL |
AUVIA_8233_SGD_STAT_FLAG_EOL << 4 |
AUVIA_8233_SGD_STAT_FLAG_EOL << 8 |
AUVIA_8233_SGD_STAT_FLAG_EOL << 12 |
AUVIA_8233_SGD_STAT_FLAG_EOL << 16 |
AUVIA_8233_SGD_STAT_FLAG_EOL << 24 |
AUVIA_8233_SGD_STAT_FLAG_EOL << 28;
} else {
card->interrupt_mask = AUVIA_SGD_STAT_ALL | (AUVIA_SGD_STAT_ALL << 4);
}
/* Init streams list */
LIST_INIT(&(card->streams));
/* Init mems list */
LIST_INIT(&(card->mems));
return B_OK;
}
static status_t
auvia_setup(auvia_dev * card)
{
status_t err = B_OK;
unsigned char cmd;
PRINT(("auvia_setup(%p)\n", card));
make_device_names(card);
card->config.nabmbar = card->info.u.h0.base_registers[0];
card->config.irq = card->info.u.h0.interrupt_line;
card->config.type = 0;
if(card->info.device_id == VIATECH_82C686_AC97_DEVICE_ID)
card->config.type |= TYPE_686;
if(card->info.device_id == VIATECH_8233_AC97_DEVICE_ID)
card->config.type |= TYPE_8233;
PRINT(("%s deviceid = %#04x chiprev = %x model = %x enhanced at %x\n", card->name, card->info.device_id,
card->info.revision, card->info.u.h0.subsystem_id, card->config.nabmbar));
cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2);
PRINT(("PCI command before: %x\n", cmd));
(*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2, cmd | PCI_command_io);
cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2);
PRINT(("PCI command after: %x\n", cmd));
/* reset the codec */
PRINT(("codec reset\n"));
auvia_codec_write(&card->config, 0x00, 0x0000);
snooze(50000); // 50 ms
ac97_init(&card->config);
ac97_amp_enable(&card->config, true);
PRINT(("codec vendor id = %#08x\n",ac97_get_vendor_id()));
PRINT(("codec description = %s\n",ac97_get_vendor_id_description()));
PRINT(("codec 3d enhancement = %s\n",ac97_get_3d_stereo_enhancement()));
PRINT(("installing interrupt : %x\n", card->config.irq));
install_io_interrupt_handler(card->config.irq, auvia_int, card, 0);
/*PRINT(("codec master output = %#04x\n",auvia_codec_read(&card->config, 0x02)));
PRINT(("codec aux output = %#04x\n",auvia_codec_read(&card->config, 0x04)));
PRINT(("codec mono output = %#04x\n",auvia_codec_read(&card->config, 0x06)));
PRINT(("codec pcm output = %#04x\n",auvia_codec_read(&card->config, 0x18)));
PRINT(("codec line in = %#04x\n",auvia_codec_read(&card->config, 0x10)));
PRINT(("codec record line in= %#04x\n",auvia_codec_read(&card->config, 0x1a)));
PRINT(("codec record gain = %#04x\n",auvia_codec_read(&card->config, 0x1c)));*/
PRINT(("writing codec registers\n"));
// TODO : to move with AC97
/* enable master output */
auvia_codec_write(&card->config, AC97_MASTER_VOLUME, 0x0000);
/* enable aux output */
auvia_codec_write(&card->config, AC97_AUX_OUT_VOLUME, 0x0000);
/* enable mono output */
//auvia_codec_write(&card->config, AC97_MONO_VOLUME, 0x0004);
/* enable pcm output */
auvia_codec_write(&card->config, AC97_PCM_OUT_VOLUME, 0x0808);
/* enable line in */
//auvia_codec_write(&card->config, AC97_LINE_IN_VOLUME, 0x8808);
/* set record line in */
auvia_codec_write(&card->config, AC97_RECORD_SELECT, 0x0404);
/* set record gain */
//auvia_codec_write(&card->config, AC97_RECORD_GAIN, 0x0000);
PRINT(("codec master output = %#04x\n",auvia_codec_read(&card->config, AC97_MASTER_VOLUME)));
PRINT(("codec aux output = %#04x\n",auvia_codec_read(&card->config, AC97_AUX_OUT_VOLUME)));
PRINT(("codec mono output = %#04x\n",auvia_codec_read(&card->config, AC97_MONO_VOLUME)));
PRINT(("codec pcm output = %#04x\n",auvia_codec_read(&card->config, AC97_PCM_OUT_VOLUME)));
PRINT(("codec line in = %#04x\n",auvia_codec_read(&card->config, AC97_LINE_IN_VOLUME)));
PRINT(("codec record line in= %#04x\n",auvia_codec_read(&card->config, AC97_RECORD_SELECT)));
PRINT(("codec record gain = %#04x\n",auvia_codec_read(&card->config, AC97_RECORD_GAIN)));
if ((err = auvia_init(card)))
return (err);
PRINT(("init_driver done\n"));
return err;
}
status_t
init_driver(void)
{
int ix=0;
pci_info info;
num_cards = 0;
PRINT(("init_driver()\n"));
load_driver_symbols("auvia");
if (get_module(pci_name, (module_info **) &pci))
return ENOSYS;
while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
if (info.vendor_id == VIATECH_VENDOR_ID &&
(info.device_id == VIATECH_82C686_AC97_DEVICE_ID
|| info.device_id == VIATECH_8233_AC97_DEVICE_ID
)) {
if (num_cards == NUM_CARDS) {
PRINT(("Too many auvia cards installed!\n"));
break;
}
memset(&cards[num_cards], 0, sizeof(auvia_dev));
cards[num_cards].info = info;
if (auvia_setup(&cards[num_cards])) {
PRINT(("Setup of auvia %ld failed\n", num_cards+1));
}
else {
num_cards++;
}
}
ix++;
}
if (!num_cards) {
PRINT(("no cards\n"));
put_module(pci_name);
PRINT(("no suitable cards found\n"));
return ENODEV;
}
#if DEBUG
//add_debugger_command("auvia", auvia_debug, "auvia [card# (1-n)]");
#endif
return B_OK;
}
static void
auvia_shutdown(auvia_dev *card)
{
PRINT(("shutdown(%p)\n", card));
remove_io_interrupt_handler(card->config.irq, auvia_int, card);
}
void
uninit_driver(void)
{
int ix, cnt = num_cards;
num_cards = 0;
PRINT(("uninit_driver()\n"));
//remove_debugger_command("auvia", auvia_debug);
for (ix=0; ix<cnt; ix++) {
auvia_shutdown(&cards[ix]);
}
memset(&cards, 0, sizeof(cards));
put_module(pci_name);
}
const char **
publish_devices(void)
{
int ix = 0;
PRINT(("publish_devices()\n"));
for (ix=0; names[ix]; ix++) {
PRINT(("publish %s\n", names[ix]));
}
return (const char **)names;
}
device_hooks *
find_device(const char * name)
{
int ix;
PRINT(("find_device(%s)\n", name));
for (ix=0; ix<num_cards; ix++) {
if (!strcmp(cards[ix].name, name)) {
return &multi_hooks;
}
}
PRINT(("find_device(%s) failed\n", name));
return NULL;
}
int32 api_version = B_CUR_DRIVER_API_VERSION;
@@ -0,0 +1,167 @@
/*
* Auvia BeOS Driver for Via VT82xx Southbridge audio
*
* Copyright (c) 2003, Jerome Duval ([email protected])
* This code is derived from software contributed to The NetBSD Foundation
* by Tyler C. Sarna
*
* 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_AUVIA_H_
#define _DEV_PCI_AUVIA_H_
#include <Drivers.h>
#include <SupportDefs.h>
#include <OS.h>
#include <PCI.h>
#include "auviareg.h"
#include "config.h"
#include "queue.h"
#include "multi_audio.h"
#include "multi.h"
#define VIATECH_VENDOR_ID 0x1106 /* Via Technologies */
#define VIATECH_82C686_AC97_DEVICE_ID 0x3058 /* Via Technologies VT82C686 AC97 */
#define VIATECH_8233_AC97_DEVICE_ID 0x3059 /* Via Technologies VT8233 AC97 */
#define VIATECH_8233_AC97_REV_8233C 0x20
#define VIATECH_8233_AC97_REV_8233 0x30
#define VIATECH_8233_AC97_REV_8233A 0x40
#define VIATECH_8233_AC97_REV_8235 0x50
#define VERSION "Version alpha 2, Copyright (c) 2003 Jérôme Duval, compiled on " ## __DATE__ ## " " ## __TIME__
#define DRIVER_NAME "auvia"
#define FRIENDLY_NAME "Auvia"
#define FRIENDLY_NAME_686 FRIENDLY_NAME" 82C686"
#define FRIENDLY_NAME_8233C FRIENDLY_NAME" 8233C"
#define FRIENDLY_NAME_8233 FRIENDLY_NAME" 8233"
#define FRIENDLY_NAME_8233A FRIENDLY_NAME" 8233A"
#define FRIENDLY_NAME_8235 FRIENDLY_NAME" 8235"
#define AUTHOR "Jérôme Duval"
#define VIA_TABLE_SIZE 255
#define AUVIA_USE_PLAY (1 << 0)
#define AUVIA_USE_RECORD (1 << 1)
#define AUVIA_STATE_STARTED (1 << 0)
/*
* Auvia memory managment
*/
typedef struct _auvia_mem {
LIST_ENTRY(_auvia_mem) next;
void *log_base;
void *phy_base;
area_id area;
size_t size;
} auvia_mem;
/*
* Streams
*/
typedef struct _auvia_stream {
struct _auvia_dev *card;
uint8 use;
uint8 state;
uint8 b16;
uint32 sample_rate;
uint8 channels;
uint32 bufframes;
uint8 bufcount;
uint32 base;
LIST_ENTRY(_auvia_stream) next;
void (*inth) (void *);
void *inthparam;
void *dmaops_log_base;
void *dmaops_phy_base;
area_id dmaops_area;
auvia_mem *buffer;
uint16 blksize; /* in samples */
uint16 trigblk; /* blk on which to trigger inth */
uint16 blkmod; /* Modulo value to wrap trigblk */
/* multi_audio */
volatile int64 frames_count; // for play or record
volatile bigtime_t real_time; // for play or record
volatile int32 buffer_cycle; // for play or record
int32 first_channel;
bool update_needed;
} auvia_stream;
/*
* Devices
*/
typedef struct _auvia_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;
sem_id buffer_ready_sem;
uint32 interrupt_mask;
LIST_HEAD(, _auvia_stream) streams;
LIST_HEAD(, _auvia_mem) mems;
auvia_stream *pstream;
auvia_stream *rstream;
/* multi_audio */
multi_dev multi;
} auvia_dev;
extern int32 num_cards;
extern auvia_dev cards[NUM_CARDS];
status_t auvia_stream_set_audioparms(auvia_stream *stream, uint8 channels,
uint8 b16, uint32 sample_rate);
status_t auvia_stream_commit_parms(auvia_stream *stream);
status_t auvia_stream_get_nth_buffer(auvia_stream *stream, uint8 chan, uint8 buf,
char** buffer, size_t *stride);
void auvia_stream_start(auvia_stream *stream, void (*inth) (void *), void *inthparam);
void auvia_stream_halt(auvia_stream *stream);
auvia_stream *auvia_stream_new(auvia_dev *card, uint8 use, uint32 bufframes, uint8 bufcount);
void auvia_stream_delete(auvia_stream *stream);
#endif /* _DEV_PCI_AUVIA_H_ */
@@ -0,0 +1,128 @@
/*
* Auvia BeOS Driver for Via VT82xx Southbridge audio
*
* Copyright (c) 2003, Jerome Duval ([email protected])
* This code is derived from software contributed to The NetBSD Foundation
* by Tyler C. Sarna
*
* 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_AUVIAREG_H_
#define _DEV_PCI_AUVIAREG_H_
// VT8233 specific registers contain a '8233_'
#define AUVIA_PCICONF_JUNK 0x40
#define AUVIA_PCICONF_ENABLES 0x00ff0000 /* reg 42 mask */
#define AUVIA_PCICONF_ACLINKENAB 0x00008000 /* ac link enab */
#define AUVIA_PCICONF_ACNOTRST 0x00004000 /* ~(ac reset) */
#define AUVIA_PCICONF_ACSYNC 0x00002000 /* ac sync */
#define AUVIA_PCICONF_ACVSR 0x00000800 /* var. samp. rate */
#define AUVIA_PCICONF_ACSGD 0x00000400 /* SGD enab */
#define AUVIA_PCICONF_ACFM 0x00000200 /* FM enab */
#define AUVIA_PCICONF_ACSB 0x00000100 /* SB enab */
#define AUVIA_PLAY_BASE 0x00
#define AUVIA_RECORD_BASE 0x10
#define AUVIA_8233_RECORD_BASE 0x60
/* *_RP_* are offsets from AUVIA_PLAY_BASE or AUVIA_RECORD_BASE or AUVIA_8233_RECORD_BASE*/
#define AUVIA_RP_STAT 0x00
#define AUVIA_RPSTAT_INTR 0x03
#define AUVIA_RP_CONTROL 0x01
#define AUVIA_RPCTRL_START 0x80
#define AUVIA_RPCTRL_TERMINATE 0x40
#define AUVIA_RPCTRL_AUTOSTART 0x20
/* The following are 8233 specific */
#define AUVIA_RPCTRL_STOP 0x04
#define AUVIA_RPCTRL_EOL 0x02
#define AUVIA_RPCTRL_FLAG 0x01
#define AUVIA_RP_MODE 0x02 /* 82c686 specific */
#define AUVIA_RPMODE_INTR_FLAG 0x01
#define AUVIA_RPMODE_INTR_EOL 0x02
#define AUVIA_RPMODE_STEREO 0x10
#define AUVIA_RPMODE_16BIT 0x20
#define AUVIA_RPMODE_AUTOSTART 0x80
#define AUVIA_RP_DMAOPS_BASE 0x04
#define AUVIA_8233_RP_DXS_LVOL 0x02
#define AUVIA_8233_RP_DXS_RVOL 0x03
#define AUVIA_8233_RP_RATEFMT 0x08
#define AUVIA_8233_RATEFMT_48K 0xfffff
#define AUVIA_8233_RATEFMT_STEREO 0x00100000
#define AUVIA_8233_RATEFMT_16BIT 0x00200000
#define VIA_RP_DMAOPS_COUNT 0x0c
#define AUVIA_8233_MP_BASE 0x40
/* STAT, CONTROL, DMAOPS_BASE, DMAOPS_COUNT are valid */
#define AUVIA_8233_OFF_MP_FORMAT 0x02
#define AUVIA_8233_MP_FORMAT_8BIT 0x00
#define AUVIA_8233_MP_FORMAT_16BIT 0x80
#define AUVIA_8233_MP_FORMAT_CHANNEL_MASK 0x70 /* 1, 2, 4, 6 */
#define AUVIA_8233_OFF_MP_SCRATCH 0x03
#define AUVIA_8233_OFF_MP_STOP 0x08
#define AUVIA_CODEC_CTL 0x80
#define AUVIA_CODEC_READ 0x00800000
#define AUVIA_CODEC_BUSY 0x01000000
#define AUVIA_CODEC_PRIVALID 0x02000000
#define AUVIA_CODEC_INDEX(x) ((x)<<16)
#define AUVIA_SGD_SHADOW 0x84
#define AUVIA_SGD_STAT_FLAG_MASK 0x00000007
#define AUVIA_SGD_STAT_EOL_MASK 0x00000070
#define AUVIA_SGD_STAT_STOP_MASK 0x00000700
#define AUVIA_SGD_STAT_ACTIVE_MASK 0x00007000
#define AUVIA_SGD_STAT_PLAYBACK 0x00000001
#define AUVIA_SGD_STAT_RECORD 0x00000002
#define AUVIA_SGD_STAT_FM 0x00000004
#define AUVIA_SGD_STAT_ALL 0x00000007
#define AUVIA_8233_SGD_STAT_SDX0_MASK 0x00000008
#define AUVIA_8233_SGD_STAT_SDX1_MASK 0x00000080
#define AUVIA_8233_SGD_STAT_SDX2_MASK 0x00000800
#define AUVIA_8233_SGD_STAT_SDX3_MASK 0x00008000
#define AUVIA_8233_SGD_STAT_MP_MASK 0x00080000
#define AUVIA_8233_SGD_STAT_REC0_MASK 0x08000000
#define AUVIA_8233_SGD_STAT_REC1_MASK 0x80000000
#define AUVIA_8233_SGD_STAT_FLAG 0x00000001
#define AUVIA_8233_SGD_STAT_EOL 0x00000002
#define AUVIA_8233_SGD_STAT_STOP 0x00000004
#define AUVIA_8233_SGD_STAT_ACTIVE 0x00000008
#define AUVIA_8233_SGD_STAT_FLAG_EOL 0x00000003
#define AUVIA_DMAOP_EOL 0x80000000
#define AUVIA_DMAOP_FLAG 0x40000000
#define AUVIA_DMAOP_STOP 0x20000000
#define AUVIA_DMAOP_COUNT(x) ((x)&0x00FFFFFF)
#endif /* _DEV_PCI_AUVIAREG_H_ */
@@ -0,0 +1,49 @@
/*
* Auvia BeOS Driver for Via VT82xx Southbridge audio
*
* Copyright (c) 2003, Jerome Duval ([email protected])
*
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
* Copyright (c) 2002, Marcus Overhagen <[email protected]>
*
* All rights reserved.
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
#define NUM_CARDS 3
#define DEVNAME 32
typedef struct
{
uint32 nabmbar;
uint32 irq;
uint32 type;
} device_config;
#define TYPE_686 0x01
#define TYPE_8233 0x02
#define IS_686(x) ((x)->type & TYPE_686)
#define IS_8233(x) ((x)->type & TYPE_8233)
#endif
@@ -0,0 +1,95 @@
/*
* Auvia BeOS Driver for Via VT82xx Southbridge audio
*
* Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr)
*
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
* Copyright (c) 2002, Marcus Overhagen <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 <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <OS.h>
#include "debug.h"
#include "auvia.h"
#if DEBUG > 0
static const char * logfile="/boot/home/auvia.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 @@
/*
* Auvia BeOS Driver for Via VT82xx Southbridge audio
*
* Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr)
*
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
* Copyright (c) 2002, Marcus Overhagen <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 _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
@@ -0,0 +1,193 @@
/*
* Auvia BeOS Driver for Via VT82xx Southbridge audio
*
* Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr)
*
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
* Copyright (c) 2002, Marcus Overhagen <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 "auviareg.h"
#include "debug.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
auvia_reg_read_8(device_config *config, int regno)
{
return read_io_8(config->nabmbar + regno);
}
uint16
auvia_reg_read_16(device_config *config, int regno)
{
return read_io_16(config->nabmbar + regno);
}
uint32
auvia_reg_read_32(device_config *config, int regno)
{
return read_io_32(config->nabmbar + regno);
}
void
auvia_reg_write_8(device_config *config, int regno, uint8 value)
{
write_io_8(config->nabmbar + regno, value);
}
void
auvia_reg_write_16(device_config *config, int regno, uint16 value)
{
write_io_16(config->nabmbar + regno, value);
}
void
auvia_reg_write_32(device_config *config, int regno, uint32 value)
{
write_io_32(config->nabmbar + regno, value);
}
/* Emu10k1 Low level */
/*uint32
auvia_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
auvia_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) |
(auvia_chan_read(config, chano, reg & 0xFFFF) & ~mask);
}
write_io_32(config->nabmbar + EMU_PTR, ptr);
write_io_32(config->nabmbar + EMU_DATA, data);
}*/
/* codec */
#define AUVIA_TIMEOUT 200
int
auvia_codec_waitready(device_config *config)
{
int i;
/* poll until codec not busy */
for(i=0; (i<AUVIA_TIMEOUT) && (read_io_32(config->nabmbar
+ AUVIA_CODEC_CTL) & AUVIA_CODEC_BUSY) ; i++)
snooze(1);
if(i>=AUVIA_TIMEOUT) {
//PRINT(("codec busy\n"));
return B_ERROR;
}
return B_OK;
}
int
auvia_codec_waitvalid(device_config *config)
{
int i;
/* poll until codec valid */
for(i=0; (i<AUVIA_TIMEOUT) && !(read_io_32(config->nabmbar
+ AUVIA_CODEC_CTL) & AUVIA_CODEC_PRIVALID) ; i++)
snooze(1);
if(i>=AUVIA_TIMEOUT) {
//PRINT(("codec invalid\n"));
return B_ERROR;
}
return B_OK;
}
uint16
auvia_codec_read(device_config *config, int regno)
{
if(auvia_codec_waitready(config)!=B_OK) {
PRINT(("codec busy (1)\n"));
return -1;
}
write_io_32(config->nabmbar + AUVIA_CODEC_CTL,
AUVIA_CODEC_PRIVALID | AUVIA_CODEC_READ | AUVIA_CODEC_INDEX(regno));
if(auvia_codec_waitready(config)!=B_OK) {
PRINT(("codec busy (2)\n"));
return -1;
}
if(auvia_codec_waitvalid(config)!=B_OK) {
PRINT(("codec invalid (3)\n"));
return -1;
}
return read_io_16(config->nabmbar + AUVIA_CODEC_CTL);
}
void
auvia_codec_write(device_config *config, int regno, uint16 value)
{
if(auvia_codec_waitready(config)!=B_OK) {
PRINT(("codec busy (4)\n"));
return;
}
write_io_32(config->nabmbar + AUVIA_CODEC_CTL,
AUVIA_CODEC_PRIVALID | AUVIA_CODEC_INDEX(regno) | value);
}
@@ -0,0 +1,47 @@
/*
* Auvia BeOS Driver for Via VT82xx Southbridge audio
*
* Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr)
*
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
* Copyright (c) 2002, Marcus Overhagen <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 auvia_reg_read_8(device_config *config, int regno);
uint16 auvia_reg_read_16(device_config *config, int regno);
uint32 auvia_reg_read_32(device_config *config, int regno);
void auvia_reg_write_8(device_config *config, int regno, uint8 value);
void auvia_reg_write_16(device_config *config, int regno, uint16 value);
void auvia_reg_write_32(device_config *config, int regno, uint32 value);
uint16 auvia_codec_read(device_config *config, int regno);
void auvia_codec_write(device_config *config, int regno, uint16 value);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,64 @@
/*
* Auvia BeOS Driver for Via VT82xx Southbridge audio
*
* Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr)
*
* Original code : BeOS Driver for Intel ICH AC'97 Link interface
* Copyright (c) 2002, Marcus Overhagen <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_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