|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1993 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: mididisp.c ! 8: ! 9: Abstract: ! 10: ! 11: This module contains code for the function dispatcher. ! 12: ! 13: Author: ! 14: ! 15: Robin Speed (RobinSp) 30-Jan-1992 ! 16: ! 17: Environment: ! 18: ! 19: Kernel mode ! 20: ! 21: Revision History: ! 22: ! 23: ! 24: --*/ ! 25: ! 26: #include "sound.h" ! 27: ! 28: BOOL SoundSynthPresent(PUCHAR base, PUCHAR inbase); ! 29: ! 30: ! 31: #ifdef ALLOC_PRAGMA ! 32: #pragma alloc_text(init,SoundSynthPresent) ! 33: #pragma alloc_text(init,SoundSynthPortValid) ! 34: #pragma alloc_text(init,SoundMidiIsOpl3) ! 35: #endif ! 36: ! 37: ! 38: ! 39: NTSTATUS ! 40: SoundMidiData( ! 41: IN OUT PLOCAL_DEVICE_INFO pLDI, ! 42: IN PIRP pIrp, ! 43: IN PIO_STACK_LOCATION pIrpStack ! 44: ) ! 45: /*++ ! 46: ! 47: Routine Description: ! 48: ! 49: The user has passed in a buffer of midi data to play ! 50: ! 51: The buffer is validated and the data passed to the device ! 52: ! 53: Arguments: ! 54: ! 55: pLDI - Local wave device info ! 56: pIrp - The IO request packet ! 57: pIrpStack - The current stack location ! 58: ! 59: Return Value: ! 60: ! 61: Irp status ! 62: ! 63: --*/ ! 64: { ! 65: NTSTATUS Status; ! 66: ! 67: ULONG Length; ! 68: PSYNTH_DATA pData; ! 69: PUCHAR SynthBase; ! 70: ! 71: Length = pIrpStack->Parameters.Write.Length; ! 72: pData = (PSYNTH_DATA)pIrp->UserBuffer; ! 73: SynthBase = ((PSOUND_HARDWARE)pLDI->HwContext)->SynthBase; ! 74: ! 75: ! 76: if (Length % sizeof(SYNTH_DATA) != 0) { ! 77: return STATUS_BUFFER_TOO_SMALL; ! 78: } ! 79: ! 80: Status = STATUS_SUCCESS; ! 81: ! 82: try { ! 83: for ( ; Length != 0 ; Length -= sizeof(SYNTH_DATA), pData++) { ! 84: USHORT IoPort; ! 85: IoPort = pData->IoPort; ! 86: if (IoPort < SYNTH_PORT || ! 87: IoPort >= SYNTH_PORT + NUMBER_OF_SYNTH_PORTS) { ! 88: Status = STATUS_INVALID_PARAMETER; ! 89: break; ! 90: } ! 91: ! 92: WRITE_PORT_UCHAR(SynthBase + (IoPort - SYNTH_PORT), ! 93: (UCHAR)pData->PortData); ! 94: ! 95: // ! 96: // Make sure the SYNTH can keep up ! 97: // newer boards need 1us - older boards need ! 98: // 3.3 us after selecting the register and 23 us after ! 99: // writing the data - as we don't know which is which, we ! 100: // wait 23us after every write ! 101: // ! 102: if (pLDI->DeviceIndex == AdlibDevice) { ! 103: KeStallExecutionProcessor(23); ! 104: } else { ! 105: KeStallExecutionProcessor(10); ! 106: } ! 107: } ! 108: ! 109: } except (EXCEPTION_EXECUTE_HANDLER) { ! 110: Status = STATUS_ACCESS_VIOLATION; ! 111: } ! 112: ! 113: pIrp->IoStatus.Information = pIrpStack->Parameters.Write.Length - Length; ! 114: ! 115: return Status; ! 116: } ! 117: ! 118: ! 119: NTSTATUS ! 120: SoundMidiReadPort( ! 121: IN OUT PLOCAL_DEVICE_INFO pLDI, ! 122: IN PIRP pIrp, ! 123: IN PIO_STACK_LOCATION pIrpStack ! 124: ) ! 125: /*++ ! 126: ! 127: Routine Description: ! 128: ! 129: The user has passed in a buffer to return the status port value ! 130: ! 131: The buffer is validated and data returned if it's length 1 ! 132: ! 133: Arguments: ! 134: ! 135: pLDI - Local wave device info ! 136: pIrp - The IO request packet ! 137: pIrpStack - The current stack location ! 138: ! 139: Return Value: ! 140: ! 141: Irp status ! 142: ! 143: --*/ ! 144: { ! 145: NTSTATUS Status; ! 146: ! 147: ULONG Length; ! 148: PUCHAR SynthBase; ! 149: PUCHAR pData; ! 150: ! 151: Length = pIrpStack->Parameters.Read.Length; ! 152: pData = (PUCHAR)pIrp->UserBuffer; ! 153: SynthBase = ((PSOUND_HARDWARE)pLDI->HwContext)->SynthBase; ! 154: ! 155: ! 156: if (Length != sizeof(UCHAR)) { ! 157: return STATUS_INVALID_PARAMETER; ! 158: } ! 159: ! 160: Status = STATUS_SUCCESS; ! 161: ! 162: try { ! 163: *pData = READ_PORT_UCHAR(SynthBase); ! 164: pIrp->IoStatus.Information = sizeof(UCHAR); ! 165: } except (EXCEPTION_EXECUTE_HANDLER) { ! 166: Status = STATUS_ACCESS_VIOLATION; ! 167: } ! 168: ! 169: ! 170: return Status; ! 171: } ! 172: ! 173: ! 174: NTSTATUS ! 175: SoundMidiDispatch( ! 176: IN OUT PLOCAL_DEVICE_INFO pLDI, ! 177: IN PIRP pIrp, ! 178: IN PIO_STACK_LOCATION IrpStack ! 179: ) ! 180: /*++ ! 181: ! 182: Routine Description: ! 183: ! 184: Driver function dispatch routine ! 185: ! 186: Arguments: ! 187: ! 188: pLDI - local device info ! 189: pIrp - Pointer to IO request packet ! 190: IrpStack - current stack location ! 191: ! 192: Return Value: ! 193: ! 194: Return status from dispatched routine ! 195: ! 196: --*/ ! 197: { ! 198: NTSTATUS Status; ! 199: ! 200: Status = STATUS_SUCCESS; ! 201: ! 202: // ! 203: // Initialize the irp information field. ! 204: // ! 205: ! 206: pIrp->IoStatus.Information = 0; ! 207: ! 208: switch (IrpStack->MajorFunction) { ! 209: case IRP_MJ_CREATE: ! 210: Status = SoundSetShareAccess(pLDI, IrpStack); ! 211: ! 212: if (IrpStack->FileObject->WriteAccess) { ! 213: // reset board to silence and to correct mode (opl3 or opl2) ! 214: SoundMidiQuiet(pLDI->DeviceIndex, pLDI->HwContext); ! 215: } ! 216: break; ! 217: ! 218: case IRP_MJ_WRITE: ! 219: if (IrpStack->FileObject->WriteAccess) { ! 220: Status = SoundMidiData(pLDI, pIrp, IrpStack); ! 221: } else { ! 222: Status = STATUS_ACCESS_DENIED; ! 223: } ! 224: break; ! 225: ! 226: case IRP_MJ_READ: ! 227: if (IrpStack->FileObject->WriteAccess) { ! 228: Status = SoundMidiReadPort(pLDI, pIrp, IrpStack); ! 229: } else { ! 230: Status = STATUS_ACCESS_DENIED; ! 231: } ! 232: break; ! 233: ! 234: case IRP_MJ_DEVICE_CONTROL: ! 235: ! 236: ! 237: // ! 238: // Check device access ! 239: // ! 240: if (!IrpStack->FileObject->WriteAccess && ! 241: pLDI->PreventVolumeSetting) { ! 242: Status = STATUS_ACCESS_DENIED; ! 243: } else { ! 244: switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) { ! 245: case IOCTL_MIDI_SET_VOLUME: ! 246: Status = SoundIoctlSetVolume(pLDI, pIrp, IrpStack); ! 247: break; ! 248: ! 249: case IOCTL_MIDI_GET_VOLUME: ! 250: Status = SoundIoctlGetVolume(pLDI, pIrp, IrpStack); ! 251: break; ! 252: ! 253: case IOCTL_SOUND_GET_CHANGED_VOLUME: ! 254: Status = SoundIoctlGetChangedVolume(pLDI, pIrp, IrpStack); ! 255: break; ! 256: ! 257: ! 258: default: ! 259: Status = STATUS_INVALID_DEVICE_REQUEST; ! 260: break; ! 261: } ! 262: } ! 263: break; ! 264: ! 265: ! 266: case IRP_MJ_CLOSE: ! 267: ! 268: Status = STATUS_SUCCESS; ! 269: ! 270: break; ! 271: ! 272: case IRP_MJ_CLEANUP: ! 273: if (IrpStack->FileObject->WriteAccess) { ! 274: SoundMidiQuiet(pLDI->DeviceIndex, pLDI->HwContext); ! 275: (*pLDI->DeviceInit->ExclusionRoutine)(pLDI, SoundExcludeClose); ! 276: pLDI->PreventVolumeSetting = FALSE; ! 277: } else { ! 278: Status = STATUS_SUCCESS; ! 279: } ! 280: break; ! 281: ! 282: default: ! 283: dprintf1(("Unimplemented major function requested: %08lXH", IrpStack->MajorFunction)); ! 284: Status = STATUS_INVALID_DEVICE_REQUEST; ! 285: break; ! 286: } ! 287: ! 288: // ! 289: // Tell the IO subsystem we're done. If the Irp is pending we ! 290: // don't touch it as it could be being processed by another ! 291: // processor (or may even be complete already !). ! 292: // ! 293: ! 294: return Status; ! 295: } ! 296: ! 297: ! 298: ! 299: VOID ! 300: SoundMidiSendFM( ! 301: IN PUCHAR PortBase, ! 302: IN ULONG Address, ! 303: IN UCHAR Data ! 304: ) ! 305: { ! 306: // these delays need to be 23us at least for old opl2 chips, even ! 307: // though new chips can handle 1 us delays. ! 308: ! 309: WRITE_PORT_UCHAR(PortBase + (Address < 0x100 ? 0 : 2), (UCHAR)Address); ! 310: KeStallExecutionProcessor(23); ! 311: WRITE_PORT_UCHAR(PortBase + (Address < 0x100 ? 1 : 3), Data); ! 312: KeStallExecutionProcessor(23); ! 313: } ! 314: ! 315: /* ! 316: * this array gives the offsets of the slots within an opl2 ! 317: * chip. This is needed to set the attenuation for all slots to max, ! 318: * to ensure that the chip is silenced completely - switching off the ! 319: * voices alone will not do this. ! 320: */ ! 321: BYTE offsetSlot[] = { ! 322: 0, 1, 2, 3, 4, 5, ! 323: 8, 9, 10, 11, 12, 13, ! 324: 16, 17, 18, 19, 20, 21 ! 325: }; ! 326: ! 327: ! 328: ! 329: VOID ! 330: SoundMidiQuiet( ! 331: IN UCHAR DeviceIndex, ! 332: IN PSOUND_HARDWARE pHw ! 333: ) ! 334: /*++ ! 335: ! 336: Routine Description: ! 337: ! 338: Initialize the SYNTH hardware to silence ! 339: ! 340: Arguments: ! 341: ! 342: pHw - hardware data ! 343: ! 344: Return Value: ! 345: ! 346: None ! 347: ! 348: --*/ ! 349: { ! 350: ! 351: ULONG i; ! 352: ! 353: // D1 ("\nMidiQuietFM"); ! 354: ! 355: /* ! 356: * sequence to initialise and silence the device ! 357: * depends on whether it is an Opl3 device or not ! 358: */ ! 359: if (DeviceIndex == Opl3Device) { ! 360: ! 361: /* tell the FM chip to use 4-operator mode, and ! 362: fill in any other random variables */ ! 363: SoundMidiSendFM (pHw->SynthBase, AD_NEW, 0x01); ! 364: SoundMidiSendFM (pHw->SynthBase, AD_MASK, 0x60); ! 365: SoundMidiSendFM (pHw->SynthBase, AD_CONNECTION, 0x3f); ! 366: SoundMidiSendFM (pHw->SynthBase, AD_NTS, 0x00); ! 367: ! 368: ! 369: /* turn off the drums, and use high vibrato/modulation */ ! 370: SoundMidiSendFM (pHw->SynthBase, AD_DRUM, 0xc0); ! 371: ! 372: /* turn off all the oscillators */ ! 373: for (i = 0; i < 0x15; i++) { ! 374: SoundMidiSendFM (pHw->SynthBase, AD_LEVEL + i, 0x3f); ! 375: SoundMidiSendFM (pHw->SynthBase, AD_LEVEL2 + i, 0x3f); ! 376: }; ! 377: ! 378: /* turn off all the voices */ ! 379: for (i = 0; i < 0x08; i++) { ! 380: SoundMidiSendFM (pHw->SynthBase, AD_BLOCK + i, 0x00); ! 381: SoundMidiSendFM (pHw->SynthBase, AD_BLOCK2 + i, 0x00); ! 382: }; ! 383: } else { ! 384: /* base adlib hardware initialisation */ ! 385: ! 386: // ensure that if we have a opl3 chip, we are in base mode ! 387: SoundMidiSendFM (pHw->SynthBase, AD_NEW, 0x00); ! 388: ! 389: // turn off all the slot oscillators ! 390: for (i = 0; i < 18; i++) { ! 391: SoundMidiSendFM(pHw->SynthBase, offsetSlot[i]+AD_LEVEL, 0x3f); ! 392: } ! 393: ! 394: /* silence all voices */ ! 395: for (i = 0; i <= 8; i++) { ! 396: SoundMidiSendFM(pHw->SynthBase, (AD_FNUMBER | i), 0); ! 397: SoundMidiSendFM(pHw->SynthBase, (AD_BLOCK | i), 0); ! 398: } ! 399: ! 400: /* switch to percussive mode and silence percussion instruments */ ! 401: SoundMidiSendFM(pHw->SynthBase, AD_DRUM, (BYTE)0x20); ! 402: } ! 403: } ! 404: ! 405: ! 406: BOOL ! 407: SoundSynthPresent(PUCHAR base, PUCHAR inbase) ! 408: /*++ ! 409: ! 410: Routine Description: ! 411: ! 412: Detect the presence or absence of a 3812 (adlib-compatible) synthesizer ! 413: at the given i/o address by starting the timer and looking for an ! 414: overflow. Can be used to detect left and right synthesizers separately. ! 415: ! 416: Arguments: ! 417: ! 418: base - base output address ! 419: inbase - base input address ! 420: ! 421: Return Value: ! 422: ! 423: TRUE if a synthesizer is present at that address ! 424: ! 425: --*/ ! 426: { ! 427: #define inport(port) READ_PORT_UCHAR((PUCHAR)(port)) ! 428: ! 429: UCHAR t1, t2; ! 430: ! 431: ! 432: // check if the chip is present ! 433: SoundMidiSendFM(base, 4, 0x60); // mask T1 & T2 ! 434: SoundMidiSendFM(base, 4, 0x80); // reset IRQ ! 435: t1 = inport(inbase); // read status register ! 436: SoundMidiSendFM(base, 2, 0xff); // set timer - 1 latch ! 437: SoundMidiSendFM(base, 4, 0x21); // unmask & start T1 ! 438: ! 439: // this timer should go off in 80 us. It sometimes ! 440: // takes more than 100us, but will always have expired within ! 441: // 200 us if it is ever going to. ! 442: KeStallExecutionProcessor(200); ! 443: ! 444: t2 = inport(inbase); // read status register ! 445: ! 446: ! 447: SoundMidiSendFM(base, 4, 0x60); ! 448: SoundMidiSendFM(base, 4, 0x80); ! 449: ! 450: ! 451: if (!((t1 & 0xE0) == 0) || !((t2 & 0xE0) == 0xC0)) { ! 452: return(FALSE); ! 453: } ! 454: ! 455: return TRUE; ! 456: ! 457: #undef inport ! 458: ! 459: } ! 460: ! 461: ! 462: ! 463: NTSTATUS ! 464: SoundSynthPortValid( ! 465: IN OUT PGLOBAL_DEVICE_INFO pGDI ! 466: ) ! 467: { ! 468: NTSTATUS Status; ! 469: ULONG Port; ! 470: ! 471: Port = SYNTH_PORT; ! 472: ! 473: // ! 474: // Check we're going to be allowed to use this port or whether ! 475: // some other device thinks it owns this hardware ! 476: // ! 477: ! 478: Status = SoundReportResourceUsage( ! 479: (PDEVICE_OBJECT)pGDI->DriverObject, ! 480: pGDI->BusType, ! 481: pGDI->BusNumber, ! 482: NULL, ! 483: 0, ! 484: FALSE, ! 485: NULL, ! 486: &Port, ! 487: NUMBER_OF_SYNTH_PORTS); ! 488: ! 489: if (!NT_SUCCESS(Status)) { ! 490: return Status; ! 491: } ! 492: ! 493: // ! 494: // Find where our device is mapped ! 495: // ! 496: ! 497: pGDI->Hw.SynthBase = SoundMapPortAddress( ! 498: pGDI->BusType, ! 499: pGDI->BusNumber, ! 500: Port, ! 501: NUMBER_OF_SYNTH_PORTS, ! 502: &pGDI->MemType); ! 503: { ! 504: PUCHAR base; ! 505: ! 506: base = pGDI->Hw.SynthBase; ! 507: ! 508: if (!SoundSynthPresent(base, base)) { ! 509: ! 510: dprintf1(("No synthesizer present")); ! 511: return STATUS_DEVICE_CONFIGURATION_ERROR; ! 512: } ! 513: } ! 514: ! 515: return STATUS_SUCCESS; ! 516: } ! 517: ! 518: ! 519: ! 520: BOOL ! 521: SoundMidiIsOpl3( ! 522: IN PSOUND_HARDWARE pHw ! 523: ) ! 524: /*++ ! 525: ! 526: Routine Description: ! 527: ! 528: Check if the midi synthesizer is Opl3 compatible or just adlib-compatible. ! 529: ! 530: Arguments: ! 531: ! 532: pHw - hardware data ! 533: ! 534: Return Value: ! 535: ! 536: TRUE if OPL3-compatible chip. FALSE otherwise. ! 537: ! 538: --*/ ! 539: { ! 540: BOOL bReturn = FALSE; ! 541: ! 542: PUCHAR Port = pHw->SynthBase; ! 543: ! 544: /* ! 545: * theory: an opl3-compatible synthesizer chip looks ! 546: * exactly like two separate 3812 synthesizers (for left and right ! 547: * channels) until switched into opl3 mode. Then, the timer-control ! 548: * register for the right half is replaced by a channel connection register ! 549: * (among other changes). ! 550: * ! 551: * We can detect 3812 synthesizers by starting a timer and looking for ! 552: * timer overflow. So if we find 3812s at both left and right addresses, ! 553: * we then switch to opl3 mode and look again for the right-half. If we ! 554: * still find it, then the switch failed and we have an old synthesizer ! 555: * if the right half disappeared, we have a new opl3 synthesizer. ! 556: * ! 557: * NB we use either monaural base-level synthesis, or stereo opl3 ! 558: * synthesis. If we discover two 3812s (as on early SB Pro and ! 559: * PAS), we ignore one of them. ! 560: */ ! 561: ! 562: /* ! 563: * nice theory - but wrong. The timer on the right half of the ! 564: * opl3 chip reports its status in the left-half status register. ! 565: * There is no right-half status register on the opl3 chip. ! 566: */ ! 567: ! 568: ! 569: /* ensure base mode */ ! 570: SoundMidiSendFM (Port, AD_NEW, 0x00); ! 571: KeStallExecutionProcessor(20); ! 572: ! 573: /* look for right half of chip */ ! 574: if (SoundSynthPresent(Port + 2, Port)) { ! 575: /* yes - is this two separate chips or a new opl3 chip ? */ ! 576: ! 577: /* switch to opl3 mode */ ! 578: SoundMidiSendFM (Port, AD_NEW, 0x01); ! 579: KeStallExecutionProcessor(20); ! 580: ! 581: ! 582: if (!SoundSynthPresent(Port + 2, Port)) { ! 583: ! 584: /* right-half disappeared - so opl3 */ ! 585: bReturn = TRUE; ! 586: } ! 587: } ! 588: ! 589: /* reset to 3812 mode */ ! 590: SoundMidiSendFM (Port, AD_NEW, 0x00); ! 591: KeStallExecutionProcessor(20); ! 592: ! 593: ! 594: return(bReturn); ! 595: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.