|
|
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.