--- /dev/null
+#include "AC97.h"
+
+
+
+
+
+/* AC97 Mixer and Mode control function prototypes */
+
+FORWARD _PROTOTYPE( int AC97_read,
+ (DEV_STRUCT * pCC, u16_t wAddr, u16_t *data) );
+FORWARD _PROTOTYPE( int AC97_write,
+ (DEV_STRUCT * pCC, u16_t wAddr, u16_t wData) );
+FORWARD _PROTOTYPE( void set_src_sync_state, (int state) );
+FORWARD _PROTOTYPE( int AC97_write_unsynced,
+ (DEV_STRUCT * pCC, u16_t wAddr, u16_t wData) );
+FORWARD _PROTOTYPE( int AC97_read_unsynced,
+ (DEV_STRUCT * pCC, u16_t wAddr, u16_t *data) );
+FORWARD _PROTOTYPE( void set_nice_volume, (void) );
+FORWARD _PROTOTYPE( int AC97_get_volume, (struct volume_level *level) );
+FORWARD _PROTOTYPE( int AC97_set_volume, (struct volume_level *level) );
+
+
+
+#define AC97_0DB_GAIN 0x0008
+#define AC97_MAX_ATTN 0x003f
+#define AC97_MUTE 0x8000U
+
+
+/* Control function defines */
+#define AC97_CTL_4SPKR 0x00U /* 4-spkr output mode enable */
+#define AC97_CTL_MICBOOST 0x01U /* Mic boost (+30 dB) enable */
+#define AC97_CTL_PWRDOWN 0x02U /* power-down mode */
+#define AC97_CTL_DOSMODE 0x03U /* A/D sync to DAC1 */
+
+ /* Timeout waiting for: */
+#define AC97_ERR_WIP_TIMEOUT -1 /* write in progress complete */
+#define AC97_ERR_DATA_TIMEOUT -2 /* data ready */
+#define AC97_ERR_SRC_NOT_BUSY_TIMEOUT -3 /* SRC not busy */
+#define AC97_ERR_SRC_SYNC_TIMEOUT -4 /* state #1 */
+
+
+
+
+
+
+/* Timeouts in milliseconds */
+#define WIP_TIMEOUT 250UL
+#define DRDY_TIMEOUT 250UL
+
+/* The default SRC syncronization state number is 1. This state occurs
+ just after de-assertion of SYNC. This is supposed to be the safest
+ state for accessing the codec with an ES1371 Rev 1. Later versions
+ of the chip allegedly don't require syncronization. Be very careful
+ if you change this ! */
+
+#define SRC_UNSYNCED 0xffffffffUL
+static u32_t SrcSyncState = 0x00010000UL;
+static DEV_STRUCT *dev;
+
+
+PRIVATE void set_src_sync_state (int state)
+{
+ if (state < 0)
+ SrcSyncState = SRC_UNSYNCED;
+ else {
+ SrcSyncState = (u32_t)state << 16;
+ SrcSyncState &= 0x00070000Ul;
+ }
+}
+
+
+PRIVATE int AC97_write (DEV_STRUCT * pCC, u16_t wAddr, u16_t wData)
+{
+u32_t dtemp, i;
+u16_t wBaseAddr = pCC->base;
+
+ /* wait for WIP bit (Write In Progress) to go away */
+ /* remember, register CODEC_READ (0x14)
+ is a pseudo read-write register */
+ if (WaitBitd (wBaseAddr + CODEC_READ, 30, 0, WIP_TIMEOUT)){
+ printf("AC97_ERR_WIP_TIMEOUT\n");
+ return (AC97_ERR_WIP_TIMEOUT);
+ }
+ if (SRC_UNSYNCED != SrcSyncState)
+ {
+ /* enable SRC state data in SRC mux */
+ if (WaitBitd (wBaseAddr + SAMPLE_RATE_CONV, SRC_BUSY_BIT, 0, 1000))
+ return (AC97_ERR_SRC_NOT_BUSY_TIMEOUT);
+
+ /* todo: why are we writing an undefined register? */
+ dtemp = pci_inl(wBaseAddr + SAMPLE_RATE_CONV);
+ pci_outl(wBaseAddr + SAMPLE_RATE_CONV, (dtemp & SRC_CTLMASK) |
+ 0x00010000UL);
+
+ /* wait for a SAFE time to write addr/data and then do it */
+ /*_disable(); */
+ for( i = 0; i < 0x1000UL; ++i )
+ if( (pci_inl(wBaseAddr + SAMPLE_RATE_CONV) & 0x00070000UL) ==
+ SrcSyncState )
+ break;
+
+ if (i >= 0x1000UL) {
+ /* _enable(); */
+ return (AC97_ERR_SRC_SYNC_TIMEOUT);
+ }
+ }
+
+ /* A test for 5880 - prime the PCI data bus */
+ {
+ u32_t dat = ((u32_t) wAddr << 16) | wData;
+ char page = pci_inb(wBaseAddr + MEM_PAGE);
+
+ pci_outl (wBaseAddr + MEM_PAGE, dat);
+
+ /* write addr and data */
+ pci_outl(wBaseAddr + CODEC_READ, dat);
+
+ pci_outb(wBaseAddr + MEM_PAGE, page); /* restore page reg */
+ }
+
+ if (SRC_UNSYNCED != SrcSyncState)
+ {
+ /* _enable(); */
+
+ /* restore SRC reg */
+ if (WaitBitd (wBaseAddr + SAMPLE_RATE_CONV, SRC_BUSY_BIT, 0, 1000))
+ return (AC97_ERR_SRC_NOT_BUSY_TIMEOUT);
+
+ pci_outl(wBaseAddr + SAMPLE_RATE_CONV, dtemp & 0xfff8ffffUL);
+ }
+
+ return 0;
+}
+
+
+PRIVATE int AC97_read (DEV_STRUCT * pCC, u16_t wAddr, u16_t *data)
+{
+u32_t dtemp, i;
+u16_t base = pCC->base;
+
+ /* wait for WIP to go away */
+ if (WaitBitd (base + CODEC_READ, 30, 0, WIP_TIMEOUT))
+ return (AC97_ERR_WIP_TIMEOUT);
+
+ if (SRC_UNSYNCED != SrcSyncState)
+ {
+ /* enable SRC state data in SRC mux */
+ if (WaitBitd (base + SAMPLE_RATE_CONV, SRC_BUSY_BIT, 0, 1000))
+ return (AC97_ERR_SRC_NOT_BUSY_TIMEOUT);
+
+ dtemp = pci_inl(base + SAMPLE_RATE_CONV);
+ pci_outl(base + SAMPLE_RATE_CONV, (dtemp & SRC_CTLMASK) |
+ 0x00010000UL);
+
+ /* wait for a SAFE time to write a read request and then do it */
+ /* todo: how do we solve the lock() problem? */
+ /* _disable(); */
+ for( i = 0; i < 0x1000UL; ++i )
+ if( (pci_inl(base + SAMPLE_RATE_CONV) & 0x00070000UL) ==
+ SrcSyncState )
+ break;
+
+ if (i >= 0x1000UL) {
+ /*_enable();*/
+ return (AC97_ERR_SRC_SYNC_TIMEOUT);
+ }
+ }
+
+ /* A test for 5880 - prime the PCI data bus */
+ {
+ /* set bit 23, this means read in stead of write. */
+ u32_t dat = ((u32_t) wAddr << 16) | (1UL << 23);
+ char page = pci_inb(base + MEM_PAGE);
+
+ /* todo: why are we putting data in the mem page register??? */
+ pci_outl(base + MEM_PAGE, dat);
+
+ /* write addr w/data=0 and assert read request */
+ pci_outl(base + CODEC_READ, dat);
+
+ pci_outb(base + MEM_PAGE, page); /* restore page reg */
+
+ }
+ if (SRC_UNSYNCED != SrcSyncState)
+ {
+
+ /*_enable();*/
+
+ /* restore SRC reg */
+ if (WaitBitd (base + SAMPLE_RATE_CONV, SRC_BUSY_BIT, 0, 1000))
+ return (AC97_ERR_SRC_NOT_BUSY_TIMEOUT);
+
+ pci_outl(base + SAMPLE_RATE_CONV, dtemp & 0xfff8ffffUL);
+ }
+
+ /* now wait for the stinkin' data (DRDY = data ready) */
+ if (WaitBitd (base + CODEC_READ, 31, 1, DRDY_TIMEOUT))
+ return (AC97_ERR_DATA_TIMEOUT);
+
+ dtemp = pci_inl(base + CODEC_READ);
+
+ if (data)
+ *data = (u16_t) dtemp;
+
+ return 0;
+}
+
+
+PRIVATE int AC97_write_unsynced (DEV_STRUCT * pCC, u16_t wAddr, u16_t wData)
+{
+ /* wait for WIP to go away */
+ if (WaitBitd (pCC->base + CODEC_READ, 30, 0, WIP_TIMEOUT))
+ return (AC97_ERR_WIP_TIMEOUT);
+
+ /* write addr and data */
+ pci_outl(pCC->base + CODEC_READ, ((u32_t) wAddr << 16) | wData);
+ return 0;
+}
+
+
+PRIVATE int AC97_read_unsynced (DEV_STRUCT * pCC, u16_t wAddr, u16_t *data)
+{
+u32_t dtemp;
+
+ /* wait for WIP to go away */
+ if (WaitBitd (pCC->base + CODEC_READ, 30, 0, WIP_TIMEOUT))
+ return (AC97_ERR_WIP_TIMEOUT);
+
+ /* write addr w/data=0 and assert read request */
+ pci_outl(pCC->base + CODEC_READ, ((u32_t) wAddr << 16) | (1UL << 23));
+
+ /* now wait for the stinkin' data (RDY) */
+ if (WaitBitd (pCC->base + CODEC_READ, 31, 1, DRDY_TIMEOUT))
+ return (AC97_ERR_DATA_TIMEOUT);
+
+ dtemp = pci_inl(pCC->base + CODEC_READ);
+
+ if (data)
+ *data = (u16_t) dtemp;
+
+ return 0;
+}
+
+
+int AC97_init( DEV_STRUCT * pCC ) {
+ int retVal;
+ /* All powerdown modes: off */
+
+ dev = pCC;
+
+ retVal = AC97_write (pCC, AC97_POWERDOWN_CONTROL_STAT, 0x0000U);
+ if (OK != retVal)
+ return (retVal);
+
+ /* Mute Line Out & set to 0dB attenuation */
+
+ retVal = AC97_write (pCC, AC97_MASTER_VOLUME, 0x0000U);
+ if (OK != retVal)
+ return (retVal);
+
+
+ retVal = AC97_write (pCC, AC97_MONO_VOLUME, 0x8000U);
+ if (OK != retVal)
+ return (retVal);
+
+ retVal = AC97_write (pCC, AC97_PHONE_VOLUME, 0x8008U);
+ if (OK != retVal)
+ return (retVal);
+
+ retVal = AC97_write (pCC, AC97_MIC_VOLUME, 0x0008U);
+ if (OK != retVal)
+ return (retVal);
+
+ retVal = AC97_write (pCC, AC97_LINE_IN_VOLUME, 0x0808U);
+ if (OK != retVal)
+ return (retVal);
+
+ retVal = AC97_write (pCC, AC97_CD_VOLUME, 0x0808U);
+ if (OK != retVal)
+ return (retVal);
+
+ retVal = AC97_write (pCC, AC97_AUX_IN_VOLUME, 0x0808U);
+ if (OK != retVal)
+ return (retVal);
+
+ retVal = AC97_write (pCC, AC97_PCM_OUT_VOLUME, 0x0808U);
+ if (OK != retVal)
+ return (retVal);
+
+ retVal = AC97_write (pCC, AC97_RECORD_GAIN_VOLUME, 0x0000U);
+ if (OK != retVal)
+ return (retVal);
+
+ /* Connect Line In to ADC */
+ retVal = AC97_write (pCC, AC97_RECORD_SELECT, 0x0404U);
+ if (OK != retVal)
+ return (retVal);
+
+ retVal = AC97_write (pCC, AC97_GENERAL_PURPOSE, 0x0000U);
+ if (OK != retVal)
+ return (retVal);
+
+ set_nice_volume();
+
+ return OK;
+}
+
+
+PRIVATE void set_nice_volume(void) {
+ /* goofy code to set the DAC1 channel to an audibe volume
+ to be able to test it without using the mixer */
+
+ AC97_write_unsynced(dev, AC97_PCM_OUT_VOLUME, 0x0808);/* the higher,
+ the softer */
+ AC97_write_unsynced(dev, AC97_MASTER_VOLUME, 0x0101);
+ AC97_write_unsynced(dev, 0x38, 0); /* not crucial */
+
+ AC97_write_unsynced(dev, AC97_LINE_IN_VOLUME, 0x0303);
+ AC97_write_unsynced(dev, AC97_MIC_VOLUME, 0x005f);
+
+ /* mute record gain */
+ AC97_write_unsynced(dev, AC97_RECORD_GAIN_VOLUME, 0xFFFF);
+ /* mic record volume high */
+ AC97_write_unsynced(dev, AC97_RECORD_GAIN_MIC_VOL, 0x0000);
+
+ /* Also, to be able test recording without mixer:
+ select ONE channel as input below. */
+
+ /* select LINE IN */
+ /*AC97_write_unsynced(dev, AC97_RECORD_SELECT, 0x0404);*/
+
+ /* select MIC */
+ AC97_write_unsynced(dev, AC97_RECORD_SELECT, 0x0000);
+
+ /* unmute record gain */
+ AC97_write_unsynced(dev, AC97_RECORD_GAIN_VOLUME, 0x0000);
+}
+
+
+PRIVATE int get_volume(u8_t *left, u8_t *right, int cmd) {
+ u16_t value;
+
+ AC97_read_unsynced(dev, (u16_t)cmd, &value);
+
+ *left = value>>8;
+ *right = value&0xff;
+
+ return OK;
+}
+
+
+PRIVATE int set_volume(int left, int right, int cmd) {
+ u16_t waarde;
+
+ waarde = (u16_t)((left<<8)|right);
+
+ AC97_write_unsynced(dev, (u16_t)cmd, waarde);
+
+ return OK;
+}
+
+
+void convert(int left_in, int right_in, int max_in, int *left_out,
+ int *right_out, int max_out, int swaplr) {
+ int tmp;
+
+ if(left_in < 0) left_in = 0;
+ else if(left_in > max_in) left_in = max_in;
+ if(right_in < 0) right_in = 0;
+ else if(right_in > max_in) right_in = max_in;
+
+ if (swaplr) {
+ tmp = left_in;
+ left_in = right_in;
+ right_in = tmp;
+ }
+
+ *left_out = (-left_in) + max_out;
+ *right_out = (-right_in) + max_out;
+}
+
+
+int AC97_get_set_volume(struct volume_level *level, int flag) {
+ if (flag) {
+ return AC97_set_volume(level);
+ }
+ else {
+ return AC97_get_volume(level);
+ }
+}
+
+
+PRIVATE int AC97_get_volume(struct volume_level *level) {
+ int cmd;
+ u8_t left;
+ u8_t right;
+
+ switch(level->device) {
+ case Master:
+ cmd = AC97_MASTER_VOLUME;
+ get_volume(&left, &right, cmd);
+ convert(left, right, 0x1f,
+ &(level->left), &(level->right), 0x1f, 0);
+ break;
+ case Dac:
+ return EINVAL;
+ break;
+ case Fm:
+ cmd = AC97_PCM_OUT_VOLUME;
+ get_volume(&left, &right, cmd);
+ convert(left, right, 0x1f,
+ &(level->left), &(level->right), 0x1f, 0);
+ break;
+ case Cd:
+ cmd = AC97_CD_VOLUME;
+ get_volume(&left, &right, cmd);
+ convert(left, right, 0x1f,
+ &(level->left), &(level->right), 0x1f, 0);
+ break;
+ case Line:
+ cmd = AC97_LINE_IN_VOLUME;
+ get_volume(&left, &right, cmd);
+ convert(left, right, 0x1f,
+ &(level->left), &(level->right), 0x1f, 0);
+ break;
+ case Mic:
+ cmd = AC97_MIC_VOLUME;
+ get_volume(&left, &right, cmd);
+ convert(left, right, 0x1f,
+ &(level->left), &(level->right), 0x1f, 1);
+ break;
+ case Speaker:
+ cmd = AC97_PC_BEEP_VOLUME;
+ return EINVAL;
+ break;
+ case Treble:
+ cmd = AC97_MASTER_TONE;
+ get_volume(&left, &right, cmd);
+ convert(left, right, 0xf,
+ &(level->left), &(level->right), 0xf, 1);
+ break;
+ case Bass:
+ cmd = AC97_MASTER_TONE;
+ get_volume(&left, &right, cmd);
+ convert(left, right, 0xf,
+ &(level->left), &(level->right), 0xf, 1);
+ break;
+ default:
+ return EINVAL;
+ }
+ return OK;
+}
+
+
+PRIVATE int AC97_set_volume(struct volume_level *level) {
+ int cmd;
+ int left;
+ int right;
+
+ switch(level->device) {
+ case Master:
+ cmd = AC97_MASTER_VOLUME;
+ convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 0);
+ break;
+ case Dac:
+ return EINVAL;
+ break;
+ case Fm:
+ cmd = AC97_PCM_OUT_VOLUME;
+ convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 0);
+ break;
+ case Cd:
+ cmd = AC97_CD_VOLUME;
+ convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 0);
+ break;
+ case Line:
+ cmd = AC97_LINE_IN_VOLUME;
+ convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 0);
+ break;
+ case Mic:
+ cmd = AC97_MIC_VOLUME;
+ convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 1);
+ break;
+ case Speaker:
+ cmd = AC97_PC_BEEP_VOLUME;
+ return EINVAL;
+ break;
+ case Treble:
+ cmd = AC97_MASTER_TONE;
+ return EINVAL;
+ break;
+ case Bass:
+ cmd = AC97_MASTER_TONE;
+ return EINVAL;
+ break;
+ default:
+ return EINVAL;
+ }
+ set_volume(left, right, cmd);
+
+ return OK;
+}
--- /dev/null
+#ifndef AC97_H
+#define AC97_H
+
+
+#include "es1371.h"
+#include "wait.h"
+#include "pci_helper.h"
+#include "sample_rate_converter.h"
+
+
+/*
+ This function initializes the AC97 to a default mode.
+*/
+int AC97_init( DEV_STRUCT * pCC );
+
+int AC97_get_set_volume(struct volume_level *level, int flag);
+
+
+
+/* This is a main memory cache copy of the codec's ac97 configuration
+ registers. See Intel's Audio Codec 97 standard (rev2.3) for info. */
+
+typedef struct ac97_struct {
+ u16_t Reset; /* 0x00 */
+ u16_t MasterVolume; /* 0x02 */
+ u16_t AUXOutVolume; /* 0x04 */
+ u16_t MonoVolume; /* 0x06 */
+ u16_t MasterTone; /* 0x08 */
+ u16_t PCBeepVolume; /* 0x0A */
+ u16_t PhoneVolume; /* 0x0C */
+ u16_t MicVolume; /* 0x0E */
+ u16_t LineInVolume; /* 0x10 */
+ u16_t CDVolume; /* 0x12 */
+ u16_t VideoVolume; /* 0x14 */
+ u16_t AUXInVolume; /* 0x16 */
+ u16_t PCMOutVolume; /* 0x18 */
+ u16_t RecordSelect; /* 0x1A */
+ u16_t RecordGain; /* 0x1C */
+ u16_t RecordGainMic; /* 0x1E */
+ u16_t GeneralPurpose; /* 0x20 */
+ u16_t Control3D; /* 0x22 */
+ u16_t AudioIntAndPaging; /* 0x24 */
+ u16_t PowerdownControlAndStat; /* 0x26 */
+ u16_t ExtendedAudio1; /* 0x28 */
+ u16_t ExtendedAudio2; /* 0x2A */
+ /* ... */
+ u16_t VendorID1; /* 0x7C */
+ u16_t VendorID2; /* 0x7E */
+} ac97_t;
+
+
+
+/* Source and output volume control register defines */
+#define AC97_MASTER_VOLUME 0x02U /* Master out */
+#define AC97_AUX_OUT_VOLUME 0x04U /* Auxiliary out volume */
+#define AC97_MONO_VOLUME 0x06U /* Mono out volume */
+#define AC97_MASTER_TONE 0x08U /* high byte= bass, low byte= treble*/
+#define AC97_PC_BEEP_VOLUME 0x0aU /* PC speaker volume */
+#define AC97_PHONE_VOLUME 0x0cU /* Phone volume */
+#define AC97_MIC_VOLUME 0x0eU /* Mic, mono */
+#define AC97_LINE_IN_VOLUME 0x10U /* Line volume */
+#define AC97_CD_VOLUME 0x12U /* CD audio volume */
+#define AC97_VIDEO_VOLUME 0x14U /* Video (TV) volume */
+#define AC97_AUX_IN_VOLUME 0x16U /* Aux line source, left */
+#define AC97_PCM_OUT_VOLUME 0x18U /* The DACs - wav+synth */
+#define AC97_RECORD_GAIN_VOLUME 0x1cU /* Record input level */
+#define AC97_RECORD_GAIN_MIC_VOL 0x1eU /* Record input level */
+
+/* Other AC97 control register defines */
+#define AC97_RESET 0x00U /* any write here to reset AC97 */
+#define AC97_GENERAL_PURPOSE 0x20U /* */
+#define AC97_POWERDOWN_CONTROL_STAT 0x26U /* */
+#define AC97_RECORD_SELECT 0x1aU /* record mux select */
+#define AC97_VENDOR_ID1 0x7cU /* 1st two Vendor ID bytes */
+#define AC97_VENDOR_ID2 0x7eU /* last Vendor ID byte plus rev.
+ number */
+
+/* Record Select defines */
+#define AC97_RECORD_MIC 0
+#define AC97_RECORD_CD 1
+#define AC97_RECORD_VIDEO 2
+#define AC97_RECORD_AUX 3
+#define AC97_RECORD_LINE 4
+#define AC97_RECORD_STEREO_MIX 5
+#define AC97_RECORD_MONO_MIX 6
+#define AC97_RECORD_PHONE 7
+
+#define MASTER_VOL_MASK 0x1F
+#define DAC_VOL_MASK 0x1F
+#define AUX_IN_VOL_MASK 0x1F
+#define MUTE_MASK 0x8000
+
+
+
+
+
+
+#endif /* AC97_H */
--- /dev/null
+#include "sample_rate_converter.h"
+
+
+
+
+#define SRC_RATE 48000U
+#define reg(n) DSP->base + n
+
+
+/* register/base and control equates for the SRC RAM */
+#define SRC_SYNTH_FIFO 0x00
+#define SRC_DAC_FIFO 0x20
+#define SRC_ADC_FIFO 0x40
+
+#define SRC_SYNTH_LVOL 0x7c
+#define SRC_SYNTH_RVOL 0x7d
+#define SRC_DAC_LVOL 0x7e
+#define SRC_DAC_RVOL 0x7f
+#define SRC_ADC_LVOL 0x6c
+#define SRC_ADC_RVOL 0x6d
+
+#define SRC_TRUNC_N_OFF 0x00
+#define SRC_INT_REGS_OFF 0x01
+#define SRC_ACCUM_FRAC_OFF 0x02
+#define SRC_VFREQ_FRAC_OFF 0x03
+
+/* miscellaneous control defines */
+#define SRC_IOPOLL_COUNT 0x1000UL
+
+#define SRC_SYNTHFREEZE (1UL << 21)
+#define SRC_DACFREEZE (1UL << 20)
+#define SRC_ADCFREEZE (1UL << 19)
+
+
+
+
+FORWARD _PROTOTYPE( int src_reg_read, (DEV_STRUCT * DSP,
+ u16_t reg, u16_t *data) );
+FORWARD _PROTOTYPE( int src_reg_write, (DEV_STRUCT * DSP,
+ u16_t reg, u16_t val) );
+
+
+int src_init ( DEV_STRUCT * DSP ) {
+ u32_t i;
+ int retVal;
+
+ /* Clear all SRC RAM then init - keep SRC disabled until done */
+ /* Wait till SRC_RAM_BUSY is 0 */
+ if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
+ return (SRC_ERR_NOT_BUSY_TIMEOUT);
+
+ pci_outl(reg(SAMPLE_RATE_CONV), SRC_DISABLE);
+
+ /* from the opensound system driver, no idea where the specification is */
+ /* there are indeed 7 bits for the addresses of the SRC */
+ for( i = 0; i < 0x80; ++i ) {
+ if (SRC_SUCCESS != (retVal = src_reg_write(DSP, (u16_t)i, 0U)))
+ return (retVal);
+ }
+
+ if (SRC_SUCCESS != (retVal =
+ src_reg_write(DSP, SRC_SYNTH_BASE + SRC_TRUNC_N_OFF, 16 << 4)))
+ return (retVal);
+ if (SRC_SUCCESS != (retVal = src_reg_write(DSP,
+ SRC_SYNTH_BASE + SRC_INT_REGS_OFF, 16 << 10)))
+ return (retVal);
+ if (SRC_SUCCESS != (retVal =
+ src_reg_write(DSP, SRC_DAC_BASE + SRC_TRUNC_N_OFF, 16 << 4)))
+ return (retVal);
+ if (SRC_SUCCESS != (retVal =
+ src_reg_write(DSP, SRC_DAC_BASE + SRC_INT_REGS_OFF, 16 << 10)))
+ return (retVal);
+ if (SRC_SUCCESS != (retVal =
+ src_reg_write(DSP, SRC_SYNTH_LVOL, 1 << 12)))
+ return (retVal);
+ if (SRC_SUCCESS != (retVal =
+ src_reg_write(DSP, SRC_SYNTH_RVOL, 1 << 12)))
+ return (retVal);
+ if (SRC_SUCCESS != (retVal =
+ src_reg_write(DSP, SRC_DAC_LVOL, 1 << 12)))
+ return (retVal);
+ if (SRC_SUCCESS != (retVal =
+ src_reg_write(DSP, SRC_DAC_RVOL, 1 << 12)))
+ return (retVal);
+ if (SRC_SUCCESS != (retVal =
+ src_reg_write(DSP, SRC_ADC_LVOL, 1 << 12)))
+ return (retVal);
+ if (SRC_SUCCESS != (retVal =
+ src_reg_write(DSP, SRC_ADC_RVOL, 1 << 12)))
+ return (retVal);
+
+ /* default some rates */
+ src_set_rate(DSP, SRC_SYNTH_BASE, SRC_RATE);
+ src_set_rate(DSP, SRC_DAC_BASE, SRC_RATE);
+ src_set_rate(DSP, SRC_ADC_BASE, SRC_RATE);
+
+ /* now enable the whole deal */
+ if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
+ return (SRC_ERR_NOT_BUSY_TIMEOUT);
+
+ pci_outl(reg(SAMPLE_RATE_CONV), 0UL);
+
+ return 0;
+}
+
+
+PRIVATE int src_reg_read(DEV_STRUCT * DSP, u16_t reg, u16_t *data) {
+ u32_t dtemp;
+
+ /* wait for ready */
+ if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
+ return (SRC_ERR_NOT_BUSY_TIMEOUT);
+
+ dtemp = pci_inl(reg(SAMPLE_RATE_CONV));
+
+ /* assert a read request */
+ /*pci_outl(reg(SAMPLE_RATE_CONV),
+ (dtemp & SRC_CTLMASK) | ((u32_t) reg << 25));*/
+ pci_outl(reg(SAMPLE_RATE_CONV), (dtemp &
+ (DIS_REC|DIS_P2|DIS_P1|SRC_DISABLE)) | ((u32_t) reg << 25));
+
+ /* now wait for the data */
+ if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
+ return (SRC_ERR_NOT_BUSY_TIMEOUT);
+
+ if (NULL != data)
+ *data = (u16_t) pci_inl(reg(SAMPLE_RATE_CONV));
+
+ return 0;
+}
+
+
+PRIVATE int src_reg_write(DEV_STRUCT * DSP, u16_t reg, u16_t val) {
+ u32_t dtemp;
+
+ /* wait for ready */
+ if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
+ return (SRC_ERR_NOT_BUSY_TIMEOUT);
+
+ dtemp = pci_inl(reg(SAMPLE_RATE_CONV));
+
+ /* assert the write request */
+ pci_outl(reg(SAMPLE_RATE_CONV),
+ (dtemp & SRC_CTLMASK) | SRC_RAM_WE | ((u32_t) reg << 25) | val);
+
+ return 0;
+}
+
+
+void src_set_rate(DEV_STRUCT * DSP, char base, u16_t rate) {
+ u32_t freq, dtemp, i;
+ u16_t N, truncM, truncStart, wtemp;
+
+
+ if( base != SRC_ADC_BASE )
+ {
+ /* freeze the channel */
+ dtemp = base == SRC_SYNTH_BASE ? SRC_SYNTHFREEZE : SRC_DACFREEZE;
+ for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
+ if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
+ break;
+ pci_outl(reg(SAMPLE_RATE_CONV),
+ (pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) |
+ dtemp);
+
+ /* calculate new frequency and write it - preserve accum */
+ /* please don't try to understand. */
+ freq = ((u32_t) rate << 16) / 3000U;
+ src_reg_read(DSP, base + SRC_INT_REGS_OFF, &wtemp);
+
+ src_reg_write(DSP, base + SRC_INT_REGS_OFF,
+ (wtemp & 0x00ffU) |
+ (u16_t) (freq >> 6) & 0xfc00);
+
+ src_reg_write(DSP, base + SRC_VFREQ_FRAC_OFF, (u16_t) freq >> 1);
+
+ /* un-freeze the channel */
+ dtemp = base == SRC_SYNTH_BASE ? SRC_SYNTHFREEZE : SRC_DACFREEZE;
+ for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
+ if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
+ break;
+ pci_outl(reg(SAMPLE_RATE_CONV),
+ (pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) &
+ ~dtemp);
+ }
+ else /* setting ADC rate */
+ {
+ /* freeze the channel */
+ for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
+ if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
+ break;
+ pci_outl(reg(SAMPLE_RATE_CONV),
+ (pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) |
+ SRC_ADCFREEZE);
+
+
+
+ /* derive oversample ratio */
+ N = rate/3000U;
+ if( N == 15 || N == 13 || N == 11 || N == 9 )
+ --N;
+ src_reg_write(DSP, SRC_ADC_LVOL, N << 8);
+ src_reg_write(DSP, SRC_ADC_RVOL, N << 8);
+
+ /* truncate the filter and write n/trunc_start */
+ truncM = (21*N - 1) | 1;
+ if( rate >= 24000U )
+ {
+ if( truncM > 239 )
+ truncM = 239;
+ truncStart = (239 - truncM) >> 1;
+ src_reg_write(DSP, base + SRC_TRUNC_N_OFF,
+ (truncStart << 9) | (N << 4));
+ }
+ else
+ {
+ if( truncM > 119 )
+ truncM = 119;
+ truncStart = (119 - truncM) >> 1;
+ src_reg_write(DSP, base + SRC_TRUNC_N_OFF,
+ 0x8000U | (truncStart << 9) | (N << 4));
+ }
+
+ /* calculate new frequency and write it - preserve accum */
+ freq = ((48000UL << 16) / rate) * N;
+ src_reg_read(DSP, base + SRC_INT_REGS_OFF, &wtemp);
+ src_reg_write(DSP, base + SRC_INT_REGS_OFF,
+ (wtemp & 0x00ffU) |
+ (u16_t) (freq >> 6) & 0xfc00);
+ src_reg_write(DSP, base + SRC_VFREQ_FRAC_OFF, (u16_t) freq >> 1);
+
+ /* un-freeze the channel */
+ for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
+ if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
+ break;
+ pci_outl(reg(SAMPLE_RATE_CONV),
+ (pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) &
+ ~SRC_ADCFREEZE);
+ }
+ return;
+}