1
0
mirror of https://github.com/deadw00d/AROS.git synced 2025-11-22 03:09:23 +00:00
Files
AROS-v0/workbench/devs/AHI/Drivers/SB128/misc.c
deadwood 5b353efd52 Remove reset handler when freeing driver data
Otherwise the node becomes invalid but is still kept in the handlers list
and next time something accesses this list, it stumbles on random memory.

Implementation copied from VIA-AC97 driver.
2025-11-15 18:41:41 +01:00

1263 lines
33 KiB
C
Executable File
Raw Blame History

/*
The contents of this file are subject to the AROS Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.aros.org/license.html
Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
ANY KIND, either express or implied. See the License for the specific language governing rights and
limitations under the License.
The Original Code is (C) Copyright 2004-2011 Ross Vumbaca.
The Initial Developer of the Original Code is Ross Vumbaca.
All Rights Reserved.
*/
#include <exec/memory.h>
#ifdef __AROS__
#include <aros/debug.h>
#endif
#include <proto/exec.h>
#include <proto/dos.h>
#include "library.h"
#include "regs.h"
#include "interrupt.h"
#include "misc.h"
#include "pci_wrapper.h"
#ifdef __AROS__
#define DebugPrintF bug
INTGW(static, void, playbackinterrupt, PlaybackInterrupt);
INTGW(static, void, recordinterrupt, RecordInterrupt);
INTGW(static, ULONG, cardinterrupt, CardInterrupt);
#endif
/* Global in Card.c */
extern const UWORD InputBits[];
/* Public functions in main.c */
int card_init(struct SB128_DATA *card);
void card_cleanup(struct SB128_DATA *card);
void AddResetHandler(struct SB128_DATA *card);
void micro_delay(unsigned int val)
{
struct timerequest* TimerIO = NULL;
struct MsgPort * replymp;
replymp = (struct MsgPort *) CreateMsgPort();
if (!replymp)
{
DebugPrintF("[SB128] Couldn't create reply port\n");
return;
}
TimerIO = (struct timerequest *)CreateIORequest(replymp, sizeof(struct timerequest));
if (TimerIO == NULL)
{
DebugPrintF("[SB128] Out of memory.\n");
return;
}
if (OpenDevice((CONST_STRPTR) "timer.device", UNIT_MICROHZ, (struct IORequest *)TimerIO, 0) != 0)
{
DebugPrintF("[SB128] Unable to open 'timer.device'.\n");
return;
}
TimerIO->tr_node.io_Command = TR_ADDREQUEST;
TimerIO->tr_time.tv_secs = 0;
TimerIO->tr_time.tv_micro = val;
DoIO((struct IORequest *)TimerIO);
CloseDevice((struct IORequest *)TimerIO);
DeleteIORequest((struct IORequest *)TimerIO);
TimerIO = NULL;
if (replymp)
{
DeleteMsgPort(replymp);
}
}
unsigned long src_ready(struct SB128_DATA *card)
{
unsigned int i;
unsigned long r;
/* Wait for the busy bit to become invalid, and then return the contents
of the SRC register. */
for (i = 0; i < 0x1000; i++)
{
if (!((r = pci_inl(SB128_SRC, card)) & SRC_BUSY))
return r;
//micro_delay(1);
}
DebugPrintF("[SB128] SRC Ready timeout.\n");
return 0;
}
void src_write(struct SB128_DATA *card, unsigned short addr, unsigned short data)
{
unsigned long r;
// ObtainSemaphore(&card->sb128_semaphore);
/* Get copy of SRC register when it's not busy, add address and data, write back. */
r = src_ready(card) & (SRC_DISABLE | SRC_DIS_DAC2 | SRC_DIS_ADC);
r = r | (addr << SRC_ADDR_SHIFT);
r = r | data;
pci_outl(r | SRC_WE, SB128_SRC, card);
//micro_delay(1);
// ReleaseSemaphore(&card->sb128_semaphore);
}
unsigned short src_read(struct SB128_DATA *card, unsigned short addr)
{
//There may be ES137x bugs that require accomodating in this section.
unsigned long r;
// ObtainSemaphore(&card->sb128_semaphore);
/* Get copy of SRC register when it's not busy, add address, write back,
wait for ready, then read back value. */
r = src_ready(card) & (SRC_DISABLE | SRC_DIS_DAC2 | SRC_DIS_ADC);
r = r | (addr << SRC_ADDR_SHIFT);
pci_outl(r, SB128_SRC, card);
/* Give the chip a chance to set the busy bit. */
//micro_delay(1);
// ReleaseSemaphore(&card->sb128_semaphore);
return (src_ready(card) & 0xFFFF);
}
/* Translate AC97 commands to AK4531 commands, and write to the AK4531 codec */
void ak4531_ac97_write(struct SB128_DATA *card, unsigned short reg, unsigned short val)
{
char ak4531_L1 = 0;
char ak4531_R1 = 0;
char ak4531_L2 = 0;
char ak4531_R2 = 0;
char input_right = 0;
char input_left = 0;
short left_vol = 0;
short right_vol = 0;
float steps = 0;
if (reg == AC97_RECORD_SELECT)
{
/* Change input select settings */
input_right = val;
input_left = val >> 8;
/* Translate as appropriate */
switch (input_left) {
case 0:
/* Mic */
ak4531_L2 = 0x80;
break;
case 1:
/* CD */
ak4531_L1 = 0x04;
break;
case 2:
/* Video */
break;
case 3:
/* Aux */
ak4531_L2 = 0x10;
break;
case 4:
/* Line in */
ak4531_L1 = 0x10;
break;
case 5:
/* Stereo Mix (all) */
ak4531_L1 = 0x14;
ak4531_L2 = 0xF4;
break;
case 6:
/* Mono Mix */
break;
case 7:
/* Phone */
ak4531_L2 = 0x60;
break;
default:
/* Shouldn't happen */
DebugPrintF("[SB128] Unsupported Record Input command\n");
}
switch (input_right) {
case 0:
/* Mic */
ak4531_R2 = 0x80;
break;
case 1:
/* CD */
ak4531_R1 = 0x02;
break;
case 2:
/* Video */
break;
case 3:
/* Aux */
ak4531_R2 = 0x08;
break;
case 4:
/* Line in */
ak4531_R1 = 0x08;
break;
case 5:
/* Stereo Mix (all) */
ak4531_R1 = 0x0A;
ak4531_R2 = 0xEC;
break;
case 6:
/* Mono Mix */
break;
case 7:
/* Phone */
ak4531_R2 = 0x60;
break;
default:
/* Shouldn't happen */
DebugPrintF("[SB128] Unsupported Record Input command\n");
}
/* Write input values to AK4531 */
codec_write(card, AK4531_INPUT_MUX_L_1, ak4531_L1);
codec_write(card, AK4531_INPUT_MUX_R_1, ak4531_R1);
codec_write(card, AK4531_INPUT_MUX_L_2, ak4531_L2);
codec_write(card, AK4531_INPUT_MUX_R_2, ak4531_R2);
return;
}
if (reg == AC97_PHONE_VOL || AC97_MIC_VOL || AC97_LINEIN_VOL || AC97_CD_VOL || AC97_AUX_VOL || AC97_PCMOUT_VOL)
{
/* Adjust PCM (from card) Input gain */
if (val & AC97_MUTE)
{
/* Using a muted volume */
right_vol = (AK4531_MUTE | 0x6);
left_vol = (AK4531_MUTE | 0x6);
}
else
{
/* Strip bits */
right_vol = (val & 0x1F);
left_vol = (val >> 8);
/* Convert right volume */
if (right_vol < 0x8)
{
steps = 0x8 - right_vol;
steps = steps * 1.5;
steps = steps / 2;
right_vol = (int) (steps + 0.5);
right_vol = 0x6 - right_vol;
}
else if (right_vol > 0x8)
{
steps = right_vol - 0x8;
steps = steps * 1.5;
steps = steps / 2;
right_vol = (int) (steps + 0.5);
right_vol = 0x6 + right_vol;
}
else if (right_vol == 0x8)
{
/* No attentuation, no mute */
right_vol = 0x6;
}
/* Convert left volume */
if (left_vol < 0x8)
{
steps = 0x8 - left_vol;
steps = steps * 1.5;
steps = steps / 2;
left_vol = (int) (steps + 0.5);
left_vol = 0x6 - left_vol;
}
else if (left_vol > 0x8)
{
steps = left_vol - 0x8;
steps = steps * 1.5;
steps = steps / 2;
left_vol = (int) (steps + 0.5);
left_vol = 0x6 + left_vol;
}
else if (left_vol == 0x8)
{
/* No attentuation, no mute */
left_vol = 0x6;
}
}
/* Write adjusted volume to appropriate place */
/* Un-mute, and disable output, if an input muted */
switch (reg) {
case AC97_PHONE_VOL:
codec_write(card, AK4531_PHONE_VOL_L, right_vol);
codec_write(card, AK4531_PHONE_VOL_R, right_vol);
break;
case AC97_MIC_VOL:
codec_write(card, AK4531_MIC_VOL, right_vol);
break;
case AC97_LINEIN_VOL:
if ((left_vol & AK4531_MUTE) && (right_vol & AK4531_MUTE))
{
left_vol = 0x6;
right_vol = 0x6;
/* Disable on OUTPUT mux */
card->ak4531_output_1 = (card->ak4531_output_1 & ~(AK4531_OUTPUT_LINE));
codec_write(card, AK4531_OUTPUT_MUX_1, card->ak4531_output_1);
}
else
{
codec_write(card, AK4531_LINEIN_VOL_L, left_vol);
codec_write(card, AK4531_LINEIN_VOL_R, right_vol);
/* Re-enable on OUTPUT mux */
card->ak4531_output_1 = (card->ak4531_output_1 | AK4531_OUTPUT_LINE);
codec_write(card, AK4531_OUTPUT_MUX_1, card->ak4531_output_1);
}
break;
case AC97_CD_VOL:
if ((left_vol & AK4531_MUTE) && (right_vol & AK4531_MUTE))
{
left_vol = 0x6;
right_vol = 0x6;
/* Disable on OUTPUT mux */
card->ak4531_output_1 = (card->ak4531_output_1 & ~(AK4531_OUTPUT_CD));
codec_write(card, AK4531_OUTPUT_MUX_1, card->ak4531_output_1);
}
else
{
codec_write(card, AK4531_CD_VOL_L, left_vol);
codec_write(card, AK4531_CD_VOL_R, right_vol);
/* Re-enable on OUTPUT mux */
card->ak4531_output_1 = (card->ak4531_output_1 | AK4531_OUTPUT_CD);
codec_write(card, AK4531_OUTPUT_MUX_1, card->ak4531_output_1);
}
break;
case AC97_AUX_VOL:
if ((left_vol & AK4531_MUTE) && (right_vol & AK4531_MUTE))
{
left_vol = 0x6;
right_vol = 0x6;
/* Disable on OUTPUT mux */
card->ak4531_output_2 = (card->ak4531_output_2 & ~(AK4531_OUTPUT_AUX));
codec_write(card, AK4531_OUTPUT_MUX_2, card->ak4531_output_2);
}
else
{
codec_write(card, AK4531_AUX_VOL_L, left_vol);
codec_write(card, AK4531_AUX_VOL_R, right_vol);
/* Re-enable on OUTPUT mux */
card->ak4531_output_2 = (card->ak4531_output_2 | AK4531_OUTPUT_AUX);
codec_write(card, AK4531_OUTPUT_MUX_2, card->ak4531_output_2);
}
break;
case AC97_PCMOUT_VOL:
codec_write(card, AK4531_PCMOUT_VOL_L, left_vol);
codec_write(card, AK4531_PCMOUT_VOL_R, right_vol);
break;
default:
DebugPrintF("[SB128] Invalid value for Volume Set\n");
}
return;
}
}
void codec_write(struct SB128_DATA *card, unsigned short reg, unsigned short val)
{
unsigned long i, r;
/* Take hold of the hardware semaphore */
//ObtainSemaphore(&card->sb128_semaphore);
if(card->es1370)
{
for (i = 0; i < 10; i++)
{
if (!(pci_inl(SB128_STATUS, card) & CODEC_CSTAT ))
goto es1370_ok1;
Delay(1);
}
DebugPrintF("[SB128] Couldn't write to ak4531!\n");
return;
es1370_ok1:
pci_outw(((unsigned char)reg << ES1370_CODEC_ADD_SHIFT) | (unsigned char)val, ES1370_SB128_CODEC, card);
micro_delay(100);
}
else
{
/* Check for WIP. */
for (i = 0; i < 0x1000; i++)
{
if (!(pci_inl(SB128_CODEC, card) & CODEC_WIP ))
goto ok1;
micro_delay(1);
}
DebugPrintF("[SB128] Couldn't write to ac97! (1)\n");
//ReleaseSemaphore(&card->sb128_semaphore);
return;
ok1:
/* Get copy of SRC register when it's not busy. */
r = src_ready(card);
/* Enable "SRC State Data", an undocumented feature! */
pci_outl((r & (SRC_DISABLE | SRC_DIS_DAC2 | SRC_DIS_ADC)) | 0x00010000, SB128_SRC, card);
/* Wait for "state 0", to avoid "transition states". */
for (i = 0; i < 0x1000; i++)
{
if ((pci_inl(SB128_SRC, card) & 0x00870000) == 0x00)
break;
micro_delay(1);
}
/* Now wait for an undocumented bit to be set (and the SRC to be NOT busy) */
for (i = 0; i < 0x1000; i++)
{
if ((pci_inl(SB128_SRC, card) & 0x00870000) == 0x00010000)
break;
micro_delay(1);
}
/* Write out the value to the codec now. */
pci_outl((((reg << CODEC_ADD_SHIFT) & CODEC_ADD_MASK) | val), SB128_CODEC, card);
/* Delay to make sure the chip had time to set the WIP after
the codec write. */
//micro_delay(1);
/* Restore SRC register. */
src_ready(card);
pci_outl(r, SB128_SRC, card);
/* Check for WIP before returning. */
for (i = 0; i < 0x1000; i++)
{
if (!(pci_inl(SB128_CODEC, card) & CODEC_WIP))
{
//ReleaseSemaphore(&card->sb128_semaphore);
return;
}
micro_delay(1);
}
DebugPrintF("[SB128] Couldn't write to ac97! (2)\n");
}
//ReleaseSemaphore(&card->sb128_semaphore);
return;
}
unsigned short codec_read(struct SB128_DATA *card, unsigned short reg)
{
unsigned long i, r;
unsigned short val;
if(card->es1370)
return 0;
//ObtainSemaphore(&card->sb128_semaphore);
/* Check for WIP. */
for (i = 0; i < 0x1000; i++) {
if (!((pci_inl(SB128_CODEC, card)) & CODEC_WIP ))
goto ok1;
micro_delay(1);
}
DebugPrintF("[SB128] Couldn't read from ac97! (1)\n");
// ReleaseSemaphore(&card->sb128_semaphore);
return 0;
ok1:
/* Get copy of SRC register when it's not busy. */
r = src_ready(card);
/* Enable "SRC State Data", an undocumented feature! */
pci_outl((r & (SRC_DISABLE | SRC_DIS_DAC1 | SRC_DIS_DAC2 | SRC_DIS_ADC)) | 0x00010000, SB128_SRC, card);
/* Wait for "state 0", to avoid "transition states".
Seen in open code. */
for (i = 0; i < 0x1000; i++)
{
if ((pci_inl(SB128_SRC, card) & 0x00870000) == 0x00)
break;
micro_delay(1);
}
/* Now wait for an undocumented bit to be set (and the SRC to be NOT busy) */
for (i = 0; i < 0x1000; i++)
{
if ((pci_inl(SB128_SRC, card) & 0x00870000) == 0x00010000)
break;
micro_delay(1);
}
/* Write the read request to the chip now */
pci_outl((((reg << CODEC_ADD_SHIFT) & CODEC_ADD_MASK) | CODEC_READ), SB128_CODEC, card);
/* Give the chip time to respond to our read request. */
//micro_delay(1);
/* Restore SRC register. */
src_ready(card);
pci_outl(r, SB128_SRC, card);
/* Check for WIP. */
for (i = 0; i < 0x1000; i++) {
if (!((pci_inl(SB128_CODEC, card)) & CODEC_WIP))
goto ok2;
micro_delay(1);
}
DebugPrintF("[SB128] Couldn't read from ac97 (2)!\n");
// ReleaseSemaphore(&card->sb128_semaphore);
return 0;
ok2:
/* Wait for RDY. */
//micro_delay(1);
for (i = 0; i < 0x1000; i++) {
if (!((pci_inl(SB128_CODEC, card)) & CODEC_RDY))
goto ok3;
micro_delay(1);
}
DebugPrintF("[SB128] Couldn't read from ac97 (3)!\n");
// ReleaseSemaphore(&card->sb128_semaphore);
return 0;
ok3:
//micro_delay(5);
Delay(1); //A delay here is crucial, remove this if you use micro_delay()
val = pci_inl(SB128_CODEC, card);
// ReleaseSemaphore(&card->sb128_semaphore);
return val;
}
void rate_set_adc(struct SB128_DATA *card, unsigned long rate)
{
unsigned long n, truncm, freq;
//ObtainSemaphore(&card->sb128_semaphore);
if (rate > 48000)
rate = 48000;
if (rate < 4000)
rate = 4000;
if (card->es1370)
{
pci_outl(((pci_inl(SB128_CONTROL, card) & ~DAC2_DIV_MASK) | (DAC2_SRTODIV(rate) << DAC2_DIV_SHIFT)), SB128_CONTROL, card);
}
else
{
/* This is completely undocumented */
n = rate / 3000;
if ((1 << n) & ((1 << 15) | (1 << 13) | (1 << 11) | (1 << 9)))
n--;
truncm = (21 * n - 1) | 1;
freq = ((48000UL << 15) / rate) * n;
if (rate >= 24000)
{
if (truncm > 239)
truncm = 239;
src_write(card, SRC_ADC + SRC_TRUNC, (((239 - truncm) >> 1) << 9) | (n << 4));
}
else
{
if (truncm > 119)
truncm = 119;
src_write(card, SRC_ADC + SRC_TRUNC, 0x8000 | (((119 - truncm) >> 1) << 9) | (n << 4));
}
src_write(card, SRC_ADC + SRC_INT,
(src_read(card, SRC_ADC + SRC_INT) & 0x00FF) | ((freq >> 5) & 0xFC00));
src_write(card, SRC_ADC + SRC_VF, freq & 0x7FFF);
src_write(card, SRC_VOL_ADC, n << 8);
src_write(card, SRC_VOL_ADC + 1, n << 8);
}
//ReleaseSemaphore(&card->sb128_semaphore);
}
void rate_set_dac2(struct SB128_DATA *card, unsigned long rate)
{
unsigned long freq, r;
//ObtainSemaphore(&card->sb128_semaphore);
if (rate > 48000)
rate = 48000;
if (rate < 4000)
rate = 4000;
if(card->es1370)
{
pci_outl(((pci_inl(SB128_CONTROL, card) & ~DAC2_DIV_MASK) | (DAC2_SRTODIV(rate) << DAC2_DIV_SHIFT)), SB128_CONTROL, card);
}
else
{
freq = ((rate << 15 ) + 1500) / 3000;
/* Get copy of SRC register when it's not busy, clear, preserve the disable bits, write back. */
r = src_ready(card) & (SRC_DISABLE | SRC_DIS_DAC1 | SRC_DIS_DAC2 | SRC_DIS_ADC);
pci_outl(r, SB128_SRC, card);
/* This is completely undocumented */
src_write(card, SRC_DAC2 + SRC_INT,
(src_read(card, SRC_DAC2 + SRC_INT) & 0x00FF) | ((freq >> 5) & 0xFC00));
src_write(card, SRC_DAC2 + SRC_VF, freq & 0x7FFF);
r = (src_ready(card) & (SRC_DISABLE | SRC_DIS_DAC1 | SRC_DIS_ADC));
pci_outl(r, SB128_SRC, card);
}
//ReleaseSemaphore(&card->sb128_semaphore);
}
/******************************************************************************
** DriverData allocation ******************************************************
******************************************************************************/
/* This code used to be in _AHIsub_AllocAudio(), but since we're now
handling CAMD support too, it needs to be done at driver loading
time. */
struct SB128_DATA*
AllocDriverData( struct PCIDevice * dev,
struct DriverBase* AHIsubBase )
{
struct SB128_DATA* card;
UWORD command_word;
D(bug("[SB128]: %s()\n", __PRETTY_FUNCTION__);)
// FIXME: This should be non-cachable, DMA-able memory
card = AllocVec( sizeof( *card ), MEMF_PUBLIC | MEMF_CLEAR );
if( card == NULL )
{
Req( "Unable to allocate driver structure." );
return NULL;
}
card->ahisubbase = AHIsubBase;
card->interrupt.is_Node.ln_Type = IRQTYPE;
card->interrupt.is_Node.ln_Pri = 0;
card->interrupt.is_Node.ln_Name = (STRPTR) LibName;
#ifdef __AROS__
card->interrupt.is_Code = (void(*)(void))&cardinterrupt;
#else
card->interrupt.is_Code = (void(*)(void))CardInterrupt;
#endif
card->interrupt.is_Data = (APTR) card;
card->playback_interrupt.is_Node.ln_Type = IRQTYPE;
card->playback_interrupt.is_Node.ln_Pri = 0;
card->playback_interrupt.is_Node.ln_Name = (STRPTR) LibName;
#ifdef __AROS__
card->playback_interrupt.is_Code = (void(*)(void))&playbackinterrupt;
#else
card->playback_interrupt.is_Code = (void(*)(void))PlaybackInterrupt;
#endif
card->playback_interrupt.is_Data = (APTR) card;
card->record_interrupt.is_Node.ln_Type = IRQTYPE;
card->record_interrupt.is_Node.ln_Pri = 0;
card->record_interrupt.is_Node.ln_Name = (STRPTR) LibName;
#ifdef __AROS__
card->record_interrupt.is_Code = (void(*)(void))&recordinterrupt;
#else
card->record_interrupt.is_Code = (void(*)(void))RecordInterrupt;
#endif
card->record_interrupt.is_Data = (APTR) card;
card->pci_dev = dev;
command_word = inw_config( PCI_COMMAND , dev);
command_word |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
outw_config( PCI_COMMAND, command_word , dev);
card->pci_master_enabled = TRUE;
card->iobase = ahi_pci_get_base_address(0, dev);
card->length = ~( ahi_pci_get_base_size(0, dev) & PCI_BASE_ADDRESS_IO_MASK );
card->irq = ahi_pci_get_irq(dev);
card->chiprev = inb_config(PCI_REVISION_ID, dev);
card->model = inw_config(PCI_SUBSYSTEM_ID, dev);
D(bug("[SB128]: %s: iobase = 0x%p, len = %d\n", __PRETTY_FUNCTION__, card->iobase, card->length);)
/* Initialise hardware access Semaphore */
InitSemaphore(&card->sb128_semaphore);
/* Initialize chip */
if( card_init( card ) < 0 )
{
DebugPrintF("[SB128] Unable to initialize Card subsystem.");
return NULL;
}
ahi_pci_add_intserver(&card->interrupt, dev);
card->interrupt_added = TRUE;
card->card_initialized = TRUE;
card->input = 0;
card->output = 0;
card->monitor_volume = Linear2MixerGain( 0, &card->monitor_volume_bits );
card->input_gain = Linear2RecordGain( 0x10000, &card->input_gain_bits );
card->output_volume = Linear2MixerGain( 0x10000, &card->output_volume_bits );
SaveMixerState(card);
AddResetHandler(card);
return card;
}
/******************************************************************************
** DriverData deallocation ****************************************************
******************************************************************************/
/* And this code used to be in _AHIsub_FreeAudio(). */
void
FreeDriverData( struct SB128_DATA* card,
struct DriverBase* AHIsubBase )
{
if( card != NULL )
{
if( card->pci_dev != NULL )
{
if( card->card_initialized )
{
card_cleanup( card );
}
if( card->pci_master_enabled )
{
UWORD cmd;
cmd = inw_config(PCI_COMMAND, (struct PCIDevice * ) card->pci_dev);
cmd &= ~( PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER );
outw_config(PCI_COMMAND, cmd, (struct PCIDevice * ) card->pci_dev );
}
}
if( card->interrupt_added )
{
ahi_pci_rem_intserver(&card->interrupt, card->pci_dev);
}
if( card->reset_handler_added )
{
RemResetCallback(&card->reset_handler);
}
FreeVec( card );
}
}
int card_init(struct SB128_DATA *card)
{
struct PCIDevice *dev = (struct PCIDevice *) card->pci_dev;
unsigned short cod;
unsigned int i;
/* Check if the card is an original ES1370 - different code needed */
if (inw_config(2, dev) == 0x5000)
card->es1370 = TRUE;
else
card->es1370 = FALSE;
/* Different init sequence for the ES1370 */
if (card->es1370)
{
/* Enable CODEC access, set DAC sample rate to 44100 */
pci_outl(CTRL_CDC_EN | (DAC2_SRTODIV(44100) << DAC2_DIV_SHIFT), SB128_CONTROL, card);
pci_outl(0x00, SB128_SCON, card);
DebugPrintF("[SB128] Did RATE init\n");
/* CODEC initialisation */
codec_write(card, AK4531_RESET, 0x03); /* Enable CODEC */
codec_write(card, AK4531_CLOCK_SEL, 0x00); /* CODEC ADC and DAC use PLL */
codec_write(card, AK4531_RECORD_SELECT, 0x00); /* CODEC ADC set to use mixer for input */
codec_write(card, AK4531_RECORD_GAIN_MIC, 0x00); /* Mic gain set to 0 dB */
/* Volume initialisation */
codec_write(card, AK4531_MASTER_VOL_L, 0x00); /* No attentuation */
codec_write(card, AK4531_MASTER_VOL_R, 0x00);
codec_write(card, AK4531_MASTER_VOL_MONO, 0x00);
/* Analogue mixer input gain registers */
codec_write(card, AK4531_PHONE_VOL_L, AK4531_MUTE | 0x06);
codec_write(card, AK4531_PHONE_VOL_R, AK4531_MUTE | 0x06);
codec_write(card, AK4531_MIC_VOL, AK4531_MUTE | 0x06);
codec_write(card, AK4531_LINEIN_VOL_L, AK4531_MUTE | 0x06);
codec_write(card, AK4531_LINEIN_VOL_R, AK4531_MUTE | 0x06);
codec_write(card, AK4531_CD_VOL_L, 0x06);
codec_write(card, AK4531_CD_VOL_R, 0x06);
codec_write(card, AK4531_AUX_VOL_L, 0x06);
codec_write(card, AK4531_AUX_VOL_R, 0x06);
codec_write(card, AK4531_PCMOUT_VOL_L, 0x06);
codec_write(card, AK4531_PCMOUT_VOL_R, 0x06);
/* Mixer registers */
/* Always on */
codec_write(card, AK4531_OUTPUT_MUX_1, 0x1F);
codec_write(card, AK4531_OUTPUT_MUX_2, 0x3F);
/* Store value of OUTPUT MUX registers */
card->ak4531_output_1 = 0x1F;
card->ak4531_output_2 = 0x3F;
/* Analogous to "Record Select", only TMIC and Phone enabled here */
codec_write(card, AK4531_INPUT_MUX_L_1, 0x00);
codec_write(card, AK4531_INPUT_MUX_R_1, 0x00);
codec_write(card, AK4531_INPUT_MUX_L_2, 0x80);
codec_write(card, AK4531_INPUT_MUX_R_2, 0x80);
DebugPrintF("[SB128] Did VOLUME init\n");
}
else
{
/* Basic clear of everything */
pci_outl(0x00, SB128_CONTROL, card);
pci_outl(0x00, SB128_SCON, card);
pci_outl(0x00, SB128_LEGACY, card);
/* Magical CT5880 AC97 enable bit plus 20ms delay
(Gotta love the undocumented stuff) */
pci_outl(0x20000000, SB128_STATUS, card);
Delay(1);
/* Assert the AC97 reset, and wait 20ms */
pci_outl(CODEC_RESET, SB128_CONTROL, card);
Delay(1);
/* De-assert delay, and wait 20ms */
pci_outl(0x00, SB128_CONTROL, card);
Delay(1);
DebugPrintF("[SB128] Did AC97 reset.\n");
/* Disable the Sample Rate Converter (SRC) */
src_ready(card);
pci_outl(SRC_DISABLE, SB128_SRC, card);
/* Clear the SRC RAM */
for (i = 0; i < 0x80; i++)
src_write(card, i, 0);
DebugPrintF("[SB128] Did SRC wipe.\n");
/* Perform basic configuration of the SRC, not well documented! */
src_write(card, SRC_DAC1 + SRC_TRUNC, 0x100);
src_write(card, SRC_DAC1 + SRC_INT, 0x4000);
src_write(card, SRC_DAC2 + SRC_TRUNC, 0x100);
src_write(card, SRC_DAC2 + SRC_INT, 0x4000);
src_write(card, SRC_VOL_ADC, 0x1000);
src_write(card, SRC_VOL_ADC + 1, 0x1000);
src_write(card, SRC_VOL_DAC1, 0x1000);
src_write(card, SRC_VOL_DAC1 + 1, 0x1000);
src_write(card, SRC_VOL_DAC2, 0x1000);
src_write(card, SRC_VOL_DAC2 + 1, 0x1000);
DebugPrintF("[SB128] Did SRC init.\n");
rate_set_adc(card, 44100);
rate_set_dac2(card, 44100);
/* Re-enable the SRC */
src_ready(card);
pci_outl(0, SB128_SRC, card);
card->currentPlayFreq = 9;
card->currentRecFreq = 9;
DebugPrintF("[SB128] Did RATE init.\n");
/* Initialise registers of AC97 to default */
codec_write(card, AC97_RESET, 0x00);
/* Initialise volumes of AC97 */
codec_write(card, AC97_MASTER_VOL_STEREO, 0x0000 ); /* no attenuation */
codec_write(card, AC97_AUXOUT_VOL, 0x0000 ); /* volume of the rear output */
codec_write(card, AC97_MASTER_VOL_MONO, 0x0000 );
codec_write(card, AC97_MASTER_TONE, 0x0f0f ); /* bass/treble control (if present) */
codec_write(card, AC97_RECORD_SELECT, 0);
codec_write(card, AC97_RECORD_GAIN, 0x0000 ); /* 0 dB gain */
/* Analogue mixer input gain registers */
codec_write(card, AC97_PHONE_VOL, AC97_MUTE | 0x0008 );
codec_write(card, AC97_MIC_VOL, AC97_MUTE | 0x0008 );
codec_write(card, AC97_LINEIN_VOL, AC97_MUTE | 0x0808 );
codec_write(card, AC97_CD_VOL, 0x0808 );
codec_write(card, AC97_VIDEO_VOL, AC97_MUTE | 0x0808 );
codec_write(card, AC97_AUX_VOL, 0x0808 );
codec_write(card, AC97_PCMOUT_VOL, 0x0808 );
DebugPrintF("[SB128] Did VOLUME init.\n");
cod = codec_read(card, AC97_RESET);
DebugPrintF("[SB128] AC97 capabilities = %x\n", cod);
cod = codec_read(card, AC97_VENDOR_ID0);
DebugPrintF("[SB128] AC97_VENDOR_ID0 = %x\n", cod);
cod = codec_read(card, AC97_VENDOR_ID1);
DebugPrintF("[SB128] AC97_VENDOR_ID1 = %x\n", cod);
}
return 0;
}
void card_cleanup(struct SB128_DATA *card)
{
}
/******************************************************************************
** Misc. **********************************************************************
******************************************************************************/
void
SaveMixerState( struct SB128_DATA* card )
{
card->ac97_mic = codec_read( card, AC97_MIC_VOL );
card->ac97_cd = codec_read( card, AC97_CD_VOL );
card->ac97_aux = codec_read( card, AC97_AUX_VOL );
card->ac97_linein = codec_read( card, AC97_LINEIN_VOL );
card->ac97_phone = codec_read( card, AC97_PHONE_VOL );
}
void
RestoreMixerState( struct SB128_DATA* card )
{
if(card->es1370)
{
/* Not possible to save the state, so restore all volumes to mid levels */
ak4531_ac97_write(card, AC97_MIC_VOL, 0x0808);
ak4531_ac97_write(card, AC97_CD_VOL, 0x0808);
ak4531_ac97_write(card, AC97_AUX_VOL, 0x0808);
ak4531_ac97_write(card, AC97_LINEIN_VOL, 0x0808);
ak4531_ac97_write(card, AC97_PHONE_VOL, 0x0808);
}
else
{
codec_write(card, AC97_MIC_VOL, card->ac97_mic );
codec_write(card, AC97_CD_VOL, card->ac97_cd );
codec_write(card, AC97_AUX_VOL, card->ac97_aux );
codec_write(card, AC97_LINEIN_VOL, card->ac97_linein );
codec_write(card, AC97_PHONE_VOL, card->ac97_phone );
}
}
void
UpdateMonitorMixer( struct SB128_DATA* card )
{
int i = InputBits[ card->input ];
UWORD m = card->monitor_volume_bits & 0x801f;
UWORD s = card->monitor_volume_bits;
UWORD mm = AC97_MUTE | 0x0008;
UWORD sm = AC97_MUTE | 0x0808;
if( i == AC97_RECMUX_STEREO_MIX )
{
/* Use the original mixer settings */
RestoreMixerState( card );
}
else
{
if(card->es1370)
{
ak4531_ac97_write(card, AC97_MIC_VOL,
i == AC97_RECMUX_MIC ? m : mm );
ak4531_ac97_write(card, AC97_CD_VOL,
i == AC97_RECMUX_CD ? s : sm );
ak4531_ac97_write(card, AC97_AUX_VOL,
i == AC97_RECMUX_AUX ? s : sm );
ak4531_ac97_write(card, AC97_LINEIN_VOL,
i == AC97_RECMUX_LINE ? s : sm );
ak4531_ac97_write(card, AC97_PHONE_VOL,
i == AC97_RECMUX_PHONE ? m : mm );
}
else
{
codec_write(card, AC97_MIC_VOL,
i == AC97_RECMUX_MIC ? m : mm );
codec_write(card, AC97_CD_VOL,
i == AC97_RECMUX_CD ? s : sm );
codec_write(card, AC97_AUX_VOL,
i == AC97_RECMUX_AUX ? s : sm );
codec_write(card, AC97_LINEIN_VOL,
i == AC97_RECMUX_LINE ? s : sm );
codec_write(card, AC97_PHONE_VOL,
i == AC97_RECMUX_PHONE ? m : mm );
}
}
}
Fixed
Linear2MixerGain( Fixed linear,
UWORD* bits )
{
static const Fixed gain[ 33 ] =
{
260904, /* +12.0 dB */
219523, /* +10.5 dB */
184706, /* +9.0 dB */
155410, /* +7.5 dB */
130762, /* +6.0 dB */
110022, /* +4.5 dB */
92572, /* +3.0 dB */
77890, /* +1.5 dB */
65536, /* <20>0.0 dB */
55142, /* -1.5 dB */
46396, /* -3.0 dB */
39037, /* -4.5 dB */
32846, /* -6.0 dB */
27636, /* -7.5 dB */
23253, /* -9.0 dB */
19565, /* -10.5 dB */
16462, /* -12.0 dB */
13851, /* -13.5 dB */
11654, /* -15.0 dB */
9806, /* -16.5 dB */
8250, /* -18.0 dB */
6942, /* -19.5 dB */
5841, /* -21.0 dB */
4915, /* -22.5 dB */
4135, /* -24.0 dB */
3479, /* -25.5 dB */
2927, /* -27.0 dB */
2463, /* -28.5 dB */
2072, /* -30.0 dB */
1744, /* -31.5 dB */
1467, /* -33.0 dB */
1234, /* -34.5 dB */
0 /* -oo dB */
};
int v = 0;
while( linear < gain[ v ] )
{
++v;
}
if( v == 32 )
{
*bits = 0x8000; /* Mute */
}
else
{
*bits = ( v << 8 ) | v;
}
return gain[ v ];
}
Fixed
Linear2RecordGain( Fixed linear,
UWORD* bits )
{
static const Fixed gain[ 17 ] =
{
873937, /* +22.5 dB */
735326, /* +21.0 dB */
618700, /* +19.5 dB */
520571, /* +18.0 dB */
438006, /* +16.5 dB */
368536, /* +15.0 dB */
310084, /* +13.5 dB */
260904, /* +12.0 dB */
219523, /* +10.5 dB */
184706, /* +9.0 dB */
155410, /* +7.5 dB */
130762, /* +6.0 dB */
110022, /* +4.5 dB */
92572, /* +3.0 dB */
77890, /* +1.5 dB */
65536, /* <20>0.0 dB */
0 /* -oo dB */
};
int v = 0;
while( linear < gain[ v ] )
{
++v;
}
if( v == 16 )
{
*bits = 0x8000; /* Mute */
}
else
{
*bits = ( ( 15 - v ) << 8 ) | ( 15 - v );
}
return gain[ v ];
}
ULONG
SamplerateToLinearPitch( ULONG samplingrate )
{
samplingrate = (samplingrate << 8) / 375;
return (samplingrate >> 1) + (samplingrate & 1);
}
void *pci_alloc_consistent(size_t size, APTR *NonAlignedAddress, unsigned int boundary)
{
void* address;
unsigned long a;
D(bug("[SB128]: %s()\n", __PRETTY_FUNCTION__);)
address = (void *) AllocVec(size + boundary, (
#if defined(__AROS__) && (__WORDSIZE==64)
MEMF_31BIT |
#endif
MEMF_PUBLIC | MEMF_CLEAR));
if (NonAlignedAddress)
{
*NonAlignedAddress = address;
}
if (address != NULL)
{
a = (unsigned long) address;
a = (a + boundary - 1) & ~((unsigned long)boundary - 1);
address = (void *) a;
}
return address;
}
void pci_free_consistent(void* addr)
{
D(bug("[SB128]: %s()\n", __PRETTY_FUNCTION__);)
FreeVec(addr);
}
#ifdef __AMIGAOS4__
static ULONG ResetHandler(struct ExceptionContext *ctx, struct ExecBase *pExecBase, struct SB128_DATA *card)
#else
static ULONG ResetHandler(struct SB128_DATA *card)
#endif
{
struct PCIDevice *dev = card->pci_dev;
//Stop SB128 interrupts and playback/recording
unsigned long ctrl;
ctrl = pci_inl(SB128_CONTROL, card);
ctrl &= ( ~(CTRL_DAC2_EN) & ~(CTRL_ADC_EN) );
/* Stop */
pci_outl(ctrl, SB128_CONTROL, card);
/* Clear and mask interrupts */
pci_outl((pci_inl(SB128_SCON, card) & SB128_IRQ_MASK), SB128_SCON, card);
return 0UL;
}
void AddResetHandler(struct SB128_DATA *card)
{
struct Interrupt *handler = &card->reset_handler;
handler->is_Code = (void (*)())ResetHandler;
handler->is_Data = (APTR) card;
handler->is_Node.ln_Pri = 0;
#ifdef __AMIGAOS4__
handler->is_Node.ln_Type = NT_EXTINTERRUPT;
#else
handler->is_Node.ln_Type = NT_INTERRUPT;
#endif
handler->is_Node.ln_Name = "SB128 Reset Handler";
card->reset_handler_added = AddResetCallback( handler );
}