From c7d0aa54503c200d448f1a43ed6f0127fae2c906 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Sat, 20 Feb 2016 14:30:43 +0100 Subject: [PATCH] fdtbus --- grub-core/bus/fdt.c | 117 ++++++++++++++++++++++++++++++++++++++++++ include/grub/fdtbus.h | 52 +++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 grub-core/bus/fdt.c create mode 100644 include/grub/fdtbus.h diff --git a/grub-core/bus/fdt.c b/grub-core/bus/fdt.c new file mode 100644 index 000000000..293d8177c --- /dev/null +++ b/grub-core/bus/fdt.c @@ -0,0 +1,117 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2016 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include + +static const void *dtb; + +struct grub_fdtbus_device +{ + struct grub_fdtbus_device *next; + int node; + struct grub_fdtbus_driver *driver; +}; + +struct grub_fdtbus_device *devs; +struct grub_fdtbus_driver *drivers; + +static int +is_compatible (struct grub_fdtbus_driver *driver, + int node) +{ + const char *compatible = grub_fdt_get_prop (dtb, node, "compatible", + 0); + return grub_strcmp (driver->compatible, compatible) == 0; +} + +void +grub_fdtbus_scan (int parent) +{ + int node; + for (node = grub_fdt_first_node (dtb, parent); node >= 0; + node = grub_fdt_next_node (dtb, node)) + { + struct grub_fdtbus_device *dev; + struct grub_fdtbus_driver *driver; + dev = grub_zalloc (sizeof (*dev)); + if (!dev) + { + grub_print_error (); + return; + } + dev->node = node; + dev->next = devs; + devs = dev; + FOR_LIST_ELEMENTS(driver, drivers) + if (is_compatible (driver, node)) + { + if (driver->attach(dtb, dev->node) == GRUB_ERR_NONE) + { + dev->driver = driver; + break; + } + grub_print_error (); + } + grub_printf ("C: %s; %s\n", grub_fdt_get_nodename (dtb, node), compatible); + } +} + +void +grub_fdtbus_register (struct grub_fdtbus_driver *driver) +{ + struct grub_fdtbus_device *dev; + grub_list_push (GRUB_AS_LIST_P (&drivers), + GRUB_AS_LIST (driver)); + FOR_LIST_ELEMENTS(dev, devs) + if (is_compatible (driver, node)) + { + if (driver->attach(dtb, dev->node) == GRUB_ERR_NONE) + { + dev->driver = driver; + break; + } + grub_print_error (); + } +} + +void +grub_fdtbus_unregister (struct grub_fdtbus_driver *driver) +{ + grub_list_remove (GRUB_AS_LIST (driver)); + struct grub_fdtbus_device *dev; + grub_list_push (GRUB_AS_LIST_P (&drivers), + GRUB_AS_LIST (driver)); + FOR_LIST_ELEMENTS(dev, devs) + if (dev->driver == driver) + { + if (driver->detach) + driver->detach(dtb, dev->node); + dev->driver = 0; + } +} + +void +grub_fdtbus_init (const void *dtb_in, grub_size_t size) +{ + if (!dtb_in || grub_fdt_check_header (dtb_in, size) < 0) + return; + dtb = dtb_in; + grub_fdtbus_scan (0); +} diff --git a/include/grub/fdtbus.h b/include/grub/fdtbus.h new file mode 100644 index 000000000..8d80802eb --- /dev/null +++ b/include/grub/fdtbus.h @@ -0,0 +1,52 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2016 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_FDTBUS_HEADER +#define GRUB_FDTBUS_HEADER 1 + +#include +#include + +struct grub_fdtbus_driver +{ + struct grub_fdtbus_driver *next; + struct grub_fdtbus_driver **prev; + + const char *compatible; + + grub_err_t (*attach) (const void *fdt, unsigned int nodeoffset); + void (*detach) (const void *fdt, unsigned int nodeoffset); +}; + +void +grub_fdtbus_register (struct grub_fdtbus_driver *driver); + +void +grub_fdtbus_unregister (struct grub_fdtbus_driver *driver); + +/* Must be called before any register(). */ +/* dtb is assumed to be unfreeable and must remain + valid for lifetime of GRUB. + */ +void +grub_fdtbus_init (const void *dtb, grub_size_t size); + +void +grub_fdtbus_scan (int nodeoffset); + +#endif -- 2.47.2