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.

1743 lines
53 KiB

  1. /*****************************************************************************
  2. * miniport.cpp - UART miniport implementation
  3. *****************************************************************************
  4. * Copyright (c) 1997-2000 Microsoft Corporation. All Rights Reserved.
  5. *
  6. * Feb 98 MartinP -- based on UART, began deltas for DirectMusic.
  7. */
  8. #include "private.h"
  9. #include "ksdebug.h"
  10. #include "stdio.h"
  11. #define STR_MODULENAME "DMusUART:Miniport: "
  12. #pragma code_seg("PAGE")
  13. /*****************************************************************************
  14. * PinDataRangesStreamLegacy
  15. * PinDataRangesStreamDMusic
  16. *****************************************************************************
  17. * Structures indicating range of valid format values for live pins.
  18. */
  19. static
  20. KSDATARANGE_MUSIC PinDataRangesStreamLegacy =
  21. {
  22. {
  23. sizeof(KSDATARANGE_MUSIC),
  24. 0,
  25. 0,
  26. 0,
  27. STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC),
  28. STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI),
  29. STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
  30. },
  31. STATICGUIDOF(KSMUSIC_TECHNOLOGY_PORT),
  32. 0,
  33. 0,
  34. 0xFFFF
  35. };
  36. static
  37. KSDATARANGE_MUSIC PinDataRangesStreamDMusic =
  38. {
  39. {
  40. sizeof(KSDATARANGE_MUSIC),
  41. 0,
  42. 0,
  43. 0,
  44. STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC),
  45. STATICGUIDOF(KSDATAFORMAT_SUBTYPE_DIRECTMUSIC),
  46. STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
  47. },
  48. STATICGUIDOF(KSMUSIC_TECHNOLOGY_PORT),
  49. 0,
  50. 0,
  51. 0xFFFF
  52. };
  53. /*****************************************************************************
  54. * PinDataRangePointersStreamLegacy
  55. * PinDataRangePointersStreamDMusic
  56. * PinDataRangePointersStreamCombined
  57. *****************************************************************************
  58. * List of pointers to structures indicating range of valid format values
  59. * for live pins.
  60. */
  61. static
  62. PKSDATARANGE PinDataRangePointersStreamLegacy[] =
  63. {
  64. PKSDATARANGE(&PinDataRangesStreamLegacy)
  65. };
  66. static
  67. PKSDATARANGE PinDataRangePointersStreamDMusic[] =
  68. {
  69. PKSDATARANGE(&PinDataRangesStreamDMusic)
  70. };
  71. static
  72. PKSDATARANGE PinDataRangePointersStreamCombined[] =
  73. {
  74. PKSDATARANGE(&PinDataRangesStreamLegacy)
  75. ,PKSDATARANGE(&PinDataRangesStreamDMusic)
  76. };
  77. /*****************************************************************************
  78. * PinDataRangesBridge
  79. *****************************************************************************
  80. * Structures indicating range of valid format values for bridge pins.
  81. */
  82. static
  83. KSDATARANGE PinDataRangesBridge[] =
  84. {
  85. {
  86. sizeof(KSDATARANGE),
  87. 0,
  88. 0,
  89. 0,
  90. STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC),
  91. STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI_BUS),
  92. STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
  93. }
  94. };
  95. /*****************************************************************************
  96. * PinDataRangePointersBridge
  97. *****************************************************************************
  98. * List of pointers to structures indicating range of valid format values
  99. * for bridge pins.
  100. */
  101. static
  102. PKSDATARANGE PinDataRangePointersBridge[] =
  103. {
  104. &PinDataRangesBridge[0]
  105. };
  106. /*****************************************************************************
  107. * SynthProperties
  108. *****************************************************************************
  109. * List of properties in the Synth set.
  110. */
  111. static
  112. PCPROPERTY_ITEM
  113. SynthProperties[] =
  114. {
  115. // Global: S/Get synthesizer caps
  116. {
  117. &KSPROPSETID_Synth,
  118. KSPROPERTY_SYNTH_CAPS,
  119. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  120. PropertyHandler_Synth
  121. },
  122. // Global: S/Get port parameters
  123. {
  124. &KSPROPSETID_Synth,
  125. KSPROPERTY_SYNTH_PORTPARAMETERS,
  126. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  127. PropertyHandler_Synth
  128. },
  129. // Per stream: S/Get channel groups
  130. {
  131. &KSPROPSETID_Synth,
  132. KSPROPERTY_SYNTH_CHANNELGROUPS,
  133. KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  134. PropertyHandler_Synth
  135. },
  136. // Per stream: Get current latency time
  137. {
  138. &KSPROPSETID_Synth,
  139. KSPROPERTY_SYNTH_LATENCYCLOCK,
  140. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  141. PropertyHandler_Synth
  142. }
  143. };
  144. DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth, SynthProperties);
  145. DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth2, SynthProperties);
  146. #define kMaxNumCaptureStreams 1
  147. #define kMaxNumLegacyRenderStreams 1
  148. #define kMaxNumDMusicRenderStreams 1
  149. /*****************************************************************************
  150. * MiniportPins
  151. *****************************************************************************
  152. * List of pins.
  153. */
  154. static
  155. PCPIN_DESCRIPTOR MiniportPins[] =
  156. {
  157. {
  158. kMaxNumLegacyRenderStreams,kMaxNumLegacyRenderStreams,0, // InstanceCount
  159. NULL, // AutomationTable
  160. { // KsPinDescriptor
  161. 0, // InterfacesCount
  162. NULL, // Interfaces
  163. 0, // MediumsCount
  164. NULL, // Mediums
  165. SIZEOF_ARRAY(PinDataRangePointersStreamLegacy), // DataRangesCount
  166. PinDataRangePointersStreamLegacy, // DataRanges
  167. KSPIN_DATAFLOW_IN, // DataFlow
  168. KSPIN_COMMUNICATION_SINK, // Communication
  169. (GUID *) &KSCATEGORY_AUDIO, // Category
  170. &KSAUDFNAME_MIDI, // Name
  171. 0 // Reserved
  172. }
  173. },
  174. {
  175. kMaxNumDMusicRenderStreams,kMaxNumDMusicRenderStreams,0, // InstanceCount
  176. NULL, // AutomationTable
  177. { // KsPinDescriptor
  178. 0, // InterfacesCount
  179. NULL, // Interfaces
  180. 0, // MediumsCount
  181. NULL, // Mediums
  182. SIZEOF_ARRAY(PinDataRangePointersStreamDMusic), // DataRangesCount
  183. PinDataRangePointersStreamDMusic, // DataRanges
  184. KSPIN_DATAFLOW_IN, // DataFlow
  185. KSPIN_COMMUNICATION_SINK, // Communication
  186. (GUID *) &KSCATEGORY_AUDIO, // Category
  187. &KSAUDFNAME_DMUSIC_MPU_OUT, // Name
  188. 0 // Reserved
  189. }
  190. },
  191. {
  192. 0,0,0, // InstanceCount
  193. NULL, // AutomationTable
  194. { // KsPinDescriptor
  195. 0, // InterfacesCount
  196. NULL, // Interfaces
  197. 0, // MediumsCount
  198. NULL, // Mediums
  199. SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount
  200. PinDataRangePointersBridge, // DataRanges
  201. KSPIN_DATAFLOW_OUT, // DataFlow
  202. KSPIN_COMMUNICATION_NONE, // Communication
  203. (GUID *) &KSCATEGORY_AUDIO, // Category
  204. NULL, // Name
  205. 0 // Reserved
  206. }
  207. },
  208. {
  209. 0,0,0, // InstanceCount
  210. NULL, // AutomationTable
  211. { // KsPinDescriptor
  212. 0, // InterfacesCount
  213. NULL, // Interfaces
  214. 0, // MediumsCount
  215. NULL, // Mediums
  216. SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount
  217. PinDataRangePointersBridge, // DataRanges
  218. KSPIN_DATAFLOW_IN, // DataFlow
  219. KSPIN_COMMUNICATION_NONE, // Communication
  220. (GUID *) &KSCATEGORY_AUDIO, // Category
  221. NULL, // Name
  222. 0 // Reserved
  223. }
  224. },
  225. {
  226. kMaxNumCaptureStreams,kMaxNumCaptureStreams,0, // InstanceCount
  227. NULL, // AutomationTable
  228. { // KsPinDescriptor
  229. 0, // InterfacesCount
  230. NULL, // Interfaces
  231. 0, // MediumsCount
  232. NULL, // Mediums
  233. SIZEOF_ARRAY(PinDataRangePointersStreamCombined), // DataRangesCount
  234. PinDataRangePointersStreamCombined, // DataRanges
  235. KSPIN_DATAFLOW_OUT, // DataFlow
  236. KSPIN_COMMUNICATION_SINK, // Communication
  237. (GUID *) &KSCATEGORY_AUDIO, // Category
  238. &KSAUDFNAME_DMUSIC_MPU_IN, // Name
  239. 0 // Reserved
  240. }
  241. }
  242. };
  243. /*****************************************************************************
  244. * MiniportNodes
  245. *****************************************************************************
  246. * List of nodes.
  247. */
  248. #define CONST_PCNODE_DESCRIPTOR(n) { 0, NULL, &n, NULL }
  249. #define CONST_PCNODE_DESCRIPTOR_AUTO(n,a) { 0, &a, &n, NULL }
  250. static
  251. PCNODE_DESCRIPTOR MiniportNodes[] =
  252. {
  253. CONST_PCNODE_DESCRIPTOR_AUTO(KSNODETYPE_SYNTHESIZER, AutomationSynth)
  254. , CONST_PCNODE_DESCRIPTOR_AUTO(KSNODETYPE_SYNTHESIZER, AutomationSynth2)
  255. };
  256. /*****************************************************************************
  257. * MiniportConnections
  258. *****************************************************************************
  259. * List of connections.
  260. */
  261. enum {
  262. eSynthNode = 0
  263. , eInputNode
  264. };
  265. enum {
  266. eFilterInputPinLeg = 0,
  267. eFilterInputPinDM,
  268. eBridgeOutputPin,
  269. eBridgeInputPin,
  270. eFilterOutputPin
  271. };
  272. static
  273. PCCONNECTION_DESCRIPTOR MiniportConnections[] =
  274. { // From To
  275. // Node pin Node pin
  276. { PCFILTER_NODE, eFilterInputPinLeg, PCFILTER_NODE, eBridgeOutputPin } // Legacy Stream in to synth.
  277. , { PCFILTER_NODE, eFilterInputPinDM, eSynthNode, KSNODEPIN_STANDARD_IN } // DM Stream in to synth.
  278. , { eSynthNode, KSNODEPIN_STANDARD_OUT, PCFILTER_NODE, eBridgeOutputPin } // Synth to bridge out.
  279. , { PCFILTER_NODE, eBridgeInputPin, eInputNode, KSNODEPIN_STANDARD_IN } // Bridge in to input.
  280. , { eInputNode, KSNODEPIN_STANDARD_OUT, PCFILTER_NODE, eFilterOutputPin } // Input to DM/Legacy Stream out.
  281. };
  282. /*****************************************************************************
  283. * MiniportCategories
  284. *****************************************************************************
  285. * List of categories.
  286. */
  287. static
  288. GUID MiniportCategories[] =
  289. {
  290. STATICGUIDOF(KSCATEGORY_AUDIO),
  291. STATICGUIDOF(KSCATEGORY_RENDER),
  292. STATICGUIDOF(KSCATEGORY_CAPTURE)
  293. };
  294. /*****************************************************************************
  295. * MiniportFilterDescriptor
  296. *****************************************************************************
  297. * Complete miniport filter description.
  298. */
  299. static
  300. PCFILTER_DESCRIPTOR MiniportFilterDescriptor =
  301. {
  302. 0, // Version
  303. NULL, // AutomationTable
  304. sizeof(PCPIN_DESCRIPTOR), // PinSize
  305. SIZEOF_ARRAY(MiniportPins), // PinCount
  306. MiniportPins, // Pins
  307. sizeof(PCNODE_DESCRIPTOR), // NodeSize
  308. SIZEOF_ARRAY(MiniportNodes), // NodeCount
  309. MiniportNodes, // Nodes
  310. SIZEOF_ARRAY(MiniportConnections), // ConnectionCount
  311. MiniportConnections, // Connections
  312. SIZEOF_ARRAY(MiniportCategories), // CategoryCount
  313. MiniportCategories // Categories
  314. };
  315. #pragma code_seg("PAGE")
  316. /*****************************************************************************
  317. * CMiniportDMusUART::GetDescription()
  318. *****************************************************************************
  319. * Gets the topology.
  320. */
  321. STDMETHODIMP_(NTSTATUS)
  322. CMiniportDMusUART::
  323. GetDescription
  324. (
  325. OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor
  326. )
  327. {
  328. PAGED_CODE();
  329. ASSERT(OutFilterDescriptor);
  330. _DbgPrintF(DEBUGLVL_BLAB,("GetDescription"));
  331. *OutFilterDescriptor = &MiniportFilterDescriptor;
  332. return STATUS_SUCCESS;
  333. }
  334. #pragma code_seg("PAGE")
  335. /*****************************************************************************
  336. * CreateMiniportDMusUART()
  337. *****************************************************************************
  338. * Creates a MPU-401 miniport driver for the adapter. This uses a
  339. * macro from STDUNK.H to do all the work.
  340. */
  341. NTSTATUS
  342. CreateMiniportDMusUART
  343. (
  344. OUT PUNKNOWN * Unknown,
  345. IN REFCLSID,
  346. IN PUNKNOWN UnknownOuter OPTIONAL,
  347. IN POOL_TYPE PoolType
  348. )
  349. {
  350. PAGED_CODE();
  351. _DbgPrintF(DEBUGLVL_BLAB, ("CreateMiniportDMusUART"));
  352. ASSERT(Unknown);
  353. STD_CREATE_BODY_( CMiniportDMusUART,
  354. Unknown,
  355. UnknownOuter,
  356. PoolType,
  357. PMINIPORTDMUS);
  358. }
  359. #pragma code_seg("PAGE")
  360. /*****************************************************************************
  361. * CMiniportDMusUART::ProcessResources()
  362. *****************************************************************************
  363. * Processes the resource list, setting up helper objects accordingly.
  364. */
  365. NTSTATUS
  366. CMiniportDMusUART::
  367. ProcessResources
  368. (
  369. IN PRESOURCELIST ResourceList
  370. )
  371. {
  372. PAGED_CODE();
  373. _DbgPrintF(DEBUGLVL_BLAB,("ProcessResources"));
  374. ASSERT(ResourceList);
  375. if (!ResourceList)
  376. {
  377. return STATUS_DEVICE_CONFIGURATION_ERROR;
  378. }
  379. //
  380. // Get counts for the types of resources.
  381. //
  382. ULONG countIO = ResourceList->NumberOfPorts();
  383. ULONG countIRQ = ResourceList->NumberOfInterrupts();
  384. ULONG countDMA = ResourceList->NumberOfDmas();
  385. ULONG lengthIO = ResourceList->FindTranslatedPort(0)->u.Port.Length;
  386. #if (DBG)
  387. _DbgPrintF(DEBUGLVL_VERBOSE,("Starting MPU401 Port 0x%X",
  388. ResourceList->FindTranslatedPort(0)->u.Port.Start.LowPart) );
  389. #endif
  390. NTSTATUS ntStatus = STATUS_SUCCESS;
  391. //
  392. // Make sure we have the expected number of resources.
  393. //
  394. if ( (countIO != 1)
  395. || (countIRQ > 1)
  396. || (countDMA != 0)
  397. || (lengthIO == 0)
  398. )
  399. {
  400. _DbgPrintF(DEBUGLVL_TERSE,("Unknown ResourceList configuraton"));
  401. ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
  402. }
  403. if (NT_SUCCESS(ntStatus))
  404. {
  405. //
  406. // Get the port address.
  407. //
  408. m_pPortBase =
  409. PUCHAR(ResourceList->FindTranslatedPort(0)->u.Port.Start.QuadPart);
  410. ntStatus = InitializeHardware(m_pInterruptSync,m_pPortBase);
  411. }
  412. return ntStatus;
  413. }
  414. #pragma code_seg("PAGE")
  415. /*****************************************************************************
  416. * CMiniportDMusUART::NonDelegatingQueryInterface()
  417. *****************************************************************************
  418. * Obtains an interface. This function works just like a COM QueryInterface
  419. * call and is used if the object is not being aggregated.
  420. */
  421. STDMETHODIMP_(NTSTATUS)
  422. CMiniportDMusUART::
  423. NonDelegatingQueryInterface
  424. (
  425. REFIID Interface,
  426. PVOID * Object
  427. )
  428. {
  429. PAGED_CODE();
  430. _DbgPrintF(DEBUGLVL_BLAB, ("Miniport::NonDelegatingQueryInterface"));
  431. ASSERT(Object);
  432. if (IsEqualGUIDAligned(Interface,IID_IUnknown))
  433. {
  434. *Object = PVOID(PUNKNOWN(PMINIPORTDMUS(this)));
  435. }
  436. else
  437. if (IsEqualGUIDAligned(Interface,IID_IMiniport))
  438. {
  439. *Object = PVOID(PMINIPORT(this));
  440. }
  441. else
  442. if (IsEqualGUIDAligned(Interface,IID_IMiniportDMus))
  443. {
  444. *Object = PVOID(PMINIPORTDMUS(this));
  445. }
  446. else
  447. if (IsEqualGUIDAligned(Interface,IID_IMusicTechnology))
  448. {
  449. *Object = PVOID(PMUSICTECHNOLOGY(this));
  450. }
  451. else
  452. if (IsEqualGUIDAligned(Interface,IID_IPowerNotify))
  453. {
  454. *Object = PVOID(PPOWERNOTIFY(this));
  455. }
  456. else
  457. {
  458. *Object = NULL;
  459. }
  460. if (*Object)
  461. {
  462. //
  463. // We reference the interface for the caller.
  464. //
  465. PUNKNOWN(*Object)->AddRef();
  466. return STATUS_SUCCESS;
  467. }
  468. return STATUS_INVALID_PARAMETER;
  469. }
  470. #pragma code_seg("PAGE")
  471. /*****************************************************************************
  472. * CMiniportDMusUART::~CMiniportDMusUART()
  473. *****************************************************************************
  474. * Destructor.
  475. */
  476. CMiniportDMusUART::~CMiniportDMusUART(void)
  477. {
  478. PAGED_CODE();
  479. _DbgPrintF(DEBUGLVL_BLAB,("~CMiniportDMusUART"));
  480. ASSERT(0 == m_NumCaptureStreams);
  481. ASSERT(0 == m_NumRenderStreams);
  482. // reset the HW so we don't get anymore interrupts
  483. if (m_UseIRQ && m_pInterruptSync)
  484. {
  485. (void) m_pInterruptSync->CallSynchronizedRoutine(InitMPU,PVOID(m_pPortBase));
  486. }
  487. else
  488. {
  489. (void) InitMPU(NULL,PVOID(m_pPortBase));
  490. }
  491. if (m_pInterruptSync)
  492. {
  493. m_pInterruptSync->Release();
  494. m_pInterruptSync = NULL;
  495. }
  496. if (m_pServiceGroup)
  497. {
  498. m_pServiceGroup->Release();
  499. m_pServiceGroup = NULL;
  500. }
  501. if (m_pPort)
  502. {
  503. m_pPort->Release();
  504. m_pPort = NULL;
  505. }
  506. }
  507. #pragma code_seg("PAGE")
  508. /*****************************************************************************
  509. * CMiniportDMusUART::Init()
  510. *****************************************************************************
  511. * Initializes a the miniport.
  512. */
  513. STDMETHODIMP_(NTSTATUS)
  514. CMiniportDMusUART::
  515. Init
  516. (
  517. IN PUNKNOWN UnknownInterruptSync OPTIONAL,
  518. IN PRESOURCELIST ResourceList,
  519. IN PPORTDMUS Port_,
  520. OUT PSERVICEGROUP * ServiceGroup
  521. )
  522. {
  523. PAGED_CODE();
  524. ASSERT(ResourceList);
  525. if (!ResourceList)
  526. {
  527. return STATUS_DEVICE_CONFIGURATION_ERROR;
  528. }
  529. ASSERT(Port_);
  530. ASSERT(ServiceGroup);
  531. _DbgPrintF(DEBUGLVL_BLAB,("Init"));
  532. *ServiceGroup = NULL;
  533. m_pPortBase = 0;
  534. m_fMPUInitialized = FALSE;
  535. // This will remain unspecified if the miniport does not get any power
  536. // messages.
  537. //
  538. m_PowerState.DeviceState = PowerDeviceUnspecified;
  539. //
  540. // AddRef() is required because we are keeping this pointer.
  541. //
  542. m_pPort = Port_;
  543. m_pPort->AddRef();
  544. // Set dataformat.
  545. //
  546. if (IsEqualGUIDAligned(m_MusicFormatTechnology, GUID_NULL))
  547. {
  548. RtlCopyMemory( &m_MusicFormatTechnology,
  549. &KSMUSIC_TECHNOLOGY_PORT,
  550. sizeof(GUID));
  551. }
  552. RtlCopyMemory( &PinDataRangesStreamLegacy.Technology,
  553. &m_MusicFormatTechnology,
  554. sizeof(GUID));
  555. RtlCopyMemory( &PinDataRangesStreamDMusic.Technology,
  556. &m_MusicFormatTechnology,
  557. sizeof(GUID));
  558. for (ULONG bufferCount = 0;bufferCount < kMPUInputBufferSize;bufferCount++)
  559. {
  560. m_MPUInputBuffer[bufferCount] = 0;
  561. }
  562. m_MPUInputBufferHead = 0;
  563. m_MPUInputBufferTail = 0;
  564. m_InputTimeStamp = 0;
  565. m_KSStateInput = KSSTATE_STOP;
  566. NTSTATUS ntStatus = STATUS_SUCCESS;
  567. m_NumRenderStreams = 0;
  568. m_NumCaptureStreams = 0;
  569. m_UseIRQ = TRUE;
  570. if (ResourceList->NumberOfInterrupts() == 0)
  571. {
  572. m_UseIRQ = FALSE;
  573. }
  574. ntStatus = PcNewServiceGroup(&m_pServiceGroup,NULL);
  575. if (NT_SUCCESS(ntStatus) && !m_pServiceGroup) // keep any error
  576. {
  577. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  578. }
  579. if (NT_SUCCESS(ntStatus))
  580. {
  581. *ServiceGroup = m_pServiceGroup;
  582. m_pServiceGroup->AddRef();
  583. //
  584. // Register the service group with the port early so the port is
  585. // prepared to handle interrupts.
  586. //
  587. m_pPort->RegisterServiceGroup(m_pServiceGroup);
  588. }
  589. if (NT_SUCCESS(ntStatus) && m_UseIRQ)
  590. {
  591. //
  592. // Due to a bug in the InterruptSync design, we shouldn't share
  593. // the interrupt sync object. Whoever goes away first
  594. // will disconnect it, and the other points off into nowhere.
  595. //
  596. // Instead we generate our own interrupt sync object.
  597. //
  598. UnknownInterruptSync = NULL;
  599. if (UnknownInterruptSync)
  600. {
  601. ntStatus =
  602. UnknownInterruptSync->QueryInterface
  603. (
  604. IID_IInterruptSync,
  605. (PVOID *) &m_pInterruptSync
  606. );
  607. if (!m_pInterruptSync && NT_SUCCESS(ntStatus)) // keep any error
  608. {
  609. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  610. }
  611. if (NT_SUCCESS(ntStatus))
  612. { // run this ISR first
  613. ntStatus = m_pInterruptSync->
  614. RegisterServiceRoutine(DMusMPUInterruptServiceRoutine,PVOID(this),TRUE);
  615. }
  616. }
  617. else
  618. { // create our own interruptsync mechanism.
  619. ntStatus =
  620. PcNewInterruptSync
  621. (
  622. &m_pInterruptSync,
  623. NULL,
  624. ResourceList,
  625. 0, // Resource Index
  626. InterruptSyncModeNormal // Run ISRs once until we get SUCCESS
  627. );
  628. if (!m_pInterruptSync && NT_SUCCESS(ntStatus)) // keep any error
  629. {
  630. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  631. }
  632. if (NT_SUCCESS(ntStatus))
  633. {
  634. ntStatus = m_pInterruptSync->RegisterServiceRoutine(
  635. DMusMPUInterruptServiceRoutine,
  636. PVOID(this),
  637. TRUE); // run this ISR first
  638. }
  639. if (NT_SUCCESS(ntStatus))
  640. {
  641. ntStatus = m_pInterruptSync->Connect();
  642. }
  643. }
  644. }
  645. if (NT_SUCCESS(ntStatus))
  646. {
  647. ntStatus = ProcessResources(ResourceList);
  648. }
  649. if (!NT_SUCCESS(ntStatus))
  650. {
  651. //
  652. // clean up our mess
  653. //
  654. // clean up the interrupt sync
  655. if( m_pInterruptSync )
  656. {
  657. m_pInterruptSync->Release();
  658. m_pInterruptSync = NULL;
  659. }
  660. // clean up the service group
  661. if( m_pServiceGroup )
  662. {
  663. m_pServiceGroup->Release();
  664. m_pServiceGroup = NULL;
  665. }
  666. // clean up the out param service group.
  667. if (*ServiceGroup)
  668. {
  669. (*ServiceGroup)->Release();
  670. (*ServiceGroup) = NULL;
  671. }
  672. // release the port
  673. m_pPort->Release();
  674. m_pPort = NULL;
  675. }
  676. return ntStatus;
  677. }
  678. #pragma code_seg("PAGE")
  679. /*****************************************************************************
  680. * CMiniportDMusUART::NewStream()
  681. *****************************************************************************
  682. * Gets the topology.
  683. */
  684. STDMETHODIMP_(NTSTATUS)
  685. CMiniportDMusUART::
  686. NewStream
  687. (
  688. OUT PMXF * MXF,
  689. IN PUNKNOWN OuterUnknown OPTIONAL,
  690. IN POOL_TYPE PoolType,
  691. IN ULONG PinID,
  692. IN DMUS_STREAM_TYPE StreamType,
  693. IN PKSDATAFORMAT DataFormat,
  694. OUT PSERVICEGROUP * ServiceGroup,
  695. IN PAllocatorMXF AllocatorMXF,
  696. IN PMASTERCLOCK MasterClock,
  697. OUT PULONGLONG SchedulePreFetch
  698. )
  699. {
  700. PAGED_CODE();
  701. _DbgPrintF(DEBUGLVL_BLAB, ("NewStream"));
  702. NTSTATUS ntStatus = STATUS_SUCCESS;
  703. // In 100 ns, we want stuff as soon as it comes in
  704. //
  705. *SchedulePreFetch = 0;
  706. // if we don't have any streams already open, get the hardware ready.
  707. if ((!m_NumCaptureStreams) && (!m_NumRenderStreams))
  708. {
  709. ntStatus = ResetHardware(m_pPortBase);
  710. if (!NT_SUCCESS(ntStatus))
  711. {
  712. _DbgPrintF(DEBUGLVL_TERSE, ("CMiniportDMusUART::NewStream ResetHardware failed"));
  713. return ntStatus;
  714. }
  715. }
  716. if ( ((m_NumCaptureStreams < kMaxNumCaptureStreams)
  717. && (StreamType == DMUS_STREAM_MIDI_CAPTURE))
  718. || ((m_NumRenderStreams < kMaxNumLegacyRenderStreams + kMaxNumDMusicRenderStreams)
  719. && (StreamType == DMUS_STREAM_MIDI_RENDER))
  720. )
  721. {
  722. CMiniportDMusUARTStream *pStream =
  723. new(PoolType) CMiniportDMusUARTStream(OuterUnknown);
  724. if (pStream)
  725. {
  726. pStream->AddRef();
  727. ntStatus =
  728. pStream->Init(this,m_pPortBase,(StreamType == DMUS_STREAM_MIDI_CAPTURE),AllocatorMXF,MasterClock);
  729. if (NT_SUCCESS(ntStatus))
  730. {
  731. *MXF = PMXF(pStream);
  732. (*MXF)->AddRef();
  733. if (StreamType == DMUS_STREAM_MIDI_CAPTURE)
  734. {
  735. m_NumCaptureStreams++;
  736. *ServiceGroup = m_pServiceGroup;
  737. (*ServiceGroup)->AddRef();
  738. }
  739. else
  740. {
  741. m_NumRenderStreams++;
  742. *ServiceGroup = NULL;
  743. }
  744. }
  745. pStream->Release();
  746. }
  747. else
  748. {
  749. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  750. }
  751. }
  752. else
  753. {
  754. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  755. if (StreamType == DMUS_STREAM_MIDI_CAPTURE)
  756. {
  757. _DbgPrintF(DEBUGLVL_TERSE,("NewStream failed, too many capture streams"));
  758. }
  759. else if (StreamType == DMUS_STREAM_MIDI_RENDER)
  760. {
  761. _DbgPrintF(DEBUGLVL_TERSE,("NewStream failed, too many render streams"));
  762. }
  763. else
  764. {
  765. _DbgPrintF(DEBUGLVL_TERSE,("NewStream invalid stream type"));
  766. }
  767. }
  768. return ntStatus;
  769. }
  770. #pragma code_seg("PAGE")
  771. /*****************************************************************************
  772. * CMiniportDMusUART::SetTechnology()
  773. *****************************************************************************
  774. * Sets pindatarange technology.
  775. */
  776. STDMETHODIMP_(NTSTATUS)
  777. CMiniportDMusUART::
  778. SetTechnology
  779. (
  780. IN const GUID * Technology
  781. )
  782. {
  783. PAGED_CODE();
  784. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  785. // Fail if miniport has already been initialized.
  786. //
  787. if (NULL == m_pPort)
  788. {
  789. RtlCopyMemory(&m_MusicFormatTechnology, Technology, sizeof(GUID));
  790. ntStatus = STATUS_SUCCESS;
  791. }
  792. return ntStatus;
  793. } // SetTechnology
  794. /*****************************************************************************
  795. * CMiniportDMusUART::PowerChangeNotify()
  796. *****************************************************************************
  797. * Handle power state change for the miniport.
  798. */
  799. #pragma code_seg("PAGE")
  800. STDMETHODIMP_(void)
  801. CMiniportDMusUART::
  802. PowerChangeNotify
  803. (
  804. IN POWER_STATE PowerState
  805. )
  806. {
  807. PAGED_CODE();
  808. _DbgPrintF(DEBUGLVL_VERBOSE, ("CMiniportDMusUART::PoweChangeNotify D%d", PowerState.DeviceState));
  809. switch (PowerState.DeviceState)
  810. {
  811. case PowerDeviceD0:
  812. if (m_PowerState.DeviceState != PowerDeviceD0)
  813. {
  814. if (!NT_SUCCESS(InitializeHardware(m_pInterruptSync,m_pPortBase)))
  815. {
  816. _DbgPrintF(DEBUGLVL_TERSE, ("InitializeHardware failed when resuming"));
  817. }
  818. }
  819. break;
  820. case PowerDeviceD1:
  821. case PowerDeviceD2:
  822. case PowerDeviceD3:
  823. default:
  824. break;
  825. }
  826. m_PowerState.DeviceState = PowerState.DeviceState;
  827. } // PowerChangeNotify
  828. #pragma code_seg("PAGE")
  829. /*****************************************************************************
  830. * CMiniportDMusUARTStream::NonDelegatingQueryInterface()
  831. *****************************************************************************
  832. * Obtains an interface. This function works just like a COM QueryInterface
  833. * call and is used if the object is not being aggregated.
  834. */
  835. STDMETHODIMP_(NTSTATUS)
  836. CMiniportDMusUARTStream::
  837. NonDelegatingQueryInterface
  838. (
  839. REFIID Interface,
  840. PVOID * Object
  841. )
  842. {
  843. PAGED_CODE();
  844. _DbgPrintF(DEBUGLVL_BLAB,("Stream::NonDelegatingQueryInterface"));
  845. ASSERT(Object);
  846. if (IsEqualGUIDAligned(Interface,IID_IUnknown))
  847. {
  848. *Object = PVOID(PUNKNOWN(this));
  849. }
  850. else
  851. if (IsEqualGUIDAligned(Interface,IID_IMXF))
  852. {
  853. *Object = PVOID(PMXF(this));
  854. }
  855. else
  856. {
  857. *Object = NULL;
  858. }
  859. if (*Object)
  860. {
  861. //
  862. // We reference the interface for the caller.
  863. //
  864. PUNKNOWN(*Object)->AddRef();
  865. return STATUS_SUCCESS;
  866. }
  867. return STATUS_INVALID_PARAMETER;
  868. }
  869. #pragma code_seg("PAGE")
  870. /*****************************************************************************
  871. * CMiniportDMusUARTStream::~CMiniportDMusUARTStream()
  872. *****************************************************************************
  873. * Destructs a stream.
  874. */
  875. CMiniportDMusUARTStream::~CMiniportDMusUARTStream(void)
  876. {
  877. PAGED_CODE();
  878. _DbgPrintF(DEBUGLVL_BLAB,("~CMiniportDMusUARTStream"));
  879. KeCancelTimer(&m_TimerEvent);
  880. if (m_DMKEvtQueue)
  881. {
  882. if (m_AllocatorMXF)
  883. {
  884. m_AllocatorMXF->PutMessage(m_DMKEvtQueue);
  885. }
  886. else
  887. {
  888. _DbgPrintF(DEBUGLVL_ERROR,("~CMiniportDMusUARTStream, no allocator, can't flush DMKEvts"));
  889. }
  890. m_DMKEvtQueue = NULL;
  891. }
  892. if (m_AllocatorMXF)
  893. {
  894. m_AllocatorMXF->Release();
  895. m_AllocatorMXF = NULL;
  896. }
  897. if (m_pMiniport)
  898. {
  899. if (m_fCapture)
  900. {
  901. m_pMiniport->m_NumCaptureStreams--;
  902. }
  903. else
  904. {
  905. m_pMiniport->m_NumRenderStreams--;
  906. }
  907. m_pMiniport->Release();
  908. }
  909. }
  910. #pragma code_seg("PAGE")
  911. /*****************************************************************************
  912. * CMiniportDMusUARTStream::Init()
  913. *****************************************************************************
  914. * Initializes a stream.
  915. */
  916. STDMETHODIMP_(NTSTATUS)
  917. CMiniportDMusUARTStream::
  918. Init
  919. (
  920. IN CMiniportDMusUART * pMiniport,
  921. IN PUCHAR pPortBase,
  922. IN BOOLEAN fCapture,
  923. IN PAllocatorMXF allocatorMXF,
  924. IN PMASTERCLOCK masterClock
  925. )
  926. {
  927. PAGED_CODE();
  928. ASSERT(pMiniport);
  929. ASSERT(pPortBase);
  930. _DbgPrintF(DEBUGLVL_BLAB,("Init"));
  931. m_NumFailedMPUTries = 0;
  932. m_TimerQueued = FALSE;
  933. KeInitializeSpinLock(&m_DpcSpinLock);
  934. m_pMiniport = pMiniport;
  935. m_pMiniport->AddRef();
  936. pMiniport->m_MasterClock = masterClock;
  937. m_pPortBase = pPortBase;
  938. m_fCapture = fCapture;
  939. m_SnapshotTimeStamp = 0;
  940. m_DMKEvtQueue = NULL;
  941. m_DMKEvtOffset = 0;
  942. m_NumberOfRetries = 0;
  943. if (allocatorMXF)
  944. {
  945. allocatorMXF->AddRef();
  946. m_AllocatorMXF = allocatorMXF;
  947. m_sinkMXF = m_AllocatorMXF;
  948. }
  949. else
  950. {
  951. return STATUS_INVALID_PARAMETER;
  952. }
  953. KeInitializeDpc
  954. (
  955. &m_Dpc,
  956. &::DMusUARTTimerDPC,
  957. PVOID(this)
  958. );
  959. KeInitializeTimer(&m_TimerEvent);
  960. return STATUS_SUCCESS;
  961. }
  962. #pragma code_seg("PAGE")
  963. /*****************************************************************************
  964. * CMiniportDMusUARTStream::SetState()
  965. *****************************************************************************
  966. * Sets the state of the channel.
  967. */
  968. STDMETHODIMP_(NTSTATUS)
  969. CMiniportDMusUARTStream::
  970. SetState
  971. (
  972. IN KSSTATE NewState
  973. )
  974. {
  975. PAGED_CODE();
  976. _DbgPrintF(DEBUGLVL_VERBOSE,("SetState %d",NewState));
  977. if (NewState == KSSTATE_RUN)
  978. {
  979. if (m_pMiniport->m_fMPUInitialized)
  980. {
  981. LARGE_INTEGER timeDue100ns;
  982. timeDue100ns.QuadPart = 0;
  983. KeSetTimer(&m_TimerEvent,timeDue100ns,&m_Dpc);
  984. }
  985. else
  986. {
  987. _DbgPrintF(DEBUGLVL_TERSE, ("CMiniportDMusUARTStream::SetState KSSTATE_RUN failed due to uninitialized MPU"));
  988. return STATUS_INVALID_DEVICE_STATE;
  989. }
  990. }
  991. if (m_fCapture)
  992. {
  993. m_pMiniport->m_KSStateInput = NewState;
  994. if (NewState == KSSTATE_STOP) // STOPping
  995. {
  996. m_pMiniport->m_MPUInputBufferHead = 0; // Previously read bytes are discarded.
  997. m_pMiniport->m_MPUInputBufferTail = 0; // The entire FIFO is available.
  998. }
  999. }
  1000. return STATUS_SUCCESS;
  1001. }
  1002. #pragma code_seg()
  1003. /*****************************************************************************
  1004. * CMiniportDMusUART::Service()
  1005. *****************************************************************************
  1006. * DPC-mode service call from the port.
  1007. */
  1008. STDMETHODIMP_(void)
  1009. CMiniportDMusUART::
  1010. Service
  1011. ( void
  1012. )
  1013. {
  1014. _DbgPrintF(DEBUGLVL_BLAB, ("Service"));
  1015. if (!m_NumCaptureStreams)
  1016. {
  1017. // we should never get here....
  1018. // if we do, we must have read some trash,
  1019. // so just reset the input FIFO
  1020. m_MPUInputBufferTail = m_MPUInputBufferHead = 0;
  1021. }
  1022. }
  1023. #pragma code_seg("PAGE")
  1024. /*****************************************************************************
  1025. * CMiniportDMusUARTStream::ConnectOutput()
  1026. *****************************************************************************
  1027. * Writes outgoing MIDI data.
  1028. */
  1029. NTSTATUS
  1030. CMiniportDMusUARTStream::
  1031. ConnectOutput(PMXF sinkMXF)
  1032. {
  1033. PAGED_CODE();
  1034. if (m_fCapture)
  1035. {
  1036. if ((sinkMXF) && (m_sinkMXF == m_AllocatorMXF))
  1037. {
  1038. _DbgPrintF(DEBUGLVL_BLAB, ("ConnectOutput"));
  1039. m_sinkMXF = sinkMXF;
  1040. return STATUS_SUCCESS;
  1041. }
  1042. else
  1043. {
  1044. _DbgPrintF(DEBUGLVL_TERSE, ("ConnectOutput failed"));
  1045. }
  1046. }
  1047. else
  1048. {
  1049. _DbgPrintF(DEBUGLVL_TERSE, ("ConnectOutput called on renderer; failed"));
  1050. }
  1051. return STATUS_UNSUCCESSFUL;
  1052. }
  1053. #pragma code_seg("PAGE")
  1054. /*****************************************************************************
  1055. * CMiniportDMusUARTStream::DisconnectOutput()
  1056. *****************************************************************************
  1057. * Writes outgoing MIDI data.
  1058. */
  1059. NTSTATUS
  1060. CMiniportDMusUARTStream::
  1061. DisconnectOutput(PMXF sinkMXF)
  1062. {
  1063. PAGED_CODE();
  1064. if (m_fCapture)
  1065. {
  1066. if ((m_sinkMXF == sinkMXF) || (!sinkMXF))
  1067. {
  1068. _DbgPrintF(DEBUGLVL_BLAB, ("DisconnectOutput"));
  1069. m_sinkMXF = m_AllocatorMXF;
  1070. return STATUS_SUCCESS;
  1071. }
  1072. else
  1073. {
  1074. _DbgPrintF(DEBUGLVL_TERSE, ("DisconnectOutput failed"));
  1075. }
  1076. }
  1077. else
  1078. {
  1079. _DbgPrintF(DEBUGLVL_TERSE, ("DisconnectOutput called on renderer; failed"));
  1080. }
  1081. return STATUS_UNSUCCESSFUL;
  1082. }
  1083. #pragma code_seg()
  1084. /*****************************************************************************
  1085. * CMiniportDMusUARTStream::PutMessageLocked()
  1086. *****************************************************************************
  1087. * Now that the spinlock is held, add this message to the queue.
  1088. *
  1089. * Writes an outgoing MIDI message.
  1090. * We don't sort a new message into the queue -- we append it.
  1091. * This is fine, since the sequencer feeds us sequenced data.
  1092. * Timestamps will ascend by design.
  1093. */
  1094. NTSTATUS CMiniportDMusUARTStream::PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt)
  1095. {
  1096. NTSTATUS ntStatus = STATUS_SUCCESS;
  1097. PDMUS_KERNEL_EVENT aDMKEvt;
  1098. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  1099. if (!m_fCapture)
  1100. {
  1101. _DbgPrintF(DEBUGLVL_BLAB, ("PutMessage to render stream"));
  1102. if (pDMKEvt)
  1103. {
  1104. // m_DpcSpinLock already held
  1105. if (m_DMKEvtQueue)
  1106. {
  1107. aDMKEvt = m_DMKEvtQueue; // put pDMKEvt in event queue
  1108. while (aDMKEvt->pNextEvt)
  1109. {
  1110. aDMKEvt = aDMKEvt->pNextEvt;
  1111. }
  1112. aDMKEvt->pNextEvt = pDMKEvt; // here is end of queue
  1113. }
  1114. else // currently nothing in queue
  1115. {
  1116. m_DMKEvtQueue = pDMKEvt;
  1117. if (m_DMKEvtOffset)
  1118. {
  1119. _DbgPrintF(DEBUGLVL_ERROR, ("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d",m_DMKEvtOffset));
  1120. m_DMKEvtOffset = 0;
  1121. }
  1122. }
  1123. // m_DpcSpinLock already held
  1124. }
  1125. if (!m_TimerQueued)
  1126. {
  1127. (void) ConsumeEvents();
  1128. }
  1129. }
  1130. else // capture
  1131. {
  1132. _DbgPrintF(DEBUGLVL_BLAB, ("PutMessage to capture stream"));
  1133. ASSERT(NULL == pDMKEvt);
  1134. SourceEvtsToPort();
  1135. }
  1136. return ntStatus;
  1137. }
  1138. #pragma code_seg()
  1139. /*****************************************************************************
  1140. * CMiniportDMusUARTStream::PutMessage()
  1141. *****************************************************************************
  1142. * Writes an outgoing MIDI message.
  1143. * We don't sort a new message into the queue -- we append it.
  1144. * This is fine, since the sequencer feeds us sequenced data.
  1145. * Timestamps will ascend by design.
  1146. */
  1147. NTSTATUS CMiniportDMusUARTStream::PutMessage(PDMUS_KERNEL_EVENT pDMKEvt)
  1148. {
  1149. NTSTATUS ntStatus = STATUS_SUCCESS;
  1150. PDMUS_KERNEL_EVENT aDMKEvt;
  1151. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  1152. if (!m_fCapture)
  1153. {
  1154. _DbgPrintF(DEBUGLVL_BLAB, ("PutMessage to render stream"));
  1155. if (pDMKEvt)
  1156. {
  1157. KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock);
  1158. if (m_DMKEvtQueue)
  1159. {
  1160. aDMKEvt = m_DMKEvtQueue; // put pDMKEvt in event queue
  1161. while (aDMKEvt->pNextEvt)
  1162. {
  1163. aDMKEvt = aDMKEvt->pNextEvt;
  1164. }
  1165. aDMKEvt->pNextEvt = pDMKEvt; // here is end of queue
  1166. }
  1167. else // currently nothing in queue
  1168. {
  1169. m_DMKEvtQueue = pDMKEvt;
  1170. if (m_DMKEvtOffset)
  1171. {
  1172. _DbgPrintF(DEBUGLVL_ERROR, ("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d",m_DMKEvtOffset));
  1173. m_DMKEvtOffset = 0;
  1174. }
  1175. }
  1176. KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock);
  1177. }
  1178. if (!m_TimerQueued)
  1179. {
  1180. (void) ConsumeEvents();
  1181. }
  1182. }
  1183. else // capture
  1184. {
  1185. _DbgPrintF(DEBUGLVL_BLAB, ("PutMessage to capture stream"));
  1186. ASSERT(NULL == pDMKEvt);
  1187. SourceEvtsToPort();
  1188. }
  1189. return ntStatus;
  1190. }
  1191. #pragma code_seg()
  1192. /*****************************************************************************
  1193. * CMiniportDMusUARTStream::ConsumeEvents()
  1194. *****************************************************************************
  1195. * Attempts to empty the render message queue.
  1196. * Called either from DPC timer or upon IRP submittal.
  1197. // TODO: support packages right
  1198. // process the package (actually, should do this above.
  1199. // treat the package as a list fragment that shouldn't be sorted.
  1200. // better yet, go through each event in the package, and when
  1201. // an event is exhausted, delete it and decrement m_offset.
  1202. */
  1203. NTSTATUS CMiniportDMusUARTStream::ConsumeEvents(void)
  1204. {
  1205. PDMUS_KERNEL_EVENT aDMKEvt;
  1206. NTSTATUS ntStatus = STATUS_SUCCESS;
  1207. ULONG bytesRemaining = 0,bytesWritten = 0;
  1208. LARGE_INTEGER aMillisecIn100ns;
  1209. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  1210. KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock);
  1211. m_TimerQueued = FALSE;
  1212. while (m_DMKEvtQueue) // do we have anything to play at all?
  1213. {
  1214. aDMKEvt = m_DMKEvtQueue; // event we try to play
  1215. if (aDMKEvt->cbEvent)
  1216. {
  1217. bytesRemaining = aDMKEvt->cbEvent - m_DMKEvtOffset; // number of bytes left in this evt
  1218. ASSERT(bytesRemaining > 0);
  1219. if (bytesRemaining <= 0)
  1220. {
  1221. bytesRemaining = aDMKEvt->cbEvent;
  1222. }
  1223. if (aDMKEvt->cbEvent <= sizeof(PBYTE)) // short message
  1224. {
  1225. _DbgPrintF(DEBUGLVL_BLAB, ("ConsumeEvents(%02x%02x%02x%02x)",aDMKEvt->uData.abData[0],aDMKEvt->uData.abData[1],aDMKEvt->uData.abData[2],aDMKEvt->uData.abData[3]));
  1226. ntStatus = Write(aDMKEvt->uData.abData + m_DMKEvtOffset,bytesRemaining,&bytesWritten);
  1227. }
  1228. else if (PACKAGE_EVT(aDMKEvt))
  1229. {
  1230. ASSERT(m_DMKEvtOffset == 0);
  1231. m_DMKEvtOffset = 0;
  1232. _DbgPrintF(DEBUGLVL_BLAB, ("ConsumeEvents(Package)"));
  1233. ntStatus = PutMessageLocked(aDMKEvt->uData.pPackageEvt); // we already own the spinlock
  1234. // null this because we are about to throw it in the allocator
  1235. aDMKEvt->uData.pPackageEvt = NULL;
  1236. aDMKEvt->cbEvent = 0;
  1237. bytesWritten = bytesRemaining;
  1238. }
  1239. else // SysEx message
  1240. {
  1241. _DbgPrintF(DEBUGLVL_BLAB, ("ConsumeEvents(%02x%02x%02x%02x)",aDMKEvt->uData.pbData[0],aDMKEvt->uData.pbData[1],aDMKEvt->uData.pbData[2],aDMKEvt->uData.pbData[3]));
  1242. ntStatus = Write(aDMKEvt->uData.pbData + m_DMKEvtOffset,bytesRemaining,&bytesWritten);
  1243. }
  1244. } // if (aDMKEvt->cbEvent)
  1245. if (STATUS_SUCCESS != ntStatus)
  1246. {
  1247. _DbgPrintF(DEBUGLVL_TERSE, ("ConsumeEvents: Write returned 0x%08x",ntStatus));
  1248. bytesWritten = bytesRemaining; // just bail on this event and try next time
  1249. }
  1250. ASSERT(bytesWritten <= bytesRemaining);
  1251. if (bytesWritten == bytesRemaining)
  1252. {
  1253. m_DMKEvtQueue = m_DMKEvtQueue->pNextEvt;
  1254. aDMKEvt->pNextEvt = NULL;
  1255. m_AllocatorMXF->PutMessage(aDMKEvt); // throw back in free pool
  1256. m_DMKEvtOffset = 0; // start fresh on next evt
  1257. m_NumberOfRetries = 0;
  1258. } // but wait ... there's more!
  1259. else // our FIFO is full for now.
  1260. {
  1261. // update our offset by that amount we did write
  1262. m_DMKEvtOffset += bytesWritten;
  1263. ASSERT(m_DMKEvtOffset < aDMKEvt->cbEvent);
  1264. _DbgPrintF(DEBUGLVL_BLAB,("ConsumeEvents tried %d, wrote %d, at offset %d",bytesRemaining,bytesWritten,m_DMKEvtOffset));
  1265. aMillisecIn100ns.QuadPart = -(kOneMillisec); // set timer, come back later
  1266. m_TimerQueued = TRUE;
  1267. m_NumberOfRetries++;
  1268. ntStatus = KeSetTimer( &m_TimerEvent, aMillisecIn100ns, &m_Dpc );
  1269. break;
  1270. } // we didn't write it all
  1271. } // go back, Jack, do it again (while m_DMKEvtQueue)
  1272. KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock);
  1273. return ntStatus;
  1274. }
  1275. #pragma code_seg()
  1276. /*****************************************************************************
  1277. * CMiniportDMusUARTStream::HandlePortParams()
  1278. *****************************************************************************
  1279. * Writes an outgoing MIDI message.
  1280. */
  1281. NTSTATUS
  1282. CMiniportDMusUARTStream::
  1283. HandlePortParams
  1284. (
  1285. IN PPCPROPERTY_REQUEST pRequest
  1286. )
  1287. {
  1288. PAGED_CODE();
  1289. NTSTATUS ntStatus;
  1290. if (pRequest->Verb & KSPROPERTY_TYPE_SET)
  1291. {
  1292. return STATUS_INVALID_DEVICE_REQUEST;
  1293. }
  1294. ntStatus = ValidatePropertyRequest(pRequest, sizeof(SYNTH_PORTPARAMS), TRUE);
  1295. if (NT_SUCCESS(ntStatus))
  1296. {
  1297. RtlCopyMemory(pRequest->Value, pRequest->Instance, sizeof(SYNTH_PORTPARAMS));
  1298. PSYNTH_PORTPARAMS Params = (PSYNTH_PORTPARAMS)pRequest->Value;
  1299. if (Params->ValidParams & ~SYNTH_PORTPARAMS_CHANNELGROUPS)
  1300. {
  1301. Params->ValidParams &= SYNTH_PORTPARAMS_CHANNELGROUPS;
  1302. }
  1303. if (!(Params->ValidParams & SYNTH_PORTPARAMS_CHANNELGROUPS))
  1304. {
  1305. Params->ChannelGroups = 1;
  1306. }
  1307. else if (Params->ChannelGroups != 1)
  1308. {
  1309. Params->ChannelGroups = 1;
  1310. }
  1311. pRequest->ValueSize = sizeof(SYNTH_PORTPARAMS);
  1312. }
  1313. return ntStatus;
  1314. }
  1315. #pragma code_seg()
  1316. /*****************************************************************************
  1317. * DMusTimerDPC()
  1318. *****************************************************************************
  1319. * The timer DPC callback. Thunks to a C++ member function.
  1320. * This is called by the OS in response to the DirectMusic pin
  1321. * wanting to wakeup later to process more DirectMusic stuff.
  1322. */
  1323. VOID
  1324. NTAPI
  1325. DMusUARTTimerDPC
  1326. (
  1327. IN PKDPC Dpc,
  1328. IN PVOID DeferredContext,
  1329. IN PVOID SystemArgument1,
  1330. IN PVOID SystemArgument2
  1331. )
  1332. {
  1333. ASSERT(DeferredContext);
  1334. CMiniportDMusUARTStream *aStream;
  1335. aStream = (CMiniportDMusUARTStream *) DeferredContext;
  1336. if (aStream)
  1337. {
  1338. _DbgPrintF(DEBUGLVL_BLAB,("DMusUARTTimerDPC"));
  1339. if (false == aStream->m_fCapture)
  1340. {
  1341. (void) aStream->ConsumeEvents();
  1342. }
  1343. // ignores return value!
  1344. }
  1345. }
  1346. /*****************************************************************************
  1347. * DirectMusic properties
  1348. ****************************************************************************/
  1349. #pragma code_seg("PAGE")
  1350. /*
  1351. * Properties concerning synthesizer functions.
  1352. */
  1353. const WCHAR wszDescOut[] = L"DMusic MPU-401 Out ";
  1354. const WCHAR wszDescIn[] = L"DMusic MPU-401 In ";
  1355. NTSTATUS PropertyHandler_Synth
  1356. (
  1357. IN PPCPROPERTY_REQUEST pRequest
  1358. )
  1359. {
  1360. NTSTATUS ntStatus;
  1361. PAGED_CODE();
  1362. if (pRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  1363. {
  1364. ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONG), TRUE);
  1365. if (NT_SUCCESS(ntStatus))
  1366. {
  1367. // if return buffer can hold a ULONG, return the access flags
  1368. PULONG AccessFlags = PULONG(pRequest->Value);
  1369. *AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT;
  1370. switch (pRequest->PropertyItem->Id)
  1371. {
  1372. case KSPROPERTY_SYNTH_CAPS:
  1373. case KSPROPERTY_SYNTH_CHANNELGROUPS:
  1374. *AccessFlags |= KSPROPERTY_TYPE_GET;
  1375. }
  1376. switch (pRequest->PropertyItem->Id)
  1377. {
  1378. case KSPROPERTY_SYNTH_CHANNELGROUPS:
  1379. *AccessFlags |= KSPROPERTY_TYPE_SET;
  1380. }
  1381. ntStatus = STATUS_SUCCESS;
  1382. pRequest->ValueSize = sizeof(ULONG);
  1383. switch (pRequest->PropertyItem->Id)
  1384. {
  1385. case KSPROPERTY_SYNTH_PORTPARAMETERS:
  1386. if (pRequest->MinorTarget)
  1387. {
  1388. *AccessFlags |= KSPROPERTY_TYPE_GET;
  1389. }
  1390. else
  1391. {
  1392. pRequest->ValueSize = 0;
  1393. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1394. }
  1395. }
  1396. }
  1397. }
  1398. else
  1399. {
  1400. ntStatus = STATUS_SUCCESS;
  1401. switch(pRequest->PropertyItem->Id)
  1402. {
  1403. case KSPROPERTY_SYNTH_CAPS:
  1404. _DbgPrintF(DEBUGLVL_VERBOSE,("PropertyHandler_Synth:KSPROPERTY_SYNTH_CAPS"));
  1405. if (pRequest->Verb & KSPROPERTY_TYPE_SET)
  1406. {
  1407. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1408. }
  1409. if (NT_SUCCESS(ntStatus))
  1410. {
  1411. ntStatus = ValidatePropertyRequest(pRequest, sizeof(SYNTHCAPS), TRUE);
  1412. if (NT_SUCCESS(ntStatus))
  1413. {
  1414. SYNTHCAPS *caps = (SYNTHCAPS*)pRequest->Value;
  1415. int increment;
  1416. RtlZeroMemory(caps, sizeof(SYNTHCAPS));
  1417. // XXX Different guids for different instances!
  1418. //
  1419. if (pRequest->Node == eSynthNode)
  1420. {
  1421. increment = sizeof(wszDescOut) - 2;
  1422. RtlCopyMemory( caps->Description,wszDescOut,increment);
  1423. caps->Guid = CLSID_MiniportDriverDMusUART;
  1424. }
  1425. else
  1426. {
  1427. increment = sizeof(wszDescIn) - 2;
  1428. RtlCopyMemory( caps->Description,wszDescIn,increment);
  1429. caps->Guid = CLSID_MiniportDriverDMusUARTCapture;
  1430. }
  1431. caps->Flags = SYNTH_PC_EXTERNAL;
  1432. caps->MemorySize = 0;
  1433. caps->MaxChannelGroups = 1;
  1434. caps->MaxVoices = 0xFFFFFFFF;
  1435. caps->MaxAudioChannels = 0xFFFFFFFF;
  1436. caps->EffectFlags = 0;
  1437. CMiniportDMusUART *aMiniport;
  1438. ASSERT(pRequest->MajorTarget);
  1439. aMiniport = (CMiniportDMusUART *)(PMINIPORTDMUS)(pRequest->MajorTarget);
  1440. WCHAR wszDesc2[16];
  1441. int cLen;
  1442. cLen = swprintf(wszDesc2,L"[%03X]\0",PtrToUlong(aMiniport->m_pPortBase));
  1443. cLen *= sizeof(WCHAR);
  1444. RtlCopyMemory((WCHAR *)((DWORD_PTR)(caps->Description) + increment),
  1445. wszDesc2,
  1446. cLen);
  1447. pRequest->ValueSize = sizeof(SYNTHCAPS);
  1448. }
  1449. }
  1450. break;
  1451. case KSPROPERTY_SYNTH_PORTPARAMETERS:
  1452. _DbgPrintF(DEBUGLVL_VERBOSE,("PropertyHandler_Synth:KSPROPERTY_SYNTH_PORTPARAMETERS"));
  1453. {
  1454. CMiniportDMusUARTStream *aStream;
  1455. aStream = (CMiniportDMusUARTStream*)(pRequest->MinorTarget);
  1456. if (aStream)
  1457. {
  1458. ntStatus = aStream->HandlePortParams(pRequest);
  1459. }
  1460. else
  1461. {
  1462. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1463. }
  1464. }
  1465. break;
  1466. case KSPROPERTY_SYNTH_CHANNELGROUPS:
  1467. _DbgPrintF(DEBUGLVL_VERBOSE,("PropertyHandler_Synth:KSPROPERTY_SYNTH_CHANNELGROUPS"));
  1468. ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONG), TRUE);
  1469. if (NT_SUCCESS(ntStatus))
  1470. {
  1471. *(PULONG)(pRequest->Value) = 1;
  1472. pRequest->ValueSize = sizeof(ULONG);
  1473. }
  1474. break;
  1475. case KSPROPERTY_SYNTH_LATENCYCLOCK:
  1476. _DbgPrintF(DEBUGLVL_VERBOSE,("PropertyHandler_Synth:KSPROPERTY_SYNTH_LATENCYCLOCK"));
  1477. if(pRequest->Verb & KSPROPERTY_TYPE_SET)
  1478. {
  1479. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1480. }
  1481. else
  1482. {
  1483. ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONGLONG), TRUE);
  1484. if(NT_SUCCESS(ntStatus))
  1485. {
  1486. REFERENCE_TIME rtLatency;
  1487. CMiniportDMusUARTStream *aStream;
  1488. aStream = (CMiniportDMusUARTStream*)(pRequest->MinorTarget);
  1489. if(aStream == NULL)
  1490. {
  1491. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1492. }
  1493. else
  1494. {
  1495. aStream->m_pMiniport->m_MasterClock->GetTime(&rtLatency);
  1496. *((PULONGLONG)pRequest->Value) = rtLatency;
  1497. pRequest->ValueSize = sizeof(ULONGLONG);
  1498. }
  1499. }
  1500. }
  1501. break;
  1502. default:
  1503. _DbgPrintF(DEBUGLVL_TERSE,("Unhandled property in PropertyHandler_Synth"));
  1504. break;
  1505. }
  1506. }
  1507. return ntStatus;
  1508. }
  1509. /*****************************************************************************
  1510. * ValidatePropertyRequest()
  1511. *****************************************************************************
  1512. * Validates pRequest.
  1513. * Checks if the ValueSize is valid
  1514. * Checks if the Value is valid
  1515. *
  1516. * This does not update pRequest->ValueSize if it returns NT_SUCCESS.
  1517. * Caller must set pRequest->ValueSize in case of NT_SUCCESS.
  1518. */
  1519. NTSTATUS ValidatePropertyRequest
  1520. (
  1521. IN PPCPROPERTY_REQUEST pRequest,
  1522. IN ULONG ulValueSize,
  1523. IN BOOLEAN fValueRequired
  1524. )
  1525. {
  1526. NTSTATUS ntStatus;
  1527. if (pRequest->ValueSize >= ulValueSize)
  1528. {
  1529. if (fValueRequired && NULL == pRequest->Value)
  1530. {
  1531. ntStatus = STATUS_INVALID_PARAMETER;
  1532. }
  1533. else
  1534. {
  1535. ntStatus = STATUS_SUCCESS;
  1536. }
  1537. }
  1538. else if (0 == pRequest->ValueSize)
  1539. {
  1540. ntStatus = STATUS_BUFFER_OVERFLOW;
  1541. }
  1542. else
  1543. {
  1544. ntStatus = STATUS_BUFFER_TOO_SMALL;
  1545. }
  1546. if (STATUS_BUFFER_OVERFLOW == ntStatus)
  1547. {
  1548. pRequest->ValueSize = ulValueSize;
  1549. }
  1550. else
  1551. {
  1552. pRequest->ValueSize = 0;
  1553. }
  1554. return ntStatus;
  1555. } // ValidatePropertyRequest
  1556. #pragma code_seg()