e1b2bf8b579facd1268fac27d75c5ea07a9d79db
[reactos.git] / reactos / drivers / input / mouclass / mouclass.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Mouse class driver
4 * FILE: drivers/mouclass/mouclass.c
5 * PURPOSE: Mouse class driver
6 *
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 #define NDEBUG
11 #include <debug.h>
12
13 #define INITGUID
14 #include "mouclass.h"
15
16 static VOID NTAPI
17 DriverUnload(IN PDRIVER_OBJECT DriverObject)
18 {
19 // nothing to do here yet
20 }
21
22 static NTSTATUS NTAPI
23 MouclassCreate(
24 IN PDEVICE_OBJECT DeviceObject,
25 IN PIRP Irp)
26 {
27 DPRINT("IRP_MJ_CREATE\n");
28
29 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
30 return ForwardIrpAndForget(DeviceObject, Irp);
31
32 /* FIXME: open all associated Port devices */
33 return STATUS_SUCCESS;
34 }
35
36 static NTSTATUS NTAPI
37 MouclassClose(
38 IN PDEVICE_OBJECT DeviceObject,
39 IN PIRP Irp)
40 {
41 DPRINT("IRP_MJ_CLOSE\n");
42
43 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
44 return ForwardIrpAndForget(DeviceObject, Irp);
45
46 /* FIXME: close all associated Port devices */
47 return STATUS_SUCCESS;
48 }
49
50 static NTSTATUS NTAPI
51 MouclassRead(
52 IN PDEVICE_OBJECT DeviceObject,
53 IN PIRP Irp)
54 {
55 DPRINT("IRP_MJ_READ\n");
56
57 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
58 return ForwardIrpAndForget(DeviceObject, Irp);
59
60 if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length < sizeof(MOUSE_INPUT_DATA))
61 {
62 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
63 Irp->IoStatus.Information = 0;
64 IoCompleteRequest(Irp, IO_NO_INCREMENT);
65
66 return STATUS_BUFFER_TOO_SMALL;
67 }
68
69 IoMarkIrpPending(Irp);
70 IoStartPacket(DeviceObject, Irp, NULL, NULL);
71 return STATUS_PENDING;
72 }
73
74 static NTSTATUS NTAPI
75 IrpStub(
76 IN PDEVICE_OBJECT DeviceObject,
77 IN PIRP Irp)
78 {
79 NTSTATUS Status = STATUS_NOT_SUPPORTED;
80
81 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
82 {
83 /* Forward some IRPs to lower device */
84 switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction)
85 {
86 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
87 return ForwardIrpAndForget(DeviceObject, Irp);
88 default:
89 {
90 DPRINT1("Port DO stub for major function 0x%lx\n",
91 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
92 ASSERT(FALSE);
93 Status = Irp->IoStatus.Status;
94 }
95 }
96 }
97 else if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) /* HACK FOR I8042PRT */
98 {
99 Status = STATUS_SUCCESS;
100 }
101 else
102 {
103 DPRINT1("Class DO stub for major function 0x%lx\n",
104 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
105 ASSERT(FALSE);
106 Status = Irp->IoStatus.Status;
107 }
108
109 Irp->IoStatus.Status = Status;
110 IoCompleteRequest(Irp, IO_NO_INCREMENT);
111 return Status;
112 }
113
114 static NTSTATUS
115 ReadRegistryEntries(
116 IN PUNICODE_STRING RegistryPath,
117 IN PMOUCLASS_DRIVER_EXTENSION DriverExtension)
118 {
119 RTL_QUERY_REGISTRY_TABLE Parameters[4];
120 NTSTATUS Status;
121
122 ULONG DefaultConnectMultiplePorts = 1;
123 ULONG DefaultMouseDataQueueSize = 0x64;
124 UNICODE_STRING DefaultPointerDeviceBaseName = RTL_CONSTANT_STRING(L"PointerClassPnp");
125
126 RtlZeroMemory(Parameters, sizeof(Parameters));
127
128 Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
129 Parameters[0].Name = L"ConnectMultiplePorts";
130 Parameters[0].EntryContext = &DriverExtension->ConnectMultiplePorts;
131 Parameters[0].DefaultType = REG_DWORD;
132 Parameters[0].DefaultData = &DefaultConnectMultiplePorts;
133 Parameters[0].DefaultLength = sizeof(ULONG);
134
135 Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
136 Parameters[1].Name = L"MouseDataQueueSize";
137 Parameters[1].EntryContext = &DriverExtension->MouseDataQueueSize;
138 Parameters[1].DefaultType = REG_DWORD;
139 Parameters[1].DefaultData = &DefaultMouseDataQueueSize;
140 Parameters[1].DefaultLength = sizeof(ULONG);
141
142 Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
143 Parameters[2].Name = L"PointerDeviceBaseName";
144 Parameters[2].EntryContext = &DriverExtension->PointerDeviceBaseName;
145 Parameters[2].DefaultType = REG_SZ;
146 Parameters[2].DefaultData = &DefaultPointerDeviceBaseName;
147 Parameters[2].DefaultLength = sizeof(ULONG);
148
149 Status = RtlQueryRegistryValues(
150 RTL_REGISTRY_ABSOLUTE,
151 RegistryPath->Buffer,
152 Parameters,
153 NULL,
154 NULL);
155
156 if (NT_SUCCESS(Status))
157 {
158 /* Check values */
159 if (DriverExtension->ConnectMultiplePorts != 0
160 && DriverExtension->ConnectMultiplePorts != 1)
161 {
162 DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
163 }
164 if (DriverExtension->MouseDataQueueSize == 0)
165 {
166 DriverExtension->MouseDataQueueSize = DefaultMouseDataQueueSize;
167 }
168 }
169
170 return Status;
171 }
172
173 static NTSTATUS
174 CreatePointerClassDeviceObject(
175 IN PDRIVER_OBJECT DriverObject,
176 OUT PDEVICE_OBJECT *ClassDO OPTIONAL)
177 {
178 PMOUCLASS_DRIVER_EXTENSION DriverExtension;
179 ULONG DeviceId = 0;
180 ULONG PrefixLength;
181 UNICODE_STRING DeviceNameU;
182 PWSTR DeviceIdW = NULL; /* Pointer into DeviceNameU.Buffer */
183 PDEVICE_OBJECT Fdo;
184 PMOUCLASS_DEVICE_EXTENSION DeviceExtension;
185 NTSTATUS Status;
186
187 DPRINT("CreatePointerClassDeviceObject(0x%p)\n", DriverObject);
188
189 /* Create new device object */
190 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
191 DeviceNameU.Length = 0;
192 DeviceNameU.MaximumLength =
193 wcslen(L"\\Device\\") * sizeof(WCHAR) /* "\Device\" */
194 + DriverExtension->PointerDeviceBaseName.Length /* "PointerClass" */
195 + 4 * sizeof(WCHAR) /* Id between 0 and 9999 */
196 + sizeof(UNICODE_NULL); /* Final NULL char */
197 DeviceNameU.Buffer = ExAllocatePool(PagedPool, DeviceNameU.MaximumLength);
198 if (!DeviceNameU.Buffer)
199 {
200 DPRINT("ExAllocatePool() failed\n");
201 return STATUS_INSUFFICIENT_RESOURCES;
202 }
203 Status = RtlAppendUnicodeToString(&DeviceNameU, L"\\Device\\");
204 if (!NT_SUCCESS(Status))
205 {
206 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
207 goto cleanup;
208 }
209 Status = RtlAppendUnicodeStringToString(&DeviceNameU, &DriverExtension->PointerDeviceBaseName);
210 if (!NT_SUCCESS(Status))
211 {
212 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
213 goto cleanup;
214 }
215 PrefixLength = DeviceNameU.MaximumLength - 4 * sizeof(WCHAR) - sizeof(UNICODE_NULL);
216 DeviceIdW = &DeviceNameU.Buffer[PrefixLength / sizeof(WCHAR)];
217 while (DeviceId < 9999)
218 {
219 DeviceNameU.Length = PrefixLength + swprintf(DeviceIdW, L"%ld", DeviceId) * sizeof(WCHAR);
220 Status = IoCreateDevice(
221 DriverObject,
222 sizeof(MOUCLASS_DEVICE_EXTENSION),
223 &DeviceNameU,
224 FILE_DEVICE_MOUSE,
225 FILE_DEVICE_SECURE_OPEN,
226 FALSE,
227 &Fdo);
228 if (NT_SUCCESS(Status))
229 goto cleanup;
230 else if (Status != STATUS_OBJECT_NAME_COLLISION)
231 {
232 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
233 goto cleanup;
234 }
235 DeviceId++;
236 }
237 DPRINT("Too much devices starting with '\\Device\\%wZ'\n", &DriverExtension->PointerDeviceBaseName);
238 Status = STATUS_UNSUCCESSFUL;
239 cleanup:
240 ExFreePool(DeviceNameU.Buffer);
241 if (!NT_SUCCESS(Status))
242 return Status;
243
244 DeviceExtension = (PMOUCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
245 RtlZeroMemory(DeviceExtension, sizeof(MOUCLASS_DEVICE_EXTENSION));
246 DeviceExtension->Common.IsClassDO = TRUE;
247 DeviceExtension->DriverExtension = DriverExtension;
248 DeviceExtension->PnpState = dsStopped;
249 KeInitializeSpinLock(&(DeviceExtension->SpinLock));
250 DeviceExtension->ReadIsPending = FALSE;
251 DeviceExtension->InputCount = 0;
252 DeviceExtension->PortData = ExAllocatePool(NonPagedPool, DeviceExtension->DriverExtension->MouseDataQueueSize * sizeof(MOUSE_INPUT_DATA));
253 Fdo->Flags |= DO_POWER_PAGABLE;
254 Fdo->Flags |= DO_BUFFERED_IO;
255 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
256
257 /* FIXME: create registry entry in HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
258
259 if (ClassDO)
260 *ClassDO = Fdo;
261
262 return STATUS_SUCCESS;
263 }
264
265 static BOOLEAN
266 MouclassCallback(
267 IN PDEVICE_OBJECT ClassDeviceObject,
268 IN OUT PMOUSE_INPUT_DATA MouseDataStart,
269 IN PMOUSE_INPUT_DATA MouseDataEnd,
270 IN OUT PULONG ConsumedCount)
271 {
272 PMOUCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
273 PIRP Irp = NULL;
274 KIRQL OldIrql;
275 PIO_STACK_LOCATION Stack;
276 ULONG InputCount = MouseDataEnd - MouseDataStart;
277 ULONG ReadSize;
278
279 ASSERT(ClassDeviceExtension->Common.IsClassDO);
280
281 DPRINT("MouclassCallback()\n");
282 /* A filter driver might have consumed all the data already; I'm
283 * not sure if they are supposed to move the packets when they
284 * consume them though.
285 */
286 if (ClassDeviceExtension->ReadIsPending == TRUE && InputCount)
287 {
288 Irp = ClassDeviceObject->CurrentIrp;
289 ClassDeviceObject->CurrentIrp = NULL;
290 Stack = IoGetCurrentIrpStackLocation(Irp);
291
292 /* A read request is waiting for input, so go straight to it */
293 RtlMoveMemory(
294 Irp->AssociatedIrp.SystemBuffer,
295 MouseDataStart,
296 sizeof(MOUSE_INPUT_DATA));
297
298 /* Go to next packet and complete this request with STATUS_SUCCESS */
299 Irp->IoStatus.Status = STATUS_SUCCESS;
300 Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA);
301 Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA);
302
303 ClassDeviceExtension->ReadIsPending = FALSE;
304
305 /* Skip the packet we just sent away */
306 MouseDataStart++;
307 (*ConsumedCount)++;
308 InputCount--;
309 }
310
311 /* If we have data from the port driver and a higher service to send the data to */
312 if (InputCount != 0)
313 {
314 KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
315
316 if (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->MouseDataQueueSize)
317 ReadSize = ClassDeviceExtension->DriverExtension->MouseDataQueueSize - ClassDeviceExtension->InputCount;
318 else
319 ReadSize = InputCount;
320
321 /*
322 * FIXME: If we exceed the buffer, mouse data gets thrown away.. better
323 * solution?
324 */
325
326 /*
327 * Move the mouse input data from the port data queue to our class data
328 * queue.
329 */
330 RtlMoveMemory(
331 ClassDeviceExtension->PortData,
332 (PCHAR)MouseDataStart,
333 sizeof(MOUSE_INPUT_DATA) * ReadSize);
334
335 /* Move the pointer and counter up */
336 ClassDeviceExtension->PortData += ReadSize;
337 ClassDeviceExtension->InputCount += ReadSize;
338
339 KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
340 (*ConsumedCount) += ReadSize;
341 }
342 else
343 {
344 DPRINT("MouclassCallBack() entered, InputCount = %lu - DOING NOTHING\n", InputCount);
345 }
346
347 if (Irp != NULL)
348 {
349 IoStartNextPacket(ClassDeviceObject, FALSE);
350 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
351 }
352
353 DPRINT("Leaving MouclassCallback()\n");
354 return TRUE;
355 }
356
357 /* Send IOCTL_INTERNAL_MOUSE_CONNECT to pointer port */
358 static NTSTATUS
359 ConnectMousePortDriver(
360 IN PDEVICE_OBJECT PointerPortDO,
361 IN PDEVICE_OBJECT PointerClassDO)
362 {
363 KEVENT Event;
364 PIRP Irp;
365 IO_STATUS_BLOCK IoStatus;
366 CONNECT_DATA ConnectData;
367 NTSTATUS Status;
368
369 KeInitializeEvent(&Event, NotificationEvent, FALSE);
370
371 ConnectData.ClassDeviceObject = PointerClassDO;
372 ConnectData.ClassService = MouclassCallback;
373
374 Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT,
375 PointerPortDO,
376 &ConnectData, sizeof(CONNECT_DATA),
377 NULL, 0,
378 TRUE, &Event, &IoStatus);
379
380 Status = IoCallDriver(PointerPortDO, Irp);
381
382 if (Status == STATUS_PENDING)
383 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
384 else
385 IoStatus.Status = Status;
386
387 return IoStatus.Status;
388 }
389
390 static NTSTATUS NTAPI
391 MouclassAddDevice(
392 IN PDRIVER_OBJECT DriverObject,
393 IN PDEVICE_OBJECT Pdo)
394 {
395 PMOUCLASS_DRIVER_EXTENSION DriverExtension;
396 PDEVICE_OBJECT Fdo;
397 PMOUCLASS_DEVICE_EXTENSION DeviceExtension;
398 NTSTATUS Status;
399
400 DPRINT("MouclassAddDevice called. Pdo = 0x%p\n", Pdo);
401
402 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
403
404 /* Create new device object */
405 Status = IoCreateDevice(
406 DriverObject,
407 sizeof(MOUCLASS_DEVICE_EXTENSION),
408 NULL,
409 Pdo->DeviceType,
410 FILE_DEVICE_SECURE_OPEN,
411 FALSE,
412 &Fdo);
413 if (!NT_SUCCESS(Status))
414 {
415 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
416 return Status;
417 }
418
419 DeviceExtension = (PMOUCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
420 RtlZeroMemory(DeviceExtension, sizeof(MOUCLASS_DEVICE_EXTENSION));
421 DeviceExtension->Common.IsClassDO = FALSE;
422 DeviceExtension->PnpState = dsStopped;
423 Fdo->Flags |= DO_POWER_PAGABLE;
424 Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
425 if (!NT_SUCCESS(Status))
426 {
427 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
428 IoDeleteDevice(Fdo);
429 return Status;
430 }
431 Fdo->Flags |= DO_BUFFERED_IO;
432 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
433
434 if (DriverExtension->ConnectMultiplePorts)
435 Status = ConnectMousePortDriver(Fdo, DriverExtension->MainMouclassDeviceObject);
436 else
437 Status = ConnectMousePortDriver(Fdo, Fdo);
438 if (!NT_SUCCESS(Status))
439 {
440 DPRINT("ConnectMousePortDriver() failed with status 0x%08lx\n", Status);
441 /* FIXME: why can't I cleanup without error? */
442 //IoDetachDevice(Fdo);
443 //IoDeleteDevice(Fdo);
444 return Status;
445 }
446
447 /* Register GUID_DEVINTERFACE_MOUSE interface */
448 Status = IoRegisterDeviceInterface(
449 Pdo,
450 &GUID_DEVINTERFACE_MOUSE,
451 NULL,
452 &DeviceExtension->MouseInterfaceName);
453 if (!NT_SUCCESS(Status))
454 {
455 DPRINT("IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
456 return Status;
457 }
458
459 return STATUS_SUCCESS;
460 }
461
462 static VOID NTAPI
463 MouclassStartIo(
464 IN PDEVICE_OBJECT DeviceObject,
465 IN PIRP Irp)
466 {
467 PMOUCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
468 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
469
470 ASSERT(DeviceExtension->Common.IsClassDO);
471
472 if (DeviceExtension->InputCount > 0)
473 {
474 KIRQL oldIrql;
475
476 KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql);
477
478 RtlMoveMemory(
479 Irp->AssociatedIrp.SystemBuffer,
480 DeviceExtension->PortData - DeviceExtension->InputCount,
481 sizeof(MOUSE_INPUT_DATA));
482
483 if (DeviceExtension->InputCount > 1)
484 {
485 RtlMoveMemory(
486 DeviceExtension->PortData - DeviceExtension->InputCount,
487 DeviceExtension->PortData - DeviceExtension->InputCount + 1,
488 (DeviceExtension->InputCount - 1) * sizeof(MOUSE_INPUT_DATA));
489 }
490 DeviceExtension->PortData--;
491 DeviceExtension->InputCount--;
492 DeviceExtension->ReadIsPending = FALSE;
493
494 /* Go to next packet and complete this request with STATUS_SUCCESS */
495 Irp->IoStatus.Status = STATUS_SUCCESS;
496 Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA);
497 Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA);
498 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
499
500 IoStartNextPacket(DeviceObject, FALSE);
501 KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
502 }
503 else
504 {
505 DeviceExtension->ReadIsPending = TRUE;
506 }
507 }
508
509 static NTSTATUS
510 SearchForLegacyDrivers(
511 IN PMOUCLASS_DRIVER_EXTENSION DriverExtension)
512 {
513 PDEVICE_OBJECT PortDeviceObject = NULL;
514 PFILE_OBJECT FileObject = NULL;
515 UNICODE_STRING PortName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0");
516 NTSTATUS Status;
517
518 /* FIXME: search for more than once legacy driver */
519
520 Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
521 if(Status != STATUS_SUCCESS)
522 {
523 DPRINT("Could not open old device object (Status 0x%08lx)\n", Status);
524 return Status;
525 }
526
527 if (DriverExtension->ConnectMultiplePorts)
528 Status = ConnectMousePortDriver(PortDeviceObject, DriverExtension->MainMouclassDeviceObject);
529 else
530 {
531 /* What to do */
532 KEBUGCHECK(0);
533 }
534 if (!NT_SUCCESS(Status))
535 {
536 DPRINT("ConnectMousePortDriver() failed with status 0x%08lx\n", Status);
537 return Status;
538 }
539 return STATUS_SUCCESS;
540 }
541
542 /*
543 * Standard DriverEntry method.
544 */
545 NTSTATUS NTAPI
546 DriverEntry(
547 IN PDRIVER_OBJECT DriverObject,
548 IN PUNICODE_STRING RegistryPath)
549 {
550 PMOUCLASS_DRIVER_EXTENSION DriverExtension;
551 ULONG i;
552 NTSTATUS Status;
553
554 Status = IoAllocateDriverObjectExtension(
555 DriverObject,
556 DriverObject,
557 sizeof(MOUCLASS_DRIVER_EXTENSION),
558 (PVOID*)&DriverExtension);
559 if (!NT_SUCCESS(Status))
560 {
561 DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
562 return Status;
563 }
564 RtlZeroMemory(DriverExtension, sizeof(MOUCLASS_DRIVER_EXTENSION));
565
566 Status = ReadRegistryEntries(RegistryPath, DriverExtension);
567 if (!NT_SUCCESS(Status))
568 {
569 DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status);
570 return Status;
571 }
572
573 if (DriverExtension->ConnectMultiplePorts == 1)
574 {
575 Status = CreatePointerClassDeviceObject(
576 DriverObject,
577 &DriverExtension->MainMouclassDeviceObject);
578 if (!NT_SUCCESS(Status))
579 {
580 DPRINT("CreatePointerClassDeviceObject() failed with status 0x%08lx\n", Status);
581 return Status;
582 }
583 }
584
585 DriverObject->DriverExtension->AddDevice = MouclassAddDevice;
586 DriverObject->DriverUnload = DriverUnload;
587
588 for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
589 DriverObject->MajorFunction[i] = IrpStub;
590
591 DriverObject->MajorFunction[IRP_MJ_CREATE] = MouclassCreate;
592 DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouclassClose;
593 DriverObject->MajorFunction[IRP_MJ_READ] = MouclassRead;
594 DriverObject->DriverStartIo = MouclassStartIo;
595
596 SearchForLegacyDrivers(DriverExtension);
597
598 return STATUS_SUCCESS;
599 }