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 ******************************************************************/
16 /* FUNCTIONS *****************************************************************/
18 /* This is all pretty confusing. There's more than one way to
19 * disable/enable the keyboard. You can send KBD_ENABLE to the
20 * keyboard, and it will start scanning keys. Sending KBD_DISABLE
21 * will disable the key scanning but also reset the parameters to
24 * You can also send 0xAE to the controller for enabling the
25 * keyboard clock line and 0xAD for disabling it. Then it'll
26 * automatically get turned on at the next command. The last
27 * way is by modifying the bit that drives the clock line in the
28 * 'command byte' of the controller. This is almost, but not quite,
29 * the same as the AE/AD thing. The difference can be used to detect
30 * some really old broken keyboard controllers which I hope won't be
33 * We change the command byte, sending KBD_ENABLE/DISABLE seems to confuse
38 IN PPORT_DEVICE_EXTENSION DeviceExtension
,
39 IN UCHAR FlagsToDisable
,
40 IN UCHAR FlagsToEnable
)
45 if (!i8042Write(DeviceExtension
, DeviceExtension
->ControlPort
, KBD_READ_MODE
))
47 WARN_(I8042PRT
, "Can't read i8042 mode\n");
51 Status
= i8042ReadDataWait(DeviceExtension
, &Value
);
52 if (!NT_SUCCESS(Status
))
54 WARN_(I8042PRT
, "No response after read i8042 mode\n");
58 Value
&= ~FlagsToDisable
;
59 Value
|= FlagsToEnable
;
61 if (!i8042Write(DeviceExtension
, DeviceExtension
->ControlPort
, KBD_WRITE_MODE
))
63 WARN_(I8042PRT
, "Can't set i8042 mode\n");
67 if (!i8042Write(DeviceExtension
, DeviceExtension
->DataPort
, Value
))
69 WARN_(I8042PRT
, "Can't send i8042 mode\n");
78 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
81 ULONG ResendIterations
;
84 /* Don't enable keyboard and mouse interrupts, disable keyboard/mouse */
85 i8042Flush(DeviceExtension
);
86 if (!i8042ChangeMode(DeviceExtension
, CCB_KBD_INT_ENAB
| CCB_MOUSE_INT_ENAB
, CCB_KBD_DISAB
| CCB_MOUSE_DISAB
))
87 return STATUS_IO_DEVICE_ERROR
;
89 i8042Flush(DeviceExtension
);
91 /* Issue a CTRL_SELF_TEST command to check if this is really an i8042 controller */
92 ResendIterations
= DeviceExtension
->Settings
.ResendIterations
+ 1;
93 while (ResendIterations
--)
95 if (!i8042Write(DeviceExtension
, DeviceExtension
->ControlPort
, CTRL_SELF_TEST
))
97 WARN_(I8042PRT
, "Writing CTRL_SELF_TEST command failed\n");
98 return STATUS_IO_TIMEOUT
;
101 Status
= i8042ReadDataWait(DeviceExtension
, &Value
);
102 if (!NT_SUCCESS(Status
))
104 WARN_(I8042PRT
, "Failed to read CTRL_SELF_TEST response, status 0x%08lx\n", Status
);
108 if (Value
== KBD_SELF_TEST_OK
)
110 INFO_(I8042PRT
, "CTRL_SELF_TEST completed successfully!\n");
113 else if (Value
== KBD_RESEND
)
115 TRACE_(I8042PRT
, "Resending...\n");
116 KeStallExecutionProcessor(50);
120 WARN_(I8042PRT
, "Got 0x%02x instead of 0x55\n", Value
);
121 return STATUS_IO_DEVICE_ERROR
;
125 return STATUS_SUCCESS
;
130 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
134 /* Set LEDs (that is not fatal if some error occurs) */
135 Status
= i8042SynchWritePort(DeviceExtension
, 0, KBD_CMD_SET_LEDS
, TRUE
);
136 if (NT_SUCCESS(Status
))
138 Status
= i8042SynchWritePort(DeviceExtension
, 0, 0, TRUE
);
139 if (!NT_SUCCESS(Status
))
141 WARN_(I8042PRT
, "Can't finish SET_LEDS (0x%08lx)\n", Status
);
147 WARN_(I8042PRT
, "Warning: can't write SET_LEDS (0x%08lx)\n", Status
);
150 /* Turn on translation and SF (Some machines don't reboot if SF is not set, see ReactOS bug #1842) */
151 if (!i8042ChangeMode(DeviceExtension
, 0, CCB_TRANSLATE
| CCB_SYSTEM_FLAG
))
155 * We used to send a KBD_LINE_TEST (0xAB) command, but on at least HP
156 * Pavilion notebooks the response to that command was incorrect.
157 * So now we just assume that a keyboard is attached.
159 DeviceExtension
->Flags
|= KEYBOARD_PRESENT
;
161 INFO_(I8042PRT
, "Keyboard detected\n");
166 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
170 UCHAR ExpectedReply
[] = { MOUSE_ACK
, 0xAA };
173 /* First do a mouse line test */
174 if (i8042Write(DeviceExtension
, DeviceExtension
->ControlPort
, MOUSE_LINE_TEST
))
176 Status
= i8042ReadDataWait(DeviceExtension
, &Value
);
178 if (!NT_SUCCESS(Status
) || Value
!= 0)
180 WARN_(I8042PRT
, "Mouse line test failed\n");
185 /* Now reset the mouse */
186 i8042Flush(DeviceExtension
);
188 if(!i8042IsrWritePort(DeviceExtension
, MOU_CMD_RESET
, CTRL_WRITE_MOUSE
))
190 WARN_(I8042PRT
, "Failed to write reset command to mouse\n");
194 /* The implementation of the "Mouse Reset" command differs much from chip to chip.
196 By default, the first byte is an ACK, when the mouse is plugged in and working and NACK when it's not.
197 On success, the next bytes are 0xAA and 0x00.
199 But on some systems (like ECS K7S5A Pro, SiS 735 chipset), we always get an ACK and 0xAA.
200 Only the last byte indicates, whether a mouse is plugged in.
201 It is either sent or not, so there is no byte, which indicates a failure here.
203 After the Mouse Reset command was issued, it usually takes some time until we get a response.
204 So get the first two bytes in a loop. */
206 ReplyByte
< sizeof(ExpectedReply
) / sizeof(ExpectedReply
[0]);
213 Status
= i8042ReadDataWait(DeviceExtension
, &Value
);
215 if(!NT_SUCCESS(Status
))
217 /* Wait some time before trying again */
218 KeStallExecutionProcessor(50);
220 } while (Status
== STATUS_IO_TIMEOUT
&& Counter
--);
222 if (!NT_SUCCESS(Status
))
224 WARN_(I8042PRT
, "No ACK after mouse reset, status 0x%08lx\n", Status
);
227 else if (Value
!= ExpectedReply
[ReplyByte
])
229 WARN_(I8042PRT
, "Unexpected reply: 0x%02x (expected 0x%02x)\n", Value
, ExpectedReply
[ReplyByte
]);
234 /* Finally get the third byte, but only try it one time (see above).
235 Otherwise this takes around 45 seconds on a K7S5A Pro, when no mouse is plugged in. */
236 Status
= i8042ReadDataWait(DeviceExtension
, &Value
);
238 if(!NT_SUCCESS(Status
))
240 WARN_(I8042PRT
, "Last byte was not transmitted after mouse reset, status 0x%08lx\n", Status
);
243 else if(Value
!= 0x00)
245 WARN_(I8042PRT
, "Last byte after mouse reset was not 0x00, but 0x%02x\n", Value
);
249 DeviceExtension
->Flags
|= MOUSE_PRESENT
;
250 INFO_(I8042PRT
, "Mouse detected\n");
254 /* There is probably no mouse present. On some systems,
255 the probe locks the entire keyboard controller. Let's
256 try to get access to the keyboard again by sending a
258 i8042Flush(DeviceExtension
);
259 i8042Write(DeviceExtension
, DeviceExtension
->ControlPort
, CTRL_SELF_TEST
);
260 i8042ReadDataWait(DeviceExtension
, &Value
);
261 i8042Flush(DeviceExtension
);
263 INFO_(I8042PRT
, "Mouse not detected\n");
267 i8042ConnectKeyboardInterrupt(
268 IN PI8042_KEYBOARD_EXTENSION DeviceExtension
)
270 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
274 TRACE_(I8042PRT
, "i8042ConnectKeyboardInterrupt()\n");
276 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
278 PortDeviceExtension
->KeyboardInterrupt
.Dirql
,
279 PortDeviceExtension
->MouseInterrupt
.Dirql
);
281 INFO_(I8042PRT
, "KeyboardInterrupt.Vector %lu\n",
282 PortDeviceExtension
->KeyboardInterrupt
.Vector
);
283 INFO_(I8042PRT
, "KeyboardInterrupt.Dirql %lu\n",
284 PortDeviceExtension
->KeyboardInterrupt
.Dirql
);
285 INFO_(I8042PRT
, "KeyboardInterrupt.DirqlMax %lu\n",
287 INFO_(I8042PRT
, "KeyboardInterrupt.InterruptMode %s\n",
288 PortDeviceExtension
->KeyboardInterrupt
.InterruptMode
== LevelSensitive
? "LevelSensitive" : "Latched");
289 INFO_(I8042PRT
, "KeyboardInterrupt.ShareInterrupt %s\n",
290 PortDeviceExtension
->KeyboardInterrupt
.ShareInterrupt
? "yes" : "no");
291 INFO_(I8042PRT
, "KeyboardInterrupt.Affinity 0x%lx\n",
292 PortDeviceExtension
->KeyboardInterrupt
.Affinity
);
293 Status
= IoConnectInterrupt(
294 &PortDeviceExtension
->KeyboardInterrupt
.Object
,
295 i8042KbdInterruptService
,
296 DeviceExtension
, &PortDeviceExtension
->SpinLock
,
297 PortDeviceExtension
->KeyboardInterrupt
.Vector
, PortDeviceExtension
->KeyboardInterrupt
.Dirql
, DirqlMax
,
298 PortDeviceExtension
->KeyboardInterrupt
.InterruptMode
, PortDeviceExtension
->KeyboardInterrupt
.ShareInterrupt
,
299 PortDeviceExtension
->KeyboardInterrupt
.Affinity
, FALSE
);
300 if (!NT_SUCCESS(Status
))
302 WARN_(I8042PRT
, "IoConnectInterrupt() failed with status 0x%08x\n", Status
);
306 if (DirqlMax
== PortDeviceExtension
->KeyboardInterrupt
.Dirql
)
307 PortDeviceExtension
->HighestDIRQLInterrupt
= PortDeviceExtension
->KeyboardInterrupt
.Object
;
308 PortDeviceExtension
->Flags
|= KEYBOARD_INITIALIZED
;
309 return STATUS_SUCCESS
;
313 i8042ConnectMouseInterrupt(
314 IN PI8042_MOUSE_EXTENSION DeviceExtension
)
316 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
320 TRACE_(I8042PRT
, "i8042ConnectMouseInterrupt()\n");
322 Status
= i8042MouInitialize(DeviceExtension
);
323 if (!NT_SUCCESS(Status
))
326 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
328 PortDeviceExtension
->KeyboardInterrupt
.Dirql
,
329 PortDeviceExtension
->MouseInterrupt
.Dirql
);
331 INFO_(I8042PRT
, "MouseInterrupt.Vector %lu\n",
332 PortDeviceExtension
->MouseInterrupt
.Vector
);
333 INFO_(I8042PRT
, "MouseInterrupt.Dirql %lu\n",
334 PortDeviceExtension
->MouseInterrupt
.Dirql
);
335 INFO_(I8042PRT
, "MouseInterrupt.DirqlMax %lu\n",
337 INFO_(I8042PRT
, "MouseInterrupt.InterruptMode %s\n",
338 PortDeviceExtension
->MouseInterrupt
.InterruptMode
== LevelSensitive
? "LevelSensitive" : "Latched");
339 INFO_(I8042PRT
, "MouseInterrupt.ShareInterrupt %s\n",
340 PortDeviceExtension
->MouseInterrupt
.ShareInterrupt
? "yes" : "no");
341 INFO_(I8042PRT
, "MouseInterrupt.Affinity 0x%lx\n",
342 PortDeviceExtension
->MouseInterrupt
.Affinity
);
343 Status
= IoConnectInterrupt(
344 &PortDeviceExtension
->MouseInterrupt
.Object
,
345 i8042MouInterruptService
,
346 DeviceExtension
, &PortDeviceExtension
->SpinLock
,
347 PortDeviceExtension
->MouseInterrupt
.Vector
, PortDeviceExtension
->MouseInterrupt
.Dirql
, DirqlMax
,
348 PortDeviceExtension
->MouseInterrupt
.InterruptMode
, PortDeviceExtension
->MouseInterrupt
.ShareInterrupt
,
349 PortDeviceExtension
->MouseInterrupt
.Affinity
, FALSE
);
350 if (!NT_SUCCESS(Status
))
352 WARN_(I8042PRT
, "IoConnectInterrupt() failed with status 0x%08x\n", Status
);
356 if (DirqlMax
== PortDeviceExtension
->MouseInterrupt
.Dirql
)
357 PortDeviceExtension
->HighestDIRQLInterrupt
= PortDeviceExtension
->MouseInterrupt
.Object
;
359 PortDeviceExtension
->Flags
|= MOUSE_INITIALIZED
;
360 Status
= STATUS_SUCCESS
;
363 if (!NT_SUCCESS(Status
))
365 PortDeviceExtension
->Flags
&= ~MOUSE_INITIALIZED
;
366 if (PortDeviceExtension
->MouseInterrupt
.Object
)
368 IoDisconnectInterrupt(PortDeviceExtension
->MouseInterrupt
.Object
);
369 PortDeviceExtension
->HighestDIRQLInterrupt
= PortDeviceExtension
->KeyboardInterrupt
.Object
;
377 IN PPORT_DEVICE_EXTENSION DeviceExtension
,
378 IN UCHAR FlagsToDisable
,
379 IN UCHAR FlagsToEnable
)
381 i8042Flush(DeviceExtension
);
383 if (!i8042ChangeMode(DeviceExtension
, FlagsToDisable
, FlagsToEnable
))
384 return STATUS_UNSUCCESSFUL
;
386 return STATUS_SUCCESS
;
391 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
393 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
394 UCHAR FlagsToDisable
= 0;
395 UCHAR FlagsToEnable
= 0;
398 if (DeviceExtension
->DataPort
== 0)
400 /* Unable to do something at the moment */
401 return STATUS_SUCCESS
;
404 if (!(DeviceExtension
->Flags
& (KEYBOARD_PRESENT
| MOUSE_PRESENT
)))
406 /* Try to detect them */
407 TRACE_(I8042PRT
, "Check if the controller is really a i8042\n");
408 Status
= i8042BasicDetect(DeviceExtension
);
409 if (!NT_SUCCESS(Status
))
411 WARN_(I8042PRT
, "i8042BasicDetect() failed with status 0x%08lx\n", Status
);
412 return STATUS_UNSUCCESSFUL
;
415 /* First detect the mouse and then the keyboard!
416 If we do it the other way round, some systems throw away settings like the keyboard translation, when detecting the mouse. */
417 TRACE_(I8042PRT
, "Detecting mouse\n");
418 i8042DetectMouse(DeviceExtension
);
419 TRACE_(I8042PRT
, "Detecting keyboard\n");
420 i8042DetectKeyboard(DeviceExtension
);
422 INFO_(I8042PRT
, "Keyboard present: %s\n", DeviceExtension
->Flags
& KEYBOARD_PRESENT
? "YES" : "NO");
423 INFO_(I8042PRT
, "Mouse present : %s\n", DeviceExtension
->Flags
& MOUSE_PRESENT
? "YES" : "NO");
425 TRACE_(I8042PRT
, "Enabling i8042 interrupts\n");
426 if (DeviceExtension
->Flags
& KEYBOARD_PRESENT
)
428 FlagsToDisable
|= CCB_KBD_DISAB
;
429 FlagsToEnable
|= CCB_KBD_INT_ENAB
;
431 if (DeviceExtension
->Flags
& MOUSE_PRESENT
)
433 FlagsToDisable
|= CCB_MOUSE_DISAB
;
434 FlagsToEnable
|= CCB_MOUSE_INT_ENAB
;
437 Status
= EnableInterrupts(DeviceExtension
, FlagsToDisable
, FlagsToEnable
);
438 if (!NT_SUCCESS(Status
))
440 WARN_(I8042PRT
, "EnableInterrupts failed: %lx\n", Status
);
441 DeviceExtension
->Flags
&= ~(KEYBOARD_PRESENT
| MOUSE_PRESENT
);
446 /* Connect interrupts */
447 if (DeviceExtension
->Flags
& KEYBOARD_PRESENT
&&
448 DeviceExtension
->Flags
& KEYBOARD_CONNECTED
&&
449 DeviceExtension
->Flags
& KEYBOARD_STARTED
&&
450 !(DeviceExtension
->Flags
& KEYBOARD_INITIALIZED
))
452 /* Keyboard is ready to be initialized */
453 Status
= i8042ConnectKeyboardInterrupt(DeviceExtension
->KeyboardExtension
);
454 if (NT_SUCCESS(Status
))
456 DeviceExtension
->Flags
|= KEYBOARD_INITIALIZED
;
460 WARN_(I8042PRT
, "i8042ConnectKeyboardInterrupt failed: %lx\n", Status
);
464 if (DeviceExtension
->Flags
& MOUSE_PRESENT
&&
465 DeviceExtension
->Flags
& MOUSE_CONNECTED
&&
466 DeviceExtension
->Flags
& MOUSE_STARTED
&&
467 !(DeviceExtension
->Flags
& MOUSE_INITIALIZED
))
469 /* Mouse is ready to be initialized */
470 Status
= i8042ConnectMouseInterrupt(DeviceExtension
->MouseExtension
);
471 if (NT_SUCCESS(Status
))
473 DeviceExtension
->Flags
|= MOUSE_INITIALIZED
;
477 WARN_(I8042PRT
, "i8042ConnectMouseInterrupt failed: %lx\n", Status
);
480 /* Start the mouse */
481 Irql
= KeAcquireInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
);
482 /* HACK: the mouse has already been reset in i8042DetectMouse. This second
483 reset prevents some touchpads/mice from working (Dell D531, D600).
485 #ifndef __I8042PRT_HACK_FOR_NOTEBOOK__
486 i8042IsrWritePort(DeviceExtension
, MOU_CMD_RESET
, CTRL_WRITE_MOUSE
);
488 KeReleaseInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
, Irql
);
496 IN PDEVICE_OBJECT DeviceObject
,
497 IN PCM_RESOURCE_LIST AllocatedResources
,
498 IN PCM_RESOURCE_LIST AllocatedResourcesTranslated
)
500 PFDO_DEVICE_EXTENSION DeviceExtension
;
501 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
502 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
, ResourceDescriptorTranslated
;
503 INTERRUPT_DATA InterruptData
= { NULL
};
504 BOOLEAN FoundDataPort
= FALSE
;
505 BOOLEAN FoundControlPort
= FALSE
;
506 BOOLEAN FoundIrq
= FALSE
;
510 TRACE_(I8042PRT
, "i8042PnpStartDevice(%p)\n", DeviceObject
);
511 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
512 PortDeviceExtension
= DeviceExtension
->PortDeviceExtension
;
514 ASSERT(DeviceExtension
->PnpState
== dsStopped
);
516 if (!AllocatedResources
)
518 WARN_(I8042PRT
, "No allocated resources sent to driver\n");
519 return STATUS_INSUFFICIENT_RESOURCES
;
521 if (AllocatedResources
->Count
!= 1)
523 WARN_(I8042PRT
, "Wrong number of allocated resources sent to driver\n");
524 return STATUS_INSUFFICIENT_RESOURCES
;
526 if (AllocatedResources
->List
[0].PartialResourceList
.Version
!= 1
527 || AllocatedResources
->List
[0].PartialResourceList
.Revision
!= 1
528 || AllocatedResourcesTranslated
->List
[0].PartialResourceList
.Version
!= 1
529 || AllocatedResourcesTranslated
->List
[0].PartialResourceList
.Revision
!= 1)
531 WARN_(I8042PRT
, "Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
532 AllocatedResources
->List
[0].PartialResourceList
.Version
,
533 AllocatedResources
->List
[0].PartialResourceList
.Revision
,
534 AllocatedResourcesTranslated
->List
[0].PartialResourceList
.Version
,
535 AllocatedResourcesTranslated
->List
[0].PartialResourceList
.Revision
);
536 return STATUS_REVISION_MISMATCH
;
539 /* Get Irq and optionally control port and data port */
540 for (i
= 0; i
< AllocatedResources
->List
[0].PartialResourceList
.Count
; i
++)
542 ResourceDescriptor
= &AllocatedResources
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
543 ResourceDescriptorTranslated
= &AllocatedResourcesTranslated
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
544 switch (ResourceDescriptor
->Type
)
546 case CmResourceTypePort
:
548 if (ResourceDescriptor
->u
.Port
.Length
== 1)
550 /* We assume that the first resource will
551 * be the control port and the second one
552 * will be the data port...
556 PortDeviceExtension
->DataPort
= ULongToPtr(ResourceDescriptor
->u
.Port
.Start
.u
.LowPart
);
557 INFO_(I8042PRT
, "Found data port: %p\n", PortDeviceExtension
->DataPort
);
558 FoundDataPort
= TRUE
;
560 else if (!FoundControlPort
)
562 PortDeviceExtension
->ControlPort
= ULongToPtr(ResourceDescriptor
->u
.Port
.Start
.u
.LowPart
);
563 INFO_(I8042PRT
, "Found control port: %p\n", PortDeviceExtension
->ControlPort
);
564 FoundControlPort
= TRUE
;
568 /* FIXME: implement PS/2 Active Multiplexing */
569 ERR_(I8042PRT
, "Unhandled I/O ranges provided: 0x%lx\n", ResourceDescriptor
->u
.Port
.Length
);
573 WARN_(I8042PRT
, "Invalid I/O range length: 0x%lx\n", ResourceDescriptor
->u
.Port
.Length
);
576 case CmResourceTypeInterrupt
:
579 return STATUS_INVALID_PARAMETER
;
580 InterruptData
.Dirql
= (KIRQL
)ResourceDescriptorTranslated
->u
.Interrupt
.Level
;
581 InterruptData
.Vector
= ResourceDescriptorTranslated
->u
.Interrupt
.Vector
;
582 InterruptData
.Affinity
= ResourceDescriptorTranslated
->u
.Interrupt
.Affinity
;
583 if (ResourceDescriptorTranslated
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
)
584 InterruptData
.InterruptMode
= Latched
;
586 InterruptData
.InterruptMode
= LevelSensitive
;
587 InterruptData
.ShareInterrupt
= (ResourceDescriptorTranslated
->ShareDisposition
== CmResourceShareShared
);
588 INFO_(I8042PRT
, "Found irq resource: %lu\n", ResourceDescriptor
->u
.Interrupt
.Level
);
593 WARN_(I8042PRT
, "Unknown resource descriptor type 0x%x\n", ResourceDescriptor
->Type
);
599 WARN_(I8042PRT
, "Interrupt resource was not found in allocated resources list\n");
600 return STATUS_INSUFFICIENT_RESOURCES
;
602 else if (DeviceExtension
->Type
== Keyboard
&& (!FoundDataPort
|| !FoundControlPort
))
604 WARN_(I8042PRT
, "Some required resources were not found in allocated resources list\n");
605 return STATUS_INSUFFICIENT_RESOURCES
;
607 else if (DeviceExtension
->Type
== Mouse
&& (FoundDataPort
|| FoundControlPort
))
609 WARN_(I8042PRT
, "Too much resources were provided in allocated resources list\n");
610 return STATUS_INVALID_PARAMETER
;
613 switch (DeviceExtension
->Type
)
618 &PortDeviceExtension
->KeyboardInterrupt
,
620 sizeof(INTERRUPT_DATA
));
621 PortDeviceExtension
->Flags
|= KEYBOARD_STARTED
;
622 Status
= StartProcedure(PortDeviceExtension
);
628 &PortDeviceExtension
->MouseInterrupt
,
630 sizeof(INTERRUPT_DATA
));
631 PortDeviceExtension
->Flags
|= MOUSE_STARTED
;
632 Status
= StartProcedure(PortDeviceExtension
);
637 WARN_(I8042PRT
, "Unknown FDO type %u\n", DeviceExtension
->Type
);
638 ASSERT(!(PortDeviceExtension
->Flags
& KEYBOARD_CONNECTED
) || !(PortDeviceExtension
->Flags
& MOUSE_CONNECTED
));
639 Status
= STATUS_INVALID_DEVICE_REQUEST
;
643 if (NT_SUCCESS(Status
))
644 DeviceExtension
->PnpState
= dsStarted
;
651 IN PDEVICE_OBJECT DeviceObject
)
653 PI8042_DRIVER_EXTENSION DriverExtension
;
655 PFDO_DEVICE_EXTENSION DeviceExtension
;
657 DriverExtension
= (PI8042_DRIVER_EXTENSION
)IoGetDriverObjectExtension(DeviceObject
->DriverObject
, DeviceObject
->DriverObject
);
658 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
660 KeAcquireSpinLock(&DriverExtension
->DeviceListLock
, &OldIrql
);
661 RemoveEntryList(&DeviceExtension
->ListEntry
);
662 KeReleaseSpinLock(&DriverExtension
->DeviceListLock
, OldIrql
);
664 IoDetachDevice(DeviceExtension
->LowerDevice
);
666 IoDeleteDevice(DeviceObject
);
671 IN PDEVICE_OBJECT DeviceObject
,
674 PIO_STACK_LOCATION Stack
;
676 I8042_DEVICE_TYPE DeviceType
;
677 ULONG_PTR Information
= 0;
680 Stack
= IoGetCurrentIrpStackLocation(Irp
);
681 MinorFunction
= Stack
->MinorFunction
;
682 DeviceType
= ((PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->Type
;
684 switch (MinorFunction
)
686 case IRP_MN_START_DEVICE
: /* 0x00 */
688 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
690 /* Call lower driver (if any) */
691 if (DeviceType
!= PhysicalDeviceObject
)
693 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
694 if (NT_SUCCESS(Status
))
695 Status
= i8042PnpStartDevice(
697 Stack
->Parameters
.StartDevice
.AllocatedResources
,
698 Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
);
701 Status
= STATUS_SUCCESS
;
704 case IRP_MN_QUERY_DEVICE_RELATIONS
: /* (optional) 0x07 */
706 switch (Stack
->Parameters
.QueryDeviceRelations
.Type
)
710 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
711 return ForwardIrpAndForget(DeviceObject
, Irp
);
713 case RemovalRelations
:
715 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
716 return ForwardIrpAndForget(DeviceObject
, Irp
);
719 ERR_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
720 Stack
->Parameters
.QueryDeviceRelations
.Type
);
721 return ForwardIrpAndForget(DeviceObject
, Irp
);
725 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
: /* (optional) 0x0d */
727 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
728 return ForwardIrpAndForget(DeviceObject
, Irp
);
730 case IRP_MN_QUERY_PNP_DEVICE_STATE
: /* 0x14 */
732 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
733 return ForwardIrpAndForget(DeviceObject
, Irp
);
735 case IRP_MN_QUERY_REMOVE_DEVICE
:
737 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_QUERY_REMOVE_DEVICE\n");
738 return ForwardIrpAndForget(DeviceObject
, Irp
);
740 case IRP_MN_CANCEL_REMOVE_DEVICE
:
742 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_CANCEL_REMOVE_DEVICE\n");
743 return ForwardIrpAndForget(DeviceObject
, Irp
);
745 case IRP_MN_REMOVE_DEVICE
:
747 TRACE_(I8042PRT
, "IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
748 Status
= ForwardIrpAndForget(DeviceObject
, Irp
);
749 i8042RemoveDevice(DeviceObject
);
754 ERR_(I8042PRT
, "IRP_MJ_PNP / unknown minor function 0x%x\n", MinorFunction
);
755 return ForwardIrpAndForget(DeviceObject
, Irp
);
759 Irp
->IoStatus
.Information
= Information
;
760 Irp
->IoStatus
.Status
= Status
;
761 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);