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)
16 FDO_QueryCapabilitiesCompletionRoutine(
17 IN PDEVICE_OBJECT DeviceObject
,
22 KeSetEvent((PRKEVENT
)Context
, 0, FALSE
);
24 /* Completion is done in the HidClassFDO_QueryCapabilities routine */
25 return STATUS_MORE_PROCESSING_REQUIRED
;
29 FDO_QueryCapabilities(
30 IN PDEVICE_OBJECT DeviceObject
,
31 IN OUT PDEVICE_CAPABILITIES Capabilities
)
36 PIO_STACK_LOCATION IoStack
;
37 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
39 /* Get device extension */
40 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
41 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
44 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
46 /* Now allocte the irp */
47 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
51 return STATUS_INSUFFICIENT_RESOURCES
;
54 /* Get next stack location */
55 IoStack
= IoGetNextIrpStackLocation(Irp
);
57 /* Init stack location */
58 IoStack
->MajorFunction
= IRP_MJ_PNP
;
59 IoStack
->MinorFunction
= IRP_MN_QUERY_CAPABILITIES
;
60 IoStack
->Parameters
.DeviceCapabilities
.Capabilities
= Capabilities
;
62 /* Set completion routine */
63 IoSetCompletionRoutine(Irp
,
64 FDO_QueryCapabilitiesCompletionRoutine
,
70 /* Init capabilities */
71 RtlZeroMemory(Capabilities
, sizeof(DEVICE_CAPABILITIES
));
72 Capabilities
->Size
= sizeof(DEVICE_CAPABILITIES
);
73 Capabilities
->Version
= 1; // FIXME hardcoded constant
74 Capabilities
->Address
= MAXULONG
;
75 Capabilities
->UINumber
= MAXULONG
;
77 /* Pnp irps have default completion code */
78 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
80 /* Call lower device */
81 Status
= IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
82 if (Status
== STATUS_PENDING
)
84 /* Wait for completion */
85 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
89 Status
= Irp
->IoStatus
.Status
;
91 /* Complete request */
100 PDEVICE_OBJECT DeviceObject
,
103 ULONG DeviceCount
= 0;
105 PDEVICE_RELATIONS DeviceRelations
;
106 PIO_STACK_LOCATION IoStack
;
107 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
109 /* Get device extension */
110 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
112 /* Get current irp stack location */
113 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
115 /* Check if relation type is BusRelations */
116 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
118 /* FDO always only handles bus relations */
119 return USBCCGP_SyncForwardIrp(FDODeviceExtension
->NextDeviceObject
, Irp
);
122 /* Go through array and count device objects */
123 for(Index
= 0; Index
< FDODeviceExtension
->FunctionDescriptorCount
; Index
++)
125 if (FDODeviceExtension
->ChildPDO
[Index
])
132 /* Allocate device relations */
133 DeviceRelations
= (PDEVICE_RELATIONS
)AllocateItem(PagedPool
,
134 sizeof(DEVICE_RELATIONS
) + (DeviceCount
> 1 ? (DeviceCount
-1) * sizeof(PDEVICE_OBJECT
) : 0));
135 if (!DeviceRelations
)
138 return STATUS_INSUFFICIENT_RESOURCES
;
141 /* Add device objects */
142 for(Index
= 0; Index
< FDODeviceExtension
->FunctionDescriptorCount
; Index
++)
144 if (FDODeviceExtension
->ChildPDO
[Index
])
146 /* Store child pdo */
147 DeviceRelations
->Objects
[DeviceRelations
->Count
] = FDODeviceExtension
->ChildPDO
[Index
];
150 ObReferenceObject(FDODeviceExtension
->ChildPDO
[Index
]);
152 /* Increment count */
153 DeviceRelations
->Count
++;
158 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
160 /* Request completed successfully */
161 return STATUS_SUCCESS
;
166 IN PDEVICE_OBJECT DeviceObject
)
169 PDEVICE_OBJECT PDODeviceObject
;
170 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
171 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
174 /* Get device extension */
175 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
176 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
178 /* Lets create array for the child PDO */
179 FDODeviceExtension
->ChildPDO
= AllocateItem(NonPagedPool
,
180 sizeof(PDEVICE_OBJECT
) * FDODeviceExtension
->FunctionDescriptorCount
);
181 if (!FDODeviceExtension
->ChildPDO
)
184 return STATUS_INSUFFICIENT_RESOURCES
;
187 /* Create pdo for each function */
188 for(Index
= 0; Index
< FDODeviceExtension
->FunctionDescriptorCount
; Index
++)
191 Status
= IoCreateDevice(FDODeviceExtension
->DriverObject
,
192 sizeof(PDO_DEVICE_EXTENSION
),
195 FILE_AUTOGENERATED_DEVICE_NAME
,
198 if (!NT_SUCCESS(Status
))
200 /* Failed to create device object */
201 DPRINT1("IoCreateDevice failed with %x\n", Status
);
206 FDODeviceExtension
->ChildPDO
[Index
] = PDODeviceObject
;
208 /* Get device extension */
209 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)PDODeviceObject
->DeviceExtension
;
210 RtlZeroMemory(PDODeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
212 /* Init device extension */
213 PDODeviceExtension
->Common
.IsFDO
= FALSE
;
214 PDODeviceExtension
->FunctionDescriptor
= &FDODeviceExtension
->FunctionDescriptor
[Index
];
215 PDODeviceExtension
->NextDeviceObject
= DeviceObject
;
216 PDODeviceExtension
->FunctionIndex
= Index
;
217 PDODeviceExtension
->FDODeviceExtension
= FDODeviceExtension
;
218 PDODeviceExtension
->InterfaceList
= FDODeviceExtension
->InterfaceList
;
219 PDODeviceExtension
->InterfaceListCount
= FDODeviceExtension
->InterfaceListCount
;
220 PDODeviceExtension
->ConfigurationHandle
= FDODeviceExtension
->ConfigurationHandle
;
221 PDODeviceExtension
->ConfigurationDescriptor
= FDODeviceExtension
->ConfigurationDescriptor
;
222 RtlCopyMemory(&PDODeviceExtension
->Capabilities
, &FDODeviceExtension
->Capabilities
, sizeof(DEVICE_CAPABILITIES
));
223 RtlCopyMemory(&PDODeviceExtension
->DeviceDescriptor
, &FDODeviceExtension
->DeviceDescriptor
, sizeof(USB_DEVICE_DESCRIPTOR
));
225 /* Patch the stack size */
226 PDODeviceObject
->StackSize
= DeviceObject
->StackSize
+ 1;
228 /* Set device flags */
229 PDODeviceObject
->Flags
|= DO_DIRECT_IO
| DO_MAP_IO_BUFFER
;
231 /* Device is initialized */
232 PDODeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
236 return STATUS_SUCCESS
;
241 PDEVICE_OBJECT DeviceObject
,
245 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
247 /* Get device extension */
248 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
249 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
251 /* First start lower device */
252 Status
= USBCCGP_SyncForwardIrp(FDODeviceExtension
->NextDeviceObject
, Irp
);
254 if (!NT_SUCCESS(Status
))
256 /* Failed to start lower device */
257 DPRINT1("FDO_StartDevice lower device failed to start with %x\n", Status
);
261 /* Get descriptors */
262 Status
= USBCCGP_GetDescriptors(DeviceObject
);
263 if (!NT_SUCCESS(Status
))
265 /* Failed to start lower device */
266 DPRINT1("FDO_StartDevice failed to get descriptors with %x\n", Status
);
270 /* Get capabilities */
271 Status
= FDO_QueryCapabilities(DeviceObject
,
272 &FDODeviceExtension
->Capabilities
);
273 if (!NT_SUCCESS(Status
))
275 /* Failed to start lower device */
276 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status
);
280 /* Now select the configuration */
281 Status
= USBCCGP_SelectConfiguration(DeviceObject
, FDODeviceExtension
);
282 if (!NT_SUCCESS(Status
))
284 /* Failed to select interface */
285 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status
);
289 /* Query bus interface */
290 USBCCGP_QueryInterface(FDODeviceExtension
->NextDeviceObject
,
291 &FDODeviceExtension
->BusInterface
);
293 /* Now enumerate the functions */
294 Status
= USBCCGP_EnumerateFunctions(DeviceObject
);
295 if (!NT_SUCCESS(Status
))
297 /* Failed to enumerate functions */
298 DPRINT1("Failed to enumerate functions with %x\n", Status
);
303 ASSERT(FDODeviceExtension
->FunctionDescriptorCount
);
304 ASSERT(FDODeviceExtension
->FunctionDescriptor
);
305 DumpFunctionDescriptor(FDODeviceExtension
->FunctionDescriptor
,
306 FDODeviceExtension
->FunctionDescriptorCount
);
308 /* Now create the pdo */
309 Status
= FDO_CreateChildPdo(DeviceObject
);
310 if (!NT_SUCCESS(Status
))
313 DPRINT1("FDO_CreateChildPdo failed with %x\n", Status
);
317 /* Inform pnp manager of new device objects */
318 IoInvalidateDeviceRelations(FDODeviceExtension
->PhysicalDeviceObject
,
322 DPRINT("[USBCCGP] FDO initialized successfully\n");
327 FDO_CloseConfiguration(
328 IN PDEVICE_OBJECT DeviceObject
)
332 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
334 /* Get device extension */
335 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
336 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
338 /* Now allocate the urb */
339 Urb
= USBD_CreateConfigurationRequestEx(FDODeviceExtension
->ConfigurationDescriptor
,
340 FDODeviceExtension
->InterfaceList
);
344 return STATUS_INSUFFICIENT_RESOURCES
;
347 /* Clear configuration descriptor to make it an unconfigure request */
348 Urb
->UrbSelectConfiguration
.ConfigurationDescriptor
= NULL
;
351 Status
= USBCCGP_SyncUrbRequest(FDODeviceExtension
->NextDeviceObject
, Urb
);
352 if (!NT_SUCCESS(Status
))
354 /* Failed to set configuration */
355 DPRINT1("USBCCGP_SyncUrbRequest failed to unconfigure device\n", Status
);
365 PDEVICE_OBJECT DeviceObject
,
368 PIO_STACK_LOCATION IoStack
;
370 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
372 /* Get device extension */
373 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
374 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
377 /* Get stack location */
378 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
379 DPRINT("[USBCCGP] PnP Minor %x\n", IoStack
->MinorFunction
);
380 switch(IoStack
->MinorFunction
)
382 case IRP_MN_REMOVE_DEVICE
:
384 // Unconfigure device */
385 DPRINT1("[USBCCGP] FDO IRP_MN_REMOVE\n");
386 FDO_CloseConfiguration(DeviceObject
);
388 /* Send the IRP down the stack */
389 Status
= USBCCGP_SyncForwardIrp(FDODeviceExtension
->NextDeviceObject
,
391 if (NT_SUCCESS(Status
))
393 /* Detach from the device stack */
394 IoDetachDevice(FDODeviceExtension
->NextDeviceObject
);
396 /* Delete the device object */
397 IoDeleteDevice(DeviceObject
);
400 /* Request completed */
403 case IRP_MN_START_DEVICE
:
405 /* Start the device */
406 Status
= FDO_StartDevice(DeviceObject
, Irp
);
409 case IRP_MN_QUERY_DEVICE_RELATIONS
:
411 /* Handle device relations */
412 Status
= FDO_DeviceRelations(DeviceObject
, Irp
);
415 case IRP_MN_QUERY_CAPABILITIES
:
417 /* Copy capabilities */
418 RtlCopyMemory(IoStack
->Parameters
.DeviceCapabilities
.Capabilities
,
419 &FDODeviceExtension
->Capabilities
,
420 sizeof(DEVICE_CAPABILITIES
));
421 Status
= USBCCGP_SyncForwardIrp(FDODeviceExtension
->NextDeviceObject
, Irp
);
422 if (NT_SUCCESS(Status
))
424 /* Surprise removal ok */
425 IoStack
->Parameters
.DeviceCapabilities
.Capabilities
->SurpriseRemovalOK
= TRUE
;
429 case IRP_MN_QUERY_REMOVE_DEVICE
:
430 case IRP_MN_QUERY_STOP_DEVICE
:
433 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
435 /* Forward irp to next device object */
436 IoSkipCurrentIrpStackLocation(Irp
);
437 return IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
441 /* Forward irp to next device object */
442 IoSkipCurrentIrpStackLocation(Irp
);
443 return IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
448 /* Complete request */
449 Irp
->IoStatus
.Status
= Status
;
450 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
455 FDO_HandleResetCyclePort(
456 PDEVICE_OBJECT DeviceObject
,
459 PIO_STACK_LOCATION IoStack
;
461 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
462 PLIST_ENTRY ListHead
, Entry
;
468 /* Get device extension */
469 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
470 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
472 /* Get stack location */
473 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
474 DPRINT("FDO_HandleResetCyclePort IOCTL %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
476 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_RESET_PORT
)
478 /* Use reset port list */
479 ListHead
= &FDODeviceExtension
->ResetPortListHead
;
480 ResetActive
= &FDODeviceExtension
->ResetPortActive
;
484 /* Use cycle port list */
485 ListHead
= &FDODeviceExtension
->CyclePortListHead
;
486 ResetActive
= &FDODeviceExtension
->CyclePortActive
;
490 KeAcquireSpinLock(&FDODeviceExtension
->Lock
, &OldLevel
);
494 /* Insert into pending list */
495 InsertTailList(ListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
497 /* Mark irp pending */
498 IoMarkIrpPending(Irp
);
499 Status
= STATUS_PENDING
;
502 KeReleaseSpinLock(&FDODeviceExtension
->Lock
, OldLevel
);
506 /* Mark reset active */
510 KeReleaseSpinLock(&FDODeviceExtension
->Lock
, OldLevel
);
512 /* Forward request synchronized */
513 USBCCGP_SyncForwardIrp(FDODeviceExtension
->NextDeviceObject
, Irp
);
516 KeAcquireSpinLock(&FDODeviceExtension
->Lock
, &OldLevel
);
518 /* Mark reset as completed */
519 *ResetActive
= FALSE
;
521 /* Move all requests into temporary list */
522 InitializeListHead(&TempList
);
523 while(!IsListEmpty(ListHead
))
525 Entry
= RemoveHeadList(ListHead
);
526 InsertTailList(&TempList
, Entry
);
530 KeReleaseSpinLock(&FDODeviceExtension
->Lock
, OldLevel
);
532 /* Complete pending irps */
533 while(!IsListEmpty(&TempList
))
535 Entry
= RemoveHeadList(&TempList
);
536 ListIrp
= (PIRP
)CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.ListEntry
);
538 /* Complete request with status success */
539 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
540 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
544 Status
= STATUS_SUCCESS
;
553 FDO_HandleInternalDeviceControl(
554 PDEVICE_OBJECT DeviceObject
,
557 PIO_STACK_LOCATION IoStack
;
559 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
561 /* Get device extension */
562 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
563 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
565 /* Get stack location */
566 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
568 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_RESET_PORT
||
569 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_CYCLE_PORT
)
571 /* Handle reset / cycle ports */
572 Status
= FDO_HandleResetCyclePort(DeviceObject
, Irp
);
573 DPRINT("FDO_HandleResetCyclePort Status %x\n", Status
);
574 if (Status
!= STATUS_PENDING
)
576 /* Complete request */
577 Irp
->IoStatus
.Status
= Status
;
578 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
583 /* Forward and forget request */
584 IoSkipCurrentIrpStackLocation(Irp
);
585 return IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
590 PDEVICE_OBJECT DeviceObject
,
593 PIO_STACK_LOCATION IoStack
;
596 /* Get stack location */
597 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
599 switch(IoStack
->MajorFunction
)
602 return FDO_HandlePnp(DeviceObject
, Irp
);
603 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
604 return FDO_HandleInternalDeviceControl(DeviceObject
, Irp
);
606 DPRINT1("FDO_Dispatch Function %x not implemented\n", IoStack
->MajorFunction
);
608 Status
= Irp
->IoStatus
.Status
;
609 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);