Пример #1
0
static VOID NTAPI
i8042KbdDpcRoutine(
	IN PKDPC Dpc,
	IN PVOID DeferredContext,
	IN PVOID SystemArgument1,
	IN PVOID SystemArgument2)
{
	PI8042_KEYBOARD_EXTENSION DeviceExtension;
	PPORT_DEVICE_EXTENSION PortDeviceExtension;
	ULONG KeysTransferred = 0;
	ULONG KeysInBufferCopy;
	KIRQL Irql;

	UNREFERENCED_PARAMETER(Dpc);
	UNREFERENCED_PARAMETER(SystemArgument1);
	UNREFERENCED_PARAMETER(SystemArgument2);

	__analysis_assume(DeferredContext != NULL);
	DeviceExtension = DeferredContext;
	PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;

	if (HandlePowerKeys(DeviceExtension))
	{
		DeviceExtension->KeyComplete = FALSE;
		return;
	}

	i8042PacketDpc(PortDeviceExtension);
	if (!DeviceExtension->KeyComplete)
		return;
	/* We got the interrupt as it was being enabled, too bad */
	if (!PortDeviceExtension->HighestDIRQLInterrupt)
		return;

	Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);

	DeviceExtension->KeyComplete = FALSE;
	KeysInBufferCopy = DeviceExtension->KeysInBuffer;

	KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);

	TRACE_(I8042PRT, "Send a key\n");

	if (!DeviceExtension->KeyboardData.ClassService)
		return;

	INFO_(I8042PRT, "Sending %lu key(s)\n", KeysInBufferCopy);
	(*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->KeyboardData.ClassService)(
		DeviceExtension->KeyboardData.ClassDeviceObject,
		DeviceExtension->KeyboardBuffer,
		DeviceExtension->KeyboardBuffer + KeysInBufferCopy,
		&KeysTransferred);

	KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
	DeviceExtension->KeysInBuffer -= KeysTransferred;
	KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
}
Пример #2
0
static
VOID
PortReleaseSpinLock(
    PFDO_DEVICE_EXTENSION DeviceExtension,
    PSTOR_LOCK_HANDLE LockHandle)
{
    DPRINT1("PortReleaseSpinLock(%p %p)\n",
            DeviceExtension, LockHandle);

    switch (LockHandle->Lock)
    {
        case DpcLock: /* 1, */
            DPRINT1("DpcLock\n");
            break;

        case StartIoLock: /* 2 */
            DPRINT1("StartIoLock\n");
            break;

        case InterruptLock: /* 3 */
            DPRINT1("InterruptLock\n");
            if (DeviceExtension->Interrupt != NULL)
                KeReleaseInterruptSpinLock(DeviceExtension->Interrupt,
                                           LockHandle->Context.OldIrql);
            break;
    }
}
Пример #3
0
/*
 * This function starts a packet. It must be called with the
 * correct DIRQL.
 */
NTSTATUS
i8042StartPacket(
	IN PPORT_DEVICE_EXTENSION DeviceExtension,
	IN PFDO_DEVICE_EXTENSION FdoDeviceExtension,
	IN PUCHAR Bytes,
	IN ULONG ByteCount,
	IN PIRP Irp)
{
	KIRQL Irql;
	NTSTATUS Status;

	Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt);

	if (DeviceExtension->Packet.State != Idle)
	{
		Status = STATUS_DEVICE_BUSY;
		goto done;
	}

	switch (FdoDeviceExtension->Type)
	{
		case Keyboard: DeviceExtension->PacketPort = 0; break;
		case Mouse: DeviceExtension->PacketPort = CTRL_WRITE_MOUSE; break;
		default:
			ERR_(I8042PRT, "Unknown FDO type %u\n", FdoDeviceExtension->Type);
			ASSERT(FALSE);
			Status = STATUS_INTERNAL_ERROR;
			goto done;
	}

	DeviceExtension->Packet.Bytes = Bytes;
	DeviceExtension->Packet.CurrentByte = 0;
	DeviceExtension->Packet.ByteCount = ByteCount;
	DeviceExtension->Packet.State = SendingBytes;
	DeviceExtension->PacketResult = Status = STATUS_PENDING;
	DeviceExtension->CurrentIrp = Irp;
	DeviceExtension->CurrentIrpDevice = FdoDeviceExtension->Fdo;

	if (!i8042PacketWrite(DeviceExtension))
	{
		Status = STATUS_IO_TIMEOUT;
		DeviceExtension->Packet.State = Idle;
		DeviceExtension->PacketResult = STATUS_ABANDONED;
		goto done;
	}

	DeviceExtension->Packet.CurrentByte++;

done:
	KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql);

	if (Status != STATUS_PENDING)
	{
		DeviceExtension->CurrentIrp = NULL;
		DeviceExtension->CurrentIrpDevice = NULL;
		Irp->IoStatus.Status = Status;
		IoCompleteRequest(Irp, IO_NO_INCREMENT);
	}
	return Status;
}
Пример #4
0
static VOID
i8042PacketDpc(
	IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
	BOOLEAN FinishIrp = FALSE;
	KIRQL Irql;
	NTSTATUS Result = STATUS_INTERNAL_ERROR; /* Shouldn't happen */

	/* If the interrupt happens before this is setup, the key
	 * was already in the buffer. Too bad! */
	if (!DeviceExtension->HighestDIRQLInterrupt)
		return;

	Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt);

	if (DeviceExtension->Packet.State == Idle
	 && DeviceExtension->PacketComplete)
	{
		FinishIrp = TRUE;
		Result = DeviceExtension->PacketResult;
		DeviceExtension->PacketComplete = FALSE;
	}

	KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql);

	if (!FinishIrp)
		return;

	if (DeviceExtension->CurrentIrp)
	{
		DeviceExtension->CurrentIrp->IoStatus.Status = Result;
		IoCompleteRequest(DeviceExtension->CurrentIrp, IO_NO_INCREMENT);
		IoStartNextPacket(DeviceExtension->CurrentIrpDevice, FALSE);
		DeviceExtension->CurrentIrp = NULL;
		DeviceExtension->CurrentIrpDevice = NULL;
	}
}
Пример #5
0
static NTSTATUS
StartProcedure(
    IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
    NTSTATUS Status;
    UCHAR FlagsToDisable = 0;
    UCHAR FlagsToEnable = 0;
    KIRQL Irql;

    if (DeviceExtension->DataPort == 0)
    {
        /* Unable to do something at the moment */
        return STATUS_SUCCESS;
    }

    if (!(DeviceExtension->Flags & (KEYBOARD_PRESENT | MOUSE_PRESENT)))
    {
        /* Try to detect them */
        TRACE_(I8042PRT, "Check if the controller is really a i8042\n");
        Status = i8042BasicDetect(DeviceExtension);
        if (!NT_SUCCESS(Status))
        {
            WARN_(I8042PRT, "i8042BasicDetect() failed with status 0x%08lx\n", Status);
            return STATUS_UNSUCCESSFUL;
        }

        /* First detect the mouse and then the keyboard!
           If we do it the other way round, some systems throw away settings like the keyboard translation, when detecting the mouse. */
        TRACE_(I8042PRT, "Detecting mouse\n");
        i8042DetectMouse(DeviceExtension);
        TRACE_(I8042PRT, "Detecting keyboard\n");
        i8042DetectKeyboard(DeviceExtension);

        INFO_(I8042PRT, "Keyboard present: %s\n", DeviceExtension->Flags & KEYBOARD_PRESENT ? "YES" : "NO");
        INFO_(I8042PRT, "Mouse present   : %s\n", DeviceExtension->Flags & MOUSE_PRESENT ? "YES" : "NO");

        TRACE_(I8042PRT, "Enabling i8042 interrupts\n");
        if (DeviceExtension->Flags & KEYBOARD_PRESENT)
        {
            FlagsToDisable |= CCB_KBD_DISAB;
            FlagsToEnable |= CCB_KBD_INT_ENAB;
        }
        if (DeviceExtension->Flags & MOUSE_PRESENT)
        {
            FlagsToDisable |= CCB_MOUSE_DISAB;
            FlagsToEnable |= CCB_MOUSE_INT_ENAB;
        }

        Status = EnableInterrupts(DeviceExtension, FlagsToDisable, FlagsToEnable);
        if (!NT_SUCCESS(Status))
        {
            DeviceExtension->Flags &= ~(KEYBOARD_PRESENT | MOUSE_PRESENT);
            return Status;
        }
    }

    /* Connect interrupts */
    if (DeviceExtension->Flags & KEYBOARD_PRESENT &&
        DeviceExtension->Flags & KEYBOARD_CONNECTED &&
        DeviceExtension->Flags & KEYBOARD_STARTED &&
        !(DeviceExtension->Flags & KEYBOARD_INITIALIZED))
    {
        /* Keyboard is ready to be initialized */
        Status = i8042ConnectKeyboardInterrupt(DeviceExtension->KeyboardExtension);
        if (NT_SUCCESS(Status))
        {
            DeviceExtension->Flags |= KEYBOARD_INITIALIZED;
        }
    }

    if (DeviceExtension->Flags & MOUSE_PRESENT &&
        DeviceExtension->Flags & MOUSE_CONNECTED &&
        DeviceExtension->Flags & MOUSE_STARTED &&
        !(DeviceExtension->Flags & MOUSE_INITIALIZED))
    {
        /* Mouse is ready to be initialized */
        Status = i8042ConnectMouseInterrupt(DeviceExtension->MouseExtension);
        if (NT_SUCCESS(Status))
        {
            DeviceExtension->Flags |= MOUSE_INITIALIZED;
        }

        /* Start the mouse */
        Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt);
        i8042IsrWritePort(DeviceExtension, MOU_CMD_RESET, CTRL_WRITE_MOUSE);
        KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql);
    }

    return Status;
}