From 9cb003642de4989f4a8eecdfb4ae4d35d87627ed Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 25 Feb 2013 01:57:03 +0000 Subject: [PATCH] Added port of Davy Wentzler's VIA VT82C686 AC97 driver. git-svn-id: https://svn.aros.org/svn/aros/trunk/AROS@46698 fb15a70f-31f2-0310-bbcc-cdcc74a49acc --- workbench/devs/AHI/Drivers/Makefile.in | 1 + workbench/devs/AHI/Drivers/VIA-AC97/DriverData.h | 231 ++++++ workbench/devs/AHI/Drivers/VIA-AC97/LEGAL | 2 + workbench/devs/AHI/Drivers/VIA-AC97/Makefile.in | 14 + workbench/devs/AHI/Drivers/VIA-AC97/VIA-AC97.s | 72 ++ workbench/devs/AHI/Drivers/VIA-AC97/accel.c | 100 +++ workbench/devs/AHI/Drivers/VIA-AC97/driver-init.c | 195 +++++ workbench/devs/AHI/Drivers/VIA-AC97/hwaccess.h | 176 ++++ workbench/devs/AHI/Drivers/VIA-AC97/interrupt.c | 218 +++++ workbench/devs/AHI/Drivers/VIA-AC97/interrupt.h | 30 + workbench/devs/AHI/Drivers/VIA-AC97/misc.c | 811 ++++++++++++++++++ workbench/devs/AHI/Drivers/VIA-AC97/misc.h | 71 ++ workbench/devs/AHI/Drivers/VIA-AC97/pci_aros.c | 453 ++++++++++ workbench/devs/AHI/Drivers/VIA-AC97/pci_wrapper.c | 15 + workbench/devs/AHI/Drivers/VIA-AC97/pci_wrapper.h | 124 +++ workbench/devs/AHI/Drivers/VIA-AC97/regs.h | 72 ++ workbench/devs/AHI/Drivers/VIA-AC97/version.date | 1 + workbench/devs/AHI/Drivers/VIA-AC97/version.rev | 1 + workbench/devs/AHI/Drivers/VIA-AC97/version.ver | 1 + workbench/devs/AHI/Drivers/VIA-AC97/via.c | 956 ++++++++++++++++++++++ workbench/devs/AHI/configure | 5 +- workbench/devs/AHI/configure.in | 3 +- 22 files changed, 3549 insertions(+), 3 deletions(-) create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/DriverData.h create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/LEGAL create mode 100755 workbench/devs/AHI/Drivers/VIA-AC97/Makefile.in create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/VIA-AC97.s create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/accel.c create mode 100755 workbench/devs/AHI/Drivers/VIA-AC97/driver-init.c create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/hwaccess.h create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/interrupt.c create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/interrupt.h create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/misc.c create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/misc.h create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/pci_aros.c create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/pci_wrapper.c create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/pci_wrapper.h create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/regs.h create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/version.date create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/version.rev create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/version.ver create mode 100644 workbench/devs/AHI/Drivers/VIA-AC97/via.c diff --git a/workbench/devs/AHI/Drivers/Makefile.in b/workbench/devs/AHI/Drivers/Makefile.in index 84085ca2b4..557d2f866c 100644 --- a/workbench/devs/AHI/Drivers/Makefile.in +++ b/workbench/devs/AHI/Drivers/Makefile.in @@ -37,6 +37,7 @@ SUBDIRS = Device Filesave Void ifneq ($(strip $(HAVE_ASMIO)),) SUBDIRS += ac97 +SUBDIRS += VIA-AC97 SUBDIRS += CMI8738 SUBDIRS += SB128 SUBDIRS += HDAudio diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/DriverData.h b/workbench/devs/AHI/Drivers/VIA-AC97/DriverData.h new file mode 100644 index 0000000000..9ab1841114 --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/DriverData.h @@ -0,0 +1,231 @@ +/* + Copyright © 2005-2013, Davy Wentzler. All rights reserved. + Copyright © 2010-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#ifndef AHI_Drivers_VIAAC97_DriverData_h +#define AHI_Drivers_VIAAC97_DriverData_h + +#include +#include +#include + +#include "hwaccess.h" + +/** Make the common library code initialize a global SysBase for us. + It's required for hwaccess.c */ + +#define DRIVER_NEEDS_GLOBAL_EXECBASE +#include "DriverBase.h" + +struct CardData; + +struct CardBase +{ + /** Skeleton's variables *************************************************/ + + struct DriverBase driverbase; + + + /** The driver's global data *********************************************/ + + + /** A sempahore used for locking */ + struct SignalSemaphore semaphore; + + /** The number of cards found */ + int cards_found; + + /** A CardData structure for each card found */ + struct CardData** driverdatas; +}; + +#define DRIVERBASE_SIZEOF (sizeof (struct CardBase)) + +#define RECORD_BUFFER_SAMPLES 4096 +#define RECORD_BUFFER_SIZE_VALUE ADCBS_BUFSIZE_16384 + + +struct snd_dma_device { + int type; /* SNDRV_DMA_TYPE_XXX */ +// struct device *dev; /* generic device */ +}; + +struct snd_dma_buffer { + struct snd_dma_device dev; /* device type */ + unsigned char *area; /* virtual pointer */ + void *addr; /* physical address */ + int bytes; /* buffer size in bytes */ + void *private_data; /* private for allocator; don't touch */ +}; + +struct snd_via_sg_table { // scatter/gather format. Oh joy, the docs talk about EOL, base counts etc... + APTR offset; + unsigned int size; +}; + +struct CardData +{ + + struct PCIDevice *pci_dev; + unsigned long iobase; + unsigned long length; + unsigned short model; + unsigned int irq; + int flip; + int recflip; + UBYTE chiprev; + + struct snd_dma_buffer table; + struct snd_via_sg_table *play_idx_table; + struct snd_via_sg_table *rec_idx_table; + + APTR play_idx_table_nonaligned; + APTR rec_idx_table_nonaligned; + + /*** PCI/Card initialization progress *********************************/ + + /** TRUE if bus mastering is activated */ + BOOL pci_master_enabled; + + /** TRUE if the Card chip has been initialized */ + BOOL card_initialized; + + /*** The driverbase ******************************************************/ + + /** This field is also used as a lock and access to is is + * semaphore protected. */ + struct DriverBase* ahisubbase; + + /*** The AudioCtrl currently using this DriverData structure *************/ + + struct AHIAudioCtrlDrv* audioctrl; + + /*** Playback/recording interrupts ***************************************/ + + /** TRUE when playback is enabled */ + BOOL is_playing; + + /** TRUE when recording is enabled */ + BOOL is_recording; + + /** The main (hardware) interrupt */ + struct Interrupt interrupt; + + /** TRUE if the hardware interrupt has been added to the PCI subsystem */ + BOOL interrupt_added; + + /** The playback software interrupt */ + struct Interrupt playback_interrupt; + + /** TRUE if the hardware interrupt may Cause() playback_interrupt */ + BOOL playback_interrupt_enabled; + + /** The recording software interrupt */ + struct Interrupt record_interrupt; + + /** TRUE if the hardware interrupt may Cause() playback_interrupt */ + BOOL record_interrupt_enabled; + + /** The reset handler */ + struct Interrupt reset_handler; + + /** TRUE if the reset handler has been added to the system */ + BOOL reset_handler_added; + + /*** CAMD support functions **********************************************/ + + /** CAMD transmitter function wrapped as a Hook */ + struct Hook* camd_transmitfunc; + + /** CAMD receiver function wrapped as a Hook */ + struct Hook* camd_receivefunc; + + /** True if CMAD V40 mode */ + ULONG camd_v40; + + /*** Card structures **************************************************/ + + APTR playback_buffer1; + APTR playback_buffer2; + APTR playback_buffer1_nonaligned; + APTR playback_buffer2_nonaligned; + + + /*** Playback interrupt variables ****************************************/ + + /** The mixing buffer (a cyclic buffer filled by AHI) */ + APTR mix_buffer; + + /** The length of each playback buffer in sample frames */ + ULONG current_frames; + + /** The length of each playback buffer in sample bytes */ + ULONG current_bytesize; + + /** Where (inside the cyclic buffer) we're currently writing */ + APTR current_buffer; + + + + /*** Recording interrupt variables ***************************************/ + + /** The recording buffer (simple double buffering is used */ + APTR record_buffer1; + APTR record_buffer2; + APTR record_buffer1_nonaligned; + APTR record_buffer2_nonaligned; + + /** Were (inside the recording buffer) the current data is */ + APTR current_record_buffer; + + /** The length of each record buffer in sample bytes */ + ULONG current_record_bytesize; + + /** Analog mixer variables ***********************************************/ + + /** The currently selected input */ + UWORD input; + + /** The currently selected output */ + UWORD output; + + /** The current (recording) monitor volume */ + Fixed monitor_volume; + + /** The current (recording) input gain */ + Fixed input_gain; + + /** The current (playback) output volume */ + Fixed output_volume; + + /** The hardware register value corresponding to monitor_volume */ + UWORD monitor_volume_bits; + + /** The hardware register value corresponding to input_gain */ + UWORD input_gain_bits; + + /** The hardware register value corresponding to output_volume */ + UWORD output_volume_bits; + + /** Saved state for AC97 mike */ + UWORD ac97_mic; + + /** Saved state for AC97 cd */ + UWORD ac97_cd; + + /** Saved state for AC97 vide */ + UWORD ac97_video; + + /** Saved state for AC97 aux */ + UWORD ac97_aux; + + /** Saved state for AC97 line in */ + UWORD ac97_linein; + + /** Saved state for AC97 phone */ + UWORD ac97_phone; +}; + +#endif /* AHI_Drivers_VIAAC97_DriverData_h */ diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/LEGAL b/workbench/devs/AHI/Drivers/VIA-AC97/LEGAL new file mode 100644 index 0000000000..8f8ee3be6b --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/LEGAL @@ -0,0 +1,2 @@ +This driver is distributed under the terms of the AROS Public License, +version 1.1. See the individual source code files for further details. diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/Makefile.in b/workbench/devs/AHI/Drivers/VIA-AC97/Makefile.in new file mode 100755 index 0000000000..1d7d3599aa --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/Makefile.in @@ -0,0 +1,14 @@ +# $Id $ +# +# Makefile.in for VIA AC97 AHI driver +# + +VPATH = @srcdir@ +srcdir = @srcdir@ + +DRIVER = via-ac97.audio +MODEFILE = VIA-AC97 + +OBJECTS = driver-init.o via.o accel.o misc.o interrupt.o pci_wrapper.o + +include ../Common/Makefile.common diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/VIA-AC97.s b/workbench/devs/AHI/Drivers/VIA-AC97/VIA-AC97.s new file mode 100644 index 0000000000..bd52ce40dd --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/VIA-AC97.s @@ -0,0 +1,72 @@ +/* + Copyright © 2005-2013, Davy Wentzler. All rights reserved. + Copyright © 2010-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + + FORM_START AHIM + + CHUNK_START AUDN + .asciz "via-ac97" + CHUNK_END + + CHUNK_START AUDM +1: + LONG2 AHIDB_AudioID, 0x02000001 + LONG2 AHIDB_Volume, TRUE + LONG2 AHIDB_Panning, FALSE + LONG2 AHIDB_Stereo, FALSE + LONG2 AHIDB_HiFi, TRUE + LONG2 AHIDB_MultTable,FALSE + LONG2 AHIDB_Name, 2f-1b + LONG TAG_DONE +2: + .asciz "VIA-AC97:HiFi 16 bit mono" + CHUNK_END + + CHUNK_START AUDM +1: + LONG2 AHIDB_AudioID, 0x02000002 + LONG2 AHIDB_Volume, TRUE + LONG2 AHIDB_Panning, TRUE + LONG2 AHIDB_Stereo, TRUE + LONG2 AHIDB_HiFi, TRUE + LONG2 AHIDB_MultTable,FALSE + LONG2 AHIDB_Name, 2f-1b + LONG TAG_DONE +2: + .asciz "VIA-AC97:HiFi 16 bit stereo++" + CHUNK_END + + CHUNK_START AUDM +1: + LONG2 AHIDB_AudioID, 0x02000003 + LONG2 AHIDB_Volume, TRUE + LONG2 AHIDB_Panning, FALSE + LONG2 AHIDB_Stereo, FALSE + LONG2 AHIDB_HiFi, FALSE + LONG2 AHIDB_MultTable,FALSE + LONG2 AHIDB_Name, 2f-1b + LONG TAG_DONE +2: + .asciz "VIA-AC97:16 bit mono" + CHUNK_END + + CHUNK_START AUDM +1: + LONG2 AHIDB_AudioID, 0x02000004 + LONG2 AHIDB_Volume, TRUE + LONG2 AHIDB_Panning, TRUE + LONG2 AHIDB_Stereo, TRUE + LONG2 AHIDB_HiFi, FALSE + LONG2 AHIDB_MultTable,FALSE + LONG2 AHIDB_Name, 2f-1b + LONG TAG_DONE +2: + .asciz "VIA-AC97:16 bit stereo++" + CHUNK_END + + FORM_END + + .END + diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/accel.c b/workbench/devs/AHI/Drivers/VIA-AC97/accel.c new file mode 100644 index 0000000000..a5afe3312d --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/accel.c @@ -0,0 +1,100 @@ +/* + Copyright © 2005-2013, Davy Wentzler. All rights reserved. + Copyright © 2010-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#include + +#include +#include + +#include "library.h" + +/****************************************************************************** +** AHIsub_SetVol ************************************************************** +******************************************************************************/ + +ULONG +_AHIsub_SetVol( UWORD channel, + Fixed volume, + sposition pan, + struct AHIAudioCtrlDrv* AudioCtrl, + ULONG flags, + struct DriverBase* AHIsubBase ) +{ + return AHIS_UNKNOWN; +} + + +/****************************************************************************** +** AHIsub_SetFreq ************************************************************* +******************************************************************************/ + +ULONG +_AHIsub_SetFreq( UWORD channel, + ULONG freq, + struct AHIAudioCtrlDrv* AudioCtrl, + ULONG flags, + struct DriverBase* AHIsubBase ) +{ + return AHIS_UNKNOWN; +} + + +/****************************************************************************** +** AHIsub_SetSound ************************************************************ +******************************************************************************/ + +ULONG +_AHIsub_SetSound( UWORD channel, + UWORD sound, + ULONG offset, + LONG length, + struct AHIAudioCtrlDrv* AudioCtrl, + ULONG flags, + struct DriverBase* AHIsubBase ) +{ + return AHIS_UNKNOWN; +} + + +/****************************************************************************** +** AHIsub_SetEffect *********************************************************** +******************************************************************************/ + +ULONG +_AHIsub_SetEffect( APTR effect, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + return AHIS_UNKNOWN; +} + + +/****************************************************************************** +** AHIsub_LoadSound *********************************************************** +******************************************************************************/ + +ULONG +_AHIsub_LoadSound( UWORD sound, + ULONG type, + APTR info, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + return AHIS_UNKNOWN; +} + + +/****************************************************************************** +** AHIsub_UnloadSound ********************************************************* +******************************************************************************/ + +ULONG +_AHIsub_UnloadSound( UWORD sound, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + return AHIS_UNKNOWN; +} diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/driver-init.c b/workbench/devs/AHI/Drivers/VIA-AC97/driver-init.c new file mode 100755 index 0000000000..9104e1c3fe --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/driver-init.c @@ -0,0 +1,195 @@ +/* + Copyright © 2005-2013, Davy Wentzler. All rights reserved. + Copyright © 2010-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#ifdef __AROS__ +#define DEBUG 0 +#include +#define DebugPrintF bug +#endif + +#include + +#if !defined(__AROS__) +#undef __USE_INLINE__ +#include +#endif + +#include +#include +#include + +#include "library.h" +#include "misc.h" +#include "regs.h" + +#include "pci_wrapper.h" + +struct DriverBase* AHIsubBase; + +struct DosLibrary* DOSBase; +struct Library* ExpansionBase = NULL; + +struct VendorDevice +{ + UWORD vendor; + UWORD device; +}; + +#define VENDOR_ID 0x1106 +#define DEVICE_ID 0x3058 +#define CARD_STRING "VIA AC97 Audio Controller" +#define MAX_DEVICE_VENDORS 512 + +struct VendorDevice *vendor_device_list = NULL; +static int vendor_device_list_size = 0; + +/****************************************************************************** +** Custom driver init ********************************************************* +******************************************************************************/ + +BOOL +DriverInit( struct DriverBase* ahisubbase ) +{ + struct CardBase *CardBase = (struct CardBase*) ahisubbase; + struct PCIDevice *dev; + int card_no, i; + struct List foundCards; + struct Node *devTmp; + + bug("[VIA-AC97]: %s()\n", __PRETTY_FUNCTION__); + + CardBase->driverdatas = 0; + CardBase->cards_found = 0; + AHIsubBase = ahisubbase; + + NewList(&foundCards); + + DOSBase = (struct DosLibrary *)OpenLibrary( DOSNAME, 37 ); + + if( DOSBase == NULL ) + { + Req( "VIA-AC97: Unable to open 'dos.library' version 37.\n" ); + return FALSE; + } + + ExpansionBase = OpenLibrary( "expansion.library", 1 ); + if( ExpansionBase == NULL ) + { + Req( "VIA-AC97: Unable to open 'expansion.library' version 1.\n" ); + return FALSE; + } + + if (!ahi_pci_init(ahisubbase)) + { + return FALSE; + } + + InitSemaphore( &CardBase->semaphore ); + + /*** Count cards ***********************************************************/ + + vendor_device_list = (struct VendorDevice *) AllocVec(sizeof(struct VendorDevice) * MAX_DEVICE_VENDORS, MEMF_PUBLIC | MEMF_CLEAR); + + vendor_device_list[0].vendor = VENDOR_ID; + vendor_device_list[0].device = DEVICE_ID; + vendor_device_list_size++; + + bug("vendor_device_list_size = %ld\n", vendor_device_list_size); + + CardBase->cards_found = 0; + dev = NULL; + + 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) + { + bug("[VIA-AC97] %s: Found VIA-AC97 #%d [%4x:%4x] pci obj @ 0x%p\n", __PRETTY_FUNCTION__, i, vendor_device_list[i].vendor, vendor_device_list[i].device, dev); + ++CardBase->cards_found; + + devTmp = AllocVec(sizeof(struct Node), MEMF_CLEAR); + devTmp->ln_Name = (APTR)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). + + if(CardBase->cards_found == 0 ) + { + DebugPrintF("No VIA-AC97 found! :-(\n"); +#if defined(VERBOSE_REQ) + Req( "No card present.\n" ); +#endif + return FALSE; + } + + /*** Allocate and init all cards *******************************************/ + + CardBase->driverdatas = AllocVec( sizeof( *CardBase->driverdatas ) * + CardBase->cards_found, + MEMF_PUBLIC | MEMF_CLEAR); + + if( CardBase->driverdatas == NULL ) + { + Req( "Out of memory." ); + return FALSE; + } + + card_no = 0; + + struct Node *scratchNode; + ForeachNodeSafe(&foundCards, devTmp, scratchNode) + { + Remove(devTmp); + + dev = (struct PCIDevice *)devTmp->ln_Name; + bug("[VIA-AC97] %s: Preparing card #%d pci obj @ 0x%p\n", __PRETTY_FUNCTION__, card_no, dev); + CardBase->driverdatas[ card_no ] = AllocDriverData( dev, AHIsubBase ); + + FreeVec(devTmp); + ++card_no; + } + + bug("[VIA-AC97] %s: Done.\n", __PRETTY_FUNCTION__); + + return TRUE; +} + + +/****************************************************************************** +** Custom driver clean-up ***************************************************** +******************************************************************************/ + +VOID +DriverCleanup( struct DriverBase* AHIsubBase ) +{ + struct CardBase* CardBase = (struct CardBase*) AHIsubBase; + int i; + + bug("[VIA-AC97]: %s()\n", __PRETTY_FUNCTION__); + + for( i = 0; i < CardBase->cards_found; ++i ) + { + FreeDriverData( CardBase->driverdatas[ i ], AHIsubBase ); + } + + FreeVec( CardBase->driverdatas ); + + ahi_pci_exit(); + + if (ExpansionBase) + CloseLibrary( (struct Library*) ExpansionBase); + + if (UtilityBase) + CloseLibrary( (struct Library*) UtilityBase); + + if (DOSBase) + CloseLibrary( (struct Library*) DOSBase); +} + diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/hwaccess.h b/workbench/devs/AHI/Drivers/VIA-AC97/hwaccess.h new file mode 100644 index 0000000000..266f182b0d --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/hwaccess.h @@ -0,0 +1,176 @@ +/* + Copyright © 2005-2013, Davy Wentzler. All rights reserved. + Copyright © 2010-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#ifndef _HWACCESS_H +#define _HWACCESS_H + +#define VIA_TABLE_SIZE 255 + +#define RECORD 0x10 + +/* common offsets */ +#define VIA_REG_OFFSET_STATUS 0x00 /* byte - channel status */ +#define VIA_REG_STAT_ACTIVE 0x80 /* RO */ +#define VIA_REG_STAT_PAUSED 0x40 /* RO */ +#define VIA_REG_STAT_TRIGGER_QUEUED 0x08 /* RO */ +#define VIA_REG_STAT_STOPPED 0x04 /* RWC */ +#define VIA_REG_STAT_EOL 0x02 /* RWC */ +#define VIA_REG_STAT_FLAG 0x01 /* RWC */ +#define VIA_REG_OFFSET_CONTROL 0x01 /* byte - channel control */ +#define VIA_REG_CTRL_START 0x80 /* WO */ +#define VIA_REG_CTRL_TERMINATE 0x40 /* WO */ +#define VIA_REG_CTRL_AUTOSTART 0x20 +#define VIA_REG_CTRL_PAUSE 0x08 /* RW */ +#define VIA_REG_CTRL_INT_STOP 0x04 +#define VIA_REG_CTRL_INT_EOL 0x02 +#define VIA_REG_CTRL_INT_FLAG 0x01 +#define VIA_REG_CTRL_RESET 0x01 /* RW - probably reset? undocumented */ +#define VIA_REG_CTRL_INT (VIA_REG_CTRL_INT_FLAG | VIA_REG_CTRL_INT_EOL | VIA_REG_CTRL_AUTOSTART) +#define VIA_REG_OFFSET_TYPE 0x02 /* byte - channel type (686 only) */ +#define VIA_REG_TYPE_AUTOSTART 0x80 /* RW - autostart at EOL */ +#define VIA_REG_TYPE_16BIT 0x20 /* RW */ +#define VIA_REG_TYPE_STEREO 0x10 /* RW */ +#define VIA_REG_TYPE_INT_LLINE 0x00 +#define VIA_REG_TYPE_INT_LSAMPLE 0x04 +#define VIA_REG_TYPE_INT_LESSONE 0x08 +#define VIA_REG_TYPE_INT_MASK 0x0c +#define VIA_REG_TYPE_INT_EOL 0x02 +#define VIA_REG_TYPE_INT_FLAG 0x01 +#define VIA_REG_OFFSET_TABLE_PTR 0x04 /* dword - channel table pointer */ +#define VIA_REG_OFFSET_CURR_PTR 0x04 /* dword - channel current pointer */ +#define VIA_REG_OFFSET_STOP_IDX 0x08 /* dword - stop index, channel type, sample rate */ +#define VIA8233_REG_TYPE_16BIT 0x00200000 /* RW */ +#define VIA8233_REG_TYPE_STEREO 0x00100000 /* RW */ +#define VIA_REG_OFFSET_CURR_COUNT 0x0c /* dword - channel current count (24 bit) */ +#define VIA_REG_OFFSET_CURR_INDEX 0x0f /* byte - channel current index (for via8233 only) */ + + + + +/* AC'97 */ +#define VIA_REG_AC97 0x80 /* dword */ +#define VIA_REG_AC97_CODEC_ID_MASK (3<<30) +#define VIA_REG_AC97_CODEC_ID_SHIFT 30 +#define VIA_REG_AC97_CODEC_ID_PRIMARY 0x00 +#define VIA_REG_AC97_CODEC_ID_SECONDARY 0x01 +#define VIA_REG_AC97_SECONDARY_VALID (1<<27) +#define VIA_REG_AC97_PRIMARY_VALID (1<<25) +#define VIA_REG_AC97_BUSY (1<<24) +#define VIA_REG_AC97_READ (1<<23) +#define VIA_REG_AC97_CMD_SHIFT 16 +#define VIA_REG_AC97_CMD_MASK 0x7e +#define VIA_REG_AC97_DATA_SHIFT 0 +#define VIA_REG_AC97_DATA_MASK 0xffff + +#define VIA_REG_SGD_SHADOW 0x84 /* dword */ +/* via686 */ +#define VIA_REG_SGD_STAT_PB_FLAG (1<<0) +#define VIA_REG_SGD_STAT_CP_FLAG (1<<1) +#define VIA_REG_SGD_STAT_FM_FLAG (1<<2) +#define VIA_REG_SGD_STAT_PB_EOL (1<<4) +#define VIA_REG_SGD_STAT_CP_EOL (1<<5) +#define VIA_REG_SGD_STAT_FM_EOL (1<<6) +#define VIA_REG_SGD_STAT_PB_STOP (1<<8) +#define VIA_REG_SGD_STAT_CP_STOP (1<<9) +#define VIA_REG_SGD_STAT_FM_STOP (1<<10) +#define VIA_REG_SGD_STAT_PB_ACTIVE (1<<12) +#define VIA_REG_SGD_STAT_CP_ACTIVE (1<<13) +#define VIA_REG_SGD_STAT_FM_ACTIVE (1<<14) +/* via8233 */ +#define VIA8233_REG_SGD_STAT_FLAG (1<<0) +#define VIA8233_REG_SGD_STAT_EOL (1<<1) +#define VIA8233_REG_SGD_STAT_STOP (1<<2) +#define VIA8233_REG_SGD_STAT_ACTIVE (1<<3) +#define VIA8233_INTR_MASK(chan) ((VIA8233_REG_SGD_STAT_FLAG|VIA8233_REG_SGD_STAT_EOL) << ((chan) * 4)) +#define VIA8233_REG_SGD_CHAN_SDX 0 +#define VIA8233_REG_SGD_CHAN_MULTI 4 +#define VIA8233_REG_SGD_CHAN_REC 6 +#define VIA8233_REG_SGD_CHAN_REC1 7 + +#define VIA_REG_GPI_STATUS 0x88 +#define VIA_REG_GPI_INTR 0x8c + +/* multi-channel and capture registers for via8233 */ +//DEFINE_VIA_REGSET(MULTPLAY, 0x40); +//DEFINE_VIA_REGSET(CAPTURE_8233, 0x60); + +/* via8233-specific registers */ +#define VIA_REG_OFS_PLAYBACK_VOLUME_L 0x02 /* byte */ +#define VIA_REG_OFS_PLAYBACK_VOLUME_R 0x03 /* byte */ +#define VIA_REG_OFS_MULTPLAY_FORMAT 0x02 /* byte - format and channels */ +#define VIA_REG_MULTPLAY_FMT_8BIT 0x00 +#define VIA_REG_MULTPLAY_FMT_16BIT 0x80 +#define VIA_REG_MULTPLAY_FMT_CH_MASK 0x70 /* # channels << 4 (valid = 1,2,4,6) */ +#define VIA_REG_OFS_CAPTURE_FIFO 0x02 /* byte - bit 6 = fifo enable */ +#define VIA_REG_CAPTURE_FIFO_ENABLE 0x40 + +#define VIA_DXS_MAX_VOLUME 31 /* max. volume (attenuation) of reg 0x32/33 */ + +#define VIA_REG_CAPTURE_CHANNEL 0x63 /* byte - input select */ +#define VIA_REG_CAPTURE_CHANNEL_MIC 0x4 +#define VIA_REG_CAPTURE_CHANNEL_LINE 0 +#define VIA_REG_CAPTURE_SELECT_CODEC 0x03 /* recording source codec (0 = primary) */ + +#define VIA_TBL_BIT_FLAG 0x40000000 +#define VIA_TBL_BIT_EOL 0x80000000 + +/* pci space */ +#define VIA_ACLINK_STAT 0x40 +#define VIA_ACLINK_C11_READY 0x20 +#define VIA_ACLINK_C10_READY 0x10 +#define VIA_ACLINK_C01_READY 0x04 /* secondary codec ready */ +#define VIA_ACLINK_LOWPOWER 0x02 /* low-power state */ +#define VIA_ACLINK_C00_READY 0x01 /* primary codec ready */ +#define VIA_ACLINK_CTRL 0x41 +#define VIA_ACLINK_CTRL_ENABLE 0x80 /* 0: disable, 1: enable */ +#define VIA_ACLINK_CTRL_RESET 0x40 /* 0: assert, 1: de-assert */ +#define VIA_ACLINK_CTRL_SYNC 0x20 /* 0: release SYNC, 1: force SYNC hi */ +#define VIA_ACLINK_CTRL_SDO 0x10 /* 0: release SDO, 1: force SDO hi */ +#define VIA_ACLINK_CTRL_VRA 0x08 /* 0: disable VRA, 1: enable VRA */ +#define VIA_ACLINK_CTRL_PCM 0x04 /* 0: disable PCM, 1: enable PCM */ +#define VIA_ACLINK_CTRL_FM 0x02 /* via686 only */ +#define VIA_ACLINK_CTRL_SB 0x01 /* via686 only */ +#define VIA_ACLINK_CTRL_INIT (VIA_ACLINK_CTRL_ENABLE|\ + VIA_ACLINK_CTRL_RESET|\ + VIA_ACLINK_CTRL_PCM|\ + VIA_ACLINK_CTRL_VRA) +#define VIA_FUNC_ENABLE 0x42 +#define VIA_FUNC_MIDI_PNP 0x80 /* FIXME: it's 0x40 in the datasheet! */ +#define VIA_FUNC_MIDI_IRQMASK 0x40 /* FIXME: not documented! */ +#define VIA_FUNC_RX2C_WRITE 0x20 +#define VIA_FUNC_SB_FIFO_EMPTY 0x10 +#define VIA_FUNC_ENABLE_GAME 0x08 +#define VIA_FUNC_ENABLE_FM 0x04 +#define VIA_FUNC_ENABLE_MIDI 0x02 +#define VIA_FUNC_ENABLE_SB 0x01 +#define VIA_PNP_CONTROL 0x43 +#define VIA_FM_NMI_CTRL 0x48 +#define VIA8233_VOLCHG_CTRL 0x48 +#define VIA8233_SPDIF_CTRL 0x49 +#define VIA8233_SPDIF_DX3 0x08 +#define VIA8233_SPDIF_SLOT_MASK 0x03 +#define VIA8233_SPDIF_SLOT_1011 0x00 +#define VIA8233_SPDIF_SLOT_34 0x01 +#define VIA8233_SPDIF_SLOT_78 0x02 +#define VIA8233_SPDIF_SLOT_69 0x03 + +/* + */ + +#define VIA_DXS_AUTO 0 +#define VIA_DXS_ENABLE 1 +#define VIA_DXS_DISABLE 2 +#define VIA_DXS_48K 3 +#define VIA_DXS_NO_VRA 4 +#define VIA_DXS_SRC 5 + + +#define VOL_6BIT 0x40 +#define VOL_5BIT 0x20 +#define VOL_4BIT 0x10 + + +#endif /* _HWACCESS_H */ diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/interrupt.c b/workbench/devs/AHI/Drivers/VIA-AC97/interrupt.c new file mode 100644 index 0000000000..4878b594d9 --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/interrupt.c @@ -0,0 +1,218 @@ +/* + Copyright © 2005-2013, Davy Wentzler. All rights reserved. + Copyright © 2010-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#include + +#undef __USE_INLINE__ +#include +#include +#include +#include +#include "library.h" +#include "regs.h" +#include "interrupt.h" +#include "misc.h" +#include "hwaccess.h" +#include "pci_wrapper.h" + +#define min(a,b) ((a)<(b)?(a):(b)) + +static int z = 0; + +/****************************************************************************** +** Hardware interrupt handler ************************************************* +******************************************************************************/ + + +#ifdef __amigaos4__ +LONG CardInterrupt(struct ExceptionContext *pContext, + struct ExecBase *SysBase, struct CardData* card) +#else +LONG CardInterrupt(struct CardData* card) +#endif +{ + struct AHIAudioCtrlDrv* AudioCtrl = card->audioctrl; + struct DriverBase* AHIsubBase = (struct DriverBase*) card->ahisubbase; +#ifdef __amigaos4__ + struct PCIDevice *dev = (struct PCIDevice * ) card->pci_dev; +#endif + + ULONG intreq, status; + LONG handled = 0; + + intreq = pci_inl(VIA_REG_SGD_SHADOW, card); + + //DebugPrintF("INT %lx\n", intreq); + if( intreq & 0x33 ) + { + unsigned char play_status = pci_inb(VIA_REG_OFFSET_STATUS, card), + rec_status = pci_inb(VIA_REG_OFFSET_STATUS + RECORD, card); + + play_status &= (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG|VIA_REG_STAT_STOPPED); + + if (play_status) + { + pci_outb(play_status, VIA_REG_OFFSET_STATUS, card); + + if (play_status & VIA_REG_STAT_FLAG) + { + card->flip = 0; + card->current_buffer = card->playback_buffer1; + } + else if (play_status & VIA_REG_STAT_EOL) + { + card->flip = 1; + card->current_buffer = card->playback_buffer2; + } + + card->playback_interrupt_enabled = FALSE; + Cause( &card->playback_interrupt ); + } + + rec_status &= (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG|VIA_REG_STAT_STOPPED); + if (rec_status) + { + //DebugPrintF("REC!\n"); + pci_outb(rec_status, VIA_REG_OFFSET_STATUS + RECORD, card); + + if (rec_status & VIA_REG_STAT_FLAG) + { + card->flip = 0; + card->current_record_buffer = card->record_buffer1; + } + else if (rec_status & VIA_REG_STAT_EOL) + { + card->flip = 1; + card->current_record_buffer = card->record_buffer2; + } + + card->record_interrupt_enabled = FALSE; + Cause( &card->record_interrupt ); + } + + handled = 1; + } + + return handled; +} + + +/****************************************************************************** +** Playback interrupt handler ************************************************* +******************************************************************************/ + +#ifdef __amigaos4__ +void PlaybackInterrupt(struct ExceptionContext *pContext, + struct ExecBase *SysBase, struct CardData* card) +#else +void PlaybackInterrupt(struct CardData* card) +#endif +{ + struct AHIAudioCtrlDrv* AudioCtrl; + struct DriverBase* AHIsubBase; + + if (card == NULL) + return; + + AudioCtrl = card->audioctrl; + AHIsubBase = (struct DriverBase*) card->ahisubbase; + + if( card->mix_buffer != NULL && card->current_buffer != NULL) + { + BOOL skip_mix; + + WORD* src; + WORD* dst; + size_t skip; + size_t samples; + int i; + + skip_mix = CallHookPkt( AudioCtrl->ahiac_PreTimerFunc, (Object*) AudioCtrl, 0 ); + CallHookPkt( AudioCtrl->ahiac_PlayerFunc, (Object*) AudioCtrl, NULL ); + + //DebugPrintF("skip_mix = %d\n", skip_mix); + + if( ! skip_mix ) + { + CallHookPkt( AudioCtrl->ahiac_MixerFunc, (Object*) AudioCtrl, card->mix_buffer ); + } + + /* Now translate and transfer to the DMA buffer */ + + + skip = ( AudioCtrl->ahiac_Flags & AHIACF_HIFI ) ? 2 : 1; + samples = card->current_bytesize >> 1; + + src = card->mix_buffer; +#if !defined(__amigaos4__) && !AROS_BIG_ENDIAN + if(skip == 2) + src++; +#endif + dst = card->current_buffer; + + i = samples; + + while( i > 0 ) + { +#ifdef __amigaos4__ + *dst = ( ( *src & 0xff ) << 8 ) | ( ( *src & 0xff00 ) >> 8 ); +#else + *dst = AROS_WORD2LE(*src); +#endif + src += skip; + dst += 1; + + --i; + } + + CacheClearE( card->current_buffer, (ULONG) dst - (ULONG) card->current_buffer, CACRF_ClearD ); + CallHookPkt( AudioCtrl->ahiac_PostTimerFunc, (Object*) AudioCtrl, 0 ); + } + + card->playback_interrupt_enabled = TRUE; +} + + +/****************************************************************************** +** Record interrupt handler *************************************************** +******************************************************************************/ + +#ifdef __amigaos4__ +void RecordInterrupt(struct ExceptionContext *pContext, + struct ExecBase *SysBase, struct CardData* card) +#else +void RecordInterrupt(struct CardData* card) +#endif +{ + struct AHIAudioCtrlDrv* AudioCtrl = card->audioctrl; + struct DriverBase* AHIsubBase = (struct DriverBase*) card->ahisubbase; + + struct AHIRecordMessage rm = + { + AHIST_S16S, + card->current_record_buffer, + RECORD_BUFFER_SAMPLES + }; + + int i = 0, shorts = card->current_record_bytesize / 2; + WORD* ptr = card->current_record_buffer; + + + while( i < shorts ) + { +#if defined(__AMIGAOS4__) || AROS_BIG_ENDIAN + *ptr = ( ( *ptr & 0xff ) << 8 ) | ( ( *ptr & 0xff00 ) >> 8 ); +#endif + ++i; + ++ptr; + } + + CallHookPkt( AudioCtrl->ahiac_SamplerFunc, (Object*) AudioCtrl, &rm ); + + card->record_interrupt_enabled = TRUE; +} + + diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/interrupt.h b/workbench/devs/AHI/Drivers/VIA-AC97/interrupt.h new file mode 100644 index 0000000000..a79639c5b5 --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/interrupt.h @@ -0,0 +1,30 @@ +/* + Copyright © 2005-2013, Davy Wentzler. All rights reserved. + Copyright © 2010-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#ifndef AHI_Drivers_VIAAC97_interrupt_h +#define AHI_Drivers_VIAAC97_interrupt_h + +#include + +#include "DriverData.h" + +#ifdef __AMIGAOS4__ +ULONG CardInterrupt(struct ExceptionContext *pContext, struct ExecBase *SysBase, struct CardData* dd); + +void PlaybackInterrupt(struct ExceptionContext *pContext, struct ExecBase *SysBase, struct CardData* dd); + +void RecordInterrupt(struct ExceptionContext *pContext, struct ExecBase *SysBase, struct CardData* dd); +#else + +LONG CardInterrupt(struct CardData* card); + +void PlaybackInterrupt(struct CardData* card); + +void RecordInterrupt(struct CardData* card); + +#endif + +#endif /* AHI_Drivers_VIAAC97_interrupt_h */ diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/misc.c b/workbench/devs/AHI/Drivers/VIA-AC97/misc.c new file mode 100644 index 0000000000..514ca2ff20 --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/misc.c @@ -0,0 +1,811 @@ +/* + Copyright © 2005-2013, Davy Wentzler. All rights reserved. + Copyright © 2010-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#include + +#include +#include + +#include + +#include "library.h" +#include "regs.h" +#include "interrupt.h" +#include "hwaccess.h" +#include "misc.h" +#include "pci_wrapper.h" + +//#define DEBUG 1 + +#ifdef __AROS__ +#include +#include +#define DebugPrintF bug +#endif + +//SB- Some debug/err/info output stuff. + +#define ERR(a) DebugPrintF("[VIA-AC97] Error: " a "\n") +#define INF(a) DebugPrintF("[VIA-AC97] Info: " a "\n") +#define INFL(a,b) DebugPrintF("[VIA-AC97] Info: " a " (0x%08lx).\n", (long)b) + +#ifdef DEBUG +#define DBG(a) DebugPrintF( "[VIA-AC97] Debug: " a "\n" ) +#define DBGL(a,b) DebugPrintF( "[VIA-AC97] Debug: " a " (0x%08lx).\n", (long)b ) +#else +#define DBG(a) +#define DBGL(a,b) +#endif + +/* Global in Card.c */ +extern const UWORD InputBits[]; +#ifdef __amigaos4__ +extern struct DOSIFace *IDOS; +extern struct PCIIFace* IPCI; +#endif + +/* Public functions in main.c */ +int card_init(struct CardData *card); +void card_cleanup(struct CardData *card); + + +struct Device *TimerBase = NULL; +struct timerequest *TimerIO = NULL; +struct MsgPort *replymp = NULL; +void AddResetHandler(struct CardData *card); + +static const unsigned long IO_PWR_MANAGEMENT = 0xdd00; +static const unsigned long IO_HW_MONITOR = 0xec00; +static const unsigned long IO_SGD = 0xdc00; +static const unsigned long IO_FM = 0xe000; +static const unsigned long IO_MIDI = 0xe400; + + + +void MicroDelay(unsigned int val) +{ + replymp = (struct MsgPort *) CreateMsgPort(); + if( !replymp ) + { + DebugPrintF("Could not create the reply port!\n" ); + return; + } + + TimerIO = (struct timerequest *) CreateIORequest( replymp, sizeof( struct timerequest) ); + + if( TimerIO == NULL) + { + DebugPrintF( "Out of memory.\n" ); + return; + } + + if( OpenDevice( "timer.device", UNIT_MICROHZ, (struct IORequest *) TimerIO, 0) != 0 ) + { + DebugPrintF( "Unable to open 'timer.device'.\n" ); + return; + } + else + { + TimerBase = (struct Device *) TimerIO->tr_node.io_Device; + } + + if (TimerIO) + { + TimerIO->tr_node.io_Command = TR_ADDREQUEST; /* Add a request. */ + TimerIO->tr_time.tv_secs = 0; /* 0 seconds. */ + TimerIO->tr_time.tv_micro = val; /* 'val' micro seconds. */ + DoIO( (struct IORequest *) TimerIO ); + CloseDevice( (struct IORequest *) TimerIO ); + DeleteIORequest( (struct IORequest *) TimerIO); + TimerIO = NULL; + } + + if( replymp ) + DeleteMsgPort(replymp); +} + + +/****************************************************************************** +** 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 CardData* +AllocDriverData( struct PCIDevice * dev, + struct DriverBase* AHIsubBase ) +{ + struct CardBase* CardBase = (struct CardBase*) AHIsubBase; + struct CardData* dd; + UWORD command_word; + int i; + unsigned short uval; + + // FIXME: This should be non-cachable, DMA-able memory + dd = AllocVec( sizeof( *dd ), MEMF_PUBLIC | MEMF_CLEAR ); + + if( dd == NULL ) + { + Req( "Unable to allocate driver structure." ); + return NULL; + } + + dd->ahisubbase = AHIsubBase; + + dd->interrupt.is_Node.ln_Type = IRQTYPE; + dd->interrupt.is_Node.ln_Pri = 0; + dd->interrupt.is_Node.ln_Name = (STRPTR) LibName; + dd->interrupt.is_Code = (void(*)(void)) CardInterrupt; + dd->interrupt.is_Data = (APTR) dd; + + dd->playback_interrupt.is_Node.ln_Type = IRQTYPE; + dd->playback_interrupt.is_Node.ln_Pri = 0; + dd->playback_interrupt.is_Node.ln_Name = (STRPTR) LibName; + dd->playback_interrupt.is_Code = PlaybackInterrupt; + dd->playback_interrupt.is_Data = (APTR) dd; + + dd->record_interrupt.is_Node.ln_Type = IRQTYPE; + dd->record_interrupt.is_Node.ln_Pri = 0; + dd->record_interrupt.is_Node.ln_Name = (STRPTR) LibName; + dd->record_interrupt.is_Code = RecordInterrupt; + dd->record_interrupt.is_Data = (APTR) dd; + + dd->pci_dev = dev; + + outw_config(PCI_COMMAND, 0x00, dd->pci_dev); + //dev->WriteConfigLong( PCI_BASE_ADDRESS_0, 0xdc00 ); + + //SB- Configure IO, if required. Force IO into 16bit/ISA address space, since it + // apparently won't work in 32bit address range. Really ought to check this in + // Linux sometime... + unsigned long tula = ( inl_config(PCI_BASE_ADDRESS_0, dd->pci_dev) & 0xfffffffc ); + if( ( tula == 0 ) || ( tula & 0xffff0000 ) ) + { + outl_config(PCI_BASE_ADDRESS_0, IO_SGD, dd->pci_dev); + DBGL( "configured audio SGD IO base", IO_SGD ); + } + + tula = ( inl_config(PCI_BASE_ADDRESS_1, dd->pci_dev) & 0xfffffffc ); + if( ( tula == 0 ) || ( tula & 0xffff0000 ) ) + { + outl_config(PCI_BASE_ADDRESS_1, IO_FM, dd->pci_dev); + //DBGL( "configured audio FM IO base", IO_FM ); + } + + tula = ( inl_config(PCI_BASE_ADDRESS_2, dd->pci_dev) & 0xfffffffc ); + if( ( tula == 0 ) || ( tula & 0xffff0000 ) ) + { + outl_config(PCI_BASE_ADDRESS_2, IO_MIDI, dd->pci_dev); + //DBGL( "configured audio MIDI IO base", IO_MIDI ); + } + + outw_config(PCI_COMMAND, PCI_COMMAND_IO, dd->pci_dev); + + dd->pci_master_enabled = TRUE; + + dd->iobase = inl_config(PCI_BASE_ADDRESS_0, dd->pci_dev) & 0xfffffffe; + + dd->length = ~( ahi_pci_get_base_size(0, dd->pci_dev) & PCI_BASE_ADDRESS_IO_MASK ); + dd->irq = ahi_pci_get_irq(dev); + dd->chiprev = inb_config(PCI_REVISION_ID, dev); + dd->model = inw_config(PCI_SUBSYSTEM_ID, dev); + + dd->table.area = NULL; + dd->table.addr = NULL; + dd->table.bytes = 0; + dd->play_idx_table = NULL; + dd->rec_idx_table = NULL; + + /* Initialize chip */ + if( card_init( dd ) < 0 ) + { + DebugPrintF("Unable to initialize Card subsystem.\n"); + + FreeVec(dd); + return NULL; + } + + + ahi_pci_add_intserver(&dd->interrupt, dd->pci_dev); + dd->interrupt_added = TRUE; + + dd->card_initialized = TRUE; + dd->input = 0; + dd->output = 0; + dd->monitor_volume = Linear2MixerGain( 0x10000, &dd->monitor_volume_bits ); + dd->input_gain = Linear2RecordGain( 0x10000, &dd->input_gain_bits ); + dd->output_volume = Linear2MixerGain( 0x10000, &dd->output_volume_bits ); + SaveMixerState(dd); + + AddResetHandler(dd); + + return dd; +} + + +/****************************************************************************** +** DriverData deallocation **************************************************** +******************************************************************************/ + +// And this code used to be in _AHIsub_FreeAudio(). + +void +FreeDriverData( struct CardData* dd, + struct DriverBase* AHIsubBase ) +{ + if( dd != NULL ) + { + if( dd->pci_dev != NULL ) + { + if( dd->card_initialized ) + { + card_cleanup( dd ); + } + + if( dd->pci_master_enabled ) + { + UWORD cmd; + + cmd = inw_config(PCI_COMMAND, dd->pci_dev); + cmd &= ~( PCI_COMMAND_IO | PCI_COMMAND_MASTER ); + outw_config(PCI_COMMAND, cmd, dd->pci_dev); + } + } + + if( dd->reset_handler_added ) + { + RemResetCallback(&dd->reset_handler); + } + + if( dd->interrupt_added ) + { + ahi_pci_rem_intserver(&dd->interrupt, dd->pci_dev); + } + + FreeVec( dd ); + } +} + + +void channel_reset(struct CardData *card) +{ + struct PCIDevice *dev = (struct PCIDevice *) card->pci_dev; + + pci_outb(VIA_REG_CTRL_TERMINATE /*| VIA_REG_CTRL_RESET*/, VIA_REG_OFFSET_CONTROL, card); + pci_inb(VIA_REG_OFFSET_CONTROL, card); + udelay(50); + /* disable interrupts */ + pci_outb(0x00, VIA_REG_OFFSET_CONTROL, card); + /* clear interrupts */ + pci_outb(0x03, VIA_REG_OFFSET_STATUS, card); + pci_outb(0x00, VIA_REG_OFFSET_TYPE, card); /* for via686 */ + // pci_outl(0, VIA_REG_OFFSET_CURR_PTR, card); +} + +//reset/init ac97 codec. Returns false if the primary codec isn't found/ready. +BOOL ac97_reset( struct PCIDevice *via686b_audio) +{ + static const unsigned long reset_delay = 100; //link operation delay, should be some uS.. + static const unsigned long codec_timeout = 50; //codec ready timeout, about half a second... + + //cold reset.. + //SB- Set the link to a known initial configuration. + //SB- Note: The 'standard' ***x reset code is quite similar to this, except it + // de-asserts SYNC at this point, possibly in case the link/codec is + // in low power mode. We don't, because if we do, the dreaded half- + // rate problem occurs, with ~100% reliability (..interesting). + // It is a bit of a worry that the 'standard' reset code fails, but + // perhaps it is simply because we have a completely untouched link, + // whereas on any 686 based PC, the link was probably confugured + // already in the BIOS. + + outb_config(VIA_ACLINK_CTRL, + VIA_ACLINK_CTRL_ENABLE | VIA_ACLINK_CTRL_RESET, + via686b_audio); + MicroDelay( reset_delay ); + + //SB- Assert reset. + outb_config(VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_ENABLE, via686b_audio); + MicroDelay( reset_delay ); + + //SB- De-assert reset, enable VRA/PCM etc. + outb_config( VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_ENABLE | + VIA_ACLINK_CTRL_RESET | + VIA_ACLINK_CTRL_VRA | + VIA_ACLINK_CTRL_PCM, + via686b_audio); + MicroDelay( reset_delay ); + + //SB- Check primary codec... + unsigned long delay = codec_timeout; + while( delay-- ) + { + if(inb_config( VIA_ACLINK_STAT, via686b_audio) & VIA_ACLINK_C00_READY) + { + //DBG( "AC-Link reset ok." ); + return TRUE; + } + + MicroDelay( 10000 ); + } + + DBG( "AC-Link reset, primary codec not ready!" ); + return FALSE; +} + + + + +int card_init(struct CardData *card) +{ + struct PCIDevice *dev = (struct PCIDevice *) card->pci_dev; + unsigned short cod, uval; + unsigned char pval, byt; + long *ptr; + int teller = 0; + ULONG val; + struct PCIDevice *via686b_ACPI; + BOOL aclink = FALSE; + + +#ifdef __amigaos4__ + via686b_ACPI = IPCI->FindDeviceTags( FDT_VendorID, 0x1106, FDT_DeviceID, 0x3057, + FDT_Index, 0x00, + TAG_DONE ); +#else + via686b_ACPI = ahi_pci_find_device(0x1106, 0x3057, NULL); +#endif + + if (via686b_ACPI == NULL) // try device 0x3058 + { +#ifdef __amigaos4__ + via686b_ACPI = IPCI->FindDeviceTags( FDT_VendorID, 0x1106, FDT_DeviceID, 0x3058, + FDT_Index, 0x00, + TAG_DONE ); +#else + via686b_ACPI = ahi_pci_find_device(0x1106, 0x3058, NULL); +#endif + } + + if (via686b_ACPI) + { + BOOL lock; + +#ifdef __amigaos4__ + lock = via686b_ACPI->Lock( PCI_LOCK_SHARED ); + if (lock == FALSE) + { + DBG( "couldn't lock the ACPI! Trying anyway..." ); + } +#endif + + //SB- Configure power management, if it isn't already. + if( !( inl_config(0x48, via686b_ACPI) & 0xfffffffe ) ) + { + outl_config(0x48, IO_PWR_MANAGEMENT, via686b_ACPI); + DBGL( "configured power management IO", IO_PWR_MANAGEMENT ); + } + else + { + DBG("Power management IO already configured"); + } + + //SB- Enable IO (preserve other bits, but note that technically speaking + // we should also be clreaing PSON gating here (it's already cleared)) + outb_config( 0x41, (inb_config(0x41, via686b_ACPI) | 0x80), via686b_ACPI); + + //SB- Power up the 686b, if it isn't already. + if( !( inb_config(0x42, via686b_ACPI) & 0x40 ) ) + { + //Cause a soft resume event... + outb(inb(IO_PWR_MANAGEMENT + 0x05) | 0x80, IO_PWR_MANAGEMENT + 0x05 ); + + //Busy loop until the soft resume completes. + //We have a bail out counter, but no idea how long we should wait really. + //..1/10th of a second wasn't long enough + unsigned long delay = 25; //1/2 a second, or so + + while( --delay ) + { + if( ( inb_config( 0x42, via686b_ACPI) & 0x40)) + { + DBG( "powered up the 686b." ); + break; //SUSC# state + } + + Delay(1); + } + + if( delay == 0 ) + ERR( "soft resume timed out!" ); + } + else + { + DBG("VIA already powered up"); + } + +#ifdef __amigaos4__ + if (lock) + via686b_ACPI->Unlock(); + + IPCI->FreeDevice( via686b_ACPI ); +#endif + } + else + { + ERR( "couldn't find the ACPI!" ); + return -1; + } + + //SB- Don't know if there's a codec yet? +// codec_write(card, 0x2, 0x8000); +// codec_write(card, 0x4, 0x8000); + + //SB- Check codec.. + aclink = ( inb_config(VIA_ACLINK_STAT, dev) & VIA_ACLINK_C00_READY ); + + //SB- If no codec, reset. + //SB- Note: This is a possible source of trouble. It might be safer to reset + // every time. Only reason not to is 'pop' avoidance on soft reboot + // and in case UBoot did the reset. + if( !aclink ) + { + aclink = ac97_reset(dev); + } + else + { + //SB- Make sure VRA/PCM are enabled if we didn't use our own reset code. + + outb_config(VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_ENABLE |\ + VIA_ACLINK_CTRL_RESET |\ + VIA_ACLINK_CTRL_VRA |\ + VIA_ACLINK_CTRL_PCM, dev); + } + + if( aclink ) + { + //INF( "initialized AC'97 codec." ); + } + else + { + ERR( "sorry, you don't seem to have the AC'97 codec!" ); + return -1; + } + +/* + Delay( 1 ); + + + pval = inb_config(VIA_ACLINK_STAT, dev); + + if (! (pval & VIA_ACLINK_C00_READY)) + { + DebugPrintF("WHY?\n"); + pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, + VIA_ACLINK_CTRL_ENABLE | + VIA_ACLINK_CTRL_RESET | + VIA_ACLINK_CTRL_SYNC); + udelay(100); + + pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, 0x00); + udelay(100); + + pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_INIT); + udelay(100); + + pval = inb_config(VIA_ACLINK_STAT, dd->pci_dev); + + if (! (pval & VIA_ACLINK_C00_READY)) + { + return -1; + } + } + + while (teller < 1000) + { + pval = inb_config(VIA_ACLINK_STAT, dd->pci_dev); + if (pval & VIA_ACLINK_C00_READY) + break; + + udelay(20); + teller++; + } +*/ + + if ((val = pci_inl(VIA_CODEC_CMD, card)) & VIA_REG_AC97_BUSY) + snd_printk("AC97 codec is not ready!\n"); + + outb_config(VIA_FM_NMI_CTRL, 0, card->pci_dev); + pci_outl(0, VIA_REG_GPI_INTR, card); + + channel_reset(card); + + codec_write(card, AC97_MASTER_VOL_STEREO, 0x0000 ); // no attenuation + codec_write(card, AC97_AUXOUT_VOL, 0x8000 ); // volume of the rear output + codec_write(card, AC97_MASTER_VOL_MONO, 0x8000 ); + codec_write(card, AC97_MASTER_TONE, 0x0f0f ); // bass/treble control (if present) + codec_write(card, AC97_PCBEEP_VOL, 0x8000 ); // PC beep internal speaker? + + codec_write(card, AC97_RECORD_SELECT, 0); + codec_write(card, AC97_RECORD_GAIN, 0x0000 ); // 0 dB gain + + + // Analog mixer input gain registers + codec_write(card, AC97_PHONE_VOL, AC97_MUTE | 0x0008 ); + codec_write(card, AC97_MIC_VOL, AC97_MUTE | 0x0048 ); // 10 dB boost + 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 ); + + DBG("card_init() was a success!"); + + return 0; +} + + +void card_cleanup(struct CardData *card) +{ +} + + + +/****************************************************************************** +** Misc. ********************************************************************** +******************************************************************************/ + +void +SaveMixerState( struct CardData* dd ) +{ + dd->ac97_mic = codec_read( dd, AC97_MIC_VOL ); + dd->ac97_cd = codec_read( dd, AC97_CD_VOL ); + dd->ac97_video = codec_read( dd, AC97_VIDEO_VOL ); + dd->ac97_aux = codec_read( dd, AC97_AUX_VOL ); + dd->ac97_linein = codec_read( dd, AC97_LINEIN_VOL ); + dd->ac97_phone = codec_read( dd, AC97_PHONE_VOL ); +} + + +void +RestoreMixerState( struct CardData* dd ) +{ + codec_write(dd, AC97_MIC_VOL, dd->ac97_mic ); + codec_write(dd, AC97_CD_VOL, dd->ac97_cd ); + codec_write(dd, AC97_VIDEO_VOL, dd->ac97_video ); + codec_write(dd, AC97_AUX_VOL, dd->ac97_aux ); + codec_write(dd, AC97_LINEIN_VOL, dd->ac97_linein ); + codec_write(dd, AC97_PHONE_VOL, dd->ac97_phone ); +} + +void +UpdateMonitorMixer( struct CardData* dd ) +{ + int i = InputBits[ dd->input ]; + UWORD m = dd->monitor_volume_bits & 0x801f; + UWORD s = dd->monitor_volume_bits; + UWORD mm = AC97_MUTE | 0x0008; + UWORD sm = AC97_MUTE | 0x0808; + + if( i == AC97_RECMUX_STEREO_MIX || + i == AC97_RECMUX_MONO_MIX ) + { + // Use the original mixer settings + RestoreMixerState( dd ); + } + else + { + codec_write(dd, AC97_MIC_VOL, + i == AC97_RECMUX_MIC ? m : mm ); + + codec_write(dd, AC97_CD_VOL, + i == AC97_RECMUX_CD ? s : sm ); + + codec_write(dd, AC97_VIDEO_VOL, + i == AC97_RECMUX_VIDEO ? s : sm ); + + codec_write(dd, AC97_AUX_VOL, + i == AC97_RECMUX_AUX ? s : sm ); + + codec_write(dd, AC97_LINEIN_VOL, + i == AC97_RECMUX_LINE ? s : sm ); + + codec_write(dd, 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, // ±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; + } + +// KPrintF( "l2mg %08lx -> %08lx (%04lx)\n", linear, gain[ v ], *bits ); + 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, // ±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); +} + + +#define CACHELINE_SIZE 32 + +void *pci_alloc_consistent(size_t size, APTR *NonAlignedAddress) +{ + void* address; + unsigned long a; + +#ifdef __amigaos4__ + if (OpenResource("newmemory.resource")) + { + address = AllocVecTags(size, AVT_Type, MEMF_SHARED, AVT_Contiguous, TRUE, AVT_Lock, TRUE, + AVT_PhysicalAlignment, 32, AVT_Clear, 0, TAG_DONE); + } + else +#endif + { + address = AllocVec( size + CACHELINE_SIZE, MEMF_PUBLIC | MEMF_CLEAR); + + if( address != NULL ) + { + a = (unsigned long) address; + a = (a + CACHELINE_SIZE - 1) & ~(CACHELINE_SIZE - 1); + address = (void *) a; + } + } + + *NonAlignedAddress = address; + + return address; +} + + +void pci_free_consistent(void* addr) +{ + FreeVec( addr ); +} + + +#ifdef __amigaos4__ +static ULONG ResetHandler(struct ExceptionContext *ctx, struct ExecBase *pExecBase, struct CardData *card) +#else +static ULONG ResetHandler(struct CardData *card) +#endif +{ + struct PCIDevice *dev = card->pci_dev; + + unsigned char val = VIA_REG_CTRL_TERMINATE; + + pci_outb(val, VIA_REG_OFFSET_CONTROL, card); + pci_outb(val, VIA_REG_OFFSET_CONTROL + RECORD, card); + + channel_reset(card); + + return 0UL; +} + + +void AddResetHandler(struct CardData *card) +{ + struct Interrupt *handler = &card->reset_handler; + + handler->is_Code = (APTR)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 = "VIA-AC97 reset handler"; + + card->reset_handler_added = AddResetCallback(handler); +} + diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/misc.h b/workbench/devs/AHI/Drivers/VIA-AC97/misc.h new file mode 100644 index 0000000000..aa23d7c685 --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/misc.h @@ -0,0 +1,71 @@ +/* + Copyright © 2005-2013, Davy Wentzler. All rights reserved. + Copyright © 2010-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#ifndef AHI_Drivers_misc_h +#define AHI_Drivers_misc_h + +#include + +#include +#include +#include + + +#define udelay MicroDelay +#define snd_printk DebugPrintF +#ifdef __amigaos4__ +#define outl(a, b) dev->OutLong(b, a) +#define outb(a, b) dev->OutByte(b, a) +#endif + + +struct CardData* +AllocDriverData( struct PCIDevice* dev, + struct DriverBase* AHIsubBase ); + +void +FreeDriverData( struct CardData* dd, + struct DriverBase* AHIsubBase ); + +void +SaveMixerState( struct CardData* dd ); + +void +RestoreMixerState( struct CardData* dd ); + +void +UpdateMonitorMixer( struct CardData* dd ); + +Fixed +Linear2MixerGain( Fixed linear, + UWORD* bits ); + +Fixed +Linear2RecordGain( Fixed linear, + UWORD* bits ); + +ULONG +SamplerateToLinearPitch( ULONG samplingrate ); + +void *pci_alloc_consistent(size_t size, APTR *NonAlignedAddress); + +void pci_free_consistent(void* addr); + +void MicroDelay(unsigned int val); +void channel_reset(struct CardData *card); + +unsigned int codec_xread(struct CardData *card); +void codec_xwrite(struct CardData *card, unsigned int val); +int codec_ready(struct CardData *card); +int codec_valid(struct CardData *card); +void codec_wait(struct CardData *card); +void codec_write(struct CardData *card, unsigned short reg, unsigned short val); +unsigned short codec_read(struct CardData *card, unsigned char reg); + +BOOL ac97_read_reg(struct CardData *card, unsigned char reg, unsigned short *data ); + + +#endif /* AHI_Drivers_misc_h */ diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/pci_aros.c b/workbench/devs/AHI/Drivers/VIA-AC97/pci_aros.c new file mode 100644 index 0000000000..90169fa88f --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/pci_aros.c @@ -0,0 +1,453 @@ +/* + Copyright © 2004-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#define __OOP_NOATTRBASES__ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "DriverData.h" +#include "pci_wrapper.h" + +#include +#define KPrintF kprintf + +struct Library *OOPBase; + +static OOP_AttrBase __IHidd_PCIDev; +static OOP_Object *pciobj; + +static OOP_MethodID mid_RB; +static OOP_MethodID mid_RW; +static OOP_MethodID mid_RL; + +static OOP_MethodID mid_WB; +static OOP_MethodID mid_WW; +static OOP_MethodID mid_WL; + +static BOOL inthandler_added; + +BOOL ahi_pci_init(struct DriverBase* AHIsubBase) +{ + OOPBase = OpenLibrary(AROSOOP_NAME, 0); + if (OOPBase) + { + __IHidd_PCIDev = OOP_ObtainAttrBase(IID_Hidd_PCIDevice); + if (__IHidd_PCIDev) + { + pciobj = OOP_NewObject(NULL, CLID_Hidd_PCI, NULL); + + if (pciobj) + { + mid_RB = OOP_GetMethodID(IID_Hidd_PCIDevice, moHidd_PCIDevice_ReadConfigByte); + mid_RW = OOP_GetMethodID(IID_Hidd_PCIDevice, moHidd_PCIDevice_ReadConfigWord); + mid_RL = OOP_GetMethodID(IID_Hidd_PCIDevice, moHidd_PCIDevice_ReadConfigLong); + + mid_WB = OOP_GetMethodID(IID_Hidd_PCIDevice, moHidd_PCIDevice_WriteConfigByte); + mid_WW = OOP_GetMethodID(IID_Hidd_PCIDevice, moHidd_PCIDevice_WriteConfigWord); + mid_WL = OOP_GetMethodID(IID_Hidd_PCIDevice, moHidd_PCIDevice_WriteConfigLong); + + return TRUE; + } + } + } + + return FALSE; +} + +void ahi_pci_exit(void) +{ + if (pciobj) + OOP_DisposeObject(pciobj); + if (__IHidd_PCIDev) + OOP_ReleaseAttrBase(IID_Hidd_PCIDevice); + if (OOPBase) + CloseLibrary(OOPBase); +} + +struct enum_data +{ + OOP_Object *prev_dev; + OOP_Object *found_dev; +}; + +static AROS_UFH3(void, Enumerator, + AROS_UFHA(struct Hook *, hook, A0), + AROS_UFHA(OOP_Object *, device, A2), + AROS_UFHA(APTR, msg, A1)) +{ + AROS_USERFUNC_INIT + + struct enum_data *ed = (struct enum_data *)hook->h_Data; + + if ((ed->found_dev == 0) && (device != ed->prev_dev)) + { + ed->found_dev = device; + } + + AROS_USERFUNC_EXIT +} + + +APTR ahi_pci_find_device(ULONG vendorid, ULONG deviceid, APTR dev) +{ + struct enum_data ed; + + struct Hook FindHook = + { + h_Entry: (HOOKFUNC)Enumerator, + h_Data: &ed, + }; + + struct TagItem Reqs[] = + { +#if 0 + { tHidd_PCI_Class , 0x04 }, /* Multimedia */ + { tHidd_PCI_SubClass , 0x01 }, /* Audio */ +#endif + { tHidd_PCI_VendorID , vendorid }, + { tHidd_PCI_ProductID , deviceid }, + { TAG_DONE , 0 }, + }; + + struct pHidd_PCI_EnumDevices enummsg = + { + mID: OOP_GetMethodID(CLID_Hidd_PCI, moHidd_PCI_EnumDevices), + callback: &FindHook, + requirements: (struct TagItem *)&Reqs, + }, *msg = &enummsg; + + ed.prev_dev = (OOP_Object *)dev; + ed.found_dev = 0; + + OOP_DoMethod(pciobj, (OOP_Msg)msg); + + //KPrintF("ahi_pci_find_device: found_dev = %lx\n", ed.found_dev); + + return (APTR)ed.found_dev; +} + +ULONG pci_inl(ULONG addr, struct CardData *card) +{ + return LONGIN(card->iobase + addr); +} + +UWORD pci_inw(ULONG addr, struct CardData *card) +{ + return WORDIN(card->iobase + addr); +} + +UBYTE pci_inb(ULONG addr, struct CardData *card) +{ + return BYTEIN(card->iobase + addr); +} + +void pci_outl(ULONG value, ULONG addr, struct CardData *card) +{ + LONGOUT(card->iobase + addr, value); +} + +void pci_outw(UWORD value, ULONG addr, struct CardData *card) +{ + WORDOUT(card->iobase + addr, value); +} + +void pci_outb(UBYTE value, ULONG addr, struct CardData *card) +{ + BYTEOUT(card->iobase + addr, value); +} + +void outb_setbits(UBYTE value, ULONG addr, struct CardData *card) +{ + UBYTE data = pci_inb(addr, card); + data |= value; + + pci_outb(data, addr, card); +} + + +void outb_clearbits(UBYTE value, ULONG addr, struct CardData *card) +{ + UBYTE data = pci_inb(addr, card); + data &= ~value; + + pci_outb(data, addr, card); +} + + +void outw_setbits(UWORD value, ULONG addr, struct CardData *card) +{ + UWORD data = pci_inw(addr, card); + data |= value; + + pci_outw(data, addr, card); +} + + +void outw_clearbits(UWORD value, ULONG addr, struct CardData *card) +{ + UWORD data = pci_inw(addr, card); + data &= ~value; + + pci_outw(data, addr, card); +} + + +void outl_setbits(ULONG value, ULONG addr, struct CardData *card) +{ + ULONG data = pci_inl(addr, card); + data |= value; + + pci_outl(data, addr, card); +} + + +void outl_clearbits(ULONG value, ULONG addr, struct CardData *card) +{ + ULONG data = pci_inl(addr, card); + data &= ~value; + + pci_outl(data, addr, card); +} + + +ULONG inl_config(UBYTE reg, APTR dev) +{ + struct pHidd_PCIDevice_ReadConfigLong msg; + + msg.mID = mid_RL; + msg.reg = reg; + + return OOP_DoMethod((OOP_Object *)dev, (OOP_Msg)&msg); +} + +UWORD inw_config(UBYTE reg, APTR dev) +{ + struct pHidd_PCIDevice_ReadConfigWord msg; + + msg.mID = mid_RW; + msg.reg = reg; + + return OOP_DoMethod((OOP_Object *)dev, (OOP_Msg)&msg); +} + +UBYTE inb_config(UBYTE reg, APTR dev) +{ + struct pHidd_PCIDevice_ReadConfigByte msg; + + msg.mID = mid_RB; + msg.reg = reg; + + return OOP_DoMethod(dev, (OOP_Msg)&msg); +} + +void outl_config(UBYTE reg, ULONG val, APTR dev) +{ + struct pHidd_PCIDevice_WriteConfigLong msg; + + msg.mID = mid_WL; + msg.reg = reg; + msg.val = val; + + OOP_DoMethod((OOP_Object *)dev, (OOP_Msg)&msg); +} + +void outw_config(UBYTE reg, UWORD val, APTR dev) +{ + struct pHidd_PCIDevice_WriteConfigWord msg; + + msg.mID = mid_WW; + msg.reg = reg; + msg.val = val; + + OOP_DoMethod((OOP_Object *)dev, (OOP_Msg)&msg); +} + +void outb_config(UBYTE reg, UBYTE val, APTR dev) +{ + struct pHidd_PCIDevice_WriteConfigByte msg; + + msg.mID = mid_WB; + msg.reg = reg; + msg.val = val; + + OOP_DoMethod((OOP_Object *)dev, (OOP_Msg)&msg); +} + +ULONG ahi_pci_get_irq(APTR dev) +{ + IPTR val; + + OOP_GetAttr((OOP_Object *)dev, aHidd_PCIDevice_INTLine, &val); + + return (ULONG)val; +} + +BOOL ahi_pci_add_intserver(struct Interrupt *i, APTR dev) +{ + IPTR val; + + OOP_GetAttr((OOP_Object *)dev, aHidd_PCIDevice_INTLine, &val); + + AddIntServer(INTB_KERNEL + val, i); + + inthandler_added = TRUE; + + return TRUE; +} + +void ahi_pci_rem_intserver(struct Interrupt *i, APTR dev) +{ + if (inthandler_added) + { + IPTR val; + + OOP_GetAttr((OOP_Object *)dev, aHidd_PCIDevice_INTLine, &val); + + RemIntServer(INTB_KERNEL + val, i); + + inthandler_added = FALSE; + } + + KPrintF("ahi_pci_rem_intserver\n"); +} + + +APTR ahi_pci_get_base_address(WORD which, APTR dev) +{ + OOP_AttrID attr = 0; + IPTR val = 0; + + switch(which) + { + case 0: + attr = aHidd_PCIDevice_Base0; + break; + + case 1: + attr = aHidd_PCIDevice_Base1; + break; + + case 2: + attr = aHidd_PCIDevice_Base2; + break; + + case 3: + attr = aHidd_PCIDevice_Base3; + break; + + case 4: + attr = aHidd_PCIDevice_Base4; + break; + + case 5: + attr = aHidd_PCIDevice_Base5; + break; + + default: + return 0; + } + + OOP_GetAttr((OOP_Object *)dev, attr, &val); + + //KPrintF("ahi_pci_get_base_address. Result %lx\n", val); + + return (APTR)val; +} + +ULONG ahi_pci_get_base_size(WORD which, APTR dev) +{ + OOP_AttrID attr = 0; + IPTR val = 0; + + switch(which) + { + case 0: + attr = aHidd_PCIDevice_Size0; + break; + + case 1: + attr = aHidd_PCIDevice_Size1; + break; + + case 2: + attr = aHidd_PCIDevice_Size2; + break; + + case 3: + attr = aHidd_PCIDevice_Size3; + break; + + case 4: + attr = aHidd_PCIDevice_Size4; + break; + + case 5: + attr = aHidd_PCIDevice_Size5; + break; + + default: + return 0; + } + + OOP_GetAttr((OOP_Object *)dev, attr, &val); + + //KPrintF("ahi_pci_get_base_size. Result %lx\n", val); + + return (ULONG)val; + +} + + + +ULONG ahi_pci_get_type(WORD which, APTR dev) +{ + OOP_AttrID attr = 0; + IPTR val = 0; + + switch(which) + { + case 0: + attr = aHidd_PCIDevice_Type0; + break; + + case 1: + attr = aHidd_PCIDevice_Type1; + break; + + case 2: + attr = aHidd_PCIDevice_Type2; + break; + + case 3: + attr = aHidd_PCIDevice_Type3; + break; + + case 4: + attr = aHidd_PCIDevice_Type4; + break; + + case 5: + attr = aHidd_PCIDevice_Type5; + break; + + default: + return 0; + } + + OOP_GetAttr((OOP_Object *)dev, attr, &val); + + //KPrintF("ahi_pci_get_type. Result %lx\n", val); + + return (ULONG) val; +} diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/pci_wrapper.c b/workbench/devs/AHI/Drivers/VIA-AC97/pci_wrapper.c new file mode 100644 index 0000000000..4e8a8a5475 --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/pci_wrapper.c @@ -0,0 +1,15 @@ +/* + Copyright © 2004-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#include + +#if defined(__AROS__) +#include "pci_aros.c" +#elif defined(__AMIGAOS4__) +#include "pci_aos4.c" +#else +#include "pci_openpci.c" +#endif + diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/pci_wrapper.h b/workbench/devs/AHI/Drivers/VIA-AC97/pci_wrapper.h new file mode 100644 index 0000000000..40e77fa69c --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/pci_wrapper.h @@ -0,0 +1,124 @@ +/* + Copyright © 2004-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#ifndef PCI_WRAPPER_H +#define PCI_WRAPPER_H + +#ifndef EXEC_TYPES_H +# include +#endif + +#include "DriverData.h" + +#undef PCI_COMMAND +#undef PCI_COMMAND_IO +#undef PCI_COMMAND_MEMORY +#undef PCI_COMMAND_MASTER +#undef PCI_BASE_ADDRESS_IO_MASK +#undef PCI_REVISION_ID +#undef PCI_SUBSYSTEM_ID +#undef PCI_DEVICE_ID +#undef PCI_SUBSYSTEM_VENDOR_ID + + +#define PCI_COMMAND 4 +#define PCI_COMMAND_IO 1 +#define PCI_COMMAND_MEMORY 2 +#define PCI_COMMAND_MASTER 4 + +#define PCI_BASE_ADDRESS_0 0x10 +#define PCI_BASE_ADDRESS_1 0x14 +#define PCI_BASE_ADDRESS_2 0x18 + +#define PCI_BASE_ADDRESS_IO_MASK (~0x3UL) + +#define PCI_REVISION_ID 8 +#define PCI_SUBSYSTEM_ID 0x2e +#define PCI_DEVICE_ID 2 +#define PCI_SUBSYSTEM_VENDOR_ID 0x2c + +BOOL ahi_pci_init(struct DriverBase* AHIsubBase); +void ahi_pci_exit(void); + +APTR ahi_pci_find_device(ULONG vendorid, ULONG deviceid, APTR dev); + +ULONG pci_inl(ULONG addr, struct CardData *card); +UWORD pci_inw(ULONG addr, struct CardData *card); +UBYTE pci_inb(ULONG addr, struct CardData *card); + +void pci_outl(ULONG value, ULONG addr, struct CardData *card); +void pci_outw(UWORD value, ULONG addr, struct CardData *card); +void pci_outb(UBYTE value, ULONG addr, struct CardData *card); + +void outb_setbits(UBYTE value, ULONG addr, struct CardData *card); +void outw_setbits(UWORD value, ULONG addr, struct CardData *card); +void outl_setbits(ULONG value, ULONG addr, struct CardData *card); +void outb_clearbits(UBYTE value, ULONG addr, struct CardData *card); +void outw_clearbits(UWORD value, ULONG addr, struct CardData *card); +void outl_clearbits(ULONG value, ULONG addr, struct CardData *card); + +ULONG inl_config(UBYTE reg, APTR dev); +UWORD inw_config(UBYTE reg, APTR dev); +UBYTE inb_config(UBYTE reg, APTR dev); + +void outl_config(UBYTE reg, ULONG val, APTR dev); +void outw_config(UBYTE reg, UWORD val, APTR dev); +void outb_config(UBYTE reg, UBYTE val, APTR dev); + +ULONG ahi_pci_get_irq(APTR dev); + +BOOL ahi_pci_add_intserver(struct Interrupt *i, APTR dev); +void ahi_pci_rem_intserver(struct Interrupt *i, APTR dev); + +APTR ahi_pci_logic_to_physic_addr(APTR addr, APTR dev); + +APTR ahi_pci_get_base_address(WORD which, APTR dev); +ULONG ahi_pci_get_base_size(WORD which, APTR dev); +ULONG ahi_pci_get_type(WORD which, APTR dev); +ULONG ahi_pci_mem_map(APTR addr, APTR dev); + +#ifdef __AMIGAOS4__ +#define ALLOCVEC AllocVec +#define FREEVEC FreeVec +#define DEBUGPRINTF IExec->DebugPrintF +#define CAUSE Cause +#define CALLHOOK CallHookPkt +#define INITSEMAPHORE InitSemaphore +#define OBTAINSEMAPHORE ObtainSemaphore +#define RELEASESEMAPHORE ReleaseSemaphore +#define CREATEPORT(a, b) CreatePort(a, b) +#define CREATEIOREQUEST CreateIORequest +#define OPENDEVICE OpenDevice +#define DOIO DoIO +#define DELETEIOREQUEST DeleteIORequest +#define CLOSEDEVICE IExec->CloseDevice +#define DELETEPORT IExec->DeletePort +#define GETTAGDATA IUtility->GetTagData +#define IRQTYPE INTERRUPT_NODE_TYPE +#define DELAY IDOS->Delay +#define bug DebugPrintF +#else +#include +#define ALLOCVEC AllocVec +#define FREEVEC FreeVec +#define DEBUGPRINTF kprintf +#define CAUSE Cause +#define CALLHOOK CallHookA +#define INITSEMAPHORE InitSemaphore +#define OBTAINSEMAPHORE ObtainSemaphore +#define RELEASESEMAPHORE ReleaseSemaphore +#define CREATEPORT(a, b) CreateMsgPort() +#define CREATEIOREQUEST CreateIORequest +#define OPENDEVICE OpenDevice +#define DOIO DoIO +#define DELETEIOREQUEST DeleteIORequest +#define CLOSEDEVICE CloseDevice +#define DELETEPORT DeleteMsgPort +#define GETTAGDATA GetTagData +#define IRQTYPE INTERRUPT_NODE_TYPE +#define DELAY Delay +#endif + +#endif diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/regs.h b/workbench/devs/AHI/Drivers/VIA-AC97/regs.h new file mode 100644 index 0000000000..4144418b04 --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/regs.h @@ -0,0 +1,72 @@ +/* + Copyright © 2005-2013, Davy Wentzler. All rights reserved. + Copyright © 2010-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#ifndef _REGS_H +#define _REGS_H + + +#define VIA_CODEC_CMD 0x80 +#define VIA_CODEC_CMD_READ (1L << 23) +#define VIA_CODEC_CMD_VALID (1L << 25) +#define VIA_CODEC_CMD_BUSY (1L << 24) + +#define PAGE_SIZE 65536 + + +#define AC97_RESET 0x0000 + +// Play master volume registers +#define AC97_MASTER_VOL_STEREO 0x0002 // -94.5 to 0.0 dB attenuation +#define AC97_AUXOUT_VOL 0x0004 // "" + can be impl. as line level out, headphone out or 4ch out. Most likely 4ch out vol. +#define AC97_MASTER_VOL_MONO 0x0006 // "" + +#define AC97_MASTER_TONE 0x0008 // bass / treble +#define AC97_PCBEEP_VOL 0x000a + +// Analog mixer input gain registers +// 5-bit gain: -32.5 dB attenuation to +12.0 dB gain +// 0x0008 is 0dB gain, 0x8008 is 0dB gain with mute on +#define AC97_PHONE_VOL 0x000c // mono: only bits 0-4 +#define AC97_MIC_VOL 0x000e // mono + bit 6 is 20dB boost switch +#define AC97_LINEIN_VOL 0x0010 // stereo +#define AC97_CD_VOL 0x0012 +#define AC97_VIDEO_VOL 0x0014 +#define AC97_AUX_VOL 0x0016 +#define AC97_PCMOUT_VOL 0x0018 + +#define AC97_RECORD_SELECT 0x001a +// 0dB to 22.5 dB gain on the stereo input +#define AC97_RECORD_GAIN 0x001c +#define AC97_RECORD_GAIN_MIC 0x001e + +#define AC97_GENERAL_PURPOSE 0x0020 +#define AC97_3D_CONTROL 0x0022 + +// mostly a read-only register (except D5 and D4 which control optional DAC slot assignment) +// controls variable SRC, double-rate output, multi-channel output and S/PDIF output +#define AC97_EXTENDED_ID 0x0028 +#define AC97_EXTENDED_CTRL 0x002a + +#define AC97_SPDIF_CTRL 0x003a + +#define AC97_SURROUND_MASTER 0x0038 + +#define AC97_VENDOR_ID0 0x007C +#define AC97_VENDOR_ID1 0x007E + +#define AC97_MUTE 0x8000 + +#define AC97_RECMUX_MIC 0x0000 +#define AC97_RECMUX_CD 0x0101 +#define AC97_RECMUX_VIDEO 0x0202 +#define AC97_RECMUX_AUX 0x0303 +#define AC97_RECMUX_LINE 0x0404 +#define AC97_RECMUX_STEREO_MIX 0x0505 +#define AC97_RECMUX_MONO_MIX 0x0606 +#define AC97_RECMUX_PHONE 0x0707 + + +#endif /* _REGS_H */ diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/version.date b/workbench/devs/AHI/Drivers/VIA-AC97/version.date new file mode 100644 index 0000000000..0517427810 --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/version.date @@ -0,0 +1 @@ +25.2.2013 diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/version.rev b/workbench/devs/AHI/Drivers/VIA-AC97/version.rev new file mode 100644 index 0000000000..f599e28b8a --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/version.rev @@ -0,0 +1 @@ +10 diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/version.ver b/workbench/devs/AHI/Drivers/VIA-AC97/version.ver new file mode 100644 index 0000000000..7ed6ff82de --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/version.ver @@ -0,0 +1 @@ +5 diff --git a/workbench/devs/AHI/Drivers/VIA-AC97/via.c b/workbench/devs/AHI/Drivers/VIA-AC97/via.c new file mode 100644 index 0000000000..1c26f2ccbd --- /dev/null +++ b/workbench/devs/AHI/Drivers/VIA-AC97/via.c @@ -0,0 +1,956 @@ +/* + Copyright © 2005-2013, Davy Wentzler. All rights reserved. + Copyright © 2010-2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#include + +#undef __USE_INLINE__ +#include +#ifdef __amigaos4__ +extern struct UtilityIFace* IUtility; +extern struct AHIsubIFace* IAHIsub; +extern struct MMUIFace* IMMU; +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "library.h" +#include "regs.h" +#include "misc.h" +#include "pci_wrapper.h" + +#ifdef __AROS__ +#include +#define DebugPrintF bug +#endif + +/****************************************************************************** +** Globals ******************************************************************** +******************************************************************************/ + +#define FREQUENCIES 11 + +static const ULONG Frequencies[ FREQUENCIES ] = +{ + 5500, + 8000, // µ- and A-Law + 9600, + 11025, // CD/4 + 16000, // DAT/3 + 19200, + 22050, // CD/2 + 32000, // DAT/1.5 + 38400, + 44100, // CD + 48000 // DAT +}; + +#define INPUTS 8 + +static const STRPTR Inputs[ INPUTS ] = +{ + "Line in", + "Mic", + "CD", + "Video", + "Aux", + "Mixer", + "Mixer (mono)", + "Phone" +}; + +/* 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 +}; + + +#define OUTPUTS 1 + + +BOOL ac97_wait_idle2(struct CardData *card); + +static const STRPTR Outputs[ OUTPUTS ] = +{ + "Line", +}; + +inline unsigned int codec_xread(struct CardData *card) +{ + return pci_inl(VIA_REG_AC97, card); +} + + +inline void codec_xwrite(struct CardData *card, unsigned int val) +{ + pci_outl(val, VIA_REG_AC97, card); +} + +int codec_ready(struct CardData *card) +{ + unsigned int timeout = 100; /* 1ms */ + unsigned int val; + + while ( --timeout ) + { + val = codec_xread(card); + if (! (val & VIA_REG_AC97_BUSY)) + return val & 0xffff; + udelay( 1000 ); + } + + snd_printk("(codec_ready()) AC97 codec not ready!\n"); + return -1; +} + +int codec_valid(struct CardData *card) +{ + unsigned int timeout = 1000; /* 1ms */ + unsigned int val, val1; + unsigned int stat = VIA_REG_AC97_PRIMARY_VALID; + + while (timeout-- > 0) { + val = codec_xread(card); + val1 = val & (VIA_REG_AC97_BUSY | stat); + if (val1 == stat) + return val & 0xffff; + udelay(1); + } + return -1; +} + +void codec_wait(struct CardData *card) +{ + int err; + err = codec_ready(card); + udelay(500); +} + +void codec_write(struct CardData *card, + unsigned short reg, + unsigned short val) +{ + unsigned int xval; + + xval = VIA_REG_AC97_CODEC_ID_PRIMARY; + xval <<= VIA_REG_AC97_CODEC_ID_SHIFT; + xval |= reg << VIA_REG_AC97_CMD_SHIFT; + xval |= val << VIA_REG_AC97_DATA_SHIFT; + codec_ready(card); + codec_xwrite(card, xval); + codec_ready(card); +} + + +BOOL ac97_wait_idle(struct CardData *card) +{ + unsigned long tul = 0; + int cnt = 10000; + unsigned long iobase = 0; + struct PCIDevice *dev = card->pci_dev; + + while( --cnt ) + { + if( !( ( tul = pci_inl(VIA_REG_AC97, card )) & VIA_REG_AC97_BUSY ) ) + return TRUE; + MicroDelay(100); + } + + DebugPrintF("Timed out waiting for AC97 controller!\n"); + return FALSE; +} + +unsigned short codec_read(struct CardData *card, unsigned char reg) +{ + unsigned long xval; + unsigned short data; + int again = 0; + + xval = 0; + xval |= VIA_REG_AC97_PRIMARY_VALID; + xval |= VIA_REG_AC97_READ; + xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT; + + ac97_wait_idle2(card); + codec_xwrite(card, xval); + + ac97_wait_idle2(card); + xval = codec_xread(card); + + data = (xval & 0xFFFF); + + if ( !( xval & VIA_REG_AC97_PRIMARY_VALID) ) + { + DebugPrintF("Codec read failed!\n"); + } + + return data; +} + + +//IO base 0 registers +static const unsigned char VIA_AC97_RX = 0x80; //ac97 register +static const unsigned long VIA_AC97_RX_PRIMARY_ID = 0x00; //primamry codec ID (RW) +static const unsigned long VIA_AC97_RX_SECODARY_ID = 0x40000000; //secondary codec ID (RW) +static const unsigned long VIA_AC97_RX_SECODARY_VALID = 0x08000000; //secondary valid data/status/index (RWC) +static const unsigned long VIA_AC97_RX_PRIMARY_VALID = 0x02000000; //primary valid data etc. (RWC) +static const unsigned long VIA_AC97_RX_BUSY = 0x01000000; //controller busy (R) +static const unsigned long VIA_AC97_RX_READ = 0x00800000; //read/write select (RW) + +static const unsigned char VIA_AC97_RX_SHIFT = 0x10; //register shift +static const unsigned long VIA_AC97_RX_DATA_MASK = 0xffff; //data mask + +BOOL ac97_wait_idle2(struct CardData *card) +{ + struct PCIDevice *dev = card->pci_dev; + unsigned long tul = 0; + int cnt = 26; //..about half a second, for no good reason + unsigned long iobase = card->iobase; + + while( --cnt ) + { + if( !( ( tul = pci_inl(VIA_AC97_RX, card) ) & VIA_AC97_RX_BUSY ) ) + return TRUE; + MicroDelay(1000); + } + + DebugPrintF("Timed out waiting for AC97 controller! VIA_AC97_RX = %lx\n", tul); + return FALSE; +} + + +//note: this only reads the primary codec +BOOL ac97_read_reg(struct CardData *card, unsigned char reg, unsigned short *data ) +{ + struct PCIDevice *dev = card->pci_dev; + unsigned long iobase = card->iobase; + //set up with required codec register, read mode, and clear the primary codec valid flag + unsigned long tul = ( ( reg << VIA_AC97_RX_SHIFT ) | VIA_AC97_RX_READ | VIA_AC97_RX_PRIMARY_VALID ); + + //wait for the controller to become free, and write the command + ac97_wait_idle2(card); + pci_outl(tul, VIA_AC97_RX, card); + + //wait for the controller to become free, and read the result + ac97_wait_idle2(card); + tul = pci_inl(VIA_AC97_RX, card); + *data = ( tul & VIA_AC97_RX_DATA_MASK ); + + //complain if the data/register etc. is invalid... + if( !( tul & VIA_AC97_RX_PRIMARY_VALID ) ) + { + DebugPrintF("Info: (ac97_read_reg) Primary codec operation failed!\n"); + return( FALSE ); + } + + return( TRUE ); +} + + + + + + +static void set_table_ptr(struct CardData *card, BOOL Play) +{ + struct PCIDevice *dev = card->pci_dev; + ULONG phys_addr; +#ifdef __amigaos4__ + APTR stack; +#endif + + codec_ready(card); + if (Play) + { +#ifdef __amigaos4__ + stack = IExec->SuperState(); + phys_addr = IMMU->GetPhysicalAddress(card->play_idx_table); + IExec->UserState(stack); +#else + phys_addr = (ULONG)card->play_idx_table; +#endif + + pci_outl(phys_addr, 4, card); + } + else + { +#ifdef __amigaos4__ + stack = IExec->SuperState(); + phys_addr = IMMU->GetPhysicalAddress(card->rec_idx_table); + IExec->UserState(stack); +#else + phys_addr = (ULONG)card->rec_idx_table; +#endif + + pci_outl(phys_addr, 4 + RECORD, card); + } + + udelay(20); + codec_ready(card); +} + + + +#ifdef __amigaos4__ +#define tolittle(a) ((((ULONG) (a) & 0xFF000000) >> 24) | \ + (((ULONG) (a) & 0x00FF0000) >> 8) | \ + (((ULONG) (a) & 0x0000FF00) << 8) | \ + (((ULONG) (a) & 0x000000FF) << 24)) +#else +#define tolittle(a) AROS_LONG2LE(a) +#endif + +static int build_via_table(struct CardData *card, APTR sgbuf1, APTR sgbuf2, int OneBufferSize, struct snd_via_sg_table **idx, + APTR *idx_nonaligned) +{ + struct PCIDevice *dev = card->pci_dev; + int i; + ULONG phys_addr; +#ifdef __amigaos4__ + APTR stack; +#endif + + *idx = pci_alloc_consistent(sizeof(**idx) * 4, idx_nonaligned); + +#ifdef __amigaos4__ + stack = IExec->SuperState(); + phys_addr = IMMU->GetPhysicalAddress(sgbuf1); + IExec->UserState(stack); +#else + phys_addr = (ULONG)sgbuf1; +#endif + + (*idx)[0].offset = (APTR) tolittle(phys_addr); + (*idx)[0].size = tolittle( (OneBufferSize) | VIA_TBL_BIT_FLAG); + +#ifdef __amigaos4__ + stack = IExec->SuperState(); + phys_addr = IMMU->GetPhysicalAddress(sgbuf2); + IExec->UserState(stack); +#else + phys_addr = (ULONG)sgbuf2; +#endif + + (*idx)[1].offset = (APTR) tolittle(phys_addr); + (*idx)[1].size = tolittle( (OneBufferSize) | VIA_TBL_BIT_EOL ); + + CacheClearE(*idx, sizeof(**idx) * 4, CACRF_ClearD); + //DebugPrintF("===> play_idx_table at %lx, %lx\n", *idx, *idx_nonaligned); + + return 0; +} + + +/****************************************************************************** +** AHIsub_AllocAudio ********************************************************** +******************************************************************************/ + +ULONG +_AHIsub_AllocAudio( struct TagItem* taglist, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CardBase* CardBase = (struct CardBase*) AHIsubBase; + + int card_num; + ULONG ret; + int i, freq = 9; + + + + card_num = (GetTagData( AHIDB_AudioID, 0, taglist) & 0x0000f000 ) >> 12; + + if( card_num >= CardBase->cards_found || + CardBase->driverdatas[ card_num ] == NULL ) + { + DebugPrintF("no date for card = %ld\n", card_num); + Req( "No CardData for card %ld.", card_num ); + return AHISF_ERROR; + } + else + { + BOOL in_use; + struct PCIDevice *dev; + struct CardData *card; + unsigned short uval; + + card = CardBase->driverdatas[ card_num ]; + AudioCtrl->ahiac_DriverData = card; + + ObtainSemaphore( &CardBase->semaphore ); + in_use = ( card->audioctrl != NULL ); + if( !in_use ) + { + card->audioctrl = AudioCtrl; + } + ReleaseSemaphore( &CardBase->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 CardBase* CardBase = (struct CardBase*) AHIsubBase; + struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData; + + if( card != NULL ) + { + ObtainSemaphore( &CardBase->semaphore ); + if( card->audioctrl == AudioCtrl ) + { + // Release it if we own it. + card->audioctrl = NULL; + } + ReleaseSemaphore( &CardBase->semaphore ); + + AudioCtrl->ahiac_DriverData = NULL; + } +} + + +/****************************************************************************** +** AHIsub_Disable ************************************************************* +******************************************************************************/ + +void +_AHIsub_Disable( struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CardBase* CardBase = (struct CardBase*) AHIsubBase; + + // V6 drivers do not have to preserve all registers + + Disable(); +} + + +/****************************************************************************** +** AHIsub_Enable ************************************************************** +******************************************************************************/ + +void +_AHIsub_Enable( struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CardBase* CardBase = (struct CardBase*) AHIsubBase; + + // V6 drivers do not have to preserve all registers + + Enable(); +} + + +/****************************************************************************** +** AHIsub_Start *************************************************************** +******************************************************************************/ + +ULONG +_AHIsub_Start( ULONG flags, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CardBase* CardBase = (struct CardBase*) AHIsubBase; + struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData; + UWORD PlayCtrlFlags = 0, RecCtrlFlags = 0; + ULONG dma_buffer_size = 0; + int i, freqbit = 9; + unsigned short uval; + + //channel_reset(card); + codec_write(card, 0x2, 0); + codec_write(card, 0x08, 0x0F0F); + codec_write(card, 0x0A, 0x8000); + codec_write(card, 0x18, 0x0808); + + uval = codec_read(card, 0x2A); + codec_write(card, 0x2A, uval | 0x1); // enable VRA + codec_write(card, 0x2C, AudioCtrl->ahiac_MixFreq); + + + if( flags & AHISF_PLAY ) + { + + ULONG dma_sample_frame_size; + int i; + short *a; + unsigned short cod, ChannelsFlag = 0; + + 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; + } + else + { + dma_sample_frame_size = 2; + dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size; + } + + //DebugPrintF("dma_buffer_size = %ld, %lx\n", dma_buffer_size, dma_buffer_size); + + card->playback_buffer1 = pci_alloc_consistent(dma_buffer_size, &card->playback_buffer1_nonaligned); + card->playback_buffer2 = pci_alloc_consistent(dma_buffer_size, &card->playback_buffer2_nonaligned); + + if (!card->playback_buffer1) + { + Req( "Unable to allocate playback buffer." ); + return AHIE_NOMEM; + } + + CacheClearE(card->playback_buffer1, dma_buffer_size, CACRF_ClearD); + CacheClearE(card->playback_buffer2, dma_buffer_size, CACRF_ClearD); + + card->current_bytesize = dma_buffer_size; + card->current_frames = AudioCtrl->ahiac_MaxBuffSamples; + card->current_buffer = card->playback_buffer1; + card->playback_interrupt_enabled = TRUE; + + build_via_table(card, card->playback_buffer1, card->playback_buffer2, dma_buffer_size, &card->play_idx_table, &card->play_idx_table_nonaligned); + set_table_ptr(card, TRUE); + + pci_outb(VIA_REG_TYPE_AUTOSTART | 0x40 | + VIA_REG_TYPE_16BIT | + VIA_REG_TYPE_STEREO | + VIA_REG_TYPE_INT_LSAMPLE | + VIA_REG_TYPE_INT_EOL | + VIA_REG_TYPE_INT_FLAG, + VIA_REG_OFFSET_TYPE, card); + + card->flip = 0; + + card->is_playing = TRUE; + } + + if( flags & AHISF_RECORD ) + { + UWORD mask; + + card->current_record_bytesize = RECORD_BUFFER_SAMPLES * 4; + + /* Allocate a new recording buffer (page aligned!) */ + card->record_buffer1 = pci_alloc_consistent(card->current_record_bytesize, &card->record_buffer1_nonaligned); + card->record_buffer2 = pci_alloc_consistent(card->current_record_bytesize, &card->record_buffer2_nonaligned); + + if( card->record_buffer1 == NULL ) + { + Req( "Unable to allocate %ld bytes for the recording buffer.", card->current_record_bytesize); + return AHIE_NOMEM; + } + + SaveMixerState( card ); + UpdateMonitorMixer( card ); + + card->record_interrupt_enabled = TRUE; + + card->recflip = 0; + + build_via_table(card, card->record_buffer1, card->record_buffer2, card->current_record_bytesize, &card->rec_idx_table, &card->rec_idx_table_nonaligned); + set_table_ptr(card, FALSE); + + pci_outb(VIA_REG_TYPE_AUTOSTART | 0x40 | + VIA_REG_TYPE_16BIT | + VIA_REG_TYPE_STEREO | + VIA_REG_TYPE_INT_EOL | + VIA_REG_TYPE_INT_FLAG, + VIA_REG_OFFSET_TYPE + RECORD, + card); + + card->is_recording = TRUE; + card->current_record_buffer = card->record_buffer1; + + } + + if( flags & AHISF_PLAY ) + { + unsigned char val; + + val = VIA_REG_CTRL_START; + pci_outb(val, VIA_REG_OFFSET_CONTROL, card); + } + + if( flags & AHISF_RECORD ) + { + unsigned char val; + + val = VIA_REG_CTRL_START; + pci_outb(val, VIA_REG_OFFSET_CONTROL + RECORD, card); + } + + return AHIE_OK; +} + + +/****************************************************************************** +** AHIsub_Update ************************************************************** +******************************************************************************/ + +void +_AHIsub_Update( ULONG flags, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CardBase* CardBase = (struct CardBase*) AHIsubBase; + struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData; + + 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; + } +} + + +/****************************************************************************** +** AHIsub_Stop **************************************************************** +******************************************************************************/ + +void +_AHIsub_Stop( ULONG flags, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CardBase* CardBase = (struct CardBase*) AHIsubBase; + struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData; + struct PCIDevice *dev = card->pci_dev; + + unsigned char val; + + val = VIA_REG_CTRL_TERMINATE; + + if( flags & AHISF_PLAY && card->is_playing) + { + pci_outb(val, VIA_REG_OFFSET_CONTROL, card); + card->is_playing= FALSE; + + if (card->current_bytesize > 0) + { + pci_free_consistent(card->playback_buffer1); + pci_free_consistent(card->playback_buffer2); + } + + 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; + + if (card->play_idx_table_nonaligned) + { + FreeVec(card->play_idx_table_nonaligned); + } + card->play_idx_table = NULL; + } + + if( flags & AHISF_RECORD && card->is_recording) + { + unsigned short rec_ctl; + + pci_outb(val, VIA_REG_OFFSET_CONTROL + RECORD, card); + if( card->is_recording ) + { + // Do not restore mixer unless they have been saved + RestoreMixerState( card ); + } + + if( card->record_buffer1 != NULL ) + { + pci_free_consistent( card->record_buffer1); + pci_free_consistent( card->record_buffer2); + } + + card->record_buffer1 = NULL; + card->record_buffer2 = NULL; + card->current_record_bytesize = 0; + + card->is_recording = FALSE; + card->record_interrupt_enabled = FALSE; + + pci_free_consistent(card->rec_idx_table_nonaligned); + card->rec_idx_table = NULL; + + } + + card->current_bytesize = 0; +} + + +/****************************************************************************** +** AHIsub_GetAttr ************************************************************* +******************************************************************************/ + +SIPTR +_AHIsub_GetAttr( ULONG attribute, + LONG argument, + LONG def, + struct TagItem* taglist, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CardBase* CardBase = (struct CardBase*) AHIsubBase; + int i; + + + switch( attribute ) + { + case AHIDB_Bits: + return 16; + + case AHIDB_Frequencies: + return FREQUENCIES; + + case AHIDB_Frequency: // Index->Frequency + return (SIPTR) 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 (SIPTR) "Davy Wentzler"; + + case AHIDB_Copyright: + return (SIPTR) "(C) Davy Wentzler"; + + case AHIDB_Version: + return (SIPTR) LibIDString; + + case AHIDB_Annotation: + return (SIPTR) + "VIA VT82C686 AC97 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 0x40000; + + case AHIDB_MinInputGain: + return 0x10000; // 0.0 dB gain + + case AHIDB_MaxInputGain: + return 0xD55D0; // 22.5 dB gain + + case AHIDB_MinOutputVolume: + return 0x00000; // -96 dB + + case AHIDB_MaxOutputVolume: + return 0x10000; // 0 dB + + case AHIDB_Inputs: + return INPUTS; + + case AHIDB_Input: + return (SIPTR) Inputs[ argument ]; + + case AHIDB_Outputs: + return OUTPUTS; + + case AHIDB_Output: + return (SIPTR) Outputs[ argument ]; + + default: + return def; + } +} + + +/****************************************************************************** +** AHIsub_HardwareControl ***************************************************** +******************************************************************************/ + +ULONG +_AHIsub_HardwareControl( ULONG attribute, + LONG argument, + struct AHIAudioCtrlDrv* AudioCtrl, + struct DriverBase* AHIsubBase ) +{ + struct CardBase* CardBase = (struct CardBase*) AHIsubBase; + struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData; + + switch( attribute ) + { + case AHIC_MonitorVolume: + card->monitor_volume = Linear2MixerGain( (Fixed) argument, &card->monitor_volume_bits ); + 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: + card->output_volume = Linear2MixerGain( (Fixed) argument, &card->output_volume_bits ); + codec_write(card, AC97_PCMOUT_VOL, card->output_volume_bits ); + return TRUE; + + case AHIC_OutputVolume_Query: + return card->output_volume; + + case AHIC_Input: + card->input = argument; + codec_write(card, AC97_RECORD_SELECT, InputBits[ card->input ] ); + + if( card->is_recording ) + { + UpdateMonitorMixer( card ); + } + + return TRUE; + + case AHIC_Input_Query: + return card->input; + + case AHIC_Output: + card->output = argument; + + return TRUE; + + case AHIC_Output_Query: + return card->output; + + default: + return FALSE; + } +} diff --git a/workbench/devs/AHI/configure b/workbench/devs/AHI/configure index 2c314a606a..c95b8c1ae2 100755 --- a/workbench/devs/AHI/configure +++ b/workbench/devs/AHI/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 39984 . +# From configure.in Revision: 40898 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.68. # @@ -5212,7 +5212,7 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h -ac_config_files="$ac_config_files Makefile AHI/Makefile AHI-Handler/Makefile AddAudioModes/Makefile Device/Makefile Docs/Makefile Drivers/Makefile Drivers/ac97/Makefile Drivers/HDAudio/Makefile Drivers/CMI8738/Makefile Drivers/SB128/Makefile Drivers/AROS/Makefile Drivers/Common/Makefile.common Drivers/Device/Makefile Drivers/EMU10kx/Makefile Drivers/Filesave/Makefile Drivers/Void/Makefile Examples/Makefile Examples/Device/PlayTest/Makefile Examples/Extras/CloneAudioModes/Makefile Examples/Low-level/PlaySineEverywhere/Makefile Examples/Low-level/Test-7.1/Makefile Examples/Low-level/ScanAudioModes/Makefile Include/Makefile" +ac_config_files="$ac_config_files Makefile AHI/Makefile AHI-Handler/Makefile AddAudioModes/Makefile Device/Makefile Docs/Makefile Drivers/Makefile Drivers/ac97/Makefile Drivers/VIA-AC97/Makefile Drivers/HDAudio/Makefile Drivers/CMI8738/Makefile Drivers/SB128/Makefile Drivers/AROS/Makefile Drivers/Common/Makefile.common Drivers/Device/Makefile Drivers/EMU10kx/Makefile Drivers/Filesave/Makefile Drivers/Void/Makefile Examples/Makefile Examples/Device/PlayTest/Makefile Examples/Extras/CloneAudioModes/Makefile Examples/Low-level/PlaySineEverywhere/Makefile Examples/Low-level/Test-7.1/Makefile Examples/Low-level/ScanAudioModes/Makefile Include/Makefile" ac_config_commands="$ac_config_commands default" @@ -5932,6 +5932,7 @@ do "Docs/Makefile") CONFIG_FILES="$CONFIG_FILES Docs/Makefile" ;; "Drivers/Makefile") CONFIG_FILES="$CONFIG_FILES Drivers/Makefile" ;; "Drivers/ac97/Makefile") CONFIG_FILES="$CONFIG_FILES Drivers/ac97/Makefile" ;; + "Drivers/VIA-AC97/Makefile") CONFIG_FILES="$CONFIG_FILES Drivers/VIA-AC97/Makefile" ;; "Drivers/HDAudio/Makefile") CONFIG_FILES="$CONFIG_FILES Drivers/HDAudio/Makefile" ;; "Drivers/CMI8738/Makefile") CONFIG_FILES="$CONFIG_FILES Drivers/CMI8738/Makefile" ;; "Drivers/SB128/Makefile") CONFIG_FILES="$CONFIG_FILES Drivers/SB128/Makefile" ;; diff --git a/workbench/devs/AHI/configure.in b/workbench/devs/AHI/configure.in index 5449a18ef1..74d1e82416 100755 --- a/workbench/devs/AHI/configure.in +++ b/workbench/devs/AHI/configure.in @@ -200,9 +200,10 @@ AC_OUTPUT(Makefile Docs/Makefile Drivers/Makefile Drivers/ac97/Makefile + Drivers/VIA-AC97/Makefile Drivers/HDAudio/Makefile Drivers/CMI8738/Makefile - Drivers/SB128/Makefile + Drivers/SB128/Makefile Drivers/AROS/Makefile Drivers/Common/Makefile.common Drivers/Device/Makefile -- 2.11.4.GIT