[CMAKE]
[reactos.git] / drivers / wdm / audio / legacy / wdmaud / control.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/legacy/wdmaud/deviface.c
5 * PURPOSE: System Audio graph builder
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 */
9 #include "wdmaud.h"
10
11 const GUID KSPROPSETID_Sysaudio = {0xCBE3FAA0L, 0xCC75, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
12
13 NTSTATUS
14 WdmAudControlOpen(
15 IN PDEVICE_OBJECT DeviceObject,
16 IN PIRP Irp,
17 IN PWDMAUD_DEVICE_INFO DeviceInfo,
18 IN PWDMAUD_CLIENT ClientInfo)
19 {
20 if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
21 {
22 return WdmAudControlOpenMixer(DeviceObject, Irp, DeviceInfo, ClientInfo);
23 }
24
25 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
26 {
27 return WdmAudControlOpenWave(DeviceObject, Irp, DeviceInfo, ClientInfo);
28 }
29
30 if (DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE)
31 {
32 return WdmAudControlOpenMidi(DeviceObject, Irp, DeviceInfo, ClientInfo);
33 }
34
35
36 return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
37 }
38
39 NTSTATUS
40 WdmAudControlDeviceType(
41 IN PDEVICE_OBJECT DeviceObject,
42 IN PIRP Irp,
43 IN PWDMAUD_DEVICE_INFO DeviceInfo,
44 IN PWDMAUD_CLIENT ClientInfo)
45 {
46 ULONG Result = 0;
47 NTSTATUS Status = STATUS_SUCCESS;
48 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
49
50 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
51
52 if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
53 {
54 Result = WdmAudGetMixerDeviceCount();
55 }
56 else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
57 {
58 Result = WdmAudGetWaveInDeviceCount();
59 }
60 else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
61 {
62 Result = WdmAudGetWaveOutDeviceCount();
63 }
64 else if (DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE)
65 {
66 Result = WdmAudGetMidiInDeviceCount();
67 }
68 else if (DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE)
69 {
70 Result = WdmAudGetMidiOutDeviceCount();
71 }
72
73
74 /* store result count */
75 DeviceInfo->DeviceCount = Result;
76
77 DPRINT("WdmAudControlDeviceType Status %x Devices %u\n", Status, DeviceInfo->DeviceCount);
78 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
79 }
80
81 NTSTATUS
82 WdmAudControlDeviceState(
83 IN PDEVICE_OBJECT DeviceObject,
84 IN PIRP Irp,
85 IN PWDMAUD_DEVICE_INFO DeviceInfo,
86 IN PWDMAUD_CLIENT ClientInfo)
87 {
88 KSPROPERTY Property;
89 KSSTATE State;
90 NTSTATUS Status;
91 ULONG BytesReturned;
92 PFILE_OBJECT FileObject;
93
94 DPRINT("WdmAudControlDeviceState\n");
95
96 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_READ | GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
97 if (!NT_SUCCESS(Status))
98 {
99 DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo->hDevice, DeviceInfo->DeviceType);
100 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
101 }
102
103 Property.Set = KSPROPSETID_Connection;
104 Property.Id = KSPROPERTY_CONNECTION_STATE;
105 Property.Flags = KSPROPERTY_TYPE_SET;
106
107 State = DeviceInfo->u.State;
108
109 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesReturned);
110
111 ObDereferenceObject(FileObject);
112
113 DPRINT("WdmAudControlDeviceState Status %x\n", Status);
114 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
115 }
116
117 NTSTATUS
118 WdmAudCapabilities(
119 IN PDEVICE_OBJECT DeviceObject,
120 IN PIRP Irp,
121 IN PWDMAUD_DEVICE_INFO DeviceInfo,
122 IN PWDMAUD_CLIENT ClientInfo)
123 {
124 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
125 NTSTATUS Status = STATUS_UNSUCCESSFUL;
126
127 DPRINT("WdmAudCapabilities entered\n");
128
129 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
130
131 if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
132 {
133 Status = WdmAudMixerCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
134 }
135 else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
136 {
137 Status = WdmAudWaveCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
138 }
139 else if (DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE || DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE)
140 {
141 Status = WdmAudMidiCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
142 }
143
144 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
145 }
146
147 NTSTATUS
148 NTAPI
149 WdmAudIoctlClose(
150 IN PDEVICE_OBJECT DeviceObject,
151 IN PIRP Irp,
152 IN PWDMAUD_DEVICE_INFO DeviceInfo,
153 IN PWDMAUD_CLIENT ClientInfo)
154 {
155 ULONG Index;
156
157 for(Index = 0; Index < ClientInfo->NumPins; Index++)
158 {
159 if (ClientInfo->hPins[Index].Handle == DeviceInfo->hDevice && ClientInfo->hPins[Index].Type != MIXER_DEVICE_TYPE)
160 {
161 DPRINT1("Closing device %p\n", DeviceInfo->hDevice);
162 ZwClose(DeviceInfo->hDevice);
163 ClientInfo->hPins[Index].Handle = NULL;
164 SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
165 return STATUS_SUCCESS;
166 }
167 else if (ClientInfo->hPins[Index].Handle == DeviceInfo->hDevice && ClientInfo->hPins[Index].Type == MIXER_DEVICE_TYPE)
168 {
169 if (ClientInfo->hPins[Index].NotifyEvent)
170 {
171 ObDereferenceObject(ClientInfo->hPins[Index].NotifyEvent);
172 ClientInfo->hPins[Index].NotifyEvent = NULL;
173 }
174 }
175 }
176
177 SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, sizeof(WDMAUD_DEVICE_INFO));
178 return STATUS_INVALID_PARAMETER;
179 }
180
181 NTSTATUS
182 NTAPI
183 WdmAudFrameSize(
184 IN PDEVICE_OBJECT DeviceObject,
185 IN PIRP Irp,
186 IN PWDMAUD_DEVICE_INFO DeviceInfo,
187 IN PWDMAUD_CLIENT ClientInfo)
188 {
189 PFILE_OBJECT FileObject;
190 KSPROPERTY Property;
191 ULONG BytesReturned;
192 KSALLOCATOR_FRAMING Framing;
193 NTSTATUS Status;
194
195 /* Get sysaudio pin file object */
196 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
197 if (!NT_SUCCESS(Status))
198 {
199 DPRINT1("Invalid buffer handle %p\n", DeviceInfo->hDevice);
200 return SetIrpIoStatus(Irp, Status, 0);
201 }
202
203 /* Setup get framing request */
204 Property.Id = KSPROPERTY_CONNECTION_ALLOCATORFRAMING;
205 Property.Flags = KSPROPERTY_TYPE_GET;
206 Property.Set = KSPROPSETID_Connection;
207
208 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Framing, sizeof(KSALLOCATOR_FRAMING), &BytesReturned);
209 /* Did we succeed */
210 if (NT_SUCCESS(Status))
211 {
212 /* Store framesize */
213 DeviceInfo->u.FrameSize = Framing.FrameSize;
214 }
215
216 /* Release file object */
217 ObDereferenceObject(FileObject);
218
219 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
220
221 }
222
223 NTSTATUS
224 NTAPI
225 WdmAudGetDeviceInterface(
226 IN PDEVICE_OBJECT DeviceObject,
227 IN PIRP Irp,
228 IN PWDMAUD_DEVICE_INFO DeviceInfo)
229 {
230 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
231 NTSTATUS Status;
232 LPWSTR Device;
233 ULONG Size, Length;
234
235 /* get device extension */
236 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
237
238 /* get device interface string input length */
239 Size = DeviceInfo->u.Interface.DeviceInterfaceStringSize;
240
241 /* get mixer info */
242 Status = WdmAudGetPnpNameByIndexAndType(DeviceInfo->DeviceIndex, DeviceInfo->DeviceType, &Device);
243
244 /* check for success */
245 if (!NT_SUCCESS(Status))
246 {
247 /* invalid device id */
248 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
249 }
250
251 /* calculate length */
252 Length = (wcslen(Device)+1) * sizeof(WCHAR);
253
254 if (!Size)
255 {
256 /* store device interface size */
257 DeviceInfo->u.Interface.DeviceInterfaceStringSize = Length;
258 }
259 else if (Size < Length)
260 {
261 /* buffer too small */
262 DeviceInfo->u.Interface.DeviceInterfaceStringSize = Length;
263 return SetIrpIoStatus(Irp, STATUS_BUFFER_OVERFLOW, sizeof(WDMAUD_DEVICE_INFO));
264 }
265 else
266 {
267 //FIXME SEH
268 RtlMoveMemory(DeviceInfo->u.Interface.DeviceInterfaceString, Device, Length);
269 }
270
271 FreeItem(Device);
272 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
273 }
274
275 NTSTATUS
276 NTAPI
277 WdmAudResetStream(
278 IN PDEVICE_OBJECT DeviceObject,
279 IN PIRP Irp,
280 IN PWDMAUD_DEVICE_INFO DeviceInfo)
281 {
282 KSRESET ResetStream;
283 NTSTATUS Status;
284 ULONG BytesReturned;
285 PFILE_OBJECT FileObject;
286
287 DPRINT("WdmAudResetStream\n");
288
289 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_READ | GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
290 if (!NT_SUCCESS(Status))
291 {
292 DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo->hDevice, DeviceInfo->DeviceType);
293 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
294 }
295
296 ResetStream = DeviceInfo->u.ResetStream;
297 ASSERT(ResetStream == KSRESET_BEGIN || ResetStream == KSRESET_END);
298
299 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_RESET_STATE, (PVOID)&ResetStream, sizeof(KSRESET), NULL, 0, &BytesReturned);
300
301 ObDereferenceObject(FileObject);
302
303 DPRINT("WdmAudResetStream Status %x\n", Status);
304 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
305 }
306
307 NTSTATUS
308 NTAPI
309 WdmAudDeviceControl(
310 IN PDEVICE_OBJECT DeviceObject,
311 IN PIRP Irp)
312 {
313 PIO_STACK_LOCATION IoStack;
314 PWDMAUD_DEVICE_INFO DeviceInfo;
315 PWDMAUD_CLIENT ClientInfo;
316
317 IoStack = IoGetCurrentIrpStackLocation(Irp);
318
319 DPRINT("WdmAudDeviceControl entered\n");
320
321 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(WDMAUD_DEVICE_INFO))
322 {
323 /* invalid parameter */
324 DPRINT1("Input buffer too small size %u expected %u\n", IoStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(WDMAUD_DEVICE_INFO));
325 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
326 }
327
328 DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer;
329
330 if (DeviceInfo->DeviceType < MIN_SOUND_DEVICE_TYPE || DeviceInfo->DeviceType > MAX_SOUND_DEVICE_TYPE)
331 {
332 /* invalid parameter */
333 DPRINT1("Error: device type not set\n");
334 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
335 }
336
337 if (!IoStack->FileObject)
338 {
339 /* file object parameter */
340 DPRINT1("Error: file object is not attached\n");
341 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
342 }
343 ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
344
345 DPRINT("WdmAudDeviceControl entered\n");
346
347 switch(IoStack->Parameters.DeviceIoControl.IoControlCode)
348 {
349 case IOCTL_OPEN_WDMAUD:
350 return WdmAudControlOpen(DeviceObject, Irp, DeviceInfo, ClientInfo);
351 case IOCTL_GETNUMDEVS_TYPE:
352 return WdmAudControlDeviceType(DeviceObject, Irp, DeviceInfo, ClientInfo);
353 case IOCTL_SETDEVICE_STATE:
354 return WdmAudControlDeviceState(DeviceObject, Irp, DeviceInfo, ClientInfo);
355 case IOCTL_GETCAPABILITIES:
356 return WdmAudCapabilities(DeviceObject, Irp, DeviceInfo, ClientInfo);
357 case IOCTL_CLOSE_WDMAUD:
358 return WdmAudIoctlClose(DeviceObject, Irp, DeviceInfo, ClientInfo);
359 case IOCTL_GETFRAMESIZE:
360 return WdmAudFrameSize(DeviceObject, Irp, DeviceInfo, ClientInfo);
361 case IOCTL_GETLINEINFO:
362 return WdmAudGetLineInfo(DeviceObject, Irp, DeviceInfo, ClientInfo);
363 case IOCTL_GETLINECONTROLS:
364 return WdmAudGetLineControls(DeviceObject, Irp, DeviceInfo, ClientInfo);
365 case IOCTL_SETCONTROLDETAILS:
366 return WdmAudSetControlDetails(DeviceObject, Irp, DeviceInfo, ClientInfo);
367 case IOCTL_GETCONTROLDETAILS:
368 return WdmAudGetControlDetails(DeviceObject, Irp, DeviceInfo, ClientInfo);
369 case IOCTL_QUERYDEVICEINTERFACESTRING:
370 return WdmAudGetDeviceInterface(DeviceObject, Irp, DeviceInfo);
371 case IOCTL_GET_MIXER_EVENT:
372 return WdmAudGetMixerEvent(DeviceObject, Irp, DeviceInfo, ClientInfo);
373 case IOCTL_RESET_STREAM:
374 return WdmAudResetStream(DeviceObject, Irp, DeviceInfo);
375 case IOCTL_GETPOS:
376 case IOCTL_GETDEVID:
377 case IOCTL_GETVOLUME:
378 case IOCTL_SETVOLUME:
379
380 DPRINT1("Unhandeled %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
381 break;
382 }
383
384 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
385 }
386
387 NTSTATUS
388 NTAPI
389 IoCompletion (
390 PDEVICE_OBJECT DeviceObject,
391 PIRP Irp,
392 PVOID Ctx)
393 {
394 PKSSTREAM_HEADER Header;
395 ULONG Length = 0;
396 PMDL Mdl, NextMdl;
397 PWDMAUD_COMPLETION_CONTEXT Context = (PWDMAUD_COMPLETION_CONTEXT)Ctx;
398
399 /* get stream header */
400 Header = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
401
402 /* sanity check */
403 ASSERT(Header);
404
405 /* iterate through all stream headers and collect size */
406 do
407 {
408 if (Context->Function == IOCTL_KS_READ_STREAM)
409 {
410 /* length is stored in DataUsed */
411 Length += Header->DataUsed;
412 }
413 else
414 {
415 /* length stored in frameextend */
416 Length += Header->FrameExtent;
417 }
418
419 /* subtract size */
420 Context->Length -= Header->Size;
421
422 /* move to next stream header */
423 Header = (PKSSTREAM_HEADER)((ULONG_PTR)Header + Header->Size);
424
425 }while(Context->Length);
426
427 /* time to free all allocated mdls */
428 Mdl = Irp->MdlAddress;
429
430 while(Mdl)
431 {
432 /* get next mdl */
433 NextMdl = Mdl->Next;
434
435 /* unlock pages */
436 MmUnlockPages(Mdl);
437
438 /* grab next mdl */
439 Mdl = NextMdl;
440 }
441
442 /* clear mdl list */
443 Irp->MdlAddress = NULL;
444
445 /* check if mdl is locked */
446 if (Context->Mdl->MdlFlags & MDL_PAGES_LOCKED)
447 {
448 /* unlock pages */
449 MmUnlockPages(Context->Mdl);
450 }
451
452 /* now free the mdl */
453 IoFreeMdl(Context->Mdl);
454
455 DPRINT("IoCompletion Irp %p IoStatus %lx Information %lx Length %lu\n", Irp, Irp->IoStatus.Status, Irp->IoStatus.Information, Length);
456
457 if (Irp->IoStatus.Status == STATUS_SUCCESS)
458 {
459 /* store the length */
460 Irp->IoStatus.Information = Length;
461 }
462 else
463 {
464 /* failed */
465 Irp->IoStatus.Information = 0;
466 }
467
468 /* free context */
469 FreeItem(Context);
470
471 return STATUS_SUCCESS;
472 }
473
474
475 NTSTATUS
476 NTAPI
477 WdmAudReadWrite(
478 IN PDEVICE_OBJECT DeviceObject,
479 IN PIRP Irp)
480 {
481 NTSTATUS Status;
482 PWDMAUD_DEVICE_INFO DeviceInfo;
483 PFILE_OBJECT FileObject;
484 PIO_STACK_LOCATION IoStack;
485 ULONG Length;
486 PMDL Mdl;
487 BOOLEAN Read = TRUE;
488 PWDMAUD_COMPLETION_CONTEXT Context;
489
490 /* allocate completion context */
491 Context = AllocateItem(NonPagedPool, sizeof(WDMAUD_COMPLETION_CONTEXT));
492
493 if (!Context)
494 {
495 /* not enough memory */
496 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
497 IoCompleteRequest(Irp, IO_NO_INCREMENT);
498
499 /* done */
500 return STATUS_INSUFFICIENT_RESOURCES;
501 }
502
503 /* get current irp stack location */
504 IoStack = IoGetCurrentIrpStackLocation(Irp);
505
506 /* store the input buffer in UserBuffer - as KsProbeStreamIrp operates on IRP_MJ_DEVICE_CONTROL */
507 Irp->UserBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
508
509 /* sanity check */
510 ASSERT(Irp->UserBuffer);
511
512 /* get the length of the request length */
513 Length = IoStack->Parameters.Write.Length;
514
515 /* store outputbuffer length */
516 IoStack->Parameters.DeviceIoControl.OutputBufferLength = Length;
517
518 /* setup context */
519 Context->Length = Length;
520 Context->Function = (IoStack->MajorFunction == IRP_MJ_WRITE ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM);
521 Context->Mdl = Irp->MdlAddress;
522
523 /* store mdl address */
524 Mdl = Irp->MdlAddress;
525
526 /* remove mdladdress as KsProbeStreamIrp will interprete it as an already probed audio buffer */
527 Irp->MdlAddress = NULL;
528
529 /* check for success */
530
531 if (IoStack->MajorFunction == IRP_MJ_WRITE)
532 {
533 /* probe the write stream irp */
534 Read = FALSE;
535 Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMWRITE | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length);
536 }
537 else
538 {
539 /* probe the read stream irp */
540 Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMREAD | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length);
541 }
542
543 if (!NT_SUCCESS(Status))
544 {
545 DPRINT1("KsProbeStreamIrp failed with Status %x Cancel %u\n", Status, Irp->Cancel);
546 Irp->MdlAddress = Mdl;
547 return SetIrpIoStatus(Irp, Status, 0);
548 }
549
550 /* get device info */
551 DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer;
552 ASSERT(DeviceInfo);
553
554 /* now get sysaudio file object */
555 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
556 if (!NT_SUCCESS(Status))
557 {
558 DPRINT1("Invalid pin handle %p\n", DeviceInfo->hDevice);
559 return SetIrpIoStatus(Irp, Status, 0);
560 }
561
562 /* skip current irp stack location */
563 IoSkipCurrentIrpStackLocation(Irp);
564
565 /* get next stack location */
566 IoStack = IoGetNextIrpStackLocation(Irp);
567
568 if (Read)
569 {
570 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_KS_READ_STREAM;
571 }
572 else
573 {
574 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_KS_WRITE_STREAM;
575 }
576
577 /* attach file object */
578 IoStack->FileObject = FileObject;
579 IoStack->Parameters.Write.Length = Length;
580 IoStack->MajorFunction = IRP_MJ_WRITE;
581
582 IoSetCompletionRoutine(Irp, IoCompletion, (PVOID)Context, TRUE, TRUE, TRUE);
583
584
585 /* mark irp as pending */
586 // IoMarkIrpPending(Irp);
587 /* call the driver */
588 Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
589
590 /* dereference file object */
591 ObDereferenceObject(FileObject);
592
593 return Status;
594 }