[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 PIO_STACK_LOCATION IoStack;
793 PURB Urb;
794 PUCHAR TransferBuffer, OutBuffer;
795 ULONG Offset, Length;
796 NTSTATUS Status;
797 PKSGATE Gate;
798
799 //DPRINT1("PinCaptureProcess\n");
800 LeadingStreamPointer = KsPinGetLeadingEdgeStreamPointer(Pin, KSSTREAM_POINTER_STATE_LOCKED);
801 if (LeadingStreamPointer == NULL)
802 {
803 /* get process control gate */
804 Gate = KsPinGetAndGate(Pin);
805
806 /* shutdown processing */
807 KsGateTurnInputOff(Gate);
808
809 return STATUS_SUCCESS;
810 }
811
812 /* get pin context */
813 PinContext = Pin->Context;
814
815 /* acquire spin lock */
816 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
817
818 while (!IsListEmpty(&PinContext->DoneIrpListHead))
819 {
820 /* remove entry from list */
821 CurEntry = RemoveHeadList(&PinContext->DoneIrpListHead);
822
823 /* release lock */
824 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
825
826 /* get irp offset */
827 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
828
829 /* get urb from irp */
830 IoStack = IoGetNextIrpStackLocation(Irp);
831 Urb = (PURB)Irp->Tail.Overlay.DriverContext[0];
832 ASSERT(Urb);
833
834 Offset = PtrToUlong(Irp->Tail.Overlay.DriverContext[1]);
835
836 /* get transfer buffer */
837 TransferBuffer = Urb->UrbIsochronousTransfer.TransferBuffer;
838
839 /* get target buffer */
840 OutBuffer = (PUCHAR)LeadingStreamPointer->StreamHeader->Data;
841
842 /* calculate length */
843 Length = min(LeadingStreamPointer->OffsetOut.Count - LeadingStreamPointer->StreamHeader->DataUsed, Urb->UrbIsochronousTransfer.TransferBufferLength - Offset);
844
845 /* FIXME copy each packet extra */
846 /* copy audio bytes */
847 RtlCopyMemory((PUCHAR)&OutBuffer[LeadingStreamPointer->StreamHeader->DataUsed], &TransferBuffer[Offset], Length);
848
849 //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);
850
851 /* adjust streampointer */
852 LeadingStreamPointer->StreamHeader->DataUsed += Length;
853
854 if (Length == LeadingStreamPointer->OffsetOut.Remaining)
855 {
856 KsStreamPointerAdvanceOffsetsAndUnlock(LeadingStreamPointer, 0, Length, TRUE);
857
858 /* acquire spin lock */
859 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
860
861 /* adjust offset */
862 Irp->Tail.Overlay.DriverContext[1] = UlongToPtr(Length);
863
864 /* reinsert into processed list */
865 InsertHeadList(&PinContext->DoneIrpListHead, &Irp->Tail.Overlay.ListEntry);
866
867 /* release lock */
868 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
869
870 LeadingStreamPointer = KsPinGetLeadingEdgeStreamPointer(Pin, KSSTREAM_POINTER_STATE_LOCKED);
871 if (LeadingStreamPointer == NULL)
872 {
873 /* no more work to be done*/
874 return STATUS_PENDING;
875 }
876 else
877 {
878 /* resume work on this irp */
879 continue;
880 }
881 }
882 else
883 {
884 Status = KsStreamPointerAdvanceOffsets(LeadingStreamPointer, 0, Length, FALSE);
885 ASSERT(Length == Urb->UrbIsochronousTransfer.TransferBufferLength - Offset);
886 }
887
888
889 /* acquire spin lock */
890 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
891
892 InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
893 }
894
895 while (!IsListEmpty(&PinContext->IrpListHead))
896 {
897 /* remove entry from list */
898 CurEntry = RemoveHeadList(&PinContext->IrpListHead);
899
900 /* release lock */
901 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
902
903 /* get irp offset */
904 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
905
906 /* reinitialize irp and urb */
907 CaptureInitializeUrbAndIrp(Pin, Irp);
908
909 IoCallDriver(PinContext->DeviceExtension->LowerDevice, Irp);
910
911 /* acquire spin lock */
912 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
913
914 }
915
916 /* release lock */
917 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
918
919 if (LeadingStreamPointer != NULL)
920 KsStreamPointerUnlock(LeadingStreamPointer, FALSE);
921
922 /* get process control gate */
923 Gate = KsPinGetAndGate(Pin);
924
925 /* shutdown processing */
926 KsGateTurnInputOff(Gate);
927
928 return STATUS_PENDING;
929 }
930
931
932 NTSTATUS
933 NTAPI
934 USBAudioPinProcess(
935 _In_ PKSPIN Pin)
936 {
937 NTSTATUS Status;
938
939 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
940 {
941 Status = PinCaptureProcess(Pin);
942 }
943 else
944 {
945 UNIMPLEMENTED;
946 Status = STATUS_NOT_IMPLEMENTED;
947 }
948
949 return Status;
950 }
951
952
953 VOID
954 NTAPI
955 USBAudioPinReset(
956 _In_ PKSPIN Pin)
957 {
958 UNIMPLEMENTED
959 }
960
961 NTSTATUS
962 NTAPI
963 USBAudioPinSetDataFormat(
964 _In_ PKSPIN Pin,
965 _In_opt_ PKSDATAFORMAT OldFormat,
966 _In_opt_ PKSMULTIPLE_ITEM OldAttributeList,
967 _In_ const KSDATARANGE* DataRange,
968 _In_opt_ const KSATTRIBUTE_LIST* AttributeRange)
969 {
970 if (OldFormat == NULL)
971 {
972 /* TODO: verify connection format */
973 UNIMPLEMENTED
974 return STATUS_SUCCESS;
975 }
976
977 return UsbAudioSetFormat(Pin);
978 }
979
980 NTSTATUS
981 StartCaptureIsocTransfer(
982 IN PKSPIN Pin)
983 {
984 PPIN_CONTEXT PinContext;
985 PLIST_ENTRY CurEntry;
986 PIRP Irp;
987 KIRQL OldLevel;
988
989 /* get pin context */
990 PinContext = Pin->Context;
991
992 /* acquire spin lock */
993 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
994
995 while(!IsListEmpty(&PinContext->IrpListHead))
996 {
997 /* remove entry from list */
998 CurEntry = RemoveHeadList(&PinContext->IrpListHead);
999
1000 /* get irp offset */
1001 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
1002
1003 /* release lock */
1004 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
1005
1006 /* reinitialize irp and urb */
1007 CaptureInitializeUrbAndIrp(Pin, Irp);
1008
1009 DPRINT("StartCaptureIsocTransfer Irp %p\n", Irp);
1010 IoCallDriver(PinContext->DeviceExtension->LowerDevice, Irp);
1011
1012 /* acquire spin lock */
1013 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
1014
1015 }
1016
1017 /* release lock */
1018 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
1019
1020 return STATUS_SUCCESS;
1021 }
1022
1023 NTSTATUS
1024 CapturePinStateChange(
1025 _In_ PKSPIN Pin,
1026 _In_ KSSTATE ToState,
1027 _In_ KSSTATE FromState)
1028 {
1029 NTSTATUS Status;
1030
1031 if (FromState != ToState)
1032 {
1033 if (ToState)
1034 {
1035 if (ToState == KSSTATE_PAUSE)
1036 {
1037 if (FromState == KSSTATE_RUN)
1038 {
1039 /* wait until pin processing is finished*/
1040 }
1041 }
1042 else
1043 {
1044 if (ToState == KSSTATE_RUN)
1045 {
1046 Status = StartCaptureIsocTransfer(Pin);
1047 }
1048 }
1049 }
1050 }
1051 return Status;
1052 }
1053
1054
1055 NTSTATUS
1056 NTAPI
1057 USBAudioPinSetDeviceState(
1058 _In_ PKSPIN Pin,
1059 _In_ KSSTATE ToState,
1060 _In_ KSSTATE FromState)
1061 {
1062 NTSTATUS Status;
1063
1064 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
1065 {
1066 /* handle capture state changes */
1067 Status = CapturePinStateChange(Pin, ToState, FromState);
1068 }
1069 else
1070 {
1071 UNIMPLEMENTED
1072 Status = STATUS_NOT_IMPLEMENTED;
1073 }
1074
1075 return Status;
1076 }