home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OpenStep 4.2J (Developer)
/
os42jdev.iso
/
NextDeveloper
/
Examples
/
DriverKit
/
ProAudioSpectrum16
/
ProAudioSpectrum16_reloc.tproj
/
ProAudioSpectrum16.m
< prev
next >
Wrap
Text File
|
1996-03-27
|
11KB
|
428 lines
/* Copyright (c) 1993-1996 NeXT Software, Inc. All rights reserved.
*
*/
#import "ProAudioSpectrum16.h"
#import "ProAudioSpectrum16Registers.h"
#import "ProAudioSpectrum16Inline.h"
#import <driverkit/generalFuncs.h>
static char pasDeviceName[] = "ProAudioSpectrum16";
static char pasDeviceKind[] = "Audio";
@implementation ProAudioSpectrum16
/*
* Probe and initialize new instance
*/
+ (BOOL) probe:description
{
ProAudioSpectrum16 *dev;
dev = [self alloc];
if (dev == nil)
return NO;
/*
* Sets the base IO address (needs to be performed before any other
* hardware access)
*/
setBaseAddress(DEFAULT_BASE_ADDRESS);
return [dev initFromDeviceDescription:description] != nil;
}
- (BOOL) reset
{
IOReturn ioReturn;
unsigned int dmaChannel = [[self deviceDescription] channel];
unsigned int interrupt = [[self deviceDescription] interrupt];
IOEISADMATransferWidth transferWidth = IO_16BitByteCount;
[self setName: pasDeviceName];
[self setDeviceKind: pasDeviceKind];
if (! (resetHardware())) {
IOLog("%s: hardware failed verification\n", [self name]);
return NO;
}
/*
* The irq and dma channel are software selectable on the
* ProAudioSpectrum16.
*/
if (! (setDMAChannel(dmaChannel))) {
IOLog("%s: %d is an invalid dma setting\n",
[self name], dmaChannel);
return NO;
}
if (! (setInterrupt(interrupt))) {
IOLog("%s: %d is an invalid irq setting\n",
[self name], interrupt);
return NO;
}
/*
* The DMA controller is initialized.
*/
[self disableChannel: 0];
/*
* On both ISA and EISA machines, the ProAudioSpectrum16 hardware
* requires that DMA channels 0-4 are set to an 8-bit transfer width.
*/
if ([self isEISAPresent]) {
if (dmaChannel < 5)
transferWidth = IO_8Bit;
ioReturn = [self setDMATransferWidth: transferWidth forChannel: 0];
if (ioReturn != IO_R_SUCCESS) {
IOLog("%s: dma transfer width error %d\n", [self name], ioReturn);
return NO;
}
}
ioReturn = [self setTransferMode: IO_Single forChannel: 0];
if (ioReturn != IO_R_SUCCESS) {
IOLog("%s: dma transfer mode error %d\n", [self name], ioReturn);
return NO;
}
ioReturn = [self setAutoinitialize: YES forChannel: 0];
if (ioReturn != IO_R_SUCCESS) {
IOLog("%s: dma auto initialize error %d", [self name], ioReturn);
return NO;
}
return YES;
}
/*
* converts gain (0 - 32768) into attenuation (0 - 31)
*/
- (void) updateInputGainLeft
{
unsigned int gain = [self inputGainLeft] / 1057;
setInputAttenuation(MICROPHONE, LEFT_CHANNEL, (unsigned char) gain);
setInputAttenuation(EXTERNAL_LINE_IN, LEFT_CHANNEL, (unsigned char) gain);
}
- (void)updateInputGainRight
{
unsigned int gain = [self inputGainRight] / 1057;
setInputAttenuation(MICROPHONE, RIGHT_CHANNEL, (unsigned char) gain);
setInputAttenuation(EXTERNAL_LINE_IN, RIGHT_CHANNEL, (unsigned char) gain);
}
- (void)updateOutputMute
{
enableAudioOutput(! [self isOutputMuted]);
}
- (void)updateLoudnessEnhanced
{
setLoudnessFilter([self isLoudnessEnhanced]);
}
/*
* (0) - (-84) needs to be converted to (0) - (31)
*/
- (void) updateOutputAttenuationLeft
{
unsigned int attenuation = [self outputAttenuationLeft] + 84;
attenuation = ((attenuation * 10)/27);
setOutputAttenuation(PCM, LEFT_CHANNEL, (unsigned char) attenuation);
}
/*
* (0) - (-84) needs to be converted to (0) - (32)
*/
- (void) updateOutputAttenuationRight
{
unsigned int attenuation = [self outputAttenuationRight] + 84;
attenuation = ((attenuation * 10)/27);
setOutputAttenuation(PCM, RIGHT_CHANNEL, (unsigned char) attenuation);
}
- (IOReturn) enableAllInterrupts
{
interruptStatus_t interruptStatus = {0};
interruptControl_t interruptControl = {0};
/*
* clear all interrupts
*/
setInterruptStatus(interruptStatus);
interruptControl.enableSampleBufferInterrupt = YES;
setInterruptControl(interruptControl);
return [super enableAllInterrupts];
}
- (void) disableAllInterrupts
{
interruptControl_t interruptControl = {0};
setInterruptControl(interruptControl);
[super disableAllInterrupts];
}
- (BOOL) startDMAForChannel: (unsigned int) localChannel
read: (BOOL) isRead
buffer: (IOEISADMABuffer) buffer
bufferSizeForInterrupts: (unsigned int) bufferSize
{
IOReturn ioReturn;
unsigned int rate = [self sampleRate];
IOEISADMATransferWidth transferWidth;
filterControl_t filterControl = {0};
crossChannelControl_t crossChannelControl = {0};
systemConfiguration2_t systemConfiguration2 = {0};
/*
* Before enabling the DMA channel, "secure" the channel via the DRQ
* bit in the Cross Channel register (0xf8a). This causes the
* ProAudioSpectrum16 to drive the DMA channel from a floating state to
* a known good state. If you enable the DMA channel with an unsecured
* DRQ line, the DMA will perform a rapid-fire data tranfer due to the
* floating DRQ line.
*/
crossChannelControl = getCrossChannelControl();
crossChannelControl.enableDMA = YES;
setCrossChannelControl(crossChannelControl);
ioReturn = [self startDMAForBuffer: buffer channel: localChannel];
if (ioReturn != IO_R_SUCCESS) {
IOLog("%s: could not start DMA channel error %d\n",
[self name], ioReturn);
return NO;
}
ioReturn = [self enableChannel: localChannel];
if (ioReturn != IO_R_SUCCESS) {
IOLog("%s: could not enable DMA channel error %d\n",
[self name], ioReturn);
return NO;
}
(void) [self enableAllInterrupts];
setSampleRateTimer(rate);
/*
* Use the Sample Buffer Count register to set the number of bytes in the
* DMA buffer division. This register holds a 16-bit value. When using a
* 16-bit DMA channel, the Sample Buffer Count must be divided by two.
*/
(void) [self getDMATransferWidth: &transferWidth forChannel: localChannel];
if (transferWidth == IO_16BitByteCount ||
transferWidth == IO_16BitWordCount)
setSampleBufferCounter(bufferSize / 2);
else
setSampleBufferCounter(bufferSize);
if ([self dataEncoding] == NX_SoundStreamDataEncoding_Linear16)
systemConfiguration2.dataEncoding = LINEAR_16;
else
systemConfiguration2.dataEncoding = LINEAR_8;
setSystemConfiguration2(systemConfiguration2);
crossChannelControl.rightToRight = YES;
crossChannelControl.leftToLeft = YES;
crossChannelControl.direction = !isRead;
/*
* The mixer has feedback problems. MediaVision advised us to mute
* the PCM output channel when recording.
*/
if (isRead)
setOutputAttenuation(PCM, BOTH_CHANNELS, 0);
if ([self channelCount] == 1)
crossChannelControl.isMono = YES;
else
crossChannelControl.isMono = NO;
setCrossChannelControl(crossChannelControl);
crossChannelControl.enablePCM = YES;
crossChannelControl.enableDMA = YES;
setCrossChannelControl(crossChannelControl);
filterControl = getFilterControl();
filterControl.enableSampleRateTimer = YES;
filterControl.enableSampleBufferCounter = YES;
setFilterControl(filterControl);
return YES;
}
- (void) stopDMAForChannel: (unsigned int) localChannel read: (BOOL) isRead
{
filterControl_t filterControl = {0};
crossChannelControl_t crossChannelControl = {0};
[self disableChannel: localChannel];
filterControl = getFilterControl();
filterControl.enableSampleRateTimer = NO;
filterControl.enableSampleBufferCounter = NO;
setFilterControl(filterControl);
(void)[self disableAllInterrupts];
crossChannelControl = getCrossChannelControl();
crossChannelControl.enablePCM = NO;
setCrossChannelControl(crossChannelControl);
crossChannelControl.enableDMA = NO;
setCrossChannelControl(crossChannelControl);
/*
* Due to mixer feedback problems, the PCM channels are muted during
* recording. Their current values are restored here.
*/
if (isRead) {
[self updateOutputAttenuationLeft];
[self updateOutputAttenuationRight];
}
}
static void clearInterrupts(void)
{
interruptStatus_t interruptStatus = {0};
/*
* clear the hardware interrupt register
*/
interruptStatus = getInterruptStatus();
if (! interruptStatus.sampleBufferInterruptPending)
return;
/*
* The chip specification states that a write to this register
* will clear the clip status and sample interrupts.
*/
interruptStatus.sampleBufferInterruptPending = NO;
setInterruptStatus(interruptStatus);
}
- (IOAudioInterruptClearFunc) interruptClearFunc
{
return clearInterrupts;
}
- (void) interruptOccurredForInput: (BOOL*)serviceInput
forOutput:(BOOL*)serviceOutput
{
interruptStatus_t interruptStatus = {0};
/*
* clear the hardware interrupt register
*/
interruptStatus = getInterruptStatus();
if (! interruptStatus.sampleBufferInterruptPending) {
IOLog("ProAudioSpectrum16: spurious dma interrupt\n");
return;
}
/*
* The chip specification states that a write to this register
* will clear the clip status and sample interrupts.
*/
interruptStatus.sampleBufferInterruptPending = NO;
setInterruptStatus(interruptStatus);
if ([self isInputActive])
*serviceInput = YES;
else
*serviceOutput = YES;
}
- (void) timeoutOccurred
{
crossChannelControl_t crossChannelControl = {0};
crossChannelControl = getCrossChannelControl();
crossChannelControl.enablePCM = NO;
setCrossChannelControl(crossChannelControl);
crossChannelControl.enablePCM = YES;
setCrossChannelControl(crossChannelControl);
}
/*
* Parameter access.
*/
- (BOOL)acceptsContinuousSamplingRates
{
return YES;
}
- (void)getSamplingRatesLow: (int *)lowRate
high: (int *)highRate
{
*lowRate = 2000;
*highRate = 44100;
}
- (void)getSamplingRates: (int *)rates
count: (unsigned int *)numRates
{
/* Return a few common rates */
rates[0] = 2000;
rates[1] = 8000;
rates[2] = 11025;
rates[3] = 16000;
rates[4] = 22050;
rates[5] = 32000;
rates[6] = 44100;
*numRates = 7;
}
- (void)getDataEncodings: (NXSoundParameterTag *)encodings
count: (unsigned int *)numEncodings
{
IOEISADMATransferWidth transferWidth;
encodings[0] = NX_SoundStreamDataEncoding_Linear8;
encodings[1] = NX_SoundStreamDataEncoding_Linear16;
*numEncodings = 2;
/*
* For EISA machines, the driver is unable to handle 16-bit linear data
* when the DMA transfer width is 8 bits.
*/
if ([self isEISAPresent]) {
(void)[self getDMATransferWidth: &transferWidth forChannel: 0];
if (transferWidth == IO_8Bit) {
encodings[1] = 0;
*numEncodings = 1;
}
}
}
- (unsigned int) channelCountLimit
{
return 2; /* stereo and mono */
}
@end