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.

1478 lines
43 KiB

  1. /****************************************************************************
  2. *
  3. * midi.c
  4. *
  5. * Midi routines for wdmaud.sys
  6. *
  7. * Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
  8. *
  9. * History
  10. * S.Mohanraj (MohanS)
  11. * M.McLaughlin (MikeM)
  12. * 5-19-97 - Noel Cross (NoelC)
  13. *
  14. ***************************************************************************/
  15. #include "wdmsys.h"
  16. #define IRP_LATENCY_100NS 3000
  17. //
  18. // This is just a scratch location that is never used for anything
  19. // but a parameter to core functions.
  20. //
  21. IO_STATUS_BLOCK gIoStatusBlock ;
  22. #pragma PAGEABLE_CODE
  23. #pragma PAGEABLE_DATA
  24. ULONGLONG
  25. GetCurrentMidiTime()
  26. {
  27. LARGE_INTEGER liFrequency,liTime;
  28. PAGED_CODE();
  29. // total ticks since system booted
  30. liTime = KeQueryPerformanceCounter(&liFrequency);
  31. // Convert ticks to 100ns units using Ks macro
  32. //
  33. return (KSCONVERT_PERFORMANCE_TIME(liFrequency.QuadPart,liTime));
  34. }
  35. //
  36. // This routine gives us a pMidiPin to play with.
  37. //
  38. NTSTATUS
  39. OpenMidiPin(
  40. PWDMACONTEXT pWdmaContext,
  41. ULONG DeviceNumber,
  42. ULONG DataFlow //DataFlow is either in or out.
  43. )
  44. {
  45. PMIDI_PIN_INSTANCE pMidiPin = NULL;
  46. NTSTATUS Status;
  47. PKSPIN_CONNECT pConnect = NULL;
  48. PKSDATARANGE pDataRange;
  49. PCONTROLS_LIST pControlList = NULL;
  50. ULONG Device;
  51. ULONG PinId;
  52. PAGED_CODE();
  53. //
  54. // Because of the ZERO_FILL_MEMORY flag, are pMidiPin structure will come
  55. // back zero'd out.
  56. //
  57. Status = AudioAllocateMemory_Fixed(sizeof(MIDI_PIN_INSTANCE),
  58. TAG_Audi_PIN,
  59. ZERO_FILL_MEMORY,
  60. &pMidiPin);
  61. if(!NT_SUCCESS(Status))
  62. {
  63. goto exit;
  64. }
  65. pMidiPin->dwSig = MIDI_PIN_INSTANCE_SIGNATURE;
  66. pMidiPin->DataFlow = DataFlow;
  67. pMidiPin->DeviceNumber = DeviceNumber;
  68. pMidiPin->PinState = KSSTATE_STOP;
  69. KeInitializeSpinLock( &pMidiPin->MidiPinSpinLock );
  70. KeInitializeEvent ( &pMidiPin->StopEvent,SynchronizationEvent,FALSE ) ;
  71. if( KSPIN_DATAFLOW_IN == DataFlow )
  72. {
  73. pMidiPin->pMidiDevice = &pWdmaContext->MidiOutDevs[DeviceNumber];
  74. if (NULL == pWdmaContext->MidiOutDevs[DeviceNumber].pMidiPin)
  75. {
  76. pWdmaContext->MidiOutDevs[DeviceNumber].pMidiPin = pMidiPin;
  77. }
  78. else
  79. {
  80. DPF(DL_TRACE|FA_MIDI, ("Midi device in use") );
  81. AudioFreeMemory( sizeof(MIDI_PIN_INSTANCE),&pMidiPin );
  82. Status = STATUS_DEVICE_BUSY;
  83. goto exit;
  84. }
  85. } else {
  86. //
  87. // KSPIN_DATAFLOW_OUT
  88. //
  89. pMidiPin->pMidiDevice = &pWdmaContext->MidiInDevs[DeviceNumber];
  90. InitializeListHead(&pMidiPin->MidiInQueueListHead);
  91. KeInitializeSpinLock(&pMidiPin->MidiInQueueSpinLock);
  92. if (NULL == pWdmaContext->MidiInDevs[DeviceNumber].pMidiPin)
  93. {
  94. pWdmaContext->MidiInDevs[DeviceNumber].pMidiPin = pMidiPin;
  95. }
  96. else
  97. {
  98. AudioFreeMemory( sizeof(MIDI_PIN_INSTANCE),&pMidiPin );
  99. Status = STATUS_DEVICE_BUSY;
  100. goto exit;
  101. }
  102. }
  103. //
  104. // We only support one midi client at a time, the check above will
  105. // only add this structure if there is not already one there. If there
  106. // was something there already, we skip all the following code and
  107. // go directly to the exit lable. Thus, fGraphRunning must not be
  108. // set when we are here.
  109. //
  110. ASSERT( !pMidiPin->fGraphRunning );
  111. pMidiPin->fGraphRunning++;
  112. //
  113. // Because of the ZERO_FILL_MEMORY flag our pConnect structure will
  114. // come back all zero'd out.
  115. //
  116. Status = AudioAllocateMemory_Fixed(sizeof(KSPIN_CONNECT) + sizeof(KSDATARANGE),
  117. TAG_Audt_CONNECT,
  118. ZERO_FILL_MEMORY,
  119. &pConnect);
  120. if(!NT_SUCCESS(Status))
  121. {
  122. pMidiPin->fGraphRunning--;
  123. goto exit ;
  124. }
  125. pDataRange = (PKSDATARANGE)(pConnect + 1);
  126. PinId = pMidiPin->pMidiDevice->PinId;
  127. Device = pMidiPin->pMidiDevice->Device;
  128. pConnect->Interface.Set = KSINTERFACESETID_Standard ;
  129. pConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
  130. pConnect->Medium.Set = KSMEDIUMSETID_Standard;
  131. pConnect->Medium.Id = KSMEDIUM_STANDARD_DEVIO;
  132. pConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
  133. pConnect->Priority.PrioritySubClass = 1;
  134. pDataRange->MajorFormat = KSDATAFORMAT_TYPE_MUSIC;
  135. pDataRange->SubFormat = KSDATAFORMAT_SUBTYPE_MIDI;
  136. pDataRange->Specifier = KSDATAFORMAT_SPECIFIER_NONE;
  137. pDataRange->FormatSize = sizeof( KSDATARANGE );
  138. pDataRange->Reserved = 0 ;
  139. Status = AudioAllocateMemory_Fixed((sizeof(CONTROLS_LIST) +
  140. ( (MAX_MIDI_CONTROLS - 1) * sizeof(CONTROL_NODE) ) ),
  141. TAG_AudC_CONTROL,
  142. ZERO_FILL_MEMORY,
  143. &pControlList) ;
  144. if(!NT_SUCCESS(Status))
  145. {
  146. pMidiPin->fGraphRunning--;
  147. AudioFreeMemory( sizeof(KSPIN_CONNECT) + sizeof(KSDATARANGE),&pConnect );
  148. goto exit ;
  149. }
  150. pControlList->Count = MAX_MIDI_CONTROLS ;
  151. pControlList->Controls[MIDI_CONTROL_VOLUME].Control = KSNODETYPE_VOLUME ;
  152. pMidiPin->pControlList = pControlList ;
  153. // Open a pin
  154. Status = OpenSysAudioPin(Device,
  155. PinId,
  156. pMidiPin->DataFlow,
  157. pConnect,
  158. &pMidiPin->pFileObject,
  159. &pMidiPin->pDeviceObject,
  160. pMidiPin->pControlList);
  161. AudioFreeMemory( sizeof(KSPIN_CONNECT) + sizeof(KSDATARANGE),&pConnect );
  162. if (!NT_SUCCESS(Status))
  163. {
  164. CloseMidiDevicePin(pMidiPin->pMidiDevice);
  165. goto exit ;
  166. }
  167. //
  168. // OpenSysAudioPin sets the file object in the pin. Now that we have
  169. // successfully returned from the call, validate that we have non-NULL
  170. // items.
  171. //
  172. ASSERT(pMidiPin->pFileObject);
  173. ASSERT(pMidiPin->pDeviceObject);
  174. //
  175. // For output we put the device in a RUN state on open
  176. // For input we have to wait until the device gets told
  177. // to start
  178. //
  179. if ( KSPIN_DATAFLOW_IN == pMidiPin->DataFlow )
  180. {
  181. Status = AttachVirtualSource(pMidiPin->pFileObject, pMidiPin->pMidiDevice->pWdmaContext->VirtualMidiPinId);
  182. if (NT_SUCCESS(Status))
  183. {
  184. Status = StateMidiOutPin(pMidiPin, KSSTATE_RUN);
  185. }
  186. if (!NT_SUCCESS(Status))
  187. {
  188. CloseMidiDevicePin(pMidiPin->pMidiDevice);
  189. }
  190. }
  191. else
  192. {
  193. //
  194. // Pause will queue a bunch of IRPs
  195. //
  196. Status = StateMidiInPin(pMidiPin, KSSTATE_PAUSE);
  197. if (!NT_SUCCESS(Status))
  198. {
  199. CloseMidiDevicePin(pMidiPin->pMidiDevice);
  200. }
  201. }
  202. exit:
  203. RETURN( Status );
  204. }
  205. //
  206. // This routine is called from multiple places. As long as it's not reentrant, it should be
  207. // ok. Should check for that.
  208. //
  209. // This routine gets called from RemoveDevNode. RemoveDevNode gets called from user mode
  210. // or from the ContextCleanup routine. Both routines are in the global mutex.
  211. //
  212. VOID
  213. CloseMidiDevicePin(
  214. PMIDIDEVICE pMidiDevice
  215. )
  216. {
  217. PAGED_CODE();
  218. if (NULL != pMidiDevice->pMidiPin )
  219. {
  220. //
  221. // CloseMidiPin must not fail.
  222. //
  223. CloseMidiPin ( pMidiDevice->pMidiPin ) ;
  224. //
  225. // AudioFreeMemory Nulls out this memory location.
  226. //
  227. AudioFreeMemory( sizeof(MIDI_PIN_INSTANCE),&pMidiDevice->pMidiPin ) ;
  228. }
  229. }
  230. #pragma LOCKED_CODE
  231. #pragma LOCKED_DATA
  232. //
  233. // The idea behind this SpinLock is that we want to protect the NumPendingIos
  234. // value in the Irp completion routine. There, there is a preemption issue
  235. // that we can't have an InterlockedIncrement or InterlockedDecrement interfer
  236. // with.
  237. //
  238. void
  239. LockedMidiIoCount(
  240. PMIDI_PIN_INSTANCE pCurMidiPin,
  241. BOOL bIncrease
  242. )
  243. {
  244. KIRQL OldIrql;
  245. KeAcquireSpinLock(&pCurMidiPin->MidiPinSpinLock,&OldIrql);
  246. if( bIncrease )
  247. pCurMidiPin->NumPendingIos++;
  248. else
  249. pCurMidiPin->NumPendingIos--;
  250. KeReleaseSpinLock(&pCurMidiPin->MidiPinSpinLock, OldIrql);
  251. }
  252. VOID
  253. FreeIrpMdls(
  254. PIRP pIrp
  255. )
  256. {
  257. if (pIrp->MdlAddress != NULL)
  258. {
  259. PMDL Mdl, nextMdl;
  260. for (Mdl = pIrp->MdlAddress; Mdl != (PMDL) NULL; Mdl = nextMdl)
  261. {
  262. nextMdl = Mdl->Next;
  263. MmUnlockPages( Mdl );
  264. AudioFreeMemory_Unknown( &Mdl );
  265. }
  266. pIrp->MdlAddress = NULL;
  267. }
  268. }
  269. #pragma PAGEABLE_CODE
  270. #pragma PAGEABLE_DATA
  271. //
  272. // This routine can not fail. When it returns, pMidiPin will be freed.
  273. //
  274. VOID
  275. CloseMidiPin(
  276. PMIDI_PIN_INSTANCE pMidiPin
  277. )
  278. {
  279. PMIDIINHDR pHdr;
  280. PMIDIINHDR pTemp;
  281. KSSTATE State;
  282. PAGED_CODE();
  283. // This is designed to bring us back to square one, even
  284. // if we were not completely opened
  285. if( !pMidiPin->fGraphRunning )
  286. {
  287. ASSERT(pMidiPin->fGraphRunning == 1);
  288. return ;
  289. }
  290. pMidiPin->fGraphRunning--;
  291. // Close the file object (pMidiPin->pFileObject, if it exists)
  292. if(pMidiPin->pFileObject)
  293. {
  294. //
  295. // For Midi Input we need to flush the queued up scratch IRPs by
  296. // issuing a STOP command.
  297. //
  298. // We don't want to do that for Midi Output because we might loose
  299. // the "all notes off" sequence that needs to get to the device.
  300. //
  301. // Regardless, in both cases we need to wait until we have
  302. // compeletely flushed the device before we can close it.
  303. //
  304. if ( KSPIN_DATAFLOW_OUT == pMidiPin->DataFlow )
  305. {
  306. PLIST_ENTRY ple;
  307. //
  308. // This is kind of a catch-22. We need to release
  309. // the mutex which was grabbed when we entered the
  310. // ioctl dispatch routine to allow the midi input
  311. // irps which are queued up in a work item waiting
  312. // until the mutex is free in order to be send
  313. // down to portcls.
  314. //
  315. WdmaReleaseMutex(pMidiPin->pMidiDevice->pWdmaContext);
  316. //
  317. // This loop removes an entry and frees it until the list is empty.
  318. //
  319. while((ple = ExInterlockedRemoveHeadList(&pMidiPin->MidiInQueueListHead,
  320. &pMidiPin->MidiInQueueSpinLock)) != NULL)
  321. {
  322. LPMIDIDATA pMidiData;
  323. PIRP UserIrp;
  324. PWDMAPENDINGIRP_CONTEXT pPendingIrpContext;
  325. pHdr = CONTAINING_RECORD(ple,MIDIINHDR,Next);
  326. //
  327. // Get into locals and zero out midi data
  328. //
  329. UserIrp = pHdr->pIrp;
  330. pMidiData = pHdr->pMidiData;
  331. pPendingIrpContext = pHdr->pPendingIrpContext;
  332. ASSERT(pPendingIrpContext);
  333. RtlZeroMemory(pMidiData, sizeof(MIDIDATA));
  334. //
  335. // unlock memory before completing the Irp
  336. //
  337. wdmaudUnmapBuffer(pHdr->pMdl);
  338. AudioFreeMemory_Unknown(&pHdr);
  339. //
  340. // Now complete the Irp for wdmaud.drv to process
  341. //
  342. DPF(DL_TRACE|FA_MIDI, ("CloseMidiPin: Freeing pending UserIrp: 0x%08lx",UserIrp));
  343. wdmaudUnprepareIrp ( UserIrp,
  344. STATUS_CANCELLED,
  345. sizeof(DEVICEINFO),
  346. pPendingIrpContext );
  347. }
  348. }
  349. //
  350. // At this point we know that the list is empty, but there
  351. // still might be an Irp in the completion process. We have
  352. // to call the standard wait routine to make sure it gets completed.
  353. //
  354. pMidiPin->StoppingSource = TRUE ;
  355. if ( KSPIN_DATAFLOW_OUT == pMidiPin->DataFlow )
  356. {
  357. StatePin ( pMidiPin->pFileObject, KSSTATE_STOP, &pMidiPin->PinState ) ;
  358. }
  359. //
  360. // Need to wait for all in and out data to complete.
  361. //
  362. MidiCompleteIo( pMidiPin, FALSE );
  363. if ( KSPIN_DATAFLOW_OUT == pMidiPin->DataFlow )
  364. {
  365. //
  366. // Grab back the mutex which was freed before we started
  367. // waiting on the I/O to complete.
  368. //
  369. WdmaGrabMutex(pMidiPin->pMidiDevice->pWdmaContext);
  370. }
  371. CloseSysAudio(pMidiPin->pMidiDevice->pWdmaContext, pMidiPin->pFileObject);
  372. pMidiPin->pFileObject = NULL;
  373. }
  374. //
  375. // AudioFreeMemory_Unknown Nulls out this location
  376. //
  377. AudioFreeMemory_Unknown ( &pMidiPin->pControlList ) ;
  378. }
  379. #pragma LOCKED_CODE
  380. #pragma LOCKED_DATA
  381. //
  382. // This is the IRP completion routine.
  383. //
  384. NTSTATUS
  385. WriteMidiEventCallBack(
  386. PDEVICE_OBJECT pDeviceObject,
  387. PIRP pIrp,
  388. IN PSTREAM_HEADER_EX pStreamHeader
  389. )
  390. {
  391. KIRQL OldIrql;
  392. PMIDI_PIN_INSTANCE pMidiOutPin;
  393. pMidiOutPin = pStreamHeader->pMidiPin;
  394. if (pMidiOutPin)
  395. {
  396. KeAcquireSpinLock(&pMidiOutPin->MidiPinSpinLock,&OldIrql);
  397. //
  398. // One less Io packet outstanding, thus we always decrement the
  399. // outstanding count. Then, we compare to see if we're the last
  400. // packet and we're stopping then we signal the saiting thead.
  401. //
  402. if( ( 0 == --pMidiOutPin->NumPendingIos ) && pMidiOutPin->StoppingSource )
  403. {
  404. KeSetEvent ( &pMidiOutPin->StopEvent, 0, FALSE ) ;
  405. }
  406. //
  407. // Upon releasing this spin lock pMidiOutPin will no longer be valid.
  408. // Thus we must not touch it.
  409. //
  410. KeReleaseSpinLock(&pMidiOutPin->MidiPinSpinLock,OldIrql);
  411. }
  412. //
  413. // If there are any Mdls, free them here otherwise IoCompleteRequest will do it after the
  414. // freeing of our data buffer below.
  415. //
  416. FreeIrpMdls(pIrp);
  417. AudioFreeMemory(sizeof(STREAM_HEADER_EX),&pStreamHeader);
  418. return STATUS_SUCCESS;
  419. }
  420. #pragma PAGEABLE_CODE
  421. #pragma PAGEABLE_DATA
  422. NTSTATUS
  423. WriteMidiEventPin(
  424. PMIDIDEVICE pMidiOutDevice,
  425. ULONG ulEvent
  426. )
  427. {
  428. PKSMUSICFORMAT pMusicFormat;
  429. PSTREAM_HEADER_EX pStreamHeader = NULL;
  430. PMIDI_PIN_INSTANCE pMidiPin;
  431. NTSTATUS Status = STATUS_SUCCESS;
  432. BYTE bEvent;
  433. ULONG TheEqualizer;
  434. ULONGLONG nsPlayTime;
  435. KEVENT keEventObject;
  436. PWDMACONTEXT pWdmaContext;
  437. PAGED_CODE();
  438. pMidiPin = pMidiOutDevice->pMidiPin;
  439. if (!pMidiPin ||!pMidiPin->fGraphRunning || !pMidiPin->pFileObject )
  440. {
  441. DPF(DL_WARNING|FA_MIDI,("Not ready pMidiPin=%X",pMidiPin) );
  442. RETURN( STATUS_DEVICE_NOT_READY );
  443. }
  444. //
  445. // allocate enough memory for the stream header
  446. // the midi/music header, the data, the work item,
  447. // and the DeviceNumber. The memroy allocation
  448. // is zero'd with the ZERO_FILL_MEMORY flag
  449. //
  450. Status = AudioAllocateMemory_Fixed(sizeof(STREAM_HEADER_EX) + sizeof(KSMUSICFORMAT) +
  451. sizeof(ULONG),
  452. TAG_Audh_STREAMHEADER,
  453. ZERO_FILL_MEMORY,
  454. &pStreamHeader); // ulEvent
  455. if(!NT_SUCCESS(Status))
  456. {
  457. return Status;
  458. }
  459. // Get a pointer to the music header
  460. pMusicFormat = (PKSMUSICFORMAT)(pStreamHeader + 1);
  461. // Play 0 ms from the time-stamp in the KSSTREAM_HEADER
  462. pMusicFormat->TimeDeltaMs = 0;
  463. RtlCopyMemory((BYTE *)(pMusicFormat + 1), // the actual data
  464. &ulEvent,
  465. sizeof(ulEvent));
  466. // setup the stream header
  467. pStreamHeader->Header.Data = pMusicFormat;
  468. pStreamHeader->Header.FrameExtent = sizeof(KSMUSICFORMAT) + sizeof(ULONG);
  469. pStreamHeader->Header.Size = sizeof( KSSTREAM_HEADER );
  470. pStreamHeader->Header.DataUsed = pStreamHeader->Header.FrameExtent;
  471. nsPlayTime = GetCurrentMidiTime() - pMidiPin->LastTimeNs + IRP_LATENCY_100NS;
  472. pStreamHeader->Header.PresentationTime.Time = nsPlayTime;
  473. pStreamHeader->Header.PresentationTime.Numerator = 1;
  474. pStreamHeader->Header.PresentationTime.Denominator = 1;
  475. pStreamHeader->pMidiPin = pMidiPin;
  476. //
  477. // Figure out how many bytes in this
  478. // event are valid.
  479. //
  480. bEvent = (BYTE)ulEvent;
  481. TheEqualizer = 0;
  482. if(!IS_STATUS(bEvent))
  483. {
  484. if (pMidiPin->bCurrentStatus)
  485. {
  486. bEvent = pMidiPin->bCurrentStatus;
  487. TheEqualizer = 1;
  488. }
  489. else
  490. {
  491. // Bad MIDI Stream didn't have a running status
  492. DPF(DL_WARNING|FA_MIDI,("No running status") );
  493. AudioFreeMemory(sizeof(STREAM_HEADER_EX),&pStreamHeader);
  494. RETURN( STATUS_UNSUCCESSFUL );
  495. }
  496. }
  497. if(IS_SYSTEM(bEvent))
  498. {
  499. if( IS_REALTIME(bEvent) ||
  500. bEvent == MIDI_TUNEREQ ||
  501. bEvent == MIDI_SYSX ||
  502. bEvent == MIDI_EOX )
  503. {
  504. pMusicFormat->ByteCount = 1;
  505. }
  506. else if(bEvent == MIDI_SONGPP)
  507. {
  508. pMusicFormat->ByteCount = 3;
  509. }
  510. else
  511. {
  512. pMusicFormat->ByteCount = 2;
  513. }
  514. }
  515. // Check for three byte messages
  516. else if((bEvent < MIDI_PCHANGE) || (bEvent >= MIDI_PBEND))
  517. {
  518. pMusicFormat->ByteCount = 3 - TheEqualizer;
  519. }
  520. else
  521. {
  522. pMusicFormat->ByteCount = 2 - TheEqualizer;
  523. }
  524. //
  525. // Cache the running status
  526. //
  527. if ( (bEvent >= MIDI_NOTEOFF) && (bEvent < MIDI_CLOCK) )
  528. {
  529. pMidiPin->bCurrentStatus = (BYTE)((bEvent < MIDI_SYSX) ? bEvent : 0);
  530. }
  531. //
  532. // Initialize our wait event, in case we need to wait.
  533. //
  534. KeInitializeEvent(&keEventObject,
  535. SynchronizationEvent,
  536. FALSE);
  537. LockedMidiIoCount(pMidiPin,INCREASE);
  538. //
  539. // Need to release the mutex so that during full-duplex
  540. // situations, we can get the midi input buffers down
  541. // to the device without blocking.
  542. //
  543. pWdmaContext = pMidiPin->pMidiDevice->pWdmaContext;
  544. WdmaReleaseMutex(pWdmaContext);
  545. // Set the packet to the device.
  546. Status = KsStreamIo(
  547. pMidiPin->pFileObject,
  548. &keEventObject, // Event
  549. NULL, // PortContext
  550. WriteMidiEventCallBack,
  551. pStreamHeader, // CompletionContext
  552. KsInvokeOnSuccess | KsInvokeOnCancel | KsInvokeOnError,
  553. &gIoStatusBlock,
  554. pStreamHeader,
  555. sizeof( KSSTREAM_HEADER ),
  556. KSSTREAM_WRITE | KSSTREAM_SYNCHRONOUS,
  557. KernelMode
  558. );
  559. if ( (Status != STATUS_PENDING) && (Status != STATUS_SUCCESS) )
  560. {
  561. DPF(DL_WARNING|FA_MIDI, ("KsStreamIO failed: 0x%08lx",Status));
  562. }
  563. //
  564. // Wait a minute here!!! If the Irp comes back pending, we
  565. // can NOT complete our user mode Irp! But, there is no
  566. // infastructure for storing the Irp in this call stack. The
  567. // other routines use wdmaudPrepareIrp to complete that user
  568. // Irp. Also, pPendingIrpContext is stored in the Irp context
  569. // so that the completion routine has the list to get the
  570. // user mode Irp from.
  571. //
  572. // .... Or, we need to make this routine synchronous and
  573. // wait like WriteMidiOutPin. I believe that this is bug
  574. // #551052. It should be fixed eventually.
  575. //
  576. //
  577. // Here is the fix. Wait if it is pending.
  578. //
  579. if ( STATUS_PENDING == Status )
  580. {
  581. //
  582. // Wait for the completion.
  583. //
  584. Status = KeWaitForSingleObject( &keEventObject,
  585. Executive,
  586. KernelMode,
  587. FALSE,
  588. (PLARGE_INTEGER) NULL );
  589. }
  590. //
  591. // Now grab the mutex again
  592. //
  593. WdmaGrabMutex(pWdmaContext);
  594. RETURN( Status );
  595. }
  596. #pragma LOCKED_CODE
  597. #pragma LOCKED_DATA
  598. //
  599. // This is an IRP completion routine.
  600. //
  601. NTSTATUS
  602. WriteMidiCallBack(
  603. PDEVICE_OBJECT pDeviceObject,
  604. PIRP pIrp,
  605. IN PSTREAM_HEADER_EX pStreamHeader
  606. )
  607. {
  608. //
  609. // If there are any Mdls, free them here otherwise IoCompleteRequest will do it after the
  610. // freeing of our data buffer below.
  611. //
  612. FreeIrpMdls(pIrp);
  613. //
  614. // Cleanup after this synchronous write
  615. //
  616. AudioFreeMemory_Unknown(&pStreamHeader->Header.Data); // Music data
  617. wdmaudUnmapBuffer(pStreamHeader->pBufferMdl);
  618. AudioFreeMemory_Unknown(&pStreamHeader->pMidiHdr);
  619. AudioFreeMemory(sizeof(STREAM_HEADER_EX),&pStreamHeader);
  620. return STATUS_SUCCESS;
  621. }
  622. #pragma PAGEABLE_CODE
  623. #pragma PAGEABLE_DATA
  624. NTSTATUS
  625. WriteMidiOutPin(
  626. LPMIDIHDR pMidiHdr,
  627. PSTREAM_HEADER_EX pStreamHeader,
  628. BOOL *pCompletedIrp
  629. )
  630. {
  631. NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
  632. PKSMUSICFORMAT pMusicFormat = NULL;
  633. KEVENT keEventObject;
  634. ULONG AlignedLength;
  635. ULONGLONG nsPlayTime;
  636. PMIDI_PIN_INSTANCE pMidiPin;
  637. PWDMACONTEXT pWdmaContext;
  638. PAGED_CODE();
  639. pMidiPin = pStreamHeader->pMidiPin;
  640. if (!pMidiPin ||!pMidiPin->fGraphRunning || !pMidiPin->pFileObject )
  641. {
  642. DPF(DL_WARNING|FA_MIDI,("Not Ready") );
  643. wdmaudUnmapBuffer(pStreamHeader->pBufferMdl);
  644. AudioFreeMemory_Unknown( &pMidiHdr );
  645. AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
  646. RETURN( STATUS_DEVICE_NOT_READY );
  647. }
  648. //
  649. // FrameExtent contains dwBufferLength right now
  650. //
  651. AlignedLength = ((pStreamHeader->Header.FrameExtent + 3) & ~3);
  652. Status = AudioAllocateMemory_Fixed(sizeof(KSMUSICFORMAT) + AlignedLength,
  653. TAG_Audm_MUSIC,
  654. ZERO_FILL_MEMORY,
  655. &pMusicFormat);
  656. if(!NT_SUCCESS(Status))
  657. {
  658. wdmaudUnmapBuffer(pStreamHeader->pBufferMdl);
  659. AudioFreeMemory_Unknown( &pMidiHdr );
  660. AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
  661. return Status;
  662. }
  663. // Play 0 ms from the time-stamp in the KSSTREAM_HEADER
  664. pMusicFormat->TimeDeltaMs = 0;
  665. //
  666. // the system mapped data was stored in the data field
  667. // of the stream header
  668. //
  669. RtlCopyMemory((BYTE *)(pMusicFormat + 1), // the actual data
  670. pStreamHeader->Header.Data,
  671. pStreamHeader->Header.FrameExtent);
  672. //
  673. // Setup the number of bytes of midi data we're sending
  674. //
  675. pMusicFormat->ByteCount = pStreamHeader->Header.FrameExtent;
  676. // setup the stream header
  677. pStreamHeader->Header.Data = pMusicFormat;
  678. // Now overwrite FrameExtent with the correct rounded up dword aligned value
  679. pStreamHeader->Header.FrameExtent = sizeof(KSMUSICFORMAT) + AlignedLength;
  680. pStreamHeader->Header.OptionsFlags= 0;
  681. pStreamHeader->Header.Size = sizeof( KSSTREAM_HEADER );
  682. pStreamHeader->Header.TypeSpecificFlags = 0;
  683. pStreamHeader->Header.DataUsed = pStreamHeader->Header.FrameExtent;
  684. pStreamHeader->pMidiHdr = pMidiHdr;
  685. nsPlayTime = GetCurrentMidiTime() - pStreamHeader->pMidiPin->LastTimeNs + IRP_LATENCY_100NS;
  686. pStreamHeader->Header.PresentationTime.Time = nsPlayTime;
  687. pStreamHeader->Header.PresentationTime.Numerator = 1;
  688. pStreamHeader->Header.PresentationTime.Denominator = 1;
  689. //
  690. // Initialize our wait event, in case we need to wait.
  691. //
  692. KeInitializeEvent(&keEventObject,
  693. SynchronizationEvent,
  694. FALSE);
  695. //
  696. // Need to release the mutex so that during full-duplex
  697. // situations, we can get the midi input buffers down
  698. // to the device without blocking.
  699. //
  700. pWdmaContext = pMidiPin->pMidiDevice->pWdmaContext;
  701. WdmaReleaseMutex(pWdmaContext);
  702. // Send the packet to the device.
  703. Status = KsStreamIo(
  704. pMidiPin->pFileObject,
  705. &keEventObject, // Event
  706. NULL, // PortContext
  707. WriteMidiCallBack,
  708. pStreamHeader, // CompletionContext
  709. KsInvokeOnSuccess | KsInvokeOnCancel | KsInvokeOnError,
  710. &gIoStatusBlock,
  711. &pStreamHeader->Header,
  712. sizeof( KSSTREAM_HEADER ),
  713. KSSTREAM_WRITE | KSSTREAM_SYNCHRONOUS,
  714. KernelMode
  715. );
  716. //
  717. // Wait if it is pending.
  718. //
  719. if ( STATUS_PENDING == Status )
  720. {
  721. //
  722. // Wait for the completion.
  723. //
  724. Status = KeWaitForSingleObject( &keEventObject,
  725. Executive,
  726. KernelMode,
  727. FALSE,
  728. (PLARGE_INTEGER) NULL );
  729. }
  730. //
  731. // From the Wait above, we can see that this routine is
  732. // always synchronous. Thus, any Irp that we passed down
  733. // in the KsStreamIo call will have been completed and KS
  734. // will have signaled keEventObject. Thus, we can
  735. // now complete our Irp.
  736. //
  737. // ... Thus we leave pCompletedIrp set to FALSE.
  738. //
  739. //
  740. // Now grab the mutex again
  741. //
  742. WdmaGrabMutex(pWdmaContext);
  743. RETURN( Status );
  744. }
  745. NTSTATUS
  746. ResetMidiInPin(
  747. PMIDI_PIN_INSTANCE pMidiPin
  748. )
  749. {
  750. NTSTATUS Status;
  751. PAGED_CODE();
  752. if (!pMidiPin || !pMidiPin->fGraphRunning)
  753. {
  754. DPF(DL_WARNING|FA_MIDI,("Not Ready") );
  755. RETURN( STATUS_DEVICE_NOT_READY );
  756. }
  757. Status = StateMidiInPin ( pMidiPin, KSSTATE_PAUSE );
  758. RETURN( Status );
  759. }
  760. NTSTATUS
  761. StateMidiOutPin(
  762. PMIDI_PIN_INSTANCE pMidiPin,
  763. KSSTATE State
  764. )
  765. {
  766. NTSTATUS Status;
  767. PAGED_CODE();
  768. if (!pMidiPin || !pMidiPin->fGraphRunning)
  769. {
  770. DPF(DL_WARNING|FA_MIDI,("Not Ready") );
  771. RETURN( STATUS_DEVICE_NOT_READY );
  772. }
  773. if (State == KSSTATE_RUN)
  774. {
  775. pMidiPin->LastTimeNs = GetCurrentMidiTime();
  776. }
  777. else if (State == KSSTATE_STOP)
  778. {
  779. pMidiPin->LastTimeNs = 0;
  780. }
  781. Status = StatePin ( pMidiPin->pFileObject, State, &pMidiPin->PinState ) ;
  782. RETURN( Status );
  783. }
  784. //
  785. // Waits for all the Irps to complete.
  786. //
  787. void
  788. MidiCompleteIo(
  789. PMIDI_PIN_INSTANCE pMidiPin,
  790. BOOL Yield
  791. )
  792. {
  793. PAGED_CODE();
  794. if ( pMidiPin->NumPendingIos )
  795. {
  796. DPF(DL_TRACE|FA_MIDI, ("Waiting on %d I/Os to flush Midi device",
  797. pMidiPin->NumPendingIos ));
  798. if( Yield )
  799. {
  800. //
  801. // This is kind of a catch-22. We need to release
  802. // the mutex which was grabbed when we entered the
  803. // ioctl dispatch routine to allow the midi input
  804. // irps which are queued up in a work item waiting
  805. // until the mutex is free in order to be send
  806. // down to portcls.
  807. //
  808. WdmaReleaseMutex(pMidiPin->pMidiDevice->pWdmaContext);
  809. }
  810. //
  811. // Wait for all the Irps to complete. The last one will
  812. // signal us to wake.
  813. //
  814. KeWaitForSingleObject ( &pMidiPin->StopEvent,
  815. Executive,
  816. KernelMode,
  817. FALSE,
  818. NULL ) ;
  819. if( Yield )
  820. {
  821. WdmaGrabMutex(pMidiPin->pMidiDevice->pWdmaContext);
  822. }
  823. DPF(DL_TRACE|FA_MIDI, ("Done waiting to flush Midi device"));
  824. }
  825. //
  826. // Why do we have this?
  827. //
  828. KeClearEvent ( &pMidiPin->StopEvent );
  829. //
  830. // All the IRPs have completed. We now restore the StoppingSource
  831. // variable so that we can recycle the pMidiPin.
  832. //
  833. pMidiPin->StoppingSource = FALSE;
  834. }
  835. //
  836. // If the driver failed the KSSTATE_STOP request, we return that error
  837. // code to the caller.
  838. //
  839. NTSTATUS
  840. StopMidiPinAndCompleteIo(
  841. PMIDI_PIN_INSTANCE pMidiPin,
  842. BOOL Yield
  843. )
  844. {
  845. NTSTATUS Status;
  846. PAGED_CODE();
  847. //
  848. // Indicate to the completion routine that we are stopping now.
  849. //
  850. pMidiPin->StoppingSource = TRUE;
  851. //
  852. // Tell the driver to stop. Regardless, we will wait for the
  853. // IRPs to complete if there are any outstanding.
  854. //
  855. Status = StatePin( pMidiPin->pFileObject, KSSTATE_STOP, &pMidiPin->PinState ) ;
  856. //
  857. // NOTE: On success, the pMidiPin->PinState value will be
  858. // KSSTATE_STOP. On Error it will be the old state.
  859. //
  860. // This raises the question - Do we hang on failure?
  861. //
  862. MidiCompleteIo( pMidiPin,Yield );
  863. return Status;
  864. }
  865. NTSTATUS
  866. StateMidiInPin(
  867. PMIDI_PIN_INSTANCE pMidiPin,
  868. KSSTATE State
  869. )
  870. {
  871. NTSTATUS Status;
  872. PAGED_CODE();
  873. if (!pMidiPin || !pMidiPin->fGraphRunning)
  874. {
  875. DPF(DL_WARNING|FA_MIDI,("Not Ready") );
  876. RETURN( STATUS_DEVICE_NOT_READY );
  877. }
  878. //
  879. // We need to complete any pending SysEx buffers on a midiInStop
  880. //
  881. //
  882. // Here, if we're asked to go to the paused state and we're not
  883. // already in the paused state, we have to go through a stop.
  884. // Thus we stop the driver, wait for it to complete all the outstanding
  885. // IRPs and then place the driver in pause and place buffers
  886. // down on it again.
  887. //
  888. if( (KSSTATE_PAUSE == State) &&
  889. (KSSTATE_PAUSE != pMidiPin->PinState) )
  890. {
  891. Status = StopMidiPinAndCompleteIo(pMidiPin,TRUE);
  892. //
  893. // If we were successful at stopping the driver, we set
  894. // the pin back up in the pause state.
  895. //
  896. if (NT_SUCCESS(Status))
  897. {
  898. ULONG BufferCount;
  899. //
  900. // Put the driver back in the pause state.
  901. //
  902. Status = StatePin ( pMidiPin->pFileObject, State, &pMidiPin->PinState ) ;
  903. if (NT_SUCCESS(Status))
  904. {
  905. //
  906. // This loop places STREAM_BUFFERS (128) of them down on the
  907. // device. NumPendingIos should be 128 when this is done.
  908. //
  909. for (BufferCount = 0; BufferCount < STREAM_BUFFERS; BufferCount++)
  910. {
  911. Status = ReadMidiPin( pMidiPin );
  912. if (!NT_SUCCESS(Status))
  913. {
  914. CloseMidiPin( pMidiPin );
  915. //
  916. // Appears that this error path is not correct. If we
  917. // call CloseMidiPin fGraphRunning will get reduced to 0.
  918. // Then, on the next close call CloseMidiPin will assert
  919. // because the pin is not running. We need to be able to
  920. // error out of this path without messing up the fGraphRunning
  921. // state.
  922. //
  923. DPFBTRAP();
  924. break;
  925. }
  926. }
  927. }
  928. }
  929. } else {
  930. //
  931. // Else we're not going to the pause state, so just make the state
  932. // change.
  933. //
  934. Status = StatePin ( pMidiPin->pFileObject, State, &pMidiPin->PinState ) ;
  935. }
  936. RETURN( Status );
  937. }
  938. #pragma LOCKED_CODE
  939. #pragma LOCKED_DATA
  940. NTSTATUS
  941. ReadMidiCallBack(
  942. PDEVICE_OBJECT pDeviceObject,
  943. PIRP pIrp,
  944. IN PSTREAM_HEADER_EX pStreamHeader
  945. )
  946. {
  947. WRITE_CONTEXT *pwc;
  948. PMIDI_PIN_INSTANCE pMidiInPin;
  949. PMIDIINHDR pMidiInHdr;
  950. PKSMUSICFORMAT IrpMusicHdr;
  951. ULONG IrpDataLeft;
  952. LPBYTE IrpData;
  953. ULONG RunningTimeMs;
  954. BOOL bResubmit = TRUE;
  955. BOOL bDataError = FALSE;
  956. NTSTATUS Status = STATUS_SUCCESS;
  957. KIRQL OldIrql;
  958. PLIST_ENTRY ple;
  959. DPF(DL_TRACE|FA_MIDI, ("Irp.Status = 0x%08lx",pIrp->IoStatus.Status));
  960. pMidiInPin = pStreamHeader->pMidiPin;
  961. //
  962. // No pin should ever be closed before all the Io comes back. So
  963. // we'll sanity check that here.
  964. //
  965. ASSERT(pMidiInPin);
  966. if( pMidiInPin )
  967. {
  968. DPF(DL_TRACE|FA_MIDI, ("R%d: 0x%08x", pMidiInPin->NumPendingIos, pStreamHeader));
  969. //
  970. // This routine should do an ExInterlockedRemoveHeadList to get the
  971. // head of the list.
  972. //
  973. if((ple = ExInterlockedRemoveHeadList(&pMidiInPin->MidiInQueueListHead,
  974. &pMidiInPin->MidiInQueueSpinLock)) != NULL)
  975. {
  976. PWDMAPENDINGIRP_CONTEXT pPendingIrpContext;
  977. LPMIDIDATA pMidiData;
  978. PIRP UserIrp;
  979. //
  980. // We have something to do.
  981. //
  982. pMidiInHdr = CONTAINING_RECORD(ple, MIDIINHDR, Next);
  983. //
  984. // Pull some information into locals
  985. //
  986. IrpData = (LPBYTE)((PKSMUSICFORMAT)(pStreamHeader->Header.Data) + 1);
  987. UserIrp = pMidiInHdr->pIrp;
  988. pMidiData = pMidiInHdr->pMidiData;
  989. pPendingIrpContext = pMidiInHdr->pPendingIrpContext;
  990. ASSERT(pPendingIrpContext);
  991. //
  992. // Let's see what we have here
  993. //
  994. DPF(DL_TRACE|FA_MIDI, ("IrpData = 0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
  995. *(LPBYTE)IrpData,*(LPBYTE)IrpData+1,*(LPBYTE)IrpData+2,
  996. *(LPBYTE)IrpData+3,*(LPBYTE)IrpData+4,*(LPBYTE)IrpData+5,
  997. *(LPBYTE)IrpData+6,*(LPBYTE)IrpData+7,*(LPBYTE)IrpData+8,
  998. *(LPBYTE)IrpData+9,*(LPBYTE)IrpData+10,*(LPBYTE)IrpData+11) );
  999. //
  1000. // Copy over the good stuff...
  1001. //
  1002. RtlCopyMemory(&pMidiData->StreamHeader,
  1003. &pStreamHeader->Header,
  1004. sizeof(KSSTREAM_HEADER));
  1005. RtlCopyMemory(&pMidiData->MusicFormat,
  1006. pStreamHeader->Header.Data,
  1007. sizeof(KSMUSICFORMAT));
  1008. RtlCopyMemory(&pMidiData->MusicData,
  1009. ((PKSMUSICFORMAT)(pStreamHeader->Header.Data) + 1),
  1010. 3 * sizeof( DWORD )); // cheesy
  1011. //
  1012. // unlock memory before completing the Irp
  1013. //
  1014. wdmaudUnmapBuffer(pMidiInHdr->pMdl);
  1015. AudioFreeMemory_Unknown(&pMidiInHdr);
  1016. //
  1017. // Now complete the Irp for wdmaud.drv to process
  1018. //
  1019. wdmaudUnprepareIrp( UserIrp,
  1020. pIrp->IoStatus.Status,
  1021. sizeof(MIDIDATA),
  1022. pPendingIrpContext );
  1023. } else {
  1024. // !!! Break here to catch underflow !!!
  1025. if (pIrp->IoStatus.Status == STATUS_SUCCESS)
  1026. {
  1027. DPF(DL_TRACE|FA_MIDI, ("!!! Underflowing MIDI Input !!!"));
  1028. //_asm { int 3 };
  1029. }
  1030. }
  1031. }
  1032. //
  1033. // If there are any Mdls, free them here otherwise IoCompleteRequest will do it after the
  1034. // freeing of our data buffer below.
  1035. //
  1036. FreeIrpMdls(pIrp);
  1037. AudioFreeMemory(sizeof(STREAM_HEADER_EX),&pStreamHeader);
  1038. if(pMidiInPin)
  1039. {
  1040. KeAcquireSpinLock(&pMidiInPin->MidiPinSpinLock,&OldIrql);
  1041. pMidiInPin->NumPendingIos--;
  1042. if ( pMidiInPin->StoppingSource || (pIrp->IoStatus.Status == STATUS_CANCELLED) ||
  1043. (pIrp->IoStatus.Status == STATUS_NO_SUCH_DEVICE) || (pIrp->Cancel) )
  1044. {
  1045. bResubmit = FALSE;
  1046. if ( 0 == pMidiInPin->NumPendingIos )
  1047. {
  1048. KeSetEvent ( &pMidiInPin->StopEvent, 0, FALSE ) ;
  1049. }
  1050. }
  1051. //
  1052. // We need to be careful about using pMidiPin after releasing the spinlock.
  1053. // if we are closing down and the NumPendingIos goes to zero the pMidiPin
  1054. // can be freed. In that case we must not touch pMidiPin. bResubmit
  1055. // protects us below.
  1056. //
  1057. KeReleaseSpinLock(&pMidiInPin->MidiPinSpinLock, OldIrql);
  1058. //
  1059. // Resubmit to keep the cycle going...and going. Note that bResubmit
  1060. // must be first in this comparison. If bResubmit is FALSE, then pMidiInPin
  1061. // could be freed.
  1062. //
  1063. if (bResubmit && pMidiInPin->fGraphRunning )
  1064. {
  1065. //
  1066. // This call to ReadMidiPin causes wdmaud.sys to place another
  1067. // buffer down on the device. One call, one buffer.
  1068. //
  1069. ReadMidiPin(pMidiInPin);
  1070. }
  1071. }
  1072. return STATUS_SUCCESS;
  1073. }
  1074. //
  1075. // Called from Irp completion routine, thus this code must be locked.
  1076. //
  1077. NTSTATUS
  1078. ReadMidiPin(
  1079. PMIDI_PIN_INSTANCE pMidiPin
  1080. )
  1081. {
  1082. PKSMUSICFORMAT pMusicFormat;
  1083. PSTREAM_HEADER_EX pStreamHeader = NULL;
  1084. PWORK_QUEUE_ITEM pWorkItem;
  1085. NTSTATUS Status = STATUS_SUCCESS;
  1086. DPF(DL_TRACE|FA_MIDI, ("Entered"));
  1087. if (!pMidiPin->fGraphRunning)
  1088. {
  1089. DPF(DL_WARNING|FA_MIDI,("Bad fGraphRunning") );
  1090. RETURN( STATUS_DEVICE_NOT_READY );
  1091. }
  1092. Status = AudioAllocateMemory_Fixed(sizeof(STREAM_HEADER_EX) + sizeof(WORK_QUEUE_ITEM) +
  1093. MUSICBUFFERSIZE,
  1094. TAG_Audh_STREAMHEADER,
  1095. ZERO_FILL_MEMORY,
  1096. &pStreamHeader);
  1097. if(!NT_SUCCESS(Status))
  1098. {
  1099. RETURN( Status );
  1100. }
  1101. pWorkItem = (PWORK_QUEUE_ITEM)(pStreamHeader + 1);
  1102. pStreamHeader->Header.Size = sizeof( KSSTREAM_HEADER );
  1103. pStreamHeader->Header.PresentationTime.Numerator = 10000;
  1104. pStreamHeader->Header.PresentationTime.Denominator = 1;
  1105. pMusicFormat = (PKSMUSICFORMAT)((BYTE *)pWorkItem + sizeof(WORK_QUEUE_ITEM));
  1106. pStreamHeader->Header.Data = pMusicFormat;
  1107. pStreamHeader->Header.FrameExtent = MUSICBUFFERSIZE;
  1108. pStreamHeader->pMidiPin = pMidiPin;
  1109. ASSERT( pMidiPin->pFileObject );
  1110. //
  1111. // Increase the number of outstanding IRPs as we get ready to add
  1112. // this one to the list.
  1113. //
  1114. LockedMidiIoCount( pMidiPin,INCREASE );
  1115. ObReferenceObject( pMidiPin->pFileObject );
  1116. Status = QueueWorkList( pMidiPin->pMidiDevice->pWdmaContext,
  1117. ReadMidiEventWorkItem,
  1118. pStreamHeader,
  1119. 0 );
  1120. if (!NT_SUCCESS(Status))
  1121. {
  1122. //
  1123. // If the memory allocation fails in QueueWorkItem then it can fail. We
  1124. // will need to free our memory and unlock things.
  1125. //
  1126. LockedMidiIoCount(pMidiPin,DECREASE);
  1127. ObDereferenceObject(pMidiPin->pFileObject);
  1128. AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
  1129. }
  1130. RETURN( Status );
  1131. }
  1132. #pragma PAGEABLE_CODE
  1133. #pragma PAGEABLE_DATA
  1134. //
  1135. // This is a work item that midi schedules. Notice that the caller did a reference
  1136. // on the file object so that it would still be valid when we're here. We should never
  1137. // get called and find that the file object is invalid. Same holds for the StreamHeader
  1138. // and the corresponding pMidiPin.
  1139. //
  1140. VOID
  1141. ReadMidiEventWorkItem(
  1142. PSTREAM_HEADER_EX pStreamHeader,
  1143. PVOID NotUsed
  1144. )
  1145. {
  1146. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1147. PFILE_OBJECT MidiFileObject;
  1148. PAGED_CODE();
  1149. ASSERT( pStreamHeader->pMidiPin->pFileObject );
  1150. DPF(DL_TRACE|FA_MIDI, ("A%d: 0x%08x", pStreamHeader->pMidiPin->NumPendingIos, pStreamHeader));
  1151. //
  1152. // We need to store the MidiFileObject here because the pStreamHeader
  1153. // will/may get freed during the KsStreamIo call. Basically, when
  1154. // you call KsStreamIo the Irp may get completed and the pStreamHeader
  1155. // will get freed. But, it's safe to store the file object because of
  1156. // this reference count.
  1157. //
  1158. MidiFileObject = pStreamHeader->pMidiPin->pFileObject;
  1159. Status = KsStreamIo(
  1160. pStreamHeader->pMidiPin->pFileObject,
  1161. NULL, // Event
  1162. NULL, // PortContext
  1163. ReadMidiCallBack,
  1164. pStreamHeader, // CompletionContext
  1165. KsInvokeOnSuccess | KsInvokeOnCancel | KsInvokeOnError,
  1166. &gIoStatusBlock,
  1167. &pStreamHeader->Header,
  1168. sizeof( KSSTREAM_HEADER ),
  1169. KSSTREAM_READ,
  1170. KernelMode
  1171. );
  1172. //
  1173. // We are done with the file object.
  1174. //
  1175. ObDereferenceObject( MidiFileObject );
  1176. // WorkItem: shouldn't this be if( !NTSUCCESS(Status) )?
  1177. if ( STATUS_UNSUCCESSFUL == Status )
  1178. DPF(DL_WARNING|FA_MIDI, ("KsStreamIo failed2: Status = 0x%08lx", Status));
  1179. //
  1180. // Warning: If, for any reason, the completion routine is not called
  1181. // for this Irp, wdmaud.sys will hang. It's been discovered that
  1182. // KsStreamIo may error out in low memory conditions. There is an
  1183. // outstanding bug to address this.
  1184. //
  1185. return;
  1186. }
  1187. //
  1188. // pNewMidiHdr will always be valid. The caller just allocated it!
  1189. //
  1190. NTSTATUS
  1191. AddBufferToMidiInQueue(
  1192. PMIDI_PIN_INSTANCE pMidiPin,
  1193. PMIDIINHDR pNewMidiInHdr
  1194. )
  1195. {
  1196. NTSTATUS Status = STATUS_SUCCESS;
  1197. PMIDIINHDR pTemp;
  1198. PAGED_CODE();
  1199. if (!pMidiPin || !pMidiPin->fGraphRunning)
  1200. {
  1201. DPF(DL_WARNING|FA_MIDI,("Bad fGraphRunning") );
  1202. RETURN( STATUS_DEVICE_NOT_READY );
  1203. }
  1204. DPF(DL_TRACE|FA_MIDI, ("received sysex buffer"));
  1205. ExInterlockedInsertTailList(&pMidiPin->MidiInQueueListHead,
  1206. &pNewMidiInHdr->Next,
  1207. &pMidiPin->MidiInQueueSpinLock);
  1208. Status = STATUS_PENDING;
  1209. RETURN( Status );
  1210. }
  1211. VOID
  1212. CleanupMidiDevices(
  1213. IN PWDMACONTEXT pWdmaContext
  1214. )
  1215. {
  1216. DWORD DeviceNumber;
  1217. DWORD DeviceType;
  1218. PMIDI_PIN_INSTANCE pMidiPin=NULL;
  1219. PAGED_CODE();
  1220. for (DeviceNumber = 0; DeviceNumber < MAXNUMDEVS; DeviceNumber++)
  1221. {
  1222. for (DeviceType = MidiInDevice; DeviceType < MixerDevice; DeviceType++)
  1223. {
  1224. if (DeviceType == MidiInDevice)
  1225. {
  1226. pMidiPin = pWdmaContext->MidiInDevs[DeviceNumber].pMidiPin;
  1227. }
  1228. else if (DeviceType == MidiOutDevice)
  1229. {
  1230. pMidiPin = pWdmaContext->MidiOutDevs[DeviceNumber].pMidiPin;
  1231. }
  1232. else
  1233. {
  1234. ASSERT(!"CleanupMidiDevices: Out of range!");
  1235. }
  1236. if (pWdmaContext->apCommonDevice[DeviceType][DeviceNumber]->Device != UNUSED_DEVICE)
  1237. {
  1238. if (pMidiPin != NULL)
  1239. {
  1240. NTSTATUS Status;
  1241. KSSTATE State;
  1242. StopMidiPinAndCompleteIo( pMidiPin, FALSE );
  1243. //
  1244. // Probably redundant, but this frees memory associated
  1245. // with the MIDI device.
  1246. //
  1247. if( DeviceType == MidiInDevice )
  1248. {
  1249. CloseMidiDevicePin(&pWdmaContext->MidiInDevs[DeviceNumber]);
  1250. }
  1251. if( DeviceType == MidiOutDevice )
  1252. {
  1253. CloseMidiDevicePin(&pWdmaContext->MidiOutDevs[DeviceNumber]);
  1254. }
  1255. } // end for active pins
  1256. } // end for valid Device
  1257. } // end for DeviceTypes
  1258. } // end for DeviceNumber
  1259. } // CleanupMidiDevices