Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2216 lines
66 KiB

  1. /****************************************************************************
  2. *
  3. * wave.c
  4. *
  5. * Wave routines for wdmaud.sys
  6. *
  7. * Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
  8. *
  9. * History
  10. * S.Mohanraj (MohanS)
  11. * M.McLaughlin (MikeM)
  12. * 5-19-97 - Noel Cross (NoelC)
  13. *
  14. ***************************************************************************/
  15. #include "wdmsys.h"
  16. //
  17. // This is just a scratch location that is never used for anything
  18. // but a parameter to core functions.
  19. //
  20. IO_STATUS_BLOCK gIoStatusBlock ;
  21. VOID
  22. SetVolumeDpc(
  23. IN PKDPC pDpc,
  24. IN PVOID DefferedContext,
  25. IN PVOID SystemArgument1,
  26. IN PVOID SystemArgument2
  27. );
  28. VOID
  29. SetVolumeWorker(
  30. IN PWAVEDEVICE pDevice,
  31. IN PVOID pNotUsed
  32. );
  33. VOID
  34. WaitForOutStandingIo(
  35. IN PWAVEDEVICE pWaveDevice,
  36. IN PWAVE_PIN_INSTANCE pCurWavePin
  37. );
  38. //
  39. // Check whether the waveformat is supported by kmixer
  40. // purpose of this is to decide whether to use WaveQueued
  41. // OR Standard Streaming
  42. //
  43. BOOL
  44. PcmWaveFormat(
  45. LPWAVEFORMATEX lpFormat
  46. )
  47. {
  48. PWAVEFORMATEXTENSIBLE pWaveExtended;
  49. WORD wFormatTag;
  50. PAGED_CODE();
  51. if (lpFormat->wFormatTag == WAVE_FORMAT_PCM) {
  52. return (TRUE);
  53. }
  54. if (lpFormat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
  55. return (TRUE);
  56. }
  57. if (lpFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
  58. pWaveExtended = (PWAVEFORMATEXTENSIBLE) lpFormat;
  59. if (IS_VALID_WAVEFORMATEX_GUID(&pWaveExtended->SubFormat)) {
  60. wFormatTag = EXTRACT_WAVEFORMATEX_ID(&pWaveExtended->SubFormat);
  61. if (wFormatTag == WAVE_FORMAT_PCM) {
  62. return (TRUE);
  63. }
  64. if (wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
  65. return (TRUE);
  66. }
  67. }
  68. }
  69. return (FALSE);
  70. }
  71. BOOL
  72. IsValidFormatTag(
  73. PKSDATARANGE_AUDIO pDataRange,
  74. LPWAVEFORMATEX lpFormat
  75. )
  76. {
  77. PAGED_CODE();
  78. //
  79. // See if we have a majorformat and subformat that
  80. // we want
  81. //
  82. if ( IsEqualGUID( &KSDATAFORMAT_TYPE_AUDIO,
  83. &pDataRange->DataRange.MajorFormat) )
  84. {
  85. if (WAVE_FORMAT_EXTENSIBLE == lpFormat->wFormatTag)
  86. {
  87. PWAVEFORMATEXTENSIBLE lpFormatExtensible;
  88. lpFormatExtensible = (PWAVEFORMATEXTENSIBLE)lpFormat;
  89. if ( IsEqualGUID( &pDataRange->DataRange.SubFormat,
  90. &lpFormatExtensible->SubFormat) )
  91. {
  92. return TRUE;
  93. }
  94. }
  95. else
  96. {
  97. if ( (EXTRACT_WAVEFORMATEX_ID(&pDataRange->DataRange.SubFormat) ==
  98. lpFormat->wFormatTag) )
  99. {
  100. return TRUE;
  101. }
  102. }
  103. }
  104. DPF(DL_TRACE|FA_WAVE,("Invalid Format Tag") );
  105. return FALSE;
  106. }
  107. BOOL
  108. IsValidSampleFrequency(
  109. PKSDATARANGE_AUDIO pDataRange,
  110. DWORD nSamplesPerSec
  111. )
  112. {
  113. PAGED_CODE();
  114. //
  115. // See if this datarange support the requested frequency
  116. //
  117. if (pDataRange->MinimumSampleFrequency <= nSamplesPerSec &&
  118. pDataRange->MaximumSampleFrequency >= nSamplesPerSec)
  119. {
  120. return TRUE;
  121. }
  122. else
  123. {
  124. DPF(DL_MAX|FA_WAVE,("Invalid Sample Frequency") );
  125. return FALSE;
  126. }
  127. }
  128. BOOL
  129. IsValidBitsPerSample(
  130. PKSDATARANGE_AUDIO pDataRange,
  131. LPWAVEFORMATEX lpFormat
  132. )
  133. {
  134. PAGED_CODE();
  135. //
  136. // See if this datarange support the requested frequency
  137. //
  138. if (pDataRange->MinimumBitsPerSample <= lpFormat->wBitsPerSample &&
  139. pDataRange->MaximumBitsPerSample >= lpFormat->wBitsPerSample)
  140. {
  141. if ( (lpFormat->wFormatTag == WAVE_FORMAT_PCM) &&
  142. (lpFormat->wBitsPerSample > 32) )
  143. {
  144. DPF(DL_TRACE|FA_WAVE,("Invalid BitsPerSample") );
  145. return FALSE;
  146. }
  147. else if ( (lpFormat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) &&
  148. (lpFormat->wBitsPerSample != 32) )
  149. {
  150. DPF(DL_TRACE|FA_WAVE,("Invalid BitsPerSample") );
  151. return FALSE;
  152. }
  153. return TRUE;
  154. }
  155. else
  156. {
  157. DPF(DL_TRACE|FA_WAVE,("Invalid BitsPerSample") );
  158. return FALSE;
  159. }
  160. }
  161. BOOL
  162. IsValidChannels(
  163. PKSDATARANGE_AUDIO pDataRange,
  164. LPWAVEFORMATEX lpFormat
  165. )
  166. {
  167. PAGED_CODE();
  168. //
  169. // See if this datarange support the requested frequency
  170. //
  171. if (pDataRange->MaximumChannels >= lpFormat->nChannels)
  172. {
  173. if ( ( (lpFormat->wFormatTag == WAVE_FORMAT_PCM) ||
  174. (lpFormat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) ) &&
  175. (lpFormat->nChannels > 2) )
  176. {
  177. DPF(DL_TRACE|FA_WAVE,("Invalid Channel") );
  178. return FALSE;
  179. }
  180. return TRUE;
  181. }
  182. else
  183. {
  184. DPF(DL_TRACE|FA_WAVE,("Invalid Channel") );
  185. return FALSE;
  186. }
  187. }
  188. NTSTATUS
  189. OpenWavePin(
  190. PWDMACONTEXT pWdmaContext,
  191. ULONG DeviceNumber,
  192. LPWAVEFORMATEX lpFormat,
  193. HANDLE32 DeviceHandle,
  194. DWORD dwFlags,
  195. ULONG DataFlow // DataFlow is either in or out.
  196. )
  197. {
  198. PWAVE_PIN_INSTANCE pNewWavePin = NULL;
  199. PWAVE_PIN_INSTANCE pCurWavePin;
  200. PKSPIN_CONNECT pConnect = NULL;
  201. PKSDATAFORMAT_WAVEFORMATEX pWaveDataFormat;
  202. ULONG RegionSize;
  203. PCONTROLS_LIST pControlList = NULL;
  204. ULONG Device;
  205. ULONG PinId;
  206. NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
  207. PAGED_CODE();
  208. //
  209. // Let's do this quickly and get out of here
  210. //
  211. if (WAVE_FORMAT_QUERY & dwFlags)
  212. {
  213. PDATARANGES AudioDataRanges;
  214. PKSDATARANGE_AUDIO pDataRange;
  215. ULONG d;
  216. //
  217. // WaveOut call? If so, use waveout info
  218. //
  219. if( KSPIN_DATAFLOW_IN == DataFlow )
  220. AudioDataRanges = pWdmaContext->WaveOutDevs[DeviceNumber].AudioDataRanges;
  221. else
  222. AudioDataRanges = pWdmaContext->WaveInDevs[DeviceNumber].AudioDataRanges;
  223. pDataRange = (PKSDATARANGE_AUDIO)&AudioDataRanges->aDataRanges[0];
  224. for(d = 0; d < AudioDataRanges->Count; d++)
  225. {
  226. if ( (IsValidFormatTag(pDataRange,lpFormat)) &&
  227. (IsValidSampleFrequency(pDataRange,lpFormat->nSamplesPerSec)) &&
  228. (IsValidBitsPerSample(pDataRange,lpFormat)) &&
  229. (IsValidChannels(pDataRange,lpFormat)) )
  230. {
  231. //
  232. // Found a good data range, successful query
  233. //
  234. Status = STATUS_SUCCESS;
  235. break;
  236. }
  237. // Get the pointer to the next data range
  238. (PUCHAR)pDataRange += ((pDataRange->DataRange.FormatSize +
  239. FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT);
  240. }
  241. goto exit;
  242. }
  243. //
  244. // Need to allocate a pin instance for multiple wave
  245. // opens on the same device
  246. //
  247. Status = AudioAllocateMemory_Fixed(sizeof(WAVE_PIN_INSTANCE),
  248. TAG_Audi_PIN,
  249. ZERO_FILL_MEMORY,
  250. &pNewWavePin);
  251. if(!NT_SUCCESS(Status))
  252. {
  253. goto exit;
  254. }
  255. //
  256. // Copy the application supplied waveformat so we can
  257. // use in the worker thread context. Don't need to zero
  258. // memory because we copy into the structure below.
  259. //
  260. Status = AudioAllocateMemory_Fixed((lpFormat->wFormatTag == WAVE_FORMAT_PCM) ?
  261. sizeof( PCMWAVEFORMAT ) :
  262. sizeof( WAVEFORMATEX ) + lpFormat->cbSize,
  263. TAG_AudF_FORMAT,
  264. DEFAULT_MEMORY,
  265. &pNewWavePin->lpFormat);
  266. if(!NT_SUCCESS(Status))
  267. {
  268. AudioFreeMemory(sizeof(WAVE_PIN_INSTANCE),&pNewWavePin);
  269. goto exit;
  270. }
  271. RtlCopyMemory( pNewWavePin->lpFormat,
  272. lpFormat,
  273. (lpFormat->wFormatTag == WAVE_FORMAT_PCM) ?
  274. sizeof( PCMWAVEFORMAT ) :
  275. sizeof( WAVEFORMATEX ) + lpFormat->cbSize);
  276. pNewWavePin->DataFlow = DataFlow;
  277. pNewWavePin->dwFlags = dwFlags;
  278. pNewWavePin->DeviceNumber = DeviceNumber;
  279. pNewWavePin->WaveHandle = DeviceHandle;
  280. pNewWavePin->Next = NULL;
  281. pNewWavePin->NumPendingIos = 0;
  282. pNewWavePin->StoppingSource = FALSE;
  283. pNewWavePin->PausingSource = FALSE;
  284. pNewWavePin->dwSig = WAVE_PIN_INSTANCE_SIGNATURE;
  285. if( KSPIN_DATAFLOW_IN == DataFlow )
  286. pNewWavePin->pWaveDevice = &pWdmaContext->WaveOutDevs[DeviceNumber];
  287. else
  288. pNewWavePin->pWaveDevice = &pWdmaContext->WaveInDevs[DeviceNumber];
  289. KeInitializeEvent ( &pNewWavePin->StopEvent,
  290. SynchronizationEvent,
  291. FALSE ) ;
  292. KeInitializeEvent ( &pNewWavePin->PauseEvent,
  293. SynchronizationEvent,
  294. FALSE ) ;
  295. KeInitializeSpinLock(&pNewWavePin->WavePinSpinLock);
  296. if( KSPIN_DATAFLOW_IN == DataFlow )
  297. {
  298. if (NULL == pWdmaContext->WaveOutDevs[DeviceNumber].pWavePin)
  299. {
  300. pWdmaContext->WaveOutDevs[DeviceNumber].pWavePin = pNewWavePin;
  301. } else {
  302. for (pCurWavePin = pWdmaContext->WaveOutDevs[DeviceNumber].pWavePin;
  303. pCurWavePin->Next != NULL; )
  304. {
  305. pCurWavePin = pCurWavePin->Next;
  306. }
  307. pCurWavePin->Next = pNewWavePin;
  308. DPF(DL_TRACE|FA_WAVE, ("Opening another waveout pin"));
  309. }
  310. } else {
  311. if (NULL == pWdmaContext->WaveInDevs[DeviceNumber].pWavePin)
  312. {
  313. pWdmaContext->WaveInDevs[DeviceNumber].pWavePin = pNewWavePin;
  314. } else {
  315. for (pCurWavePin = pWdmaContext->WaveInDevs[DeviceNumber].pWavePin;
  316. pCurWavePin->Next != NULL; )
  317. {
  318. pCurWavePin = pCurWavePin->Next;
  319. }
  320. pCurWavePin->Next = pNewWavePin;
  321. DPF(DL_TRACE|FA_WAVE, ("Opening another wavein pin"));
  322. }
  323. }
  324. //
  325. // We only support one client at a time.
  326. //
  327. ASSERT( !pNewWavePin->fGraphRunning );
  328. //
  329. // We need to allocate enough memory to handle the
  330. // extended waveformat structure
  331. //
  332. if (WAVE_FORMAT_PCM == lpFormat->wFormatTag)
  333. {
  334. RegionSize = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX);
  335. }
  336. else
  337. {
  338. RegionSize = sizeof(KSPIN_CONNECT) +
  339. sizeof(KSDATAFORMAT_WAVEFORMATEX) +
  340. lpFormat->cbSize;
  341. }
  342. Status = AudioAllocateMemory_Fixed(RegionSize,
  343. TAG_Audt_CONNECT,
  344. ZERO_FILL_MEMORY,
  345. &pConnect);
  346. if(!NT_SUCCESS(Status))
  347. {
  348. DPF(DL_WARNING|FA_WAVE, ("pConnect not valid"));
  349. goto exit;
  350. }
  351. pWaveDataFormat = (PKSDATAFORMAT_WAVEFORMATEX)(pConnect + 1);
  352. //
  353. // Use WAVE_QUEUED for PCM waveOut and Standard Streaming for WaveIn
  354. // and non-PCM waveOut
  355. //
  356. if ( pNewWavePin->DataFlow == KSPIN_DATAFLOW_IN )
  357. {
  358. if (PcmWaveFormat(lpFormat)) { // if it is KMIXER supported waveformat
  359. pConnect->Interface.Set = KSINTERFACESETID_Media;
  360. pConnect->Interface.Id = KSINTERFACE_MEDIA_WAVE_QUEUED;
  361. pNewWavePin->fWaveQueued = TRUE;
  362. } else {
  363. pConnect->Interface.Set = KSINTERFACESETID_Standard;
  364. pConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
  365. pNewWavePin->fWaveQueued = FALSE;
  366. }
  367. pConnect->Interface.Flags = 0;
  368. PinId = pNewWavePin->pWaveDevice->PinId;
  369. Device = pNewWavePin->pWaveDevice->Device;
  370. } else {
  371. pConnect->Interface.Set = KSINTERFACESETID_Standard;
  372. pConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
  373. pConnect->Interface.Flags = 0;
  374. PinId = pNewWavePin->pWaveDevice->PinId;
  375. Device = pNewWavePin->pWaveDevice->Device;
  376. }
  377. pConnect->Medium.Set = KSMEDIUMSETID_Standard;
  378. pConnect->Medium.Id = KSMEDIUM_STANDARD_DEVIO;
  379. pConnect->Medium.Flags = 0 ;
  380. pConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
  381. pConnect->Priority.PrioritySubClass = 1;
  382. pWaveDataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
  383. if (WAVE_FORMAT_EXTENSIBLE == lpFormat->wFormatTag)
  384. {
  385. PWAVEFORMATEXTENSIBLE lpFormatExtensible;
  386. lpFormatExtensible = (PWAVEFORMATEXTENSIBLE)lpFormat;
  387. pWaveDataFormat->DataFormat.SubFormat = lpFormatExtensible->SubFormat;
  388. }
  389. else
  390. {
  391. INIT_WAVEFORMATEX_GUID( &pWaveDataFormat->DataFormat.SubFormat,
  392. lpFormat->wFormatTag );
  393. }
  394. pWaveDataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
  395. pWaveDataFormat->DataFormat.Flags = 0 ;
  396. pWaveDataFormat->DataFormat.FormatSize = RegionSize - sizeof(KSPIN_CONNECT);
  397. pWaveDataFormat->DataFormat.SampleSize = lpFormat->nBlockAlign ;
  398. pWaveDataFormat->DataFormat.Reserved = 0 ;
  399. //
  400. // Copy over the whole waveformat structure
  401. //
  402. RtlCopyMemory( &pWaveDataFormat->WaveFormatEx,
  403. lpFormat,
  404. (lpFormat->wFormatTag == WAVE_FORMAT_PCM) ?
  405. sizeof( PCMWAVEFORMAT ) :
  406. sizeof( WAVEFORMATEX ) + lpFormat->cbSize);
  407. Status = AudioAllocateMemory_Fixed(( sizeof(CONTROLS_LIST)+
  408. ((MAX_WAVE_CONTROLS-1)*sizeof(CONTROL_NODE)) ),
  409. TAG_AudC_CONTROL,
  410. ZERO_FILL_MEMORY,
  411. &pControlList) ;
  412. if(!NT_SUCCESS(Status))
  413. {
  414. AudioFreeMemory_Unknown( &pConnect );
  415. DPF(DL_WARNING|FA_WAVE, ("Could not allocate ControlList"));
  416. goto exit;
  417. }
  418. pControlList->Count = MAX_WAVE_CONTROLS ;
  419. pControlList->Controls[WAVE_CONTROL_VOLUME].Control = KSNODETYPE_VOLUME ;
  420. pControlList->Controls[WAVE_CONTROL_RATE].Control = KSNODETYPE_SRC ;
  421. pControlList->Controls[WAVE_CONTROL_QUALITY].Control = KSNODETYPE_SRC ;
  422. pNewWavePin->pControlList = pControlList ;
  423. //
  424. // Open a pin
  425. //
  426. Status = OpenSysAudioPin(Device,
  427. PinId,
  428. pNewWavePin->DataFlow,
  429. pConnect,
  430. &pNewWavePin->pFileObject,
  431. &pNewWavePin->pDeviceObject,
  432. pNewWavePin->pControlList);
  433. AudioFreeMemory_Unknown( &pConnect );
  434. if(!NT_SUCCESS(Status))
  435. {
  436. CloseTheWavePin(pNewWavePin->pWaveDevice, pNewWavePin->WaveHandle);
  437. goto exit;
  438. }
  439. if ( pNewWavePin->DataFlow == KSPIN_DATAFLOW_IN ) {
  440. Status = AttachVirtualSource(pNewWavePin->pFileObject, pNewWavePin->pWaveDevice->pWdmaContext->VirtualWavePinId);
  441. if (!NT_SUCCESS(Status))
  442. {
  443. CloseTheWavePin(pNewWavePin->pWaveDevice, pNewWavePin->WaveHandle);
  444. goto exit;
  445. }
  446. }
  447. //
  448. // Now we've gotten through everything so we can mark this one as running.
  449. // We do it here because of the close path. In that path fGraphRunning gets
  450. // decremented and the assert fires in the checked build.
  451. //
  452. pNewWavePin->fGraphRunning=TRUE;
  453. //
  454. // Why do we set this to KSSTATE_STOP and then change it to KSSTATE_PAUSE? If
  455. // StatePin is able to successfully change the state to KSSTATE_PAUSE, the
  456. // PinState will get updated to KSSTATE_PAUSE.
  457. //
  458. pNewWavePin->PinState = KSSTATE_STOP;
  459. StatePin(pNewWavePin->pFileObject, KSSTATE_PAUSE, &pNewWavePin->PinState);
  460. exit:
  461. RETURN( Status );
  462. }
  463. void
  464. CloseTheWavePin(
  465. PWAVEDEVICE pWaveDevice,
  466. HANDLE32 DeviceHandle
  467. )
  468. {
  469. PWAVE_PIN_INSTANCE *ppCur;
  470. PWAVE_PIN_INSTANCE pCurFree;
  471. PAGED_CODE();
  472. //
  473. // Remove from device chain. Notice that ppCur gets the address of the
  474. // location of pWaveDevice->pWavePin. Thus, the *ppCur = (*ppCur)->Next
  475. // assignment below updates the pWaveDevice->pWavePin location if we
  476. // close the first pin.
  477. //
  478. for (ppCur = &pWaveDevice->pWavePin;
  479. *ppCur != NULL;
  480. ppCur = &(*ppCur)->Next)
  481. {
  482. if ( NULL == DeviceHandle || (*ppCur)->WaveHandle == DeviceHandle )
  483. {
  484. //
  485. // Note that if there is outstanding Io we can not call CloseWavePin
  486. // until it's all come back. Thus, we'll need to tell the device
  487. // to stop and then wait for the Io here.
  488. //
  489. if( (*ppCur)->pFileObject )
  490. {
  491. //
  492. // We will never have outstanding Io if we don't have a file object
  493. // to send it too.
  494. //
  495. WaitForOutStandingIo(pWaveDevice,*ppCur);
  496. }
  497. CloseWavePin ( *ppCur );
  498. pCurFree = *ppCur;
  499. *ppCur = (*ppCur)->Next;
  500. AudioFreeMemory( sizeof(WAVE_PIN_INSTANCE), &pCurFree );
  501. break;
  502. }
  503. }
  504. }
  505. //
  506. // This routine can not fail!
  507. //
  508. VOID
  509. CloseWavePin(
  510. PWAVE_PIN_INSTANCE pWavePin
  511. )
  512. {
  513. ASSERT(pWavePin->NumPendingIos==0);
  514. PAGED_CODE();
  515. //
  516. // This routine can get called on the error path thus fGraphRunning may be FALSE.
  517. // In either case, we will need to close sysaudio and free memory.
  518. //
  519. pWavePin->fGraphRunning = FALSE;
  520. // Close the file object (pFileObject, if it exists)
  521. if(pWavePin->pFileObject)
  522. {
  523. CloseSysAudio(pWavePin->pWaveDevice->pWdmaContext, pWavePin->pFileObject);
  524. pWavePin->pFileObject = NULL;
  525. }
  526. //
  527. // AudioFreeMemory_Unknown NULLs out this location after freeing the memory.
  528. //
  529. AudioFreeMemory_Unknown ( &pWavePin->lpFormat );
  530. AudioFreeMemory_Unknown ( &pWavePin->pControlList ) ;
  531. //
  532. // Caller needs to free pWavePin if it wants to.
  533. //
  534. }
  535. #pragma LOCKED_CODE
  536. #pragma LOCKED_DATA
  537. //
  538. // This routine is used rather then an InterlockedIncrement and InterlockedDecrement
  539. // because the routine that needs to determine what to do based on this information
  540. // needs to perform multiple checks on different variables to determine exactly what
  541. // to do. Thus, we need a "critical section" for NumPendingIos. Also, SpinLocks
  542. // must be called from locked code. :)
  543. //
  544. void
  545. LockedWaveIoCount(
  546. PWAVE_PIN_INSTANCE pCurWavePin,
  547. BOOL bIncrease
  548. )
  549. {
  550. KIRQL OldIrql;
  551. KeAcquireSpinLock(&pCurWavePin->WavePinSpinLock,&OldIrql);
  552. if( bIncrease )
  553. pCurWavePin->NumPendingIos++;
  554. else
  555. pCurWavePin->NumPendingIos--;
  556. KeReleaseSpinLock(&pCurWavePin->WavePinSpinLock, OldIrql);
  557. }
  558. void
  559. CompleteNumPendingIos(
  560. PWAVE_PIN_INSTANCE pCurWavePin
  561. )
  562. {
  563. KIRQL OldIrql;
  564. if( pCurWavePin )
  565. {
  566. KeAcquireSpinLock(&pCurWavePin->WavePinSpinLock,&OldIrql);
  567. //
  568. // We always decrement NumPendingIos and then perform the comparisons.
  569. // If the count goes to zero, we're the last IRP so we need to check
  570. // to see if we need to signal any waiting thread.
  571. //
  572. if( ( --pCurWavePin->NumPendingIos == 0 ) && pCurWavePin->StoppingSource )
  573. {
  574. //
  575. // If this Io is the last one to come through, and we're currently
  576. // sitting waiting for the reset to finish, then we signal it here.
  577. //
  578. KeSetEvent ( &pCurWavePin->StopEvent, 0, FALSE ) ;
  579. }
  580. //
  581. // Upon leaving this spinlock, pCurWavePin can be freed by the close
  582. // routine if NumPendingIos went to zero!
  583. //
  584. KeReleaseSpinLock(&pCurWavePin->WavePinSpinLock, OldIrql);
  585. }
  586. //
  587. // Must not touch pCurWavePin after this!
  588. //
  589. }
  590. void
  591. UnmapWriteContext(
  592. PWRITE_CONTEXT pWriteContext
  593. )
  594. {
  595. wdmaudUnmapBuffer(pWriteContext->pBufferMdl);
  596. AudioFreeMemory_Unknown(&pWriteContext->pCapturedWaveHdr);
  597. AudioFreeMemory(sizeof(WRITE_CONTEXT),&pWriteContext);
  598. }
  599. void
  600. FreeWriteContext(
  601. PWRITE_CONTEXT pWriteContext,
  602. NTSTATUS IrpStatus
  603. )
  604. {
  605. PIRP UserIrp;
  606. PWDMAPENDINGIRP_CONTEXT pPendingIrpContext;
  607. //
  608. // grab the parent IRP from the reserved field
  609. //
  610. UserIrp = (PIRP)pWriteContext->whInstance.wh.reserved;
  611. pPendingIrpContext = pWriteContext->pPendingIrpContext;
  612. UnmapWriteContext( pWriteContext );
  613. if( UserIrp )
  614. wdmaudUnprepareIrp( UserIrp,IrpStatus,0,pPendingIrpContext);
  615. }
  616. //
  617. // This is the Irp completion routine.
  618. //
  619. NTSTATUS
  620. wqWriteWaveCallBack(
  621. PDEVICE_OBJECT pDeviceObject,
  622. PIRP pIrp,
  623. IN PWAVEHDR pWriteData
  624. )
  625. {
  626. PWAVE_PIN_INSTANCE pCurWavePin;
  627. PMDL Mdl;
  628. PMDL nextMdl;
  629. PIRP UserIrp;
  630. PWDMAPENDINGIRP_CONTEXT pPendingIrpContext;
  631. PWRITE_CONTEXT pWriteContext = (PWRITE_CONTEXT)pWriteData;
  632. ASSERT(pWriteData);
  633. pCurWavePin = pWriteContext->whInstance.pWaveInstance;
  634. DPF(DL_TRACE|FA_WAVE, ("R%d: 0x%08x", pCurWavePin->NumPendingIos,pIrp));
  635. //
  636. // After we get our pCurWavePin, we don't need the write context any longer.
  637. //
  638. FreeWriteContext(pWriteContext, pIrp->IoStatus.Status);
  639. //
  640. // Consider putting this in a routine.
  641. //
  642. if (pIrp->MdlAddress != NULL)
  643. {
  644. //
  645. // Unlock any pages that may be described by MDLs.
  646. //
  647. Mdl = pIrp->MdlAddress;
  648. while (Mdl != NULL)
  649. {
  650. MmUnlockPages( Mdl );
  651. Mdl = Mdl->Next;
  652. }
  653. }
  654. if (pIrp->MdlAddress != NULL)
  655. {
  656. for (Mdl = pIrp->MdlAddress; Mdl != (PMDL) NULL; Mdl = nextMdl)
  657. {
  658. nextMdl = Mdl->Next;
  659. if (Mdl->MdlFlags & MDL_PARTIAL_HAS_BEEN_MAPPED)
  660. {
  661. ASSERT( Mdl->MdlFlags & MDL_PARTIAL );
  662. MmUnmapLockedPages( Mdl->MappedSystemVa, Mdl );
  663. }
  664. else if (!(Mdl->MdlFlags & MDL_PARTIAL))
  665. {
  666. ASSERT(!(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA ));
  667. }
  668. AudioFreeMemory_Unknown( &Mdl );
  669. }
  670. }
  671. IoFreeIrp( pIrp );
  672. CompleteNumPendingIos( pCurWavePin );
  673. return ( STATUS_MORE_PROCESSING_REQUIRED );
  674. }
  675. //
  676. // Consider combining ssWriteWaveCallback and wqWriteWaveCallBack. They look
  677. // like the same routine!
  678. //
  679. NTSTATUS
  680. ssWriteWaveCallBack(
  681. PDEVICE_OBJECT pDeviceObject,
  682. PIRP pIrp,
  683. IN PSTREAM_HEADER_EX pStreamHeader
  684. )
  685. {
  686. PWAVE_PIN_INSTANCE pCurWavePin;
  687. PIRP UserIrp;
  688. PWDMAPENDINGIRP_CONTEXT pPendingIrpContext;
  689. PWRITE_CONTEXT pWriteContext = (PWRITE_CONTEXT)pStreamHeader->pWaveHdr;
  690. ASSERT(pWriteContext);
  691. pCurWavePin = pWriteContext->whInstance.pWaveInstance;
  692. DPF(DL_TRACE|FA_WAVE, ("R%d: 0x%08x", pCurWavePin->NumPendingIos,pIrp));
  693. FreeWriteContext( pWriteContext, pIrp->IoStatus.Status );
  694. CompleteNumPendingIos( pCurWavePin );
  695. return STATUS_SUCCESS;
  696. }
  697. #pragma PAGEABLE_CODE
  698. #pragma PAGEABLE_DATA
  699. //
  700. // Walk the list and if we find a matching pin, write it back for the caller.
  701. //
  702. NTSTATUS
  703. FindRunningPin(
  704. IN PWAVEDEVICE pWaveDevice,
  705. IN HANDLE32 DeviceHandle,
  706. OUT PWAVE_PIN_INSTANCE* ppCurWavePin
  707. )
  708. {
  709. PWAVE_PIN_INSTANCE pCurWavePin;
  710. NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
  711. //
  712. // Prepare for the error condition.
  713. //
  714. *ppCurWavePin = NULL;
  715. //
  716. // find the right pin based off of the wave handle
  717. //
  718. for (pCurWavePin = pWaveDevice->pWavePin;
  719. pCurWavePin != NULL;
  720. pCurWavePin = pCurWavePin->Next)
  721. {
  722. if (pCurWavePin->WaveHandle == DeviceHandle)
  723. {
  724. if (pCurWavePin->fGraphRunning)
  725. {
  726. //
  727. // Write back the pointer and return success
  728. //
  729. *ppCurWavePin = pCurWavePin;
  730. Status = STATUS_SUCCESS;
  731. } else {
  732. DPF(DL_WARNING|FA_WAVE,("Invalid fGraphRunning") );
  733. Status = STATUS_DEVICE_NOT_READY;
  734. }
  735. return Status;
  736. }
  737. }
  738. return Status;
  739. }
  740. //
  741. // WriteWaveOutPin walks the device list like the other routines.
  742. //
  743. // pUserIrp is the Irp on which this call from user mode was made. It's
  744. // always going to be valid. We don't need to check it.
  745. //
  746. // This routine needs to set pCompletedIrp to either TRUE or FALSE. If
  747. // TRUE, the Irp was successfully marked STATUS_PENDING and it will get
  748. // completed later. If FALSE, there was some type of error that prevented
  749. // us from submitting the Irp. The caller to this routine will need to
  750. // handle freeing the Irp.
  751. //
  752. //
  753. // This routine should be the one storing the user's irp in the reserved field.
  754. // Not the caller.
  755. // pWriteContext->whInstance.wh.reserved = (DWORD_PTR)pIrp; // store to complete later
  756. //
  757. NTSTATUS
  758. WriteWaveOutPin(
  759. PWAVEDEVICE pWaveOutDevice,
  760. HANDLE32 DeviceHandle,
  761. LPWAVEHDR pWriteData,
  762. PSTREAM_HEADER_EX pStreamHeader,
  763. PIRP pUserIrp,
  764. PWDMACONTEXT pContext,
  765. BOOL *pCompletedIrp
  766. )
  767. {
  768. PWAVE_PIN_INSTANCE pCurWavePin;
  769. PWRITE_CONTEXT pWriteContext = (PWRITE_CONTEXT)pWriteData;
  770. PWDMAPENDINGIRP_CONTEXT pPendingIrpContext;
  771. NTSTATUS Status;
  772. PAGED_CODE();
  773. //
  774. // We assumee that pCompletedIrp is FALSE on entry.
  775. //
  776. ASSERT( *pCompletedIrp == FALSE );
  777. Status = FindRunningPin(pWaveOutDevice,DeviceHandle,&pCurWavePin);
  778. if( NT_SUCCESS(Status) )
  779. {
  780. if (pCurWavePin->fWaveQueued)
  781. {
  782. PIO_STACK_LOCATION pIrpStack;
  783. LARGE_INTEGER StartingOffset;
  784. PIRP pIrp = NULL;
  785. //
  786. // Can't use KsStreamIo because these are not
  787. // true stream headers. Sending down headers
  788. // using the WAVE_QUEUED interface
  789. //
  790. StartingOffset.QuadPart = 0;
  791. pIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
  792. pCurWavePin->pDeviceObject,
  793. (PVOID)pWriteContext,
  794. sizeof(WAVEHDR),
  795. &StartingOffset,
  796. &gIoStatusBlock);
  797. if( pIrp )
  798. {
  799. Status = wdmaudPrepareIrp( pUserIrp,
  800. WaveOutDevice,
  801. pContext,
  802. &pPendingIrpContext );
  803. if( NT_SUCCESS(Status) )
  804. {
  805. //
  806. // The Irp was successfully marked STATUS_PENDING and put in
  807. // our queue. Now let's send it.
  808. //
  809. pWriteContext->whInstance.pWaveInstance = pCurWavePin;
  810. pWriteContext->pPendingIrpContext = pPendingIrpContext;
  811. pIrp->RequestorMode = KernelMode;
  812. pIrp->Tail.Overlay.OriginalFileObject = pCurWavePin->pFileObject;
  813. pIrpStack = IoGetNextIrpStackLocation(pIrp);
  814. pIrpStack->FileObject = pCurWavePin->pFileObject;
  815. IoSetCompletionRoutine(pIrp,
  816. wqWriteWaveCallBack,
  817. pWriteData,
  818. TRUE,TRUE,TRUE);
  819. //
  820. // one more IRP pending
  821. //
  822. LockedWaveIoCount(pCurWavePin,INCREASE);
  823. DPF(DL_TRACE|FA_WAVE, ("A%d", pCurWavePin->NumPendingIos));
  824. //
  825. // We don't need to check the return code because the
  826. // completion routine will ALWAYS be called. See
  827. // IoSetCompletionRoutine(...TRUE,TRUE,TRUE).
  828. //
  829. IofCallDriver( pCurWavePin->pDeviceObject, pIrp );
  830. //
  831. // At this point, the Irp may have been completed and our
  832. // callback routine will have been called. We can not touch
  833. // the irp after this call. The Callback routine Completes
  834. // the Irp and unprepares the user's Irp.
  835. //
  836. *pCompletedIrp = TRUE;
  837. //
  838. // In wdmaudPrepareIrp we call IoCsqInsertIrp which calls
  839. // IoMarkIrpPending, thus we must always return STATUS_PENDING.
  840. //
  841. return STATUS_PENDING;
  842. } else {
  843. //
  844. // We where not successful at putting the Irp in the queue.
  845. // cleanup and indicated that we did not complete the Irp.
  846. // The status will have been set by wdmaudPrepareIrp.
  847. DPF(DL_WARNING|FA_WAVE,("wdmaudPrepareIrp failed Status=%X",Status) );
  848. }
  849. } else {
  850. //
  851. // Could not create a Irp to send down - error out!
  852. //
  853. DPF(DL_WARNING|FA_WAVE,("IoBuildAsynchronousFsdRequest failed") );
  854. Status = STATUS_UNSUCCESSFUL;
  855. //
  856. // We can't get an Irp to schedule. Cleanup memory
  857. // and return. The caller will complete the Irp.
  858. //
  859. }
  860. } else {
  861. //
  862. // If it's not wave queued we need to make sure that it's a PCM
  863. // looped call.
  864. //
  865. if ( (pWriteData->dwFlags & (WHDR_BEGINLOOP|WHDR_ENDLOOP)) )
  866. {
  867. //
  868. // Error out non-PCM looped calls
  869. //
  870. Status = STATUS_NOT_IMPLEMENTED;
  871. } else {
  872. //
  873. // The graph is running so we can use it. Proceed.
  874. //
  875. Status = wdmaudPrepareIrp( pUserIrp, WaveOutDevice, pContext, &pPendingIrpContext );
  876. if( NT_SUCCESS(Status) )
  877. {
  878. //
  879. // The Irp was successfully marked STATUS_PENDING and put in
  880. // our queue. Now let's send it.
  881. //
  882. pWriteContext->whInstance.pWaveInstance = pCurWavePin;
  883. pWriteContext->pPendingIrpContext = pPendingIrpContext;
  884. //
  885. // one more IRP pending
  886. //
  887. LockedWaveIoCount(pCurWavePin,INCREASE);
  888. DPF(DL_TRACE|FA_WAVE, ("A%d", pCurWavePin->NumPendingIos));
  889. pStreamHeader->pWavePin = pCurWavePin;
  890. pStreamHeader->Header.FrameExtent = pWriteData->dwBufferLength ;
  891. pStreamHeader->Header.DataUsed = pWriteData->dwBufferLength;
  892. pStreamHeader->Header.OptionsFlags = 0 ;
  893. pStreamHeader->Header.Size = sizeof( KSSTREAM_HEADER );
  894. pStreamHeader->Header.TypeSpecificFlags = 0;
  895. pStreamHeader->pWaveHdr = pWriteData; // store so we can use later
  896. Status = KsStreamIo(pCurWavePin->pFileObject,
  897. NULL, // Event
  898. NULL, // PortContext
  899. ssWriteWaveCallBack,
  900. pStreamHeader, // CompletionContext
  901. KsInvokeOnSuccess | KsInvokeOnCancel | KsInvokeOnError,
  902. &gIoStatusBlock,
  903. &pStreamHeader->Header,
  904. sizeof( KSSTREAM_HEADER ),
  905. KSSTREAM_WRITE,
  906. KernelMode );
  907. //
  908. // At this point, the Irp may have been completed and our
  909. // callback routine will have been called. We can not touch
  910. // the irp after this call. The Callback routine Completes
  911. // the Irp and unprepares the user's Irp.
  912. //
  913. *pCompletedIrp = TRUE;
  914. //
  915. // In wdmaudPrepareIrp we call IoCsqInsertIrp which calls
  916. // IoMarkIrpPending, thus we must always return STATUS_PENDING.
  917. // also, we don't want to clean up anything.... just return.
  918. //
  919. return STATUS_PENDING;
  920. //
  921. // Warning: If, for any reason, the completion routine is not called
  922. // for this Irp, wdmaud.sys will hang. It's been discovered that
  923. // KsStreamIo may error out in low memory conditions. There is an
  924. // outstanding bug to address this.
  925. //
  926. } else {
  927. //
  928. // We where not successful at putting the Irp in the queue.
  929. // cleanup and indicated that we did not complete the Irp.
  930. // The Status was set by wdmaudPrepareIrp.
  931. DPF(DL_WARNING|FA_WAVE,("wdmaudPrepareIrp failed Status=%X",Status) );
  932. }
  933. }
  934. }
  935. }
  936. //
  937. // All error paths end up here. All error paths should cleanup the
  938. // memory so we don't leak.
  939. //
  940. UnmapWriteContext( pWriteContext );
  941. RETURN( Status );
  942. }
  943. //
  944. // These next three routines all perform the same type of walk and checks.
  945. // They should be combined into one walk routine and a callback.
  946. //
  947. NTSTATUS
  948. PosWavePin(
  949. PWAVEDEVICE pWaveDevice,
  950. HANDLE32 DeviceHandle,
  951. PWAVEPOSITION pWavePos
  952. )
  953. {
  954. PWAVE_PIN_INSTANCE pCurWavePin;
  955. KSAUDIO_POSITION AudioPosition;
  956. NTSTATUS Status;
  957. PAGED_CODE();
  958. Status = FindRunningPin(pWaveDevice,DeviceHandle,&pCurWavePin);
  959. if( NT_SUCCESS(Status) )
  960. {
  961. if ( pWavePos->Operation == KSPROPERTY_TYPE_SET )
  962. {
  963. AudioPosition.WriteOffset = pWavePos->BytePos;
  964. }
  965. Status = PinProperty(pCurWavePin->pFileObject,
  966. &KSPROPSETID_Audio,
  967. KSPROPERTY_AUDIO_POSITION,
  968. pWavePos->Operation,
  969. sizeof(AudioPosition),
  970. &AudioPosition);
  971. if (NT_SUCCESS(Status))
  972. {
  973. pWavePos->BytePos = (DWORD)AudioPosition.PlayOffset;
  974. }
  975. }
  976. RETURN( Status );
  977. }
  978. NTSTATUS
  979. BreakLoopWaveOutPin(
  980. PWAVEDEVICE pWaveOutDevice,
  981. HANDLE32 DeviceHandle
  982. )
  983. {
  984. PWAVE_PIN_INSTANCE pCurWavePin;
  985. NTSTATUS Status;
  986. PAGED_CODE();
  987. Status = FindRunningPin(pWaveOutDevice,DeviceHandle,&pCurWavePin);
  988. if( NT_SUCCESS(Status) )
  989. {
  990. if (pCurWavePin->fWaveQueued) {
  991. Status = PinMethod ( pCurWavePin->pFileObject,
  992. &KSMETHODSETID_Wave_Queued,
  993. KSMETHOD_WAVE_QUEUED_BREAKLOOP,
  994. KSMETHOD_TYPE_WRITE, // TODO :: change to TYPE_NONE
  995. 0,
  996. NULL ) ;
  997. }
  998. else {
  999. //
  1000. // Error out non-pcm loop related commands
  1001. //
  1002. Status = STATUS_NOT_IMPLEMENTED;
  1003. }
  1004. }
  1005. RETURN( Status );
  1006. }
  1007. NTSTATUS
  1008. ResetWaveOutPin(
  1009. PWAVEDEVICE pWaveOutDevice,
  1010. HANDLE32 DeviceHandle
  1011. )
  1012. {
  1013. PWAVE_PIN_INSTANCE pCurWavePin;
  1014. NTSTATUS Status;
  1015. KSRESET ResetValue ;
  1016. PAGED_CODE();
  1017. Status = FindRunningPin(pWaveOutDevice,DeviceHandle,&pCurWavePin);
  1018. if( NT_SUCCESS(Status))
  1019. {
  1020. pCurWavePin->StoppingSource = TRUE ;
  1021. ResetValue = KSRESET_BEGIN ;
  1022. Status = ResetWavePin(pCurWavePin, &ResetValue) ;
  1023. //
  1024. // If the driver fails to reset will will not wait for the
  1025. // Irps to complete. But, that would be bad in the
  1026. // CleanupWavePins case because we're going to free
  1027. // the memory when we return from this call. Thus,
  1028. // will choose a hang over a bugcheck and wait for
  1029. // the Irps to complete.
  1030. //
  1031. if ( pCurWavePin->NumPendingIos )
  1032. {
  1033. DPF(DL_TRACE|FA_WAVE, ("Start waiting for stop to complete"));
  1034. KeWaitForSingleObject ( &pCurWavePin->StopEvent,
  1035. Executive,
  1036. KernelMode,
  1037. FALSE,
  1038. NULL ) ;
  1039. }
  1040. DPF(DL_TRACE|FA_WAVE, ("Done waiting for stop to complete"));
  1041. ResetValue = KSRESET_END ;
  1042. ResetWavePin(pCurWavePin, &ResetValue) ;
  1043. //
  1044. // Why do we have this KeClearEvent ???
  1045. //
  1046. KeClearEvent ( &pCurWavePin->StopEvent );
  1047. pCurWavePin->StoppingSource = FALSE ;
  1048. }
  1049. RETURN( Status );
  1050. }
  1051. //
  1052. // The only difference between this and StatePin is KSPROPERTY_CONNECTION_STATE
  1053. // and IOCTL_KS_RESET_STATE. Consider using StatePin if possible.
  1054. //
  1055. NTSTATUS
  1056. ResetWavePin(
  1057. PWAVE_PIN_INSTANCE pWavePin,
  1058. KSRESET *pResetValue
  1059. )
  1060. {
  1061. NTSTATUS Status = STATUS_SUCCESS;
  1062. ULONG BytesReturned ;
  1063. PAGED_CODE();
  1064. if (!pWavePin->fGraphRunning)
  1065. {
  1066. DPF(DL_WARNING|FA_WAVE,("Invalid fGraphRunning") );
  1067. RETURN( STATUS_INVALID_DEVICE_REQUEST );
  1068. }
  1069. DPF(DL_TRACE|FA_SYSAUDIO,("IOCTL_KS_RESET_STATE pResetValue=%X",pResetValue) );
  1070. Status = KsSynchronousIoControlDevice(pWavePin->pFileObject,
  1071. KernelMode,
  1072. IOCTL_KS_RESET_STATE,
  1073. pResetValue,
  1074. sizeof(KSRESET),
  1075. NULL,
  1076. 0,
  1077. &BytesReturned);
  1078. DPF(DL_TRACE|FA_SYSAUDIO,("IOCTL_KS_RESET_STATE result=%X",Status) );
  1079. RETURN( Status );
  1080. }
  1081. //
  1082. // Looks the same, different flavor.
  1083. //
  1084. NTSTATUS
  1085. StateWavePin(
  1086. PWAVEDEVICE pWaveInDevice,
  1087. HANDLE32 DeviceHandle,
  1088. KSSTATE State
  1089. )
  1090. {
  1091. PWAVE_PIN_INSTANCE pCurWavePin;
  1092. NTSTATUS Status;
  1093. PAGED_CODE();
  1094. Status = FindRunningPin(pWaveInDevice,DeviceHandle,&pCurWavePin);
  1095. if( NT_SUCCESS(Status) )
  1096. {
  1097. if( pCurWavePin->DataFlow == KSPIN_DATAFLOW_OUT )
  1098. {
  1099. //
  1100. // We have an In pin.
  1101. //
  1102. //
  1103. // On a waveInStop, one more buffer needs to make
  1104. // it up to the application before the device can
  1105. // stop. The caveat is that if the buffer is
  1106. // large it might take awhile for the stop to happen.
  1107. //
  1108. // Don't return let this extra buffer complete if the
  1109. // device is already in a paused state.
  1110. //
  1111. if( (KSSTATE_PAUSE == State) &&
  1112. (KSSTATE_PAUSE != pCurWavePin->PinState) )
  1113. {
  1114. pCurWavePin->PausingSource = TRUE ;
  1115. if ( pCurWavePin->NumPendingIos )
  1116. {
  1117. DPF(DL_TRACE|FA_WAVE, ("Waiting for PauseEvent..."));
  1118. KeWaitForSingleObject ( &pCurWavePin->PauseEvent,
  1119. Executive,
  1120. KernelMode,
  1121. FALSE,
  1122. NULL ) ;
  1123. DPF(DL_TRACE|FA_WAVE, ("...Done waiting for PauseEvent"));
  1124. }
  1125. KeClearEvent ( &pCurWavePin->PauseEvent );
  1126. pCurWavePin->PausingSource = FALSE ;
  1127. }
  1128. Status = StatePin ( pCurWavePin->pFileObject, State, &pCurWavePin->PinState ) ;
  1129. if ( NT_SUCCESS(Status) )
  1130. {
  1131. ASSERT(pCurWavePin->PinState == State);
  1132. if ( KSSTATE_STOP == State )
  1133. {
  1134. Status = StatePin( pCurWavePin->pFileObject,KSSTATE_PAUSE,&pCurWavePin->PinState);
  1135. }
  1136. }
  1137. } else {
  1138. //
  1139. // We have an out pin.
  1140. //
  1141. Status = StatePin ( pCurWavePin->pFileObject, State, &pCurWavePin->PinState ) ;
  1142. }
  1143. }
  1144. RETURN( Status );
  1145. }
  1146. #pragma LOCKED_CODE
  1147. #pragma LOCKED_DATA
  1148. void
  1149. UnmapStreamHeader(
  1150. PSTREAM_HEADER_EX pStreamHeader
  1151. )
  1152. {
  1153. wdmaudUnmapBuffer(pStreamHeader->pBufferMdl);
  1154. wdmaudUnmapBuffer(pStreamHeader->pHeaderMdl);
  1155. AudioFreeMemory_Unknown(&pStreamHeader->pWaveHdrAligned);
  1156. AudioFreeMemory(sizeof(STREAM_HEADER_EX),&pStreamHeader);
  1157. }
  1158. void
  1159. FreeStreamHeader(
  1160. PSTREAM_HEADER_EX pStreamHeader,
  1161. NTSTATUS IrpStatus
  1162. )
  1163. {
  1164. PIRP UserIrp;
  1165. PWDMAPENDINGIRP_CONTEXT pPendingIrpContext;
  1166. UserIrp = pStreamHeader->pIrp;
  1167. ASSERT(UserIrp);
  1168. pPendingIrpContext = pStreamHeader->pPendingIrpContext;
  1169. UnmapStreamHeader( pStreamHeader );
  1170. wdmaudUnprepareIrp( UserIrp,IrpStatus,sizeof(DEVICEINFO),pPendingIrpContext );
  1171. }
  1172. //
  1173. // This is the read Irp completion routine.
  1174. //
  1175. NTSTATUS
  1176. ReadWaveCallBack(
  1177. PDEVICE_OBJECT pDeviceObject,
  1178. PIRP pIrp,
  1179. IN PSTREAM_HEADER_EX pStreamHeader
  1180. )
  1181. {
  1182. // cast the reserved field to the parent IRP that we stored in here
  1183. PWAVE_PIN_INSTANCE pCurWavePin;
  1184. NTSTATUS Status;
  1185. KIRQL OldIrql;
  1186. //
  1187. // Must get the current pin before we free the stream header structure.
  1188. //
  1189. pCurWavePin = pStreamHeader->pWavePin;
  1190. //
  1191. // Get the dataused and fill the bytes recorded field
  1192. //
  1193. if (pIrp->IoStatus.Status == STATUS_CANCELLED)
  1194. pStreamHeader->pWaveHdrAligned->dwBytesRecorded = 0L;
  1195. else
  1196. pStreamHeader->pWaveHdrAligned->dwBytesRecorded = pStreamHeader->Header.DataUsed;
  1197. //
  1198. // Copy back the contents of the captured buffer
  1199. //
  1200. try
  1201. {
  1202. RtlCopyMemory( pStreamHeader->pdwBytesRecorded,
  1203. &pStreamHeader->pWaveHdrAligned->dwBytesRecorded,
  1204. sizeof(DWORD));
  1205. }
  1206. except (EXCEPTION_EXECUTE_HANDLER)
  1207. {
  1208. DPF(DL_WARNING|FA_WAVE, ("Couldn't copy waveheader (0x%08x)", GetExceptionCode()) );
  1209. }
  1210. FreeStreamHeader( pStreamHeader, pIrp->IoStatus.Status );
  1211. if ( pCurWavePin )
  1212. {
  1213. //
  1214. // Need to lock this code so we can decrement and check and set an event
  1215. // with no preemption windows.
  1216. //
  1217. KeAcquireSpinLock(&pCurWavePin->WavePinSpinLock, &OldIrql);
  1218. //
  1219. // We always decrement NumPendingIos before doing any comparisons. This
  1220. // is so that we're consistant.
  1221. //
  1222. pCurWavePin->NumPendingIos--;
  1223. if( pCurWavePin->PausingSource )
  1224. {
  1225. //
  1226. // Let this I/O squeeze out of the queue on a waveInStop
  1227. //
  1228. KeSetEvent ( &pCurWavePin->PauseEvent, 0, FALSE ) ;
  1229. }
  1230. //
  1231. // If the count went to zero, we're the last IRP so we need to check
  1232. // to see if we need to signal any waiting thread.
  1233. //
  1234. if( (pCurWavePin->NumPendingIos == 0) && pCurWavePin->StoppingSource )
  1235. {
  1236. //
  1237. // Because we do not block (FALSE), we can call KeSetEvent in this
  1238. // Lock.
  1239. //
  1240. KeSetEvent ( &pCurWavePin->StopEvent, 0, FALSE ) ;
  1241. }
  1242. //
  1243. // Upon leaving this spinlock, pCurWavePin can be freed by the close
  1244. // routine if NumPendingIos went to zero!
  1245. //
  1246. KeReleaseSpinLock(&pCurWavePin->WavePinSpinLock, OldIrql);
  1247. }
  1248. return STATUS_SUCCESS;
  1249. }
  1250. #pragma PAGEABLE_CODE
  1251. #pragma PAGEABLE_DATA
  1252. //
  1253. // pUserIrp will always be valid when this call is made. It is the Irp
  1254. // that we got for the user mode request.
  1255. //
  1256. // pStreamHeader is alway going to be valid.
  1257. //
  1258. NTSTATUS
  1259. ReadWaveInPin(
  1260. PWAVEDEVICE pWaveInDevice,
  1261. HANDLE32 DeviceHandle,
  1262. PSTREAM_HEADER_EX pStreamHeader,
  1263. PIRP pUserIrp,
  1264. PWDMACONTEXT pContext,
  1265. BOOL *pCompletedIrp
  1266. )
  1267. {
  1268. PWAVE_PIN_INSTANCE pCurWavePin;
  1269. PWDMAPENDINGIRP_CONTEXT pPendingIrpContext;
  1270. NTSTATUS Status;
  1271. PAGED_CODE();
  1272. //
  1273. // We assumee that pCompletedIrp is FALSE on entry.
  1274. //
  1275. ASSERT( *pCompletedIrp == FALSE );
  1276. Status = FindRunningPin(pWaveInDevice,DeviceHandle,&pCurWavePin);
  1277. if( NT_SUCCESS(Status) )
  1278. {
  1279. Status = wdmaudPrepareIrp( pUserIrp, WaveInDevice, pContext, &pPendingIrpContext );
  1280. if( NT_SUCCESS(Status) )
  1281. {
  1282. pStreamHeader->pWavePin = pCurWavePin;
  1283. pStreamHeader->pPendingIrpContext = pPendingIrpContext;
  1284. ASSERT(pPendingIrpContext);
  1285. pStreamHeader->Header.OptionsFlags = 0 ;
  1286. pStreamHeader->Header.Size = sizeof( KSSTREAM_HEADER );
  1287. pStreamHeader->Header.TypeSpecificFlags = 0;
  1288. LockedWaveIoCount(pCurWavePin,INCREASE);
  1289. DPF(DL_TRACE|FA_WAVE, ("A%d: 0x%08x", pCurWavePin->NumPendingIos,
  1290. pStreamHeader));
  1291. Status = KsStreamIo(pCurWavePin->pFileObject,
  1292. NULL, // Event
  1293. NULL, // PortContext
  1294. ReadWaveCallBack,
  1295. pStreamHeader, // CompletionContext
  1296. KsInvokeOnSuccess | KsInvokeOnCancel | KsInvokeOnError,
  1297. &gIoStatusBlock,
  1298. &pStreamHeader->Header,
  1299. sizeof( KSSTREAM_HEADER ),
  1300. KSSTREAM_READ,
  1301. KernelMode );
  1302. //
  1303. // In wdmaudPrepareIrp we call IoCsqInsertIrp which calls
  1304. // IoMarkIrpPending, thus we must always return STATUS_PENDING.
  1305. // And we completed the Irp.
  1306. //
  1307. *pCompletedIrp = TRUE;
  1308. return STATUS_PENDING;
  1309. //
  1310. // Warning: If, for any reason, the completion routine is not called
  1311. // for this Irp, wdmaud.sys will hang. It's been discovered that
  1312. // KsStreamIo may error out in low memory conditions. There is an
  1313. // outstanding bug to address this.
  1314. //
  1315. } else {
  1316. //
  1317. // wdmaudPrepareIrp would have set Status for this error path
  1318. //
  1319. DPF(DL_WARNING|FA_WAVE,("wdmaudPrepareIrp failed Status=%X",Status) );
  1320. }
  1321. }
  1322. //
  1323. // All error paths lead here.
  1324. //
  1325. UnmapStreamHeader( pStreamHeader );
  1326. RETURN( Status );
  1327. }
  1328. NTSTATUS
  1329. FindVolumeControl(
  1330. IN PWDMACONTEXT pWdmaContext,
  1331. IN PCWSTR DeviceInterface,
  1332. IN DWORD DeviceType
  1333. )
  1334. {
  1335. PCOMMONDEVICE *papCommonDevice;
  1336. PWAVEDEVICE paWaveOutDevs;
  1337. PMIDIDEVICE paMidiOutDevs;
  1338. PAUXDEVICE paAuxDevs;
  1339. ULONG DeviceNumber;
  1340. ULONG MixerIndex;
  1341. NTSTATUS Status;
  1342. PAGED_CODE();
  1343. papCommonDevice = &pWdmaContext->apCommonDevice[DeviceType][0];
  1344. paWaveOutDevs = pWdmaContext->WaveOutDevs;
  1345. paMidiOutDevs = pWdmaContext->MidiOutDevs;
  1346. paAuxDevs = pWdmaContext->AuxDevs;
  1347. for( DeviceNumber = 0; DeviceNumber < MAXNUMDEVS; DeviceNumber++ ) {
  1348. if(papCommonDevice[DeviceNumber]->Device == UNUSED_DEVICE) {
  1349. continue;
  1350. }
  1351. if(MyWcsicmp(papCommonDevice[DeviceNumber]->DeviceInterface, DeviceInterface)) {
  1352. continue;
  1353. }
  1354. MixerIndex = FindMixerForDevNode(pWdmaContext->MixerDevs, DeviceInterface);
  1355. if ( (MixerIndex == UNUSED_DEVICE) || (pWdmaContext->MixerDevs[MixerIndex].pwstrName == NULL) ) {
  1356. continue;
  1357. }
  1358. switch(DeviceType) {
  1359. case WaveOutDevice:
  1360. Status = IsVolumeControl(
  1361. pWdmaContext,
  1362. DeviceInterface,
  1363. MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT,
  1364. &paWaveOutDevs[ DeviceNumber ].dwVolumeID,
  1365. &paWaveOutDevs[ DeviceNumber ].cChannels);
  1366. if(!NT_SUCCESS(Status)) {
  1367. break;
  1368. }
  1369. if( paWaveOutDevs[ DeviceNumber ].pTimer == NULL ) {
  1370. Status = AudioAllocateMemory_Fixed(sizeof(KTIMER),
  1371. TAG_AudT_TIMER,
  1372. ZERO_FILL_MEMORY,
  1373. &paWaveOutDevs[ DeviceNumber ].pTimer);
  1374. if(!NT_SUCCESS(Status)) {
  1375. return Status;
  1376. }
  1377. KeInitializeTimerEx( paWaveOutDevs[ DeviceNumber ].pTimer,
  1378. NotificationTimer
  1379. );
  1380. }
  1381. if( paWaveOutDevs[ DeviceNumber ].pDpc == NULL ) {
  1382. Status = AudioAllocateMemory_Fixed(sizeof(KDPC),
  1383. TAG_AudE_EVENT,
  1384. ZERO_FILL_MEMORY,
  1385. &paWaveOutDevs[ DeviceNumber ].pDpc);
  1386. if(!NT_SUCCESS(Status)) {
  1387. return Status;
  1388. }
  1389. KeInitializeDpc( paWaveOutDevs[ DeviceNumber ].pDpc,
  1390. SetVolumeDpc,
  1391. &paWaveOutDevs[ DeviceNumber ]
  1392. );
  1393. // Initialize the left and right channels to goofy values.
  1394. // This signifies that the cache is invalid
  1395. paWaveOutDevs[ DeviceNumber ].LeftVolume = 0x4321;
  1396. paWaveOutDevs[ DeviceNumber ].RightVolume = 0x6789;
  1397. paWaveOutDevs[ DeviceNumber ].fNeedToSetVol = FALSE;
  1398. }
  1399. break;
  1400. case MidiOutDevice:
  1401. Status = IsVolumeControl(
  1402. pWdmaContext,
  1403. DeviceInterface,
  1404. MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER,
  1405. &paMidiOutDevs[ DeviceNumber ].dwVolumeID,
  1406. &paMidiOutDevs[ DeviceNumber ].cChannels);
  1407. break;
  1408. case AuxDevice:
  1409. Status = IsVolumeControl(
  1410. pWdmaContext,
  1411. DeviceInterface,
  1412. MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC,
  1413. &paAuxDevs[ DeviceNumber ].dwVolumeID,
  1414. &paAuxDevs[ DeviceNumber ].cChannels);
  1415. break;
  1416. }
  1417. } // while
  1418. return( STATUS_SUCCESS );
  1419. }
  1420. NTSTATUS
  1421. IsVolumeControl(
  1422. IN PWDMACONTEXT pWdmaContext,
  1423. IN PCWSTR DeviceInterface,
  1424. IN DWORD dwComponentType,
  1425. IN PDWORD pdwControlID,
  1426. IN PDWORD pcChannels
  1427. )
  1428. {
  1429. MIXERLINE ml;
  1430. MIXERLINECONTROLS mlc;
  1431. MIXERCONTROL mc;
  1432. MMRESULT mmr;
  1433. PAGED_CODE();
  1434. ml.dwComponentType = dwComponentType;
  1435. ml.cbStruct = sizeof( MIXERLINE );
  1436. mmr = kmxlGetLineInfo( pWdmaContext,
  1437. DeviceInterface,
  1438. &ml,
  1439. MIXER_GETLINEINFOF_COMPONENTTYPE
  1440. );
  1441. if( mmr != MMSYSERR_NOERROR ) {
  1442. DPF(DL_WARNING|FA_WAVE,("kmxlGetLineInfo failed mmr=%X",mmr) );
  1443. RETURN( STATUS_UNSUCCESSFUL );
  1444. }
  1445. mlc.cbStruct = sizeof( MIXERLINECONTROLS );
  1446. mlc.dwLineID = ml.dwLineID;
  1447. mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
  1448. mlc.cControls = 1;
  1449. mlc.cbmxctrl = sizeof( MIXERCONTROL );
  1450. mlc.pamxctrl = &mc;
  1451. mmr = kmxlGetLineControls(
  1452. pWdmaContext,
  1453. DeviceInterface,
  1454. &mlc,
  1455. MIXER_GETLINECONTROLSF_ONEBYTYPE
  1456. );
  1457. if( mmr != MMSYSERR_NOERROR ) {
  1458. DPF(DL_WARNING|FA_WAVE,( "kmxlGetLineControls failed mmr=%x!", mmr ) );
  1459. return( STATUS_UNSUCCESSFUL );
  1460. }
  1461. *pdwControlID = mc.dwControlID;
  1462. *pcChannels = ml.cChannels;
  1463. return( STATUS_SUCCESS );
  1464. }
  1465. #pragma LOCKED_CODE
  1466. NTSTATUS
  1467. MapMmSysError(
  1468. IN MMRESULT mmr
  1469. )
  1470. {
  1471. if ( (mmr == MMSYSERR_INVALPARAM) ||
  1472. (mmr == MIXERR_INVALCONTROL) ) {
  1473. return (STATUS_INVALID_PARAMETER);
  1474. }
  1475. if (mmr == MMSYSERR_NOTSUPPORTED) {
  1476. return (STATUS_NOT_SUPPORTED);
  1477. }
  1478. if (mmr == MMSYSERR_NOMEM) {
  1479. return(STATUS_INSUFFICIENT_RESOURCES);
  1480. }
  1481. if (mmr == MMSYSERR_NOERROR) {
  1482. return(STATUS_SUCCESS);
  1483. }
  1484. return(STATUS_UNSUCCESSFUL);
  1485. }
  1486. NTSTATUS
  1487. SetVolume(
  1488. PWDMACONTEXT pWdmaContext,
  1489. IN DWORD DeviceNumber,
  1490. IN DWORD DeviceType,
  1491. IN DWORD LeftChannel,
  1492. IN DWORD RightChannel
  1493. )
  1494. {
  1495. MIXERCONTROLDETAILS mcd;
  1496. MIXERCONTROLDETAILS_UNSIGNED mcd_u[ 2 ];
  1497. LARGE_INTEGER li;
  1498. if( DeviceNumber == (ULONG) -1 ) {
  1499. RETURN( STATUS_INVALID_PARAMETER );
  1500. }
  1501. if( DeviceType == WaveOutDevice ) {
  1502. PWAVEDEVICE paWaveOutDevs = pWdmaContext->WaveOutDevs;
  1503. mcd_u[ 0 ].dwValue = LeftChannel;
  1504. mcd_u[ 1 ].dwValue = RightChannel;
  1505. mcd.cbStruct = sizeof( MIXERCONTROLDETAILS );
  1506. mcd.dwControlID = paWaveOutDevs[ DeviceNumber ].dwVolumeID;
  1507. mcd.cChannels = paWaveOutDevs[ DeviceNumber ].cChannels;
  1508. mcd.cMultipleItems = 0;
  1509. mcd.cbDetails = mcd.cChannels *
  1510. sizeof( MIXERCONTROLDETAILS_UNSIGNED );
  1511. mcd.paDetails = &mcd_u[0];
  1512. return( MapMmSysError(kmxlSetControlDetails( pWdmaContext,
  1513. paWaveOutDevs[ DeviceNumber ].DeviceInterface,
  1514. &mcd,
  1515. 0
  1516. ))
  1517. );
  1518. }
  1519. if( DeviceType == MidiOutDevice ) {
  1520. PMIDIDEVICE paMidiOutDevs = pWdmaContext->MidiOutDevs;
  1521. //
  1522. // We don't support volume changes on a MIDIPORT
  1523. //
  1524. if ( paMidiOutDevs[ DeviceNumber ].MusicDataRanges ) {
  1525. WORD wTechnology;
  1526. wTechnology = GetMidiTechnology( (PKSDATARANGE_MUSIC)
  1527. &paMidiOutDevs[ DeviceNumber ].MusicDataRanges->aDataRanges[0] );
  1528. if (wTechnology == MOD_MIDIPORT) {
  1529. RETURN( STATUS_INVALID_DEVICE_REQUEST );
  1530. }
  1531. }
  1532. mcd_u[ 0 ].dwValue = LeftChannel;
  1533. mcd_u[ 1 ].dwValue = RightChannel;
  1534. mcd.cbStruct = sizeof( MIXERCONTROLDETAILS );
  1535. mcd.dwControlID = paMidiOutDevs[ DeviceNumber ].dwVolumeID;
  1536. mcd.cChannels = paMidiOutDevs[ DeviceNumber ].cChannels;
  1537. mcd.cMultipleItems = 0;
  1538. mcd.cbDetails = mcd.cChannels *
  1539. sizeof( MIXERCONTROLDETAILS_UNSIGNED );
  1540. mcd.paDetails = &mcd_u[0];
  1541. return( MapMmSysError(kmxlSetControlDetails( pWdmaContext,
  1542. paMidiOutDevs[ DeviceNumber ].DeviceInterface,
  1543. &mcd,
  1544. 0
  1545. ))
  1546. );
  1547. }
  1548. if( DeviceType == AuxDevice ) {
  1549. PAUXDEVICE paAuxDevs = pWdmaContext->AuxDevs;
  1550. mcd_u[ 0 ].dwValue = LeftChannel;
  1551. mcd_u[ 1 ].dwValue = RightChannel;
  1552. mcd.cbStruct = sizeof( MIXERCONTROLDETAILS );
  1553. mcd.dwControlID = paAuxDevs[ DeviceNumber ].dwVolumeID;
  1554. mcd.cChannels = paAuxDevs[ DeviceNumber ].cChannels;
  1555. mcd.cMultipleItems = 0;
  1556. mcd.cbDetails = mcd.cChannels *
  1557. sizeof( MIXERCONTROLDETAILS_UNSIGNED );
  1558. mcd.paDetails = &mcd_u[0];
  1559. return( MapMmSysError(kmxlSetControlDetails( pWdmaContext,
  1560. paAuxDevs[ DeviceNumber ].DeviceInterface,
  1561. &mcd,
  1562. 0
  1563. ))
  1564. );
  1565. }
  1566. return( STATUS_SUCCESS );
  1567. }
  1568. VOID
  1569. SetVolumeDpc(
  1570. IN PKDPC pDpc,
  1571. IN PWAVEDEVICE pWaveDevice,
  1572. IN PVOID SystemArgument1,
  1573. IN PVOID SystemArgument2
  1574. )
  1575. {
  1576. QueueWorkList(pWaveDevice->pWdmaContext, SetVolumeWorker, pWaveDevice, NULL ) ;
  1577. }
  1578. VOID
  1579. SetVolumeWorker(
  1580. IN PWAVEDEVICE pDevice,
  1581. IN PVOID pNotUsed
  1582. )
  1583. {
  1584. MIXERCONTROLDETAILS mcd;
  1585. MIXERCONTROLDETAILS_UNSIGNED mcd_u[ 2 ];
  1586. DPF(DL_TRACE|FA_WAVE,( "Left %X Right %X",
  1587. pDevice->LeftVolume,
  1588. pDevice->RightVolume ) );
  1589. pDevice->fNeedToSetVol = FALSE;
  1590. mcd_u[ 0 ].dwValue = pDevice->LeftVolume;
  1591. mcd_u[ 1 ].dwValue = pDevice->RightVolume;
  1592. mcd.cbStruct = sizeof( MIXERCONTROLDETAILS );
  1593. mcd.dwControlID = pDevice->dwVolumeID;
  1594. mcd.cChannels = pDevice->cChannels;
  1595. mcd.cMultipleItems = 0;
  1596. mcd.cbDetails = mcd.cChannels * sizeof( MIXERCONTROLDETAILS_UNSIGNED );
  1597. mcd.paDetails = &mcd_u[0];
  1598. kmxlSetControlDetails( pDevice->pWdmaContext,
  1599. pDevice->DeviceInterface,
  1600. &mcd,
  1601. 0
  1602. );
  1603. }
  1604. #pragma PAGEABLE_CODE
  1605. NTSTATUS
  1606. GetVolume(
  1607. IN PWDMACONTEXT pWdmaContext,
  1608. IN DWORD DeviceNumber,
  1609. IN DWORD DeviceType,
  1610. OUT PDWORD LeftChannel,
  1611. OUT PDWORD RightChannel
  1612. )
  1613. {
  1614. MIXERCONTROLDETAILS mcd;
  1615. MIXERCONTROLDETAILS_UNSIGNED mcd_u[ 2 ];
  1616. MMRESULT mmr;
  1617. PAGED_CODE();
  1618. if( DeviceType == WaveOutDevice ) {
  1619. PWAVEDEVICE pWaveOutDevice = &pWdmaContext->WaveOutDevs[DeviceNumber];
  1620. if( ( pWaveOutDevice->LeftVolume != 0x4321 ) &&
  1621. ( pWaveOutDevice->RightVolume != 0x6789 ) ) {
  1622. *LeftChannel = pWaveOutDevice->LeftVolume;
  1623. *RightChannel = pWaveOutDevice->RightVolume;
  1624. return( STATUS_SUCCESS );
  1625. } else {
  1626. mcd.cbStruct = sizeof( MIXERCONTROLDETAILS );
  1627. mcd.dwControlID = pWaveOutDevice->dwVolumeID;
  1628. mcd.cChannels = pWaveOutDevice->cChannels;
  1629. mcd.cMultipleItems = 0;
  1630. mcd.cbDetails = mcd.cChannels *
  1631. sizeof( MIXERCONTROLDETAILS_UNSIGNED );
  1632. mcd.paDetails = &mcd_u[0];
  1633. mmr = kmxlGetControlDetails( pWdmaContext,
  1634. pWaveOutDevice->DeviceInterface,
  1635. &mcd,
  1636. 0 );
  1637. if( mmr == MMSYSERR_NOERROR )
  1638. {
  1639. *LeftChannel = mcd_u[ 0 ].dwValue;
  1640. *RightChannel = mcd_u[ 1 ].dwValue;
  1641. }
  1642. return( MapMmSysError(mmr) );
  1643. }
  1644. }
  1645. if( DeviceType == MidiOutDevice ) {
  1646. PMIDIDEVICE pMidiOutDevice = &pWdmaContext->MidiOutDevs[DeviceNumber];
  1647. //
  1648. // We don't support volume changes on a MIDIPORT
  1649. //
  1650. if ( pMidiOutDevice->MusicDataRanges ) {
  1651. WORD wTechnology;
  1652. wTechnology = GetMidiTechnology( (PKSDATARANGE_MUSIC)
  1653. &pMidiOutDevice->MusicDataRanges->aDataRanges[0] );
  1654. if (wTechnology == MOD_MIDIPORT) {
  1655. RETURN( STATUS_INVALID_DEVICE_REQUEST );
  1656. }
  1657. }
  1658. mcd.cbStruct = sizeof( MIXERCONTROLDETAILS );
  1659. mcd.dwControlID = pMidiOutDevice->dwVolumeID;
  1660. mcd.cChannels = pMidiOutDevice->cChannels;
  1661. mcd.cMultipleItems = 0;
  1662. mcd.cbDetails = mcd.cChannels *
  1663. sizeof( MIXERCONTROLDETAILS_UNSIGNED );
  1664. mcd.paDetails = &mcd_u[0];
  1665. mmr = kmxlGetControlDetails( pWdmaContext,
  1666. pMidiOutDevice->DeviceInterface,
  1667. &mcd,
  1668. 0 );
  1669. if( mmr == MMSYSERR_NOERROR )
  1670. {
  1671. *LeftChannel = mcd_u[ 0 ].dwValue;
  1672. *RightChannel = mcd_u[ 1 ].dwValue;
  1673. }
  1674. return( MapMmSysError(mmr) );
  1675. }
  1676. if( DeviceType == AuxDevice ) {
  1677. PAUXDEVICE pAuxDevice = &pWdmaContext->AuxDevs[DeviceNumber];
  1678. mcd.cbStruct = sizeof( MIXERCONTROLDETAILS );
  1679. mcd.dwControlID = pAuxDevice->dwVolumeID;
  1680. mcd.cChannels = pAuxDevice->cChannels;
  1681. mcd.cMultipleItems = 0;
  1682. mcd.cbDetails = mcd.cChannels *
  1683. sizeof( MIXERCONTROLDETAILS_UNSIGNED );
  1684. mcd.paDetails = &mcd_u[0];
  1685. mmr = kmxlGetControlDetails( pWdmaContext,
  1686. pAuxDevice->DeviceInterface,
  1687. &mcd,
  1688. 0 );
  1689. if( mmr == MMSYSERR_NOERROR )
  1690. {
  1691. *LeftChannel = mcd_u[ 0 ].dwValue;
  1692. *RightChannel = mcd_u[ 1 ].dwValue;
  1693. }
  1694. return( MapMmSysError(mmr) );
  1695. }
  1696. RETURN( STATUS_INVALID_PARAMETER );
  1697. }
  1698. //
  1699. // This routine waits for the Io to complete on the device after telling
  1700. // the device to stop.
  1701. //
  1702. VOID
  1703. WaitForOutStandingIo(
  1704. IN PWAVEDEVICE pWaveDevice,
  1705. IN PWAVE_PIN_INSTANCE pCurWavePin
  1706. )
  1707. {
  1708. if( pCurWavePin->DataFlow == KSPIN_DATAFLOW_IN)
  1709. {
  1710. //
  1711. // We have a wave out pin to close. Force pending data
  1712. // to come back on running pins. Non-running pins are
  1713. // ignored on this call.
  1714. //
  1715. ResetWaveOutPin( pWaveDevice, pCurWavePin->WaveHandle);
  1716. } else {
  1717. //
  1718. // We have a wave in pin to close
  1719. //
  1720. pCurWavePin->StoppingSource = TRUE ;
  1721. //
  1722. // We can not fail on this path. Doesn't look like we need to make sure
  1723. // that we're running here.
  1724. //
  1725. StatePin ( pCurWavePin->pFileObject, KSSTATE_STOP, &pCurWavePin->PinState ) ;
  1726. //
  1727. // Regardless of the return code we're going to wait for all the
  1728. // irps to complete. If the driver do not successfuly complete
  1729. // the irps, we will hang waiting for them here.
  1730. //
  1731. if( pCurWavePin->NumPendingIos )
  1732. {
  1733. KeWaitForSingleObject ( &pCurWavePin->StopEvent,
  1734. Executive,
  1735. KernelMode,
  1736. FALSE,
  1737. NULL ) ;
  1738. }
  1739. //
  1740. // Why do we have this KeClearEvent???
  1741. //
  1742. KeClearEvent ( &pCurWavePin->StopEvent );
  1743. pCurWavePin->StoppingSource = FALSE ;
  1744. }
  1745. }
  1746. //
  1747. // Replaces CleanupWaveOutPins and CleanupWaveInPins.
  1748. //
  1749. VOID
  1750. CleanupWavePins(
  1751. IN PWAVEDEVICE pWaveDevice
  1752. )
  1753. {
  1754. PWAVE_PIN_INSTANCE pCurWavePin;
  1755. PWAVE_PIN_INSTANCE pFreeWavePin;
  1756. PAGED_CODE();
  1757. while (pCurWavePin = pWaveDevice->pWavePin)
  1758. {
  1759. DPF(DL_TRACE|FA_WAVE, ("0x%08x", pCurWavePin));
  1760. WaitForOutStandingIo(pWaveDevice,pCurWavePin);
  1761. CloseWavePin( pCurWavePin );
  1762. pFreeWavePin = pCurWavePin;
  1763. pWaveDevice->pWavePin = pCurWavePin->Next;
  1764. AudioFreeMemory( sizeof(WAVE_PIN_INSTANCE),&pFreeWavePin );
  1765. }
  1766. }
  1767. VOID
  1768. CleanupWaveDevices(
  1769. IN PWDMACONTEXT pWdmaContext
  1770. )
  1771. {
  1772. DWORD DeviceNumber;
  1773. PAGED_CODE();
  1774. for (DeviceNumber = 0; DeviceNumber < MAXNUMDEVS; DeviceNumber++)
  1775. {
  1776. //
  1777. // Handle waveout devices first...
  1778. //
  1779. if (pWdmaContext->apCommonDevice[WaveOutDevice][DeviceNumber]->Device != UNUSED_DEVICE)
  1780. {
  1781. if ( pWdmaContext->WaveOutDevs[DeviceNumber].pTimer != NULL)
  1782. KeCancelTimer(pWdmaContext->WaveOutDevs[DeviceNumber].pTimer);
  1783. CleanupWavePins(&pWdmaContext->WaveOutDevs[DeviceNumber]);
  1784. //
  1785. // Sense we have removed it from the list, the other routine that would do
  1786. // the same thing (RemoveDevNode) will also attempt to remove it from the
  1787. // the list because the value it non-null. Thus, the only safe thing that
  1788. // we can do here is free the memory.
  1789. //
  1790. // Note: This routine will only get called when the handle to the driver is
  1791. // closed.
  1792. //
  1793. AudioFreeMemory_Unknown(&pWdmaContext->WaveOutDevs[DeviceNumber].pTimer);
  1794. }
  1795. //
  1796. // ...then handle wavein devices
  1797. //
  1798. if (pWdmaContext->apCommonDevice[WaveInDevice][DeviceNumber]->Device != UNUSED_DEVICE)
  1799. {
  1800. CleanupWavePins(&pWdmaContext->WaveInDevs[DeviceNumber]);
  1801. }
  1802. }
  1803. }
  1804. #pragma LOCKED_CODE
  1805. #pragma LOCKED_DATA
  1806. //
  1807. // --------------------------------------------------------------------------------
  1808. //
  1809. // The following routines are used by more then just wave.c
  1810. //
  1811. // --------------------------------------------------------------------------------
  1812. //
  1813. NTSTATUS
  1814. wdmaudPrepareIrp(
  1815. PIRP pIrp,
  1816. ULONG IrpDeviceType,
  1817. PWDMACONTEXT pContext,
  1818. PWDMAPENDINGIRP_CONTEXT *ppPendingIrpContext
  1819. )
  1820. {
  1821. return AddIrpToPendingList( pIrp,
  1822. IrpDeviceType,
  1823. pContext,
  1824. ppPendingIrpContext );
  1825. }
  1826. NTSTATUS
  1827. wdmaudUnprepareIrp(
  1828. PIRP pIrp,
  1829. NTSTATUS IrpStatus,
  1830. ULONG_PTR Information,
  1831. PWDMAPENDINGIRP_CONTEXT pPendingIrpContext
  1832. )
  1833. {
  1834. NTSTATUS Status;
  1835. // Note that the IrpContext may have been zero'ed out already because the cancel
  1836. // routine has already been called. The cancel safe queue API zeroes out the Irp
  1837. // field in the context when it performs a cancel.
  1838. Status = RemoveIrpFromPendingList( pPendingIrpContext );
  1839. if (NT_SUCCESS(Status)) {
  1840. pIrp->IoStatus.Status = IrpStatus;
  1841. if (Information) {
  1842. pIrp->IoStatus.Information = Information;
  1843. }
  1844. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  1845. }
  1846. RETURN( Status );
  1847. }
  1848. #pragma PAGEABLE_CODE
  1849. #pragma PAGEABLE_DATA
  1850. //
  1851. // StatePin - This is used by both Midi and Wave functionality.
  1852. //
  1853. // On success State will get updated to the new state. Must make sure that
  1854. // fGraphRunning is TRUE before calling this routine.
  1855. //
  1856. // call like:
  1857. // if( pWavePin->fGraphRunning )
  1858. // StatePin(pWavePin->pFileObject, KSSTATE_PAUSE, &pWavePin->State);
  1859. //
  1860. NTSTATUS
  1861. StatePin(
  1862. IN PFILE_OBJECT pFileObject,
  1863. IN KSSTATE State,
  1864. OUT PKSSTATE pResultingState
  1865. )
  1866. {
  1867. NTSTATUS Status;
  1868. PAGED_CODE();
  1869. Status = PinProperty(pFileObject,
  1870. &KSPROPSETID_Connection,
  1871. KSPROPERTY_CONNECTION_STATE,
  1872. KSPROPERTY_TYPE_SET,
  1873. sizeof(State),
  1874. &State);
  1875. if(NT_SUCCESS(Status))
  1876. {
  1877. *pResultingState = State;
  1878. }
  1879. RETURN( Status );
  1880. }