|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1992 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: midi.c ! 8: ! 9: Abstract: ! 10: ! 11: This module contains code for playing and recording Midi ! 12: data. ! 13: ! 14: Author: ! 15: ! 16: Robin Speed (robinsp) 25-Nov-92 ! 17: ! 18: Environment: ! 19: ! 20: Kernel mode ! 21: ! 22: Revision History: ! 23: ! 24: --*/ ! 25: ! 26: #include <soundlib.h> ! 27: #include <midi.h> ! 28: ! 29: // ! 30: // Internal routines ! 31: // ! 32: ! 33: VOID ! 34: MidiRecord( ! 35: IN OUT PMIDI_INFO pMidi, ! 36: IN OUT PIRP pIrp ! 37: ); ! 38: ! 39: // ! 40: // Macros to assist in safely using our spin lock (midi input only) ! 41: // ! 42: ! 43: #if DBG ! 44: #define MidiEnter(pMidi) \ ! 45: { \ ! 46: KIRQL OldIrql; \ ! 47: KeAcquireSpinLock(&(pMidi)->DeviceSpinLock, &OldIrql);\ ! 48: ASSERT((pMidi)->LockHeld == FALSE); \ ! 49: (pMidi)->LockHeld = TRUE; ! 50: ! 51: #define MidiLeave(pMidi) \ ! 52: ASSERT((pMidi)->LockHeld == TRUE); \ ! 53: (pMidi)->LockHeld = FALSE; \ ! 54: KeReleaseSpinLock(&(pMidi)->DeviceSpinLock, OldIrql);\ ! 55: } ! 56: #else ! 57: #define MidiEnter(pMidi) \ ! 58: { \ ! 59: KIRQL OldIrql; \ ! 60: ASSERT((pMidi)->LockHeld == FALSE); \ ! 61: KeAcquireSpinLock(&(pMidi)->DeviceSpinLock, &OldIrql); ! 62: ! 63: #define MidiLeave(pMidi) \ ! 64: ASSERT((pMidi)->LockHeld == TRUE); \ ! 65: KeReleaseSpinLock(&(pMidi)->DeviceSpinLock, OldIrql);\ ! 66: } ! 67: #endif ! 68: ! 69: ! 70: VOID SoundInitMidiIn( ! 71: IN OUT PMIDI_INFO pMidi, ! 72: IN PVOID HwContext ! 73: ) ! 74: /*++ ! 75: ! 76: Routine Description: ! 77: ! 78: Initialize midi input data structure. Assumes the structure is ! 79: initialized to 0 apart from the hardware routine entries which ! 80: should have been initialized. ! 81: ! 82: Arguments: ! 83: ! 84: pMidi - pointer to MIDI_INFO data structure ! 85: ! 86: Return Value: ! 87: None ! 88: ! 89: --*/ ! 90: { ! 91: KeInitializeSpinLock(&pMidi->DeviceSpinLock); ! 92: InitializeListHead(&pMidi->QueueHead); ! 93: pMidi->Key = MIDI_INFO_KEY; ! 94: pMidi->HwContext = HwContext; ! 95: ! 96: ASSERTMSG("Midi hardware routines not initialized", ! 97: pMidi->HwStartMidiIn != NULL && ! 98: pMidi->HwStopMidiIn != NULL && ! 99: pMidi->HwMidiRead != NULL && ! 100: pMidi->HwMidiOut != NULL); ! 101: ! 102: } ! 103: ! 104: ! 105: NTSTATUS ! 106: SoundIoctlGetMidiState( ! 107: IN OUT PLOCAL_DEVICE_INFO pLDI, ! 108: IN PIRP pIrp, ! 109: IN PIO_STACK_LOCATION IrpStack ! 110: ) ! 111: /*++ ! 112: ! 113: Routine Description: ! 114: ! 115: Get the current state of the device and return it to the caller. ! 116: This code is COMMON for : ! 117: Midi in ! 118: Midi out ! 119: ! 120: Arguments: ! 121: ! 122: pLDI - Pointer to our own device data ! 123: pIrp - Pointer to the IO Request Packet ! 124: IrpStack - Pointer to current stack location ! 125: ! 126: Return Value: ! 127: ! 128: Status to put into request packet by caller. ! 129: ! 130: --*/ ! 131: { ! 132: PULONG pState; ! 133: ! 134: if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { ! 135: dprintf1(("Supplied buffer to small for requested data")); ! 136: return STATUS_BUFFER_TOO_SMALL; ! 137: } ! 138: ! 139: // ! 140: // say how much we're sending back ! 141: // ! 142: ! 143: pIrp->IoStatus.Information = sizeof(ULONG); ! 144: ! 145: // ! 146: // cast the buffer address to the pointer type we want ! 147: // ! 148: ! 149: pState = (PULONG)pIrp->AssociatedIrp.SystemBuffer; ! 150: ! 151: // ! 152: // fill in the info - ! 153: // ! 154: ! 155: *pState = pLDI->State; ! 156: ! 157: return STATUS_SUCCESS; ! 158: } ! 159: ! 160: ! 161: NTSTATUS SoundIoctlMidiPlay( ! 162: IN OUT PLOCAL_DEVICE_INFO pLDI, ! 163: IN PIRP pIrp, ! 164: IN PIO_STACK_LOCATION IrpStack ! 165: ) ! 166: /*++ ! 167: ! 168: Routine Description: ! 169: ! 170: Play Midi output (if this is an output device). ! 171: This call is implemented SYNCRHONOUSLY since the device does ! 172: not support interrupts. However, for MP systems we should really ! 173: complete the request asynchronously. We do release the spin lock while ! 174: actually outputting data. ! 175: ! 176: Arguments: ! 177: ! 178: pLDI - our local device data ! 179: pIrp - IO request packet ! 180: IrpStack - The current stack location ! 181: ! 182: ! 183: Return Value: ! 184: ! 185: STATUS_SUCCESS - OK ! 186: STATUS_DEVICE_BUSY - Device in use ! 187: STATUS_NOT_SUPPORTED - wrong device ! 188: ! 189: --*/ ! 190: ! 191: { ! 192: PUCHAR pUserBuffer; // Pointer to mapped user buffer ! 193: ULONG UserBufferSize; // Amount of user data ! 194: ULONG i; // Buffer index ! 195: NTSTATUS Status; ! 196: PMIDI_INFO pMidi; ! 197: ! 198: pMidi = pLDI->DeviceSpecificData; ! 199: Status = STATUS_SUCCESS; ! 200: ! 201: // ! 202: // Check it's valid ! 203: // ! 204: ! 205: if (pLDI->DeviceType != MIDI_OUT) { ! 206: dprintf1(("Attempt play on input device")); ! 207: return STATUS_NOT_SUPPORTED; ! 208: } ! 209: ! 210: ! 211: // ! 212: // Find the length of the data and the buffer ! 213: // ! 214: ! 215: UserBufferSize = ! 216: IrpStack->Parameters.DeviceIoControl.InputBufferLength; ! 217: ! 218: pUserBuffer = IrpStack->Parameters.DeviceIoControl.Type3InputBuffer; ! 219: ! 220: ! 221: // ! 222: // Send the data to the device ! 223: // ! 224: ! 225: dprintf4(("Outputting %d Midi bytes", UserBufferSize)); ! 226: ! 227: // ! 228: // Our memory is not locked down or checked since we're ! 229: // executing the call SYNCHRONOUSLY - so we defend here against ! 230: // bad applications. This is aimed at getting a fast path ! 231: // for short messages. ! 232: // ! 233: ! 234: try { ! 235: (*pMidi->HwMidiOut)(pMidi, pUserBuffer, UserBufferSize); ! 236: } except (EXCEPTION_EXECUTE_HANDLER) { ! 237: Status = STATUS_ACCESS_VIOLATION; ! 238: } ! 239: ! 240: return Status; ! 241: } ! 242: ! 243: ! 244: ! 245: NTSTATUS ! 246: SoundIoctlMidiRecord( ! 247: IN OUT PLOCAL_DEVICE_INFO pLDI, ! 248: IN PIRP pIrp, ! 249: IN PIO_STACK_LOCATION pIrpStack ! 250: ) ! 251: /*++ ! 252: ! 253: Routine Description: ! 254: ! 255: Record midi input. ! 256: ! 257: The input buffer size is checked ! 258: ! 259: If there is still data to be read from the device then read as ! 260: much as possible and complete the buffer. Otherwise queue ! 261: the request. ! 262: ! 263: ! 264: Arguments: ! 265: ! 266: pLDI - our local device data ! 267: pIrp - IO request packet ! 268: IrpStack - The current stack location ! 269: ! 270: Return Value: ! 271: ! 272: STATUS_BUFFER_TOO_SMALL - Not enough room to record anything ! 273: STATUS_PENDING - request queued (at least logically). ! 274: STATUS_NOT_SUPPORTED - wrong device ! 275: ! 276: --*/ ! 277: { ! 278: NTSTATUS Status; ! 279: PMIDI_INFO pMidi; ! 280: ! 281: pMidi = pLDI->DeviceSpecificData; ! 282: ! 283: // ! 284: // confirm we are doing this on the input device! ! 285: // ! 286: ! 287: ASSERT(pLDI->DeviceType == MIDI_IN); ! 288: ! 289: // ! 290: // Check size of buffer ! 291: // ! 292: if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < ! 293: sizeof(MIDI_DD_INPUT_DATA)) { ! 294: dprintf1(("Supplied buffer to small for requested data")); ! 295: ! 296: return STATUS_BUFFER_TOO_SMALL; ! 297: } ! 298: ! 299: // ! 300: // Initialize data length. ! 301: // ! 302: ! 303: pIrp->IoStatus.Information = 0; ! 304: ! 305: // ! 306: // See if there's data to complete the request synchronously ! 307: // ! 308: ! 309: MidiEnter(pMidi); ! 310: ! 311: if (pMidi->InputBytes != 0) { ! 312: ASSERT(pMidi->fMidiInStarted); ! 313: ! 314: // ! 315: // If there was data and a free buffer someone else should ! 316: // have dispatched it ! ! 317: // ! 318: ! 319: ASSERT(IsListEmpty(&pMidi->QueueHead)); ! 320: ! 321: // ! 322: // Pull our data ! 323: // ! 324: ! 325: MidiRecord(pMidi, pIrp); ! 326: Status = STATUS_SUCCESS; ! 327: ! 328: } else { ! 329: // ! 330: // Request not completed - add it to our list and mark it pending ! 331: // ! 332: ! 333: SoundAddIrpToCancellableQ(&pMidi->QueueHead, ! 334: pIrp, ! 335: FALSE); // Means insert at tail ! 336: dprintf3(("irp added")); ! 337: ! 338: // ! 339: // Mark request pending ! 340: // ! 341: pIrp->IoStatus.Status = STATUS_PENDING; ! 342: Status = STATUS_PENDING; ! 343: IoMarkIrpPending(pIrp); ! 344: } ! 345: ! 346: MidiLeave(pMidi); ! 347: ! 348: return Status; ! 349: } ! 350: ! 351: ! 352: ! 353: VOID ! 354: SoundMidiInDeferred( ! 355: IN PKDPC pDpc, ! 356: IN PDEVICE_OBJECT pDeviceObject, ! 357: IN OUT PIRP pIrpDeferred, ! 358: IN OUT PVOID Context ! 359: ) ! 360: /*++ ! 361: ! 362: Routine Description: ! 363: ! 364: Process data after a midi input interrupt. ! 365: If we have started a new batch of data try to grab the first ! 366: byte. ! 367: While there is data record it using MidiRecord for each buffer ! 368: in the queue. ! 369: The last buffer which has data in it is always completed since ! 370: we must get data to the application in real time. ! 371: ! 372: ! 373: Arguments: ! 374: ! 375: pDpc - Dpc object ! 376: pDeviceObject - Our device (points to our device extension) ! 377: pIrpDeferred - Not meaningful here ! 378: Context - NULL for our Dpcs ! 379: ! 380: Return Value: ! 381: ! 382: None ! 383: ! 384: --*/ ! 385: { ! 386: // ! 387: // The job here is just to read the Midi data in until ! 388: // the top bit is set. The data is sent to the buffers ! 389: // supplied by the application. ! 390: // ! 391: ! 392: PLOCAL_DEVICE_INFO pLDI; ! 393: PMIDI_INFO pMidi; ! 394: ! 395: pLDI = (PLOCAL_DEVICE_INFO)pDeviceObject->DeviceExtension; ! 396: pMidi = pLDI->DeviceSpecificData; ! 397: ! 398: dprintf4(("(")); ! 399: ! 400: MidiEnter(pMidi); ! 401: ! 402: // ! 403: // If input is not running something has gone wrong. ! 404: // (copied from windows 3.1 driver so I assume that ! 405: // resetting the SB will also cancel any pending interrupt if ! 406: // we stop midi input) ! 407: // ! 408: ! 409: ASSERT(pMidi->fMidiInStarted); ! 410: ! 411: // ! 412: // Try to grab as many bytes as possible ! 413: // ! 414: ! 415: ! 416: while (pMidi->InputBytes < sizeof(pMidi->MidiInputByte)) { ! 417: if ((*pMidi->HwMidiRead)( ! 418: pMidi, ! 419: pMidi->MidiInputByte + ! 420: (pMidi->InputPosition + pMidi->InputBytes) % ! 421: sizeof(pMidi->MidiInputByte))) { ! 422: pMidi->InputBytes++; ! 423: } else { ! 424: break; ! 425: } ! 426: } ! 427: ! 428: // ! 429: // If there is a LOT of data coming in then we expect that ! 430: // the application will only supply a fairly small number of ! 431: // buffers at a time. We then pass the buffers back and if ! 432: // there's still more the buffers are passed in again. This way ! 433: // other threads get in for long messages. On the other hand ! 434: // short messages need passing back quickly so 2 buffers should ! 435: // kept in motion. ! 436: // ! 437: ! 438: // ! 439: // Loop while there's still data and still somewhere to put it ! 440: // ! 441: ! 442: while (pMidi->InputBytes) { ! 443: ! 444: PIRP pIrp; ! 445: ! 446: // ! 447: // Get our next buffer if there is one ! 448: // ! 449: ! 450: pIrp = SoundRemoveFromCancellableQ(&pMidi->QueueHead); ! 451: ! 452: if (pIrp == NULL) { ! 453: break; ! 454: } ! 455: ! 456: ! 457: // ! 458: // Try filling it with data. MidiRecord will turn off the ! 459: // InputAvailable flag if it runs out of data. ! 460: // ! 461: ! 462: MidiRecord(pMidi, pIrp); ! 463: ! 464: // ! 465: // Complete the request ! 466: // ! 467: ! 468: pIrp->IoStatus.Status = STATUS_SUCCESS; ! 469: IoCompleteRequest(pIrp, IO_SOUND_INCREMENT); ! 470: } ! 471: ! 472: // ! 473: // Release the spin lock ! 474: // ! 475: ! 476: MidiLeave(pMidi); ! 477: ! 478: dprintf4((")")); ! 479: } ! 480: ! 481: ! 482: NTSTATUS ! 483: SoundSetMidiInputState( ! 484: IN OUT PLOCAL_DEVICE_INFO pLDI, ! 485: IN ULONG State ! 486: ) ! 487: /*++ ! 488: ! 489: Routine Description: ! 490: ! 491: Perform the state changes for midi input : ! 492: MIDI_DD_RECORD - Start recording ! 493: MIDI_DD_TOP - suspend recording ! 494: MIDI_DD_RESET - suspend recording and cancel buffers ! 495: ! 496: Arguments: ! 497: ! 498: pLDI - Pointer to local device data ! 499: State - the new state to set ! 500: ! 501: Return Value: ! 502: ! 503: Return status for caller ! 504: ! 505: --*/ ! 506: { ! 507: NTSTATUS Status; ! 508: PMIDI_INFO pMidi; ! 509: ! 510: pMidi = pLDI->DeviceSpecificData; ! 511: ! 512: switch (State) { ! 513: case MIDI_DD_RECORD: ! 514: ! 515: pMidi->RefTime = SoundGetTime(); ! 516: ! 517: pMidi->InputBytes = 0; // Clear buffer ! 518: pMidi->InputPosition = 0; ! 519: ! 520: (*pMidi->HwStartMidiIn)(pLDI->DeviceSpecificData); ! 521: pLDI->State = MIDI_DD_RECORDING; ! 522: pMidi->fMidiInStarted = TRUE; ! 523: Status = STATUS_SUCCESS; ! 524: dprintf3(("Midi Input started")); ! 525: break; ! 526: ! 527: case MIDI_DD_STOP: ! 528: ! 529: (*pMidi->HwStopMidiIn)(pLDI->DeviceSpecificData); ! 530: pLDI->State = MIDI_DD_STOPPED; ! 531: pMidi->fMidiInStarted = FALSE; ! 532: pMidi->InputBytes = 0; ! 533: Status = STATUS_SUCCESS; ! 534: dprintf3(("Midi Input stopped")); ! 535: break; ! 536: ! 537: case MIDI_DD_RESET: ! 538: ! 539: (*pMidi->HwStopMidiIn)(pLDI->DeviceSpecificData); ! 540: pLDI->State = MIDI_DD_STOPPED; ! 541: pMidi->fMidiInStarted = FALSE; ! 542: pMidi->InputBytes = 0; ! 543: ! 544: // ! 545: // Free any pending Irps. ! 546: // ! 547: ! 548: SoundFreeQ(&pMidi->QueueHead, STATUS_CANCELLED); ! 549: ! 550: Status = STATUS_SUCCESS; ! 551: dprintf3(("Midi Input reset")); ! 552: break; ! 553: ! 554: default: ! 555: ! 556: dprintf1(("Bogus set midi input state request: %08lXH", State)); ! 557: Status = STATUS_INVALID_PARAMETER; ! 558: break; ! 559: } ! 560: ! 561: return Status; ! 562: } ! 563: ! 564: ! 565: ! 566: VOID ! 567: MidiRecord( ! 568: IN OUT PMIDI_INFO pMidi, ! 569: IN OUT PIRP pIrp ! 570: ) ! 571: /*++ ! 572: ! 573: Routine Description: ! 574: ! 575: Read midi input data into user's buffer. The time stamp field ! 576: in the user's buffer is also filled in. See ntddmidi.h. ! 577: ! 578: Arguments: ! 579: ! 580: pMidi - Pointer to global device data ! 581: ! 582: Return Value: ! 583: ! 584: None ! 585: ! 586: --*/ ! 587: { ! 588: int i; ! 589: int BufferLength; ! 590: ! 591: PMIDI_DD_INPUT_DATA pData; ! 592: ! 593: ! 594: pData = (PMIDI_DD_INPUT_DATA) ! 595: MmGetSystemAddressForMdl(pIrp->MdlAddress); ! 596: ! 597: // ! 598: // Find out how much room we've got for our data ! 599: // ! 600: { ! 601: PIO_STACK_LOCATION pIrpStack; ! 602: ! 603: pIrpStack = IoGetCurrentIrpStackLocation(pIrp); ! 604: BufferLength = ! 605: pIrpStack->Parameters.Read.Length - ! 606: FIELD_OFFSET(MIDI_DD_INPUT_DATA, Data[0]); ! 607: ! 608: ASSERT(BufferLength > 0); ! 609: } ! 610: ! 611: ! 612: // ! 613: // Try filling it with data. MidiRecord will turn off the ! 614: // InputActive flag if it runs out of data. There must be ! 615: // at least one byte of data available because callers are ! 616: // expecting to complete the Irp on return with data ! 617: // ! 618: ! 619: ASSERT(pMidi->InputBytes != 0); ! 620: ! 621: // ! 622: // Remember the time ! 623: // ! 624: ! 625: pData->Time = RtlLargeIntegerSubtract(SoundGetTime(), pMidi->RefTime); ! 626: ! 627: // ! 628: // Read bytes until exhaused or buffer full ! 629: // ! 630: ! 631: for (i = 0; pMidi->InputBytes != 0 && i < BufferLength; i++) { ! 632: // ! 633: // Record the byte ! 634: // ! 635: ! 636: pData->Data[i] = pMidi->MidiInputByte[pMidi->InputPosition]; ! 637: pMidi->InputPosition = ! 638: (pMidi->InputPosition + 1) % sizeof(pMidi->MidiInputByte); ! 639: ! 640: pMidi->InputBytes--; ! 641: ! 642: dprintf4(("%2X", (ULONG)pData->Data[i])); ! 643: ! 644: // ! 645: // Try to read our next byte ! 646: // ! 647: ! 648: if (pMidi->InputBytes == 0) { ! 649: pMidi->InputPosition = 0; ! 650: ! 651: // ! 652: // Read as many bytes as we can ! 653: // ! 654: ! 655: while (pMidi->InputBytes < sizeof(pMidi->MidiInputByte)) { ! 656: ! 657: if ((*pMidi->HwMidiRead)( ! 658: pMidi, ! 659: pMidi->MidiInputByte + pMidi->InputBytes)) { ! 660: pMidi->InputBytes++; ! 661: } else { ! 662: break; ! 663: } ! 664: } ! 665: } ! 666: } ! 667: ! 668: // ! 669: // Record the amount of data returned in the Irp ! 670: // The caller will complete the request. ! 671: ! 672: pIrp->IoStatus.Information = i + sizeof(LARGE_INTEGER); ! 673: } ! 674: ! 675: ! 676: ! 677: VOID ! 678: SoundMidiReset( ! 679: IN OUT PMIDI_INFO pMidi ! 680: ) ! 681: /*++ ! 682: ! 683: Routine Description: ! 684: ! 685: Reset midi output state ! 686: ! 687: Arguments: ! 688: ! 689: pMidi - Pointer to Midi device data ! 690: ! 691: Return Value: ! 692: ! 693: None ! 694: ! 695: --*/ ! 696: { ! 697: int i, j; ! 698: // ! 699: // Send a note off to each key on each channel ! 700: // !!! this is not recommended by the midi spec !!! ! 701: // ! 702: for (i = 0; i < 16; i++) { ! 703: ! 704: UCHAR Data[4 + 256]; ! 705: ! 706: // Turn the damper pedal off (sustain) ! 707: ! 708: Data[0] = (UCHAR)(0xB0 + i); // Control change status byte ! 709: Data[1] = 0x40; // Control number for sustain ! 710: Data[2] = 0x00; // value (0 = off) ! 711: ! 712: // Send note off for each key ! 713: ! 714: Data[3] = (UCHAR)(0x80 + i); // Note off status byte ! 715: ! 716: for (j = 0; j < 128; j++) { ! 717: Data[4 + j * 2] = (UCHAR)j; // Key number ! 718: Data[4 + j * 2 + 1] = 0x40; // Velocity (64 recommended) ! 719: } ! 720: ! 721: (*pMidi->HwMidiOut)(pMidi, Data, sizeof(Data)); ! 722: } ! 723: } ! 724: ! 725: ! 726: ! 727: NTSTATUS ! 728: SoundMidiDispatch( ! 729: IN OUT PLOCAL_DEVICE_INFO pLDI, ! 730: IN PIRP pIrp, ! 731: IN PIO_STACK_LOCATION IrpStack ! 732: ) ! 733: /*++ ! 734: ! 735: Routine Description: ! 736: ! 737: Midi Irp call dispatcher ! 738: ! 739: Arguments: ! 740: ! 741: pLDI - Pointer to local device data ! 742: pIrp - Pointer to IO request packet ! 743: IrpStack - Pointer to current stack location ! 744: ! 745: Return Value: ! 746: ! 747: Return status from dispatched routine ! 748: ! 749: --*/ ! 750: { ! 751: NTSTATUS Status; ! 752: ! 753: Status = STATUS_SUCCESS; ! 754: ! 755: switch (IrpStack->MajorFunction) { ! 756: case IRP_MJ_CREATE: ! 757: Status = SoundSetShareAccess(pLDI, IrpStack); ! 758: if (NT_SUCCESS(Status) && IrpStack->FileObject->WriteAccess) { ! 759: ! 760: if (pLDI->DeviceType == MIDI_OUT) { ! 761: // ! 762: // We can open Midi output ! 763: // ! 764: pLDI->State = MIDI_DD_IDLE; ! 765: dprintf3(("Opened for midi output")); ! 766: Status = STATUS_SUCCESS; ! 767: } else { ! 768: // ! 769: // Open midi input ! 770: // Only midi input has state data ! 771: // ! 772: ! 773: PMIDI_INFO pMidi; ! 774: pMidi = pLDI->DeviceSpecificData; ! 775: ! 776: ASSERT(IsListEmpty(&pMidi->QueueHead)); ! 777: ! 778: pLDI->State = MIDI_DD_STOPPED; ! 779: ASSERT(!pMidi->fMidiInStarted); ! 780: dprintf3(("Opened for midi input")); ! 781: Status = STATUS_SUCCESS; ! 782: } ! 783: } ! 784: break; ! 785: ! 786: case IRP_MJ_CLOSE: ! 787: ! 788: Status = STATUS_SUCCESS; ! 789: ! 790: break; ! 791: ! 792: case IRP_MJ_READ: ! 793: ! 794: if (pLDI->DeviceType != MIDI_IN) { ! 795: Status = STATUS_INVALID_DEVICE_REQUEST; ! 796: } else { ! 797: if (IrpStack->FileObject->WriteAccess) { ! 798: Status = SoundIoctlMidiRecord(pLDI, pIrp, IrpStack); ! 799: } else { ! 800: Status = STATUS_ACCESS_DENIED; ! 801: } ! 802: } ! 803: break; ! 804: ! 805: ! 806: case IRP_MJ_DEVICE_CONTROL: ! 807: ! 808: // ! 809: // Check that if someone has the device open for 'write' it's ! 810: // marked as in use ! 811: // ! 812: ! 813: ASSERT(!IrpStack->FileObject->WriteAccess || ! 814: (*pLDI->DeviceInit->ExclusionRoutine)(pLDI, SoundExcludeQueryOpen)); ! 815: ! 816: // ! 817: // Dispatch the IOCTL function ! 818: // Note that some IOCTLs only make sense for input or output ! 819: // devices and not both. ! 820: // Note that APIs which are possibly asynchronous do not ! 821: // go through the Irp cleanup at the end here because they ! 822: // may get completed before returning here or they are made ! 823: // accessible to other requests by being queued. ! 824: // ! 825: ! 826: switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) { ! 827: ! 828: case IOCTL_MIDI_GET_CAPABILITIES: ! 829: Status = (*pLDI->DeviceInit->DevCapsRoutine)(pLDI, pIrp, IrpStack); ! 830: break; ! 831: ! 832: case IOCTL_MIDI_PLAY: ! 833: Status = SoundIoctlMidiPlay(pLDI, pIrp, IrpStack); ! 834: break; ! 835: ! 836: case IOCTL_MIDI_SET_STATE: ! 837: if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { ! 838: dprintf1(("Supplied buffer too small for expected data")); ! 839: Status = STATUS_BUFFER_TOO_SMALL; ! 840: } else { ! 841: PULONG pState; ! 842: ! 843: // ! 844: // cast the buffer address to the pointer type we want ! 845: // ! 846: ! 847: pState = (PULONG)pIrp->AssociatedIrp.SystemBuffer; ! 848: ! 849: if (pLDI->DeviceType == MIDI_IN) { ! 850: Status = SoundSetMidiInputState(pLDI, *pState); ! 851: } else { ! 852: ! 853: switch (*pState) { ! 854: case MIDI_DD_RESET: ! 855: // ! 856: // Sent note-off to all notes ! 857: // ! 858: SoundMidiReset( ! 859: (PMIDI_INFO)pLDI->DeviceSpecificData); ! 860: ! 861: break; ! 862: ! 863: default: ! 864: Status = STATUS_INVALID_PARAMETER; ! 865: } ! 866: } ! 867: } ! 868: break; ! 869: ! 870: case IOCTL_MIDI_GET_STATE: ! 871: Status = SoundIoctlGetMidiState(pLDI, pIrp, IrpStack); ! 872: break; ! 873: ! 874: ! 875: default: ! 876: dprintf2(("Unimplemented IOCTL (%08lXH) requested", IrpStack->Parameters.DeviceIoControl.IoControlCode)); ! 877: Status = STATUS_INVALID_DEVICE_REQUEST; ! 878: break; ! 879: } ! 880: break; ! 881: ! 882: ! 883: case IRP_MJ_CLEANUP: ! 884: if (IrpStack->FileObject->WriteAccess) { ! 885: ! 886: PMIDI_INFO pMidi; ! 887: ! 888: pMidi = pLDI->DeviceSpecificData; ! 889: ! 890: switch (pLDI->DeviceType) { ! 891: case MIDI_OUT: ! 892: SoundMidiReset(pMidi); ! 893: break; ! 894: ! 895: case MIDI_IN: ! 896: (*pMidi->HwStopMidiIn)(pLDI->DeviceSpecificData); ! 897: pMidi->fMidiInStarted = FALSE; ! 898: pMidi->InputBytes = 0; ! 899: SoundFreeQ(&pMidi->QueueHead, STATUS_CANCELLED); ! 900: break; ! 901: } ! 902: pLDI->PreventVolumeSetting = FALSE; ! 903: ! 904: (*pLDI->DeviceInit->ExclusionRoutine)(pLDI, SoundExcludeClose); ! 905: ! 906: } else { ! 907: Status = STATUS_SUCCESS; ! 908: } ! 909: break; ! 910: ! 911: ! 912: default: ! 913: dprintf1(("Unimplemented major function requested: %08lXH", IrpStack->MajorFunction)); ! 914: Status = STATUS_INVALID_DEVICE_REQUEST; ! 915: break; ! 916: } ! 917: ! 918: return Status; ! 919: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.