2 * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/input/i8042prt/pnp.c
5 * PURPOSE: IRP_MJ_PNP operations
6 * PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
7 * Copyright 2008 Colin Finck (mail@colinfinck.de)
10 /* INCLUDES ******************************************************************/
14 /* FUNCTIONS *****************************************************************/
16 /* This is all pretty confusing. There's more than one way to
17 * disable/enable the keyboard. You can send KBD_ENABLE to the
18 * keyboard, and it will start scanning keys. Sending KBD_DISABLE
19 * will disable the key scanning but also reset the parameters to
22 * You can also send 0xAE to the controller for enabling the
23 * keyboard clock line and 0xAD for disabling it. Then it'll
24 * automatically get turned on at the next command. The last
25 * way is by modifying the bit that drives the clock line in the
26 * 'command byte' of the controller. This is almost, but not quite,
27 * the same as the AE/AD thing. The difference can be used to detect
28 * some really old broken keyboard controllers which I hope won't be
31 * We change the command byte, sending KBD_ENABLE/DISABLE seems to confuse
36 IN PPORT_DEVICE_EXTENSION DeviceExtension
,
37 IN UCHAR FlagsToDisable
,
38 IN UCHAR FlagsToEnable
)
43 if (!i8042Write(DeviceExtension
, DeviceExtension
->ControlPort
, KBD_READ_MODE
))
45 WARN_(I8042PRT
, "Can't read i8042 mode\n");
49 Status
= i8042ReadDataWait(DeviceExtension
, &Value
);
50 if (!NT_SUCCESS(Status
))
52 WARN_(I8042PRT
, "No response after read i8042 mode\n");
56 Value
&= ~FlagsToDisable
;
57 Value
|= FlagsToEnable
;
59 if (!i8042Write(DeviceExtension
, DeviceExtension
->ControlPort
, KBD_WRITE_MODE
))
61 WARN_(I8042PRT
, "Can't set i8042 mode\n");
65 if (!i8042Write(DeviceExtension
, DeviceExtension
->DataPort
, Value
))
67 WARN_(I8042PRT
, "Can't send i8042 mode\n");
76 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
79 ULONG ResendIterations
;
82 /* Don't enable keyboard and mouse interrupts, disable keyboard/mouse */
83 i8042Flush(DeviceExtension
);
84 if (!i8042ChangeMode(DeviceExtension
, CCB_KBD_INT_ENAB
| CCB_MOUSE_INT_ENAB
, CCB_KBD_DISAB
| CCB_MOUSE_DISAB
))
85 return STATUS_IO_DEVICE_ERROR
;
87 i8042Flush(DeviceExtension
);
89 /* Issue a CTRL_SELF_TEST command to check if this is really an i8042 controller */
90 ResendIterations
= DeviceExtension
->Settings
.ResendIterations
+ 1;
91 while (ResendIterations
--)
93 if (!i8042Write(DeviceExtension
, DeviceExtension
->ControlPort
, CTRL_SELF_TEST
))
95 WARN_(I8042PRT
, "Writing CTRL_SELF_TEST command failed\n");
96 return STATUS_IO_TIMEOUT
;
99 Status
= i8042ReadDataWait(DeviceExtension
, &Value
);
100 if (!NT_SUCCESS(Status
))
102 WARN_(I8042PRT
, "Failed to read CTRL_SELF_TEST response, status 0x%08lx\n", Status
);
106 if (Value
== KBD_SELF_TEST_OK
)
108 INFO_(I8042PRT
, "CTRL_SELF_TEST completed successfully!\n");
111 else if (Value
== KBD_RESEND
)
113 TRACE_(I8042PRT
, "Resending...\n", Value
);
114 KeStallExecutionProcessor(50);
118 WARN_(I8042PRT
, "Got 0x%02x instead of 0x55\n", Value
);
119 return STATUS_IO_DEVICE_ERROR
;
123 return STATUS_SUCCESS
;
128 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
132 /* Set LEDs (that is not fatal if some error occurs) */
133 Status
= i8042SynchWritePort(DeviceExtension
, 0, KBD_CMD_SET_LEDS
, TRUE
);
134 if (NT_SUCCESS(Status
))
136 Status
= i8042SynchWritePort(DeviceExtension
, 0, 0, TRUE
);
137 if (!NT_SUCCESS(Status
))
139 WARN_(I8042PRT
, "Can't finish SET_LEDS (0x%08lx)\n", Status
);
145 WARN_(I8042PRT
, "Warning: can't write SET_LEDS (0x%08lx)\n", Status
);
148 /* Turn on translation and SF (Some machines don't reboot if SF is not set, see ReactOS bug #1842) */
149 if (!i8042ChangeMode(DeviceExtension
, 0, CCB_TRANSLATE
| CCB_SYSTEM_FLAG
))
153 * We used to send a KBD_LINE_TEST (0xAB) command, but on at least HP
154 * Pavilion notebooks the response to that command was incorrect.
155 * So now we just assume that a keyboard is attached.
157 DeviceExtension
->Flags
|= KEYBOARD_PRESENT
;
159 INFO_(I8042PRT
, "Keyboard detected\n");
164 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
168 UCHAR ExpectedReply
[] = { MOUSE_ACK
, 0xAA };
171 /* First do a mouse line test */
172 if (i8042Write(DeviceExtension
, DeviceExtension
->ControlPort
, MOUSE_LINE_TEST
))
174 Status
= i8042ReadDataWait(DeviceExtension
, &Value
);
176 if (!NT_SUCCESS(Status
) || Value
!= 0)
178 WARN_(I8042PRT
, "Mouse line test failed\n");
183 /* Now reset the mouse */
184 i8042Flush(DeviceExtension
);
186 if(!i8042IsrWritePort(DeviceExtension
, MOU_CMD_RESET
, CTRL_WRITE_MOUSE
))
188 WARN_(I8042PRT
, "Failed to write reset command to mouse\n");
192 /* The implementation of the "Mouse Reset" command differs much from chip to chip.
194 By default, the first byte is an ACK, when the mouse is plugged in and working and NACK when it's not.
195 On success, the next bytes are 0xAA and 0x00.
197 But on some systems (like ECS K7S5A Pro, SiS 735 chipset), we always get an ACK and 0xAA.
198 Only the last byte indicates, whether a mouse is plugged in.
199 It is either sent or not, so there is no byte, which indicates a failure here.
201 After the Mouse Reset command was issued, it usually takes some time until we get a response.
202 So get the first two bytes in a loop. */
204 ReplyByte
< sizeof(ExpectedReply
) / sizeof(ExpectedReply
[0]);
211 Status
= i8042ReadDataWait(DeviceExtension
, &Value
);
213 if(!NT_SUCCESS(Status
))
215 /* Wait some time before trying again */
216 KeStallExecutionProcessor(50);
218 } while (Status
== STATUS_IO_TIMEOUT
&& Counter
--);
220 if (!NT_SUCCESS(Status
))
222 WARN_(I8042PRT
, "No ACK after mouse reset, status 0x%08lx\n", Status
);
225 else if (Value
!= ExpectedReply
[ReplyByte
])
227 WARN_(I8042PRT
, "Unexpected reply: 0x%02x (expected 0x%02x)\n", Value
, ExpectedReply
[ReplyByte
]);
232 /* Finally get the third byte, but only try it one time (see above).
233 Otherwise this takes around 45 seconds on a K7S5A Pro, when no mouse is plugged in. */
234 Status
= i8042ReadDataWait(DeviceExtension
, &Value
);
236 if(!NT_SUCCESS(Status
))
238 WARN_(I8042PRT
, "Last byte was not transmitted after mouse reset, status 0x%08lx\n", Status
);
241 else if(Value
!= 0x00)
243 WARN_(I8042PRT
, "Last byte after mouse reset was not 0x00, but 0x%02x\n", Value
);
247 DeviceExtension
->Flags
|= MOUSE_PRESENT
;
248 INFO_(I8042PRT
, "Mouse detected\n");
252 /* There is probably no mouse present. On some systems,
253 the probe locks the entire keyboard controller. Let's
254 try to get access to the keyboard again by sending a
256 i8042Flush(DeviceExtension
);
257 i8042Write(DeviceExtension
, DeviceExtension
->ControlPort
, CTRL_SELF_TEST
);
258 i8042ReadDataWait(DeviceExtension
, &Value
);
259 i8042Flush(DeviceExtension
);
261 INFO_(I8042PRT
, "Mouse not detected\n");
265 i8042ConnectKeyboardInterrupt(
266 IN PI8042_KEYBOARD_EXTENSION DeviceExtension
)
268 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
272 TRACE_(I8042PRT
, "i8042ConnectKeyboardInterrupt()\n");
274 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
276 PortDeviceExtension
->KeyboardInterrupt
.Dirql
,
277 PortDeviceExtension
->MouseInterrupt
.Dirql
);
279 INFO_(I8042PRT
, "KeyboardInterrupt.Vector %lu\n",
280 PortDeviceExtension
->KeyboardInterrupt
.Vector
);
281 INFO_(I8042PRT
, "KeyboardInterrupt.Dirql %lu\n",
282 PortDeviceExtension
->KeyboardInterrupt
.Dirql
);
283 INFO_(I8042PRT
, "KeyboardInterrupt.DirqlMax %lu\n",
285 INFO_(I8042PRT
, "KeyboardInterrupt.InterruptMode %s\n",
286 PortDeviceExtension
->KeyboardInterrupt
.InterruptMode
== LevelSensitive
? "LevelSensitive" : "Latched");
287 INFO_(I8042PRT
, "KeyboardInterrupt.ShareInterrupt %s\n",
288 PortDeviceExtension
->KeyboardInterrupt
.ShareInterrupt
? "yes" : "no");
289 INFO_(I8042PRT
, "KeyboardInterrupt.Affinity 0x%lx\n",
290 PortDeviceExtension
->KeyboardInterrupt
.Affinity
);
291 Status
= IoConnectInterrupt(
292 &PortDeviceExtension
->KeyboardInterrupt
.Object
,
293 i8042KbdInterruptService
,
294 DeviceExtension
, &PortDeviceExtension
->SpinLock
,
295 PortDeviceExtension
->KeyboardInterrupt
.Vector
, PortDeviceExtension
->KeyboardInterrupt
.Dirql
, DirqlMax
,
296 PortDeviceExtension
->KeyboardInterrupt
.InterruptMode
, PortDeviceExtension
->KeyboardInterrupt
.ShareInterrupt
,
297 PortDeviceExtension
->KeyboardInterrupt
.Affinity
, FALSE
);
298 if (!NT_SUCCESS(Status
))
300 WARN_(I8042PRT
, "IoConnectInterrupt() failed with status 0x%08x\n", Status
);
304 if (DirqlMax
== PortDeviceExtension
->KeyboardInterrupt
.Dirql
)
305 PortDeviceExtension
->HighestDIRQLInterrupt
= PortDeviceExtension
->KeyboardInterrupt
.Object
;
306 PortDeviceExtension
->Flags
|= KEYBOARD_INITIALIZED
;
307 return STATUS_SUCCESS
;
311 i8042ConnectMouseInterrupt(
312 IN PI8042_MOUSE_EXTENSION DeviceExtension
)
314 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
318 TRACE_(I8042PRT
, "i8042ConnectMouseInterrupt()\n");
320 Status
= i8042MouInitialize(DeviceExtension
);
321 if (!NT_SUCCESS(Status
))
324 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
326 PortDeviceExtension
->KeyboardInterrupt
.Dirql
,
327 PortDeviceExtension
->MouseInterrupt
.Dirql
);
329 INFO_(I8042PRT
, "MouseInterrupt.Vector %lu\n",
330 PortDeviceExtension
->MouseInterrupt
.Vector
);
331 INFO_(I8042PRT
, "MouseInterrupt.Dirql %lu\n",
332 PortDeviceExtension
->MouseInterrupt
.Dirql
);
333 INFO_(I8042PRT
, "MouseInterrupt.DirqlMax %lu\n",
335 INFO_(I8042PRT
, "MouseInterrupt.InterruptMode %s\n",
336 PortDeviceExtension
->MouseInterrupt
.InterruptMode
== LevelSensitive
? "LevelSensitive" : "Latched");
337 INFO_(I8042PRT
, "MouseInterrupt.ShareInterrupt %s\n",
338 PortDeviceExtension
->MouseInterrupt
.ShareInterrupt
? "yes" : "no");
339 INFO_(I8042PRT
, "MouseInterrupt.Affinity 0x%lx\n",
340 PortDeviceExtension
->MouseInterrupt
.Affinity
);
341 Status
= IoConnectInterrupt(
342 &PortDeviceExtension
->MouseInterrupt
.Object
,
343 i8042MouInterruptService
,
344 DeviceExtension
, &PortDeviceExtension
->SpinLock
,
345 PortDeviceExtension
->MouseInterrupt
.Vector
, PortDeviceExtension
->MouseInterrupt
.Dirql
, DirqlMax
,
346 PortDeviceExtension
->MouseInterrupt
.InterruptMode
, PortDeviceExtension
->MouseInterrupt
.ShareInterrupt
,
347 PortDeviceExtension
->MouseInterrupt
.Affinity
, FALSE
);
348 if (!NT_SUCCESS(Status
))
350 WARN_(I8042PRT
, "IoConnectInterrupt() failed with status 0x%08x\n", Status
);
354 if (DirqlMax
== PortDeviceExtension
->MouseInterrupt
.Dirql
)
355 PortDeviceExtension
->HighestDIRQLInterrupt
= PortDeviceExtension
->MouseInterrupt
.Object
;
357 PortDeviceExtension
->Flags
|= MOUSE_INITIALIZED
;
358 Status
= STATUS_SUCCESS
;
361 if (!NT_SUCCESS(Status
))
363 PortDeviceExtension
->Flags
&= ~MOUSE_INITIALIZED
;
364 if (PortDeviceExtension
->MouseInterrupt
.Object
)
366 IoDisconnectInterrupt(PortDeviceExtension
->MouseInterrupt
.Object
);
367 PortDeviceExtension
->HighestDIRQLInterrupt
= PortDeviceExtension
->KeyboardInterrupt
.Object
;
375 IN PPORT_DEVICE_EXTENSION DeviceExtension
,
376 IN UCHAR FlagsToDisable
,
377 IN UCHAR FlagsToEnable
)
379 i8042Flush(DeviceExtension
);
381 if (!i8042ChangeMode(DeviceExtension
, FlagsToDisable
, FlagsToEnable
))
382 return STATUS_UNSUCCESSFUL
;
384 return STATUS_SUCCESS
;
389 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
392 UCHAR FlagsToDisable
= 0;
393 UCHAR FlagsToEnable
= 0;
396 if (DeviceExtension
->DataPort
== 0)
398 /* Unable to do something at the moment */
399 return STATUS_SUCCESS
;
402 if (!(DeviceExtension
->Flags
& (KEYBOARD_PRESENT
| MOUSE_PRESENT
)))
404 /* Try to detect them */
405 TRACE_(I8042PRT
, "Check if the controller is really a i8042\n");
406 Status
= i8042BasicDetect(DeviceExtension
);
407 if (!NT_SUCCESS(Status
))
409 WARN_(I8042PRT
, "i8042BasicDetect() failed with status 0x%08lx\n", Status
);
410 return STATUS_UNSUCCESSFUL
;
413 /* First detect the mouse and then the keyboard!
414 If we do it the other way round, some systems throw away settings like the keyboard translation, when detecting the mouse. */
415 TRACE_(I8042PRT
, "Detecting mouse\n");
416 i8042DetectMouse(DeviceExtension
);
417 TRACE_(I8042PRT
, "Detecting keyboard\n");
418 i8042DetectKeyboard(DeviceExtension
);
420 INFO_(I8042PRT
, "Keyboard present: %s\n", DeviceExtension
->Flags
& KEYBOARD_PRESENT
? "YES" : "NO");
421 INFO_(I8042PRT
, "Mouse present : %s\n", DeviceExtension
->Flags
& MOUSE_PRESENT
? "YES" : "NO");
423 TRACE_(I8042PRT
, "Enabling i8042 interrupts\n");
424 if (DeviceExtension
->Flags
& KEYBOARD_PRESENT
)
426 FlagsToDisable
|= CCB_KBD_DISAB
;
427 FlagsToEnable
|= CCB_KBD_INT_ENAB
;
429 if (DeviceExtension
->Flags
& MOUSE_PRESENT
)
431 FlagsToDisable
|= CCB_MOUSE_DISAB
;
432 FlagsToEnable
|= CCB_MOUSE_INT_ENAB
;
435 Status
= EnableInterrupts(DeviceExtension
, FlagsToDisable
, FlagsToEnable
);
436 if (!NT_SUCCESS(Status
))
438 DeviceExtension
->Flags
&= ~(KEYBOARD_PRESENT
| MOUSE_PRESENT
);
443 /* Connect interrupts */
444 if (DeviceExtension
->Flags
& KEYBOARD_PRESENT
&&
445 DeviceExtension
->Flags
& KEYBOARD_CONNECTED
&&
446 DeviceExtension
->Flags
& KEYBOARD_STARTED
&&
447 !(DeviceExtension
->Flags
& KEYBOARD_INITIALIZED
))
449 /* Keyboard is ready to be initialized */
450 Status
= i8042ConnectKeyboardInterrupt(DeviceExtension
->KeyboardExtension
);
451 if (NT_SUCCESS(Status
))
453 DeviceExtension
->Flags
|= KEYBOARD_INITIALIZED
;
457 if (DeviceExtension
->Flags
& MOUSE_PRESENT
&&
458 DeviceExtension
->Flags
& MOUSE_CONNECTED
&&
459 DeviceExtension
->Flags
& MOUSE_STARTED
&&
460 !(DeviceExtension
->Flags
& MOUSE_INITIALIZED
))
462 /* Mouse is ready to be initialized */
463 Status
= i8042ConnectMouseInterrupt(DeviceExtension
->MouseExtension
);
464 if (NT_SUCCESS(Status
))
466 DeviceExtension
->Flags
|= MOUSE_INITIALIZED
;
469 /* Start the mouse */
470 Irql
= KeAcquireInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
);
471 i8042IsrWritePort(DeviceExtension
, MOU_CMD_RESET
, CTRL_WRITE_MOUSE
);
472 KeReleaseInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
, Irql
);
480 IN PDEVICE_OBJECT DeviceObject
,
481 IN PCM_RESOURCE_LIST AllocatedResources
,
482 IN PCM_RESOURCE_LIST AllocatedResourcesTranslated
)
484 PFDO_DEVICE_EXTENSION DeviceExtension
;
485 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
486 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
, ResourceDescriptorTranslated
;
487 INTERRUPT_DATA InterruptData
;
488 BOOLEAN FoundDataPort
= FALSE
;
489 BOOLEAN FoundControlPort
= FALSE
;
490 BOOLEAN FoundIrq
= FALSE
;
494 TRACE_(I8042PRT
, "i8042PnpStartDevice(%p)\n", DeviceObject
);
495 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
496 PortDeviceExtension
= DeviceExtension
->PortDeviceExtension
;
498 ASSERT(DeviceExtension
->PnpState
== dsStopped
);
500 if (!AllocatedResources
)
502 WARN_(I8042PRT
, "No allocated resources sent to driver\n");
503 return STATUS_INSUFFICIENT_RESOURCES
;
505 if (AllocatedResources
->Count
!= 1)
507 WARN_(I8042PRT
, "Wrong number of allocated resources sent to driver\n");
508 return STATUS_INSUFFICIENT_RESOURCES
;
510 if (AllocatedResources
->List
[0].PartialResourceList
.Version
!= 1
511 || AllocatedResources
->List
[0].PartialResourceList
.Revision
!= 1
512 || AllocatedResourcesTranslated
->List
[0].PartialResourceList
.Version
!= 1
513 || AllocatedResourcesTranslated
->List
[0].PartialResourceList
.Revision
!= 1)
515 WARN_(I8042PRT
, "Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
516 AllocatedResources
->List
[0].PartialResourceList
.Version
,
517 AllocatedResources
->List
[0].PartialResourceList
.Revision
,
518 AllocatedResourcesTranslated
->List
[0].PartialResourceList
.Version
,
519 AllocatedResourcesTranslated
->List
[0].PartialResourceList
.Revision
);
520 return STATUS_REVISION_MISMATCH
;
523 /* Get Irq and optionally control port and data port */
524 for (i
= 0; i
< AllocatedResources
->List
[0].PartialResourceList
.Count
; i
++)
526 ResourceDescriptor
= &AllocatedResources
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
527 ResourceDescriptorTranslated
= &AllocatedResourcesTranslated
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
528 switch (ResourceDescriptor
->Type
)
530 case CmResourceTypePort
:
532 if (ResourceDescriptor
->u
.Port
.Length
== 1)
534 /* We assume that the first ressource will
535 * be the control port and the second one
536 * will be the data port...
540 PortDeviceExtension
->DataPort
= ULongToPtr(ResourceDescriptor
->u
.Port
.Start
.u
.LowPart
);
541 INFO_(I8042PRT
, "Found data port: %p\n", PortDeviceExtension
->DataPort
);
542 FoundDataPort
= TRUE
;
544 else if (!FoundControlPort
)
546 PortDeviceExtension
->ControlPort
= ULongToPtr(ResourceDescriptor
->u
.Port
.Start
.u
.LowPart
);
547 INFO_(I8042PRT
, "Found control port: %p\n", PortDeviceExtension
->ControlPort
);
548 FoundControlPort
= TRUE
;
552 WARN_(I8042PRT
, "Too much I/O ranges provided: 0x%lx\n", ResourceDescriptor
->u
.Port
.Length
);
553 return STATUS_INVALID_PARAMETER
;
557 WARN_(I8042PRT
, "Invalid I/O range length: 0x%lx\n", ResourceDescriptor
->u
.Port
.Length
);
560 case CmResourceTypeInterrupt
:
563 return STATUS_INVALID_PARAMETER
;
564 InterruptData
.Dirql
= (KIRQL
)ResourceDescriptorTranslated
->u
.Interrupt
.Level
;
565 InterruptData
.Vector
= ResourceDescriptorTranslated
->u
.Interrupt
.Vector
;
566 InterruptData
.Affinity
= ResourceDescriptorTranslated
->u
.Interrupt
.Affinity
;
567 if (ResourceDescriptorTranslated
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
)
568 InterruptData
.InterruptMode
= Latched
;
570 InterruptData
.InterruptMode
= LevelSensitive
;
571 InterruptData
.ShareInterrupt
= (ResourceDescriptorTranslated
->ShareDisposition
== CmResourceShareShared
);
572 INFO_(I8042PRT
, "Found irq resource: %lu\n", ResourceDescriptor
->u
.Interrupt
.Level
);
577 WARN_(I8042PRT
, "Unknown resource descriptor type 0x%x\n", ResourceDescriptor
->Type
);
583 WARN_(I8042PRT
, "Interrupt resource was not found in allocated resources list\n");
584 return STATUS_INSUFFICIENT_RESOURCES
;
586 else if (DeviceExtension
->Type
== Keyboard
&& (!FoundDataPort
|| !FoundControlPort
))
588 WARN_(I8042PRT
, "Some required resources were not found in allocated resources list\n");
589 return STATUS_INSUFFICIENT_RESOURCES
;
591 else if (DeviceExtension
->Type
== Mouse
&& (FoundDataPort
|| FoundControlPort
))
593 WARN_(I8042PRT
, "Too much resources were provided in allocated resources list\n");
594 return STATUS_INVALID_PARAMETER
;
597 switch (DeviceExtension
->Type
)
602 &PortDeviceExtension
->KeyboardInterrupt
,
604 sizeof(INTERRUPT_DATA
));
605 PortDeviceExtension
->Flags
|= KEYBOARD_STARTED
;
606 Status
= StartProcedure(PortDeviceExtension
);
612 &PortDeviceExtension
->MouseInterrupt
,
614 sizeof(INTERRUPT_DATA
));
615 PortDeviceExtension
->Flags
|= MOUSE_STARTED
;
616 Status
= StartProcedure(PortDeviceExtension
);
621 WARN_(I8042PRT
, "Unknown FDO type %u\n", DeviceExtension
->Type
);
622 ASSERT(!(PortDeviceExtension
->Flags
& KEYBOARD_CONNECTED
) || !(PortDeviceExtension
->Flags
& MOUSE_CONNECTED
));
623 Status
= STATUS_INVALID_DEVICE_REQUEST
;
627 if (NT_SUCCESS(Status
))
628 DeviceExtension
->PnpState
= dsStarted
;
635 IN PDEVICE_OBJECT DeviceObject
,
638 PIO_STACK_LOCATION Stack
;
640 I8042_DEVICE_TYPE DeviceType
;
641 ULONG_PTR Information
= 0;
644 Stack
= IoGetCurrentIrpStackLocation(Irp
);
645 MinorFunction
= Stack
->MinorFunction
;
646 DeviceType
= ((PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->Type
;
648 switch (MinorFunction
)
650 case IRP_MN_START_DEVICE
: /* 0x00 */
652 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
654 /* Call lower driver (if any) */
655 if (DeviceType
!= PhysicalDeviceObject
)
657 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
658 if (NT_SUCCESS(Status
))
659 Status
= i8042PnpStartDevice(
661 Stack
->Parameters
.StartDevice
.AllocatedResources
,
662 Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
);
665 Status
= STATUS_SUCCESS
;
668 case IRP_MN_QUERY_DEVICE_RELATIONS
: /* (optional) 0x07 */
670 switch (Stack
->Parameters
.QueryDeviceRelations
.Type
)
674 PDEVICE_RELATIONS DeviceRelations
;
676 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
677 DeviceRelations
= ExAllocatePool(PagedPool
, sizeof(DEVICE_RELATIONS
));
680 DeviceRelations
->Count
= 0;
681 Information
= (ULONG_PTR
)DeviceRelations
;
682 Status
= STATUS_SUCCESS
;
685 Status
= STATUS_INSUFFICIENT_RESOURCES
;
688 case RemovalRelations
:
690 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
691 return ForwardIrpAndForget(DeviceObject
, Irp
);
694 ERR_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
695 Stack
->Parameters
.QueryDeviceRelations
.Type
);
697 return ForwardIrpAndForget(DeviceObject
, Irp
);
701 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
: /* (optional) 0x0d */
703 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
705 Status
= Irp
->IoStatus
.Status
;
708 case IRP_MN_QUERY_PNP_DEVICE_STATE
: /* 0x14 */
710 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
711 /* Nothing much to tell */
713 Status
= STATUS_SUCCESS
;
718 ERR_(I8042PRT
, "IRP_MJ_PNP / unknown minor function 0x%x\n", MinorFunction
);
719 return ForwardIrpAndForget(DeviceObject
, Irp
);
723 Irp
->IoStatus
.Information
= Information
;
724 Irp
->IoStatus
.Status
= Status
;
725 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);