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:
parent
6df0b2d554
commit
87ebb10a40
@ -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 ;
|
||||
|
14
src/add-ons/kernel/drivers/audio/ac97/es1370/Jamfile
Normal file
14
src/add-ons/kernel/drivers/audio/ac97/es1370/Jamfile
Normal 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
|
||||
;
|
||||
|
296
src/add-ons/kernel/drivers/audio/ac97/es1370/ac97.c
Normal file
296
src/add-ons/kernel/drivers/audio/ac97/es1370/ac97.c
Normal 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]));
|
107
src/add-ons/kernel/drivers/audio/ac97/es1370/ac97.h
Normal file
107
src/add-ons/kernel/drivers/audio/ac97/es1370/ac97.h
Normal 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
|
24
src/add-ons/kernel/drivers/audio/ac97/es1370/config.h
Normal file
24
src/add-ons/kernel/drivers/audio/ac97/es1370/config.h
Normal 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
|
76
src/add-ons/kernel/drivers/audio/ac97/es1370/debug.c
Normal file
76
src/add-ons/kernel/drivers/audio/ac97/es1370/debug.c
Normal 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
|
||||
}
|
||||
|
51
src/add-ons/kernel/drivers/audio/ac97/es1370/debug.h
Normal file
51
src/add-ons/kernel/drivers/audio/ac97/es1370/debug.h
Normal 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
|
613
src/add-ons/kernel/drivers/audio/ac97/es1370/es1370.c
Normal file
613
src/add-ons/kernel/drivers/audio/ac97/es1370/es1370.c
Normal 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;
|
||||
|
136
src/add-ons/kernel/drivers/audio/ac97/es1370/es1370.h
Normal file
136
src/add-ons/kernel/drivers/audio/ac97/es1370/es1370.h
Normal 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_ */
|
@ -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
|
194
src/add-ons/kernel/drivers/audio/ac97/es1370/es1370reg.h
Normal file
194
src/add-ons/kernel/drivers/audio/ac97/es1370/es1370reg.h
Normal 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
|
97
src/add-ons/kernel/drivers/audio/ac97/es1370/io.c
Normal file
97
src/add-ons/kernel/drivers/audio/ac97/es1370/io.c
Normal 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);
|
||||
}
|
27
src/add-ons/kernel/drivers/audio/ac97/es1370/io.h
Normal file
27
src/add-ons/kernel/drivers/audio/ac97/es1370/io.h
Normal 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
|
881
src/add-ons/kernel/drivers/audio/ac97/es1370/multi.c
Normal file
881
src/add-ons/kernel/drivers/audio/ac97/es1370/multi.c
Normal 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;
|
||||
}
|
||||
|
41
src/add-ons/kernel/drivers/audio/ac97/es1370/multi.h
Normal file
41
src/add-ons/kernel/drivers/audio/ac97/es1370/multi.h
Normal 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
|
529
src/add-ons/kernel/drivers/audio/ac97/es1370/queue.h
Normal file
529
src/add-ons/kernel/drivers/audio/ac97/es1370/queue.h
Normal 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_ */
|
113
src/add-ons/kernel/drivers/audio/ac97/es1370/util.c
Normal file
113
src/add-ons/kernel/drivers/audio/ac97/es1370/util.c
Normal 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;
|
||||
}
|
41
src/add-ons/kernel/drivers/audio/ac97/es1370/util.h
Normal file
41
src/add-ons/kernel/drivers/audio/ac97/es1370/util.h
Normal 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
|
Loading…
Reference in New Issue
Block a user