- Partly Implement KsCacheMedium
[reactos.git] / reactos / drivers / ksfilter / ks / connectivity.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/ksfilter/ks/connectivity.c
5 * PURPOSE: KS Pin functions
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9
10 #include "priv.h"
11
12 /*
13 @implemented
14 */
15 KSDDKAPI
16 NTSTATUS
17 NTAPI
18 KsCreatePin(
19 IN HANDLE FilterHandle,
20 IN PKSPIN_CONNECT Connect,
21 IN ACCESS_MASK DesiredAccess,
22 OUT PHANDLE ConnectionHandle)
23 {
24 UINT ConnectSize = sizeof(KSPIN_CONNECT);
25
26 PKSDATAFORMAT_WAVEFORMATEX Format = (PKSDATAFORMAT_WAVEFORMATEX)(Connect + 1);
27 if (Format->DataFormat.FormatSize == sizeof(KSDATAFORMAT) ||
28 Format->DataFormat.FormatSize == sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX))
29 {
30 ConnectSize += Format->DataFormat.FormatSize;
31 }
32
33 return KspCreateObjectType(FilterHandle,
34 KSSTRING_Pin,
35 (PVOID)Connect,
36 ConnectSize,
37 DesiredAccess,
38 ConnectionHandle);
39 }
40
41 /*
42 @unimplemented
43 */
44 KSDDKAPI
45 NTSTATUS
46 NTAPI
47 KsValidateConnectRequest(
48 IN PIRP Irp,
49 IN ULONG DescriptorsCount,
50 IN KSPIN_DESCRIPTOR* Descriptor,
51 OUT PKSPIN_CONNECT* Connect)
52 {
53 PIO_STACK_LOCATION IoStack;
54 PKSPIN_CONNECT ConnectDetails;
55 LPWSTR PinName = L"{146F1A80-4791-11D0-A5D6-28DB04C10000}\\";
56 PKSDATAFORMAT DataFormat;
57 LPWSTR Offset;
58
59 IoStack = IoGetCurrentIrpStackLocation(Irp);
60 if (!IoStack->FileObject->FileName.Buffer)
61 return STATUS_INVALID_PARAMETER;
62
63 if (IoStack->FileObject->FileName.Length < wcslen(PinName) + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT))
64 return STATUS_INVALID_PARAMETER;
65
66 Offset = wcsstr(IoStack->FileObject->FileName.Buffer, PinName);
67 if (!Offset)
68 {
69 /* request is not targeted for a pin */
70 return STATUS_INVALID_PARAMETER;
71 }
72
73 ConnectDetails = (PKSPIN_CONNECT)(Offset + wcslen(PinName));
74
75 if (ConnectDetails->PinToHandle != NULL)
76 {
77 UNIMPLEMENTED
78 return STATUS_NOT_IMPLEMENTED;
79 }
80
81 if (ConnectDetails->PinId >= DescriptorsCount)
82 return STATUS_INVALID_PARAMETER;
83
84 #if 0
85 if (!IsEqualGUIDAligned(&ConnectDetails->Interface.Set, &KSINTERFACESETID_Standard) &&
86 ConnectDetails->Interface.Id != KSINTERFACE_STANDARD_STREAMING)
87 {
88 //FIXME
89 // validate provided interface set
90 DPRINT1("FIXME\n");
91 }
92
93 if (!IsEqualGUIDAligned(&ConnectDetails->Medium.Set, &KSMEDIUMSETID_Standard) &&
94 ConnectDetails->Medium.Id != KSMEDIUM_TYPE_ANYINSTANCE)
95 {
96 //FIXME
97 // validate provided medium set
98 DPRINT1("FIXME\n");
99 }
100 #endif
101
102 /// FIXME
103 /// implement format checking
104
105 DataFormat = (PKSDATAFORMAT) (ConnectDetails + 1);
106 *Connect = ConnectDetails;
107
108 return STATUS_SUCCESS;
109 }
110
111 /*
112 @implemented
113 */
114 KSDDKAPI
115 NTSTATUS
116 NTAPI
117 KsPinPropertyHandler(
118 IN PIRP Irp,
119 IN PKSPROPERTY Property,
120 IN OUT PVOID Data,
121 IN ULONG DescriptorsCount,
122 IN const KSPIN_DESCRIPTOR* Descriptor)
123 {
124 KSP_PIN * Pin;
125 KSMULTIPLE_ITEM * Item;
126 PIO_STACK_LOCATION IoStack;
127 ULONG Size, Index;
128 PVOID Buffer;
129 PKSDATARANGE_AUDIO *WaveFormatOut;
130 PKSDATAFORMAT_WAVEFORMATEX WaveFormatIn;
131
132 IoStack = IoGetCurrentIrpStackLocation(Irp);
133 Buffer = Irp->UserBuffer;
134
135 switch(Property->Id)
136 {
137 case KSPROPERTY_PIN_CTYPES:
138 (*(PULONG)Buffer) = DescriptorsCount;
139 Irp->IoStatus.Information = sizeof(ULONG);
140 Irp->IoStatus.Status = STATUS_SUCCESS;
141 break;
142 case KSPROPERTY_PIN_DATAFLOW:
143 Pin = (KSP_PIN*)Property;
144 if (Pin->PinId >= DescriptorsCount)
145 {
146 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
147 Irp->IoStatus.Information = 0;
148 break;
149 }
150 Size = sizeof(KSPIN_DATAFLOW);
151 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
152 {
153 Irp->IoStatus.Information = Size;
154 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
155 break;
156 }
157
158 *((KSPIN_DATAFLOW*)Buffer) = Descriptor[Pin->PinId].DataFlow;
159 Irp->IoStatus.Information = sizeof(KSPIN_DATAFLOW);
160 Irp->IoStatus.Status = STATUS_SUCCESS;
161 break;
162
163 case KSPROPERTY_PIN_DATARANGES:
164 Pin = (KSP_PIN*)Property;
165 if (Pin->PinId >= DescriptorsCount)
166 {
167 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
168 Irp->IoStatus.Information = 0;
169 break;
170 }
171 Size = sizeof(KSMULTIPLE_ITEM);
172 for (Index = 0; Index < Descriptor[Pin->PinId].DataRangesCount; Index++)
173 {
174 Size += Descriptor[Pin->PinId].DataRanges[Index]->FormatSize;
175 }
176
177 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
178 {
179 Irp->IoStatus.Information = Size;
180 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
181 break;
182 }
183
184 Item = (KSMULTIPLE_ITEM*)Buffer;
185 Item->Size = Size;
186 Item->Count = Descriptor[Pin->PinId].DataRangesCount;
187
188 Data = (PUCHAR)(Item +1);
189 for (Index = 0; Index < Descriptor[Pin->PinId].DataRangesCount; Index++)
190 {
191 RtlMoveMemory(Data, Descriptor[Pin->PinId].DataRanges[Index], Descriptor[Pin->PinId].DataRanges[Index]->FormatSize);
192 Data = ((PUCHAR)Data + Descriptor[Pin->PinId].DataRanges[Index]->FormatSize);
193 }
194
195 Irp->IoStatus.Status = STATUS_SUCCESS;
196 Irp->IoStatus.Information = Size;
197 break;
198 case KSPROPERTY_PIN_INTERFACES:
199 Pin = (KSP_PIN*)Property;
200 if (Pin->PinId >= DescriptorsCount)
201 {
202 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
203 Irp->IoStatus.Information = 0;
204 break;
205 }
206
207 Size = sizeof(KSMULTIPLE_ITEM) + sizeof(KSPIN_INTERFACE) * Descriptor[Pin->PinId].InterfacesCount;
208
209 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
210 {
211 Irp->IoStatus.Information = Size;
212 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
213 break;
214 }
215
216 Item = (KSMULTIPLE_ITEM*)Buffer;
217 Item->Size = Size;
218 Item->Count = Descriptor[Pin->PinId].InterfacesCount;
219 RtlMoveMemory((PVOID)(Item + 1), Descriptor[Pin->PinId].Interfaces, Descriptor[Pin->PinId].InterfacesCount * sizeof(KSDATARANGE));
220
221 Irp->IoStatus.Status = STATUS_SUCCESS;
222 Irp->IoStatus.Information = Size;
223 break;
224 case KSPROPERTY_PIN_MEDIUMS:
225 Pin = (KSP_PIN*)Property;
226 if (Pin->PinId >= DescriptorsCount)
227 {
228 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
229 Irp->IoStatus.Information = 0;
230 break;
231 }
232
233 Size = sizeof(KSMULTIPLE_ITEM) + sizeof(KSPIN_MEDIUM) * Descriptor[Pin->PinId].MediumsCount;
234 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
235 {
236 Irp->IoStatus.Information = Size;
237 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
238 break;
239 }
240
241 Item = (KSMULTIPLE_ITEM*)Buffer;
242 Item->Size = Size;
243 Item->Count = Descriptor[Pin->PinId].MediumsCount;
244 RtlMoveMemory((PVOID)(Item + 1), Descriptor[Pin->PinId].Mediums, Descriptor[Pin->PinId].MediumsCount * sizeof(KSDATARANGE));
245
246 Irp->IoStatus.Status = STATUS_SUCCESS;
247 Irp->IoStatus.Information = Size;
248 break;
249
250 case KSPROPERTY_PIN_COMMUNICATION:
251 Pin = (KSP_PIN*)Property;
252 if (Pin->PinId >= DescriptorsCount)
253 {
254 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
255 Irp->IoStatus.Information = 0;
256 break;
257 }
258
259 Size = sizeof(KSPIN_COMMUNICATION);
260 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
261 {
262 Irp->IoStatus.Information = Size;
263 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
264 break;
265 }
266
267 *((KSPIN_COMMUNICATION*)Buffer) = Descriptor[Pin->PinId].Communication;
268 Irp->IoStatus.Status = STATUS_SUCCESS;
269 Irp->IoStatus.Information = Size;
270 break;
271
272 case KSPROPERTY_PIN_CATEGORY:
273 Pin = (KSP_PIN*)Property;
274 if (Pin->PinId >= DescriptorsCount)
275 {
276 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
277 Irp->IoStatus.Information = 0;
278 break;
279 }
280
281 Size = sizeof(GUID);
282 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
283 {
284 Irp->IoStatus.Information = Size;
285 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
286 break;
287 }
288
289 RtlMoveMemory(Buffer, &Descriptor[Pin->PinId].Category, sizeof(GUID));
290 Irp->IoStatus.Status = STATUS_SUCCESS;
291 Irp->IoStatus.Information = Size;
292 break;
293
294 case KSPROPERTY_PIN_NAME:
295 Pin = (KSP_PIN*)Property;
296 if (Pin->PinId >= DescriptorsCount)
297 {
298 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
299 Irp->IoStatus.Information = 0;
300 break;
301 }
302
303 Size = sizeof(GUID);
304 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
305 {
306 Irp->IoStatus.Information = Size;
307 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
308 break;
309 }
310
311
312 RtlMoveMemory(Buffer, &Descriptor[Pin->PinId].Name, sizeof(GUID));
313 Irp->IoStatus.Status = STATUS_SUCCESS;
314 Irp->IoStatus.Information = Size;
315 break;
316 case KSPROPERTY_PIN_PROPOSEDATAFORMAT:
317 Pin = (KSP_PIN*)Property;
318 if (Pin->PinId >= DescriptorsCount)
319 {
320 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
321 Irp->IoStatus.Information = 0;
322 break;
323 }
324 Size = sizeof(KSDATAFORMAT);
325 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
326 {
327 Irp->IoStatus.Information = Size;
328 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
329 break;
330 }
331 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(KSDATAFORMAT_WAVEFORMATEX))
332 {
333 UNIMPLEMENTED
334 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
335 Irp->IoStatus.Information = 0;
336 return STATUS_NOT_IMPLEMENTED;
337 }
338
339 WaveFormatIn = (PKSDATAFORMAT_WAVEFORMATEX)Buffer;
340 if (!Descriptor[Pin->PinId].DataRanges || !Descriptor[Pin->PinId].DataRangesCount)
341 {
342 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
343 Irp->IoStatus.Information = 0;
344 return STATUS_UNSUCCESSFUL;
345 }
346 WaveFormatOut = (PKSDATARANGE_AUDIO*)Descriptor[Pin->PinId].DataRanges;
347 for(Index = 0; Index < Descriptor[Pin->PinId].DataRangesCount; Index++)
348 {
349 if (WaveFormatOut[Index]->DataRange.FormatSize != sizeof(KSDATARANGE_AUDIO))
350 {
351 UNIMPLEMENTED
352 continue;
353 }
354
355 if (WaveFormatOut[Index]->MinimumSampleFrequency > WaveFormatIn->WaveFormatEx.nSamplesPerSec ||
356 WaveFormatOut[Index]->MaximumSampleFrequency < WaveFormatIn->WaveFormatEx.nSamplesPerSec ||
357 WaveFormatOut[Index]->MinimumBitsPerSample > WaveFormatIn->WaveFormatEx.wBitsPerSample ||
358 WaveFormatOut[Index]->MaximumBitsPerSample < WaveFormatIn->WaveFormatEx.wBitsPerSample ||
359 WaveFormatOut[Index]->MaximumChannels < WaveFormatIn->WaveFormatEx.nChannels)
360 {
361 Irp->IoStatus.Status = STATUS_NO_MATCH;
362 Irp->IoStatus.Information = 0;
363 return STATUS_NO_MATCH;
364 }
365 else
366 {
367 Irp->IoStatus.Status = STATUS_SUCCESS;
368 Irp->IoStatus.Information = 0;
369 return STATUS_SUCCESS;
370 }
371 }
372 Irp->IoStatus.Status = STATUS_NO_MATCH;
373 Irp->IoStatus.Information = 0;
374 return STATUS_NO_MATCH;
375 default:
376 DPRINT1("Unhandled property request %x\n", Property->Id);
377 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
378 Irp->IoStatus.Information = 0;
379 }
380
381 return Irp->IoStatus.Status;
382 }
383
384 /*
385 @implemented
386 */
387 KSDDKAPI
388 NTSTATUS
389 NTAPI
390 KsPinDataIntersection(
391 IN PIRP Irp,
392 IN PKSP_PIN Pin,
393 OUT PVOID Data,
394 IN ULONG DescriptorsCount,
395 IN const KSPIN_DESCRIPTOR* Descriptor,
396 IN PFNKSINTERSECTHANDLER IntersectHandler)
397 {
398 KSMULTIPLE_ITEM * Item;
399 KSDATARANGE * DataRange;
400 PIO_STACK_LOCATION IoStack;
401 ULONG Size;
402 ULONG Index;
403 NTSTATUS Status;
404
405 /* get current irp stack location */
406 IoStack = IoGetCurrentIrpStackLocation(Irp);
407
408 /* calculate minimum data size */
409 Size = sizeof(KSP_PIN) + sizeof(KSMULTIPLE_ITEM) + sizeof(KSDATARANGE);
410 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < Size)
411 {
412 /* buffer too small */
413 Irp->IoStatus.Information = Size;
414 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
415 return STATUS_BUFFER_TOO_SMALL;
416 }
417 /* is pin id out of bounds */
418 if (Pin->PinId >= DescriptorsCount)
419 {
420 /* it is */
421 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
422 Irp->IoStatus.Information = 0;
423 return STATUS_INVALID_PARAMETER;
424 }
425
426 /* get start item */
427 Item = (KSMULTIPLE_ITEM*)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
428 /* get first data range */
429 DataRange = (KSDATARANGE*)(Item + 1);
430 /* iterate through all data ranges */
431 for(Index = 0; Index < Item->Count; Index++, DataRange++)
432 {
433 /* call intersect handler */
434 Status = IntersectHandler(Irp, Pin, DataRange, Data);
435 if (NT_SUCCESS(Status))
436 {
437 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < DataRange->FormatSize)
438 {
439 /* buffer is too small */
440 Irp->IoStatus.Information = DataRange->FormatSize;
441 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
442 return STATUS_BUFFER_TOO_SMALL;
443 }
444 RtlMoveMemory(Irp->UserBuffer, DataRange, sizeof(KSDATARANGE));
445 Irp->IoStatus.Information = sizeof(KSDATARANGE);
446 Irp->IoStatus.Status = STATUS_SUCCESS;
447 return STATUS_SUCCESS;
448 }
449
450 }
451
452 Irp->IoStatus.Information = 0;
453 Irp->IoStatus.Status = STATUS_NO_MATCH;
454 return STATUS_NO_MATCH;
455 }
456
457 /*
458 @implemented
459 */
460
461 KSDDKAPI
462 NTSTATUS
463 NTAPI
464 KsHandleSizedListQuery(
465 IN PIRP Irp,
466 IN ULONG DataItemsCount,
467 IN ULONG DataItemSize,
468 IN const VOID* DataItems)
469 {
470 ULONG Size;
471 PIO_STACK_LOCATION IoStack;
472 PKSMULTIPLE_ITEM Item;
473
474 /* get current irp stack location */
475 IoStack = IoGetCurrentIrpStackLocation(Irp);
476
477 Size = DataItemSize * DataItemsCount + sizeof(KSMULTIPLE_ITEM);
478
479
480 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < Size)
481 {
482 /* buffer too small */
483 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
484 Irp->IoStatus.Information = Size;
485 return STATUS_BUFFER_TOO_SMALL;
486 }
487
488 /* get multiple item */
489 Item = (PKSMULTIPLE_ITEM)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
490
491 Item->Count = DataItemsCount;
492 Item->Size = DataItemSize;
493 /* copy items */
494 RtlMoveMemory((PVOID)(Item + 1), DataItems, DataItemSize * DataItemsCount);
495 /* store result */
496 Irp->IoStatus.Status = STATUS_SUCCESS;
497 Irp->IoStatus.Information = Size;
498 /* done */
499 return STATUS_SUCCESS;
500 }
501