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