|
|
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: /* ! 10: * Base address. ! 11: */ ! 12: static unsigned int sbBaseRegisterAddress = 0; ! 13: ! 14: /* ! 15: * Register addresses. The base register addressess are determined at ! 16: * run-time. ! 17: */ ! 18: ! 19: static unsigned int sbResetReg = 0; ! 20: static unsigned int sbReadDataReg = 0; ! 21: static unsigned int sbWriteDataOrCommandReg = 0; ! 22: ! 23: static unsigned int sbWriteBufferStatusReg = 0; ! 24: static unsigned int sbDataAvailableStatusReg = 0; ! 25: ! 26: static __inline__ ! 27: void ! 28: assignDSPRegAddresses(void) ! 29: { ! 30: sbResetReg = ! 31: (sbBaseRegisterAddress + SB_DSP_RESET_OFFSET); ! 32: sbReadDataReg = ! 33: (sbBaseRegisterAddress + SB_DSP_READ_DATA_OFFSET); ! 34: sbWriteDataOrCommandReg = ! 35: (sbBaseRegisterAddress + SB_DSP_WRITE_DATA_OR_COMMAND_OFFSET); ! 36: ! 37: sbWriteBufferStatusReg = ! 38: (sbBaseRegisterAddress + SB_DSP_WRITE_BUFFER_STATUS_OFFSET); ! 39: sbDataAvailableStatusReg = ! 40: (sbBaseRegisterAddress + SB_DSP_DATA_AVAILABLE_STATUS_OFFSET); ! 41: } ! 42: ! 43: ! 44: /* ! 45: * Print what is being written. ! 46: */ ! 47: static __inline__ ! 48: void ! 49: outbV(unsigned int address, unsigned int data) ! 50: { ! 51: #ifdef DEBUG ! 52: IOLog("SoundBlaster8: Writing %x at address %x\n", data, address); ! 53: #endif DEBUG ! 54: outb(address, data); ! 55: } ! 56: ! 57: static unsigned int sbMixerAddressReg = 0; ! 58: static unsigned int sbMixerDataReg = 0; ! 59: ! 60: static __inline__ ! 61: void ! 62: assignMixerRegAddresses(void) ! 63: { ! 64: sbMixerAddressReg = ! 65: (sbBaseRegisterAddress + SB_MIXER_ADDRESS_OFFSET); ! 66: sbMixerDataReg = ! 67: (sbBaseRegisterAddress + SB_MIXER_DATA_OFFSET); ! 68: } ! 69: ! 70: /* ! 71: * Shadow registers for volume. Add more to this list when necessary. ! 72: */ ! 73: ! 74: static sbStereoMixerRegister_t volMaster = {0}; ! 75: static sbStereoMixerRegister_t volFM = {0}; ! 76: static sbStereoMixerRegister_t volLine = {0}; ! 77: static sbStereoMixerRegister_t volVoc = {0}; ! 78: ! 79: static sbMonoMixerRegister_t volMic = {0}; ! 80: static sbMonoMixerRegister_t volCD = {0}; ! 81: ! 82: static sbRecordingMode_t sbRecord = {0}; ! 83: static sbPlaybackMode_t sbPlayback = {0}; ! 84: ! 85: ! 86: #define MAX_WAIT_FOR_DATA_AVAILABLE 2000 ! 87: #define SB_WAIT_DELAY 10 ! 88: #define SB_RESET_DELAY 100 ! 89: ! 90: static __inline__ ! 91: BOOL ! 92: dspReadWait() ! 93: { ! 94: int i; ! 95: unsigned int val; ! 96: ! 97: for (i = 0; i < MAX_WAIT_FOR_DATA_AVAILABLE; i++) { ! 98: IODelay(SB_WAIT_DELAY); ! 99: val = inb(sbDataAvailableStatusReg); ! 100: if (val & 0x080) /* MSB == 1 before reading */ ! 101: return YES; ! 102: } ! 103: ! 104: /* Reset DSP, hopefully we will recover. */ ! 105: outbV(sbResetReg, 0x01); ! 106: IODelay(SB_ADDRESS_WRITE_DELAY); ! 107: outbV(sbResetReg, 0x00); ! 108: IODelay(SB_ADDRESS_WRITE_DELAY); ! 109: IODelay(SB_RESET_DELAY); ! 110: ! 111: #ifdef DEBUG ! 112: IOLog("SoundBlaster8: DSP not ready for reading!\n"); ! 113: #endif DEBUG ! 114: ! 115: return NO; ! 116: } ! 117: ! 118: static __inline__ ! 119: BOOL ! 120: dspWriteWait() ! 121: { ! 122: int i; ! 123: unsigned int val; ! 124: ! 125: for (i = 0; i < MAX_WAIT_FOR_DATA_AVAILABLE; i++) { ! 126: IODelay(SB_WAIT_DELAY); ! 127: val = inb(sbWriteBufferStatusReg); ! 128: if (!(val & 0x080)) /* MSB == 0 before writing */ ! 129: return YES; ! 130: } ! 131: ! 132: /* Reset DSP */ ! 133: outbV(sbResetReg, 0x01); ! 134: IODelay(SB_ADDRESS_WRITE_DELAY); ! 135: outbV(sbResetReg, 0x00); ! 136: IODelay(SB_ADDRESS_WRITE_DELAY); ! 137: IODelay(SB_RESET_DELAY); ! 138: ! 139: #ifdef DEBUG ! 140: IOLog("SoundBlaster8: DSP not ready for writing!\n"); ! 141: #endif DEBUG ! 142: ! 143: return NO; ! 144: } ! 145: ! 146: /* ! 147: * Send some data or command to SoundBlaster8 DSP. ! 148: */ ! 149: static ! 150: BOOL ! 151: writeToDSP(unsigned int dataOrCommand) ! 152: { ! 153: outbV(sbWriteDataOrCommandReg, dataOrCommand); ! 154: IODelay(SB_DATA_WRITE_DELAY); ! 155: ! 156: #ifdef DEBUG ! 157: //IOLog("SoundBlaster8: Wrote DSP command %x\n", dataOrCommand); ! 158: #endif DEBUG ! 159: ! 160: return YES; ! 161: } ! 162: ! 163: /* ! 164: * Read from the SoundBlaster DSP. ! 165: */ ! 166: static ! 167: unsigned int ! 168: readFromDSP(void) ! 169: { ! 170: unsigned int val; ! 171: ! 172: val = inb(sbReadDataReg); ! 173: IODelay(SB_DATA_READ_DELAY); ! 174: ! 175: #ifdef DEBUG ! 176: IOLog("SoundBlaster8: read from DSP %x\n", val); ! 177: #endif DEBUG ! 178: ! 179: return val; ! 180: } ! 181: ! 182: /* ! 183: * Function to read from the Mixer registers. ! 184: */ ! 185: static __inline__ ! 186: unsigned int ! 187: inbIXMixer(unsigned int address) ! 188: { ! 189: unsigned int val = 0xff; ! 190: ! 191: outbV(sbMixerAddressReg, address); ! 192: IODelay(SB_ADDRESS_WRITE_DELAY); ! 193: val = inb(sbMixerDataReg); ! 194: ! 195: #ifdef DEBUG ! 196: IOLog("SoundBlaster8: Mixer address %x. Read %x\n", address, val); ! 197: #endif DEBUG ! 198: return val; ! 199: } ! 200: ! 201: /* ! 202: * Function to write to the Mixer registers. ! 203: */ ! 204: static __inline__ ! 205: void ! 206: outbIXMixer(unsigned int address, unsigned int val) ! 207: { ! 208: outbV(sbMixerAddressReg, address); ! 209: IODelay(SB_ADDRESS_WRITE_DELAY); ! 210: outbV(sbMixerDataReg, val); ! 211: IODelay(SB_DATA_WRITE_DELAY); ! 212: ! 213: #ifdef DEBUG ! 214: IOLog("SoundBlaster8: Mixer address %x. Wrote %x\n", address, val); ! 215: #endif DEBUG ! 216: } ! 217: ! 218: /* ! 219: * Initialize DSP registers. There aren't any. ! 220: */ ! 221: ! 222: static __inline__ ! 223: void ! 224: initDSPRegisters(void) ! 225: { ! 226: } ! 227: ! 228: /* ! 229: * Initialize the registers on the Mixer. ! 230: */ ! 231: ! 232: static __inline__ ! 233: void ! 234: initMixerRegisters(void) ! 235: { ! 236: if (sbCardType.mixerPresent == NO) ! 237: return; ! 238: ! 239: #ifdef DEBUG ! 240: IOLog("SoundBlaster8: Initializing mixer registers.\n"); ! 241: #endif DEBUG ! 242: ! 243: /* ! 244: * First set the volume controlling registers to their default values. ! 245: */ ! 246: volMaster.reg.left = 10; ! 247: volMaster.reg.right = 10; ! 248: outbIXMixer(MC_MASTER_VOLUME, volMaster.data); ! 249: ! 250: volFM.reg.left = 0; ! 251: volFM.reg.right = 0; ! 252: outbIXMixer(MC_FM_VOLUME, volFM.data); ! 253: ! 254: volCD = 0; ! 255: outbIXMixer(MC_CD_VOLUME, volCD); ! 256: ! 257: volLine.reg.left = 0; ! 258: volLine.reg.right = 0; ! 259: outbIXMixer(MC_LINE_VOLUME, volLine.data); ! 260: ! 261: volVoc.reg.left = 10; ! 262: volVoc.reg.right = 10; ! 263: outbIXMixer(MC_VOC_VOLUME, volVoc.data); ! 264: ! 265: /* Microphone can go only upto 7. */ ! 266: volMic = 6; ! 267: outbIXMixer(MC_MICROPHONE_VOLUME, volMic); ! 268: ! 269: /* ! 270: * Now set the record and playback mode registers. ! 271: */ ! 272: sbRecord.data = 0; ! 273: sbRecord.reg.source = SB_RECORD_SOURCE_MIC; ! 274: sbRecord.reg.inputFilter = SB_RECORD_ANFI_OFF; ! 275: sbRecord.reg.highFreq = SB_RECORD_FREQ_HIGH; ! 276: outbIXMixer(MC_RECORD_CONTROL, sbRecord.data); ! 277: ! 278: sbPlayback.data = 0; ! 279: sbPlayback.reg.outputFilter = SB_PLAYBACK_DNFI_OFF; ! 280: sbPlayback.reg.stereo = SB_PLAYBACK_STEREO; ! 281: outbIXMixer(MC_PLAYBACK_CONTROL, sbPlayback.data); ! 282: } ! 283: ! 284: /* ! 285: * Input can be either microphone level or line level. We don't support other ! 286: * inputs. ! 287: */ ! 288: ! 289: static __inline__ ! 290: void ! 291: setInputLevel(unsigned int level) ! 292: { ! 293: if (sbCardType.mixerPresent == NO) ! 294: return; ! 295: ! 296: if (level == LINE_LEVEL_INPUT) { ! 297: sbRecord.reg.source = SB_RECORD_SOURCE_LINE; ! 298: } else { ! 299: sbRecord.reg.source = SB_RECORD_SOURCE_MIC; ! 300: } ! 301: ! 302: outbIXMixer(MC_RECORD_CONTROL, sbRecord.data); ! 303: } ! 304: ! 305: /* ! 306: * Output level cannot be changed. ! 307: */ ! 308: ! 309: static __inline__ ! 310: void ! 311: setOutputLevel(unsigned int channel, unsigned int level) ! 312: { ! 313: #ifdef DEBUG ! 314: IOLog("SoundBlaster8: Audio output level is fixed.\n"); ! 315: #endif DEBUG ! 316: } ! 317: ! 318: /* ! 319: * Initialize the hardware registers. ! 320: */ ! 321: static __inline__ ! 322: void ! 323: initRegisters(void) ! 324: { ! 325: initDSPRegisters(); ! 326: initMixerRegisters(); ! 327: } ! 328: ! 329: ! 330: /* ! 331: * These two routines are used to avoid clicks. ! 332: */ ! 333: ! 334: static __inline__ ! 335: void ! 336: muteOutput(void) ! 337: { ! 338: sbStereoMixerRegister_t volMaster = {0}; ! 339: ! 340: if (sbCardType.mixerPresent == NO) ! 341: return; ! 342: ! 343: volMaster.reg.left = 0; ! 344: volMaster.reg.right = 0; ! 345: ! 346: outbIXMixer(MC_MASTER_VOLUME, volMaster.data); ! 347: } ! 348: ! 349: /* ! 350: * This takes it back to the old values. So it is not exactly unmute. ! 351: */ ! 352: static __inline__ ! 353: void ! 354: unMuteOutput(void) ! 355: { ! 356: if (sbCardType.mixerPresent == NO) ! 357: return; ! 358: ! 359: outbIXMixer(MC_MASTER_VOLUME, volMaster.data); ! 360: } ! 361: ! 362: /* ! 363: * This routine does a quick reset of the card. This is needed because ! 364: * apparently the SoundBlaster8 cards need to be reset if you go from the ! 365: * high speed to the low speed mode (wonderful world of hardware). ! 366: */ ! 367: ! 368: static __inline__ ! 369: void ! 370: resetDSPQuick(void) ! 371: { ! 372: outbV(sbResetReg, 0x01); ! 373: IODelay(SB_ADDRESS_WRITE_DELAY); ! 374: outbV(sbResetReg, 0x00); ! 375: IODelay(SB_ADDRESS_WRITE_DELAY); ! 376: ! 377: /* It takes about 100us to reset */ ! 378: dspReadWait(); ! 379: if (readFromDSP() != 0xaa) { ! 380: IOLog("SoundBlaster8: Can not reset DSP.\n"); ! 381: } ! 382: } ! 383: ! 384: ! 385: #define SB_DELAY 100 ! 386: #define MAX_RESET_WAIT 1000 ! 387: ! 388: /* ! 389: * Reset the SoundBlaster card. This routine also detects if the card is ! 390: * present and the type of card. ! 391: */ ! 392: static __inline__ ! 393: void ! 394: resetDSP(void) ! 395: { ! 396: unsigned int val; ! 397: ! 398: /* ! 399: * Assume no sound card in the system. ! 400: */ ! 401: sbCardType.version = SB_NONE; ! 402: sbCardType.name = ""; ! 403: sbCardType.majorVersion = 0; ! 404: sbCardType.minorVersion = 0; ! 405: sbCardType.mixerPresent = NO; ! 406: ! 407: outbV(sbResetReg, 0x01); ! 408: IODelay(SB_ADDRESS_WRITE_DELAY); ! 409: outbV(sbResetReg, 0x00); ! 410: IODelay(SB_ADDRESS_WRITE_DELAY); ! 411: ! 412: /* Now we can read the data. */ ! 413: dspReadWait(); ! 414: val = readFromDSP(); ! 415: if (val == 0xaa) { ! 416: #ifdef DEBUG ! 417: IOLog("SoundBlaster8: DSP detected.\n"); ! 418: #endif DEBUG ! 419: IOSleep(1); ! 420: } else { ! 421: #ifdef DEBUG ! 422: IOLog("SoundBlaster8: Read ID %x is wrong.\n", val); ! 423: IOLog("SoundBlaster8: SoundBlaster not detected at address 0x%0x.\n", ! 424: sbBaseRegisterAddress); ! 425: #endif DEBUG ! 426: return; ! 427: } ! 428: ! 429: /* ! 430: * We have a SoundBlaster card. We will upgrade it to a pro if we detect ! 431: * a mixer as well. ! 432: */ ! 433: sbCardType.version = SB_CLASSIC; ! 434: ! 435: /* ! 436: * Another confirmatory test here. This is not documented in the SB SDK ! 437: * so it might fail on some compatible cards. Maybe we should just print ! 438: * a warning message if this test fails. ! 439: */ ! 440: dspWriteWait(); ! 441: writeToDSP(DC_INVERT_BYTE); ! 442: ! 443: dspWriteWait(); ! 444: writeToDSP(0x43); /* Send some test pattern. */ ! 445: ! 446: dspReadWait(); ! 447: val = readFromDSP(); ! 448: ! 449: if (val == 0xbc) { ! 450: #ifdef DEBUG ! 451: IOLog("SoundBlaster8: Invert test passed.\n"); ! 452: #endif DEBUG ! 453: } else { ! 454: #ifdef DEBUG ! 455: IOLog("SoundBlaster8: Invert test failed!!\n"); ! 456: IOLog("SoundBlaster8: SoundBlaster not detected at address 0x%0x.\n", ! 457: sbBaseRegisterAddress); ! 458: #endif DEBUG ! 459: } ! 460: ! 461: /* ! 462: * Reset the DSP here because sometimes you may get crazy values as ! 463: * version. So just to be on the safe side.. ! 464: */ ! 465: resetDSPQuick(); ! 466: ! 467: /* ! 468: * Now we know that a SoundBlaster or compatible card exists. We need to ! 469: * find the version number to decide the type of card. ! 470: */ ! 471: dspWriteWait(); ! 472: writeToDSP(DC_GET_VERSION); ! 473: ! 474: dspReadWait(); ! 475: sbCardType.majorVersion = readFromDSP() & 0x0f; ! 476: sbCardType.minorVersion = readFromDSP() & 0x0f; ! 477: ! 478: #ifdef DEBUG ! 479: //IOLog("SoundBlaster8: Major 0x%x Minor 0x%x\n", sbCardType.majorVersion, sbCardType.minorVersion); ! 480: #endif DEBUG ! 481: ! 482: /* ! 483: * Upgrade the card to SB_20 or SB_16 depending upon what the version ! 484: * number reads. ! 485: */ ! 486: if (sbCardType.majorVersion >= 2) ! 487: sbCardType.version = SB_20; ! 488: ! 489: if (sbCardType.majorVersion >= 4) ! 490: sbCardType.version = SB_16; ! 491: } ! 492: ! 493: ! 494: ! 495: static __inline__ ! 496: void ! 497: resetMixer(void) ! 498: { ! 499: unsigned int val1, val2; ! 500: ! 501: /* ! 502: * Reset the mixer by sending zero to both address and data ports. ! 503: */ ! 504: outbIXMixer(0x0, 0x0); ! 505: ! 506: /* ! 507: * Now try to write and then read from one of the mixer registers. ! 508: */ ! 509: outbIXMixer(MC_MASTER_VOLUME, 0x15); ! 510: outbIXMixer(MC_MICROPHONE_VOLUME, 0x13); ! 511: ! 512: val1 = inbIXMixer(MC_MASTER_VOLUME); ! 513: val2 = inbIXMixer(MC_MICROPHONE_VOLUME); ! 514: ! 515: if ((val1 == 0x15) && (val2 == 0x13)) { ! 516: sbCardType.mixerPresent = YES; ! 517: } else { ! 518: sbCardType.mixerPresent = NO; ! 519: } ! 520: ! 521: /* ! 522: * Try once more, so that we are really sure. ! 523: */ ! 524: outbIXMixer(MC_LINE_VOLUME, 0x17); ! 525: outbIXMixer(MC_FM_VOLUME, 0x19); ! 526: ! 527: val1 = inbIXMixer(MC_LINE_VOLUME); ! 528: val2 = inbIXMixer(MC_FM_VOLUME); ! 529: ! 530: if ((val1 == 0x17) && (val2 == 0x19)) { ! 531: sbCardType.mixerPresent = YES; ! 532: } else { ! 533: sbCardType.mixerPresent = NO; ! 534: } ! 535: ! 536: /* ! 537: * We have a pro card if we found the mixer. ! 538: */ ! 539: if (sbCardType.mixerPresent == YES) { ! 540: sbCardType.version = SB_PRO; ! 541: outbIXMixer(0x0, 0x0); /* reset the mixer to a good state */ ! 542: } ! 543: ! 544: #ifdef DEBUG ! 545: if (sbCardType.mixerPresent == YES) ! 546: IOLog("SoundBlaster8: Mixer detected.\n"); ! 547: else ! 548: IOLog("SoundBlaster8: Mixer not detected.\n"); ! 549: #endif DEBUG ! 550: } ! 551: ! 552: ! 553: /* ! 554: * Reset all hardware and bring us back to the default state. ! 555: */ ! 556: static __inline__ ! 557: void ! 558: resetHardware(void) ! 559: { ! 560: resetDSP(); ! 561: resetMixer(); ! 562: initRegisters(); ! 563: } ! 564: ! 565: /* ! 566: * There seems to be no way to change input gain. ! 567: */ ! 568: static __inline__ ! 569: void ! 570: setInputGain(unsigned int channel, unsigned int gain) ! 571: { ! 572: if (sbCardType.mixerPresent == NO) ! 573: return; ! 574: ! 575: volMic = gain; ! 576: outbIXMixer(MC_MICROPHONE_VOLUME, volMic); ! 577: ! 578: #ifdef DEBUG ! 579: IOLog("SoundBlaster8: set input gain %d\n", gain); ! 580: #endif DEBUG ! 581: } ! 582: ! 583: static __inline__ ! 584: void ! 585: setOutputAttenuation(unsigned int channel, unsigned int attenuation) ! 586: { ! 587: if (sbCardType.mixerPresent == NO) ! 588: return; ! 589: ! 590: if (channel == LEFT_CHANNEL) { ! 591: volMaster.reg.left = attenuation; ! 592: outbIXMixer(MC_MASTER_VOLUME, volMaster.data); ! 593: ! 594: } else { ! 595: volMaster.reg.right = attenuation; ! 596: outbIXMixer(MC_MASTER_VOLUME, volMaster.data); ! 597: } ! 598: #ifdef DEBUG ! 599: IOLog("SoundBlaster8: set output attenuation %d\n", attenuation); ! 600: #endif DEBUG ! 601: } ! 602: ! 603: /* ! 604: * This will not work for SB16 running in SBPro compatibility mode. The mixer ! 605: * registers need to be written to mute output. ! 606: */ ! 607: ! 608: static __inline__ ! 609: void ! 610: enableAudioOutput(BOOL enable) ! 611: { ! 612: dspWriteWait(); ! 613: if (enable) { ! 614: writeToDSP(DC_TURN_ON_SPEAKER); ! 615: } else { ! 616: writeToDSP(DC_TURN_OFF_SPEAKER); ! 617: } ! 618: } ! 619: ! 620: static __inline__ ! 621: void setSampleBufferCounter(unsigned int count) ! 622: { ! 623: if (!lowSpeedDMA) { ! 624: dspWriteWait(); ! 625: writeToDSP(DC_SET_BLOCK_SIZE); ! 626: } ! 627: ! 628: count -= 1; ! 629: dspWriteWait(); ! 630: writeToDSP(count & 0x0ff); ! 631: dspWriteWait(); ! 632: writeToDSP((count >> 8) & 0x0ff); ! 633: #ifdef DEBUG ! 634: //IOLog("SoundBlaster8: buffer counter set to %x\n", count); ! 635: #endif DEBUG ! 636: } ! 637: ! 638: /* ! 639: * Start DMA. Command patterns are different depending upon whether we are ! 640: * doing low speed or high speed transfers. ! 641: */ ! 642: ! 643: static __inline__ ! 644: void startDMA(unsigned int direction) ! 645: { ! 646: dspWriteWait(); ! 647: if (lowSpeedDMA) { ! 648: if (direction == DMA_DIRECTION_IN) ! 649: writeToDSP(DC_START_LS_DMA_ADC_8); ! 650: else ! 651: writeToDSP(DC_START_LS_DMA_DAC_8); ! 652: } else { ! 653: if (direction == DMA_DIRECTION_IN) ! 654: writeToDSP(DC_START_HS_DMA_ADC_8); ! 655: else ! 656: writeToDSP(DC_START_HS_DMA_DAC_8); ! 657: } ! 658: } ! 659: ! 660: /* No can do */ ! 661: static __inline__ ! 662: void enableCodecInterrupts(void) ! 663: { ! 664: } ! 665: ! 666: static __inline__ ! 667: void disableCodecInterrupts(void) ! 668: { ! 669: } ! 670: ! 671: static __inline__ ! 672: void stopDMA(void) ! 673: { ! 674: writeToDSP(DC_HALT_DMA); ! 675: } ! 676: ! 677: /* ! 678: * This routine will stop input dma. ! 679: */ ! 680: static __inline__ ! 681: void stopDMAInput(void) ! 682: { ! 683: stopDMA(); ! 684: } ! 685: ! 686: /* ! 687: * Likewise, but for output dma. ! 688: */ ! 689: static __inline__ ! 690: void stopDMAOutput(void) ! 691: { ! 692: stopDMA(); ! 693: } ! 694: ! 695: /* ! 696: * Select between DSP_MONO_MODE and DSP_STEREO_MODE mode. Note that stereo ! 697: * recording is undocumented so it could potentially break on some clone ! 698: * cards. ! 699: */ ! 700: static __inline__ ! 701: void setCodecDataMode(unsigned int mode, unsigned int dir) ! 702: { ! 703: if (sbCardType.mixerPresent == NO) ! 704: return; ! 705: ! 706: if (dir == DMA_DIRECTION_OUT) { ! 707: if (mode == DSP_STEREO_MODE) { ! 708: sbPlayback.reg.stereo = SB_PLAYBACK_STEREO; ! 709: } else { ! 710: sbPlayback.reg.stereo = SB_PLAYBACK_MONO; ! 711: } ! 712: outbIXMixer(MC_PLAYBACK_CONTROL, sbPlayback.data); ! 713: } else if (dir == DMA_DIRECTION_IN) { ! 714: dspWriteWait(); ! 715: if (mode == DSP_STEREO_MODE) { ! 716: writeToDSP(DC_RECORD_IN_STEREO); ! 717: } else { ! 718: writeToDSP(DC_RECORD_IN_MONO); ! 719: } ! 720: } ! 721: } ! 722: ! 723: ! 724: static __inline__ ! 725: void setCodecSamplingRate(unsigned int rate) ! 726: { ! 727: unsigned int timeConstant; ! 728: ! 729: /* Sanity check. */ ! 730: if (rate < SB_MIN_SAMPLE_RATE) ! 731: rate = SB_MIN_SAMPLE_RATE; ! 732: else if (rate > SB_MAX_SAMPLE_RATE) ! 733: rate = SB_MAX_SAMPLE_RATE; ! 734: ! 735: dspWriteWait(); ! 736: if (lowSpeedDMA) { ! 737: timeConstant = 256 - (1000*1000)/rate; ! 738: writeToDSP(DC_SET_TIME_CONSTANT); ! 739: dspWriteWait(); ! 740: writeToDSP(timeConstant); ! 741: #ifdef DEBUG ! 742: IOLog("SoundBlaster8: Sample rate = %u, timeConstant = %x\n", rate, timeConstant); ! 743: #endif DEBUG ! 744: } else { ! 745: timeConstant = 65536 - (256*1000*1000)/rate; ! 746: writeToDSP(DC_SET_TIME_CONSTANT); ! 747: dspWriteWait(); ! 748: writeToDSP(timeConstant >> 8); ! 749: #ifdef DEBUG ! 750: IOLog("SoundBlaster8: Sample rate = %u, timeConstant = %x\n", rate, timeConstant >> 8); ! 751: #endif DEBUG ! 752: } ! 753: } ! 754: ! 755: /* ! 756: * We test here if the user supplied dma/irq selections are correct. Actually ! 757: * it is more complicated than this because not all kinds of cards can use ! 758: * all dma/irq combinations. We simply allow the superset and avoid ! 759: * complicated version dependent verification. (Available interrupts are 3, ! 760: * 5, 7 for SBPro and 5, 7, 10 for other kinds, clone cards may have slight ! 761: * differences.) ! 762: */ ! 763: ! 764: static __inline__ ! 765: BOOL ! 766: checkSelectedDMAAndIRQ(unsigned int channel, unsigned int irq) ! 767: { ! 768: BOOL status = YES; ! 769: ! 770: if ((channel != 0) && (channel != 1) && (channel != 3)) { ! 771: IOLog("SoundBlaster8: Audio DMA channel is %d.\n", channel); ! 772: IOLog("SoundBlaster8: Audio DMA channel must be one of 0, 1, 3.\n"); ! 773: status = NO; ! 774: } ! 775: if ((irq != 3) && (irq != 5) && ! 776: (irq != 7) && (irq != 10)) { ! 777: IOLog("SoundBlaster8: Audio irq is %d.\n", irq); ! 778: IOLog("SoundBlaster8: Audio IRQ must be one of 3, 5, 7, 10.\n"); ! 779: status = NO; ! 780: } ! 781: ! 782: return status; ! 783: } ! 784:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.