Prevent i8042prt to search for a keyboard/mouse more than once
[reactos.git] / reactos / drivers / input / i8042prt / i8042prt.c
index b0ddcab..208916d 100644 (file)
 
 /* INCLUDES ****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <ddk/ntddkbd.h>
-#include <ddk/ntdd8042.h>
-
 #define NDEBUG
 #include <debug.h>
 
 #define I8042_MAX_COMMAND_LENGTH 16
 #define I8042_MAX_UPWARDS_STACK 5
 
+UNICODE_STRING I8042RegistryPath;
+
 /* FUNCTIONS *****************************************************************/
 
 /*
  * FUNCTION: Write data to a port, waiting first for it to become ready
  */
-BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, int addr, BYTE data)
+BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, PUCHAR addr, UCHAR data)
 {
        ULONG ResendIterations = DevExt->Settings.PollingIterations;
 
-       while ((KBD_IBF & READ_PORT_UCHAR((PUCHAR)I8042_CTRL_PORT)) &&
+       while ((KBD_IBF & READ_PORT_UCHAR(I8042_CTRL_PORT)) &&
               (ResendIterations--))
        {
                KeStallExecutionProcessor(50);
        }
 
        if (ResendIterations) {
-               WRITE_PORT_UCHAR((PUCHAR)addr,data);
+               WRITE_PORT_UCHAR(addr,data);
                DPRINT("Sent %x to %x\n", data, addr);
                return TRUE;
        }
@@ -56,7 +54,7 @@ BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, int addr, BYTE data)
 /*
  * FUNCTION: Write data to a port, without waiting first
  */
-static BOOLEAN I8042WriteNoWait(PDEVICE_EXTENSION DevExt, int addr, BYTE data)
+static BOOLEAN I8042WriteNoWait(PDEVICE_EXTENSION DevExt, int addr, UCHAR data)
 {
        WRITE_PORT_UCHAR((PUCHAR)addr,data);
        DPRINT("Sent %x to %x\n", data, addr);
@@ -67,10 +65,10 @@ static BOOLEAN I8042WriteNoWait(PDEVICE_EXTENSION DevExt, int addr, BYTE data)
 /*
  * FUNCTION: Read data from port 0x60
  */
-NTSTATUS I8042ReadData(BYTE *Data)
+NTSTATUS I8042ReadData(UCHAR *Data)
 {
-       BYTE Status;
-       Status=READ_PORT_UCHAR((PUCHAR)I8042_CTRL_PORT);
+       UCHAR Status;
+       Status=READ_PORT_UCHAR(I8042_CTRL_PORT);
 
        // If data is available
        if ((Status & KBD_OBF)) {
@@ -78,22 +76,22 @@ NTSTATUS I8042ReadData(BYTE *Data)
                DPRINT("Read: %x (status: %x)\n", Data[0], Status);
 
                // If the data is valid (not timeout, not parity error)
-               if (0 == (Status & (KBD_GTO | KBD_PERR)))
+               if (0 == (Status & KBD_PERR))
                        return STATUS_SUCCESS;
        }
        return STATUS_UNSUCCESSFUL;
 }
 
-NTSTATUS I8042ReadStatus(BYTE *Status)
+NTSTATUS I8042ReadStatus(UCHAR *Status)
 {
-       Status[0]=READ_PORT_UCHAR((PUCHAR)I8042_CTRL_PORT);
+       Status[0]=READ_PORT_UCHAR(I8042_CTRL_PORT);
        return STATUS_SUCCESS;
 }
 
 /*
  * FUNCTION: Read data from port 0x60
  */
-NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, BYTE *Data)
+NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, UCHAR *Data)
 {
        ULONG Counter = DevExt->Settings.PollingIterations;
        NTSTATUS Status;
@@ -112,10 +110,10 @@ NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, BYTE *Data)
 
 VOID I8042Flush()
 {
-       BYTE Ignore;
+       UCHAR Ignore;
 
        while (STATUS_SUCCESS == I8042ReadData(&Ignore)) {
-               ; /* drop */
+               DPRINT("Data flushed\n"); /* drop */
        }
 }
 
@@ -141,30 +139,43 @@ NTSTATUS STDCALL I8042SynchWritePort(PDEVICE_EXTENSION DevExt,
 {
        NTSTATUS Status;
        UCHAR Ack;
-       UINT ResendIterations = DevExt->Settings.ResendIterations + 1;
+       ULONG ResendIterations = DevExt->Settings.ResendIterations + 1;
 
        do {
                if (Port)
                        if (!I8042Write(DevExt, I8042_DATA_PORT, Port))
-                               return STATUS_TIMEOUT;
+                       {
+                               DPRINT1("Failed to write Port\n");
+                               return STATUS_IO_TIMEOUT;
+                       }
 
                if (!I8042Write(DevExt, I8042_DATA_PORT, Value))
-                       return STATUS_TIMEOUT;
+               {
+                       DPRINT1("Failed to write Value\n");
+                       return STATUS_IO_TIMEOUT;
+               }
 
                if (WaitForAck) {
                        Status = I8042ReadDataWait(DevExt, &Ack);
                        if (!NT_SUCCESS(Status))
+                       {
+                               DPRINT1("Failed to read Ack\n");
                                return Status;
+                       }
                        if (Ack == KBD_ACK)
                                return STATUS_SUCCESS;
                        if (Ack != KBD_RESEND)
+                       {
+                               DPRINT1("Unexpected Ack 0x%x\n", Ack);
                                return STATUS_UNEXPECTED_IO_ERROR;
+                       }
                } else {
                        return STATUS_SUCCESS;
                }
+               DPRINT("Reiterating\n");
                ResendIterations--;
        } while (ResendIterations);
-       return STATUS_TIMEOUT;
+       return STATUS_IO_TIMEOUT;
 }
 
 /*
@@ -241,7 +252,7 @@ NTSTATUS STDCALL I8042StartPacket(PDEVICE_EXTENSION DevExt,
                DevExt->PacketPort = 0;
 
        if (!I8042PacketWrite(DevExt)) {
-               Status = STATUS_TIMEOUT;
+               Status = STATUS_IO_TIMEOUT;
                DevExt->Packet.State = Idle;
                DevExt->PacketResult = STATUS_ABANDONED;
                goto startpacketdone;
@@ -273,7 +284,7 @@ BOOLEAN STDCALL I8042PacketIsr(PDEVICE_EXTENSION DevExt,
                if (DevExt->PacketResends > DevExt->Settings.ResendIterations) {
                        DevExt->Packet.State = Idle;
                        DevExt->PacketComplete = TRUE;
-                       DevExt->PacketResult = STATUS_TIMEOUT;
+                       DevExt->PacketResult = STATUS_IO_TIMEOUT;
                        DevExt->PacketResends = 0;
                        return TRUE;
                }
@@ -301,7 +312,7 @@ BOOLEAN STDCALL I8042PacketIsr(PDEVICE_EXTENSION DevExt,
        if (!I8042PacketWrite(DevExt)) {
                DevExt->Packet.State = Idle;
                DevExt->PacketComplete = TRUE;
-               DevExt->PacketResult = STATUS_TIMEOUT;
+               DevExt->PacketResult = STATUS_IO_TIMEOUT;
                return TRUE;
        }
        DevExt->Packet.CurrentByte++;
@@ -311,7 +322,7 @@ BOOLEAN STDCALL I8042PacketIsr(PDEVICE_EXTENSION DevExt,
 
 VOID I8042PacketDpc(PDEVICE_EXTENSION DevExt)
 {
-       BOOL FinishIrp = FALSE;
+       BOOLEAN FinishIrp = FALSE;
        NTSTATUS Result = STATUS_INTERNAL_ERROR; /* Shouldn't happen */
        KIRQL Irql;
 
@@ -460,14 +471,14 @@ hookworkitemdone:
        DPRINT("HookWorkItem done\n");
 }
 
-VOID STDCALL I8042StartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+static VOID STDCALL I8042StartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
 {
        if (!I8042StartIoKbd(DeviceObject, Irp)) {
                DPRINT1("Unhandled StartIo!\n");
        }
 }
 
-NTSTATUS STDCALL I8042InternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+static NTSTATUS STDCALL I8042InternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
 {
        NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
        PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
@@ -493,7 +504,7 @@ NTSTATUS STDCALL I8042InternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Ir
        return Status;
 }
 
-NTSTATUS STDCALL I8042CreateDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+static NTSTATUS STDCALL I8042CreateDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
 {
        NTSTATUS Status;
 
@@ -512,40 +523,67 @@ static NTSTATUS STDCALL I8042BasicDetect(PDEVICE_EXTENSION DevExt)
 {
        NTSTATUS Status;
        UCHAR Value = 0;
-       UINT Counter;
+       ULONG Counter;
 
        DevExt->MouseExists = FALSE;
        DevExt->KeyboardExists = FALSE;
 
-       if (!I8042Write(DevExt, I8042_DATA_PORT, 0x74))
-               return STATUS_TIMEOUT;
-
        I8042Flush();
 
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST))
-               return STATUS_TIMEOUT;
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST)) {
+               DPRINT1("Writing KBD_SELF_TEST command failed\n");
+               return STATUS_IO_TIMEOUT;
+       }
 
        // Wait longer?
        Counter = 3;
        do {
                Status = I8042ReadDataWait(DevExt, &Value);
-       } while ((Counter--) && (STATUS_TIMEOUT == Status));
+       } while ((Counter--) && (STATUS_IO_TIMEOUT == Status));
 
-       if (!NT_SUCCESS(Status))
+       if (!NT_SUCCESS(Status)) {
+               DPRINT1("Failed to read KBD_SELF_TEST response, status 0x%x\n",
+                       Status);
                return Status;
+       }
 
        if (Value != 0x55) {
                DPRINT1("Got %x instead of 55\n", Value);
                return STATUS_IO_DEVICE_ERROR;
        }
 
-       if (I8042Write(DevExt, I8042_CTRL_PORT, KBD_LINE_TEST))
-       {
-               Status = I8042ReadDataWait(DevExt, &Value);
-               if (NT_SUCCESS(Status) && Value == 0)
-                       DevExt->KeyboardExists = TRUE;
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
+               DPRINT1("Can't read i8042 mode\n");
+               return FALSE;
        }
 
+       Status = I8042ReadDataWait(DevExt, &Value);
+       if (!NT_SUCCESS(Status)) {
+               DPRINT1("No response after read i8042 mode\n");
+               return FALSE;
+       }
+
+       Value |= CCB_KBD_DISAB | CCB_MOUSE_DISAB; /* disable keyboard/mouse */
+       Value &= ~(CCB_KBD_INT_ENAB | CCB_MOUSE_INT_ENAB);
+                 /* don't enable keyboard and mouse interrupts */
+
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
+               DPRINT1("Can't set i8042 mode\n");
+               return FALSE;
+       }
+
+       if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
+               DPRINT1("Can't send i8042 mode\n");
+               return FALSE;
+       }
+
+       /*
+        * We used to send a KBD_LINE_TEST command here, but on at least HP
+        * Pavilion notebooks the response to that command was incorrect.
+        * So now we just assume that a keyboard is attached.
+        */
+       DevExt->KeyboardExists = TRUE;
+
        if (I8042Write(DevExt, I8042_CTRL_PORT, MOUSE_LINE_TEST))
        {
                Status = I8042ReadDataWait(DevExt, &Value);
@@ -566,6 +604,11 @@ static NTSTATUS STDCALL I8042Initialize(PDEVICE_EXTENSION DevExt)
                return Status;
        }
 
+       if (DevExt->MouseExists) {
+               DPRINT("Aux port detected\n");
+               DevExt->MouseExists = I8042DetectMouse(DevExt);
+       }
+
        if (!DevExt->KeyboardExists) {
                DPRINT("Keyboard port not detected\n");
                if (DevExt->Settings.Headless)
@@ -576,11 +619,6 @@ static NTSTATUS STDCALL I8042Initialize(PDEVICE_EXTENSION DevExt)
                DevExt->KeyboardExists = I8042DetectKeyboard(DevExt);
        }
 
-       if (DevExt->MouseExists) {
-               DPRINT("Mouse port detected\n");
-               DevExt->MouseExists = I8042DetectMouse(DevExt);
-       }
-
        if (DevExt->KeyboardExists) {
                DPRINT("Keyboard detected\n");
                I8042KeyboardEnable(DevExt);
@@ -609,9 +647,15 @@ static NTSTATUS STDCALL I8042AddDevice(PDRIVER_OBJECT DriverObject,
        PDEVICE_EXTENSION DevExt;
        PFDO_DEVICE_EXTENSION FdoDevExt;
        PDEVICE_OBJECT Fdo;
+       static BOOLEAN AlreadyAdded = FALSE;
 
        DPRINT("I8042AddDevice\n");
 
+       /* HACK! */
+       if (AlreadyAdded)
+               return STATUS_UNSUCCESSFUL;
+       AlreadyAdded = TRUE;
+
        Status = IoCreateDevice(DriverObject,
                       sizeof(DEVICE_EXTENSION),
                       NULL,
@@ -804,6 +848,21 @@ NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
 {
        DPRINT("I8042 Driver 0.0.1\n");
 
+        I8042RegistryPath.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters");
+        I8042RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool, 
+                                                         I8042RegistryPath.MaximumLength,
+                                                         TAG_I8042);
+        if (I8042RegistryPath.Buffer == NULL) {
+
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        RtlCopyUnicodeString(&I8042RegistryPath, RegistryPath);
+        RtlAppendUnicodeToString(&I8042RegistryPath, L"\\Parameters");
+        I8042RegistryPath.Buffer[I8042RegistryPath.Length / sizeof(WCHAR)] = 0;
+
+
+
        DriverObject->MajorFunction[IRP_MJ_CREATE] = I8042CreateDispatch;
        DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
                                               I8042InternalDeviceControl;
@@ -813,4 +872,3 @@ NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
 
        return(STATUS_SUCCESS);
 }
-