Merge r51067
[reactos.git] / reactos / 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 /* time to free all allocated mdls */
406 Mdl = Irp->MdlAddress;
407
408 while(Mdl)
409 {
410 /* get next mdl */
411 NextMdl = Mdl->Next;
412
413 /* unlock pages */
414 MmUnlockPages(Mdl);
415
416 /* grab next mdl */
417 Mdl = NextMdl;
418 }
419
420 /* clear mdl list */
421 Irp->MdlAddress = NULL;
422
423 /* check if mdl is locked */
424 if (Context->Mdl->MdlFlags & MDL_PAGES_LOCKED)
425 {
426 /* unlock pages */
427 MmUnlockPages(Context->Mdl);
428 }
429
430 /* now free the mdl */
431 IoFreeMdl(Context->Mdl);
432
433 DPRINT("IoCompletion Irp %p IoStatus %lx Information %lx Length %lu\n", Irp, Irp->IoStatus.Status, Irp->IoStatus.Information, Length);
434
435 if (!NT_SUCCESS(Irp->IoStatus.Status))
436 {
437 /* failed */
438 Irp->IoStatus.Information = 0;
439 }
440
441 /* free context */
442 FreeItem(Context);
443
444 return STATUS_SUCCESS;
445 }
446
447 NTSTATUS
448 NTAPI
449 WdmAudReadWrite(
450 IN PDEVICE_OBJECT DeviceObject,
451 IN PIRP Irp)
452 {
453 NTSTATUS Status;
454 PWDMAUD_DEVICE_INFO DeviceInfo;
455 PFILE_OBJECT FileObject;
456 PIO_STACK_LOCATION IoStack;
457 ULONG Length;
458 PMDL Mdl;
459 BOOLEAN Read = TRUE;
460 PWDMAUD_COMPLETION_CONTEXT Context;
461
462 /* allocate completion context */
463 Context = AllocateItem(NonPagedPool, sizeof(WDMAUD_COMPLETION_CONTEXT));
464
465 if (!Context)
466 {
467 /* not enough memory */
468 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
469 IoCompleteRequest(Irp, IO_NO_INCREMENT);
470
471 /* done */
472 return STATUS_INSUFFICIENT_RESOURCES;
473 }
474
475 /* get current irp stack location */
476 IoStack = IoGetCurrentIrpStackLocation(Irp);
477
478 /* store the input buffer in UserBuffer - as KsProbeStreamIrp operates on IRP_MJ_DEVICE_CONTROL */
479 Irp->UserBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
480
481 /* sanity check */
482 ASSERT(Irp->UserBuffer);
483
484 /* get the length of the request length */
485 Length = IoStack->Parameters.Write.Length;
486
487 /* store outputbuffer length */
488 IoStack->Parameters.DeviceIoControl.OutputBufferLength = Length;
489
490 /* setup context */
491 Context->Length = Length;
492 Context->Function = (IoStack->MajorFunction == IRP_MJ_WRITE ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM);
493 Context->Mdl = Irp->MdlAddress;
494
495 /* store mdl address */
496 Mdl = Irp->MdlAddress;
497
498 /* remove mdladdress as KsProbeStreamIrp will interprete it as an already probed audio buffer */
499 Irp->MdlAddress = NULL;
500
501 /* check for success */
502
503 if (IoStack->MajorFunction == IRP_MJ_WRITE)
504 {
505 /* probe the write stream irp */
506 Read = FALSE;
507 Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMWRITE | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length);
508 }
509 else
510 {
511 /* probe the read stream irp */
512 Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMREAD | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length);
513 }
514
515 if (!NT_SUCCESS(Status))
516 {
517 DPRINT1("KsProbeStreamIrp failed with Status %x Cancel %u\n", Status, Irp->Cancel);
518 Irp->MdlAddress = Mdl;
519 return SetIrpIoStatus(Irp, Status, 0);
520 }
521
522 /* get device info */
523 DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer;
524 ASSERT(DeviceInfo);
525
526 /* now get sysaudio file object */
527 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
528 if (!NT_SUCCESS(Status))
529 {
530 DPRINT1("Invalid pin handle %p\n", DeviceInfo->hDevice);
531 return SetIrpIoStatus(Irp, Status, 0);
532 }
533
534 /* skip current irp stack location */
535 IoSkipCurrentIrpStackLocation(Irp);
536
537 /* get next stack location */
538 IoStack = IoGetNextIrpStackLocation(Irp);
539
540 if (Read)
541 {
542 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_KS_READ_STREAM;
543 }
544 else
545 {
546 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_KS_WRITE_STREAM;
547 }
548
549 /* attach file object */
550 IoStack->FileObject = FileObject;
551 IoStack->Parameters.Write.Length = Length;
552 IoStack->MajorFunction = IRP_MJ_WRITE;
553
554 IoSetCompletionRoutine(Irp, IoCompletion, (PVOID)Context, TRUE, TRUE, TRUE);
555
556
557 /* mark irp as pending */
558 // IoMarkIrpPending(Irp);
559 /* call the driver */
560 Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
561
562 /* dereference file object */
563 ObDereferenceObject(FileObject);
564
565 return Status;
566 }