Sync with trunk r63383 .
[reactos.git] / drivers / usb / usbccgp / fdo.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbccgp/fdo.c
5 * PURPOSE: USB device driver.
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 * Cameron Gutman
10 */
11
12 #include "usbccgp.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 NTSTATUS
18 NTAPI
19 FDO_QueryCapabilitiesCompletionRoutine(
20 IN PDEVICE_OBJECT DeviceObject,
21 IN PIRP Irp,
22 IN PVOID Context)
23 {
24 /* Set event */
25 KeSetEvent((PRKEVENT)Context, 0, FALSE);
26
27 /* Completion is done in the HidClassFDO_QueryCapabilities routine */
28 return STATUS_MORE_PROCESSING_REQUIRED;
29 }
30
31 NTSTATUS
32 FDO_QueryCapabilities(
33 IN PDEVICE_OBJECT DeviceObject,
34 IN OUT PDEVICE_CAPABILITIES Capabilities)
35 {
36 PIRP Irp;
37 KEVENT Event;
38 NTSTATUS Status;
39 PIO_STACK_LOCATION IoStack;
40 PFDO_DEVICE_EXTENSION FDODeviceExtension;
41
42 /* Get device extension */
43 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
44 ASSERT(FDODeviceExtension->Common.IsFDO);
45
46 /* Init event */
47 KeInitializeEvent(&Event, NotificationEvent, FALSE);
48
49 /* Now allocte the irp */
50 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
51 if (!Irp)
52 {
53 /* No memory */
54 return STATUS_INSUFFICIENT_RESOURCES;
55 }
56
57 /* Get next stack location */
58 IoStack = IoGetNextIrpStackLocation(Irp);
59
60 /* Init stack location */
61 IoStack->MajorFunction = IRP_MJ_PNP;
62 IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
63 IoStack->Parameters.DeviceCapabilities.Capabilities = Capabilities;
64
65 /* Set completion routine */
66 IoSetCompletionRoutine(Irp,
67 FDO_QueryCapabilitiesCompletionRoutine,
68 (PVOID)&Event,
69 TRUE,
70 TRUE,
71 TRUE);
72
73 /* Init capabilities */
74 RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES));
75 Capabilities->Size = sizeof(DEVICE_CAPABILITIES);
76 Capabilities->Version = 1; // FIXME hardcoded constant
77 Capabilities->Address = MAXULONG;
78 Capabilities->UINumber = MAXULONG;
79
80 /* Pnp irps have default completion code */
81 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
82
83 /* Call lower device */
84 Status = IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
85 if (Status == STATUS_PENDING)
86 {
87 /* Wait for completion */
88 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
89 }
90
91 /* Get status */
92 Status = Irp->IoStatus.Status;
93
94 /* Complete request */
95 IoFreeIrp(Irp);
96
97 /* Done */
98 return Status;
99 }
100
101 NTSTATUS
102 FDO_DeviceRelations(
103 PDEVICE_OBJECT DeviceObject,
104 PIRP Irp)
105 {
106 ULONG DeviceCount = 0;
107 ULONG Index;
108 PDEVICE_RELATIONS DeviceRelations;
109 PIO_STACK_LOCATION IoStack;
110 PFDO_DEVICE_EXTENSION FDODeviceExtension;
111
112 /* Get device extension */
113 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
114
115 /* Get current irp stack location */
116 IoStack = IoGetCurrentIrpStackLocation(Irp);
117
118 /* Check if relation type is BusRelations */
119 if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
120 {
121 /* FDO always only handles bus relations */
122 return USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
123 }
124
125 /* Go through array and count device objects */
126 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
127 {
128 if (FDODeviceExtension->ChildPDO[Index])
129 {
130 /* Child pdo */
131 DeviceCount++;
132 }
133 }
134
135 /* Allocate device relations */
136 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool,
137 sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? (DeviceCount-1) * sizeof(PDEVICE_OBJECT) : 0));
138 if (!DeviceRelations)
139 {
140 /* No memory */
141 return STATUS_INSUFFICIENT_RESOURCES;
142 }
143
144 /* Add device objects */
145 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
146 {
147 if (FDODeviceExtension->ChildPDO[Index])
148 {
149 /* Store child pdo */
150 DeviceRelations->Objects[DeviceRelations->Count] = FDODeviceExtension->ChildPDO[Index];
151
152 /* Add reference */
153 ObReferenceObject(FDODeviceExtension->ChildPDO[Index]);
154
155 /* Increment count */
156 DeviceRelations->Count++;
157 }
158 }
159
160 /* Store result */
161 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
162
163 /* Request completed successfully */
164 return STATUS_SUCCESS;
165 }
166
167 NTSTATUS
168 FDO_CreateChildPdo(
169 IN PDEVICE_OBJECT DeviceObject)
170 {
171 NTSTATUS Status;
172 PDEVICE_OBJECT PDODeviceObject;
173 PPDO_DEVICE_EXTENSION PDODeviceExtension;
174 PFDO_DEVICE_EXTENSION FDODeviceExtension;
175 ULONG Index;
176
177 /* Get device extension */
178 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
179 ASSERT(FDODeviceExtension->Common.IsFDO);
180
181 /* Lets create array for the child PDO */
182 FDODeviceExtension->ChildPDO = AllocateItem(NonPagedPool,
183 sizeof(PDEVICE_OBJECT) * FDODeviceExtension->FunctionDescriptorCount);
184 if (!FDODeviceExtension->ChildPDO)
185 {
186 /* No memory */
187 return STATUS_INSUFFICIENT_RESOURCES;
188 }
189
190 /* Create pdo for each function */
191 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
192 {
193 /* Create the PDO */
194 Status = IoCreateDevice(FDODeviceExtension->DriverObject,
195 sizeof(PDO_DEVICE_EXTENSION),
196 NULL,
197 FILE_DEVICE_USB,
198 FILE_AUTOGENERATED_DEVICE_NAME,
199 FALSE,
200 &PDODeviceObject);
201 if (!NT_SUCCESS(Status))
202 {
203 /* Failed to create device object */
204 DPRINT1("IoCreateDevice failed with %x\n", Status);
205 return Status;
206 }
207
208 /* Store in array */
209 FDODeviceExtension->ChildPDO[Index] = PDODeviceObject;
210
211 /* Get device extension */
212 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
213 RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
214
215 /* Init device extension */
216 PDODeviceExtension->Common.IsFDO = FALSE;
217 PDODeviceExtension->FunctionDescriptor = &FDODeviceExtension->FunctionDescriptor[Index];
218 PDODeviceExtension->NextDeviceObject = DeviceObject;
219 PDODeviceExtension->FunctionIndex = Index;
220 PDODeviceExtension->FDODeviceExtension = FDODeviceExtension;
221 PDODeviceExtension->InterfaceList = FDODeviceExtension->InterfaceList;
222 PDODeviceExtension->InterfaceListCount = FDODeviceExtension->InterfaceListCount;
223 PDODeviceExtension->ConfigurationHandle = FDODeviceExtension->ConfigurationHandle;
224 PDODeviceExtension->ConfigurationDescriptor = FDODeviceExtension->ConfigurationDescriptor;
225 RtlCopyMemory(&PDODeviceExtension->Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
226 RtlCopyMemory(&PDODeviceExtension->DeviceDescriptor, &FDODeviceExtension->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
227
228 /* Patch the stack size */
229 PDODeviceObject->StackSize = DeviceObject->StackSize + 1;
230
231 /* Set device flags */
232 PDODeviceObject->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
233
234 /* Device is initialized */
235 PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
236 }
237
238 /* Done */
239 return STATUS_SUCCESS;
240 }
241
242 NTSTATUS
243 FDO_StartDevice(
244 PDEVICE_OBJECT DeviceObject,
245 PIRP Irp)
246 {
247 NTSTATUS Status;
248 PFDO_DEVICE_EXTENSION FDODeviceExtension;
249
250 /* Get device extension */
251 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
252 ASSERT(FDODeviceExtension->Common.IsFDO);
253
254 /* First start lower device */
255 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
256
257 if (!NT_SUCCESS(Status))
258 {
259 /* Failed to start lower device */
260 DPRINT1("FDO_StartDevice lower device failed to start with %x\n", Status);
261 return Status;
262 }
263
264 /* Get descriptors */
265 Status = USBCCGP_GetDescriptors(DeviceObject);
266 if (!NT_SUCCESS(Status))
267 {
268 /* Failed to start lower device */
269 DPRINT1("FDO_StartDevice failed to get descriptors with %x\n", Status);
270 return Status;
271 }
272
273 /* Get capabilities */
274 Status = FDO_QueryCapabilities(DeviceObject,
275 &FDODeviceExtension->Capabilities);
276 if (!NT_SUCCESS(Status))
277 {
278 /* Failed to start lower device */
279 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
280 return Status;
281 }
282
283 /* Now select the configuration */
284 Status = USBCCGP_SelectConfiguration(DeviceObject, FDODeviceExtension);
285 if (!NT_SUCCESS(Status))
286 {
287 /* Failed to select interface */
288 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
289 return Status;
290 }
291
292 /* Query bus interface */
293 USBCCGP_QueryInterface(FDODeviceExtension->NextDeviceObject,
294 &FDODeviceExtension->BusInterface);
295
296 /* Now enumerate the functions */
297 Status = USBCCGP_EnumerateFunctions(DeviceObject);
298 if (!NT_SUCCESS(Status))
299 {
300 /* Failed to enumerate functions */
301 DPRINT1("Failed to enumerate functions with %x\n", Status);
302 return Status;
303 }
304
305 /* Sanity checks */
306 ASSERT(FDODeviceExtension->FunctionDescriptorCount);
307 ASSERT(FDODeviceExtension->FunctionDescriptor);
308 DumpFunctionDescriptor(FDODeviceExtension->FunctionDescriptor,
309 FDODeviceExtension->FunctionDescriptorCount);
310
311 /* Now create the pdo */
312 Status = FDO_CreateChildPdo(DeviceObject);
313 if (!NT_SUCCESS(Status))
314 {
315 /* Failed */
316 DPRINT1("FDO_CreateChildPdo failed with %x\n", Status);
317 return Status;
318 }
319
320 /* Inform pnp manager of new device objects */
321 IoInvalidateDeviceRelations(FDODeviceExtension->PhysicalDeviceObject,
322 BusRelations);
323
324 /* Done */
325 DPRINT("[USBCCGP] FDO initialized successfully\n");
326 return Status;
327 }
328
329 NTSTATUS
330 FDO_CloseConfiguration(
331 IN PDEVICE_OBJECT DeviceObject)
332 {
333 NTSTATUS Status;
334 PURB Urb;
335 PFDO_DEVICE_EXTENSION FDODeviceExtension;
336
337 /* Get device extension */
338 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
339 ASSERT(FDODeviceExtension->Common.IsFDO);
340
341 /* Now allocate the urb */
342 Urb = USBD_CreateConfigurationRequestEx(FDODeviceExtension->ConfigurationDescriptor,
343 FDODeviceExtension->InterfaceList);
344 if (!Urb)
345 {
346 /* No memory */
347 return STATUS_INSUFFICIENT_RESOURCES;
348 }
349
350 /* Clear configuration descriptor to make it an unconfigure request */
351 Urb->UrbSelectConfiguration.ConfigurationDescriptor = NULL;
352
353 /* Submit urb */
354 Status = USBCCGP_SyncUrbRequest(FDODeviceExtension->NextDeviceObject, Urb);
355 if (!NT_SUCCESS(Status))
356 {
357 /* Failed to set configuration */
358 DPRINT1("USBCCGP_SyncUrbRequest failed to unconfigure device\n", Status);
359 }
360
361 ExFreePool(Urb);
362 return Status;
363 }
364
365
366 NTSTATUS
367 FDO_HandlePnp(
368 PDEVICE_OBJECT DeviceObject,
369 PIRP Irp)
370 {
371 PIO_STACK_LOCATION IoStack;
372 NTSTATUS Status;
373 PFDO_DEVICE_EXTENSION FDODeviceExtension;
374
375 /* Get device extension */
376 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
377 ASSERT(FDODeviceExtension->Common.IsFDO);
378
379
380 /* Get stack location */
381 IoStack = IoGetCurrentIrpStackLocation(Irp);
382 DPRINT("[USBCCGP] PnP Minor %x\n", IoStack->MinorFunction);
383 switch(IoStack->MinorFunction)
384 {
385 case IRP_MN_REMOVE_DEVICE:
386 {
387 // Unconfigure device */
388 DPRINT1("[USBCCGP] FDO IRP_MN_REMOVE\n");
389 FDO_CloseConfiguration(DeviceObject);
390
391 /* Send the IRP down the stack */
392 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject,
393 Irp);
394 if (NT_SUCCESS(Status))
395 {
396 /* Detach from the device stack */
397 IoDetachDevice(FDODeviceExtension->NextDeviceObject);
398
399 /* Delete the device object */
400 IoDeleteDevice(DeviceObject);
401 }
402
403 /* Request completed */
404 break;
405 }
406 case IRP_MN_START_DEVICE:
407 {
408 /* Start the device */
409 Status = FDO_StartDevice(DeviceObject, Irp);
410 break;
411 }
412 case IRP_MN_QUERY_DEVICE_RELATIONS:
413 {
414 /* Handle device relations */
415 Status = FDO_DeviceRelations(DeviceObject, Irp);
416 break;
417 }
418 case IRP_MN_QUERY_CAPABILITIES:
419 {
420 /* Copy capabilities */
421 RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities,
422 &FDODeviceExtension->Capabilities,
423 sizeof(DEVICE_CAPABILITIES));
424 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
425 if (NT_SUCCESS(Status))
426 {
427 /* Surprise removal ok */
428 IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
429 }
430 break;
431 }
432 case IRP_MN_QUERY_REMOVE_DEVICE:
433 case IRP_MN_QUERY_STOP_DEVICE:
434 {
435 /* Sure */
436 Irp->IoStatus.Status = STATUS_SUCCESS;
437
438 /* Forward irp to next device object */
439 IoSkipCurrentIrpStackLocation(Irp);
440 return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
441 }
442 default:
443 {
444 /* Forward irp to next device object */
445 IoSkipCurrentIrpStackLocation(Irp);
446 return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
447 }
448
449 }
450
451 /* Complete request */
452 Irp->IoStatus.Status = Status;
453 IoCompleteRequest(Irp, IO_NO_INCREMENT);
454 return Status;
455 }
456
457 NTSTATUS
458 FDO_HandleResetCyclePort(
459 PDEVICE_OBJECT DeviceObject,
460 PIRP Irp)
461 {
462 PIO_STACK_LOCATION IoStack;
463 NTSTATUS Status;
464 PFDO_DEVICE_EXTENSION FDODeviceExtension;
465 PLIST_ENTRY ListHead, Entry;
466 LIST_ENTRY TempList;
467 PUCHAR ResetActive;
468 PIRP ListIrp;
469 KIRQL OldLevel;
470
471 /* Get device extension */
472 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
473 ASSERT(FDODeviceExtension->Common.IsFDO);
474
475 /* Get stack location */
476 IoStack = IoGetCurrentIrpStackLocation(Irp);
477 DPRINT("FDO_HandleResetCyclePort IOCTL %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
478
479 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_RESET_PORT)
480 {
481 /* Use reset port list */
482 ListHead = &FDODeviceExtension->ResetPortListHead;
483 ResetActive = &FDODeviceExtension->ResetPortActive;
484 }
485 else
486 {
487 /* Use cycle port list */
488 ListHead = &FDODeviceExtension->CyclePortListHead;
489 ResetActive = &FDODeviceExtension->CyclePortActive;
490 }
491
492 /* Acquire lock */
493 KeAcquireSpinLock(&FDODeviceExtension->Lock, &OldLevel);
494
495 if (*ResetActive)
496 {
497 /* Insert into pending list */
498 InsertTailList(ListHead, &Irp->Tail.Overlay.ListEntry);
499
500 /* Mark irp pending */
501 IoMarkIrpPending(Irp);
502 Status = STATUS_PENDING;
503
504 /* Release lock */
505 KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
506 }
507 else
508 {
509 /* Mark reset active */
510 *ResetActive = TRUE;
511
512 /* Release lock */
513 KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
514
515 /* Forward request synchronized */
516 USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
517
518 /* Reacquire lock */
519 KeAcquireSpinLock(&FDODeviceExtension->Lock, &OldLevel);
520
521 /* Mark reset as completed */
522 *ResetActive = FALSE;
523
524 /* Move all requests into temporary list */
525 InitializeListHead(&TempList);
526 while(!IsListEmpty(ListHead))
527 {
528 Entry = RemoveHeadList(ListHead);
529 InsertTailList(&TempList, Entry);
530 }
531
532 /* Release lock */
533 KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
534
535 /* Complete pending irps */
536 while(!IsListEmpty(&TempList))
537 {
538 Entry = RemoveHeadList(&TempList);
539 ListIrp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
540
541 /* Complete request with status success */
542 ListIrp->IoStatus.Status = STATUS_SUCCESS;
543 IoCompleteRequest(ListIrp, IO_NO_INCREMENT);
544 }
545
546 /* Status success */
547 Status = STATUS_SUCCESS;
548 }
549
550 return Status;
551 }
552
553
554
555 NTSTATUS
556 FDO_HandleInternalDeviceControl(
557 PDEVICE_OBJECT DeviceObject,
558 PIRP Irp)
559 {
560 PIO_STACK_LOCATION IoStack;
561 NTSTATUS Status;
562 PFDO_DEVICE_EXTENSION FDODeviceExtension;
563
564 /* Get device extension */
565 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
566 ASSERT(FDODeviceExtension->Common.IsFDO);
567
568 /* Get stack location */
569 IoStack = IoGetCurrentIrpStackLocation(Irp);
570
571 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_RESET_PORT ||
572 IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_CYCLE_PORT)
573 {
574 /* Handle reset / cycle ports */
575 Status = FDO_HandleResetCyclePort(DeviceObject, Irp);
576 DPRINT("FDO_HandleResetCyclePort Status %x\n", Status);
577 if (Status != STATUS_PENDING)
578 {
579 /* Complete request */
580 Irp->IoStatus.Status = Status;
581 IoCompleteRequest(Irp, IO_NO_INCREMENT);
582 }
583 return Status;
584 }
585
586 /* Forward and forget request */
587 IoSkipCurrentIrpStackLocation(Irp);
588 return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
589 }
590
591 NTSTATUS
592 FDO_HandleSystemControl(
593 PDEVICE_OBJECT DeviceObject,
594 PIRP Irp)
595 {
596 PFDO_DEVICE_EXTENSION FDODeviceExtension;
597
598 /* Get device extension */
599 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
600 ASSERT(FDODeviceExtension->Common.IsFDO);
601
602 /* Forward and forget request */
603 IoSkipCurrentIrpStackLocation(Irp);
604 return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
605 }
606
607 NTSTATUS
608 FDO_Dispatch(
609 PDEVICE_OBJECT DeviceObject,
610 PIRP Irp)
611 {
612 PIO_STACK_LOCATION IoStack;
613 NTSTATUS Status;
614 PFDO_DEVICE_EXTENSION FDODeviceExtension;
615
616 /* Get device extension */
617 FDODeviceExtension = DeviceObject->DeviceExtension;
618 ASSERT(FDODeviceExtension->Common.IsFDO);
619
620 /* Get stack location */
621 IoStack = IoGetCurrentIrpStackLocation(Irp);
622
623 switch(IoStack->MajorFunction)
624 {
625 case IRP_MJ_PNP:
626 return FDO_HandlePnp(DeviceObject, Irp);
627 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
628 return FDO_HandleInternalDeviceControl(DeviceObject, Irp);
629 case IRP_MJ_POWER:
630 PoStartNextPowerIrp(Irp);
631 IoSkipCurrentIrpStackLocation(Irp);
632 return PoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
633 case IRP_MJ_SYSTEM_CONTROL:
634 return FDO_HandleSystemControl(DeviceObject, Irp);
635 default:
636 DPRINT1("FDO_Dispatch Function %x not implemented\n", IoStack->MajorFunction);
637 ASSERT(FALSE);
638 Status = Irp->IoStatus.Status;
639 IoCompleteRequest(Irp, IO_NO_INCREMENT);
640 return Status;
641 }
642
643 }