f922970263a8ac301cedadc1e41ae4af3e953fb2
[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 "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(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 }