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.
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
19 FDO_QueryCapabilitiesCompletionRoutine(
20 IN PDEVICE_OBJECT DeviceObject
,
25 KeSetEvent((PRKEVENT
)Context
, 0, FALSE
);
27 /* Completion is done in the HidClassFDO_QueryCapabilities routine */
28 return STATUS_MORE_PROCESSING_REQUIRED
;
32 FDO_QueryCapabilities(
33 IN PDEVICE_OBJECT DeviceObject
,
34 IN OUT PDEVICE_CAPABILITIES Capabilities
)
39 PIO_STACK_LOCATION IoStack
;
40 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
42 /* Get device extension */
43 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
44 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
47 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
49 /* Now allocate the irp */
50 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
54 return STATUS_INSUFFICIENT_RESOURCES
;
57 /* Get next stack location */
58 IoStack
= IoGetNextIrpStackLocation(Irp
);
60 /* Init stack location */
61 IoStack
->MajorFunction
= IRP_MJ_PNP
;
62 IoStack
->MinorFunction
= IRP_MN_QUERY_CAPABILITIES
;
63 IoStack
->Parameters
.DeviceCapabilities
.Capabilities
= Capabilities
;
65 /* Set completion routine */
66 IoSetCompletionRoutine(Irp
,
67 FDO_QueryCapabilitiesCompletionRoutine
,
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
;
80 /* Pnp irps have default completion code */
81 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
83 /* Call lower device */
84 Status
= IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
85 if (Status
== STATUS_PENDING
)
87 /* Wait for completion */
88 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
92 Status
= Irp
->IoStatus
.Status
;
94 /* Complete request */
103 PDEVICE_OBJECT DeviceObject
,
106 ULONG DeviceCount
= 0;
108 PDEVICE_RELATIONS DeviceRelations
;
109 PIO_STACK_LOCATION IoStack
;
110 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
112 /* Get device extension */
113 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
115 /* Get current irp stack location */
116 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
118 /* Check if relation type is BusRelations */
119 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
121 /* FDO always only handles bus relations */
122 return STATUS_SUCCESS
;
125 /* Go through array and count device objects */
126 for(Index
= 0; Index
< FDODeviceExtension
->FunctionDescriptorCount
; Index
++)
128 if (FDODeviceExtension
->ChildPDO
[Index
])
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
)
141 return STATUS_INSUFFICIENT_RESOURCES
;
144 /* Add device objects */
145 for(Index
= 0; Index
< FDODeviceExtension
->FunctionDescriptorCount
; Index
++)
147 if (FDODeviceExtension
->ChildPDO
[Index
])
149 /* Store child pdo */
150 DeviceRelations
->Objects
[DeviceRelations
->Count
] = FDODeviceExtension
->ChildPDO
[Index
];
153 ObReferenceObject(FDODeviceExtension
->ChildPDO
[Index
]);
155 /* Increment count */
156 DeviceRelations
->Count
++;
161 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
162 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
164 /* Request completed successfully */
165 return STATUS_SUCCESS
;
170 IN PDEVICE_OBJECT DeviceObject
)
173 PDEVICE_OBJECT PDODeviceObject
;
174 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
175 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
178 /* Get device extension */
179 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
180 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
182 /* Lets create array for the child PDO */
183 FDODeviceExtension
->ChildPDO
= AllocateItem(NonPagedPool
,
184 sizeof(PDEVICE_OBJECT
) * FDODeviceExtension
->FunctionDescriptorCount
);
185 if (!FDODeviceExtension
->ChildPDO
)
188 return STATUS_INSUFFICIENT_RESOURCES
;
191 /* Create pdo for each function */
192 for(Index
= 0; Index
< FDODeviceExtension
->FunctionDescriptorCount
; Index
++)
195 Status
= IoCreateDevice(FDODeviceExtension
->DriverObject
,
196 sizeof(PDO_DEVICE_EXTENSION
),
199 FILE_AUTOGENERATED_DEVICE_NAME
,
202 if (!NT_SUCCESS(Status
))
204 /* Failed to create device object */
205 DPRINT1("IoCreateDevice failed with %x\n", Status
);
210 FDODeviceExtension
->ChildPDO
[Index
] = PDODeviceObject
;
212 /* Get device extension */
213 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)PDODeviceObject
->DeviceExtension
;
214 RtlZeroMemory(PDODeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
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
));
229 /* Patch the stack size */
230 PDODeviceObject
->StackSize
= DeviceObject
->StackSize
+ 1;
232 /* Set device flags */
233 PDODeviceObject
->Flags
|= DO_DIRECT_IO
| DO_MAP_IO_BUFFER
;
235 /* Device is initialized */
236 PDODeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
240 return STATUS_SUCCESS
;
245 PDEVICE_OBJECT DeviceObject
,
249 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
251 /* Get device extension */
252 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
253 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
255 /* First start lower device */
256 Status
= USBCCGP_SyncForwardIrp(FDODeviceExtension
->NextDeviceObject
, Irp
);
258 if (!NT_SUCCESS(Status
))
260 /* Failed to start lower device */
261 DPRINT1("FDO_StartDevice lower device failed to start with %x\n", Status
);
265 /* Get descriptors */
266 Status
= USBCCGP_GetDescriptors(DeviceObject
);
267 if (!NT_SUCCESS(Status
))
269 /* Failed to start lower device */
270 DPRINT1("FDO_StartDevice failed to get descriptors with %x\n", Status
);
274 /* Get capabilities */
275 Status
= FDO_QueryCapabilities(DeviceObject
,
276 &FDODeviceExtension
->Capabilities
);
277 if (!NT_SUCCESS(Status
))
279 /* Failed to start lower device */
280 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status
);
284 /* Now select the configuration */
285 Status
= USBCCGP_SelectConfiguration(DeviceObject
, FDODeviceExtension
);
286 if (!NT_SUCCESS(Status
))
288 /* Failed to select interface */
289 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status
);
293 /* Query bus interface */
294 USBCCGP_QueryInterface(FDODeviceExtension
->NextDeviceObject
,
295 &FDODeviceExtension
->BusInterface
);
297 /* Now enumerate the functions */
298 Status
= USBCCGP_EnumerateFunctions(DeviceObject
);
299 if (!NT_SUCCESS(Status
))
301 /* Failed to enumerate functions */
302 DPRINT1("Failed to enumerate functions with %x\n", Status
);
307 ASSERT(FDODeviceExtension
->FunctionDescriptorCount
);
308 ASSERT(FDODeviceExtension
->FunctionDescriptor
);
309 DumpFunctionDescriptor(FDODeviceExtension
->FunctionDescriptor
,
310 FDODeviceExtension
->FunctionDescriptorCount
);
312 /* Now create the pdo */
313 Status
= FDO_CreateChildPdo(DeviceObject
);
314 if (!NT_SUCCESS(Status
))
317 DPRINT1("FDO_CreateChildPdo failed with %x\n", Status
);
321 /* Inform pnp manager of new device objects */
322 IoInvalidateDeviceRelations(FDODeviceExtension
->PhysicalDeviceObject
,
326 DPRINT("[USBCCGP] FDO initialized successfully\n");
331 FDO_CloseConfiguration(
332 IN PDEVICE_OBJECT DeviceObject
)
336 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
338 /* Get device extension */
339 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
340 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
342 /* Nothing to do if we're not configured */
343 if (FDODeviceExtension
->ConfigurationDescriptor
== NULL
||
344 FDODeviceExtension
->InterfaceList
== NULL
)
346 return STATUS_SUCCESS
;
349 /* Now allocate the urb */
350 Urb
= USBD_CreateConfigurationRequestEx(FDODeviceExtension
->ConfigurationDescriptor
,
351 FDODeviceExtension
->InterfaceList
);
355 return STATUS_INSUFFICIENT_RESOURCES
;
358 /* Clear configuration descriptor to make it an unconfigure request */
359 Urb
->UrbSelectConfiguration
.ConfigurationDescriptor
= NULL
;
362 Status
= USBCCGP_SyncUrbRequest(FDODeviceExtension
->NextDeviceObject
, Urb
);
363 if (!NT_SUCCESS(Status
))
365 /* Failed to set configuration */
366 DPRINT1("USBCCGP_SyncUrbRequest failed to unconfigure device\n", Status
);
376 PDEVICE_OBJECT DeviceObject
,
379 PIO_STACK_LOCATION IoStack
;
381 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
383 /* Get device extension */
384 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
385 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
388 /* Get stack location */
389 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
390 DPRINT("[USBCCGP] PnP Minor %x\n", IoStack
->MinorFunction
);
391 switch(IoStack
->MinorFunction
)
393 case IRP_MN_REMOVE_DEVICE
:
395 // Unconfigure device */
396 DPRINT1("[USBCCGP] FDO IRP_MN_REMOVE\n");
397 FDO_CloseConfiguration(DeviceObject
);
399 /* Send the IRP down the stack */
400 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
401 IoSkipCurrentIrpStackLocation(Irp
);
402 Status
= IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
404 /* Detach from the device stack */
405 IoDetachDevice(FDODeviceExtension
->NextDeviceObject
);
407 /* Delete the device object */
408 IoDeleteDevice(DeviceObject
);
410 /* Request completed */
413 case IRP_MN_START_DEVICE
:
415 /* Start the device */
416 Status
= FDO_StartDevice(DeviceObject
, Irp
);
419 case IRP_MN_QUERY_DEVICE_RELATIONS
:
421 /* Handle device relations */
422 Status
= FDO_DeviceRelations(DeviceObject
, Irp
);
423 if (!NT_SUCCESS(Status
))
428 /* Forward irp to next device object */
429 IoSkipCurrentIrpStackLocation(Irp
);
430 return IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
432 case IRP_MN_QUERY_CAPABILITIES
:
434 /* Copy capabilities */
435 RtlCopyMemory(IoStack
->Parameters
.DeviceCapabilities
.Capabilities
,
436 &FDODeviceExtension
->Capabilities
,
437 sizeof(DEVICE_CAPABILITIES
));
438 Status
= USBCCGP_SyncForwardIrp(FDODeviceExtension
->NextDeviceObject
, Irp
);
439 if (NT_SUCCESS(Status
))
441 /* Surprise removal ok */
442 IoStack
->Parameters
.DeviceCapabilities
.Capabilities
->SurpriseRemovalOK
= TRUE
;
446 case IRP_MN_QUERY_REMOVE_DEVICE
:
447 case IRP_MN_QUERY_STOP_DEVICE
:
450 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
452 /* Forward irp to next device object */
453 IoSkipCurrentIrpStackLocation(Irp
);
454 return IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
458 /* Forward irp to next device object */
459 IoSkipCurrentIrpStackLocation(Irp
);
460 return IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
465 /* Complete request */
466 Irp
->IoStatus
.Status
= Status
;
467 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
472 FDO_HandleResetCyclePort(
473 PDEVICE_OBJECT DeviceObject
,
476 PIO_STACK_LOCATION IoStack
;
478 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
479 PLIST_ENTRY ListHead
, Entry
;
485 /* Get device extension */
486 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
487 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
489 /* Get stack location */
490 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
491 DPRINT("FDO_HandleResetCyclePort IOCTL %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
493 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_RESET_PORT
)
495 /* Use reset port list */
496 ListHead
= &FDODeviceExtension
->ResetPortListHead
;
497 ResetActive
= &FDODeviceExtension
->ResetPortActive
;
501 /* Use cycle port list */
502 ListHead
= &FDODeviceExtension
->CyclePortListHead
;
503 ResetActive
= &FDODeviceExtension
->CyclePortActive
;
507 KeAcquireSpinLock(&FDODeviceExtension
->Lock
, &OldLevel
);
511 /* Insert into pending list */
512 InsertTailList(ListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
514 /* Mark irp pending */
515 IoMarkIrpPending(Irp
);
516 Status
= STATUS_PENDING
;
519 KeReleaseSpinLock(&FDODeviceExtension
->Lock
, OldLevel
);
523 /* Mark reset active */
527 KeReleaseSpinLock(&FDODeviceExtension
->Lock
, OldLevel
);
529 /* Forward request synchronized */
530 USBCCGP_SyncForwardIrp(FDODeviceExtension
->NextDeviceObject
, Irp
);
533 KeAcquireSpinLock(&FDODeviceExtension
->Lock
, &OldLevel
);
535 /* Mark reset as completed */
536 *ResetActive
= FALSE
;
538 /* Move all requests into temporary list */
539 InitializeListHead(&TempList
);
540 while(!IsListEmpty(ListHead
))
542 Entry
= RemoveHeadList(ListHead
);
543 InsertTailList(&TempList
, Entry
);
547 KeReleaseSpinLock(&FDODeviceExtension
->Lock
, OldLevel
);
549 /* Complete pending irps */
550 while(!IsListEmpty(&TempList
))
552 Entry
= RemoveHeadList(&TempList
);
553 ListIrp
= (PIRP
)CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.ListEntry
);
555 /* Complete request with status success */
556 ListIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
557 IoCompleteRequest(ListIrp
, IO_NO_INCREMENT
);
561 Status
= STATUS_SUCCESS
;
570 FDO_HandleInternalDeviceControl(
571 PDEVICE_OBJECT DeviceObject
,
574 PIO_STACK_LOCATION IoStack
;
576 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
578 /* Get device extension */
579 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
580 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
582 /* Get stack location */
583 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
585 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_RESET_PORT
||
586 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_CYCLE_PORT
)
588 /* Handle reset / cycle ports */
589 Status
= FDO_HandleResetCyclePort(DeviceObject
, Irp
);
590 DPRINT("FDO_HandleResetCyclePort Status %x\n", Status
);
591 if (Status
!= STATUS_PENDING
)
593 /* Complete request */
594 Irp
->IoStatus
.Status
= Status
;
595 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
600 /* Forward and forget request */
601 IoSkipCurrentIrpStackLocation(Irp
);
602 return IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
606 FDO_HandleSystemControl(
607 PDEVICE_OBJECT DeviceObject
,
610 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
612 /* Get device extension */
613 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
614 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
616 /* Forward and forget request */
617 IoSkipCurrentIrpStackLocation(Irp
);
618 return IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
623 PDEVICE_OBJECT DeviceObject
,
626 PIO_STACK_LOCATION IoStack
;
628 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
630 /* Get device extension */
631 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
632 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
634 /* Get stack location */
635 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
637 switch(IoStack
->MajorFunction
)
640 return FDO_HandlePnp(DeviceObject
, Irp
);
641 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
642 return FDO_HandleInternalDeviceControl(DeviceObject
, Irp
);
644 PoStartNextPowerIrp(Irp
);
645 IoSkipCurrentIrpStackLocation(Irp
);
646 return PoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
647 case IRP_MJ_SYSTEM_CONTROL
:
648 return FDO_HandleSystemControl(DeviceObject
, Irp
);
650 DPRINT1("FDO_Dispatch Function %x not implemented\n", IoStack
->MajorFunction
);
652 Status
= Irp
->IoStatus
.Status
;
653 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);