Sync up to trunk head.
[reactos.git] / 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 along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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_PARENT_HUB_INFO,
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 /* Initialize the status block before sending the IRP */
55 IoGetNextIrpStackLocation(Irp)->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
56 IoStatus.Status = STATUS_NOT_SUPPORTED;
57 IoStatus.Information = 0;
58
59 Status = IoCallDriver(Pdo, Irp);
60
61 if (Status == STATUS_PENDING)
62 {
63 DPRINT("Usbhub: Operation pending\n");
64 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
65 Status = IoStatus.Status;
66 }
67
68 return Status;
69 }
70
71 NTSTATUS NTAPI
72 UsbhubAddDevice(
73 IN PDRIVER_OBJECT DriverObject,
74 IN PDEVICE_OBJECT Pdo)
75 {
76 PDEVICE_OBJECT Fdo;
77 PHUB_DEVICE_EXTENSION DeviceExtension;
78 NTSTATUS Status;
79
80 Status = IoCreateDevice(DriverObject,
81 sizeof(HUB_DEVICE_EXTENSION),
82 NULL, /* DeviceName */
83 FILE_DEVICE_BUS_EXTENDER,
84 0,
85 FALSE,
86 &Fdo);
87 if (!NT_SUCCESS(Status))
88 {
89 DPRINT1("Usbhub: IoCreateDevice() failed with status 0x%08lx\n", Status);
90 return Status;
91 }
92
93 // zerofill device extension
94 DeviceExtension = (PHUB_DEVICE_EXTENSION)Fdo->DeviceExtension;
95 RtlZeroMemory(DeviceExtension, sizeof(HUB_DEVICE_EXTENSION));
96
97 /* Get a pointer to the linux structure created by the USB controller,
98 * by sending IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO to lower device.
99 */
100 Status = GetRootHubPointer(Pdo, (PVOID*)&DeviceExtension->dev);
101 if (!NT_SUCCESS(Status))
102 {
103 DPRINT("Usbhub: GetRootHubPointer() failed with status 0x%08lx\n", Status);
104 IoDeleteDevice(Fdo);
105 return Status;
106 }
107 DeviceExtension->dev->dev.dev_ext = Pdo;
108
109 DeviceExtension->IsFDO = TRUE;
110 Fdo->Flags |= DO_POWER_PAGABLE;
111 Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
112 if (!NT_SUCCESS(Status))
113 {
114 DPRINT("Usbhub: IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
115 IoDeleteDevice(Fdo);
116 return Status;
117 }
118 Fdo->Flags |= DO_BUFFERED_IO;
119 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
120
121 return STATUS_SUCCESS;
122 }
123
124 static NTSTATUS NTAPI
125 IrpStub(
126 IN PDEVICE_OBJECT DeviceObject,
127 IN PIRP Irp)
128 {
129 NTSTATUS Status;
130
131 if (((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
132 {
133 DPRINT1("Usbhub: FDO stub for major function 0x%lx\n",
134 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
135 #ifndef NDEBUG
136 DbgBreakPoint();
137 #endif
138 return ForwardIrpAndForget(DeviceObject, Irp);
139 }
140 else
141 {
142 /* We can't forward request to the lower driver, because
143 * we are a Pdo, so we don't have lower driver...
144 */
145 DPRINT1("Usbhub: PDO stub for major function 0x%lx\n",
146 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
147 #ifndef NDEBUG
148 DbgBreakPoint();
149 #endif
150 }
151
152 Status = Irp->IoStatus.Status;
153 IoCompleteRequest(Irp, IO_NO_INCREMENT);
154 return Status;
155 }
156
157 static NTSTATUS NTAPI
158 DispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
159 {
160 if (((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
161 return UsbhubDeviceControlFdo(DeviceObject, Irp);
162 else
163 return IrpStub(DeviceObject, Irp);
164 }
165
166 static NTSTATUS NTAPI
167 DispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
168 {
169 if (((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
170 return IrpStub(DeviceObject, Irp);
171 else
172 return UsbhubInternalDeviceControlPdo(DeviceObject, Irp);
173 }
174
175 static NTSTATUS NTAPI
176 DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
177 {
178 if (((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
179 return UsbhubPnpFdo(DeviceObject, Irp);
180 else
181 return UsbhubPnpPdo(DeviceObject, Irp);
182 }
183
184 /*
185 * Standard DriverEntry method.
186 */
187 NTSTATUS NTAPI
188 DriverEntry(
189 IN PDRIVER_OBJECT DriverObject,
190 IN PUNICODE_STRING RegistryPath)
191 {
192 ULONG i;
193
194 DriverObject->DriverExtension->AddDevice = UsbhubAddDevice;
195
196 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
197 DriverObject->MajorFunction[i] = IrpStub;
198
199 DriverObject->MajorFunction[IRP_MJ_CREATE] = UsbhubCreate;
200 DriverObject->MajorFunction[IRP_MJ_CLOSE] = UsbhubClose;
201 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = UsbhubCleanup;
202 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;
203 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = DispatchInternalDeviceControl;
204 DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
205
206 return STATUS_SUCCESS;
207 }
208