e4d1ca0f996c214e5a5a2c8299462d3ad49ad38d
[reactos.git] / reactos / drivers / usb / usbhub / usbhub.c
1 /*
2 * ReactOS USB hub driver
3 * Copyright (C) 2004 Aleksey Bragin
4 * (C) 2005 Mark Tempel
5 * (C) 2005 Hervé Poussineau
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 */
22
23 /* INCLUDES *******************************************************************/
24 //#define NDEBUG
25 #include "usbhub.h"
26
27 /* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/
28
29 static NTSTATUS
30 GetRootHubPointer(
31 IN PDEVICE_OBJECT Pdo,
32 OUT PVOID* RootHubPointer)
33 {
34 KEVENT Event;
35 PIRP Irp;
36 IO_STATUS_BLOCK IoStatus;
37 NTSTATUS Status;
38
39 KeInitializeEvent (&Event, NotificationEvent, FALSE);
40
41 Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_ROOT_USB_DEVICE,
42 Pdo,
43 NULL, sizeof(NULL),
44 RootHubPointer, sizeof(*RootHubPointer),
45 FALSE,
46 &Event,
47 &IoStatus);
48 if (Irp == NULL)
49 {
50 DPRINT("Usbhub: IoBuildDeviceIoControlRequest() failed\n");
51 return STATUS_INSUFFICIENT_RESOURCES;
52 }
53
54 Status = IoCallDriver(Pdo, Irp);
55
56 if (Status == STATUS_PENDING)
57 {
58 DPRINT("Usbhub: Operation pending\n");
59 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
60 Status = IoStatus.Status;
61 }
62
63 return Status;
64 }
65
66 NTSTATUS STDCALL
67 UsbhubAddDevice(
68 IN PDRIVER_OBJECT DriverObject,
69 IN PDEVICE_OBJECT Pdo)
70 {
71 PDEVICE_OBJECT Fdo;
72 PHUB_DEVICE_EXTENSION DeviceExtension;
73 NTSTATUS Status;
74
75 Status = IoCreateDevice(DriverObject,
76 sizeof(HUB_DEVICE_EXTENSION),
77 NULL, /* DeviceName */
78 FILE_DEVICE_BUS_EXTENDER,
79 0,
80 FALSE,
81 &Fdo);
82 if (!NT_SUCCESS(Status))
83 {
84 DPRINT1("Usbhub: IoCreateDevice() failed with status 0x%08lx\n", Status);
85 return Status;
86 }
87
88 // zerofill device extension
89 DeviceExtension = (PHUB_DEVICE_EXTENSION)Fdo->DeviceExtension;
90 RtlZeroMemory(DeviceExtension, sizeof(HUB_DEVICE_EXTENSION));
91
92 /* Get a pointer to the linux structure created by the USB controller,
93 * by sending IOCTL_INTERNAL_USB_GET_ROOT_USB_DEVICE to lower device.
94 */
95 Status = GetRootHubPointer(Pdo, (PVOID*)&DeviceExtension->dev);
96 if (!NT_SUCCESS(Status))
97 {
98 DPRINT("Usbhub: GetRootHubPointer() failed with status 0x%08lx\n", Status);
99 IoDeleteDevice(Fdo);
100 return Status;
101 }
102
103 DeviceExtension->IsFDO = TRUE;
104 Fdo->Flags |= DO_POWER_PAGABLE;
105 Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
106 if (!NT_SUCCESS(Status))
107 {
108 DPRINT("Usbhub: IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
109 IoDeleteDevice(Fdo);
110 return Status;
111 }
112 Fdo->Flags |= DO_BUFFERED_IO;
113 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
114
115 return STATUS_SUCCESS;
116 }
117
118 static NTSTATUS STDCALL
119 IrpStub(
120 IN PDEVICE_OBJECT DeviceObject,
121 IN PIRP Irp)
122 {
123 NTSTATUS Status;
124
125 if (((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
126 {
127 DPRINT1("Usbhub: FDO stub for major function 0x%lx\n",
128 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
129 #ifndef NDEBUG
130 DbgBreakPoint();
131 #endif
132 return ForwardIrpAndForget(DeviceObject, Irp);
133 }
134 else
135 {
136 /* We can't forward request to the lower driver, because
137 * we are a Pdo, so we don't have lower driver...
138 */
139 DPRINT1("Usbhub: PDO stub for major function 0x%lx\n",
140 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
141 #ifndef NDEBUG
142 DbgBreakPoint();
143 #endif
144 }
145
146 Status = Irp->IoStatus.Status;
147 IoCompleteRequest(Irp, IO_NO_INCREMENT);
148 return Status;
149 }
150
151 static NTSTATUS STDCALL
152 DispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
153 {
154 if (((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
155 return UsbhubDeviceControlFdo(DeviceObject, Irp);
156 else
157 return UsbhubDeviceControlPdo(DeviceObject, Irp);
158 }
159
160 static NTSTATUS STDCALL
161 DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
162 {
163 if (((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
164 return UsbhubPnpFdo(DeviceObject, Irp);
165 else
166 return UsbhubPnpPdo(DeviceObject, Irp);
167 }
168
169 /*
170 * Standard DriverEntry method.
171 */
172 NTSTATUS STDCALL
173 DriverEntry(
174 IN PDRIVER_OBJECT DriverObject,
175 IN PUNICODE_STRING RegistryPath)
176 {
177 ULONG i;
178
179 DriverObject->DriverExtension->AddDevice = UsbhubAddDevice;
180
181 for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
182 DriverObject->MajorFunction[i] = IrpStub;
183
184 DriverObject->MajorFunction[IRP_MJ_CREATE] = UsbhubCreate;
185 DriverObject->MajorFunction[IRP_MJ_CLOSE] = UsbhubClose;
186 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = UsbhubCleanup;
187 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;
188 DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
189
190 return STATUS_SUCCESS;
191 }
192