diff --git a/reactos/drivers/usb/cromwell/directory.xml b/reactos/drivers/usb/cromwell/directory.xml
index eaa3fbbaaa7..af5453d66b3 100644
--- a/reactos/drivers/usb/cromwell/directory.xml
+++ b/reactos/drivers/usb/cromwell/directory.xml
@@ -7,6 +7,9 @@
+
+
+
\ No newline at end of file
diff --git a/reactos/drivers/usb/cromwell/hub/createclose.c b/reactos/drivers/usb/cromwell/hub/createclose.c
new file mode 100644
index 00000000000..7001f24aad7
--- /dev/null
+++ b/reactos/drivers/usb/cromwell/hub/createclose.c
@@ -0,0 +1,50 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: USB hub driver
+ * FILE: drivers/usb/cromwell/usbhub/createclose.c
+ * PURPOSE: IRP_MJ_CREATE and IRP_MJ_CLOSE operations
+ *
+ * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
+ */
+
+#define NDEBUG
+#include "usbhub.h"
+
+NTSTATUS STDCALL
+UsbhubCreate(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ DPRINT("Usbhub: IRP_MJ_CREATE\n");
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS STDCALL
+UsbhubClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ DPRINT("Usbhub: IRP_MJ_CLOSE\n");
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS STDCALL
+UsbhubCleanup(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ DPRINT("Usbhub: IRP_MJ_CLEANUP\n");
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+}
diff --git a/reactos/drivers/usb/cromwell/hub/fdo.c b/reactos/drivers/usb/cromwell/hub/fdo.c
new file mode 100644
index 00000000000..0c1890b8d57
--- /dev/null
+++ b/reactos/drivers/usb/cromwell/hub/fdo.c
@@ -0,0 +1,180 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: USB hub driver
+ * FILE: drivers/usb/cromwell/hub/fdo.c
+ * PURPOSE: IRP_MJ_PNP operations for FDOs
+ *
+ * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
+ */
+
+//#define NDEBUG
+#include "usbhub.h"
+
+extern struct usb_driver hub_driver;
+
+#define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
+
+static VOID
+UsbhubGetUserBuffers(
+ IN PIRP Irp,
+ IN ULONG IoControlCode,
+ OUT PVOID* BufferIn,
+ OUT PVOID* BufferOut)
+{
+ ASSERT(Irp);
+ ASSERT(BufferIn);
+ ASSERT(BufferOut);
+
+ switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
+ {
+ case METHOD_BUFFERED:
+ *BufferIn = *BufferOut = Irp->AssociatedIrp.SystemBuffer;
+ break;
+ case METHOD_IN_DIRECT:
+ case METHOD_OUT_DIRECT:
+ *BufferIn = Irp->AssociatedIrp.SystemBuffer;
+ *BufferOut = MmGetSystemAddressForMdl(Irp->MdlAddress);
+ break;
+ case METHOD_NEITHER:
+ *BufferIn = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.Type3InputBuffer;
+ *BufferOut = Irp->UserBuffer;
+ break;
+ default:
+ /* Should never happen */
+ *BufferIn = NULL;
+ *BufferOut = NULL;
+ break;
+ }
+}
+
+NTSTATUS STDCALL
+UsbhubPnpFdo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION IrpSp;
+ NTSTATUS Status;
+ ULONG MinorFunction;
+ ULONG_PTR Information = 0;
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = IrpSp->MinorFunction;
+
+ switch (MinorFunction)
+ {
+ case IRP_MN_START_DEVICE:
+ {
+ DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
+ Status = ForwardIrpAndWait(DeviceObject, Irp);
+ //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
+ // Status = OHCD_PnPStartDevice(DeviceObject, Irp);
+ break;
+ }
+
+ case IRP_MN_REMOVE_DEVICE:
+ //case IRP_MN_QUERY_REMOVE_DEVICE:
+ //case IRP_MN_CANCEL_REMOVE_DEVICE:
+ case IRP_MN_SURPRISE_REMOVAL:
+
+ case IRP_MN_STOP_DEVICE:
+ {
+ DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_STOP_DEVICE\n");
+ Status = ForwardIrpAndWait(DeviceObject, Irp);
+ if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
+ Status = STATUS_SUCCESS;
+ IoDeleteDevice(DeviceObject); // just delete device for now
+ break;
+ }
+ case IRP_MN_QUERY_STOP_DEVICE:
+ case IRP_MN_CANCEL_STOP_DEVICE:
+ {
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ default:
+ {
+ DPRINT1("Usbhub: IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+ }
+ Irp->IoStatus.Information = Information;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+}
+
+static inline struct device *hubdev (struct usb_device *dev)
+{
+ return &dev->actconfig->interface [0].dev;
+}
+
+NTSTATUS
+UsbhubDeviceControlFdo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION Stack;
+ ULONG IoControlCode;
+ PHUB_DEVICE_EXTENSION DeviceExtension;
+ ULONG LengthIn, LengthOut;
+ ULONG_PTR Information = 0;
+ PVOID BufferIn, BufferOut;
+ NTSTATUS Status;
+
+ DPRINT("Usbhub: UsbhubDeviceControlFdo() called\n");
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ LengthIn = Stack->Parameters.DeviceIoControl.InputBufferLength;
+ LengthOut = Stack->Parameters.DeviceIoControl.OutputBufferLength;
+ DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode;
+ UsbhubGetUserBuffers(Irp, IoControlCode, &BufferIn, &BufferOut);
+
+ switch (IoControlCode)
+ {
+ case IOCTL_USB_GET_NODE_INFORMATION:
+ {
+ PUSB_NODE_INFORMATION NodeInformation;
+ struct usb_device* dev;
+ struct device* device;
+ struct usb_interface * intf;
+ struct usb_hub *hub;
+ struct usb_hub_descriptor *descriptor;
+ DPRINT("Usbhub: IOCTL_USB_GET_NODE_INFORMATION\n");
+ if (LengthOut < sizeof(USB_NODE_INFORMATION))
+ Status = STATUS_BUFFER_TOO_SMALL;
+ else if (BufferOut == NULL)
+ Status = STATUS_INVALID_PARAMETER;
+ else
+ {
+ NodeInformation = (PUSB_NODE_INFORMATION)BufferOut;
+ dev = ((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->dev;
+ device = hubdev(dev);
+ intf = to_usb_interface(device);
+ hub = usb_get_intfdata(intf);
+ descriptor = hub->descriptor;
+ NodeInformation->NodeType = UsbHub;
+ RtlCopyMemory(
+ &NodeInformation->u.HubInformation.HubDescriptor,
+ descriptor,
+ sizeof(USB_HUB_DESCRIPTOR));
+ NodeInformation->u.HubInformation.HubIsBusPowered = TRUE; /* FIXME */
+ Information = sizeof(USB_NODE_INFORMATION);
+ Status = STATUS_SUCCESS;
+ }
+ break;
+ }
+ default:
+ {
+ /* Pass Irp to lower driver */
+ DPRINT1("Usbhub: Unknown IOCTL code 0x%lx\n", Stack->Parameters.DeviceIoControl.IoControlCode);
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+ }
+
+ Irp->IoStatus.Information = Information;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+}
diff --git a/reactos/drivers/usb/cromwell/hub/hub.xml b/reactos/drivers/usb/cromwell/hub/hub.xml
new file mode 100644
index 00000000000..1d67b40ae25
--- /dev/null
+++ b/reactos/drivers/usb/cromwell/hub/hub.xml
@@ -0,0 +1,16 @@
+
+
+
+ include
+ ../linux
+ sys_base
+ ntoskrnl
+ hal
+ usbcore
+ createclose.c
+ fdo.c
+ misc.c
+ pdo.c
+ usbhub.c
+ usbhub.rc
+
diff --git a/reactos/drivers/usb/cromwell/hub/misc.c b/reactos/drivers/usb/cromwell/hub/misc.c
new file mode 100644
index 00000000000..16fcb331ff8
--- /dev/null
+++ b/reactos/drivers/usb/cromwell/hub/misc.c
@@ -0,0 +1,166 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: USB hub driver
+ * FILE: drivers/usb/cromwell/hub/misc.c
+ * PURPOSE: Misceallenous operations
+ *
+ * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com),
+ */
+
+#define NDEBUG
+#include "usbhub.h"
+#include
+
+NTSTATUS STDCALL
+ForwardIrpAndWaitCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ if (Irp->PendingReturned)
+ KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+ForwardIrpAndWait(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PDEVICE_OBJECT LowerDevice = ((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
+ KEVENT Event;
+ NTSTATUS Status;
+
+ ASSERT(LowerDevice);
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+
+ DPRINT("UHCI: Calling lower device %p [%wZ]\n", LowerDevice, &LowerDevice->DriverObject->DriverName);
+ IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE);
+
+ Status = IoCallDriver(LowerDevice, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
+ if (NT_SUCCESS(Status))
+ Status = Irp->IoStatus.Status;
+ }
+
+ return Status;
+}
+
+NTSTATUS STDCALL
+ForwardIrpAndForget(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PDEVICE_OBJECT LowerDevice = ((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
+
+ ASSERT(LowerDevice);
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ return IoCallDriver(LowerDevice, Irp);
+}
+
+/* I really want PCSZ strings as last arguments because
+ * PnP ids are ANSI-encoded in PnP device string
+ * identification */
+NTSTATUS
+UsbhubInitMultiSzString(
+ OUT PUNICODE_STRING Destination,
+ ... /* list of PCSZ */)
+{
+ va_list args;
+ PCSZ Source;
+ ANSI_STRING AnsiString;
+ UNICODE_STRING UnicodeString;
+ ULONG DestinationSize = 0;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ ASSERT(Destination);
+
+ /* Calculate length needed for destination unicode string */
+ va_start(args, Destination);
+ Source = va_arg(args, PCSZ);
+ while (Source != NULL)
+ {
+ RtlInitAnsiString(&AnsiString, Source);
+ DestinationSize += RtlAnsiStringToUnicodeSize(&AnsiString)
+ + sizeof(WCHAR) /* final NULL */;
+ Source = va_arg(args, PCSZ);
+ }
+ va_end(args);
+ if (DestinationSize == 0)
+ {
+ RtlInitUnicodeString(Destination, NULL);
+ return STATUS_SUCCESS;
+ }
+
+ /* Initialize destination string */
+ DestinationSize += sizeof(WCHAR); // final NULL
+ Destination->Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, DestinationSize, USB_HUB_TAG);
+ if (!Destination->Buffer)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ Destination->Length = 0;
+ Destination->MaximumLength = (USHORT)DestinationSize;
+
+ /* Copy arguments to destination string */
+ /* Use a temporary unicode string, which buffer is shared with
+ * destination string, to copy arguments */
+ UnicodeString.Length = Destination->Length;
+ UnicodeString.MaximumLength = Destination->MaximumLength;
+ UnicodeString.Buffer = Destination->Buffer;
+ va_start(args, Destination);
+ Source = va_arg(args, PCSZ);
+ while (Source != NULL)
+ {
+ RtlInitAnsiString(&AnsiString, Source);
+ Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(Destination->Buffer, USB_HUB_TAG);
+ break;
+ }
+ Destination->Length += UnicodeString.Length + sizeof(WCHAR);
+ UnicodeString.MaximumLength -= UnicodeString.Length + sizeof(WCHAR);
+ UnicodeString.Buffer += UnicodeString.Length / sizeof(WCHAR) + 1;
+ UnicodeString.Length = 0;
+ Source = va_arg(args, PCSZ);
+ }
+ va_end(args);
+ if (NT_SUCCESS(Status))
+ {
+ /* Finish multi-sz string */
+ Destination->Buffer[Destination->Length / sizeof(WCHAR)] = L'\0';
+ Destination->Length += sizeof(WCHAR);
+ }
+ return Status;
+}
+
+NTSTATUS
+UsbhubDuplicateUnicodeString(
+ OUT PUNICODE_STRING Destination,
+ IN PUNICODE_STRING Source,
+ IN POOL_TYPE PoolType)
+{
+ ASSERT(Destination);
+
+ if (Source == NULL)
+ {
+ RtlInitUnicodeString(Destination, NULL);
+ return STATUS_SUCCESS;
+ }
+
+ Destination->Buffer = ExAllocatePool(PoolType, Source->MaximumLength);
+ if (Destination->Buffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Destination->MaximumLength = Source->MaximumLength;
+ Destination->Length = Source->Length;
+ RtlCopyMemory(Destination->Buffer, Source->Buffer, Source->MaximumLength);
+
+ return STATUS_SUCCESS;
+}
diff --git a/reactos/drivers/usb/cromwell/hub/pdo.c b/reactos/drivers/usb/cromwell/hub/pdo.c
new file mode 100644
index 00000000000..20274c12354
--- /dev/null
+++ b/reactos/drivers/usb/cromwell/hub/pdo.c
@@ -0,0 +1,78 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: USB hub driver
+ * FILE: drivers/usb/cromwell/hub/pdo.c
+ * PURPOSE: IRP_MJ_PNP operations for PDOs
+ *
+ * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
+ */
+
+//#define NDEBUG
+#include "usbhub.h"
+
+extern struct usb_driver hub_driver;
+
+#define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
+
+NTSTATUS
+UsbhubDeviceControlPdo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION Stack;
+ ULONG_PTR Information = 0;
+ NTSTATUS Status;
+
+ DPRINT("Usbhub: UsbhubDeviceControlPdo() called\n");
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ Status = Irp->IoStatus.Status;
+
+ switch (Stack->Parameters.DeviceIoControl.IoControlCode)
+ {
+ default:
+ {
+ DPRINT1("Usbhub: Unknown IOCTL code 0x%lx\n", Stack->Parameters.DeviceIoControl.IoControlCode);
+ Information = Irp->IoStatus.Information;
+ Status = Irp->IoStatus.Status;
+ }
+ }
+
+ Irp->IoStatus.Information = Information;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+}
+
+NTSTATUS STDCALL
+UsbhubPnpPdo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ ULONG MinorFunction;
+ PIO_STACK_LOCATION Stack;
+ ULONG_PTR Information = 0;
+ NTSTATUS Status;
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = Stack->MinorFunction;
+
+ switch (MinorFunction)
+ {
+ default:
+ {
+ /* We can't forward request to the lower driver, because
+ * we are a Pdo, so we don't have lower driver...
+ */
+ DPRINT1("Usbhub: IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
+ Information = Irp->IoStatus.Information;
+ Status = Irp->IoStatus.Status;
+ }
+ }
+
+ Irp->IoStatus.Information = Information;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+}
+
diff --git a/reactos/drivers/usb/cromwell/hub/usbhub.c b/reactos/drivers/usb/cromwell/hub/usbhub.c
new file mode 100644
index 00000000000..89c5af4b9b6
--- /dev/null
+++ b/reactos/drivers/usb/cromwell/hub/usbhub.c
@@ -0,0 +1,192 @@
+/*
+ * ReactOS USB hub driver
+ * Copyright (C) 2004 Aleksey Bragin
+ * (C) 2005 Mark Tempel
+ * (C) 2005 Hervé Poussineau
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+/* INCLUDES *******************************************************************/
+//#define NDEBUG
+#include "usbhub.h"
+
+/* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/
+
+static NTSTATUS
+GetRootHubPointer(
+ IN PDEVICE_OBJECT Pdo,
+ OUT PVOID* RootHubPointer)
+{
+ KEVENT Event;
+ PIRP Irp;
+ IO_STATUS_BLOCK IoStatus;
+ NTSTATUS Status;
+
+ KeInitializeEvent (&Event, NotificationEvent, FALSE);
+
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_ROOT_USB_DEVICE,
+ Pdo,
+ NULL, sizeof(NULL),
+ RootHubPointer, sizeof(*RootHubPointer),
+ FALSE,
+ &Event,
+ &IoStatus);
+ if (Irp == NULL)
+ {
+ DPRINT("Usbhub: IoBuildDeviceIoControlRequest() failed\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Status = IoCallDriver(Pdo, Irp);
+
+ if (Status == STATUS_PENDING)
+ {
+ DPRINT("Usbhub: Operation pending\n");
+ KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
+ Status = IoStatus.Status;
+ }
+
+ return Status;
+}
+
+NTSTATUS STDCALL
+UsbhubAddDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT Pdo)
+{
+ PDEVICE_OBJECT Fdo;
+ PHUB_DEVICE_EXTENSION DeviceExtension;
+ NTSTATUS Status;
+
+ Status = IoCreateDevice(DriverObject,
+ sizeof(HUB_DEVICE_EXTENSION),
+ NULL, /* DeviceName */
+ FILE_DEVICE_BUS_EXTENDER,
+ 0,
+ FALSE,
+ &Fdo);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Usbhub: IoCreateDevice() failed with status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ // zerofill device extension
+ DeviceExtension = (PHUB_DEVICE_EXTENSION)Fdo->DeviceExtension;
+ RtlZeroMemory(DeviceExtension, sizeof(HUB_DEVICE_EXTENSION));
+
+ /* Get a pointer to the linux structure created by the USB controller,
+ * by sending IOCTL_INTERNAL_USB_GET_ROOT_USB_DEVICE to lower device.
+ */
+ Status = GetRootHubPointer(Pdo, (PVOID*)&DeviceExtension->dev);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Usbhub: GetRootHubPointer() failed with status 0x%08lx\n", Status);
+ IoDeleteDevice(Fdo);
+ return Status;
+ }
+
+ DeviceExtension->IsFDO = TRUE;
+ Fdo->Flags |= DO_POWER_PAGABLE;
+ Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Usbhub: IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
+ IoDeleteDevice(Fdo);
+ return Status;
+ }
+ Fdo->Flags |= DO_BUFFERED_IO;
+ Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS STDCALL
+IrpStub(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ NTSTATUS Status;
+
+ if (((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
+ {
+ DPRINT1("Usbhub: FDO stub for major function 0x%lx\n",
+ IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
+#ifndef NDEBUG
+ DbgBreakPoint();
+#endif
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+ else
+ {
+ /* We can't forward request to the lower driver, because
+ * we are a Pdo, so we don't have lower driver...
+ */
+ DPRINT1("Usbhub: PDO stub for major function 0x%lx\n",
+ IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
+#ifndef NDEBUG
+ DbgBreakPoint();
+#endif
+ }
+
+ Status = Irp->IoStatus.Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+}
+
+static NTSTATUS STDCALL
+DispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ if (((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
+ return UsbhubDeviceControlFdo(DeviceObject, Irp);
+ else
+ return UsbhubDeviceControlPdo(DeviceObject, Irp);
+}
+
+static NTSTATUS STDCALL
+DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ if (((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
+ return UsbhubPnpFdo(DeviceObject, Irp);
+ else
+ return UsbhubPnpPdo(DeviceObject, Irp);
+}
+
+/*
+ * Standard DriverEntry method.
+ */
+NTSTATUS STDCALL
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath)
+{
+ ULONG i;
+
+ DriverObject->DriverExtension->AddDevice = UsbhubAddDevice;
+
+ for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
+ DriverObject->MajorFunction[i] = IrpStub;
+
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = UsbhubCreate;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = UsbhubClose;
+ DriverObject->MajorFunction[IRP_MJ_CLEANUP] = UsbhubCleanup;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;
+ DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
+
+ return STATUS_SUCCESS;
+}
+
diff --git a/reactos/drivers/usb/cromwell/hub/usbhub.h b/reactos/drivers/usb/cromwell/hub/usbhub.h
new file mode 100644
index 00000000000..4d402d9480b
--- /dev/null
+++ b/reactos/drivers/usb/cromwell/hub/usbhub.h
@@ -0,0 +1,82 @@
+#include
+
+#include
+#include
+
+#include "../usb_wrapper.h"
+#include "../core/hub.h"
+
+#define USB_HUB_TAG TAG('u','s','b','h')
+
+NTSTATUS STDCALL
+IoAttachDeviceToDeviceStackSafe(
+ IN PDEVICE_OBJECT SourceDevice,
+ IN PDEVICE_OBJECT TargetDevice,
+ OUT PDEVICE_OBJECT *AttachedToDeviceObject);
+
+typedef struct _HUB_DEVICE_EXTENSION
+{
+ BOOLEAN IsFDO;
+ struct usb_device* dev;
+ PDEVICE_OBJECT LowerDevice;
+} HUB_DEVICE_EXTENSION, *PHUB_DEVICE_EXTENSION;
+
+/* createclose.c */
+NTSTATUS STDCALL
+UsbhubCreate(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS STDCALL
+UsbhubClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS STDCALL
+UsbhubCleanup(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+/* fdo.c */
+NTSTATUS STDCALL
+UsbhubPnpFdo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS
+UsbhubDeviceControlFdo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+/* misc.c */
+NTSTATUS
+ForwardIrpAndWait(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS STDCALL
+ForwardIrpAndForget(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS
+UsbhubDuplicateUnicodeString(
+ OUT PUNICODE_STRING Destination,
+ IN PUNICODE_STRING Source,
+ IN POOL_TYPE PoolType);
+
+NTSTATUS
+UsbhubInitMultiSzString(
+ OUT PUNICODE_STRING Destination,
+ ... /* list of PCSZ */);
+
+/* pdo.c */
+NTSTATUS STDCALL
+UsbhubPnpPdo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS
+UsbhubDeviceControlPdo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
diff --git a/reactos/drivers/usb/cromwell/hub/usbhub.rc b/reactos/drivers/usb/cromwell/hub/usbhub.rc
new file mode 100644
index 00000000000..92314b2b0ce
--- /dev/null
+++ b/reactos/drivers/usb/cromwell/hub/usbhub.rc
@@ -0,0 +1,5 @@
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "USB Hub Driver\0"
+#define REACTOS_STR_INTERNAL_NAME "usbhub\0"
+#define REACTOS_STR_ORIGINAL_FILENAME "usbhub.sys\0"
+#include
diff --git a/reactos/drivers/usb/cromwell/usb_wrapper.h b/reactos/drivers/usb/cromwell/usb_wrapper.h
index 2e99e4c1855..9d3ad6ae9ff 100644
--- a/reactos/drivers/usb/cromwell/usb_wrapper.h
+++ b/reactos/drivers/usb/cromwell/usb_wrapper.h
@@ -26,3 +26,5 @@ int swprintf(wchar_t *buf, const wchar_t *fmt, ...);
#include "linux/usb.h"
#include "linux/pci_ids.h"
+#define IOCTL_INTERNAL_USB_GET_ROOT_USB_DEVICE \
+ CTL_CODE(FILE_DEVICE_USB, 4000, METHOD_BUFFERED, FILE_ANY_ACCESS)
diff --git a/reactos/drivers/usb/directory.xml b/reactos/drivers/usb/directory.xml
index 3c38d9b942b..04a748464ab 100644
--- a/reactos/drivers/usb/directory.xml
+++ b/reactos/drivers/usb/directory.xml
@@ -11,5 +11,5 @@
-
-
+
+