|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1991 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: config.c ! 8: ! 9: Abstract: ! 10: ! 11: This module contains code configuration code for the initialization phase ! 12: of the Microsoft Sound System device driver. ! 13: ! 14: Author: ! 15: ! 16: Robin Speed (RobinSp) 17-Oct-1992 ! 17: ! 18: Environment: ! 19: ! 20: Kernel mode ! 21: ! 22: Revision History: ! 23: ! 24: --*/ ! 25: ! 26: ! 27: #include "sound.h" ! 28: ! 29: // ! 30: // Internal routines ! 31: // ! 32: NTSTATUS ! 33: SoundInitIoPort( ! 34: IN OUT PGLOBAL_DEVICE_INFO pGDI, ! 35: IN OUT PSB_CONFIG_DATA ConfigData ! 36: ); ! 37: NTSTATUS ! 38: SoundPortValid( ! 39: IN OUT PGLOBAL_DEVICE_INFO pGDI, ! 40: IN OUT PULONG Port ! 41: ); ! 42: NTSTATUS ! 43: SoundInitDmaChannel( ! 44: IN OUT PGLOBAL_DEVICE_INFO pGDI, ! 45: IN OUT PULONG DmaChannel, ! 46: IN ULONG DmaBufferSize ! 47: ); ! 48: NTSTATUS ! 49: SoundDmaChannelValid( ! 50: IN OUT PGLOBAL_DEVICE_INFO pGDI, ! 51: IN OUT PULONG DmaChannel ! 52: ); ! 53: NTSTATUS ! 54: SoundInitInterrupt( ! 55: IN OUT PGLOBAL_DEVICE_INFO pGDI, ! 56: IN OUT PULONG Interrupt ! 57: ); ! 58: NTSTATUS ! 59: SoundInterruptValid( ! 60: IN OUT PGLOBAL_DEVICE_INFO pGDI, ! 61: IN OUT PULONG Interrupt ! 62: ); ! 63: VOID ! 64: SoundSetVersion( ! 65: IN PGLOBAL_DEVICE_INFO pGlobalInfo, ! 66: IN ULONG DSPVersion ! 67: ); ! 68: ! 69: #ifdef ALLOC_PRAGMA ! 70: #pragma alloc_text(init,SoundSetVersion) ! 71: #pragma alloc_text(init,SoundInitHardwareConfig) ! 72: #pragma alloc_text(init,SoundInitIoPort) ! 73: #pragma alloc_text(init,SoundInitDmaChannel) ! 74: #pragma alloc_text(init,SoundInitInterrupt) ! 75: #pragma alloc_text(init,SoundSaveConfig) ! 76: #pragma alloc_text(init,SoundReadConfiguration) ! 77: #endif ! 78: ! 79: ! 80: VOID ! 81: SoundSetVersion( ! 82: IN PGLOBAL_DEVICE_INFO pGlobalInfo, ! 83: IN ULONG DSPVersion ! 84: ) ! 85: /*++ ! 86: ! 87: Routine Description : ! 88: ! 89: Sets a version DWORD into the registry as a pseudo return code ! 90: to sndblst.drv ! 91: ! 92: As a side effect the key to the registry entry is closed. ! 93: ! 94: Arguments : ! 95: ! 96: pGlobalInfo - Our driver global info ! 97: ! 98: DSPVersion - the version number we want to set ! 99: ! 100: Return Value : ! 101: ! 102: None ! 103: ! 104: --*/ ! 105: { ! 106: UNICODE_STRING VersionString; ! 107: ! 108: RtlInitUnicodeString(&VersionString, L"DSP Version"); ! 109: if (pGlobalInfo->RegistryPathName) { ! 110: NTSTATUS SetStatus; ! 111: ! 112: SetStatus = ! 113: ! 114: SoundWriteRegistryDWORD(pGlobalInfo->RegistryPathName, ! 115: L"DSP Version", ! 116: DSPVersion); ! 117: ! 118: if (!NT_SUCCESS(SetStatus)) { ! 119: dprintf1(("Failed to write version - status %x", SetStatus)); ! 120: } ! 121: } ! 122: } ! 123: ! 124: ! 125: NTSTATUS ! 126: SoundInitHardwareConfig( ! 127: IN OUT PGLOBAL_DEVICE_INFO pGDI, ! 128: IN PSB_CONFIG_DATA ConfigData ! 129: ) ! 130: { ! 131: ! 132: NTSTATUS Status; ! 133: ! 134: // ! 135: // Check the input source ! 136: // ! 137: ! 138: if (ConfigData->InputSource > INPUT_OUTPUT) { ! 139: return STATUS_DEVICE_CONFIGURATION_ERROR; ! 140: } ! 141: ! 142: pGDI->Hw.InputSource = ConfigData->InputSource; ! 143: ! 144: // ! 145: // Find port ! 146: // ! 147: ! 148: Status = SoundInitIoPort(pGDI, ConfigData); ! 149: ! 150: if (!NT_SUCCESS(Status)) { ! 151: return Status; ! 152: } ! 153: ! 154: // ! 155: // Find interrupt ! 156: // ! 157: ! 158: Status = SoundInitInterrupt(pGDI, &ConfigData->InterruptNumber); ! 159: ! 160: if (!NT_SUCCESS(Status)) { ! 161: return Status; ! 162: } ! 163: ! 164: // ! 165: // Find DMA channel ! 166: // ! 167: ! 168: Status = SoundInitDmaChannel(pGDI, &ConfigData->DmaChannel, ! 169: ConfigData->DmaBufferSize); ! 170: ! 171: if (!NT_SUCCESS(Status)) { ! 172: return Status; ! 173: } ! 174: ! 175: // ! 176: // Report the sound-blaster version number (and a flag ! 177: // to say if it's a Thunderboard. ! 178: // We do this via an entry in our registry node - under ! 179: // our device-specific section. If this fails then configuration ! 180: // won't work so well but the driver will work fine. ! 181: // ! 182: // We use the registry handle generated by SoundReadConfiguration ! 183: ! 184: { ! 185: ULONG DSPVersion; ! 186: ! 187: DSPVersion = pGDI->Hw.DSPVersion; ! 188: ! 189: // ! 190: // If it's a pro audio spectrum set a bit to say it is ! 191: // ! 192: ! 193: if (pGDI->ProAudioSpectrum) { ! 194: DSPVersion |= 0x800; ! 195: } else { ! 196: // ! 197: // If it's a Thunderboard following comparison will fail. ! 198: // There's not much point having a constant for a flag ! 199: // because there's no logical way to share info between ! 200: // sndblst.sys and sndblst.drv ! 201: // ! 202: ! 203: if (pGDI->Hw.ThunderBoard) { ! 204: DSPVersion |= 0x8000; ! 205: ! 206: // ! 207: // Note - it MAY be a pro spectrum ! ! 208: // ! 209: } ! 210: } ! 211: ! 212: // ! 213: // Put the version number in the registry (if we can) ! 214: // ! 215: ! 216: SoundSetVersion(pGDI, DSPVersion); ! 217: } ! 218: ! 219: ! 220: // ! 221: // turn on the speaker ! 222: // ! 223: ! 224: dspSpeakerOn(&pGDI->Hw); ! 225: ! 226: return STATUS_SUCCESS; ! 227: ! 228: } ! 229: ! 230: ! 231: ! 232: ! 233: NTSTATUS ! 234: SoundInitIoPort( ! 235: IN OUT PGLOBAL_DEVICE_INFO pGDI, ! 236: IN OUT PSB_CONFIG_DATA ConfigData ! 237: ) ! 238: { ! 239: NTSTATUS Status; ! 240: ! 241: // ! 242: // Find where our device is mapped ! 243: // ! 244: ! 245: pGDI->Hw.PortBase = SoundMapPortAddress( ! 246: pGDI->BusType, ! 247: pGDI->BusNumber, ! 248: ConfigData->Port, ! 249: NUMBER_OF_SOUND_PORTS, ! 250: &pGDI->MemType); ! 251: ! 252: // ! 253: // Check and see if the hardware is happy ! 254: // ! 255: ! 256: // ! 257: // Check the SoundBlaster is where we think it is and get ! 258: // the dsp version code. ! 259: // ! 260: ! 261: if (!dspReset(&pGDI->Hw)) { ! 262: NTSTATUS PasStatus = STATUS_DEVICE_CONFIGURATION_ERROR; ! 263: ! 264: #ifdef PAS16 // There's a proper driver now ! 265: ! 266: // ! 267: // Try to wake up any lurking Pro audio spectrums ! 268: // that are asleep ! 269: // ! 270: ! 271: PasStatus = FindPasHardware(pGDI, ConfigData); ! 272: ! 273: #endif // PAS16 ! 274: ! 275: if (!NT_SUCCESS(PasStatus) || !dspReset(&pGDI->Hw)) { ! 276: pGDI->Hw.DSPVersion = 0; ! 277: SoundSetVersion(pGDI, 0x4000); // Means port was wrong ! 278: return STATUS_DEVICE_CONFIGURATION_ERROR; ! 279: } ! 280: ! 281: pGDI->ProAudioSpectrum = TRUE; ! 282: } ! 283: ! 284: pGDI->Hw.DSPVersion = dspGetVersion(&pGDI->Hw); ! 285: ! 286: // ! 287: // Check for Thunderboards and Pro Spectrums ! 288: // ! 289: ! 290: if (dspGetVersion(&pGDI->Hw) != pGDI->Hw.DSPVersion) { ! 291: pGDI->Hw.ThunderBoard = TRUE; ! 292: ! 293: #ifdef PAS16 // We now have a proper driver for this ! 294: // ! 295: // See if this guy is a Pro audio spectrum. By this ! 296: // stage it will be woken up but we still need to tell if ! 297: // it is one and set its features and mixer. ! 298: // ! 299: ! 300: if (pGDI->ProAudioSpectrum || ! 301: NT_SUCCESS(FindPasHardware(pGDI, ConfigData))) { ! 302: ! 303: pGDI->ProAudioSpectrum = TRUE; ! 304: InitPasAndMixer(&pGDI->PASInfo, ConfigData); ! 305: } ! 306: #endif // PAS16 ! 307: } ! 308: ! 309: ! 310: // ! 311: // Set up version - dependent stuff ! 312: // ! 313: if (pGDI->Hw.DSPVersion >= MIN_DSP_VERSION) { ! 314: ! 315: pGDI->MinHz = 4000; ! 316: ! 317: if (SB1(&pGDI->Hw)) { ! 318: pGDI->MaxInHz = 12000; ! 319: pGDI->MaxOutHz = 23000; ! 320: } else { ! 321: if (!SBPRO(&pGDI->Hw)) { ! 322: pGDI->MaxInHz = 13000; ! 323: pGDI->MaxOutHz = 23000; ! 324: } else { ! 325: pGDI->MaxInHz = 23000; ! 326: pGDI->MaxOutHz = 23000; ! 327: } ! 328: } ! 329: return STATUS_SUCCESS; ! 330: } else { ! 331: return STATUS_DEVICE_CONFIGURATION_ERROR; ! 332: } ! 333: } ! 334: ! 335: ! 336: ! 337: NTSTATUS ! 338: SoundInitDmaChannel( ! 339: IN OUT PGLOBAL_DEVICE_INFO pGDI, ! 340: IN OUT PULONG DmaChannel, ! 341: IN ULONG DmaBufferSize ! 342: ) ! 343: { ! 344: NTSTATUS Status; ! 345: ! 346: DEVICE_DESCRIPTION DeviceDescription; // DMA adapter object ! 347: ! 348: // ! 349: // See if we can get this channel ! 350: // ! 351: ! 352: // ! 353: // Zero the device description structure. ! 354: // ! 355: ! 356: RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION)); ! 357: ! 358: // ! 359: // Get the adapter object for this card. ! 360: // ! 361: ! 362: DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; ! 363: DeviceDescription.AutoInitialize = !SB1(&pGDI->Hw); ! 364: DeviceDescription.ScatterGather = FALSE; ! 365: DeviceDescription.DmaChannel = *DmaChannel; ! 366: DeviceDescription.InterfaceType = Isa; // Must use Isa DMA ! 367: DeviceDescription.DmaWidth = Width8Bits; ! 368: DeviceDescription.DmaSpeed = Compatible; ! 369: DeviceDescription.MaximumLength = DmaBufferSize; ! 370: DeviceDescription.BusNumber = pGDI->BusNumber; ! 371: ! 372: return SoundGetCommonBuffer(&DeviceDescription, &pGDI->WaveInfo.DMABuf); ! 373: } ! 374: ! 375: ! 376: ! 377: NTSTATUS ! 378: SoundInitInterrupt( ! 379: IN OUT PGLOBAL_DEVICE_INFO pGDI, ! 380: IN OUT PULONG Interrupt ! 381: ) ! 382: { ! 383: NTSTATUS Status; ! 384: ! 385: // ! 386: // See if we can get this interrupt ! 387: // ! 388: ! 389: ! 390: Status = SoundConnectInterrupt( ! 391: *Interrupt, ! 392: pGDI->BusType, ! 393: pGDI->BusNumber, ! 394: SoundISR, ! 395: (PVOID)pGDI, ! 396: INTERRUPT_MODE, ! 397: IRQ_SHARABLE, ! 398: &pGDI->WaveInfo.Interrupt); ! 399: ! 400: if (!NT_SUCCESS(Status)) { ! 401: return Status; ! 402: } ! 403: ! 404: // ! 405: // Check if our interrupts are working. ! 406: // To do this we write a special code to make the card generate ! 407: // an interrupt. We wait a reasonable amount of time for ! 408: // this to happen. This is tried 10 times. ! 409: // ! 410: { ! 411: int i; ! 412: int j; ! 413: ULONG CurrentCount; ! 414: CurrentCount = pGDI->InterruptsReceived + 1; ! 415: ! 416: for (i = 0; i < 10; i++, CurrentCount++) { ! 417: ! 418: // Tell the card to generate an interrupt ! 419: ! 420: dspWrite(&pGDI->Hw, DSP_GENERATE_INT); ! 421: ! 422: // ! 423: // The interrupt routine will increment the InterruptsReceived ! 424: // field if we get an interrupt. ! 425: // ! 426: ! 427: for (j = 0; j < 1000; j++) { ! 428: if (CurrentCount == pGDI->InterruptsReceived) { ! 429: break; ! 430: } ! 431: KeStallExecutionProcessor(10); ! 432: } ! 433: ! 434: // ! 435: // This test catches both too many and too few interrupts ! 436: // ! 437: ! 438: if (CurrentCount != pGDI->InterruptsReceived) { ! 439: ! 440: dprintf1(("Sound blaster configured at wrong interrupt")); ! 441: ! 442: SoundSetVersion(pGDI, 0x2000); // Means wrong interrupt ! 443: return STATUS_DEVICE_CONFIGURATION_ERROR; ! 444: } ! 445: } ! 446: } ! 447: ! 448: return STATUS_SUCCESS; ! 449: } ! 450: ! 451: ! 452: ! 453: NTSTATUS ! 454: SoundSaveConfig( ! 455: IN PWSTR DeviceKey, ! 456: IN ULONG Port, ! 457: IN ULONG DmaChannel, ! 458: IN ULONG Interrupt, ! 459: IN ULONG InputSource ! 460: ) ! 461: { ! 462: NTSTATUS Status; ! 463: ! 464: Status = SoundWriteRegistryDWORD(DeviceKey, SOUND_REG_PORT, Port); ! 465: ! 466: if (!NT_SUCCESS(Status)) { ! 467: return Status; ! 468: } ! 469: ! 470: Status = SoundWriteRegistryDWORD(DeviceKey, SOUND_REG_DMACHANNEL, DmaChannel); ! 471: ! 472: if (!NT_SUCCESS(Status)) { ! 473: return Status; ! 474: } ! 475: ! 476: Status = SoundWriteRegistryDWORD(DeviceKey, SOUND_REG_INTERRUPT, Interrupt); ! 477: ! 478: if (!NT_SUCCESS(Status)) { ! 479: return Status; ! 480: } ! 481: ! 482: Status = SoundWriteRegistryDWORD(DeviceKey, SOUND_REG_INPUTSOURCE, InputSource); ! 483: ! 484: if (!NT_SUCCESS(Status)) { ! 485: return Status; ! 486: } ! 487: ! 488: // ! 489: // Make sure the config routine sees the data ! 490: // ! 491: } ! 492: ! 493: ! 494: VOID ! 495: SoundSaveVolume( ! 496: PGLOBAL_DEVICE_INFO pGDI ! 497: ) ! 498: { ! 499: NTSTATUS Status; ! 500: ! 501: // ! 502: // Write out left and right volume settings for each device ! 503: // ! 504: ! 505: int i; ! 506: for (i = 0; i < NumberOfDevices; i++) { ! 507: PLOCAL_DEVICE_INFO pLDI; ! 508: ! 509: if (pGDI->DeviceObject[i]){ ! 510: pLDI = (PLOCAL_DEVICE_INFO)pGDI->DeviceObject[i]->DeviceExtension; ! 511: SoundSaveDeviceVolume(pLDI, pGDI->RegistryPathName); ! 512: } ! 513: ! 514: } ! 515: ! 516: // ! 517: // Make sure the volume settings make it do disk ! 518: // ! 519: ! 520: SoundFlushRegistryKey(pGDI->RegistryPathName); ! 521: } ! 522: ! 523: ! 524: ! 525: NTSTATUS ! 526: SoundReadConfiguration( ! 527: IN PWSTR ValueName, ! 528: IN ULONG ValueType, ! 529: IN PVOID ValueData, ! 530: IN ULONG ValueLength, ! 531: IN PVOID Context, ! 532: IN PVOID EntryContext ! 533: ) ! 534: /*++ ! 535: ! 536: Routine Description : ! 537: ! 538: Return configuration information for our device ! 539: ! 540: Arguments : ! 541: ! 542: ConfigData - where to store the result ! 543: ! 544: Return Value : ! 545: ! 546: NT status code - STATUS_SUCCESS if no problems ! 547: ! 548: --*/ ! 549: { ! 550: PSB_CONFIG_DATA ConfigData; ! 551: ! 552: ConfigData = Context; ! 553: ! 554: if (ValueType == REG_DWORD) { ! 555: ! 556: if (wcsicmp(ValueName, SOUND_REG_PORT) == 0) { ! 557: ConfigData->Port = *(PULONG)ValueData; ! 558: dprintf3(("Read Port Base : %x", ConfigData->Port)); ! 559: } ! 560: ! 561: else if (wcsicmp(ValueName, SOUND_REG_INTERRUPT) == 0) { ! 562: ConfigData->InterruptNumber = *(PULONG)ValueData; ! 563: dprintf3(("Read Interrupt : %x", ConfigData->InterruptNumber)); ! 564: } ! 565: ! 566: else if (wcsicmp(ValueName, SOUND_REG_DMACHANNEL) == 0) { ! 567: ConfigData->DmaChannel = *(PULONG)ValueData; ! 568: dprintf3(("Read DMA Channel : %x", ConfigData->DmaChannel)); ! 569: } ! 570: ! 571: else if (wcsicmp(ValueName, SOUND_REG_DMABUFFERSIZE) == 0) { ! 572: ConfigData->DmaBufferSize = *(PULONG)ValueData; ! 573: dprintf3(("Read DMA Channel : %x", ConfigData->DmaBufferSize)); ! 574: } ! 575: ! 576: else if (wcsicmp(ValueName, SOUND_REG_INPUTSOURCE) == 0) { ! 577: ConfigData->InputSource = *(PULONG)ValueData; ! 578: dprintf3(("Read Input Source : %s", ! 579: ConfigData->InputSource == INPUT_LINEIN ? "Line in" : ! 580: ConfigData->InputSource == INPUT_AUX ? "Aux" : ! 581: ConfigData->InputSource == INPUT_MIC ? "Microphone" : ! 582: ConfigData->InputSource == INPUT_OUTPUT ? "Output" : ! 583: "Invalid input source" ! 584: )); ! 585: } ! 586: ! 587: else { ! 588: int i; ! 589: for (i = 0; i < NumberOfDevices; i++) { ! 590: if (DeviceInit[i].LeftVolumeName != NULL && ! 591: wcsicmp(ValueName, DeviceInit[i].LeftVolumeName) == 0) { ! 592: ConfigData->Volume[i].Left = *(PULONG)ValueData; ! 593: ! 594: dprintf3(("%ls = %8X", DeviceInit[i].LeftVolumeName, ! 595: ConfigData->Volume[i].Left)); ! 596: break; ! 597: } ! 598: if (DeviceInit[i].RightVolumeName != NULL && ! 599: wcsicmp(ValueName, DeviceInit[i].RightVolumeName) == 0) { ! 600: ConfigData->Volume[i].Right = *(PULONG)ValueData; ! 601: ! 602: dprintf3(("%ls = %8X", DeviceInit[i].RightVolumeName, ! 603: ConfigData->Volume[i].Right)); ! 604: break; ! 605: } ! 606: } ! 607: } ! 608: ! 609: } ! 610: ! 611: return STATUS_SUCCESS; ! 612: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.