home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Examples / DriverKit / ProAudioSpectrum16 / ProAudioSpectrum16_reloc.tproj / ProAudioSpectrum16.m < prev    next >
Text File  |  1996-03-27  |  11KB  |  428 lines

  1. /*     Copyright (c) 1993-1996 NeXT Software, Inc.  All rights reserved. 
  2.  *
  3.  */
  4. #import "ProAudioSpectrum16.h"
  5. #import "ProAudioSpectrum16Registers.h"
  6. #import "ProAudioSpectrum16Inline.h"
  7.  
  8. #import <driverkit/generalFuncs.h>
  9.  
  10. static char pasDeviceName[] = "ProAudioSpectrum16";
  11. static char pasDeviceKind[] = "Audio";
  12.  
  13. @implementation ProAudioSpectrum16
  14.  
  15. /*
  16.  *  Probe and initialize new instance
  17.  */
  18. + (BOOL) probe:description
  19. {
  20.     ProAudioSpectrum16    *dev;
  21.     
  22.     dev = [self alloc];
  23.     if (dev == nil)
  24.         return NO;
  25.     
  26.     /*
  27.      * Sets the base IO address (needs to be performed before any other
  28.      * hardware access)
  29.      */
  30.     setBaseAddress(DEFAULT_BASE_ADDRESS);
  31.  
  32.     return [dev initFromDeviceDescription:description] != nil;
  33. }
  34.  
  35. - (BOOL) reset
  36. {
  37.     IOReturn    ioReturn;
  38.     unsigned int dmaChannel    = [[self deviceDescription] channel];
  39.     unsigned int interrupt    = [[self deviceDescription] interrupt];
  40.     IOEISADMATransferWidth    transferWidth = IO_16BitByteCount;
  41.     
  42.     [self setName: pasDeviceName];
  43.     [self setDeviceKind: pasDeviceKind];
  44.     
  45.     if (! (resetHardware())) {
  46.         IOLog("%s: hardware failed verification\n", [self name]);
  47.         return NO;
  48.     }
  49.     
  50.     /*
  51.      * The irq and dma channel are software selectable on the 
  52.      * ProAudioSpectrum16.
  53.      */
  54.     if (! (setDMAChannel(dmaChannel))) {
  55.         IOLog("%s: %d is an invalid dma setting\n",
  56.         [self name], dmaChannel);
  57.     return NO;
  58.     }
  59.  
  60.     if (! (setInterrupt(interrupt))) {
  61.         IOLog("%s: %d is an invalid irq setting\n",
  62.         [self name], interrupt);
  63.     return NO;
  64.     }
  65.  
  66.     /*
  67.      * The DMA controller is initialized.
  68.      */
  69.     [self disableChannel: 0];
  70.  
  71.     /*
  72.      * On both ISA and EISA machines, the ProAudioSpectrum16 hardware
  73.      * requires that DMA channels 0-4 are set to an 8-bit transfer width. 
  74.      */
  75.     if ([self isEISAPresent]) {
  76.         if (dmaChannel < 5)
  77.         transferWidth = IO_8Bit;
  78.         
  79.         ioReturn = [self setDMATransferWidth: transferWidth forChannel: 0];
  80.     if (ioReturn != IO_R_SUCCESS) {
  81.         IOLog("%s: dma transfer width error %d\n", [self name], ioReturn);
  82.         return NO;
  83.     }
  84.     }
  85.  
  86.     ioReturn = [self setTransferMode: IO_Single forChannel: 0];
  87.  
  88.     if (ioReturn != IO_R_SUCCESS)  {
  89.         IOLog("%s: dma transfer mode error %d\n", [self name], ioReturn);
  90.     return NO;
  91.     }
  92.  
  93.     ioReturn = [self setAutoinitialize: YES forChannel: 0];
  94.     if (ioReturn != IO_R_SUCCESS) {
  95.         IOLog("%s: dma auto initialize error %d", [self name], ioReturn);
  96.     return NO;
  97.     }
  98.  
  99.     return YES;
  100. }
  101.  
  102. /*
  103.  * converts gain (0 - 32768) into attenuation (0 - 31)
  104.  */
  105.  
  106. - (void) updateInputGainLeft
  107. {
  108.     unsigned int gain = [self inputGainLeft] / 1057;
  109.     
  110.     setInputAttenuation(MICROPHONE, LEFT_CHANNEL, (unsigned char) gain);
  111.     setInputAttenuation(EXTERNAL_LINE_IN, LEFT_CHANNEL, (unsigned char) gain);
  112. }
  113.  
  114. - (void)updateInputGainRight
  115. {
  116.     unsigned int gain = [self inputGainRight] / 1057;
  117.     
  118.     setInputAttenuation(MICROPHONE, RIGHT_CHANNEL, (unsigned char) gain);
  119.     setInputAttenuation(EXTERNAL_LINE_IN, RIGHT_CHANNEL, (unsigned char) gain);
  120. }
  121.  
  122. - (void)updateOutputMute
  123. {
  124.     enableAudioOutput(! [self isOutputMuted]);
  125. }
  126.  
  127. - (void)updateLoudnessEnhanced
  128. {
  129.     setLoudnessFilter([self isLoudnessEnhanced]);
  130. }
  131.  
  132. /*
  133.  * (0) - (-84) needs to be converted to (0) - (31)
  134.  */
  135. - (void) updateOutputAttenuationLeft
  136. {
  137.    unsigned int attenuation = [self outputAttenuationLeft] + 84;
  138.    attenuation = ((attenuation * 10)/27);
  139.     
  140.     setOutputAttenuation(PCM, LEFT_CHANNEL, (unsigned char) attenuation);
  141. }
  142.  
  143. /*
  144.  * (0) - (-84) needs to be converted to (0) - (32)
  145.  */
  146. - (void) updateOutputAttenuationRight
  147. {
  148.    unsigned int attenuation = [self outputAttenuationRight] + 84;
  149.    attenuation = ((attenuation * 10)/27);
  150.  
  151.     setOutputAttenuation(PCM, RIGHT_CHANNEL, (unsigned char) attenuation);
  152. }
  153.  
  154. - (IOReturn) enableAllInterrupts
  155. {
  156.     interruptStatus_t    interruptStatus = {0};
  157.     interruptControl_t    interruptControl = {0};
  158.     
  159.     /*
  160.      * clear all interrupts
  161.      */
  162.     setInterruptStatus(interruptStatus);
  163.  
  164.     interruptControl.enableSampleBufferInterrupt = YES;
  165.     setInterruptControl(interruptControl);
  166.     
  167.     return [super enableAllInterrupts];
  168. }
  169.  
  170. - (void) disableAllInterrupts
  171. {
  172.     interruptControl_t    interruptControl = {0};
  173.  
  174.     setInterruptControl(interruptControl);
  175.     
  176.     [super disableAllInterrupts];
  177. }
  178.  
  179.  
  180. - (BOOL) startDMAForChannel: (unsigned int) localChannel
  181.                        read: (BOOL) isRead
  182.                      buffer: (IOEISADMABuffer) buffer
  183.     bufferSizeForInterrupts: (unsigned int) bufferSize
  184. {
  185.  
  186.     IOReturn ioReturn;
  187.     unsigned int rate = [self sampleRate];
  188.     
  189.     IOEISADMATransferWidth    transferWidth;
  190.     
  191.     filterControl_t        filterControl        = {0};
  192.     crossChannelControl_t    crossChannelControl    = {0};
  193.     systemConfiguration2_t    systemConfiguration2    = {0};
  194.  
  195.  
  196.     /*
  197.      * Before enabling the DMA channel, "secure" the channel via the DRQ
  198.      * bit in the Cross Channel register (0xf8a). This causes the
  199.      * ProAudioSpectrum16 to drive the DMA channel from a floating state to
  200.      * a known good state. If you enable the DMA channel with an unsecured
  201.      * DRQ line, the DMA will perform a rapid-fire data tranfer due to the
  202.      * floating DRQ line.
  203.      */
  204.     crossChannelControl = getCrossChannelControl();
  205.     crossChannelControl.enableDMA = YES;
  206.     setCrossChannelControl(crossChannelControl);
  207.     
  208.     ioReturn = [self startDMAForBuffer: buffer channel: localChannel];
  209.  
  210.     if (ioReturn != IO_R_SUCCESS) {
  211.         IOLog("%s: could not start DMA channel error %d\n",
  212.         [self name], ioReturn);
  213.     return NO;
  214.     }
  215.         
  216.     ioReturn = [self enableChannel: localChannel];
  217.     
  218.     if (ioReturn != IO_R_SUCCESS) {
  219.         IOLog("%s: could not enable DMA channel error %d\n",
  220.         [self name], ioReturn);
  221.     return NO;
  222.     }
  223.  
  224.     (void) [self enableAllInterrupts];
  225.  
  226.     setSampleRateTimer(rate);
  227.    
  228.     /*
  229.      * Use the Sample Buffer Count register to set the number of bytes in the
  230.      * DMA buffer division. This register holds a 16-bit value. When using a
  231.      * 16-bit DMA channel, the Sample Buffer Count must be divided by two.
  232.      */
  233.     (void) [self getDMATransferWidth: &transferWidth forChannel: localChannel];
  234.     if (transferWidth == IO_16BitByteCount ||
  235.     transferWidth == IO_16BitWordCount)
  236.     setSampleBufferCounter(bufferSize / 2);
  237.     else
  238.     setSampleBufferCounter(bufferSize);
  239.      
  240.  
  241.     if ([self dataEncoding] == NX_SoundStreamDataEncoding_Linear16)
  242.     systemConfiguration2.dataEncoding = LINEAR_16;
  243.     else
  244.         systemConfiguration2.dataEncoding = LINEAR_8;
  245.     
  246.     setSystemConfiguration2(systemConfiguration2);
  247.     
  248.     crossChannelControl.rightToRight = YES;
  249.     crossChannelControl.leftToLeft = YES;
  250.  
  251.     crossChannelControl.direction = !isRead;
  252.     
  253.     /*
  254.      * The mixer has feedback problems. MediaVision advised us to mute
  255.      * the PCM output channel when recording.
  256.      */
  257.     if (isRead)
  258.         setOutputAttenuation(PCM, BOTH_CHANNELS, 0);
  259.     
  260.     if ([self channelCount] == 1) 
  261.         crossChannelControl.isMono = YES;
  262.     else
  263.         crossChannelControl.isMono = NO;
  264.     
  265.     setCrossChannelControl(crossChannelControl);
  266.     crossChannelControl.enablePCM = YES;
  267.     crossChannelControl.enableDMA = YES;
  268.     setCrossChannelControl(crossChannelControl);
  269.     
  270.     filterControl = getFilterControl();
  271.     filterControl.enableSampleRateTimer = YES;
  272.     filterControl.enableSampleBufferCounter = YES;
  273.     setFilterControl(filterControl);
  274.  
  275.     return YES;
  276. }
  277.  
  278. - (void) stopDMAForChannel: (unsigned int) localChannel read: (BOOL) isRead
  279. {
  280.     filterControl_t        filterControl        = {0};
  281.     crossChannelControl_t    crossChannelControl    = {0};
  282.  
  283.     [self disableChannel: localChannel];
  284.     
  285.     filterControl = getFilterControl();
  286.     filterControl.enableSampleRateTimer = NO;
  287.     filterControl.enableSampleBufferCounter = NO;
  288.     setFilterControl(filterControl);
  289.  
  290.     (void)[self disableAllInterrupts];   
  291.  
  292.     crossChannelControl = getCrossChannelControl();
  293.     crossChannelControl.enablePCM = NO;
  294.     setCrossChannelControl(crossChannelControl);
  295.     crossChannelControl.enableDMA = NO;
  296.     setCrossChannelControl(crossChannelControl);
  297.     
  298.     /*
  299.      * Due to mixer feedback problems, the PCM channels are muted during
  300.      * recording. Their current values are restored here.
  301.      */
  302.     if (isRead) {
  303.         [self updateOutputAttenuationLeft];
  304.     [self updateOutputAttenuationRight];
  305.     }
  306. }
  307.  
  308. static void clearInterrupts(void)
  309. {
  310.     interruptStatus_t    interruptStatus = {0};
  311.  
  312.     /*
  313.      * clear the hardware interrupt register
  314.      */
  315.     interruptStatus = getInterruptStatus();
  316.     if (! interruptStatus.sampleBufferInterruptPending)
  317.     return;
  318.     
  319.     /*
  320.      * The chip specification states that a write to this register
  321.      * will clear the clip status and sample interrupts.
  322.      */
  323.     interruptStatus.sampleBufferInterruptPending = NO;
  324.     setInterruptStatus(interruptStatus);
  325. }
  326.  
  327. - (IOAudioInterruptClearFunc) interruptClearFunc
  328. {
  329.     return clearInterrupts;
  330. }
  331.  
  332. - (void) interruptOccurredForInput: (BOOL*)serviceInput
  333.                          forOutput:(BOOL*)serviceOutput
  334. {
  335.     interruptStatus_t    interruptStatus = {0};
  336.  
  337.     /*
  338.      * clear the hardware interrupt register
  339.      */
  340.     interruptStatus = getInterruptStatus();
  341.     if (! interruptStatus.sampleBufferInterruptPending) {
  342.     IOLog("ProAudioSpectrum16: spurious dma interrupt\n");
  343.     return;
  344.     }
  345.     
  346.     /*
  347.      * The chip specification states that a write to this register
  348.      * will clear the clip status and sample interrupts.
  349.      */
  350.     interruptStatus.sampleBufferInterruptPending = NO;
  351.     setInterruptStatus(interruptStatus);
  352.  
  353.     if ([self isInputActive])
  354.         *serviceInput = YES;
  355.     else
  356.         *serviceOutput = YES;
  357. }
  358.  
  359. - (void) timeoutOccurred
  360. {
  361.     crossChannelControl_t    crossChannelControl    = {0};
  362.  
  363.     crossChannelControl = getCrossChannelControl();
  364.     crossChannelControl.enablePCM = NO;
  365.     setCrossChannelControl(crossChannelControl);
  366.     crossChannelControl.enablePCM = YES;
  367.     setCrossChannelControl(crossChannelControl);
  368. }
  369.  
  370. /*
  371.  * Parameter access.
  372.  */
  373.  
  374. - (BOOL)acceptsContinuousSamplingRates
  375. {
  376.     return YES;
  377. }
  378.  
  379. - (void)getSamplingRatesLow: (int *)lowRate
  380.                        high: (int *)highRate
  381. {
  382.     *lowRate = 2000;
  383.     *highRate = 44100;
  384. }
  385.  
  386. - (void)getSamplingRates: (int *)rates
  387.                    count: (unsigned int *)numRates
  388. {
  389.     /* Return a few common rates */
  390.     rates[0] = 2000;
  391.     rates[1] = 8000;
  392.     rates[2] = 11025;
  393.     rates[3] = 16000;
  394.     rates[4] = 22050;
  395.     rates[5] = 32000;
  396.     rates[6] = 44100;
  397.     *numRates = 7;
  398. }
  399.  
  400. - (void)getDataEncodings: (NXSoundParameterTag *)encodings
  401.                    count: (unsigned int *)numEncodings
  402. {
  403.     IOEISADMATransferWidth transferWidth;
  404.  
  405.     encodings[0] = NX_SoundStreamDataEncoding_Linear8;
  406.     encodings[1] = NX_SoundStreamDataEncoding_Linear16;
  407.     *numEncodings = 2;
  408.  
  409.     /*
  410.      * For EISA machines, the driver is unable to handle 16-bit linear data
  411.      * when the DMA transfer width is 8 bits.
  412.      */
  413.     if ([self isEISAPresent]) {
  414.         (void)[self getDMATransferWidth: &transferWidth forChannel: 0];
  415.     if (transferWidth == IO_8Bit) {
  416.         encodings[1] = 0;
  417.         *numEncodings = 1;
  418.     }
  419.     }
  420. }
  421.  
  422. - (unsigned int) channelCountLimit
  423. {
  424.     return 2;    /* stereo and mono */
  425. }
  426.  
  427. @end
  428.