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 allocte 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 USBCCGP_SyncForwardIrp(FDODeviceExtension
->NextDeviceObject
, Irp
);
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
;
163 /* Request completed successfully */
164 return STATUS_SUCCESS
;
169 IN PDEVICE_OBJECT DeviceObject
)
172 PDEVICE_OBJECT PDODeviceObject
;
173 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
174 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
177 /* Get device extension */
178 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
179 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
181 /* Lets create array for the child PDO */
182 FDODeviceExtension
->ChildPDO
= AllocateItem(NonPagedPool
,
183 sizeof(PDEVICE_OBJECT
) * FDODeviceExtension
->FunctionDescriptorCount
);
184 if (!FDODeviceExtension
->ChildPDO
)
187 return STATUS_INSUFFICIENT_RESOURCES
;
190 /* Create pdo for each function */
191 for(Index
= 0; Index
< FDODeviceExtension
->FunctionDescriptorCount
; Index
++)
194 Status
= IoCreateDevice(FDODeviceExtension
->DriverObject
,
195 sizeof(PDO_DEVICE_EXTENSION
),
198 FILE_AUTOGENERATED_DEVICE_NAME
,
201 if (!NT_SUCCESS(Status
))
203 /* Failed to create device object */
204 DPRINT1("IoCreateDevice failed with %x\n", Status
);
209 FDODeviceExtension
->ChildPDO
[Index
] = PDODeviceObject
;
211 /* Get device extension */
212 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)PDODeviceObject
->DeviceExtension
;
213 RtlZeroMemory(PDODeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
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
));
228 /* Patch the stack size */
229 PDODeviceObject
->StackSize
= DeviceObject
->StackSize
+ 1;
231 /* Set device flags */
232 PDODeviceObject
->Flags
|= DO_DIRECT_IO
| DO_MAP_IO_BUFFER
;
234 /* Device is initialized */
235 PDODeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
239 return STATUS_SUCCESS
;
244 PDEVICE_OBJECT DeviceObject
,
248 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
250 /* Get device extension */
251 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
252 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
254 /* First start lower device */
255 Status
= USBCCGP_SyncForwardIrp(FDODeviceExtension
->NextDeviceObject
, Irp
);
257 if (!NT_SUCCESS(Status
))
259 /* Failed to start lower device */
260 DPRINT1("FDO_StartDevice lower device failed to start with %x\n", Status
);
264 /* Get descriptors */
265 Status
= USBCCGP_GetDescriptors(DeviceObject
);
266 if (!NT_SUCCESS(Status
))
268 /* Failed to start lower device */
269 DPRINT1("FDO_StartDevice failed to get descriptors with %x\n", Status
);
273 /* Get capabilities */
274 Status
= FDO_QueryCapabilities(DeviceObject
,
275 &FDODeviceExtension
->Capabilities
);
276 if (!NT_SUCCESS(Status
))
278 /* Failed to start lower device */
279 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status
);
283 /* Now select the configuration */
284 Status
= USBCCGP_SelectConfiguration(DeviceObject
, FDODeviceExtension
);
285 if (!NT_SUCCESS(Status
))
287 /* Failed to select interface */
288 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status
);
292 /* Query bus interface */
293 USBCCGP_QueryInterface(FDODeviceExtension
->NextDeviceObject
,
294 &FDODeviceExtension
->BusInterface
);
296 /* Now enumerate the functions */
297 Status
= USBCCGP_EnumerateFunctions(DeviceObject
);
298 if (!NT_SUCCESS(Status
))
300 /* Failed to enumerate functions */
301 DPRINT1("Failed to enumerate functions with %x\n", Status
);
306 ASSERT(FDODeviceExtension
->FunctionDescriptorCount
);
307 ASSERT(FDODeviceExtension
->FunctionDescriptor
);
308 DumpFunctionDescriptor(FDODeviceExtension
->FunctionDescriptor
,
309 FDODeviceExtension
->FunctionDescriptorCount
);
311 /* Now create the pdo */
312 Status
= FDO_CreateChildPdo(DeviceObject
);
313 if (!NT_SUCCESS(Status
))
316 DPRINT1("FDO_CreateChildPdo failed with %x\n", Status
);
320 /* Inform pnp manager of new device objects */
321 IoInvalidateDeviceRelations(FDODeviceExtension
->PhysicalDeviceObject
,
325 DPRINT("[USBCCGP] FDO initialized successfully\n");
330 FDO_CloseConfiguration(
331 IN PDEVICE_OBJECT DeviceObject
)
335 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
337 /* Get device extension */
338 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
339 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
341 /* Now allocate the urb */
342 Urb
= USBD_CreateConfigurationRequestEx(FDODeviceExtension
->ConfigurationDescriptor
,
343 FDODeviceExtension
->InterfaceList
);
347 return STATUS_INSUFFICIENT_RESOURCES
;
350 /* Clear configuration descriptor to make it an unconfigure request */
351 Urb
->UrbSelectConfiguration
.ConfigurationDescriptor
= NULL
;
354 Status
= USBCCGP_SyncUrbRequest(FDODeviceExtension
->NextDeviceObject
, Urb
);
355 if (!NT_SUCCESS(Status
))
357 /* Failed to set configuration */
358 DPRINT1("USBCCGP_SyncUrbRequest failed to unconfigure device\n", Status
);
368 PDEVICE_OBJECT DeviceObject
,
371 PIO_STACK_LOCATION IoStack
;
373 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
375 /* Get device extension */
376 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
377 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
380 /* Get stack location */
381 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
382 DPRINT("[USBCCGP] PnP Minor %x\n", IoStack
->MinorFunction
);
383 switch(IoStack
->MinorFunction
)
385 case IRP_MN_REMOVE_DEVICE
:
387 // Unconfigure device */
388 DPRINT1("[USBCCGP] FDO IRP_MN_REMOVE\n");
389 FDO_CloseConfiguration(DeviceObject
);
391 /* Send the IRP down the stack */
392 Status
= USBCCGP_SyncForwardIrp(FDODeviceExtension
->NextDeviceObject
,
394 if (NT_SUCCESS(Status
))
396 /* Detach from the device stack */
397 IoDetachDevice(FDODeviceExtension
->NextDeviceObject
);
399 /* Delete the device object */
400 IoDeleteDevice(DeviceObject
);
403 /* Request completed */
406 case IRP_MN_START_DEVICE
:
408 /* Start the device */
409 Status
= FDO_StartDevice(DeviceObject
, Irp
);
412 case IRP_MN_QUERY_DEVICE_RELATIONS
:
414 /* Handle device relations */
415 Status
= FDO_DeviceRelations(DeviceObject
, Irp
);
418 case IRP_MN_QUERY_CAPABILITIES
:
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
))
427 /* Surprise removal ok */
428 IoStack
->Parameters
.DeviceCapabilities
.Capabilities
->SurpriseRemovalOK
= TRUE
;
432 case IRP_MN_QUERY_REMOVE_DEVICE
:
433 case IRP_MN_QUERY_STOP_DEVICE
:
436 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
438 /* Forward irp to next device object */
439 IoSkipCurrentIrpStackLocation(Irp
);
440 return IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
444 /* Forward irp to next device object */
445 IoSkipCurrentIrpStackLocation(Irp
);
446 return IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
451 /* Complete request */
452 Irp
->IoStatus
.Status
= Status
;
453 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
458 FDO_HandleResetCyclePort(
459 PDEVICE_OBJECT DeviceObject
,
462 PIO_STACK_LOCATION IoStack
;
464 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
465 PLIST_ENTRY ListHead
, Entry
;
471 /* Get device extension */
472 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
473 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
475 /* Get stack location */
476 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
477 DPRINT("FDO_HandleResetCyclePort IOCTL %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
479 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_RESET_PORT
)
481 /* Use reset port list */
482 ListHead
= &FDODeviceExtension
->ResetPortListHead
;
483 ResetActive
= &FDODeviceExtension
->ResetPortActive
;
487 /* Use cycle port list */
488 ListHead
= &FDODeviceExtension
->CyclePortListHead
;
489 ResetActive
= &FDODeviceExtension
->CyclePortActive
;
493 KeAcquireSpinLock(&FDODeviceExtension
->Lock
, &OldLevel
);
497 /* Insert into pending list */
498 InsertTailList(ListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
500 /* Mark irp pending */
501 IoMarkIrpPending(Irp
);
502 Status
= STATUS_PENDING
;
505 KeReleaseSpinLock(&FDODeviceExtension
->Lock
, OldLevel
);
509 /* Mark reset active */
513 KeReleaseSpinLock(&FDODeviceExtension
->Lock
, OldLevel
);
515 /* Forward request synchronized */
516 USBCCGP_SyncForwardIrp(FDODeviceExtension
->NextDeviceObject
, Irp
);
519 KeAcquireSpinLock(&FDODeviceExtension
->Lock
, &OldLevel
);
521 /* Mark reset as completed */
522 *ResetActive
= FALSE
;
524 /* Move all requests into temporary list */
525 InitializeListHead(&TempList
);
526 while(!IsListEmpty(ListHead
))
528 Entry
= RemoveHeadList(ListHead
);
529 InsertTailList(&TempList
, Entry
);
533 KeReleaseSpinLock(&FDODeviceExtension
->Lock
, OldLevel
);
535 /* Complete pending irps */
536 while(!IsListEmpty(&TempList
))
538 Entry
= RemoveHeadList(&TempList
);
539 ListIrp
= (PIRP
)CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.ListEntry
);
541 /* Complete request with status success */
542 ListIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
543 IoCompleteRequest(ListIrp
, IO_NO_INCREMENT
);
547 Status
= STATUS_SUCCESS
;
556 FDO_HandleInternalDeviceControl(
557 PDEVICE_OBJECT DeviceObject
,
560 PIO_STACK_LOCATION IoStack
;
562 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
564 /* Get device extension */
565 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
566 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
568 /* Get stack location */
569 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
571 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_RESET_PORT
||
572 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_CYCLE_PORT
)
574 /* Handle reset / cycle ports */
575 Status
= FDO_HandleResetCyclePort(DeviceObject
, Irp
);
576 DPRINT("FDO_HandleResetCyclePort Status %x\n", Status
);
577 if (Status
!= STATUS_PENDING
)
579 /* Complete request */
580 Irp
->IoStatus
.Status
= Status
;
581 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
586 /* Forward and forget request */
587 IoSkipCurrentIrpStackLocation(Irp
);
588 return IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
592 FDO_HandleSystemControl(
593 PDEVICE_OBJECT DeviceObject
,
596 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
598 /* Get device extension */
599 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
600 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
602 /* Forward and forget request */
603 IoSkipCurrentIrpStackLocation(Irp
);
604 return IoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
609 PDEVICE_OBJECT DeviceObject
,
612 PIO_STACK_LOCATION IoStack
;
614 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
616 /* Get device extension */
617 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
618 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
620 /* Get stack location */
621 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
623 switch(IoStack
->MajorFunction
)
626 return FDO_HandlePnp(DeviceObject
, Irp
);
627 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
628 return FDO_HandleInternalDeviceControl(DeviceObject
, Irp
);
630 PoStartNextPowerIrp(Irp
);
631 IoSkipCurrentIrpStackLocation(Irp
);
632 return PoCallDriver(FDODeviceExtension
->NextDeviceObject
, Irp
);
633 case IRP_MJ_SYSTEM_CONTROL
:
634 return FDO_HandleSystemControl(DeviceObject
, Irp
);
636 DPRINT1("FDO_Dispatch Function %x not implemented\n", IoStack
->MajorFunction
);
638 Status
= Irp
->IoStatus
.Status
;
639 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);