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>
27 #include <grub/efi/efi.h>
28 #include <grub/efi/api.h>
30 GRUB_MOD_LICENSE ("GPLv3+");
32 #define GRUB_EFI_SIMPLE_POINTER_GUID \
33 { 0x31878c87, 0x0b75, 0x11d5, \
34 { 0x9a, 0x4f, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
42 grub_efi_boolean_t left
;
43 grub_efi_boolean_t right
;
44 } grub_efi_mouse_state
;
46 grub_efi_mouse_state no_move
= {0, 0, 0, 0, 0};
53 grub_efi_boolean_t left
;
54 grub_efi_boolean_t right
;
55 } grub_efi_mouse_mode
;
57 struct grub_efi_simple_pointer_protocol
59 grub_efi_status_t (*reset
) (struct grub_efi_simple_pointer_protocol
*this,
60 grub_efi_boolean_t extended_verification
);
61 grub_efi_status_t (*get_state
) (struct grub_efi_simple_pointer_protocol
*this,
62 grub_efi_mouse_state
*state
);
63 grub_efi_event_t
*wait_for_input
;
64 grub_efi_mouse_mode
*mode
;
66 typedef struct grub_efi_simple_pointer_protocol grub_efi_simple_pointer_protocol_t
;
70 grub_efi_uintn_t count
;
71 grub_efi_simple_pointer_protocol_t
**mouse
;
72 } grub_efi_mouse_prot_t
;
75 mouse_div (grub_int32_t a
, grub_uint64_t b
)
77 grub_int32_t s
= 1, q
, ret
;
86 q
= grub_divmod64 (n
, b
, NULL
);
87 ret
= s
* (q
> 0 ? q
: -q
);
91 static grub_efi_mouse_prot_t
*
92 grub_efi_mouse_prot_init (void)
94 grub_efi_status_t status
;
95 grub_efi_guid_t mouse_guid
= GRUB_EFI_SIMPLE_POINTER_GUID
;
96 grub_efi_mouse_prot_t
*mouse_input
= NULL
;
97 grub_efi_boot_services_t
*b
= grub_efi_system_table
->boot_services
;
98 grub_efi_handle_t
*buf
;
99 grub_efi_uintn_t count
;
102 status
= efi_call_5 (b
->locate_handle_buffer
, GRUB_EFI_BY_PROTOCOL
,
103 &mouse_guid
, NULL
, &count
, &buf
);
104 if (status
!= GRUB_EFI_SUCCESS
)
107 grub_printf ("ERROR: SimplePointerProtocol not found.\n");
112 mouse_input
= grub_malloc (sizeof (grub_efi_mouse_prot_t
));
115 mouse_input
->mouse
= grub_malloc (count
116 * sizeof (grub_efi_simple_pointer_protocol_t
*));
117 if (!mouse_input
->mouse
)
119 grub_free (mouse_input
);
122 mouse_input
->count
= count
;
123 for (i
= 0; i
< count
; i
++)
125 efi_call_3 (b
->handle_protocol
,
126 buf
[i
], &mouse_guid
, (void **)&mouse_input
->mouse
[i
]);
128 grub_printf ("%d %p ", (int)i
, mouse_input
->mouse
[i
]);
130 efi_call_2 (mouse_input
->mouse
[i
]->reset
, mouse_input
->mouse
[i
], 1);
133 ("[%"PRIuGRUB_UINT64_T
"] [%"PRIuGRUB_UINT64_T
"] [%"PRIuGRUB_UINT64_T
"]\n",
134 mouse_input
->mouse
[i
]->mode
->x
,
135 mouse_input
->mouse
[i
]->mode
->y
, mouse_input
->mouse
[i
]->mode
->z
);
142 grub_efi_mouse_input_init (struct grub_term_input
*term
)
144 grub_efi_mouse_prot_t
*mouse_input
= NULL
;
147 mouse_input
= grub_efi_mouse_prot_init ();
149 return GRUB_ERR_BAD_OS
;
151 term
->data
= (void *)mouse_input
;
157 grub_mouse_getkey (struct grub_term_input
*term
)
159 grub_efi_mouse_state cur
;
160 grub_efi_mouse_prot_t
*mouse
= term
->data
;
167 return GRUB_TERM_NO_KEY
;
169 env
= grub_env_get("mouse_delta");
171 delta
= (int)grub_strtol(env
, NULL
, 10);
173 for (i
= 0; i
< mouse
->count
; i
++)
175 efi_call_2 (mouse
->mouse
[i
]->get_state
, mouse
->mouse
[i
], &cur
);
176 if (grub_memcmp (&cur
, &no_move
, sizeof (grub_efi_mouse_state
)) != 0)
178 y
= mouse_div (cur
.y
, mouse
->mouse
[i
]->mode
->y
);
182 return GRUB_TERM_ESC
;
184 return GRUB_TERM_KEY_DOWN
;
186 return GRUB_TERM_KEY_UP
;
189 return GRUB_TERM_NO_KEY
;
194 grub_cmd_mouse_test (grub_command_t cmd
__attribute__ ((unused
)),
195 int argc
__attribute__ ((unused
)),
196 char **args
__attribute__ ((unused
)))
199 grub_efi_mouse_state cur
;
200 int x
= 0, y
= 0, z
= 0;
202 grub_efi_mouse_prot_t
*mouse
= NULL
;
204 mouse
= grub_efi_mouse_prot_init ();
206 return grub_error (GRUB_ERR_BAD_OS
, "mouse not found.\n");
207 grub_printf ("Press [1] to exit.\n");
210 if (grub_getkey_noblock () == '1')
212 for (i
= 0; i
< mouse
->count
; i
++)
214 efi_call_2 (mouse
->mouse
[i
]->get_state
, mouse
->mouse
[i
], &cur
);
215 if (grub_memcmp (&cur
, &no_move
, sizeof (grub_efi_mouse_state
)) != 0)
217 x
= mouse_div (cur
.x
, mouse
->mouse
[i
]->mode
->x
);
218 y
= mouse_div (cur
.y
, mouse
->mouse
[i
]->mode
->y
);
219 z
= mouse_div (cur
.z
, mouse
->mouse
[i
]->mode
->z
);
220 grub_printf ("[ID=%d] X=%d Y=%d Z=%d L=%d R=%d\n",
221 (int)i
, x
, y
, z
, cur
.left
, cur
.right
);
226 grub_free (mouse
->mouse
);
228 return GRUB_ERR_NONE
;
230 static grub_command_t cmd
;
233 static struct grub_term_input grub_mouse_term_input
=
236 .getkey
= grub_mouse_getkey
,
237 .init
= grub_efi_mouse_input_init
,
242 grub_term_register_input ("mouse", &grub_mouse_term_input
);
244 cmd
= grub_register_command ("mouse_test", grub_cmd_mouse_test
, 0,
245 N_("UEFI mouse test."));
251 grub_term_unregister_input (&grub_mouse_term_input
);
253 grub_unregister_command (cmd
);