home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.2 (Developer) / NS_dev_3.2.iso / NextDeveloper / Examples / DriverKit / ProAudioSpectrum / ProAudioSpectrum_reloc.tproj / ProAudioSpectrum.m < prev    next >
Text File  |  1993-08-06  |  11KB  |  425 lines

  1. /*     Copyright (c) 1993 NeXT Computer, Inc.  All rights reserved. 
  2.  *
  3.  */
  4. #import "ProAudioSpectrum.h"
  5. #import "ProAudioSpectrumRegisters.h"
  6. #import "ProAudioSpectrumInline.h"
  7.  
  8. #import <driverkit/generalFuncs.h>
  9.  
  10. static char pasDeviceName[] = "ProAudioSpectrum";
  11. static char pasDeviceKind[] = "Audio";
  12.  
  13. @implementation ProAudioSpectrum
  14.  
  15. /*
  16.  *  Probe and initialize new instance
  17.  */
  18. + (BOOL) probe:description
  19. {
  20.     ProAudioSpectrum    *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 channel    = [[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.      * ProAudioSpectrum.
  53.      */
  54.     if (! (setDMAChannel(channel))) {
  55.         IOLog("%s: %d is an invalid dma setting\n",
  56.         [self name], channel);
  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 ProAudioSpectrum hardware requires that
  73.      * DMA channels 0-4 are set to an 8-bit transfer width.
  74.      */
  75.     if ([self isEISAPresent]) {
  76.         if (channel < 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. - (BOOL) startDMAForChannel: (unsigned int) localChannel
  180.                        read: (BOOL) isRead
  181.                      buffer: (IOEISADMABuffer) buffer
  182.     bufferSizeForInterrupts: (unsigned int) bufferSize
  183. {
  184.  
  185.     IOReturn ioReturn;
  186.     unsigned int rate = [self sampleRate];
  187.     
  188.     IOEISADMATransferWidth    transferWidth;
  189.     
  190.     filterControl_t        filterControl        = {0};
  191.     crossChannelControl_t    crossChannelControl    = {0};
  192.     systemConfiguration2_t    systemConfiguration2    = {0};
  193.  
  194.  
  195.     /*
  196.      * Before enabling the DMA channel, "secure" the channel via the DRQ
  197.      * bit in the Cross Channel register (0xf8a). This causes the
  198.      * ProAudioSpectrum to drive the DMA channel from a floating state to
  199.      * a known good state. If you enable the DMA channel with an unsecured
  200.      * DRQ line, the DMA will perform a rapid-fire data tranfer due to the
  201.      * floating DRQ line.
  202.      */
  203.     crossChannelControl = getCrossChannelControl();
  204.     crossChannelControl.enableDMA = YES;
  205.     setCrossChannelControl(crossChannelControl);
  206.     
  207.     ioReturn = [self startDMAForBuffer: buffer channel: localChannel];
  208.  
  209.     if (ioReturn != IO_R_SUCCESS) {
  210.         IOLog("%s: could not start DMA channel error %d\n",
  211.         [self name], ioReturn);
  212.     return NO;
  213.     }
  214.         
  215.     ioReturn = [self enableChannel: localChannel];
  216.     
  217.     if (ioReturn != IO_R_SUCCESS) {
  218.         IOLog("%s: could not enable DMA channel error %d\n",
  219.         [self name], ioReturn);
  220.     return NO;
  221.     }
  222.  
  223.     (void) [self enableAllInterrupts];
  224.  
  225.     setSampleRateTimer(rate);
  226.    
  227.     /*
  228.      * Use the Sample Buffer Count register to set the number of bytes in the
  229.      * DMA buffer division. This register holds a 16-bit value. When using a
  230.      * 16-bit DMA channel, the Sample Buffer Count must be divided by two.
  231.      */
  232.     (void) [self getDMATransferWidth: &transferWidth forChannel: localChannel];
  233.     if (transferWidth == IO_16BitByteCount)
  234.     bufferSize /= 2;
  235.      
  236.     setSampleBufferCounter(bufferSize);
  237.  
  238.     if ([self dataEncoding] == NX_SoundStreamDataEncoding_Linear16)
  239.     systemConfiguration2.dataEncoding = LINEAR_16;
  240.     else
  241.         systemConfiguration2.dataEncoding = LINEAR_8;
  242.     
  243.     setSystemConfiguration2(systemConfiguration2);
  244.     
  245.     crossChannelControl.rightToRight = YES;
  246.     crossChannelControl.leftToLeft = YES;
  247.  
  248.     crossChannelControl.direction = !isRead;
  249.     
  250.     /*
  251.      * The mixer has feedback problems. MediaVision advised us to mute
  252.      * the PCM output channel when recording.
  253.      */
  254.     if (isRead)
  255.         setOutputAttenuation(PCM, BOTH_CHANNELS, 0);
  256.     
  257.     if ([self channelCount] == 1) 
  258.         crossChannelControl.isMono = YES;
  259.     else
  260.         crossChannelControl.isMono = NO;
  261.     
  262.     setCrossChannelControl(crossChannelControl);
  263.     crossChannelControl.enablePCM = YES;
  264.     crossChannelControl.enableDMA = YES;
  265.     setCrossChannelControl(crossChannelControl);
  266.     
  267.     filterControl = getFilterControl();
  268.     filterControl.enableSampleRateTimer = YES;
  269.     filterControl.enableSampleBufferCounter = YES;
  270.     setFilterControl(filterControl);
  271.  
  272.     return YES;
  273. }
  274.  
  275. - (void) stopDMAForChannel: (unsigned int) localChannel read: (BOOL) isRead
  276. {
  277.     filterControl_t        filterControl        = {0};
  278.     crossChannelControl_t    crossChannelControl    = {0};
  279.  
  280.     [self disableChannel: localChannel];
  281.     
  282.     filterControl = getFilterControl();
  283.     filterControl.enableSampleRateTimer = NO;
  284.     filterControl.enableSampleBufferCounter = NO;
  285.     setFilterControl(filterControl);
  286.  
  287.     (void)[self disableAllInterrupts];   
  288.  
  289.     crossChannelControl = getCrossChannelControl();
  290.     crossChannelControl.enablePCM = NO;
  291.     setCrossChannelControl(crossChannelControl);
  292.     crossChannelControl.enableDMA = NO;
  293.     setCrossChannelControl(crossChannelControl);
  294.     
  295.     /*
  296.      * Due to mixer feedback problems, the PCM channels are muted during
  297.      * recording. Their current values are restored here.
  298.      */
  299.     if (isRead) {
  300.         [self updateOutputAttenuationLeft];
  301.     [self updateOutputAttenuationRight];
  302.     }
  303. }
  304.  
  305. static void clearInterrupts(void)
  306. {
  307.     interruptStatus_t    interruptStatus = {0};
  308.  
  309.     /*
  310.      * clear the hardware interrupt register
  311.      */
  312.     interruptStatus = getInterruptStatus();
  313.     if (! interruptStatus.sampleBufferInterruptPending)
  314.     return;
  315.     
  316.     /*
  317.      * The chip specification states that a write to this register
  318.      * will clear the clip status and sample interrupts.
  319.      */
  320.     interruptStatus.sampleBufferInterruptPending = NO;
  321.     setInterruptStatus(interruptStatus);
  322. }
  323.  
  324. - (IOAudioInterruptClearFunc) interruptClearFunc
  325. {
  326.     return clearInterrupts;
  327. }
  328.  
  329. - (void) interruptOccurredForInput: (BOOL*)serviceInput
  330.                          forOutput:(BOOL*)serviceOutput
  331. {
  332.     interruptStatus_t    interruptStatus = {0};
  333.  
  334.     /*
  335.      * clear the hardware interrupt register
  336.      */
  337.     interruptStatus = getInterruptStatus();
  338.     if (! interruptStatus.sampleBufferInterruptPending) {
  339.     IOLog("ProAudioSpectrum: spurious dma interrupt\n");
  340.     return;
  341.     }
  342.     
  343.     /*
  344.      * The chip specification states that a write to this register
  345.      * will clear the clip status and sample interrupts.
  346.      */
  347.     interruptStatus.sampleBufferInterruptPending = NO;
  348.     setInterruptStatus(interruptStatus);
  349.  
  350.     if ([self isInputActive])
  351.         *serviceInput = YES;
  352.     else
  353.         *serviceOutput = YES;
  354. }
  355.  
  356. - (void) timeoutOccurred
  357. {
  358.     crossChannelControl_t    crossChannelControl    = {0};
  359.  
  360.     crossChannelControl = getCrossChannelControl();
  361.     crossChannelControl.enablePCM = NO;
  362.     setCrossChannelControl(crossChannelControl);
  363.     crossChannelControl.enablePCM = YES;
  364.     setCrossChannelControl(crossChannelControl);
  365. }
  366.  
  367. /*
  368.  * Parameter access.
  369.  */
  370.  
  371. - (BOOL)acceptsContinuousSamplingRates
  372. {
  373.     return YES;
  374. }
  375.  
  376. - (void)getSamplingRatesLow: (int *)lowRate
  377.                        high: (int *)highRate
  378. {
  379.     *lowRate = 2000;
  380.     *highRate = 44100;
  381. }
  382.  
  383. - (void)getSamplingRates: (int *)rates
  384.                    count: (unsigned int *)numRates
  385. {
  386.     /* Return a few common rates */
  387.     rates[0] = 2000;
  388.     rates[1] = 8000;
  389.     rates[2] = 11025;
  390.     rates[3] = 16000;
  391.     rates[4] = 22050;
  392.     rates[5] = 32000;
  393.     rates[6] = 44100;
  394.     *numRates = 7;
  395. }
  396.  
  397. - (void)getDataEncodings: (NXSoundParameterTag *)encodings
  398.                    count: (unsigned int *)numEncodings
  399. {
  400.     IOEISADMATransferWidth transferWidth;
  401.  
  402.     encodings[0] = NX_SoundStreamDataEncoding_Linear8;
  403.     encodings[1] = NX_SoundStreamDataEncoding_Linear16;
  404.     *numEncodings = 2;
  405.  
  406.     /*
  407.      * For EISA machines, the driver is unable to handle 16-bit linear data
  408.      * when the DMA transfer width is 8 bits.
  409.      */
  410.     if ([self isEISAPresent]) {
  411.         (void)[self getDMATransferWidth: &transferWidth forChannel: 0];
  412.     if (transferWidth == IO_8Bit) {
  413.         encodings[1] = 0;
  414.         *numEncodings = 1;
  415.     }
  416.     }
  417. }
  418.  
  419. - (unsigned int) channelCountLimit
  420. {
  421.     return 2;    /* stereo and mono */
  422. }
  423.  
  424. @end
  425.