ES1370 audio driver for QEmu, first version.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21760 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval 2007-07-30 23:35:00 +00:00
parent 6df0b2d554
commit 87ebb10a40
18 changed files with 3250 additions and 0 deletions

View File

@ -2,5 +2,6 @@ SubDir HAIKU_TOP src add-ons kernel drivers audio ac97 ;
SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 auich ;
SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 auvia ;
SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 es1370 ;
SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 ich ;
# SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 ichaudio ;

View File

@ -0,0 +1,14 @@
SubDir HAIKU_TOP src add-ons kernel drivers audio ac97 es1370 ;
SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders media ;
KernelAddon es1370 :
debug.c
es1370.c
io.c
multi.c
util.c
;

View File

@ -0,0 +1,296 @@
/*
* Auich BeOS Driver for Intel 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 <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 */
};
static 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 = auich_codec_read(config, AC97_RESET);
data = (data >> 10) & 31;
return stereo_enhancement_technique[data];
}
const char *
ac97_get_vendor_id_description(device_config *config)
{
uint32 id = ac97_get_vendor_id(config);
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 = auich_codec_read(config, AC97_VENDOR_ID1);
data2 = auich_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);
auich_codec_write(config, AC97_EXTENDED_AUDIO_STATUS,
auich_codec_read(config, AC97_EXTENDED_AUDIO_STATUS) | 1);
}
void default_init(device_config *config)
{
LOG(("default_init\n"));
}
void ad1886_init(device_config *config)
{
LOG(("ad1886_init\n"));
auich_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",auich_codec_read(config, AC97_POWERDOWN)));
#if REVERSE_EAMP_POLARITY
yesno = !yesno;
LOG(("using reverse eamp polarity\n"));
#endif
if (yesno)
auich_codec_write(config, AC97_POWERDOWN, auich_codec_read(config, AC97_POWERDOWN) & ~0x8000); /* switch on (low active) */
else
auich_codec_write(config, AC97_POWERDOWN, auich_codec_read(config, AC97_POWERDOWN) | 0x8000); /* switch off */
LOG(("powerdown register is = %#04x\n", auich_codec_read(config, AC97_POWERDOWN)));
}
void cs4299_amp_enable(device_config *config, bool yesno)
{
LOG(("cs4299_amp_enable\n"));
if (yesno)
auich_codec_write(config, 0x68, 0x8004);
else
auich_codec_write(config, 0x68, 0);
}
const ac97_source_info source_info[] = {
{ "Recording", 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/Treble", 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]));

View File

@ -0,0 +1,107 @@
/*
* Auich BeOS Driver for Intel 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 _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(device_config *config);
const char * ac97_get_vendor_id_description(device_config *config);
uint32 ac97_get_vendor_id(device_config *config);
void ac97_init(device_config *config);
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

View File

@ -0,0 +1,24 @@
/*
* ES1370 Haiku Driver for ES1370 audio
*
* Copyright 2002-2007, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen, marcus@overhagen.de
* Jerome Duval, jerome.duval@free.fr
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
#define NUM_CARDS 3
#define DEVNAME 32
typedef struct
{
uint32 base;
uint32 irq;
uint32 type;
} device_config;
#endif

View File

@ -0,0 +1,76 @@
/*
* ES1370 Haiku Driver for ES1370 audio
*
* Copyright 2002-2007, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen, marcus@overhagen.de
* Jerome Duval, jerome.duval@free.fr
*/
#include <KernelExport.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <OS.h>
#include "debug.h"
#include "es1370.h"
#if DEBUG > 0
static const char * logfile="/boot/home/es1370.log";
static sem_id loglock;
#endif
void debug_printf(const char *text,...);
void log_printf(const char *text,...);
void log_create(void);
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
}

View File

@ -0,0 +1,51 @@
/*
* ES1370 Haiku Driver for ES1370 audio
*
* Copyright 2002-2007, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen, marcus@overhagen.de
* Jerome Duval, jerome.duval@free.fr
*/
#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 1
#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

View File

@ -0,0 +1,613 @@
/*
* ES1370 Haiku Driver for ES1370 audio
*
* Copyright 2002-2007, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jerome Duval, jerome.duval@free.fr
*/
#include <KernelExport.h>
#include <PCI.h>
#include <driver_settings.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "es1370.h"
#include "debug.h"
#include "config.h"
#include "util.h"
#include "io.h"
#include <fcntl.h>
#include <unistd.h>
#include <malloc.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 *);
status_t es1370_init(es1370_dev * card);
static char pci_name[] = B_PCI_MODULE_NAME;
pci_module_info *pci;
int32 num_cards;
es1370_dev cards[NUM_CARDS];
int32 num_names;
char * names[NUM_CARDS*20+1];
extern device_hooks multi_hooks;
es1370_settings current_settings = {
44100, // sample rate
512, // buffer frames
2, // buffer count
};
/* es1370 Memory management */
static es1370_mem *
es1370_mem_new(es1370_dev *card, size_t size)
{
es1370_mem *mem;
if ((mem = malloc(sizeof(*mem))) == NULL)
return (NULL);
mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "es1370 buffer");
mem->size = size;
if (mem->area < B_OK) {
free(mem);
return NULL;
}
return mem;
}
static void
es1370_mem_delete(es1370_mem *mem)
{
if(mem->area > B_OK)
delete_area(mem->area);
free(mem);
}
static void *
es1370_mem_alloc(es1370_dev *card, size_t size)
{
es1370_mem *mem;
mem = es1370_mem_new(card, size);
if (mem == NULL)
return (NULL);
LIST_INSERT_HEAD(&(card->mems), mem, next);
return mem;
}
static void
es1370_mem_free(es1370_dev *card, void *ptr)
{
es1370_mem *mem;
LIST_FOREACH(mem, &card->mems, next) {
if (mem->log_base != ptr)
continue;
LIST_REMOVE(mem, next);
es1370_mem_delete(mem);
break;
}
}
/* es1370 stream functions */
status_t
es1370_stream_set_audioparms(es1370_stream *stream, uint8 channels,
uint8 b16, uint32 sample_rate)
{
uint8 sample_size, frame_size;
LOG(("es1370_stream_set_audioparms\n"));
if ((stream->channels == channels) &&
(stream->b16 == b16) &&
(stream->sample_rate == sample_rate))
return B_OK;
if(stream->buffer)
es1370_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 = es1370_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
es1370_stream_commit_parms(es1370_stream *stream)
{
uint8 sample_size, frame_size;
uint32 ctrl;
es1370_dev *card = stream->card;
LOG(("es1370_stream_commit_parms\n"));
ctrl = es1370_reg_read_32(&card->config, ES1370_REG_CONTROL) & ~CTRL_PCLKDIV;
ctrl |= DAC2_SRTODIV((uint16)stream->sample_rate) << CTRL_SH_PCLKDIV;
es1370_reg_write_32(&card->config, ES1370_REG_CONTROL, ctrl);
sample_size = stream->b16 + 1;
frame_size = sample_size * stream->channels;
if (stream->use & ES1370_USE_RECORD) {
es1370_reg_write_32(&card->config, ES1370_REG_MEMPAGE, 0xd);
es1370_reg_write_32(&card->config, ES1370_REG_ADC_FRAMEADR & 0xff, (uint32)stream->buffer->phy_base);
es1370_reg_write_32(&card->config, ES1370_REG_ADC_FRAMECNT & 0xff, ((stream->blksize * stream->bufcount) >> 2) - 1);
es1370_reg_write_32(&card->config, ES1370_REG_ADC_SCOUNT & 0xff, stream->bufframes - 1);
} else {
es1370_reg_write_32(&card->config, ES1370_REG_MEMPAGE, 0xc);
es1370_reg_write_32(&card->config, ES1370_REG_DAC2_FRAMEADR & 0xff, (uint32)stream->buffer->phy_base);
es1370_reg_write_32(&card->config, ES1370_REG_DAC2_FRAMECNT & 0xff, ((stream->blksize * stream->bufcount) >> 2) - 1);
es1370_reg_write_32(&card->config, ES1370_REG_DAC2_SCOUNT & 0xff, stream->bufframes - 1);
LOG(("es1370_stream_commit_parms %ld %ld\n", ((stream->blksize * stream->bufcount) >> 2) - 1, (stream->blksize / frame_size) - 1));
}
return B_OK;
}
status_t
es1370_stream_get_nth_buffer(es1370_stream *stream, uint8 chan, uint8 buf,
char** buffer, size_t *stride)
{
uint8 sample_size, frame_size;
LOG(("es1370_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
es1370_stream_curaddr(es1370_stream *stream)
{
es1370_dev *card = stream->card;
uint32 reg = 0, cnt = 0;
if (stream->use & ES1370_USE_RECORD) {
reg = ES1370_REG_ADC_FRAMECNT;
} else {
reg = ES1370_REG_DAC2_FRAMECNT;
}
es1370_reg_write_32(&card->config, ES1370_REG_MEMPAGE, reg >> 8);
cnt = es1370_reg_read_32(&card->config, reg & 0xff) >> 16;
//TRACE(("stream_curaddr %lx\n", (cnt << 2) / stream->blksize));
return (cnt << 2) / stream->blksize;
}
void
es1370_stream_start(es1370_stream *stream, void (*inth) (void *), void *inthparam)
{
uint32 sctrl = 0, ctrl = 0;
es1370_dev *card = stream->card;
LOG(("es1370_stream_start\n"));
stream->inth = inth;
stream->inthparam = inthparam;
stream->state |= ES1370_STATE_STARTED;
sctrl = es1370_reg_read_32(&card->config, ES1370_REG_SERIAL_CONTROL);
ctrl = es1370_reg_read_32(&card->config, ES1370_REG_CONTROL);
if (stream->use & ES1370_USE_RECORD) {
sctrl &= ~(SCTRL_R1SEB | SCTRL_R1SMB);
if (stream->b16)
sctrl |= SCTRL_R1SEB;
if (stream->channels == 2)
sctrl |= SCTRL_R1SMB;
es1370_reg_write_32(&card->config, ES1370_REG_SERIAL_CONTROL, sctrl & ~SCTRL_R1INTEN);
es1370_reg_write_32(&card->config, ES1370_REG_SERIAL_CONTROL, sctrl | SCTRL_R1INTEN);
ctrl |= CTRL_ADC_EN;
} else {
sctrl &= ~(SCTRL_P2SEB | SCTRL_P2SMB | 0x003f0000);
if (stream->b16)
sctrl |= SCTRL_P2SEB;
if (stream->channels == 2)
sctrl |= SCTRL_P2SMB;
sctrl |= (stream->b16 + 1) << SCTRL_SH_P2ENDINC;
es1370_reg_write_32(&card->config, ES1370_REG_SERIAL_CONTROL, sctrl & ~SCTRL_P2INTEN);
es1370_reg_write_32(&card->config, ES1370_REG_SERIAL_CONTROL, sctrl | SCTRL_P2INTEN);
ctrl |= CTRL_DAC2_EN;
}
es1370_reg_write_32(&card->config, ES1370_REG_SERIAL_CONTROL, sctrl);
es1370_reg_write_32(&card->config, ES1370_REG_CONTROL, ctrl);
#ifdef DEBUG
//dump_hardware_regs(&stream->card->config);
#endif
}
void
es1370_stream_halt(es1370_stream *stream)
{
uint32 ctrl;
es1370_dev *card = stream->card;
LOG(("es1370_stream_halt\n"));
stream->state &= ~ES1370_STATE_STARTED;
ctrl = es1370_reg_read_32(&card->config, ES1370_REG_CONTROL);
if (stream->use & ES1370_USE_RECORD)
ctrl &= ~CTRL_ADC_EN;
else
ctrl &= ~CTRL_DAC2_EN;
es1370_reg_write_32(&card->config, ES1370_REG_CONTROL, ctrl);
}
es1370_stream *
es1370_stream_new(es1370_dev *card, uint8 use, uint32 bufframes, uint8 bufcount)
{
es1370_stream *stream;
cpu_status status;
LOG(("es1370_stream_new\n"));
stream = malloc(sizeof(es1370_stream));
if (stream == NULL)
return (NULL);
stream->card = card;
stream->use = use;
stream->state = !ES1370_STATE_STARTED;
stream->b16 = 0;
stream->sample_rate = 0;
stream->channels = 0;
stream->bufframes = bufframes;
stream->bufcount = bufcount;
stream->inth = NULL;
stream->inthparam = NULL;
stream->buffer = NULL;
stream->blksize = 0;
stream->trigblk = 0;
stream->blkmod = 0;
stream->buffer_cycle = 0;
stream->frames_count = 0;
stream->real_time = 0;
stream->update_needed = false;
status = lock();
LIST_INSERT_HEAD((&card->streams), stream, next);
unlock(status);
return stream;
}
void
es1370_stream_delete(es1370_stream *stream)
{
cpu_status status;
int32 i;
LOG(("es1370_stream_delete\n"));
es1370_stream_halt(stream);
if(stream->buffer)
es1370_mem_free(stream->card, stream->buffer->log_base);
status = lock();
LIST_REMOVE(stream, next);
unlock(status);
free(stream);
}
/* es1370 interrupt */
static int32
es1370_int(void *arg)
{
es1370_dev *card = arg;
bool gotone = false;
uint32 curblk;
es1370_stream *stream = NULL;
uint32 sta, sctrl;
// TRACE(("es1370_int(%p)\n", card));
sta = es1370_reg_read_32(&card->config, ES1370_REG_STATUS);
if (sta & card->interrupt_mask) {
//TRACE(("interrupt !! %x\n", sta));
sctrl = es1370_reg_read_32(&card->config, ES1370_REG_SERIAL_CONTROL);
LIST_FOREACH(stream, &card->streams, next) {
if (stream->use & ES1370_USE_RECORD) {
if ((sta & STAT_ADC) == 0)
continue;
es1370_reg_write_32(&card->config, ES1370_REG_SERIAL_CONTROL, sctrl & ~SCTRL_R1INTEN);
es1370_reg_write_32(&card->config, ES1370_REG_SERIAL_CONTROL, sctrl | SCTRL_R1INTEN);
} else {
if ((sta & STAT_DAC2) == 0)
continue;
es1370_reg_write_32(&card->config, ES1370_REG_SERIAL_CONTROL, sctrl & ~SCTRL_P2INTEN);
es1370_reg_write_32(&card->config, ES1370_REG_SERIAL_CONTROL, sctrl | SCTRL_P2INTEN);
}
curblk = es1370_stream_curaddr(stream);
// TRACE(("INTR at trigblk %lu, stream->trigblk %lu\n", curblk, stream->trigblk));
if (curblk == stream->trigblk) {
stream->trigblk++;
stream->trigblk = stream->trigblk % stream->blkmod;
if (stream->inth)
stream->inth(stream->inthparam);
}
gotone = true;
}
} else {
//TRACE(("interrupt masked %x, ", card->interrupt_mask));
//TRACE(("sta %x\n", sta));
}
if (gotone)
return B_INVOKE_SCHEDULER;
//TRACE(("Got unhandled interrupt\n"));
return B_UNHANDLED_INTERRUPT;
}
/* es1370 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 == 0x1274
&& (info.device_id == 0x5000
/*|| info.device_id == 0x1371
|| info.device_id == 0x5880*/)
)
{
err = B_OK;
}
ix++;
}
put_module(pci_name);
return err;
}
static void
make_device_names(
es1370_dev * card)
{
sprintf(card->name, "audio/hmulti/es1370/%ld", card-cards+1);
names[num_names++] = card->name;
names[num_names] = NULL;
}
status_t
es1370_init(es1370_dev * card)
{
card->interrupt_mask = STAT_DAC2 | STAT_ADC;
/* Init streams list */
LIST_INIT(&(card->streams));
/* Init mems list */
LIST_INIT(&(card->mems));
return B_OK;
}
static status_t
es1370_setup(es1370_dev * card)
{
status_t err = B_OK;
status_t rv;
unsigned char cmd;
PRINT(("es1370_setup(%p)\n", card));
make_device_names(card);
card->config.base = card->info.u.h0.base_registers[0];
card->config.irq = card->info.u.h0.interrupt_line;
card->config.type = 0;
PRINT(("%s deviceid = %#04x chiprev = %x model = %x enhanced at %lx\n", card->name, card->info.device_id,
card->info.revision, card->info.u.h0.subsystem_id, card->config.base));
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));
es1370_reg_write_32(&card->config, ES1370_REG_SERIAL_CONTROL, SCTRL_P2INTEN | SCTRL_R1INTEN);
es1370_reg_write_32(&card->config, ES1370_REG_CONTROL, CTRL_CDC_EN);
/* reset the codec */
PRINT(("codec reset\n"));
es1370_codec_write(&card->config, CODEC_RES_PD, 0x2);
es1370_codec_write(&card->config, CODEC_RES_PD, 0x3);
es1370_codec_write(&card->config, CODEC_CSEL, 0x0);
es1370_codec_write(&card->config, 0x0, 0x0);
es1370_codec_write(&card->config, 0x1, 0x0);
es1370_codec_write(&card->config, 0x2, 0x0);
es1370_codec_write(&card->config, 0x3, 0x0);
snooze(50000); // 50 ms
PRINT(("installing interrupt : %lx\n", card->config.irq));
install_io_interrupt_handler(card->config.irq, es1370_int, card, 0);
if ((err = es1370_init(card)))
return (err);
PRINT(("init_driver done\n"));
return err;
}
status_t
init_driver(void)
{
int ix=0;
void *settings_handle;
pci_info info;
num_cards = 0;
PRINT(("init_driver()\n"));
load_driver_symbols("es1370");
// get driver settings
settings_handle = load_driver_settings ("es1370.settings");
if (settings_handle != NULL) {
const char *item;
char *end;
uint32 value;
item = get_driver_parameter (settings_handle, "sample_rate", "44100", "44100");
value = strtoul (item, &end, 0);
if (*end == '\0') current_settings.sample_rate = value;
item = get_driver_parameter (settings_handle, "buffer_frames", "512", "512");
value = strtoul (item, &end, 0);
if (*end == '\0') current_settings.buffer_frames = value;
item = get_driver_parameter (settings_handle, "buffer_count", "2", "2");
value = strtoul (item, &end, 0);
if (*end == '\0') current_settings.buffer_count = value;
unload_driver_settings (settings_handle);
}
if (get_module(pci_name, (module_info **) &pci))
return ENOSYS;
while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
if (info.vendor_id == 0x1274
&& (info.device_id == 0x5000
/*|| info.device_id == 0x1371
|| info.device_id == 0x5880*/)
) {
if (num_cards == NUM_CARDS) {
PRINT(("Too many es1370 cards installed!\n"));
break;
}
memset(&cards[num_cards], 0, sizeof(es1370_dev));
cards[num_cards].info = info;
if (es1370_setup(&cards[num_cards])) {
PRINT(("Setup of es1370 %ld failed\n", num_cards+1));
}
else {
num_cards++;
}
}
ix++;
}
if (!num_cards) {
PRINT(("no cards\n"));
put_module(pci_name);
PRINT(("no suitable cards found\n"));
return ENODEV;
}
return B_OK;
}
static void
es1370_shutdown(es1370_dev *card)
{
PRINT(("shutdown(%p)\n", card));
//ac97_amp_enable(&card->config, false);
card->interrupt_mask = 0;
remove_io_interrupt_handler(card->config.irq, es1370_int, card);
}
void
uninit_driver(void)
{
int ix, cnt = num_cards;
num_cards = 0;
PRINT(("uninit_driver()\n"));
for (ix=0; ix<cnt; ix++)
es1370_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;

View File

@ -0,0 +1,136 @@
/*
* ES1370 Haiku Driver for ES1370 audio
*
* Copyright 2003-2007, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jerome Duval, jerome.duval@free.fr
*/
#ifndef _DEV_PCI_ES1370_H_
#define _DEV_PCI_ES1370_H_
#include <Drivers.h>
#include <SupportDefs.h>
#include <OS.h>
#include <PCI.h>
#include "es1370reg.h"
#include "config.h"
#include "queue.h"
#include "hmulti_audio.h"
#include "multi.h"
#define VERSION "Version alpha 1, Copyright (c) 2007 Jérôme Duval, compiled on " __DATE__ " " __TIME__
#define DRIVER_NAME "es1370"
#define FRIENDLY_NAME "ES1370"
#define AUTHOR "Jérôme Duval"
#define FRIENDLY_NAME_ES1370 "ES1370"
#define ES1370_USE_PLAY (1 << 0)
#define ES1370_USE_RECORD (1 << 1)
#define ES1370_STATE_STARTED (1 << 0)
/*
* es1370 memory managment
*/
typedef struct _es1370_mem {
LIST_ENTRY(_es1370_mem) next;
void *log_base;
void *phy_base;
area_id area;
size_t size;
} es1370_mem;
/*
* Streams
*/
typedef struct _es1370_stream {
struct _es1370_dev *card;
uint8 use;
uint8 state;
uint8 b16;
uint32 sample_rate;
uint8 channels;
uint32 bufframes;
uint8 bufcount;
uint32 base;
LIST_ENTRY(_es1370_stream) next;
void (*inth) (void *);
void *inthparam;
void *dmaops_log_base;
void *dmaops_phy_base;
area_id dmaops_area;
es1370_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;
} es1370_stream;
/*
* Devices
*/
typedef struct _es1370_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(, _es1370_stream) streams;
LIST_HEAD(, _es1370_mem) mems;
es1370_stream *pstream;
es1370_stream *rstream;
/* multi_audio */
multi_dev multi;
} es1370_dev;
typedef struct {
uint32 sample_rate;
uint32 buffer_frames;
int32 buffer_count;
} es1370_settings;
extern es1370_settings current_settings;
extern int32 num_cards;
extern es1370_dev cards[NUM_CARDS];
status_t es1370_stream_set_audioparms(es1370_stream *stream, uint8 channels,
uint8 b16, uint32 sample_rate);
status_t es1370_stream_commit_parms(es1370_stream *stream);
status_t es1370_stream_get_nth_buffer(es1370_stream *stream, uint8 chan, uint8 buf,
char** buffer, size_t *stride);
void es1370_stream_start(es1370_stream *stream, void (*inth) (void *), void *inthparam);
void es1370_stream_halt(es1370_stream *stream);
es1370_stream *es1370_stream_new(es1370_dev *card, uint8 use, uint32 bufframes, uint8 bufcount);
void es1370_stream_delete(es1370_stream *stream);
#endif /* _DEV_PCI_ES1370_H_ */

View File

@ -0,0 +1,9 @@
# Settings file for the es1370 driver
#
# This file should be moved to the directory
# ~/config/settings/kernel/drivers/
#
#sample_rate 48000
#buffer_frames 512
#buffer_count 2

View File

@ -0,0 +1,194 @@
/*-
* This supports the ENSONIQ AudioPCI board based on the ES1370.
*
* Copyright (c) 1998 Joachim Kuebart <joki@kuebart.stuttgart.netsurf.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:
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* 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. Absolutely no warranty of function or purpose is made by the author
* Joachim Kuebart.
* 4. Modifications may be freely made to this file if the above conditions
* are met.
*
* $FreeBSD: /repoman/r/ncvs/src/sys/dev/sound/pci/es137x.h,v 1.6 2005/07/31 13:19:38 netchild Exp $
*/
#ifndef _ES1370_REG_H
#define _ES1370_REG_H
#define ES1370_REG_CONTROL 0x00
#define ES1370_REG_STATUS 0x04
#define ES1370_REG_UART_DATA 0x08
#define ES1370_REG_UART_STATUS 0x09
#define ES1370_REG_UART_CONTROL 0x09
#define ES1370_REG_UART_TEST 0x0a
#define ES1370_REG_MEMPAGE 0x0c
#define ES1370_REG_CODEC 0x10
#define CODEC_INDEX_SHIFT 8
#define ES1370_REG_SERIAL_CONTROL 0x20
#define ES1370_REG_DAC1_SCOUNT 0x24
#define ES1370_REG_DAC2_SCOUNT 0x28
#define ES1370_REG_ADC_SCOUNT 0x2c
#define ES1370_REG_DAC1_FRAMEADR 0xc30
#define ES1370_REG_DAC1_FRAMECNT 0xc34
#define ES1370_REG_DAC2_FRAMEADR 0xc38
#define ES1370_REG_DAC2_FRAMECNT 0xc3c
#define ES1370_REG_ADC_FRAMEADR 0xd30
#define ES1370_REG_ADC_FRAMECNT 0xd34
#define DAC2_SRTODIV(x) (((1411200 + (x) / 2) / (x) - 2) & 0x1fff)
#define DAC2_DIVTOSR(x) (1411200 / ((x) + 2))
#define CTRL_ADC_STOP 0x80000000 /* 1 = ADC stopped */
#define CTRL_XCTL1 0x40000000 /* SERR pin if enabled */
#define CTRL_OPEN 0x20000000 /* no function, can be read and
* written */
#define CTRL_PCLKDIV 0x1fff0000 /* ADC/DAC2 clock divider */
#define CTRL_SH_PCLKDIV 16
#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1
* = I2S */
#define CTRL_M_SBB 0x00004000 /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */
#define CTRL_WTSRSEL 0x00003000 /* DAC1 clock freq: 0=5512, 1=11025,
* 2=22050, 3=44100 */
#define CTRL_SH_WTSRSEL 12
#define CTRL_DAC_SYNC 0x00000800 /* 1 = DAC2 runs off DAC1 clock */
#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */
#define CTRL_M_CB 0x00000200 /* recording source: 0 = ADC, 1 =
* MPEG */
#define CTRL_XCTL0 0x00000100 /* 0 = Line in, 1 = Line out */
#define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */
#define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */
#define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */
#define CTRL_ADC_EN 0x00000010 /* enable ADC */
#define CTRL_UART_EN 0x00000008 /* enable MIDI uart */
#define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port (presumably
* at address 0x200) */
#define CTRL_CDC_EN 0x00000002 /* enable serial (CODEC) interface */
#define CTRL_SERR_DIS 0x00000001 /* 1 = disable PCI SERR signal */
#define SCTRL_P2ENDINC 0x00380000 /* */
#define SCTRL_SH_P2ENDINC 19
#define SCTRL_P2STINC 0x00070000 /* */
#define SCTRL_SH_P2STINC 16
#define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */
#define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */
#define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */
#define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */
#define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */
#define SCTRL_R1INTEN 0x00000400 /* enable interrupt */
#define SCTRL_P2INTEN 0x00000200 /* enable interrupt */
#define SCTRL_P1INTEN 0x00000100 /* enable interrupt */
#define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for
* DAC1 */
#define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample
* when disabled */
#define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */
#define SCTRL_R1SMB 0x00000010 /* 1 = stereo */
#define SCTRL_R1FMT 0x00000030 /* format mask */
#define SCTRL_SH_R1FMT 4
#define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */
#define SCTRL_P2SMB 0x00000004 /* 1 = stereo */
#define SCTRL_P2FMT 0x0000000c /* format mask */
#define SCTRL_SH_P2FMT 2
#define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */
#define SCTRL_P1SMB 0x00000001 /* 1 = stereo */
#define SCTRL_P1FMT 0x00000003 /* format mask */
#define SCTRL_SH_P1FMT 0
#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */
#define STAT_CSTAT 0x00000400 /* 1 = codec busy or codec write in
* progress */
#define STAT_CBUSY 0x00000200 /* 1 = codec busy */
#define STAT_CWRIP 0x00000100 /* 1 = codec write in progress */
#define STAT_VC 0x00000060 /* CCB int source, 0=DAC1, 1=DAC2,
* 2=ADC, 3=undef */
#define STAT_SH_VC 5
#define STAT_MCCB 0x00000010 /* CCB int pending */
#define STAT_UART 0x00000008 /* UART int pending */
#define STAT_DAC1 0x00000004 /* DAC1 int pending */
#define STAT_DAC2 0x00000002 /* DAC2 int pending */
#define STAT_ADC 0x00000001 /* ADC int pending */
#define CODEC_OMIX1 0x10
#define CODEC_OMIX2 0x11
#define CODEC_LIMIX1 0x12
#define CODEC_RIMIX1 0x13
#define CODEC_LIMIX2 0x14
#define CODEC_RIMIX2 0x15
#define CODEC_RES_PD 0x16
#define CODEC_CSEL 0x17
#define CODEC_ADSEL 0x18
#define CODEC_MGAIN 0x19
/* ES1371 specific */
#define CODEC_ID_SESHIFT 10
#define CODEC_ID_SEMASK 0x1f
#define CODEC_PIRD 0x00800000 /* 0 = write AC97 register */
#define CODEC_PIADD_MASK 0x007f0000
#define CODEC_PIADD_SHIFT 16
#define CODEC_PIDAT_MASK 0x0000ffff
#define CODEC_PIDAT_SHIFT 0
#define CODEC_PORD 0x00800000 /* 0 = write AC97 register */
#define CODEC_POADD_MASK 0x007f0000
#define CODEC_POADD_SHIFT 16
#define CODEC_PODAT_MASK 0x0000ffff
#define CODEC_PODAT_SHIFT 0
#define CODEC_RDY 0x80000000 /* AC97 read data valid */
#define CODEC_WIP 0x40000000 /* AC97 write in progress */
#define ES1370_REG_CONTROL 0x00
#define ES1370_REG_SERIAL_CONTROL 0x20
#define ES1371_REG_CODEC 0x14
#define ES1371_REG_LEGACY 0x18 /* W/R: Legacy control/status register */
#define ES1371_REG_SMPRATE 0x10 /* W/R: Codec rate converter interface register */
#define ES1371_SYNC_RES (1<<14) /* Warm AC97 reset */
#define ES1371_DIS_R1 (1<<19) /* record channel accumulator update disable */
#define ES1371_DIS_P2 (1<<20) /* playback channel 2 accumulator update disable */
#define ES1371_DIS_P1 (1<<21) /* playback channel 1 accumulator update disable */
#define ES1371_DIS_SRC (1<<22) /* sample rate converter disable */
#define ES1371_SRC_RAM_BUSY (1<<23) /* R/O: sample rate memory is busy */
#define ES1371_SRC_RAM_WE (1<<24) /* R/W: read/write control for sample rate converter */
#define ES1371_SRC_RAM_ADDRO(o) (((o)&0x7f)<<25) /* address of the sample rate converter */
#define ES1371_SRC_RAM_DATAO(o) (((o)&0xffff)<<0) /* current value of the sample rate converter */
#define ES1371_SRC_RAM_DATAI(i) (((i)>>0)&0xffff) /* current value of the sample rate converter */
/*
* S/PDIF specific
*/
/* Use ES1370_REG_CONTROL */
#define RECEN_B 0x08000000 /* Used to control mixing of analog with digital data */
#define SPDIFEN_B 0x04000000 /* Reset to switch digital output mux to "THRU" mode */
/* Use ES1370_REG_STATUS */
#define ENABLE_SPDIF 0x00040000 /* Used to enable the S/PDIF circuitry */
#define TEST_SPDIF 0x00020000 /* Used to put the S/PDIF module in "test mode" */
/*
* Sample rate converter addresses
*/
#define ES_SMPREG_DAC1 0x70
#define ES_SMPREG_DAC2 0x74
#define ES_SMPREG_ADC 0x78
#define ES_SMPREG_TRUNC_N 0x00
#define ES_SMPREG_INT_REGS 0x01
#define ES_SMPREG_VFREQ_FRAC 0x03
#define ES_SMPREG_VOL_ADC 0x6c
#define ES_SMPREG_VOL_DAC1 0x7c
#define ES_SMPREG_VOL_DAC2 0x7e
#endif

View File

@ -0,0 +1,97 @@
/*
* ES1370 Haiku Driver for ES1370 audio
*
* Copyright 2002-2007, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen, marcus@overhagen.de
* Jerome Duval, jerome.duval@free.fr
*/
#include <KernelExport.h>
#include <OS.h>
#include "io.h"
#include "es1370reg.h"
#include "debug.h"
#include <PCI.h>
extern pci_module_info *pci;
uint8
es1370_reg_read_8(device_config *config, int regno)
{
ASSERT(regno >= 0);
return pci->read_io_8(config->base + regno);
}
uint16
es1370_reg_read_16(device_config *config, int regno)
{
ASSERT(regno >= 0);
return pci->read_io_16(config->base + regno);
}
uint32
es1370_reg_read_32(device_config *config, int regno)
{
ASSERT(regno >= 0);
return pci->read_io_32(config->base + regno);
}
void
es1370_reg_write_8(device_config *config, int regno, uint8 value)
{
ASSERT(regno >= 0);
pci->write_io_8(config->base + regno, value);
}
void
es1370_reg_write_16(device_config *config, int regno, uint16 value)
{
ASSERT(regno >= 0);
pci->write_io_16(config->base + regno, value);
}
void
es1370_reg_write_32(device_config *config, int regno, uint32 value)
{
ASSERT(regno >= 0);
pci->write_io_32(config->base + regno, value);
}
/* codec */
static int
es1370_codec_wait(device_config *config)
{
int i;
for (i = 0; i < 1100; i++) {
if ((es1370_reg_read_32(config, ES1370_REG_STATUS) & STAT_CWRIP) == 0)
return B_OK;
if (i > 100)
snooze(1);
}
return B_TIMED_OUT;
}
uint16
es1370_codec_read(device_config *config, int regno)
{
ASSERT(regno >= 0);
if(es1370_codec_wait(config)!=B_OK) {
PRINT(("codec busy (2)\n"));
return -1;
}
return pci->read_io_32(config->base + ES1370_REG_CODEC);
}
void
es1370_codec_write(device_config *config, int regno, uint16 value)
{
ASSERT(regno >= 0);
if(es1370_codec_wait(config)!=B_OK) {
PRINT(("codec busy (4)\n"));
return;
}
pci->write_io_32(config->base + ES1370_REG_CODEC, (regno << 8) | value);
}

View File

@ -0,0 +1,27 @@
/*
* ES1370 Haiku Driver for ES1370 audio
*
* Copyright 2002-2007, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen, marcus@overhagen.de
* Jerome Duval, jerome.duval@free.fr
*/
#ifndef _IO_H_
#define _IO_H_
#include "config.h"
uint8 es1370_reg_read_8(device_config *config, int regno);
uint16 es1370_reg_read_16(device_config *config, int regno);
uint32 es1370_reg_read_32(device_config *config, int regno);
void es1370_reg_write_8(device_config *config, int regno, uint8 value);
void es1370_reg_write_16(device_config *config, int regno, uint16 value);
void es1370_reg_write_32(device_config *config, int regno, uint32 value);
uint16 es1370_codec_read(device_config *config, int regno);
void es1370_codec_write(device_config *config, int regno, uint16 value);
#endif

View File

@ -0,0 +1,881 @@
/*
* ES1370 Haiku Driver for ES1370 audio
*
* Copyright 2002-2007, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jerome Duval, jerome.duval@free.fr
*/
#include <OS.h>
#include <MediaDefs.h>
#include <strings.h>
#include "hmulti_audio.h"
#include "multi.h"
#include "ac97.h"
//#define DEBUG 1
#include "debug.h"
#include "es1370.h"
#include "util.h"
#include "io.h"
static void
es1370_ac97_get_mix(void *card, const void *cookie, int32 type, float *values) {
es1370_dev *dev = (es1370_dev*)card;
ac97_source_info *info = (ac97_source_info *)cookie;
uint16 value, mask;
float gain;
switch(type) {
case B_MIX_GAIN:
value = es1370_codec_read(&dev->config, info->reg);
//PRINT(("B_MIX_GAIN value : %u\n", value));
if(info->type & B_MIX_STEREO) {
mask = ((1 << (info->bits + 1)) - 1) << 8;
gain = ((value & mask) >> 8) * info->granularity;
if(info->polarity == 1)
values[0] = info->max_gain - gain;
else
values[0] = gain - info->min_gain;
mask = ((1 << (info->bits + 1)) - 1);
gain = (value & mask) * info->granularity;
if(info->polarity == 1)
values[1] = info->max_gain - gain;
else
values[1] = gain - info->min_gain;
} else {
mask = ((1 << (info->bits + 1)) - 1);
gain = (value & mask) * info->granularity;
if(info->polarity == 1)
values[0] = info->max_gain - gain;
else
values[0] = gain - info->min_gain;
}
break;
case B_MIX_MUTE:
mask = ((1 << 1) - 1) << 15;
value = es1370_codec_read(&dev->config, info->reg);
//PRINT(("B_MIX_MUTE value : %u\n", value));
value &= mask;
values[0] = ((value >> 15) == 1) ? 1.0 : 0.0;
break;
case B_MIX_MICBOOST:
mask = ((1 << 1) - 1) << 6;
value = es1370_codec_read(&dev->config, info->reg);
//PRINT(("B_MIX_MICBOOST value : %u\n", value));
value &= mask;
values[0] = ((value >> 6) == 1) ? 1.0 : 0.0;
break;
case B_MIX_MUX:
mask = ((1 << 3) - 1);
value = es1370_codec_read(&dev->config, AC97_RECORD_SELECT);
value &= mask;
//PRINT(("B_MIX_MUX value : %u\n", value));
values[0] = (float)value;
break;
}
}
static void
es1370_ac97_set_mix(void *card, const void *cookie, int32 type, float *values) {
es1370_dev *dev = (es1370_dev*)card;
ac97_source_info *info = (ac97_source_info *)cookie;
uint16 value, mask;
float gain;
switch(type) {
case B_MIX_GAIN:
value = es1370_codec_read(&dev->config, info->reg);
if(info->type & B_MIX_STEREO) {
mask = ((1 << (info->bits + 1)) - 1) << 8;
value &= ~mask;
if(info->polarity == 1)
gain = info->max_gain - values[0];
else
gain = values[0] - info->min_gain;
value |= ((uint16)(gain / info->granularity) << 8) & mask;
mask = ((1 << (info->bits + 1)) - 1);
value &= ~mask;
if(info->polarity == 1)
gain = info->max_gain - values[1];
else
gain = values[1] - info->min_gain;
value |= ((uint16)(gain / info->granularity)) & mask;
} else {
mask = ((1 << (info->bits + 1)) - 1);
value &= ~mask;
if(info->polarity == 1)
gain = info->max_gain - values[0];
else
gain = values[0] - info->min_gain;
value |= ((uint16)(gain / info->granularity)) & mask;
}
//PRINT(("B_MIX_GAIN value : %u\n", value));
es1370_codec_write(&dev->config, info->reg, value);
break;
case B_MIX_MUTE:
mask = ((1 << 1) - 1) << 15;
value = es1370_codec_read(&dev->config, info->reg);
value &= ~mask;
value |= ((values[0] == 1.0 ? 1 : 0 ) << 15 & mask);
if(info->reg == AC97_SURROUND_VOLUME) {
// there is a independent mute for each channel
mask = ((1 << 1) - 1) << 7;
value &= ~mask;
value |= ((values[0] == 1.0 ? 1 : 0 ) << 7 & mask);
}
//PRINT(("B_MIX_MUTE value : %u\n", value));
es1370_codec_write(&dev->config, info->reg, value);
break;
case B_MIX_MICBOOST:
mask = ((1 << 1) - 1) << 6;
value = es1370_codec_read(&dev->config, info->reg);
value &= ~mask;
value |= ((values[0] == 1.0 ? 1 : 0 ) << 6 & mask);
//PRINT(("B_MIX_MICBOOST value : %u\n", value));
es1370_codec_write(&dev->config, info->reg, value);
break;
case B_MIX_MUX:
mask = ((1 << 3) - 1);
value = ((int32)values[0]) & mask;
value = value | (value << 8);
//PRINT(("B_MIX_MUX value : %u\n", value));
es1370_codec_write(&dev->config, AC97_RECORD_SELECT, value);
break;
}
}
static int32
es1370_create_group_control(multi_dev *multi, int32 *index, int32 parent,
int32 string, const char* name) {
int32 i = *index;
(*index)++;
multi->controls[i].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + i;
multi->controls[i].mix_control.parent = parent;
multi->controls[i].mix_control.flags = B_MULTI_MIX_GROUP;
multi->controls[i].mix_control.master = EMU_MULTI_CONTROL_MASTERID;
multi->controls[i].mix_control.string = string;
if(name)
strcpy(multi->controls[i].mix_control.name, name);
return multi->controls[i].mix_control.id;
}
static status_t
es1370_create_controls_list(multi_dev *multi)
{
multi->control_count = 0;
PRINT(("multi->control_count %lu\n", multi->control_count));
return B_OK;
}
static status_t
es1370_get_mix(es1370_dev *card, multi_mix_value_info * MMVI)
{
int32 i, id;
multi_mixer_control *control = NULL;
for(i=0; i<MMVI->item_count; i++) {
id = MMVI->values[i].id - EMU_MULTI_CONTROL_FIRSTID;
if(id < 0 || id >= card->multi.control_count) {
PRINT(("es1370_get_mix : invalid control id requested : %li\n", id));
continue;
}
control = &card->multi.controls[id];
if(control->mix_control.flags & B_MULTI_MIX_GAIN) {
if(control->get) {
float values[2];
control->get(card, control->cookie, control->type, values);
if(control->mix_control.master == EMU_MULTI_CONTROL_MASTERID)
MMVI->values[i].u.gain = values[0];
else
MMVI->values[i].u.gain = values[1];
}
}
if(control->mix_control.flags & B_MULTI_MIX_ENABLE && control->get) {
float values[1];
control->get(card, control->cookie, control->type, values);
MMVI->values[i].u.enable = (values[0] == 1.0);
}
if(control->mix_control.flags & B_MULTI_MIX_MUX && control->get) {
float values[1];
control->get(card, control->cookie, control->type, values);
MMVI->values[i].u.mux = (int32)values[0];
}
}
return B_OK;
}
static status_t
es1370_set_mix(es1370_dev *card, multi_mix_value_info * MMVI)
{
int32 i, id;
multi_mixer_control *control = NULL;
for(i=0; i<MMVI->item_count; i++) {
id = MMVI->values[i].id - EMU_MULTI_CONTROL_FIRSTID;
if(id < 0 || id >= card->multi.control_count) {
PRINT(("es1370_set_mix : invalid control id requested : %li\n", id));
continue;
}
control = &card->multi.controls[id];
if(control->mix_control.flags & B_MULTI_MIX_GAIN) {
multi_mixer_control *control2 = NULL;
if(i+1<MMVI->item_count) {
id = MMVI->values[i + 1].id - EMU_MULTI_CONTROL_FIRSTID;
if(id < 0 || id >= card->multi.control_count) {
PRINT(("es1370_set_mix : invalid control id requested : %li\n", id));
} else {
control2 = &card->multi.controls[id];
if(control2->mix_control.master != control->mix_control.id)
control2 = NULL;
}
}
if(control->set) {
float values[2];
values[0] = 0.0;
values[1] = 0.0;
if(control->mix_control.master == EMU_MULTI_CONTROL_MASTERID)
values[0] = MMVI->values[i].u.gain;
else
values[1] = MMVI->values[i].u.gain;
if(control2 && control2->mix_control.master != EMU_MULTI_CONTROL_MASTERID)
values[1] = MMVI->values[i+1].u.gain;
control->set(card, control->cookie, control->type, values);
}
if(control2)
i++;
}
if(control->mix_control.flags & B_MULTI_MIX_ENABLE && control->set) {
float values[1];
values[0] = MMVI->values[i].u.enable ? 1.0 : 0.0;
control->set(card, control->cookie, control->type, values);
}
if(control->mix_control.flags & B_MULTI_MIX_MUX && control->set) {
float values[1];
values[0] = (float)MMVI->values[i].u.mux;
control->set(card, control->cookie, control->type, values);
}
}
return B_OK;
}
static status_t
es1370_list_mix_controls(es1370_dev *card, multi_mix_control_info * MMCI)
{
multi_mix_control *MMC;
int32 i;
MMC = MMCI->controls;
if(MMCI->control_count < 24)
return B_ERROR;
if(es1370_create_controls_list(&card->multi) < B_OK)
return B_ERROR;
for(i=0; i<card->multi.control_count; i++) {
MMC[i] = card->multi.controls[i].mix_control;
}
MMCI->control_count = card->multi.control_count;
return B_OK;
}
static status_t
es1370_list_mix_connections(es1370_dev *card, multi_mix_connection_info * data)
{
return B_ERROR;
}
static status_t
es1370_list_mix_channels(es1370_dev *card, multi_mix_channel_info *data)
{
return B_ERROR;
}
/*multi_channel_info chans[] = {
{ 0, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
{ 1, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
{ 2, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
{ 3, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
{ 4, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
{ 5, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
{ 6, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
{ 7, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
{ 8, B_MULTI_OUTPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
{ 9, B_MULTI_OUTPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
{ 10, B_MULTI_INPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
{ 11, B_MULTI_INPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
};*/
/*multi_channel_info chans[] = {
{ 0, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
{ 1, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
{ 2, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_SURROUND_BUS, 0 },
{ 3, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_SURROUND_BUS, 0 },
{ 4, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_REARLEFT | B_CHANNEL_SURROUND_BUS, 0 },
{ 5, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_REARRIGHT | B_CHANNEL_SURROUND_BUS, 0 },
{ 6, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
{ 7, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
{ 8, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
{ 9, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
{ 10, B_MULTI_OUTPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
{ 11, B_MULTI_OUTPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
{ 12, B_MULTI_INPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
{ 13, B_MULTI_INPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
};*/
static void
es1370_create_channels_list(multi_dev *multi)
{
es1370_stream *stream;
uint32 index, i, mode, designations;
multi_channel_info *chans;
uint32 chan_designations[] = {
B_CHANNEL_LEFT,
B_CHANNEL_RIGHT,
B_CHANNEL_REARLEFT,
B_CHANNEL_REARRIGHT,
B_CHANNEL_CENTER,
B_CHANNEL_SUB
};
chans = multi->chans;
index = 0;
for(mode=ES1370_USE_PLAY; mode!=-1;
mode = (mode == ES1370_USE_PLAY) ? ES1370_USE_RECORD : -1) {
LIST_FOREACH(stream, &((es1370_dev*)multi->card)->streams, next) {
if ((stream->use & mode) == 0)
continue;
if(stream->channels == 2)
designations = B_CHANNEL_STEREO_BUS;
else
designations = B_CHANNEL_SURROUND_BUS;
for(i=0; i<stream->channels; i++) {
chans[index].channel_id = index;
chans[index].kind = (mode == ES1370_USE_PLAY) ? B_MULTI_OUTPUT_CHANNEL : B_MULTI_INPUT_CHANNEL;
chans[index].designations = designations | chan_designations[i];
chans[index].connectors = 0;
index++;
}
}
if(mode==ES1370_USE_PLAY) {
multi->output_channel_count = index;
} else {
multi->input_channel_count = index - multi->output_channel_count;
}
}
chans[index].channel_id = index;
chans[index].kind = B_MULTI_OUTPUT_BUS;
chans[index].designations = B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS;
chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO;
index++;
chans[index].channel_id = index;
chans[index].kind = B_MULTI_OUTPUT_BUS;
chans[index].designations = B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS;
chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO;
index++;
multi->output_bus_channel_count = index - multi->output_channel_count
- multi->input_channel_count;
chans[index].channel_id = index;
chans[index].kind = B_MULTI_INPUT_BUS;
chans[index].designations = B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS;
chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO;
index++;
chans[index].channel_id = index;
chans[index].kind = B_MULTI_INPUT_BUS;
chans[index].designations = B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS;
chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO;
index++;
multi->input_bus_channel_count = index - multi->output_channel_count
- multi->input_channel_count - multi->output_bus_channel_count;
multi->aux_bus_channel_count = 0;
}
static status_t
es1370_get_description(es1370_dev *card, multi_description *data)
{
uint32 size;
data->interface_version = B_CURRENT_INTERFACE_VERSION;
data->interface_minimum = B_CURRENT_INTERFACE_VERSION;
strncpy(data->friendly_name, FRIENDLY_NAME, 32);
strcpy(data->vendor_info, AUTHOR);
data->output_channel_count = card->multi.output_channel_count;
data->input_channel_count = card->multi.input_channel_count;
data->output_bus_channel_count = card->multi.output_bus_channel_count;
data->input_bus_channel_count = card->multi.input_bus_channel_count;
data->aux_bus_channel_count = card->multi.aux_bus_channel_count;
size = card->multi.output_channel_count + card->multi.input_channel_count
+ card->multi.output_bus_channel_count + card->multi.input_bus_channel_count
+ card->multi.aux_bus_channel_count;
// for each channel, starting with the first output channel,
// then the second, third..., followed by the first input
// channel, second, third, ..., followed by output bus
// channels and input bus channels and finally auxillary channels,
LOG(("request_channel_count = %d\n",data->request_channel_count));
if (data->request_channel_count >= size) {
LOG(("copying data\n"));
memcpy(data->channels, card->multi.chans, size * sizeof(card->multi.chans[0]));
}
data->output_rates = B_SR_44100;// | B_SR_48000 | B_SR_CVSR;
data->input_rates = B_SR_44100;// | B_SR_48000 | B_SR_CVSR;
data->output_rates = B_SR_44100;
data->input_rates = B_SR_44100;
data->min_cvsr_rate = 0;
data->max_cvsr_rate = 44100;
data->output_formats = B_FMT_16BIT;
data->input_formats = B_FMT_16BIT;
data->lock_sources = B_MULTI_LOCK_INTERNAL;
data->timecode_sources = 0;
data->interface_flags = B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD;
data->start_latency = 3000;
strcpy(data->control_panel,"");
return B_OK;
}
static status_t
es1370_get_enabled_channels(es1370_dev *card, multi_channel_enable *data)
{
B_SET_CHANNEL(data->enable_bits, 0, true);
B_SET_CHANNEL(data->enable_bits, 1, true);
B_SET_CHANNEL(data->enable_bits, 2, true);
B_SET_CHANNEL(data->enable_bits, 3, true);
data->lock_source = B_MULTI_LOCK_INTERNAL;
/*
uint32 lock_source;
int32 lock_data;
uint32 timecode_source;
uint32 * connectors;
*/
return B_OK;
}
static status_t
es1370_set_enabled_channels(es1370_dev *card, multi_channel_enable *data)
{
PRINT(("set_enabled_channels 0 : %s\n", B_TEST_CHANNEL(data->enable_bits, 0) ? "enabled": "disabled"));
PRINT(("set_enabled_channels 1 : %s\n", B_TEST_CHANNEL(data->enable_bits, 1) ? "enabled": "disabled"));
PRINT(("set_enabled_channels 2 : %s\n", B_TEST_CHANNEL(data->enable_bits, 2) ? "enabled": "disabled"));
PRINT(("set_enabled_channels 3 : %s\n", B_TEST_CHANNEL(data->enable_bits, 3) ? "enabled": "disabled"));
return B_OK;
}
static status_t
es1370_get_global_format(es1370_dev *card, multi_format_info *data)
{
data->output_latency = 0;
data->input_latency = 0;
data->timecode_kind = 0;
data->input.rate = B_SR_44100;
data->input.cvsr = 44100;
data->input.format = B_FMT_16BIT;
data->output.rate = B_SR_44100;
data->output.cvsr = 44100;
data->output.format = B_FMT_16BIT;
return B_OK;
}
static status_t
es1370_get_buffers(es1370_dev *card, multi_buffer_list *data)
{
uint8 i, j, pchannels, rchannels, bufcount;
LOG(("flags = %#x\n",data->flags));
LOG(("request_playback_buffers = %#x\n",data->request_playback_buffers));
LOG(("request_playback_channels = %#x\n",data->request_playback_channels));
LOG(("request_playback_buffer_size = %#x\n",data->request_playback_buffer_size));
LOG(("request_record_buffers = %#x\n",data->request_record_buffers));
LOG(("request_record_channels = %#x\n",data->request_record_channels));
LOG(("request_record_buffer_size = %#x\n",data->request_record_buffer_size));
pchannels = card->pstream->channels;
rchannels = card->rstream->channels;
if (data->request_playback_buffers < current_settings.buffer_count ||
data->request_playback_channels < (pchannels) ||
data->request_record_buffers < current_settings.buffer_count ||
data->request_record_channels < (rchannels)) {
LOG(("not enough channels/buffers\n"));
}
data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD; // XXX ???
// data->flags = 0;
data->return_playback_buffers = current_settings.buffer_count; /* playback_buffers[b][] */
data->return_playback_channels = pchannels; /* playback_buffers[][c] */
data->return_playback_buffer_size = current_settings.buffer_frames; /* frames */
bufcount = current_settings.buffer_count;
if(bufcount > data->request_playback_buffers)
bufcount = data->request_playback_buffers;
for(i=0; i<bufcount; i++)
for(j=0; j<pchannels; j++)
es1370_stream_get_nth_buffer(card->pstream, j, i,
&data->playback_buffers[i][j].base,
&data->playback_buffers[i][j].stride);
data->return_record_buffers = current_settings.buffer_count;
data->return_record_channels = rchannels;
data->return_record_buffer_size = current_settings.buffer_frames; /* frames */
bufcount = current_settings.buffer_count;
if(bufcount > data->request_record_buffers)
bufcount = data->request_record_buffers;
for(i=0; i<bufcount; i++)
for(j=0; j<rchannels; j++)
es1370_stream_get_nth_buffer(card->rstream, j, i,
&data->record_buffers[i][j].base,
&data->record_buffers[i][j].stride);
return B_OK;
}
static void
es1370_play_inth(void* inthparams)
{
es1370_stream *stream = (es1370_stream *)inthparams;
//int32 count;
acquire_spinlock(&slock);
stream->real_time = system_time();
stream->frames_count += current_settings.buffer_frames;
stream->buffer_cycle = stream->trigblk;
stream->update_needed = true;
release_spinlock(&slock);
//TRACE(("es1370_play_inth : cycle : %d\n", stream->buffer_cycle));
release_sem_etc(stream->card->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE);
}
static void
es1370_record_inth(void* inthparams)
{
es1370_stream *stream = (es1370_stream *)inthparams;
//int32 count;
acquire_spinlock(&slock);
stream->real_time = system_time();
stream->frames_count += current_settings.buffer_frames;
stream->buffer_cycle = (stream->trigblk
+ stream->blkmod - 1) % stream->blkmod;
stream->update_needed = true;
release_spinlock(&slock);
//TRACE(("es1370_record_inth : cycle : %d\n", stream->buffer_cycle));
release_sem_etc(stream->card->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE);
}
static status_t
es1370_buffer_exchange(es1370_dev *card, multi_buffer_info *data)
{
cpu_status status;
es1370_stream *pstream, *rstream;
data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD;
if (!(card->pstream->state & ES1370_STATE_STARTED))
es1370_stream_start(card->pstream, es1370_play_inth, card->pstream);
if (!(card->rstream->state & ES1370_STATE_STARTED))
es1370_stream_start(card->rstream, es1370_record_inth, card->rstream);
if (acquire_sem_etc(card->buffer_ready_sem, 1, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT, 100000)
== B_TIMED_OUT) {
LOG(("buffer_exchange timeout ff\n"));
}
status = lock();
LIST_FOREACH(pstream, &card->streams, next) {
if ((pstream->use & ES1370_USE_PLAY) == 0 ||
(pstream->state & ES1370_STATE_STARTED) == 0)
continue;
if(pstream->update_needed)
break;
}
LIST_FOREACH(rstream, &card->streams, next) {
if ((rstream->use & ES1370_USE_RECORD) == 0 ||
(rstream->state & ES1370_STATE_STARTED) == 0)
continue;
if(rstream->update_needed)
break;
}
if(!pstream)
pstream = card->pstream;
if(!rstream)
rstream = card->rstream;
/* do playback */
data->playback_buffer_cycle = pstream->buffer_cycle;
data->played_real_time = pstream->real_time;
data->played_frames_count = pstream->frames_count;
data->_reserved_0 = pstream->first_channel;
pstream->update_needed = false;
/* do record */
data->record_buffer_cycle = rstream->buffer_cycle;
data->recorded_frames_count = rstream->frames_count;
data->recorded_real_time = rstream->real_time;
data->_reserved_1 = rstream->first_channel;
rstream->update_needed = false;
unlock(status);
//TRACE(("buffer_exchange ended\n"));
return B_OK;
}
static status_t
es1370_buffer_force_stop(es1370_dev *card)
{
//es1370_voice_halt(card->pvoice);
return B_OK;
}
static status_t
es1370_multi_control(void *cookie, uint32 op, void *data, size_t length)
{
es1370_dev *card = (es1370_dev *)cookie;
switch (op) {
case B_MULTI_GET_DESCRIPTION:
LOG(("B_MULTI_GET_DESCRIPTION\n"));
return es1370_get_description(card, (multi_description *)data);
case B_MULTI_GET_EVENT_INFO:
LOG(("B_MULTI_GET_EVENT_INFO\n"));
return B_ERROR;
case B_MULTI_SET_EVENT_INFO:
LOG(("B_MULTI_SET_EVENT_INFO\n"));
return B_ERROR;
case B_MULTI_GET_EVENT:
LOG(("B_MULTI_GET_EVENT\n"));
return B_ERROR;
case B_MULTI_GET_ENABLED_CHANNELS:
LOG(("B_MULTI_GET_ENABLED_CHANNELS\n"));
return es1370_get_enabled_channels(card, (multi_channel_enable *)data);
case B_MULTI_SET_ENABLED_CHANNELS:
LOG(("B_MULTI_SET_ENABLED_CHANNELS\n"));
return es1370_set_enabled_channels(card, (multi_channel_enable *)data);
case B_MULTI_GET_GLOBAL_FORMAT:
LOG(("B_MULTI_GET_GLOBAL_FORMAT\n"));
return es1370_get_global_format(card, (multi_format_info *)data);
case B_MULTI_SET_GLOBAL_FORMAT:
LOG(("B_MULTI_SET_GLOBAL_FORMAT\n"));
return B_OK; /* XXX BUG! we *MUST* return B_OK, returning B_ERROR will prevent
* BeOS to accept the format returned in B_MULTI_GET_GLOBAL_FORMAT
*/
case B_MULTI_GET_CHANNEL_FORMATS:
LOG(("B_MULTI_GET_CHANNEL_FORMATS\n"));
return B_ERROR;
case B_MULTI_SET_CHANNEL_FORMATS: /* only implemented if possible */
LOG(("B_MULTI_SET_CHANNEL_FORMATS\n"));
return B_ERROR;
case B_MULTI_GET_MIX:
LOG(("B_MULTI_GET_MIX\n"));
return es1370_get_mix(card, (multi_mix_value_info *)data);
case B_MULTI_SET_MIX:
LOG(("B_MULTI_SET_MIX\n"));
return es1370_set_mix(card, (multi_mix_value_info *)data);
case B_MULTI_LIST_MIX_CHANNELS:
LOG(("B_MULTI_LIST_MIX_CHANNELS\n"));
return es1370_list_mix_channels(card, (multi_mix_channel_info *)data);
case B_MULTI_LIST_MIX_CONTROLS:
LOG(("B_MULTI_LIST_MIX_CONTROLS\n"));
return es1370_list_mix_controls(card, (multi_mix_control_info *)data);
case B_MULTI_LIST_MIX_CONNECTIONS:
LOG(("B_MULTI_LIST_MIX_CONNECTIONS\n"));
return es1370_list_mix_connections(card, (multi_mix_connection_info *)data);
case B_MULTI_GET_BUFFERS: /* Fill out the struct for the first time; doesn't start anything. */
LOG(("B_MULTI_GET_BUFFERS\n"));
return es1370_get_buffers(card, data);
case B_MULTI_SET_BUFFERS: /* Set what buffers to use, if the driver supports soft buffers. */
LOG(("B_MULTI_SET_BUFFERS\n"));
return B_ERROR; /* we do not support soft buffers */
case B_MULTI_SET_START_TIME: /* When to actually start */
LOG(("B_MULTI_SET_START_TIME\n"));
return B_ERROR;
case B_MULTI_BUFFER_EXCHANGE: /* stop and go are derived from this being called */
//TRACE(("B_MULTI_BUFFER_EXCHANGE\n"));
return es1370_buffer_exchange(card, (multi_buffer_info *)data);
case B_MULTI_BUFFER_FORCE_STOP: /* force stop of playback, nothing in data */
LOG(("B_MULTI_BUFFER_FORCE_STOP\n"));
return es1370_buffer_force_stop(card);
}
LOG(("ERROR: unknown multi_control %#x\n",op));
return B_ERROR;
}
static status_t es1370_open(const char *name, uint32 flags, void** cookie);
static status_t es1370_close(void* cookie);
static status_t es1370_free(void* cookie);
static status_t es1370_control(void* cookie, uint32 op, void* arg, size_t len);
static status_t es1370_read(void* cookie, off_t position, void *buf, size_t* num_bytes);
static status_t es1370_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes);
device_hooks multi_hooks = {
es1370_open, /* -> open entry point */
es1370_close, /* -> close entry point */
es1370_free, /* -> free cookie */
es1370_control, /* -> control entry point */
es1370_read, /* -> read entry point */
es1370_write, /* -> write entry point */
NULL, /* start select */
NULL, /* stop select */
NULL, /* scatter-gather read from the device */
NULL /* scatter-gather write to the device */
};
static status_t
es1370_open(const char *name, uint32 flags, void** cookie)
{
es1370_dev *card = NULL;
int ix;
LOG(("open()\n"));
for (ix=0; ix<num_cards; ix++) {
if (!strcmp(cards[ix].name, name)) {
card = &cards[ix];
}
}
if(card == NULL) {
LOG(("open() card not found %s\n", name));
for (ix=0; ix<num_cards; ix++) {
LOG(("open() card available %s\n", cards[ix].name));
}
return B_ERROR;
}
LOG(("open() got card\n"));
if (card->pstream !=NULL)
return B_ERROR;
if (card->rstream !=NULL)
return B_ERROR;
*cookie = card;
card->multi.card = card;
LOG(("stream_new\n"));
card->rstream = es1370_stream_new(card, ES1370_USE_RECORD, current_settings.buffer_frames, current_settings.buffer_count);
card->pstream = es1370_stream_new(card, ES1370_USE_PLAY, current_settings.buffer_frames, current_settings.buffer_count);
card->buffer_ready_sem = create_sem(0, "pbuffer ready");
LOG(("stream_setaudio\n"));
es1370_stream_set_audioparms(card->pstream, 2, true, current_settings.sample_rate);
es1370_stream_set_audioparms(card->rstream, 2, true, current_settings.sample_rate);
card->pstream->first_channel = 0;
card->rstream->first_channel = 2;
es1370_stream_commit_parms(card->pstream);
es1370_stream_commit_parms(card->rstream);
es1370_create_channels_list(&card->multi);
return B_OK;
}
static status_t
es1370_close(void* cookie)
{
//es1370_dev *card = cookie;
LOG(("close()\n"));
return B_OK;
}
static status_t
es1370_free(void* cookie)
{
es1370_dev *card = cookie;
es1370_stream *stream;
LOG(("free()\n"));
if (card->buffer_ready_sem > B_OK)
delete_sem(card->buffer_ready_sem);
LIST_FOREACH(stream, &card->streams, next) {
es1370_stream_halt(stream);
}
while (!LIST_EMPTY(&card->streams)) {
es1370_stream_delete(LIST_FIRST(&card->streams));
}
card->pstream = NULL;
card->rstream = NULL;
return B_OK;
}
static status_t
es1370_control(void* cookie, uint32 op, void* arg, size_t len)
{
return es1370_multi_control(cookie, op, arg, len);
}
static status_t
es1370_read(void* cookie, off_t position, void *buf, size_t* num_bytes)
{
*num_bytes = 0; /* tell caller nothing was read */
return B_IO_ERROR;
}
static status_t
es1370_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
{
*num_bytes = 0; /* tell caller nothing was written */
return B_IO_ERROR;
}

View File

@ -0,0 +1,41 @@
/*
* ES1370 Haiku Driver for ES1370 audio
*
* Copyright 2002-2007, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jerome Duval, jerome.duval@free.fr
*/
#ifndef _MULTI_H_
#define _MULTI_H_
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

View File

@ -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_ */

View File

@ -0,0 +1,113 @@
/*
* 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;
}
/* This is not the most advanced method to map physical memory for io access.
* Perhaps using B_ANY_KERNEL_ADDRESS instead of B_ANY_KERNEL_BLOCK_ADDRESS
* makes the whole offset calculation and relocation obsolete. But the code
* below does work, and I can't test if using B_ANY_KERNEL_ADDRESS also works.
*/
area_id map_mem(void **log, void *phy, size_t size, const char *name)
{
uint32 offset;
void *phyadr;
void *mapadr;
area_id area;
LOG(("mapping physical address %p with %#x bytes for %s\n",phy,size,name));
offset = (uint32)phy & (B_PAGE_SIZE - 1);
phyadr = phy - offset;
size = round_to_pagesize(size + offset);
area = map_physical_memory(name, phyadr, size, B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA, &mapadr);
*log = mapadr + offset;
LOG(("physical = %p, logical = %p, offset = %#x, phyadr = %p, mapadr = %p, size = %#x, area = %#x\n",
phy, *log, offset, phyadr, mapadr, size, area));
return area;
}

View File

@ -0,0 +1,41 @@
/*
* 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);
area_id map_mem(void **log, void *phy, size_t size, const char *name);
cpu_status lock(void);
void unlock(cpu_status status);
extern spinlock slock;
#endif