[drivers][core] 完善设备模型 (#8384)
This commit is contained in:
parent
cc157baf23
commit
10b16273b8
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
|
@ -10,7 +10,6 @@
|
|||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -19,16 +18,6 @@
|
|||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#ifdef RT_USING_DM
|
||||
#include <drivers/core/bus.h>
|
||||
|
||||
static struct rt_bus bus_root =
|
||||
{
|
||||
.name = "root",
|
||||
.children = RT_LIST_OBJECT_INIT(bus_root.children),
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_DEV_BUS
|
||||
|
||||
#if defined(RT_USING_POSIX_DEVIO)
|
||||
|
@ -95,12 +84,19 @@ rt_err_t rt_device_bus_destroy(rt_device_t dev)
|
|||
#endif
|
||||
|
||||
#ifdef RT_USING_DM
|
||||
/**
|
||||
* @brief This function get the root bus
|
||||
*/
|
||||
rt_bus_t rt_bus_root(void)
|
||||
#include <drivers/core/bus.h>
|
||||
|
||||
static struct rt_spinlock bus_lock = {};
|
||||
static rt_list_t bus_nodes = RT_LIST_OBJECT_INIT(bus_nodes);
|
||||
|
||||
static void _dm_bus_lock(struct rt_spinlock *spinlock)
|
||||
{
|
||||
return &bus_root;
|
||||
rt_hw_spin_lock(&spinlock->lock);
|
||||
}
|
||||
|
||||
static void _dm_bus_unlock(struct rt_spinlock *spinlock)
|
||||
{
|
||||
rt_hw_spin_unlock(&spinlock->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,30 +104,43 @@ rt_bus_t rt_bus_root(void)
|
|||
*
|
||||
* @param bus the target bus
|
||||
*
|
||||
* @param drv the target drv to be matched
|
||||
* @param data the data push when call fn
|
||||
*
|
||||
* @param fn the function callback in each loop
|
||||
*
|
||||
* @return the error code, RT_EOK on added successfully.
|
||||
*/
|
||||
rt_err_t rt_bus_for_each_dev(rt_bus_t bus, rt_driver_t drv, int (*fn)(rt_driver_t drv, rt_device_t dev))
|
||||
rt_err_t rt_bus_for_each_dev(rt_bus_t bus, void *data, int (*fn)(rt_device_t dev, void *))
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_device_t dev;
|
||||
rt_err_t err = -RT_EEMPTY;
|
||||
rt_list_t *dev_list;
|
||||
struct rt_spinlock *dev_lock;
|
||||
|
||||
RT_ASSERT(bus != RT_NULL);
|
||||
RT_ASSERT(drv != RT_NULL);
|
||||
|
||||
level = rt_spin_lock_irqsave(&bus->spinlock);
|
||||
dev_list = &bus->dev_list;
|
||||
dev_lock = &bus->dev_lock;
|
||||
|
||||
rt_list_for_each_entry(dev, &bus->dev_list, node)
|
||||
_dm_bus_lock(dev_lock);
|
||||
dev = rt_list_entry(dev_list->next, struct rt_device, node);
|
||||
_dm_bus_unlock(dev_lock);
|
||||
|
||||
while (&dev->node != dev_list)
|
||||
{
|
||||
fn(drv, dev);
|
||||
if (!fn(dev, data))
|
||||
{
|
||||
err = RT_EOK;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
_dm_bus_lock(dev_lock);
|
||||
dev = rt_list_entry(dev->node.next, struct rt_device, node);
|
||||
_dm_bus_unlock(dev_lock);
|
||||
}
|
||||
|
||||
rt_spin_unlock_irqrestore(&bus->spinlock, level);
|
||||
|
||||
return RT_EOK;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,104 +148,97 @@ rt_err_t rt_bus_for_each_dev(rt_bus_t bus, rt_driver_t drv, int (*fn)(rt_driver_
|
|||
*
|
||||
* @param bus the target bus
|
||||
*
|
||||
* @param dev the target dev to be matched
|
||||
* @param data the data push when call fn
|
||||
*
|
||||
* @param fn the function callback in each loop
|
||||
*
|
||||
* @return the error code, RT_EOK on added successfully.
|
||||
*/
|
||||
rt_err_t rt_bus_for_each_drv(rt_bus_t bus, rt_device_t dev, int (*fn)(rt_driver_t drv, rt_device_t dev))
|
||||
rt_err_t rt_bus_for_each_drv(rt_bus_t bus, void *data, int (*fn)(rt_driver_t drv, void *))
|
||||
{
|
||||
rt_err_t err;
|
||||
rt_base_t level;
|
||||
rt_driver_t drv;
|
||||
rt_err_t err = -RT_EEMPTY;
|
||||
rt_list_t *drv_list;
|
||||
struct rt_spinlock *drv_lock;
|
||||
|
||||
RT_ASSERT(bus != RT_NULL);
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
if (rt_list_isempty(&bus->drv_list))
|
||||
drv_list = &bus->drv_list;
|
||||
drv_lock = &bus->drv_lock;
|
||||
|
||||
_dm_bus_lock(drv_lock);
|
||||
drv = rt_list_entry(drv_list->next, struct rt_driver, node);
|
||||
_dm_bus_unlock(drv_lock);
|
||||
|
||||
while (&drv->node != drv_list)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
err = -RT_ERROR;
|
||||
|
||||
level = rt_spin_lock_irqsave(&bus->spinlock);
|
||||
|
||||
rt_list_for_each_entry(drv, &bus->drv_list, node)
|
||||
{
|
||||
if (fn(drv, dev))
|
||||
if (!fn(drv, data))
|
||||
{
|
||||
err = -RT_EOK;
|
||||
err = RT_EOK;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rt_spin_unlock_irqrestore(&bus->spinlock, level);
|
||||
_dm_bus_lock(drv_lock);
|
||||
drv = rt_list_entry(drv->node.next, struct rt_driver, node);
|
||||
_dm_bus_unlock(drv_lock);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function add a bus to the root
|
||||
*
|
||||
* @param bus_node the bus to be added
|
||||
*
|
||||
* @return the error code, RT_EOK on added successfully.
|
||||
*/
|
||||
rt_err_t rt_bus_add(rt_bus_t bus_node)
|
||||
static rt_err_t bus_probe(rt_driver_t drv, rt_device_t dev)
|
||||
{
|
||||
rt_base_t level;
|
||||
|
||||
RT_ASSERT(bus_node != RT_NULL);
|
||||
|
||||
bus_node->bus = &bus_root;
|
||||
rt_list_init(&bus_node->list);
|
||||
|
||||
level = rt_spin_lock_irqsave(&bus_node->spinlock);
|
||||
|
||||
rt_list_insert_before(&bus_root.children, &bus_node->list);
|
||||
|
||||
rt_spin_unlock_irqrestore(&bus_node->spinlock, level);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function match the device and driver, probe them if match successed
|
||||
*
|
||||
* @param drv the drv to match/probe
|
||||
*
|
||||
* @param dev the dev to match/probe
|
||||
*
|
||||
* @return the result of probe, 1 on added successfully.
|
||||
*/
|
||||
static int rt_bus_probe(rt_driver_t drv, rt_device_t dev)
|
||||
{
|
||||
int ret = 0;
|
||||
rt_bus_t bus = drv->bus;
|
||||
rt_err_t err = -RT_EEMPTY;
|
||||
|
||||
if (!bus)
|
||||
{
|
||||
bus = dev->bus;
|
||||
}
|
||||
|
||||
RT_ASSERT(bus != RT_NULL);
|
||||
|
||||
if (!dev->drv && bus->match(drv, dev))
|
||||
{
|
||||
dev->drv = drv;
|
||||
|
||||
ret = bus->probe(dev);
|
||||
err = bus->probe(dev);
|
||||
|
||||
if (ret)
|
||||
if (err)
|
||||
{
|
||||
dev->drv = RT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bus_probe_driver(rt_device_t dev, void *drv_ptr)
|
||||
{
|
||||
bus_probe(drv_ptr, dev);
|
||||
|
||||
/*
|
||||
* The driver is shared by multiple devices,
|
||||
* so we always return the '1' to enumerate all devices.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bus_probe_device(rt_driver_t drv, void *dev_ptr)
|
||||
{
|
||||
rt_err_t err;
|
||||
|
||||
err = bus_probe(drv, dev_ptr);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
rt_bus_t bus = drv->bus;
|
||||
|
||||
_dm_bus_lock(&bus->drv_lock);
|
||||
++drv->ref_count;
|
||||
_dm_bus_unlock(&bus->drv_lock);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -250,20 +252,17 @@ static int rt_bus_probe(rt_driver_t drv, rt_device_t dev)
|
|||
*/
|
||||
rt_err_t rt_bus_add_driver(rt_bus_t bus, rt_driver_t drv)
|
||||
{
|
||||
rt_base_t level;
|
||||
|
||||
RT_ASSERT(bus != RT_NULL);
|
||||
RT_ASSERT(drv != RT_NULL);
|
||||
|
||||
drv->bus = bus;
|
||||
rt_list_init(&drv->node);
|
||||
|
||||
level = rt_spin_lock_irqsave(&bus->spinlock);
|
||||
|
||||
_dm_bus_lock(&bus->drv_lock);
|
||||
rt_list_insert_before(&bus->drv_list, &drv->node);
|
||||
_dm_bus_unlock(&bus->drv_lock);
|
||||
|
||||
rt_spin_unlock_irqrestore(&bus->spinlock, level);
|
||||
|
||||
rt_bus_for_each_dev(drv->bus, drv, rt_bus_probe);
|
||||
rt_bus_for_each_dev(bus, drv, bus_probe_driver);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
@ -279,20 +278,17 @@ rt_err_t rt_bus_add_driver(rt_bus_t bus, rt_driver_t drv)
|
|||
*/
|
||||
rt_err_t rt_bus_add_device(rt_bus_t bus, rt_device_t dev)
|
||||
{
|
||||
rt_base_t level;
|
||||
|
||||
RT_ASSERT(bus != RT_NULL);
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
dev->bus = bus;
|
||||
rt_list_init(&dev->node);
|
||||
|
||||
level = rt_spin_lock_irqsave(&bus->spinlock);
|
||||
|
||||
_dm_bus_lock(&bus->dev_lock);
|
||||
rt_list_insert_before(&bus->dev_list, &dev->node);
|
||||
_dm_bus_unlock(&bus->dev_lock);
|
||||
|
||||
rt_spin_unlock_irqrestore(&bus->spinlock, level);
|
||||
|
||||
rt_bus_for_each_drv(dev->bus, dev, rt_bus_probe);
|
||||
rt_bus_for_each_drv(bus, dev, bus_probe_device);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
@ -306,13 +302,31 @@ rt_err_t rt_bus_add_device(rt_bus_t bus, rt_device_t dev)
|
|||
*/
|
||||
rt_err_t rt_bus_remove_driver(rt_driver_t drv)
|
||||
{
|
||||
rt_err_t err;
|
||||
rt_bus_t bus;
|
||||
|
||||
RT_ASSERT(drv != RT_NULL);
|
||||
RT_ASSERT(drv->bus != RT_NULL);
|
||||
|
||||
LOG_D("Bus(%s) remove driver %s", drv->bus->name, drv->name);
|
||||
bus = drv->bus;
|
||||
|
||||
rt_list_remove(&drv->node);
|
||||
LOG_D("Bus(%s) remove driver %s", bus->name, drv->parent.name);
|
||||
|
||||
return RT_EOK;
|
||||
_dm_bus_lock(&bus->drv_lock);
|
||||
|
||||
if (drv->ref_count)
|
||||
{
|
||||
err = -RT_EBUSY;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_list_remove(&drv->node);
|
||||
err = RT_EOK;
|
||||
}
|
||||
|
||||
_dm_bus_unlock(&bus->drv_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -324,13 +338,104 @@ rt_err_t rt_bus_remove_driver(rt_driver_t drv)
|
|||
*/
|
||||
rt_err_t rt_bus_remove_device(rt_device_t dev)
|
||||
{
|
||||
rt_bus_t bus;
|
||||
rt_driver_t drv;
|
||||
rt_err_t err = RT_EOK;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(dev->bus != RT_NULL);
|
||||
|
||||
LOG_D("Bus(%s) remove device %s", dev->bus->name, dev->name);
|
||||
bus = dev->bus;
|
||||
drv = dev->drv;
|
||||
|
||||
LOG_D("Bus(%s) remove device %s", bus->name, dev->parent.name);
|
||||
|
||||
_dm_bus_lock(&bus->dev_lock);
|
||||
rt_list_remove(&dev->node);
|
||||
_dm_bus_unlock(&bus->dev_lock);
|
||||
|
||||
return RT_EOK;
|
||||
if (dev->bus->remove)
|
||||
{
|
||||
err = dev->bus->remove(dev);
|
||||
}
|
||||
else if (drv)
|
||||
{
|
||||
if (drv->shutdown)
|
||||
{
|
||||
err = drv->shutdown(dev);
|
||||
}
|
||||
|
||||
/* device and driver are in the same bus */
|
||||
_dm_bus_lock(&bus->drv_lock);
|
||||
--drv->ref_count;
|
||||
_dm_bus_unlock(&bus->drv_lock);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct bus_shutdown_info
|
||||
{
|
||||
rt_bus_t bus;
|
||||
|
||||
rt_err_t err;
|
||||
};
|
||||
|
||||
static int device_shutdown(rt_device_t dev, void *info_ptr)
|
||||
{
|
||||
rt_bus_t bus;
|
||||
rt_err_t err = RT_EOK;
|
||||
struct bus_shutdown_info *info = info_ptr;
|
||||
|
||||
bus = info->bus;
|
||||
|
||||
if (bus->shutdown)
|
||||
{
|
||||
LOG_D("Device(%s) shutdown", dev->parent.name);
|
||||
err = bus->shutdown(dev);
|
||||
LOG_D(" Result: %s", rt_strerror(err));
|
||||
}
|
||||
else if (dev->drv && dev->drv->shutdown)
|
||||
{
|
||||
LOG_D("Device(%s) shutdown", dev->parent.name);
|
||||
err = dev->drv->shutdown(dev);
|
||||
LOG_D(" Result: %s", rt_strerror(err));
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
/* Only get the last one while system not crash */
|
||||
info->err = err;
|
||||
}
|
||||
|
||||
/* Go on, we want to ask all devices to shutdown */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function call all buses' shutdown
|
||||
*
|
||||
* @return the error code, RT_EOK on shutdown successfully.
|
||||
*/
|
||||
rt_err_t rt_bus_shutdown(void)
|
||||
{
|
||||
rt_bus_t bus = RT_NULL;
|
||||
struct bus_shutdown_info info =
|
||||
{
|
||||
.err = RT_EOK,
|
||||
};
|
||||
|
||||
_dm_bus_lock(&bus_lock);
|
||||
|
||||
rt_list_for_each_entry(bus, &bus_nodes, list)
|
||||
{
|
||||
info.bus = bus;
|
||||
rt_bus_for_each_dev(bus, &info, device_shutdown);
|
||||
}
|
||||
|
||||
_dm_bus_unlock(&bus_lock);
|
||||
|
||||
return info.err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -339,24 +444,24 @@ rt_err_t rt_bus_remove_device(rt_device_t dev)
|
|||
*
|
||||
* @return the bus finded by name.
|
||||
*/
|
||||
rt_bus_t rt_bus_find_by_name(char *name)
|
||||
rt_bus_t rt_bus_find_by_name(const char *name)
|
||||
{
|
||||
rt_bus_t bus = RT_NULL;
|
||||
struct rt_list_node *node = RT_NULL;
|
||||
|
||||
if (!rt_list_isempty(&bus_root.children))
|
||||
RT_ASSERT(name != RT_NULL);
|
||||
|
||||
_dm_bus_lock(&bus_lock);
|
||||
|
||||
rt_list_for_each_entry(bus, &bus_nodes, list)
|
||||
{
|
||||
rt_list_for_each(node, &bus_root.children)
|
||||
if (!rt_strncmp(bus->name, name, RT_NAME_MAX))
|
||||
{
|
||||
bus = rt_list_entry(node, struct rt_bus, list);
|
||||
|
||||
if (!rt_strncmp(bus->name, name, RT_NAME_MAX))
|
||||
{
|
||||
return bus;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_dm_bus_unlock(&bus_lock);
|
||||
|
||||
return bus;
|
||||
}
|
||||
|
||||
|
@ -371,22 +476,20 @@ rt_bus_t rt_bus_find_by_name(char *name)
|
|||
*/
|
||||
rt_err_t rt_bus_reload_driver_device(rt_bus_t new_bus, rt_device_t dev)
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_bus_t old_bus;
|
||||
|
||||
RT_ASSERT(new_bus != RT_NULL);
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(dev->bus != RT_NULL);
|
||||
RT_ASSERT(dev->bus != new_bus);
|
||||
|
||||
level = rt_spin_lock_irqsave(&new_bus->spinlock);
|
||||
old_bus = dev->bus;
|
||||
|
||||
_dm_bus_lock(&old_bus->dev_lock);
|
||||
rt_list_remove(&dev->node);
|
||||
rt_list_insert_before(&new_bus->dev_list, &dev->node);
|
||||
_dm_bus_unlock(&old_bus->dev_lock);
|
||||
|
||||
rt_list_remove(&dev->drv->node);
|
||||
rt_list_insert_before(&new_bus->drv_list, &dev->drv->node);
|
||||
|
||||
rt_spin_unlock_irqrestore(&new_bus->spinlock, level);
|
||||
|
||||
return RT_EOK;
|
||||
return rt_bus_add_device(new_bus, dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -397,13 +500,20 @@ rt_err_t rt_bus_reload_driver_device(rt_bus_t new_bus, rt_device_t dev)
|
|||
*/
|
||||
rt_err_t rt_bus_register(rt_bus_t bus)
|
||||
{
|
||||
rt_list_init(&bus->children);
|
||||
RT_ASSERT(bus != RT_NULL);
|
||||
|
||||
rt_list_init(&bus->list);
|
||||
rt_list_init(&bus->dev_list);
|
||||
rt_list_init(&bus->drv_list);
|
||||
|
||||
rt_spin_lock_init(&bus->spinlock);
|
||||
rt_spin_lock_init(&bus->dev_lock);
|
||||
rt_spin_lock_init(&bus->drv_lock);
|
||||
|
||||
rt_bus_add(bus);
|
||||
_dm_bus_lock(&bus_lock);
|
||||
|
||||
rt_list_insert_before(&bus_nodes, &bus->list);
|
||||
|
||||
_dm_bus_unlock(&bus_lock);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
|
@ -10,6 +10,10 @@
|
|||
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
#include <drivers/ofw_io.h>
|
||||
#include <drivers/ofw_irq.h>
|
||||
#endif
|
||||
#include <drivers/core/dm.h>
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
|
@ -56,10 +60,10 @@ struct prefix_track
|
|||
int uid;
|
||||
const char *prefix;
|
||||
};
|
||||
static struct rt_spinlock _prefix_nodes_lock;
|
||||
static struct rt_spinlock _prefix_nodes_lock = { 0 };
|
||||
static rt_list_t _prefix_nodes = RT_LIST_OBJECT_INIT(_prefix_nodes);
|
||||
|
||||
int rt_dm_set_dev_name_auto(rt_device_t dev, const char *prefix)
|
||||
int rt_dm_dev_set_name_auto(rt_device_t dev, const char *prefix)
|
||||
{
|
||||
int uid = -1;
|
||||
struct prefix_track *pt = RT_NULL;
|
||||
|
@ -104,17 +108,17 @@ int rt_dm_set_dev_name_auto(rt_device_t dev, const char *prefix)
|
|||
rt_spin_unlock(&_prefix_nodes_lock);
|
||||
}
|
||||
|
||||
return rt_dm_set_dev_name(dev, "%s%u", prefix, uid);
|
||||
return rt_dm_dev_set_name(dev, "%s%u", prefix, uid);
|
||||
}
|
||||
|
||||
int rt_dm_get_dev_name_id(rt_device_t dev)
|
||||
int rt_dm_dev_get_name_id(rt_device_t dev)
|
||||
{
|
||||
int id = 0, len;
|
||||
const char *name;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
name = rt_dm_get_dev_name(dev);
|
||||
name = rt_dm_dev_get_name(dev);
|
||||
len = rt_strlen(name) - 1;
|
||||
name += len;
|
||||
|
||||
|
@ -137,7 +141,7 @@ int rt_dm_get_dev_name_id(rt_device_t dev)
|
|||
return id;
|
||||
}
|
||||
|
||||
int rt_dm_set_dev_name(rt_device_t dev, const char *format, ...)
|
||||
int rt_dm_dev_set_name(rt_device_t dev, const char *format, ...)
|
||||
{
|
||||
int n;
|
||||
va_list arg_ptr;
|
||||
|
@ -152,9 +156,314 @@ int rt_dm_set_dev_name(rt_device_t dev, const char *format, ...)
|
|||
return n;
|
||||
}
|
||||
|
||||
const char *rt_dm_get_dev_name(rt_device_t dev)
|
||||
const char *rt_dm_dev_get_name(rt_device_t dev)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
return dev->parent.name;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
#define ofw_api_call(name, ...) rt_ofw_##name(__VA_ARGS__)
|
||||
#define ofw_api_call_ptr(name, ...) ofw_api_call(name, __VA_ARGS__)
|
||||
#else
|
||||
#define ofw_api_call(name, ...) (-RT_ENOSYS)
|
||||
#define ofw_api_call_ptr(name, ...) RT_NULL
|
||||
#endif
|
||||
|
||||
int rt_dm_dev_get_address_count(rt_device_t dev)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(get_address_count, dev->ofw_node);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
rt_err_t rt_dm_dev_get_address(rt_device_t dev, int index,
|
||||
rt_uint64_t *out_address, rt_uint64_t *out_size)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(get_address, dev->ofw_node, index,
|
||||
out_address, out_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
rt_err_t rt_dm_dev_get_address_by_name(rt_device_t dev, const char *name,
|
||||
rt_uint64_t *out_address, rt_uint64_t *out_size)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(get_address_by_name, dev->ofw_node, name,
|
||||
out_address, out_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
int rt_dm_dev_get_address_array(rt_device_t dev, int nr, rt_uint64_t *out_regs)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(get_address_array, dev->ofw_node, nr, out_regs);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
void *rt_dm_dev_iomap(rt_device_t dev, int index)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call_ptr(iomap, dev->ofw_node, index);
|
||||
}
|
||||
#endif
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
void *rt_dm_dev_iomap_by_name(rt_device_t dev, const char *name)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call_ptr(iomap_by_name, dev->ofw_node, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
int rt_dm_dev_get_irq_count(rt_device_t dev)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(get_irq_count, dev->ofw_node);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
int rt_dm_dev_get_irq(rt_device_t dev, int index)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(get_irq, dev->ofw_node, index);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
int rt_dm_dev_get_irq_by_name(rt_device_t dev, const char *name)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(get_irq_by_name, dev->ofw_node, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
void rt_dm_dev_bind_fwdata(rt_device_t dev, void *fw_np, void *data)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (!dev->ofw_node && fw_np)
|
||||
{
|
||||
dev->ofw_node = fw_np;
|
||||
rt_ofw_data(fw_np) = data;
|
||||
}
|
||||
|
||||
if (dev->ofw_node == RT_NULL)
|
||||
{
|
||||
rt_kprintf("[%s:%s] line=%d ofw_node is NULL\r\n", __FILE__, __func__, __LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
rt_ofw_data(dev->ofw_node) = data;
|
||||
#endif
|
||||
}
|
||||
|
||||
void rt_dm_dev_unbind_fwdata(rt_device_t dev, void *fw_np)
|
||||
{
|
||||
RT_ASSERT(dev!= RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
void *dev_fw_np;
|
||||
|
||||
if (!dev->ofw_node && fw_np)
|
||||
{
|
||||
dev_fw_np = fw_np;
|
||||
rt_ofw_data(fw_np) = RT_NULL;
|
||||
}
|
||||
|
||||
if (dev_fw_np == RT_NULL)
|
||||
{
|
||||
rt_kprintf("[%s:%s] line=%d dev_fw_np is NULL\r\n", __FILE__, __func__, __LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
rt_ofw_data(dev_fw_np) = RT_NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int rt_dm_dev_prop_read_u8_array_index(rt_device_t dev, const char *propname,
|
||||
int index, int nr, rt_uint8_t *out_values)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_UISNG_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(prop_read_u8_array_index, dev->ofw_node, propname,
|
||||
index, nr, out_value);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
int rt_dm_dev_prop_read_u16_array_index(rt_device_t dev, const char *propname,
|
||||
int index, int nr, rt_uint16_t *out_values)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(prop_read_u16_array_index, dev->ofw_node, propname,
|
||||
index, nr, out_values);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
int rt_dm_dev_prop_read_u32_array_index(rt_device_t dev, const char *propname,
|
||||
int index, int nr, rt_uint32_t *out_values)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(prop_read_u32_array_index, dev->ofw_node, propname,
|
||||
index, nr, out_values);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
int rt_dm_dev_prop_read_u64_array_index(rt_device_t dev, const char *propname,
|
||||
int index, int nr, rt_uint64_t *out_values)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(prop_read_u64_array_index, dev->ofw_node, propname,
|
||||
index, nr, out_values);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
int rt_dm_dev_prop_read_string_array_index(rt_device_t dev, const char *propname,
|
||||
int index, int nr, const char **out_strings)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(prop_read_string_array_index, dev->ofw_node, propname,
|
||||
index, nr, out_strings);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
int rt_dm_dev_prop_count_of_size(rt_device_t dev, const char *propname, int size)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(prop_count_of_size, dev->ofw_node, propname, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
int rt_dm_dev_prop_index_of_string(rt_device_t dev, const char *propname, const char *string)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(prop_index_of_string, dev->ofw_node, propname, string);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
rt_bool_t rt_dm_dev_prop_read_bool(rt_device_t dev, const char *propname)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node)
|
||||
{
|
||||
return ofw_api_call(prop_read_bool, dev->ofw_node, propname);
|
||||
}
|
||||
#endif
|
||||
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define DBG_TAG "rtdm.pltaform"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <drivers/platform.h>
|
||||
#include <drivers/core/bus.h>
|
||||
#include <drivers/core/dm.h>
|
||||
|
@ -28,6 +32,11 @@ struct rt_platform_device *rt_platform_device_alloc(const char *name)
|
|||
{
|
||||
struct rt_platform_device *pdev = rt_calloc(1, sizeof(*pdev));
|
||||
|
||||
if (!pdev)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
pdev->parent.bus = &platform_bus;
|
||||
pdev->name = name;
|
||||
|
||||
|
@ -44,7 +53,11 @@ rt_err_t rt_platform_driver_register(struct rt_platform_driver *pdrv)
|
|||
RT_ASSERT(pdrv != RT_NULL);
|
||||
|
||||
pdrv->parent.bus = &platform_bus;
|
||||
|
||||
#if RT_NAME_MAX > 0
|
||||
rt_strcpy(pdrv->parent.parent.name, pdrv->name);
|
||||
#else
|
||||
pdrv->parent.parent.name = pdrv->name;
|
||||
#endif
|
||||
return rt_driver_register(&pdrv->parent);
|
||||
}
|
||||
|
||||
|
@ -67,20 +80,22 @@ static rt_bool_t platform_match(rt_driver_t drv, rt_device_t dev)
|
|||
|
||||
#ifdef RT_USING_OFW
|
||||
struct rt_ofw_node *np = dev->ofw_node;
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
/* 1、match with ofw node */
|
||||
if (np)
|
||||
{
|
||||
/* 1、match with ofw node */
|
||||
pdev->id = rt_ofw_node_match(np, pdrv->ids);
|
||||
|
||||
return !!pdev->id;
|
||||
if (pdev->id)
|
||||
{
|
||||
return RT_TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 2、match with name */
|
||||
if (pdev->name && pdrv->name)
|
||||
{
|
||||
/* 2、match with name */
|
||||
if (pdev->name == pdrv->name)
|
||||
{
|
||||
return RT_TRUE;
|
||||
|
@ -97,7 +112,6 @@ static rt_bool_t platform_match(rt_driver_t drv, rt_device_t dev)
|
|||
static rt_err_t platform_probe(rt_device_t dev)
|
||||
{
|
||||
rt_err_t err;
|
||||
|
||||
struct rt_platform_driver *pdrv = rt_container_of(dev->drv, struct rt_platform_driver, parent);
|
||||
struct rt_platform_device *pdev = rt_container_of(dev, struct rt_platform_device, parent);
|
||||
#ifdef RT_USING_OFW
|
||||
|
@ -106,22 +120,22 @@ static rt_err_t platform_probe(rt_device_t dev)
|
|||
|
||||
err = pdrv->probe(pdev);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (!err)
|
||||
{
|
||||
#ifdef RT_USING_OFW
|
||||
if (np)
|
||||
{
|
||||
rt_ofw_node_set_flag(np, RT_OFW_F_READLY);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (np)
|
||||
if (err == -RT_ENOMEM)
|
||||
{
|
||||
rt_ofw_data(np) = &pdev->parent;
|
||||
LOG_W("System not memory in driver %s", pdrv->name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
|
@ -14,9 +14,13 @@
|
|||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <drivers/ofw_io.h>
|
||||
#include <drivers/ofw_fdt.h>
|
||||
#include <drivers/platform.h>
|
||||
#include <drivers/core/dm.h>
|
||||
|
||||
#include "../ofw/ofw_internal.h"
|
||||
|
||||
static const struct rt_ofw_node_id platform_ofw_ids[] =
|
||||
{
|
||||
{ .compatible = "simple-bus", },
|
||||
|
@ -36,10 +40,76 @@ static const struct rt_ofw_node_id platform_ofw_ids[] =
|
|||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static void ofw_device_rename(struct rt_device *dev)
|
||||
{
|
||||
rt_uint32_t mask;
|
||||
rt_uint64_t addr;
|
||||
const char *dev_name = dev->parent.name;
|
||||
struct rt_ofw_node *np = dev->ofw_node;
|
||||
|
||||
#if RT_NAME_MAX > 0
|
||||
if (dev_name[0] == '\0')
|
||||
{
|
||||
dev_name = RT_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (np->parent)
|
||||
{
|
||||
if (!rt_ofw_get_address(np, 0, &addr, RT_NULL))
|
||||
{
|
||||
const char *node_name = rt_fdt_node_name(np->full_name);
|
||||
rt_size_t tag_len = strchrnul(node_name, '@') - node_name;
|
||||
|
||||
if (!rt_ofw_prop_read_u32(np, "mask", &mask))
|
||||
{
|
||||
rt_dm_dev_set_name(dev, dev_name ? "%lx.%x.%.*s:%s" : "%lx.%x.%.*s",
|
||||
addr, __rt_ffs(mask) - 1, tag_len, node_name, dev_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_dm_dev_set_name(dev, dev_name ? "%lx.%.*s:%s" : "%lx.%.*s",
|
||||
addr, tag_len, node_name, dev_name);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
rt_dm_dev_set_name(dev, dev_name ? "%s:%s" : "%s",
|
||||
rt_fdt_node_name(np->full_name), dev_name);
|
||||
|
||||
np = np->parent;
|
||||
}
|
||||
}
|
||||
|
||||
static struct rt_platform_device *alloc_ofw_platform_device(struct rt_ofw_node *np)
|
||||
{
|
||||
struct rt_platform_device *pdev = rt_platform_device_alloc("");
|
||||
|
||||
if (pdev)
|
||||
{
|
||||
/* inc reference of dt-node */
|
||||
rt_ofw_node_get(np);
|
||||
rt_ofw_node_set_flag(np, RT_OFW_F_PLATFORM);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
pdev->parent.ofw_node = np;
|
||||
#endif
|
||||
|
||||
ofw_device_rename(&pdev->parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("Alloc device fail for %s", rt_ofw_node_full_name(np));
|
||||
}
|
||||
|
||||
return pdev;
|
||||
}
|
||||
|
||||
static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
struct rt_ofw_node *np, *child;
|
||||
struct rt_ofw_node *np;
|
||||
struct rt_platform_device *pdev;
|
||||
|
||||
rt_ofw_foreach_available_child_node(parent_np, np)
|
||||
|
@ -48,6 +118,8 @@ static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np)
|
|||
struct rt_ofw_node_id *id;
|
||||
struct rt_ofw_prop *compat_prop = RT_NULL;
|
||||
|
||||
LOG_D("%s found in %s", np->full_name, parent_np->full_name);
|
||||
|
||||
/* Is system node or have driver */
|
||||
if (rt_ofw_node_test_flag(np, RT_OFW_F_SYSTEM) ||
|
||||
rt_ofw_node_test_flag(np, RT_OFW_F_READLY))
|
||||
|
@ -66,35 +138,32 @@ static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np)
|
|||
|
||||
id = rt_ofw_prop_match(compat_prop, platform_ofw_ids);
|
||||
|
||||
if (id && (child = rt_ofw_get_next_child(np, RT_NULL)))
|
||||
if (id && np->child)
|
||||
{
|
||||
/* scan next level */
|
||||
err = platform_ofw_device_probe_once(child);
|
||||
|
||||
rt_ofw_node_put(child);
|
||||
err = platform_ofw_device_probe_once(np);
|
||||
|
||||
if (err)
|
||||
{
|
||||
rt_ofw_node_put(np);
|
||||
LOG_E("%s bus probe fail", np->full_name);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pdev = rt_platform_device_alloc(np->name);
|
||||
pdev = alloc_ofw_platform_device(np);
|
||||
|
||||
if (!pdev)
|
||||
{
|
||||
rt_ofw_node_put(np);
|
||||
err = -RT_ENOMEM;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* inc reference of dt-node */
|
||||
rt_ofw_node_get(np);
|
||||
rt_ofw_node_set_flag(np, RT_OFW_F_PLATFORM);
|
||||
|
||||
pdev->parent.ofw_node = np;
|
||||
pdev->dev_id = ofw_alias_node_id(np);
|
||||
LOG_D("%s register to bus", np->full_name);
|
||||
|
||||
rt_platform_device_register(pdev);
|
||||
}
|
||||
|
@ -102,18 +171,58 @@ static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np)
|
|||
return err;
|
||||
}
|
||||
|
||||
rt_err_t rt_platform_ofw_device_probe_child(struct rt_ofw_node *np)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_ofw_node *parent = rt_ofw_get_parent(np);
|
||||
|
||||
if (parent && rt_strcmp(parent->name, "/") &&
|
||||
rt_ofw_get_prop(np, "compatible", RT_NULL) &&
|
||||
!rt_ofw_node_test_flag(np, RT_OFW_F_PLATFORM))
|
||||
{
|
||||
struct rt_platform_device *pdev = alloc_ofw_platform_device(np);
|
||||
|
||||
if (pdev)
|
||||
{
|
||||
err = rt_platform_device_register(pdev);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_ENOMEM;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
rt_ofw_node_put(parent);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int platform_ofw_device_probe(void)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
struct rt_ofw_node *root_np;
|
||||
struct rt_ofw_node *node;
|
||||
|
||||
root_np = rt_ofw_find_node_by_path("/");
|
||||
|
||||
if (root_np)
|
||||
if (ofw_node_root)
|
||||
{
|
||||
err = platform_ofw_device_probe_once(root_np);
|
||||
err = platform_ofw_device_probe_once(ofw_node_root);
|
||||
|
||||
rt_ofw_node_put(root_np);
|
||||
rt_ofw_node_put(ofw_node_root);
|
||||
|
||||
if ((node = rt_ofw_find_node_by_path("/firmware")))
|
||||
{
|
||||
platform_ofw_device_probe_once(node);
|
||||
rt_ofw_node_put(node);
|
||||
}
|
||||
|
||||
if ((node = rt_ofw_get_child_by_compatible(ofw_node_chosen, "simple-framebuffer")))
|
||||
{
|
||||
platform_ofw_device_probe_once(node);
|
||||
rt_ofw_node_put(node);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -21,32 +21,32 @@ struct rt_bus
|
|||
{
|
||||
struct rt_object parent; /**< inherit from rt_object */
|
||||
|
||||
char *name;
|
||||
struct rt_bus *bus;
|
||||
const char *name;
|
||||
|
||||
rt_list_t list;
|
||||
rt_list_t children;
|
||||
rt_list_t dev_list;
|
||||
rt_list_t drv_list;
|
||||
|
||||
struct rt_spinlock spinlock;
|
||||
struct rt_spinlock dev_lock;
|
||||
struct rt_spinlock drv_lock;
|
||||
|
||||
rt_bool_t (*match)(rt_driver_t drv, rt_device_t dev);
|
||||
rt_err_t (*probe)(rt_device_t dev);
|
||||
rt_err_t (*remove)(rt_device_t dev);
|
||||
rt_err_t (*shutdown)(rt_device_t dev);
|
||||
};
|
||||
|
||||
rt_bus_t rt_bus_root(void);
|
||||
rt_err_t rt_bus_for_each_dev(rt_bus_t bus, void *data, int (*fn)(rt_device_t dev, void *));
|
||||
rt_err_t rt_bus_for_each_drv(rt_bus_t bus, void *data, int (*fn)(rt_driver_t drv, void *));
|
||||
|
||||
rt_err_t rt_bus_for_each_dev(rt_bus_t bus, rt_driver_t drv, int (*fn)(rt_driver_t drv, rt_device_t dev));
|
||||
rt_err_t rt_bus_for_each_drv(rt_bus_t bus, rt_device_t dev, int (*fn)(rt_driver_t drv, rt_device_t dev));
|
||||
|
||||
rt_err_t rt_bus_add(rt_bus_t bus);
|
||||
rt_err_t rt_bus_add_driver(rt_bus_t bus, rt_driver_t drv);
|
||||
rt_err_t rt_bus_add_device(rt_bus_t bus, rt_device_t dev);
|
||||
rt_err_t rt_bus_remove_driver(rt_driver_t drv);
|
||||
rt_err_t rt_bus_remove_device(rt_device_t dev);
|
||||
|
||||
rt_bus_t rt_bus_find_by_name(char *name);
|
||||
rt_err_t rt_bus_shutdown(void);
|
||||
|
||||
rt_bus_t rt_bus_find_by_name(const char *name);
|
||||
rt_err_t rt_bus_reload_driver_device(rt_bus_t new_bus, rt_device_t dev);
|
||||
|
||||
rt_err_t rt_bus_register(rt_bus_t bus);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <rthw.h>
|
||||
#include <rtdef.h>
|
||||
#include <ioremap.h>
|
||||
#include <drivers/misc.h>
|
||||
#include <drivers/byteorder.h>
|
||||
|
||||
|
@ -26,10 +27,139 @@ extern int rt_hw_cpu_id(void);
|
|||
|
||||
void rt_dm_secondary_cpu_init(void);
|
||||
|
||||
int rt_dm_set_dev_name_auto(rt_device_t dev, const char *prefix);
|
||||
int rt_dm_get_dev_name_id(rt_device_t dev);
|
||||
int rt_dm_dev_set_name_auto(rt_device_t dev, const char *prefix);
|
||||
int rt_dm_dev_get_name_id(rt_device_t dev);
|
||||
|
||||
int rt_dm_set_dev_name(rt_device_t dev, const char *format, ...);
|
||||
const char *rt_dm_get_dev_name(rt_device_t dev);
|
||||
int rt_dm_dev_set_name(rt_device_t dev, const char *format, ...);
|
||||
const char *rt_dm_dev_get_name(rt_device_t dev);
|
||||
|
||||
int rt_dm_dev_get_address_count(rt_device_t dev);
|
||||
rt_err_t rt_dm_dev_get_address(rt_device_t dev, int index,
|
||||
rt_uint64_t *out_address, rt_uint64_t *out_size);
|
||||
rt_err_t rt_dm_dev_get_address_by_name(rt_device_t dev, const char *name,
|
||||
rt_uint64_t *out_address, rt_uint64_t *out_size);
|
||||
int rt_dm_dev_get_address_array(rt_device_t dev, int nr, rt_uint64_t *out_regs);
|
||||
|
||||
void *rt_dm_dev_iomap(rt_device_t dev, int index);
|
||||
void *rt_dm_dev_iomap_by_name(rt_device_t dev, const char *name);
|
||||
|
||||
int rt_dm_dev_get_irq_count(rt_device_t dev);
|
||||
int rt_dm_dev_get_irq(rt_device_t dev, int index);
|
||||
int rt_dm_dev_get_irq_by_name(rt_device_t dev, const char *name);
|
||||
|
||||
void rt_dm_dev_bind_fwdata(rt_device_t dev, void *fw_np, void *data);
|
||||
void rt_dm_dev_unbind_fwdata(rt_device_t dev, void *fw_np);
|
||||
|
||||
int rt_dm_dev_prop_read_u8_array_index(rt_device_t dev, const char *propname,
|
||||
int index, int nr, rt_uint8_t *out_values);
|
||||
int rt_dm_dev_prop_read_u16_array_index(rt_device_t dev, const char *propname,
|
||||
int index, int nr, rt_uint16_t *out_values);
|
||||
int rt_dm_dev_prop_read_u32_array_index(rt_device_t dev, const char *propname,
|
||||
int index, int nr, rt_uint32_t *out_values);
|
||||
int rt_dm_dev_prop_read_u64_array_index(rt_device_t dev, const char *propname,
|
||||
int index, int nr, rt_uint64_t *out_values);
|
||||
int rt_dm_dev_prop_read_string_array_index(rt_device_t dev, const char *propname,
|
||||
int index, int nr, const char **out_strings);
|
||||
|
||||
int rt_dm_dev_prop_count_of_size(rt_device_t dev, const char *propname, int size);
|
||||
int rt_dm_dev_prop_index_of_string(rt_device_t dev, const char *propname, const char *string);
|
||||
|
||||
rt_bool_t rt_dm_dev_prop_read_bool(rt_device_t dev, const char *propname);
|
||||
|
||||
rt_inline rt_err_t rt_dm_dev_prop_read_u8_index(rt_device_t dev, const char *propname,
|
||||
int index, rt_uint8_t *out_value)
|
||||
{
|
||||
int nr = rt_dm_dev_prop_read_u8_array_index(dev, propname, index, 1, out_value);
|
||||
|
||||
return nr > 0 ? RT_EOK : (rt_err_t)nr;
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_dm_dev_prop_read_u16_index(rt_device_t dev, const char *propname,
|
||||
int index, rt_uint16_t *out_value)
|
||||
{
|
||||
int nr = rt_dm_dev_prop_read_u16_array_index(dev, propname, index, 1, out_value);
|
||||
|
||||
return nr > 0 ? RT_EOK : (rt_err_t)nr;
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_dm_dev_prop_read_u32_index(rt_device_t dev, const char *propname,
|
||||
int index, rt_uint32_t *out_value)
|
||||
{
|
||||
int nr = rt_dm_dev_prop_read_u32_array_index(dev, propname, index, 1, out_value);
|
||||
|
||||
return nr > 0 ? RT_EOK : (rt_err_t)nr;
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_dm_dev_prop_read_u64_index(rt_device_t dev, const char *propname,
|
||||
int index, rt_uint64_t *out_value)
|
||||
{
|
||||
int nr = rt_dm_dev_prop_read_u64_array_index(dev, propname, index, 1, out_value);
|
||||
|
||||
return nr > 0 ? RT_EOK : (rt_err_t)nr;
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_dm_dev_prop_read_string_index(rt_device_t dev, const char *propname,
|
||||
int index, const char **out_string)
|
||||
{
|
||||
int nr = rt_dm_dev_prop_read_string_array_index(dev, propname, index, 1, out_string);
|
||||
|
||||
return nr > 0 ? RT_EOK : (rt_err_t)nr;
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_dm_dev_prop_read_u8(rt_device_t dev, const char *propname,
|
||||
rt_uint8_t *out_value)
|
||||
{
|
||||
return rt_dm_dev_prop_read_u8_index(dev, propname, 0, out_value);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_dm_dev_prop_read_u16(rt_device_t dev, const char *propname,
|
||||
rt_uint16_t *out_value)
|
||||
{
|
||||
return rt_dm_dev_prop_read_u16_index(dev, propname, 0, out_value);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_dm_dev_prop_read_u32(rt_device_t dev, const char *propname,
|
||||
rt_uint32_t *out_value)
|
||||
{
|
||||
return rt_dm_dev_prop_read_u32_index(dev, propname, 0, out_value);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_dm_dev_prop_read_s32(rt_device_t dev, const char *propname,
|
||||
rt_int32_t *out_value)
|
||||
{
|
||||
return rt_dm_dev_prop_read_u32_index(dev, propname, 0, (rt_uint32_t *)out_value);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_dm_dev_prop_read_u64(rt_device_t dev, const char *propname,
|
||||
rt_uint64_t *out_value)
|
||||
{
|
||||
return rt_dm_dev_prop_read_u64_index(dev, propname, 0, out_value);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_dm_dev_prop_read_string(rt_device_t dev, const char *propname,
|
||||
const char **out_string)
|
||||
{
|
||||
return rt_dm_dev_prop_read_string_index(dev, propname, 0, out_string);
|
||||
}
|
||||
|
||||
rt_inline int rt_dm_dev_prop_count_of_u8(rt_device_t dev, const char *propname)
|
||||
{
|
||||
return rt_dm_dev_prop_count_of_size(dev, propname, sizeof(rt_uint8_t));
|
||||
}
|
||||
|
||||
rt_inline int rt_dm_dev_prop_count_of_u16(rt_device_t dev, const char *propname)
|
||||
{
|
||||
return rt_dm_dev_prop_count_of_size(dev, propname, sizeof(rt_uint16_t));
|
||||
}
|
||||
|
||||
rt_inline int rt_dm_dev_prop_count_of_u32(rt_device_t dev, const char *propname)
|
||||
{
|
||||
return rt_dm_dev_prop_count_of_size(dev, propname, sizeof(rt_uint32_t));
|
||||
}
|
||||
|
||||
rt_inline int rt_dm_dev_prop_count_of_u64(rt_device_t dev, const char *propname)
|
||||
{
|
||||
return rt_dm_dev_prop_count_of_size(dev, propname, sizeof(rt_uint64_t));
|
||||
}
|
||||
|
||||
#endif /* __RT_DM_H__ */
|
||||
|
|
|
@ -13,13 +13,14 @@
|
|||
|
||||
#include <rtdef.h>
|
||||
|
||||
struct rt_bus;
|
||||
|
||||
struct rt_driver
|
||||
{
|
||||
struct rt_object parent;
|
||||
struct rt_bus *bus;
|
||||
rt_list_t node;
|
||||
|
||||
rt_uint32_t ref_count;
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const struct rt_device_ops *dev_ops;
|
||||
#else
|
||||
|
@ -34,16 +35,10 @@ struct rt_driver
|
|||
|
||||
const struct filesystem_ops *fops;
|
||||
|
||||
const char *name;
|
||||
|
||||
int (*probe)(struct rt_device *dev);
|
||||
int (*remove)(struct rt_device *dev);
|
||||
|
||||
void *priv;
|
||||
int (*shutdown)(struct rt_device *dev);
|
||||
};
|
||||
typedef struct rt_driver* rt_driver_t;
|
||||
|
||||
int rt_driver_probe_device(struct rt_driver *drv, struct rt_device *dev);
|
||||
|
||||
rt_err_t rt_driver_register(rt_driver_t drv);
|
||||
rt_err_t rt_driver_unregister(rt_driver_t drv);
|
||||
|
|
|
@ -205,11 +205,15 @@ struct rt_ofw_node *rt_ofw_get_alias_node(const char *tag, int id);
|
|||
int rt_ofw_get_alias_id(struct rt_ofw_node *np, const char *tag);
|
||||
int rt_ofw_get_alias_last_id(const char *tag);
|
||||
|
||||
struct rt_ofw_node *rt_ofw_append_child(struct rt_ofw_node *parent, const char *full_name);
|
||||
rt_err_t rt_ofw_append_prop(struct rt_ofw_node *np, const char *name, int length, void *value);
|
||||
|
||||
struct rt_ofw_node *rt_ofw_parse_phandle(const struct rt_ofw_node *np, const char *phandle_name, int index);
|
||||
rt_err_t rt_ofw_parse_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name,
|
||||
int index, struct rt_ofw_cell_args *out_args);
|
||||
int rt_ofw_count_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name);
|
||||
|
||||
const char *rt_ofw_get_prop_fuzzy_name(const struct rt_ofw_node *np, const char *name);
|
||||
struct rt_ofw_prop *rt_ofw_get_prop(const struct rt_ofw_node *np, const char *name, rt_ssize_t *out_length);
|
||||
|
||||
rt_inline const void *rt_ofw_prop_read_raw(const struct rt_ofw_node *np, const char *name, rt_ssize_t *out_length)
|
||||
|
|
|
@ -20,6 +20,7 @@ struct rt_fdt_earlycon
|
|||
union { rt_ubase_t size, width; };
|
||||
|
||||
void *fdt;
|
||||
char options[32];
|
||||
long nodeoffset;
|
||||
|
||||
void *data;
|
||||
|
@ -41,8 +42,6 @@ struct rt_fdt_earlycon_id
|
|||
rt_err_t (*setup)(struct rt_fdt_earlycon *earlycon, const char *options);
|
||||
};
|
||||
|
||||
#define RT_FDT_EARLYCON_OPTION_SIGNATURE '\n'
|
||||
|
||||
#define RT_FDT_EARLYCON_EXPORT(_name, _type, _compatible, _setup) \
|
||||
static const struct rt_fdt_earlycon_id __rt_fdt_##_name##_earlycon \
|
||||
rt_used RT_OFW_SYMBOL(earlycon, _) = \
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#ifndef __OFW_IO_H__
|
||||
#define __OFW_IO_H__
|
||||
|
||||
#include <ioremap.h>
|
||||
#include <drivers/ofw.h>
|
||||
|
||||
int rt_ofw_bus_addr_cells(struct rt_ofw_node *np);
|
||||
|
|
|
@ -22,6 +22,8 @@ struct rt_platform_device
|
|||
{
|
||||
struct rt_device parent;
|
||||
|
||||
int dev_id;
|
||||
|
||||
const char *name;
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
|
@ -42,6 +44,8 @@ struct rt_platform_driver
|
|||
#endif
|
||||
|
||||
rt_err_t (*probe)(struct rt_platform_device *pdev);
|
||||
rt_err_t (*remove)(struct rt_platform_device *pdev);
|
||||
rt_err_t (*shutdown)(struct rt_platform_device *pdev);
|
||||
};
|
||||
|
||||
struct rt_platform_device *rt_platform_device_alloc(const char *name);
|
||||
|
@ -49,6 +53,8 @@ struct rt_platform_device *rt_platform_device_alloc(const char *name);
|
|||
rt_err_t rt_platform_driver_register(struct rt_platform_driver *pdrv);
|
||||
rt_err_t rt_platform_device_register(struct rt_platform_device *pdev);
|
||||
|
||||
rt_err_t rt_platform_ofw_device_probe_child(struct rt_ofw_node *np);
|
||||
|
||||
#define RT_PLATFORM_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, platform, BUILIN)
|
||||
|
||||
#endif /* __PLATFORM_H__ */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
|
@ -8,7 +8,7 @@
|
|||
* 2022-08-25 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include <drivers/ofw.h>
|
||||
|
@ -28,7 +28,7 @@ struct rt_ofw_node *ofw_node_chosen = RT_NULL;
|
|||
struct rt_ofw_node *ofw_node_aliases = RT_NULL;
|
||||
struct rt_ofw_node *ofw_node_reserved_memory = RT_NULL;
|
||||
|
||||
static rt_phandle _phandle_range[2] = { 1, 1 };
|
||||
static rt_phandle _phandle_range[2] = { 1, 1 }, _phandle_next = 1;
|
||||
static struct rt_ofw_node **_phandle_hash = RT_NULL;
|
||||
|
||||
static rt_list_t _aliases_nodes = RT_LIST_OBJECT_INIT(_aliases_nodes);
|
||||
|
@ -36,6 +36,7 @@ static rt_list_t _aliases_nodes = RT_LIST_OBJECT_INIT(_aliases_nodes);
|
|||
rt_err_t ofw_phandle_hash_reset(rt_phandle min, rt_phandle max)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
rt_phandle next = max;
|
||||
struct rt_ofw_node **hash_ptr = RT_NULL;
|
||||
|
||||
max = RT_ALIGN(max, OFW_NODE_MIN_HASH);
|
||||
|
@ -69,7 +70,7 @@ rt_err_t ofw_phandle_hash_reset(rt_phandle min, rt_phandle max)
|
|||
_phandle_range[0] = min;
|
||||
}
|
||||
_phandle_range[1] = max;
|
||||
|
||||
_phandle_next = next + 1;
|
||||
_phandle_hash = hash_ptr;
|
||||
}
|
||||
else
|
||||
|
@ -80,6 +81,39 @@ rt_err_t ofw_phandle_hash_reset(rt_phandle min, rt_phandle max)
|
|||
return err;
|
||||
}
|
||||
|
||||
static rt_phandle ofw_phandle_next(void)
|
||||
{
|
||||
rt_phandle next;
|
||||
static struct rt_spinlock op_lock = {};
|
||||
|
||||
rt_hw_spin_lock(&op_lock.lock);
|
||||
|
||||
RT_ASSERT(_phandle_next != OFW_PHANDLE_MAX);
|
||||
|
||||
if (_phandle_next <= _phandle_range[1])
|
||||
{
|
||||
next = _phandle_next++;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_err_t err = ofw_phandle_hash_reset(_phandle_range[0], _phandle_next);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
next = _phandle_next++;
|
||||
}
|
||||
else
|
||||
{
|
||||
next = 0;
|
||||
LOG_E("Expanded phandle hash[%u, %u] fail error = %s",
|
||||
_phandle_range[0], _phandle_next + 1, rt_strerror(err));
|
||||
}
|
||||
}
|
||||
|
||||
rt_hw_spin_unlock(&op_lock.lock);
|
||||
|
||||
return next;
|
||||
}
|
||||
static void ofw_prop_destroy(struct rt_ofw_prop *prop)
|
||||
{
|
||||
struct rt_ofw_prop *next;
|
||||
|
@ -230,6 +264,7 @@ static void ofw_node_release(struct rt_ref *r)
|
|||
struct rt_ofw_node *np = rt_container_of(r, struct rt_ofw_node, ref);
|
||||
|
||||
LOG_E("%s is release", np->full_name);
|
||||
(void)np;
|
||||
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
|
@ -610,7 +645,7 @@ struct rt_ofw_node *rt_ofw_find_node_by_path(const char *path)
|
|||
break;
|
||||
}
|
||||
|
||||
path += len;
|
||||
path += len + !!*next;
|
||||
}
|
||||
|
||||
np = tmp;
|
||||
|
@ -1031,9 +1066,9 @@ rt_err_t ofw_alias_scan(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
end = name + rt_strlen(name);
|
||||
end = name + rt_strlen(name) - 1;
|
||||
|
||||
while (*end && !(*end >= '0' && *end <= '9'))
|
||||
while (*end && !(*end >= '0' && *end <= '9') && end > name)
|
||||
{
|
||||
--end;
|
||||
}
|
||||
|
@ -1043,7 +1078,7 @@ rt_err_t ofw_alias_scan(void)
|
|||
id += (*end - '0') * rate;
|
||||
rate *= 10;
|
||||
|
||||
--end;
|
||||
++end;
|
||||
}
|
||||
|
||||
info = rt_malloc(sizeof(*info));
|
||||
|
@ -1058,7 +1093,7 @@ rt_err_t ofw_alias_scan(void)
|
|||
|
||||
info->id = id;
|
||||
info->tag = name;
|
||||
info->tag_len = end - name;
|
||||
info->tag_len = end - name - 1;
|
||||
info->np = tmp;
|
||||
|
||||
rt_list_insert_after(&_aliases_nodes, &info->list);
|
||||
|
@ -1092,6 +1127,32 @@ struct rt_ofw_node *rt_ofw_get_alias_node(const char *tag, int id)
|
|||
return np;
|
||||
}
|
||||
|
||||
int ofw_alias_node_id(struct rt_ofw_node *np)
|
||||
{
|
||||
int id;
|
||||
struct alias_info *info;
|
||||
|
||||
if (np)
|
||||
{
|
||||
id = -1;
|
||||
|
||||
rt_list_for_each_entry(info, &_aliases_nodes, list)
|
||||
{
|
||||
if (info->np == np)
|
||||
{
|
||||
id = info->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
id = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int rt_ofw_get_alias_id(struct rt_ofw_node *np, const char *tag)
|
||||
{
|
||||
int id;
|
||||
|
@ -1153,6 +1214,109 @@ int rt_ofw_get_alias_last_id(const char *tag)
|
|||
return id;
|
||||
}
|
||||
|
||||
struct rt_ofw_node *rt_ofw_append_child(struct rt_ofw_node *parent, const char *full_name)
|
||||
{
|
||||
rt_phandle phandle;
|
||||
rt_err_t err = RT_EOK;
|
||||
fdt32_t *phandle_value;
|
||||
struct rt_ofw_node *np = RT_NULL, *child;
|
||||
|
||||
if (full_name)
|
||||
{
|
||||
if ((phandle = ofw_phandle_next()))
|
||||
{
|
||||
np = rt_calloc(1, sizeof(*np) + sizeof(*phandle_value));
|
||||
}
|
||||
}
|
||||
|
||||
if (np)
|
||||
{
|
||||
parent = parent ? : ofw_node_root;
|
||||
|
||||
np->full_name = full_name;
|
||||
np->phandle = phandle;
|
||||
np->parent = parent;
|
||||
|
||||
rt_ref_init(&np->ref);
|
||||
|
||||
phandle_value = (void *)np + sizeof(*np);
|
||||
*phandle_value = cpu_to_fdt32(phandle);
|
||||
|
||||
err = rt_ofw_append_prop(np, "phandle", sizeof(*phandle_value), phandle_value);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
if (parent->child)
|
||||
{
|
||||
rt_ofw_foreach_child_node(parent, child)
|
||||
{
|
||||
if (!child->sibling)
|
||||
{
|
||||
child->sibling = np;
|
||||
rt_ofw_node_put(child);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parent->child = np;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_free(np);
|
||||
np = RT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return np;
|
||||
}
|
||||
|
||||
rt_err_t rt_ofw_append_prop(struct rt_ofw_node *np, const char *name, int length, void *value)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
|
||||
if (np && name && ((length && value) || (!length && !value)))
|
||||
{
|
||||
struct rt_ofw_prop *prop = rt_malloc(sizeof(*prop)), *last_prop;
|
||||
|
||||
if (prop)
|
||||
{
|
||||
prop->name = name;
|
||||
prop->length = length;
|
||||
prop->value = value;
|
||||
prop->next = RT_NULL;
|
||||
|
||||
if (np->props)
|
||||
{
|
||||
rt_ofw_foreach_prop(np, last_prop)
|
||||
{
|
||||
if (!last_prop->next)
|
||||
{
|
||||
last_prop->next = prop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
np->props = prop;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_ENOMEM;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct rt_ofw_node *rt_ofw_parse_phandle(const struct rt_ofw_node *np, const char *phandle_name, int index)
|
||||
{
|
||||
struct rt_ofw_cell_args args;
|
||||
|
@ -1296,6 +1460,170 @@ int rt_ofw_count_phandle_cells(const struct rt_ofw_node *np, const char *list_na
|
|||
return count;
|
||||
}
|
||||
|
||||
static const char *ofw_get_prop_fuzzy_name(const struct rt_ofw_node *np, const char *name)
|
||||
{
|
||||
char *sf, split_field[64];
|
||||
rt_size_t len = 0, max_ak = 0;
|
||||
const char *str, *result = RT_NULL;
|
||||
RT_DECLARE_BITMAP(ak, sizeof(split_field));
|
||||
struct rt_ofw_prop *prop;
|
||||
|
||||
/*
|
||||
* List:
|
||||
*
|
||||
* node {
|
||||
* property;
|
||||
* front-prop-rear;
|
||||
* front-prop;
|
||||
* prop-rear;
|
||||
* };
|
||||
*
|
||||
* if call:
|
||||
* ofw_get_prop_fuzzy_name(node, name):
|
||||
* ["prop"] => property
|
||||
* ["-prop"] => front-prop-rear
|
||||
* ["prop-"] => front-prop-rear
|
||||
* ["-prop$"] => front-prop
|
||||
* ["^prop-"] => prop-rear
|
||||
* ["-prop-"] => front-prop-rear
|
||||
* ["front-*-rear"] => front-prop-rear
|
||||
*/
|
||||
|
||||
str = name;
|
||||
sf = split_field;
|
||||
|
||||
if (str[0] != '^')
|
||||
{
|
||||
/* As '*' */
|
||||
*sf++ = '\0';
|
||||
rt_bitmap_set_bit(ak, len++);
|
||||
}
|
||||
else
|
||||
{
|
||||
++str;
|
||||
}
|
||||
|
||||
for (; *str && len < sizeof(split_field); ++str, ++sf, ++len)
|
||||
{
|
||||
if (*str != '*')
|
||||
{
|
||||
*sf = *str;
|
||||
rt_bitmap_clear_bit(ak, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
max_ak = len;
|
||||
*sf = '\0';
|
||||
rt_bitmap_set_bit(ak, len);
|
||||
}
|
||||
}
|
||||
*sf = '\0';
|
||||
|
||||
if (str[-1] != '$')
|
||||
{
|
||||
/* As '*' */
|
||||
max_ak = len;
|
||||
rt_bitmap_set_bit(ak, len++);
|
||||
}
|
||||
else
|
||||
{
|
||||
sf[-1] = '\0';
|
||||
--len;
|
||||
}
|
||||
|
||||
sf = split_field;
|
||||
|
||||
if (len >= sizeof(split_field))
|
||||
{
|
||||
LOG_W("%s fuzzy name = %s len is %d out of %d", np->full_name, name, rt_strlen(name), sizeof(split_field));
|
||||
}
|
||||
|
||||
rt_ofw_foreach_prop(np, prop)
|
||||
{
|
||||
int prep_ak = 0, next_ak, field;
|
||||
rt_bool_t match = RT_TRUE;
|
||||
const char *propname = prop->name, *fuzzy_name = sf;
|
||||
|
||||
if (!rt_bitmap_test_bit(ak, prep_ak))
|
||||
{
|
||||
next_ak = rt_bitmap_next_set_bit(ak, prep_ak + 1, max_ak) ? : len;
|
||||
field = next_ak - prep_ak;
|
||||
|
||||
if (rt_strncmp(propname, fuzzy_name, field))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
propname += field;
|
||||
fuzzy_name += field;
|
||||
prep_ak = next_ak;
|
||||
}
|
||||
|
||||
rt_bitmap_for_each_set_bit_from(ak, prep_ak, next_ak, max_ak)
|
||||
{
|
||||
/* Skip the '*' */
|
||||
if (prep_ak == next_ak)
|
||||
{
|
||||
++fuzzy_name;
|
||||
|
||||
next_ak = rt_bitmap_next_set_bit(ak, prep_ak + 1, max_ak);
|
||||
}
|
||||
|
||||
if (!(str = rt_strstr(propname, fuzzy_name)))
|
||||
{
|
||||
match = RT_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
field = next_ak - prep_ak;
|
||||
propname = str + field - 1;
|
||||
fuzzy_name += field;
|
||||
prep_ak = next_ak;
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
if ((max_ak || !split_field[0]) && next_ak >= max_ak && len - max_ak > 1)
|
||||
{
|
||||
if (next_ak == max_ak)
|
||||
{
|
||||
/* Skip the last '*' */
|
||||
++fuzzy_name;
|
||||
}
|
||||
|
||||
if (!(propname = rt_strstr(propname, fuzzy_name)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check end flag */
|
||||
if (propname[len - max_ak - 1] != '\0')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
result = prop->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const char *rt_ofw_get_prop_fuzzy_name(const struct rt_ofw_node *np, const char *name)
|
||||
{
|
||||
const char *propname = RT_NULL;
|
||||
|
||||
if (np && name)
|
||||
{
|
||||
propname = ofw_get_prop_fuzzy_name(np, name);
|
||||
}
|
||||
|
||||
return propname;
|
||||
}
|
||||
|
||||
|
||||
struct rt_ofw_prop *rt_ofw_get_prop(const struct rt_ofw_node *np, const char *name, rt_ssize_t *out_length)
|
||||
{
|
||||
struct rt_ofw_prop *prop = RT_NULL;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
|
@ -321,7 +321,7 @@ static rt_err_t fdt_reserved_memory_reg(int nodeoffset, const char *uname)
|
|||
}
|
||||
else
|
||||
{
|
||||
while (len >= t_len)
|
||||
for (; len >= t_len; len -= t_len)
|
||||
{
|
||||
base = rt_fdt_next_cell(&prop, _root_addr_cells);
|
||||
size = rt_fdt_next_cell(&prop, _root_size_cells);
|
||||
|
@ -664,12 +664,17 @@ void rt_fdt_earlycon_kick(int why)
|
|||
fdt_earlycon.console_kick(&fdt_earlycon, why);
|
||||
}
|
||||
|
||||
if (why == FDT_EARLYCON_KICK_COMPLETED && fdt_earlycon.msg_idx)
|
||||
if (why == FDT_EARLYCON_KICK_COMPLETED)
|
||||
{
|
||||
fdt_earlycon.msg_idx = 0;
|
||||
fdt_earlycon.console_putc = RT_NULL;
|
||||
|
||||
/* Dump old messages */
|
||||
rt_kputs(fdt_earlycon.msg);
|
||||
if (fdt_earlycon.msg_idx)
|
||||
{
|
||||
fdt_earlycon.msg_idx = 0;
|
||||
|
||||
/* Dump old messages */
|
||||
rt_kputs(fdt_earlycon.msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -787,6 +792,8 @@ rt_err_t rt_fdt_scan_chosen_stdout(void)
|
|||
if (options && *options && *options != ' ')
|
||||
{
|
||||
options_len = strchrnul(options, ' ') - options;
|
||||
|
||||
rt_strncpy(fdt_earlycon.options, options, options_len);
|
||||
}
|
||||
|
||||
/* console > stdout-path */
|
||||
|
@ -824,7 +831,7 @@ rt_err_t rt_fdt_scan_chosen_stdout(void)
|
|||
|
||||
if (best_earlycon_id && best_earlycon_id->setup)
|
||||
{
|
||||
rt_bool_t used_options = RT_FALSE;
|
||||
const char earlycon_magic[] = { 'O', 'F', 'W', '\0' };
|
||||
|
||||
if (!con_type)
|
||||
{
|
||||
|
@ -833,24 +840,25 @@ rt_err_t rt_fdt_scan_chosen_stdout(void)
|
|||
fdt_earlycon.fdt = _fdt;
|
||||
fdt_earlycon.nodeoffset = offset;
|
||||
|
||||
err = best_earlycon_id->setup(&fdt_earlycon, options);
|
||||
options = &fdt_earlycon.options[options_len + 1];
|
||||
rt_strncpy((void *)options, earlycon_magic, RT_ARRAY_SIZE(earlycon_magic));
|
||||
|
||||
for (int i = 0; i < options_len; ++i)
|
||||
err = best_earlycon_id->setup(&fdt_earlycon, fdt_earlycon.options);
|
||||
|
||||
if (rt_strncmp(options, earlycon_magic, RT_ARRAY_SIZE(earlycon_magic)))
|
||||
{
|
||||
if (options[i] == RT_FDT_EARLYCON_OPTION_SIGNATURE)
|
||||
const char *option_start = options - 1;
|
||||
|
||||
while (option_start[-1] != '\0')
|
||||
{
|
||||
/* Restore ',' */
|
||||
((char *)options)[i++] = ',';
|
||||
options = &options[i];
|
||||
options_len -= i;
|
||||
used_options = RT_TRUE;
|
||||
break;
|
||||
--option_start;
|
||||
}
|
||||
|
||||
rt_memmove(fdt_earlycon.options, option_start, options - option_start);
|
||||
}
|
||||
if (!used_options)
|
||||
else
|
||||
{
|
||||
options = RT_NULL;
|
||||
options_len = 0;
|
||||
fdt_earlycon.options[0] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -877,8 +885,8 @@ rt_err_t rt_fdt_scan_chosen_stdout(void)
|
|||
|
||||
if (fdt_earlycon.mmio)
|
||||
{
|
||||
LOG_I("Earlycon: %s at MMIO/PIO %p (options '%.*s')",
|
||||
con_type, fdt_earlycon.mmio, options_len, options ? options : "");
|
||||
LOG_I("Earlycon: %s at MMIO/PIO %p (options '%s')",
|
||||
con_type, fdt_earlycon.mmio, fdt_earlycon.options);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include <ioremap.h>
|
||||
#include <drivers/ofw.h>
|
||||
#include <drivers/ofw_io.h>
|
||||
#include <drivers/ofw_fdt.h>
|
||||
|
@ -155,7 +154,7 @@ static rt_err_t ofw_get_address_by_name(struct rt_ofw_node *np, const char *name
|
|||
|
||||
{
|
||||
int index = 0;
|
||||
rt_err_t err = RT_EOK;
|
||||
rt_err_t err = -RT_EEMPTY;
|
||||
const char *reg_name;
|
||||
struct rt_ofw_prop *prop;
|
||||
|
||||
|
@ -386,6 +385,22 @@ rt_uint64_t rt_ofw_translate_address(struct rt_ofw_node *np, const char *range_t
|
|||
return cpu_addr;
|
||||
}
|
||||
|
||||
#ifdef ARCH_CPU_64BIT
|
||||
#define ofw_address_cpu_cast(np, address) (void *)(address)
|
||||
#else
|
||||
#define ofw_address_cpu_cast(np, address) \
|
||||
({ \
|
||||
if (((address) >> 32)) \
|
||||
{ \
|
||||
LOG_W("%s find 64 bits address = %x%x", \
|
||||
rt_ofw_node_full_name(np), \
|
||||
ofw_static_cast(rt_ubase_t, (address) >> 32), \
|
||||
ofw_static_cast(rt_ubase_t, (address))); \
|
||||
} \
|
||||
(void *)ofw_static_cast(rt_ubase_t, (address)); \
|
||||
})
|
||||
#endif
|
||||
|
||||
void *rt_ofw_iomap(struct rt_ofw_node *np, int index)
|
||||
{
|
||||
void *iomem = RT_NULL;
|
||||
|
@ -396,7 +411,7 @@ void *rt_ofw_iomap(struct rt_ofw_node *np, int index)
|
|||
|
||||
if (!ofw_get_address(np, index, ®s[0], ®s[1]))
|
||||
{
|
||||
iomem = rt_ioremap((void *)regs[0], (size_t)regs[1]);
|
||||
iomem = rt_ioremap(ofw_address_cpu_cast(np, regs[0]), (size_t)regs[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -413,7 +428,7 @@ void *rt_ofw_iomap_by_name(struct rt_ofw_node *np, const char *name)
|
|||
|
||||
if (!ofw_get_address_by_name(np, name, ®s[0], ®s[1]))
|
||||
{
|
||||
iomem = rt_ioremap((void *)regs[0], (size_t)regs[1]);
|
||||
iomem = rt_ioremap(ofw_address_cpu_cast(np, regs[0]), (size_t)regs[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
|
@ -85,6 +85,41 @@ static const char *ofw_console_serial_find(char *dst_con, struct rt_ofw_node *np
|
|||
return ofw_name;
|
||||
}
|
||||
|
||||
static int tty_device_compare(rt_device_t dev, void *data)
|
||||
{
|
||||
rt_ubase_t *args_list;
|
||||
char *dst_con;
|
||||
const char *console, **ofw_name;
|
||||
const struct rt_ofw_node_id *id;
|
||||
struct rt_platform_device *pdev;
|
||||
int *tty_idx, tty_id, tty_name_len;
|
||||
|
||||
pdev = rt_container_of(dev, struct rt_platform_device, parent);
|
||||
id = pdev->id;
|
||||
|
||||
args_list = data;
|
||||
tty_idx = (int *)args_list[0];
|
||||
tty_id = args_list[1];
|
||||
console = (const char *)args_list[2];
|
||||
tty_name_len = args_list[3];
|
||||
dst_con = (char *)args_list[4];
|
||||
ofw_name = (const char **)args_list[5];
|
||||
|
||||
if (id && id->type[0] && !strncmp(id->type, console, tty_name_len))
|
||||
{
|
||||
if (*tty_idx == tty_id)
|
||||
{
|
||||
*ofw_name = ofw_console_serial_find(dst_con, pdev->parent.ofw_node);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
++*tty_idx;
|
||||
}
|
||||
|
||||
return -RT_EEMPTY;
|
||||
}
|
||||
|
||||
static const char *ofw_console_tty_find(char *dst_con, const char *con)
|
||||
{
|
||||
const char *ofw_name = RT_NULL;
|
||||
|
@ -97,8 +132,7 @@ static const char *ofw_console_tty_find(char *dst_con, const char *con)
|
|||
|
||||
if (platform_bus)
|
||||
{
|
||||
rt_device_t dev;
|
||||
rt_ubase_t level;
|
||||
rt_ubase_t args_list[6];
|
||||
const char *console = con;
|
||||
int tty_idx = 0, tty_id = 0, tty_name_len;
|
||||
|
||||
|
@ -119,27 +153,13 @@ static const char *ofw_console_tty_find(char *dst_con, const char *con)
|
|||
++con;
|
||||
}
|
||||
|
||||
level = rt_spin_lock_irqsave(&platform_bus->spinlock);
|
||||
|
||||
rt_list_for_each_entry(dev, &platform_bus->dev_list, node)
|
||||
{
|
||||
struct rt_platform_device *pdev = rt_container_of(dev, struct rt_platform_device, parent);
|
||||
const struct rt_ofw_node_id *id = pdev->id;
|
||||
|
||||
if (id && id->type[0] && !rt_strncmp(id->type, console, tty_name_len))
|
||||
{
|
||||
if (tty_idx == tty_id)
|
||||
{
|
||||
ofw_name = ofw_console_serial_find(dst_con, pdev->parent.ofw_node);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
++tty_idx;
|
||||
}
|
||||
}
|
||||
|
||||
rt_spin_unlock_irqrestore(&platform_bus->spinlock, level);
|
||||
args_list[0] = (rt_ubase_t)&tty_idx;
|
||||
args_list[1] = tty_id;
|
||||
args_list[2] = (rt_ubase_t)console;
|
||||
args_list[3] = tty_name_len;
|
||||
args_list[4] = (rt_ubase_t)dst_con;
|
||||
args_list[5] = (rt_ubase_t)&ofw_name;
|
||||
rt_bus_for_each_dev(platform_bus, &args_list, tty_device_compare);
|
||||
}
|
||||
|
||||
return ofw_name;
|
||||
|
@ -463,6 +483,11 @@ static void ofw_node_dump_dts(struct rt_ofw_node *np, rt_bool_t sibling_too)
|
|||
dts_put_depth(depth);
|
||||
rt_kputs("};\n");
|
||||
|
||||
if (!sibling_too && org_np == np)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
while (np->parent && !np->sibling)
|
||||
{
|
||||
np = np->parent;
|
||||
|
|
|
@ -68,6 +68,7 @@ extern struct rt_fdt_earlycon fdt_earlycon;
|
|||
(to_type)(((value) >> ((sizeof(value) - sizeof(to_type)) * 8)))
|
||||
|
||||
rt_err_t ofw_alias_scan(void);
|
||||
int ofw_alias_node_id(struct rt_ofw_node *np);
|
||||
rt_err_t ofw_phandle_hash_reset(rt_phandle min, rt_phandle max);
|
||||
|
||||
#endif /* __OFW_INTERNAL_H__ */
|
||||
|
|
|
@ -1470,6 +1470,7 @@ enum rt_device_class_type
|
|||
*/
|
||||
#define RT_DEVICE_CTRL_BASE(Type) ((RT_Device_Class_##Type + 1) * 0x100)
|
||||
|
||||
typedef struct rt_driver *rt_driver_t;
|
||||
typedef struct rt_device *rt_device_t;
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
|
|
Loading…
Reference in New Issue