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