[USBAUDIO]
[reactos.git] / reactos / drivers / usb / usbaudio / pin.c
1 /*
2 * PROJECT: ReactOS Universal Audio Class Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbaudio/pin.c
5 * PURPOSE: USB Audio device driver.
6 * PROGRAMMERS:
7 * Johannes Anderwald (johannes.anderwald@reactos.org)
8 */
9
10 #include "usbaudio.h"
11
12 NTSTATUS
13 GetMaxPacketSizeForInterface(
14 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
15 IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
16 KSPIN_DATAFLOW DataFlow)
17 {
18 PUSB_COMMON_DESCRIPTOR CommonDescriptor;
19 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
20
21 /* loop descriptors */
22 CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
23 ASSERT(InterfaceDescriptor->bNumEndpoints > 0);
24 while (CommonDescriptor)
25 {
26 if (CommonDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)
27 {
28 EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)CommonDescriptor;
29 return EndpointDescriptor->wMaxPacketSize;
30 }
31
32 if (CommonDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
33 {
34 /* reached next interface descriptor */
35 break;
36 }
37
38 if ((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
39 break;
40
41 CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
42 }
43
44 /* default to 100 */
45 return 100;
46 }
47
48 NTSTATUS
49 UsbAudioAllocCaptureUrbIso(
50 IN USBD_PIPE_HANDLE PipeHandle,
51 IN ULONG MaxPacketSize,
52 IN PVOID Buffer,
53 IN ULONG BufferLength,
54 OUT PURB * OutUrb)
55 {
56 PURB Urb;
57 ULONG PacketCount;
58 ULONG UrbSize;
59 ULONG Index;
60
61 /* calculate packet count */
62 PacketCount = BufferLength / MaxPacketSize;
63
64 /* calculate urb size*/
65 UrbSize = GET_ISO_URB_SIZE(PacketCount);
66
67 /* allocate urb */
68 Urb = AllocFunction(UrbSize);
69 if (!Urb)
70 {
71 /* no memory */
72 return STATUS_INSUFFICIENT_RESOURCES;
73 }
74
75 /* init urb */
76 Urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
77 Urb->UrbIsochronousTransfer.Hdr.Length = UrbSize;
78 Urb->UrbIsochronousTransfer.PipeHandle = PipeHandle;
79 Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_START_ISO_TRANSFER_ASAP;
80 Urb->UrbIsochronousTransfer.TransferBufferLength = BufferLength;
81 Urb->UrbIsochronousTransfer.TransferBuffer = Buffer;
82 Urb->UrbIsochronousTransfer.NumberOfPackets = PacketCount;
83
84 for (Index = 0; Index < PacketCount; Index++)
85 {
86 Urb->UrbIsochronousTransfer.IsoPacket[Index].Offset = Index * MaxPacketSize;
87 }
88
89 *OutUrb = Urb;
90 return STATUS_SUCCESS;
91
92 }
93
94
95
96 NTSTATUS
97 UsbAudioSetFormat(
98 IN PKSPIN Pin)
99 {
100 PURB Urb;
101 PUCHAR SampleRateBuffer;
102 PPIN_CONTEXT PinContext;
103 NTSTATUS Status;
104 PKSDATAFORMAT_WAVEFORMATEX WaveFormatEx;
105
106 /* allocate sample rate buffer */
107 SampleRateBuffer = AllocFunction(sizeof(ULONG));
108 if (!SampleRateBuffer)
109 {
110 /* no memory */
111 return STATUS_INSUFFICIENT_RESOURCES;
112 }
113
114 if (IsEqualGUIDAligned(&Pin->ConnectionFormat->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
115 IsEqualGUIDAligned(&Pin->ConnectionFormat->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
116 IsEqualGUIDAligned(&Pin->ConnectionFormat->Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
117 {
118 WaveFormatEx = (PKSDATAFORMAT_WAVEFORMATEX)Pin->ConnectionFormat;
119 SampleRateBuffer[2] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 16) & 0xFF;
120 SampleRateBuffer[1] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 8) & 0xFF;
121 SampleRateBuffer[0] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 0) & 0xFF;
122
123 /* TODO: verify connection format */
124 }
125 else
126 {
127 /* not supported yet*/
128 UNIMPLEMENTED;
129 FreeFunction(SampleRateBuffer);
130 return STATUS_INVALID_PARAMETER;
131 }
132
133 /* allocate urb */
134 Urb = AllocFunction(sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
135 if (!Urb)
136 {
137 /* no memory */
138 FreeFunction(SampleRateBuffer);
139 return STATUS_INSUFFICIENT_RESOURCES;
140 }
141
142 /* format urb */
143 UsbBuildVendorRequest(Urb,
144 URB_FUNCTION_CLASS_ENDPOINT,
145 sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
146 USBD_TRANSFER_DIRECTION_OUT,
147 0,
148 0x01,
149 0x100,
150 0x81, //FIXME bEndpointAddress
151 SampleRateBuffer,
152 NULL,
153 3,
154 NULL);
155
156 /* get pin context */
157 PinContext = Pin->Context;
158
159 /* submit urb */
160 Status = SubmitUrbSync(PinContext->LowerDevice, Urb);
161
162 DPRINT1("USBAudioPinSetDataFormat Pin %p Status %x\n", Pin, Status);
163 FreeFunction(Urb);
164 FreeFunction(SampleRateBuffer);
165 return Status;
166 }
167
168 NTSTATUS
169 USBAudioSelectAudioStreamingInterface(
170 IN PPIN_CONTEXT PinContext,
171 IN PDEVICE_EXTENSION DeviceExtension,
172 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
173 {
174 PURB Urb;
175 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
176 NTSTATUS Status;
177
178 /* grab interface descriptor */
179 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
180 if (!InterfaceDescriptor)
181 {
182 /* no such interface */
183 return STATUS_INVALID_PARAMETER;
184 }
185
186 /* FIXME selects the first interface with audio streaming and non zero num of endpoints */
187 while (InterfaceDescriptor != NULL)
188 {
189 if (InterfaceDescriptor->bInterfaceSubClass == 0x02 /* AUDIO_STREAMING */ && InterfaceDescriptor->bNumEndpoints > 0)
190 {
191 break;
192 }
193 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
194 }
195
196 if (!InterfaceDescriptor)
197 {
198 /* no such interface */
199 return STATUS_INVALID_PARAMETER;
200 }
201
202 Urb = AllocFunction(GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints));
203 if (!Urb)
204 {
205 /* no memory */
206 return USBD_STATUS_INSUFFICIENT_RESOURCES;
207 }
208
209 /* now prepare interface urb */
210 UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting);
211
212 /* now select the interface */
213 Status = SubmitUrbSync(DeviceExtension->LowerDevice, Urb);
214
215 DPRINT1("USBAudioSelectAudioStreamingInterface Status %x UrbStatus %x\n", Status, Urb->UrbSelectInterface.Hdr.Status);
216
217 /* did it succeeed */
218 if (NT_SUCCESS(Status))
219 {
220 /* free old interface info */
221 if (DeviceExtension->InterfaceInfo)
222 {
223 /* free old info */
224 FreeFunction(DeviceExtension->InterfaceInfo);
225 }
226
227 /* alloc interface info */
228 DeviceExtension->InterfaceInfo = AllocFunction(Urb->UrbSelectInterface.Interface.Length);
229 if (DeviceExtension->InterfaceInfo == NULL)
230 {
231 /* no memory */
232 FreeFunction(Urb);
233 return STATUS_INSUFFICIENT_RESOURCES;
234 }
235
236 /* copy interface info */
237 RtlCopyMemory(DeviceExtension->InterfaceInfo, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
238 PinContext->InterfaceDescriptor = InterfaceDescriptor;
239 }
240
241 /* free urb */
242 FreeFunction(Urb);
243 return Status;
244 }
245
246 NTSTATUS
247 InitCapturePin(
248 IN PKSPIN Pin)
249 {
250 NTSTATUS Status;
251 ULONG Index;
252 ULONG BufferSize;
253 ULONG MaximumPacketSize;
254 PIRP Irp;
255 PURB Urb;
256 PPIN_CONTEXT PinContext;
257 PIO_STACK_LOCATION IoStack;
258 PKSALLOCATOR_FRAMING_EX Framing;
259
260 /* set sample rate */
261 Status = UsbAudioSetFormat(Pin);
262 if (!NT_SUCCESS(Status))
263 {
264 /* failed */
265 return Status;
266 }
267
268 /* get pin context */
269 PinContext = Pin->Context;
270
271 /* lets get maximum packet size */
272 MaximumPacketSize = GetMaxPacketSizeForInterface(PinContext->DeviceExtension->ConfigurationDescriptor, PinContext->InterfaceDescriptor, Pin->DataFlow);
273
274 /* lets edit framing struct */
275 Framing = (PKSALLOCATOR_FRAMING_EX)Pin->Descriptor->AllocatorFraming;
276 Framing->FramingItem[0].PhysicalRange.MinFrameSize =
277 Framing->FramingItem[0].PhysicalRange.MaxFrameSize =
278 Framing->FramingItem[0].FramingRange.Range.MinFrameSize =
279 Framing->FramingItem[0].FramingRange.Range.MaxFrameSize =
280 MaximumPacketSize;
281
282 /* calculate buffer size 8 irps * 10 iso packets * max packet size */
283 BufferSize = 8 * 10 * MaximumPacketSize;
284
285 /* allocate pin capture buffer */
286 PinContext->Buffer = AllocFunction(BufferSize);
287 if (!PinContext->Buffer)
288 {
289 /* no memory */
290 return STATUS_INSUFFICIENT_RESOURCES;
291 }
292 KsAddItemToObjectBag(Pin->Bag, PinContext->Buffer, ExFreePool);
293
294 /* init irps */
295 for (Index = 0; Index < 8; Index++)
296 {
297 /* allocate irp */
298 Irp = IoAllocateIrp(PinContext->DeviceExtension->LowerDevice->StackSize, FALSE);
299 if (!Irp)
300 {
301 /* no memory */
302 return STATUS_INSUFFICIENT_RESOURCES;
303 }
304
305 DPRINT1("InitCapturePin Irp %p\n", Irp);
306 /* insert into irp list */
307 InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
308
309 /* add to object bag*/
310 KsAddItemToObjectBag(Pin->Bag, Irp, IoFreeIrp);
311
312 /* FIXME select correct pipe handle */
313 Status = UsbAudioAllocCaptureUrbIso(PinContext->DeviceExtension->InterfaceInfo->Pipes[0].PipeHandle,
314 MaximumPacketSize,
315 &PinContext->Buffer[MaximumPacketSize * 10 * Index],
316 MaximumPacketSize * 10,
317 &Urb);
318
319 if (NT_SUCCESS(Status))
320 {
321 /* get next stack location */
322 IoStack = IoGetNextIrpStackLocation(Irp);
323
324 /* store urb */
325 IoStack->Parameters.Others.Argument1 = Urb;
326 Irp->Tail.Overlay.DriverContext[0] = Urb;
327 }
328 else
329 {
330 /* failed */
331 return Status;
332 }
333 }
334 return Status;
335 }
336
337 NTSTATUS
338 InitStreamPin(
339 IN PKSPIN Pin)
340 {
341 UNIMPLEMENTED
342 return STATUS_NOT_IMPLEMENTED;
343 }
344
345
346 NTSTATUS
347 NTAPI
348 USBAudioPinCreate(
349 _In_ PKSPIN Pin,
350 _In_ PIRP Irp)
351 {
352 PKSFILTER Filter;
353 PFILTER_CONTEXT FilterContext;
354 PPIN_CONTEXT PinContext;
355 NTSTATUS Status;
356
357 Filter = KsPinGetParentFilter(Pin);
358 if (Filter == NULL)
359 {
360 /* invalid parameter */
361 return STATUS_INVALID_PARAMETER;
362 }
363
364 /* get filter context */
365 FilterContext = Filter->Context;
366
367 /* allocate pin context */
368 PinContext = AllocFunction(sizeof(PIN_CONTEXT));
369 if (!PinContext)
370 {
371 /* no memory*/
372 return STATUS_INSUFFICIENT_RESOURCES;
373 }
374
375 /* init pin context */
376 PinContext->DeviceExtension = FilterContext->DeviceExtension;
377 PinContext->LowerDevice = FilterContext->LowerDevice;
378 InitializeListHead(&PinContext->IrpListHead);
379 InitializeListHead(&PinContext->DoneIrpListHead);
380 KeInitializeSpinLock(&PinContext->IrpListLock);
381
382 /* store pin context*/
383 Pin->Context = PinContext;
384
385 /* lets edit allocator framing struct */
386 Status = _KsEdit(Pin->Bag, &Pin->Descriptor, sizeof(KSPIN_DESCRIPTOR_EX), sizeof(KSPIN_DESCRIPTOR_EX), USBAUDIO_TAG);
387 if (NT_SUCCESS(Status))
388 {
389 Status = _KsEdit(Pin->Bag, &Pin->Descriptor->AllocatorFraming, sizeof(KSALLOCATOR_FRAMING_EX), sizeof(KSALLOCATOR_FRAMING_EX), USBAUDIO_TAG);
390 ASSERT(Status == STATUS_SUCCESS);
391 }
392
393
394 /* select streaming interface */
395 Status = USBAudioSelectAudioStreamingInterface(PinContext, PinContext->DeviceExtension, PinContext->DeviceExtension->ConfigurationDescriptor);
396 if (!NT_SUCCESS(Status))
397 {
398 /* failed */
399 return Status;
400 }
401
402 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
403 {
404 /* init capture pin */
405 Status = InitCapturePin(Pin);
406 }
407 else
408 {
409 /* audio streaming pin*/
410 Status = InitStreamPin(Pin);
411 }
412
413 return STATUS_SUCCESS;
414 }
415
416 NTSTATUS
417 NTAPI
418 USBAudioPinClose(
419 _In_ PKSPIN Pin,
420 _In_ PIRP Irp)
421 {
422 UNIMPLEMENTED
423 return STATUS_NOT_IMPLEMENTED;
424 }
425
426 NTSTATUS
427 NTAPI
428 UsbAudioCaptureComplete(
429 IN PDEVICE_OBJECT DeviceObject,
430 IN PIRP Irp,
431 IN PVOID Context)
432 {
433 PKSPIN Pin;
434 PPIN_CONTEXT PinContext;
435 KIRQL OldLevel;
436
437 /* get pin context */
438 Pin = Context;
439 PinContext = Pin->Context;
440
441 /* acquire lock */
442 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
443
444 /* insert entry into done list */
445 InsertTailList(&PinContext->DoneIrpListHead, &Irp->Tail.Overlay.ListEntry);
446
447 /* release lock */
448 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
449
450 DPRINT1("UsbAudioCaptureComplete Irp %p\n", Irp);
451
452 /* done */
453 return STATUS_MORE_PROCESSING_REQUIRED;
454 }
455
456 NTSTATUS
457 PinCaptureProcess(
458 IN PKSPIN Pin)
459 {
460 PKSSTREAM_POINTER LeadingStreamPointer;
461 KIRQL OldLevel;
462 PPIN_CONTEXT PinContext;
463 PLIST_ENTRY CurEntry;
464 PIRP Irp;
465 PIO_STACK_LOCATION IoStack;
466 PURB Urb;
467 PUCHAR TransferBuffer;
468 ULONG Index, Offset;
469
470 LeadingStreamPointer = KsPinGetLeadingEdgeStreamPointer(Pin, KSSTREAM_POINTER_STATE_LOCKED);
471 if (LeadingStreamPointer == NULL)
472 return STATUS_SUCCESS;
473
474 /* get pin context */
475 PinContext = Pin->Context;
476
477 /* acquire spin lock */
478 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
479
480 while (!IsListEmpty(&PinContext->DoneIrpListHead))
481 {
482 /* remove entry from list */
483 CurEntry = RemoveHeadList(&PinContext->DoneIrpListHead);
484
485 /* release lock */
486 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
487
488 /* get irp offset */
489 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
490
491 /* get urb from irp */
492 IoStack = IoGetNextIrpStackLocation(Irp);
493 Urb = (PURB)Irp->Tail.Overlay.DriverContext[0];
494 ASSERT(Urb);
495
496 Offset = 0;
497 for (Index = 0; Index < Urb->UrbIsochronousTransfer.NumberOfPackets; Index++)
498 {
499 /* add offset */
500 Offset += Urb->UrbIsochronousTransfer.IsoPacket[Index].Offset;
501
502 /* get transfer buffer */
503 TransferBuffer = Urb->UrbIsochronousTransfer.TransferBuffer;
504
505 /* copy data */
506 if (LeadingStreamPointer->OffsetOut.Remaining >= Urb->UrbIsochronousTransfer.IsoPacket[Index].Length)
507 {
508 /* copy buffer */
509 RtlCopyMemory((PUCHAR)LeadingStreamPointer->OffsetOut.Data, &TransferBuffer[Offset], Urb->UrbIsochronousTransfer.IsoPacket[Index].Length);
510 }
511 else
512 {
513 /* advance to next frame */
514 KsStreamPointerAdvanceOffsetsAndUnlock(LeadingStreamPointer, 0, 0, TRUE);
515 LeadingStreamPointer = KsPinGetLeadingEdgeStreamPointer(Pin, KSSTREAM_POINTER_STATE_LOCKED);
516 if (LeadingStreamPointer == NULL)
517 {
518 /* FIXME handle half processed packets */
519 //ASSERT(FALSE);
520 break;
521 }
522
523 ASSERT(LeadingStreamPointer->OffsetOut.Remaining >= Urb->UrbIsochronousTransfer.IsoPacket[Index].Length);
524
525 /* copy buffer */
526 RtlCopyMemory((PUCHAR)LeadingStreamPointer->OffsetOut.Data, &TransferBuffer[Offset], Urb->UrbIsochronousTransfer.IsoPacket[Index].Length);
527 }
528
529 if (LeadingStreamPointer->OffsetOut.Remaining == Urb->UrbIsochronousTransfer.IsoPacket[Index].Length)
530 {
531 KsStreamPointerAdvanceOffsetsAndUnlock(LeadingStreamPointer, 0, Urb->UrbIsochronousTransfer.IsoPacket[Index].Length, TRUE);
532 LeadingStreamPointer = KsPinGetLeadingEdgeStreamPointer(Pin, KSSTREAM_POINTER_STATE_LOCKED);
533 if (LeadingStreamPointer == NULL)
534 break;
535 }
536 else
537 {
538 KsStreamPointerAdvanceOffsets(LeadingStreamPointer, 0, Urb->UrbIsochronousTransfer.IsoPacket[Index].Length, FALSE);
539 }
540 }
541
542 /* acquire spin lock */
543 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
544
545 /* get next stack location */
546 IoStack = IoGetNextIrpStackLocation(Irp);
547
548 /* init stack location */
549 IoStack->Parameters.Others.Argument1 = Urb;
550 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
551 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
552
553 IoSetCompletionRoutine(Irp, UsbAudioCaptureComplete, Pin, TRUE, TRUE, TRUE);
554
555 InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
556
557 if (LeadingStreamPointer == NULL)
558 break;
559 }
560
561 while (!IsListEmpty(&PinContext->IrpListHead))
562 {
563 /* remove entry from list */
564 CurEntry = RemoveHeadList(&PinContext->IrpListHead);
565
566 /* get irp offset */
567 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
568
569 /* get next stack location */
570 IoStack = IoGetNextIrpStackLocation(Irp);
571
572 /* init stack location */
573 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
574 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
575
576 IoSetCompletionRoutine(Irp, UsbAudioCaptureComplete, Pin, TRUE, TRUE, TRUE);
577
578 /* release lock */
579 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
580
581 DPRINT1("PinCaptureProcess Irp %p\n", Irp);
582 IoCallDriver(PinContext->DeviceExtension->LowerDevice, Irp);
583
584 /* acquire spin lock */
585 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
586
587 }
588
589 /* release lock */
590 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
591
592 if (LeadingStreamPointer != NULL)
593 KsStreamPointerUnlock(LeadingStreamPointer, FALSE);
594
595 return STATUS_SUCCESS;
596 }
597
598
599 NTSTATUS
600 NTAPI
601 USBAudioPinProcess(
602 _In_ PKSPIN Pin)
603 {
604 NTSTATUS Status;
605
606 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
607 {
608 Status = PinCaptureProcess(Pin);
609 }
610 else
611 {
612 UNIMPLEMENTED;
613 Status = STATUS_NOT_IMPLEMENTED;
614 }
615
616 return Status;
617 }
618
619
620 VOID
621 NTAPI
622 USBAudioPinReset(
623 _In_ PKSPIN Pin)
624 {
625 UNIMPLEMENTED
626 }
627
628 NTSTATUS
629 NTAPI
630 USBAudioPinSetDataFormat(
631 _In_ PKSPIN Pin,
632 _In_opt_ PKSDATAFORMAT OldFormat,
633 _In_opt_ PKSMULTIPLE_ITEM OldAttributeList,
634 _In_ const KSDATARANGE* DataRange,
635 _In_opt_ const KSATTRIBUTE_LIST* AttributeRange)
636 {
637 if (OldFormat == NULL)
638 {
639 /* TODO: verify connection format */
640 UNIMPLEMENTED
641 return STATUS_SUCCESS;
642 }
643
644 return UsbAudioSetFormat(Pin);
645 }
646
647 NTSTATUS
648 StartCaptureIsocTransfer(
649 IN PKSPIN Pin)
650 {
651 PPIN_CONTEXT PinContext;
652 PLIST_ENTRY CurEntry;
653 PIRP Irp;
654 PIO_STACK_LOCATION IoStack;
655 NTSTATUS Status;
656 KIRQL OldLevel;
657
658 /* get pin context */
659 PinContext = Pin->Context;
660
661 /* acquire spin lock */
662 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
663
664 while(!IsListEmpty(&PinContext->IrpListHead))
665 {
666 /* remove entry from list */
667 CurEntry = RemoveHeadList(&PinContext->IrpListHead);
668
669 /* get irp offset */
670 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
671
672
673 /* get next stack location */
674 IoStack = IoGetNextIrpStackLocation(Irp);
675
676 /* init stack location */
677 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
678 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
679
680 IoSetCompletionRoutine(Irp, UsbAudioCaptureComplete, Pin, TRUE, TRUE, TRUE);
681
682 /* release lock */
683 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
684
685 DPRINT1("StartCaptureIsocTransfer Irp %p\n", Irp);
686 Status = IoCallDriver(PinContext->DeviceExtension->LowerDevice, Irp);
687
688 /* acquire spin lock */
689 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
690
691 }
692
693 /* release lock */
694 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
695
696 return STATUS_SUCCESS;
697 }
698
699 NTSTATUS
700 CapturePinStateChange(
701 _In_ PKSPIN Pin,
702 _In_ KSSTATE ToState,
703 _In_ KSSTATE FromState)
704 {
705 NTSTATUS Status;
706
707 if (FromState != ToState)
708 {
709 if (ToState)
710 {
711 if (ToState == KSSTATE_PAUSE)
712 {
713 if (FromState == KSSTATE_RUN)
714 {
715 /* wait until pin processing is finished*/
716 }
717 }
718 else
719 {
720 if (ToState == KSSTATE_RUN)
721 {
722 Status = StartCaptureIsocTransfer(Pin);
723 }
724 }
725 }
726 }
727 return Status;
728 }
729
730
731 NTSTATUS
732 NTAPI
733 USBAudioPinSetDeviceState(
734 _In_ PKSPIN Pin,
735 _In_ KSSTATE ToState,
736 _In_ KSSTATE FromState)
737 {
738 NTSTATUS Status;
739
740 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
741 {
742 /* handle capture state changes */
743 Status = CapturePinStateChange(Pin, ToState, FromState);
744 }
745 else
746 {
747 UNIMPLEMENTED
748 Status = STATUS_NOT_IMPLEMENTED;
749 }
750
751 return Status;
752 }