2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: lib/drivers/sound/mmixer/midi.c
5 * PURPOSE: Midi Support Functions
6 * PROGRAMMER: Johannes Anderwald
12 MMixerGetPinDataFlowAndCommunication(
13 IN PMIXER_CONTEXT MixerContext
,
14 IN LPMIXER_DATA MixerData
,
16 OUT PKSPIN_DATAFLOW DataFlow
,
17 OUT PKSPIN_COMMUNICATION Communication
)
26 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
27 Pin
.Property
.Id
= KSPROPERTY_PIN_DATAFLOW
;
28 Pin
.Property
.Set
= KSPROPSETID_Pin
;
30 /* get pin dataflow */
31 Status
= MixerContext
->Control(MixerData
->hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)DataFlow
, sizeof(KSPIN_DATAFLOW
), &BytesReturned
);
32 if (Status
!= MM_STATUS_SUCCESS
)
34 /* failed to retrieve dataflow */
38 /* setup communication request */
39 Pin
.Property
.Id
= KSPROPERTY_PIN_COMMUNICATION
;
41 /* get pin communication */
42 Status
= MixerContext
->Control(MixerData
->hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Communication
, sizeof(KSPIN_COMMUNICATION
), &BytesReturned
);
49 IN PMIXER_CONTEXT MixerContext
,
50 IN PMIXER_LIST MixerList
,
58 /* allocate midi info */
59 MidiInfo
= MixerContext
->Alloc(sizeof(MIDI_INFO
));
64 return MM_STATUS_NO_MEMORY
;
67 /* initialize midi info */
68 MidiInfo
->DeviceId
= DeviceId
;
69 MidiInfo
->PinId
= PinId
;
72 ASSERT(wcslen(DeviceName
) + 1 < MAXPNAMELEN
);
74 /* copy device name */
75 if (bInput
&& DeviceName
)
77 wcscpy(MidiInfo
->u
.InCaps
.szPname
, DeviceName
);
79 else if (!bInput
&& DeviceName
)
81 wcscpy(MidiInfo
->u
.OutCaps
.szPname
, DeviceName
);
84 /* FIXME determine manufacturer / product id */
87 MidiInfo
->u
.InCaps
.dwSupport
= 0;
88 MidiInfo
->u
.InCaps
.wMid
= MM_MICROSOFT
;
89 MidiInfo
->u
.InCaps
.wPid
= MM_PID_UNMAPPED
;
90 MidiInfo
->u
.InCaps
.vDriverVersion
= 1;
94 MidiInfo
->u
.OutCaps
.dwSupport
= 0;
95 MidiInfo
->u
.OutCaps
.wMid
= MM_MICROSOFT
;
96 MidiInfo
->u
.OutCaps
.wPid
= MM_PID_UNMAPPED
;
97 MidiInfo
->u
.OutCaps
.vDriverVersion
= 1;
102 /* insert into list */
103 InsertTailList(&MixerList
->MidiInList
, &MidiInfo
->Entry
);
104 MixerList
->MidiInListCount
++;
108 /* insert into list */
109 InsertTailList(&MixerList
->MidiOutList
, &MidiInfo
->Entry
);
110 MixerList
->MidiOutListCount
++;
113 return MM_STATUS_SUCCESS
;
117 MMixerCheckFilterPinMidiSupport(
118 IN PMIXER_CONTEXT MixerContext
,
119 IN PMIXER_LIST MixerList
,
120 IN LPMIXER_DATA MixerData
,
122 IN PKSMULTIPLE_ITEM MultipleItem
,
126 PKSDATARANGE DataRange
;
127 KSPIN_COMMUNICATION Communication
;
128 KSPIN_DATAFLOW DataFlow
;
131 /* get first datarange */
132 DataRange
= (PKSDATARANGE
)(MultipleItem
+ 1);
134 /* alignment assert */
135 ASSERT(((ULONG_PTR
)DataRange
& 0x7) == 0);
137 /* iterate through all data ranges */
138 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
140 if (IsEqualGUIDAligned(&DataRange
->MajorFormat
, &KSDATAFORMAT_TYPE_MUSIC
) &&
141 IsEqualGUIDAligned(&DataRange
->SubFormat
, &KSDATAFORMAT_SUBTYPE_MIDI
) &&
142 IsEqualGUIDAligned(&DataRange
->Specifier
, &KSDATAFORMAT_SPECIFIER_NONE
))
144 /* pin supports midi datarange */
145 if (MMixerGetPinDataFlowAndCommunication(MixerContext
, MixerData
, PinId
, &DataFlow
, &Communication
) == MM_STATUS_SUCCESS
)
147 if (DataFlow
== KSPIN_DATAFLOW_IN
&& Communication
== KSPIN_COMMUNICATION_SINK
)
149 Status
= MMixerAddMidiPin(MixerContext
, MixerList
, MixerData
->DeviceId
, PinId
, FALSE
, szPname
);
151 else if (DataFlow
== KSPIN_DATAFLOW_OUT
&& Communication
== KSPIN_COMMUNICATION_SOURCE
)
153 Status
= MMixerAddMidiPin(MixerContext
, MixerList
, MixerData
->DeviceId
, PinId
, TRUE
, szPname
);
158 /* move to next datarange */
159 DataRange
= (PKSDATARANGE
)((ULONG_PTR
)DataRange
+ DataRange
->FormatSize
);
161 /* alignment assert */
162 ASSERT(((ULONG_PTR
)DataRange
& 0x7) == 0);
164 /* data ranges are 64-bit aligned */
165 DataRange
= (PVOID
)(((ULONG_PTR
)DataRange
+ 0x7) & ~0x7);
170 MMixerInitializeMidiForFilter(
171 IN PMIXER_CONTEXT MixerContext
,
172 IN PMIXER_LIST MixerList
,
173 IN LPMIXER_DATA MixerData
,
174 IN PTOPOLOGY Topology
)
176 ULONG PinCount
, Index
;
178 PKSMULTIPLE_ITEM MultipleItem
;
179 WCHAR szPname
[MAXPNAMELEN
];
181 /* get filter pin count */
182 MMixerGetTopologyPinCount(Topology
, &PinCount
);
185 if (MMixerGetDeviceName(MixerContext
, szPname
, MixerData
->hDeviceInterfaceKey
) != MM_STATUS_SUCCESS
)
191 /* iterate all pins and check for KSDATARANGE_MUSIC support */
192 for(Index
= 0; Index
< PinCount
; Index
++)
194 /* get audio pin data ranges */
195 Status
= MMixerGetAudioPinDataRanges(MixerContext
, MixerData
->hDevice
, Index
, &MultipleItem
);
197 /* check for success */
198 if (Status
== MM_STATUS_SUCCESS
)
200 /* check if there is support KSDATARANGE_MUSIC */
201 MMixerCheckFilterPinMidiSupport(MixerContext
, MixerList
, MixerData
, Index
, MultipleItem
, szPname
);
208 IN PMIXER_CONTEXT MixerContext
,
209 IN PMIXER_LIST MixerList
,
212 IN ACCESS_MASK DesiredAccess
,
213 IN PIN_CREATE_CALLBACK CreateCallback
,
215 OUT PHANDLE PinHandle
)
217 PKSPIN_CONNECT PinConnect
;
218 PKSDATAFORMAT DataFormat
;
219 LPMIXER_DATA MixerData
;
221 MIXER_STATUS MixerStatus
;
223 MixerData
= MMixerGetDataByDeviceId(MixerList
, DeviceId
);
225 return MM_STATUS_INVALID_PARAMETER
;
227 /* allocate pin connect */
228 PinConnect
= MMixerAllocatePinConnect(MixerContext
, sizeof(KSDATAFORMAT
));
232 return MM_STATUS_NO_MEMORY
;
235 /* initialize pin connect struct */
236 MMixerInitializePinConnect(PinConnect
, PinId
);
238 /* get offset to dataformat */
239 DataFormat
= (PKSDATAFORMAT
) (PinConnect
+ 1);
241 /* initialize data format */
242 RtlMoveMemory(&DataFormat
->MajorFormat
, &KSDATAFORMAT_TYPE_MUSIC
, sizeof(GUID
));
243 RtlMoveMemory(&DataFormat
->SubFormat
, &KSDATAFORMAT_SUBTYPE_MIDI
, sizeof(GUID
));
244 RtlMoveMemory(&DataFormat
->Specifier
, &KSDATAFORMAT_SPECIFIER_NONE
, sizeof(GUID
));
248 /* let the callback handle the creation */
249 MixerStatus
= CreateCallback(Context
, DeviceId
, PinId
, MixerData
->hDevice
, PinConnect
, DesiredAccess
, PinHandle
);
253 /* now create the pin */
254 Status
= KsCreatePin(MixerData
->hDevice
, PinConnect
, DesiredAccess
, PinHandle
);
256 /* normalize status */
257 if (Status
== STATUS_SUCCESS
)
258 MixerStatus
= MM_STATUS_SUCCESS
;
260 MixerStatus
= MM_STATUS_UNSUCCESSFUL
;
263 /* free create info */
264 MixerContext
->Free(PinConnect
);
271 MMixerGetMidiInfoByIndexAndType(
272 IN PMIXER_LIST MixerList
,
273 IN ULONG DeviceIndex
,
274 IN ULONG bMidiInputType
,
275 OUT LPMIDI_INFO
*OutMidiInfo
)
278 PLIST_ENTRY Entry
, ListHead
;
279 LPMIDI_INFO MidiInfo
;
282 ListHead
= &MixerList
->MidiInList
;
284 ListHead
= &MixerList
->MidiOutList
;
286 /* get first entry */
287 Entry
= ListHead
->Flink
;
289 while(Entry
!= ListHead
)
291 MidiInfo
= (LPMIDI_INFO
)CONTAINING_RECORD(Entry
, MIDI_INFO
, Entry
);
293 if (Index
== DeviceIndex
)
295 *OutMidiInfo
= MidiInfo
;
296 return MM_STATUS_SUCCESS
;
299 Entry
= Entry
->Flink
;
302 return MM_STATUS_INVALID_PARAMETER
;
306 MMixerMidiOutCapabilities(
307 IN PMIXER_CONTEXT MixerContext
,
308 IN ULONG DeviceIndex
,
309 OUT LPMIDIOUTCAPSW Caps
)
311 PMIXER_LIST MixerList
;
313 LPMIDI_INFO MidiInfo
;
315 /* verify mixer context */
316 Status
= MMixerVerifyContext(MixerContext
);
318 if (Status
!= MM_STATUS_SUCCESS
)
320 /* invalid context passed */
324 /* grab mixer list */
325 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
327 /* find destination midi */
328 Status
= MMixerGetMidiInfoByIndexAndType(MixerList
, DeviceIndex
, FALSE
, &MidiInfo
);
329 if (Status
!= MM_STATUS_SUCCESS
)
331 /* failed to find midi info */
332 return MM_STATUS_UNSUCCESSFUL
;
335 /* copy capabilities */
336 MixerContext
->Copy(Caps
, &MidiInfo
->u
.OutCaps
, sizeof(MIDIOUTCAPSW
));
338 return MM_STATUS_SUCCESS
;
342 MMixerMidiInCapabilities(
343 IN PMIXER_CONTEXT MixerContext
,
344 IN ULONG DeviceIndex
,
345 OUT LPMIDIINCAPSW Caps
)
347 PMIXER_LIST MixerList
;
349 LPMIDI_INFO MidiInfo
;
351 /* verify mixer context */
352 Status
= MMixerVerifyContext(MixerContext
);
354 if (Status
!= MM_STATUS_SUCCESS
)
356 /* invalid context passed */
360 /* grab mixer list */
361 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
363 /* find destination midi */
364 Status
= MMixerGetMidiInfoByIndexAndType(MixerList
, DeviceIndex
, TRUE
, &MidiInfo
);
365 if (Status
!= MM_STATUS_SUCCESS
)
367 /* failed to find midi info */
368 return MM_STATUS_UNSUCCESSFUL
;
371 /* copy capabilities */
372 MixerContext
->Copy(Caps
, &MidiInfo
->u
.InCaps
, sizeof(MIDIINCAPSW
));
374 return MM_STATUS_SUCCESS
;
378 MMixerGetMidiDevicePath(
379 IN PMIXER_CONTEXT MixerContext
,
382 OUT LPWSTR
* DevicePath
)
384 PMIXER_LIST MixerList
;
385 LPMIXER_DATA MixerData
;
386 LPMIDI_INFO MidiInfo
;
390 /* verify mixer context */
391 Status
= MMixerVerifyContext(MixerContext
);
393 if (Status
!= MM_STATUS_SUCCESS
)
395 /* invalid context passed */
399 /* grab mixer list */
400 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
402 /* find destination midi */
403 Status
= MMixerGetMidiInfoByIndexAndType(MixerList
, DeviceId
, bMidiIn
, &MidiInfo
);
404 if (Status
!= MM_STATUS_SUCCESS
)
406 /* failed to find midi info */
407 return MM_STATUS_INVALID_PARAMETER
;
410 /* get associated device id */
411 MixerData
= MMixerGetDataByDeviceId(MixerList
, MidiInfo
->DeviceId
);
413 return MM_STATUS_INVALID_PARAMETER
;
415 /* calculate length */
416 Length
= wcslen(MixerData
->DeviceName
)+1;
418 /* allocate destination buffer */
419 *DevicePath
= MixerContext
->Alloc(Length
* sizeof(WCHAR
));
424 return MM_STATUS_NO_MEMORY
;
427 /* copy device path */
428 MixerContext
->Copy(*DevicePath
, MixerData
->DeviceName
, Length
* sizeof(WCHAR
));
431 return MM_STATUS_SUCCESS
;
436 IN PMIXER_CONTEXT MixerContext
,
443 /* setup property request */
444 Property
.Set
= KSPROPSETID_Connection
;
445 Property
.Id
= KSPROPERTY_CONNECTION_STATE
;
446 Property
.Flags
= KSPROPERTY_TYPE_SET
;
448 return MixerContext
->Control(PinHandle
, IOCTL_KS_PROPERTY
, &Property
, sizeof(KSPROPERTY
), &State
, sizeof(KSSTATE
), &Length
);
453 IN PMIXER_CONTEXT MixerContext
,
454 IN ULONG DeviceIndex
,
456 IN PIN_CREATE_CALLBACK CreateCallback
,
458 OUT PHANDLE PinHandle
)
460 PMIXER_LIST MixerList
;
462 LPMIDI_INFO MidiInfo
;
463 ACCESS_MASK DesiredAccess
= 0;
465 /* verify mixer context */
466 Status
= MMixerVerifyContext(MixerContext
);
468 if (Status
!= MM_STATUS_SUCCESS
)
470 /* invalid context passed */
474 /* grab mixer list */
475 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
477 /* find destination midi */
478 Status
= MMixerGetMidiInfoByIndexAndType(MixerList
, DeviceIndex
, bMidiIn
, &MidiInfo
);
479 if (Status
!= MM_STATUS_SUCCESS
)
481 /* failed to find midi info */
482 return MM_STATUS_INVALID_PARAMETER
;
485 /* get desired access */
488 DesiredAccess
|= GENERIC_READ
;
492 DesiredAccess
|= GENERIC_WRITE
;
495 /* now try open the pin */
496 return MMixerOpenMidiPin(MixerContext
, MixerList
, MidiInfo
->DeviceId
, MidiInfo
->PinId
, DesiredAccess
, CreateCallback
, Context
, PinHandle
);
500 MMixerGetMidiInCount(
501 IN PMIXER_CONTEXT MixerContext
)
503 PMIXER_LIST MixerList
;
506 /* verify mixer context */
507 Status
= MMixerVerifyContext(MixerContext
);
509 if (Status
!= MM_STATUS_SUCCESS
)
511 /* invalid context passed */
515 /* grab mixer list */
516 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
518 return MixerList
->MidiInListCount
;
522 MMixerGetMidiOutCount(
523 IN PMIXER_CONTEXT MixerContext
)
525 PMIXER_LIST MixerList
;
528 /* verify mixer context */
529 Status
= MMixerVerifyContext(MixerContext
);
531 if (Status
!= MM_STATUS_SUCCESS
)
533 /* invalid context passed */
537 /* grab mixer list */
538 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
540 return MixerList
->MidiOutListCount
;