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

3534 lines
118 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.
  1424. //
  1425. ASSERT(Status == STATUS_PENDING);
  1426. }
  1427. }
  1428. }
  1429. return Status;
  1430. }
  1431. NTSTATUS
  1432. Dispatch_MidiInReadPin(
  1433. PIRP pIrp,
  1434. PWDMACONTEXT pContext,
  1435. LPDEVICEINFO DeviceInfo,
  1436. OUT BOOL *pCompletedIrp // TRUE if Irp was completed.
  1437. )
  1438. {
  1439. ULONG TranslatedDeviceNumber;
  1440. PMIDIINHDR pNewMidiInHdr = NULL;
  1441. LPMIDIDATA pMidiData;
  1442. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1443. //
  1444. // Assume that things will be successful. Write back that it's not completed.
  1445. //
  1446. ASSERT(FALSE == *pCompletedIrp );
  1447. //
  1448. // Verify that we received a valid mididata structure
  1449. //
  1450. Status = ValidateAndTranslate(pContext,
  1451. DeviceInfo,
  1452. sizeof(MIDIDATA),
  1453. &TranslatedDeviceNumber);
  1454. if( NT_SUCCESS(Status) )
  1455. {
  1456. Status = AudioAllocateMemory_Fixed(sizeof(*pNewMidiInHdr),
  1457. TAG_Aude_MIDIHEADER,
  1458. ZERO_FILL_MEMORY,
  1459. &pNewMidiInHdr);
  1460. if(NT_SUCCESS(Status))
  1461. {
  1462. wdmaudMapBuffer( pIrp,
  1463. DeviceInfo->DataBuffer,
  1464. DeviceInfo->DataBufferSize,
  1465. &pMidiData,
  1466. &pNewMidiInHdr->pMdl,
  1467. pContext,
  1468. TRUE);
  1469. if (NULL == pNewMidiInHdr->pMdl)
  1470. {
  1471. AudioFreeMemory( sizeof(*pNewMidiInHdr),&pNewMidiInHdr );
  1472. Status = STATUS_INSUFFICIENT_RESOURCES;
  1473. } else {
  1474. PWDMAPENDINGIRP_CONTEXT pPendingIrpContext;
  1475. //
  1476. // wdmaudPreparteIrp marks the irp as pending, thus
  1477. // we must not complete the irp when we get to this
  1478. // point in the code.
  1479. //
  1480. Status = wdmaudPrepareIrp ( pIrp, MidiInDevice, pContext, &pPendingIrpContext );
  1481. if (NT_SUCCESS(Status))
  1482. {
  1483. //
  1484. // Initialize this new MidiIn header
  1485. //
  1486. pNewMidiInHdr->pMidiData = pMidiData;
  1487. pNewMidiInHdr->pIrp = pIrp;
  1488. pNewMidiInHdr->pPendingIrpContext = pPendingIrpContext;
  1489. //
  1490. // Add this header to the tail of the queue
  1491. //
  1492. // Must cleanup any mapped buffers and allocated memory
  1493. // on error paths in AddBufferToMidiInQueue
  1494. //
  1495. Status = AddBufferToMidiInQueue( pContext->MidiInDevs[TranslatedDeviceNumber].pMidiPin,
  1496. pNewMidiInHdr );
  1497. if (STATUS_PENDING != Status)
  1498. {
  1499. // Must have been an error, complete Irp
  1500. wdmaudUnmapBuffer( pNewMidiInHdr->pMdl );
  1501. AudioFreeMemory_Unknown( &pNewMidiInHdr );
  1502. wdmaudUnprepareIrp( pIrp, Status, 0, pPendingIrpContext );
  1503. }
  1504. //
  1505. // because we marked the irp pending, we don't want to
  1506. // complete it when we return. So, tell the caller not
  1507. // to complete the Irp.
  1508. //
  1509. *pCompletedIrp = TRUE;
  1510. }
  1511. }
  1512. }
  1513. }
  1514. return Status;
  1515. }
  1516. NTSTATUS
  1517. Dispatch_State(
  1518. PIRP pIrp,
  1519. PWDMACONTEXT pContext,
  1520. LPDEVICEINFO DeviceInfo,
  1521. ULONG IoCode
  1522. )
  1523. {
  1524. ULONG TranslatedDeviceNumber;
  1525. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1526. Status = ValidateAndTranslate(pContext,
  1527. DeviceInfo,
  1528. 0,
  1529. &TranslatedDeviceNumber);
  1530. if( NT_SUCCESS(Status) )
  1531. {
  1532. switch(IoCode)
  1533. {
  1534. //
  1535. // Midi out state changes
  1536. //
  1537. case IOCTL_WDMAUD_MIDI_OUT_RESET:
  1538. Status = StateMidiOutPin ( pContext->MidiOutDevs[TranslatedDeviceNumber].pMidiPin,
  1539. KSSTATE_STOP );
  1540. break;
  1541. case IOCTL_WDMAUD_MIDI_OUT_WRITE_DATA:
  1542. Status = WriteMidiEventPin(&pContext->MidiOutDevs[TranslatedDeviceNumber],
  1543. PtrToUlong(DeviceInfo->DataBuffer));
  1544. break;
  1545. //
  1546. // Midi in state changes
  1547. //
  1548. case IOCTL_WDMAUD_MIDI_IN_STOP:
  1549. Status = StateMidiInPin ( pContext->MidiInDevs[TranslatedDeviceNumber].pMidiPin,
  1550. KSSTATE_PAUSE );
  1551. break;
  1552. case IOCTL_WDMAUD_MIDI_IN_RECORD:
  1553. Status = StateMidiInPin ( pContext->MidiInDevs[TranslatedDeviceNumber].pMidiPin,
  1554. KSSTATE_RUN );
  1555. break;
  1556. case IOCTL_WDMAUD_MIDI_IN_RESET:
  1557. Status = ResetMidiInPin ( pContext->MidiInDevs[TranslatedDeviceNumber].pMidiPin );
  1558. break;
  1559. //
  1560. // Wave out state changes
  1561. //
  1562. case IOCTL_WDMAUD_WAVE_OUT_PAUSE:
  1563. Status = StateWavePin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
  1564. DeviceInfo->DeviceHandle,
  1565. KSSTATE_PAUSE );
  1566. break;
  1567. case IOCTL_WDMAUD_WAVE_OUT_PLAY:
  1568. Status = StateWavePin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
  1569. DeviceInfo->DeviceHandle,
  1570. KSSTATE_RUN );
  1571. break;
  1572. case IOCTL_WDMAUD_WAVE_OUT_RESET:
  1573. Status = StateWavePin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
  1574. DeviceInfo->DeviceHandle,
  1575. KSSTATE_PAUSE );
  1576. if ( NT_SUCCESS(Status) )
  1577. {
  1578. Status = ResetWaveOutPin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
  1579. DeviceInfo->DeviceHandle ) ;
  1580. }
  1581. break;
  1582. case IOCTL_WDMAUD_WAVE_OUT_BREAKLOOP:
  1583. Status = BreakLoopWaveOutPin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
  1584. DeviceInfo->DeviceHandle );
  1585. break;
  1586. //
  1587. // Wave In State changes
  1588. //
  1589. case IOCTL_WDMAUD_WAVE_IN_STOP:
  1590. Status = StateWavePin ( &pContext->WaveInDevs[TranslatedDeviceNumber],
  1591. DeviceInfo->DeviceHandle,
  1592. KSSTATE_PAUSE );
  1593. break;
  1594. case IOCTL_WDMAUD_WAVE_IN_RECORD:
  1595. Status = StateWavePin ( &pContext->WaveInDevs[TranslatedDeviceNumber],
  1596. DeviceInfo->DeviceHandle,
  1597. KSSTATE_RUN );
  1598. break;
  1599. case IOCTL_WDMAUD_WAVE_IN_RESET:
  1600. Status = StateWavePin ( &pContext->WaveInDevs[TranslatedDeviceNumber],
  1601. DeviceInfo->DeviceHandle,
  1602. KSSTATE_STOP );
  1603. break;
  1604. default:
  1605. break;
  1606. }
  1607. }
  1608. return Status;
  1609. }
  1610. NTSTATUS
  1611. Dispatch_GetCapabilities(
  1612. PIRP pIrp,
  1613. PWDMACONTEXT pContext,
  1614. LPDEVICEINFO DeviceInfo
  1615. )
  1616. {
  1617. ULONG TranslatedDeviceNumber;
  1618. PVOID pMappedBuffer;
  1619. PMDL pMdl;
  1620. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1621. //
  1622. // Passing in DeviceInfo->DataBufferSize as the validation size because we don't care
  1623. // about the buffer check but we still want the translation code. It's just a short
  1624. // cut on the ValidateAndTranslate function.
  1625. //
  1626. Status = ValidateAndTranslate(pContext,
  1627. DeviceInfo,
  1628. DeviceInfo->DataBufferSize, // Don't care about buffer
  1629. &TranslatedDeviceNumber);
  1630. if( NT_SUCCESS(Status) )
  1631. {
  1632. //
  1633. // Map this buffer into a system address
  1634. //
  1635. wdmaudMapBuffer( pIrp,
  1636. DeviceInfo->DataBuffer,
  1637. DeviceInfo->DataBufferSize,
  1638. &pMappedBuffer,
  1639. &pMdl,
  1640. pContext,
  1641. TRUE);
  1642. if (NULL == pMappedBuffer)
  1643. {
  1644. Status = STATUS_INSUFFICIENT_RESOURCES;
  1645. }
  1646. else
  1647. {
  1648. Status = wdmaudGetDevCaps( pContext,
  1649. DeviceInfo->DeviceType,
  1650. TranslatedDeviceNumber,
  1651. pMappedBuffer,
  1652. DeviceInfo->DataBufferSize);
  1653. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  1654. //
  1655. // Free the MDL
  1656. //
  1657. wdmaudUnmapBuffer( pMdl );
  1658. }
  1659. }
  1660. return Status;
  1661. }
  1662. NTSTATUS
  1663. Dispatch_OpenPin(
  1664. PIRP pIrp,
  1665. PWDMACONTEXT pContext,
  1666. LPDEVICEINFO DeviceInfo
  1667. )
  1668. {
  1669. ULONG TranslatedDeviceNumber;
  1670. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1671. //
  1672. // Passing in DeviceInfo->DataBufferSize as the validation size because we don't care
  1673. // about the buffer check but we still want the translation code. It's just a short
  1674. // cut on the ValidateAndTranslate function.
  1675. //
  1676. Status = ValidateAndTranslate(pContext,
  1677. DeviceInfo,
  1678. DeviceInfo->DataBufferSize, // Don't care about buffer
  1679. &TranslatedDeviceNumber);
  1680. if( NT_SUCCESS(Status) )
  1681. {
  1682. switch (DeviceInfo->DeviceType)
  1683. {
  1684. case WaveOutDevice:
  1685. case WaveInDevice:
  1686. if (DeviceInfo->DataBufferSize < sizeof(PCMWAVEFORMAT))
  1687. {
  1688. Status = STATUS_INVALID_BUFFER_SIZE;
  1689. } else {
  1690. LPWAVEFORMATEX pWaveFmt = NULL;
  1691. //
  1692. // Ensure alignment by copying to temporary buffer
  1693. //
  1694. Status = CaptureBufferToLocalPool(DeviceInfo->DataBuffer,
  1695. DeviceInfo->DataBufferSize,
  1696. &pWaveFmt
  1697. #ifdef _WIN64
  1698. ,0
  1699. #endif
  1700. );
  1701. if (!NT_SUCCESS(Status))
  1702. {
  1703. Status = STATUS_INSUFFICIENT_RESOURCES;
  1704. } else {
  1705. if ((pWaveFmt->wFormatTag != WAVE_FORMAT_PCM) &&
  1706. ((DeviceInfo->DataBufferSize < sizeof(WAVEFORMATEX)) ||
  1707. (DeviceInfo->DataBufferSize != sizeof(WAVEFORMATEX) + pWaveFmt->cbSize)))
  1708. {
  1709. Status = STATUS_INVALID_BUFFER_SIZE;
  1710. }
  1711. else
  1712. {
  1713. Status = OpenWavePin( pContext,
  1714. TranslatedDeviceNumber,
  1715. pWaveFmt,
  1716. DeviceInfo->DeviceHandle,
  1717. DeviceInfo->dwFlags,
  1718. (WaveOutDevice == DeviceInfo->DeviceType?
  1719. KSPIN_DATAFLOW_IN:KSPIN_DATAFLOW_OUT) );
  1720. }
  1721. //
  1722. // Free the temporary buffer
  1723. //
  1724. AudioFreeMemory_Unknown( &pWaveFmt );
  1725. }
  1726. }
  1727. break;
  1728. case MidiOutDevice:
  1729. Status = OpenMidiPin( pContext, TranslatedDeviceNumber, KSPIN_DATAFLOW_IN );
  1730. break;
  1731. case MidiInDevice:
  1732. Status = OpenMidiPin( pContext, TranslatedDeviceNumber, KSPIN_DATAFLOW_OUT );
  1733. break;
  1734. default:
  1735. Status = STATUS_NOT_SUPPORTED;
  1736. break;
  1737. }
  1738. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  1739. }
  1740. return Status;
  1741. }
  1742. NTSTATUS
  1743. Dispatch_ClosePin(
  1744. PIRP pIrp,
  1745. PWDMACONTEXT pContext,
  1746. LPDEVICEINFO DeviceInfo
  1747. )
  1748. {
  1749. ULONG TranslatedDeviceNumber;
  1750. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1751. Status = ValidateAndTranslate(pContext,
  1752. DeviceInfo,
  1753. 0,
  1754. &TranslatedDeviceNumber);
  1755. if( NT_SUCCESS(Status) )
  1756. {
  1757. switch (DeviceInfo->DeviceType)
  1758. {
  1759. case WaveOutDevice:
  1760. CloseTheWavePin( &pContext->WaveOutDevs[TranslatedDeviceNumber],
  1761. DeviceInfo->DeviceHandle );
  1762. break;
  1763. case WaveInDevice:
  1764. CloseTheWavePin( &pContext->WaveInDevs[TranslatedDeviceNumber],
  1765. DeviceInfo->DeviceHandle );
  1766. break;
  1767. case MidiOutDevice:
  1768. CloseMidiDevicePin( &pContext->MidiOutDevs[TranslatedDeviceNumber] );
  1769. break;
  1770. case MidiInDevice:
  1771. CloseMidiDevicePin( &pContext->MidiInDevs[TranslatedDeviceNumber] );
  1772. break;
  1773. default:
  1774. Status = STATUS_NOT_SUPPORTED;
  1775. break;
  1776. }
  1777. }
  1778. return Status;
  1779. }
  1780. NTSTATUS
  1781. Dispatch_GetVolume(
  1782. PIRP pIrp,
  1783. PWDMACONTEXT pContext,
  1784. LPDEVICEINFO DeviceInfo,
  1785. ULONG IoCode
  1786. )
  1787. {
  1788. DWORD dwLeft, dwRight;
  1789. ULONG TranslatedDeviceNumber;
  1790. PVOID pMappedBuffer;
  1791. PMDL pMdl;
  1792. ULONG ulDeviceType;
  1793. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1794. Status = ValidateAndTranslate(pContext,
  1795. DeviceInfo,
  1796. sizeof(DWORD),
  1797. &TranslatedDeviceNumber);
  1798. if( NT_SUCCESS(Status) )
  1799. {
  1800. switch(IoCode)
  1801. {
  1802. case IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME:
  1803. ulDeviceType = MidiOutDevice;
  1804. break;
  1805. case IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME:
  1806. ulDeviceType = WaveOutDevice;
  1807. break;
  1808. case IOCTL_WDMAUD_GET_VOLUME:
  1809. ulDeviceType = DeviceInfo->DeviceType;
  1810. break;
  1811. default:
  1812. return STATUS_INVALID_PARAMETER;
  1813. break;
  1814. }
  1815. Status = GetVolume(pContext,
  1816. TranslatedDeviceNumber,
  1817. ulDeviceType,
  1818. &dwLeft,
  1819. &dwRight);
  1820. if( NT_SUCCESS( Status ) )
  1821. {
  1822. wdmaudMapBuffer( pIrp, // Wave buffers look like
  1823. DeviceInfo->DataBuffer, // DeviceInfo->DataBuffer
  1824. DeviceInfo->DataBufferSize, // DeviceInfo->DataBufferSize
  1825. &pMappedBuffer,
  1826. &pMdl,
  1827. pContext,
  1828. TRUE);
  1829. if (NULL == pMappedBuffer)
  1830. {
  1831. Status = STATUS_INSUFFICIENT_RESOURCES;
  1832. } else {
  1833. //
  1834. // Write this info back.
  1835. //
  1836. *((LPDWORD)pMappedBuffer) = MAKELONG(LOWORD(dwLeft),
  1837. LOWORD(dwRight));
  1838. wdmaudUnmapBuffer( pMdl );
  1839. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  1840. }
  1841. }
  1842. }
  1843. return Status;
  1844. }
  1845. NTSTATUS
  1846. Dispatch_SetVolume(
  1847. PIRP pIrp,
  1848. PWDMACONTEXT pContext,
  1849. LPDEVICEINFO DeviceInfo,
  1850. ULONG IoCode
  1851. )
  1852. {
  1853. ULONG TranslatedDeviceNumber;
  1854. PVOID pMappedBuffer;
  1855. PMDL pMdl;
  1856. ULONG ulDeviceType;
  1857. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1858. Status = ValidateAndTranslate(pContext,
  1859. DeviceInfo,
  1860. sizeof(DWORD),
  1861. &TranslatedDeviceNumber);
  1862. if( NT_SUCCESS(Status) )
  1863. {
  1864. wdmaudMapBuffer( pIrp,
  1865. DeviceInfo->DataBuffer,
  1866. DeviceInfo->DataBufferSize,
  1867. &pMappedBuffer,
  1868. &pMdl,
  1869. pContext,
  1870. TRUE);
  1871. if (NULL == pMappedBuffer)
  1872. {
  1873. Status = STATUS_INSUFFICIENT_RESOURCES;
  1874. }
  1875. else
  1876. {
  1877. switch(IoCode)
  1878. {
  1879. case IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME:
  1880. ulDeviceType = MidiOutDevice;
  1881. break;
  1882. case IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME:
  1883. ulDeviceType = WaveOutDevice;
  1884. break;
  1885. case IOCTL_WDMAUD_SET_VOLUME:
  1886. ulDeviceType = DeviceInfo->DeviceType;
  1887. break;
  1888. default:
  1889. return STATUS_INVALID_PARAMETER;
  1890. break;
  1891. }
  1892. Status = SetVolume(pContext,
  1893. TranslatedDeviceNumber,
  1894. ulDeviceType,
  1895. LOWORD(*((LPDWORD)pMappedBuffer)),
  1896. HIWORD(*((LPDWORD)pMappedBuffer)));
  1897. wdmaudUnmapBuffer( pMdl );
  1898. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  1899. }
  1900. }
  1901. return Status;
  1902. }
  1903. NTSTATUS
  1904. Dispatch_WaveGetPos(
  1905. PIRP pIrp,
  1906. PWDMACONTEXT pContext,
  1907. LPDEVICEINFO DeviceInfo,
  1908. ULONG IoCode
  1909. )
  1910. {
  1911. WAVEPOSITION WavePos;
  1912. ULONG TranslatedDeviceNumber;
  1913. PVOID pMappedBuffer;
  1914. PMDL pMdl;
  1915. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1916. Status = ValidateAndTranslate(pContext,
  1917. DeviceInfo,
  1918. sizeof(DWORD),
  1919. &TranslatedDeviceNumber);
  1920. if( NT_SUCCESS(Status) )
  1921. {
  1922. //
  1923. // Map this buffer into a system address
  1924. //
  1925. wdmaudMapBuffer( pIrp,
  1926. DeviceInfo->DataBuffer,
  1927. DeviceInfo->DataBufferSize,
  1928. &pMappedBuffer,
  1929. &pMdl,
  1930. pContext,
  1931. TRUE);
  1932. if (NULL == pMappedBuffer)
  1933. {
  1934. Status = STATUS_INSUFFICIENT_RESOURCES;
  1935. } else {
  1936. WavePos.Operation = KSPROPERTY_TYPE_GET;
  1937. switch(IoCode)
  1938. {
  1939. case IOCTL_WDMAUD_WAVE_OUT_GET_POS:
  1940. Status = PosWavePin(&pContext->WaveOutDevs[TranslatedDeviceNumber],
  1941. DeviceInfo->DeviceHandle,
  1942. &WavePos );
  1943. break;
  1944. case IOCTL_WDMAUD_WAVE_IN_GET_POS:
  1945. Status = PosWavePin ( &pContext->WaveInDevs[TranslatedDeviceNumber],
  1946. DeviceInfo->DeviceHandle,
  1947. &WavePos );
  1948. break;
  1949. default:
  1950. return STATUS_INVALID_PARAMETER;
  1951. break;
  1952. }
  1953. *((LPDWORD)pMappedBuffer) = WavePos.BytePos;
  1954. //
  1955. // Free the MDL
  1956. //
  1957. wdmaudUnmapBuffer( pMdl );
  1958. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  1959. }
  1960. }
  1961. return Status;
  1962. }
  1963. NTSTATUS
  1964. Dispatch_MidiOutWriteLongdata(
  1965. PIRP pIrp,
  1966. PWDMACONTEXT pContext,
  1967. LPDEVICEINFO DeviceInfo,
  1968. BOOL *pCompletedIrp
  1969. )
  1970. {
  1971. ULONG TranslatedDeviceNumber;
  1972. LPMIDIHDR pMidiHdr = NULL;
  1973. #ifdef _WIN64
  1974. LPMIDIHDR32 pMidiHdr32;
  1975. #endif
  1976. PSTREAM_HEADER_EX pStreamHeader = NULL;
  1977. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  1978. ASSERT( FALSE == *pCompletedIrp );
  1979. //
  1980. // Verify that we received a valid midiheader
  1981. //
  1982. Status = ValidateAndTranslateEx(pIrp, pContext, DeviceInfo,
  1983. #ifdef _WIN64
  1984. sizeof(MIDIHDR32),
  1985. #endif
  1986. sizeof(MIDIHDR), &TranslatedDeviceNumber);
  1987. if( !NT_SUCCESS(Status) )
  1988. {
  1989. return Status;
  1990. }
  1991. Status = AudioAllocateMemory_Fixed(sizeof(STREAM_HEADER_EX),
  1992. TAG_Audh_STREAMHEADER,
  1993. ZERO_FILL_MEMORY,
  1994. &pStreamHeader);
  1995. if(NT_SUCCESS(Status))
  1996. {
  1997. Status = CaptureBufferToLocalPool(DeviceInfo->DataBuffer,
  1998. DeviceInfo->DataBufferSize,
  1999. &pMidiHdr
  2000. #ifdef _WIN64
  2001. ,(IoIs32bitProcess(pIrp))?sizeof(MIDIHDR):0
  2002. #endif
  2003. );
  2004. if (!NT_SUCCESS(Status))
  2005. {
  2006. AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
  2007. //
  2008. // Why do we change the status here?
  2009. //
  2010. return STATUS_INSUFFICIENT_RESOURCES;
  2011. } else {
  2012. LPVOID lpData;
  2013. DWORD dwBufferLength;
  2014. #ifdef _WIN64
  2015. // Thunk the midi header if required.
  2016. // Note this is an IN PLACE thunk, so we MUST do it in
  2017. // last element to first element order!!!
  2018. if (IoIs32bitProcess(pIrp)) {
  2019. // Thunk pMidiHdr to 64 bits.
  2020. pMidiHdr32=(LPMIDIHDR32)pMidiHdr;
  2021. #if (WINVER >= 0x0400)
  2022. {
  2023. ULONG i;
  2024. // Again we must go from LAST element to first element in this array.
  2025. // This IS the reverse of for (i=0; i<(sizeof(pMidiHdr32->dwReserved)/sizeof(UINT32)); i++)
  2026. for (i=(sizeof(pMidiHdr32->dwReserved)/sizeof(UINT32)); i--;) {
  2027. pMidiHdr->dwReserved[i]=(DWORD_PTR)pMidiHdr32->dwReserved[i];
  2028. }
  2029. }
  2030. pMidiHdr->dwOffset=pMidiHdr32->dwOffset;
  2031. #endif
  2032. pMidiHdr->reserved=(DWORD_PTR)pMidiHdr32->reserved;
  2033. pMidiHdr->lpNext=(LPMIDIHDR)(UINT_PTR)pMidiHdr32->lpNext;
  2034. pMidiHdr->dwFlags=pMidiHdr32->dwFlags;
  2035. pMidiHdr->dwUser=(DWORD_PTR)pMidiHdr32->dwUser;
  2036. pMidiHdr->dwBytesRecorded=pMidiHdr32->dwBytesRecorded;
  2037. pMidiHdr->dwBufferLength=pMidiHdr32->dwBufferLength;
  2038. pMidiHdr->lpData=(LPSTR)(UINT_PTR)pMidiHdr32->lpData;
  2039. }
  2040. #endif
  2041. //
  2042. // Capture these parameters before probing
  2043. //
  2044. lpData = pMidiHdr->lpData;
  2045. dwBufferLength = pMidiHdr->dwBufferLength;
  2046. try
  2047. {
  2048. ProbeForRead(lpData, dwBufferLength, sizeof(BYTE));
  2049. }
  2050. except (EXCEPTION_EXECUTE_HANDLER)
  2051. {
  2052. AudioFreeMemory_Unknown( &pMidiHdr );
  2053. AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
  2054. Status = GetExceptionCode();
  2055. }
  2056. if (!NT_SUCCESS(Status))
  2057. {
  2058. return Status;
  2059. }
  2060. wdmaudMapBuffer(pIrp,
  2061. lpData,
  2062. dwBufferLength,
  2063. &pStreamHeader->Header.Data,
  2064. &pStreamHeader->pBufferMdl,
  2065. pContext,
  2066. TRUE); // will be freed on completion
  2067. //
  2068. // If we get a zero-length buffer, it is alright to not have
  2069. // a kernel mapped buffer. Otherwise, fail if no Mdl or buffer.
  2070. //
  2071. if ( (dwBufferLength != 0) &&
  2072. ((NULL == pStreamHeader->pBufferMdl) ||
  2073. (NULL == pStreamHeader->Header.Data)) )
  2074. {
  2075. Status = STATUS_INSUFFICIENT_RESOURCES;
  2076. wdmaudUnmapBuffer(pStreamHeader->pBufferMdl);
  2077. AudioFreeMemory_Unknown( &pMidiHdr );
  2078. AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
  2079. } else {
  2080. pStreamHeader->pIrp = pIrp; // store so we can complete later
  2081. pStreamHeader->pMidiPin =
  2082. pContext->MidiOutDevs[TranslatedDeviceNumber].pMidiPin;
  2083. pStreamHeader->Header.FrameExtent = dwBufferLength;
  2084. //
  2085. // Must cleanup any mapped buffers and allocated memory
  2086. // on error paths in WriteMidiOutPin
  2087. //
  2088. Status = WriteMidiOutPin( pMidiHdr,pStreamHeader,pCompletedIrp );
  2089. //
  2090. // Because WriteMidiOutPin is synchronous, pCompetedIrp will
  2091. // always come back FALSE so that the caller can clean up the
  2092. // Irp.
  2093. //
  2094. ASSERT( FALSE == *pCompletedIrp );
  2095. }
  2096. }
  2097. }
  2098. return Status;
  2099. }
  2100. NTSTATUS
  2101. ValidateAndCapture(
  2102. PIRP pIrp,
  2103. LPDEVICEINFO DeviceInfo,
  2104. #ifdef _WIN64
  2105. DWORD ValidationSize32,
  2106. #endif
  2107. DWORD ValidationSize,
  2108. PVOID *ppMappedBuffer
  2109. )
  2110. {
  2111. NTSTATUS Status = STATUS_SUCCESS;
  2112. //
  2113. // Assume that we're going to have a problem.
  2114. //
  2115. *ppMappedBuffer = NULL;
  2116. #ifdef _WIN64
  2117. if (IoIs32bitProcess(pIrp)) {
  2118. if (DeviceInfo->DataBufferSize != ValidationSize32)
  2119. {
  2120. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2121. return STATUS_INVALID_BUFFER_SIZE;
  2122. }
  2123. } else {
  2124. #endif
  2125. if (DeviceInfo->DataBufferSize != ValidationSize)
  2126. {
  2127. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2128. return STATUS_INVALID_BUFFER_SIZE;
  2129. }
  2130. #ifdef _WIN64
  2131. }
  2132. #endif
  2133. //
  2134. // Copy to local data storage
  2135. //
  2136. Status = CaptureBufferToLocalPool(DeviceInfo->DataBuffer,
  2137. DeviceInfo->DataBufferSize,
  2138. ppMappedBuffer
  2139. #ifdef _WIN64
  2140. ,(IoIs32bitProcess(pIrp))?ValidationSize:0
  2141. #endif
  2142. );
  2143. return Status;
  2144. }
  2145. NTSTATUS
  2146. Dispatch_GetLineInfo(
  2147. PIRP pIrp,
  2148. PWDMACONTEXT pContext,
  2149. LPDEVICEINFO DeviceInfo
  2150. )
  2151. {
  2152. PVOID pMappedBuffer;
  2153. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  2154. //
  2155. // The size specified in this member must be large enough to
  2156. // contain the base MIXERLINE structure.
  2157. //
  2158. Status = ValidateAndCapture(pIrp,DeviceInfo,
  2159. #ifdef _WIN64
  2160. sizeof(MIXERLINE32),
  2161. #endif
  2162. sizeof(MIXERLINE), &pMappedBuffer);
  2163. if( !NT_SUCCESS(Status) )
  2164. {
  2165. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2166. goto Exit;
  2167. }
  2168. #ifdef _WIN64
  2169. // Now thunk the MIXERLINE structure to 64 bits.
  2170. // WARNING we do this a simple easy way, but it is DEPENDENT on the
  2171. // structure of MIXERLINE. There is currently only 1 parameter that
  2172. // changes in size between the 32 and 64 bit structures. dwUser.
  2173. // This will have to get more complicated if the MIXERLINE structure
  2174. // ever has more stuff in it that needs to be thunked.
  2175. if (IoIs32bitProcess(pIrp)) {
  2176. // First move everything following the dwUser field in the 32 bit
  2177. // structure down 4 bytes.
  2178. RtlMoveMemory(&((PMIXERLINE32)pMappedBuffer)->cChannels,
  2179. &((PMIXERLINE32)pMappedBuffer)->dwComponentType,
  2180. sizeof(MIXERLINE32)-FIELD_OFFSET(MIXERLINE32,dwComponentType));
  2181. // Now thunk dwUser to 64 bits.
  2182. ((PMIXERLINE)pMappedBuffer)->dwUser=(DWORD_PTR)((PMIXERLINE32)pMappedBuffer)->dwUser;
  2183. }
  2184. #endif
  2185. if (NT_SUCCESS(Status))
  2186. {
  2187. Status = kmxlGetLineInfoHandler( pContext, DeviceInfo, pMappedBuffer );
  2188. //
  2189. // This call should have set the DeviceInfo->mmr and returned a valid
  2190. // NTSTATUS value.
  2191. //
  2192. #ifdef _WIN64
  2193. // Now thunk the MIXERLINE structure back to 32 bits.
  2194. // WARNING we do this a simple easy way, but it is DEPENDENT on the
  2195. // structure of MIXERLINE. There is currently only 1 parameter that
  2196. // changes in size between the 32 and 64 bit structures. dwUser.
  2197. // This will have to get more complicated if the MIXERLINE structure
  2198. // ever has more stuff in it that needs to be thunked.
  2199. // Note that for in place thunks we must do them from LAST to FIRST
  2200. // field order when thunking up to 64 bits and in FIRST to LAST
  2201. // field order when thunking back down to 32 bits!!!
  2202. if (IoIs32bitProcess(pIrp)) {
  2203. // Just move everything that now is after dwComponentType back up 4 bytes.
  2204. RtlMoveMemory(&((PMIXERLINE32)pMappedBuffer)->dwComponentType,
  2205. &((PMIXERLINE32)pMappedBuffer)->cChannels,
  2206. sizeof(MIXERLINE32)-FIELD_OFFSET(MIXERLINE32,dwComponentType));
  2207. }
  2208. #endif
  2209. //
  2210. // Copy back the contents of the captured buffer
  2211. //
  2212. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2213. DeviceInfo->DataBufferSize,
  2214. &pMappedBuffer);
  2215. }
  2216. Exit:
  2217. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2218. return Status;
  2219. }
  2220. NTSTATUS
  2221. Dispatch_GetLineControls(
  2222. PIRP pIrp,
  2223. PWDMACONTEXT pContext,
  2224. LPDEVICEINFO DeviceInfo
  2225. )
  2226. {
  2227. PVOID pamxctrl = NULL;
  2228. PVOID pamxctrlUnmapped;
  2229. DWORD dwSize;
  2230. PVOID pMappedBuffer;
  2231. NTSTATUS Status = STATUS_SUCCESS; // Assume success
  2232. //
  2233. // The size specified in this member must be large enough to
  2234. // contain the base MIXERLINECONTROL structure.
  2235. //
  2236. Status = ValidateAndCapture(pIrp,DeviceInfo,
  2237. #ifdef _WIN64
  2238. sizeof(MIXERLINECONTROLS32),
  2239. #endif
  2240. sizeof(MIXERLINECONTROLS), &pMappedBuffer);
  2241. if( !NT_SUCCESS(Status) )
  2242. {
  2243. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2244. goto Exit;
  2245. }
  2246. #ifdef _WIN64
  2247. // Now thunk the MIXERLINECONTROL structure to 64 bits.
  2248. // Currently this is easy to do as only the last field is different
  2249. // in size and simply needs to be zero extended.
  2250. // NOTE: This structure also thus does NOT need any thunking in
  2251. // the reverse direction! How nice.
  2252. // NOTE: None of the mixer controls themselves need any thunking.
  2253. // YEAH!!!
  2254. if (IoIs32bitProcess(pIrp)) {
  2255. ((LPMIXERLINECONTROLS)pMappedBuffer)->pamxctrl=(LPMIXERCONTROL)(UINT_PTR)((LPMIXERLINECONTROLS32)pMappedBuffer)->pamxctrl;
  2256. }
  2257. #endif
  2258. //
  2259. // Pick reasonable max values for the size and number of controls to eliminate overflow
  2260. //
  2261. if ( ( ((LPMIXERLINECONTROLS) pMappedBuffer)->cbmxctrl > 10000 ) ||
  2262. ( ((LPMIXERLINECONTROLS) pMappedBuffer)->cControls > 10000 ) )
  2263. {
  2264. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2265. DeviceInfo->DataBufferSize,
  2266. &pMappedBuffer);
  2267. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2268. Status = STATUS_INVALID_PARAMETER;
  2269. }
  2270. else
  2271. {
  2272. pamxctrlUnmapped = ((LPMIXERLINECONTROLS) pMappedBuffer)->pamxctrl;
  2273. dwSize = ((LPMIXERLINECONTROLS) pMappedBuffer)->cbmxctrl *
  2274. ((LPMIXERLINECONTROLS) pMappedBuffer)->cControls;
  2275. try
  2276. {
  2277. ProbeForWrite(pamxctrlUnmapped, dwSize, sizeof(DWORD));
  2278. }
  2279. except (EXCEPTION_EXECUTE_HANDLER)
  2280. {
  2281. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2282. DeviceInfo->DataBufferSize,
  2283. &pMappedBuffer);
  2284. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2285. Status = GetExceptionCode();
  2286. }
  2287. }
  2288. if (NT_SUCCESS(Status))
  2289. {
  2290. //
  2291. // Map the array of mixer controls into system space. The
  2292. // size of this buffer is the number of controls times the
  2293. // size of each control.
  2294. //
  2295. Status = CaptureBufferToLocalPool(pamxctrlUnmapped,
  2296. dwSize,
  2297. &pamxctrl
  2298. #ifdef _WIN64
  2299. ,0
  2300. #endif
  2301. );
  2302. if (NT_SUCCESS(Status))
  2303. {
  2304. //
  2305. // Call the handler.
  2306. //
  2307. Status = kmxlGetLineControlsHandler(pContext,
  2308. DeviceInfo,
  2309. pMappedBuffer,
  2310. pamxctrl );
  2311. //
  2312. // The previous call should have set the DeviceInfo->mmr and returned
  2313. // a valid Status value.
  2314. //
  2315. CopyAndFreeCapturedBuffer(pamxctrlUnmapped,
  2316. dwSize,
  2317. &pamxctrl);
  2318. } else {
  2319. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2320. }
  2321. } else {
  2322. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2323. }
  2324. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2325. DeviceInfo->DataBufferSize,
  2326. &pMappedBuffer);
  2327. Exit:
  2328. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2329. return Status;
  2330. }
  2331. #ifdef _WIN64
  2332. void
  2333. ThunkMixerControlDetails_Enter(
  2334. PVOID pMappedBuffer
  2335. )
  2336. {
  2337. // Now thunk the MIXERCONTROLDETAILS structure to 64 bits.
  2338. // This is an IN PLACE thunk, so MUST be done from last to first fields.
  2339. ((LPMIXERCONTROLDETAILS)pMappedBuffer)->paDetails=(LPVOID)(UINT_PTR)((LPMIXERCONTROLDETAILS32)pMappedBuffer)->paDetails;
  2340. ((LPMIXERCONTROLDETAILS)pMappedBuffer)->cbDetails=((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cbDetails;
  2341. // We always thunk the next field as if it were an HWND since that works for both cases.
  2342. ((LPMIXERCONTROLDETAILS)pMappedBuffer)->hwndOwner=(HWND)(UINT_PTR)((LPMIXERCONTROLDETAILS32)pMappedBuffer)->hwndOwner;
  2343. ((LPMIXERCONTROLDETAILS)pMappedBuffer)->cChannels=((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cChannels;
  2344. ((LPMIXERCONTROLDETAILS)pMappedBuffer)->dwControlID=((LPMIXERCONTROLDETAILS32)pMappedBuffer)->dwControlID;
  2345. ((LPMIXERCONTROLDETAILS)pMappedBuffer)->cbStruct=((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cbStruct;
  2346. }
  2347. void
  2348. ThunkMixerControlDetails_Leave(
  2349. PVOID pMappedBuffer
  2350. )
  2351. {
  2352. // Now thunk the MIXERCONTROLDETAILS structure back to 32 bits.
  2353. // This is an IN PLACE thunk, so MUST be done from FIRST to LAST
  2354. // fields. Remember the order is different depending on direction!
  2355. ((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cbStruct=((LPMIXERCONTROLDETAILS)pMappedBuffer)->cbStruct;
  2356. ((LPMIXERCONTROLDETAILS32)pMappedBuffer)->dwControlID=((LPMIXERCONTROLDETAILS)pMappedBuffer)->dwControlID;
  2357. ((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cChannels=((LPMIXERCONTROLDETAILS)pMappedBuffer)->cChannels;
  2358. // We always thunk the next field as if it were an HWND since that works for both cases.
  2359. ((LPMIXERCONTROLDETAILS32)pMappedBuffer)->hwndOwner=(UINT32)(UINT_PTR)((LPMIXERCONTROLDETAILS)pMappedBuffer)->hwndOwner;
  2360. ((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cbDetails=((LPMIXERCONTROLDETAILS)pMappedBuffer)->cbDetails;
  2361. ((LPMIXERCONTROLDETAILS32)pMappedBuffer)->paDetails=(UINT32)(UINT_PTR)((LPMIXERCONTROLDETAILS)pMappedBuffer)->paDetails;
  2362. }
  2363. #endif
  2364. NTSTATUS
  2365. Dispatch_GetControlDetails(
  2366. PIRP pIrp,
  2367. PWDMACONTEXT pContext,
  2368. LPDEVICEINFO DeviceInfo
  2369. )
  2370. {
  2371. PVOID paDetails = NULL;
  2372. PVOID paDetailsUnmapped;
  2373. DWORD dwSize;
  2374. PVOID pMappedBuffer;
  2375. NTSTATUS Status = STATUS_SUCCESS; // Assume success.
  2376. Status = ValidateAndCapture(pIrp,DeviceInfo,
  2377. #ifdef _WIN64
  2378. sizeof(MIXERCONTROLDETAILS32),
  2379. #endif
  2380. sizeof(MIXERCONTROLDETAILS), &pMappedBuffer);
  2381. if( !NT_SUCCESS(Status) )
  2382. {
  2383. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2384. goto Exit;
  2385. }
  2386. #ifdef _WIN64
  2387. if (IoIs32bitProcess(pIrp)) {
  2388. ThunkMixerControlDetails_Enter(pMappedBuffer);
  2389. }
  2390. #endif
  2391. //
  2392. // Pick reasonable max values for the data and number of controls to eliminate overflow
  2393. //
  2394. if ( ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails > 10000 ) ||
  2395. ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels > 100 ) ||
  2396. ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems > 100 ) )
  2397. {
  2398. #ifdef _WIN64
  2399. if (IoIs32bitProcess(pIrp)) {
  2400. ThunkMixerControlDetails_Leave(pMappedBuffer);
  2401. }
  2402. #endif
  2403. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2404. DeviceInfo->DataBufferSize,
  2405. &pMappedBuffer);
  2406. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2407. Status = STATUS_INVALID_PARAMETER;
  2408. } else {
  2409. //
  2410. // Map the array control details into system space.
  2411. //
  2412. paDetailsUnmapped = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->paDetails;
  2413. if( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems )
  2414. {
  2415. dwSize = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels *
  2416. ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems *
  2417. ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails;
  2418. } else {
  2419. dwSize = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels *
  2420. ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails;
  2421. }
  2422. try
  2423. {
  2424. ProbeForWrite(paDetailsUnmapped,
  2425. dwSize,
  2426. sizeof(DWORD));
  2427. }
  2428. except (EXCEPTION_EXECUTE_HANDLER)
  2429. {
  2430. #ifdef _WIN64
  2431. if (IoIs32bitProcess(pIrp)) {
  2432. ThunkMixerControlDetails_Leave(pMappedBuffer);
  2433. }
  2434. #endif
  2435. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2436. DeviceInfo->DataBufferSize,
  2437. &pMappedBuffer);
  2438. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2439. Status = GetExceptionCode();
  2440. }
  2441. }
  2442. if (NT_SUCCESS(Status))
  2443. {
  2444. Status = CaptureBufferToLocalPool(paDetailsUnmapped,
  2445. dwSize,
  2446. &paDetails
  2447. #ifdef _WIN64
  2448. ,0
  2449. #endif
  2450. );
  2451. if (NT_SUCCESS(Status))
  2452. {
  2453. //
  2454. // Call the handler.
  2455. //
  2456. Status = kmxlGetControlDetailsHandler(pContext,
  2457. DeviceInfo,
  2458. pMappedBuffer,
  2459. paDetails);
  2460. //
  2461. // The previous call should have set DeviceInfo->mmr and returned
  2462. // a valid Status value.
  2463. //
  2464. CopyAndFreeCapturedBuffer(paDetailsUnmapped,
  2465. dwSize,
  2466. &paDetails);
  2467. } else {
  2468. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2469. }
  2470. } else {
  2471. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2472. }
  2473. #ifdef _WIN64
  2474. if (IoIs32bitProcess(pIrp) && pMappedBuffer) {
  2475. ThunkMixerControlDetails_Leave(pMappedBuffer);
  2476. }
  2477. #endif
  2478. CopyAndFreeCapturedBuffer( DeviceInfo->DataBuffer,
  2479. DeviceInfo->DataBufferSize,
  2480. &pMappedBuffer);
  2481. Exit:
  2482. //
  2483. // Always return the DEVICEINFO number of bytes from this call.
  2484. //
  2485. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2486. return Status;
  2487. }
  2488. NTSTATUS
  2489. Dispatch_SetControlDetails(
  2490. PIRP pIrp,
  2491. PWDMACONTEXT pContext,
  2492. LPDEVICEINFO DeviceInfo
  2493. )
  2494. {
  2495. PVOID paDetails = NULL;
  2496. PVOID paDetailsUnmapped;
  2497. DWORD dwSize;
  2498. PVOID pMappedBuffer;
  2499. NTSTATUS Status = STATUS_SUCCESS; //Assume success.
  2500. Status = ValidateAndCapture(pIrp,DeviceInfo,
  2501. #ifdef _WIN64
  2502. sizeof(MIXERCONTROLDETAILS32),
  2503. #endif
  2504. sizeof(MIXERCONTROLDETAILS), &pMappedBuffer);
  2505. if( !NT_SUCCESS(Status) )
  2506. {
  2507. goto Exit;
  2508. }
  2509. #ifdef _WIN64
  2510. // Now thunk the MIXERCONTROLDETAILS structure to 64 bits.
  2511. // This is an IN PLACE thunk, so MUST be done from last to first fields.
  2512. if (IoIs32bitProcess(pIrp)) {
  2513. ThunkMixerControlDetails_Enter(pMappedBuffer);
  2514. }
  2515. #endif
  2516. //
  2517. // Pick reasonable max values for the data and number of controls to eliminate overflow
  2518. //
  2519. if ( ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails > 10000 ) ||
  2520. ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels > 100 ) ||
  2521. ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems > 100 ) )
  2522. {
  2523. #ifdef _WIN64
  2524. if (IoIs32bitProcess(pIrp)) {
  2525. ThunkMixerControlDetails_Leave(pMappedBuffer);
  2526. }
  2527. #endif
  2528. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2529. DeviceInfo->DataBufferSize,
  2530. &pMappedBuffer);
  2531. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2532. Status = STATUS_INVALID_PARAMETER;
  2533. } else {
  2534. //
  2535. // Map the array control details into system space.
  2536. //
  2537. paDetailsUnmapped = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->paDetails;
  2538. if( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems )
  2539. {
  2540. dwSize = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels *
  2541. ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems *
  2542. ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails;
  2543. } else {
  2544. dwSize = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels *
  2545. ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails;
  2546. }
  2547. try
  2548. {
  2549. ProbeForRead(((LPMIXERCONTROLDETAILS) pMappedBuffer)->paDetails,
  2550. dwSize,
  2551. sizeof(DWORD));
  2552. }
  2553. except (EXCEPTION_EXECUTE_HANDLER)
  2554. {
  2555. #ifdef _WIN64
  2556. if (IoIs32bitProcess(pIrp)) {
  2557. ThunkMixerControlDetails_Leave(pMappedBuffer);
  2558. }
  2559. #endif
  2560. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2561. DeviceInfo->DataBufferSize,
  2562. &pMappedBuffer);
  2563. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2564. Status = GetExceptionCode();
  2565. }
  2566. }
  2567. if (NT_SUCCESS(Status))
  2568. {
  2569. Status = CaptureBufferToLocalPool(paDetailsUnmapped,
  2570. dwSize,
  2571. &paDetails
  2572. #ifdef _WIN64
  2573. ,0
  2574. #endif
  2575. );
  2576. if (NT_SUCCESS(Status))
  2577. {
  2578. //
  2579. // Call the handler.
  2580. //
  2581. Status = kmxlSetControlDetailsHandler(pContext,
  2582. DeviceInfo,
  2583. pMappedBuffer,
  2584. paDetails,
  2585. MIXER_FLAG_PERSIST );
  2586. //
  2587. // The previous call should have set DeviceInfo->mmr and returned
  2588. // a valid Status value.
  2589. //
  2590. CopyAndFreeCapturedBuffer(paDetailsUnmapped,
  2591. dwSize,
  2592. &paDetails);
  2593. } else {
  2594. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2595. }
  2596. } else {
  2597. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2598. }
  2599. #ifdef _WIN64
  2600. if (IoIs32bitProcess(pIrp) && pMappedBuffer) {
  2601. ThunkMixerControlDetails_Leave(pMappedBuffer);
  2602. }
  2603. #endif
  2604. CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
  2605. DeviceInfo->DataBufferSize,
  2606. &pMappedBuffer);
  2607. Exit:
  2608. //
  2609. // Always return sizeof(DEVICEINFO) for this call.
  2610. //
  2611. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2612. return Status;
  2613. }
  2614. NTSTATUS
  2615. Dispatch_GetHardwareEventData(
  2616. PIRP pIrp,
  2617. LPDEVICEINFO DeviceInfo
  2618. )
  2619. {
  2620. NTSTATUS Status = STATUS_SUCCESS;
  2621. //
  2622. // Always return sizeof(DEVICEINFO) for this call.
  2623. //
  2624. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2625. if (DeviceInfo->DataBufferSize != 0)
  2626. {
  2627. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2628. Status = STATUS_INVALID_PARAMETER;
  2629. } else {
  2630. GetHardwareEventData(DeviceInfo);
  2631. }
  2632. return Status;
  2633. }
  2634. NTSTATUS
  2635. SoundDispatch(
  2636. IN PDEVICE_OBJECT pDO,
  2637. IN PIRP pIrp
  2638. )
  2639. /*++
  2640. Routine Description:
  2641. Driver dispatch routine. Processes IRPs based on IRP MajorFunction
  2642. Arguments:
  2643. pDO -- pointer to the device object
  2644. pIrp -- pointer to the IRP to process
  2645. Return Value:
  2646. Returns the value of the IRP IoStatus.Status
  2647. --*/
  2648. {
  2649. PIO_STACK_LOCATION pIrpStack;
  2650. PWDMACONTEXT pContext;
  2651. LPDEVICEINFO DeviceInfo;
  2652. #ifdef _WIN64
  2653. LPDEVICEINFO32 DeviceInfo32=NULL;
  2654. LOCALDEVICEINFO LocalDeviceInfo;
  2655. #endif
  2656. LPVOID DataBuffer;
  2657. DWORD DataBufferSize;
  2658. ULONG IoCode;
  2659. NTSTATUS Status = STATUS_SUCCESS;
  2660. PAGED_CODE();
  2661. //
  2662. // Get the CurrentStackLocation and log it so we know what is going on
  2663. //
  2664. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  2665. IoCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
  2666. pContext = pIrpStack->FileObject->FsContext;
  2667. ASSERT(pContext);
  2668. ASSERT(pIrpStack->MajorFunction != IRP_MJ_CREATE &&
  2669. pIrpStack->MajorFunction != IRP_MJ_CLOSE);
  2670. //
  2671. // Can't assume that FsContext is initialized if the device has
  2672. // been opened with FO_DIRECT_DEVICE_OPEN
  2673. //
  2674. if (pIrpStack->FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
  2675. {
  2676. DPF(DL_TRACE|FA_IOCTL, ("IRP_MJ_DEVICE_CONTROL: Opened with FO_DIRECT_DEVICE_OPEN, no device context") );
  2677. return KsDefaultDeviceIoCompletion(pDO, pIrp);
  2678. }
  2679. Status = ValidateIrp(pIrp);
  2680. if (!NT_SUCCESS(Status))
  2681. {
  2682. pIrp->IoStatus.Status = Status;
  2683. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  2684. RETURN( Status );
  2685. }
  2686. #ifdef _WIN64
  2687. if (IoIs32bitProcess(pIrp)) {
  2688. DeviceInfo32=((LPDEVICEINFO32)pIrp->AssociatedIrp.SystemBuffer);
  2689. RtlZeroMemory(&LocalDeviceInfo, sizeof(LOCALDEVICEINFO));
  2690. DeviceInfo=&LocalDeviceInfo.DeviceInfo;
  2691. ThunkDeviceInfo3264(DeviceInfo32, DeviceInfo);
  2692. } else {
  2693. #endif
  2694. DeviceInfo = ((LPDEVICEINFO)pIrp->AssociatedIrp.SystemBuffer);
  2695. #ifdef _WIN64
  2696. }
  2697. #endif
  2698. DataBufferSize = DeviceInfo->DataBufferSize;
  2699. WdmaGrabMutex(pContext);
  2700. switch (pIrpStack->MajorFunction)
  2701. {
  2702. case IRP_MJ_DEVICE_CONTROL:
  2703. {
  2704. switch (IoCode)
  2705. {
  2706. case IOCTL_WDMAUD_INIT:
  2707. DPF( DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_INIT"));
  2708. if (DataBufferSize != 0)
  2709. {
  2710. Status = STATUS_INVALID_BUFFER_SIZE;
  2711. break;
  2712. }
  2713. WdmaReleaseMutex(pContext);
  2714. //
  2715. // If sysaudio fails to load, the device interface
  2716. // will be disabled and the SysAudioPnPNotification
  2717. // will not be called anymore until the sysaudio
  2718. // device interface is reenabled.
  2719. //
  2720. if ( IsSysaudioInterfaceActive() )
  2721. {
  2722. KeWaitForSingleObject(&pContext->InitializedSysaudioEvent,
  2723. Executive, KernelMode, FALSE, NULL);
  2724. // This could happen if there was an error in InitializeSysaudio or
  2725. // the memory allocation failed in QueueWorkList
  2726. if (pContext->fInitializeSysaudio == FALSE)
  2727. {
  2728. Status = STATUS_NOT_SUPPORTED;
  2729. DPF(DL_WARNING|FA_IOCTL, ("IOCTL_WDMAUD_INIT: Didn't init sysaudio! Failing IOCTL_WDMAUD_INIT: %08x", Status));
  2730. }
  2731. }
  2732. else
  2733. {
  2734. Status = STATUS_NOT_SUPPORTED;
  2735. DPF(DL_WARNING|FA_IOCTL, ("IOCTL_WDMAUD_INIT: Sysaudio Device interface disabled! Failing IOCTL_WDMAUD_INIT: %08x", Status));
  2736. }
  2737. WdmaGrabMutex(pContext);
  2738. break;
  2739. case IOCTL_WDMAUD_EXIT:
  2740. if (DataBufferSize != 0)
  2741. {
  2742. Status = STATUS_INVALID_BUFFER_SIZE;
  2743. break;
  2744. }
  2745. DPF( DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_EXIT"));
  2746. break;
  2747. case IOCTL_WDMAUD_ADD_DEVNODE:
  2748. {
  2749. DPF( DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_ADD_DEVNODE"));
  2750. if (DataBufferSize != 0)
  2751. {
  2752. Status = STATUS_INVALID_BUFFER_SIZE;
  2753. break;
  2754. }
  2755. DPF(DL_TRACE|FA_INSTANCE,("pContext=%08X, DI=%08X DeviceType=%08X",
  2756. pContext,
  2757. DeviceInfo->wstrDeviceInterface,
  2758. DeviceInfo->DeviceType) );
  2759. Status=AddDevNode(pContext, DeviceInfo->wstrDeviceInterface, DeviceInfo->DeviceType);
  2760. break;
  2761. }
  2762. case IOCTL_WDMAUD_REMOVE_DEVNODE:
  2763. {
  2764. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_REMOVE_DEVNODE"));
  2765. if (DataBufferSize != 0)
  2766. {
  2767. Status = STATUS_INVALID_BUFFER_SIZE;
  2768. break;
  2769. }
  2770. RemoveDevNode(pContext, DeviceInfo->wstrDeviceInterface, DeviceInfo->DeviceType);
  2771. break;
  2772. }
  2773. case IOCTL_WDMAUD_GET_CAPABILITIES:
  2774. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_GET_CAPABILITIES"));
  2775. Status = Dispatch_GetCapabilities(pIrp,pContext,
  2776. DeviceInfo);
  2777. break;
  2778. case IOCTL_WDMAUD_GET_NUM_DEVS:
  2779. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_GET_NUM_DEVS"));
  2780. if (DataBufferSize != 0)
  2781. {
  2782. Status = STATUS_INVALID_BUFFER_SIZE;
  2783. break;
  2784. }
  2785. Status = wdmaudGetNumDevs(pContext,
  2786. DeviceInfo->DeviceType,
  2787. DeviceInfo->wstrDeviceInterface,
  2788. &DeviceInfo->DeviceNumber);
  2789. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2790. DeviceInfo->mmr=MMSYSERR_NOERROR;
  2791. break;
  2792. case IOCTL_WDMAUD_SET_PREFERRED_DEVICE:
  2793. DPF(DL_TRACE|FA_IOCTL,
  2794. ("IOCTL_WDMAUD_SET_PREFERRED_DEVICE %d",
  2795. DeviceInfo->DeviceNumber));
  2796. Status = SetPreferredDevice(pContext, DeviceInfo);
  2797. break;
  2798. case IOCTL_WDMAUD_OPEN_PIN:
  2799. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_OPEN_PIN"));
  2800. UpdatePreferredDevice(pContext);
  2801. Status = Dispatch_OpenPin(pIrp,
  2802. pContext,
  2803. DeviceInfo);
  2804. break;
  2805. case IOCTL_WDMAUD_CLOSE_PIN:
  2806. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_CLOSE_PIN"));
  2807. Status = Dispatch_ClosePin(pIrp,
  2808. pContext,
  2809. DeviceInfo);
  2810. break;
  2811. //
  2812. // WaveOut, wavein, midiout and midiin routines
  2813. //
  2814. case IOCTL_WDMAUD_WAVE_OUT_PAUSE:
  2815. case IOCTL_WDMAUD_WAVE_OUT_PLAY:
  2816. case IOCTL_WDMAUD_WAVE_OUT_RESET:
  2817. case IOCTL_WDMAUD_WAVE_OUT_BREAKLOOP:
  2818. case IOCTL_WDMAUD_WAVE_IN_STOP:
  2819. case IOCTL_WDMAUD_WAVE_IN_RECORD:
  2820. case IOCTL_WDMAUD_WAVE_IN_RESET:
  2821. case IOCTL_WDMAUD_MIDI_OUT_RESET:
  2822. case IOCTL_WDMAUD_MIDI_OUT_WRITE_DATA:
  2823. case IOCTL_WDMAUD_MIDI_IN_STOP:
  2824. case IOCTL_WDMAUD_MIDI_IN_RECORD:
  2825. case IOCTL_WDMAUD_MIDI_IN_RESET:
  2826. Status = Dispatch_State(pIrp,
  2827. pContext,
  2828. DeviceInfo,
  2829. IoCode);
  2830. break;
  2831. case IOCTL_WDMAUD_WAVE_OUT_GET_POS:
  2832. case IOCTL_WDMAUD_WAVE_IN_GET_POS:
  2833. Status = Dispatch_WaveGetPos(pIrp,pContext,
  2834. DeviceInfo,IoCode);
  2835. break;
  2836. case IOCTL_WDMAUD_GET_VOLUME:
  2837. case IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME:
  2838. case IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME:
  2839. Status = Dispatch_GetVolume(pIrp,pContext,
  2840. DeviceInfo,IoCode);
  2841. break;
  2842. case IOCTL_WDMAUD_SET_VOLUME:
  2843. case IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME:
  2844. case IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME:
  2845. Status = Dispatch_SetVolume(pIrp,pContext,
  2846. DeviceInfo,IoCode);
  2847. break;
  2848. case IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN:
  2849. {
  2850. BOOL bCompletedIrp = FALSE;
  2851. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN"));
  2852. Status = Dispatch_WaveOutWritePin(pIrp,pContext,
  2853. DeviceInfo,&bCompletedIrp);
  2854. if( bCompletedIrp )
  2855. {
  2856. //
  2857. // !!! NOTE: Must return here so that we don't call IoCompleteRequest later !!!
  2858. //
  2859. WdmaReleaseMutex(pContext);
  2860. // For 32 bit irps we do NOT need to thunk DeviceInfo back to 32 bits, since
  2861. // nothing in this case statement has written anything into the DeviceInfo
  2862. // structure. If thunking back is ever required, make sure to NOT touch a
  2863. // potentially already completed irp. WriteWaveOutPin now completes the irp
  2864. // in some cases.
  2865. return Status ;
  2866. }
  2867. //
  2868. // If there was some problem trying to schedule the Irp we will
  2869. // end up here. bCompleteIrp will still be FALSE indicating that
  2870. // we need to complete the Irp. So, we break out of the switch
  2871. // statement, endin up at the end of SoundDispatch perform cleanup
  2872. // and complete the Irp.
  2873. //
  2874. }
  2875. break;
  2876. //
  2877. // WaveIn routines
  2878. //
  2879. case IOCTL_WDMAUD_WAVE_IN_READ_PIN:
  2880. {
  2881. BOOL bCompletedIrp = FALSE;
  2882. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_WAVE_IN_READ_PIN"));
  2883. Status = Dispatch_WaveInReadPin(pIrp,pContext,
  2884. DeviceInfo,&bCompletedIrp);
  2885. if( bCompletedIrp )
  2886. {
  2887. //
  2888. // Don't need the lock any longer.
  2889. //
  2890. WdmaReleaseMutex(pContext);
  2891. return Status;
  2892. }
  2893. // For 32 bit irps we do NOT need to thunk DeviceInfo back to 32 bits, since
  2894. // nothing in this case statement has written anything into the DeviceInfo
  2895. // structure. If thunking back is ever required, make sure to NOT touch a
  2896. // potentially already completed irp. ReadWaveInPin now completes the irp
  2897. // in some cases.
  2898. //
  2899. // If there was some problem trying to schedule the Irp we will
  2900. // end up here. bCompleteIrp will still be FALSE indicating that
  2901. // we need to complete the Irp. So, we break out of the switch
  2902. // statement, endin up at the end of SoundDispatch perform cleanup
  2903. // and complete the Irp.
  2904. //
  2905. }
  2906. break;
  2907. //
  2908. // MidiOut routines
  2909. //
  2910. case IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA:
  2911. {
  2912. BOOL bCompletedIrp = FALSE;
  2913. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA"));
  2914. Status = Dispatch_MidiOutWriteLongdata(pIrp,
  2915. pContext,
  2916. DeviceInfo,
  2917. &bCompletedIrp);
  2918. //
  2919. // If it was completed already, don't do it again!
  2920. //
  2921. if( bCompletedIrp )
  2922. {
  2923. //
  2924. // Don't need the lock any longer.
  2925. //
  2926. WdmaReleaseMutex(pContext);
  2927. // For 32 bit irps we do NOT need to thunk DeviceInfo back to 32 bits, since
  2928. // nothing in this case statement has written anything into the DeviceInfo
  2929. // structure. If thunking back is ever required, make sure to NOT touch a
  2930. // potentially already completed irp. wdmaudUnprepareIrp now completes the irp
  2931. // in most cases.
  2932. return Status;
  2933. }
  2934. //
  2935. // If there was some problem trying to schedule the Irp we will
  2936. // end up here. bCompleteIrp will still be FALSE indicating that
  2937. // we need to complete the Irp. So, we break out of the switch
  2938. // statement, endin up at the end of SoundDispatch perform cleanup
  2939. // and complete the Irp.
  2940. //
  2941. }
  2942. break;
  2943. //
  2944. // MidiIn routines
  2945. //
  2946. //
  2947. // Buffers for recording MIDI messages...
  2948. //
  2949. case IOCTL_WDMAUD_MIDI_IN_READ_PIN:
  2950. {
  2951. BOOL bCompletedIrp = FALSE;
  2952. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIDI_IN_READ_PIN"));
  2953. Status = Dispatch_MidiInReadPin(pIrp,pContext,
  2954. DeviceInfo,&bCompletedIrp);
  2955. //
  2956. // If it was completed already, don't do it again!
  2957. //
  2958. if( bCompletedIrp )
  2959. {
  2960. //
  2961. // Don't need the lock any longer.
  2962. //
  2963. WdmaReleaseMutex(pContext);
  2964. // For 32 bit irps we do NOT need to thunk DeviceInfo back to 32 bits, since
  2965. // nothing in this case statement has written anything into the DeviceInfo
  2966. // structure. If thunking back is ever required, make sure to NOT touch a
  2967. // potentially already completed irp. wdmaudUnprepareIrp now completes the irp
  2968. // in most cases.
  2969. return Status;
  2970. }
  2971. //
  2972. // If there was some problem trying to schedule the Irp we will
  2973. // end up here. bCompleteIrp will still be FALSE indicating that
  2974. // we need to complete the Irp. So, we break out of the switch
  2975. // statement, endin up at the end of SoundDispatch perform cleanup
  2976. // and complete the Irp.
  2977. //
  2978. }
  2979. break;
  2980. case IOCTL_WDMAUD_MIXER_OPEN:
  2981. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_OPEN"));
  2982. {
  2983. extern PKEVENT pHardwareCallbackEvent;
  2984. if (DataBufferSize != 0)
  2985. {
  2986. Status = STATUS_INVALID_BUFFER_SIZE;
  2987. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  2988. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2989. break;
  2990. }
  2991. if (pHardwareCallbackEvent==NULL && DeviceInfo->HardwareCallbackEventHandle) {
  2992. Status = ObReferenceObjectByHandle(DeviceInfo->HardwareCallbackEventHandle, EVENT_ALL_ACCESS, *ExEventObjectType, pIrp->RequestorMode, (PVOID *)&pHardwareCallbackEvent, NULL);
  2993. if (Status!=STATUS_SUCCESS) {
  2994. DPF(DL_WARNING|FA_IOCTL, ("Could not reference hardware callback event object!"));
  2995. }
  2996. }
  2997. Status = kmxlOpenHandler( pContext, DeviceInfo, NULL );
  2998. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  2999. }
  3000. break;
  3001. case IOCTL_WDMAUD_MIXER_CLOSE:
  3002. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_CLOSE"));
  3003. if (DataBufferSize != 0)
  3004. {
  3005. Status = STATUS_INVALID_PARAMETER;
  3006. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  3007. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  3008. break;
  3009. }
  3010. Status = kmxlCloseHandler( DeviceInfo, NULL );
  3011. pIrp->IoStatus.Information = sizeof(DEVICEINFO);
  3012. break;
  3013. case IOCTL_WDMAUD_MIXER_GETLINEINFO:
  3014. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_GETLINEINFO"));
  3015. Status = Dispatch_GetLineInfo(pIrp,
  3016. pContext,
  3017. DeviceInfo);
  3018. break;
  3019. case IOCTL_WDMAUD_MIXER_GETLINECONTROLS:
  3020. {
  3021. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_GETLINECONTROLS"));
  3022. Status = Dispatch_GetLineControls(pIrp,
  3023. pContext,
  3024. DeviceInfo);
  3025. break;
  3026. }
  3027. case IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS:
  3028. {
  3029. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS"));
  3030. Status = Dispatch_GetControlDetails(pIrp,
  3031. pContext,
  3032. DeviceInfo);
  3033. break;
  3034. }
  3035. case IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS:
  3036. {
  3037. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS"));
  3038. Status = Dispatch_SetControlDetails(pIrp,
  3039. pContext,
  3040. DeviceInfo);
  3041. break;
  3042. }
  3043. case IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA:
  3044. {
  3045. DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA"));
  3046. Status = Dispatch_GetHardwareEventData(pIrp,
  3047. DeviceInfo);
  3048. break;
  3049. }
  3050. default:
  3051. {
  3052. Status = STATUS_NOT_SUPPORTED;
  3053. break;
  3054. }
  3055. } // end of switch on IOCTL
  3056. break;
  3057. }
  3058. default:
  3059. {
  3060. Status = STATUS_NOT_SUPPORTED;
  3061. break;
  3062. }
  3063. } // end of switch on IRP_MAJOR_XXXX
  3064. #ifdef _WIN64
  3065. if (IoIs32bitProcess(pIrp)) {
  3066. if (DeviceInfo32!=NULL) {
  3067. ThunkDeviceInfo6432(DeviceInfo, DeviceInfo32);
  3068. }
  3069. else {
  3070. DPF(DL_WARNING|FA_IOCTL,("DeviceInfo32") );
  3071. }
  3072. }
  3073. #endif
  3074. //
  3075. // Now complete the IRP
  3076. //
  3077. pIrp->IoStatus.Status = Status;
  3078. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  3079. WdmaReleaseMutex(pContext);
  3080. RETURN( Status );
  3081. }