/* List of all events */
extern struct list_head efi_events;
+/**
+ * struct efi_protocol_notification - handle for notified protocol
+ *
+ * When a protocol interface is installed for which an event was registered with
+ * the RegisterProtocolNotify() service this structure is used to hold the
+ * handle on which the protocol interface was installed.
+ *
+ * @link: link to list of all handles notified for this event
+ * @handle: handle on which the notified protocol interface was installed
+ */
+struct efi_protocol_notification {
+ struct list_head link;
+ efi_handle_t handle;
+};
+
/**
* efi_register_notify_event - event registered by RegisterProtocolNotify()
*
* The address of this structure serves as registration value.
*
- * @link: link to list of all registered events
- * @event: registered event. The same event may registered for
- * multiple GUIDs.
- * @protocol: protocol for which the event is registered
+ * @link: link to list of all registered events
+ * @event: registered event. The same event may registered for multiple
+ * GUIDs.
+ * @protocol: protocol for which the event is registered
+ * @handles: linked list of all handles on which the notified protocol was
+ * installed
*/
struct efi_register_notify_event {
struct list_head link;
struct efi_event *event;
efi_guid_t protocol;
+ struct list_head handles;
};
/* List of all events registered by RegisterProtocolNotify() */
list_for_each_entry_safe(item, next, &efi_register_notify_events,
link) {
if (event == item->event) {
+ struct efi_protocol_notification *hitem, *hnext;
+
+ /* Remove signaled handles */
+ list_for_each_entry_safe(hitem, hnext, &item->handles,
+ link) {
+ list_del(&hitem->link);
+ free(hitem);
+ }
list_del(&item->link);
free(item);
}
/* Notify registered events */
list_for_each_entry(event, &efi_register_notify_events, link) {
- if (!guidcmp(protocol, &event->protocol))
+ if (!guidcmp(protocol, &event->protocol)) {
+ struct efi_protocol_notification *notif;
+
+ notif = calloc(1, sizeof(*notif));
+ if (!notif) {
+ list_del(&handler->link);
+ free(handler);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ notif->handle = handle;
+ list_add_tail(¬if->link, &event->handles);
efi_signal_event(event->event, true);
+ }
}
if (!guidcmp(&efi_guid_device_path, protocol))
item->event = event;
memcpy(&item->protocol, protocol, sizeof(efi_guid_t));
+ INIT_LIST_HEAD(&item->handles);
list_add_tail(&item->link, &efi_register_notify_events);
switch (search_type) {
case ALL_HANDLES:
return 0;
- case BY_REGISTER_NOTIFY:
case BY_PROTOCOL:
ret = efi_search_protocol(handle, protocol, NULL);
return (ret != EFI_SUCCESS);
struct efi_object *efiobj;
efi_uintn_t size = 0;
struct efi_register_notify_event *item, *event = NULL;
+ struct efi_protocol_notification *handle = NULL;
/* Check parameters */
switch (search_type) {
}
if (!event)
return EFI_INVALID_PARAMETER;
-
- protocol = &event->protocol;
break;
case BY_PROTOCOL:
if (!protocol)
}
/* Count how much space we need */
- list_for_each_entry(efiobj, &efi_obj_list, link) {
- if (!efi_search(search_type, protocol, efiobj))
- size += sizeof(void *);
+ if (search_type == BY_REGISTER_NOTIFY) {
+ if (list_empty(&event->handles))
+ return EFI_NOT_FOUND;
+ handle = list_first_entry(&event->handles,
+ struct efi_protocol_notification,
+ link);
+ efiobj = handle->handle;
+ size += sizeof(void *);
+ } else {
+ list_for_each_entry(efiobj, &efi_obj_list, link) {
+ if (!efi_search(search_type, protocol, efiobj))
+ size += sizeof(void *);
+ }
+ if (size == 0)
+ return EFI_NOT_FOUND;
}
- if (size == 0)
- return EFI_NOT_FOUND;
-
if (!buffer_size)
return EFI_INVALID_PARAMETER;
return EFI_INVALID_PARAMETER;
/* Then fill the array */
- list_for_each_entry(efiobj, &efi_obj_list, link) {
- if (!efi_search(search_type, protocol, efiobj))
- *buffer++ = efiobj;
+ if (search_type == BY_REGISTER_NOTIFY) {
+ *buffer = efiobj;
+ list_del(&handle->link);
+ } else {
+ list_for_each_entry(efiobj, &efi_obj_list, link) {
+ if (!efi_search(search_type, protocol, efiobj))
+ *buffer++ = efiobj;
+ }
}
return EFI_SUCCESS;
{
struct context *cp = context;
efi_status_t ret;
+ efi_uintn_t handle_count;
+ efi_handle_t *handles;
cp->notify_count++;
- ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY, NULL,
- cp->registration_key,
- &cp->handle_count,
- &cp->handles);
- if (ret != EFI_SUCCESS)
- cp->handle_count = 0;
+ for (;;) {
+ ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY, NULL,
+ cp->registration_key,
+ &handle_count, &handles);
+ if (ret != EFI_SUCCESS)
+ break;
+ cp->handle_count += handle_count;
+ cp->handles = handles;
+ }
}
/*
efi_st_error("reinstall was notified too often\n");
return EFI_ST_FAILURE;
}
- if (context.handle_count != 1) {
+ if (context.handle_count != 2) {
efi_st_error("LocateHandle failed\n");
return EFI_ST_FAILURE;
}
efi_st_error("install was notified too often\n");
return EFI_ST_FAILURE;
}
- if (context.handle_count != 2) {
+ if (context.handle_count != 3) {
efi_st_error("LocateHandle failed\n");
return EFI_ST_FAILURE;
}