xref: /reactos/sdk/lib/drivers/sound/mmixer/midi.c (revision c2c66aff)
1 /*
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
7  */
8 
9 #include "precomp.h"
10 
11 #define YDEBUG
12 #include <debug.h>
13 
14 MIXER_STATUS
15 MMixerGetPinDataFlowAndCommunication(
16     IN PMIXER_CONTEXT MixerContext,
17     IN HANDLE hDevice,
18     IN ULONG PinId,
19     OUT PKSPIN_DATAFLOW DataFlow,
20     OUT PKSPIN_COMMUNICATION Communication)
21 {
22     KSP_PIN Pin;
23     ULONG BytesReturned;
24     MIXER_STATUS Status;
25 
26     /* setup request */
27     Pin.PinId = PinId;
28     Pin.Reserved = 0;
29     Pin.Property.Flags = KSPROPERTY_TYPE_GET;
30     Pin.Property.Id = KSPROPERTY_PIN_DATAFLOW;
31     Pin.Property.Set = KSPROPSETID_Pin;
32 
33     /* get pin dataflow */
34     Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
35     if (Status != MM_STATUS_SUCCESS)
36     {
37         /* failed to retrieve dataflow */
38         return Status;
39     }
40 
41     /* setup communication request */
42     Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
43 
44     /* get pin communication */
45     Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
46 
47     return Status;
48 }
49 
50 MIXER_STATUS
51 MMixerAddMidiPin(
52     IN PMIXER_CONTEXT MixerContext,
53     IN PMIXER_LIST MixerList,
54     IN ULONG DeviceId,
55     IN ULONG PinId,
56     IN ULONG bInput,
57     IN LPWSTR DeviceName)
58 {
59     LPMIDI_INFO MidiInfo;
60 
61     /* allocate midi info */
62     MidiInfo = MixerContext->Alloc(sizeof(MIDI_INFO));
63 
64     if (!MidiInfo)
65     {
66         /* no memory */
67         return MM_STATUS_NO_MEMORY;
68     }
69 
70     /* initialize midi info */
71     MidiInfo->DeviceId = DeviceId;
72     MidiInfo->PinId = PinId;
73 
74     /* sanity check */
75     ASSERT(!DeviceName || (wcslen(DeviceName) + 1 < MAXPNAMELEN));
76 
77     /* copy device name */
78     if (bInput && DeviceName)
79     {
80         wcscpy(MidiInfo->u.InCaps.szPname, DeviceName);
81     }
82     else if (!bInput && DeviceName)
83     {
84         wcscpy(MidiInfo->u.OutCaps.szPname, DeviceName);
85     }
86 
87    /* FIXME determine manufacturer / product id */
88     if (bInput)
89     {
90         MidiInfo->u.InCaps.dwSupport = 0;
91         MidiInfo->u.InCaps.wMid = MM_MICROSOFT;
92         MidiInfo->u.InCaps.wPid = MM_PID_UNMAPPED;
93         MidiInfo->u.InCaps.vDriverVersion = 1;
94     }
95     else
96     {
97         MidiInfo->u.OutCaps.dwSupport = 0;
98         MidiInfo->u.OutCaps.wMid = MM_MICROSOFT;
99         MidiInfo->u.OutCaps.wPid = MM_PID_UNMAPPED;
100         MidiInfo->u.OutCaps.vDriverVersion = 1;
101     }
102 
103     if (bInput)
104     {
105         /* insert into list */
106         InsertTailList(&MixerList->MidiInList, &MidiInfo->Entry);
107         MixerList->MidiInListCount++;
108     }
109     else
110     {
111         /* insert into list */
112         InsertTailList(&MixerList->MidiOutList, &MidiInfo->Entry);
113         MixerList->MidiOutListCount++;
114     }
115 
116     return MM_STATUS_SUCCESS;
117 }
118 
119 VOID
120 MMixerCheckFilterPinMidiSupport(
121     IN PMIXER_CONTEXT MixerContext,
122     IN PMIXER_LIST MixerList,
123     IN LPMIXER_DATA MixerData,
124     IN ULONG PinId,
125     IN PKSMULTIPLE_ITEM MultipleItem,
126     IN LPWSTR szPname)
127 {
128     ULONG Index;
129     PKSDATARANGE DataRange;
130     KSPIN_COMMUNICATION Communication;
131     KSPIN_DATAFLOW DataFlow;
132 
133     /* get first datarange */
134     DataRange = (PKSDATARANGE)(MultipleItem + 1);
135 
136     /* alignment assert */
137     ASSERT(((ULONG_PTR)DataRange & 0x7) == 0);
138 
139     /* iterate through all data ranges */
140     for(Index = 0; Index < MultipleItem->Count; Index++)
141     {
142         if (IsEqualGUIDAligned(&DataRange->MajorFormat, &KSDATAFORMAT_TYPE_MUSIC) &&
143             IsEqualGUIDAligned(&DataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_MIDI) &&
144             IsEqualGUIDAligned(&DataRange->Specifier, &KSDATAFORMAT_SPECIFIER_NONE))
145         {
146             /* pin supports midi datarange */
147             if (MMixerGetPinDataFlowAndCommunication(MixerContext, MixerData->hDevice, PinId, &DataFlow, &Communication) == MM_STATUS_SUCCESS)
148             {
149                 if (DataFlow == KSPIN_DATAFLOW_IN && Communication == KSPIN_COMMUNICATION_SINK)
150                 {
151                     MMixerAddMidiPin(MixerContext, MixerList, MixerData->DeviceId, PinId, FALSE, szPname);
152                 }
153                 else if (DataFlow == KSPIN_DATAFLOW_OUT && Communication == KSPIN_COMMUNICATION_SOURCE)
154                 {
155                     MMixerAddMidiPin(MixerContext, MixerList, MixerData->DeviceId, PinId, TRUE, szPname);
156                 }
157             }
158         }
159 
160         /* move to next datarange */
161         DataRange = (PKSDATARANGE)((ULONG_PTR)DataRange + DataRange->FormatSize);
162 
163         /* alignment assert */
164         ASSERT(((ULONG_PTR)DataRange & 0x7) == 0);
165 
166         /* data ranges are 64-bit aligned */
167         DataRange = (PVOID)(((ULONG_PTR)DataRange + 0x7) & ~0x7);
168     }
169 }
170 
171 VOID
172 MMixerInitializeMidiForFilter(
173     IN PMIXER_CONTEXT MixerContext,
174     IN PMIXER_LIST MixerList,
175     IN LPMIXER_DATA MixerData,
176     IN PTOPOLOGY Topology)
177 {
178     ULONG PinCount, Index;
179     MIXER_STATUS Status;
180     PKSMULTIPLE_ITEM MultipleItem;
181     WCHAR szPname[MAXPNAMELEN];
182 
183     /* get filter pin count */
184     MMixerGetTopologyPinCount(Topology, &PinCount);
185 
186     /* get mixer name */
187     if (MMixerGetDeviceName(MixerContext, szPname, MixerData->hDeviceInterfaceKey) != MM_STATUS_SUCCESS)
188     {
189         /* clear name */
190         szPname[0] = 0;
191     }
192 
193     /* iterate all pins and check for KSDATARANGE_MUSIC support */
194     for(Index = 0; Index < PinCount; Index++)
195     {
196         /* get audio pin data ranges */
197         Status = MMixerGetAudioPinDataRanges(MixerContext, MixerData->hDevice, Index, &MultipleItem);
198 
199         /* check for success */
200         if (Status == MM_STATUS_SUCCESS)
201         {
202             /* check if there is support KSDATARANGE_MUSIC */
203             MMixerCheckFilterPinMidiSupport(MixerContext, MixerList, MixerData, Index, MultipleItem, szPname);
204         }
205     }
206 }
207 
208 MIXER_STATUS
209 MMixerOpenMidiPin(
210     IN PMIXER_CONTEXT MixerContext,
211     IN PMIXER_LIST MixerList,
212     IN ULONG DeviceId,
213     IN ULONG PinId,
214     IN ACCESS_MASK DesiredAccess,
215     IN PIN_CREATE_CALLBACK CreateCallback,
216     IN PVOID Context,
217     OUT PHANDLE PinHandle)
218 {
219     PKSPIN_CONNECT PinConnect;
220     PKSDATAFORMAT DataFormat;
221     LPMIXER_DATA MixerData;
222     NTSTATUS Status;
223     MIXER_STATUS MixerStatus;
224 
225     MixerData = MMixerGetDataByDeviceId(MixerList, DeviceId);
226     if (!MixerData)
227         return MM_STATUS_INVALID_PARAMETER;
228 
229     /* allocate pin connect */
230     PinConnect = MMixerAllocatePinConnect(MixerContext, sizeof(KSDATAFORMAT));
231     if (!PinConnect)
232     {
233         /* no memory */
234         return MM_STATUS_NO_MEMORY;
235     }
236 
237     /* initialize pin connect struct */
238     MMixerInitializePinConnect(PinConnect, PinId);
239 
240     /* get offset to dataformat */
241     DataFormat = (PKSDATAFORMAT) (PinConnect + 1);
242 
243     /* initialize data format */
244     RtlMoveMemory(&DataFormat->MajorFormat, &KSDATAFORMAT_TYPE_MUSIC, sizeof(GUID));
245     RtlMoveMemory(&DataFormat->SubFormat, &KSDATAFORMAT_SUBTYPE_MIDI, sizeof(GUID));
246     RtlMoveMemory(&DataFormat->Specifier, &KSDATAFORMAT_SPECIFIER_NONE, sizeof(GUID));
247 
248     if (CreateCallback)
249     {
250         /* let the callback handle the creation */
251         MixerStatus = CreateCallback(Context, DeviceId, PinId, MixerData->hDevice, PinConnect, DesiredAccess, PinHandle);
252     }
253     else
254     {
255         /* now create the pin */
256         Status = KsCreatePin(MixerData->hDevice, PinConnect, DesiredAccess, PinHandle);
257 
258         /* normalize status */
259         if (Status == STATUS_SUCCESS)
260             MixerStatus = MM_STATUS_SUCCESS;
261         else
262             MixerStatus = MM_STATUS_UNSUCCESSFUL;
263     }
264 
265     /* free create info */
266     MixerContext->Free(PinConnect);
267 
268     /* done */
269     return MixerStatus;
270 }
271 
272 MIXER_STATUS
273 MMixerGetMidiInfoByIndexAndType(
274     IN  PMIXER_LIST MixerList,
275     IN  ULONG DeviceIndex,
276     IN  ULONG bMidiInputType,
277     OUT LPMIDI_INFO *OutMidiInfo)
278 {
279     ULONG Index = 0;
280     PLIST_ENTRY Entry, ListHead;
281     LPMIDI_INFO MidiInfo;
282 
283     if (bMidiInputType)
284         ListHead = &MixerList->MidiInList;
285     else
286         ListHead = &MixerList->MidiOutList;
287 
288     /* get first entry */
289     Entry = ListHead->Flink;
290 
291     while(Entry != ListHead)
292     {
293         MidiInfo = (LPMIDI_INFO)CONTAINING_RECORD(Entry, MIDI_INFO, Entry);
294 
295         if (Index == DeviceIndex)
296         {
297             *OutMidiInfo = MidiInfo;
298             return MM_STATUS_SUCCESS;
299         }
300         Index++;
301         Entry = Entry->Flink;
302     }
303 
304     return MM_STATUS_INVALID_PARAMETER;
305 }
306 
307 MIXER_STATUS
308 MMixerMidiOutCapabilities(
309     IN PMIXER_CONTEXT MixerContext,
310     IN ULONG DeviceIndex,
311     OUT LPMIDIOUTCAPSW Caps)
312 {
313     PMIXER_LIST MixerList;
314     MIXER_STATUS Status;
315     LPMIDI_INFO MidiInfo;
316 
317     /* verify mixer context */
318     Status = MMixerVerifyContext(MixerContext);
319 
320     if (Status != MM_STATUS_SUCCESS)
321     {
322         /* invalid context passed */
323         return Status;
324     }
325 
326     /* grab mixer list */
327     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
328 
329     /* find destination midi */
330     Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceIndex, FALSE, &MidiInfo);
331     if (Status != MM_STATUS_SUCCESS)
332     {
333         /* failed to find midi info */
334         return MM_STATUS_UNSUCCESSFUL;
335     }
336 
337     /* copy capabilities */
338     MixerContext->Copy(Caps, &MidiInfo->u.OutCaps, sizeof(MIDIOUTCAPSW));
339 
340     return MM_STATUS_SUCCESS;
341 }
342 
343 MIXER_STATUS
344 MMixerMidiInCapabilities(
345     IN PMIXER_CONTEXT MixerContext,
346     IN ULONG DeviceIndex,
347     OUT LPMIDIINCAPSW Caps)
348 {
349     PMIXER_LIST MixerList;
350     MIXER_STATUS Status;
351     LPMIDI_INFO MidiInfo;
352 
353     /* verify mixer context */
354     Status = MMixerVerifyContext(MixerContext);
355 
356     if (Status != MM_STATUS_SUCCESS)
357     {
358         /* invalid context passed */
359         return Status;
360     }
361 
362     /* grab mixer list */
363     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
364 
365     /* find destination midi */
366     Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceIndex, TRUE, &MidiInfo);
367     if (Status != MM_STATUS_SUCCESS)
368     {
369         /* failed to find midi info */
370         return MM_STATUS_UNSUCCESSFUL;
371     }
372 
373     /* copy capabilities */
374     MixerContext->Copy(Caps, &MidiInfo->u.InCaps, sizeof(MIDIINCAPSW));
375 
376     return MM_STATUS_SUCCESS;
377 }
378 
379 MIXER_STATUS
380 MMixerGetMidiDevicePath(
381     IN PMIXER_CONTEXT MixerContext,
382     IN ULONG bMidiIn,
383     IN ULONG DeviceId,
384     OUT LPWSTR * DevicePath)
385 {
386     PMIXER_LIST MixerList;
387     LPMIXER_DATA MixerData;
388     LPMIDI_INFO MidiInfo;
389     ULONG Length;
390     MIXER_STATUS Status;
391 
392     /* verify mixer context */
393     Status = MMixerVerifyContext(MixerContext);
394 
395     if (Status != MM_STATUS_SUCCESS)
396     {
397         /* invalid context passed */
398         return Status;
399     }
400 
401     /* grab mixer list */
402     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
403 
404     /* find destination midi */
405     Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceId, bMidiIn, &MidiInfo);
406     if (Status != MM_STATUS_SUCCESS)
407     {
408         /* failed to find midi info */
409         return MM_STATUS_INVALID_PARAMETER;
410     }
411 
412     /* get associated device id */
413     MixerData = MMixerGetDataByDeviceId(MixerList, MidiInfo->DeviceId);
414     if (!MixerData)
415         return MM_STATUS_INVALID_PARAMETER;
416 
417     /* calculate length */
418     Length = wcslen(MixerData->DeviceName)+1;
419 
420     /* allocate destination buffer */
421     *DevicePath = MixerContext->Alloc(Length * sizeof(WCHAR));
422 
423     if (!*DevicePath)
424     {
425         /* no memory */
426         return MM_STATUS_NO_MEMORY;
427     }
428 
429     /* copy device path */
430     MixerContext->Copy(*DevicePath, MixerData->DeviceName, Length * sizeof(WCHAR));
431 
432     /* done */
433     return MM_STATUS_SUCCESS;
434 }
435 
436 MIXER_STATUS
437 MMixerSetMidiStatus(
438     IN PMIXER_CONTEXT MixerContext,
439     IN HANDLE PinHandle,
440     IN KSSTATE State)
441 {
442     KSPROPERTY Property;
443     ULONG Length;
444 
445     /* setup property request */
446     Property.Set = KSPROPSETID_Connection;
447     Property.Id = KSPROPERTY_CONNECTION_STATE;
448     Property.Flags = KSPROPERTY_TYPE_SET;
449 
450     return MixerContext->Control(PinHandle, IOCTL_KS_PROPERTY, &Property, sizeof(KSPROPERTY), &State, sizeof(KSSTATE), &Length);
451 }
452 
453 MIXER_STATUS
454 MMixerOpenMidi(
455     IN PMIXER_CONTEXT MixerContext,
456     IN ULONG DeviceIndex,
457     IN ULONG bMidiIn,
458     IN PIN_CREATE_CALLBACK CreateCallback,
459     IN PVOID Context,
460     OUT PHANDLE PinHandle)
461 {
462     PMIXER_LIST MixerList;
463     MIXER_STATUS Status;
464     LPMIDI_INFO MidiInfo;
465     ACCESS_MASK DesiredAccess = 0;
466 
467     /* verify mixer context */
468     Status = MMixerVerifyContext(MixerContext);
469 
470     if (Status != MM_STATUS_SUCCESS)
471     {
472         /* invalid context passed */
473         return Status;
474     }
475 
476     /* grab mixer list */
477     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
478 
479     /* find destination midi */
480     Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceIndex, bMidiIn, &MidiInfo);
481     if (Status != MM_STATUS_SUCCESS)
482     {
483         /* failed to find midi info */
484         return MM_STATUS_INVALID_PARAMETER;
485     }
486 
487     /* get desired access */
488     if (bMidiIn)
489     {
490         DesiredAccess |= GENERIC_READ;
491     }
492      else
493     {
494         DesiredAccess |= GENERIC_WRITE;
495     }
496 
497     /* now try open the pin */
498     return MMixerOpenMidiPin(MixerContext, MixerList, MidiInfo->DeviceId, MidiInfo->PinId, DesiredAccess, CreateCallback, Context, PinHandle);
499 }
500 
501 ULONG
502 MMixerGetMidiInCount(
503     IN PMIXER_CONTEXT MixerContext)
504 {
505     PMIXER_LIST MixerList;
506     MIXER_STATUS Status;
507 
508      /* verify mixer context */
509     Status = MMixerVerifyContext(MixerContext);
510 
511     if (Status != MM_STATUS_SUCCESS)
512     {
513         /* invalid context passed */
514         return Status;
515     }
516 
517     /* grab mixer list */
518     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
519 
520     return MixerList->MidiInListCount;
521 }
522 
523 ULONG
524 MMixerGetMidiOutCount(
525     IN PMIXER_CONTEXT MixerContext)
526 {
527     PMIXER_LIST MixerList;
528     MIXER_STATUS Status;
529 
530      /* verify mixer context */
531     Status = MMixerVerifyContext(MixerContext);
532 
533     if (Status != MM_STATUS_SUCCESS)
534     {
535         /* invalid context passed */
536         return Status;
537     }
538 
539     /* grab mixer list */
540     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
541 
542     return MixerList->MidiOutListCount;
543 }
544