daba4c477dbea77c59b1ef65edbb3ba77951a761
[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 #define PACKET_COUNT 10
13
14
15 NTSTATUS
16 GetMaxPacketSizeForInterface(
17 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
18 IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
19 KSPIN_DATAFLOW DataFlow)
20 {
21 PUSB_COMMON_DESCRIPTOR CommonDescriptor;
22 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
23
24 /* loop descriptors */
25 CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
26 ASSERT(InterfaceDescriptor->bNumEndpoints > 0);
27 while (CommonDescriptor)
28 {
29 if (CommonDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)
30 {
31 EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)CommonDescriptor;
32 return EndpointDescriptor->wMaxPacketSize;
33 }
34
35 if (CommonDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
36 {
37 /* reached next interface descriptor */
38 break;
39 }
40
41 if ((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
42 break;
43
44 CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
45 }
46
47 /* default to 100 */
48 return 100;
49 }
50
51 NTSTATUS
52 UsbAudioAllocCaptureUrbIso(
53 IN USBD_PIPE_HANDLE PipeHandle,
54 IN ULONG MaxPacketSize,
55 IN PVOID Buffer,
56 IN ULONG BufferLength,
57 OUT PURB * OutUrb)
58 {
59 PURB Urb;
60 ULONG UrbSize;
61 ULONG Index;
62
63 /* calculate urb size*/
64 UrbSize = GET_ISO_URB_SIZE(PACKET_COUNT);
65
66 /* allocate urb */
67 Urb = AllocFunction(UrbSize);
68 if (!Urb)
69 {
70 /* no memory */
71 return STATUS_INSUFFICIENT_RESOURCES;
72 }
73
74 /* init urb */
75 Urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
76 Urb->UrbIsochronousTransfer.Hdr.Length = UrbSize;
77 Urb->UrbIsochronousTransfer.PipeHandle = PipeHandle;
78 Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_START_ISO_TRANSFER_ASAP;
79 Urb->UrbIsochronousTransfer.TransferBufferLength = BufferLength;
80 Urb->UrbIsochronousTransfer.TransferBuffer = Buffer;
81 Urb->UrbIsochronousTransfer.NumberOfPackets = PACKET_COUNT;
82
83 for (Index = 0; Index < PACKET_COUNT; Index++)
84 {
85 Urb->UrbIsochronousTransfer.IsoPacket[Index].Offset = Index * MaxPacketSize;
86 }
87
88 *OutUrb = Urb;
89 return STATUS_SUCCESS;
90
91 }
92
93 NTSTATUS
94 UsbAudioSetVolume(
95 IN PKSPIN Pin)
96 {
97 PURB Urb;
98 PUCHAR SampleRateBuffer;
99 PPIN_CONTEXT PinContext;
100 NTSTATUS Status;
101
102 /* allocate sample rate buffer */
103 SampleRateBuffer = AllocFunction(sizeof(ULONG));
104 if (!SampleRateBuffer)
105 {
106 /* no memory */
107 return STATUS_INSUFFICIENT_RESOURCES;
108 }
109
110 /* allocate urb */
111 Urb = AllocFunction(sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
112 if (!Urb)
113 {
114 /* no memory */
115 FreeFunction(SampleRateBuffer);
116 return STATUS_INSUFFICIENT_RESOURCES;
117 }
118
119 /* FIXME: determine controls and format urb */
120 UsbBuildVendorRequest(Urb,
121 URB_FUNCTION_CLASS_INTERFACE,
122 sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
123 USBD_TRANSFER_DIRECTION_OUT,
124 0,
125 0x01,
126 0x200,
127 0x300,
128 SampleRateBuffer,
129 NULL,
130 2,
131 NULL);
132
133 /* get pin context */
134 PinContext = Pin->Context;
135
136 SampleRateBuffer[0] = 0xC2;
137 SampleRateBuffer[1] = 0xFE;
138
139 /* submit urb */
140 Status = SubmitUrbSync(PinContext->LowerDevice, Urb);
141
142 DPRINT1("UsbAudioSetVolume Pin %p Status %x\n", Pin, Status);
143 FreeFunction(Urb);
144 FreeFunction(SampleRateBuffer);
145 return Status;
146 }
147
148 NTSTATUS
149 UsbAudioSetFormat(
150 IN PKSPIN Pin)
151 {
152 PURB Urb;
153 PUCHAR SampleRateBuffer;
154 PPIN_CONTEXT PinContext;
155 NTSTATUS Status;
156 PKSDATAFORMAT_WAVEFORMATEX WaveFormatEx;
157
158 /* allocate sample rate buffer */
159 SampleRateBuffer = AllocFunction(sizeof(ULONG));
160 if (!SampleRateBuffer)
161 {
162 /* no memory */
163 return STATUS_INSUFFICIENT_RESOURCES;
164 }
165
166 if (IsEqualGUIDAligned(&Pin->ConnectionFormat->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
167 IsEqualGUIDAligned(&Pin->ConnectionFormat->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
168 IsEqualGUIDAligned(&Pin->ConnectionFormat->Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
169 {
170 WaveFormatEx = (PKSDATAFORMAT_WAVEFORMATEX)Pin->ConnectionFormat;
171 SampleRateBuffer[2] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 16) & 0xFF;
172 SampleRateBuffer[1] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 8) & 0xFF;
173 SampleRateBuffer[0] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 0) & 0xFF;
174
175 /* TODO: verify connection format */
176 }
177 else
178 {
179 /* not supported yet*/
180 UNIMPLEMENTED;
181 FreeFunction(SampleRateBuffer);
182 return STATUS_INVALID_PARAMETER;
183 }
184
185 /* allocate urb */
186 Urb = AllocFunction(sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
187 if (!Urb)
188 {
189 /* no memory */
190 FreeFunction(SampleRateBuffer);
191 return STATUS_INSUFFICIENT_RESOURCES;
192 }
193
194 /* FIXME: determine controls and format urb */
195 UsbBuildVendorRequest(Urb,
196 URB_FUNCTION_CLASS_ENDPOINT,
197 sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
198 USBD_TRANSFER_DIRECTION_OUT,
199 0,
200 0x01, // SET_CUR
201 0x100,
202 0x81, //FIXME bEndpointAddress
203 SampleRateBuffer,
204 NULL,
205 3,
206 NULL);
207
208 /* get pin context */
209 PinContext = Pin->Context;
210
211 /* submit urb */
212 Status = SubmitUrbSync(PinContext->LowerDevice, Urb);
213
214 DPRINT1("USBAudioPinSetDataFormat Pin %p Status %x\n", Pin, Status);
215 FreeFunction(Urb);
216 FreeFunction(SampleRateBuffer);
217 return Status;
218 }
219
220 NTSTATUS
221 USBAudioSelectAudioStreamingInterface(
222 IN PPIN_CONTEXT PinContext,
223 IN PDEVICE_EXTENSION DeviceExtension,
224 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
225 {
226 PURB Urb;
227 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
228 NTSTATUS Status;
229
230 /* grab interface descriptor */
231 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
232 if (!InterfaceDescriptor)
233 {
234 /* no such interface */
235 return STATUS_INVALID_PARAMETER;
236 }
237
238 /* FIXME selects the first interface with audio streaming and non zero num of endpoints */
239 while (InterfaceDescriptor != NULL)
240 {
241 if (InterfaceDescriptor->bInterfaceSubClass == 0x02 /* AUDIO_STREAMING */ && InterfaceDescriptor->bNumEndpoints > 0)
242 {
243 break;
244 }
245 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
246 }
247
248 if (!InterfaceDescriptor)
249 {
250 /* no such interface */
251 return STATUS_INVALID_PARAMETER;
252 }
253
254 Urb = AllocFunction(GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints));
255 if (!Urb)
256 {
257 /* no memory */
258 return USBD_STATUS_INSUFFICIENT_RESOURCES;
259 }
260
261 /* now prepare interface urb */
262 UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting);
263
264 /* now select the interface */
265 Status = SubmitUrbSync(DeviceExtension->LowerDevice, Urb);
266
267 DPRINT1("USBAudioSelectAudioStreamingInterface Status %x UrbStatus %x\n", Status, Urb->UrbSelectInterface.Hdr.Status);
268
269 /* did it succeeed */
270 if (NT_SUCCESS(Status))
271 {
272 /* free old interface info */
273 if (DeviceExtension->InterfaceInfo)
274 {
275 /* free old info */
276 FreeFunction(DeviceExtension->InterfaceInfo);
277 }
278
279 /* alloc interface info */
280 DeviceExtension->InterfaceInfo = AllocFunction(Urb->UrbSelectInterface.Interface.Length);
281 if (DeviceExtension->InterfaceInfo == NULL)
282 {
283 /* no memory */
284 FreeFunction(Urb);
285 return STATUS_INSUFFICIENT_RESOURCES;
286 }
287
288 /* copy interface info */
289 RtlCopyMemory(DeviceExtension->InterfaceInfo, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
290 PinContext->InterfaceDescriptor = InterfaceDescriptor;
291 }
292
293 /* free urb */
294 FreeFunction(Urb);
295 return Status;
296 }
297
298 VOID
299 NTAPI
300 CaptureGateOnWorkItem(
301 _In_ PVOID Context)
302 {
303 PKSPIN Pin;
304 PPIN_CONTEXT PinContext;
305 PKSGATE Gate;
306 ULONG Count;
307
308 /* get pin */
309 Pin = Context;
310
311 /* get pin context */
312 PinContext = Pin->Context;
313
314 do
315 {
316 /* acquire processing mutex */
317 KsPinAcquireProcessingMutex(Pin);
318
319 /* get pin control gate */
320 Gate = KsPinGetAndGate(Pin);
321
322 /* turn input on */
323 KsGateTurnInputOn(Gate);
324
325 /* schedule processing */
326 KsPinAttemptProcessing(Pin, TRUE);
327
328 /* release processing mutex */
329 KsPinReleaseProcessingMutex(Pin);
330
331 /* decrement worker count */
332 Count = KsDecrementCountedWorker(PinContext->CaptureWorker);
333 } while (Count);
334 }
335
336
337
338 VOID
339 CaptureInitializeUrbAndIrp(
340 IN PKSPIN Pin,
341 IN PIRP Irp)
342 {
343 PIO_STACK_LOCATION IoStack;
344 PURB Urb;
345 PUCHAR TransferBuffer;
346 ULONG Index;
347 PPIN_CONTEXT PinContext;
348
349 /* get pin context */
350 PinContext = Pin->Context;
351
352 /* backup urb and transferbuffer */
353 Urb = Irp->Tail.Overlay.DriverContext[0];
354 TransferBuffer = Urb->UrbIsochronousTransfer.TransferBuffer;
355
356 /* initialize irp */
357 IoInitializeIrp(Irp, IoSizeOfIrp(PinContext->DeviceExtension->LowerDevice->StackSize), PinContext->DeviceExtension->LowerDevice->StackSize);
358
359 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
360 Irp->IoStatus.Information = 0;
361 Irp->Flags = 0;
362 Irp->UserBuffer = NULL;
363 Irp->Tail.Overlay.DriverContext[0] = Urb;
364 Irp->Tail.Overlay.DriverContext[1] = NULL;
365
366 /* init stack location */
367 IoStack = IoGetNextIrpStackLocation(Irp);
368 IoStack->DeviceObject = PinContext->DeviceExtension->LowerDevice;
369 IoStack->Parameters.Others.Argument1 = Urb;
370 IoStack->Parameters.Others.Argument2 = NULL;
371 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
372 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
373
374 IoSetCompletionRoutine(Irp, UsbAudioCaptureComplete, Pin, TRUE, TRUE, TRUE);
375
376 RtlZeroMemory(Urb, GET_ISO_URB_SIZE(PACKET_COUNT));
377
378 /* init urb */
379 Urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
380 Urb->UrbIsochronousTransfer.Hdr.Length = GET_ISO_URB_SIZE(10);
381 Urb->UrbIsochronousTransfer.PipeHandle = PinContext->DeviceExtension->InterfaceInfo->Pipes[0].PipeHandle;
382 Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_START_ISO_TRANSFER_ASAP;
383 Urb->UrbIsochronousTransfer.TransferBufferLength = PinContext->DeviceExtension->InterfaceInfo->Pipes[0].MaximumPacketSize * 10;
384 Urb->UrbIsochronousTransfer.TransferBuffer = TransferBuffer;
385 Urb->UrbIsochronousTransfer.NumberOfPackets = PACKET_COUNT;
386 Urb->UrbIsochronousTransfer.StartFrame = 0;
387
388 for (Index = 0; Index < PACKET_COUNT; Index++)
389 {
390 Urb->UrbIsochronousTransfer.IsoPacket[Index].Offset = Index * PinContext->DeviceExtension->InterfaceInfo->Pipes[0].MaximumPacketSize;
391 }
392 }
393
394
395 VOID
396 NTAPI
397 CaptureAvoidPipeStarvationWorker(
398 _In_ PVOID Context)
399 {
400 PKSPIN Pin;
401 PPIN_CONTEXT PinContext;
402 KIRQL OldLevel;
403 PLIST_ENTRY CurEntry;
404 PIRP Irp;
405
406 /* get pin */
407 Pin = Context;
408
409 /* get pin context */
410 PinContext = Pin->Context;
411
412 /* acquire spin lock */
413 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
414
415 if (!IsListEmpty(&PinContext->IrpListHead))
416 {
417 /* sanity check */
418 ASSERT(!IsListEmpty(&PinContext->IrpListHead));
419
420 /* remove entry from list */
421 CurEntry = RemoveHeadList(&PinContext->IrpListHead);
422
423 /* release lock */
424 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
425
426 /* get irp offset */
427 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
428
429 /* reinitialize irp and urb */
430 CaptureInitializeUrbAndIrp(Pin, Irp);
431
432 KsDecrementCountedWorker(PinContext->StarvationWorker);
433
434 /* call driver */
435 IoCallDriver(PinContext->DeviceExtension->LowerDevice, Irp);
436 }
437 else
438 {
439 /* release lock */
440 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
441
442 KsDecrementCountedWorker(PinContext->StarvationWorker);
443 }
444 }
445
446
447
448 NTSTATUS
449 InitCapturePin(
450 IN PKSPIN Pin)
451 {
452 NTSTATUS Status;
453 ULONG Index;
454 ULONG BufferSize;
455 ULONG MaximumPacketSize;
456 PIRP Irp;
457 PURB Urb;
458 PPIN_CONTEXT PinContext;
459 PIO_STACK_LOCATION IoStack;
460 PKSALLOCATOR_FRAMING_EX Framing;
461 PKSGATE Gate;
462
463
464 /* set sample rate */
465 Status = UsbAudioSetFormat(Pin);
466 if (!NT_SUCCESS(Status))
467 {
468 /* failed */
469 return Status;
470 }
471
472 /* get pin context */
473 PinContext = Pin->Context;
474
475 /* lets get maximum packet size */
476 MaximumPacketSize = GetMaxPacketSizeForInterface(PinContext->DeviceExtension->ConfigurationDescriptor, PinContext->InterfaceDescriptor, Pin->DataFlow);
477
478 /* initialize work item for capture worker */
479 ExInitializeWorkItem(&PinContext->CaptureWorkItem, CaptureGateOnWorkItem, (PVOID)Pin);
480
481 /* register worker */
482 Status = KsRegisterCountedWorker(CriticalWorkQueue, &PinContext->CaptureWorkItem, &PinContext->CaptureWorker);
483 if (!NT_SUCCESS(Status))
484 {
485 /* failed */
486 return Status;
487 }
488
489 /* initialize work item */
490 ExInitializeWorkItem(&PinContext->StarvationWorkItem, CaptureAvoidPipeStarvationWorker, (PVOID)Pin);
491
492 /* register worker */
493 Status = KsRegisterCountedWorker(CriticalWorkQueue, &PinContext->StarvationWorkItem, &PinContext->StarvationWorker);
494 if (!NT_SUCCESS(Status))
495 {
496 /* failed */
497 KsUnregisterWorker(PinContext->CaptureWorker);
498 }
499
500 /* lets edit framing struct */
501 Framing = (PKSALLOCATOR_FRAMING_EX)Pin->Descriptor->AllocatorFraming;
502 Framing->FramingItem[0].PhysicalRange.MinFrameSize =
503 Framing->FramingItem[0].PhysicalRange.MaxFrameSize =
504 Framing->FramingItem[0].FramingRange.Range.MinFrameSize =
505 Framing->FramingItem[0].FramingRange.Range.MaxFrameSize =
506 MaximumPacketSize;
507
508 /* calculate buffer size 8 irps * 10 iso packets * max packet size */
509 BufferSize = 8 * PACKET_COUNT * MaximumPacketSize;
510
511 /* allocate pin capture buffer */
512 PinContext->BufferSize = BufferSize;
513 PinContext->Buffer = AllocFunction(BufferSize);
514 if (!PinContext->Buffer)
515 {
516 /* no memory */
517 return STATUS_INSUFFICIENT_RESOURCES;
518 }
519 KsAddItemToObjectBag(Pin->Bag, PinContext->Buffer, ExFreePool);
520
521 /* init irps */
522 for (Index = 0; Index < 8; Index++)
523 {
524 /* allocate irp */
525 Irp = AllocFunction(IoSizeOfIrp(PinContext->DeviceExtension->LowerDevice->StackSize));
526 if (!Irp)
527 {
528 /* no memory */
529 return STATUS_INSUFFICIENT_RESOURCES;
530 }
531
532 /* initialize irp */
533 IoInitializeIrp(Irp, IoSizeOfIrp(PinContext->DeviceExtension->LowerDevice->StackSize), PinContext->DeviceExtension->LowerDevice->StackSize);
534
535 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
536 Irp->IoStatus.Information = 0;
537 Irp->Flags = 0;
538 Irp->UserBuffer = NULL;
539
540 IoStack = IoGetNextIrpStackLocation(Irp);
541 IoStack->DeviceObject = PinContext->DeviceExtension->LowerDevice;
542 IoStack->Parameters.Others.Argument2 = NULL;
543 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
544 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
545
546 IoSetCompletionRoutine(Irp, UsbAudioCaptureComplete, Pin, TRUE, TRUE, TRUE);
547
548 /* insert into irp list */
549 InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
550
551 /* add to object bag*/
552 KsAddItemToObjectBag(Pin->Bag, Irp, ExFreePool);
553
554 /* FIXME select correct pipe handle */
555 Status = UsbAudioAllocCaptureUrbIso(PinContext->DeviceExtension->InterfaceInfo->Pipes[0].PipeHandle,
556 MaximumPacketSize,
557 &PinContext->Buffer[MaximumPacketSize * PACKET_COUNT * Index],
558 MaximumPacketSize * PACKET_COUNT,
559 &Urb);
560
561 DPRINT1("InitCapturePin Irp %p Urb %p\n", Irp, Urb);
562
563 if (NT_SUCCESS(Status))
564 {
565 /* get next stack location */
566 IoStack = IoGetNextIrpStackLocation(Irp);
567
568 /* store urb */
569 IoStack->Parameters.Others.Argument1 = Urb;
570 Irp->Tail.Overlay.DriverContext[0] = Urb;
571 }
572 else
573 {
574 /* failed */
575 return Status;
576 }
577 }
578
579 /* get process control gate */
580 Gate = KsPinGetAndGate(Pin);
581
582 /* turn input off */
583 KsGateTurnInputOff(Gate);
584
585 return Status;
586 }
587
588 NTSTATUS
589 InitStreamPin(
590 IN PKSPIN Pin)
591 {
592 UNIMPLEMENTED
593 return STATUS_NOT_IMPLEMENTED;
594 }
595
596
597
598
599 NTSTATUS
600 NTAPI
601 USBAudioPinCreate(
602 _In_ PKSPIN Pin,
603 _In_ PIRP Irp)
604 {
605 PKSFILTER Filter;
606 PFILTER_CONTEXT FilterContext;
607 PPIN_CONTEXT PinContext;
608 NTSTATUS Status;
609
610 Filter = KsPinGetParentFilter(Pin);
611 if (Filter == NULL)
612 {
613 /* invalid parameter */
614 return STATUS_INVALID_PARAMETER;
615 }
616
617 /* get filter context */
618 FilterContext = Filter->Context;
619
620 /* allocate pin context */
621 PinContext = AllocFunction(sizeof(PIN_CONTEXT));
622 if (!PinContext)
623 {
624 /* no memory*/
625 return STATUS_INSUFFICIENT_RESOURCES;
626 }
627
628 /* init pin context */
629 PinContext->DeviceExtension = FilterContext->DeviceExtension;
630 PinContext->LowerDevice = FilterContext->LowerDevice;
631 InitializeListHead(&PinContext->IrpListHead);
632 InitializeListHead(&PinContext->DoneIrpListHead);
633 KeInitializeSpinLock(&PinContext->IrpListLock);
634
635 /* store pin context*/
636 Pin->Context = PinContext;
637
638 /* lets edit allocator framing struct */
639 Status = _KsEdit(Pin->Bag, (PVOID*)&Pin->Descriptor, sizeof(KSPIN_DESCRIPTOR_EX), sizeof(KSPIN_DESCRIPTOR_EX), USBAUDIO_TAG);
640 if (NT_SUCCESS(Status))
641 {
642 Status = _KsEdit(Pin->Bag, (PVOID*)&Pin->Descriptor->AllocatorFraming, sizeof(KSALLOCATOR_FRAMING_EX), sizeof(KSALLOCATOR_FRAMING_EX), USBAUDIO_TAG);
643 ASSERT(Status == STATUS_SUCCESS);
644 }
645
646 /* FIXME move to build filter topology*/
647 UsbAudioSetVolume(Pin);
648
649 /* select streaming interface */
650 Status = USBAudioSelectAudioStreamingInterface(PinContext, PinContext->DeviceExtension, PinContext->DeviceExtension->ConfigurationDescriptor);
651 if (!NT_SUCCESS(Status))
652 {
653 /* failed */
654 return Status;
655 }
656
657 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
658 {
659 /* init capture pin */
660 Status = InitCapturePin(Pin);
661 }
662 else
663 {
664 /* audio streaming pin*/
665 Status = InitStreamPin(Pin);
666 }
667
668 return STATUS_SUCCESS;
669 }
670
671 NTSTATUS
672 NTAPI
673 USBAudioPinClose(
674 _In_ PKSPIN Pin,
675 _In_ PIRP Irp)
676 {
677 UNIMPLEMENTED
678 return STATUS_NOT_IMPLEMENTED;
679 }
680
681 NTSTATUS
682 NTAPI
683 UsbAudioCaptureComplete(
684 IN PDEVICE_OBJECT DeviceObject,
685 IN PIRP Irp,
686 IN PVOID Context)
687 {
688 PKSPIN Pin;
689 PPIN_CONTEXT PinContext;
690 KIRQL OldLevel;
691 PURB Urb;
692
693 /* get pin context */
694 Pin = Context;
695 PinContext = Pin->Context;
696
697 /* get urb */
698 Urb = Irp->Tail.Overlay.DriverContext[0];
699
700 /* acquire lock */
701 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
702
703 if (!NT_SUCCESS(Urb->UrbIsochronousTransfer.Hdr.Status))
704 {
705 //DPRINT("UsbAudioCaptureComplete Irp %p Urb %p Status %x Packet Status %x\n", Irp, Urb, Urb->UrbIsochronousTransfer.Hdr.Status, Urb->UrbIsochronousTransfer.IsoPacket[0].Status);
706
707 /* insert entry into ready list */
708 InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
709
710 /* release lock */
711 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
712
713 KsIncrementCountedWorker(PinContext->StarvationWorker);
714 }
715 else
716 {
717 /* insert entry into done list */
718 InsertTailList(&PinContext->DoneIrpListHead, &Irp->Tail.Overlay.ListEntry);
719
720 /* release lock */
721 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
722
723 KsIncrementCountedWorker(PinContext->CaptureWorker);
724 }
725
726 /* done */
727 return STATUS_MORE_PROCESSING_REQUIRED;
728 }
729
730 NTSTATUS
731 PinCaptureProcess(
732 IN PKSPIN Pin)
733 {
734 PKSSTREAM_POINTER LeadingStreamPointer;
735 KIRQL OldLevel;
736 PPIN_CONTEXT PinContext;
737 PLIST_ENTRY CurEntry;
738 PIRP Irp;
739 PURB Urb;
740 PUCHAR TransferBuffer, OutBuffer;
741 ULONG Offset, Length;
742 NTSTATUS Status;
743 PKSGATE Gate;
744
745 //DPRINT1("PinCaptureProcess\n");
746 LeadingStreamPointer = KsPinGetLeadingEdgeStreamPointer(Pin, KSSTREAM_POINTER_STATE_LOCKED);
747 if (LeadingStreamPointer == NULL)
748 {
749 /* get process control gate */
750 Gate = KsPinGetAndGate(Pin);
751
752 /* shutdown processing */
753 KsGateTurnInputOff(Gate);
754
755 return STATUS_SUCCESS;
756 }
757
758 /* get pin context */
759 PinContext = Pin->Context;
760
761 /* acquire spin lock */
762 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
763
764 while (!IsListEmpty(&PinContext->DoneIrpListHead))
765 {
766 /* remove entry from list */
767 CurEntry = RemoveHeadList(&PinContext->DoneIrpListHead);
768
769 /* release lock */
770 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
771
772 /* get irp offset */
773 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
774
775 /* get urb from irp */
776 Urb = (PURB)Irp->Tail.Overlay.DriverContext[0];
777 ASSERT(Urb);
778
779 Offset = PtrToUlong(Irp->Tail.Overlay.DriverContext[1]);
780
781 /* get transfer buffer */
782 TransferBuffer = Urb->UrbIsochronousTransfer.TransferBuffer;
783
784 /* get target buffer */
785 OutBuffer = (PUCHAR)LeadingStreamPointer->StreamHeader->Data;
786
787 /* calculate length */
788 Length = min(LeadingStreamPointer->OffsetOut.Count - LeadingStreamPointer->StreamHeader->DataUsed, Urb->UrbIsochronousTransfer.TransferBufferLength - Offset);
789
790 /* FIXME copy each packet extra */
791 /* copy audio bytes */
792 RtlCopyMemory((PUCHAR)&OutBuffer[LeadingStreamPointer->StreamHeader->DataUsed], &TransferBuffer[Offset], Length);
793
794 //DPRINT1("Irp %p Urb %p OutBuffer %p TransferBuffer %p Offset %lu Remaining %lu TransferBufferLength %lu Length %lu\n", Irp, Urb, OutBuffer, TransferBuffer, Offset, LeadingStreamPointer->OffsetOut.Remaining, Urb->UrbIsochronousTransfer.TransferBufferLength, Length);
795
796 /* adjust streampointer */
797 LeadingStreamPointer->StreamHeader->DataUsed += Length;
798
799 if (Length == LeadingStreamPointer->OffsetOut.Remaining)
800 {
801 KsStreamPointerAdvanceOffsetsAndUnlock(LeadingStreamPointer, 0, Length, TRUE);
802
803 /* acquire spin lock */
804 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
805
806 /* adjust offset */
807 Irp->Tail.Overlay.DriverContext[1] = UlongToPtr(Length);
808
809 /* reinsert into processed list */
810 InsertHeadList(&PinContext->DoneIrpListHead, &Irp->Tail.Overlay.ListEntry);
811
812 /* release lock */
813 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
814
815 LeadingStreamPointer = KsPinGetLeadingEdgeStreamPointer(Pin, KSSTREAM_POINTER_STATE_LOCKED);
816 if (LeadingStreamPointer == NULL)
817 {
818 /* no more work to be done*/
819 return STATUS_PENDING;
820 }
821 else
822 {
823 /* resume work on this irp */
824 continue;
825 }
826 }
827 else
828 {
829 Status = KsStreamPointerAdvanceOffsets(LeadingStreamPointer, 0, Length, FALSE);
830 NT_ASSERT(NT_SUCCESS(Status));
831 ASSERT(Length == Urb->UrbIsochronousTransfer.TransferBufferLength - Offset);
832 }
833
834
835 /* acquire spin lock */
836 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
837
838 InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
839 }
840
841 while (!IsListEmpty(&PinContext->IrpListHead))
842 {
843 /* remove entry from list */
844 CurEntry = RemoveHeadList(&PinContext->IrpListHead);
845
846 /* release lock */
847 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
848
849 /* get irp offset */
850 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
851
852 /* reinitialize irp and urb */
853 CaptureInitializeUrbAndIrp(Pin, Irp);
854
855 IoCallDriver(PinContext->DeviceExtension->LowerDevice, Irp);
856
857 /* acquire spin lock */
858 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
859
860 }
861
862 /* release lock */
863 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
864
865 if (LeadingStreamPointer != NULL)
866 KsStreamPointerUnlock(LeadingStreamPointer, FALSE);
867
868 /* get process control gate */
869 Gate = KsPinGetAndGate(Pin);
870
871 /* shutdown processing */
872 KsGateTurnInputOff(Gate);
873
874 return STATUS_PENDING;
875 }
876
877
878 NTSTATUS
879 NTAPI
880 USBAudioPinProcess(
881 _In_ PKSPIN Pin)
882 {
883 NTSTATUS Status;
884
885 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
886 {
887 Status = PinCaptureProcess(Pin);
888 }
889 else
890 {
891 UNIMPLEMENTED;
892 Status = STATUS_NOT_IMPLEMENTED;
893 }
894
895 return Status;
896 }
897
898
899 VOID
900 NTAPI
901 USBAudioPinReset(
902 _In_ PKSPIN Pin)
903 {
904 UNIMPLEMENTED
905 }
906
907 NTSTATUS
908 NTAPI
909 USBAudioPinSetDataFormat(
910 _In_ PKSPIN Pin,
911 _In_opt_ PKSDATAFORMAT OldFormat,
912 _In_opt_ PKSMULTIPLE_ITEM OldAttributeList,
913 _In_ const KSDATARANGE* DataRange,
914 _In_opt_ const KSATTRIBUTE_LIST* AttributeRange)
915 {
916 if (OldFormat == NULL)
917 {
918 /* TODO: verify connection format */
919 UNIMPLEMENTED
920 return STATUS_SUCCESS;
921 }
922
923 return UsbAudioSetFormat(Pin);
924 }
925
926 NTSTATUS
927 StartCaptureIsocTransfer(
928 IN PKSPIN Pin)
929 {
930 PPIN_CONTEXT PinContext;
931 PLIST_ENTRY CurEntry;
932 PIRP Irp;
933 KIRQL OldLevel;
934
935 /* get pin context */
936 PinContext = Pin->Context;
937
938 /* acquire spin lock */
939 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
940
941 while(!IsListEmpty(&PinContext->IrpListHead))
942 {
943 /* remove entry from list */
944 CurEntry = RemoveHeadList(&PinContext->IrpListHead);
945
946 /* get irp offset */
947 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
948
949 /* release lock */
950 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
951
952 /* reinitialize irp and urb */
953 CaptureInitializeUrbAndIrp(Pin, Irp);
954
955 DPRINT("StartCaptureIsocTransfer Irp %p\n", Irp);
956 IoCallDriver(PinContext->DeviceExtension->LowerDevice, Irp);
957
958 /* acquire spin lock */
959 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
960
961 }
962
963 /* release lock */
964 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
965
966 return STATUS_SUCCESS;
967 }
968
969 NTSTATUS
970 CapturePinStateChange(
971 _In_ PKSPIN Pin,
972 _In_ KSSTATE ToState,
973 _In_ KSSTATE FromState)
974 {
975 NTSTATUS Status;
976
977 if (FromState != ToState)
978 {
979 if (ToState)
980 {
981 if (ToState == KSSTATE_PAUSE)
982 {
983 if (FromState == KSSTATE_RUN)
984 {
985 /* wait until pin processing is finished*/
986 }
987 }
988 else
989 {
990 if (ToState == KSSTATE_RUN)
991 {
992 Status = StartCaptureIsocTransfer(Pin);
993 }
994 }
995 }
996 }
997 return Status;
998 }
999
1000
1001 NTSTATUS
1002 NTAPI
1003 USBAudioPinSetDeviceState(
1004 _In_ PKSPIN Pin,
1005 _In_ KSSTATE ToState,
1006 _In_ KSSTATE FromState)
1007 {
1008 NTSTATUS Status;
1009
1010 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
1011 {
1012 /* handle capture state changes */
1013 Status = CapturePinStateChange(Pin, ToState, FromState);
1014 }
1015 else
1016 {
1017 UNIMPLEMENTED
1018 Status = STATUS_NOT_IMPLEMENTED;
1019 }
1020
1021 return Status;
1022 }
1023
1024
1025 NTSTATUS
1026 NTAPI
1027 UsbAudioPinDataIntersect(
1028 _In_ PVOID Context,
1029 _In_ PIRP Irp,
1030 _In_ PKSP_PIN Pin,
1031 _In_ PKSDATARANGE DataRange,
1032 _In_ PKSDATARANGE MatchingDataRange,
1033 _In_ ULONG DataBufferSize,
1034 _Out_ PVOID Data,
1035 _Out_ PULONG DataSize)
1036 {
1037 PKSFILTER Filter;
1038 PKSPIN_DESCRIPTOR_EX PinDescriptor;
1039 PKSDATAFORMAT_WAVEFORMATEX DataFormat;
1040 PKSDATARANGE_AUDIO DataRangeAudio;
1041
1042 /* get filter from irp*/
1043 Filter = KsGetFilterFromIrp(Irp);
1044 if (!Filter)
1045 {
1046 /* no match*/
1047 return STATUS_NO_MATCH;
1048 }
1049
1050 /* get pin descriptor */
1051 PinDescriptor = (PKSPIN_DESCRIPTOR_EX)&Filter->Descriptor->PinDescriptors[Pin->PinId];
1052
1053 *DataSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
1054 if (DataBufferSize == 0)
1055 {
1056 /* buffer too small */
1057 return STATUS_BUFFER_OVERFLOW;
1058 }
1059
1060 /* sanity checks*/
1061 ASSERT(PinDescriptor->PinDescriptor.DataRangesCount >= 0);
1062 ASSERT(PinDescriptor->PinDescriptor.DataRanges[0]->FormatSize == sizeof(KSDATARANGE_AUDIO));
1063
1064 DataRangeAudio = (PKSDATARANGE_AUDIO)PinDescriptor->PinDescriptor.DataRanges[0];
1065
1066 DataFormat = Data;
1067 DataFormat->WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
1068 DataFormat->WaveFormatEx.nChannels = DataRangeAudio->MaximumChannels;
1069 DataFormat->WaveFormatEx.nSamplesPerSec = DataRangeAudio->MaximumSampleFrequency;
1070 DataFormat->WaveFormatEx.nAvgBytesPerSec = DataRangeAudio->MaximumSampleFrequency * (DataRangeAudio->MaximumBitsPerSample / 8) * DataRangeAudio->MaximumChannels;
1071 DataFormat->WaveFormatEx.nBlockAlign = (DataRangeAudio->MaximumBitsPerSample / 8) * DataRangeAudio->MaximumChannels;
1072 DataFormat->WaveFormatEx.wBitsPerSample = DataRangeAudio->MaximumBitsPerSample;
1073 DataFormat->WaveFormatEx.cbSize = 0;
1074
1075 DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
1076 DataFormat->DataFormat.Flags = 0;
1077 DataFormat->DataFormat.Reserved = 0;
1078 DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
1079 DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1080 DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
1081 DataFormat->DataFormat.SampleSize = (DataRangeAudio->MaximumBitsPerSample / 8) * DataRangeAudio->MaximumChannels;
1082
1083 return STATUS_SUCCESS;
1084 }