OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
AIM.c
Go to the documentation of this file.
1
15#include <Uefi.h>
16
17#include "AIM.h"
18
19#include <Library/BaseMemoryLib.h>
20#include <Library/DebugLib.h>
21#include <Library/OcInputLib.h>
22#include <Library/UefiBootServicesTableLib.h>
23
25
26STATIC UINT8 gIndex = 0;
27STATIC UINT8 gXCounts[5] = { 0, 0, 0, 0, 0 };
28STATIC UINT8 gYCounts[5] = { 0, 0, 0, 0, 0 };
29
30UINT8
31EFIAPI
33 IN INT32 Value
34 )
35{
36 return (UINT8)(Value < 0 ? -Value : Value);
37}
38
39INT32
40EFIAPI
42 IN INT32 Value,
43 IN INT32 Min,
44 IN INT32 Max
45 )
46{
47 if (Value > Max) {
48 return Max;
49 } else if (Value < Min) {
50 return Min;
51 }
52
53 return Value;
54}
55
56VOID
57EFIAPI
59 IN OUT UINT8 *AbsX,
60 IN OUT UINT8 *AbsY,
61 IN OUT INT32 *X,
62 IN OUT INT32 *Y
63 )
64{
65 UINT8 Index;
66
67 if (*AbsX == 0) {
68 gXCounts[gIndex] = 1;
69 } else if (*AbsX <= 2) {
70 for (Index = 0; Index < 5; Index++) {
71 if (!gXCounts[Index]) {
72 break;
73 }
74 }
75
76 if (Index == 5) {
77 *AbsX = 0;
78 *X = 0;
79 }
80
81 gXCounts[gIndex] = 0;
82 }
83
84 if (*AbsY == 0) {
85 gYCounts[gIndex] = 1;
86 } else if (*AbsY <= 2) {
87 for (Index = 0; Index < 5; Index++) {
88 if (!gYCounts[Index]) {
89 break;
90 }
91 }
92
93 if (Index == 5) {
94 *AbsY = 0;
95 *Y = 0;
96 }
97
98 gYCounts[gIndex] = 0;
99 }
100
101 gIndex = gIndex < 4 ? gIndex + 1 : 0;
102}
103
104#ifdef AMI_SHIM_POINTER_AMI_SMOOTHING
105
106STATIC UINT8 gAbsRange[8] = { 42, 36, 30, 24, 18, 12, 6, 1 };
107STATIC INT32 gMultipliers[8] = { 8, 7, 6, 5, 4, 3, 2, 1 };
108STATIC INT32 gIndices[8] = { 2, 2, 2, 2, 2, 2, 2, 0 };
109
110INT32
111AmiShimPointerScale (
112 IN INT32 Value,
113 IN UINT8 AbsValue
114 )
115{
116 UINT8 TmpIndex;
117
118 for (TmpIndex = 0; TmpIndex < 8; TmpIndex++) {
119 if (AbsValue >= gAbsRange[TmpIndex]) {
120 break;
121 }
122 }
123
124 if (TmpIndex != 8) {
125 if (Value >= 0) {
126 Value = gIndices[TmpIndex] + Value * gMultipliers[TmpIndex];
127 } else {
128 Value = Value * gMultipliers[TmpIndex] - gIndices[TmpIndex];
129 }
130 }
131
132 return Value;
133}
134
135VOID
136EFIAPI
138 IN OUT INT32 *X,
139 IN OUT INT32 *Y,
140 IN OUT INT32 *Z
141 )
142{
143 UINT8 AbsX, AbsY;
144
145 *X = Clamp (*X, -16, 16);
146 *Y = Clamp (*Y, -16, 16);
147 // According to AMI it should not be reported
148 *Z = 0;
149 AbsX = Abs (*X);
150 AbsY = Abs (*Y);
151
152 if ((*X == 0) && (*Y == 0)) {
153 return;
154 }
155
156 AmiShimPointerFilterOut (&AbsX, &AbsY, X, Y);
157
158 *X = AmiShimPointerScale (*X, AbsX);
159 *Y = AmiShimPointerScale (*Y, AbsY);
160
161 *X *= AIM_SCALE_FACTOR;
162 *Y *= AIM_SCALE_FACTOR;
163}
164
165#else
166
167STATIC UINT8 gAbsRange[4] = { 80, 64, 48, 1 };
168STATIC INT32 gMultipliers[4] = { 4, 3, 2, 1 };
169
170VOID
171EFIAPI
173 IN OUT INT32 *Value,
174 IN INT32 AbsValue
175 )
176{
177 UINTN Index;
178
179 for (Index = 0; Index < 4; Index++) {
180 if (gAbsRange[Index] > AbsValue) {
181 *Value *= gMultipliers[Index];
182 return;
183 }
184 }
185}
186
187VOID
188EFIAPI
190 IN OUT INT32 *X,
191 IN OUT INT32 *Y,
192 IN OUT INT32 *Z
193 )
194{
195 UINT8 AbsX, AbsY;
196
197 *X = InternalClamp (*X, -96, 96);
198 *Y = InternalClamp (*Y, -96, 96);
199 *Z = 0;
200
201 AbsX = Abs (*X);
202 AbsY = Abs (*Y);
203
204 if ((*X == 0) && (*Y == 0)) {
205 return;
206 }
207
208 AmiShimPointerFilterOut (&AbsX, &AbsY, X, Y);
209
210 AmiShimPointerBoostValue (X, AbsX);
211 AmiShimPointerBoostValue (Y, AbsY);
212}
213
214#endif
215
216VOID
217EFIAPI
219 IN EFI_EVENT Event,
220 IN VOID *Context
221 )
222{
223 UINTN Index;
226
227 // Do not poll until somebody actually starts using the mouse
228 // Otherwise first move will be quite random
230 return;
231 }
232
233 // This is important to do quickly and separately, because AMI stores positioning data in INT8.
234 // If we move the mouse quickly it will overflow and return invalid data.
235 for (Index = 0; Index < AIM_MAX_POINTERS; Index++) {
236 Pointer = &mAmiShimPointer.PointerMap[Index];
237 if (Pointer->DeviceHandle != NULL) {
238 PositionState.Changed = 0;
239 Pointer->EfiPointer->GetPositionState (Pointer->EfiPointer, &PositionState);
240 if (PositionState.Changed == 1) {
241 if (PositionState.Absolute == 0) {
242 DEBUG ((
243 DEBUG_VERBOSE,
244 "Position: %d %d %d %d\n",
245 PositionState.Changed,
246 PositionState.PositionX,
247 PositionState.PositionY,
248 PositionState.PositionZ
249 ));
250 AmiShimPointerSmooth (&PositionState.PositionX, &PositionState.PositionY, &PositionState.PositionZ);
251 if ((PositionState.PositionX != 0) || (PositionState.PositionY != 0) || (PositionState.PositionZ != 0)) {
252 Pointer->PositionX += PositionState.PositionX;
253 Pointer->PositionY += PositionState.PositionY;
254 Pointer->PositionZ += PositionState.PositionZ;
255 Pointer->PositionChanged = TRUE;
256 }
257 } else {
258 // FIXME: Add support for devices with absolute positioning
259 }
260 }
261 }
262 }
263}
264
265EFI_STATUS
266EFIAPI
268 IN AMI_SHIM_POINTER_INSTANCE *Pointer,
269 OUT EFI_SIMPLE_POINTER_STATE *State
270 )
271{
273
277 }
278
279 ButtonState.Changed = 0;
280 Pointer->EfiPointer->GetButtonState (Pointer->EfiPointer, &ButtonState);
281
282 if ((ButtonState.Changed == 0) && (Pointer->PositionChanged == 0)) {
283 return EFI_NOT_READY;
284 }
285
286 DEBUG ((
287 DEBUG_VERBOSE,
288 "Button: %d %d %d %d, Position: %d %d %d %d\n",
289 ButtonState.Changed,
290 ButtonState.LeftButton,
291 ButtonState.MiddleButton,
292 ButtonState.RightButton,
293 Pointer->PositionChanged,
294 Pointer->PositionX,
295 Pointer->PositionY,
296 Pointer->PositionZ
297 ));
298
299 if (ButtonState.Changed) {
300 State->LeftButton = ButtonState.LeftButton;
301 State->RightButton = ButtonState.RightButton;
302 } else {
303 State->LeftButton = State->RightButton = FALSE;
304 }
305
306 if (Pointer->PositionChanged) {
307 State->RelativeMovementX = Pointer->PositionX;
308 State->RelativeMovementY = Pointer->PositionY;
309 State->RelativeMovementZ = Pointer->PositionZ;
310 } else {
311 State->RelativeMovementX = State->RelativeMovementY = State->RelativeMovementZ = 0;
312 }
313
314 Pointer->PositionChanged = 0;
315 Pointer->PositionX = Pointer->PositionY = Pointer->PositionZ = 0;
316
317 return EFI_SUCCESS;
318}
319
320EFI_STATUS
321EFIAPI
323 IN EFI_SIMPLE_POINTER_PROTOCOL *This,
324 IN OUT EFI_SIMPLE_POINTER_STATE *State
325 )
326{
327 EFI_STATUS Status;
328 UINTN Index;
330
331 if ((This == NULL) || (State == NULL)) {
332 return EFI_INVALID_PARAMETER;
333 }
334
335 for (Index = 0, Pointer = mAmiShimPointer.PointerMap; Index < AIM_MAX_POINTERS; Index++, Pointer++) {
336 if (Pointer->SimplePointer == This) {
337 break;
338 }
339 }
340
341 if (Index != AIM_MAX_POINTERS) {
342 Status = AmiShimPointerUpdateState (Pointer, State);
343
344 if (!EFI_ERROR (Status)) {
345 if ((State->RelativeMovementX != 0) ||
346 (State->RelativeMovementY != 0) ||
347 (State->RelativeMovementZ != 0))
348 {
349 DEBUG ((
350 DEBUG_VERBOSE,
351 "Received[%p] %d %d %d <%d, %d>\n",
352 This,
353 State->RelativeMovementX,
354 State->RelativeMovementY,
355 State->RelativeMovementZ,
356 State->LeftButton,
357 State->RightButton
358 ));
359 } else {
360 DEBUG ((DEBUG_VERBOSE, "Received[%p] %d %d %d\n", This, State->RelativeMovementX, State->RelativeMovementY, State->RelativeMovementZ));
361 }
362 }
363 } else {
364 DEBUG ((DEBUG_VERBOSE, "Received unknown this %p\n", This));
365 Status = EFI_INVALID_PARAMETER;
366 }
367
368 return Status;
369}
370
371EFI_STATUS
372EFIAPI
374 VOID
375 )
376{
377 EFI_STATUS Status;
378
380 return EFI_ALREADY_STARTED;
381 }
382
383 Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, AmiShimPointerPositionHandler, NULL, &mAmiShimPointer.PositionEvent);
384
385 if (EFI_ERROR (Status)) {
386 DEBUG ((DEBUG_INFO, "AmiShimPointerPositionHandler event creation failed %d\n", Status));
387 return Status;
388 }
389
390 Status = gBS->SetTimer (mAmiShimPointer.PositionEvent, TimerPeriodic, AIM_POSITION_POLL_INTERVAL);
391
392 if (EFI_ERROR (Status)) {
393 DEBUG ((DEBUG_INFO, "AmiShimPointerPositionHandler timer setting failed %d\n", Status));
394 gBS->CloseEvent (mAmiShimPointer.PositionEvent);
395 return Status;
396 }
397
399
400 return EFI_SUCCESS;
401}
402
403EFI_STATUS
404EFIAPI
406 VOID
407 )
408{
409 EFI_STATUS Status;
410
412 return EFI_SUCCESS;
413 }
414
415 if (mAmiShimPointer.PositionEvent != NULL) {
416 Status = gBS->SetTimer (mAmiShimPointer.PositionEvent, TimerCancel, 0);
417 if (!EFI_ERROR (Status)) {
418 gBS->CloseEvent (mAmiShimPointer.PositionEvent);
420 } else {
421 DEBUG ((DEBUG_INFO, "AmiShimPointerPositionHandler timer unsetting failed %d\n", Status));
422 }
423 }
424
426
427 return EFI_SUCCESS;
428}
429
430EFI_STATUS
431EFIAPI
433 IN EFI_HANDLE DeviceHandle,
434 IN AMI_EFIPOINTER_PROTOCOL *EfiPointer,
435 IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer
436 )
437{
438 UINTN Index;
440 AMI_SHIM_POINTER_INSTANCE *FreePointer;
441
442 FreePointer = NULL;
443
444 for (Index = 0; Index < AIM_MAX_POINTERS; Index++) {
445 Pointer = &mAmiShimPointer.PointerMap[Index];
446 if ((Pointer->DeviceHandle == NULL) && (FreePointer == NULL)) {
447 FreePointer = Pointer;
448 } else if (Pointer->DeviceHandle == DeviceHandle) {
449 return EFI_ALREADY_STARTED;
450 }
451 }
452
453 if (FreePointer == NULL) {
454 return EFI_OUT_OF_RESOURCES;
455 }
456
457 DEBUG ((DEBUG_INFO, "Installed onto %X\n", DeviceHandle));
458 FreePointer->DeviceHandle = DeviceHandle;
459 FreePointer->EfiPointer = EfiPointer;
460 FreePointer->SimplePointer = SimplePointer;
461 if (FreePointer->SimplePointer->GetState == AmiShimPointerGetState) {
462 FreePointer->OriginalGetState = NULL;
463 DEBUG ((DEBUG_INFO, "Function is already hooked\n"));
464 } else {
465 FreePointer->OriginalGetState = FreePointer->SimplePointer->GetState;
466 FreePointer->SimplePointer->GetState = AmiShimPointerGetState;
467 }
468
469 return EFI_SUCCESS;
470}
471
472EFI_STATUS
473EFIAPI
475 VOID
476 )
477{
478 EFI_STATUS Status;
479 UINTN NoHandles;
480 EFI_HANDLE *Handles;
481 UINTN Index;
482 BOOLEAN Installed;
483 AMI_EFIPOINTER_PROTOCOL *EfiPointer;
484 EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;
485
486 Status = gBS->LocateHandleBuffer (ByProtocol, &gAmiEfiPointerProtocolGuid, NULL, &NoHandles, &Handles);
487 if (EFI_ERROR (Status)) {
488 return EFI_NOT_FOUND;
489 }
490
491 DEBUG ((DEBUG_INFO, "Found %d Handles located by protocol\n", NoHandles));
492
493 Installed = FALSE;
494
495 for (Index = 0; Index < NoHandles; Index++) {
496 Status = gBS->HandleProtocol (Handles[Index], &gAmiEfiPointerProtocolGuid, (VOID **)&EfiPointer);
497 if (EFI_ERROR (Status)) {
498 DEBUG ((DEBUG_INFO, "Handle %d has no AmiEfiPointerl %d\n", Index, Status));
499 continue;
500 }
501
502 Status = gBS->HandleProtocol (Handles[Index], &gEfiSimplePointerProtocolGuid, (VOID **)&SimplePointer);
503 if (EFI_ERROR (Status)) {
504 DEBUG ((DEBUG_INFO, "Handle %d has no EfiSimplePointer %d\n", Index, Status));
505 continue;
506 }
507
508 Status = AmiShimPointerInstallOnHandle (Handles[Index], EfiPointer, SimplePointer);
509 if (EFI_ERROR (Status)) {
510 DEBUG ((DEBUG_INFO, "Handle %d failed to get installed %d\n", Index, Status));
511 continue;
512 }
513
514 Installed = TRUE;
515 }
516
517 gBS->FreePool (Handles);
518
519 if (!Installed) {
520 return EFI_NOT_FOUND;
521 }
522
524 return AmiShimPointerTimerSetup ();
525 }
526
527 return EFI_SUCCESS;
528}
529
530EFI_STATUS
531EFIAPI
533 VOID
534 )
535{
536 UINTN Index;
538
540
541 for (Index = 0; Index < AIM_MAX_POINTERS; Index++) {
542 Pointer = &mAmiShimPointer.PointerMap[Index];
543 if (Pointer->DeviceHandle != NULL) {
544 Pointer->SimplePointer->GetState = Pointer->OriginalGetState;
545 gBS->DisconnectController (Pointer->DeviceHandle, NULL, NULL);
546 Pointer->DeviceHandle = NULL;
547 }
548 }
549
550 return EFI_SUCCESS;
551}
552
553VOID
554EFIAPI
556 IN EFI_EVENT Event,
557 IN VOID *Context
558 )
559{
561}
562
563EFI_STATUS
566 )
567{
568 EFI_STATUS Status;
569 VOID *Registration;
570
571 //
572 // Currently, ASUS is the only supported mode, hence it is not verified.
573 // The caller is required to pass a valid mode.
574 //
575
576 Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, AmiShimPointerArriveHandler, NULL, &mAmiShimPointer.ProtocolArriveEvent);
577
578 if (EFI_ERROR (Status)) {
579 DEBUG ((DEBUG_INFO, "AmiShimPointerArriveHandler event creation failed %d\n", Status));
580 return Status;
581 }
582
583 // EfiSimplePointer gets installed after AMI proprietary protocol
584 Status = gBS->RegisterProtocolNotify (&gEfiSimplePointerProtocolGuid, mAmiShimPointer.ProtocolArriveEvent, &Registration);
585
586 if (EFI_ERROR (Status)) {
587 DEBUG ((DEBUG_INFO, "AmiShimProtocolArriveHandler protocol registration failed %d\n", Status));
589 return Status;
590 }
591
592 return AmiShimPointerInstall ();
593}
594
595EFI_STATUS
597 VOID
598 )
599{
600 return AmiShimPointerUninstall ();
601}
VOID EFIAPI AmiShimPointerArriveHandler(IN EFI_EVENT Event, IN VOID *Context)
Definition AIM.c:555
EFI_STATUS EFIAPI AmiShimPointerUpdateState(IN AMI_SHIM_POINTER_INSTANCE *Pointer, OUT EFI_SIMPLE_POINTER_STATE *State)
Definition AIM.c:267
EFI_STATUS EFIAPI AmiShimPointerTimerSetup(VOID)
Definition AIM.c:373
VOID EFIAPI AmiShimPointerSmooth(IN OUT INT32 *X, IN OUT INT32 *Y, IN OUT INT32 *Z)
Definition AIM.c:189
INT32 EFIAPI InternalClamp(IN INT32 Value, IN INT32 Min, IN INT32 Max)
Definition AIM.c:41
VOID EFIAPI AmiShimPointerFilterOut(IN OUT UINT8 *AbsX, IN OUT UINT8 *AbsY, IN OUT INT32 *X, IN OUT INT32 *Y)
Definition AIM.c:58
UINT8 EFIAPI Abs(IN INT32 Value)
Definition AIM.c:32
VOID EFIAPI AmiShimPointerPositionHandler(IN EFI_EVENT Event, IN VOID *Context)
Definition AIM.c:218
EFI_STATUS EFIAPI AmiShimPointerInstall(VOID)
Definition AIM.c:474
STATIC AMI_SHIM_POINTER mAmiShimPointer
Definition AIM.c:24
STATIC UINT8 gXCounts[5]
Definition AIM.c:27
EFI_STATUS OcAppleGenericInputPointerExit(VOID)
Definition AIM.c:596
EFI_STATUS EFIAPI AmiShimPointerGetState(IN EFI_SIMPLE_POINTER_PROTOCOL *This, IN OUT EFI_SIMPLE_POINTER_STATE *State)
Definition AIM.c:322
STATIC UINT8 gYCounts[5]
Definition AIM.c:28
STATIC UINT8 gAbsRange[4]
Definition AIM.c:167
STATIC INT32 gMultipliers[4]
Definition AIM.c:168
EFI_STATUS OcAppleGenericInputPointerInit(IN OC_INPUT_POINTER_MODE Mode)
Definition AIM.c:564
STATIC UINT8 gIndex
Definition AIM.c:26
EFI_STATUS EFIAPI AmiShimPointerTimerUninstall(VOID)
Definition AIM.c:405
EFI_STATUS EFIAPI AmiShimPointerInstallOnHandle(IN EFI_HANDLE DeviceHandle, IN AMI_EFIPOINTER_PROTOCOL *EfiPointer, IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer)
Definition AIM.c:432
VOID EFIAPI AmiShimPointerBoostValue(IN OUT INT32 *Value, IN INT32 AbsValue)
Definition AIM.c:172
EFI_STATUS EFIAPI AmiShimPointerUninstall(VOID)
Definition AIM.c:532
#define AIM_SCALE_FACTOR
Definition AIM.h:36
#define AIM_MAX_POINTERS
Definition AIM.h:25
#define AIM_POSITION_POLL_INTERVAL
Definition AIM.h:31
EFI_GUID gAmiEfiPointerProtocolGuid
EFI_BOOT_SERVICES * gBS
OC_INPUT_POINTER_MODE
Definition OcInputLib.h:18
EFI_GUID gEfiSimplePointerProtocolGuid
AMI_EFIPOINTER_GET_POSITION_STATE GetPositionState
Definition AmiPointer.h:79
EFI_HANDLE DeviceHandle
Definition AIM.h:39
BOOLEAN PositionChanged
Definition AIM.h:43
AMI_EFIPOINTER_PROTOCOL * EfiPointer
Definition AIM.h:40
EFI_SIMPLE_POINTER_PROTOCOL * SimplePointer
Definition AIM.h:41
EFI_SIMPLE_POINTER_GET_STATE OriginalGetState
Definition AIM.h:42
EFI_EVENT ProtocolArriveEvent
Definition AIM.h:52
EFI_EVENT PositionEvent
Definition AIM.h:53
BOOLEAN UsageStarted
Definition AIM.h:51
AMI_SHIM_POINTER_INSTANCE PointerMap[AIM_MAX_POINTERS]
Definition AIM.h:54
BOOLEAN TimersInitialised
Definition AIM.h:50