2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2022 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/term.h>
21 #include <grub/misc.h>
22 #include <grub/types.h>
23 #include <grub/command.h>
24 #include <grub/i18n.h>
26 #include <grub/efi/efi.h>
27 #include <grub/efi/api.h>
29 GRUB_MOD_LICENSE ("GPLv3+");
31 #define GRUB_EFI_SIMPLE_POINTER_GUID \
32 { 0x31878c87, 0x0b75, 0x11d5, \
33 { 0x9a, 0x4f, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
41 grub_efi_boolean_t left
;
42 grub_efi_boolean_t right
;
43 } grub_efi_mouse_state
;
45 grub_efi_mouse_state no_move
= {0, 0, 0, 0, 0};
52 grub_efi_boolean_t left
;
53 grub_efi_boolean_t right
;
54 } grub_efi_mouse_mode
;
56 struct grub_efi_simple_pointer_protocol
58 grub_efi_status_t (*reset
) (struct grub_efi_simple_pointer_protocol
*this,
59 grub_efi_boolean_t extended_verification
);
60 grub_efi_status_t (*get_state
) (struct grub_efi_simple_pointer_protocol
*this,
61 grub_efi_mouse_state
*state
);
62 grub_efi_event_t
*wait_for_input
;
63 grub_efi_mouse_mode
*mode
;
65 typedef struct grub_efi_simple_pointer_protocol grub_efi_simple_pointer_protocol_t
;
69 grub_efi_uintn_t count
;
70 grub_efi_simple_pointer_protocol_t
**mouse
;
71 } grub_efi_mouse_prot_t
;
74 mouse_div (grub_int32_t a
, grub_uint64_t b
)
76 grub_int32_t s
= 1, q
, ret
;
85 q
= grub_divmod64 (n
, b
, NULL
);
86 ret
= s
* (q
> 0 ? q
: -q
);
90 static grub_efi_mouse_prot_t
*
91 grub_efi_mouse_prot_init (void)
93 grub_efi_status_t status
;
94 grub_efi_guid_t mouse_guid
= GRUB_EFI_SIMPLE_POINTER_GUID
;
95 grub_efi_mouse_prot_t
*mouse_input
= NULL
;
96 grub_efi_boot_services_t
*b
= grub_efi_system_table
->boot_services
;
97 grub_efi_handle_t
*buf
;
98 grub_efi_uintn_t count
;
101 status
= efi_call_5 (b
->locate_handle_buffer
, GRUB_EFI_BY_PROTOCOL
,
102 &mouse_guid
, NULL
, &count
, &buf
);
103 if (status
!= GRUB_EFI_SUCCESS
)
106 grub_printf ("ERROR: SimplePointerProtocol not found.\n");
111 mouse_input
= grub_malloc (sizeof (grub_efi_mouse_prot_t
));
114 mouse_input
->mouse
= grub_malloc (count
115 * sizeof (grub_efi_simple_pointer_protocol_t
*));
116 if (!mouse_input
->mouse
)
118 grub_free (mouse_input
);
121 mouse_input
->count
= count
;
122 for (i
= 0; i
< count
; i
++)
124 efi_call_3 (b
->handle_protocol
,
125 buf
[i
], &mouse_guid
, (void **)&mouse_input
->mouse
[i
]);
127 grub_printf ("%d %p ", (int)i
, mouse_input
->mouse
[i
]);
129 efi_call_2 (mouse_input
->mouse
[i
]->reset
, mouse_input
->mouse
[i
], 1);
132 ("[%"PRIuGRUB_UINT64_T
"] [%"PRIuGRUB_UINT64_T
"] [%"PRIuGRUB_UINT64_T
"]\n",
133 mouse_input
->mouse
[i
]->mode
->x
,
134 mouse_input
->mouse
[i
]->mode
->y
, mouse_input
->mouse
[i
]->mode
->z
);
141 grub_efi_mouse_input_init (struct grub_term_input
*term
)
143 grub_efi_mouse_prot_t
*mouse_input
= NULL
;
146 mouse_input
= grub_efi_mouse_prot_init ();
148 return GRUB_ERR_BAD_OS
;
150 term
->data
= (void *)mouse_input
;
156 grub_mouse_getkey (struct grub_term_input
*term
)
158 grub_efi_mouse_state cur
;
159 grub_efi_mouse_prot_t
*mouse
= term
->data
;
164 return GRUB_TERM_NO_KEY
;
165 for (i
= 0; i
< mouse
->count
; i
++)
167 efi_call_2 (mouse
->mouse
[i
]->get_state
, mouse
->mouse
[i
], &cur
);
168 if (grub_memcmp (&cur
, &no_move
, sizeof (grub_efi_mouse_state
)) != 0)
170 y
= mouse_div (cur
.y
, mouse
->mouse
[i
]->mode
->y
);
174 return GRUB_TERM_ESC
;
176 return GRUB_TERM_KEY_DOWN
;
178 return GRUB_TERM_KEY_UP
;
181 return GRUB_TERM_NO_KEY
;
186 grub_cmd_mouse_test (grub_command_t cmd
__attribute__ ((unused
)),
187 int argc
__attribute__ ((unused
)),
188 char **args
__attribute__ ((unused
)))
191 grub_efi_mouse_state cur
;
192 int x
= 0, y
= 0, z
= 0;
194 grub_efi_mouse_prot_t
*mouse
= NULL
;
196 mouse
= grub_efi_mouse_prot_init ();
198 return grub_error (GRUB_ERR_BAD_OS
, "mouse not found.\n");
199 grub_printf ("Press [1] to exit.\n");
202 if (grub_getkey_noblock () == '1')
204 for (i
= 0; i
< mouse
->count
; i
++)
206 efi_call_2 (mouse
->mouse
[i
]->get_state
, mouse
->mouse
[i
], &cur
);
207 if (grub_memcmp (&cur
, &no_move
, sizeof (grub_efi_mouse_state
)) != 0)
209 x
= mouse_div (cur
.x
, mouse
->mouse
[i
]->mode
->x
);
210 y
= mouse_div (cur
.y
, mouse
->mouse
[i
]->mode
->y
);
211 z
= mouse_div (cur
.z
, mouse
->mouse
[i
]->mode
->z
);
212 grub_printf ("[ID=%d] X=%d Y=%d Z=%d L=%d R=%d\n",
213 (int)i
, x
, y
, z
, cur
.left
, cur
.right
);
218 grub_free (mouse
->mouse
);
220 return GRUB_ERR_NONE
;
222 static grub_command_t cmd
;
225 static struct grub_term_input grub_mouse_term_input
=
228 .getkey
= grub_mouse_getkey
,
229 .init
= grub_efi_mouse_input_init
,
234 grub_term_register_input ("mouse", &grub_mouse_term_input
);
236 cmd
= grub_register_command ("mouse_test", grub_cmd_mouse_test
, 0,
237 N_("UEFI mouse test."));
243 grub_term_unregister_input (&grub_mouse_term_input
);
245 grub_unregister_command (cmd
);