From 4f43fc38e3489ea45d12b7b5ba6fff50b69c5746 Mon Sep 17 00:00:00 2001 From: NicJA Date: Fri, 26 Aug 2011 22:47:45 +0000 Subject: [PATCH] change init code to support multiple cards. small fixes and corrections to code. git-svn-id: https://svn.aros.org/svn/aros/trunk/AROS@40901 fb15a70f-31f2-0310-bbcc-cdcc74a49acc --- workbench/devs/AHI/Drivers/CMI8738/DriverData.h | 16 +- workbench/devs/AHI/Drivers/CMI8738/cmi8738.c | 1653 +++++++++++----------- workbench/devs/AHI/Drivers/CMI8738/driver-init.c | 192 +-- workbench/devs/AHI/Drivers/CMI8738/interrupt.c | 28 +- workbench/devs/AHI/Drivers/CMI8738/interrupt.h | 6 +- workbench/devs/AHI/Drivers/CMI8738/misc.c | 273 ++-- workbench/devs/AHI/Drivers/CMI8738/pci_aros.c | 19 +- workbench/devs/AHI/Drivers/CMI8738/regs.h | 6 + 8 files changed, 1134 insertions(+), 1059 deletions(-) rewrite workbench/devs/AHI/Drivers/CMI8738/cmi8738.c (66%) diff --git a/workbench/devs/AHI/Drivers/CMI8738/DriverData.h b/workbench/devs/AHI/Drivers/CMI8738/DriverData.h index f93c5049f3..351a65be61 100755 --- a/workbench/devs/AHI/Drivers/CMI8738/DriverData.h +++ b/workbench/devs/AHI/Drivers/CMI8738/DriverData.h @@ -9,8 +9,8 @@ limitations under the License. The Original Code is written by Davy Wentzler. */ -#ifndef AHI_Drivers_Card_DriverData_h -#define AHI_Drivers_Card_DriverData_h +#ifndef AHI_Drivers_CMI8738_DriverData_h +#define AHI_Drivers_CMI8738_DriverData_h #include #include @@ -67,11 +67,13 @@ struct CMI8738_DATA /*** PCI/Card initialization progress *********************************/ struct PCIDevice *pci_dev; - APTR iobase; - unsigned long length; - unsigned short model; + APTR iobase; + unsigned long length; + unsigned short model; unsigned char chiprev; - unsigned int irq; + unsigned char chipvers; + unsigned int channels; + unsigned int irq; /** TRUE if bus mastering is activated */ BOOL pci_master_enabled; @@ -223,4 +225,4 @@ struct CMI8738_DATA UWORD ac97_phone; }; -#endif /* AHI_Drivers_Card_DriverData_h */ +#endif /* AHI_Drivers_CMI8738_DriverData_h */ diff --git a/workbench/devs/AHI/Drivers/CMI8738/cmi8738.c b/workbench/devs/AHI/Drivers/CMI8738/cmi8738.c dissimilarity index 66% index 471a6b21f9..06977bd85d 100755 --- a/workbench/devs/AHI/Drivers/CMI8738/cmi8738.c +++ b/workbench/devs/AHI/Drivers/CMI8738/cmi8738.c @@ -1,826 +1,827 @@ -/* -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 written by Davy Wentzler. -*/ - -//#include - -#if !defined(__AROS__) -#undef __USE_INLINE__ -#include -#endif - -#include -#include -#include - -#include -#include -#include -#include - -#ifdef __AROS__ -#define DEBUG 1 -#include -#define DebugPrintF bug -#endif -#include -#include - -#include "library.h" -#include "regs.h" -#include "misc.h" -#include "pci_wrapper.h" - -extern int z; - -/****************************************************************************** -** Globals ******************************************************************** -******************************************************************************/ - -#define FREQUENCIES 8 - -static const ULONG Frequencies[ FREQUENCIES ] = -{ - 5512, - 8000, // µ- and A-Law - 11025, // CD/4 - 16000, // DAT/3 - 22050, // CD/2 - 32000, // DAT/1.5 - 44100, // CD - 48000 // DAT -}; - - -static const ULONG FrequencyBits[ FREQUENCIES ] = -{ - 0, - 4, - 1, - 5, - 2, - 6, - 3, - 7 -}; - - - - -#define INPUTS 5 - -static const STRPTR Inputs[ INPUTS ] = -{ - "Line in", - "Mic", - "CD", - "Aux", - "S/PDIF" -}; - -#if 0 -/* Not static since it's used in misc.c too */ -const UWORD InputBits[ INPUTS ] = -{ - AC97_RECMUX_LINE, - AC97_RECMUX_MIC, - AC97_RECMUX_CD, - AC97_RECMUX_VIDEO, - AC97_RECMUX_AUX, - AC97_RECMUX_STEREO_MIX, - AC97_RECMUX_MONO_MIX, - AC97_RECMUX_PHONE -}; -#endif - - -#define OUTPUTS 2 - -static const STRPTR Outputs[ OUTPUTS ] = -{ - "Line Out", - "Digital Out" -}; - - - -/****************************************************************************** -** AHIsub_AllocAudio ********************************************************** -******************************************************************************/ - -ULONG -_AHIsub_AllocAudio( struct TagItem* taglist, - struct AHIAudioCtrlDrv* AudioCtrl, - struct DriverBase* AHIsubBase ) -{ - struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; - - int card_num; - ULONG ret; - int i, freq = 6; - - bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); - - card_num = ( GetTagData( AHIDB_AudioID, 0, taglist) & 0x0000f000 ) >> 12; - - if( card_num >= CMI8738Base->cards_found || - CMI8738Base->driverdatas[ card_num ] == NULL ) - { - DebugPrintF("no date for card = %ld\n", card_num); - Req( "No CMI8738_DATA for card %ld.", card_num ); - return AHISF_ERROR; - } - else - { - struct CMI8738_DATA* card; - BOOL in_use; - struct PCIDevice *dev; - - card = CMI8738Base->driverdatas[ card_num ]; - AudioCtrl->ahiac_DriverData = card; - - ObtainSemaphore( &CMI8738Base->semaphore ); - in_use = ( card->audioctrl != NULL ); - if( !in_use ) - { - card->audioctrl = AudioCtrl; - } - ReleaseSemaphore( &CMI8738Base->semaphore ); - - if( in_use ) - { - return AHISF_ERROR; - } - - dev = card->pci_dev; - card->playback_interrupt_enabled = FALSE; - card->record_interrupt_enabled = FALSE; - - for( i = 1; i < FREQUENCIES; i++ ) - { - if( (ULONG) Frequencies[ i ] > AudioCtrl->ahiac_MixFreq ) - { - if ( ( AudioCtrl->ahiac_MixFreq - (LONG) Frequencies[ i - 1 ] ) < ( (LONG) Frequencies[ i ] - AudioCtrl->ahiac_MixFreq ) ) - { - freq = i-1; - break; - } - else - { - freq = i; - break; - } - } - } - - } - - ret = AHISF_KNOWHIFI | AHISF_KNOWSTEREO | AHISF_MIXING | AHISF_TIMING; - - - for( i = 0; i < FREQUENCIES; ++i ) - { - if( AudioCtrl->ahiac_MixFreq == Frequencies[ i ] ) - { - ret |= AHISF_CANRECORD; - break; - } - } - - return ret; -} - - - -/****************************************************************************** -** AHIsub_FreeAudio *********************************************************** -******************************************************************************/ - -void -_AHIsub_FreeAudio( struct AHIAudioCtrlDrv* AudioCtrl, - struct DriverBase* AHIsubBase ) -{ - struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; - struct CMI8738_DATA* card = (struct CMI8738_DATA*) AudioCtrl->ahiac_DriverData; - - bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); - - if( card != NULL ) - { - ObtainSemaphore( &CMI8738Base->semaphore ); - if( card->audioctrl == AudioCtrl ) - { - // Release it if we own it. - card->audioctrl = NULL; - } - ReleaseSemaphore( &CMI8738Base->semaphore ); - - AudioCtrl->ahiac_DriverData = NULL; - } -} - - -/****************************************************************************** -** AHIsub_Disable ************************************************************* -******************************************************************************/ - -void -_AHIsub_Disable( struct AHIAudioCtrlDrv* AudioCtrl, - struct DriverBase* AHIsubBase ) -{ - struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; - - bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); - - // V6 drivers do not have to preserve all registers - - Disable(); -} - - -/****************************************************************************** -** AHIsub_Enable ************************************************************** -******************************************************************************/ - -void -_AHIsub_Enable( struct AHIAudioCtrlDrv* AudioCtrl, - struct DriverBase* AHIsubBase ) -{ - struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; - - bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); - - // V6 drivers do not have to preserve all registers - - Enable(); -} - - -/****************************************************************************** -** AHIsub_Start *************************************************************** -******************************************************************************/ - -ULONG -_AHIsub_Start( ULONG flags, - struct AHIAudioCtrlDrv* AudioCtrl, - struct DriverBase* AHIsubBase ) -{ - struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; - struct CMI8738_DATA* card = (struct CMI8738_DATA*) AudioCtrl->ahiac_DriverData; - struct PCIDevice *dev = card->pci_dev; - UWORD PlayCtrlFlags = 0, RecCtrlFlags = 0; - ULONG dma_buffer_size = 0; - int i, freqbit = 6; - unsigned long phys_addr; - APTR stack; - - bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); - - /* Stop playback/recording, free old buffers (if any) */ - //IAHIsub->AHIsub_Stop( flags, AudioCtrl ); - - for( i = 0; i < FREQUENCIES; ++i ) - { - if( AudioCtrl->ahiac_MixFreq == Frequencies[ i ] ) - { - freqbit = i; - break; - } - } - - card->mixerstate = cmimix_rd(dev, card, CMPCI_SB16_MIXER_OUTMIX); - - if( flags & AHISF_PLAY ) - { - ULONG dma_sample_frame_size; - int i; - short *a; - unsigned short cod, ChannelsFlag = CMPCI_REG_FORMAT_16BIT; - - //WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET); - //ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET); - - /* Allocate a new mixing buffer. Note: The buffer must be cleared, since - it might not be filled by the mixer software interrupt because of - pretimer/posttimer! */ - - card->mix_buffer = AllocVec( AudioCtrl->ahiac_BuffSize, MEMF_PUBLIC | MEMF_CLEAR ); - - if( card->mix_buffer == NULL ) - { - Req( "Unable to allocate %ld bytes for mixing buffer.", AudioCtrl->ahiac_BuffSize ); - return AHIE_NOMEM; - } - - /* Allocate a buffer large enough for 16-bit double-buffered - playback (mono or stereo) */ - - - if( AudioCtrl->ahiac_Flags & AHIACF_STEREO ) - { - dma_sample_frame_size = 4; - dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size; - ChannelsFlag |= CMPCI_REG_FORMAT_STEREO; - } - else - { - dma_sample_frame_size = 2; - dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size; - } - - //DebugPrintF("dma_buffer_size = %ld, AudioCtrl->ahiac_BuffSize = %ld, AudioCtrl->ahiac_MaxBuffSamples = %ld\nAudioCtrl->ahiac_BuffSamples = %ld", dma_buffer_size, AudioCtrl->ahiac_BuffSize, AudioCtrl->ahiac_MaxBuffSamples, AudioCtrl->ahiac_BuffSamples); - - card->playback_buffer = pci_alloc_consistent(dma_buffer_size * 2, &card->playback_buffer_nonaligned, 128); - - if (!card->playback_buffer) - { - Req( "Unable to allocate playback buffer." ); - return AHIE_NOMEM; - } - - card->current_bytesize = dma_buffer_size; - card->current_frames = AudioCtrl->ahiac_MaxBuffSamples; - card->current_buffer = card->playback_buffer + card->current_bytesize; - card->playback_interrupt_enabled = TRUE; - - card->flip = 0; - card->oldflip = 0; - - WritePartialMask(dev, card, CMPCI_REG_FUNC_1, CMPCI_REG_DAC_FS_SHIFT, CMPCI_REG_DAC_FS_MASK, FrequencyBits[freqbit]); - WritePartialMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CMPCI_REG_CH0_FORMAT_SHIFT, CMPCI_REG_CH0_FORMAT_MASK, ChannelsFlag); - WriteMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, (13 << 1)); - -#if !defined(__AROS__) - if (IFakeDMA == NULL) - { - stack = SuperState(); - card->playback_buffer_phys = IMMU->GetPhysicalAddress(card->playback_buffer); - UserState(stack); - } - else -#endif - card->playback_buffer_phys = card->playback_buffer; - - bug("[CMI8738] %s: Playback buffer @ 0x%p\n", __PRETTY_FUNCTION__, card->playback_buffer); - - pci_outl(card->playback_buffer_phys, CMPCI_REG_DMA0_BASE, card ); - pci_outw((dma_buffer_size / dma_sample_frame_size) * 2 - 1, CMPCI_REG_DMA0_LENGTH, card); - pci_outw((dma_buffer_size / dma_sample_frame_size) - 1, CMPCI_REG_DMA0_INTLEN, card); - - card->is_playing = TRUE; - } - - if( flags & AHISF_RECORD ) - { - UWORD mask; - ULONG ChannelsFlag = CMPCI_REG_FORMAT_16BIT; - unsigned char byte; - - card->current_record_bytesize = RECORD_BUFFER_SAMPLES * 4; - - /* Allocate a new recording buffer (page aligned!) */ - card->record_buffer = pci_alloc_consistent(card->current_record_bytesize * 2, &card->record_buffer_nonaligned, 128); - - if( card->record_buffer == NULL ) - { - Req( "Unable to allocate %ld bytes for the recording buffer.", card->current_record_bytesize, 128); - return AHIE_NOMEM; - } - - SaveMixerState( card ); - UpdateMonitorMixer( card ); - - - - switch (card->input) - { - case 0: // line - cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, card->mixerstate | CMPCI_SB16_SW_LINE); - break; - - case 1: // mic - cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, card->mixerstate | CMPCI_SB16_SW_MIC); - break; - - case 2: // CD - cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, card->mixerstate | CMPCI_SB16_SW_CD); - break; - - case 3: // Aux - byte = pci_inb(CMPCI_REG_MIXER25, card); - byte |= 0x30; - pci_outb(byte, CMPCI_REG_MIXER25, card); // unmute Aux - break; - - default: - break; - } - - card->record_interrupt_enabled = TRUE; - - card->recflip = 0; - - WritePartialMask(dev, card, CMPCI_REG_FUNC_1, CMPCI_REG_ADC_FS_SHIFT, CMPCI_REG_ADC_FS_MASK, FrequencyBits[freqbit]); - WritePartialMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CMPCI_REG_CH1_FORMAT_SHIFT, CMPCI_REG_CH1_FORMAT_MASK, CMPCI_REG_FORMAT_16BIT | CMPCI_REG_FORMAT_STEREO); - -#if !defined(__AROS__) - if (IFakeDMA == NULL) - { - stack = SuperState(); - card->record_buffer_phys = IMMU->GetPhysicalAddress(card->record_buffer); - UserState(stack); - } - else -#endif - card->record_buffer_phys = card->record_buffer; - - - pci_outl(card->record_buffer_phys, CMPCI_REG_DMA1_BASE, card); - udelay(10); - pci_outw((card->current_record_bytesize / 4) * 2 - 1, CMPCI_REG_DMA1_LENGTH, card); - udelay(10); - pci_outw((card->current_record_bytesize / 4) - 1, CMPCI_REG_DMA1_INTLEN, card); - udelay(10); - card->current_record_buffer = card->record_buffer + card->current_record_bytesize; - card->is_recording = TRUE; - } - - if( flags & AHISF_PLAY ) - { - z = 0; - WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE); - WriteMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE); - } - - if( flags & AHISF_RECORD ) - { - WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE); - WriteMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); - } - - return AHIE_OK; -} - - -/****************************************************************************** -** AHIsub_Update ************************************************************** -******************************************************************************/ - -void -_AHIsub_Update( ULONG flags, - struct AHIAudioCtrlDrv* AudioCtrl, - struct DriverBase* AHIsubBase ) -{ - struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; - struct CMI8738_DATA* card = (struct CMI8738_DATA*) AudioCtrl->ahiac_DriverData; - - bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); - -#if 0 - card->current_frames = AudioCtrl->ahiac_BuffSamples; - - if( AudioCtrl->ahiac_Flags & AHIACF_STEREO ) - { - card->current_bytesize = card->current_frames * 4; - } - else - { - card->current_bytesize = card->current_frames * 2; - } -#endif -} - - -/****************************************************************************** -** AHIsub_Stop **************************************************************** -******************************************************************************/ - -void -_AHIsub_Stop( ULONG flags, - struct AHIAudioCtrlDrv* AudioCtrl, - struct DriverBase* AHIsubBase ) -{ - struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; - struct CMI8738_DATA* card = (struct CMI8738_DATA*) AudioCtrl->ahiac_DriverData; - struct PCIDevice *dev = card->pci_dev; - - bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); - - if( flags & AHISF_PLAY ) - { - unsigned short play_ctl; - - card->is_playing= FALSE; - - ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE); - ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE); - - if (card->current_bytesize > 0) - pci_free_consistent(card->playback_buffer_nonaligned); - - card->current_bytesize = 0; - card->current_frames = 0; - card->current_buffer = NULL; - - if ( card->mix_buffer) - FreeVec( card->mix_buffer ); - card->mix_buffer = NULL; - card->playback_interrupt_enabled = FALSE; - card->current_bytesize = 0; - //DebugPrintF("#IRQ's = %ld\n", z); - } - - if( flags & AHISF_RECORD && card->is_recording) - { - unsigned short rec_ctl, val; - unsigned char byte; - - ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); - ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE); - - switch (card->input) - { - case 0: // line - cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, card->mixerstate); - break; - - case 1: // mic - cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, card->mixerstate); - break; - - case 2: // CD - cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, card->mixerstate); - break; - - case 3: // Aux - byte = pci_inb(CMPCI_REG_MIXER25, card); - pci_outb(byte & ~0x30, CMPCI_REG_MIXER25, card); // mute Aux - break; - - default: - break; - } - - if( card->record_buffer != NULL ) - { - pci_free_consistent( card->record_buffer_nonaligned); - } - - card->record_buffer = NULL; - card->current_record_bytesize = 0; - - card->is_recording = FALSE; - card->record_interrupt_enabled = FALSE; - } - - -} - - -/****************************************************************************** -** AHIsub_GetAttr ************************************************************* -******************************************************************************/ - -LONG -_AHIsub_GetAttr( ULONG attribute, - LONG argument, - LONG def, - struct TagItem* taglist, - struct AHIAudioCtrlDrv* AudioCtrl, - struct DriverBase* AHIsubBase ) -{ - struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; - int i; - - bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); - - switch( attribute ) - { - case AHIDB_Bits: - return 16; - - case AHIDB_Frequencies: - return FREQUENCIES; - - case AHIDB_Frequency: // Index->Frequency - return (LONG) Frequencies[ argument ]; - - case AHIDB_Index: // Frequency->Index - if( argument <= (LONG) Frequencies[ 0 ] ) - { - return 0; - } - - if( argument >= (LONG) Frequencies[ FREQUENCIES - 1 ] ) - { - return FREQUENCIES-1; - } - - for( i = 1; i < FREQUENCIES; i++ ) - { - if( (LONG) Frequencies[ i ] > argument ) - { - if( ( argument - (LONG) Frequencies[ i - 1 ] ) < ( (LONG) Frequencies[ i ] - argument ) ) - { - return i-1; - } - else - { - return i; - } - } - } - - return 0; // Will not happen - - case AHIDB_Author: - return (LONG) "Davy Wentzler"; - - case AHIDB_Copyright: - return (LONG) "(C) 2011 The AROS Dev Team"; - - case AHIDB_Version: - return (LONG) LibIDString; - - case AHIDB_Annotation: - return (LONG) - "AROS CMI8738 Audio driver"; - - case AHIDB_Record: - return TRUE; - - case AHIDB_FullDuplex: - return TRUE; - - case AHIDB_Realtime: - return TRUE; - - case AHIDB_MaxRecordSamples: - return RECORD_BUFFER_SAMPLES; - - /* formula's: - #include - - unsigned long res = (unsigned long) (0x10000 * pow (10.0, dB / 20.0)); - double dB = 20.0 * log10(0xVALUE / 65536.0); - - printf("dB = %f, res = %lx\n", dB, res);*/ - - case AHIDB_MinMonitorVolume: - return 0x00000; - - case AHIDB_MaxMonitorVolume: - return 0x00000; - - case AHIDB_MinInputGain: - return 0x10000; // 0.0 dB gain - - case AHIDB_MaxInputGain: - return 0x10000; // 0 dB gain - - case AHIDB_MinOutputVolume: - return 0x34; // -62 dB - - case AHIDB_MaxOutputVolume: - return 0x10000; // 0 dB - - case AHIDB_Inputs: - return INPUTS; - - case AHIDB_Input: - return (LONG) Inputs[ argument ]; - - case AHIDB_Outputs: - return OUTPUTS; - - case AHIDB_Output: - return (LONG) Outputs[ argument ]; - - default: - return def; - } -} - - -/****************************************************************************** -** AHIsub_HardwareControl ***************************************************** -******************************************************************************/ - -ULONG -_AHIsub_HardwareControl( ULONG attribute, - LONG argument, - struct AHIAudioCtrlDrv* AudioCtrl, - struct DriverBase* AHIsubBase ) -{ - struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; - struct CMI8738_DATA* card = (struct CMI8738_DATA*) AudioCtrl->ahiac_DriverData; - struct PCIDevice *dev = card->pci_dev; - unsigned char byte; - - bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); - - switch( attribute ) - { - case AHIC_MonitorVolume: - card->monitor_volume = Linear2MixerGain( (Fixed) argument, &card->monitor_volume_bits ); - //DebugPrintF("card->monitor_volume = %lu, %lx\n", card->monitor_volume, card->monitor_volume); - if( card->is_recording ) - { - UpdateMonitorMixer( card ); - } - return TRUE; - - case AHIC_MonitorVolume_Query: - return card->monitor_volume; - - case AHIC_InputGain: - card->input_gain = Linear2RecordGain( (Fixed) argument, &card->input_gain_bits ); - //codec_write(card, AC97_RECORD_GAIN, card->input_gain_bits ); - return TRUE; - - case AHIC_InputGain_Query: - return card->input_gain; - - case AHIC_OutputVolume: - { - double dB = 20.0 * log10((Fixed) argument / 65536.0); - unsigned int val = 0xFF - ( ((unsigned int)(-dB/2)) << 3); - cmimix_wr(dev, card, 0x30, val); - cmimix_wr(dev, card, 0x31, val); - return TRUE; - } - case AHIC_OutputVolume_Query: - return card->output_volume; - - case AHIC_Input: - card->input = argument; - - switch (card->input) - { - case 0: // line - cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_L, (CMPCI_SB16_MIXER_LINE_SRC_R << 1) ); - cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_R, CMPCI_SB16_MIXER_LINE_SRC_R ); - break; - - case 1: // mic - cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_L, CMPCI_SB16_MIXER_MIC_SRC); - cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_R, CMPCI_SB16_MIXER_MIC_SRC); - break; - - case 2: // CD - cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_L, (CMPCI_SB16_MIXER_CD_SRC_R << 1) ); - cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_R, CMPCI_SB16_MIXER_CD_SRC_R ); - break; - - case 3: // Aux - byte = pci_inb(CMPCI_REG_MIXER25, card); - pci_outb(byte | 0xC0, CMPCI_REG_MIXER25, card); // rec source Aux - break; - - case 4: // SPDIF - - break; - - default: - break; - } - - if( card->is_recording ) - { - UpdateMonitorMixer( card ); - } - - return TRUE; - - case AHIC_Input_Query: - return card->input; - - case AHIC_Output: - card->output = argument; - - if( card->output == 0 ) - { - ClearMask(dev, card, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIFOUT_DAC | CMPCI_REG_SPDIF0_ENABLE); - ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_XSPDIF_ENABLE); - } - else - { - WriteMask(dev, card, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIFOUT_DAC | CMPCI_REG_SPDIF0_ENABLE); - WriteMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_XSPDIF_ENABLE); - } - return TRUE; - - case AHIC_Output_Query: - return card->output; - - default: - return FALSE; - } -} +/* +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 written by Davy Wentzler. +*/ + +//#include + +#if !defined(__AROS__) +#undef __USE_INLINE__ +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef __AROS__ +#define DEBUG 1 +#include +#define DebugPrintF bug +#endif +#include +#include + +#include "library.h" +#include "regs.h" +#include "misc.h" +#include "pci_wrapper.h" + +extern int z; + +/****************************************************************************** +** Globals ******************************************************************** +******************************************************************************/ + +#define FREQUENCIES 8 + +static const ULONG Frequencies[ FREQUENCIES ] = +{ + 5512, + 8000, // µ- and A-Law + 11025, // CD/4 + 16000, // DAT/3 + 22050, // CD/2 + 32000, // DAT/1.5 + 44100, // CD + 48000 // DAT +}; + +static const ULONG FrequencyBits[ FREQUENCIES ] = +{ + 0, + 4, + 1, + 5, + 2, + 6, + 3, + 7 +}; + +#define INPUTS 5 + +static const STRPTR Inputs[ INPUTS ] = +{ + "Line in", + "Mic", + "CD", + "Aux", + "S/PDIF" +}; + +#if 0 +/* Not static since it's used in misc.c too */ +const UWORD InputBits[ INPUTS ] = +{ + AC97_RECMUX_LINE, + AC97_RECMUX_MIC, + AC97_RECMUX_CD, + AC97_RECMUX_VIDEO, + AC97_RECMUX_AUX, + AC97_RECMUX_STEREO_MIX, + AC97_RECMUX_MONO_MIX, + AC97_RECMUX_PHONE +}; +#endif + +#define OUTPUTS 2 + +static const STRPTR Outputs[ OUTPUTS ] = +{ + "Line Out", + "Digital Out" +}; + +/****************************************************************************** +** AHIsub_AllocAudio ********************************************************** +******************************************************************************/ + +ULONG +_AHIsub_AllocAudio( struct TagItem* taglist, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; + + int card_num; + ULONG ret; + int i, freq = 6; + + bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); + + card_num = ( GetTagData( AHIDB_AudioID, 0, taglist) & 0x0000f000 ) >> 12; + + if( card_num >= CMI8738Base->cards_found || + CMI8738Base->driverdatas[ card_num ] == NULL ) + { + DebugPrintF("no date for card = %ld\n", card_num); + Req( "No CMI8738_DATA for card %ld.", card_num ); + return AHISF_ERROR; + } + else + { + struct CMI8738_DATA* card; + BOOL in_use; + struct PCIDevice *dev; + + card = CMI8738Base->driverdatas[ card_num ]; + AudioCtrl->ahiac_DriverData = card; + + ObtainSemaphore( &CMI8738Base->semaphore ); + in_use = ( card->audioctrl != NULL ); + if( !in_use ) + { + card->audioctrl = AudioCtrl; + } + ReleaseSemaphore( &CMI8738Base->semaphore ); + + if( in_use ) + { + return AHISF_ERROR; + } + + dev = card->pci_dev; + card->playback_interrupt_enabled = FALSE; + card->record_interrupt_enabled = FALSE; + + for( i = 1; i < FREQUENCIES; i++ ) + { + if( (ULONG) Frequencies[ i ] > AudioCtrl->ahiac_MixFreq ) + { + if ( ( AudioCtrl->ahiac_MixFreq - (LONG) Frequencies[ i - 1 ] ) < ( (LONG) Frequencies[ i ] - AudioCtrl->ahiac_MixFreq ) ) + { + freq = i-1; + break; + } + else + { + freq = i; + break; + } + } + } + } + + ret = AHISF_KNOWHIFI | AHISF_KNOWSTEREO | AHISF_MIXING | AHISF_TIMING; + + for( i = 0; i < FREQUENCIES; ++i ) + { + if( AudioCtrl->ahiac_MixFreq == Frequencies[ i ] ) + { + ret |= AHISF_CANRECORD; + break; + } + } + + return ret; +} + + + +/****************************************************************************** +** AHIsub_FreeAudio *********************************************************** +******************************************************************************/ + +void +_AHIsub_FreeAudio( struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; + struct CMI8738_DATA* card = (struct CMI8738_DATA*) AudioCtrl->ahiac_DriverData; + + bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); + + if( card != NULL ) + { + ObtainSemaphore( &CMI8738Base->semaphore ); + if( card->audioctrl == AudioCtrl ) + { + // Release it if we own it. + card->audioctrl = NULL; + } + ReleaseSemaphore( &CMI8738Base->semaphore ); + + AudioCtrl->ahiac_DriverData = NULL; + } +} + + +/****************************************************************************** +** AHIsub_Disable ************************************************************* +******************************************************************************/ + +void +_AHIsub_Disable( struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; + + bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); + + // V6 drivers do not have to preserve all registers + + Disable(); +} + + +/****************************************************************************** +** AHIsub_Enable ************************************************************** +******************************************************************************/ + +void +_AHIsub_Enable( struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; + + bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); + + // V6 drivers do not have to preserve all registers + + Enable(); +} + + +/****************************************************************************** +** AHIsub_Start *************************************************************** +******************************************************************************/ + +ULONG +_AHIsub_Start( ULONG flags, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; + struct CMI8738_DATA* card = (struct CMI8738_DATA*) AudioCtrl->ahiac_DriverData; + struct PCIDevice *dev = card->pci_dev; + UWORD PlayCtrlFlags = 0, RecCtrlFlags = 0; + ULONG dma_buffer_size = 0; + int i, freqbit = 6; + unsigned long phys_addr; + APTR stack; + + bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); + + /* Stop playback/recording, free old buffers (if any) */ + //IAHIsub->AHIsub_Stop( flags, AudioCtrl ); + + for( i = 0; i < FREQUENCIES; ++i ) + { + if( AudioCtrl->ahiac_MixFreq == Frequencies[ i ] ) + { + freqbit = i; + break; + } + } + + card->mixerstate = cmimix_rd(dev, card, CMPCI_SB16_MIXER_OUTMIX); + + if( flags & AHISF_PLAY ) + { + ULONG dma_sample_frame_size; + int i; + short *a; + unsigned short cod, ChannelsFlag = CMPCI_REG_FORMAT_16BIT; + + //WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET); + //ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET); + + /* Allocate a new mixing buffer. Note: The buffer must be cleared, since + it might not be filled by the mixer software interrupt because of + pretimer/posttimer! */ + + card->mix_buffer = AllocVec( AudioCtrl->ahiac_BuffSize, MEMF_PUBLIC | MEMF_CLEAR ); + + if( card->mix_buffer == NULL ) + { + Req( "Unable to allocate %ld bytes for mixing buffer.", AudioCtrl->ahiac_BuffSize ); + return AHIE_NOMEM; + } + + /* Allocate a buffer large enough for 16-bit double-buffered + playback (mono or stereo) */ + + if( AudioCtrl->ahiac_Flags & AHIACF_STEREO ) + { + dma_sample_frame_size = 4; + dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size; + ChannelsFlag |= CMPCI_REG_FORMAT_STEREO; + } + else + { + dma_sample_frame_size = 2; + dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size; + } + + //DebugPrintF("dma_buffer_size = %ld, AudioCtrl->ahiac_BuffSize = %ld, AudioCtrl->ahiac_MaxBuffSamples = %ld\nAudioCtrl->ahiac_BuffSamples = %ld", dma_buffer_size, AudioCtrl->ahiac_BuffSize, AudioCtrl->ahiac_MaxBuffSamples, AudioCtrl->ahiac_BuffSamples); + + card->playback_buffer = pci_alloc_consistent(dma_buffer_size * 2, &card->playback_buffer_nonaligned, 128); + + if (!card->playback_buffer) + { + Req( "Unable to allocate playback buffer." ); + return AHIE_NOMEM; + } + + card->current_bytesize = dma_buffer_size; + card->current_frames = AudioCtrl->ahiac_MaxBuffSamples; + card->current_buffer = card->playback_buffer + card->current_bytesize; + card->playback_interrupt_enabled = TRUE; + + card->flip = 0; + card->oldflip = 0; + + WritePartialMask(dev, card, CMPCI_REG_FUNC_1, CMPCI_REG_DAC_FS_SHIFT, CMPCI_REG_DAC_FS_MASK, FrequencyBits[freqbit]); + WritePartialMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CMPCI_REG_CH0_FORMAT_SHIFT, CMPCI_REG_CH0_FORMAT_MASK, ChannelsFlag); + WriteMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, (13 << 1)); + +#if !defined(__AROS__) + if (IFakeDMA == NULL) + { + stack = SuperState(); + card->playback_buffer_phys = IMMU->GetPhysicalAddress(card->playback_buffer); + UserState(stack); + } + else +#endif + card->playback_buffer_phys = card->playback_buffer; + + bug("[CMI8738] %s: Playback buffer @ 0x%p\n", __PRETTY_FUNCTION__, card->playback_buffer); + + pci_outl(card->playback_buffer_phys, CMPCI_REG_DMA0_BASE, card); + pci_outw((dma_buffer_size / dma_sample_frame_size) * 2 - 1, CMPCI_REG_DMA0_LENGTH, card); + pci_outw((dma_buffer_size / dma_sample_frame_size) - 1, CMPCI_REG_DMA0_INTLEN, card); + + card->is_playing = TRUE; + } + + if( flags & AHISF_RECORD ) + { + UWORD mask; + ULONG ChannelsFlag = CMPCI_REG_FORMAT_16BIT; + unsigned char byte; + + card->current_record_bytesize = RECORD_BUFFER_SAMPLES * 4; + + /* Allocate a new recording buffer (page aligned!) */ + card->record_buffer = pci_alloc_consistent(card->current_record_bytesize * 2, &card->record_buffer_nonaligned, 128); + + if( card->record_buffer == NULL ) + { + Req( "Unable to allocate %ld bytes for the recording buffer.", card->current_record_bytesize, 128); + return AHIE_NOMEM; + } + + SaveMixerState( card ); + UpdateMonitorMixer( card ); + + switch (card->input) + { + case 0: // line + cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, card->mixerstate | CMPCI_SB16_SW_LINE); + break; + + case 1: // mic + cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, card->mixerstate | CMPCI_SB16_SW_MIC); + break; + + case 2: // CD + cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, card->mixerstate | CMPCI_SB16_SW_CD); + break; + + case 3: // Aux + byte = pci_inb(CMPCI_REG_MIXER25, card); + byte |= 0x30; + pci_outb(byte, CMPCI_REG_MIXER25, card); // unmute Aux + break; + + default: + break; + } + + card->record_interrupt_enabled = TRUE; + + card->recflip = 0; + + WritePartialMask(dev, card, CMPCI_REG_FUNC_1, CMPCI_REG_ADC_FS_SHIFT, CMPCI_REG_ADC_FS_MASK, FrequencyBits[freqbit]); + WritePartialMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CMPCI_REG_CH1_FORMAT_SHIFT, CMPCI_REG_CH1_FORMAT_MASK, CMPCI_REG_FORMAT_16BIT | CMPCI_REG_FORMAT_STEREO); + +#if !defined(__AROS__) + if (IFakeDMA == NULL) + { + stack = SuperState(); + card->record_buffer_phys = IMMU->GetPhysicalAddress(card->record_buffer); + UserState(stack); + } + else +#endif + card->record_buffer_phys = card->record_buffer; + + pci_outl(card->record_buffer_phys, CMPCI_REG_DMA1_BASE, card); + udelay(1); + pci_outw((card->current_record_bytesize / 4) * 2 - 1, CMPCI_REG_DMA1_LENGTH, card); + udelay(1); + pci_outw((card->current_record_bytesize / 4) - 1, CMPCI_REG_DMA1_INTLEN, card); + udelay(1); + card->current_record_buffer = card->record_buffer + card->current_record_bytesize; + card->is_recording = TRUE; + } + + if( flags & AHISF_PLAY ) + { + z = 0; + WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE); + WriteMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE); + } + + if( flags & AHISF_RECORD ) + { + WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE); + WriteMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); + } + + return AHIE_OK; +} + + +/****************************************************************************** +** AHIsub_Update ************************************************************** +******************************************************************************/ + +void +_AHIsub_Update( ULONG flags, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; + struct CMI8738_DATA* card = (struct CMI8738_DATA*) AudioCtrl->ahiac_DriverData; + + bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); + +#if 0 + card->current_frames = AudioCtrl->ahiac_BuffSamples; + + if( AudioCtrl->ahiac_Flags & AHIACF_STEREO ) + { + card->current_bytesize = card->current_frames * 4; + } + else + { + card->current_bytesize = card->current_frames * 2; + } +#endif +} + + +/****************************************************************************** +** AHIsub_Stop **************************************************************** +******************************************************************************/ + +void +_AHIsub_Stop( ULONG flags, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; + struct CMI8738_DATA* card = (struct CMI8738_DATA*) AudioCtrl->ahiac_DriverData; + struct PCIDevice *dev = card->pci_dev; + + bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); + + if( flags & AHISF_PLAY ) + { + unsigned short play_ctl; + + card->is_playing= FALSE; + + ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE); + ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE); + + if (card->current_bytesize > 0) + pci_free_consistent(card->playback_buffer_nonaligned); + + card->current_bytesize = 0; + card->current_frames = 0; + card->current_buffer = NULL; + + if ( card->mix_buffer) + FreeVec( card->mix_buffer ); + + card->mix_buffer = NULL; + card->playback_interrupt_enabled = FALSE; + card->current_bytesize = 0; + //DebugPrintF("#IRQ's = %ld\n", z); + } + + if( flags & AHISF_RECORD && card->is_recording) + { + unsigned short rec_ctl, val; + unsigned char byte; + + ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); + ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE); + + switch (card->input) + { + case 0: // line + cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, card->mixerstate); + break; + + case 1: // mic + cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, card->mixerstate); + break; + + case 2: // CD + cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, card->mixerstate); + break; + + case 3: // Aux + byte = pci_inb(CMPCI_REG_MIXER25, card); + pci_outb(byte & ~0x30, CMPCI_REG_MIXER25, card); // mute Aux + break; + + default: + break; + } + + if( card->record_buffer != NULL ) + { + pci_free_consistent( card->record_buffer_nonaligned); + } + + card->record_buffer = NULL; + card->current_record_bytesize = 0; + + card->is_recording = FALSE; + card->record_interrupt_enabled = FALSE; + } +} + + +/****************************************************************************** +** AHIsub_GetAttr ************************************************************* +******************************************************************************/ + +LONG +_AHIsub_GetAttr( ULONG attribute, + LONG argument, + LONG def, + struct TagItem* taglist, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; + int i; + + bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); + + struct CMI8738_DATA* card = (struct CMI8738_DATA*) AudioCtrl->ahiac_DriverData; + if (card == NULL) + { + int card_num = ( GetTagData( AHIDB_AudioID, 0, taglist) & 0x0000f000 ) >> 12; + + if( card_num <= CMI8738Base->cards_found || + CMI8738Base->driverdatas[ card_num ] != NULL ) + card = CMI8738Base->driverdatas[ card_num ]; + } + bug("[CMI8738] %s: card data @ 0x%p\n", __PRETTY_FUNCTION__, card); + + switch( attribute ) + { + case AHIDB_Bits: + return 16; + + case AHIDB_MaxChannels: + if (card) + return card->channels; + return 2; + + case AHIDB_Frequencies: + return FREQUENCIES; + + case AHIDB_Frequency: // Index->Frequency + return (LONG) Frequencies[ argument ]; + + case AHIDB_Index: // Frequency->Index + if( argument <= (LONG) Frequencies[ 0 ] ) + { + return 0; + } + + if( argument >= (LONG) Frequencies[ FREQUENCIES - 1 ] ) + { + return FREQUENCIES-1; + } + + for( i = 1; i < FREQUENCIES; i++ ) + { + if( (LONG) Frequencies[ i ] > argument ) + { + if( ( argument - (LONG) Frequencies[ i - 1 ] ) < ( (LONG) Frequencies[ i ] - argument ) ) + { + return i-1; + } + else + { + return i; + } + } + } + + return 0; // Will not happen + + case AHIDB_Author: + return (LONG) "Davy Wentzler"; + + case AHIDB_Copyright: + return (LONG) "(C) 2011 The AROS Dev Team"; + + case AHIDB_Version: + return (LONG) LibIDString; + + case AHIDB_Annotation: + return (LONG) "AROS CMI8738 Audio driver"; + + case AHIDB_Record: + return TRUE; + + case AHIDB_FullDuplex: + return TRUE; + + case AHIDB_Realtime: + return TRUE; + + case AHIDB_MaxRecordSamples: + return RECORD_BUFFER_SAMPLES; + + /* formula's: + #include + + unsigned long res = (unsigned long) (0x10000 * pow (10.0, dB / 20.0)); + double dB = 20.0 * log10(0xVALUE / 65536.0); + + printf("dB = %f, res = %lx\n", dB, res);*/ + + case AHIDB_MinMonitorVolume: + return 0x00000; + + case AHIDB_MaxMonitorVolume: + return 0x00000; + + case AHIDB_MinInputGain: + return 0x10000; // 0.0 dB gain + + case AHIDB_MaxInputGain: + return 0x10000; // 0 dB gain + + case AHIDB_MinOutputVolume: + return 0x34; // -62 dB + + case AHIDB_MaxOutputVolume: + return 0x10000; // 0 dB + + case AHIDB_Inputs: + return INPUTS; + + case AHIDB_Input: + return (LONG) Inputs[ argument ]; + + case AHIDB_Outputs: + return OUTPUTS; + + case AHIDB_Output: + return (LONG) Outputs[ argument ]; + + default: + return def; + } +} + + +/****************************************************************************** +** AHIsub_HardwareControl ***************************************************** +******************************************************************************/ + +ULONG +_AHIsub_HardwareControl( ULONG attribute, + LONG argument, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; + struct CMI8738_DATA* card = (struct CMI8738_DATA*) AudioCtrl->ahiac_DriverData; + struct PCIDevice *dev = card->pci_dev; + unsigned char byte; + + bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); + + switch( attribute ) + { + case AHIC_MonitorVolume: + card->monitor_volume = Linear2MixerGain( (Fixed) argument, &card->monitor_volume_bits ); + //DebugPrintF("card->monitor_volume = %lu, %lx\n", card->monitor_volume, card->monitor_volume); + if( card->is_recording ) + { + UpdateMonitorMixer( card ); + } + return TRUE; + + case AHIC_MonitorVolume_Query: + return card->monitor_volume; + + case AHIC_InputGain: + card->input_gain = Linear2RecordGain( (Fixed) argument, &card->input_gain_bits ); + //codec_write(card, AC97_RECORD_GAIN, card->input_gain_bits ); + return TRUE; + + case AHIC_InputGain_Query: + return card->input_gain; + + case AHIC_OutputVolume: + { + double dB = 20.0 * log10((Fixed) argument / 65536.0); + unsigned int val = 0xFF - ( ((unsigned int)(-dB/2)) << 3); + cmimix_wr(dev, card, 0x30, val); + cmimix_wr(dev, card, 0x31, val); + return TRUE; + } + case AHIC_OutputVolume_Query: + return card->output_volume; + + case AHIC_Input: + card->input = argument; + + switch (card->input) + { + case 0: // line + cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_L, (CMPCI_SB16_MIXER_LINE_SRC_R << 1) ); + cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_R, CMPCI_SB16_MIXER_LINE_SRC_R ); + break; + + case 1: // mic + cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_L, CMPCI_SB16_MIXER_MIC_SRC); + cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_R, CMPCI_SB16_MIXER_MIC_SRC); + break; + + case 2: // CD + cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_L, (CMPCI_SB16_MIXER_CD_SRC_R << 1) ); + cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_R, CMPCI_SB16_MIXER_CD_SRC_R ); + break; + + case 3: // Aux + byte = pci_inb(CMPCI_REG_MIXER25, card); + pci_outb(byte | 0xC0, CMPCI_REG_MIXER25, card); // rec source Aux + break; + + case 4: // SPDIF + + break; + + default: + break; + } + + if( card->is_recording ) + { + UpdateMonitorMixer( card ); + } + + return TRUE; + + case AHIC_Input_Query: + return card->input; + + case AHIC_Output: + card->output = argument; + + if( card->output == 0 ) + { + ClearMask(dev, card, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIFOUT_DAC | CMPCI_REG_SPDIF0_ENABLE); + ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_XSPDIF_ENABLE); + } + else + { + WriteMask(dev, card, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIFOUT_DAC | CMPCI_REG_SPDIF0_ENABLE); + WriteMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_XSPDIF_ENABLE); + } + return TRUE; + + case AHIC_Output_Query: + return card->output; + + default: + return FALSE; + } +} diff --git a/workbench/devs/AHI/Drivers/CMI8738/driver-init.c b/workbench/devs/AHI/Drivers/CMI8738/driver-init.c index 93e11a68a6..992ca35a9c 100755 --- a/workbench/devs/AHI/Drivers/CMI8738/driver-init.c +++ b/workbench/devs/AHI/Drivers/CMI8738/driver-init.c @@ -9,7 +9,11 @@ limitations under the License. The Original Code is written by Davy Wentzler. */ -//#include +#ifdef __AROS__ +#define DEBUG 1 +#include +#define DebugPrintF bug +#endif #include @@ -21,12 +25,6 @@ The Original Code is written by Davy Wentzler. #include #include -#ifdef __AROS__ -#define DEBUG 1 -#include -#define DebugPrintF bug -#endif - #include "library.h" #include "version.h" #include "misc.h" @@ -60,125 +58,137 @@ static int vendor_device_list_size = 0; BOOL DriverInit( struct DriverBase* ahisubbase ) { - struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) ahisubbase; - struct PCIDevice *dev; - int card_no, i; + struct CMI8738Base *CMI8738Base = (struct CMI8738Base*) ahisubbase; + struct PCIDevice *dev; + int card_no, i; + struct List foundCards; + struct Node *devTmp; bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); - CMI8738Base->driverdatas = 0; - CMI8738Base->cards_found = 0; - AHIsubBase = ahisubbase; + CMI8738Base->driverdatas = 0; + CMI8738Base->cards_found = 0; + AHIsubBase = ahisubbase; - DOSBase = OpenLibrary( DOSNAME, 37 ); + NewList(&foundCards); - if( DOSBase == NULL ) - { - Req( "Unable to open 'dos.library' version 37.\n" ); - return FALSE; - } + DOSBase = OpenLibrary( DOSNAME, 37 ); - ExpansionBase = OpenLibrary( "expansion.library", 1 ); - if( ExpansionBase == NULL ) - { - Req( "Unable to open 'expansion.library' version 1.\n" ); - return FALSE; - } + if( DOSBase == NULL ) + { + Req( "CMI8738: Unable to open 'dos.library' version 37.\n" ); + return FALSE; + } - if (!ahi_pci_init(ahisubbase)) - { - return FALSE; - } + ExpansionBase = OpenLibrary( "expansion.library", 1 ); + if( ExpansionBase == NULL ) + { + Req( "CMI8738: Unable to open 'expansion.library' version 1.\n" ); + return FALSE; + } - InitSemaphore( &CMI8738Base->semaphore ); + if (!ahi_pci_init(ahisubbase)) + { + return FALSE; + } - /*** Count cards ***********************************************************/ + InitSemaphore( &CMI8738Base->semaphore ); - vendor_device_list = (struct VendorDevice *) AllocVec(sizeof(struct VendorDevice) * MAX_DEVICE_VENDORS, MEMF_PUBLIC | MEMF_CLEAR); + /*** Count cards ***********************************************************/ - vendor_device_list[0].vendor = VENDOR_ID; - vendor_device_list[0].device = DEVICE_ID; - vendor_device_list_size++; + vendor_device_list = (struct VendorDevice *) AllocVec(sizeof(struct VendorDevice) * MAX_DEVICE_VENDORS, MEMF_PUBLIC | MEMF_CLEAR); - bug("vendor_device_list_size = %ld\n", vendor_device_list_size); + vendor_device_list[0].vendor = VENDOR_ID; + vendor_device_list[0].device = DEVICE_ID; + vendor_device_list_size++; - CMI8738Base->cards_found = 0; - dev = NULL; + bug("vendor_device_list_size = %ld\n", vendor_device_list_size); - for (i = 0; i < vendor_device_list_size; i++) - { - dev = ahi_pci_find_device(vendor_device_list[i].vendor, vendor_device_list[i].device, dev); - - if (dev != NULL) + CMI8738Base->cards_found = 0; + dev = NULL; + + for (i = 0; i < vendor_device_list_size; i++) { - bug("Found CMI8738 #%d [%4x:%4x]\n", i, vendor_device_list[i].vendor, vendor_device_list[i].device); - ++CMI8738Base->cards_found; - break; // stop at first found controller + dev = ahi_pci_find_device(vendor_device_list[i].vendor, vendor_device_list[i].device, dev); + + if (dev != NULL) + { + bug("[CMI8738] %s: Found CMI8738 #%d [%4x:%4x] pci obj @ 0x%p\n", __PRETTY_FUNCTION__, i, vendor_device_list[i].vendor, vendor_device_list[i].device, dev); + ++CMI8738Base->cards_found; + + devTmp = AllocVec(sizeof(struct Node), MEMF_CLEAR); + devTmp->ln_Name = dev; + AddTail(&foundCards, devTmp); + } } - } - // Fail if no hardware is present (prevents the audio modes from being added to - // the database if the driver cannot be used). + // Fail if no hardware is present (prevents the audio modes from being added to + // the database if the driver cannot be used). - if(CMI8738Base->cards_found == 0 ) - { - DebugPrintF("No CMI8738 found! :-(\n"); - Req( "No card present.\n" ); - return FALSE; - } + if(CMI8738Base->cards_found == 0 ) + { + DebugPrintF("No CMI8738 found! :-(\n"); +#if defined(VERBOSE_REQ) + Req( "No card present.\n" ); +#endif + return FALSE; + } - /*** CAMD ******************************************************************/ + /*** CAMD ******************************************************************/ #if 0 - InitSemaphore( &CMI8738Base->camd.Semaphore ); - CMI8738Base->camd.Semaphore.ss_Link.ln_Pri = 0; + InitSemaphore( &CMI8738Base->camd.Semaphore ); + CMI8738Base->camd.Semaphore.ss_Link.ln_Pri = 0; - CMI8738Base->camd.Semaphore.ss_Link.ln_Name = Card_CAMD_SEMAPHORE; - AddSemaphore( &CMI8738Base->camd.Semaphore ); + CMI8738Base->camd.Semaphore.ss_Link.ln_Name = Card_CAMD_SEMAPHORE; + AddSemaphore( &CMI8738Base->camd.Semaphore ); - CMI8738Base->camd.Cards = CMI8738Base->cards_found; - CMI8738Base->camd.Version = VERSION; - CMI8738Base->camd.Revision = REVISION; + CMI8738Base->camd.Cards = CMI8738Base->cards_found; + CMI8738Base->camd.Version = VERSION; + CMI8738Base->camd.Revision = REVISION; + CMI8738Base->camd.OpenPortFunc.h_Entry = OpenCAMDPort; + CMI8738Base->camd.OpenPortFunc.h_SubEntry = NULL; + CMI8738Base->camd.OpenPortFunc.h_Data = NULL; - CMI8738Base->camd.OpenPortFunc.h_Entry = OpenCAMDPort; - CMI8738Base->camd.OpenPortFunc.h_SubEntry = NULL; - CMI8738Base->camd.OpenPortFunc.h_Data = NULL; + CMI8738Base->camd.ClosePortFunc.h_Entry = (HOOKFUNC) CloseCAMDPort; + CMI8738Base->camd.ClosePortFunc.h_SubEntry = NULL; + CMI8738Base->camd.ClosePortFunc.h_Data = NULL; - CMI8738Base->camd.ClosePortFunc.h_Entry = (HOOKFUNC) CloseCAMDPort; - CMI8738Base->camd.ClosePortFunc.h_SubEntry = NULL; - CMI8738Base->camd.ClosePortFunc.h_Data = NULL; - - CMI8738Base->camd.ActivateXmitFunc.h_Entry = (HOOKFUNC) ActivateCAMDXmit; - CMI8738Base->camd.ActivateXmitFunc.h_SubEntry = NULL; - CMI8738Base->camd.ActivateXmitFunc.h_Data = NULL; + CMI8738Base->camd.ActivateXmitFunc.h_Entry = (HOOKFUNC) ActivateCAMDXmit; + CMI8738Base->camd.ActivateXmitFunc.h_SubEntry = NULL; + CMI8738Base->camd.ActivateXmitFunc.h_Data = NULL; #endif - /*** Allocate and init all cards *******************************************/ + /*** Allocate and init all cards *******************************************/ - CMI8738Base->driverdatas = AllocVec( sizeof( *CMI8738Base->driverdatas ) * - CMI8738Base->cards_found, - MEMF_PUBLIC ); + CMI8738Base->driverdatas = AllocVec( sizeof( *CMI8738Base->driverdatas ) * + CMI8738Base->cards_found, + MEMF_PUBLIC | MEMF_CLEAR); - if( CMI8738Base->driverdatas == NULL ) - { - Req( "Out of memory." ); - return FALSE; - } + if( CMI8738Base->driverdatas == NULL ) + { + Req( "Out of memory." ); + return FALSE; + } - card_no = 0; + card_no = 0; - if(dev) - { - CMI8738Base->driverdatas[ card_no ] = AllocDriverData( dev, AHIsubBase ); - if (CMI8738Base->driverdatas[card_no] == NULL) + struct Node *scratchNode; + ForeachNodeSafe(&foundCards, devTmp, scratchNode) { - return FALSE; + Remove(devTmp); + + dev = devTmp->ln_Name; + bug("[CMI8738] %s: Prepairing card #%d pci obj @ 0x%p\n", __PRETTY_FUNCTION__, card_no, dev); + CMI8738Base->driverdatas[ card_no ] = AllocDriverData( dev, AHIsubBase ); + + FreeVec(devTmp); + ++card_no; } - ++card_no; - } bug("[CMI8738] %s: Done.\n", __PRETTY_FUNCTION__); - return TRUE; + + return TRUE; } diff --git a/workbench/devs/AHI/Drivers/CMI8738/interrupt.c b/workbench/devs/AHI/Drivers/CMI8738/interrupt.c index 5b3ce1552e..fa7a6d44bb 100755 --- a/workbench/devs/AHI/Drivers/CMI8738/interrupt.c +++ b/workbench/devs/AHI/Drivers/CMI8738/interrupt.c @@ -52,12 +52,21 @@ CardInterrupt( struct CMI8738_DATA* card ) ULONG intreq; LONG handled = 0; - bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); + bug("[CMI8738]: %s(card @ 0x%p)\n", __PRETTY_FUNCTION__, card); + bug("[CMI8738] %s: AHIAudioCtrlDrv @ 0x%p\n", __PRETTY_FUNCTION__, AudioCtrl); - while ( (( intreq = ( pci_inl(CMPCI_REG_INTR_STATUS, card) ) ) & CMPCI_REG_ANY_INTR )!= 0 ) + for (;;) +// while (((intreq = pci_inl(CMPCI_REG_INTR_STATUS, card)) & CMPCI_REG_ANY_INTR) != 0) { + intreq = pci_inl(CMPCI_REG_INTR_STATUS, card); + + bug("[CMI8738] %s: INTR_STATUS = %08x\n", __PRETTY_FUNCTION__, intreq); + + if (((intreq & CMPCI_REG_ANY_INTR) == 0) || (AudioCtrl == NULL)) + break; + //DebugPrintF("INT %lx\n", intreq); - if( intreq & CMPCI_REG_CH0_INTR && AudioCtrl != NULL ) + if( intreq & CMPCI_REG_CH0_INTR) { unsigned long diff = pci_inl(CMPCI_REG_DMA0_BASE, card) - (unsigned long) card->playback_buffer_phys; @@ -80,7 +89,9 @@ CardInterrupt( struct CMI8738_DATA* card ) if (diff >= card->current_bytesize) //card->flip == 0) // just played buf 1 { if (card->flip == 1) + { DebugPrintF("A:Missed IRQ! diff = %lu\n", diff); + } card->flip = 1; card->current_buffer = card->playback_buffer; @@ -88,7 +99,9 @@ CardInterrupt( struct CMI8738_DATA* card ) else // just played buf 2 { if (card->flip == 0) + { DebugPrintF("B:Missed IRQ! diff = %lu\n", diff); + } card->flip = 0; card->current_buffer = (APTR) ((long) card->playback_buffer + card->current_bytesize); @@ -102,7 +115,7 @@ CardInterrupt( struct CMI8738_DATA* card ) Cause( &card->playback_interrupt ); } - if( intreq & CMPCI_REG_CH1_INTR && AudioCtrl != NULL ) + if( intreq & CMPCI_REG_CH1_INTR) { ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); @@ -184,9 +197,14 @@ PlaybackInterrupt( struct CMI8738_DATA* card ) i = samples; + while( i > 0 ) { +#ifdef __AMIGAOS4__ *dst = ( ( *src & 0xff ) << 8 ) | ( ( *src & 0xff00 ) >> 8 ); +#else + *dst = *src; +#endif src += skip; dst += 1; @@ -195,7 +213,7 @@ PlaybackInterrupt( struct CMI8738_DATA* card ) } CacheClearE( card->current_buffer, (ULONG) dst - (ULONG) card->current_buffer, CACRF_ClearD ); - + CallHookPkt( AudioCtrl->ahiac_PostTimerFunc, (Object*) AudioCtrl, 0 ); } diff --git a/workbench/devs/AHI/Drivers/CMI8738/interrupt.h b/workbench/devs/AHI/Drivers/CMI8738/interrupt.h index 1dd9d6ee99..df346ce568 100755 --- a/workbench/devs/AHI/Drivers/CMI8738/interrupt.h +++ b/workbench/devs/AHI/Drivers/CMI8738/interrupt.h @@ -9,8 +9,8 @@ limitations under the License. The Original Code is written by Davy Wentzler. */ -#ifndef AHI_Drivers_interrupt_h -#define AHI_Drivers_interrupt_h +#ifndef AHI_Drivers_CMI8738_interrupt_h +#define AHI_Drivers_CMI8738_interrupt_h //#include @@ -25,4 +25,4 @@ PlaybackInterrupt( struct CMI8738_DATA* dd ); void RecordInterrupt( struct CMI8738_DATA* dd ); -#endif /* AHI_Drivers_interrupt_h */ +#endif /* AHI_Drivers_CMI8738_interrupt_h */ diff --git a/workbench/devs/AHI/Drivers/CMI8738/misc.c b/workbench/devs/AHI/Drivers/CMI8738/misc.c index a6aeea5671..6972625d9b 100755 --- a/workbench/devs/AHI/Drivers/CMI8738/misc.c +++ b/workbench/devs/AHI/Drivers/CMI8738/misc.c @@ -46,16 +46,16 @@ extern const UWORD InputBits[]; int card_init(struct CMI8738_DATA *card); void card_cleanup(struct CMI8738_DATA *card); -struct Device *TimerBase = NULL; -struct timerequest *TimerIO = NULL; -struct MsgPort *replymp = NULL; - #if !defined(__AROS__) void AddResetHandler(struct CMI8738_DATA *card); #endif void micro_delay(unsigned int val) { + struct Device* TimerBase = NULL; + struct timerequest* TimerIO = NULL; + struct MsgPort * replymp; + replymp = (struct MsgPort *) CreateMsgPort(); if (!replymp) { @@ -100,44 +100,44 @@ void micro_delay(unsigned int val) void WritePartialMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long shift, unsigned long mask, unsigned long val) { - ULONG tmp; - - tmp = pci_inl(reg, card); - tmp &= ~(mask << shift); - tmp |= val << shift; - pci_outl(tmp, reg, card); + ULONG tmp; + + tmp = pci_inl(reg, card); + tmp &= ~(mask << shift); + tmp |= val << shift; + pci_outl(tmp, reg, card); } void ClearMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long mask) { - ULONG tmp; - - tmp = pci_inl(reg, card); - tmp &= ~mask; - pci_outl(tmp, reg, card); + ULONG tmp; + + tmp = pci_inl(reg, card); + tmp &= ~mask; + pci_outl(tmp, reg, card); } void WriteMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long mask) { - ULONG tmp; - - tmp = pci_inl(reg, card); - tmp |= mask; - pci_outl(tmp, reg, card); + ULONG tmp; + + tmp = pci_inl(reg, card); + tmp |= mask; + pci_outl(tmp, reg, card); } void cmimix_wr(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned char port, unsigned char val) { - pci_outb(port, CMPCI_REG_SBADDR, card); - pci_outb(val, CMPCI_REG_SBDATA, card); + pci_outb(port, CMPCI_REG_SBADDR, card); + pci_outb(val, CMPCI_REG_SBDATA, card); } unsigned char cmimix_rd(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned char port) { - pci_outb(port, CMPCI_REG_SBADDR, card); - return (unsigned char) pci_inb(CMPCI_REG_SBDATA, card); + pci_outb(port, CMPCI_REG_SBADDR, card); + return (unsigned char) pci_inb(CMPCI_REG_SBDATA, card); } @@ -153,137 +153,182 @@ struct CMI8738_DATA* AllocDriverData( struct PCIDevice *dev, struct DriverBase* AHIsubBase ) { - struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; - struct CMI8738_DATA* card; - UWORD command_word; - int i, v; - unsigned char byte; + struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase; + struct CMI8738_DATA* card; + UWORD command_word; + ULONG chipvers; + int i, v; + unsigned char byte; bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__); - // FIXME: This should be non-cachable, DMA-able memory - card = AllocVec( sizeof( *card ), MEMF_PUBLIC | MEMF_CLEAR ); + // 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; - } + if( card == NULL ) + { + Req( "Unable to allocate driver structure." ); + return NULL; + } - card->ahisubbase = AHIsubBase; + 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; + 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; + card->interrupt.is_Code = (void(*)(void))&cardinterrupt; #else - card->interrupt.is_Code = (void(*)(void)) CardInterrupt; + card->interrupt.is_Code = (void(*)(void))CardInterrupt; #endif - card->interrupt.is_Data = (APTR) card; + 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; + 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 = &playbackinterrupt; + card->playback_interrupt.is_Code = (void(*)(void))&playbackinterrupt; #else - card->playback_interrupt.is_Code = PlaybackInterrupt; + card->playback_interrupt.is_Code = (void(*)(void))PlaybackInterrupt; #endif - card->playback_interrupt.is_Data = (APTR) card; + 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; + 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 = &recordinterrupt; + card->record_interrupt.is_Code = (void(*)(void))&recordinterrupt; #else - card->record_interrupt.is_Code = RecordInterrupt; + card->record_interrupt.is_Code = (void(*)(void))RecordInterrupt; #endif - card->record_interrupt.is_Data = (APTR) card; + card->record_interrupt.is_Data = (APTR) card; - card->pci_dev = dev; + 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); + 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->pci_master_enabled = TRUE; - /*for (i = 0; i < 6; i++) - { - if (dev->GetResourceRange(i)) - DebugPrintF("BAR[%ld] = %lx\n", i, dev->GetResourceRange(i)->BaseAddress); - }*/ + /*for (i = 0; i < 6; i++) + { + if (dev->GetResourceRange(i)) + DebugPrintF("BAR[%ld] = %lx\n", i, dev->GetResourceRange(i)->BaseAddress); + }*/ + + card->iobase = ahi_pci_get_base_address(0, dev); + card->length = ahi_pci_get_base_size(0, dev); + card->irq = ahi_pci_get_irq(dev); + card->chiprev = inb_config(PCI_REVISION_ID, dev); + card->model = inw_config(PCI_SUBSYSTEM_ID, dev); - card->iobase = ahi_pci_get_base_address(0, dev); - card->length = ahi_pci_get_base_size(0, dev); - card->irq = ahi_pci_get_irq(dev); - card->chiprev = inb_config(PCI_REVISION_ID, dev); - card->model = inw_config(PCI_SUBSYSTEM_ID, dev); + bug("[CMI8738]: %s: iobase = 0x%p, len = %d\n", __PRETTY_FUNCTION__, card->iobase, card->length); + chipvers = pci_inl(CMPCI_REG_INTR_CTRL, card) & CMPCI_REG_VERSION_MASK; + if (chipvers) + { + if (chipvers & CMPCI_REG_VERSION_68) + { + card->chipvers = 68; + card->channels = 8; + } + if (chipvers & CMPCI_REG_VERSION_55) + { + card->chipvers = 55; + card->channels = 6; + } + if (chipvers & CMPCI_REG_VERSION_39) + { + card->chipvers = 39; + if (chipvers & CMPCI_REG_VERSION_39B) + { + card->channels = 6; + } + else + { + card->channels = 4; + } + } + } + else + { + chipvers = pci_inl(CMPCI_REG_CHANNEL_FORMAT, card) & CMPCI_REG_VERSION_37; + if (!chipvers) + { + card->chipvers = 33; + card->channels = 2; + } + else + { + card->chipvers = 37; + card->channels = 2; + } + } /*DebugPrintF("---> chiprev = %u, model = %x, Vendor = %x\n", dev->ReadConfigByte( PCI_REVISION_ID), dev->ReadConfigWord( PCI_SUBSYSTEM_ID), dev->ReadConfigWord( PCI_SUBSYSTEM_VENDOR_ID));*/ - bug("[CMI8738]: %s: chiprev = %u, model = %x, Vendor = %x\n", __PRETTY_FUNCTION__, - card->chiprev, + bug("[CMI8738]: %s: chipvers = %u, chiprev = %u, model = %x, Vendor = %x\n", __PRETTY_FUNCTION__, + card->chipvers, card->chiprev, card->model, inw_config( PCI_SUBSYSTEM_VENDOR_ID, dev)); - /* Initialize chip */ - if( card_init( card ) < 0 ) - { - DebugPrintF("Unable to initialize Card subsystem."); - return NULL; - } + bug("[CMI8738]: %s: max channels = %d\n", __PRETTY_FUNCTION__, card->channels); + + /* Initialize chip */ + if( card_init( card ) < 0 ) + { + DebugPrintF("Unable to initialize Card subsystem."); + return NULL; + } - //DebugPrintF("INTERRUPT %lu\n", dev->MapInterrupt()); - ahi_pci_add_intserver(&card->interrupt, dev); - card->interrupt_added = TRUE; + //DebugPrintF("INTERRUPT %lu\n", dev->MapInterrupt()); + 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); + 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); - cmimix_wr(dev, card, CMPCI_SB16_MIXER_RESET, 0); - cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_L, 0); //(CMPCI_SB16_MIXER_LINE_SRC_R << 1) ); // set input to line - cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_R, 0); //CMPCI_SB16_MIXER_LINE_SRC_R); + cmimix_wr(dev, card, CMPCI_SB16_MIXER_RESET, 0); + cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_L, 0); //(CMPCI_SB16_MIXER_LINE_SRC_R << 1) ); // set input to line + cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_R, 0); //CMPCI_SB16_MIXER_LINE_SRC_R); - cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, 0); // set output mute off for line and CD + cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, 0); // set output mute off for line and CD - cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_L, 0xFF); // PCM - cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_R, 0xFF); + cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_L, 0xFF); // PCM + cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_R, 0xFF); - cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_L, 0x00); - cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_R, 0x00); + cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_L, 0x00); + cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_R, 0x00); - cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_L, 0x00); - cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_R, 0x00); + cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_L, 0x00); + cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_R, 0x00); - byte = pci_inb(CMPCI_REG_MIXER25, card); - pci_outb(byte & ~0x30, CMPCI_REG_MIXER25, card); // mute Aux - pci_outb(byte & ~0x01, CMPCI_REG_MIXER25, card); // turn on mic 20dB boost - pci_outb(0x00, CMPCI_REG_MIXER_AUX, card); + byte = pci_inb(CMPCI_REG_MIXER25, card); + pci_outb(byte & ~0x30, CMPCI_REG_MIXER25, card); // mute Aux + pci_outb(byte & ~0x01, CMPCI_REG_MIXER25, card); // turn on mic 20dB boost + pci_outb(0x00, CMPCI_REG_MIXER_AUX, card); - byte = pci_inb(CMPCI_REG_MIXER24, card); - pci_outb(byte | CMPCI_REG_FMMUTE, CMPCI_REG_MIXER24, card); + byte = pci_inb(CMPCI_REG_MIXER24, card); + pci_outb(byte | CMPCI_REG_FMMUTE, CMPCI_REG_MIXER24, card); - cmimix_wr(dev, card, CMPCI_SB16_MIXER_MIC, 0x00); + cmimix_wr(dev, card, CMPCI_SB16_MIXER_MIC, 0x00); - cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_L, 0xFF); - cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_R, 0xFF); + cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_L, 0xFF); + cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_R, 0xFF); - card->mixerstate = cmimix_rd(dev, card, CMPCI_SB16_MIXER_OUTMIX); + card->mixerstate = cmimix_rd(dev, card, CMPCI_SB16_MIXER_OUTMIX); #if !defined(__AROS__) - AddResetHandler(card); + AddResetHandler(card); #endif - return card; + return card; } @@ -340,12 +385,12 @@ int card_init(struct CMI8738_DATA *card) ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); // power up WriteMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET); -// IDOS->Delay(1); + udelay(1); ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET); /* reset channels */ WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET); -// IDOS->Delay(1); + udelay(1); ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET); /* Disable interrupts and channels */ @@ -626,8 +671,8 @@ void AddResetHandler(struct CMI8738_DATA *card) interrupt.is_Code = (void (*)())ResetHandler; interrupt.is_Data = (APTR) card; interrupt.is_Node.ln_Pri = 0; - interrupt.is_Node.ln_Type = IRQTYPE; - interrupt.is_Node.ln_Name = "reset handler"; + interrupt.is_Node.ln_Type = NT_EXTINTERRUPT; + interrupt.is_Node.ln_Name = "CMI8738 Reset Handler"; AddResetCallback( &interrupt ); } diff --git a/workbench/devs/AHI/Drivers/CMI8738/pci_aros.c b/workbench/devs/AHI/Drivers/CMI8738/pci_aros.c index 58167d37ff..ea221f4c38 100644 --- a/workbench/devs/AHI/Drivers/CMI8738/pci_aros.c +++ b/workbench/devs/AHI/Drivers/CMI8738/pci_aros.c @@ -140,41 +140,34 @@ APTR ahi_pci_find_device(ULONG vendorid, ULONG deviceid, APTR dev) ULONG pci_inl(ULONG addr, struct CMI8738_DATA *card) { - volatile ULONG *real_addr = (ULONG *) (card->iobase + addr); // card->iobase should be virtual - - return *(real_addr); + return (*((ULONG *)(card->iobase + addr))); } UWORD pci_inw(ULONG addr, struct CMI8738_DATA *card) { - volatile UWORD *real_addr = (UWORD *) (card->iobase + addr); - - return *(real_addr); + return (*((UWORD *)(card->iobase + addr))); } UBYTE pci_inb(ULONG addr, struct CMI8738_DATA *card) { - volatile UBYTE *real_addr = (UBYTE *) (card->iobase + addr); - - return *(real_addr); + return (*((UBYTE *)(card->iobase + addr))); } void pci_outl(ULONG value, ULONG addr, struct CMI8738_DATA *card) { - *((volatile ULONG *) (card->iobase + addr)) = value; + *((ULONG *)(card->iobase + addr)) = (value); } void pci_outw(UWORD value, ULONG addr, struct CMI8738_DATA *card) { - *((volatile UWORD *) (card->iobase + addr)) = value; + *((UWORD *)(card->iobase + addr)) = (value); } void pci_outb(UBYTE value, ULONG addr, struct CMI8738_DATA *card) { - *((volatile UBYTE *) (card->iobase + addr)) = value; + *((UBYTE *)(card->iobase + addr)) = (value); } - void outb_setbits(UBYTE value, ULONG addr, struct CMI8738_DATA *card) { UBYTE data = pci_inb(addr, card); diff --git a/workbench/devs/AHI/Drivers/CMI8738/regs.h b/workbench/devs/AHI/Drivers/CMI8738/regs.h index 3cc0fcf282..6cc280b3ab 100755 --- a/workbench/devs/AHI/Drivers/CMI8738/regs.h +++ b/workbench/devs/AHI/Drivers/CMI8738/regs.h @@ -85,11 +85,17 @@ # define CMPCI_REG_FORMAT_STEREO 0x00000001 # define CMPCI_REG_FORMAT_8BIT 0x00000000 # define CMPCI_REG_FORMAT_16BIT 0x00000002 +# define CMPCI_REG_VERSION_37 0x01000000 // hardware revision 37 #define CMPCI_REG_INTR_CTRL 0x0c # define CMPCI_REG_CH0_INTR_ENABLE 0x00010000 # define CMPCI_REG_CH1_INTR_ENABLE 0x00020000 # define CMPCI_REG_TDMA_INTR_ENABLE 0x00040000 +# define CMPCI_REG_VERSION_MASK 0xFF000000 // version number mask (bits 31:24) +# define CMPCI_REG_VERSION_39 0x04000000 // revision 39 +# define CMPCI_REG_VERSION_39B 0x01000000 // 6 channel version of revision 39 +# define CMPCI_REG_VERSION_55 0x08000000 // revision 55 +# define CMPCI_REG_VERSION_68 0x20000000 // revision 68 (8768) #define CMPCI_REG_INTR_STATUS 0x10 # define CMPCI_REG_CH0_INTR 0x00000001 -- 2.11.4.GIT