Big move of driver input stack to a Plug-and-Play model:
[reactos.git] / reactos / drivers / usb / miniport / common / main.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS USB miniport driver (Cromwell type)
4 * FILE: drivers/usb/miniport/common/main.c
5 * PURPOSE: Driver entry
6 *
7 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.com)
8 * Hervé Poussineau (hpoussin@reactos.org),
9 *
10 * Some parts of code are inspired (or even just copied) from
11 * ReactOS Videoport driver (drivers/video/videoprt)
12 */
13
14 #define NDEBUG
15 #include <debug.h>
16
17 #define INITGUID
18 #include "usbcommon.h"
19
20 // data for embedded drivers
21 CONNECT_DATA KbdClassInformation;
22 CONNECT_DATA MouseClassInformation;
23 PDEVICE_OBJECT KeyboardFdo = NULL;
24 PDEVICE_OBJECT MouseFdo = NULL;
25
26 static NTSTATUS
27 CreateRootHubPdo(
28 IN PDRIVER_OBJECT DriverObject,
29 IN PDEVICE_OBJECT Fdo,
30 OUT PDEVICE_OBJECT* pPdo)
31 {
32 PDEVICE_OBJECT Pdo;
33 PUSBMP_DEVICE_EXTENSION DeviceExtension;
34 NTSTATUS Status;
35
36 DPRINT("USBMP: CreateRootHubPdo()\n");
37
38 Status = IoCreateDevice(
39 DriverObject,
40 sizeof(USBMP_DEVICE_EXTENSION),
41 NULL, /* DeviceName */
42 FILE_DEVICE_BUS_EXTENDER,
43 FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,
44 FALSE,
45 &Pdo);
46 if (!NT_SUCCESS(Status))
47 {
48 DPRINT("USBMP: IoCreateDevice() call failed with status 0x%08x\n", Status);
49 return Status;
50 }
51
52 Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
53 Pdo->Flags |= DO_POWER_PAGABLE;
54
55 // zerofill device extension
56 DeviceExtension = (PUSBMP_DEVICE_EXTENSION)Pdo->DeviceExtension;
57 RtlZeroMemory(DeviceExtension, sizeof(USBMP_DEVICE_EXTENSION));
58
59 DeviceExtension->IsFDO = FALSE;
60 DeviceExtension->FunctionalDeviceObject = Fdo;
61
62 Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
63
64 *pPdo = Pdo;
65 return STATUS_SUCCESS;
66 }
67
68 static NTSTATUS
69 AddRegistryEntry(
70 IN PCWSTR PortTypeName,
71 IN PUNICODE_STRING DeviceName,
72 IN PCWSTR RegistryPath)
73 {
74 UNICODE_STRING PathU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
75 OBJECT_ATTRIBUTES ObjectAttributes;
76 HANDLE hDeviceMapKey = (HANDLE)-1;
77 HANDLE hPortKey = (HANDLE)-1;
78 UNICODE_STRING PortTypeNameU;
79 NTSTATUS Status;
80
81 InitializeObjectAttributes(&ObjectAttributes, &PathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
82 Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
83 if (!NT_SUCCESS(Status))
84 {
85 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
86 goto cleanup;
87 }
88
89 RtlInitUnicodeString(&PortTypeNameU, PortTypeName);
90 InitializeObjectAttributes(&ObjectAttributes, &PortTypeNameU, OBJ_KERNEL_HANDLE, hDeviceMapKey, NULL);
91 Status = ZwCreateKey(&hPortKey, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
92 if (!NT_SUCCESS(Status))
93 {
94 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
95 goto cleanup;
96 }
97
98 Status = ZwSetValueKey(hPortKey, DeviceName, 0, REG_SZ, (PVOID)RegistryPath, wcslen(RegistryPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
99 if (!NT_SUCCESS(Status))
100 {
101 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
102 goto cleanup;
103 }
104
105 Status = STATUS_SUCCESS;
106
107 cleanup:
108 if (hDeviceMapKey != (HANDLE)-1)
109 ZwClose(hDeviceMapKey);
110 if (hPortKey != (HANDLE)-1)
111 ZwClose(hPortKey);
112 return Status;
113 }
114
115 static NTSTATUS
116 AddDevice_Keyboard(
117 IN PDRIVER_OBJECT DriverObject,
118 IN PDEVICE_OBJECT Pdo)
119 {
120 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardPortUSB");
121 PDEVICE_OBJECT Fdo;
122 NTSTATUS Status;
123
124 Status = AddRegistryEntry(L"KeyboardPort", &DeviceName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\usbport");
125 if (!NT_SUCCESS(Status))
126 {
127 DPRINT1("USBMP: AddRegistryEntry() for usb keyboard driver failed with status 0x%08lx\n", Status);
128 return Status;
129 }
130
131 Status = IoCreateDevice(DriverObject,
132 8, // debug
133 &DeviceName,
134 FILE_DEVICE_KEYBOARD,
135 FILE_DEVICE_SECURE_OPEN,
136 TRUE,
137 &Fdo);
138
139 if (!NT_SUCCESS(Status))
140 {
141 DPRINT1("USBMP: IoCreateDevice() for usb keyboard driver failed with status 0x%08lx\n", Status);
142 return Status;
143 }
144 KeyboardFdo = Fdo;
145 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
146 DPRINT("USBMP: Created keyboard Fdo: %p\n", Fdo);
147
148 return STATUS_SUCCESS;
149 }
150
151 static NTSTATUS
152 AddDevice_Mouse(
153 IN PDRIVER_OBJECT DriverObject,
154 IN PDEVICE_OBJECT Pdo)
155 {
156 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\PointerPortUSB");
157 PDEVICE_OBJECT Fdo;
158 NTSTATUS Status;
159
160 Status = AddRegistryEntry(L"PointerPort", &DeviceName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\usbport");
161 if (!NT_SUCCESS(Status))
162 {
163 DPRINT1("USBMP: AddRegistryEntry() for usb mouse driver failed with status 0x%08lx\n", Status);
164 return Status;
165 }
166
167 Status = IoCreateDevice(DriverObject,
168 8, // debug
169 &DeviceName,
170 FILE_DEVICE_MOUSE,
171 FILE_DEVICE_SECURE_OPEN,
172 TRUE,
173 &Fdo);
174
175 if (!NT_SUCCESS(Status))
176 {
177 DPRINT1("USBMP: IoCreateDevice() for usb mouse driver failed with status 0x%08lx\n", Status);
178 return Status;
179 }
180 MouseFdo = Fdo;
181 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
182 DPRINT("USBMP: Created mouse Fdo: %p\n", Fdo);
183
184 return STATUS_SUCCESS;
185 }
186
187 NTSTATUS STDCALL
188 AddDevice(
189 IN PDRIVER_OBJECT DriverObject,
190 IN PDEVICE_OBJECT pdo)
191 {
192 PDEVICE_OBJECT fdo;
193 NTSTATUS Status;
194 WCHAR DeviceBuffer[20];
195 WCHAR LinkDeviceBuffer[20];
196 UNICODE_STRING DeviceName;
197 UNICODE_STRING LinkDeviceName;
198 PUSBMP_DRIVER_EXTENSION DriverExtension;
199 PUSBMP_DEVICE_EXTENSION DeviceExtension;
200 ULONG DeviceNumber;
201
202 /* FIXME: actually, we prevent multiple USB controllers on a computer */
203 static BOOLEAN xbox_workaround = FALSE;
204
205 DPRINT("USBMP: AddDevice called\n");
206
207 if (xbox_workaround)
208 // Fail for any other host controller than the first
209 return STATUS_INSUFFICIENT_RESOURCES;
210 xbox_workaround = TRUE;
211
212 // Allocate driver extension now
213 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
214 if (DriverExtension == NULL)
215 {
216 Status = IoAllocateDriverObjectExtension(
217 DriverObject,
218 DriverObject,
219 sizeof(USBMP_DRIVER_EXTENSION),
220 (PVOID *)&DriverExtension);
221
222 if (!NT_SUCCESS(Status))
223 {
224 DPRINT("USBMP: Allocating DriverObjectExtension failed.\n");
225 return Status;
226 }
227 }
228
229 // Create a unicode device name
230 DeviceNumber = 0; //TODO: Allocate new device number every time
231 swprintf(DeviceBuffer, L"\\Device\\USBFDO-%lu", DeviceNumber);
232 RtlInitUnicodeString(&DeviceName, DeviceBuffer);
233
234 Status = IoCreateDevice(DriverObject,
235 sizeof(USBMP_DEVICE_EXTENSION),
236 &DeviceName,
237 FILE_DEVICE_BUS_EXTENDER,
238 0,
239 FALSE,
240 &fdo);
241
242 if (!NT_SUCCESS(Status))
243 {
244 DPRINT("USBMP: IoCreateDevice call failed with status 0x%08lx\n", Status);
245 return Status;
246 }
247
248 // zerofill device extension
249 DeviceExtension = (PUSBMP_DEVICE_EXTENSION)fdo->DeviceExtension;
250 RtlZeroMemory(DeviceExtension, sizeof(USBMP_DEVICE_EXTENSION));
251
252 /* Create root hub Pdo */
253 Status = CreateRootHubPdo(DriverObject, fdo, &DeviceExtension->RootHubPdo);
254 if (!NT_SUCCESS(Status))
255 {
256 DPRINT("USBMP: CreateRootHubPdo() failed with status 0x%08lx\n", Status);
257 IoDeleteDevice(fdo);
258 return Status;
259 }
260
261 /* Register device interface for controller */
262 Status = IoRegisterDeviceInterface(
263 pdo,
264 &GUID_DEVINTERFACE_USB_HOST_CONTROLLER,
265 NULL,
266 &DeviceExtension->HcdInterfaceName);
267 if (!NT_SUCCESS(Status))
268 {
269 DPRINT("USBMP: IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
270 IoDeleteDevice(DeviceExtension->RootHubPdo);
271 IoDeleteDevice(fdo);
272 return Status;
273 }
274
275 DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo);
276
277 // Initialize device extension
278 DeviceExtension->IsFDO = TRUE;
279 DeviceExtension->DeviceNumber = DeviceNumber;
280 DeviceExtension->PhysicalDeviceObject = pdo;
281 DeviceExtension->FunctionalDeviceObject = fdo;
282 DeviceExtension->DriverExtension = DriverExtension;
283
284 fdo->Flags &= ~DO_DEVICE_INITIALIZING;
285
286 /* FIXME: do a loop to find an available number */
287 swprintf(LinkDeviceBuffer, L"\\??\\HCD%lu", 0);
288
289 RtlInitUnicodeString(&LinkDeviceName, LinkDeviceBuffer);
290
291 Status = IoCreateSymbolicLink(&LinkDeviceName, &DeviceName);
292
293 if (NT_SUCCESS(Status))
294 Status = AddDevice_Keyboard(DriverObject, pdo);
295 if (NT_SUCCESS(Status))
296 Status = AddDevice_Mouse(DriverObject, pdo);
297
298 if (!NT_SUCCESS(Status))
299 {
300 DPRINT("USBMP: IoCreateSymbolicLink() call failed with status 0x%08x\n", Status);
301 IoDeleteDevice(DeviceExtension->RootHubPdo);
302 IoDeleteDevice(fdo);
303 return Status;
304 }
305
306
307 return STATUS_SUCCESS;
308 }
309
310 NTSTATUS STDCALL
311 IrpStub(
312 IN PDEVICE_OBJECT DeviceObject,
313 IN PIRP Irp)
314 {
315 NTSTATUS Status = STATUS_NOT_SUPPORTED;
316
317 if (((PUSBMP_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
318 {
319 DPRINT1("USBMP: FDO stub for major function 0x%lx\n",
320 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
321 #ifndef NDEBUG
322 DbgBreakPoint();
323 #endif
324 return ForwardIrpAndForget(DeviceObject, Irp);
325 }
326 else
327 {
328 /* We can't forward request to the lower driver, because
329 * we are a Pdo, so we don't have lower driver...
330 */
331 DPRINT1("USBMP: PDO stub for major function 0x%lx\n",
332 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
333 #ifndef NDEBUG
334 DbgBreakPoint();
335 #endif
336 }
337
338 Status = Irp->IoStatus.Status;
339 IoCompleteRequest(Irp, IO_NO_INCREMENT);
340 return Status;
341 }
342
343 static NTSTATUS STDCALL
344 DispatchCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
345 {
346 if (((PUSBMP_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
347 return UsbMpCreate(DeviceObject, Irp);
348 else
349 return IrpStub(DeviceObject, Irp);
350 }
351
352 static NTSTATUS STDCALL
353 DispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
354 {
355 if (((PUSBMP_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
356 return UsbMpClose(DeviceObject, Irp);
357 else
358 return IrpStub(DeviceObject, Irp);
359 }
360
361 static NTSTATUS STDCALL
362 DispatchCleanup(PDEVICE_OBJECT DeviceObject, PIRP Irp)
363 {
364 if (((PUSBMP_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
365 return UsbMpCleanup(DeviceObject, Irp);
366 else
367 return IrpStub(DeviceObject, Irp);
368 }
369
370 static NTSTATUS STDCALL
371 DispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
372 {
373 if (((PUSBMP_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
374 return UsbMpDeviceControlFdo(DeviceObject, Irp);
375 else
376 return UsbMpDeviceControlPdo(DeviceObject, Irp);
377 }
378
379 static NTSTATUS STDCALL
380 DispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
381 {
382 if (((PUSBMP_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
383 return UsbMpInternalDeviceControlFdo(DeviceObject, Irp);
384 else
385 return IrpStub(DeviceObject, Irp);
386 }
387
388 static NTSTATUS STDCALL
389 DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
390 {
391 if (((PUSBMP_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
392 return UsbMpPnpFdo(DeviceObject, Irp);
393 else
394 return UsbMpPnpPdo(DeviceObject, Irp);
395 }
396
397 static NTSTATUS STDCALL
398 DispatchPower(PDEVICE_OBJECT fido, PIRP Irp)
399 {
400 DPRINT1("USBMP: IRP_MJ_POWER unimplemented\n");
401 Irp->IoStatus.Information = 0;
402 Irp->IoStatus.Status = STATUS_SUCCESS;
403 IoCompleteRequest(Irp, IO_NO_INCREMENT);
404 return STATUS_SUCCESS;
405 }
406
407 /*
408 * Standard DriverEntry method.
409 */
410 NTSTATUS STDCALL
411 DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath)
412 {
413 USBPORT_INTERFACE UsbPortInterface;
414 ULONG i;
415
416 DriverObject->DriverUnload = DriverUnload;
417 DriverObject->DriverExtension->AddDevice = AddDevice;
418
419 for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
420 DriverObject->MajorFunction[i] = IrpStub;
421
422 DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
423 DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
424 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DispatchCleanup;
425 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;
426 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = DispatchInternalDeviceControl;
427 DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
428 DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;
429
430 // Register in usbcore.sys
431 UsbPortInterface.KbdConnectData = &KbdClassInformation;
432 UsbPortInterface.MouseConnectData = &MouseClassInformation;
433
434 KbdClassInformation.ClassService = NULL;
435 KbdClassInformation.ClassDeviceObject = NULL;
436 MouseClassInformation.ClassService = NULL;
437 MouseClassInformation.ClassDeviceObject = NULL;
438
439 RegisterPortDriver(DriverObject, &UsbPortInterface);
440
441 return STATUS_SUCCESS;
442 }