xref: /reactos/drivers/usb/usbccgp/fdo.c (revision 09dde2cf)
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 allocate 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 STATUS_SUCCESS;
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     Irp->IoStatus.Status = STATUS_SUCCESS;
163 
164     /* Request completed successfully */
165     return STATUS_SUCCESS;
166 }
167 
168 NTSTATUS
169 FDO_CreateChildPdo(
170     IN PDEVICE_OBJECT DeviceObject)
171 {
172     NTSTATUS Status;
173     PDEVICE_OBJECT PDODeviceObject;
174     PPDO_DEVICE_EXTENSION PDODeviceExtension;
175     PFDO_DEVICE_EXTENSION FDODeviceExtension;
176     ULONG Index;
177 
178     /* Get device extension */
179     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
180     ASSERT(FDODeviceExtension->Common.IsFDO);
181 
182     /* Lets create array for the child PDO */
183     FDODeviceExtension->ChildPDO = AllocateItem(NonPagedPool,
184                                                 sizeof(PDEVICE_OBJECT) * FDODeviceExtension->FunctionDescriptorCount);
185     if (!FDODeviceExtension->ChildPDO)
186     {
187         /* No memory */
188         return STATUS_INSUFFICIENT_RESOURCES;
189     }
190 
191     /* Create pdo for each function */
192     for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
193     {
194         /* Create the PDO */
195         Status = IoCreateDevice(FDODeviceExtension->DriverObject,
196                                 sizeof(PDO_DEVICE_EXTENSION),
197                                 NULL,
198                                 FILE_DEVICE_USB,
199                                 FILE_AUTOGENERATED_DEVICE_NAME,
200                                 FALSE,
201                                 &PDODeviceObject);
202         if (!NT_SUCCESS(Status))
203         {
204             /* Failed to create device object */
205             DPRINT1("IoCreateDevice failed with %x\n", Status);
206             return Status;
207         }
208 
209         /* Store in array */
210         FDODeviceExtension->ChildPDO[Index] = PDODeviceObject;
211 
212         /* Get device extension */
213         PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
214         RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
215 
216         /* Init device extension */
217         PDODeviceExtension->Common.IsFDO = FALSE;
218         PDODeviceExtension->FunctionDescriptor = &FDODeviceExtension->FunctionDescriptor[Index];
219         PDODeviceExtension->NextDeviceObject = DeviceObject;
220         PDODeviceExtension->FunctionIndex = Index;
221         PDODeviceExtension->FDODeviceExtension = FDODeviceExtension;
222         PDODeviceExtension->InterfaceList = FDODeviceExtension->InterfaceList;
223         PDODeviceExtension->InterfaceListCount = FDODeviceExtension->InterfaceListCount;
224         PDODeviceExtension->ConfigurationHandle = FDODeviceExtension->ConfigurationHandle;
225         PDODeviceExtension->ConfigurationDescriptor = FDODeviceExtension->ConfigurationDescriptor;
226         RtlCopyMemory(&PDODeviceExtension->Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
227         RtlCopyMemory(&PDODeviceExtension->DeviceDescriptor, FDODeviceExtension->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
228 
229         /* Patch the stack size */
230         PDODeviceObject->StackSize = DeviceObject->StackSize + 1;
231 
232         /* Set device flags */
233         PDODeviceObject->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
234 
235         /* Device is initialized */
236         PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
237     }
238 
239     /* Done */
240     return STATUS_SUCCESS;
241 }
242 
243 NTSTATUS
244 FDO_StartDevice(
245     PDEVICE_OBJECT DeviceObject,
246     PIRP Irp)
247 {
248     NTSTATUS Status;
249     PFDO_DEVICE_EXTENSION FDODeviceExtension;
250 
251     /* Get device extension */
252     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
253     ASSERT(FDODeviceExtension->Common.IsFDO);
254 
255     /* First start lower device */
256     if (IoForwardIrpSynchronously(FDODeviceExtension->NextDeviceObject, Irp))
257     {
258         Status = Irp->IoStatus.Status;
259     }
260     else
261     {
262         Status = STATUS_UNSUCCESSFUL;
263     }
264 
265     if (!NT_SUCCESS(Status))
266     {
267         /* Failed to start lower device */
268         DPRINT1("FDO_StartDevice lower device failed to start with %x\n", Status);
269         return Status;
270     }
271 
272     /* Get descriptors */
273     Status = USBCCGP_GetDescriptors(DeviceObject);
274     if (!NT_SUCCESS(Status))
275     {
276         /* Failed to start lower device */
277         DPRINT1("FDO_StartDevice failed to get descriptors with %x\n", Status);
278         return Status;
279     }
280 
281     /* Get capabilities */
282     Status = FDO_QueryCapabilities(DeviceObject,
283                                    &FDODeviceExtension->Capabilities);
284     if (!NT_SUCCESS(Status))
285     {
286         /* Failed to start lower device */
287         DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
288         return Status;
289     }
290 
291     /* Now select the configuration */
292     Status = USBCCGP_SelectConfiguration(DeviceObject, FDODeviceExtension);
293     if (!NT_SUCCESS(Status))
294     {
295         /* Failed to select interface */
296         DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
297         return Status;
298     }
299 
300     /* Query bus interface */
301     USBCCGP_QueryInterface(FDODeviceExtension->NextDeviceObject,
302                            &FDODeviceExtension->BusInterface);
303 
304     /* Now enumerate the functions */
305     Status = USBCCGP_EnumerateFunctions(DeviceObject);
306     if (!NT_SUCCESS(Status))
307     {
308         /* Failed to enumerate functions */
309         DPRINT1("Failed to enumerate functions with %x\n", Status);
310         return Status;
311     }
312 
313     /* Sanity checks */
314     ASSERT(FDODeviceExtension->FunctionDescriptorCount);
315     ASSERT(FDODeviceExtension->FunctionDescriptor);
316     DumpFunctionDescriptor(FDODeviceExtension->FunctionDescriptor,
317                            FDODeviceExtension->FunctionDescriptorCount);
318 
319     /* Now create the pdo */
320     Status = FDO_CreateChildPdo(DeviceObject);
321     if (!NT_SUCCESS(Status))
322     {
323         /* Failed */
324         DPRINT1("FDO_CreateChildPdo failed with %x\n", Status);
325         return Status;
326     }
327 
328     /* Inform pnp manager of new device objects */
329     IoInvalidateDeviceRelations(FDODeviceExtension->PhysicalDeviceObject,
330                                 BusRelations);
331 
332     /* Done */
333     DPRINT("[USBCCGP] FDO initialized successfully\n");
334     return Status;
335 }
336 
337 NTSTATUS
338 FDO_CloseConfiguration(
339     IN PDEVICE_OBJECT DeviceObject)
340 {
341     NTSTATUS Status;
342     PURB Urb;
343     PFDO_DEVICE_EXTENSION FDODeviceExtension;
344 
345     /* Get device extension */
346     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
347     ASSERT(FDODeviceExtension->Common.IsFDO);
348 
349     /* Nothing to do if we're not configured */
350     if (FDODeviceExtension->ConfigurationDescriptor == NULL ||
351         FDODeviceExtension->InterfaceList == NULL)
352     {
353         return STATUS_SUCCESS;
354     }
355 
356     /* Now allocate the urb */
357     Urb = USBD_CreateConfigurationRequestEx(FDODeviceExtension->ConfigurationDescriptor,
358                                             FDODeviceExtension->InterfaceList);
359     if (!Urb)
360     {
361         /* No memory */
362         return STATUS_INSUFFICIENT_RESOURCES;
363     }
364 
365     /* Clear configuration descriptor to make it an unconfigure request */
366     Urb->UrbSelectConfiguration.ConfigurationDescriptor = NULL;
367 
368     /* Submit urb */
369     Status = USBCCGP_SyncUrbRequest(FDODeviceExtension->NextDeviceObject, Urb);
370     if (!NT_SUCCESS(Status))
371     {
372         /* Failed to set configuration */
373         DPRINT1("USBCCGP_SyncUrbRequest failed to unconfigure device\n", Status);
374     }
375 
376     ExFreePool(Urb);
377     return Status;
378 }
379 
380 
381 NTSTATUS
382 FDO_HandlePnp(
383     PDEVICE_OBJECT DeviceObject,
384     PIRP Irp)
385 {
386     PIO_STACK_LOCATION IoStack;
387     NTSTATUS Status;
388     PFDO_DEVICE_EXTENSION FDODeviceExtension;
389 
390     /* Get device extension */
391     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
392     ASSERT(FDODeviceExtension->Common.IsFDO);
393 
394 
395     /* Get stack location */
396     IoStack = IoGetCurrentIrpStackLocation(Irp);
397     DPRINT("[USBCCGP] PnP Minor %x\n", IoStack->MinorFunction);
398     switch(IoStack->MinorFunction)
399     {
400         case IRP_MN_REMOVE_DEVICE:
401         {
402             // Unconfigure device */
403             DPRINT1("[USBCCGP] FDO IRP_MN_REMOVE\n");
404             FDO_CloseConfiguration(DeviceObject);
405 
406             /* Send the IRP down the stack */
407             Irp->IoStatus.Status = STATUS_SUCCESS;
408             IoSkipCurrentIrpStackLocation(Irp);
409             Status = IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
410 
411             /* Detach from the device stack */
412             IoDetachDevice(FDODeviceExtension->NextDeviceObject);
413 
414             /* Delete the device object */
415             IoDeleteDevice(DeviceObject);
416 
417             /* Request completed */
418             break;
419         }
420         case IRP_MN_START_DEVICE:
421         {
422             /* Start the device */
423             Status = FDO_StartDevice(DeviceObject, Irp);
424             break;
425         }
426         case IRP_MN_QUERY_DEVICE_RELATIONS:
427         {
428             /* Handle device relations */
429             Status = FDO_DeviceRelations(DeviceObject, Irp);
430             if (!NT_SUCCESS(Status))
431             {
432                 break;
433             }
434 
435             /* Forward irp to next device object */
436             IoSkipCurrentIrpStackLocation(Irp);
437             return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
438         }
439         case IRP_MN_QUERY_CAPABILITIES:
440         {
441             /* Copy capabilities */
442             RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities,
443                           &FDODeviceExtension->Capabilities,
444                           sizeof(DEVICE_CAPABILITIES));
445             Status = STATUS_UNSUCCESSFUL;
446 
447             if (IoForwardIrpSynchronously(FDODeviceExtension->NextDeviceObject, Irp))
448             {
449                 Status = Irp->IoStatus.Status;
450                 if (NT_SUCCESS(Status))
451                 {
452                     IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
453                 }
454             }
455             break;
456        }
457         case IRP_MN_QUERY_REMOVE_DEVICE:
458         case IRP_MN_QUERY_STOP_DEVICE:
459         {
460             /* Sure */
461             Irp->IoStatus.Status = STATUS_SUCCESS;
462 
463             /* Forward irp to next device object */
464             IoSkipCurrentIrpStackLocation(Irp);
465             return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
466         }
467        default:
468        {
469             /* Forward irp to next device object */
470             IoSkipCurrentIrpStackLocation(Irp);
471             return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
472        }
473 
474     }
475 
476     /* Complete request */
477     Irp->IoStatus.Status = Status;
478     IoCompleteRequest(Irp, IO_NO_INCREMENT);
479     return Status;
480 }
481 
482 NTSTATUS
483 FDO_HandleResetCyclePort(
484     PDEVICE_OBJECT DeviceObject,
485     PIRP Irp)
486 {
487     PIO_STACK_LOCATION IoStack;
488     NTSTATUS Status;
489     PFDO_DEVICE_EXTENSION FDODeviceExtension;
490     PLIST_ENTRY ListHead, Entry;
491     LIST_ENTRY TempList;
492     PUCHAR ResetActive;
493     PIRP ListIrp;
494     KIRQL OldLevel;
495 
496     /* Get device extension */
497     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
498     ASSERT(FDODeviceExtension->Common.IsFDO);
499 
500     /* Get stack location */
501     IoStack = IoGetCurrentIrpStackLocation(Irp);
502     DPRINT("FDO_HandleResetCyclePort IOCTL %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
503 
504     if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_RESET_PORT)
505     {
506         /* Use reset port list */
507         ListHead = &FDODeviceExtension->ResetPortListHead;
508         ResetActive = &FDODeviceExtension->ResetPortActive;
509     }
510     else
511     {
512         /* Use cycle port list */
513         ListHead = &FDODeviceExtension->CyclePortListHead;
514         ResetActive = &FDODeviceExtension->CyclePortActive;
515     }
516 
517     /* Acquire lock */
518     KeAcquireSpinLock(&FDODeviceExtension->Lock, &OldLevel);
519 
520     if (*ResetActive)
521     {
522         /* Insert into pending list */
523         InsertTailList(ListHead, &Irp->Tail.Overlay.ListEntry);
524 
525         /* Mark irp pending */
526         IoMarkIrpPending(Irp);
527         Status = STATUS_PENDING;
528 
529         /* Release lock */
530         KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
531     }
532     else
533     {
534         /* Mark reset active */
535         *ResetActive = TRUE;
536 
537         /* Release lock */
538         KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
539 
540         /* Forward request synchronized */
541         NT_VERIFY(IoForwardIrpSynchronously(FDODeviceExtension->NextDeviceObject, Irp));
542 
543         /* Reacquire lock */
544         KeAcquireSpinLock(&FDODeviceExtension->Lock, &OldLevel);
545 
546         /* Mark reset as completed */
547         *ResetActive = FALSE;
548 
549         /* Move all requests into temporary list */
550         InitializeListHead(&TempList);
551         while(!IsListEmpty(ListHead))
552         {
553             Entry = RemoveHeadList(ListHead);
554             InsertTailList(&TempList, Entry);
555         }
556 
557         /* Release lock */
558         KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
559 
560         /* Complete pending irps */
561         while(!IsListEmpty(&TempList))
562         {
563             Entry = RemoveHeadList(&TempList);
564             ListIrp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
565 
566             /* Complete request with status success */
567             ListIrp->IoStatus.Status = STATUS_SUCCESS;
568             IoCompleteRequest(ListIrp, IO_NO_INCREMENT);
569         }
570 
571         /* Status success */
572         Status = STATUS_SUCCESS;
573     }
574 
575     return Status;
576 }
577 
578 
579 
580 NTSTATUS
581 FDO_HandleInternalDeviceControl(
582     PDEVICE_OBJECT DeviceObject,
583     PIRP Irp)
584 {
585     PIO_STACK_LOCATION IoStack;
586     NTSTATUS Status;
587     PFDO_DEVICE_EXTENSION FDODeviceExtension;
588 
589     /* Get device extension */
590     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
591     ASSERT(FDODeviceExtension->Common.IsFDO);
592 
593     /* Get stack location */
594     IoStack = IoGetCurrentIrpStackLocation(Irp);
595 
596     if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_RESET_PORT ||
597         IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_CYCLE_PORT)
598     {
599         /* Handle reset / cycle ports */
600         Status = FDO_HandleResetCyclePort(DeviceObject, Irp);
601         DPRINT("FDO_HandleResetCyclePort Status %x\n", Status);
602         if (Status != STATUS_PENDING)
603         {
604             /* Complete request */
605             Irp->IoStatus.Status = Status;
606             IoCompleteRequest(Irp, IO_NO_INCREMENT);
607         }
608         return Status;
609     }
610 
611     /* Forward and forget request */
612     IoSkipCurrentIrpStackLocation(Irp);
613     return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
614 }
615 
616 NTSTATUS
617 FDO_HandleSystemControl(
618     PDEVICE_OBJECT DeviceObject,
619     PIRP Irp)
620 {
621     PFDO_DEVICE_EXTENSION FDODeviceExtension;
622 
623     /* Get device extension */
624     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
625     ASSERT(FDODeviceExtension->Common.IsFDO);
626 
627     /* Forward and forget request */
628     IoSkipCurrentIrpStackLocation(Irp);
629     return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
630 }
631 
632 NTSTATUS
633 FDO_Dispatch(
634     PDEVICE_OBJECT DeviceObject,
635     PIRP Irp)
636 {
637     PIO_STACK_LOCATION IoStack;
638     NTSTATUS Status;
639     PFDO_DEVICE_EXTENSION FDODeviceExtension;
640 
641     /* Get device extension */
642     FDODeviceExtension = DeviceObject->DeviceExtension;
643     ASSERT(FDODeviceExtension->Common.IsFDO);
644 
645     /* Get stack location */
646     IoStack = IoGetCurrentIrpStackLocation(Irp);
647 
648     switch(IoStack->MajorFunction)
649     {
650         case IRP_MJ_PNP:
651             return FDO_HandlePnp(DeviceObject, Irp);
652         case IRP_MJ_INTERNAL_DEVICE_CONTROL:
653             return FDO_HandleInternalDeviceControl(DeviceObject, Irp);
654         case IRP_MJ_POWER:
655             PoStartNextPowerIrp(Irp);
656             IoSkipCurrentIrpStackLocation(Irp);
657             return PoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
658         case IRP_MJ_SYSTEM_CONTROL:
659             return FDO_HandleSystemControl(DeviceObject, Irp);
660         default:
661             DPRINT1("FDO_Dispatch Function %x not implemented\n", IoStack->MajorFunction);
662             ASSERT(FALSE);
663             Status = Irp->IoStatus.Status;
664             IoCompleteRequest(Irp, IO_NO_INCREMENT);
665             return Status;
666     }
667 
668 }
669