2 * Uclass for EFI drivers
4 * Copyright (c) 2017 Heinrich Schuchardt
6 * SPDX-License-Identifier: GPL-2.0+
8 * For each EFI driver the uclass
10 * - installs the driver binding protocol
12 * The uclass provides the bind, start, and stop entry points for the driver
15 * In bind() and stop() it checks if the controller implements the protocol
16 * supported by the EFI driver. In the start() function it calls the bind()
17 * function of the EFI driver. In the stop() function it destroys the child
21 #include <efi_driver.h>
24 * Check node type. We do not support partitions as controller handles.
26 * @handle handle to be checked
29 static efi_status_t check_node_type(efi_handle_t handle)
31 efi_status_t r, ret = EFI_SUCCESS;
32 const struct efi_device_path *dp;
34 /* Open the device path protocol */
35 r = EFI_CALL(systab.boottime->open_protocol(
36 handle, &efi_guid_device_path, (void **)&dp,
37 NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL));
38 if (r == EFI_SUCCESS && dp) {
39 /* Get the last node */
40 const struct efi_device_path *node = efi_dp_last_node(dp);
41 /* We do not support partitions as controller */
42 if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE)
43 ret = EFI_UNSUPPORTED;
49 * Check if the driver supports the controller.
51 * @this driver binding protocol
52 * @controller_handle handle of the controller
53 * @remaining_device_path path specifying the child controller
56 static efi_status_t EFIAPI efi_uc_supported(
57 struct efi_driver_binding_protocol *this,
58 efi_handle_t controller_handle,
59 struct efi_device_path *remaining_device_path)
63 struct efi_driver_binding_extended_protocol *bp =
64 (struct efi_driver_binding_extended_protocol *)this;
66 EFI_ENTRY("%p, %p, %ls", this, controller_handle,
67 efi_dp_str(remaining_device_path));
69 ret = EFI_CALL(systab.boottime->open_protocol(
70 controller_handle, bp->ops->protocol,
71 &interface, this->driver_binding_handle,
72 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
74 case EFI_ACCESS_DENIED:
75 case EFI_ALREADY_STARTED:
80 ret = EFI_UNSUPPORTED;
84 ret = check_node_type(controller_handle);
86 r = EFI_CALL(systab.boottime->close_protocol(
87 controller_handle, bp->ops->protocol,
88 this->driver_binding_handle,
91 ret = EFI_UNSUPPORTED;
97 * Create child controllers and attach driver.
99 * @this driver binding protocol
100 * @controller_handle handle of the controller
101 * @remaining_device_path path specifying the child controller
102 * @return status code
104 static efi_status_t EFIAPI efi_uc_start(
105 struct efi_driver_binding_protocol *this,
106 efi_handle_t controller_handle,
107 struct efi_device_path *remaining_device_path)
110 void *interface = NULL;
111 struct efi_driver_binding_extended_protocol *bp =
112 (struct efi_driver_binding_extended_protocol *)this;
114 EFI_ENTRY("%p, %pUl, %ls", this, controller_handle,
115 efi_dp_str(remaining_device_path));
117 /* Attach driver to controller */
118 ret = EFI_CALL(systab.boottime->open_protocol(
119 controller_handle, bp->ops->protocol,
120 &interface, this->driver_binding_handle,
121 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
123 case EFI_ACCESS_DENIED:
124 case EFI_ALREADY_STARTED:
129 ret = EFI_UNSUPPORTED;
132 ret = check_node_type(controller_handle);
133 if (ret != EFI_SUCCESS) {
134 r = EFI_CALL(systab.boottime->close_protocol(
135 controller_handle, bp->ops->protocol,
136 this->driver_binding_handle,
138 if (r != EFI_SUCCESS)
139 EFI_PRINT("Failure to close handle\n");
143 /* TODO: driver specific stuff */
144 bp->ops->bind(controller_handle, interface);
147 return EFI_EXIT(ret);
151 * Remove a single child controller from the parent controller.
153 * @controller_handle parent controller
154 * @child_handle child controller
155 * @return status code
157 static efi_status_t disconnect_child(efi_handle_t controller_handle,
158 efi_handle_t child_handle)
161 efi_guid_t *guid_controller = NULL;
162 efi_guid_t *guid_child_controller = NULL;
164 ret = EFI_CALL(systab.boottime->close_protocol(
165 controller_handle, guid_controller,
166 child_handle, child_handle));
167 if (ret != EFI_SUCCESS) {
168 EFI_PRINT("Cannot close protocol\n");
171 ret = EFI_CALL(systab.boottime->uninstall_protocol_interface(
172 child_handle, guid_child_controller, NULL));
173 if (ret != EFI_SUCCESS) {
174 EFI_PRINT("Cannot uninstall protocol interface\n");
181 * Remove child controllers and disconnect the controller.
183 * @this driver binding protocol
184 * @controller_handle handle of the controller
185 * @number_of_children number of child controllers to remove
186 * @child_handle_buffer handles of the child controllers to remove
187 * @return status code
189 static efi_status_t EFIAPI efi_uc_stop(
190 struct efi_driver_binding_protocol *this,
191 efi_handle_t controller_handle,
192 size_t number_of_children,
193 efi_handle_t *child_handle_buffer)
197 struct efi_open_protocol_info_entry *entry_buffer;
198 efi_guid_t *guid_controller = NULL;
200 EFI_ENTRY("%p, %pUl, %zu, %p", this, controller_handle,
201 number_of_children, child_handle_buffer);
203 /* Destroy provided child controllers */
204 if (number_of_children) {
207 for (i = 0; i < number_of_children; ++i) {
208 ret = disconnect_child(controller_handle,
209 child_handle_buffer[i]);
210 if (ret != EFI_SUCCESS)
216 /* Destroy all children */
217 ret = EFI_CALL(systab.boottime->open_protocol_information(
218 controller_handle, guid_controller,
219 &entry_buffer, &count));
220 if (ret != EFI_SUCCESS)
223 if (entry_buffer[--count].attributes &
224 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
225 ret = disconnect_child(
227 entry_buffer[count].agent_handle);
228 if (ret != EFI_SUCCESS)
232 ret = EFI_CALL(systab.boottime->free_pool(entry_buffer));
233 if (ret != EFI_SUCCESS)
234 printf("%s(%u) %s: ERROR: Cannot free pool\n",
235 __FILE__, __LINE__, __func__);
237 /* Detach driver from controller */
238 ret = EFI_CALL(systab.boottime->close_protocol(
239 controller_handle, guid_controller,
240 this->driver_binding_handle, controller_handle));
242 return EFI_EXIT(ret);
245 static efi_status_t efi_add_driver(struct driver *drv)
248 const struct efi_driver_ops *ops = drv->ops;
249 struct efi_driver_binding_extended_protocol *bp;
251 debug("EFI: Adding driver '%s'\n", drv->name);
252 if (!ops->protocol) {
253 printf("EFI: ERROR: protocol GUID missing for driver '%s'\n",
255 return EFI_INVALID_PARAMETER;
257 bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
259 return EFI_OUT_OF_RESOURCES;
261 bp->bp.supported = efi_uc_supported;
262 bp->bp.start = efi_uc_start;
263 bp->bp.stop = efi_uc_stop;
264 bp->bp.version = 0xffffffff;
267 ret = efi_create_handle(&bp->bp.driver_binding_handle);
268 if (ret != EFI_SUCCESS) {
272 bp->bp.image_handle = bp->bp.driver_binding_handle;
273 ret = efi_add_protocol(bp->bp.driver_binding_handle,
274 &efi_guid_driver_binding_protocol, bp);
275 if (ret != EFI_SUCCESS) {
276 efi_delete_handle(bp->bp.driver_binding_handle);
285 * Initialize the EFI drivers.
286 * Called by board_init_r().
288 * @return 0 = success, any other value will stop further execution
290 efi_status_t efi_driver_init(void)
293 efi_status_t ret = EFI_SUCCESS;
295 /* Save 'gd' pointer */
298 debug("EFI: Initializing EFI driver framework\n");
299 for (drv = ll_entry_start(struct driver, driver);
300 drv < ll_entry_end(struct driver, driver); ++drv) {
301 if (drv->id == UCLASS_EFI) {
302 ret = efi_add_driver(drv);
303 if (ret != EFI_SUCCESS) {
304 printf("EFI: ERROR: failed to add driver %s\n",
313 static int efi_uc_init(struct uclass *class)
315 printf("EFI: Initializing UCLASS_EFI\n");
319 static int efi_uc_destroy(struct uclass *class)
321 printf("Destroying UCLASS_EFI\n");
325 UCLASS_DRIVER(efi) = {
329 .destroy = efi_uc_destroy,