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