Leaked source code of windows server 2003
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.

3539 lines
122 KiB

  1. /****************************************************************************
  2. *
  3. * ioctl.c
  4. *
  5. * DeviceIoControl communication interface between 32-bit wdmaud.drv
  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. #include <devioctl.h>
  17. extern ULONG gWavePreferredSysaudioDevice;
  18. #pragma LOCKED_CODE
  19. #pragma LOCKED_DATA
  20. WDMAPENDINGIRP_QUEUE wdmaPendingIrpQueue;
  21. #ifdef PROFILE
  22. LIST_ENTRY WdmaAllocatedMdlListHead;
  23. KSPIN_LOCK WdmaAllocatedMdlListSpinLock;
  24. // Initialize the List Heads and Mutexes in order to track resources
  25. VOID WdmaInitProfile()
  26. {
  27. InitializeListHead(&WdmaAllocatedMdlListHead);
  28. KeInitializeSpinLock(&WdmaAllocatedMdlListSpinLock);
  29. }
  30. NTSTATUS AddMdlToList
  31. (
  32. PMDL pMdl,
  33. PWDMACONTEXT pWdmaContext
  34. )
  35. {
  36. PALLOCATED_MDL_LIST_ITEM pAllocatedMdlListItem = NULL;
  37. NTSTATUS Status;
  38. Status = AudioAllocateMemory_Fixed(sizeof(*pAllocatedMdlListItem),
  39. TAG_AudM_MDL,
  40. ZERO_FILL_MEMORY,
  41. &pAllocatedMdlListItem);
  42. if (NT_SUCCESS(Status))
  43. {
  44. pAllocatedMdlListItem->pMdl = pMdl;
  45. pAllocatedMdlListItem->pContext = pWdmaContext;
  46. ExInterlockedInsertTailList(&WdmaAllocatedMdlListHead,
  47. &pAllocatedMdlListItem->Next,
  48. &WdmaAllocatedMdlListSpinLock);
  49. }
  50. RETURN( Status );
  51. }
  52. NTSTATUS RemoveMdlFromList
  53. (
  54. PMDL pMdl
  55. )
  56. {
  57. PLIST_ENTRY ple;
  58. PALLOCATED_MDL_LIST_ITEM pAllocatedMdlListItem;
  59. KIRQL OldIrql;
  60. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  61. ExAcquireSpinLock(&WdmaAllocatedMdlListSpinLock, &OldIrql);
  62. for(ple = WdmaAllocatedMdlListHead.Flink;
  63. ple != &WdmaAllocatedMdlListHead;
  64. ple = ple->Flink)
  65. {
  66. pAllocatedMdlListItem = CONTAINING_RECORD(ple, ALLOCATED_MDL_LIST_ITEM, Next);
  67. if (pAllocatedMdlListItem->pMdl == pMdl)
  68. {
  69. RemoveEntryList(&pAllocatedMdlListItem->Next);
  70. AudioFreeMemory(sizeof(*pAllocatedMdlListItem),&pAllocatedMdlListItem);
  71. Status = STATUS_SUCCESS;
  72. break;
  73. }
  74. }
  75. ExReleaseSpinLock(&WdmaAllocatedMdlListSpinLock, OldIrql);
  76. RETURN( Status );
  77. }
  78. #endif
  79. VOID WdmaCsqInsertIrp
  80. (
  81. IN struct _IO_CSQ *Csq,
  82. IN PIRP Irp
  83. )
  84. {
  85. PWDMAPENDINGIRP_QUEUE PendingIrpQueue = CONTAINING_RECORD(Csq, WDMAPENDINGIRP_QUEUE, Csq);
  86. InsertTailList(&PendingIrpQueue->WdmaPendingIrpListHead,
  87. &Irp->Tail.Overlay.ListEntry);
  88. }
  89. VOID WdmaCsqRemoveIrp
  90. (
  91. IN PIO_CSQ Csq,
  92. IN PIRP Irp
  93. )
  94. {
  95. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  96. }
  97. PIRP WdmaCsqPeekNextIrp
  98. (
  99. IN PIO_CSQ Csq,
  100. IN PIRP Irp,
  101. IN PVOID PeekContext
  102. )
  103. {
  104. PWDMAPENDINGIRP_QUEUE PendingIrpQueue = CONTAINING_RECORD(Csq, WDMAPENDINGIRP_QUEUE, Csq);
  105. PIRP nextIrp;
  106. PLIST_ENTRY listEntry;
  107. if (Irp == NULL) {
  108. listEntry = PendingIrpQueue->WdmaPendingIrpListHead.Flink;
  109. if (listEntry == &PendingIrpQueue->WdmaPendingIrpListHead) {
  110. DPF(DL_TRACE|FA_IOCTL, ("Irp is NULL, queue is empty"));
  111. return NULL;
  112. }
  113. nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
  114. DPF(DL_TRACE|FA_IOCTL, ("Irp is NULL, nextIrp %x", nextIrp));
  115. return nextIrp;
  116. }
  117. listEntry = Irp->Tail.Overlay.ListEntry.Flink;
  118. //
  119. // Enumerated to end of queue.
  120. //
  121. if (listEntry == &PendingIrpQueue->WdmaPendingIrpListHead) {
  122. DPF(DL_TRACE|FA_IOCTL, ("End of queue reached Irp %x", Irp));
  123. return NULL;
  124. }
  125. nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
  126. return nextIrp;
  127. }
  128. VOID WdmaCsqAcquireLock
  129. (
  130. IN PIO_CSQ Csq,
  131. OUT PKIRQL Irql
  132. )
  133. {
  134. PWDMAPENDINGIRP_QUEUE PendingIrpQueue = CONTAINING_RECORD(Csq, WDMAPENDINGIRP_QUEUE, Csq);
  135. KeAcquireSpinLock(&PendingIrpQueue->WdmaPendingIrpListSpinLock, Irql);
  136. }
  137. VOID WdmaCsqReleaseLock
  138. (
  139. IN PIO_CSQ Csq,
  140. IN KIRQL Irql
  141. )
  142. {
  143. PWDMAPENDINGIRP_QUEUE PendingIrpQueue = CONTAINING_RECORD(Csq, WDMAPENDINGIRP_QUEUE, Csq);
  144. KeReleaseSpinLock(&PendingIrpQueue->WdmaPendingIrpListSpinLock, Irql);
  145. }
  146. VOID WdmaCsqCompleteCanceledIrp
  147. (
  148. IN PIO_CSQ pCsq,
  149. IN PIRP Irp
  150. )
  151. {
  152. Irp->IoStatus.Status = STATUS_CANCELLED;
  153. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  154. }
  155. NTSTATUS AddIrpToPendingList
  156. (
  157. PIRP pIrp,
  158. ULONG IrpDeviceType,
  159. PWDMACONTEXT pWdmaContext,
  160. PWDMAPENDINGIRP_CONTEXT *ppPendingIrpContext
  161. )
  162. {
  163. PWDMAPENDINGIRP_CONTEXT pPendingIrpContext = NULL;
  164. NTSTATUS Status;
  165. Status = AudioAllocateMemory_Fixed(sizeof(*pPendingIrpContext),
  166. TAG_AudR_IRP,
  167. ZERO_FILL_MEMORY,
  168. &pPendingIrpContext);
  169. if (NT_SUCCESS(Status))
  170. {
  171. *ppPendingIrpContext = pPendingIrpContext;
  172. pPendingIrpContext->IrpDeviceType = IrpDeviceType;
  173. pPendingIrpContext->pContext = pWdmaContext;
  174. IoCsqInsertIrp(&wdmaPendingIrpQueue.Csq,
  175. pIrp,
  176. &pPendingIrpContext->IrpContext);
  177. }
  178. RETURN( Status );
  179. }
  180. NTSTATUS RemoveIrpFromPendingList
  181. (
  182. PWDMAPENDINGIRP_CONTEXT pPendingIrpContext
  183. )
  184. {
  185. PIO_CSQ_IRP_CONTEXT irpContext = &(pPendingIrpContext->IrpContext);
  186. PIRP Irp;
  187. NTSTATUS Status;
  188. Irp = IoCsqRemoveIrp(&wdmaPendingIrpQueue.Csq, irpContext);
  189. if (Irp) {
  190. Status = STATUS_SUCCESS;
  191. }
  192. else {
  193. Status = STATUS_UNSUCCESSFUL;
  194. }
  195. AudioFreeMemory(sizeof(*pPendingIrpContext),&irpContext);
  196. RETURN( Status );
  197. }
  198. /****************************************************************************
  199. * @doc INTERNAL
  200. *
  201. * @api BOOL | IsSysaudioInterfaceActive | Checks to see if the sysaudio
  202. * device interface is active.
  203. *
  204. * @rdesc returns TRUE if sysaudio has been found, otherwise FALSE
  205. ***************************************************************************/
  206. BOOL IsSysaudioInterfaceActive()
  207. {
  208. NTSTATUS Status;
  209. PWSTR pwstrSymbolicLinkList = NULL;
  210. BOOL bRet = FALSE;
  211. Status = IoGetDeviceInterfaces(
  212. &KSCATEGORY_SYSAUDIO,
  213. NULL,
  214. 0,
  215. &pwstrSymbolicLinkList);
  216. if (NT_SUCCESS(Status))
  217. {
  218. if (*pwstrSymbolicLinkList != UNICODE_NULL)
  219. {
  220. DPF(DL_TRACE|FA_IOCTL, ("yes"));
  221. bRet = TRUE;
  222. }
  223. AudioFreeMemory_Unknown(&pwstrSymbolicLinkList);
  224. } else {
  225. DPF(DL_WARNING|FA_IOCTL,("IoGetDeviceInterface failed Statue=%08X",Status) );
  226. }
  227. DPF(DL_TRACE|FA_IOCTL, ("No"));
  228. return bRet;
  229. }
  230. PVOID
  231. GetSystemAddressForMdlWithFailFlag
  232. (
  233. PMDL pMdl
  234. )
  235. {
  236. PVOID pAddress;
  237. CSHORT OldFlags;
  238. OldFlags = (pMdl->MdlFlags & MDL_MAPPING_CAN_FAIL);
  239. pMdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
  240. pAddress = MmGetSystemAddressForMdl( pMdl ) ;
  241. pMdl->MdlFlags &= ~(MDL_MAPPING_CAN_FAIL);
  242. pMdl->MdlFlags |= OldFlags;
  243. return pAddress;
  244. }
  245. /****************************************************************************
  246. * @doc INTERNAL
  247. *
  248. * @api VOID | wdmaudMapBuffer | Allocates an MDL and returns a system address
  249. * mapped pointer to the passed in buffer.
  250. *
  251. * @rdesc returns nothing
  252. ***************************************************************************/
  253. VOID wdmaudMapBuffer
  254. (
  255. IN PIRP pIrp,
  256. IN PVOID DataBuffer,
  257. IN DWORD DataBufferSize,
  258. OUT PVOID *ppMappedBuffer,
  259. OUT PMDL *ppMdl,
  260. IN PWDMACONTEXT pContext,
  261. IN BOOL bWrite
  262. )
  263. {
  264. NTSTATUS ListAddStatus = STATUS_UNSUCCESSFUL;
  265. // Make sure that these are initialized to NULL
  266. *ppMdl = NULL;
  267. *ppMappedBuffer = NULL;
  268. if (DataBuffer)
  269. {
  270. if (DataBufferSize)
  271. {
  272. *ppMdl = MmCreateMdl( NULL,
  273. DataBuffer,
  274. DataBufferSize );
  275. if (*ppMdl)
  276. {
  277. try
  278. {
  279. MmProbeAndLockPages( *ppMdl,
  280. pIrp->RequestorMode,
  281. bWrite ? IoWriteAccess:IoReadAccess );
  282. *ppMappedBuffer = GetSystemAddressForMdlWithFailFlag( *ppMdl ) ;
  283. ListAddStatus = AddMdlToList(*ppMdl, pContext);
  284. }
  285. except (EXCEPTION_EXECUTE_HANDLER)
  286. {
  287. if (NT_SUCCESS(ListAddStatus))
  288. {
  289. RemoveMdlFromList( *ppMdl );
  290. }
  291. IoFreeMdl( *ppMdl );
  292. *ppMdl = NULL;
  293. *ppMappedBuffer = NULL;
  294. }
  295. }
  296. //
  297. // Must have failed in GetSystemAddressForMdlWithFailFlag, but since we set the
  298. // MDL_MAPPING_CAN_FAIL flag our exception handler won't get executed. Do the
  299. // cleanup here for the MDL creation.
  300. //
  301. if (NULL == *ppMappedBuffer)
  302. {
  303. if (NT_SUCCESS(ListAddStatus))
  304. {
  305. RemoveMdlFromList( *ppMdl );
  306. }
  307. if (*ppMdl)
  308. {
  309. MmUnlockPages(*ppMdl);
  310. IoFreeMdl( *ppMdl );
  311. *ppMdl = NULL;
  312. }
  313. }
  314. }
  315. }
  316. return;
  317. }
  318. /****************************************************************************
  319. * @doc INTERNAL
  320. *
  321. * @api VOID | wdmaudUnmapBuffer | Frees the MDL allocated by wdmaudMapBuffer
  322. *
  323. * @parm PMDL | pMdl | Pointer to the MDL to free.
  324. *
  325. * @rdesc returns nothing
  326. ***************************************************************************/
  327. VOID wdmaudUnmapBuffer
  328. (
  329. PMDL pMdl
  330. )
  331. {
  332. if (pMdl)
  333. {
  334. RemoveMdlFromList(pMdl);
  335. MmUnlockPages(pMdl);
  336. IoFreeMdl(pMdl);
  337. }
  338. return;
  339. }
  340. NTSTATUS
  341. CaptureBufferToLocalPool(
  342. PVOID DataBuffer,
  343. DWORD DataBufferSize,
  344. PVOID *ppMappedBuffer
  345. #ifdef _WIN64
  346. ,DWORD ThunkBufferSize
  347. #endif
  348. )
  349. {
  350. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  351. DWORD CopySize=DataBufferSize;
  352. #ifdef _WIN64
  353. if (ThunkBufferSize) {
  354. DataBufferSize=ThunkBufferSize;
  355. ASSERT( DataBufferSize >= CopySize );
  356. }
  357. #endif
  358. if (DataBufferSize)
  359. {
  360. Status = AudioAllocateMemory_Fixed(DataBufferSize,
  361. TAG_AudB_BUFFER,
  362. ZERO_FILL_MEMORY,
  363. ppMappedBuffer);
  364. if (NT_SUCCESS(Status))
  365. {
  366. // Wrap around a try/except because the user mode memory
  367. // might have been removed from underneath us.
  368. try
  369. {
  370. RtlCopyMemory( *ppMappedBuffer,
  371. DataBuffer,
  372. CopySize);
  373. }
  374. except (EXCEPTION_EXECUTE_HANDLER)
  375. {
  376. AudioFreeMemory(DataBufferSize,ppMappedBuffer);
  377. Status = GetExceptionCode();
  378. }
  379. }
  380. }
  381. RETURN( Status );
  382. }
  383. NTSTATUS
  384. CopyAndFreeCapturedBuffer(
  385. PVOID DataBuffer,
  386. DWORD DataBufferSize,
  387. PVOID *ppMappedBuffer
  388. )
  389. {
  390. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  391. ASSERT(DataBuffer);
  392. if (*ppMappedBuffer)
  393. {
  394. // Wrap around a try/except because the user mode memory
  395. // might have been removed from underneath us.
  396. try
  397. {
  398. RtlCopyMemory( DataBuffer,
  399. *ppMappedBuffer,
  400. DataBufferSize);
  401. Status = STATUS_SUCCESS;
  402. }
  403. except (EXCEPTION_EXECUTE_HANDLER)
  404. {
  405. Status = GetExceptionCode();
  406. }
  407. AudioFreeMemory_Unknown(ppMappedBuffer);
  408. }
  409. RETURN( Status );
  410. }
  411. #pragma PAGEABLE_CODE
  412. #pragma PAGEABLE_DATA
  413. NTSTATUS
  414. SoundDispatchCreate(
  415. IN PDEVICE_OBJECT pDO,
  416. IN PIRP pIrp
  417. )
  418. {
  419. PIO_STACK_LOCATION pIrpStack;
  420. PWDMACONTEXT pContext = NULL;
  421. NTSTATUS Status;
  422. int i;
  423. PAGED_CODE();
  424. DPF(DL_TRACE|FA_IOCTL, ("IRP_MJ_CREATE"));
  425. Status = KsReferenceSoftwareBusObject(((PDEVICE_INSTANCE)pDO->DeviceExtension)->pDeviceHeader );
  426. if (!NT_SUCCESS(Status))
  427. {
  428. RETURN( Status );
  429. }
  430. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  431. Status = AudioAllocateMemory_Fixed(sizeof(*pContext),
  432. TAG_Audx_CONTEXT,
  433. ZERO_FILL_MEMORY,
  434. &pContext);
  435. if (NT_SUCCESS(Status))
  436. {
  437. pIrpStack->FileObject->FsContext = pContext;
  438. //
  439. // Initialize out all the winmm device data structures.
  440. //
  441. #ifdef DEBUG
  442. pContext->dwSig=CONTEXT_SIGNATURE;
  443. #endif
  444. pContext->VirtualWavePinId = MAXULONG;
  445. pContext->VirtualMidiPinId = MAXULONG;
  446. pContext->VirtualCDPinId = MAXULONG;
  447. pContext->PreferredSysaudioWaveDevice = gWavePreferredSysaudioDevice;
  448. if ( IsSysaudioInterfaceActive() )
  449. {
  450. pContext->pFileObjectSysaudio = kmxlOpenSysAudio();
  451. } else {
  452. DPF(DL_WARNING|FA_SYSAUDIO,("sysaudio not available") );
  453. }
  454. for (i = 0; i < MAXNUMDEVS; i++)
  455. {
  456. pContext->WaveOutDevs[i].pWdmaContext = pContext;
  457. pContext->WaveInDevs[i].pWdmaContext = pContext;
  458. pContext->MidiOutDevs[i].pWdmaContext = pContext;
  459. pContext->MidiInDevs[i].pWdmaContext = pContext;
  460. pContext->MixerDevs[i].pWdmaContext = pContext;
  461. pContext->AuxDevs[i].pWdmaContext = pContext;
  462. pContext->WaveOutDevs[i].Device = UNUSED_DEVICE;
  463. pContext->WaveInDevs[i].Device = UNUSED_DEVICE;
  464. pContext->MidiOutDevs[i].Device = UNUSED_DEVICE;
  465. pContext->MidiInDevs[i].Device = UNUSED_DEVICE;
  466. pContext->MixerDevs[i].Device = UNUSED_DEVICE;
  467. pContext->AuxDevs[i].Device = UNUSED_DEVICE;
  468. #ifdef DEBUG
  469. pContext->MixerDevs[i].dwSig = MIXERDEVICE_SIGNATURE;
  470. #endif
  471. DPFASSERT(pContext->WaveOutDevs[i].pWavePin == NULL);
  472. pContext->apCommonDevice[WaveInDevice][i] = (PCOMMONDEVICE)&pContext->WaveInDevs[i];
  473. pContext->apCommonDevice[WaveOutDevice][i] = (PCOMMONDEVICE)&pContext->WaveOutDevs[i];
  474. pContext->apCommonDevice[MidiInDevice][i] = (PCOMMONDEVICE)&pContext->MidiInDevs[i];
  475. pContext->apCommonDevice[MidiOutDevice][i] = (PCOMMONDEVICE)&pContext->MidiOutDevs[i];
  476. pContext->apCommonDevice[MixerDevice][i] = (PCOMMONDEVICE)&pContext->MixerDevs[i];
  477. pContext->apCommonDevice[AuxDevice][i] = (PCOMMONDEVICE)&pContext->AuxDevs[i];
  478. }
  479. InitializeListHead(&pContext->DevNodeListHead);
  480. pContext->DevNodeListCount = 0;
  481. InitializeListHead(&pContext->WorkListHead);
  482. KeInitializeSpinLock(&pContext->WorkListSpinLock);
  483. ExInitializeWorkItem(&pContext->WorkListWorkItem, WorkListWorker, pContext);
  484. ExInitializeWorkItem(&pContext->SysaudioWorkItem, SysaudioAddRemove, pContext);
  485. KeInitializeEvent(&pContext->InitializedSysaudioEvent, NotificationEvent, FALSE);
  486. Status = KsRegisterWorker( DelayedWorkQueue, &pContext->WorkListWorkerObject );
  487. if (NT_SUCCESS(Status))
  488. {
  489. Status = KsRegisterWorker( DelayedWorkQueue, &pContext->SysaudioWorkerObject );
  490. if (NT_SUCCESS(Status))
  491. {
  492. Status = IoRegisterPlugPlayNotification(
  493. EventCategoryDeviceInterfaceChange,
  494. PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
  495. (GUID *)&KSCATEGORY_SYSAUDIO,
  496. pIrpStack->DeviceObject->DriverObject,
  497. SysAudioPnPNotification,
  498. pContext,
  499. &pContext->NotificationEntry);
  500. if (NT_SUCCESS(Status))
  501. {
  502. AddFsContextToList(pContext);
  503. DPF(DL_TRACE|FA_IOCTL, ("New pContext=%08Xh", pContext) );
  504. }
  505. if (!NT_SUCCESS(Status))
  506. {
  507. KsUnregisterWorker( pContext->SysaudioWorkerObject );
  508. pContext->SysaudioWorkerObject = NULL;
  509. }
  510. }
  511. if (!NT_SUCCESS(Status))
  512. {
  513. KsUnregisterWorker( pContext->WorkListWorkerObject );
  514. pContext->WorkListWorkerObject = NULL;
  515. }
  516. }
  517. if (!NT_SUCCESS(Status))
  518. {
  519. AudioFreeMemory(sizeof(*pContext),&pContext);
  520. pIrpStack->FileObject->FsContext = NULL;
  521. }
  522. }
  523. if (!NT_SUCCESS(Status))
  524. {
  525. KsDereferenceSoftwareBusObject(((PDEVICE_INSTANCE)pDO->DeviceExtension)->pDeviceHeader );
  526. }
  527. pIrp->IoStatus.Status = Status;
  528. pIrp->IoStatus.Information = 0;
  529. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  530. RETURN( Status );
  531. }
  532. NTSTATUS
  533. SoundDispatchClose(
  534. IN PDEVICE_OBJECT pDO,
  535. IN PIRP pIrp
  536. )
  537. {
  538. PIO_STACK_LOCATION pIrpStack;
  539. PKSWORKER WorkListWorkerObject;
  540. PKSWORKER SysaudioWorkerObject;
  541. PWDMACONTEXT pContext;
  542. PAGED_CODE();
  543. DPF(DL_TRACE|FA_IOCTL, ("IRP_MJ_CLOSE"));
  544. //
  545. // This routine is serialized by the i/o subsystem so there is no need to grab the
  546. // mutex for protection. Furthermore, it is not possible to release the mutex
  547. // after UninitializeSysaudio is called.
  548. //
  549. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  550. //
  551. // Can't assume that FsContext is initialized if the device has
  552. // been opened with FO_DIRECT_DEVICE_OPEN
  553. //
  554. if (pIrpStack->FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
  555. {
  556. DPF(DL_TRACE|FA_IOCTL, ("Opened with FO_DIRECT_DEVICE_OPEN, no device context") );
  557. goto exit;
  558. }
  559. pContext = pIrpStack->FileObject->FsContext;
  560. ASSERT(pContext);
  561. DPF(DL_TRACE|FA_IOCTL, ("pWdmaContext=%08Xh", pContext) );
  562. if (pContext->NotificationEntry != NULL)
  563. {
  564. IoUnregisterPlugPlayNotification(pContext->NotificationEntry);
  565. pContext->NotificationEntry = NULL;
  566. }
  567. //
  568. // force turds to be freed for a particular context
  569. //
  570. WdmaGrabMutex(pContext);
  571. CleanupWaveDevices(pContext);
  572. CleanupMidiDevices(pContext);
  573. WdmaContextCleanup(pContext);
  574. UninitializeSysaudio(pContext);
  575. WorkListWorkerObject = pContext->WorkListWorkerObject;
  576. pContext->WorkListWorkerObject = NULL;
  577. SysaudioWorkerObject = pContext->SysaudioWorkerObject;
  578. pContext->SysaudioWorkerObject = NULL;
  579. WdmaReleaseMutex(pContext);
  580. if (WorkListWorkerObject != NULL)
  581. {
  582. KsUnregisterWorker( WorkListWorkerObject );
  583. }
  584. if (SysaudioWorkerObject != NULL)
  585. {
  586. KsUnregisterWorker( SysaudioWorkerObject );
  587. }
  588. RemoveFsContextFromList(pContext);
  589. //
  590. // Workitem: Shouldn't WdmaReleaseMutex(pContext) be here rather then above?
  591. // I would think that if we release the mutex before cleanly getting throug the
  592. // cleanup we could have reentrancy problems. ???
  593. //
  594. // Also, note that all of pContext will be invalid after this AudioFreeMemory call!
  595. //
  596. kmxlRemoveContextFromNoteList(pContext);
  597. if( pContext->pFileObjectSysaudio )
  598. {
  599. kmxlCloseSysAudio(pContext->pFileObjectSysaudio);
  600. pContext->pFileObjectSysaudio = NULL;
  601. }
  602. AudioFreeMemory(sizeof(*pContext),&pContext);
  603. pIrpStack->FileObject->FsContext = NULL;
  604. exit:
  605. KsDereferenceSoftwareBusObject(((PDEVICE_INSTANCE)pDO->DeviceExtension)->pDeviceHeader );
  606. pIrp->IoStatus.Status = STATUS_SUCCESS;
  607. pIrp->IoStatus.Information = 0;
  608. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  609. return STATUS_SUCCESS;
  610. }
  611. NTSTATUS
  612. SoundDispatchCleanup(
  613. IN PDEVICE_OBJECT pDO,
  614. IN PIRP pIrp
  615. )
  616. {
  617. PIO_STACK_LOCATION pIrpStack;
  618. PWDMACONTEXT pContext;
  619. PAGED_CODE();
  620. DPF(DL_TRACE|FA_IOCTL, ("IRP_MJ_CLEANUP"));
  621. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  622. //
  623. // Can't assume that FsContext is initialized if the device has
  624. // been opened with FO_DIRECT_DEVICE_OPEN
  625. //
  626. if (pIrpStack->FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
  627. {
  628. DPF(DL_TRACE|FA_IOCTL, ("Opened with FO_DIRECT_DEVICE_OPEN, no device context") );
  629. goto exit;
  630. }
  631. pContext = pIrpStack->FileObject->FsContext;
  632. ASSERT(pContext);
  633. DPF(DL_TRACE|FA_IOCTL, ("pWdmaContext=%08Xh", pContext) );
  634. //
  635. // force turds to be freed for a particular context
  636. //
  637. WdmaGrabMutex(pContext);
  638. CleanupWaveDevices(pContext);
  639. CleanupMidiDevices(pContext);
  640. WdmaContextCleanup(pContext);
  641. WdmaReleaseMutex(pContext);
  642. exit:
  643. pIrp->IoStatus.Status = STATUS_SUCCESS;
  644. pIrp->IoStatus.Information = 0;
  645. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  646. return STATUS_SUCCESS;
  647. }
  648. NTSTATUS
  649. ValidateIoCode
  650. (
  651. IN ULONG IoCode
  652. )
  653. {
  654. NTSTATUS Status;
  655. PAGED_CODE();
  656. switch (IoCode)
  657. {
  658. case IOCTL_WDMAUD_INIT:
  659. case IOCTL_WDMAUD_ADD_DEVNODE:
  660. case IOCTL_WDMAUD_REMOVE_DEVNODE:
  661. case IOCTL_WDMAUD_SET_PREFERRED_DEVICE:
  662. case IOCTL_WDMAUD_GET_CAPABILITIES:
  663. case IOCTL_WDMAUD_GET_NUM_DEVS:
  664. case IOCTL_WDMAUD_OPEN_PIN:
  665. case IOCTL_WDMAUD_CLOSE_PIN:
  666. case IOCTL_WDMAUD_GET_VOLUME:
  667. case IOCTL_WDMAUD_SET_VOLUME:
  668. case IOCTL_WDMAUD_EXIT:
  669. case IOCTL_WDMAUD_WAVE_OUT_PAUSE:
  670. case IOCTL_WDMAUD_WAVE_OUT_PLAY:
  671. case IOCTL_WDMAUD_WAVE_OUT_RESET:
  672. case IOCTL_WDMAUD_WAVE_OUT_BREAKLOOP:
  673. case IOCTL_WDMAUD_WAVE_OUT_GET_POS:
  674. case IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME:
  675. case IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME:
  676. case IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN:
  677. case IOCTL_WDMAUD_WAVE_IN_STOP:
  678. case IOCTL_WDMAUD_WAVE_IN_RECORD:
  679. case IOCTL_WDMAUD_WAVE_IN_RESET:
  680. case IOCTL_WDMAUD_WAVE_IN_GET_POS:
  681. case IOCTL_WDMAUD_WAVE_IN_READ_PIN:
  682. case IOCTL_WDMAUD_MIDI_OUT_RESET:
  683. case IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME:
  684. case IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME:
  685. case IOCTL_WDMAUD_MIDI_OUT_WRITE_DATA:
  686. case IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA:
  687. case IOCTL_WDMAUD_MIDI_IN_STOP:
  688. case IOCTL_WDMAUD_MIDI_IN_RECORD:
  689. case IOCTL_WDMAUD_MIDI_IN_RESET:
  690. case IOCTL_WDMAUD_MIDI_IN_READ_PIN:
  691. case IOCTL_WDMAUD_MIXER_OPEN:
  692. case IOCTL_WDMAUD_MIXER_CLOSE:
  693. case IOCTL_WDMAUD_MIXER_GETLINEINFO:
  694. case IOCTL_WDMAUD_MIXER_GETLINECONTROLS:
  695. case IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS:
  696. case IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS:
  697. case IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA:
  698. Status = STATUS_SUCCESS;
  699. break;
  700. default:
  701. Status = STATUS_NOT_SUPPORTED;
  702. break;
  703. }
  704. RETURN( Status );
  705. }
  706. NTSTATUS
  707. ValidateDeviceType
  708. (
  709. IN ULONG IoCode,
  710. IN DWORD DeviceType
  711. )
  712. {
  713. NTSTATUS Status = STATUS_SUCCESS;
  714. PAGED_CODE();
  715. switch (IoCode)
  716. {
  717. // These IOCTLs can handle any DeviceType
  718. case IOCTL_WDMAUD_ADD_DEVNODE:
  719. case IOCTL_WDMAUD_REMOVE_DEVNODE:
  720. case IOCTL_WDMAUD_SET_PREFERRED_DEVICE:
  721. case IOCTL_WDMAUD_GET_CAPABILITIES:
  722. case IOCTL_WDMAUD_GET_NUM_DEVS:
  723. case IOCTL_WDMAUD_OPEN_PIN:
  724. case IOCTL_WDMAUD_CLOSE_PIN:
  725. if (DeviceType != WaveInDevice &&
  726. DeviceType != WaveOutDevice &&
  727. DeviceType != MidiInDevice &&
  728. DeviceType != MidiOutDevice &&
  729. DeviceType != MixerDevice &&
  730. DeviceType != AuxDevice)
  731. {
  732. Status = STATUS_INVALID_PARAMETER;
  733. }
  734. break;
  735. // These IOCTLs can handle only AUX devices
  736. case IOCTL_WDMAUD_GET_VOLUME:
  737. case IOCTL_WDMAUD_SET_VOLUME:
  738. if (DeviceType != AuxDevice)
  739. {
  740. Status = STATUS_INVALID_PARAMETER;
  741. }
  742. break;
  743. // These IOCTLs can handle only WaveOut devices
  744. case IOCTL_WDMAUD_WAVE_OUT_PAUSE:
  745. case IOCTL_WDMAUD_WAVE_OUT_PLAY:
  746. case IOCTL_WDMAUD_WAVE_OUT_RESET:
  747. case IOCTL_WDMAUD_WAVE_OUT_BREAKLOOP:
  748. case IOCTL_WDMAUD_WAVE_OUT_GET_POS:
  749. case IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME:
  750. case IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME:
  751. case IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN:
  752. if (DeviceType != WaveOutDevice)
  753. {
  754. Status = STATUS_INVALID_PARAMETER;
  755. }
  756. break;
  757. // These IOCTLs can handle only WaveIn devices
  758. case IOCTL_WDMAUD_WAVE_IN_STOP:
  759. case IOCTL_WDMAUD_WAVE_IN_RECORD:
  760. case IOCTL_WDMAUD_WAVE_IN_RESET:
  761. case IOCTL_WDMAUD_WAVE_IN_GET_POS:
  762. case IOCTL_WDMAUD_WAVE_IN_READ_PIN:
  763. if (DeviceType != WaveInDevice)
  764. {
  765. Status = STATUS_INVALID_PARAMETER;
  766. }
  767. break;
  768. // These IOCTLs can handle only MidiOut devices
  769. case IOCTL_WDMAUD_MIDI_OUT_RESET:
  770. case IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME:
  771. case IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME:
  772. case IOCTL_WDMAUD_MIDI_OUT_WRITE_DATA:
  773. case IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA:
  774. if (DeviceType != MidiOutDevice)
  775. {
  776. Status = STATUS_INVALID_PARAMETER;
  777. }
  778. break;
  779. // These IOCTLs can handle only MidiIn devices
  780. case IOCTL_WDMAUD_MIDI_IN_STOP:
  781. case IOCTL_WDMAUD_MIDI_IN_RECORD:
  782. case IOCTL_WDMAUD_MIDI_IN_RESET:
  783. case IOCTL_WDMAUD_MIDI_IN_READ_PIN:
  784. if (DeviceType != MidiInDevice)
  785. {
  786. Status = STATUS_INVALID_PARAMETER;
  787. }
  788. break;
  789. // These IOCTLs can handle only Mixer devices
  790. case IOCTL_WDMAUD_MIXER_OPEN:
  791. case IOCTL_WDMAUD_MIXER_CLOSE:
  792. case IOCTL_WDMAUD_MIXER_GETLINEINFO:
  793. case IOCTL_WDMAUD_MIXER_GETLINECONTROLS:
  794. case IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS:
  795. case IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS:
  796. case IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA:
  797. if (DeviceType != MixerDevice)
  798. {
  799. Status = STATUS_INVALID_PARAMETER;
  800. }
  801. break;
  802. // No device type for these IOCTLs
  803. case IOCTL_WDMAUD_INIT:
  804. case IOCTL_WDMAUD_EXIT:
  805. // Status is already STATUS_SUCCESS
  806. break;
  807. default:
  808. Status = STATUS_NOT_SUPPORTED;
  809. break;
  810. }
  811. RETURN( Status );
  812. }
  813. #ifdef _WIN64
  814. // Note that on 64 bit Windows, handles have 32 bits of information in them,
  815. // but no more. Thus they can be safely zero extended and truncated for thunks.
  816. // All memory allocations made in 32 bit processes are guaranteed to be in the
  817. // first 4 Gigs, again so that pointers from those processes can be thunked simply
  818. // by zero extending them and truncating them.
  819. VOID ThunkDeviceInfo3264(
  820. LPDEVICEINFO32 DeviceInfo32,
  821. LPDEVICEINFO DeviceInfo
  822. )
  823. {
  824. ULONG i;
  825. PAGED_CODE();
  826. DeviceInfo->Next = (LPDEVICEINFO)(UINT_PTR)DeviceInfo32->Next;
  827. DeviceInfo->DeviceNumber = DeviceInfo32->DeviceNumber ;
  828. DeviceInfo->DeviceType = DeviceInfo32->DeviceType ;
  829. DeviceInfo->DeviceHandle = (HANDLE32)(UINT_PTR)DeviceInfo32->DeviceHandle ;
  830. DeviceInfo->dwInstance = (DWORD_PTR)DeviceInfo32->dwInstance ;
  831. DeviceInfo->dwCallback = (DWORD_PTR)DeviceInfo32->dwCallback ;
  832. DeviceInfo->dwCallback16 = DeviceInfo32->dwCallback16 ;
  833. DeviceInfo->dwFlags = DeviceInfo32->dwFlags ;
  834. DeviceInfo->DataBuffer = (LPVOID)(UINT_PTR)DeviceInfo32->DataBuffer ;
  835. DeviceInfo->DataBufferSize = DeviceInfo32->DataBufferSize ;
  836. DeviceInfo->OpenDone = DeviceInfo32->OpenDone ;
  837. DeviceInfo->OpenStatus = DeviceInfo32->OpenStatus ;
  838. DeviceInfo->HardwareCallbackEventHandle = (HANDLE)(UINT_PTR)DeviceInfo32->HardwareCallbackEventHandle ;
  839. DeviceInfo->dwCallbackType = DeviceInfo32->dwCallbackType ;
  840. for (i=0; i<MAXCALLBACKS; i++)
  841. DeviceInfo->dwID[i] = DeviceInfo32->dwID[i] ;
  842. DeviceInfo->dwLineID = DeviceInfo32->dwLineID ;
  843. DeviceInfo->ControlCallbackCount = DeviceInfo32->ControlCallbackCount ;
  844. DeviceInfo->dwFormat = DeviceInfo32->dwFormat ;
  845. DeviceInfo->mmr = DeviceInfo32->mmr ;
  846. DeviceInfo->DeviceState = (LPDEVICESTATE)(UINT_PTR)DeviceInfo32->DeviceState ;
  847. DeviceInfo->dwSig = DeviceInfo32->dwSig ;
  848. wcsncpy(DeviceInfo->wstrDeviceInterface, DeviceInfo32->wstrDeviceInterface, MAXDEVINTERFACE+1) ;
  849. }
  850. VOID ThunkDeviceInfo6432(
  851. LPDEVICEINFO DeviceInfo,
  852. LPDEVICEINFO32 DeviceInfo32
  853. )
  854. {
  855. ULONG i;
  856. PAGED_CODE();
  857. DeviceInfo32->Next = (UINT32)(UINT_PTR)DeviceInfo->Next;
  858. DeviceInfo32->DeviceNumber = DeviceInfo->DeviceNumber ;
  859. DeviceInfo32->DeviceType = DeviceInfo->DeviceType ;
  860. DeviceInfo32->DeviceHandle = (UINT32)(UINT_PTR)DeviceInfo->DeviceHandle ;
  861. DeviceInfo32->dwInstance = (UINT32)DeviceInfo->dwInstance ;
  862. DeviceInfo32->dwCallback = (UINT32)DeviceInfo->dwCallback ;
  863. DeviceInfo32->dwCallback16 = DeviceInfo->dwCallback16 ;
  864. DeviceInfo32->dwFlags = DeviceInfo->dwFlags ;
  865. DeviceInfo32->DataBuffer = (UINT32)(UINT_PTR)DeviceInfo->DataBuffer ;
  866. DeviceInfo32->DataBufferSize = DeviceInfo->DataBufferSize ;
  867. DeviceInfo32->OpenDone = DeviceInfo->OpenDone ;
  868. DeviceInfo32->OpenStatus = DeviceInfo->OpenStatus ;
  869. DeviceInfo32->HardwareCallbackEventHandle = (UINT32)(UINT_PTR)DeviceInfo->HardwareCallbackEventHandle ;
  870. DeviceInfo32->dwCallbackType = DeviceInfo->dwCallbackType ;
  871. for (i=0; i<MAXCALLBACKS; i++)
  872. DeviceInfo32->dwID[i] = DeviceInfo->dwID[i] ;
  873. DeviceInfo32->dwLineID = DeviceInfo->dwLineID ;
  874. DeviceInfo32->ControlCallbackCount = DeviceInfo->ControlCallbackCount ;
  875. DeviceInfo32->dwFormat = DeviceInfo->dwFormat ;
  876. DeviceInfo32->mmr = DeviceInfo->mmr ;
  877. DeviceInfo32->DeviceState = (UINT32)(UINT_PTR)DeviceInfo->DeviceState ;
  878. DeviceInfo32->dwSig = DeviceInfo->dwSig ;
  879. wcscpy(DeviceInfo32->wstrDeviceInterface, DeviceInfo->wstrDeviceInterface) ;
  880. }
  881. #endif
  882. NTSTATUS
  883. ValidateIrp
  884. (
  885. IN PIRP pIrp
  886. )
  887. {
  888. PIO_STACK_LOCATION pIrpStack;
  889. ULONG InputBufferLength;
  890. ULONG OutputBufferLength;
  891. LPDEVICEINFO DeviceInfo;
  892. #ifdef _WIN64
  893. LPDEVICEINFO32 DeviceInfo32;
  894. LOCALDEVICEINFO LocalDeviceInfo;
  895. #endif
  896. LPVOID DataBuffer;
  897. DWORD DataBufferSize;
  898. ULONG IoCode;
  899. NTSTATUS Status = STATUS_SUCCESS;
  900. PAGED_CODE();
  901. //
  902. // Get the CurrentStackLocation and log it so we know what is going on
  903. //
  904. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  905. IoCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
  906. //
  907. // Checks to see that we have a WDMAUD Ioctl (buffered) request
  908. //
  909. Status = ValidateIoCode(IoCode);
  910. if (NT_SUCCESS(Status))
  911. {
  912. //
  913. // Check the sizes of the input and output buffers.
  914. //
  915. InputBufferLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
  916. OutputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  917. #ifdef _WIN64
  918. if (IoIs32bitProcess(pIrp)) {
  919. if ((InputBufferLength < sizeof(DEVICEINFO32)) ||
  920. (OutputBufferLength != sizeof(DEVICEINFO32)) )
  921. {
  922. Status = STATUS_INVALID_BUFFER_SIZE;
  923. if (IoCode == IOCTL_WDMAUD_WAVE_OUT_GET_POS)
  924. {
  925. DPF(DL_ERROR|FA_IOCTL, ("IOCTL_WDMAUD_WAVE_OUT_GET_POS: InputBufferLength = %d, OuputBufferLength = %d", InputBufferLength, OutputBufferLength));
  926. }
  927. }
  928. }
  929. else
  930. // WARNING!!! If you add additional statements after the if that need
  931. // to be part of this else clause, you will need to add brackets!
  932. #endif
  933. if ((InputBufferLength < sizeof(DEVICEINFO)) ||
  934. (OutputBufferLength != sizeof(DEVICEINFO)) )
  935. {
  936. Status = STATUS_INVALID_BUFFER_SIZE;
  937. if (IoCode == IOCTL_WDMAUD_WAVE_OUT_GET_POS)
  938. {
  939. DPF(DL_WARNING|FA_IOCTL, ("IOCTL_WDMAUD_WAVE_OUT_GET_POS: InputBufferLength = %d, OuputBufferLength = %d", InputBufferLength, OutputBufferLength));
  940. }
  941. }
  942. if (NT_SUCCESS(Status))
  943. {
  944. #ifdef _WIN64
  945. if (IoIs32bitProcess(pIrp)) {
  946. DeviceInfo32=((LPDEVICEINFO32)pIrp->AssociatedIrp.SystemBuffer);
  947. RtlZeroMemory(&LocalDeviceInfo, sizeof(LOCALDEVICEINFO));
  948. DeviceInfo=&LocalDeviceInfo.DeviceInfo;
  949. ThunkDeviceInfo3264(DeviceInfo32, DeviceInfo);
  950. }
  951. else
  952. // WARNING!!! If you add additional statements after the assignment that need
  953. // to be part of this else clause, you will need to add brackets!
  954. #endif
  955. DeviceInfo = ((LPDEVICEINFO)pIrp->AssociatedIrp.SystemBuffer);
  956. DataBuffer = DeviceInfo->DataBuffer;
  957. DataBufferSize = DeviceInfo->DataBufferSize;
  958. //
  959. // Check to make sure that our DeviceInfo->wstrDeviceInterface is terminated
  960. //
  961. if (InputBufferLength % sizeof(WCHAR)) // must be WCHAR aligned
  962. {
  963. Status = STATUS_INVALID_PARAMETER;
  964. }
  965. else
  966. {
  967. //
  968. // Get the last widechar and compare with UNICODE_NULL
  969. //
  970. UINT TermCharPos;
  971. #ifdef _WIN64
  972. if (IoIs32bitProcess(pIrp)) {
  973. TermCharPos = (InputBufferLength - sizeof(DEVICEINFO32)) / sizeof(WCHAR);
  974. // Now make sure we had enough local buffer space to hold the whole string.
  975. if (TermCharPos>MAXDEVINTERFACE) {
  976. Status = STATUS_INVALID_PARAMETER;
  977. // Make sure we don't go past end of local buffer space when
  978. // we check if the last character is null.
  979. TermCharPos=MAXDEVINTERFACE;
  980. }
  981. }
  982. else
  983. // WARNING!!! If you add additional statements after the assignment that need
  984. // to be part of this else clause, you will need to add brackets!
  985. #endif
  986. TermCharPos = (InputBufferLength - sizeof(DEVICEINFO)) / sizeof(WCHAR);
  987. if (DeviceInfo->wstrDeviceInterface[TermCharPos] != UNICODE_NULL)
  988. {
  989. Status = STATUS_INVALID_PARAMETER;
  990. }
  991. }
  992. }
  993. }
  994. if (NT_SUCCESS(Status))
  995. {
  996. Status = ValidateDeviceType(IoCode,DeviceInfo->DeviceType);
  997. }
  998. if (NT_SUCCESS(Status))
  999. {
  1000. //
  1001. // Validate the pointers if the client is not trusted.
  1002. //
  1003. if (pIrp->RequestorMode != KernelMode)
  1004. {
  1005. if (DataBufferSize)
  1006. {
  1007. try
  1008. {
  1009. ASSERT(pIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL);
  1010. switch (IoCode)
  1011. {
  1012. //
  1013. // IoCode's that require a probe for reading
  1014. //
  1015. case IOCTL_WDMAUD_OPEN_PIN:
  1016. case IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN:
  1017. case IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA:
  1018. case IOCTL_WDMAUD_MIXER_OPEN:
  1019. case IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS:
  1020. ProbeForRead(DataBuffer,
  1021. DataBufferSize,
  1022. sizeof(BYTE));
  1023. break;
  1024. //
  1025. // IoCode's that require a probe for writing
  1026. //
  1027. case IOCTL_WDMAUD_GET_CAPABILITIES:
  1028. case IOCTL_WDMAUD_WAVE_IN_READ_PIN:
  1029. case IOCTL_WDMAUD_MIXER_GETLINEINFO:
  1030. case IOCTL_WDMAUD_MIXER_GETLINECONTROLS:
  1031. case IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS:
  1032. ProbeForWrite(DataBuffer,
  1033. DataBufferSize,
  1034. sizeof(BYTE));
  1035. break;
  1036. //
  1037. // IoCode's that require a probe for reading on DWORD alignment
  1038. //
  1039. case IOCTL_WDMAUD_SET_VOLUME:
  1040. case IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME:
  1041. case IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME:
  1042. ProbeForRead(DataBuffer,
  1043. DataBufferSize,
  1044. sizeof(DWORD));
  1045. break;
  1046. //
  1047. // IoCode's that require a probe for writing on DWORD alignment
  1048. //
  1049. case IOCTL_WDMAUD_GET_VOLUME:
  1050. case IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME:
  1051. case IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME:
  1052. case IOCTL_WDMAUD_WAVE_OUT_GET_POS:
  1053. case IOCTL_WDMAUD_WAVE_IN_GET_POS:
  1054. case IOCTL_WDMAUD_MIDI_IN_READ_PIN:
  1055. ProbeForWrite(DataBuffer,
  1056. DataBufferSize,
  1057. sizeof(DWORD));
  1058. break;
  1059. // Don't know about this ioctl
  1060. default:
  1061. Status = STATUS_NOT_SUPPORTED;
  1062. break;
  1063. }
  1064. }
  1065. except (EXCEPTION_EXECUTE_HANDLER)
  1066. {
  1067. Status = GetExceptionCode();
  1068. }
  1069. }
  1070. }
  1071. }
  1072. RETURN( Status );
  1073. }
  1074. //
  1075. // Helper routines.
  1076. //
  1077. NTSTATUS
  1078. ValidateAndTranslate(
  1079. PWDMACONTEXT pContext,
  1080. LPDEVICEINFO DeviceInfo,
  1081. DWORD ValidationSize,
  1082. ULONG *pTranslatedDeviceNumber
  1083. )
  1084. {
  1085. if (DeviceInfo->DataBufferSize != ValidationSize)
  1086. {
  1087. return STATUS_INVALID_BUFFER_SIZE;
  1088. }
  1089. *pTranslatedDeviceNumber = wdmaudTranslateDeviceNumber(pContext,
  1090. DeviceInfo->DeviceType,
  1091. DeviceInfo->wstrDeviceInterface,
  1092. DeviceInfo->DeviceNumber);
  1093. if (MAXULONG == *pTranslatedDeviceNumber) {
  1094. DPF(DL_WARNING|FA_IOCTL,("IOCTL_WDMAUD_SET_VOLUME: invalid device number, C %08x [%ls] DT %02x DN %02x",
  1095. pContext,
  1096. DeviceInfo->wstrDeviceInterface,
  1097. DeviceInfo->DeviceType,
  1098. DeviceInfo->DeviceNumber) );
  1099. return STATUS_INVALID_PARAMETER;
  1100. }
  1101. return STATUS_SUCCESS;
  1102. }
  1103. NTSTATUS
  1104. ValidateAndTranslateEx(
  1105. PIRP pIrp,
  1106. PWDMACONTEXT pContext,
  1107. LPDEVICEINFO DeviceInfo,
  1108. #ifdef _WIN64
  1109. DWORD ValidationSize32,
  1110. #endif
  1111. DWORD ValidationSize,
  1112. ULONG *pTranslatedDeviceNumber
  1113. )
  1114. {
  1115. #ifdef _WIN64
  1116. if (IoIs32bitProcess(pIrp)) {
  1117. if (DeviceInfo->DataBufferSize != ValidationSize32)
  1118. {
  1119. RETURN( STATUS_INVALID_BUFFER_SIZE );
  1120. }
  1121. } else {
  1122. #endif
  1123. if (DeviceInfo->DataBufferSize != ValidationSize)
  1124. {
  1125. RETURN( STATUS_INVALID_BUFFER_SIZE );
  1126. }
  1127. #ifdef _WIN64
  1128. }
  1129. #endif
  1130. *pTranslatedDeviceNumber = wdmaudTranslateDeviceNumber(pContext,
  1131. DeviceInfo->DeviceType,
  1132. DeviceInfo->wstrDeviceInterface,
  1133. DeviceInfo->DeviceNumber);
  1134. if (MAXULONG == *pTranslatedDeviceNumber) {
  1135. DPF(DL_WARNING|FA_IOCTL,("IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA: invalid device number, C %08x [%ls] DT %02x DN %02x",
  1136. pContext,
  1137. DeviceInfo->wstrDeviceInterface,
  1138. DeviceInfo->DeviceType,
  1139. DeviceInfo->DeviceNumber) );
  1140. RETURN( STATUS_INVALID_PARAMETER );
  1141. }
  1142. return STATUS_SUCCESS;
  1143. }
  1144. //
  1145. // Now come the dispatch routines.
  1146. //
  1147. NTSTATUS
  1148. Dispatch_WaveOutWritePin(
  1149. PIRP pIrp,
  1150. PWDMACONTEXT pContext,
  1151. LPDEVICEINFO DeviceInfo,
  1152. OUT BOOL *pCompletedIrp // TRUE if Irp was completed.
  1153. )
  1154. {
  1155. ULONG TranslatedDeviceNumber;
  1156. PSTREAM_HEADER_EX pStreamHeader;
  1157. LPWAVEHDR pWaveHdr = NULL;
  1158. #ifdef _WIN64
  1159. LPWAVEHDR32 pWaveHdr32;
  1160. #endif
  1161. PWRITE_CONTEXT pWriteContext = NULL;
  1162. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1163. //
  1164. // Verify that we received a valid waveheader
  1165. //
  1166. Status = ValidateAndTranslateEx(pIrp, pContext, DeviceInfo,
  1167. #ifdef _WIN64
  1168. sizeof(WAVEHDR32),
  1169. #endif
  1170. sizeof(WAVEHDR), &TranslatedDeviceNumber);
  1171. if( NT_SUCCESS(Status) )
  1172. {
  1173. Status = AudioAllocateMemory_Fixed(sizeof(WRITE_CONTEXT) + sizeof(STREAM_HEADER_EX),
  1174. TAG_Audx_CONTEXT,
  1175. ZERO_FILL_MEMORY,
  1176. &pWriteContext);
  1177. if(NT_SUCCESS(Status))
  1178. {
  1179. Status = CaptureBufferToLocalPool(DeviceInfo->DataBuffer,
  1180. DeviceInfo->DataBufferSize,
  1181. &pWaveHdr
  1182. #ifdef _WIN64
  1183. ,0
  1184. #endif
  1185. );
  1186. if (!NT_SUCCESS(Status))
  1187. {
  1188. AudioFreeMemory( sizeof(WRITE_CONTEXT) + sizeof(STREAM_HEADER_EX),
  1189. &pWriteContext );
  1190. return STATUS_INSUFFICIENT_RESOURCES;
  1191. } else {
  1192. #ifdef _WIN64
  1193. if (IoIs32bitProcess(pIrp)) {
  1194. // Thunk pWaveHdr to 64 bits.
  1195. pWaveHdr32=(LPWAVEHDR32)pWaveHdr;
  1196. pWriteContext->whInstance.wh.lpData=(LPSTR)(UINT_PTR)pWaveHdr32->lpData;
  1197. pWriteContext->whInstance.wh.dwBufferLength=pWaveHdr32->dwBufferLength;
  1198. pWriteContext->whInstance.wh.dwBytesRecorded=pWaveHdr32->dwBytesRecorded;
  1199. pWriteContext->whInstance.wh.dwUser=(DWORD_PTR)pWaveHdr32->dwUser;
  1200. pWriteContext->whInstance.wh.dwFlags=pWaveHdr32->dwFlags;
  1201. pWriteContext->whInstance.wh.dwLoops=pWaveHdr32->dwLoops;
  1202. pWriteContext->whInstance.wh.lpNext=(LPWAVEHDR)(UINT_PTR)pWaveHdr32->lpNext;
  1203. pWriteContext->whInstance.wh.reserved=(DWORD_PTR)pWaveHdr32->reserved;
  1204. } else {
  1205. #endif
  1206. //
  1207. // Copy the wavehdr to our local structure
  1208. //
  1209. RtlCopyMemory( &pWriteContext->whInstance.wh,
  1210. pWaveHdr,
  1211. sizeof(WAVEHDR));
  1212. #ifdef _WIN64
  1213. }
  1214. #endif
  1215. try
  1216. {
  1217. ProbeForRead(pWriteContext->whInstance.wh.lpData,
  1218. pWriteContext->whInstance.wh.dwBufferLength,
  1219. sizeof(BYTE));
  1220. }
  1221. except (EXCEPTION_EXECUTE_HANDLER)
  1222. {
  1223. AudioFreeMemory_Unknown( &pWaveHdr );
  1224. AudioFreeMemory( sizeof(WRITE_CONTEXT) + sizeof(STREAM_HEADER_EX),
  1225. &pWriteContext );
  1226. Status = GetExceptionCode();
  1227. }
  1228. if (!NT_SUCCESS(Status))
  1229. {
  1230. return Status;
  1231. }
  1232. wdmaudMapBuffer ( pIrp,
  1233. (PVOID)pWriteContext->whInstance.wh.lpData,
  1234. pWriteContext->whInstance.wh.dwBufferLength,
  1235. &pWriteContext->whInstance.wh.lpData,
  1236. &pWriteContext->pBufferMdl,
  1237. pContext,
  1238. FALSE);
  1239. //
  1240. // If we get a zero-length buffer, it is alright to not have
  1241. // a kernel mapped buffer. Otherwise, fail if no Mdl or buffer.
  1242. //
  1243. if ( (pWriteContext->whInstance.wh.dwBufferLength != 0) &&
  1244. ((NULL == pWriteContext->pBufferMdl) ||
  1245. (NULL == pWriteContext->whInstance.wh.lpData)) )
  1246. {
  1247. wdmaudUnmapBuffer( pWriteContext->pBufferMdl );
  1248. AudioFreeMemory_Unknown( &pWaveHdr );
  1249. AudioFreeMemory_Unknown( &pWriteContext );
  1250. return STATUS_INSUFFICIENT_RESOURCES;
  1251. } else {
  1252. pWriteContext->whInstance.wh.reserved = (DWORD_PTR)pIrp; // store to complete later
  1253. pWriteContext->pCapturedWaveHdr = pWaveHdr;
  1254. pStreamHeader = (PSTREAM_HEADER_EX)(pWriteContext + 1);
  1255. pStreamHeader->Header.Data = pWriteContext->whInstance.wh.lpData;
  1256. //
  1257. // Must cleanup any mapped buffers and allocated memory
  1258. // on error paths in WriteWaveOutPin
  1259. //
  1260. Status = WriteWaveOutPin(&pContext->WaveOutDevs[TranslatedDeviceNumber],
  1261. DeviceInfo->DeviceHandle,
  1262. (LPWAVEHDR)pWriteContext,
  1263. pStreamHeader,
  1264. pIrp,
  1265. pContext,
  1266. pCompletedIrp );
  1267. //
  1268. // Upon return from this routine, pCompetedIrp will be set.
  1269. // if TRUE, the issue of the Irp was successful and it was
  1270. // marked pending when it was added to the delay queue. Thus
  1271. // we must not complete it a second time.
  1272. // If FALSE, there was some error and the Irp should be
  1273. // completed.
  1274. //
  1275. }
  1276. }
  1277. }
  1278. }
  1279. return Status;
  1280. }
  1281. NTSTATUS
  1282. Dispatch_WaveInReadPin(
  1283. PIRP pIrp,
  1284. PWDMACONTEXT pContext,
  1285. LPDEVICEINFO DeviceInfo,
  1286. OUT BOOL *pCompletedIrp // TRUE if Irp was completed.
  1287. )
  1288. {
  1289. ULONG TranslatedDeviceNumber;
  1290. PSTREAM_HEADER_EX pStreamHeader = NULL;
  1291. LPWAVEHDR pWaveHdr;
  1292. #ifdef _WIN64
  1293. LPWAVEHDR32 pWaveHdr32;
  1294. #endif
  1295. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1296. //
  1297. // Assume that things will be successful. Write back that it's not completed.
  1298. //
  1299. *pCompletedIrp = FALSE;
  1300. //
  1301. // Verify that we received a valid waveheader
  1302. //
  1303. Status = ValidateAndTranslateEx(pIrp, pContext, DeviceInfo,
  1304. #ifdef _WIN64
  1305. sizeof(WAVEHDR32),
  1306. #endif
  1307. sizeof(WAVEHDR), &TranslatedDeviceNumber);
  1308. Status = AudioAllocateMemory_Fixed(sizeof(STREAM_HEADER_EX),
  1309. TAG_Audh_STREAMHEADER,
  1310. ZERO_FILL_MEMORY,
  1311. &pStreamHeader);
  1312. if(NT_SUCCESS(Status))
  1313. {
  1314. wdmaudMapBuffer(pIrp,
  1315. DeviceInfo->DataBuffer,
  1316. DeviceInfo->DataBufferSize,
  1317. &pWaveHdr,
  1318. &pStreamHeader->pHeaderMdl,
  1319. pContext,
  1320. TRUE);
  1321. if (NULL == pStreamHeader->pHeaderMdl)
  1322. {
  1323. AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
  1324. return STATUS_INSUFFICIENT_RESOURCES;
  1325. } else {
  1326. LPVOID lpData;
  1327. DWORD dwBufferLength;
  1328. Status = CaptureBufferToLocalPool(
  1329. DeviceInfo->DataBuffer,
  1330. DeviceInfo->DataBufferSize,
  1331. &pStreamHeader->pWaveHdrAligned
  1332. #ifdef _WIN64
  1333. ,(IoIs32bitProcess(pIrp))?sizeof(WAVEHDR):0
  1334. #endif
  1335. );
  1336. if (!NT_SUCCESS(Status))
  1337. {
  1338. wdmaudUnmapBuffer( pStreamHeader->pHeaderMdl );
  1339. AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
  1340. return STATUS_INSUFFICIENT_RESOURCES;
  1341. }
  1342. #ifdef _WIN64
  1343. // Thunk the wave header if required.
  1344. // Note this is an IN PLACE thunk, so we MUST do it in
  1345. // last element to first element order!!!
  1346. if (IoIs32bitProcess(pIrp)) {
  1347. // Thunk pWaveHdrAligned to 64 bits.
  1348. pWaveHdr32=(LPWAVEHDR32)pStreamHeader->pWaveHdrAligned;
  1349. pStreamHeader->pWaveHdrAligned->reserved=(DWORD_PTR)pWaveHdr32->reserved;
  1350. pStreamHeader->pWaveHdrAligned->lpNext=(LPWAVEHDR)(UINT_PTR)pWaveHdr32->lpNext;
  1351. pStreamHeader->pWaveHdrAligned->dwLoops=pWaveHdr32->dwLoops;
  1352. pStreamHeader->pWaveHdrAligned->dwFlags=pWaveHdr32->dwFlags;
  1353. pStreamHeader->pWaveHdrAligned->dwUser=(DWORD_PTR)pWaveHdr32->dwUser;
  1354. pStreamHeader->pWaveHdrAligned->dwBytesRecorded=pWaveHdr32->dwBytesRecorded;
  1355. pStreamHeader->pWaveHdrAligned->dwBufferLength=pWaveHdr32->dwBufferLength;
  1356. pStreamHeader->pWaveHdrAligned->lpData=(LPSTR)(UINT_PTR)pWaveHdr32->lpData;
  1357. }
  1358. #endif
  1359. //
  1360. // Capture these parameters before probing
  1361. //
  1362. lpData = pStreamHeader->pWaveHdrAligned->lpData;
  1363. dwBufferLength = pStreamHeader->pWaveHdrAligned->dwBufferLength;
  1364. try
  1365. {
  1366. ProbeForWrite(lpData,
  1367. dwBufferLength,
  1368. sizeof(BYTE));
  1369. }
  1370. except (EXCEPTION_EXECUTE_HANDLER)
  1371. {
  1372. AudioFreeMemory_Unknown( &pStreamHeader->pWaveHdrAligned );
  1373. wdmaudUnmapBuffer(pStreamHeader->pHeaderMdl);
  1374. AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
  1375. Status = GetExceptionCode();
  1376. }
  1377. if (!NT_SUCCESS(Status))
  1378. {
  1379. return Status;
  1380. }
  1381. wdmaudMapBuffer( pIrp,
  1382. lpData,
  1383. dwBufferLength,
  1384. &pStreamHeader->Header.Data,
  1385. &pStreamHeader->pBufferMdl,
  1386. pContext,
  1387. TRUE); // will be freed on completion
  1388. //
  1389. // If we get a zero-length buffer, it is alright to not have
  1390. // a kernel mapped buffer. Otherwise, fail if no Mdl or buffer.
  1391. //
  1392. if ( (dwBufferLength != 0) &&
  1393. ((NULL == pStreamHeader->pBufferMdl) ||
  1394. (NULL == pStreamHeader->Header.Data)) )
  1395. {
  1396. wdmaudUnmapBuffer(pStreamHeader->pBufferMdl);
  1397. AudioFreeMemory_Unknown( &pStreamHeader->pWaveHdrAligned );
  1398. wdmaudUnmapBuffer(pStreamHeader->pHeaderMdl);
  1399. AudioFreeMemory_Unknown( &pStreamHeader );
  1400. return STATUS_INSUFFICIENT_RESOURCES;
  1401. } else {
  1402. pStreamHeader->pIrp = pIrp; // store so we can complete later
  1403. pStreamHeader->Header.FrameExtent = dwBufferLength ;
  1404. pStreamHeader->pdwBytesRecorded = &pWaveHdr->dwBytesRecorded; // store so we can use later
  1405. #ifdef _WIN64
  1406. // Fixup dwBytesRecorded pointer for 32 bit irps.
  1407. if (IoIs32bitProcess(pIrp)) {
  1408. pStreamHeader->pdwBytesRecorded = &((LPWAVEHDR32)pWaveHdr)->dwBytesRecorded;
  1409. }
  1410. #endif
  1411. //
  1412. // Must cleanup any mapped buffers and allocated memory
  1413. // on error paths in ReadWaveInPin
  1414. //
  1415. Status = ReadWaveInPin( &pContext->WaveInDevs[TranslatedDeviceNumber],
  1416. DeviceInfo->DeviceHandle,
  1417. pStreamHeader,
  1418. pIrp,
  1419. pContext,
  1420. pCompletedIrp );
  1421. //
  1422. // If ReadWaveInPin returns something other then STATUS_PENDING
  1423. // we could have problems. But only if we marked the IRP as pending.
  1424. // All other return codes should be handled normally.
  1425. //
  1426. #ifdef DEBUG
  1427. if( *pCompletedIrp ) {
  1428. ASSERT(Status == STATUS_PENDING);
  1429. }
  1430. #endif
  1431. }
  1432. }
  1433. }
  1434. return Status;
  1435. }
  1436. NTSTATUS
  1437. Dispatch_MidiInReadPin(
  1438. PIRP pIrp,
  1439. PWDMACONTEXT pContext,
  1440. LPDEVICEINFO DeviceInfo,
  1441. OUT BOOL *pCompletedIrp // TRUE if Irp was completed.
  1442. )
  1443. {
  1444. ULONG TranslatedDeviceNumber;
  1445. PMIDIINHDR pNewMidiInHdr = NULL;
  1446. LPMIDIDATA pMidiData;
  1447. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1448. //
  1449. // Assume that things will be successful. Write back that it's not completed.
  1450. //
  1451. ASSERT(FALSE == *pCompletedIrp );
  1452. //
  1453. // Verify that we received a valid mididata structure
  1454. //
  1455. Status = ValidateAndTranslate(pContext,
  1456. DeviceInfo,
  1457. sizeof(MIDIDATA),
  1458. &TranslatedDeviceNumber);
  1459. if( NT_SUCCESS(Status) )
  1460. {
  1461. Status = AudioAllocateMemory_Fixed(sizeof(*pNewMidiInHdr),
  1462. TAG_Aude_MIDIHEADER,
  1463. ZERO_FILL_MEMORY,
  1464. &pNewMidiInHdr);
  1465. if(NT_SUCCESS(Status))
  1466. {
  1467. wdmaudMapBuffer( pIrp,
  1468. DeviceInfo->DataBuffer,
  1469. DeviceInfo->DataBufferSize,
  1470. &pMidiData,
  1471. &pNewMidiInHdr->pMdl,
  1472. pContext,
  1473. TRUE);
  1474. if (NULL == pNewMidiInHdr->pMdl)
  1475. {
  1476. AudioFreeMemory( sizeof(*pNewMidiInHdr),&pNewMidiInHdr );
  1477. Status = STATUS_INSUFFICIENT_RESOURCES;
  1478. } else {
  1479. PWDMAPENDINGIRP_CONTEXT pPendingIrpContext;
  1480. //
  1481. // wdmaudPreparteIrp marks the irp as pending, thus
  1482. // we must not complete the irp when we get to this
  1483. // point in the code.
  1484. //
  1485. Status = wdmaudPrepareIrp ( pIrp, MidiInDevice, pContext, &pPendingIrpContext );
  1486. if (NT_SUCCESS(Status))
  1487. {
  1488. //
  1489. // Initialize this new MidiIn header
  1490. //
  1491. pNewMidiInHdr->pMidiData = pMidiData;
  1492. pNewMidiInHdr->pIrp = pIrp;
  1493. pNewMidiInHdr->pPendingIrpContext = pPendingIrpContext;
  1494. //
  1495. // Add this header to the tail of the queue
  1496. //
  1497. // Must cleanup any mapped buffers and allocated memory
  1498. // on error paths in AddBufferToMidiInQueue
  1499. //
  1500. Status = AddBufferToMidiInQueue( pContext->MidiInDevs[TranslatedDeviceNumber].pMidiPin,
  1501. pNewMidiInHdr );
  1502. if (STATUS_PENDING != Status)
  1503. {
  1504. // Must have been an error, complete Irp
  1505. wdmaudUnmapBuffer( pNewMidiInHdr->pMdl );
  1506. AudioFreeMemory_Unknown( &pNewMidiInHdr );
  1507. wdmaudUnprepareIrp( pIrp, Status, 0, pPendingIrpContext );
  1508. }
  1509. //
  1510. // because we marked the irp pending, we don't want to
  1511. // complete it when we return. So, tell the caller not
  1512. // to complete the Irp.
  1513. //
  1514. *pCompletedIrp = TRUE;
  1515. }
  1516. }
  1517. }
  1518. }
  1519. return Status;
  1520. }
  1521. NTSTATUS
  1522. Dispatch_State(
  1523. PIRP pIrp,
  1524. PWDMACONTEXT pContext,
  1525. LPDEVICEINFO DeviceInfo,
  1526. ULONG IoCode
  1527. )
  1528. {
  1529. ULONG TranslatedDeviceNumber;
  1530. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1531. Status = ValidateAndTranslate(pContext,
  1532. DeviceInfo,
  1533. 0,
  1534. &TranslatedDeviceNumber);
  1535. if( NT_SUCCESS(Status) )
  1536. {
  1537. switch(IoCode)
  1538. {
  1539. //
  1540. // Midi out state changes
  1541. //
  1542. case IOCTL_WDMAUD_MIDI_OUT_RESET:
  1543. Status = StateMidiOutPin ( pContext->MidiOutDevs[TranslatedDeviceNumber].pMidiPin,
  1544. KSSTATE_STOP );
  1545. break;
  1546. case IOCTL_WDMAUD_MIDI_OUT_WRITE_DATA:
  1547. Status = WriteMidiEventPin(&pContext->MidiOutDevs[TranslatedDeviceNumber],
  1548. PtrToUlong(DeviceInfo->DataBuffer));
  1549. break;
  1550. //
  1551. // Midi in state changes
  1552. //
  1553. case IOCTL_WDMAUD_MIDI_IN_STOP:
  1554. Status = StateMidiInPin ( pContext->MidiInDevs[TranslatedDeviceNumber].pMidiPin,
  1555. KSSTATE_PAUSE );
  1556. break;
  1557. case IOCTL_WDMAUD_MIDI_IN_RECORD:
  1558. Status = StateMidiInPin ( pContext->MidiInDevs[TranslatedDeviceNumber].pMidiPin,
  1559. KSSTATE_RUN );
  1560. break;
  1561. case IOCTL_WDMAUD_MIDI_IN_RESET:
  1562. Status = ResetMidiInPin ( pContext->MidiInDevs[TranslatedDeviceNumber].pMidiPin );
  1563. break;
  1564. //
  1565. // Wave out state changes
  1566. //
  1567. case IOCTL_WDMAUD_WAVE_OUT_PAUSE:
  1568. Status = StateWavePin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
  1569. DeviceInfo->DeviceHandle,
  1570. KSSTATE_PAUSE );
  1571. break;
  1572. case IOCTL_WDMAUD_WAVE_OUT_PLAY:
  1573. Status = StateWavePin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
  1574. DeviceInfo->DeviceHandle,
  1575. KSSTATE_RUN );
  1576. break;
  1577. case IOCTL_WDMAUD_WAVE_OUT_RESET:
  1578. Status = StateWavePin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
  1579. DeviceInfo->DeviceHandle,
  1580. KSSTATE_PAUSE );
  1581. if ( NT_SUCCESS(Status) )
  1582. {
  1583. Status = ResetWaveOutPin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
  1584. DeviceInfo->DeviceHandle ) ;
  1585. }
  1586. break;
  1587. case IOCTL_WDMAUD_WAVE_OUT_BREAKLOOP:
  1588. Status = BreakLoopWaveOutPin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
  1589. DeviceInfo->DeviceHandle );
  1590. break;
  1591. //
  1592. // Wave In State changes
  1593. //
  1594. case IOCTL_WDMAUD_WAVE_IN_STOP:
  1595. Status = StateWavePin ( &pContext->WaveInDevs[TranslatedDeviceNumber],
  1596. DeviceInfo->DeviceHandle,
  1597. KSSTATE_PAUSE );
  1598. break;
  1599. case IOCTL_WDMAUD_WAVE_IN_RECORD:
  1600. Status = StateWavePin ( &pContext->WaveInDevs[TranslatedDeviceNumber],
  1601. DeviceInfo->DeviceHandle,
  1602. KSSTATE_RUN );
  1603. break;
  1604. case IOCTL_WDMAUD_WAVE_IN_RESET:
  1605. Status = StateWavePin ( &pContext->WaveInDevs[TranslatedDeviceNumber],
  1606. DeviceInfo->DeviceHandle,
  1607. KSSTATE_STOP );
  1608. break;
  1609. default:
  1610. break;
  1611. }
  1612. }
  1613. return Status;
  1614. }
  1615. NTSTATUS
  1616. Dispatch_GetCapabilities(
  1617. PIRP pIrp,
  1618. PWDMACONTEXT pContext,
  1619. LPDEVICEINFO DeviceInfo
  1620. )
  1621. {
  1622. ULONG TranslatedDeviceNumber;
  1623. PVOID pMappedBuffer;
  1624. PMDL pMdl;
  1625. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1626. //
  1627. // Passing in DeviceInfo->DataBufferSize as the validation size because we don't care
  1628. // about the buffer check but we still want the translation code. It's just a short
  1629. // cut on the ValidateAndTranslate function.
  1630. //
  1631. Status = ValidateAndTranslate(pContext,
  1632. DeviceInfo,
  1633. DeviceInfo->DataBufferSize, // Don't care about buffer
  1634. &TranslatedDeviceNumber);
  1635. if( NT_SUCCESS(Status) )
  1636. {
  1637. //
  1638. // Map this buffer into a system address
  1639. //
  1640. wdmaudMapBuffer( pIrp,
  1641. DeviceInfo->DataBuffer,
  1642. DeviceInfo->DataBufferSize,
  1643. &pMappedBuffer,
  1644. &pMdl,
  1645. pContext,
  1646. TRUE);
  1647. if (NULL == pMappedBuffer)
  1648. {
  1649. Status = STATUS_INSUFFICIENT_RESOURCES;
  1650. }
  1651. else
  1652. {
  1653. Status = wdmaudGetDevCaps( pContext,
  1654. DeviceInfo->DeviceType,
  1655. TranslatedDeviceNumber,
  1656. pMappedBuffer,
  1657. DeviceInfo->DataBufferSize);
  1658. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  1659. //
  1660. // Free the MDL
  1661. //
  1662. wdmaudUnmapBuffer( pMdl );
  1663. }
  1664. }
  1665. return Status;
  1666. }
  1667. NTSTATUS
  1668. Dispatch_OpenPin(
  1669. PIRP pIrp,
  1670. PWDMACONTEXT pContext,
  1671. LPDEVICEINFO DeviceInfo
  1672. )
  1673. {
  1674. ULONG TranslatedDeviceNumber;
  1675. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1676. //
  1677. // Passing in DeviceInfo->DataBufferSize as the validation size because we don't care
  1678. // about the buffer check but we still want the translation code. It's just a short
  1679. // cut on the ValidateAndTranslate function.
  1680. //
  1681. Status = ValidateAndTranslate(pContext,
  1682. DeviceInfo,
  1683. DeviceInfo->DataBufferSize, // Don't care about buffer
  1684. &TranslatedDeviceNumber);
  1685. if( NT_SUCCESS(Status) )
  1686. {
  1687. switch (DeviceInfo->DeviceType)
  1688. {
  1689. case WaveOutDevice:
  1690. case WaveInDevice:
  1691. if (DeviceInfo->DataBufferSize < sizeof(PCMWAVEFORMAT))
  1692. {
  1693. Status = STATUS_INVALID_BUFFER_SIZE;
  1694. } else {
  1695. LPWAVEFORMATEX pWaveFmt = NULL;
  1696. //
  1697. // Ensure alignment by copying to temporary buffer
  1698. //
  1699. Status = CaptureBufferToLocalPool(DeviceInfo->DataBuffer,
  1700. DeviceInfo->DataBufferSize,
  1701. &pWaveFmt
  1702. #ifdef _WIN64
  1703. ,0
  1704. #endif
  1705. );
  1706. if (!NT_SUCCESS(Status))
  1707. {
  1708. Status = STATUS_INSUFFICIENT_RESOURCES;
  1709. } else {
  1710. if ((pWaveFmt->wFormatTag != WAVE_FORMAT_PCM) &&
  1711. ((DeviceInfo->DataBufferSize < sizeof(WAVEFORMATEX)) ||
  1712. (DeviceInfo->DataBufferSize != sizeof(WAVEFORMATEX) + pWaveFmt->cbSize)))
  1713. {
  1714. Status = STATUS_INVALID_BUFFER_SIZE;
  1715. }
  1716. else
  1717. {
  1718. Status = OpenWavePin( pContext,
  1719. TranslatedDeviceNumber,
  1720. pWaveFmt,
  1721. DeviceInfo->DeviceHandle,
  1722. DeviceInfo->dwFlags,
  1723. (WaveOutDevice == DeviceInfo->DeviceType?
  1724. KSPIN_DATAFLOW_IN:KSPIN_DATAFLOW_OUT) );
  1725. }
  1726. //
  1727. // Free the temporary buffer
  1728. //
  1729. AudioFreeMemory_Unknown( &pWaveFmt );
  1730. }
  1731. }
  1732. break;
  1733. case MidiOutDevice:
  1734. Status = OpenMidiPin( pContext, TranslatedDeviceNumber, KSPIN_DATAFLOW_IN );
  1735. break;
  1736. case MidiInDevice:
  1737. Status = OpenMidiPin( pContext, TranslatedDeviceNumber, KSPIN_DATAFLOW_OUT );
  1738. break;
  1739. default:
  1740. Status = STATUS_NOT_SUPPORTED;
  1741. break;
  1742. }
  1743. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  1744. }
  1745. return Status;
  1746. }
  1747. NTSTATUS
  1748. Dispatch_ClosePin(
  1749. PIRP pIrp,
  1750. PWDMACONTEXT pContext,
  1751. LPDEVICEINFO DeviceInfo
  1752. )
  1753. {
  1754. ULONG TranslatedDeviceNumber;
  1755. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1756. Status = ValidateAndTranslate(pContext,
  1757. DeviceInfo,
  1758. 0,
  1759. &TranslatedDeviceNumber);
  1760. if( NT_SUCCESS(Status) )
  1761. {
  1762. switch (DeviceInfo->DeviceType)
  1763. {
  1764. case WaveOutDevice:
  1765. CloseTheWavePin( &pContext->WaveOutDevs[TranslatedDeviceNumber],
  1766. DeviceInfo->DeviceHandle );
  1767. break;
  1768. case WaveInDevice:
  1769. CloseTheWavePin( &pContext->WaveInDevs[TranslatedDeviceNumber],
  1770. DeviceInfo->DeviceHandle );
  1771. break;
  1772. case MidiOutDevice:
  1773. CloseMidiDevicePin( &pContext->MidiOutDevs[TranslatedDeviceNumber] );
  1774. break;
  1775. case MidiInDevice:
  1776. CloseMidiDevicePin( &pContext->MidiInDevs[TranslatedDeviceNumber] );
  1777. break;
  1778. default:
  1779. Status = STATUS_NOT_SUPPORTED;
  1780. break;
  1781. }
  1782. }
  1783. return Status;
  1784. }
  1785. NTSTATUS
  1786. Dispatch_GetVolume(
  1787. PIRP pIrp,
  1788. PWDMACONTEXT pContext,
  1789. LPDEVICEINFO DeviceInfo,
  1790. ULONG IoCode
  1791. )
  1792. {
  1793. DWORD dwLeft, dwRight;
  1794. ULONG TranslatedDeviceNumber;
  1795. PVOID pMappedBuffer;
  1796. PMDL pMdl;
  1797. ULONG ulDeviceType;
  1798. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1799. Status = ValidateAndTranslate(pContext,
  1800. DeviceInfo,
  1801. sizeof(DWORD),
  1802. &TranslatedDeviceNumber);
  1803. if( NT_SUCCESS(Status) )
  1804. {
  1805. switch(IoCode)
  1806. {
  1807. case IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME:
  1808. ulDeviceType = MidiOutDevice;
  1809. break;
  1810. case IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME:
  1811. ulDeviceType = WaveOutDevice;
  1812. break;
  1813. case IOCTL_WDMAUD_GET_VOLUME:
  1814. ulDeviceType = DeviceInfo->DeviceType;
  1815. break;
  1816. default:
  1817. return STATUS_INVALID_PARAMETER;
  1818. break;
  1819. }
  1820. Status = GetVolume(pContext,
  1821. TranslatedDeviceNumber,
  1822. ulDeviceType,
  1823. &dwLeft,
  1824. &dwRight);
  1825. if( NT_SUCCESS( Status ) )
  1826. {
  1827. wdmaudMapBuffer( pIrp, // Wave buffers look like
  1828. DeviceInfo->DataBuffer, // DeviceInfo->DataBuffer
  1829. DeviceInfo->DataBufferSize, // DeviceInfo->DataBufferSize
  1830. &pMappedBuffer,
  1831. &pMdl,
  1832. pContext,
  1833. TRUE);
  1834. if (NULL == pMappedBuffer)
  1835. {
  1836. Status = STATUS_INSUFFICIENT_RESOURCES;
  1837. } else {
  1838. //
  1839. // Write this info back.
  1840. //
  1841. *((LPDWORD)pMappedBuffer) = MAKELONG(LOWORD(dwLeft),
  1842. LOWORD(dwRight));
  1843. wdmaudUnmapBuffer( pMdl );
  1844. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  1845. }
  1846. }
  1847. }
  1848. return Status;
  1849. }
  1850. NTSTATUS
  1851. Dispatch_SetVolume(
  1852. PIRP pIrp,
  1853. PWDMACONTEXT pContext,
  1854. LPDEVICEINFO DeviceInfo,
  1855. ULONG IoCode
  1856. )
  1857. {
  1858. ULONG TranslatedDeviceNumber;
  1859. PVOID pMappedBuffer;
  1860. PMDL pMdl;
  1861. ULONG ulDeviceType;
  1862. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1863. Status = ValidateAndTranslate(pContext,
  1864. DeviceInfo,
  1865. sizeof(DWORD),
  1866. &TranslatedDeviceNumber);
  1867. if( NT_SUCCESS(Status) )
  1868. {
  1869. wdmaudMapBuffer( pIrp,
  1870. DeviceInfo->DataBuffer,
  1871. DeviceInfo->DataBufferSize,
  1872. &pMappedBuffer,
  1873. &pMdl,
  1874. pContext,
  1875. TRUE);
  1876. if (NULL == pMappedBuffer)
  1877. {
  1878. Status = STATUS_INSUFFICIENT_RESOURCES;
  1879. }
  1880. else
  1881. {
  1882. switch(IoCode)
  1883. {
  1884. case IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME:
  1885. ulDeviceType = MidiOutDevice;
  1886. break;
  1887. case IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME:
  1888. ulDeviceType = WaveOutDevice;
  1889. break;
  1890. case IOCTL_WDMAUD_SET_VOLUME:
  1891. ulDeviceType = DeviceInfo->DeviceType;
  1892. break;
  1893. default:
  1894. return STATUS_INVALID_PARAMETER;
  1895. break;
  1896. }
  1897. Status = SetVolume(pContext,
  1898. TranslatedDeviceNumber,
  1899. ulDeviceType,
  1900. LOWORD(*((LPDWORD)pMappedBuffer)),
  1901. HIWORD(*((LPDWORD)pMappedBuffer)));
  1902. wdmaudUnmapBuffer( pMdl );
  1903. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  1904. }
  1905. }
  1906. return Status;
  1907. }
  1908. NTSTATUS
  1909. Dispatch_WaveGetPos(
  1910. PIRP pIrp,
  1911. PWDMACONTEXT pContext,
  1912. LPDEVICEINFO DeviceInfo,
  1913. ULONG IoCode
  1914. )
  1915. {
  1916. WAVEPOSITION WavePos;
  1917. ULONG TranslatedDeviceNumber;
  1918. PVOID pMappedBuffer;
  1919. PMDL pMdl;
  1920. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1921. Status = ValidateAndTranslate(pContext,
  1922. DeviceInfo,
  1923. sizeof(DWORD),
  1924. &TranslatedDeviceNumber);
  1925. if( NT_SUCCESS(Status) )
  1926. {
  1927. //
  1928. // Map this buffer into a system address
  1929. //
  1930. wdmaudMapBuffer( pIrp,
  1931. DeviceInfo->DataBuffer,
  1932. DeviceInfo->DataBufferSize,
  1933. &pMappedBuffer,
  1934. &pMdl,
  1935. pContext,
  1936. TRUE);
  1937. if (NULL == pMappedBuffer)
  1938. {
  1939. Status = STATUS_INSUFFICIENT_RESOURCES;
  1940. } else {
  1941. WavePos.Operation = KSPROPERTY_TYPE_GET;
  1942. switch(IoCode)
  1943. {
  1944. case IOCTL_WDMAUD_WAVE_OUT_GET_POS:
  1945. Status = PosWavePin(&pContext->WaveOutDevs[TranslatedDeviceNumber],
  1946. DeviceInfo->DeviceHandle,
  1947. &WavePos );
  1948. break;
  1949. case IOCTL_WDMAUD_WAVE_IN_GET_POS:
  1950. Status = PosWavePin ( &pContext->WaveInDevs[TranslatedDeviceNumber],
  1951. DeviceInfo->DeviceHandle,
  1952. &WavePos );
  1953. break;
  1954. default:
  1955. return STATUS_INVALID_PARAMETER;
  1956. break;
  1957. }
  1958. *((LPDWORD)pMappedBuffer) = WavePos.BytePos;
  1959. //
  1960. // Free the MDL
  1961. //
  1962. wdmaudUnmapBuffer( pMdl );
  1963. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  1964. }
  1965. }
  1966. return Status;
  1967. }
  1968. NTSTATUS
  1969. Dispatch_MidiOutWriteLongdata(
  1970. PIRP pIrp,
  1971. PWDMACONTEXT pContext,
  1972. LPDEVICEINFO DeviceInfo,
  1973. BOOL *pCompletedIrp
  1974. )
  1975. {
  1976. ULONG TranslatedDeviceNumber;
  1977. LPMIDIHDR pMidiHdr = NULL;
  1978. #ifdef _WIN64
  1979. LPMIDIHDR32 pMidiHdr32;
  1980. #endif
  1981. PSTREAM_HEADER_EX pStreamHeader = NULL;
  1982. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1983. ASSERT( FALSE == *pCompletedIrp );
  1984. //
  1985. // Verify that we received a valid midiheader
  1986. //
  1987. Status = ValidateAndTranslateEx(pIrp, pContext, DeviceInfo,
  1988. #ifdef _WIN64
  1989. sizeof(MIDIHDR32),
  1990. #endif
  1991. sizeof(MIDIHDR), &TranslatedDeviceNumber);
  1992. if( !NT_SUCCESS(Status) )
  1993. {
  1994. return Status;
  1995. }
  1996. Status = AudioAllocateMemory_Fixed(sizeof(STREAM_HEADER_EX),
  1997. TAG_Audh_STREAMHEADER,
  1998. ZERO_FILL_MEMORY,
  1999. &pStreamHeader);
  2000. if(NT_SUCCESS(Status))
  2001. {
  2002. Status = CaptureBufferToLocalPool(DeviceInfo->DataBuffer,
  2003. DeviceInfo->DataBufferSize,
  2004. &pMidiHdr
  2005. #ifdef _WIN64
  2006. ,(IoIs32bitProcess(pIrp))?sizeof(MIDIHDR):0
  2007. #endif
  2008. );
  2009. if (!NT_SUCCESS(Status))
  2010. {
  2011. AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
  2012. //
  2013. // Why do we change the status here?
  2014. //
  2015. return STATUS_INSUFFICIENT_RESOURCES;
  2016. } else {
  2017. LPVOID lpData;
  2018. DWORD dwBufferLength;
  2019. #ifdef _WIN64
  2020. // Thunk the midi header if required.
  2021. // Note this is an IN PLACE thunk, so we MUST do it in
  2022. // last element to first element order!!!
  2023. if (IoIs32bitProcess(pIrp)) {
  2024. // Thunk pMidiHdr to 64 bits.
  2025. pMidiHdr32=(LPMIDIHDR32)pMidiHdr;
  2026. #if (WINVER >= 0x0400)
  2027. {
  2028. ULONG i;
  2029. // Again we must go from LAST element to first element in this array.
  2030. // This IS the reverse of for (i=0; i<(sizeof(pMidiHdr32->dwReserved)/sizeof(UINT32)); i++)
  2031. for (i=(sizeof(pMidiHdr32->dwReserved)/sizeof(UINT32)); i--;) {
  2032. pMidiHdr->dwReserved[i]=(DWORD_PTR)pMidiHdr32->dwReserved[i];
  2033. }
  2034. }
  2035. pMidiHdr->dwOffset=pMidiHdr32->dwOffset;
  2036. #endif
  2037. pMidiHdr->reserved=(DWORD_PTR)pMidiHdr32->reserved;
  2038. pMidiHdr->lpNext=(LPMIDIHDR)(UINT_PTR)pMidiHdr32->lpNext;
  2039. pMidiHdr->dwFlags=pMidiHdr32->dwFlags;
  2040. pMidiHdr->dwUser=(DWORD_PTR)pMidiHdr32->dwUser;
  2041. pMidiHdr->dwBytesRecorded=pMidiHdr32->dwBytesRecorded;
  2042. pMidiHdr->dwBufferLength=pMidiHdr32->dwBufferLength;
  2043. pMidiHdr->lpData=(LPSTR)(UINT_PTR)pMidiHdr32->lpData;
  2044. }
  2045. #endif
  2046. //
  2047. // Capture these parameters before probing
  2048. //
  2049. lpData = pMidiHdr->lpData;
  2050. dwBufferLength = pMidiHdr->dwBufferLength;
  2051. try
  2052. {
  2053. ProbeForRead(lpData, dwBufferLength, sizeof(BYTE));
  2054. }
  2055. except (EXCEPTION_EXECUTE_HANDLER)
  2056. {
  2057. AudioFreeMemory_Unknown( &pMidiHdr );
  2058. AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
  2059. Status = GetExceptionCode();
  2060. }
  2061. if (!NT_SUCCESS(Status))
  2062. {
  2063. return Status;
  2064. }
  2065. wdmaudMapBuffer(pIrp,
  2066. lpData,
  2067. dwBufferLength,
  2068. &pStreamHeader->Header.Data,
  2069. &pStreamHeader->pBufferMdl,
  2070. pContext,
  2071. TRUE); // will be freed on completion
  2072. //
  2073. // If we get a zero-length buffer, it is alright to not have
  2074. // a kernel mapped buffer. Otherwise, fail if no Mdl or buffer.
  2075. //
  2076. if ( (dwBufferLength != 0) &&
  2077. ((NULL == pStreamHeader->pBufferMdl) ||
  2078. (NULL == pStreamHeader->Header.Data)) )
  2079. {
  2080. Status = STATUS_INSUFFICIENT_RESOURCES;
  2081. wdmaudUnmapBuffer(pStreamHeader->pBufferMdl);
  2082. AudioFreeMemory_Unknown( &pMidiHdr );
  2083. AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
  2084. } else {
  2085. pStreamHeader->pIrp = pIrp; // store so we can complete later
  2086. pStreamHeader->pMidiPin =
  2087. pContext->MidiOutDevs[TranslatedDeviceNumber].pMidiPin;
  2088. pStreamHeader->Header.FrameExtent = dwBufferLength;
  2089. //
  2090. // Must cleanup any mapped buffers and allocated memory
  2091. // on error paths in WriteMidiOutPin
  2092. //
  2093. Status = WriteMidiOutPin( pMidiHdr,pStreamHeader,pCompletedIrp );
  2094. //
  2095. // Because WriteMidiOutPin is synchronous, pCompetedIrp will
  2096. // always come back FALSE so that the caller can clean up the
  2097. // Irp.
  2098. //
  2099. ASSERT( FALSE == *pCompletedIrp );
  2100. }
  2101. }
  2102. }
  2103. return Status;
  2104. }
  2105. NTSTATUS
  2106. ValidateAndCapture(
  2107. PIRP pIrp,
  2108. LPDEVICEINFO DeviceInfo,
  2109. #ifdef _WIN64
  2110. DWORD ValidationSize32,
  2111. #endif
  2112. DWORD ValidationSize,
  2113. PVOID *ppMappedBuffer
  2114. )
  2115. {
  2116. NTSTATUS Status = STATUS_SUCCESS;
  2117. //
  2118. // Assume that we're going to have a problem.
  2119. //
  2120. *ppMappedBuffer = NULL;
  2121. #ifdef _WIN64
  2122. if (IoIs32bitProcess(pIrp)) {
  2123. if (DeviceInfo->DataBufferSize != ValidationSize32)
  2124. {
  2125. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2126. return STATUS_INVALID_BUFFER_SIZE;
  2127. }
  2128. } else {
  2129. #endif
  2130. if (DeviceInfo->DataBufferSize != ValidationSize)
  2131. {
  2132. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2133. return STATUS_INVALID_BUFFER_SIZE;
  2134. }
  2135. #ifdef _WIN64
  2136. }
  2137. #endif
  2138. //
  2139. // Copy to local data storage
  2140. //
  2141. Status = CaptureBufferToLocalPool(DeviceInfo->DataBuffer,
  2142. DeviceInfo->DataBufferSize,
  2143. ppMappedBuffer
  2144. #ifdef _WIN64
  2145. ,(IoIs32bitProcess(pIrp))?ValidationSize:0
  2146. #endif
  2147. );
  2148. return Status;
  2149. }
  2150. NTSTATUS
  2151. Dispatch_GetLineInfo(
  2152. PIRP pIrp,
  2153. PWDMACONTEXT pContext,
  2154. LPDEVICEINFO DeviceInfo
  2155. )
  2156. {
  2157. PVOID pMappedBuffer;
  2158. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  2159. //
  2160. // The size specified in this member must be large enough to
  2161. // contain the base MIXERLINE structure.
  2162. //
  2163. Status = ValidateAndCapture(pIrp,DeviceInfo,
  2164. #ifdef _WIN64
  2165. sizeof(MIXERLINE32),
  2166. #endif
  2167. sizeof(MIXERLINE), &pMappedBuffer);
  2168. if( !NT_SUCCESS(Status) )
  2169. {
  2170. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2171. goto Exit;
  2172. }
  2173. #ifdef _WIN64
  2174. // Now thunk the MIXERLINE structure to 64 bits.
  2175. // WARNING we do this a simple easy way, but it is DEPENDENT on the
  2176. // structure of MIXERLINE. There is currently only 1 parameter that
  2177. // changes in size between the 32 and 64 bit structures. dwUser.
  2178. // This will have to get more complicated if the MIXERLINE structure
  2179. // ever has more stuff in it that needs to be thunked.
  2180. if (IoIs32bitProcess(pIrp)) {
  2181. // First move everything following the dwUser field in the 32 bit
  2182. // structure down 4 bytes.
  2183. RtlMoveMemory(&((PMIXERLINE32)pMappedBuffer)->cChannels,
  2184. &((PMIXERLINE32)pMappedBuffer)->dwComponentType,
  2185. sizeof(MIXERLINE32)-FIELD_OFFSET(MIXERLINE32,dwComponentType));
  2186. // Now thunk dwUser to 64 bits.
  2187. ((PMIXERLINE)pMappedBuffer)->dwUser=(DWORD_PTR)((PMIXERLINE32)pMappedBuffer)->dwUser;
  2188. }
  2189. #endif
  2190. if (NT_SUCCESS(Status))
  2191. {
  2192. Status = kmxlGetLineInfoHandler( pContext, DeviceInfo, pMappedBuffer );
  2193. //
  2194. // This call should have set the DeviceInfo->mmr and returned a valid
  2195. // NTSTATUS value.
  2196. //
  2197. #ifdef _WIN64
  2198. // Now thunk the MIXERLINE structure back to 32 bits.
  2199. // WARNING we do this a simple easy way, but it is DEPENDENT on the
  2200. // structure of MIXERLINE. There is currently only 1 parameter that
  2201. // changes in size between the 32 and 64 bit structures. dwUser.
  2202. // This will have to get more complicated if the MIXERLINE structure
  2203. // ever has more stuff in it that needs to be thunked.
  2204. // Note that for in place thunks we must do them from LAST to FIRST
  2205. // field order when thunking up to 64 bits and in FIRST to LAST
  2206. // field order when thunking back down to 32 bits!!!
  2207. if (IoIs32bitProcess(pIrp)) {
  2208. // Just move everything that now is after dwComponentType back up 4 bytes.
  2209. RtlMoveMemory(&((PMIXERLINE32)pMappedBuffer)->dwComponentType,
  2210. &((PMIXERLINE32)pMappedBuffer)->cChannels,
  2211. sizeof(MIXERLINE32)-FIELD_OFFSET(MIXERLINE32,dwComponentType));
  2212. }
  2213. #endif
  2214. //
  2215. // Copy back the contents of the captured buffer
  2216. //
  2217. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2218. DeviceInfo->DataBufferSize,
  2219. &pMappedBuffer);
  2220. }
  2221. Exit:
  2222. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2223. return Status;
  2224. }
  2225. NTSTATUS
  2226. Dispatch_GetLineControls(
  2227. PIRP pIrp,
  2228. PWDMACONTEXT pContext,
  2229. LPDEVICEINFO DeviceInfo
  2230. )
  2231. {
  2232. PVOID pamxctrl = NULL;
  2233. PVOID pamxctrlUnmapped;
  2234. DWORD dwSize;
  2235. PVOID pMappedBuffer;
  2236. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  2237. //
  2238. // The size specified in this member must be large enough to
  2239. // contain the base MIXERLINECONTROL structure.
  2240. //
  2241. Status = ValidateAndCapture(pIrp,DeviceInfo,
  2242. #ifdef _WIN64
  2243. sizeof(MIXERLINECONTROLS32),
  2244. #endif
  2245. sizeof(MIXERLINECONTROLS), &pMappedBuffer);
  2246. if( !NT_SUCCESS(Status) )
  2247. {
  2248. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2249. goto Exit;
  2250. }
  2251. #ifdef _WIN64
  2252. // Now thunk the MIXERLINECONTROL structure to 64 bits.
  2253. // Currently this is easy to do as only the last field is different
  2254. // in size and simply needs to be zero extended.
  2255. // NOTE: This structure also thus does NOT need any thunking in
  2256. // the reverse direction! How nice.
  2257. // NOTE: None of the mixer controls themselves need any thunking.
  2258. // YEAH!!!
  2259. if (IoIs32bitProcess(pIrp)) {
  2260. ((LPMIXERLINECONTROLS)pMappedBuffer)->pamxctrl=(LPMIXERCONTROL)(UINT_PTR)((LPMIXERLINECONTROLS32)pMappedBuffer)->pamxctrl;
  2261. }
  2262. #endif
  2263. //
  2264. // Pick reasonable max values for the size and number of controls to eliminate overflow
  2265. //
  2266. if ( ( ((LPMIXERLINECONTROLS) pMappedBuffer)->cbmxctrl > 10000 ) ||
  2267. ( ((LPMIXERLINECONTROLS) pMappedBuffer)->cControls > 10000 ) )
  2268. {
  2269. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2270. DeviceInfo->DataBufferSize,
  2271. &pMappedBuffer);
  2272. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2273. Status = STATUS_INVALID_PARAMETER;
  2274. }
  2275. else
  2276. {
  2277. pamxctrlUnmapped = ((LPMIXERLINECONTROLS) pMappedBuffer)->pamxctrl;
  2278. dwSize = ((LPMIXERLINECONTROLS) pMappedBuffer)->cbmxctrl *
  2279. ((LPMIXERLINECONTROLS) pMappedBuffer)->cControls;
  2280. try
  2281. {
  2282. ProbeForWrite(pamxctrlUnmapped, dwSize, sizeof(DWORD));
  2283. }
  2284. except (EXCEPTION_EXECUTE_HANDLER)
  2285. {
  2286. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2287. DeviceInfo->DataBufferSize,
  2288. &pMappedBuffer);
  2289. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2290. Status = GetExceptionCode();
  2291. }
  2292. }
  2293. if (NT_SUCCESS(Status))
  2294. {
  2295. //
  2296. // Map the array of mixer controls into system space. The
  2297. // size of this buffer is the number of controls times the
  2298. // size of each control.
  2299. //
  2300. Status = CaptureBufferToLocalPool(pamxctrlUnmapped,
  2301. dwSize,
  2302. &pamxctrl
  2303. #ifdef _WIN64
  2304. ,0
  2305. #endif
  2306. );
  2307. if (NT_SUCCESS(Status))
  2308. {
  2309. //
  2310. // Call the handler.
  2311. //
  2312. Status = kmxlGetLineControlsHandler(pContext,
  2313. DeviceInfo,
  2314. pMappedBuffer,
  2315. pamxctrl );
  2316. //
  2317. // The previous call should have set the DeviceInfo->mmr and returned
  2318. // a valid Status value.
  2319. //
  2320. CopyAndFreeCapturedBuffer(pamxctrlUnmapped,
  2321. dwSize,
  2322. &pamxctrl);
  2323. } else {
  2324. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2325. }
  2326. } else {
  2327. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2328. }
  2329. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2330. DeviceInfo->DataBufferSize,
  2331. &pMappedBuffer);
  2332. Exit:
  2333. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2334. return Status;
  2335. }
  2336. #ifdef _WIN64
  2337. void
  2338. ThunkMixerControlDetails_Enter(
  2339. PVOID pMappedBuffer
  2340. )
  2341. {
  2342. // Now thunk the MIXERCONTROLDETAILS structure to 64 bits.
  2343. // This is an IN PLACE thunk, so MUST be done from last to first fields.
  2344. ((LPMIXERCONTROLDETAILS)pMappedBuffer)->paDetails=(LPVOID)(UINT_PTR)((LPMIXERCONTROLDETAILS32)pMappedBuffer)->paDetails;
  2345. ((LPMIXERCONTROLDETAILS)pMappedBuffer)->cbDetails=((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cbDetails;
  2346. // We always thunk the next field as if it were an HWND since that works for both cases.
  2347. ((LPMIXERCONTROLDETAILS)pMappedBuffer)->hwndOwner=(HWND)(UINT_PTR)((LPMIXERCONTROLDETAILS32)pMappedBuffer)->hwndOwner;
  2348. ((LPMIXERCONTROLDETAILS)pMappedBuffer)->cChannels=((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cChannels;
  2349. ((LPMIXERCONTROLDETAILS)pMappedBuffer)->dwControlID=((LPMIXERCONTROLDETAILS32)pMappedBuffer)->dwControlID;
  2350. ((LPMIXERCONTROLDETAILS)pMappedBuffer)->cbStruct=((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cbStruct;
  2351. }
  2352. void
  2353. ThunkMixerControlDetails_Leave(
  2354. PVOID pMappedBuffer
  2355. )
  2356. {
  2357. // Now thunk the MIXERCONTROLDETAILS structure back to 32 bits.
  2358. // This is an IN PLACE thunk, so MUST be done from FIRST to LAST
  2359. // fields. Remember the order is different depending on direction!
  2360. ((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cbStruct=((LPMIXERCONTROLDETAILS)pMappedBuffer)->cbStruct;
  2361. ((LPMIXERCONTROLDETAILS32)pMappedBuffer)->dwControlID=((LPMIXERCONTROLDETAILS)pMappedBuffer)->dwControlID;
  2362. ((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cChannels=((LPMIXERCONTROLDETAILS)pMappedBuffer)->cChannels;
  2363. // We always thunk the next field as if it were an HWND since that works for both cases.
  2364. ((LPMIXERCONTROLDETAILS32)pMappedBuffer)->hwndOwner=(UINT32)(UINT_PTR)((LPMIXERCONTROLDETAILS)pMappedBuffer)->hwndOwner;
  2365. ((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cbDetails=((LPMIXERCONTROLDETAILS)pMappedBuffer)->cbDetails;
  2366. ((LPMIXERCONTROLDETAILS32)pMappedBuffer)->paDetails=(UINT32)(UINT_PTR)((LPMIXERCONTROLDETAILS)pMappedBuffer)->paDetails;
  2367. }
  2368. #endif
  2369. NTSTATUS
  2370. Dispatch_GetControlDetails(
  2371. PIRP pIrp,
  2372. PWDMACONTEXT pContext,
  2373. LPDEVICEINFO DeviceInfo
  2374. )
  2375. {
  2376. PVOID paDetails = NULL;
  2377. PVOID paDetailsUnmapped;
  2378. DWORD dwSize;
  2379. PVOID pMappedBuffer;
  2380. NTSTATUS Status = STATUS_SUCCESS; // Assume success.
  2381. Status = ValidateAndCapture(pIrp,DeviceInfo,
  2382. #ifdef _WIN64
  2383. sizeof(MIXERCONTROLDETAILS32),
  2384. #endif
  2385. sizeof(MIXERCONTROLDETAILS), &pMappedBuffer);
  2386. if( !NT_SUCCESS(Status) )
  2387. {
  2388. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2389. goto Exit;
  2390. }
  2391. #ifdef _WIN64
  2392. if (IoIs32bitProcess(pIrp)) {
  2393. ThunkMixerControlDetails_Enter(pMappedBuffer);
  2394. }
  2395. #endif
  2396. //
  2397. // Pick reasonable max values for the data and number of controls to eliminate overflow
  2398. //
  2399. if ( ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails > 10000 ) ||
  2400. ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels > 100 ) ||
  2401. ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems > 100 ) )
  2402. {
  2403. #ifdef _WIN64
  2404. if (IoIs32bitProcess(pIrp)) {
  2405. ThunkMixerControlDetails_Leave(pMappedBuffer);
  2406. }
  2407. #endif
  2408. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2409. DeviceInfo->DataBufferSize,
  2410. &pMappedBuffer);
  2411. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2412. Status = STATUS_INVALID_PARAMETER;
  2413. } else {
  2414. //
  2415. // Map the array control details into system space.
  2416. //
  2417. paDetailsUnmapped = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->paDetails;
  2418. if( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems )
  2419. {
  2420. dwSize = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels *
  2421. ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems *
  2422. ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails;
  2423. } else {
  2424. dwSize = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels *
  2425. ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails;
  2426. }
  2427. try
  2428. {
  2429. ProbeForWrite(paDetailsUnmapped,
  2430. dwSize,
  2431. sizeof(DWORD));
  2432. }
  2433. except (EXCEPTION_EXECUTE_HANDLER)
  2434. {
  2435. #ifdef _WIN64
  2436. if (IoIs32bitProcess(pIrp)) {
  2437. ThunkMixerControlDetails_Leave(pMappedBuffer);
  2438. }
  2439. #endif
  2440. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2441. DeviceInfo->DataBufferSize,
  2442. &pMappedBuffer);
  2443. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2444. Status = GetExceptionCode();
  2445. }
  2446. }
  2447. if (NT_SUCCESS(Status))
  2448. {
  2449. Status = CaptureBufferToLocalPool(paDetailsUnmapped,
  2450. dwSize,
  2451. &paDetails
  2452. #ifdef _WIN64
  2453. ,0
  2454. #endif
  2455. );
  2456. if (NT_SUCCESS(Status))
  2457. {
  2458. //
  2459. // Call the handler.
  2460. //
  2461. Status = kmxlGetControlDetailsHandler(pContext,
  2462. DeviceInfo,
  2463. pMappedBuffer,
  2464. paDetails);
  2465. //
  2466. // The previous call should have set DeviceInfo->mmr and returned
  2467. // a valid Status value.
  2468. //
  2469. CopyAndFreeCapturedBuffer(paDetailsUnmapped,
  2470. dwSize,
  2471. &paDetails);
  2472. } else {
  2473. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2474. }
  2475. } else {
  2476. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2477. }
  2478. #ifdef _WIN64
  2479. if (IoIs32bitProcess(pIrp) && pMappedBuffer) {
  2480. ThunkMixerControlDetails_Leave(pMappedBuffer);
  2481. }
  2482. #endif
  2483. CopyAndFreeCapturedBuffer( DeviceInfo->DataBuffer,
  2484. DeviceInfo->DataBufferSize,
  2485. &pMappedBuffer);
  2486. Exit:
  2487. //
  2488. // Always return the DEVICEINFO number of bytes from this call.
  2489. //
  2490. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2491. return Status;
  2492. }
  2493. NTSTATUS
  2494. Dispatch_SetControlDetails(
  2495. PIRP pIrp,
  2496. PWDMACONTEXT pContext,
  2497. LPDEVICEINFO DeviceInfo
  2498. )
  2499. {
  2500. PVOID paDetails = NULL;
  2501. PVOID paDetailsUnmapped;
  2502. DWORD dwSize;
  2503. PVOID pMappedBuffer;
  2504. NTSTATUS Status = STATUS_SUCCESS; //Assume success.
  2505. Status = ValidateAndCapture(pIrp,DeviceInfo,
  2506. #ifdef _WIN64
  2507. sizeof(MIXERCONTROLDETAILS32),
  2508. #endif
  2509. sizeof(MIXERCONTROLDETAILS), &pMappedBuffer);
  2510. if( !NT_SUCCESS(Status) )
  2511. {
  2512. goto Exit;
  2513. }
  2514. #ifdef _WIN64
  2515. // Now thunk the MIXERCONTROLDETAILS structure to 64 bits.
  2516. // This is an IN PLACE thunk, so MUST be done from last to first fields.
  2517. if (IoIs32bitProcess(pIrp)) {
  2518. ThunkMixerControlDetails_Enter(pMappedBuffer);
  2519. }
  2520. #endif
  2521. //
  2522. // Pick reasonable max values for the data and number of controls to eliminate overflow
  2523. //
  2524. if ( ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails > 10000 ) ||
  2525. ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels > 100 ) ||
  2526. ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems > 100 ) )
  2527. {
  2528. #ifdef _WIN64
  2529. if (IoIs32bitProcess(pIrp)) {
  2530. ThunkMixerControlDetails_Leave(pMappedBuffer);
  2531. }
  2532. #endif
  2533. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2534. DeviceInfo->DataBufferSize,
  2535. &pMappedBuffer);
  2536. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2537. Status = STATUS_INVALID_PARAMETER;
  2538. } else {
  2539. //
  2540. // Map the array control details into system space.
  2541. //
  2542. paDetailsUnmapped = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->paDetails;
  2543. if( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems )
  2544. {
  2545. dwSize = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels *
  2546. ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems *
  2547. ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails;
  2548. } else {
  2549. dwSize = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels *
  2550. ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails;
  2551. }
  2552. try
  2553. {
  2554. ProbeForRead(((LPMIXERCONTROLDETAILS) pMappedBuffer)->paDetails,
  2555. dwSize,
  2556. sizeof(DWORD));
  2557. }
  2558. except (EXCEPTION_EXECUTE_HANDLER)
  2559. {
  2560. #ifdef _WIN64
  2561. if (IoIs32bitProcess(pIrp)) {
  2562. ThunkMixerControlDetails_Leave(pMappedBuffer);
  2563. }
  2564. #endif
  2565. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2566. DeviceInfo->DataBufferSize,
  2567. &pMappedBuffer);
  2568. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2569. Status = GetExceptionCode();
  2570. }
  2571. }
  2572. if (NT_SUCCESS(Status))
  2573. {
  2574. Status = CaptureBufferToLocalPool(paDetailsUnmapped,
  2575. dwSize,
  2576. &paDetails
  2577. #ifdef _WIN64
  2578. ,0
  2579. #endif
  2580. );
  2581. if (NT_SUCCESS(Status))
  2582. {
  2583. //
  2584. // Call the handler.
  2585. //
  2586. Status = kmxlSetControlDetailsHandler(pContext,
  2587. DeviceInfo,
  2588. pMappedBuffer,
  2589. paDetails,
  2590. MIXER_FLAG_PERSIST );
  2591. //
  2592. // The previous call should have set DeviceInfo->mmr and returned
  2593. // a valid Status value.
  2594. //
  2595. CopyAndFreeCapturedBuffer(paDetailsUnmapped,
  2596. dwSize,
  2597. &paDetails);
  2598. } else {
  2599. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2600. }
  2601. } else {
  2602. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2603. }
  2604. #ifdef _WIN64
  2605. if (IoIs32bitProcess(pIrp) && pMappedBuffer) {
  2606. ThunkMixerControlDetails_Leave(pMappedBuffer);
  2607. }
  2608. #endif
  2609. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2610. DeviceInfo->DataBufferSize,
  2611. &pMappedBuffer);
  2612. Exit:
  2613. //
  2614. // Always return sizeof(DEVICEINFO) for this call.
  2615. //
  2616. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2617. return Status;
  2618. }
  2619. NTSTATUS
  2620. Dispatch_GetHardwareEventData(
  2621. PIRP pIrp,
  2622. LPDEVICEINFO DeviceInfo
  2623. )
  2624. {
  2625. NTSTATUS Status = STATUS_SUCCESS;
  2626. //
  2627. // Always return sizeof(DEVICEINFO) for this call.
  2628. //
  2629. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2630. if (DeviceInfo->DataBufferSize != 0)
  2631. {
  2632. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2633. Status = STATUS_INVALID_PARAMETER;
  2634. } else {
  2635. GetHardwareEventData(DeviceInfo);
  2636. }
  2637. return Status;
  2638. }
  2639. NTSTATUS
  2640. SoundDispatch(
  2641. IN PDEVICE_OBJECT pDO,
  2642. IN PIRP pIrp
  2643. )
  2644. /*++
  2645. Routine Description:
  2646. Driver dispatch routine. Processes IRPs based on IRP MajorFunction
  2647. Arguments:
  2648. pDO -- pointer to the device object
  2649. pIrp -- pointer to the IRP to process
  2650. Return Value:
  2651. Returns the value of the IRP IoStatus.Status
  2652. --*/
  2653. {
  2654. PIO_STACK_LOCATION pIrpStack;
  2655. PWDMACONTEXT pContext;
  2656. LPDEVICEINFO DeviceInfo;
  2657. #ifdef _WIN64
  2658. LPDEVICEINFO32 DeviceInfo32=NULL;
  2659. LOCALDEVICEINFO LocalDeviceInfo;
  2660. #endif
  2661. LPVOID DataBuffer;
  2662. DWORD DataBufferSize;
  2663. ULONG IoCode;
  2664. NTSTATUS Status = STATUS_SUCCESS;
  2665. PAGED_CODE();
  2666. //
  2667. // Get the CurrentStackLocation and log it so we know what is going on
  2668. //
  2669. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  2670. IoCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
  2671. pContext = pIrpStack->FileObject->FsContext;
  2672. ASSERT(pContext);
  2673. ASSERT(pIrpStack->MajorFunction != IRP_MJ_CREATE &&
  2674. pIrpStack->MajorFunction != IRP_MJ_CLOSE);
  2675. //
  2676. // Can't assume that FsContext is initialized if the device has
  2677. // been opened with FO_DIRECT_DEVICE_OPEN
  2678. //
  2679. if (pIrpStack->FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
  2680. {
  2681. DPF(DL_TRACE|FA_IOCTL, ("IRP_MJ_DEVICE_CONTROL: Opened with FO_DIRECT_DEVICE_OPEN, no device context") );
  2682. return KsDefaultDeviceIoCompletion(pDO, pIrp);
  2683. }
  2684. Status = ValidateIrp(pIrp);
  2685. if (!NT_SUCCESS(Status))
  2686. {
  2687. pIrp->IoStatus.Status = Status;
  2688. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  2689. RETURN( Status );
  2690. }
  2691. #ifdef _WIN64
  2692. if (IoIs32bitProcess(pIrp)) {
  2693. DeviceInfo32=((LPDEVICEINFO32)pIrp->AssociatedIrp.SystemBuffer);
  2694. RtlZeroMemory(&LocalDeviceInfo, sizeof(LOCALDEVICEINFO));
  2695. DeviceInfo=&LocalDeviceInfo.DeviceInfo;
  2696. ThunkDeviceInfo3264(DeviceInfo32, DeviceInfo);
  2697. } else {
  2698. #endif
  2699. DeviceInfo = ((LPDEVICEINFO)pIrp->AssociatedIrp.SystemBuffer);
  2700. #ifdef _WIN64
  2701. }
  2702. #endif
  2703. DataBufferSize = DeviceInfo->DataBufferSize;
  2704. WdmaGrabMutex(pContext);
  2705. switch (pIrpStack->MajorFunction)
  2706. {
  2707. case IRP_MJ_DEVICE_CONTROL:
  2708. {
  2709. switch (IoCode)
  2710. {
  2711. case IOCTL_WDMAUD_INIT:
  2712. DPF( DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_INIT"));
  2713. if (DataBufferSize != 0)
  2714. {
  2715. Status = STATUS_INVALID_BUFFER_SIZE;
  2716. break;
  2717. }
  2718. WdmaReleaseMutex(pContext);
  2719. //
  2720. // If sysaudio fails to load, the device interface
  2721. // will be disabled and the SysAudioPnPNotification
  2722. // will not be called anymore until the sysaudio
  2723. // device interface is reenabled.
  2724. //
  2725. if ( IsSysaudioInterfaceActive() )
  2726. {
  2727. KeWaitForSingleObject(&pContext->InitializedSysaudioEvent,
  2728. Executive, KernelMode, FALSE, NULL);
  2729. // This could happen if there was an error in InitializeSysaudio or
  2730. // the memory allocation failed in QueueWorkList
  2731. if (pContext->fInitializeSysaudio == FALSE)
  2732. {
  2733. Status = STATUS_NOT_SUPPORTED;
  2734. DPF(DL_WARNING|FA_IOCTL, ("IOCTL_WDMAUD_INIT: Didn't init sysaudio! Failing IOCTL_WDMAUD_INIT: %08x", Status));
  2735. }
  2736. }
  2737. else
  2738. {
  2739. Status = STATUS_NOT_SUPPORTED;
  2740. DPF(DL_WARNING|FA_IOCTL, ("IOCTL_WDMAUD_INIT: Sysaudio Device interface disabled! Failing IOCTL_WDMAUD_INIT: %08x", Status));
  2741. }
  2742. WdmaGrabMutex(pContext);
  2743. break;
  2744. case IOCTL_WDMAUD_EXIT:
  2745. if (DataBufferSize != 0)
  2746. {
  2747. Status = STATUS_INVALID_BUFFER_SIZE;
  2748. break;
  2749. }
  2750. DPF( DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_EXIT"));
  2751. break;
  2752. case IOCTL_WDMAUD_ADD_DEVNODE:
  2753. {
  2754. DPF( DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_ADD_DEVNODE"));
  2755. if (DataBufferSize != 0)
  2756. {
  2757. Status = STATUS_INVALID_BUFFER_SIZE;
  2758. break;
  2759. }
  2760. DPF(DL_TRACE|FA_INSTANCE,("pContext=%08X, DI=%08X DeviceType=%08X",
  2761. pContext,
  2762. DeviceInfo->wstrDeviceInterface,
  2763. DeviceInfo->DeviceType) );
  2764. Status=AddDevNode(pContext, DeviceInfo->wstrDeviceInterface, DeviceInfo->DeviceType);
  2765. break;
  2766. }
  2767. case IOCTL_WDMAUD_REMOVE_DEVNODE:
  2768. {
  2769. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_REMOVE_DEVNODE"));
  2770. if (DataBufferSize != 0)
  2771. {
  2772. Status = STATUS_INVALID_BUFFER_SIZE;
  2773. break;
  2774. }
  2775. RemoveDevNode(pContext, DeviceInfo->wstrDeviceInterface, DeviceInfo->DeviceType);
  2776. break;
  2777. }
  2778. case IOCTL_WDMAUD_GET_CAPABILITIES:
  2779. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_GET_CAPABILITIES"));
  2780. Status = Dispatch_GetCapabilities(pIrp,pContext,
  2781. DeviceInfo);
  2782. break;
  2783. case IOCTL_WDMAUD_GET_NUM_DEVS:
  2784. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_GET_NUM_DEVS"));
  2785. if (DataBufferSize != 0)
  2786. {
  2787. Status = STATUS_INVALID_BUFFER_SIZE;
  2788. break;
  2789. }
  2790. Status = wdmaudGetNumDevs(pContext,
  2791. DeviceInfo->DeviceType,
  2792. DeviceInfo->wstrDeviceInterface,
  2793. &DeviceInfo->DeviceNumber);
  2794. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2795. DeviceInfo->mmr=MMSYSERR_NOERROR;
  2796. break;
  2797. case IOCTL_WDMAUD_SET_PREFERRED_DEVICE:
  2798. DPF(DL_TRACE|FA_IOCTL,
  2799. ("IOCTL_WDMAUD_SET_PREFERRED_DEVICE %d",
  2800. DeviceInfo->DeviceNumber));
  2801. Status = SetPreferredDevice(pContext, DeviceInfo);
  2802. break;
  2803. case IOCTL_WDMAUD_OPEN_PIN:
  2804. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_OPEN_PIN"));
  2805. UpdatePreferredDevice(pContext);
  2806. Status = Dispatch_OpenPin(pIrp,
  2807. pContext,
  2808. DeviceInfo);
  2809. break;
  2810. case IOCTL_WDMAUD_CLOSE_PIN:
  2811. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_CLOSE_PIN"));
  2812. Status = Dispatch_ClosePin(pIrp,
  2813. pContext,
  2814. DeviceInfo);
  2815. break;
  2816. //
  2817. // WaveOut, wavein, midiout and midiin routines
  2818. //
  2819. case IOCTL_WDMAUD_WAVE_OUT_PAUSE:
  2820. case IOCTL_WDMAUD_WAVE_OUT_PLAY:
  2821. case IOCTL_WDMAUD_WAVE_OUT_RESET:
  2822. case IOCTL_WDMAUD_WAVE_OUT_BREAKLOOP:
  2823. case IOCTL_WDMAUD_WAVE_IN_STOP:
  2824. case IOCTL_WDMAUD_WAVE_IN_RECORD:
  2825. case IOCTL_WDMAUD_WAVE_IN_RESET:
  2826. case IOCTL_WDMAUD_MIDI_OUT_RESET:
  2827. case IOCTL_WDMAUD_MIDI_OUT_WRITE_DATA:
  2828. case IOCTL_WDMAUD_MIDI_IN_STOP:
  2829. case IOCTL_WDMAUD_MIDI_IN_RECORD:
  2830. case IOCTL_WDMAUD_MIDI_IN_RESET:
  2831. Status = Dispatch_State(pIrp,
  2832. pContext,
  2833. DeviceInfo,
  2834. IoCode);
  2835. break;
  2836. case IOCTL_WDMAUD_WAVE_OUT_GET_POS:
  2837. case IOCTL_WDMAUD_WAVE_IN_GET_POS:
  2838. Status = Dispatch_WaveGetPos(pIrp,pContext,
  2839. DeviceInfo,IoCode);
  2840. break;
  2841. case IOCTL_WDMAUD_GET_VOLUME:
  2842. case IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME:
  2843. case IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME:
  2844. Status = Dispatch_GetVolume(pIrp,pContext,
  2845. DeviceInfo,IoCode);
  2846. break;
  2847. case IOCTL_WDMAUD_SET_VOLUME:
  2848. case IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME:
  2849. case IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME:
  2850. Status = Dispatch_SetVolume(pIrp,pContext,
  2851. DeviceInfo,IoCode);
  2852. break;
  2853. case IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN:
  2854. {
  2855. BOOL bCompletedIrp = FALSE;
  2856. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN"));
  2857. Status = Dispatch_WaveOutWritePin(pIrp,pContext,
  2858. DeviceInfo,&bCompletedIrp);
  2859. if( bCompletedIrp )
  2860. {
  2861. //
  2862. // !!! NOTE: Must return here so that we don't call IoCompleteRequest later !!!
  2863. //
  2864. WdmaReleaseMutex(pContext);
  2865. // For 32 bit irps we do NOT need to thunk DeviceInfo back to 32 bits, since
  2866. // nothing in this case statement has written anything into the DeviceInfo
  2867. // structure. If thunking back is ever required, make sure to NOT touch a
  2868. // potentially already completed irp. WriteWaveOutPin now completes the irp
  2869. // in some cases.
  2870. return Status ;
  2871. }
  2872. //
  2873. // If there was some problem trying to schedule the Irp we will
  2874. // end up here. bCompleteIrp will still be FALSE indicating that
  2875. // we need to complete the Irp. So, we break out of the switch
  2876. // statement, endin up at the end of SoundDispatch perform cleanup
  2877. // and complete the Irp.
  2878. //
  2879. }
  2880. break;
  2881. //
  2882. // WaveIn routines
  2883. //
  2884. case IOCTL_WDMAUD_WAVE_IN_READ_PIN:
  2885. {
  2886. BOOL bCompletedIrp = FALSE;
  2887. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_WAVE_IN_READ_PIN"));
  2888. Status = Dispatch_WaveInReadPin(pIrp,pContext,
  2889. DeviceInfo,&bCompletedIrp);
  2890. if( bCompletedIrp )
  2891. {
  2892. //
  2893. // Don't need the lock any longer.
  2894. //
  2895. WdmaReleaseMutex(pContext);
  2896. return Status;
  2897. }
  2898. // For 32 bit irps we do NOT need to thunk DeviceInfo back to 32 bits, since
  2899. // nothing in this case statement has written anything into the DeviceInfo
  2900. // structure. If thunking back is ever required, make sure to NOT touch a
  2901. // potentially already completed irp. ReadWaveInPin now completes the irp
  2902. // in some cases.
  2903. //
  2904. // If there was some problem trying to schedule the Irp we will
  2905. // end up here. bCompleteIrp will still be FALSE indicating that
  2906. // we need to complete the Irp. So, we break out of the switch
  2907. // statement, endin up at the end of SoundDispatch perform cleanup
  2908. // and complete the Irp.
  2909. //
  2910. }
  2911. break;
  2912. //
  2913. // MidiOut routines
  2914. //
  2915. case IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA:
  2916. {
  2917. BOOL bCompletedIrp = FALSE;
  2918. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA"));
  2919. Status = Dispatch_MidiOutWriteLongdata(pIrp,
  2920. pContext,
  2921. DeviceInfo,
  2922. &bCompletedIrp);
  2923. //
  2924. // If it was completed already, don't do it again!
  2925. //
  2926. if( bCompletedIrp )
  2927. {
  2928. //
  2929. // Don't need the lock any longer.
  2930. //
  2931. WdmaReleaseMutex(pContext);
  2932. // For 32 bit irps we do NOT need to thunk DeviceInfo back to 32 bits, since
  2933. // nothing in this case statement has written anything into the DeviceInfo
  2934. // structure. If thunking back is ever required, make sure to NOT touch a
  2935. // potentially already completed irp. wdmaudUnprepareIrp now completes the irp
  2936. // in most cases.
  2937. return Status;
  2938. }
  2939. //
  2940. // If there was some problem trying to schedule the Irp we will
  2941. // end up here. bCompleteIrp will still be FALSE indicating that
  2942. // we need to complete the Irp. So, we break out of the switch
  2943. // statement, endin up at the end of SoundDispatch perform cleanup
  2944. // and complete the Irp.
  2945. //
  2946. }
  2947. break;
  2948. //
  2949. // MidiIn routines
  2950. //
  2951. //
  2952. // Buffers for recording MIDI messages...
  2953. //
  2954. case IOCTL_WDMAUD_MIDI_IN_READ_PIN:
  2955. {
  2956. BOOL bCompletedIrp = FALSE;
  2957. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIDI_IN_READ_PIN"));
  2958. Status = Dispatch_MidiInReadPin(pIrp,pContext,
  2959. DeviceInfo,&bCompletedIrp);
  2960. //
  2961. // If it was completed already, don't do it again!
  2962. //
  2963. if( bCompletedIrp )
  2964. {
  2965. //
  2966. // Don't need the lock any longer.
  2967. //
  2968. WdmaReleaseMutex(pContext);
  2969. // For 32 bit irps we do NOT need to thunk DeviceInfo back to 32 bits, since
  2970. // nothing in this case statement has written anything into the DeviceInfo
  2971. // structure. If thunking back is ever required, make sure to NOT touch a
  2972. // potentially already completed irp. wdmaudUnprepareIrp now completes the irp
  2973. // in most cases.
  2974. return Status;
  2975. }
  2976. //
  2977. // If there was some problem trying to schedule the Irp we will
  2978. // end up here. bCompleteIrp will still be FALSE indicating that
  2979. // we need to complete the Irp. So, we break out of the switch
  2980. // statement, endin up at the end of SoundDispatch perform cleanup
  2981. // and complete the Irp.
  2982. //
  2983. }
  2984. break;
  2985. case IOCTL_WDMAUD_MIXER_OPEN:
  2986. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_OPEN"));
  2987. {
  2988. extern PKEVENT pHardwareCallbackEvent;
  2989. if (DataBufferSize != 0)
  2990. {
  2991. Status = STATUS_INVALID_BUFFER_SIZE;
  2992. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2993. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2994. break;
  2995. }
  2996. if (pHardwareCallbackEvent==NULL && DeviceInfo->HardwareCallbackEventHandle) {
  2997. Status = ObReferenceObjectByHandle(DeviceInfo->HardwareCallbackEventHandle, EVENT_ALL_ACCESS, *ExEventObjectType, pIrp->RequestorMode, (PVOID *)&pHardwareCallbackEvent, NULL);
  2998. if (Status!=STATUS_SUCCESS) {
  2999. DPF(DL_WARNING|FA_IOCTL, ("Could not reference hardware callback event object!"));
  3000. }
  3001. }
  3002. Status = kmxlOpenHandler( pContext, DeviceInfo, NULL );
  3003. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  3004. }
  3005. break;
  3006. case IOCTL_WDMAUD_MIXER_CLOSE:
  3007. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_CLOSE"));
  3008. if (DataBufferSize != 0)
  3009. {
  3010. Status = STATUS_INVALID_PARAMETER;
  3011. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  3012. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  3013. break;
  3014. }
  3015. Status = kmxlCloseHandler( DeviceInfo, NULL );
  3016. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  3017. break;
  3018. case IOCTL_WDMAUD_MIXER_GETLINEINFO:
  3019. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_GETLINEINFO"));
  3020. Status = Dispatch_GetLineInfo(pIrp,
  3021. pContext,
  3022. DeviceInfo);
  3023. break;
  3024. case IOCTL_WDMAUD_MIXER_GETLINECONTROLS:
  3025. {
  3026. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_GETLINECONTROLS"));
  3027. Status = Dispatch_GetLineControls(pIrp,
  3028. pContext,
  3029. DeviceInfo);
  3030. break;
  3031. }
  3032. case IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS:
  3033. {
  3034. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS"));
  3035. Status = Dispatch_GetControlDetails(pIrp,
  3036. pContext,
  3037. DeviceInfo);
  3038. break;
  3039. }
  3040. case IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS:
  3041. {
  3042. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS"));
  3043. Status = Dispatch_SetControlDetails(pIrp,
  3044. pContext,
  3045. DeviceInfo);
  3046. break;
  3047. }
  3048. case IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA:
  3049. {
  3050. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA"));
  3051. Status = Dispatch_GetHardwareEventData(pIrp,
  3052. DeviceInfo);
  3053. break;
  3054. }
  3055. default:
  3056. {
  3057. Status = STATUS_NOT_SUPPORTED;
  3058. break;
  3059. }
  3060. } // end of switch on IOCTL
  3061. break;
  3062. }
  3063. default:
  3064. {
  3065. Status = STATUS_NOT_SUPPORTED;
  3066. break;
  3067. }
  3068. } // end of switch on IRP_MAJOR_XXXX
  3069. #ifdef _WIN64
  3070. if (IoIs32bitProcess(pIrp)) {
  3071. if (DeviceInfo32!=NULL) {
  3072. ThunkDeviceInfo6432(DeviceInfo, DeviceInfo32);
  3073. }
  3074. else {
  3075. DPF(DL_WARNING|FA_IOCTL,("DeviceInfo32") );
  3076. }
  3077. }
  3078. #endif
  3079. //
  3080. // Now complete the IRP
  3081. //
  3082. pIrp->IoStatus.Status = Status;
  3083. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  3084. WdmaReleaseMutex(pContext);
  3085. RETURN( Status );
  3086. }