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