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.
416 Don't detect the mouse if we're in 1st stage setup! */
417 if(!IsFirstStageSetup())
419 TRACE_(I8042PRT
, "Detecting mouse\n");
420 i8042DetectMouse(DeviceExtension
);
423 TRACE_(I8042PRT
, "Detecting keyboard\n");
424 i8042DetectKeyboard(DeviceExtension
);
426 INFO_(I8042PRT
, "Keyboard present: %s\n", DeviceExtension
->Flags
& KEYBOARD_PRESENT
? "YES" : "NO");
427 INFO_(I8042PRT
, "Mouse present : %s\n", DeviceExtension
->Flags
& MOUSE_PRESENT
? "YES" : "NO");
429 TRACE_(I8042PRT
, "Enabling i8042 interrupts\n");
430 if (DeviceExtension
->Flags
& KEYBOARD_PRESENT
)
432 FlagsToDisable
|= CCB_KBD_DISAB
;
433 FlagsToEnable
|= CCB_KBD_INT_ENAB
;
435 if (DeviceExtension
->Flags
& MOUSE_PRESENT
)
437 FlagsToDisable
|= CCB_MOUSE_DISAB
;
438 FlagsToEnable
|= CCB_MOUSE_INT_ENAB
;
441 Status
= EnableInterrupts(DeviceExtension
, FlagsToDisable
, FlagsToEnable
);
442 if (!NT_SUCCESS(Status
))
444 DeviceExtension
->Flags
&= ~(KEYBOARD_PRESENT
| MOUSE_PRESENT
);
449 /* Connect interrupts */
450 if (DeviceExtension
->Flags
& KEYBOARD_PRESENT
&&
451 DeviceExtension
->Flags
& KEYBOARD_CONNECTED
&&
452 DeviceExtension
->Flags
& KEYBOARD_STARTED
&&
453 !(DeviceExtension
->Flags
& KEYBOARD_INITIALIZED
))
455 /* Keyboard is ready to be initialized */
456 Status
= i8042ConnectKeyboardInterrupt(DeviceExtension
->KeyboardExtension
);
457 if (NT_SUCCESS(Status
))
459 DeviceExtension
->Flags
|= KEYBOARD_INITIALIZED
;
463 if (DeviceExtension
->Flags
& MOUSE_PRESENT
&&
464 DeviceExtension
->Flags
& MOUSE_CONNECTED
&&
465 DeviceExtension
->Flags
& MOUSE_STARTED
&&
466 !(DeviceExtension
->Flags
& MOUSE_INITIALIZED
))
468 /* Mouse is ready to be initialized */
469 Status
= i8042ConnectMouseInterrupt(DeviceExtension
->MouseExtension
);
470 if (NT_SUCCESS(Status
))
472 DeviceExtension
->Flags
|= MOUSE_INITIALIZED
;
475 /* Start the mouse */
476 Irql
= KeAcquireInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
);
477 i8042IsrWritePort(DeviceExtension
, MOU_CMD_RESET
, CTRL_WRITE_MOUSE
);
478 KeReleaseInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
, Irql
);
486 IN PDEVICE_OBJECT DeviceObject
,
487 IN PCM_RESOURCE_LIST AllocatedResources
,
488 IN PCM_RESOURCE_LIST AllocatedResourcesTranslated
)
490 PFDO_DEVICE_EXTENSION DeviceExtension
;
491 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
492 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
, ResourceDescriptorTranslated
;
493 INTERRUPT_DATA InterruptData
;
494 BOOLEAN FoundDataPort
= FALSE
;
495 BOOLEAN FoundControlPort
= FALSE
;
496 BOOLEAN FoundIrq
= FALSE
;
500 TRACE_(I8042PRT
, "i8042PnpStartDevice(%p)\n", DeviceObject
);
501 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
502 PortDeviceExtension
= DeviceExtension
->PortDeviceExtension
;
504 ASSERT(DeviceExtension
->PnpState
== dsStopped
);
506 if (!AllocatedResources
)
508 WARN_(I8042PRT
, "No allocated resources sent to driver\n");
509 return STATUS_INSUFFICIENT_RESOURCES
;
511 if (AllocatedResources
->Count
!= 1)
513 WARN_(I8042PRT
, "Wrong number of allocated resources sent to driver\n");
514 return STATUS_INSUFFICIENT_RESOURCES
;
516 if (AllocatedResources
->List
[0].PartialResourceList
.Version
!= 1
517 || AllocatedResources
->List
[0].PartialResourceList
.Revision
!= 1
518 || AllocatedResourcesTranslated
->List
[0].PartialResourceList
.Version
!= 1
519 || AllocatedResourcesTranslated
->List
[0].PartialResourceList
.Revision
!= 1)
521 WARN_(I8042PRT
, "Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
522 AllocatedResources
->List
[0].PartialResourceList
.Version
,
523 AllocatedResources
->List
[0].PartialResourceList
.Revision
,
524 AllocatedResourcesTranslated
->List
[0].PartialResourceList
.Version
,
525 AllocatedResourcesTranslated
->List
[0].PartialResourceList
.Revision
);
526 return STATUS_REVISION_MISMATCH
;
529 /* Get Irq and optionally control port and data port */
530 for (i
= 0; i
< AllocatedResources
->List
[0].PartialResourceList
.Count
; i
++)
532 ResourceDescriptor
= &AllocatedResources
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
533 ResourceDescriptorTranslated
= &AllocatedResourcesTranslated
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
534 switch (ResourceDescriptor
->Type
)
536 case CmResourceTypePort
:
538 if (ResourceDescriptor
->u
.Port
.Length
== 1)
540 /* We assume that the first ressource will
541 * be the control port and the second one
542 * will be the data port...
546 PortDeviceExtension
->DataPort
= ULongToPtr(ResourceDescriptor
->u
.Port
.Start
.u
.LowPart
);
547 INFO_(I8042PRT
, "Found data port: %p\n", PortDeviceExtension
->DataPort
);
548 FoundDataPort
= TRUE
;
550 else if (!FoundControlPort
)
552 PortDeviceExtension
->ControlPort
= ULongToPtr(ResourceDescriptor
->u
.Port
.Start
.u
.LowPart
);
553 INFO_(I8042PRT
, "Found control port: %p\n", PortDeviceExtension
->ControlPort
);
554 FoundControlPort
= TRUE
;
558 WARN_(I8042PRT
, "Too much I/O ranges provided: 0x%lx\n", ResourceDescriptor
->u
.Port
.Length
);
559 return STATUS_INVALID_PARAMETER
;
563 WARN_(I8042PRT
, "Invalid I/O range length: 0x%lx\n", ResourceDescriptor
->u
.Port
.Length
);
566 case CmResourceTypeInterrupt
:
569 return STATUS_INVALID_PARAMETER
;
570 InterruptData
.Dirql
= (KIRQL
)ResourceDescriptorTranslated
->u
.Interrupt
.Level
;
571 InterruptData
.Vector
= ResourceDescriptorTranslated
->u
.Interrupt
.Vector
;
572 InterruptData
.Affinity
= ResourceDescriptorTranslated
->u
.Interrupt
.Affinity
;
573 if (ResourceDescriptorTranslated
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
)
574 InterruptData
.InterruptMode
= Latched
;
576 InterruptData
.InterruptMode
= LevelSensitive
;
577 InterruptData
.ShareInterrupt
= (ResourceDescriptorTranslated
->ShareDisposition
== CmResourceShareShared
);
578 INFO_(I8042PRT
, "Found irq resource: %lu\n", ResourceDescriptor
->u
.Interrupt
.Level
);
583 WARN_(I8042PRT
, "Unknown resource descriptor type 0x%x\n", ResourceDescriptor
->Type
);
589 WARN_(I8042PRT
, "Interrupt resource was not found in allocated resources list\n");
590 return STATUS_INSUFFICIENT_RESOURCES
;
592 else if (DeviceExtension
->Type
== Keyboard
&& (!FoundDataPort
|| !FoundControlPort
))
594 WARN_(I8042PRT
, "Some required resources were not found in allocated resources list\n");
595 return STATUS_INSUFFICIENT_RESOURCES
;
597 else if (DeviceExtension
->Type
== Mouse
&& (FoundDataPort
|| FoundControlPort
))
599 WARN_(I8042PRT
, "Too much resources were provided in allocated resources list\n");
600 return STATUS_INVALID_PARAMETER
;
603 switch (DeviceExtension
->Type
)
608 &PortDeviceExtension
->KeyboardInterrupt
,
610 sizeof(INTERRUPT_DATA
));
611 PortDeviceExtension
->Flags
|= KEYBOARD_STARTED
;
612 Status
= StartProcedure(PortDeviceExtension
);
618 &PortDeviceExtension
->MouseInterrupt
,
620 sizeof(INTERRUPT_DATA
));
621 PortDeviceExtension
->Flags
|= MOUSE_STARTED
;
622 Status
= StartProcedure(PortDeviceExtension
);
627 WARN_(I8042PRT
, "Unknown FDO type %u\n", DeviceExtension
->Type
);
628 ASSERT(!(PortDeviceExtension
->Flags
& KEYBOARD_CONNECTED
) || !(PortDeviceExtension
->Flags
& MOUSE_CONNECTED
));
629 Status
= STATUS_INVALID_DEVICE_REQUEST
;
633 if (NT_SUCCESS(Status
))
634 DeviceExtension
->PnpState
= dsStarted
;
641 IN PDEVICE_OBJECT DeviceObject
,
644 PIO_STACK_LOCATION Stack
;
646 I8042_DEVICE_TYPE DeviceType
;
647 ULONG_PTR Information
= 0;
650 Stack
= IoGetCurrentIrpStackLocation(Irp
);
651 MinorFunction
= Stack
->MinorFunction
;
652 DeviceType
= ((PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->Type
;
654 switch (MinorFunction
)
656 case IRP_MN_START_DEVICE
: /* 0x00 */
658 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
660 /* Call lower driver (if any) */
661 if (DeviceType
!= PhysicalDeviceObject
)
663 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
664 if (NT_SUCCESS(Status
))
665 Status
= i8042PnpStartDevice(
667 Stack
->Parameters
.StartDevice
.AllocatedResources
,
668 Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
);
671 Status
= STATUS_SUCCESS
;
674 case IRP_MN_QUERY_DEVICE_RELATIONS
: /* (optional) 0x07 */
676 switch (Stack
->Parameters
.QueryDeviceRelations
.Type
)
680 PDEVICE_RELATIONS DeviceRelations
;
682 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
683 DeviceRelations
= ExAllocatePool(PagedPool
, sizeof(DEVICE_RELATIONS
));
686 DeviceRelations
->Count
= 0;
687 Information
= (ULONG_PTR
)DeviceRelations
;
688 Status
= STATUS_SUCCESS
;
691 Status
= STATUS_INSUFFICIENT_RESOURCES
;
694 case RemovalRelations
:
696 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
697 return ForwardIrpAndForget(DeviceObject
, Irp
);
700 ERR_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
701 Stack
->Parameters
.QueryDeviceRelations
.Type
);
703 return ForwardIrpAndForget(DeviceObject
, Irp
);
707 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
: /* (optional) 0x0d */
709 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
711 Status
= Irp
->IoStatus
.Status
;
714 case IRP_MN_QUERY_PNP_DEVICE_STATE
: /* 0x14 */
716 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
717 /* Nothing much to tell */
719 Status
= STATUS_SUCCESS
;
724 ERR_(I8042PRT
, "IRP_MJ_PNP / unknown minor function 0x%x\n", MinorFunction
);
725 return ForwardIrpAndForget(DeviceObject
, Irp
);
729 Irp
->IoStatus
.Information
= Information
;
730 Irp
->IoStatus
.Status
= Status
;
731 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);