ftp.nice.ch/pub/next/system/driver/audio/PAS_ForAudioCD.I.b.tar.gz#/ProAudioSpectrumInline.h

This is ProAudioSpectrumInline.h in view mode; [Download] [Up]

/* 
 * Copyright (c) 1993 NeXT Computer, Inc.  All rights reserved. 
 */
 
#import "ProAudioSpectrumRegisters.h"
#import <driverkit/i386/ioPorts.h>
#import <driverkit/generalFuncs.h>

static inline
void
setBaseAddress(unsigned int baseAddress)
{
    /*
     * To relocate the I/O addresses, two 8-bit values are written to the
     * Master Address Pointer (0x9a01):
     * (1) board ID value (valid settings are 0xbc-0xbf)
     * (2) base address shifted right by two positions
     */
    outb(MASTER_ADDRESS_POINTER, FIRST_BOARD_ID);
    outb(MASTER_ADDRESS_POINTER, (baseAddress) >> 2);
}

static inline
filterControl_t
getFilterControl()
{
    union {
	filterControl_t reg;
	unsigned char	data;
    } filterControl;
    
    filterControl.data = inb(FILTER_CONTROL);
    
    return (filterControl.reg);
}
 
static inline
void
setFilterControl(filterControl_t reg)
{
    union {
	filterControl_t	reg;
	unsigned char	data;
    } filterControl;
    
    filterControl.reg = reg;
    
    outb(FILTER_CONTROL, filterControl.data);
}

static inline
void
enableAudioOutput(boolean_t enable)
{
    filterControl_t	filterControl	= {0};
    
    filterControl = getFilterControl();
    filterControl.enableAudioOutput = enable;
    setFilterControl(filterControl);
}

static inline
interruptControl_t
getInterruptControl()
{
    union {
	interruptControl_t	reg;
	unsigned char		data;
    } interruptControl;
    
    interruptControl.data = inb(INTERRUPT_CONTROL);
    
    return (interruptControl.reg);
}
 
static inline
void
setInterruptControl(interruptControl_t reg)
{
    union {
	interruptControl_t	reg;
	unsigned char		data;
    } interruptControl;
    
    interruptControl.reg = reg;
    
    outb(INTERRUPT_CONTROL, interruptControl.data);
}

static inline
interruptStatus_t
getInterruptStatus()
{
    union {
	interruptStatus_t	reg;
	unsigned char		data;
    } interruptStatus;
    
    interruptStatus.data = inb(INTERRUPT_STATUS);
    
    return (interruptStatus.reg);
}
 
static inline
void
setInterruptStatus(interruptStatus_t reg)
{
    union {
	interruptStatus_t	reg;
	unsigned char		data;
    } interruptStatus;
    
    interruptStatus.reg = reg;
    
    outb(INTERRUPT_STATUS, interruptStatus.data);
}

static inline
crossChannelControl_t
getCrossChannelControl()
{
    union {
	crossChannelControl_t	reg;
	unsigned char		data;
    } crossChannelControl;
    
    crossChannelControl.data = inb(CROSS_CHANNEL_CONTROL);
    
    return (crossChannelControl.reg);
}
 
static inline
void
setCrossChannelControl(crossChannelControl_t reg)
{
    union {
	crossChannelControl_t	reg;
	unsigned char		data;
    } crossChannelControl;
    
    crossChannelControl.reg = reg;
    
    outb(CROSS_CHANNEL_CONTROL, crossChannelControl.data);
}

static inline
sampleCounterControl_t
getSampleCounterControl()
{
    union {
	sampleCounterControl_t	reg;
	unsigned char		data;
    } sampleCounterControl;
    
    sampleCounterControl.data = inb(SAMPLE_COUNTER_CONTROL);
    
    return (sampleCounterControl.reg);
}
 
static inline
void
setSampleCounterControl(sampleCounterControl_t reg)
{
    union {
	sampleCounterControl_t	reg;
	unsigned char		data;
    } sampleCounterControl;
    
    sampleCounterControl.reg = reg;
    
    outb(SAMPLE_COUNTER_CONTROL, sampleCounterControl.data);
}

static inline
systemConfiguration1_t
getSystemConfiguration1()
{
    union {
	systemConfiguration1_t	reg;
	unsigned char		data;
    } systemConfiguration1;
    
    systemConfiguration1.data = inb(SYSTEM_CONFIGURATION_1);
    
    return (systemConfiguration1.reg);
}
 
static inline
void
setSystemConfiguration1(systemConfiguration1_t reg)
{
    union {
	systemConfiguration1_t	reg;
	unsigned char		data;
    } systemConfiguration1;
    
    systemConfiguration1.reg = reg;
    
    outb(SYSTEM_CONFIGURATION_1, systemConfiguration1.data);
}

static inline
systemConfiguration2_t
getSystemConfiguration2()
{
    union {
	systemConfiguration2_t	reg;
	unsigned char			data;
    } systemConfiguration2;
    
    systemConfiguration2.data = inb(SYSTEM_CONFIGURATION_2);
    
    return (systemConfiguration2.reg);
}
 
static inline
void
setSystemConfiguration2(systemConfiguration2_t reg)
{
    union {
	systemConfiguration2_t	reg;
	unsigned char			data;
    } systemConfiguration2;
    
    systemConfiguration2.reg = reg;
    
    outb(SYSTEM_CONFIGURATION_2, systemConfiguration2.data);
}

static inline
DMAChannelConfiguration_t
getDMAChannelConfiguration()
{
    union {
	DMAChannelConfiguration_t	reg;
	unsigned char			data;
    } DMAChannelConfiguration;
    
    DMAChannelConfiguration.data = inb(DMA_CHANNEL_CONFIGURATION);
    
    return (DMAChannelConfiguration.reg);
}
 
static inline
void
setDMAChannelConfiguration(DMAChannelConfiguration_t reg)
{
    union {
	DMAChannelConfiguration_t	reg;
	unsigned char			data;
    } DMAChannelConfiguration;
    
    DMAChannelConfiguration.reg = reg;
    
    outb(DMA_CHANNEL_CONFIGURATION, DMAChannelConfiguration.data);
}

static inline
boolean_t
setDMAChannel(int channel)
{
   static DMAChannelConfiguration_t	DMAChannelConfiguration = {0};
   static const unsigned char DMAMap[] =	{
   					DMA_CHANNEL_0,
                                        DMA_CHANNEL_1,
                                        DMA_CHANNEL_2,
                                        DMA_CHANNEL_3,
                                        DMA_CHANNEL_NONE,
                                        DMA_CHANNEL_5,
                                        DMA_CHANNEL_6,
                                        DMA_CHANNEL_7,
    					};

    if (DMAMap[channel] == DMA_CHANNEL_NONE)
        return FALSE;
	
    DMAChannelConfiguration.channel = DMAMap[channel];
    setDMAChannelConfiguration(DMAChannelConfiguration);
    return TRUE;
   
}

static inline
IRQConfiguration_t
getIRQConfiguration()
{
    union {
	IRQConfiguration_t	reg;
	unsigned char		data;
    } IRQConfiguration;
    
    IRQConfiguration.data = inb(IRQ_CONFIGURATION);
    
    return (IRQConfiguration.reg);
}
 
static inline
void
setIRQConfiguration(IRQConfiguration_t reg)
{
    union {
	IRQConfiguration_t	reg;
	unsigned char		data;
    } IRQConfiguration;
    
    IRQConfiguration.reg = reg;
    
    outb(IRQ_CONFIGURATION, IRQConfiguration.data);
}

static inline
boolean_t
setInterrupt(int interrupt)
{

   static IRQConfiguration_t	IRQConfiguration = {0};
   static const unsigned char IRQMap[] =	{
   					INTERRUPT_NONE,
                                        INTERRUPT_NONE,
                                        INTERRUPT_2,
                                        INTERRUPT_3,
                                        INTERRUPT_4,
                                        INTERRUPT_5,
                                        INTERRUPT_6,
                                        INTERRUPT_7,
                                        INTERRUPT_NONE,
                                        INTERRUPT_NONE,
                                        INTERRUPT_10,
                                        INTERRUPT_11,
                                        INTERRUPT_12,
                                        INTERRUPT_NONE,
                                        INTERRUPT_14,
                                        INTERRUPT_15
    					};

    if (IRQMap[interrupt] == INTERRUPT_NONE)
        return FALSE;
	
    IRQConfiguration.interrupt = IRQMap[interrupt];
    setIRQConfiguration(IRQConfiguration);
    return TRUE;
}


static inline
void
setMasterOutputAttenuation(u_int channel, masterAttenuation_t attenuation)
{
    union {
        channelSelection_t	reg;
	unsigned char		data;
    } channelSelection;
    
    // avoid a warning
    channelSelection.data = 0;
    
    // select the master A mixer
    channelSelection.reg.selectAddress = MIXER_A_MASTER;
    channelSelection.reg.selectChannel = channel;
    channelSelection.reg.isTransfer = TRUE;

    outb(MIXER_CONTROL, channelSelection.data);
    
    // set the attenuation
    outb(MIXER_CONTROL, (char)attenuation);
}

static inline
void
setOutputAttenuation(u_int address, u_int channel, u_int attenuation)
{

    union {
        channelSelection_t	reg;
	unsigned char		data;
    } channelSelection;

    union {
        channelAttenuation_t	reg;
	unsigned char		data;
    } channelAttenuation;
    
    // avoid a warning
    channelSelection.data = 0;
    channelAttenuation.data = 0;
    
    channelSelection.reg.selectAddress = address;
    channelSelection.reg.selectChannel = channel;
    channelSelection.reg.isTransfer = TRUE;
    outb(MIXER_CONTROL, channelSelection.data);
    
    channelAttenuation.reg.attenuation = attenuation;
    channelAttenuation.reg.routeChannel = MIXER_A_ROUTE;
    channelAttenuation.reg.swapChannels = NORMAL_STEREO;
    outb(MIXER_CONTROL, channelAttenuation.data);
 }

static inline
void
setMasterInputAttenuation(u_int channel, masterAttenuation_t attenuation)
{
    union {
        channelSelection_t	reg;
	unsigned char		data;
    } channelSelection;
    
    // avoid a warning
    channelSelection.data = 0;
    
    // select the master B mixer
    channelSelection.reg.selectAddress = MIXER_B_MASTER;
    channelSelection.reg.selectChannel = channel;
    channelSelection.reg.isTransfer = TRUE;
    outb(MIXER_CONTROL, channelSelection.data);
    
    // set the attenuation
    outb(MIXER_CONTROL, (char)attenuation);
}

static inline
void
setInputAttenuation(u_int address, u_int channel, u_int attenuation)
{
    union {
        channelSelection_t	reg;
	unsigned char		data;
    } channelSelection;

    union {
        channelAttenuation_t	reg;
	unsigned char		data;
    } channelAttenuation;
    
    // avoid a warning
    channelSelection.data = 0;
    channelAttenuation.data = 0;
    
    channelSelection.reg.selectAddress = address;
    channelSelection.reg.selectChannel = channel;
    channelSelection.reg.isTransfer = TRUE;
    outb(MIXER_CONTROL, channelSelection.data);
    
    channelAttenuation.reg.attenuation = attenuation;
    channelAttenuation.reg.routeChannel = MIXER_B_ROUTE;
    channelAttenuation.reg.swapChannels = NORMAL_STEREO;
    outb(MIXER_CONTROL, channelAttenuation.data);

}

/*
 * In the 3.1 release, the driver set the sample rate using the technique
 * described in the Developer Reference. Unfortunately, this was imprecise
 * due to rounding errors. The values were calculated as follows:
 *
 * 1193180 / (sample rate * channel count)
 * 1193180 / (44100 * 1) = 27		// 44.1 kHz mono
 * 1193180 / (44100 * 2) = 13		// 44.1 kHz stereo
 *
 * MediaVision has provided us with the calculateRate function which calculates
 * the sample rate with more precision. This technique (which also sets the
 * prescale register) is undocumented in their reference manual.
 *
 */
static inline
void
calculateRate(u_int sampleRate, u_int *timer, u_int *prescale)
{
long targetRatio;
long bestRatio;
long testRatio;
long bestDifference;
long lastDifference;
long testDifference;
long p;
long t;

    targetRatio = (441000L << 10) / sampleRate;
    bestRatio = 300L << 10;
    bestDifference = 7000L << 10;
    *prescale = 0;
    *timer = 0;
    
    for (p = 2; p < 256; p++) {
        lastDifference = 300L << 10;
	
	for (t = p+1; t < 256; t++) {
	    testRatio = (t << 10) / p;
	    
	    if (testRatio == targetRatio) {
	        bestRatio = testRatio;
		*prescale = p;
		*timer = t;
		return;
	    }
	    
	    testDifference = testRatio - targetRatio;
	    
	    if (testDifference < 0)
	        testDifference = -testDifference;
		
	    if (testDifference > lastDifference)
	        break;
		
	    if (testDifference < bestDifference) {
	        bestRatio = testRatio;
		bestDifference = testDifference;
		*prescale = p;
		*timer = t;
	   }
	   
	   lastDifference = testDifference;
         }
    }
}

static inline
void
setSampleRateTimer(u_int rate)
{

    u_int prescale;
    u_int timer;

    union {
        sampleRateTimer_t rate;
        unsigned char   data[2];
    } sampleRateTimer;
    
    
    filterControl_t		filterControl		= {0};
    sampleCounterControl_t	sampleCounterControl	= {0};

    /*
     * Before setting the sample rate interval, be sure to select the
     * Sample Rate Timer using Local Timer Control Register (0x138b). Also
     * remember to set the Sample Rate Timer Gate of the Audio Filter Control
     * Register (0xb8a) to 0 before programming the timer.
     */
    filterControl = getFilterControl();
    filterControl.enableSampleRateTimer = FALSE;
    setFilterControl(filterControl);
    
    sampleCounterControl.countFormat = BINARY_COUNT_FORMAT;
    sampleCounterControl.selectMode = SAMPLE_RATE_MODE;
    sampleCounterControl.latchCounter = 3;
    sampleCounterControl.selectCounter = SAMPLE_RATE_COUNT;
    setSampleCounterControl(sampleCounterControl);

    switch (rate) {
    
        case 44100:
	    timer = 20;
	    prescale = 2;
	    break;
	    
	case 22050:
	    timer = 40;
	    prescale = 2;
	    break;
	    
	case 8012:
	    timer = 110;
	    prescale = 2;
	    break;
	    
 	default:
	    calculateRate(rate, &timer, &prescale);
	    break;
    }    
  
    sampleRateTimer.rate = timer;

    outb(SAMPLE_RATE_TIMER, sampleRateTimer.data[0]);
    outb(SAMPLE_RATE_TIMER, sampleRateTimer.data[1]);

    outb(PRESCALE_DIVIDER, prescale & 0x0F);

}
    
static inline
void
setSampleBufferCounter(sampleBufferCounter_t count)
{
    union {
        sampleBufferCounter_t count;
	unsigned char data[2];
    } sampleBufferCounter;

    filterControl_t		filterControl		= {0};
    sampleCounterControl_t	sampleCounterControl	= {0};

    filterControl = getFilterControl();
    filterControl.enableSampleBufferCounter = FALSE;
    setFilterControl(filterControl);

    sampleCounterControl.countFormat = BINARY_COUNT_FORMAT;
    sampleCounterControl.latchCounter = 3;
    sampleCounterControl.selectMode = SAMPLE_BUFFER_MODE;
    sampleCounterControl.selectCounter = SAMPLE_BUFFER_COUNT;
    setSampleCounterControl(sampleCounterControl);

    sampleBufferCounter.count = count;
    outb(SAMPLE_BUFFER_COUNTER, sampleBufferCounter.data[0]);
    outb(SAMPLE_BUFFER_COUNTER, sampleBufferCounter.data[1]);
}

static inline
void
setMasterModeControl(masterModeControl_t mode)
{
    union {
        masterModeControl_t reg;
	unsigned char data;
    } masterModeControl;
    
    union {
        channelSelection_t	reg;
	unsigned char		data;
    } channelSelection;

    
    // avoid a warning
    channelSelection.data = 0;
    
    channelSelection.reg.selectAddress = MASTER_MODE_CONTROL;
    channelSelection.reg.selectChannel = BOTH_CHANNELS;
    channelSelection.reg.isTransfer = TRUE;
    outb(MIXER_CONTROL, channelSelection.data);
    
    masterModeControl.reg = mode;
    outb(MIXER_CONTROL, masterModeControl.data);
}

static inline
void
setLoudnessFilter(boolean_t flag)
{
    masterModeControl_t		masterModeControl = {0};

    masterModeControl.loudnessFilter = flag;
    setMasterModeControl(masterModeControl);
}  
    

static inline
void
setBassControl(unsigned char boost)
{
    union {
        channelSelection_t	reg;
	unsigned char		data;
    } channelSelection;

    // avoid a warning
    channelSelection.data = 0;
    
    channelSelection.reg.selectAddress = BASS_CONTROL;
    channelSelection.reg.selectChannel = BOTH_CHANNELS;
    channelSelection.reg.isTransfer = TRUE;
    outb(MIXER_CONTROL, channelSelection.data);
    
    outb(MIXER_CONTROL, boost);
}

static inline
void
setTrebleControl(unsigned char boost)
{
    union {
        channelSelection_t	reg;
	unsigned char		data;
    } channelSelection;

    // avoid a warning
    channelSelection.data = 0;
    
    channelSelection.reg.selectAddress = TREBLE_CONTROL;
    channelSelection.reg.selectChannel = BOTH_CHANNELS;
    channelSelection.reg.isTransfer = TRUE;
    outb(MIXER_CONTROL, channelSelection.data);
    
    outb(MIXER_CONTROL, boost);
}

static inline
void
resetMixer()
{
    setMasterOutputAttenuation(BOTH_CHANNELS,
	  DEFAULT_MASTER_OUTPUT_ATTENUATION);
	  
    setOutputAttenuation(PCM,
    	BOTH_CHANNELS,
	DEFAULT_OUTPUT_ATTENUATION);

    /*
     * mute all other output channels
     */

  
/* Don't mute this so that CD-Audio can get through, I have no idea why.
 *	Modified 12/8/94	Jason LaPierre	
 */
   setOutputAttenuation(INPUT_MIXER_LOOPBACK,
    	BOTH_CHANNELS,
	DEFAULT_OUTPUT_ATTENUATION);
    
    setMasterInputAttenuation(BOTH_CHANNELS,
        DEFAULT_MASTER_INPUT_ATTENUATION);
	
    setInputAttenuation(MICROPHONE,
    	BOTH_CHANNELS,
	DEFAULT_MICROPHONE_ATTENUATION);
	
    setInputAttenuation(EXTERNAL_LINE_IN,
        BOTH_CHANNELS, 
	DEFAULT_INPUT_ATTENUATION);

    /*
     * mute all other input channels
     */
    setInputAttenuation(FM_SYNTHESIS,
        BOTH_CHANNELS,
	MUTE);

/* Don't mute internal jack so that CD-Audio can get through
 *	Modified 12/8/94	Jason LaPierre	
 */
    setInputAttenuation(INTERNAL_LINE_IN,
         BOTH_CHANNELS,
	 DEFAULT_INPUT_ATTENUATION);
	 
    setInputAttenuation(SPEAKER,
        BOTH_CHANNELS,
	MUTE);
	
    setInputAttenuation(SOUNDBLASTER,
        BOTH_CHANNELS,
	MUTE);
    
    /*
     * set treble and bass boost to 0db
     */
     setBassControl(DEFAULT_BASS_BOOST);
     setTrebleControl(DEFAULT_TREBLE_BOOST);
}



/*
 * resetHardware uses "magic" values recommended by MediaVision. These 
 * settings are not always documented in the reference guide. In addition,
 * some of the values are specific to a particular version of the hardware.
 */
static inline
boolean_t
resetHardware()
{
    systemConfiguration1_t	systemConfiguration1;
    
    union {
	interruptControl_t	reg;
	unsigned char		data;
    } interruptControl;
    
    unsigned char		version;
    
    /*
     * The presence of the hardware is verified. The version bits in the
     * interrupt control register are read only. 
     */
    interruptControl.data = inb(INTERRUPT_CONTROL);
    
    if (interruptControl.data == 0xff)
	return FALSE;
    
    version = interruptControl.reg.version;
    interruptControl.reg.version = 0;
    
    outb(INTERRUPT_CONTROL, interruptControl.data);
    interruptControl.data = inb(INTERRUPT_CONTROL);
    
    if (interruptControl.reg.version != version)
        return FALSE;

    /*
     * Turn off MPU and SoundBlaster emulation
     *
    outb(COMPATIBILITY_ENABLE, 0);
   
    /*
     * Turn off MPU and SoundBlaster interrupts
     */   
    outb(EMULATION_CONFIGURATION, 0);

    /*
     * Sets wait state to 140ns period
     */
    outb(WAIT_STATE, WAIT_STATE_RESET);

    /*
     * D0 - resets FM
     * D1 - resets Codec
     * D2 - resets SoundBlaster
     * D4 - resets MVA508 Mixer
     */
    outb(AUDIO_MIXER, 0);
    outb(AUDIO_MIXER, AUDIO_MIXER_RESET);

    /*
     * This is required when using the prescale register for more precise
     * sample rate timing.
     */
    systemConfiguration1 = getSystemConfiguration1();
    systemConfiguration1.selectCompatibleClock = TRUE;
    setSystemConfiguration1(systemConfiguration1);

    outb(SYSTEM_CONFIGURATION_2, SYSTEM_CONFIGURATION_2_RESET);
    /*
     * D3 (invert bclk output)
     * D4 (use codec sync output)
     */ 
    outb(SYSTEM_CONFIGURATION_3, SYSTEM_CONFIGURATION_3_RESET);

    outb(SYSTEM_CONFIGURATION_4, SYSTEM_CONFIGURATION_4_RESET);
    
    /*
     * When a 16 bit Codec is attached, the Prescale counter is used to
     * set the ratio between the incoming Codec bit clock and the outgoing
     * master clock.
     */
    outb(PRESCALE_DIVIDER, PRESCALE_DIVIDER_RESET);
    
    resetMixer();
    return TRUE;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.