Annotation of Examples/DriverKit/SoundBlaster8/SoundBlaster8_reloc.tproj/SoundBlaster8.m, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1994 NeXT Computer, Inc.  All rights reserved. 
                      3:  *
                      4:  * HISTORY
                      5:  * 4-Mar-94    Rakesh Dubey at NeXT
                      6:  *      Created. 
                      7:  */
                      8: 
                      9: #import "SoundBlaster8.h"
                     10: #import "SoundBlaster8Registers.h"
                     11: 
                     12: #import <driverkit/generalFuncs.h>
                     13: 
                     14: static const char codecDeviceName[] = "SoundBlaster8";
                     15: static const char codecDeviceKind[] = "Audio";
                     16: 
                     17: static  sbCardParameters_t sbCardType;         // hardware type
                     18: static  BOOL lowSpeedDMA;                      // different programming
                     19: 
                     20: /*
                     21:  * Include inline functions. 
                     22:  */
                     23: #import "SoundBlaster8Inline.h"
                     24: 
                     25: @implementation SoundBlaster8
                     26: 
                     27: /*
                     28:  * Probe and initialize new instance 
                     29:  */
                     30: + (BOOL) probe:deviceDescription
                     31: {
                     32:     SoundBlaster8       *dev;
                     33:     IORange             *portRangeList;
                     34:     int                 numPortRanges;
                     35:     unsigned int        baseAddress;
                     36: 
                     37: #ifdef DEBUG
                     38:     int                 i;
                     39: #endif DEBUG
                     40:  
                     41:     dev = [self alloc];
                     42:     if (dev == nil)
                     43:         return NO;
                     44: 
                     45:     portRangeList = [deviceDescription portRangeList];
                     46:     numPortRanges = [deviceDescription numPortRanges];
                     47:     
                     48:     if (numPortRanges < 1)
                     49:        return NO;
                     50: 
                     51: #ifdef DEBUG
                     52:     for (i=0; i < numPortRanges; i++) {
                     53:         IOLog("SoundBlaster8: port %x %d\n",
                     54:                 portRangeList[i].start, portRangeList[i].size);
                     55:     }
                     56: #endif DEBUG
                     57: 
                     58:     baseAddress = portRangeList[0].start;
                     59: #ifdef DEBUG
                     60:     IOLog("SoundBlaster8: Base address = 0x%x.\n", baseAddress);
                     61: #endif DEBUG
                     62: 
                     63: 
                     64:     /*
                     65:      * Check base address to verify if this is a legal address.
                     66:      */
                     67: 
                     68:     if ((baseAddress == SB_BASE_ADDRESS_1) ||
                     69:         (baseAddress == SB_BASE_ADDRESS_2) ||
                     70:         (baseAddress == SB_BASE_ADDRESS_3) ||
                     71:         (baseAddress == SB_BASE_ADDRESS_4) ||
                     72:         (baseAddress == SB_BASE_ADDRESS_5) ||
                     73:         (baseAddress == SB_BASE_ADDRESS_6))     {
                     74:         sbBaseRegisterAddress = baseAddress;
                     75:     } else {
                     76:         IOLog("SoundBlaster8: Invalid port address 0x%0x.\n", baseAddress);
                     77:         [dev free];
                     78:         return NO;
                     79:     }
                     80: 
                     81:     /*
                     82:      * Now assign all SB DSP and Mixer registers their addresses.
                     83:      */
                     84:     assignDSPRegAddresses();
                     85:     assignMixerRegAddresses();
                     86:     
                     87:     return [dev initFromDeviceDescription:deviceDescription] != nil;
                     88: }
                     89: 
                     90: 
                     91: - (BOOL)reset
                     92: {
                     93:     unsigned int channel        = [[self deviceDescription] channel];
                     94:     unsigned int interrupt      = [[self deviceDescription] interrupt];
                     95: 
                     96:     IOReturn ioReturn;
                     97: 
                     98:     [self setName:codecDeviceName];
                     99:     [self setDeviceKind:codecDeviceKind];
                    100: 
                    101:     /*
                    102:      * Are user selections valid?
                    103:      */
                    104:     if (checkSelectedDMAAndIRQ(channel, interrupt) == NO) {
                    105:        return NO;
                    106:     }
                    107:     
                    108:     /*
                    109:      * Now that all hardware parameters have been assigned and/or verified
                    110:      * initialize the hardware.
                    111:      */
                    112:     [self initializeHardware];
                    113: 
                    114:     /*
                    115:      * This driver is only for 8-bit Sound Blaster cards. If this is not one
                    116:      * of these systems we quit since the test is fully reliable.
                    117:      */
                    118:     
                    119:     switch (sbCardType.version) {
                    120:       case SB_CLASSIC:
                    121:         sbCardType.name = "Classic";
                    122:         break;
                    123:       case SB_20:
                    124:         sbCardType.name = "2.0";
                    125:         break;
                    126:       case SB_PRO:
                    127:         sbCardType.name = "Pro";
                    128:         break;
                    129:       case SB_16:
                    130:         sbCardType.name = "Pro";
                    131:         sbCardType.version = SB_PRO;    /* SB16 will emulate it */
                    132:         break;
                    133:       default:  {
                    134:         IOLog("SoundBlaster8: Hardware not detected at port 0x%0x.\n",
                    135:                sbBaseRegisterAddress);
                    136:         return NO;
                    137:       }
                    138:     }
                    139:     
                    140:     IOLog("SoundBlaster8: Sound Blaster %s (ver %d.%d) at port 0x%0x.\n", 
                    141:                 sbCardType.name, 
                    142:                 sbCardType.majorVersion, sbCardType.minorVersion, 
                    143:                 sbBaseRegisterAddress);
                    144:     
                    145:     /*
                    146:      * Initialize DMA controller.
                    147:      */
                    148:      
                    149:     [self disableChannel: 0];
                    150: 
                    151:     /*
                    152:      * This call is only applicable in EISA systems. All dma channels
                    153:      * that are available to this driver in ISA machines are 8-bit. So we do
                    154:      * this setup only for EISA machines. 
                    155:      */
                    156:     if ([self isEISAPresent]) {
                    157:         ioReturn = [self setDMATransferWidth:IO_8Bit forChannel:0];
                    158:         if (ioReturn != IO_R_SUCCESS) {
                    159:             IOLog("SoundBlaster8: could not set transfer width to 8 bits, error %d.\n", ioReturn);
                    160:             return NO;
                    161:         }
                    162:     }
                    163:     
                    164:     ioReturn = [self setTransferMode: IO_Single forChannel: 0];
                    165:     if (ioReturn != IO_R_SUCCESS)  {
                    166:         IOLog("%s: dma transfer mode error %d\n", [self name], ioReturn);
                    167:         return NO;
                    168:     }
                    169: 
                    170:     /*
                    171:      * We will program the DMA controller in auto-init mode but the card is
                    172:      * in single cycle mode. So at every interrupt we only need to reprogram
                    173:      * the card.
                    174:      */
                    175:     ioReturn = [self setAutoinitialize: YES forChannel: 0];
                    176:     if (ioReturn != IO_R_SUCCESS) {
                    177:         IOLog("%s: dma auto initialize error %d", [self name], ioReturn);
                    178:         return NO;
                    179:     }
                    180:     
                    181:     return YES;
                    182: }
                    183: 
                    184: 
                    185: - (void) initializeHardware
                    186: {
                    187:     resetHardware();
                    188: }
                    189: 
                    190: /*
                    191:  * Converts gain (0 - 32768) into hardware supported gain (0 - 7). If the
                    192:  * input source is line (not supported now), simply double the gain. 
                    193:  */
                    194: 
                    195: - (void)updateInputGainLeft
                    196: {
                    197:     unsigned int gain = [self inputGainLeft];
                    198:     unsigned int left  = 0;
                    199:     
                    200:     if (gain)
                    201:         left = ((gain * MAX_INPUT_GAIN_MICROPHONE)/32768);
                    202:     else
                    203:         left = gain;    // minimum input gain = 0
                    204:         
                    205:     setInputGain(LEFT_CHANNEL, left);
                    206: #ifdef DEBUG
                    207:     IOLog("%s: updateInputGainLeft %d based on gain %d\n", [self name],left, gain);
                    208: #endif DEBUG
                    209: }
                    210: 
                    211: /*
                    212:  * Converts gain (0 - 32768) into hardware supported gain (0 - 7)
                    213:  */
                    214: 
                    215: - (void)updateInputGainRight
                    216: {
                    217:     unsigned int gain = [self inputGainRight];
                    218:     unsigned int right = 0;
                    219:     
                    220:     if (gain)
                    221:         right = ((gain * MAX_INPUT_GAIN_MICROPHONE)/32768);
                    222:     else
                    223:         right = gain;   // minimum input gain = 0
                    224:         
                    225:     setInputGain(RIGHT_CHANNEL, right);
                    226: #ifdef DEBUG
                    227:     IOLog("%s: updateInputGainRight %d based on gain %d\n", [self name], right, gain);
                    228: #endif DEBUG
                    229: }
                    230: 
                    231: - (void)updateOutputMute
                    232: {
                    233:     enableAudioOutput(! [self isOutputMuted]);
                    234: }
                    235: 
                    236: /*
                    237:  * (0) - (-84) needs to be converted to hardware supported (0) - (15)
                    238:  */
                    239: - (void) updateOutputAttenuationLeft
                    240: {
                    241:     unsigned int attenuation = [self outputAttenuationLeft] + 84;
                    242:     unsigned int left = 0;
                    243:     
                    244:     left = ((attenuation * MAX_MASTER_OUTPUT_VOLUME)/84);
                    245:    
                    246:     setOutputAttenuation(LEFT_CHANNEL, left);
                    247:     
                    248: #ifdef DEBUG
                    249:     IOLog("%s: converted la: %d into %d\n", [self name], attenuation, left);
                    250: #endif DEBUG
                    251: }
                    252: 
                    253: /*
                    254:  * (0) - (-84) needs to be converted to hardware supported (0) - (15)
                    255:  */
                    256: - (void) updateOutputAttenuationRight
                    257: {
                    258:     unsigned int attenuation = [self outputAttenuationRight] + 84;
                    259:     unsigned int right = 0;
                    260:     
                    261:     right = ((attenuation * MAX_MASTER_OUTPUT_VOLUME)/84);
                    262:     
                    263:     setOutputAttenuation(RIGHT_CHANNEL, right);
                    264:    
                    265: #ifdef DEBUG
                    266:     IOLog("SoundBlaster8: converted ra: %d into %d\n", attenuation, right);
                    267: #endif DEBUG
                    268: }
                    269: 
                    270: /*
                    271:  * Program DSP.
                    272:  */
                    273: - (void)updateSampleRate
                    274: {
                    275:     unsigned int rate;
                    276:     unsigned int mode;
                    277:     
                    278:     rate = [self sampleRate];
                    279:     mode = ([self channelCount] == 2) ? DSP_STEREO_MODE : DSP_MONO_MODE;
                    280: 
                    281:     /*
                    282:      * Programming sequence depends upon whether we are doing a low speed or
                    283:      * high speed transfer. Rather messy, see SB SDK page 12-5.
                    284:      */
                    285:     if (sbCardType.version == SB_CLASSIC) {
                    286:        lowSpeedDMA = YES;
                    287:     } else if (sbCardType.version == SB_20) {
                    288:        if (currentDMADirection == DMA_DIRECTION_IN)
                    289:            lowSpeedDMA = (rate < SB_20_LOW_SPEED_RECORD) ? YES : NO;
                    290:        else
                    291:            lowSpeedDMA = (rate < SB_20_LOW_SPEED_PLAYBACK) ? YES : NO;
                    292:     } else if (sbCardType.version == SB_PRO) {
                    293:         if (mode == DSP_STEREO_MODE)
                    294:            rate *= 2;
                    295:        lowSpeedDMA = (rate < SB_PRO_LOW_SPEED) ? YES : NO;
                    296:     }
                    297:     
                    298:     setCodecDataMode(mode, currentDMADirection);
                    299:     setCodecSamplingRate(rate);
                    300: }
                    301: 
                    302: 
                    303: /*
                    304:  * Sets the DMA Counter Load register which decides when the next interrupt
                    305:  * will arrive.
                    306:  */
                    307: - (void) setBufferCount:(int)count
                    308: {
                    309:     setSampleBufferCounter(count);      
                    310: }
                    311: 
                    312: 
                    313: - (IOReturn) enableAllInterrupts
                    314: {
                    315:     enableCodecInterrupts();
                    316:     return [super enableAllInterrupts];
                    317: }
                    318: 
                    319: - (void) disableAllInterrupts
                    320: {
                    321:    disableCodecInterrupts();
                    322:    [super disableAllInterrupts];
                    323: }
                    324: 
                    325: /*
                    326:  * Return NO if the hardware does not support this particular playback/record
                    327:  * request. The parameter scheme in soundkit does not fit the anarchy
                    328:  * of PC world very well.
                    329:  */
                    330: - (BOOL)isValidRequest: (BOOL)isRead
                    331: {
                    332:     unsigned int rate;
                    333:     unsigned int mode;
                    334:     unsigned int encoding;
                    335:     
                    336:     rate = [self sampleRate];
                    337:     encoding = [self dataEncoding];
                    338:     mode = ([self channelCount] == 2) ? DSP_STEREO_MODE : DSP_MONO_MODE;
                    339: 
                    340: #ifdef DEBUG
                    341:     IOLog("SoundBlaster8: rate: %d ", rate);
                    342:     
                    343:     if (mode == DSP_MONO_MODE)
                    344:         IOLog("dataMode: mono ");
                    345:     else if (mode == DSP_STEREO_MODE)
                    346:         IOLog("dataMode: stereo ");
                    347:     else
                    348:         IOLog("dataMode: unknown ");
                    349:         
                    350:     if (encoding == NX_SoundStreamDataEncoding_Linear16)
                    351:         IOLog("dataEncoding: linear 16\n");
                    352:     else if (encoding == NX_SoundStreamDataEncoding_Linear8)
                    353:         IOLog("dataEncoding: linear 8\n");
                    354:     else if (encoding == NX_SoundStreamDataEncoding_Mulaw8)
                    355:         IOLog("dataEncoding: mulaw 8\n");
                    356:     else if (encoding == NX_SoundStreamDataEncoding_Alaw8)
                    357:         IOLog("dataEncoding: Alaw 8\n");
                    358:     else
                    359:         IOLog("dataEncoding: unknown\n");
                    360: #endif DEBUG
                    361:        
                    362:     if (sbCardType.version == SB_PRO) {
                    363:         if ((mode == DSP_STEREO_MODE) &&
                    364:             (rate > SB_PRO_LOW_SPEED))
                    365:             return NO;          
                    366:     }
                    367:     
                    368:     if (sbCardType.version == SB_20) {
                    369:        if (isRead && rate > SB_20_LOW_SPEED_RECORD)
                    370:            return NO;
                    371:     }
                    372:                 
                    373:     if (sbCardType.version == SB_CLASSIC) {
                    374:        if (isRead && rate > SB_CLASSIC_MAX_SPEED_RECORD)
                    375:            return NO;
                    376:        if (!isRead && rate > SB_CLASSIC_MAX_SPEED_PLAYBACK)
                    377:            return NO;
                    378:     }
                    379:     
                    380:     return YES;
                    381: }
                    382: 
                    383: 
                    384: - (BOOL) startDMAForChannel: (unsigned int) localChannel
                    385:         read: (BOOL) isRead
                    386:         buffer: (IOEISADMABuffer) buffer
                    387:         bufferSizeForInterrupts: (unsigned int) bufferSize
                    388: {
                    389:     IOReturn ioReturn;
                    390:     
                    391: #ifdef DEBUG
                    392:     IOLog("SoundBlaster8: startDMAForChannel\n");
                    393: #endif DEBUG
                    394: 
                    395:     isValidRequest = [self isValidRequest:isRead];
                    396:     
                    397:     interruptTimedOut = NO;
                    398:     
                    399:     if (isValidRequest == NO)   {
                    400:         IOLog("%s: unsupported %s mode.\n", [self name],
                    401:                 isRead ? "recording" : "playback");
                    402:        
                    403:        if (isRead)
                    404:            return YES;
                    405:        else
                    406:            return NO;
                    407:     }
                    408:         
                    409:     if (isRead)
                    410:         currentDMADirection = DMA_DIRECTION_IN;
                    411:     else
                    412:         currentDMADirection = DMA_DIRECTION_OUT;
                    413: 
                    414:     /*
                    415:      * Output must be off while recording. 
                    416:      */
                    417:     if (![self isOutputMuted])
                    418:        enableAudioOutput(isRead ? NO : YES);
                    419: 
                    420:     [self updateSampleRate];
                    421:     
                    422:     dmaDescriptorSize = bufferSize;    // used by interrupt handler
                    423:             
                    424: #ifdef DEBUG
                    425:     if (lowSpeedDMA)
                    426:         IOLog("SoundBlaster8: starting low speed DMA ");
                    427:     else
                    428:         IOLog("SoundBlaster8: starting high speed DMA ");
                    429:         
                    430:     if (isRead)
                    431:         IOLog("input.\n");
                    432:     else
                    433:         IOLog("output.\n");
                    434: #endif DEBUG
                    435: 
                    436:     ioReturn = [self startDMAForBuffer: buffer channel: localChannel];
                    437: 
                    438:     if (ioReturn != IO_R_SUCCESS) {
                    439:         IOLog("%s: could not start DMA channel error %d\n",
                    440:                 [self name], ioReturn);
                    441:         return NO;
                    442:     }
                    443:         
                    444:     ioReturn = [self enableChannel: localChannel];
                    445:     
                    446:     if (ioReturn != IO_R_SUCCESS) {
                    447:         IOLog("%s: could not enable DMA channel error %d\n",
                    448:                 [self name], ioReturn);
                    449:         return NO;
                    450:     }
                    451: 
                    452:     (void) [self enableAllInterrupts];
                    453: 
                    454:     /*
                    455:      * The order is important here. See SB SDK page 12-8 and 12-13. 
                    456:      */
                    457:     if (lowSpeedDMA)    {
                    458:         if (isRead) {
                    459:             startDMA(DMA_DIRECTION_IN);
                    460:         } else {
                    461:             startDMA(DMA_DIRECTION_OUT);
                    462:         }
                    463:         [self setBufferCount: dmaDescriptorSize];
                    464:     } else {
                    465:         [self setBufferCount: dmaDescriptorSize];
                    466:         if (isRead) {
                    467:             startDMA(DMA_DIRECTION_IN);
                    468:         } else {
                    469:             startDMA(DMA_DIRECTION_OUT);
                    470:         }
                    471:     }
                    472:     
                    473:     return YES;
                    474: }
                    475: 
                    476: - (void) stopDMAForChannel: (unsigned int) localChannel read: (BOOL) isRead
                    477: {
                    478: #ifdef DEBUG
                    479:     IOLog("SoundBlaster8: stopDMAForChannel\n");
                    480: #endif DEBUG
                    481: 
                    482:     /*
                    483:      * DMA request was denied bacause of lack of hardware support. 
                    484:      */
                    485:     if (isValidRequest == NO)
                    486:         return;
                    487:     
                    488:     if (isRead) {
                    489:         stopDMAInput();
                    490:     } else {
                    491:         stopDMAOutput();
                    492:     }
                    493:     
                    494:     (void)[self disableAllInterrupts];
                    495:     
                    496:     /*
                    497:      * Disable channel only after disabling capture and playback. 
                    498:      */
                    499:     [self disableChannel: localChannel];
                    500: 
                    501:     if (isRead == NO)
                    502:         enableAudioOutput(NO);
                    503:        
                    504:     /*
                    505:      * Reset DSP to stop high speed DMA transfer. This is necessary since the
                    506:      * current "DMA block" might be continuing in case the transfer was
                    507:      * interrupted. 
                    508:      */
                    509:     if (lowSpeedDMA == NO) {
                    510:        resetDSPQuick();
                    511:     }
                    512: }
                    513: 
                    514: static void clearInterrupts(void)
                    515: {
                    516:     /*
                    517:      * Acknowledge and clear the interrupt.
                    518:      */
                    519: 
                    520:     inb(sbDataAvailableStatusReg);
                    521: }
                    522: 
                    523: - (IOAudioInterruptClearFunc) interruptClearFunc
                    524: {
                    525:     return clearInterrupts;
                    526: }
                    527: 
                    528: - (void) interruptOccurredForInput: (BOOL *) serviceInput  
                    529:                          forOutput: (BOOL *) serviceOutput
                    530: {
                    531: #ifdef DEBUG
                    532:     IOLog("SoundBlaster8: handleHardwareInterrupt\n");
                    533: #endif DEBUG
                    534:     
                    535:     /*
                    536:      * Acknowledge and clear the interrupt.
                    537:      */
                    538: 
                    539:     inb(sbDataAvailableStatusReg);
                    540:     
                    541:     /*
                    542:      * We do not have simultaneous playback and record in SB.
                    543:      */
                    544:     if (currentDMADirection == DMA_DIRECTION_OUT)
                    545:         *serviceOutput = YES;
                    546:     else
                    547:         *serviceInput = YES;
                    548:         
                    549:     if (lowSpeedDMA)    {
                    550:         if (currentDMADirection == DMA_DIRECTION_IN) {
                    551:             startDMA(DMA_DIRECTION_IN);
                    552:         } else {
                    553:             startDMA(DMA_DIRECTION_OUT);
                    554:         }
                    555:         [self setBufferCount: dmaDescriptorSize];      /* needed here */
                    556:     } else {
                    557:         //[self setBufferCount: dmaDescriptorSize];    /* but not here */
                    558:         if (currentDMADirection == DMA_DIRECTION_IN) {
                    559:             startDMA(DMA_DIRECTION_IN);
                    560:         } else {
                    561:             startDMA(DMA_DIRECTION_OUT);
                    562:         }
                    563:     }
                    564: }
                    565: 
                    566: /*
                    567:  * This routine will be called if interrupts are not being received. Some
                    568:  * cards seem to lock up once in a while. 
                    569:  */
                    570: - (void) timeoutOccurred
                    571: {
                    572: #ifdef DEBUG
                    573:     IOLog("%s: timeout occurred.\n", [self name]);
                    574: #endif DEBUG
                    575: 
                    576:     if (interruptTimedOut == NO) {
                    577:        resetDSPQuick();
                    578:        interruptTimedOut = YES;                // reset only once
                    579:     }
                    580: }
                    581: 
                    582: /*
                    583:  * Choose between different input sources.
                    584:  */
                    585:  
                    586: - (void)setAnalogInputSource:(NXSoundParameterTag) val
                    587: {
                    588:     if (val == NX_SoundDeviceAnalogInputSource_Microphone) {
                    589:         setInputLevel(MICROPHONE_LEVEL_INPUT);
                    590:     } else if (val == NX_SoundDeviceAnalogInputSource_LineIn) {
                    591:         setInputLevel(LINE_LEVEL_INPUT);
                    592:     } else {
                    593:         setInputLevel(MICROPHONE_LEVEL_INPUT);  // default
                    594:     }
                    595: }
                    596: 
                    597: /*
                    598:  * Parameter access.
                    599:  */
                    600: 
                    601: - (BOOL)acceptsContinuousSamplingRates
                    602: {
                    603:     return YES;
                    604: }
                    605: 
                    606: - (void)getSamplingRatesLow:(int *)lowRate
                    607:                                          high:(int *)highRate
                    608: {
                    609:     *lowRate = 4000;
                    610:     *highRate = 44100;
                    611: }
                    612: 
                    613: - (void)getSamplingRates:(int *)rates
                    614:                                 count:(unsigned int *)numRates
                    615: {
                    616:     /* Return some supported rates */
                    617:     rates[0] = 4000;
                    618:     rates[1] = 8000;
                    619:     rates[2] = 11025;
                    620:     rates[3] = 22050;
                    621:     rates[4] = 44100;
                    622:     *numRates = 5;
                    623: }
                    624: 
                    625: - (void)getDataEncodings: (NXSoundParameterTag *)encodings
                    626:                                 count:(unsigned int *)numEncodings
                    627: {
                    628:     encodings[0] = NX_SoundStreamDataEncoding_Linear8;
                    629:     *numEncodings = 1;
                    630: }
                    631: 
                    632: - (unsigned int)channelCountLimit
                    633: {
                    634:     return (sbCardType.version == SB_PRO) ? 2 : 1;      /* stereo and mono */
                    635: }
                    636: 
                    637: @end
                    638: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.