|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1992 Microsoft Corporation
4:
5: Module Name:
6:
7: wave.c
8:
9: Abstract:
10:
11: This module contains code for wave input and output which is non
12: hardware specific.
13:
14: Author:
15:
16: Robin Speed (RobinSp) 1-Nov-1992
17:
18: Environment:
19:
20: Kernel mode
21:
22: Revision History:
23:
24: 03-11-93 EPA
25: Added SoundGetDMABufferSize( IN OUT PWAVE_INFO WaveInfo )
26:
27: Notes:
28:
29: This component implements a wave type device with recording and
30: playing.
31:
32: Dispatch routine :
33: Create device IRP_MJ_CREATE
34: Cleanup and close device IRP_MJ_CLEANUP and IRP_MJ_CLOSE
35: Read for recording IRP_MJ_READ
36: Write for playing IRP_MJ_WRITE
37: IO controls IRP_MJ_DEVICE_CONTROL
38:
39: The device state is held mainly in a WAVE_INFO structure except
40: for actual state variable itself (playing, paused) which is in the
41: local device info.
42:
43: The device is assume to use DMA. The design is always to copy the
44: DMA data into a designated buffer which divided into two halves :
45:
46: The half that is playing
47: The half that is prepared for playing
48:
49: DMA stops either because of a request to stop or because the data
50: runs out. The latter condition is detected rather lazily by waiting
51: until a half buffer completes and testing if there's anything in the
52: buffer prepared for playing. This could be improved by setting a
53: timer at the start of the 'last' buffer. We don't switch our method
54: of playing for the 'last' buffer because the application could
55: supply more data while this buffer is playing.
56:
57: Once DMA is started a 'deferred procedure call' (Dpc) routine
58: is queued for every interrupt (the device specific code outside this
59: component must arrange for this by making SoundWaveDeferred) the
60: Dpc routine for the device object and calling IoRequestDpc from
61: its interrupt service routine ONLY IF the DMABusy flag is set.
62:
63: The DMA buffer size is varied depending on the number of bits
64: per second.
65:
66: Mutual exclusion is on 4 levels :
67:
68: 1. At the application request level by the application's exclusion
69: routine which is called back for every request (usually a MUTANT
70: or MUTEX - NOT a spin lock).
71:
72: 2. Between routines on the application thread and the Dpc routines
73: for variables owned by this component by a spin lock.
74:
75: 3. Between routines below device level and device level by the
76: interrupt object.
77:
78: 4. Exclusion implemented for device access (eg synch with ISR or
79: between multiple devices) by the hardware access callback routines.
80:
81: Irp handling :
82: --------------
83:
84: Both wave input and output have an input queue or Irps attached
85: to QueueHead in the WAVE_INFO structure. Irps on this queue
86: can be cancelled at any time and can only be accessed under
87: the Cancel spin lock.
88:
89: Wave output has an additional queue of non-cancellable Irps
90: attached from ProgressQueue. These Irps have some or all of
91: their data actually in the DMA buffers. The head Irp in this
92: second queue has its IoStatus.Information field set to the position
93: where the first data byte in the DMA buffers was copied from. When
94: a DMA buffer completes Irps are completed for the bytes in the
95: buffer and a new IoStatus.Information field set.
96:
97: If output is paused the ProgressQueue is moved back under QueueHead
98: and the Irps in it become cancellable. Restarting from Pause
99: takes note of the IoStatus.Information field for the first byte
100: to take from the first buffer (which may not be the same as that
101: when we were paused because in theory that one could have been
102: cancelled).
103:
104: Timer monitoring of devices to make sure they aren't dead
105: ---------------------------------------------------------
106:
107: When DMA starts we start a timer Dpc with a timeout of 3 seconds.
108:
109: Each time an IO completion Dpc runs we set a flag to say we've had
110: a Dpc routine (and hence an interrupt).
111:
112: The timer Dpc routine checks that we've had a interrupt in the last
113: 3 seconds and shuts down the device (forever - by setting DeviceBad
114: in the WAVE_INFO) if not. Otherwise it queues a clone of itself.
115:
116: If we detect the bad state and set DeviceBad we stop the DMA so
117: as to release resources. Any new request to the driver will
118: receive STATUS_INVALID_DEVICE_REQUEST.
119:
120: Shutting down the timer Dpc is rather complicated :
121:
122: We aim to get to a state where either :
123:
124: A. The Dpc will not run again (unless re-initiated) and is
125: not running.
126:
127: B. We can wait for the Dpc routine to set an event.
128:
129: And to know which of A or B we reached.
130:
131: The timer logical thread can be in one of :
132:
133: X. Really complete
134:
135: Y. On timer queue
136:
137: Z. On Dpc queue
138:
139: W1. Dpc routine running before getting spin lock
140:
141: W2. Dpc routine running after releasing spin lock.
142: This is just the tail of the routine which does nothing
143: so regard the timer as 'finished' (state X).
144:
145: W3. Holding spin lock
146:
147: Outside the device spin lock the TimerActive boolean is TRUE
148: in case X and FALSE in other cases (except when we're synchronously
149: starting the thing up when we set it prior to setting the
150: first timer).
151:
152:
153: The method of reaching a known state is :
154:
155: Inside the device spin lock :
156:
157: If TimerActive is FALSE do nothing
158:
159: Cancel the timer
160:
161: If the timer was set we were in state Y and we're done
162:
163: Otherwise note that we cannot now enter state Y while
164: we have the spin lock here because we would have to
165: go through state W3 (because the Dpc routine is the one
166: which restarts the timer and it has the spin lock while it
167: does it).
168:
169: Thus we know we're in state Z or W1 so now we just reset our
170: event and set TimerActive to be FALSE.
171:
172: We then release the device spin lock and wait
173: for the event to be set by the timer Dpc routine. We
174:
175:
176: --*/
177:
178: #include <stdlib.h> // For min, max
179: #include <string.h>
180: #include <soundlib.h>
181: #include <wave.h>
182:
183: //
184: // Local definitions
185: //
186:
187: VOID
188: SoundStartWaveRecord(
189: IN OUT PLOCAL_DEVICE_INFO pLDI
190: );
191:
192: VOID
193: SoundStopWaveRecord(
194: IN OUT PLOCAL_DEVICE_INFO pLDI
195: );
196: VOID
197: SoundStartDMA(
198: IN PWAVE_INFO WaveInfo
199: );
200: IO_ALLOCATION_ACTION
201: SoundProgramDMA(
202: IN PDEVICE_OBJECT pDO,
203: IN PIRP pIrp,
204: IN PVOID pMRB,
205: IN PVOID Context
206: );
207: VOID
208: SoundTerminateDMA(
209: IN PWAVE_INFO WaveInfo,
210: IN BOOLEAN Pause
211: );
212: VOID
213: SoundStopDMA(
214: IN PWAVE_INFO WaveInfo,
215: IN BOOLEAN Pause
216: );
217: VOID
218: SoundResetOutput(
219: IN OUT PSOUND_BUFFER_QUEUE BufferQueue
220: );
221: BOOLEAN
222: SoundAdjustHalf(
223: PVOID Context
224: );
225: NTSTATUS
226: SoundSetWaveInputState(
227: IN OUT PLOCAL_DEVICE_INFO pLDI,
228: IN ULONG State
229: );
230: NTSTATUS
231: SoundSetWaveOutputState(
232: PLOCAL_DEVICE_INFO pLDI,
233: ULONG State,
234: PIRP pIrp
235: );
236: VOID
237: SoundGetNextBuffer(
238: PSOUND_BUFFER_QUEUE BufferQueue
239: );
240:
241: VOID
242: SoundCompleteIoBuffer(
243: PSOUND_BUFFER_QUEUE BufferQueue
244: );
245: VOID
246: SoundInitializeBufferQ(
247: PSOUND_BUFFER_QUEUE BufferQueue
248: );
249:
250: VOID
251: SoundInitializeDoubleBuffer(
252: IN OUT PWAVE_INFO WaveInfo
253: );
254:
255: VOID
256: SoundClearDoubleBuffer(
257: IN OUT PWAVE_INFO WaveInfo
258: );
259:
260: VOID
261: SoundLoadDMABuffer(
262: PSOUND_BUFFER_QUEUE BufferQueue,
263: struct SOUND_DMABUF *pDMA,
264: UCHAR pad
265: );
266: VOID
267: SoundTestDeviceDeferred(
268: IN PKDPC Dpc,
269: IN PVOID Context,
270: IN PVOID Param1,
271: IN PVOID Param2
272: );
273: VOID
274: SoundSynchTimer(
275: IN PWAVE_INFO WaveInfo
276: );
277:
278:
279: WAVE_INTERFACE_ROUTINE SoundFillOutputBuffers;
280: WAVE_INTERFACE_ROUTINE SoundFillInputBuffers;
281:
282: WAVE_INTERFACE_ROUTINE SoundMapDMA;
283: WAVE_INTERFACE_ROUTINE SoundFlushDMA;
284:
285: //
286: // Remove initialization stuff from resident memory
287: //
288:
289: #ifdef ALLOC_PRAGMA
290: #pragma alloc_text(init,SoundGetCommonBuffer)
291: #pragma alloc_text(init,SoundTestWaveDevice)
292: #endif
293:
294:
295: /***************************************************************************
296: *
297: * Allocate DMA Buffer for auto-init DMA
298: *
299: ***************************************************************************/
300:
301: NTSTATUS
302: SoundGetCommonBuffer(
303: IN PDEVICE_DESCRIPTION DeviceDescription,
304: IN OUT PSOUND_DMA_BUFFER AutoBuffer
305: )
306: /*++
307:
308: Routine Description :
309:
310: Find the adapter object for our adapter
311:
312: Allocate and map a common buffer for use with auto-init DMA
313: devices. The buffer returned should not cross a 64KB boundary
314: for an Isa device
315:
316: Arguments :
317:
318: DeviceDescription - The adapter object description
319: SoundAutoData - the information describing our buffer
320:
321: Return Value :
322:
323: NTSTATUS code - STATUS_SUCCESS if OK
324:
325: --*/
326: {
327: SOUND_DMA_BUFFER SoundAutoData;
328: ULONG NumberOfMapRegisters;
329:
330: SoundAutoData.BufferSize = DeviceDescription->MaximumLength;
331:
332: //
333: // Try to find an adapter
334: //
335:
336: SoundAutoData.AdapterObject[0] = HalGetAdapter(
337: DeviceDescription,
338: &NumberOfMapRegisters);
339: //
340: // Check we got a good adapter and enough registers
341: //
342:
343: if (SoundAutoData.AdapterObject[0] == NULL) {
344: dprintf1(("Could not find adapter"));
345: return STATUS_DEVICE_CONFIGURATION_ERROR;
346: }
347:
348: if (NumberOfMapRegisters < BYTES_TO_PAGES(SoundAutoData.BufferSize)) {
349: dprintf1(("Could only get %u mapping registers for DMA buffer",
350: NumberOfMapRegisters));
351:
352: if (NumberOfMapRegisters == 0) {
353: return STATUS_INSUFFICIENT_RESOURCES;
354: }
355: SoundAutoData.BufferSize = NumberOfMapRegisters * PAGE_SIZE;
356: }
357:
358: //
359: // Call the Hal to allocate the right kind of memory. It may
360: // not be able to get enough - but we never accept less than 4K
361: // and decrease our requirement in 1K chunks.
362: //
363:
364: for (;
365: SoundAutoData.BufferSize >= SOUND_MINIMUM_WAVE_BUFFER_SIZE ;
366: SoundAutoData.BufferSize -= SOUND_MINIMUM_WAVE_BUFFER_SIZE / 4) {
367: SoundAutoData.VirtualAddress =
368: HalAllocateCommonBuffer(SoundAutoData.AdapterObject[0],
369: SoundAutoData.BufferSize,
370: &SoundAutoData.LogicalAddress,
371: FALSE // Non-cached
372: );
373:
374: if (SoundAutoData.VirtualAddress == NULL) {
375: dprintf1(("Could not allocate DMA buffer size %8X",
376: SoundAutoData.BufferSize));
377: } else {
378: break;
379: }
380: }
381:
382: if (SoundAutoData.BufferSize < SOUND_MINIMUM_WAVE_BUFFER_SIZE) {
383: return STATUS_INSUFFICIENT_RESOURCES;
384: }
385:
386:
387: SoundAutoData.Mdl = IoAllocateMdl(
388: SoundAutoData.VirtualAddress,
389: SoundAutoData.BufferSize,
390: FALSE, // not a secondary buffer
391: FALSE, // no charge of quota
392: NULL // no irp
393: );
394:
395:
396: if (SoundAutoData.VirtualAddress == NULL) {
397: dprintf1(("Could not allocate DMA buffer size %8X",
398: SoundAutoData.BufferSize));
399:
400: HalFreeCommonBuffer(
401: SoundAutoData.AdapterObject[0],
402: SoundAutoData.BufferSize,
403: SoundAutoData.LogicalAddress,
404: SoundAutoData.VirtualAddress,
405: FALSE);
406:
407: return STATUS_INSUFFICIENT_RESOURCES;
408: }
409:
410: //
411: // Build an Mdl (ie fill in the physical addresses)
412: //
413:
414: MmBuildMdlForNonPagedPool(SoundAutoData.Mdl);
415:
416:
417: dprintf4((" DMA Buffer : %08lXH - physical %08lXH, Length %8lXH",
418: SoundAutoData.VirtualAddress,
419: MmGetPhysicalAddress((PVOID)SoundAutoData.VirtualAddress),
420: SoundAutoData.BufferSize));
421:
422: *AutoBuffer = SoundAutoData;
423:
424: return STATUS_SUCCESS;
425: }
426:
427:
428: VOID
429: SoundFreeCommonBuffer(
430: IN OUT PSOUND_DMA_BUFFER SoundAutoData
431: )
432: /*++
433:
434: Routine Description :
435:
436: Free the data associated with a common buffer
437:
438: Arguments :
439:
440: SoundAutoData - The data created when we created the buffer
441:
442: Return Value :
443:
444: None
445:
446: --*/
447: {
448: if (SoundAutoData->Mdl) {
449:
450: IoFreeMdl(SoundAutoData->Mdl);
451:
452: HalFreeCommonBuffer(
453: SoundAutoData->AdapterObject[0],
454: SoundAutoData->BufferSize,
455: SoundAutoData->LogicalAddress,
456: SoundAutoData->VirtualAddress,
457: FALSE);
458: }
459: }
460:
461:
462:
463: /**************************************************************************
464: *
465: * Open, close and dispatch routines
466: *
467: **************************************************************************/
468:
469:
470: VOID
471: SoundStartWaveDevice(
472: IN OUT PLOCAL_DEVICE_INFO pLDI,
473: IN PIRP pIrp OPTIONAL
474: )
475: /*++
476:
477: Routine Description:
478:
479: Add the input Irp (if any) to the device's input queue.
480:
481: Start the data flow and DMA on the device if necessary (ie
482: if we're in playing or recording state and it's not running
483: already.
484:
485: Arguments:
486:
487: pLDI - Local device info
488: pIrp - IO request packet from application
489:
490: Return Value:
491:
492: Irp status
493:
494: --*/
495: {
496: BOOLEAN StartDMA;
497: PWAVE_INFO WaveInfo;
498:
499: WaveInfo = pLDI->DeviceSpecificData;
500:
501: ASSERTMSG("WAVE_INFO structure not correctly initialized",
502: WaveInfo != NULL && WaveInfo->Key == WAVE_INFO_KEY);
503:
504: DMAEnter(WaveInfo);
505:
506: StartDMA = !WaveInfo->DMABusy;
507:
508: //
509: // Put the request in the queue. This is valid for any state if
510: // the device is open.
511: //
512:
513: if (pIrp) {
514: SoundAddIrpToCancellableQ(&WaveInfo->BufferQueue.QueueHead, pIrp, FALSE);
515:
516: dprintf3(("irp added"));
517: }
518: DMALeave(WaveInfo);
519:
520: //
521: // NOTE - at this point it is possible for some old output to
522: // complete but not pick up the buffer we've just inserted.
523: // This is OK - we'll notice this just below. This has
524: // actually happened.
525: //
526:
527:
528: if (pLDI->State == WAVE_DD_PLAYING ||
529: pLDI->State == WAVE_DD_RECORDING) {
530:
531: //
532: // Set the format if necessary
533: //
534:
535: if (StartDMA) {
536: //
537: // We always initialize the buffers for wave recording.
538: // For wave output we may be paused so we usually don't
539: // initialize things.
540: //
541: // Also select DMA Buffer size dependent on number of bytes per
542: // second.
543: //
544:
545:
546: if (WaveInfo->FormatChanged || !WaveInfo->Direction) {
547: SoundInitializeDoubleBuffer(WaveInfo);
548: }
549: }
550:
551:
552: //
553: // Acquire the spin lock so we are synchronized with the Dpc routine
554: //
555:
556: DMAEnter(WaveInfo);
557:
558: //
559: // Remember whether Dma was running :
560: //
561: // If it is running now (while we hold the spin lock) then
562: // the data we've added will keep it going until the data we've
563: // added runs out - so it's safe to release the spin lock
564: //
565: // If the Dma is not running now then it needs restarting. In
566: // this case nobody but us can restart it (we hold the device
567: // mutex) so it's safe to release the spin lock
568: //
569: // DMA may have finished when we released the spin lock so re-test it
570: //
571:
572: StartDMA = !WaveInfo->DMABusy;
573:
574: //
575: // If we're not currently running DMA we need to init the buffers
576: //
577:
578: if (WaveInfo->DMABusy) {
579:
580: //
581: // Find out which half we're really in by counting overruns
582: // BUGBUG this is currently a NOOP
583: //
584:
585: KeSynchronizeExecution(
586: WaveInfo->Interrupt,
587: SoundAdjustHalf,
588: (PVOID)WaveInfo);
589: }
590:
591:
592: //
593: // Process as much data as we can
594: //
595:
596: (WaveInfo->Direction ?
597: SoundFillOutputBuffers :
598: SoundFillInputBuffers)
599: (WaveInfo);
600:
601:
602:
603: //
604: // Ok to release the spin lock now
605: //
606:
607: DMALeave(WaveInfo);
608:
609:
610: //
611: // Start the Dma if necessary
612: //
613:
614: if (StartDMA) {
615: //
616: // Set the format
617: //
618:
619: (*WaveInfo->HwSetWaveFormat)(WaveInfo);
620:
621: //
622: // Synchronize with our timer routine if necessary
623: //
624:
625: SoundSynchTimer(WaveInfo);
626:
627: //
628: // Start the DMA
629: //
630:
631: SoundStartDMA(WaveInfo);
632: }
633: } else {
634: ASSERT(!WaveInfo->DMABusy);
635: StartDMA = FALSE;
636: }
637: }
638:
639:
640: NTSTATUS
641: SoundWaveData(
642: IN OUT PLOCAL_DEVICE_INFO pLDI,
643: IN PIRP pIrp,
644: IN PIO_STACK_LOCATION pIrpStack
645: )
646: /*++
647:
648: Routine Description:
649:
650: The user has passed in a buffer of wave data to play or of wave data
651: to record into.
652:
653: Call SoundStartWaveDevice to process the request.
654:
655: Arguments:
656:
657: pLDI - Local wave device info
658: pIrp - The IO request packet
659: pIrpStack - The current stack location
660:
661: Return Value:
662:
663: Irp status
664:
665: --*/
666: {
667: NTSTATUS Status;
668:
669: //
670: // Check we're the right kind of device
671: //
672:
673: if (pIrpStack->MajorFunction == IRP_MJ_READ &&
674: pLDI->DeviceType != WAVE_IN ||
675: pIrpStack->MajorFunction == IRP_MJ_WRITE &&
676: pLDI->DeviceType != WAVE_OUT) {
677: return STATUS_NOT_SUPPORTED;
678: }
679:
680: //
681: // Mark the Irp pending before starting processing
682: //
683:
684: IoMarkIrpPending(pIrp);
685: pIrp->IoStatus.Status = STATUS_PENDING;
686:
687: //
688: // Mark this request as pending completion.
689: //
690:
691: Status = STATUS_PENDING;
692:
693: if (pLDI->DeviceType == WAVE_IN) {
694: //
695: // Inform debuggers that 0 length buffers are rather strange
696: //
697:
698: if (pIrpStack->Parameters.Read.Length == 0) {
699: dprintf2(("Wave buffer is zero length"));
700: }
701:
702: } else {
703: //
704: // Inform debuggers that 0 length buffers are rather strange
705: //
706:
707: if (pIrpStack->Parameters.Write.Length == 0) {
708: dprintf2(("Wave buffer is zero length"));
709: }
710: }
711:
712: SoundStartWaveDevice(pLDI, pIrp);
713:
714:
715: return Status;
716: }
717:
718:
719:
720:
721: VOID
722: SoundWaveCreate(
723: IN OUT PLOCAL_DEVICE_INFO pLDI,
724: IN PDEVICE_OBJECT DeviceObject
725: )
726: /*++
727:
728: Routine Description:
729:
730: Create call (for FILE_WRITE_DATA access). Read access is granted
731: to anyone in SoundWaveDispatch. SoundWaveDispatch has also
732: verified whether the device can be opened by calling back to
733: the device-specific exlusion routine.
734:
735: Arguments:
736:
737: pLDI - our local device into
738:
739: Return Value:
740:
741: STATUS_SUCCESS if OK or
742: STATUS_BUSY if someone else has the device
743:
744:
745: --*/
746: {
747: NTSTATUS Status;
748: PWAVE_INFO WaveInfo;
749:
750: WaveInfo = (PWAVE_INFO)pLDI->DeviceSpecificData;
751:
752: ASSERTMSG("Invalid Wave Info Pointer",
753: WaveInfo != NULL && WaveInfo->Key == WAVE_INFO_KEY);
754:
755:
756: ASSERT(pLDI->State == 0 &&
757: IsListEmpty(&WaveInfo->BufferQueue.QueueHead));
758:
759: //
760: // Check the device thinks we're open
761: //
762:
763: ASSERT((*pLDI->DeviceInit->ExclusionRoutine)
764: (pLDI, SoundExcludeQueryOpen));
765:
766: //
767: // Initialize format changed flag
768: //
769:
770: WaveInfo->FormatChanged = TRUE;
771:
772: //
773: // Initialize state data and interrupt usage for
774: // the chosen device type. We set the rates etc to
775: // something anyone can handle. In reality a device is
776: // never used before the format is set but we must be
777: // unbreakable.
778: //
779:
780: switch (pLDI->DeviceType) {
781: case WAVE_IN:
782: pLDI->State = WAVE_DD_STOPPED;
783: WaveInfo->DeviceObject = DeviceObject;
784: WaveInfo->Direction = FALSE;
785:
786:
787: WaveInfo->SamplesPerSec = WAVE_DEFAULT_RATE;
788: WaveInfo->BitsPerSample = WAVE_DEFAULT_BITS_PER_SAMPLE;
789: WaveInfo->Channels = 1;
790:
791: ASSERT(WaveInfo->BufferQueue.BytesProcessed == 0);
792:
793: dprintf3(("Opened for wave input"));
794: Status = STATUS_SUCCESS;
795: break;
796:
797: case WAVE_OUT:
798: pLDI->State = WAVE_DD_PLAYING;
799: WaveInfo->DeviceObject = DeviceObject;
800: WaveInfo->Direction = TRUE;
801:
802: WaveInfo->SamplesPerSec = WAVE_DEFAULT_RATE;
803: WaveInfo->BitsPerSample = WAVE_DEFAULT_BITS_PER_SAMPLE;
804: WaveInfo->Channels = 1;
805:
806: ASSERT(WaveInfo->BufferQueue.BytesProcessed == 0);
807:
808: dprintf3(("Opened for wave output"));
809: Status = STATUS_SUCCESS;
810: break;
811:
812: default:
813: ASSERT(FALSE);
814: break;
815: }
816:
817: }
818:
819:
820:
821: NTSTATUS
822: SoundWaveCleanup(
823: IN OUT PLOCAL_DEVICE_INFO pLDI
824: )
825: /*++
826:
827: Routine Description:
828:
829: Clean up the requested device (this is effectively CLOSE)
830:
831: Arguments:
832:
833: pLDI - pointer to our local device info
834:
835: Return Value:
836:
837: STATUS_SUCCESS if OK otherwise
838: STATUS_INTERNAL_ERROR
839:
840: --*/
841: {
842: NTSTATUS Status = STATUS_SUCCESS;
843: PWAVE_INFO WaveInfo;
844:
845: WaveInfo = (PWAVE_INFO)pLDI->DeviceSpecificData;
846:
847: ASSERTMSG("Invalid Wave Info Pointer",
848: WaveInfo != NULL && WaveInfo->Key == WAVE_INFO_KEY);
849:
850: //
851: // Check this is valid call
852: //
853:
854: ASSERT((*pLDI->DeviceInit->ExclusionRoutine)(pLDI, SoundExcludeQueryOpen));
855:
856: //
857: // Call the device reset function to complete any
858: // pending i/o requests and terminate any current
859: // requests in progress
860: //
861:
862: switch (pLDI->DeviceType) {
863: case WAVE_IN:
864:
865: SoundStopWaveRecord(pLDI);
866:
867: //
868: // Reset position to start and free any pending Irps.
869: //
870:
871: SoundFreeQ(&WaveInfo->BufferQueue.QueueHead, STATUS_CANCELLED);
872: WaveInfo->BufferQueue.BytesProcessed = 0;
873:
874: SoundSynchTimer(WaveInfo);
875:
876: break;
877:
878: case WAVE_OUT:
879:
880: //
881: // If anything is in the queue then free it.
882: // beware that the final block of a request may still be
883: // being dma'd when we get this call. We now kill this as well
884: // because we've changed such that the if the application thinks
885: // all the requests are complete then they are complete.
886: //
887:
888: SoundStopDMA(WaveInfo, FALSE); // Stop with no pause
889:
890: SoundResetOutput(&WaveInfo->BufferQueue);
891:
892: SoundSynchTimer(WaveInfo);
893:
894: break;
895:
896: default:
897: dprintf1(("Bogus device type for cleanup request"));
898: Status = STATUS_INTERNAL_ERROR;
899: break;
900: }
901:
902: //
903: // return the device to it's idle state
904: //
905:
906: if (NT_SUCCESS(Status)) {
907: pLDI->State = 0;
908: (*pLDI->DeviceInit->ExclusionRoutine)(pLDI, SoundExcludeClose);
909: dprintf3(("Device closing"));
910: }
911:
912: return Status;
913: }
914:
915:
916: NTSTATUS
917: SoundIoctlGetWaveState(
918: IN OUT PLOCAL_DEVICE_INFO pLDI,
919: IN PIRP pIrp,
920: IN PIO_STACK_LOCATION IrpStack
921: )
922: /*++
923:
924: Routine Description:
925:
926: Get the current state of the device and return it to the caller.
927: This code is COMMON for :
928: Wave out
929: Wave in
930:
931: Arguments:
932:
933: pLDI - Pointer to our own device data
934: pIrp - Pointer to the IO Request Packet
935: IrpStack - Pointer to current stack location
936:
937: Return Value:
938:
939: Status to put into request packet by caller.
940:
941: --*/
942: {
943: PULONG pState;
944:
945: if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) {
946: dprintf1(("Supplied buffer to small for requested data"));
947: return STATUS_BUFFER_TOO_SMALL;
948: }
949:
950: //
951: // say how much we're sending back
952: //
953:
954: pIrp->IoStatus.Information = sizeof(ULONG);
955:
956: //
957: // cast the buffer address to the pointer type we want
958: //
959:
960: pState = (PULONG)pIrp->AssociatedIrp.SystemBuffer;
961:
962: //
963: // fill in the info -
964: //
965:
966:
967: //
968: // We don't bother to maintain the WAVE_DD_IDLE state internally
969: // for Wave output
970: //
971:
972: if (pLDI->State == WAVE_DD_PLAYING) {
973:
974: ASSERT(pLDI->DeviceType == WAVE_OUT);
975:
976: //
977: // We need to know if it's really playing
978: // and DMABusy can be cleared by the Dpc routine so we need the spin lock
979: //
980:
981: if (!((PWAVE_INFO)pLDI->DeviceSpecificData)->DMABusy) {
982: *pState = WAVE_DD_IDLE;
983: }
984:
985: } else {
986: *pState = pLDI->State;
987: }
988:
989:
990: return STATUS_SUCCESS;
991: }
992:
993:
994: NTSTATUS SoundIoctlQueryFormat(
995: IN PLOCAL_DEVICE_INFO pLDI,
996: IN OUT PIRP pIrp,
997: IN PIO_STACK_LOCATION IrpStack
998: )
999: /*++
1000:
1001: Routine Description:
1002:
1003: Tell the caller whether the wave format specified (input or
1004: output) is supported
1005:
1006: Arguments:
1007:
1008: pLDI - pointer to local device info
1009: pIrp - the Irp
1010: IrpStack - the current stack location
1011:
1012: Return Value:
1013:
1014: STATUS_SUCCESS - format is supported
1015: STATUS_NOT_SUPPORTED - format not supported
1016:
1017: --*/
1018: {
1019: PPCMWAVEFORMAT pFormat;
1020: NTSTATUS Status;
1021: PWAVE_INFO WaveInfo;
1022: WaveInfo = pLDI->DeviceSpecificData;
1023:
1024: ASSERT(WaveInfo->Key == WAVE_INFO_KEY);
1025:
1026: //
1027: // check the buffer really is big enough to contain the struct
1028: // we expect before digging into it. If not then assume it's a
1029: // format we don't know how to do.
1030: //
1031:
1032: if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
1033: sizeof(PCMWAVEFORMAT)) {
1034:
1035: dprintf1(("Format data wrong size"));
1036: return STATUS_NOT_SUPPORTED;
1037: }
1038:
1039:
1040: pFormat = (PPCMWAVEFORMAT)pIrp->AssociatedIrp.SystemBuffer;
1041:
1042: //
1043: // Check if the device can support this format
1044: //
1045:
1046: Status = (*WaveInfo->QueryFormat)(pLDI, pFormat);
1047:
1048: //
1049: // If we're setting the format then copy it to our global info
1050: //
1051:
1052: if (Status == STATUS_SUCCESS &&
1053: IrpStack->Parameters.DeviceIoControl.IoControlCode ==
1054: IOCTL_WAVE_SET_FORMAT) {
1055:
1056: WaveInfo->FormatChanged = TRUE;
1057: WaveInfo->SamplesPerSec = pFormat->wf.nSamplesPerSec;
1058: WaveInfo->BitsPerSample = pFormat->wBitsPerSample;
1059: WaveInfo->Channels = pFormat->wf.nChannels;
1060: }
1061:
1062: return Status;
1063: }
1064:
1065:
1066: NTSTATUS
1067: SoundWaveDispatch(
1068: IN OUT PLOCAL_DEVICE_INFO pLDI,
1069: IN PIRP pIrp,
1070: IN PIO_STACK_LOCATION IrpStack
1071: )
1072: /*++
1073:
1074: Routine Description:
1075:
1076: WAVE IOCTL call dispatcher. This is the entry point for all wave
1077: specific calls. See dispatch.c.
1078:
1079: This routine should be in the DispatchRoutine entry of the DeviceInit
1080: structure hanging off the local device info - see devices.h.
1081:
1082: Arguments:
1083:
1084: pLDI - Pointer to local device data
1085: pIrp - Pointer to IO request packet
1086: IrpStack - Pointer to current stack location
1087:
1088: Return Value:
1089:
1090: Return status from dispatched routine
1091:
1092: --*/
1093: {
1094: NTSTATUS Status;
1095:
1096: Status = STATUS_SUCCESS;
1097:
1098: if (((PWAVE_INFO)pLDI->DeviceSpecificData)->DeviceBad) {
1099: return STATUS_INVALID_DEVICE_REQUEST;
1100: }
1101:
1102: switch (IrpStack->MajorFunction) {
1103: case IRP_MJ_CREATE:
1104: Status = SoundSetShareAccess(pLDI, IrpStack);
1105: if (NT_SUCCESS(Status) && IrpStack->FileObject->WriteAccess) {
1106: SoundWaveCreate(pLDI, IrpStack->DeviceObject);
1107: }
1108: break;
1109:
1110: case IRP_MJ_CLOSE:
1111:
1112: Status = STATUS_SUCCESS;
1113:
1114: break;
1115:
1116: case IRP_MJ_READ:
1117: case IRP_MJ_WRITE:
1118:
1119: if (IrpStack->FileObject->WriteAccess) {
1120: Status = SoundWaveData(pLDI, pIrp, IrpStack);
1121: } else {
1122: Status = STATUS_ACCESS_DENIED;
1123: }
1124: break;
1125:
1126:
1127: case IRP_MJ_DEVICE_CONTROL:
1128:
1129: //
1130: // Check that if someone has the device open for 'write' it's
1131: // marked as in use
1132: //
1133:
1134: ASSERT(!IrpStack->FileObject->WriteAccess ||
1135: (*pLDI->DeviceInit->ExclusionRoutine)
1136: (pLDI, SoundExcludeQueryOpen));
1137: //
1138: // Check device access
1139: //
1140: if (!IrpStack->FileObject->WriteAccess) {
1141:
1142: switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
1143: case IOCTL_WAVE_GET_VOLUME:
1144: case IOCTL_WAVE_SET_VOLUME:
1145: case IOCTL_SOUND_GET_CHANGED_VOLUME:
1146:
1147: if (pLDI->PreventVolumeSetting) {
1148: Status = STATUS_ACCESS_DENIED;
1149: }
1150: break;
1151:
1152:
1153: case IOCTL_WAVE_GET_CAPABILITIES:
1154: case IOCTL_WAVE_QUERY_FORMAT:
1155: break;
1156:
1157: default:
1158: Status = STATUS_ACCESS_DENIED;
1159: break;
1160: }
1161: }
1162:
1163: if (NT_SUCCESS(Status)) {
1164: //
1165: // Dispatch the IOCTL function
1166: // Note that some IOCTLs only make sense for input or output
1167: // devices and not both.
1168: // Note that APIs which are possibly asynchronous do not
1169: // go through the Irp cleanup at the end here because they
1170: // may get completed before returning here or they are made
1171: // accessible to other requests by being queued.
1172: //
1173:
1174: switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
1175:
1176: case IOCTL_WAVE_SET_FORMAT:
1177: case IOCTL_WAVE_QUERY_FORMAT:
1178: Status = SoundIoctlQueryFormat(pLDI, pIrp, IrpStack);
1179: break;
1180:
1181: case IOCTL_WAVE_GET_CAPABILITIES:
1182: Status = (*pLDI->DeviceInit->DevCapsRoutine)(pLDI, pIrp, IrpStack);
1183: break;
1184:
1185: case IOCTL_WAVE_SET_STATE:
1186: if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) {
1187: dprintf1(("Supplied buffer too small for expected data"));
1188: Status = STATUS_BUFFER_TOO_SMALL;
1189: } else {
1190: PULONG pState;
1191:
1192: //
1193: // cast the buffer address to the pointer type we want
1194: //
1195:
1196: pState = (PULONG)pIrp->AssociatedIrp.SystemBuffer;
1197:
1198: switch (pLDI->DeviceType) {
1199: case WAVE_IN:
1200: Status = SoundSetWaveInputState(pLDI, *pState);
1201: break;
1202:
1203: case WAVE_OUT:
1204: Status = SoundSetWaveOutputState(pLDI, *pState, pIrp);
1205: break;
1206: }
1207: }
1208: break;
1209:
1210: case IOCTL_WAVE_GET_STATE:
1211: Status = SoundIoctlGetWaveState(pLDI, pIrp, IrpStack);
1212: break;
1213:
1214: case IOCTL_WAVE_GET_POSITION:
1215: Status = SoundIoctlGetPosition(pLDI, pIrp, IrpStack);
1216: break;
1217:
1218: case IOCTL_WAVE_SET_VOLUME:
1219: Status = SoundIoctlSetVolume(pLDI, pIrp, IrpStack);
1220: break;
1221:
1222: case IOCTL_WAVE_GET_VOLUME:
1223: Status = SoundIoctlGetVolume(pLDI, pIrp, IrpStack);
1224: break;
1225:
1226: case IOCTL_SOUND_GET_CHANGED_VOLUME:
1227: Status = SoundIoctlGetChangedVolume(pLDI, pIrp, IrpStack);
1228: break;
1229:
1230: case IOCTL_WAVE_SET_PITCH:
1231: Status = STATUS_NOT_SUPPORTED;
1232: break;
1233:
1234: case IOCTL_WAVE_GET_PITCH:
1235: // Status = SoundIoctlGetPitch(pLDI, pIrp, IrpStack);
1236: Status = STATUS_NOT_SUPPORTED;
1237: break;
1238:
1239: case IOCTL_WAVE_SET_PLAYBACK_RATE:
1240: Status = STATUS_NOT_SUPPORTED;
1241: break;
1242:
1243: case IOCTL_WAVE_GET_PLAYBACK_RATE:
1244: // Status = SoundIoctlGetPlaybackRate(pLDI, pIrp, IrpStack);
1245: Status = STATUS_NOT_SUPPORTED;
1246: break;
1247:
1248: #if 0
1249: case IOCTL_WAVE_SET_DEBUG_LEVEL:
1250: Status = SoundIoctlSetDebugLevel(pLDI, pIrp, IrpStack);
1251: break;
1252: #endif
1253:
1254: default:
1255: dprintf2(("Unimplemented IOCTL (%08lXH) requested", IrpStack->Parameters.DeviceIoControl.IoControlCode));
1256: Status = STATUS_INVALID_DEVICE_REQUEST;
1257: break;
1258: }
1259: break;
1260: }
1261:
1262:
1263: case IRP_MJ_CLEANUP:
1264: if (IrpStack->FileObject->WriteAccess) {
1265: Status = SoundWaveCleanup(pLDI);
1266: pLDI->PreventVolumeSetting = FALSE;
1267: } else {
1268: Status = STATUS_SUCCESS;
1269: }
1270: break;
1271:
1272:
1273: default:
1274: dprintf2(("Unimplemented major function requested: %08lXH", IrpStack->MajorFunction));
1275: Status = STATUS_INVALID_DEVICE_REQUEST;
1276: break;
1277: }
1278:
1279: return Status;
1280: }
1281:
1282:
1283:
1284: NTSTATUS
1285: SoundSetWaveInputState(
1286: IN OUT PLOCAL_DEVICE_INFO pLDI,
1287: IN ULONG State
1288: )
1289: /*++
1290:
1291: Routine Description:
1292:
1293: Determine which sound recording function to call depending on the
1294: state to be set.
1295:
1296: Arguments:
1297:
1298: pLDI - Pointer to local device data
1299: State - the new state to set
1300:
1301: Return Value:
1302:
1303: Return status for caller
1304:
1305: --*/
1306: {
1307: NTSTATUS Status;
1308: PWAVE_INFO WaveInfo;
1309:
1310: WaveInfo = pLDI->DeviceSpecificData;
1311:
1312: switch (State) {
1313: case WAVE_DD_RECORD:
1314:
1315: SoundStartWaveRecord(pLDI);
1316: Status = STATUS_SUCCESS;
1317: dprintf3(("Input started"));
1318: break;
1319:
1320: case WAVE_DD_STOP:
1321:
1322: SoundStopWaveRecord(pLDI);
1323: Status = STATUS_SUCCESS;
1324: dprintf3(("Input stopped"));
1325: break;
1326:
1327: case WAVE_DD_RESET:
1328:
1329: SoundStopWaveRecord(pLDI);
1330:
1331: //
1332: // Reset position to start and free any pending Irps.
1333: //
1334:
1335: SoundFreeQ(&WaveInfo->BufferQueue.QueueHead, STATUS_CANCELLED);
1336: WaveInfo->BufferQueue.BytesProcessed = 0;
1337:
1338: Status = STATUS_SUCCESS;
1339: dprintf3(("Input reset"));
1340: break;
1341:
1342: default:
1343:
1344: dprintf1(("Bogus set output state request: %08lXH", State));
1345: Status = STATUS_INVALID_PARAMETER;
1346: break;
1347: }
1348:
1349: return Status;
1350: }
1351:
1352:
1353: VOID
1354: SoundResetOutput(
1355: IN OUT PSOUND_BUFFER_QUEUE BufferQueue
1356: )
1357: /*++
1358:
1359: Routine Description:
1360:
1361: Clear out all the wave output buffers supplied by the application,
1362: cancelling related IO request packets.
1363:
1364: Set the Position to 0.
1365:
1366: Arguments:
1367:
1368: WaveInfo - Pointer to structure controlling processing of Irps for
1369: this device
1370:
1371: Return Value:
1372:
1373: None
1374:
1375: --*/
1376: {
1377:
1378: SoundCompleteIoBuffer(BufferQueue);
1379:
1380: //
1381: // Free all our lists of Irps, in the correct order
1382: //
1383: SoundFreeQ(&BufferQueue->ProgressQueue, STATUS_CANCELLED);
1384: SoundFreeQ(&BufferQueue->QueueHead, STATUS_CANCELLED);
1385:
1386: //
1387: // Reset the output position count
1388: //
1389:
1390: BufferQueue->BytesProcessed = 0;
1391: }
1392:
1393:
1394: NTSTATUS
1395: SoundSetWaveOutputState(
1396: PLOCAL_DEVICE_INFO pLDI,
1397: ULONG State,
1398: PIRP pIrp
1399: )
1400: /*++
1401:
1402: Routine Description:
1403:
1404: Set the new sound state. This is the most complicated part of the
1405: wave stuff because pauses cannot be completed immediately if there
1406: is stuff being DMAd.
1407:
1408: If reset is requested then additionally all the data supplied by
1409: the application is deleted (the Irps are signalled as cancelled)
1410: and the Position is set to 0. In this case the WAVE_DD_STOPPED
1411: state is set until the reset is complete.
1412:
1413:
1414: Arguments:
1415:
1416: pLDI - local device info
1417: State - the new state
1418:
1419:
1420: Return Value:
1421:
1422:
1423: --*/
1424: {
1425: NTSTATUS Status = STATUS_INTERNAL_ERROR;
1426: PWAVE_INFO WaveInfo;
1427:
1428: WaveInfo = pLDI->DeviceSpecificData;
1429:
1430: switch (State) {
1431:
1432: case WAVE_DD_RESET:
1433: case WAVE_DD_STOP:
1434:
1435: SoundStopDMA(WaveInfo, (BOOLEAN)(State == WAVE_DD_STOP));
1436:
1437: if (State == WAVE_DD_RESET) {
1438: SoundResetOutput(&WaveInfo->BufferQueue);
1439: pLDI->State = WAVE_DD_PLAYING;
1440: } else {
1441: //
1442: // Set STOPPED state for now anyway so we don't try to put
1443: // anything more in the buffer
1444: //
1445:
1446: pLDI->State = WAVE_DD_STOPPED;
1447:
1448: }
1449:
1450: Status = STATUS_SUCCESS;
1451:
1452:
1453:
1454: dprintf3(("Output stopped"));
1455: break;
1456:
1457:
1458: case WAVE_DD_PLAY:
1459: //
1460: // Restart playing. If we're already playing no need to
1461: // restart, otherwise it's safe to restart.
1462: //
1463:
1464: pLDI->State = WAVE_DD_PLAYING;
1465: SoundStartWaveDevice(pLDI, NULL);
1466:
1467: Status = STATUS_SUCCESS;
1468: dprintf3(("Output restarted"));
1469: break;
1470:
1471: default:
1472:
1473: dprintf1(("Bogus set output state request: %08lXH", State));
1474: Status = STATUS_INVALID_PARAMETER;
1475: break;
1476: }
1477:
1478: return Status;
1479: }
1480:
1481:
1482:
1483: VOID
1484: SoundStartWaveRecord(
1485: IN OUT PLOCAL_DEVICE_INFO pLDI
1486: )
1487: /*++
1488:
1489: Routine Description:
1490:
1491: Process the WAVE_DD_RECORD state change
1492:
1493: If recording has already started just return
1494: Otherwise start our DMA.
1495:
1496: Arguments:
1497:
1498: pLDI - our local device info
1499:
1500: Return Value:
1501:
1502: None
1503:
1504: --*/
1505: {
1506: PWAVE_INFO WaveInfo;
1507:
1508: WaveInfo = pLDI->DeviceSpecificData;
1509:
1510: ASSERTMSG("Recording on output device !", !WaveInfo->Direction);
1511:
1512: if (pLDI->State == WAVE_DD_RECORDING) {
1513: ASSERT(WaveInfo->DMABusy);
1514: return;
1515: }
1516:
1517: //
1518: // Set state
1519: //
1520:
1521: pLDI->State = WAVE_DD_RECORDING;
1522:
1523: //
1524: // Start the input
1525: //
1526:
1527: SoundStartWaveDevice(pLDI, NULL);
1528:
1529:
1530: //
1531: // Function is complete
1532: //
1533:
1534: }
1535:
1536:
1537: VOID
1538: SoundStopWaveRecord(
1539: IN OUT PLOCAL_DEVICE_INFO pLDI
1540: )
1541: /*++
1542:
1543: Routine Description:
1544:
1545: Stop wave recording.
1546:
1547: If recording is not in progress just return sucess.
1548: Otherwise stop the DMA and return the data we have so far
1549: recorded in the DMA buffer.
1550:
1551: Arguments:
1552:
1553: pLDI - pointer to our local device data
1554:
1555: Return Value:
1556:
1557: None
1558:
1559: --*/
1560: {
1561: PWAVE_INFO WaveInfo;
1562:
1563: WaveInfo = pLDI->DeviceSpecificData;
1564:
1565: ASSERTMSG("Recording on output device !", !WaveInfo->Direction);
1566:
1567: if (WaveInfo->DMABusy) {
1568:
1569: ASSERT(pLDI->State == WAVE_DD_RECORDING);
1570:
1571: //
1572: // Stop any more input
1573: //
1574:
1575: SoundStopDMA(WaveInfo, FALSE);
1576:
1577: //
1578: // Pass back any data to the application. SoundFillInputBuffers
1579: // returns TRUE if it completes any buffers
1580: //
1581:
1582: if (!SoundFillInputBuffers(WaveInfo)) {
1583: SoundGetNextBuffer(&WaveInfo->BufferQueue);
1584:
1585: //
1586: // Send back the first buffer if there is one
1587: //
1588:
1589: if (WaveInfo->BufferQueue.UserBuffer) {
1590: WaveInfo->BufferQueue.pIrp->IoStatus.Status = STATUS_SUCCESS;
1591:
1592: SoundCompleteIoBuffer(&WaveInfo->BufferQueue);
1593:
1594: IoCompleteRequest(WaveInfo->BufferQueue.pIrp, IO_SOUND_INCREMENT);
1595: }
1596: }
1597:
1598: //
1599: // Set state and make sure buffers are clear
1600: //
1601:
1602: pLDI->State = WAVE_DD_STOPPED;
1603: }
1604: }
1605:
1606:
1607: ULONG
1608: SoundGetHalfBufferPosition(
1609: IN PWAVE_INFO WaveInfo
1610: )
1611: /*++
1612:
1613: Routine Description
1614: Find position in current half buffer by reading the Dma counter
1615: Returns 0 if Dma is not running.
1616:
1617: Requires caller to hold spin lock.
1618:
1619: --*/
1620: {
1621: ULONG DmaPosition;
1622: ULONG BytesPerSample;
1623:
1624:
1625: //
1626: // Find out where we are in the DMA buffer
1627: //
1628:
1629: DmaPosition = WaveInfo->DoubleBuffer.BufferSize -
1630: HalReadDmaCounter(WaveInfo->DMABuf.AdapterObject[0]);
1631:
1632: //
1633: // Make sure we don't get in the middle of a sample
1634: //
1635: BytesPerSample = (WaveInfo->BitsPerSample * WaveInfo->Channels) >> 3;
1636: DmaPosition = (DmaPosition / BytesPerSample) * BytesPerSample;
1637:
1638: //
1639: // NextHalf is the half we think is being played or recorded into
1640: // We want the position relative to the beginning of that half so
1641: // if we're playing the upper half we subtract (= add in this
1642: // case) the size of the lower half modulo the buffer size
1643: //
1644:
1645: if (WaveInfo->DoubleBuffer.NextHalf == UpperHalf) {
1646: if (DmaPosition < WaveInfo->DoubleBuffer.Buffer[LowerHalf].Size) {
1647: DmaPosition = 0;
1648: } else {
1649: DmaPosition -= WaveInfo->DoubleBuffer.Buffer[LowerHalf].Size;
1650: }
1651: }
1652: //
1653: // Round down to the current half buffer because if we're overrun
1654: // we're not playing data the user gave us at all.
1655: // In the case of input the number of bytes in the buffer is always
1656: // set to the buffer size. In the output case the number of bytes
1657: // is the number of bytes actually copied to the buffer.
1658: //
1659:
1660: DmaPosition =
1661: min(DmaPosition,
1662: WaveInfo->DoubleBuffer.Buffer
1663: [WaveInfo->DoubleBuffer.NextHalf].nBytes);
1664:
1665: return DmaPosition;
1666: }
1667:
1668:
1669:
1670: NTSTATUS
1671: SoundIoctlGetPosition(
1672: IN PLOCAL_DEVICE_INFO pLDI,
1673: IN PIRP pIrp,
1674: IN PIO_STACK_LOCATION IrpStack
1675: )
1676: /*++
1677:
1678: Routine Description:
1679:
1680: IOCTL get wave position. Read the current position of wave output.
1681:
1682:
1683: Arguments:
1684:
1685: pLDI - Local device data
1686: pIrp - IO request packet
1687: IrpStack - current Irp stack location
1688:
1689: Return Value:
1690:
1691: Irp status
1692:
1693: --*/
1694: {
1695: PWAVE_DD_POSITION pPosition;
1696: NTSTATUS status;
1697: PWAVE_INFO WaveInfo;
1698:
1699: status = STATUS_SUCCESS;
1700: WaveInfo = pLDI->DeviceSpecificData;
1701:
1702: if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
1703: sizeof(WAVE_DD_POSITION)) {
1704: dprintf1(("Supplied buffer to small for requested data"));
1705: return STATUS_BUFFER_TOO_SMALL;
1706: }
1707:
1708: //
1709: // say how much we're sending back
1710: //
1711:
1712: pIrp->IoStatus.Information = sizeof(WAVE_DD_POSITION);
1713:
1714: //
1715: // cast the buffer address to the pointer type we want
1716: //
1717:
1718: pPosition = (PWAVE_DD_POSITION)pIrp->AssociatedIrp.SystemBuffer;
1719:
1720:
1721: //
1722: // If DMA is still running we need to check how far it has
1723: // progressed
1724: //
1725:
1726: DMAEnter(WaveInfo);
1727:
1728: pPosition->ByteCount = WaveInfo->BufferQueue.BytesProcessed;
1729:
1730: //
1731: // Don't adjust answer for wave record becase we haven't
1732: // yet copied the data to the application's buffers. Sound
1733: // recorder in particular would get confused by this and mess
1734: // up its display.
1735: //
1736:
1737: if (WaveInfo->DMABusy && WaveInfo->Direction) {
1738: pPosition->ByteCount += SoundGetHalfBufferPosition(WaveInfo);
1739: }
1740:
1741: DMALeave(WaveInfo);
1742:
1743: //
1744: // Convert to samples
1745: //
1746:
1747: pPosition->SampleCount =
1748: (pPosition->ByteCount << 3) /
1749: (WaveInfo->BitsPerSample * WaveInfo->Channels);
1750:
1751: return status;
1752: }
1753:
1754:
1755: /**************************************************************************
1756: *
1757: * Starting and stopping DMA
1758: *
1759: **************************************************************************/
1760:
1761: BOOLEAN
1762: SoundMapDMA(
1763: IN PWAVE_INFO WaveInfo
1764: )
1765: /*++
1766:
1767: Routine Description:
1768:
1769: Call IoMapTransfer to start the DMA
1770:
1771: Arguments:
1772:
1773: WaveInfo - Wave parameters and state
1774:
1775: Return Value:
1776:
1777: None
1778:
1779: --*/
1780: {
1781: ULONG length;
1782:
1783: #if DBG
1784: ULONG LengthRequested;
1785: #endif // DBG
1786:
1787: ULONG offset;
1788: int Half;
1789:
1790: Half = 0;
1791:
1792: if (WaveInfo->DMAType == SoundAutoInitDMA) {
1793: length = WaveInfo->DoubleBuffer.BufferSize;
1794: offset = 0;
1795: } else {
1796: length = WaveInfo->DoubleBuffer.BufferSize / 2;
1797: offset = WaveInfo->DoubleBuffer.NextHalf == LowerHalf ? 0 : length;
1798: if (WaveInfo->DMAType == Sound2ChannelDMA) {
1799: Half = WaveInfo->DoubleBuffer.NextHalf;
1800: }
1801: }
1802:
1803: #if DBG
1804: LengthRequested = length;
1805: #endif // DBG
1806:
1807: dprintf4(("Calling IoMapTransfer"));
1808: IoMapTransfer(WaveInfo->DMABuf.AdapterObject[Half],
1809: WaveInfo->DMABuf.Mdl,
1810: WaveInfo->MRB[Half],
1811: (PUCHAR)MmGetMdlVirtualAddress(WaveInfo->DMABuf.Mdl) +
1812: offset,
1813: &length,
1814: WaveInfo->Direction);
1815: // Direction
1816:
1817: ASSERTMSG("Incorrect length mapped by IoMapTransfer",
1818: length == LengthRequested);
1819: //
1820: // Now program the card to begin the transfer.
1821: // Note that this must be synchronized with the isr so
1822: // that we don't start taking interrupts prematurely
1823: //
1824:
1825: dprintf4(("Calling (sync) HwSetupDMA"));
1826:
1827: //
1828: // Prepare the hardware for running DMA
1829: //
1830:
1831: (*WaveInfo->HwSetupDMA)(WaveInfo);
1832:
1833: return TRUE;
1834: }
1835:
1836:
1837: BOOLEAN
1838: SoundFlushDMA(
1839: IN PWAVE_INFO WaveInfo
1840: )
1841: /*++
1842:
1843: Routine Description:
1844:
1845: Call IoMapTransfer to start the DMA
1846:
1847: Arguments:
1848:
1849: WaveInfo - Wave parameters and state
1850:
1851: Return Value:
1852:
1853: None
1854:
1855: --*/
1856: {
1857: ULONG length;
1858: ULONG offset;
1859: int Half;
1860:
1861: Half = 0;
1862:
1863: if (WaveInfo->DMAType == SoundAutoInitDMA) {
1864: length = WaveInfo->DoubleBuffer.BufferSize;
1865: offset = 0;
1866: } else {
1867: length = WaveInfo->DoubleBuffer.BufferSize / 2;
1868: offset = WaveInfo->DoubleBuffer.NextHalf == LowerHalf ? 0 : length;
1869: if (WaveInfo->DMAType == Sound2ChannelDMA) {
1870: Half = WaveInfo->DoubleBuffer.NextHalf;
1871: }
1872: }
1873:
1874: //
1875: // IoFlushAdapterBuffers masks off the DMA amongst other things
1876: //
1877:
1878: IoFlushAdapterBuffers(WaveInfo->DMABuf.AdapterObject[Half],
1879: WaveInfo->DMABuf.Mdl,
1880: WaveInfo->MRB[Half],
1881: (PUCHAR)MmGetMdlVirtualAddress(WaveInfo->DMABuf.Mdl) +
1882: offset,
1883: length,
1884: WaveInfo->Direction);
1885: // Direction
1886: return TRUE;
1887: }
1888:
1889: VOID
1890: SoundTestDeviceDeferred(
1891: IN PKDPC Dpc,
1892: IN PVOID Context,
1893: IN PVOID Param1,
1894: IN PVOID Param2
1895: )
1896: /*++
1897:
1898: Routine Description:
1899:
1900: Tests if our kernel device is still active
1901:
1902: Arguments:
1903:
1904: Dpc - Our DPC object
1905: Context - our wave info structure
1906: Param1 - not used - system time
1907: Param2 - not used - system time
1908:
1909: Return Value:
1910:
1911: None
1912:
1913: --*/
1914: {
1915: PWAVE_INFO WaveInfo;
1916: KIRQL OldIrql;
1917:
1918:
1919: WaveInfo = (PWAVE_INFO)Context;
1920:
1921: DMAEnter(WaveInfo);
1922:
1923: if (WaveInfo->DMABusy) {
1924:
1925: if (!WaveInfo->GotWaveDpc) {
1926:
1927: //
1928: // We're broken
1929: //
1930:
1931: dprintf2(("No interrupt from Wave device for 3 seconds! - cancelling IO"));
1932: dprintf2(("Device was wave %s", WaveInfo->Direction ? "output" : "input"));
1933:
1934: if (WaveInfo->FailureCount++ == 30 ) {
1935: dprintf1(("Device has failed 30 times in a row - mark it as bad"));
1936: WaveInfo->DeviceBad = TRUE;
1937: }
1938:
1939: //
1940: // But we might be able to start up again! so clean up our
1941: // state
1942: //
1943:
1944: WaveInfo->TimerActive = FALSE;
1945: WaveInfo->DMABusy = FALSE;
1946:
1947: SoundTerminateDMA(WaveInfo, FALSE);
1948:
1949: //
1950: // Free any outstanding IO - all future requests will be
1951: // denied
1952: //
1953:
1954: if (WaveInfo->Direction) {
1955: SoundResetOutput(&WaveInfo->BufferQueue);
1956: } else {
1957:
1958: //
1959: // We ensure in SoundFillInputBuffers that there are no
1960: // part-filled buffers for input
1961: //
1962:
1963: SoundFreeQ(&WaveInfo->BufferQueue.QueueHead, STATUS_CANCELLED);
1964:
1965: ((PLOCAL_DEVICE_INFO)
1966: WaveInfo->DeviceObject->DeviceExtension)->State = WAVE_DD_STOPPED;
1967: }
1968:
1969:
1970: } else {
1971: //
1972: // Start our timer off again
1973: //
1974:
1975: WaveInfo->GotWaveDpc = FALSE;
1976:
1977: KeInitializeDpc(&WaveInfo->TimerDpc,
1978: SoundTestDeviceDeferred,
1979: (PVOID)WaveInfo);
1980:
1981: //
1982: // Wait for 3 seconds (in 100 ns units)
1983: //
1984:
1985: KeSetTimer(&WaveInfo->DeviceCheckTimer,
1986: RtlConvertLongToLargeInteger(-30000000),
1987: &WaveInfo->TimerDpc);
1988: }
1989: } else {
1990:
1991: //
1992: // Timers dropped off end
1993: //
1994:
1995: WaveInfo->TimerActive = FALSE;
1996: }
1997:
1998: KeSetEvent(&WaveInfo->TimerDpcEvent, 0, FALSE);
1999:
2000: DMALeave(WaveInfo);
2001: }
2002:
2003:
2004: VOID
2005: SoundSynchTimer(
2006: IN PWAVE_INFO WaveInfo
2007: )
2008: /*++
2009:
2010: Routine Description:
2011:
2012: Kill any timer running 'device alive' timer
2013:
2014: Arguments:
2015:
2016: WaveInfo - Wave parameters and state
2017:
2018: Return Value:
2019:
2020: None
2021:
2022: --*/
2023: {
2024:
2025: BOOLEAN Wait;
2026:
2027: Wait = FALSE;
2028:
2029: DMAEnter(WaveInfo);
2030:
2031: //
2032: // 2 cases
2033: //
2034: // 1. TimerActive = FALSE - no timer is set, no Dpc routine is
2035: // queued or about to be queued
2036: //
2037: // 2. TimerActive = TRUE ...
2038: //
2039: // NB TimerActive is synchronized via this spin lock
2040: //
2041:
2042: if (WaveInfo->TimerActive) {
2043:
2044: //
2045: // 2 cases :
2046: //
2047: // 1. Timer set - in this case killing the timer does it
2048: //
2049: // 2. Timer not set - dpc on queue or running but not
2050: // yet entered device spin lock. Just reset the event
2051: // so we can wait for it.
2052: //
2053:
2054: if (!KeCancelTimer(&WaveInfo->DeviceCheckTimer)) {
2055:
2056: Wait = TRUE;
2057: KeResetEvent(&WaveInfo->TimerDpcEvent);
2058: }
2059:
2060: WaveInfo->TimerActive = FALSE;
2061: }
2062:
2063: DMALeave(WaveInfo);
2064:
2065: if (Wait) {
2066: KeWaitForSingleObject(&WaveInfo->TimerDpcEvent,
2067: Executive,
2068: KernelMode,
2069: FALSE,
2070: NULL);
2071: }
2072:
2073: ASSERTMSG("Timer synch failed", WaveInfo->TimerActive == FALSE);
2074: }
2075:
2076:
2077:
2078: VOID
2079: SoundStartDMA(
2080: IN PWAVE_INFO WaveInfo
2081: )
2082: /*++
2083:
2084: Routine Description:
2085:
2086: Set up the DMA by calling IoAllocateAdapterChannel
2087:
2088: Arguments:
2089:
2090: WaveInfo - Wave parameters and state
2091:
2092: Return Value:
2093:
2094: None
2095:
2096: --*/
2097: {
2098: KIRQL OldIrql;
2099:
2100: //
2101: // Check that DMA is not already running
2102: //
2103:
2104: //
2105: // Set DMABusy early so that the Hardware routines etc know we're
2106: // getting things going
2107: //
2108:
2109: WaveInfo->DMABusy = TRUE;
2110:
2111:
2112: //
2113: // The following is not necessary because we allocated non-cached
2114: // memory for our common buffer
2115: //
2116: // KeFlushIoBuffers(pGDI->pDMABufferMDL,
2117: // pGDI->Usage == SBInterruptUsageWaveIn,
2118: // TRUE);
2119:
2120: //
2121: // Be prepared to wait
2122: //
2123:
2124: KeInitializeEvent(&WaveInfo->DmaSetupEvent,
2125: SynchronizationEvent,
2126: FALSE);
2127:
2128:
2129: //
2130: // Allocate an adapter channel. When the system allocates
2131: // the channel, processing will continue in the SoundProgramDMA
2132: // routine below.
2133: //
2134:
2135: dprintf3(("Allocating adapter channel"));
2136:
2137: OldIrql = KeGetCurrentIrql();
2138: if (OldIrql != DISPATCH_LEVEL) {
2139: KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2140: }
2141: IoAllocateAdapterChannel(WaveInfo->DMABuf.AdapterObject[0],
2142: WaveInfo->DeviceObject,
2143: BYTES_TO_PAGES(WaveInfo->DMABuf.BufferSize),
2144: SoundProgramDMA,
2145: (PVOID)WaveInfo);
2146: if (OldIrql != DISPATCH_LEVEL) {
2147: KeLowerIrql(OldIrql);
2148: }
2149:
2150: //
2151: // Execution will continue in SoundProgramDMA when the
2152: // adapter has been allocated
2153: //
2154:
2155: //
2156: // Wait for it to complete
2157: //
2158:
2159: KeWaitForSingleObject(&WaveInfo->DmaSetupEvent,
2160: Executive,
2161: KernelMode,
2162: FALSE,
2163: NULL);
2164: //
2165: // Set up our timer to check the device is alive occasionally
2166: // (if we're not just restarting DMA)
2167:
2168: if (OldIrql != DISPATCH_LEVEL) {
2169:
2170: KeInitializeEvent(&WaveInfo->TimerDpcEvent,
2171: SynchronizationEvent,
2172: FALSE);
2173:
2174: WaveInfo->TimerActive = TRUE;
2175: WaveInfo->GotWaveDpc = TRUE; // Get through first time OK
2176: SoundTestDeviceDeferred(NULL, (PVOID)WaveInfo, NULL, NULL);
2177:
2178: }
2179:
2180: //
2181: // Program the DMA controller registers for the transfer
2182: // Set the direction of transfer by whether we're wave in or
2183: // wave out.
2184: //
2185:
2186: SoundMapDMA(WaveInfo);
2187:
2188: }
2189:
2190:
2191:
2192: IO_ALLOCATION_ACTION
2193: SoundProgramDMA(
2194: IN PDEVICE_OBJECT pDO,
2195: IN PIRP pIrp,
2196: IN PVOID pMRB,
2197: IN PVOID Context
2198: )
2199: /*++
2200:
2201: Routine Description:
2202:
2203: This routine is executed when an adapter channel is allocated
2204: for our DMA needs. It saves away the MRB (mapping register
2205: base which has been extracted from the adapter object) and
2206: sets the event which SoundStartDMA is waiting on.
2207:
2208: Arguments:
2209:
2210: pDO - Device object
2211: pIrp - IO request packet
2212: pMRB - Map register base of registers allocated by adapter
2213: Context - Pointer to our device global data
2214:
2215:
2216: Return Value:
2217:
2218: Tell the system what to do with the adapter object
2219:
2220: --*/
2221: {
2222: PWAVE_INFO WaveInfo;
2223:
2224: WaveInfo = (PWAVE_INFO) Context;
2225:
2226: ASSERT(WaveInfo->Key == WAVE_INFO_KEY);
2227:
2228: WaveInfo->MRB[0] = pMRB;// Remember our map register base
2229:
2230:
2231: //
2232: // Tell the caller it's time to go!
2233: //
2234:
2235: KeSetEvent(&WaveInfo->DmaSetupEvent, 0, FALSE);
2236:
2237: //
2238: // return a value that says we want to keep the channel
2239: // and map registers.
2240: //
2241:
2242: return KeepObject;
2243: }
2244:
2245:
2246: VOID
2247: SoundAppendList(
2248: PLIST_ENTRY QueueHead,
2249: PLIST_ENTRY ListToAppend
2250: )
2251: /*++
2252:
2253: Routine Description:
2254:
2255: Append a list of Irps to the head of a cancellable list
2256: The list itself is emptied.
2257:
2258: NOTE: Irps involved in these operations could be cancelled and
2259: and freed from the cancellable list while this is going on.
2260: This is OK.
2261:
2262: Arguments:
2263:
2264: QueueHead - The cancellable queue to be appended to
2265: ListToAppend - The list to be appended
2266:
2267: Return Value:
2268:
2269: Note
2270:
2271: --*/
2272: {
2273: while (!IsListEmpty(ListToAppend)) {
2274: PLIST_ENTRY ListEntry;
2275: PIRP Irp;
2276:
2277: //
2278: // Remove Irp from tail of queue and put it at
2279: // head of input queue, making it cancellable
2280: // at the same time
2281: //
2282:
2283: ListEntry = RemoveTailList(ListToAppend);
2284:
2285:
2286: Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry);
2287:
2288: SoundAddIrpToCancellableQ(QueueHead,
2289: Irp,
2290: TRUE);
2291: }
2292: }
2293:
2294:
2295: VOID
2296: SoundFreeWaveOutputBuffers(
2297: PLIST_ENTRY Queue,
2298: ULONG BytesProcessed
2299: )
2300: /*++
2301:
2302: Routine Description:
2303:
2304: This routine frees entries from the queue until all the bytes are
2305: used. If the last entry is not entirely used up then its
2306: IoStatus.Information is bumped by the residual bytes.
2307:
2308:
2309: Arguments:
2310:
2311:
2312: Return Value:
2313:
2314:
2315: --*/
2316: {
2317: while (BytesProcessed != 0) {
2318: PIRP Irp;
2319: ULONG BytesInEntry;
2320:
2321: //
2322: // We should NEVER exhaust the queue
2323: //
2324:
2325: ASSERT(!IsListEmpty(Queue));
2326:
2327: Irp = CONTAINING_RECORD(Queue->Flink, IRP, Tail.Overlay.ListEntry);
2328:
2329: //
2330: // The Information field in the Irp records where we have completed
2331: // to up until now
2332: //
2333:
2334: BytesInEntry =
2335: IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length -
2336: Irp->IoStatus.Information;
2337:
2338: if (BytesInEntry > BytesProcessed) {
2339: Irp->IoStatus.Information += BytesProcessed;
2340: BytesProcessed = 0;
2341: } else {
2342: //
2343: // Free this entry
2344: //
2345:
2346: RemoveHeadList(Queue);
2347:
2348: Irp->IoStatus.Information += BytesInEntry;
2349:
2350: ASSERT(Irp->IoStatus.Information ==
2351: IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length);
2352:
2353: Irp->IoStatus.Status = STATUS_SUCCESS;
2354:
2355: IoCompleteRequest(Irp, IO_SOUND_INCREMENT);
2356:
2357: BytesProcessed -= BytesInEntry;
2358: }
2359: }
2360: }
2361:
2362: VOID
2363: SoundTerminateDMA(
2364: IN PWAVE_INFO WaveInfo,
2365: IN BOOLEAN Pause
2366: )
2367: /*++
2368:
2369: Routine Description:
2370:
2371: Stop the DMA at once by passing HALT to the DSP.
2372: Free the adapter channel.
2373: (Opposite of SoundStartDMA).
2374:
2375: Arguments:
2376:
2377: WaveInfo - pointer to wave parameters and data
2378:
2379: Return Value:
2380:
2381: None
2382:
2383: --*/
2384: {
2385: ULONG HalfBufferPosition; // How far we're into current buffer
2386: KIRQL OldIrql;
2387: struct SOUND_DMABUF *DmaBuf;
2388:
2389: DmaBuf = &WaveInfo->DoubleBuffer.Buffer
2390: [WaveInfo->DoubleBuffer.NextHalf];
2391:
2392:
2393: //
2394: // Quiesce the hardware - do this before getting the buffer position
2395: // so we get an accurate reading.
2396: //
2397:
2398: (*WaveInfo->HwStopDMA)(WaveInfo);
2399:
2400: //
2401: // Adjust our position before we stop the DMA
2402: //
2403:
2404: HalfBufferPosition = SoundGetHalfBufferPosition(WaveInfo);
2405: ASSERT(HalfBufferPosition <= DmaBuf->Size);
2406:
2407: //
2408: // For input work out how many more bytes we have for the user.
2409: //
2410:
2411: if (!WaveInfo->Direction) {
2412: //
2413: // For input the 'nBytes' field means the number of bytes
2414: // already processed from the buffer - Size - nBytes is the
2415: // number of bytes still available
2416: //
2417:
2418: DmaBuf->nBytes = DmaBuf->Size - HalfBufferPosition;
2419:
2420: //
2421: // Move the bytes we have to where they will be found by
2422: // SoundFillInputBuffers which will update BytesProcessed if
2423: // there are buffers to fill.
2424: //
2425:
2426: RtlMoveMemory(DmaBuf->Buf + DmaBuf->nBytes, DmaBuf->Buf,
2427: HalfBufferPosition);
2428: } else {
2429:
2430:
2431: // We could simplify things here by using the hardware pause
2432: // in the device at the expense of introducing an extra state
2433: //
2434:
2435: if (Pause) {
2436: //
2437: // Complete any buffers which may now be complete
2438: //
2439:
2440: SoundFreeWaveOutputBuffers(&WaveInfo->BufferQueue.ProgressQueue,
2441: HalfBufferPosition);
2442:
2443: //
2444: // Update the position
2445: //
2446:
2447: WaveInfo->BufferQueue.BytesProcessed += HalfBufferPosition;
2448:
2449: //
2450: // Tidy up partially completed input buffer. We don't
2451: // need to remember where we are here because we know
2452: // at the other end where the DMA buffers start.
2453: //
2454:
2455: SoundCompleteIoBuffer(&WaveInfo->BufferQueue);
2456:
2457: //
2458: // Roll everything back into the input queue so we can
2459: // support cancel of a paused state properly.
2460: //
2461:
2462: SoundAppendList(&WaveInfo->BufferQueue.QueueHead,
2463: &WaveInfo->BufferQueue.ProgressQueue);
2464:
2465: }
2466:
2467: WaveInfo->DoubleBuffer.Buffer[LowerHalf].nBytes = 0;
2468: WaveInfo->DoubleBuffer.Buffer[UpperHalf].nBytes = 0;
2469:
2470: //
2471: // In either case we must be set up to restart DMA from the
2472: // start of the lower half of the buffer next time
2473: //
2474:
2475: WaveInfo->DoubleBuffer.NextHalf = LowerHalf;
2476:
2477: }
2478:
2479: SoundFlushDMA(WaveInfo);
2480:
2481: //
2482: // Free the adapter channel
2483: //
2484:
2485: {
2486: KIRQL OldIrql;
2487: OldIrql = KeGetCurrentIrql();
2488: if (OldIrql != DISPATCH_LEVEL) {
2489: KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2490: }
2491: IoFreeAdapterChannel(WaveInfo->DMABuf.AdapterObject[0]);
2492: if (OldIrql != DISPATCH_LEVEL) {
2493: KeLowerIrql(OldIrql);
2494: }
2495: }
2496: }
2497:
2498:
2499: VOID
2500: SoundStopDMA(
2501: IN PWAVE_INFO WaveInfo,
2502: IN BOOLEAN Pause
2503: )
2504: /*++
2505:
2506: Routine Description:
2507:
2508: Stop the DMA at once by passing HALT to the DSP.
2509: Free the adapter channel.
2510: (Opposite of SoundStartDMA).
2511:
2512: Arguments:
2513:
2514: WaveInfo - pointer to wave parameters and data
2515:
2516: Return Value:
2517:
2518: None
2519:
2520: --*/
2521: {
2522: BOOLEAN DMABusy;
2523:
2524: //
2525: // Acquire the spin lock so we can synchronize with the Dpc
2526: // routine and correctly test DMABusy etc
2527: //
2528:
2529: DMAEnter(WaveInfo);
2530:
2531: DMABusy = WaveInfo->DMABusy;
2532:
2533: if (DMABusy) {
2534:
2535: //
2536: // Note our new state. We do this inside the spin lock
2537: // so that if any Dpc routine runs now it knows that it
2538: // should act as a NOOP.
2539: //
2540: // The ISR will not do anything once DMABusy is turned off,
2541: // nor will the Dpc routine.
2542: //
2543:
2544: WaveInfo->DMABusy = FALSE;
2545: WaveInfo->Overrun = FALSE;
2546:
2547: //
2548: // At this stage we know :
2549: // 1. We won't get (or act on) any more interrupts
2550: // 2. Nobody can start any more DMA because we hold the
2551: // common wave input and output mutants
2552: // 3. If a Dpc routine runs it will NOOP because DMABusy is FALSE
2553: //
2554:
2555: }
2556:
2557: //
2558: // Have a stab at stopping our timer
2559: //
2560:
2561: if (KeCancelTimer(&WaveInfo->DeviceCheckTimer)) {
2562:
2563: //
2564: // Update the state - otherwise SoundSynchTimer will
2565: // hang waiting for non-existent timers
2566: //
2567:
2568: WaveInfo->TimerActive = FALSE;
2569: }
2570:
2571:
2572: DMALeave(WaveInfo);
2573:
2574:
2575: if (DMABusy) {
2576:
2577: SoundTerminateDMA(WaveInfo, Pause);
2578: }
2579:
2580: //
2581: // Make sure no more Dpc routines are about to run!
2582: //
2583:
2584: KeResetEvent(&WaveInfo->DpcEvent);
2585:
2586: //
2587: // The Dpc routine clears DpcQueued just before setting this event
2588: // so if it's set then the event will certainly be set.
2589: //
2590: // Note that there's no need to syncrhorinze with the ISR here
2591: // because we NOOPed interrupts when we cleared DMABusy above.
2592: //
2593:
2594: if (WaveInfo->DpcQueued) {
2595:
2596: dprintf2(("Waiting for Dpc routine to finish"));
2597: KeWaitForSingleObject(&WaveInfo->DpcEvent,
2598: Executive,
2599: KernelMode,
2600: FALSE, // Not alertable
2601: NULL);
2602: }
2603: }
2604:
2605:
2606: /***************************************************************************
2607: *
2608: * Dpc routine and support code
2609: *
2610: ***************************************************************************/
2611:
2612: VOID
2613: SoundOutDeferred(
2614: PWAVE_INFO WaveInfo
2615: )
2616: /*++
2617:
2618: Routine Description:
2619:
2620: Deferred procedure call routine for wave output interrupts.
2621:
2622: The basic job is just to move to the next buffer which consists of
2623:
2624: -- Completing Irps that made up the buffer just played (in ProgressQueue)
2625:
2626: -- Filling up the next buffer
2627:
2628: However, if the buffer which is about to play is empty we can deduce
2629: that there isn't anything to play - either output was stopped by a
2630: WAVE_DD_STOP or no buffers have arrived (otherwise data would
2631: have already been moved into the buffer which is about to play).
2632:
2633: In this case we
2634:
2635: -- Stop the DMA
2636:
2637: -- Complete any pause packet
2638:
2639: -- Set our new state (WAVE_DD_IDLE if not currently WAVE_DD_STOPPED).
2640:
2641: Arguments:
2642:
2643: WaveInfo - Data associated with wave input/output
2644:
2645: Return Value:
2646:
2647: TRUE if DMA is to be halted
2648:
2649: --*/
2650: {
2651: ULONG BytesProcessed;
2652:
2653: ASSERTMSG("SoundOutDeferred called when DMA not busy!",
2654: WaveInfo->DMABusy);
2655:
2656: //
2657: // Flush the DMA unless we're doing autoinit
2658: //
2659: if (WaveInfo->DMAType != SoundAutoInitDMA) {
2660: SoundFlushDMA(WaveInfo);
2661: }
2662:
2663: //
2664: // Get number of bytes just done (note the buffer may not have
2665: // been full) and empty the buffer.
2666: //
2667:
2668: BytesProcessed =
2669: WaveInfo->DoubleBuffer.Buffer[WaveInfo->DoubleBuffer.NextHalf].nBytes;
2670:
2671: WaveInfo->DoubleBuffer.Buffer[WaveInfo->DoubleBuffer.NextHalf].nBytes = 0;
2672:
2673: //
2674: // Kill everything on the dead queue
2675: // move the transit queue to the dead queue
2676: // and reinitialize the transit queue ready to receive
2677: // data from the queue of new buffers
2678: //
2679:
2680: SoundFreeWaveOutputBuffers(&WaveInfo->BufferQueue.ProgressQueue,
2681: BytesProcessed);
2682:
2683: //
2684: // The block we've just done is now empty, ready for reuse
2685: // Update the number of bytes processed, then free it
2686: //
2687:
2688: WaveInfo->BufferQueue.BytesProcessed += BytesProcessed;
2689:
2690: //
2691: // See if we were doing the last block.
2692: //
2693:
2694: if (WaveInfo->DoubleBuffer.Buffer[UpperHalf + LowerHalf -
2695: WaveInfo->DoubleBuffer.NextHalf].nBytes == 0) {
2696:
2697: dprintf4(("end_last"));
2698:
2699: //
2700: // It's possible that a request was queued during the last block
2701: // but that would have caused the LastBlock flag to have been
2702: // cleared if there were any data, unless we're STOPPED.
2703: // If a restart occurred after a stop the silence would
2704: // have been filled out.
2705: //
2706: //
2707: // However, with 0 length buffers possible the dead queue
2708: // can be non-empty even though the next buffer has nothing
2709: // to play in it.
2710: //
2711:
2712: //ASSERT(IsListEmpty(&WaveInfo->BufferQueue.QueueHead) ||
2713: // ((PLOCAL_DEVICE_INFO)WaveInfo->DeviceObject->
2714: // DeviceExtension)->State == WAVE_DD_STOPPED);
2715:
2716: if (!IsListEmpty(&WaveInfo->BufferQueue.ProgressQueue)) {
2717:
2718: //
2719: // Note that it should not be possible for there to be
2720: // a half complete buffer lying around. If we're paused
2721: // that buffer would have been moved back to the
2722: // input queue.
2723:
2724: ASSERTMSG("Unexpected incomplete buffer",
2725: WaveInfo->BufferQueue.UserBuffer == NULL);
2726:
2727: dprintf1(("Empty buffers being freed at end of playing"));
2728: SoundFreeQ(&WaveInfo->BufferQueue.ProgressQueue, STATUS_SUCCESS);
2729: }
2730:
2731: WaveInfo->DMABusy = FALSE;
2732:
2733: SoundTerminateDMA(WaveInfo, FALSE); // Stop DMA
2734:
2735:
2736: } else {
2737: WaveInfo->DoubleBuffer.NextHalf =
2738: LowerHalf + UpperHalf - WaveInfo->DoubleBuffer.NextHalf;
2739:
2740: //
2741: // If we're not doing auto-initialize re-start the DMA
2742: //
2743:
2744: if (WaveInfo->DMAType != SoundAutoInitDMA) {
2745: SoundMapDMA(WaveInfo);
2746: }
2747:
2748: //
2749: // That was the end of a normal block.
2750: // Try to load the next half of the dma buffer.
2751: // If this is the tail of the request, the load routine
2752: // will pad it out with silence so we get a full block.
2753: //
2754:
2755: if (((PLOCAL_DEVICE_INFO)WaveInfo->DeviceObject->
2756: DeviceExtension)->State != WAVE_DD_STOPPED) {
2757: SoundLoadDMABuffer(
2758: &WaveInfo->BufferQueue,
2759: &WaveInfo->DoubleBuffer.Buffer[
2760: UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf],
2761: WaveInfo->DoubleBuffer.Pad);
2762: }
2763: return;
2764: }
2765: }
2766:
2767:
2768: VOID
2769: SoundInDeferred(
2770: IN OUT PWAVE_INFO WaveInfo
2771: )
2772: /*++
2773:
2774: Routine Description:
2775:
2776: Dpc routine for wave input device
2777:
2778: Collect the data from the DMA buffer and pass it to the application's
2779: buffer(s).
2780:
2781: Arguments:
2782:
2783: WaveInfo - wave data structure
2784:
2785:
2786: Return Value:
2787:
2788: None.
2789:
2790: --*/
2791: {
2792: //
2793: // Fill in any buffers we can
2794: //
2795:
2796:
2797: dprintf4((WaveInfo->DoubleBuffer.NextHalf == LowerHalf ? "L" : "U"));
2798:
2799: //
2800: // Zero bytes taken out of new buffer
2801: //
2802:
2803: WaveInfo->DoubleBuffer.Buffer[WaveInfo->DoubleBuffer.NextHalf].nBytes = 0;
2804:
2805: //
2806: // Move on to next buffer
2807: //
2808:
2809: WaveInfo->DoubleBuffer.NextHalf =
2810: UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf;
2811:
2812: //
2813: // If we're not doing auto-initialize re-start the DMA
2814: //
2815:
2816: if (WaveInfo->DMAType != SoundAutoInitDMA) {
2817: SoundMapDMA(WaveInfo);
2818: }
2819:
2820: //
2821: // Request input without posting the last buffer
2822: //
2823:
2824: SoundFillInputBuffers(WaveInfo);
2825:
2826:
2827: return;
2828: }
2829:
2830:
2831: BOOLEAN
2832: SoundSignalDpcEnd(
2833: PVOID Context
2834: )
2835: {
2836: PWAVE_INFO WaveInfo;
2837:
2838: WaveInfo = (PWAVE_INFO)Context;
2839: WaveInfo->DpcQueued = FALSE;
2840:
2841: return TRUE;
2842: }
2843:
2844:
2845: BOOLEAN
2846: SoundAdjustHalf(
2847: PVOID Context
2848: )
2849: {
2850: PWAVE_INFO WaveInfo;
2851:
2852: WaveInfo = (PWAVE_INFO)Context;
2853:
2854: //
2855: // Caller MUST have spin lock
2856: //
2857:
2858: ASSERTMSG("Can't adjust half without spin lock", WaveInfo->LockHeld);
2859:
2860: if (FALSE /* WaveInfo->Overrun != 0 */) {
2861: //
2862: // Make sure we look at the half that the latest interrupt
2863: // processed
2864: //
2865: if (WaveInfo->Overrun & 1) {
2866: WaveInfo->DoubleBuffer.NextHalf =
2867: UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf;
2868: }
2869: //
2870: // If we're adrift then free the buffers
2871: //
2872: WaveInfo->DoubleBuffer.Buffer[LowerHalf].nBytes =
2873: WaveInfo->Direction ?
2874: 0 :
2875: WaveInfo->DoubleBuffer.Buffer[LowerHalf].Size;
2876: WaveInfo->DoubleBuffer.Buffer[UpperHalf].nBytes =
2877: WaveInfo->Direction ?
2878: 0 :
2879: WaveInfo->DoubleBuffer.Buffer[UpperHalf].Size;
2880: }
2881:
2882: return TRUE;
2883: }
2884:
2885:
2886: VOID
2887: SoundWaveDeferred(
2888: PKDPC pDpc,
2889: PDEVICE_OBJECT pDeviceObject,
2890: PIRP pIrp,
2891: PVOID Context
2892: )
2893: /*++
2894:
2895: Routine Description:
2896:
2897: Deferred procedure call routine for wave output interrupts.
2898:
2899: The job is to call the appropriate wave input or output
2900: Dpc routine under the spin lock if DMA is still busy.
2901:
2902: The Dpc complete event is then signalled in case we're waiting
2903: to synchronize on some thread.
2904:
2905: Arguments:
2906:
2907: pDPC - pointer to DPC object
2908: pDeviceObject - pointer to our device object
2909: pIrp - ???
2910: Context - our Dpc context (NULL in our case).
2911:
2912: Return Value:
2913:
2914: None
2915:
2916: --*/
2917: {
2918: PWAVE_INFO WaveInfo;
2919: PLOCAL_DEVICE_INFO pLDI;
2920: BOOLEAN StopDMA;
2921:
2922: pLDI = (PLOCAL_DEVICE_INFO)pDeviceObject->DeviceExtension;
2923: ASSERT(pLDI->Key == LDI_WAVE_IN_KEY ||
2924: pLDI->Key == LDI_WAVE_OUT_KEY);
2925:
2926: WaveInfo = (PWAVE_INFO)pLDI->DeviceSpecificData;
2927:
2928: ASSERTMSG("Invalid Wave Info structure in SoundAutoInitDeferred",
2929: WaveInfo->Key == WAVE_INFO_KEY);
2930:
2931: dprintf4(("("));
2932:
2933: //
2934: // Acquire the spin lock before we mess with the list
2935: //
2936:
2937: DMAEnter(WaveInfo);
2938:
2939: //
2940: // Keep the timer check stuff happy
2941: //
2942:
2943: WaveInfo->GotWaveDpc = TRUE;
2944: WaveInfo->FailureCount = 0;
2945:
2946: //
2947: // The Dpc routine only does something if Dma is active.
2948: // This means that if the device is paused, reset etc
2949: // this routine can be disabled by turning off DMABusy
2950: //
2951:
2952: if (WaveInfo->DMABusy) {
2953:
2954: //
2955: // Find out which half we're really in by counting overruns
2956: //
2957:
2958: KeSynchronizeExecution(
2959: WaveInfo->Interrupt,
2960: SoundAdjustHalf,
2961: (PVOID)WaveInfo);
2962:
2963: (WaveInfo->Direction ? SoundOutDeferred : SoundInDeferred)(WaveInfo);
2964: }
2965:
2966: //
2967: // Release the spin lock
2968: //
2969:
2970: DMALeave(WaveInfo);
2971:
2972: //
2973: // Tell the world we've finished.
2974: //
2975:
2976: KeSynchronizeExecution(
2977: WaveInfo->Interrupt,
2978: SoundSignalDpcEnd,
2979: (PVOID)WaveInfo);
2980:
2981: //
2982: // Tell SoundStopDMA that we're really finished
2983: // (Note this MUST be done after calling SoundSignalDpcEnd)
2984: //
2985:
2986: KeSetEvent(&WaveInfo->DpcEvent, 0, FALSE);
2987:
2988: dprintf4((")"));
2989:
2990: return;
2991: }
2992:
2993:
2994: /************************************************************************
2995: *
2996: * Routines to handle filling and emptying of the DMA buffer
2997: *
2998: ************************************************************************/
2999:
3000:
3001: VOID
3002: SoundLoadDMABuffer(
3003: PSOUND_BUFFER_QUEUE BufferQueue,
3004: struct SOUND_DMABUF *pDMA,
3005: UCHAR pad
3006: )
3007: /*++
3008:
3009: Routine Description:
3010:
3011: Fill the given DMA buffer with as much data as is available.
3012:
3013: This is where the supply of bytes is chopped if we're in a
3014: WAVE_DD_STOPPED state. The supply then dries up and the Dpc routine
3015: stops the DMA (and posts the pause packet).
3016:
3017:
3018: Arguments:
3019:
3020: BufferQueue - our stream of application buffers
3021: pDMA - The buffer and how full it is now
3022: pad - 0x80 for 8-bit sound, 0x00 for 16-bit sound
3023:
3024: Return Value:
3025:
3026:
3027: --*/
3028: {
3029: //
3030: // Loop copying data to the output buffers. Typically the
3031: // output buffer will be much bigger than the DMA buffer.
3032: //
3033:
3034: while (pDMA->nBytes < pDMA->Size) {
3035:
3036: ULONG BytesToCopy;
3037:
3038: //
3039: // We might have completed the last buffer
3040: // Note that we cope with 0 length buffers here
3041: //
3042:
3043: if (BufferQueue->UserBuffer == NULL) {
3044: SoundGetNextBuffer(BufferQueue);
3045: if (BufferQueue->UserBuffer == NULL) {
3046:
3047: //
3048: // There REALLY aren't any buffers
3049: //
3050:
3051: break;
3052: } else {
3053: InsertTailList(
3054: &BufferQueue->ProgressQueue,
3055: &BufferQueue->pIrp->Tail.Overlay.ListEntry);
3056: }
3057: }
3058:
3059: //
3060: // Find out how much space we have left in the
3061: // client's buffers
3062: //
3063: // Note that BytesToCopy may be 0 - this is OK
3064: //
3065:
3066: BytesToCopy =
3067: min(BufferQueue->UserBufferSize - BufferQueue->UserBufferPosition,
3068: pDMA->Size - (ULONG)pDMA->nBytes);
3069:
3070: //
3071: // Copy the data
3072: //
3073:
3074: RtlCopyMemory(pDMA->Buf + pDMA->nBytes,
3075: BufferQueue->UserBuffer + BufferQueue->UserBufferPosition,
3076: BytesToCopy);
3077:
3078: //
3079: // Update counters etc.
3080: //
3081:
3082: BufferQueue->UserBufferPosition += BytesToCopy;
3083: pDMA->nBytes += BytesToCopy;
3084:
3085: //
3086: // BufferQueue->BytesProcessed will be updated by the
3087: // Dpc routine
3088: //
3089:
3090: //
3091: // See if we've now filled a buffer
3092: //
3093:
3094: if (BufferQueue->UserBufferPosition == BufferQueue->UserBufferSize) {
3095:
3096: dprintf4((" finished"));
3097:
3098: //
3099: // Complete the buffer
3100: //
3101:
3102: SoundCompleteIoBuffer(BufferQueue);
3103: }
3104:
3105: } // Continue around the loop until the request is satisfied
3106:
3107: //
3108: // if we transferred something, pad out the request with
3109: // silence
3110: //
3111: // BUGBUG do the exponential decay thing here
3112:
3113: if (pDMA->nBytes < pDMA->Size) {
3114: dprintf4((" pad"));
3115: RtlFillMemory(pDMA->Buf + pDMA->nBytes,
3116: pDMA->Size - pDMA->nBytes,
3117: pad);
3118: }
3119:
3120: //
3121: // flush the i/o buffers
3122: //
3123: // BUGBUG is this right ? Actually I386 needs none of this
3124: // KeFlushIoBuffers(BufferQueue->pDMABufferMDL, FALSE); // flush for write
3125:
3126: }
3127:
3128:
3129:
3130: BOOLEAN
3131: SoundFillOutputBuffers(
3132: PWAVE_INFO WaveInfo
3133: )
3134: /*++
3135:
3136: Routine Description:
3137:
3138: This routine is called whenever an event occurs which could
3139: output more wave data :
3140:
3141: A new buffer is supplied
3142: The state is changed from stopped to idle
3143:
3144: If wave data is already playing it may still be possible to move
3145: some data into the half buffer which is not playing.
3146:
3147: If no data is playing then both dma half buffers are primed if
3148: possible. If no data exists to be played this function is
3149: a NOOP except that some 0 length buffers may be completed.
3150:
3151:
3152: Arguments:
3153:
3154:
3155: Return Value:
3156:
3157:
3158: --*/
3159:
3160: {
3161: //
3162: // Try to fill up both buffers
3163: //
3164:
3165:
3166: //
3167: // If DMA is running we may be able to pad out some silence to
3168: // stop DMA from dying later. If not just initiate everything.
3169: //
3170:
3171: //
3172: // Check we have a consistent state
3173: //
3174:
3175: #if 0
3176: if (!WaveInfo->DMABusy &&
3177: WaveInfo->DoubleBuffer.Buffer[LowerHalf].nBytes == 0) {
3178:
3179: ASSERT(IsListEmpty(&WaveInfo->BufferQueue.ProgressQueue));
3180: ASSERT(WaveInfo->DoubleBuffer.NextHalf == LowerHalf);
3181: }
3182: #endif
3183:
3184: //
3185: // First try to stoke up the buffer currently being output (or about
3186: // to be started if DMA is not currently running).
3187: //
3188:
3189: if (WaveInfo->DoubleBuffer.Buffer[WaveInfo->DoubleBuffer.NextHalf].nBytes <
3190: WaveInfo->DoubleBuffer.Buffer[WaveInfo->DoubleBuffer.NextHalf].Size) {
3191:
3192: //
3193: // Try to stoke up our buffer. We may also succeed in
3194: // putting data in an empty buffer
3195: //
3196:
3197: SoundLoadDMABuffer(
3198: &WaveInfo->BufferQueue,
3199: &WaveInfo->DoubleBuffer.Buffer[WaveInfo->DoubleBuffer.NextHalf],
3200: WaveInfo->DoubleBuffer.Pad);
3201: }
3202:
3203: //
3204: // Try to fill the second buffer
3205: //
3206:
3207: if (WaveInfo->DoubleBuffer.Buffer[UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf].nBytes <
3208: WaveInfo->DoubleBuffer.Buffer[UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf].Size
3209: ) {
3210:
3211: SoundLoadDMABuffer(
3212: &WaveInfo->BufferQueue,
3213: &WaveInfo->DoubleBuffer.Buffer[
3214: UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf],
3215: WaveInfo->DoubleBuffer.Pad);
3216: }
3217:
3218: return TRUE;
3219: }
3220:
3221:
3222: BOOLEAN
3223: SoundFillInputBuffers(
3224: PWAVE_INFO WaveInfo
3225: )
3226: /*++
3227:
3228: Routine Description:
3229:
3230: Send input to client
3231:
3232: Take the data from the last recorded position in the DMA
3233: buffer. The length of the data is passed in. Try to
3234: insert it into the caller's buffers. Note that the client gets
3235: no notification if the data is truncated.
3236:
3237: Arguments:
3238:
3239: WaveInfo - current wave (input) state
3240:
3241: Return Value:
3242:
3243: TRUE if we completed at least one of the user's Irps
3244:
3245: --*/
3246:
3247: {
3248: BOOLEAN BufferCompleted;
3249: struct SOUND_DMABUF *pDMA;
3250: PSOUND_BUFFER_QUEUE BufferQueue;
3251:
3252: BufferQueue = &WaveInfo->BufferQueue;
3253:
3254: pDMA = &WaveInfo->DoubleBuffer.Buffer[
3255: UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf];
3256:
3257: BufferCompleted = FALSE;
3258:
3259: //
3260: // While there is data and somewhere to put it
3261: //
3262:
3263: while (pDMA->nBytes < pDMA->Size) {
3264:
3265: ULONG BytesToCopy;
3266:
3267: //
3268: // We might have completed the last buffer
3269: // Note that we cope with 0 length buffers here
3270: //
3271:
3272: if (BufferQueue->UserBuffer == NULL) {
3273: SoundGetNextBuffer(BufferQueue);
3274:
3275:
3276: if (BufferQueue->UserBuffer == NULL) {
3277:
3278: //
3279: // There REALLY aren't any buffers
3280: //
3281:
3282: break;
3283: }
3284: }
3285:
3286: //
3287: // Find out how much space we have left in the
3288: // client's buffers
3289: // Note that BytesToCopy may be 0 - this is OK
3290: //
3291:
3292: BytesToCopy =
3293: min(BufferQueue->UserBufferSize - BufferQueue->pIrp->IoStatus.Information,
3294: pDMA->Size - pDMA->nBytes);
3295:
3296: //
3297: // Copy the data
3298: //
3299:
3300: RtlCopyMemory(BufferQueue->UserBuffer +
3301: BufferQueue->pIrp->IoStatus.Information,
3302: pDMA->Buf + pDMA->nBytes,
3303: BytesToCopy);
3304:
3305: //
3306: // Update counters etc.
3307: //
3308:
3309: BufferQueue->pIrp->IoStatus.Information += BytesToCopy;
3310: BufferQueue->BytesProcessed += BytesToCopy;
3311: pDMA->nBytes += BytesToCopy;
3312:
3313: //
3314: // See if we've now filled a buffer
3315: //
3316:
3317: if (BufferQueue->pIrp->IoStatus.Information == BufferQueue->UserBufferSize) {
3318:
3319: SoundCompleteIoBuffer(BufferQueue);
3320:
3321: //
3322: // Mark request as complete
3323: //
3324:
3325: BufferQueue->pIrp->IoStatus.Status = STATUS_SUCCESS;
3326: IoCompleteRequest(BufferQueue->pIrp, IO_SOUND_INCREMENT);
3327:
3328: BufferCompleted = TRUE;
3329: }
3330: }
3331:
3332: //
3333: // If there is a buffer part filled put it back on the queue so that
3334: // it can be cancelled if necessary
3335: //
3336:
3337: if (BufferQueue->UserBuffer != NULL) {
3338: SoundAddIrpToCancellableQ(&BufferQueue->QueueHead,
3339: BufferQueue->pIrp,
3340: TRUE);
3341:
3342: BufferQueue->UserBuffer = NULL;
3343: }
3344:
3345: return BufferCompleted;
3346: }
3347:
3348: /************************************************************************
3349: *
3350: * Routines to handle queues of wave buffers
3351: *
3352: ************************************************************************/
3353:
3354:
3355:
3356: VOID
3357: SoundGetNextBuffer(
3358: PSOUND_BUFFER_QUEUE BufferQueue
3359: )
3360: /*++
3361:
3362: Routine Description:
3363:
3364: Get the next user's buffer :
3365:
3366: If there is another buffer :
3367:
3368: Remove the first buffer from the head of the list
3369: Discard it if it's cancelled and go to the next
3370: Map the locked user pages so we can refer to them
3371: Update the BufferQueue fields :
3372: UserBuffer - our pointer to buffer
3373: UserBufferPosition - 0
3374: pIrp - The request packet for the current buffer
3375:
3376:
3377: Arguments:
3378:
3379: BufferQueue - pointer to our local queue info
3380:
3381: Return Value:
3382:
3383: None
3384:
3385: --*/
3386: {
3387: PIO_STACK_LOCATION pIrpStack;
3388: KIRQL OldIrql;
3389:
3390: dprintf4(("New Packet"));
3391:
3392: ASSERT(BufferQueue->UserBuffer == NULL);
3393:
3394: //
3395: // May be no more buffers. If there are they may be cancelled
3396: // IO requests.
3397: //
3398:
3399: for (;;) {
3400:
3401: //
3402: // pull the next request packet from the front of the list
3403: // This call makes the Irp non cancellable.
3404: //
3405:
3406:
3407: BufferQueue->pIrp =
3408: SoundRemoveFromCancellableQ(&BufferQueue->QueueHead);
3409:
3410: if (BufferQueue->pIrp == NULL) {
3411: break;
3412: }
3413:
3414: pIrpStack = IoGetCurrentIrpStackLocation(BufferQueue->pIrp);
3415:
3416: //
3417: // Get the length of the wave bits
3418: //
3419:
3420: BufferQueue->UserBufferSize =
3421: pIrpStack->MajorFunction == IRP_MJ_WRITE ?
3422: pIrpStack->Parameters.Write.Length :
3423: pIrpStack->Parameters.Read.Length;
3424:
3425: //
3426: // Map the buffer pages to kernel mode
3427: // Keep the address of the start so we can unmap them later
3428: // Note the system falls over mapping 0 length buffers !
3429: //
3430:
3431: if (BufferQueue->UserBufferSize != 0) {
3432: BufferQueue->UserBuffer =
3433: (PUCHAR) MmGetSystemAddressForMdl(BufferQueue->pIrp->MdlAddress);
3434: } else {
3435: BufferQueue->UserBuffer = (PUCHAR)BufferQueue; // Dummy
3436: }
3437:
3438: //
3439: // We now have a buffer - set the position from the
3440: // information field.
3441: //
3442:
3443: BufferQueue->UserBufferPosition =
3444: BufferQueue->pIrp->IoStatus.Information;
3445:
3446: break;
3447: }
3448: }
3449:
3450:
3451: VOID
3452: SoundCompleteIoBuffer(
3453: PSOUND_BUFFER_QUEUE BufferQueue
3454: )
3455: /*++
3456:
3457: Routine Description:
3458:
3459: Complete the processing of a wave buffer
3460:
3461: This involves
3462:
3463: -- Setting the length of data processed in the Irp and
3464:
3465: -- Clearing the UserBuffer field.
3466:
3467: Arguments:
3468:
3469: BufferQueue - pointer to our queue data
3470:
3471: Return Value:
3472:
3473: None
3474:
3475: --*/
3476:
3477: {
3478: //
3479: // Note that there is currently no mapped buffer to use
3480: //
3481:
3482: BufferQueue->UserBuffer = NULL;
3483: }
3484:
3485:
3486: VOID
3487: SoundInitializeWaveInfo(
3488: PWAVE_INFO WaveInfo,
3489: UCHAR DMAType,
3490: PSOUND_QUERY_FORMAT_ROUTINE QueryFormat,
3491: PVOID HwContext
3492: )
3493: /*++
3494:
3495: Routine Description:
3496:
3497: Initialize the WAVE_INFO structure
3498:
3499: Arguments:
3500:
3501: WaveInfo - The one to initialize
3502: DMAType - type of DMA to do (autoinit, 2 channel etc)
3503: QueryFormat - callback to see if format is supported
3504: Context - hardware specific context stored in WAVE_INFO structure
3505:
3506: Return Value:
3507:
3508: None.
3509:
3510: --*/
3511: {
3512: WaveInfo->Key = WAVE_INFO_KEY;
3513: WaveInfo->DMAType = DMAType;
3514: WaveInfo->QueryFormat = QueryFormat;
3515: WaveInfo->HwContext = HwContext;
3516: SoundInitializeBufferQ(&WaveInfo->BufferQueue);
3517:
3518: KeInitializeSpinLock(&WaveInfo->DeviceSpinLock);
3519: KeInitializeTimer(&WaveInfo->DeviceCheckTimer);
3520:
3521: //
3522: // The event is used for waiting for the Dpc routine to complete -
3523: // it is not reset on completion - hence use of NotificationEvent type.
3524: //
3525:
3526: KeInitializeEvent(&WaveInfo->DpcEvent,
3527: NotificationEvent,
3528: TRUE);
3529: }
3530:
3531: VOID
3532: SoundInitializeBufferQ(
3533: PSOUND_BUFFER_QUEUE BufferQueue
3534: )
3535: /*++
3536:
3537: Routine Description:
3538:
3539: Initialize the BufferQ structure
3540:
3541: Arguments:
3542:
3543: BufferQueue - The one to initialize
3544:
3545: Return Value:
3546:
3547: None.
3548:
3549: --*/
3550: {
3551: //
3552: // Set up the lists
3553: //
3554:
3555: InitializeListHead(&BufferQueue->QueueHead);
3556: InitializeListHead(&BufferQueue->ProgressQueue);
3557: }
3558:
3559:
3560: VOID
3561: SoundInitializeDoubleBuffer(
3562: IN OUT PWAVE_INFO WaveInfo
3563: )
3564: /*++
3565:
3566: Routine Description:
3567:
3568: Initialize the Double buffer structure
3569:
3570: Arguments:
3571:
3572: WaveInfo - pointer to containing structure
3573:
3574: Return Value:
3575:
3576: None.
3577:
3578: --*/
3579: {
3580: ULONG BufferSize;
3581: ULONG HalfBufferSize;
3582:
3583: ASSERTMSG("Setting buffer size while DMA running!", !WaveInfo->DMABusy);
3584:
3585: //
3586: // go for 8 interrupts per second, and round down to the nearest
3587: // 8 bytes
3588: //
3589:
3590: BufferSize = SoundGetDMABufferSize( WaveInfo );
3591:
3592: HalfBufferSize = BufferSize >> 1;
3593:
3594: WaveInfo->DoubleBuffer.Pad = WaveInfo->BitsPerSample == 8 ? 0x80 : 0;
3595: WaveInfo->DoubleBuffer.BufferSize = BufferSize;
3596: WaveInfo->DoubleBuffer.NextHalf = LowerHalf;
3597: WaveInfo->DoubleBuffer.Buffer[LowerHalf].Size = HalfBufferSize;
3598: WaveInfo->DoubleBuffer.Buffer[UpperHalf].Size = HalfBufferSize;
3599: WaveInfo->DoubleBuffer.Buffer[LowerHalf].nBytes =
3600: WaveInfo->Direction ? 0 : HalfBufferSize;
3601: WaveInfo->DoubleBuffer.Buffer[UpperHalf].nBytes =
3602: WaveInfo->Direction ? 0 : HalfBufferSize;
3603: WaveInfo->DoubleBuffer.Buffer[LowerHalf].Buf =
3604: (PUCHAR)WaveInfo->DMABuf.VirtualAddress;
3605: WaveInfo->DoubleBuffer.Buffer[UpperHalf].Buf =
3606: (PUCHAR)WaveInfo->DMABuf.VirtualAddress + HalfBufferSize;
3607: }
3608:
3609:
3610: int
3611: SoundTestWaveDevice(
3612: IN PDEVICE_OBJECT pDO
3613: )
3614: /*++
3615:
3616: Routine Description:
3617:
3618: Fire up the wave device for a short transfer and return whether it's
3619: working (ie interrupts) or not.
3620:
3621: This routine should not be called except from the DriverEntry routine.
3622:
3623: NOTE - ONLY use this as a last resort - if there's no configuration
3624: information.
3625:
3626: ALSO - before unloading your driver if it fails make sure any termination
3627: of the transfer is complete (eg ExWorker routines etc).
3628:
3629: WARNING - this routine currently only works for auto-init devices - the
3630: test on the DMA position at the end should be corrected for other
3631: forms of DMA.
3632:
3633: Arguments:
3634:
3635: pDO - device object of wave device
3636:
3637: Return Value:
3638:
3639: 0 if success
3640: 1 if bad interrupt
3641: 2 if bad DMA
3642:
3643: --*/
3644: {
3645: PWAVE_INFO WaveInfo;
3646: PLOCAL_DEVICE_INFO pLDI;
3647: ULONG DmaBytesLeft;
3648:
3649: pLDI = (PLOCAL_DEVICE_INFO)pDO->DeviceExtension;
3650:
3651: WaveInfo = pLDI->DeviceSpecificData;
3652:
3653: //
3654: // To test the wave device we just start a 0 length transfer. The
3655: // way the code is written this will actually cause a half DMA buffer
3656: // to be sent so we should get an interrupt in less than 1/8 of a second.
3657: // We arrange to wait for 1/4 of a second and see if we got one
3658: //
3659:
3660: if (!(*pLDI->DeviceInit->ExclusionRoutine)(
3661: pLDI, SoundExcludeOpen)) {
3662: return FALSE; // Something funny going on here
3663: }
3664:
3665: SoundWaveCreate(pLDI, pDO);
3666:
3667: if (!WaveInfo->Direction) {
3668: SoundSetWaveInputState(pLDI, WAVE_DD_RECORDING);
3669: }
3670:
3671: SoundStartWaveDevice(pLDI, NULL);
3672:
3673: SoundDelay(125); // 125 ms = 1/8 second
3674:
3675: SoundWaveCleanup(pLDI);
3676:
3677: //
3678: // Should be around half a buffer left to go - ie we're in the second
3679: // half buffer
3680: //
3681: DmaBytesLeft = HalReadDmaCounter(WaveInfo->DMABuf.AdapterObject[0]);
3682:
3683: if (!WaveInfo->GotWaveDpc) {
3684: return 1; // Bad interrupt
3685: }
3686: if (DmaBytesLeft > 0 &&
3687: DmaBytesLeft < WaveInfo->DoubleBuffer.Buffer[UpperHalf].Size) {
3688:
3689: return 0; // OK
3690: } else {
3691: return 2; // Bad DMA
3692: }
3693: }
3694:
3695: /****************************************************************************
3696:
3697: Routine Description:
3698:
3699: Get the DMA Buffer size based on the Sample Rate
3700:
3701: Arguments:
3702:
3703: WaveInfo - pointer to containing structure
3704:
3705: Return Value:
3706:
3707: ULONG DmaBufferSize
3708:
3709: ****************************************************************************/
3710: ULONG SoundGetDMABufferSize( IN OUT PWAVE_INFO WaveInfo )
3711: {
3712: /***** Local Variables *****/
3713:
3714: ULONG BytesPerSecond;
3715: ULONG BufferSize;
3716:
3717: /***** Start *****/
3718:
3719: BytesPerSecond = (WaveInfo->Channels *
3720: WaveInfo->SamplesPerSec *
3721: WaveInfo->BitsPerSample) >> 3;
3722: //
3723: // go for 8 interrupts per second, and round down to the nearest
3724: // 8 bytes
3725: //
3726: BufferSize = min((BytesPerSecond >> 2) & ~7,
3727: WaveInfo->DMABuf.BufferSize);
3728:
3729: dprintf2(("SoundGetDMABufferSize(): DMA Buffer Size calculated = %XH", BufferSize));
3730:
3731: return( BufferSize );
3732:
3733: } // End SoundGetDMABufferSize()
3734:
3735:
3736: /************************************ END ***********************************/
3737:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.