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