|
@@ -392,8 +392,23 @@ struct efi_simple_text_output_protocol efi_con_out = {
|
|
.mode = (void*)&efi_con_mode,
|
|
.mode = (void*)&efi_con_mode,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * struct efi_cin_notify_function - registered console input notify function
|
|
|
|
+ *
|
|
|
|
+ * @link: link to list
|
|
|
|
+ * @data: key to notify
|
|
|
|
+ * @function: function to call
|
|
|
|
+ */
|
|
|
|
+struct efi_cin_notify_function {
|
|
|
|
+ struct list_head link;
|
|
|
|
+ struct efi_key_data key;
|
|
|
|
+ efi_status_t (EFIAPI *function)
|
|
|
|
+ (struct efi_key_data *key_data);
|
|
|
|
+};
|
|
|
|
+
|
|
static bool key_available;
|
|
static bool key_available;
|
|
static struct efi_key_data next_key;
|
|
static struct efi_key_data next_key;
|
|
|
|
+static LIST_HEAD(cin_notify_functions);
|
|
|
|
|
|
/**
|
|
/**
|
|
* set_shift_mask() - set shift mask
|
|
* set_shift_mask() - set shift mask
|
|
@@ -597,6 +612,34 @@ static efi_status_t efi_cin_read_key(struct efi_key_data *key)
|
|
return EFI_SUCCESS;
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * efi_cin_notify() - notify registered functions
|
|
|
|
+ */
|
|
|
|
+static void efi_cin_notify(void)
|
|
|
|
+{
|
|
|
|
+ struct efi_cin_notify_function *item;
|
|
|
|
+
|
|
|
|
+ list_for_each_entry(item, &cin_notify_functions, link) {
|
|
|
|
+ bool match = true;
|
|
|
|
+
|
|
|
|
+ /* We do not support toggle states */
|
|
|
|
+ if (item->key.key.unicode_char || item->key.key.scan_code) {
|
|
|
|
+ if (item->key.key.unicode_char !=
|
|
|
|
+ next_key.key.unicode_char ||
|
|
|
|
+ item->key.key.scan_code != next_key.key.scan_code)
|
|
|
|
+ match = false;
|
|
|
|
+ }
|
|
|
|
+ if (item->key.key_state.key_shift_state &&
|
|
|
|
+ item->key.key_state.key_shift_state !=
|
|
|
|
+ next_key.key_state.key_shift_state)
|
|
|
|
+ match = false;
|
|
|
|
+
|
|
|
|
+ if (match)
|
|
|
|
+ /* We don't bother about the return code */
|
|
|
|
+ EFI_CALL(item->function(&next_key));
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* efi_cin_check() - check if keyboard input is available
|
|
* efi_cin_check() - check if keyboard input is available
|
|
*/
|
|
*/
|
|
@@ -614,8 +657,12 @@ static void efi_cin_check(void)
|
|
if (ret == EFI_SUCCESS) {
|
|
if (ret == EFI_SUCCESS) {
|
|
key_available = true;
|
|
key_available = true;
|
|
|
|
|
|
|
|
+ /* Notify registered functions */
|
|
|
|
+ efi_cin_notify();
|
|
|
|
+
|
|
/* Queue the wait for key event */
|
|
/* Queue the wait for key event */
|
|
- efi_signal_event(efi_con_in.wait_for_key, true);
|
|
|
|
|
|
+ if (key_available)
|
|
|
|
+ efi_signal_event(efi_con_in.wait_for_key, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -757,9 +804,35 @@ static efi_status_t EFIAPI efi_cin_register_key_notify(
|
|
struct efi_key_data *key_data),
|
|
struct efi_key_data *key_data),
|
|
void **notify_handle)
|
|
void **notify_handle)
|
|
{
|
|
{
|
|
|
|
+ efi_status_t ret = EFI_SUCCESS;
|
|
|
|
+ struct efi_cin_notify_function *notify_function;
|
|
|
|
+
|
|
EFI_ENTRY("%p, %p, %p, %p",
|
|
EFI_ENTRY("%p, %p, %p, %p",
|
|
this, key_data, key_notify_function, notify_handle);
|
|
this, key_data, key_notify_function, notify_handle);
|
|
- return EFI_EXIT(EFI_OUT_OF_RESOURCES);
|
|
|
|
|
|
+
|
|
|
|
+ /* Check parameters */
|
|
|
|
+ if (!this || !key_data || !key_notify_function || !notify_handle) {
|
|
|
|
+ ret = EFI_INVALID_PARAMETER;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n",
|
|
|
|
+ key_data->key.unicode_char,
|
|
|
|
+ key_data->key.scan_code,
|
|
|
|
+ key_data->key_state.key_shift_state,
|
|
|
|
+ key_data->key_state.key_toggle_state);
|
|
|
|
+
|
|
|
|
+ notify_function = calloc(1, sizeof(struct efi_cin_notify_function));
|
|
|
|
+ if (!notify_function) {
|
|
|
|
+ ret = EFI_OUT_OF_RESOURCES;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+ notify_function->key = *key_data;
|
|
|
|
+ notify_function->function = key_notify_function;
|
|
|
|
+ list_add_tail(¬ify_function->link, &cin_notify_functions);
|
|
|
|
+ *notify_handle = notify_function;
|
|
|
|
+out:
|
|
|
|
+ return EFI_EXIT(ret);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -779,8 +852,30 @@ static efi_status_t EFIAPI efi_cin_unregister_key_notify(
|
|
struct efi_simple_text_input_ex_protocol *this,
|
|
struct efi_simple_text_input_ex_protocol *this,
|
|
void *notification_handle)
|
|
void *notification_handle)
|
|
{
|
|
{
|
|
|
|
+ efi_status_t ret = EFI_INVALID_PARAMETER;
|
|
|
|
+ struct efi_cin_notify_function *item, *notify_function =
|
|
|
|
+ notification_handle;
|
|
|
|
+
|
|
EFI_ENTRY("%p, %p", this, notification_handle);
|
|
EFI_ENTRY("%p, %p", this, notification_handle);
|
|
- return EFI_EXIT(EFI_INVALID_PARAMETER);
|
|
|
|
|
|
+
|
|
|
|
+ /* Check parameters */
|
|
|
|
+ if (!this || !notification_handle)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ list_for_each_entry(item, &cin_notify_functions, link) {
|
|
|
|
+ if (item == notify_function) {
|
|
|
|
+ ret = EFI_SUCCESS;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (ret != EFI_SUCCESS)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ /* Remove the notify function */
|
|
|
|
+ list_del(¬ify_function->link);
|
|
|
|
+ free(notify_function);
|
|
|
|
+out:
|
|
|
|
+ return EFI_EXIT(ret);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|