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