Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmouse.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: drivers/input/i8042prt/mouse.c 00005 * PURPOSE: Mouse specific functions 00006 * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com) 00007 Copyright Jason Filby (jasonfilby@yahoo.com) 00008 Copyright Martijn Vernooij (o112w8r02@sneakemail.com) 00009 Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org) 00010 Copyright 2008 Colin Finck (mail@colinfinck.de) 00011 */ 00012 00013 /* INCLUDES ****************************************************************/ 00014 00015 #include "i8042prt.h" 00016 00017 /* FUNCTIONS *****************************************************************/ 00018 00019 /* 00020 * These functions are callbacks for filter driver custom interrupt 00021 * service routines. 00022 */ 00023 static VOID NTAPI 00024 i8042MouIsrWritePort( 00025 IN PVOID Context, 00026 IN UCHAR Value) 00027 { 00028 PI8042_MOUSE_EXTENSION DeviceExtension; 00029 00030 DeviceExtension = (PI8042_MOUSE_EXTENSION)Context; 00031 00032 if (DeviceExtension->MouseHook.IsrWritePort != i8042MouIsrWritePort) 00033 { 00034 DeviceExtension->MouseHook.IsrWritePort( 00035 DeviceExtension->MouseHook.CallContext, 00036 Value); 00037 } 00038 else 00039 i8042IsrWritePort(DeviceExtension->Common.PortDeviceExtension, Value, CTRL_WRITE_MOUSE); 00040 } 00041 00042 static VOID NTAPI 00043 i8042MouQueuePacket( 00044 IN PVOID Context) 00045 { 00046 PI8042_MOUSE_EXTENSION DeviceExtension; 00047 00048 DeviceExtension = (PI8042_MOUSE_EXTENSION)Context; 00049 00050 DeviceExtension->MouseComplete = TRUE; 00051 DeviceExtension->MouseInBuffer++; 00052 if (DeviceExtension->MouseInBuffer >= DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize) 00053 { 00054 WARN_(I8042PRT, "Mouse buffer overflow\n"); 00055 DeviceExtension->MouseInBuffer--; 00056 } 00057 00058 TRACE_(I8042PRT, "Irq completes mouse packet\n"); 00059 KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL); 00060 } 00061 00062 VOID 00063 i8042MouHandle( 00064 IN PI8042_MOUSE_EXTENSION DeviceExtension, 00065 IN UCHAR Output) 00066 { 00067 PMOUSE_INPUT_DATA MouseInput; 00068 CHAR Scroll; 00069 00070 MouseInput = DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer; 00071 00072 switch (DeviceExtension->MouseState) 00073 { 00074 case MouseIdle: 00075 /* This bit should be 1, if not drop the packet, we 00076 * might be lucky and get in sync again 00077 */ 00078 if (!(Output & 8)) { 00079 WARN_(I8042PRT, "Bad input, dropping..\n"); 00080 return; 00081 } 00082 00083 MouseInput->Buttons = 0; 00084 MouseInput->RawButtons = 0; 00085 MouseInput->Flags = MOUSE_MOVE_RELATIVE; 00086 00087 /* Note how we ignore the overflow bits, like Windows 00088 * is said to do. There's no reasonable thing to do 00089 * anyway. 00090 */ 00091 00092 if (Output & 16) 00093 MouseInput->LastX = 1; 00094 else 00095 MouseInput->LastX = 0; 00096 if (Output & 32) 00097 MouseInput->LastY = 1; 00098 else 00099 MouseInput->LastY = 0; 00100 00101 if (Output & 1) 00102 MouseInput->RawButtons |= MOUSE_LEFT_BUTTON_DOWN; 00103 if (Output & 2) 00104 MouseInput->RawButtons |= MOUSE_RIGHT_BUTTON_DOWN; 00105 if (Output & 4) 00106 MouseInput->RawButtons |= MOUSE_MIDDLE_BUTTON_DOWN; 00107 00108 DeviceExtension->MouseState = XMovement; 00109 break; 00110 00111 case XMovement: 00112 if (MouseInput->LastX) 00113 MouseInput->LastX = (LONG) Output - 256; 00114 else 00115 MouseInput->LastX = Output; 00116 00117 DeviceExtension->MouseState = YMovement; 00118 break; 00119 00120 case YMovement: 00121 if (MouseInput->LastY) 00122 MouseInput->LastY = (LONG)Output - 256; 00123 else 00124 MouseInput->LastY = (LONG)Output; 00125 00126 /* Windows wants it the other way around */ 00127 MouseInput->LastY = -MouseInput->LastY; 00128 00129 if (DeviceExtension->MouseType == GenericPS2 || 00130 DeviceExtension->MouseType == Ps2pp) 00131 { 00132 i8042MouHandleButtons( 00133 DeviceExtension, 00134 MOUSE_LEFT_BUTTON_DOWN | 00135 MOUSE_RIGHT_BUTTON_DOWN | 00136 MOUSE_MIDDLE_BUTTON_DOWN); 00137 DeviceExtension->MouseHook.QueueMousePacket(DeviceExtension->MouseHook.CallContext); 00138 DeviceExtension->MouseState = MouseIdle; 00139 } 00140 else 00141 { 00142 DeviceExtension->MouseState = ZMovement; 00143 } 00144 break; 00145 00146 case ZMovement: 00147 Scroll = Output & 0x0f; 00148 if (Scroll & 8) 00149 Scroll |= 0xf0; 00150 00151 if (Scroll) 00152 { 00153 MouseInput->RawButtons |= MOUSE_WHEEL; 00154 MouseInput->ButtonData = (USHORT)(Scroll * -WHEEL_DELTA); 00155 } 00156 00157 if (DeviceExtension->MouseType == IntellimouseExplorer) 00158 { 00159 if (Output & 16) 00160 MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN; 00161 if (Output & 32) 00162 MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN; 00163 } 00164 i8042MouHandleButtons( 00165 DeviceExtension, 00166 MOUSE_LEFT_BUTTON_DOWN | 00167 MOUSE_RIGHT_BUTTON_DOWN | 00168 MOUSE_MIDDLE_BUTTON_DOWN | 00169 MOUSE_BUTTON_4_DOWN | 00170 MOUSE_BUTTON_5_DOWN); 00171 DeviceExtension->MouseHook.QueueMousePacket(DeviceExtension->MouseHook.CallContext); 00172 DeviceExtension->MouseState = MouseIdle; 00173 break; 00174 00175 default: 00176 ERR_(I8042PRT, "Unexpected state 0x%u!\n", DeviceExtension->MouseState); 00177 ASSERT(FALSE); 00178 } 00179 } 00180 00181 /* 00182 * Updates ButtonFlags according to RawButtons and a saved state; 00183 * Only takes in account the bits that are set in Mask 00184 */ 00185 VOID 00186 i8042MouHandleButtons( 00187 IN PI8042_MOUSE_EXTENSION DeviceExtension, 00188 IN USHORT Mask) 00189 { 00190 PMOUSE_INPUT_DATA MouseInput; 00191 USHORT NewButtonData; 00192 USHORT ButtonDiff; 00193 00194 MouseInput = DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer; 00195 NewButtonData = (USHORT)(MouseInput->RawButtons & Mask); 00196 ButtonDiff = (NewButtonData ^ DeviceExtension->MouseButtonState) & Mask; 00197 00198 /* Note that the defines are such: 00199 * MOUSE_LEFT_BUTTON_DOWN 1 00200 * MOUSE_LEFT_BUTTON_UP 2 00201 */ 00202 MouseInput->ButtonFlags |= (NewButtonData & ButtonDiff) | 00203 (((~(NewButtonData)) << 1) & (ButtonDiff << 1)) | 00204 (MouseInput->RawButtons & 0xfc00); 00205 00206 INFO_(I8042PRT, "Left raw/up/down: %u/%u/%u\n", 00207 MouseInput->RawButtons & MOUSE_LEFT_BUTTON_DOWN, 00208 MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN, 00209 MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_UP); 00210 00211 DeviceExtension->MouseButtonState = 00212 (DeviceExtension->MouseButtonState & ~Mask) | (NewButtonData & Mask); 00213 } 00214 00215 /* Does lastest initializations for the mouse. This method 00216 * is called just before connecting the interrupt. 00217 */ 00218 NTSTATUS 00219 i8042MouInitialize( 00220 IN PI8042_MOUSE_EXTENSION DeviceExtension) 00221 { 00222 NTSTATUS Status; 00223 UCHAR Value; 00224 00225 /* Enable the PS/2 mouse port */ 00226 i8042Write(DeviceExtension->Common.PortDeviceExtension, DeviceExtension->Common.PortDeviceExtension->ControlPort, MOUSE_ENAB); 00227 00228 /* Enable the mouse */ 00229 if(!i8042IsrWritePort(DeviceExtension->Common.PortDeviceExtension, MOU_ENAB, CTRL_WRITE_MOUSE)) 00230 { 00231 WARN_(I8042PRT, "Failed to enable mouse!\n"); 00232 return STATUS_IO_DEVICE_ERROR; 00233 } 00234 00235 Status = i8042ReadDataWait(DeviceExtension->Common.PortDeviceExtension, &Value); 00236 if (!NT_SUCCESS(Status)) 00237 { 00238 WARN_(I8042PRT, "Failed to read the response of MOU_ENAB, status 0x%08lx\n", Status); 00239 return Status; 00240 } 00241 00242 if(Value == MOUSE_ACK) 00243 { 00244 INFO_(I8042PRT, "Mouse was enabled successfully!\n"); 00245 return STATUS_SUCCESS; 00246 } 00247 00248 WARN_(I8042PRT, "Got 0x%02x instead of 0xFA\n", Value); 00249 return STATUS_IO_DEVICE_ERROR; 00250 } 00251 00252 static VOID NTAPI 00253 i8042MouDpcRoutine( 00254 IN PKDPC Dpc, 00255 IN PVOID DeferredContext, 00256 IN PVOID SystemArgument1, 00257 IN PVOID SystemArgument2) 00258 { 00259 PI8042_MOUSE_EXTENSION DeviceExtension; 00260 PPORT_DEVICE_EXTENSION PortDeviceExtension; 00261 ULONG MouseTransferred = 0; 00262 ULONG MouseInBufferCopy; 00263 KIRQL Irql; 00264 LARGE_INTEGER Timeout; 00265 00266 UNREFERENCED_PARAMETER(Dpc); 00267 UNREFERENCED_PARAMETER(SystemArgument1); 00268 UNREFERENCED_PARAMETER(SystemArgument2); 00269 00270 DeviceExtension = (PI8042_MOUSE_EXTENSION)DeferredContext; 00271 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension; 00272 00273 switch (DeviceExtension->MouseTimeoutState) 00274 { 00275 case TimeoutStart: 00276 { 00277 DeviceExtension->MouseTimeoutState = NoChange; 00278 if (DeviceExtension->MouseTimeoutActive && 00279 !KeCancelTimer(&DeviceExtension->TimerMouseTimeout)) 00280 { 00281 /* The timer fired already, give up */ 00282 DeviceExtension->MouseTimeoutActive = FALSE; 00283 return; 00284 } 00285 00286 Timeout.QuadPart = -15000000; /* 1.5 seconds, should be enough */ 00287 00288 KeSetTimer( 00289 &DeviceExtension->TimerMouseTimeout, 00290 Timeout, 00291 &DeviceExtension->DpcMouseTimeout); 00292 DeviceExtension->MouseTimeoutActive = TRUE; 00293 return; 00294 } 00295 00296 case TimeoutCancel: 00297 { 00298 DeviceExtension->MouseTimeoutState = NoChange; 00299 KeCancelTimer(&DeviceExtension->TimerMouseTimeout); 00300 DeviceExtension->MouseTimeoutActive = FALSE; 00301 } 00302 00303 default: 00304 ;/* nothing, don't want a warning */ 00305 } 00306 00307 /* Should be unlikely */ 00308 if (!DeviceExtension->MouseComplete) 00309 return; 00310 00311 Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt); 00312 00313 DeviceExtension->MouseComplete = FALSE; 00314 MouseInBufferCopy = DeviceExtension->MouseInBuffer; 00315 00316 KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql); 00317 00318 TRACE_(I8042PRT, "Send a mouse packet\n"); 00319 00320 if (!DeviceExtension->MouseData.ClassService) 00321 return; 00322 00323 INFO_(I8042PRT, "Sending %lu mouse move(s)\n", MouseInBufferCopy); 00324 (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->MouseData.ClassService)( 00325 DeviceExtension->MouseData.ClassDeviceObject, 00326 DeviceExtension->MouseBuffer, 00327 DeviceExtension->MouseBuffer + MouseInBufferCopy, 00328 &MouseTransferred); 00329 00330 Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt); 00331 DeviceExtension->MouseInBuffer -= MouseTransferred; 00332 if (DeviceExtension->MouseInBuffer) 00333 RtlMoveMemory( 00334 DeviceExtension->MouseBuffer, 00335 DeviceExtension->MouseBuffer + MouseTransferred, 00336 DeviceExtension->MouseInBuffer * sizeof(MOUSE_INPUT_DATA)); 00337 KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql); 00338 } 00339 00340 /* This timer DPC will be called when the mouse reset times out. 00341 * I'll just send the 'disable mouse port' command to the controller 00342 * and say the mouse doesn't exist. 00343 */ 00344 static VOID NTAPI 00345 i8042DpcRoutineMouseTimeout( 00346 IN PKDPC Dpc, 00347 IN PVOID DeferredContext, 00348 IN PVOID SystemArgument1, 00349 IN PVOID SystemArgument2) 00350 { 00351 PI8042_MOUSE_EXTENSION DeviceExtension; 00352 PPORT_DEVICE_EXTENSION PortDeviceExtension; 00353 KIRQL Irql; 00354 00355 UNREFERENCED_PARAMETER(Dpc); 00356 UNREFERENCED_PARAMETER(SystemArgument1); 00357 UNREFERENCED_PARAMETER(SystemArgument2); 00358 00359 DeviceExtension = (PI8042_MOUSE_EXTENSION)DeferredContext; 00360 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension; 00361 00362 Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt); 00363 00364 WARN_(I8042PRT, "Mouse initialization timeout! (substate %x)\n", 00365 DeviceExtension->MouseResetState); 00366 00367 PortDeviceExtension->Flags &= ~MOUSE_PRESENT; 00368 00369 KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql); 00370 } 00371 00372 /* 00373 * Runs the mouse IOCTL_INTERNAL dispatch. 00374 */ 00375 NTSTATUS NTAPI 00376 i8042MouInternalDeviceControl( 00377 IN PDEVICE_OBJECT DeviceObject, 00378 IN PIRP Irp) 00379 { 00380 PIO_STACK_LOCATION Stack; 00381 PI8042_MOUSE_EXTENSION DeviceExtension; 00382 NTSTATUS Status; 00383 00384 Stack = IoGetCurrentIrpStackLocation(Irp); 00385 Irp->IoStatus.Information = 0; 00386 DeviceExtension = (PI8042_MOUSE_EXTENSION)DeviceObject->DeviceExtension; 00387 00388 switch (Stack->Parameters.DeviceIoControl.IoControlCode) 00389 { 00390 case IOCTL_INTERNAL_MOUSE_CONNECT: 00391 { 00392 SIZE_T Size; 00393 PIO_WORKITEM WorkItem = NULL; 00394 PI8042_HOOK_WORKITEM WorkItemData = NULL; 00395 00396 TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_CONNECT\n"); 00397 if (Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(CONNECT_DATA)) 00398 { 00399 Status = STATUS_INVALID_PARAMETER; 00400 goto cleanup; 00401 } 00402 00403 DeviceExtension->MouseData = 00404 *((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer); 00405 00406 /* Send IOCTL_INTERNAL_I8042_HOOK_MOUSE to device stack */ 00407 WorkItem = IoAllocateWorkItem(DeviceObject); 00408 if (!WorkItem) 00409 { 00410 WARN_(I8042PRT, "IoAllocateWorkItem() failed\n"); 00411 Status = STATUS_INSUFFICIENT_RESOURCES; 00412 goto cleanup; 00413 } 00414 WorkItemData = ExAllocatePoolWithTag( 00415 NonPagedPool, 00416 sizeof(I8042_HOOK_WORKITEM), 00417 I8042PRT_TAG); 00418 if (!WorkItemData) 00419 { 00420 WARN_(I8042PRT, "ExAllocatePoolWithTag() failed\n"); 00421 Status = STATUS_NO_MEMORY; 00422 goto cleanup; 00423 } 00424 WorkItemData->WorkItem = WorkItem; 00425 WorkItemData->Irp = Irp; 00426 00427 /* Initialize extension */ 00428 DeviceExtension->Common.Type = Mouse; 00429 Size = DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize * sizeof(MOUSE_INPUT_DATA); 00430 DeviceExtension->MouseBuffer = ExAllocatePoolWithTag( 00431 NonPagedPool, 00432 Size, 00433 I8042PRT_TAG); 00434 if (!DeviceExtension->MouseBuffer) 00435 { 00436 WARN_(I8042PRT, "ExAllocatePoolWithTag() failed\n"); 00437 Status = STATUS_NO_MEMORY; 00438 goto cleanup; 00439 } 00440 RtlZeroMemory(DeviceExtension->MouseBuffer, Size); 00441 DeviceExtension->MouseAttributes.InputDataQueueLength = 00442 DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize; 00443 KeInitializeDpc( 00444 &DeviceExtension->DpcMouse, 00445 i8042MouDpcRoutine, 00446 DeviceExtension); 00447 KeInitializeDpc( 00448 &DeviceExtension->DpcMouseTimeout, 00449 i8042DpcRoutineMouseTimeout, 00450 DeviceExtension); 00451 KeInitializeTimer(&DeviceExtension->TimerMouseTimeout); 00452 DeviceExtension->Common.PortDeviceExtension->MouseExtension = DeviceExtension; 00453 DeviceExtension->Common.PortDeviceExtension->Flags |= MOUSE_CONNECTED; 00454 00455 IoMarkIrpPending(Irp); 00456 DeviceExtension->MouseState = MouseResetting; 00457 DeviceExtension->MouseResetState = ExpectingReset; 00458 DeviceExtension->MouseHook.IsrWritePort = i8042MouIsrWritePort; 00459 DeviceExtension->MouseHook.QueueMousePacket = i8042MouQueuePacket; 00460 DeviceExtension->MouseHook.CallContext = DeviceExtension; 00461 IoQueueWorkItem(WorkItem, 00462 i8042SendHookWorkItem, 00463 DelayedWorkQueue, 00464 WorkItemData); 00465 Status = STATUS_PENDING; 00466 break; 00467 00468 cleanup: 00469 if (DeviceExtension->MouseBuffer) 00470 ExFreePoolWithTag(DeviceExtension->MouseBuffer, I8042PRT_TAG); 00471 if (WorkItem) 00472 IoFreeWorkItem(WorkItem); 00473 if (WorkItemData) 00474 ExFreePoolWithTag(WorkItemData, I8042PRT_TAG); 00475 break; 00476 } 00477 case IOCTL_INTERNAL_MOUSE_DISCONNECT: 00478 { 00479 TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_DISCONNECT\n"); 00480 /* MSDN says that operation is to implemented. 00481 * To implement it, we just have to do: 00482 * DeviceExtension->MouseData.ClassService = NULL; 00483 */ 00484 Status = STATUS_NOT_IMPLEMENTED; 00485 break; 00486 } 00487 case IOCTL_INTERNAL_I8042_HOOK_MOUSE: 00488 { 00489 PINTERNAL_I8042_HOOK_MOUSE MouseHook; 00490 TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_MOUSE\n"); 00491 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(INTERNAL_I8042_HOOK_MOUSE)) 00492 { 00493 Status = STATUS_INVALID_PARAMETER; 00494 break; 00495 } 00496 MouseHook = (PINTERNAL_I8042_HOOK_MOUSE)Stack->Parameters.DeviceIoControl.Type3InputBuffer; 00497 00498 DeviceExtension->MouseHook.Context = MouseHook->Context; 00499 if (MouseHook->IsrRoutine) 00500 DeviceExtension->MouseHook.IsrRoutine = MouseHook->IsrRoutine; 00501 00502 Status = STATUS_SUCCESS; 00503 break; 00504 } 00505 case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER: 00506 { 00507 DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER not implemented\n"); 00508 Status = STATUS_NOT_IMPLEMENTED; 00509 break; 00510 } 00511 case IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION: 00512 { 00513 DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION not implemented\n"); 00514 Status = STATUS_NOT_IMPLEMENTED; 00515 break; 00516 } 00517 case IOCTL_MOUSE_QUERY_ATTRIBUTES: 00518 { 00519 TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_MOUSE_QUERY_ATTRIBUTES\n"); 00520 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES)) 00521 { 00522 Status = STATUS_BUFFER_TOO_SMALL; 00523 break; 00524 } 00525 00526 *(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer = DeviceExtension->MouseAttributes; 00527 Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES); 00528 Status = STATUS_SUCCESS; 00529 break; 00530 } 00531 default: 00532 { 00533 ERR_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n", 00534 Stack->Parameters.DeviceIoControl.IoControlCode); 00535 ASSERT(FALSE); 00536 return ForwardIrpAndForget(DeviceObject, Irp); 00537 } 00538 } 00539 00540 Irp->IoStatus.Status = Status; 00541 if (Status != STATUS_PENDING) 00542 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00543 return Status; 00544 } 00545 00546 /* Test if packets are taking too long to come in. If they do, we 00547 * might have gotten out of sync and should just drop what we have. 00548 * 00549 * If we want to be totally right, we'd also have to keep a count of 00550 * errors, and totally reset the mouse after too much of them (can 00551 * happen if the user is using a KVM switch and an OS on another port 00552 * resets the mouse, or if the user hotplugs the mouse, or if we're just 00553 * generally unlucky). Also note the input parsing routine where we 00554 * drop invalid input packets. 00555 */ 00556 static VOID 00557 i8042MouInputTestTimeout( 00558 IN PI8042_MOUSE_EXTENSION DeviceExtension) 00559 { 00560 ULARGE_INTEGER Now; 00561 00562 if (DeviceExtension->MouseState == MouseExpectingACK || 00563 DeviceExtension->MouseState == MouseResetting) 00564 return; 00565 00566 Now.QuadPart = KeQueryInterruptTime(); 00567 00568 if (DeviceExtension->MouseState != MouseIdle) { 00569 /* Check if the last byte came too long ago */ 00570 if (Now.QuadPart - DeviceExtension->MousePacketStartTime.QuadPart > 00571 DeviceExtension->Common.PortDeviceExtension->Settings.MouseSynchIn100ns) 00572 { 00573 WARN_(I8042PRT, "Mouse input packet timeout\n"); 00574 DeviceExtension->MouseState = MouseIdle; 00575 } 00576 } 00577 00578 if (DeviceExtension->MouseState == MouseIdle) 00579 DeviceExtension->MousePacketStartTime.QuadPart = Now.QuadPart; 00580 } 00581 00582 /* 00583 * Call the customization hook. The ToReturn parameter is about wether 00584 * we should go on with the interrupt. The return value is what 00585 * we should return (indicating to the system wether someone else 00586 * should try to handle the interrupt) 00587 */ 00588 static BOOLEAN 00589 i8042MouCallIsrHook( 00590 IN PI8042_MOUSE_EXTENSION DeviceExtension, 00591 IN UCHAR Status, 00592 IN UCHAR Input, 00593 OUT PBOOLEAN ToReturn) 00594 { 00595 BOOLEAN HookReturn, HookContinue; 00596 00597 HookContinue = FALSE; 00598 00599 if (DeviceExtension->MouseHook.IsrRoutine) 00600 { 00601 HookReturn = DeviceExtension->MouseHook.IsrRoutine( 00602 DeviceExtension->MouseHook.Context, 00603 DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer, 00604 &DeviceExtension->Common.PortDeviceExtension->Packet, 00605 Status, 00606 &Input, 00607 &HookContinue, 00608 &DeviceExtension->MouseState, 00609 &DeviceExtension->MouseResetState); 00610 00611 if (!HookContinue) 00612 { 00613 *ToReturn = HookReturn; 00614 return TRUE; 00615 } 00616 } 00617 return FALSE; 00618 } 00619 00620 static BOOLEAN 00621 i8042MouResetIsr( 00622 IN PI8042_MOUSE_EXTENSION DeviceExtension, 00623 IN UCHAR Status, 00624 IN UCHAR Value) 00625 { 00626 PPORT_DEVICE_EXTENSION PortDeviceExtension; 00627 BOOLEAN ToReturn = FALSE; 00628 00629 if (i8042MouCallIsrHook(DeviceExtension, Status, Value, &ToReturn)) 00630 return ToReturn; 00631 00632 if (MouseIdle == DeviceExtension->MouseState) 00633 { 00634 /* Magic packet value that indicates a reset */ 00635 if (0xAA == Value) 00636 { 00637 WARN_(I8042PRT, "Hot plugged mouse!\n"); 00638 DeviceExtension->MouseState = MouseResetting; 00639 DeviceExtension->MouseResetState = ExpectingReset; 00640 } 00641 else 00642 return FALSE; 00643 } 00644 else if (MouseResetting != DeviceExtension->MouseState) 00645 return FALSE; 00646 00647 DeviceExtension->MouseTimeoutState = TimeoutStart; 00648 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension; 00649 00650 switch ((ULONG)DeviceExtension->MouseResetState) 00651 { 00652 case ExpectingReset: 00653 if (MOUSE_ACK == Value) 00654 { 00655 WARN_(I8042PRT, "Dropping extra ACK\n"); 00656 return TRUE; 00657 } 00658 00659 /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok, FC00 if not. */ 00660 if (0xAA == Value) 00661 { 00662 DeviceExtension->MouseResetState++; 00663 } 00664 else 00665 { 00666 PortDeviceExtension->Flags &= ~MOUSE_PRESENT; 00667 DeviceExtension->MouseState = MouseIdle; 00668 WARN_(I8042PRT, "Mouse returned bad reset reply: %x (expected aa)\n", Value); 00669 } 00670 return TRUE; 00671 case ExpectingResetId: 00672 if (MOUSE_ACK == Value) 00673 { 00674 WARN_(I8042PRT, "Dropping extra ACK #2\n"); 00675 return TRUE; 00676 } 00677 00678 if (0x00 == Value) 00679 { 00680 DeviceExtension->MouseResetState++; 00681 DeviceExtension->MouseType = GenericPS2; 00682 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF2); 00683 } 00684 else 00685 { 00686 PortDeviceExtension->Flags &= ~MOUSE_PRESENT; 00687 DeviceExtension->MouseState = MouseIdle; 00688 WARN_(I8042PRT, "Mouse returned bad reset reply part two: %x (expected 0)\n", Value); 00689 } 00690 return TRUE; 00691 case ExpectingGetDeviceIdACK: 00692 if (MOUSE_ACK == Value) 00693 { 00694 DeviceExtension->MouseResetState++; 00695 } 00696 else if (MOUSE_NACK == Value || MOUSE_ERROR == Value) 00697 { 00698 DeviceExtension->MouseResetState++; 00699 /* Act as if 00 (normal mouse) was received */ 00700 WARN_(I8042PRT, "Mouse doesn't support 0xd2, (returns %x, expected %x), faking\n", Value, MOUSE_ACK); 00701 i8042MouResetIsr(DeviceExtension, Status, 0); 00702 } 00703 return TRUE; 00704 case ExpectingGetDeviceIdValue: 00705 switch (Value) 00706 { 00707 case 0x02: 00708 DeviceExtension->MouseAttributes.MouseIdentifier = 00709 BALLPOINT_I8042_HARDWARE; 00710 break; 00711 case 0x03: 00712 case 0x04: 00713 DeviceExtension->MouseAttributes.MouseIdentifier = 00714 WHEELMOUSE_I8042_HARDWARE; 00715 break; 00716 default: 00717 DeviceExtension->MouseAttributes.MouseIdentifier = 00718 MOUSE_I8042_HARDWARE; 00719 } 00720 DeviceExtension->MouseResetState++; 00721 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE8); 00722 return TRUE; 00723 case ExpectingSetResolutionDefaultACK: 00724 DeviceExtension->MouseResetState++; 00725 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x00); 00726 return TRUE; 00727 case ExpectingSetResolutionDefaultValueACK: 00728 DeviceExtension->MouseResetState = ExpectingSetScaling1to1ACK; 00729 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE6); 00730 return TRUE; 00731 case ExpectingSetScaling1to1ACK: 00732 case ExpectingSetScaling1to1ACK2: 00733 DeviceExtension->MouseResetState++; 00734 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE6); 00735 return TRUE; 00736 case ExpectingSetScaling1to1ACK3: 00737 DeviceExtension->MouseResetState++; 00738 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE9); 00739 return TRUE; 00740 case ExpectingReadMouseStatusACK: 00741 DeviceExtension->MouseResetState++; 00742 return TRUE; 00743 case ExpectingReadMouseStatusByte1: 00744 DeviceExtension->MouseLogiBuffer[0] = Value; 00745 DeviceExtension->MouseResetState++; 00746 return TRUE; 00747 case ExpectingReadMouseStatusByte2: 00748 DeviceExtension->MouseLogiBuffer[1] = Value; 00749 DeviceExtension->MouseResetState++; 00750 return TRUE; 00751 case ExpectingReadMouseStatusByte3: 00752 DeviceExtension->MouseLogiBuffer[2] = Value; 00753 /* Now MouseLogiBuffer is a set of info. If the second 00754 * byte is 0, the mouse didn't understand the magic 00755 * code. Otherwise, it it a Logitech and the second byte 00756 * is the number of buttons, bit 7 of the first byte tells 00757 * if it understands special E7 commands, the rest is an ID. 00758 */ 00759 if (DeviceExtension->MouseLogiBuffer[1]) 00760 { 00761 DeviceExtension->MouseAttributes.NumberOfButtons = 00762 DeviceExtension->MouseLogiBuffer[1]; 00763 DeviceExtension->MouseType = Ps2pp; 00764 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3); 00765 DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK; 00766 /* TODO: Go through EnableWheel and Enable5Buttons */ 00767 return TRUE; 00768 } 00769 DeviceExtension->MouseResetState = EnableWheel; 00770 i8042MouResetIsr(DeviceExtension, Status, Value); 00771 return TRUE; 00772 case EnableWheel: 00773 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3); 00774 DeviceExtension->MouseResetState = 1001; 00775 return TRUE; 00776 case 1001: 00777 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xC8); 00778 DeviceExtension->MouseResetState++; 00779 return TRUE; 00780 case 1002: 00781 case 1004: 00782 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3); 00783 DeviceExtension->MouseResetState++; 00784 return TRUE; 00785 case 1003: 00786 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x64); 00787 DeviceExtension->MouseResetState++; 00788 return TRUE; 00789 case 1005: 00790 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x50); 00791 DeviceExtension->MouseResetState++; 00792 return TRUE; 00793 case 1006: 00794 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF2); 00795 DeviceExtension->MouseResetState++; 00796 return TRUE; 00797 case 1007: 00798 /* Ignore ACK */ 00799 DeviceExtension->MouseResetState++; 00800 return TRUE; 00801 case 1008: 00802 if (0x03 == Value) { 00803 /* It's either an Intellimouse or Intellimouse Explorer. */ 00804 DeviceExtension->MouseAttributes.NumberOfButtons = 3; 00805 DeviceExtension->MouseAttributes.MouseIdentifier = 00806 WHEELMOUSE_I8042_HARDWARE; 00807 DeviceExtension->MouseType = Intellimouse; 00808 DeviceExtension->MouseResetState = Enable5Buttons; 00809 i8042MouResetIsr(DeviceExtension, Status, Value); 00810 } 00811 else 00812 { 00813 /* Just set the default settings and be done */ 00814 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3); 00815 DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK; 00816 } 00817 return TRUE; 00818 case Enable5Buttons: 00819 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3); 00820 DeviceExtension->MouseResetState = 1021; 00821 return TRUE; 00822 case 1022: 00823 case 1024: 00824 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3); 00825 DeviceExtension->MouseResetState++; 00826 return TRUE; 00827 case 1021: 00828 case 1023: 00829 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xC8); 00830 DeviceExtension->MouseResetState++; 00831 return TRUE; 00832 case 1025: 00833 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x50); 00834 DeviceExtension->MouseResetState++; 00835 return TRUE; 00836 case 1026: 00837 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF2); 00838 DeviceExtension->MouseResetState++; 00839 return TRUE; 00840 case 1027: 00841 if (0x04 == Value) 00842 { 00843 DeviceExtension->MouseAttributes.NumberOfButtons = 5; 00844 DeviceExtension->MouseAttributes.MouseIdentifier = 00845 WHEELMOUSE_I8042_HARDWARE; 00846 DeviceExtension->MouseType = IntellimouseExplorer; 00847 } 00848 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3); 00849 DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK; 00850 return TRUE; 00851 case ExpectingSetSamplingRateACK: 00852 DeviceExtension->MouseHook.IsrWritePort( 00853 DeviceExtension->MouseHook.CallContext, 00854 (UCHAR)DeviceExtension->MouseAttributes.SampleRate); 00855 DeviceExtension->MouseResetState++; 00856 return TRUE; 00857 case ExpectingSetSamplingRateValueACK: 00858 if (MOUSE_NACK == Value) 00859 { 00860 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x3C); 00861 DeviceExtension->MouseAttributes.SampleRate = (USHORT)PortDeviceExtension->Settings.SampleRate; 00862 DeviceExtension->MouseResetState = 1040; 00863 return TRUE; 00864 } 00865 case 1040: /* Fallthrough */ 00866 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE8); 00867 DeviceExtension->MouseResetState = ExpectingFinalResolutionACK; 00868 return TRUE; 00869 case ExpectingFinalResolutionACK: 00870 DeviceExtension->MouseHook.IsrWritePort( 00871 DeviceExtension->MouseHook.CallContext, 00872 (UCHAR)(PortDeviceExtension->Settings.MouseResolution & 0xff)); 00873 INFO_(I8042PRT, "Mouse resolution %lu\n", 00874 PortDeviceExtension->Settings.MouseResolution); 00875 DeviceExtension->MouseResetState = ExpectingFinalResolutionValueACK; 00876 return TRUE; 00877 case ExpectingFinalResolutionValueACK: 00878 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF4); 00879 DeviceExtension->MouseResetState = ExpectingEnableACK; 00880 return TRUE; 00881 case ExpectingEnableACK: 00882 PortDeviceExtension->Flags |= MOUSE_PRESENT; 00883 DeviceExtension->MouseState = MouseIdle; 00884 DeviceExtension->MouseTimeoutState = TimeoutCancel; 00885 INFO_(I8042PRT, "Mouse type = %u\n", DeviceExtension->MouseType); 00886 return TRUE; 00887 default: 00888 if (DeviceExtension->MouseResetState < 100 || DeviceExtension->MouseResetState > 999) 00889 ERR_(I8042PRT, "MouseResetState went out of range: %lu\n", DeviceExtension->MouseResetState); 00890 return FALSE; 00891 } 00892 } 00893 00894 BOOLEAN NTAPI 00895 i8042MouInterruptService( 00896 IN PKINTERRUPT Interrupt, 00897 PVOID Context) 00898 { 00899 PI8042_MOUSE_EXTENSION DeviceExtension; 00900 PPORT_DEVICE_EXTENSION PortDeviceExtension; 00901 ULONG Counter; 00902 UCHAR Output = 0, PortStatus = 0; 00903 NTSTATUS Status; 00904 00905 UNREFERENCED_PARAMETER(Interrupt); 00906 00907 DeviceExtension = (PI8042_MOUSE_EXTENSION)Context; 00908 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension; 00909 Counter = PortDeviceExtension->Settings.PollStatusIterations; 00910 00911 while (Counter) 00912 { 00913 Status = i8042ReadStatus(PortDeviceExtension, &PortStatus); 00914 if (!NT_SUCCESS(Status)) 00915 { 00916 WARN_(I8042PRT, "i8042ReadStatus() failed with status 0x%08lx\n", Status); 00917 return FALSE; 00918 } 00919 Status = i8042ReadMouseData(PortDeviceExtension, &Output); 00920 if (NT_SUCCESS(Status)) 00921 break; 00922 KeStallExecutionProcessor(1); 00923 Counter--; 00924 } 00925 if (Counter == 0) 00926 { 00927 WARN_(I8042PRT, "Spurious i8042 mouse interrupt\n"); 00928 return FALSE; 00929 } 00930 00931 INFO_(I8042PRT, "Got: 0x%02x\n", Output); 00932 00933 if (i8042PacketIsr(PortDeviceExtension, Output)) 00934 { 00935 if (PortDeviceExtension->PacketComplete) 00936 { 00937 TRACE_(I8042PRT, "Packet complete\n"); 00938 KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL); 00939 } 00940 TRACE_(I8042PRT, "Irq eaten by packet\n"); 00941 return TRUE; 00942 } 00943 00944 TRACE_(I8042PRT, "Irq is mouse input\n"); 00945 00946 i8042MouInputTestTimeout(DeviceExtension); 00947 00948 if (i8042MouResetIsr(DeviceExtension, PortStatus, Output)) 00949 { 00950 TRACE_(I8042PRT, "Handled by ResetIsr or hooked Isr\n"); 00951 if (NoChange != DeviceExtension->MouseTimeoutState) { 00952 KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL); 00953 } 00954 return TRUE; 00955 } 00956 00957 if (DeviceExtension->MouseType == Ps2pp) 00958 i8042MouHandlePs2pp(DeviceExtension, Output); 00959 else 00960 i8042MouHandle(DeviceExtension, Output); 00961 00962 return TRUE; 00963 } Generated on Sat May 26 2012 04:16:00 for ReactOS by
1.7.6.1
|