blob: 5291cec22eb5acf472e68c6a8fe456f89b8f9f16 [file] [log] [blame] [edit]
// Copyright 2017 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <assert.h>
#include <stdio.h>
#include <pdev/driver.h>
#include <pdev/pdev.h>
#include <lk/init.h>
static const bootdata_t* driver_bootdata = NULL;
extern const struct lk_pdev_init_struct __start_lk_pdev_init[];
extern const struct lk_pdev_init_struct __stop_lk_pdev_init[];
static void pdev_init_driver(uint32_t type, const void* driver_data, uint32_t length, uint level) {
const struct lk_pdev_init_struct *ptr;
for (ptr = __start_lk_pdev_init; ptr != __stop_lk_pdev_init; ptr++) {
if (ptr->type == type && ptr->level == level) {
ptr->hook(driver_data, length);
return;
}
}
}
static void pdev_run_hooks(uint level) {
if (!driver_bootdata) return;
const bootdata_t* bootdata = driver_bootdata;
DEBUG_ASSERT(bootdata->type == BOOTDATA_CONTAINER);
DEBUG_ASSERT(bootdata->extra == BOOTDATA_MAGIC);
const uint8_t* start = (uint8_t*)bootdata + sizeof(bootdata_t);
const uint8_t* end = start + bootdata->length;
while ((uint32_t)(end - start) > sizeof(bootdata_t)) {
bootdata = (const bootdata_t*)start;
if (bootdata->type == BOOTDATA_KERNEL_DRIVER) {
// kernel driver type is in bootdata extra
// driver data follows bootdata
pdev_init_driver(bootdata->extra, &bootdata[1], bootdata->length, level);
}
start += BOOTDATA_ALIGN(sizeof(bootdata_t) + bootdata->length);
}
}
void pdev_init(const bootdata_t* bootdata) {
ASSERT(bootdata);
driver_bootdata = bootdata;
pdev_run_hooks(LK_INIT_LEVEL_PLATFORM_EARLY);
}
static void platform_dev_init(uint level) {
pdev_run_hooks(level);
}
LK_INIT_HOOK(platform_dev_init, platform_dev_init, LK_INIT_LEVEL_PLATFORM);