|
|
1.1 ! root 1: /* Copyright (c) 1993 NeXT Computer, 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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.