📄 mouse.c
字号:
} else {
DevExt->MouseState = ZMovement;
}
break;
case ZMovement:
Scroll = Output & 0x0f;
if (Scroll & 8)
Scroll |= 0xf0;
if (Scroll) {
MouseInput->RawButtons |= MOUSE_WHEEL;
MouseInput->ButtonData = (USHORT)(Scroll * -WHEEL_DELTA);
}
if (DevExt->MouseType == IntellimouseExplorer) {
if (Output & 16)
MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
if (Output & 32)
MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
}
I8042MouseHandleButtons(DevExt, MOUSE_LEFT_BUTTON_DOWN |
MOUSE_RIGHT_BUTTON_DOWN |
MOUSE_MIDDLE_BUTTON_DOWN |
MOUSE_BUTTON_4_DOWN |
MOUSE_BUTTON_5_DOWN);
I8042QueueMousePacket(DevExt->MouseObject);
DevExt->MouseState = MouseIdle;
break;
default:
DPRINT1("Unexpected state!\n");
}
}
BOOLEAN STDCALL I8042InterruptServiceMouse(struct _KINTERRUPT *Interrupt,
VOID *Context)
{
UCHAR Output, PortStatus;
NTSTATUS Status;
PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
ULONG Iterations = 0;
do {
Status = I8042ReadStatus(&PortStatus);
Status = I8042ReadData(&Output);
Iterations++;
if (STATUS_SUCCESS == Status)
break;
KeStallExecutionProcessor(1);
} while (Iterations < DevExt->Settings.PollStatusIterations);
if (STATUS_SUCCESS != Status) {
DPRINT1("Spurious I8042 mouse interrupt\n");
return FALSE;
}
DPRINT("Got: %x\n", Output);
if (I8042PacketIsr(DevExt, Output)) {
if (DevExt->PacketComplete) {
DPRINT("Packet complete\n");
KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
}
DPRINT("Irq eaten by packet\n");
return TRUE;
}
I8042MouseInputTestTimeout(DevExt);
if (I8042MouseResetIsr(DevExt, PortStatus, &Output)) {
DPRINT("Handled by ResetIsr or hooked Isr\n");
if (NoChange != DevExt->MouseTimeoutState) {
KeInsertQueueDpc(&DevExt->DpcMouse, DevExt, NULL);
}
return TRUE;
}
if (DevExt->MouseType == Ps2pp)
I8042MouseHandlePs2pp(DevExt, Output);
else
I8042MouseHandle(DevExt, Output);
return TRUE;
}
VOID STDCALL I8042DpcRoutineMouse(PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2)
{
PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
ULONG MouseTransferred = 0;
ULONG MouseInBufferCopy;
KIRQL Irql;
LARGE_INTEGER Timeout;
switch (DevExt->MouseTimeoutState) {
case TimeoutStart:
DevExt->MouseTimeoutState = NoChange;
if (DevExt->MouseTimeoutActive &&
!KeCancelTimer(&DevExt->TimerMouseTimeout)) {
/* The timer fired already, give up */
DevExt->MouseTimeoutActive = FALSE;
return;
}
Timeout.QuadPart = -15000000;
/* 1.5 seconds, should be enough */
KeSetTimer(&DevExt->TimerMouseTimeout,
Timeout,
&DevExt->DpcMouseTimeout);
DevExt->MouseTimeoutActive = TRUE;
return;
case TimeoutCancel:
DevExt->MouseTimeoutState = NoChange;
KeCancelTimer(&DevExt->TimerMouseTimeout);
DevExt->MouseTimeoutActive = FALSE;
default:
/* nothing, don't want a warning */ ;
}
/* Should be unlikely */
if (!DevExt->MouseComplete)
return;
Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
DevExt->MouseComplete = FALSE;
MouseInBufferCopy = DevExt->MouseInBuffer;
KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
DPRINT ("Send a mouse packet\n");
if (!DevExt->MouseData.ClassService)
return;
((PSERVICE_CALLBACK_ROUTINE) DevExt->MouseData.ClassService)(
DevExt->MouseData.ClassDeviceObject,
DevExt->MouseBuffer,
DevExt->MouseBuffer + MouseInBufferCopy,
&MouseTransferred);
Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
DevExt->MouseInBuffer -= MouseTransferred;
if (DevExt->MouseInBuffer)
RtlMoveMemory(DevExt->MouseBuffer,
DevExt->MouseBuffer+MouseTransferred,
DevExt->MouseInBuffer * sizeof(MOUSE_INPUT_DATA));
KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
}
/* This timer DPC will be called when the mouse reset times out.
* I'll just send the 'disable mouse port' command to the controller
* and say the mouse doesn't exist.
*/
VOID STDCALL I8042DpcRoutineMouseTimeout(PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2)
{
PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)DeferredContext;
KIRQL Irql;
Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
DPRINT1("Mouse initialization timeout! (substate %x) "
"Disabling mouse.\n",
DevExt->MouseResetState);
if (!I8042MouseDisable(DevExt)) {
DPRINT1("Failed to disable mouse.\n");
}
DevExt->MouseExists = FALSE;
KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
}
/*
* Process the mouse internal device requests
* returns FALSE if it doesn't understand the
* call so someone else can handle it.
*/
#if 0
static BOOLEAN STDCALL I8042StartIoMouse(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION Stk;
PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
Stk = IoGetCurrentIrpStackLocation(Irp);
switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
I8042StartPacket(
DevExt,
DeviceObject,
Stk->Parameters.DeviceIoControl.Type3InputBuffer,
Stk->Parameters.DeviceIoControl.InputBufferLength,
Irp);
break;
default:
return FALSE;
}
return TRUE;
}
#endif
/*
* Runs the mouse IOCTL_INTERNAL dispatch.
* Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
* so someone else can have a try at it.
*/
NTSTATUS STDCALL I8042InternalDeviceControlMouse(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION Stk;
PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
DPRINT("InternalDeviceControl\n");
Irp->IoStatus.Information = 0;
Stk = IoGetCurrentIrpStackLocation(Irp);
switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_INTERNAL_MOUSE_CONNECT:
DPRINT("IOCTL_INTERNAL_MOUSE_CONNECT\n");
if (Stk->Parameters.DeviceIoControl.InputBufferLength <
sizeof(CONNECT_DATA)) {
DPRINT1("Mouse IOCTL_INTERNAL_MOUSE_CONNECT "
"invalid buffer size\n");
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
goto intcontfailure;
}
if (!DevExt->MouseExists) {
Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
goto intcontfailure;
}
if (DevExt->MouseClaimed) {
DPRINT1("IOCTL_INTERNAL_MOUSE_CONNECT: "
"Mouse is already claimed\n");
Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
goto intcontfailure;
}
memcpy(&DevExt->MouseData,
Stk->Parameters.DeviceIoControl.Type3InputBuffer,
sizeof(CONNECT_DATA));
DevExt->MouseHook.IsrWritePort = I8042IsrWritePortMouse;
DevExt->MouseHook.QueueMousePacket =
I8042QueueMousePacket;
DevExt->MouseHook.CallContext = DevExt;
{
PIO_WORKITEM WorkItem;
PI8042_HOOK_WORKITEM WorkItemData;
WorkItem = IoAllocateWorkItem(DeviceObject);
if (!WorkItem) {
DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
"Can't allocate work item\n");
Irp->IoStatus.Status =
STATUS_INSUFFICIENT_RESOURCES;
goto intcontfailure;
}
WorkItemData = ExAllocatePoolWithTag(
NonPagedPool,
sizeof(I8042_HOOK_WORKITEM),
TAG_I8042);
if (!WorkItemData) {
DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
"Can't allocate work item data\n");
Irp->IoStatus.Status =
STATUS_INSUFFICIENT_RESOURCES;
IoFreeWorkItem(WorkItem);
goto intcontfailure;
}
WorkItemData->WorkItem = WorkItem;
WorkItemData->Target =
DevExt->MouseData.ClassDeviceObject;
WorkItemData->Irp = Irp;
IoMarkIrpPending(Irp);
DevExt->MouseState = MouseResetting;
DevExt->MouseResetState = 1100;
IoQueueWorkItem(WorkItem,
I8042SendHookWorkItem,
DelayedWorkQueue,
WorkItemData);
Irp->IoStatus.Status = STATUS_PENDING;
}
break;
case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
DPRINT("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER\n");
if (Stk->Parameters.DeviceIoControl.InputBufferLength < 1) {
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
goto intcontfailure;
}
if (!DevExt->MouseInterruptObject) {
Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
goto intcontfailure;
}
IoMarkIrpPending(Irp);
IoStartPacket(DeviceObject, Irp, NULL, NULL);
Irp->IoStatus.Status = STATUS_PENDING;
break;
case IOCTL_MOUSE_QUERY_ATTRIBUTES:
DPRINT("IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
if (Stk->Parameters.DeviceIoControl.InputBufferLength <
sizeof(MOUSE_ATTRIBUTES)) {
DPRINT("Mouse IOCTL_MOUSE_QUERY_ATTRIBUTES "
"invalid buffer size\n");
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
goto intcontfailure;
}
memcpy(Irp->AssociatedIrp.SystemBuffer,
&DevExt->MouseAttributes,
sizeof(MOUSE_ATTRIBUTES));
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
default:
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
intcontfailure:
return Irp->IoStatus.Status;
}
BOOLEAN STDCALL I8042MouseEnable(PDEVICE_EXTENSION DevExt)
{
UCHAR Value;
NTSTATUS Status;
DPRINT("Enabling mouse\n");
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 &= ~(0x20); // don't disable mouse
Value |= 0x02; // enable 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;
}
return TRUE;
}
BOOLEAN STDCALL I8042MouseDisable(PDEVICE_EXTENSION DevExt)
{
UCHAR Value;
NTSTATUS Status;
DPRINT("Disabling mouse\n");
I8042Flush(); /* Just to be (kind of) sure */
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 |= 0x20; // don't disable mouse
Value &= ~(0x02); // enable 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;
}
I8042Flush();
/* Just to be (kind of) sure; if the mouse would
* say something while we are disabling it, these bytes would
* block the keyboard.
*/
return TRUE;
}
BOOLEAN STDCALL I8042DetectMouse(PDEVICE_EXTENSION DevExt)
{
BOOLEAN Ok = TRUE;
NTSTATUS Status;
UCHAR Value;
UCHAR ExpectedReply[] = { 0xFA, 0xAA, 0x00 };
unsigned ReplyByte;
ULONG Counter;
I8042Flush();
if (! I8042Write(DevExt, I8042_CTRL_PORT, 0xD4) ||
! I8042Write(DevExt, I8042_DATA_PORT, 0xFF))
{
DPRINT1("Failed to write reset command to mouse\n");
Ok = FALSE;
}
for (ReplyByte = 0;
ReplyByte < sizeof(ExpectedReply) / sizeof(ExpectedReply[0]) && Ok;
ReplyByte++)
{
Counter = 500;
do {
Status = I8042ReadDataWait(DevExt, &Value);
} while (Status == STATUS_IO_TIMEOUT && Counter--);
if (! NT_SUCCESS(Status))
{
DPRINT1("No ACK after mouse reset, status 0x%08x\n",
Status);
Ok = FALSE;
}
else if (Value != ExpectedReply[ReplyByte])
{
DPRINT1("Unexpected reply: 0x%02x (expected 0x%02x)\n",
Value, ExpectedReply[ReplyByte]);
Ok = FALSE;
}
}
if (! Ok)
{
/* There is probably no mouse present. On some systems,
the probe locks the entire keyboard controller. Let's
try to get access to the keyboard again by sending a
reset */
I8042Flush();
I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST);
I8042ReadDataWait(DevExt, &Value);
I8042Flush();
}
DPRINT("Mouse %sdetected\n", Ok ? "" : "not ");
return Ok;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -