添加rtthread相关代码
This commit is contained in:
		
							
								
								
									
										18
									
								
								riscv/rtthread/components/drivers/core/SConscript
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										18
									
								
								riscv/rtthread/components/drivers/core/SConscript
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| from building import * | ||||
|  | ||||
| cwd = GetCurrentDir() | ||||
| src = ['device.c'] | ||||
| CPPPATH = [cwd + '/../include'] | ||||
|  | ||||
| if GetDepend(['RT_USING_DEV_BUS']) or GetDepend(['RT_USING_DM']): | ||||
|     src = src + ['bus.c'] | ||||
|  | ||||
| if GetDepend(['RT_USING_DM']): | ||||
|     src = src + ['dm.c', 'driver.c', 'platform.c'] | ||||
|  | ||||
| if GetDepend(['RT_USING_OFW']): | ||||
|     src += ['platform_ofw.c'] | ||||
|  | ||||
| group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_DEVICE'], CPPPATH = CPPPATH) | ||||
|  | ||||
| Return('group') | ||||
							
								
								
									
										520
									
								
								riscv/rtthread/components/drivers/core/bus.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										520
									
								
								riscv/rtthread/components/drivers/core/bus.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,520 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2024, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2022-10-13     flybreak     the first version | ||||
|  * 2023-04-12     ErikChan     support rt_bus | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
|  | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| #define DBG_TAG "dev_bus" | ||||
| #define DBG_LVL DBG_INFO | ||||
| #include <rtdbg.h> | ||||
|  | ||||
| #ifdef RT_USING_DEV_BUS | ||||
|  | ||||
| #if defined(RT_USING_POSIX_DEVIO) | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| #include <poll.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <dfs_file.h> | ||||
|  | ||||
| static int bus_fops_open(struct dfs_file *fd) | ||||
| { | ||||
|     LOG_D("bus fops open"); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int bus_fops_close(struct dfs_file *fd) | ||||
| { | ||||
|     LOG_D("bus fops close"); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static const struct dfs_file_ops bus_fops = | ||||
| { | ||||
|     bus_fops_open, | ||||
|     bus_fops_close, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| rt_device_t rt_device_bus_create(char *name, int attach_size) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     rt_device_t dev = rt_device_create(RT_Device_Class_Bus, 0); | ||||
|  | ||||
|     result = rt_device_register(dev, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE); | ||||
|     if (result < 0) | ||||
|     { | ||||
|         rt_kprintf("dev bus [%s] register failed!, ret=%d\n", name, result); | ||||
|         return RT_NULL; | ||||
|     } | ||||
| #if defined(RT_USING_POSIX_DEVIO) | ||||
|     dev->fops = &bus_fops; | ||||
| #endif | ||||
|  | ||||
|     LOG_D("bus create"); | ||||
|     return dev; | ||||
| } | ||||
|  | ||||
| rt_err_t rt_device_bus_destroy(rt_device_t dev) | ||||
| { | ||||
|     rt_device_unregister(dev); | ||||
|     dev->parent.type = RT_Object_Class_Device; | ||||
|     rt_device_destroy(dev); | ||||
|     LOG_D("bus destroy"); | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| #ifdef RT_USING_DM | ||||
| #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) | ||||
| { | ||||
|     rt_hw_spin_lock(&spinlock->lock); | ||||
| } | ||||
|  | ||||
| static void _dm_bus_unlock(struct rt_spinlock *spinlock) | ||||
| { | ||||
|     rt_hw_spin_unlock(&spinlock->lock); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  *  @brief This function loop the dev_list of the bus, and call fn in each loop | ||||
|  * | ||||
|  *  @param bus the target bus | ||||
|  * | ||||
|  *  @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, void *data, int (*fn)(rt_device_t dev, void *)) | ||||
| { | ||||
|     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); | ||||
|  | ||||
|     dev_list = &bus->dev_list; | ||||
|     dev_lock = &bus->dev_lock; | ||||
|  | ||||
|     _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) | ||||
|     { | ||||
|         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); | ||||
|     } | ||||
|  | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  *  @brief This function loop the drv_list of the bus, and call fn in each loop | ||||
|  * | ||||
|  *  @param bus the target bus | ||||
|  * | ||||
|  *  @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, void *data, int (*fn)(rt_driver_t drv, void *)) | ||||
| { | ||||
|     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); | ||||
|  | ||||
|     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) | ||||
|     { | ||||
|         if (!fn(drv, data)) | ||||
|         { | ||||
|             err = RT_EOK; | ||||
|  | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         _dm_bus_lock(drv_lock); | ||||
|         drv = rt_list_entry(drv->node.next, struct rt_driver, node); | ||||
|         _dm_bus_unlock(drv_lock); | ||||
|     } | ||||
|  | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| static rt_err_t bus_probe(rt_driver_t drv, rt_device_t dev) | ||||
| { | ||||
|     rt_bus_t bus = drv->bus; | ||||
|     rt_err_t err = -RT_EEMPTY; | ||||
|  | ||||
|     if (!bus) | ||||
|     { | ||||
|         bus = dev->bus; | ||||
|     } | ||||
|  | ||||
|     if (!dev->drv && bus->match(drv, dev)) | ||||
|     { | ||||
|         dev->drv = drv; | ||||
|  | ||||
|         err = bus->probe(dev); | ||||
|  | ||||
|         if (err) | ||||
|         { | ||||
|             dev->drv = RT_NULL; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     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; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  *  @brief This function add a driver to the drv_list of a specific bus | ||||
|  * | ||||
|  *  @param bus the bus to add | ||||
|  * | ||||
|  *  @param drv the driver to be added | ||||
|  * | ||||
|  *  @return the error code, RT_EOK on added successfully. | ||||
|  */ | ||||
| rt_err_t rt_bus_add_driver(rt_bus_t bus, rt_driver_t drv) | ||||
| { | ||||
|     RT_ASSERT(bus != RT_NULL); | ||||
|     RT_ASSERT(drv != RT_NULL); | ||||
|  | ||||
|     drv->bus = bus; | ||||
|     rt_list_init(&drv->node); | ||||
|  | ||||
|     _dm_bus_lock(&bus->drv_lock); | ||||
|     rt_list_insert_before(&bus->drv_list, &drv->node); | ||||
|     _dm_bus_unlock(&bus->drv_lock); | ||||
|  | ||||
|     rt_bus_for_each_dev(bus, drv, bus_probe_driver); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  *  @brief This function add a device to the dev_list of a specific bus | ||||
|  * | ||||
|  *  @param bus the bus to add | ||||
|  * | ||||
|  *  @param dev the device to be added | ||||
|  * | ||||
|  *  @return the error code, RT_EOK on added successfully. | ||||
|  */ | ||||
| rt_err_t rt_bus_add_device(rt_bus_t bus, rt_device_t dev) | ||||
| { | ||||
|     RT_ASSERT(bus != RT_NULL); | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|  | ||||
|     dev->bus = bus; | ||||
|     rt_list_init(&dev->node); | ||||
|  | ||||
|     _dm_bus_lock(&bus->dev_lock); | ||||
|     rt_list_insert_before(&bus->dev_list, &dev->node); | ||||
|     _dm_bus_unlock(&bus->dev_lock); | ||||
|  | ||||
|     rt_bus_for_each_drv(bus, dev, bus_probe_device); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  *  @brief This function remove a driver from bus | ||||
|  * | ||||
|  *  @param drv the driver to be removed | ||||
|  * | ||||
|  *  @return the error code, RT_EOK on added successfully. | ||||
|  */ | ||||
| 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); | ||||
|  | ||||
|     bus = drv->bus; | ||||
|  | ||||
|     LOG_D("Bus(%s) remove driver %s", bus->name, drv->parent.name); | ||||
|  | ||||
|     _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; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  *  @brief This function remove a device from bus | ||||
|  * | ||||
|  *  @param dev the device to be removed | ||||
|  * | ||||
|  *  @return the error code, RT_EOK on added successfully. | ||||
|  */ | ||||
| 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); | ||||
|  | ||||
|     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); | ||||
|  | ||||
|     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; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  *  @brief This function find a bus by name | ||||
|  *  @param bus the name to be finded | ||||
|  * | ||||
|  *  @return the bus finded by name. | ||||
|  */ | ||||
| rt_bus_t rt_bus_find_by_name(const char *name) | ||||
| { | ||||
|     rt_bus_t bus = RT_NULL; | ||||
|  | ||||
|     RT_ASSERT(name != RT_NULL); | ||||
|  | ||||
|     _dm_bus_lock(&bus_lock); | ||||
|  | ||||
|     rt_list_for_each_entry(bus, &bus_nodes, list) | ||||
|     { | ||||
|         if (!rt_strncmp(bus->name, name, RT_NAME_MAX)) | ||||
|         { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     _dm_bus_unlock(&bus_lock); | ||||
|  | ||||
|     return bus; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  *  @brief This function transfer dev_list and drv_list to the other bus | ||||
|  * | ||||
|  *  @param new_bus the bus to transfer | ||||
|  * | ||||
|  *  @param dev the target device | ||||
|  * | ||||
|  *  @return the error code, RT_EOK on added successfully. | ||||
|  */ | ||||
| rt_err_t rt_bus_reload_driver_device(rt_bus_t new_bus, rt_device_t dev) | ||||
| { | ||||
|     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); | ||||
|  | ||||
|     old_bus = dev->bus; | ||||
|  | ||||
|     _dm_bus_lock(&old_bus->dev_lock); | ||||
|     rt_list_remove(&dev->node); | ||||
|     _dm_bus_unlock(&old_bus->dev_lock); | ||||
|  | ||||
|     return rt_bus_add_device(new_bus, dev); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  *  @brief This function register a bus | ||||
|  *  @param bus the bus to be registered | ||||
|  * | ||||
|  *  @return the error code, RT_EOK on registeration successfully. | ||||
|  */ | ||||
| rt_err_t rt_bus_register(rt_bus_t bus) | ||||
| { | ||||
|     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->dev_lock); | ||||
|     rt_spin_lock_init(&bus->drv_lock); | ||||
|  | ||||
|     _dm_bus_lock(&bus_lock); | ||||
|  | ||||
|     rt_list_insert_before(&bus_nodes, &bus->list); | ||||
|  | ||||
|     _dm_bus_unlock(&bus_lock); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										481
									
								
								riscv/rtthread/components/drivers/core/device.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										481
									
								
								riscv/rtthread/components/drivers/core/device.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,481 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2021, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2007-01-21     Bernard      the first version | ||||
|  * 2010-05-04     Bernard      add rt_device_init implementation | ||||
|  * 2012-10-20     Bernard      add device check in register function, | ||||
|  *                             provided by Rob <rdent@iinet.net.au> | ||||
|  * 2012-12-25     Bernard      return RT_EOK if the device interface not exist. | ||||
|  * 2013-07-09     Grissiom     add ref_count support | ||||
|  * 2016-04-02     Bernard      fix the open_flag initialization issue. | ||||
|  * 2021-03-19     Meco Man     remove rt_device_init_all() | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
|  | ||||
| #define DBG_TAG           "kernel.device" | ||||
| #ifdef RT_DEBUG_DEVICE | ||||
| #define DBG_LVL           DBG_LOG | ||||
| #else | ||||
| #define DBG_LVL           DBG_WARNING | ||||
| #endif /* defined (RT_DEBUG_DEVICE) */ | ||||
| #include <rtdbg.h> | ||||
|  | ||||
| #ifdef RT_USING_POSIX_DEVIO | ||||
| #include <rtdevice.h> /* for wqueue_init */ | ||||
| #endif /* RT_USING_POSIX_DEVIO */ | ||||
|  | ||||
| #ifdef RT_USING_DFS_V2 | ||||
| #include <devfs.h> | ||||
| #endif /* RT_USING_DFS_V2 */ | ||||
|  | ||||
| #ifdef RT_USING_DEVICE | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
| #define device_init     (dev->ops ? dev->ops->init : RT_NULL) | ||||
| #define device_open     (dev->ops ? dev->ops->open : RT_NULL) | ||||
| #define device_close    (dev->ops ? dev->ops->close : RT_NULL) | ||||
| #define device_read     (dev->ops ? dev->ops->read : RT_NULL) | ||||
| #define device_write    (dev->ops ? dev->ops->write : RT_NULL) | ||||
| #define device_control  (dev->ops ? dev->ops->control : RT_NULL) | ||||
| #else | ||||
| #define device_init     (dev->init) | ||||
| #define device_open     (dev->open) | ||||
| #define device_close    (dev->close) | ||||
| #define device_read     (dev->read) | ||||
| #define device_write    (dev->write) | ||||
| #define device_control  (dev->control) | ||||
| #endif /* RT_USING_DEVICE_OPS */ | ||||
|  | ||||
| /** | ||||
|  * @brief This function registers a device driver with a specified name. | ||||
|  * | ||||
|  * @param dev is the pointer of device driver structure. | ||||
|  * | ||||
|  * @param name is the device driver's name. | ||||
|  * | ||||
|  * @param flags is the capabilities flag of device. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on initialization successfully. | ||||
|  */ | ||||
| rt_err_t rt_device_register(rt_device_t dev, | ||||
|                             const char *name, | ||||
|                             rt_uint16_t flags) | ||||
| { | ||||
|     if (dev == RT_NULL) | ||||
|         return -RT_ERROR; | ||||
|  | ||||
|     if (rt_device_find(name) != RT_NULL) | ||||
|         return -RT_ERROR; | ||||
|  | ||||
|     rt_object_init(&(dev->parent), RT_Object_Class_Device, name); | ||||
|     dev->flag = flags; | ||||
|     dev->ref_count = 0; | ||||
|     dev->open_flag = 0; | ||||
|  | ||||
| #ifdef RT_USING_POSIX_DEVIO | ||||
|     dev->fops = RT_NULL; | ||||
|     rt_wqueue_init(&(dev->wait_queue)); | ||||
| #endif /* RT_USING_POSIX_DEVIO */ | ||||
|  | ||||
| #ifdef RT_USING_DFS_V2 | ||||
|     dfs_devfs_device_add(dev); | ||||
| #endif /* RT_USING_DFS_V2 */ | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
| RTM_EXPORT(rt_device_register); | ||||
|  | ||||
| /** | ||||
|  * @brief This function removes a previously registered device driver. | ||||
|  * | ||||
|  * @param dev is the pointer of device driver structure. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_device_unregister(rt_device_t dev) | ||||
| { | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); | ||||
|     RT_ASSERT(rt_object_is_systemobject(&dev->parent)); | ||||
|  | ||||
|     rt_object_detach(&(dev->parent)); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
| RTM_EXPORT(rt_device_unregister); | ||||
|  | ||||
| /** | ||||
|  * @brief This function finds a device driver by specified name. | ||||
|  * | ||||
|  * @param name is the device driver's name. | ||||
|  * | ||||
|  * @return the registered device driver on successful, or RT_NULL on failure. | ||||
|  */ | ||||
| rt_device_t rt_device_find(const char *name) | ||||
| { | ||||
|     return (rt_device_t)rt_object_find(name, RT_Object_Class_Device); | ||||
| } | ||||
| RTM_EXPORT(rt_device_find); | ||||
|  | ||||
| #ifdef RT_USING_HEAP | ||||
| /** | ||||
|  * @brief This function creates a device object with user data size. | ||||
|  * | ||||
|  * @param type is the type of the device object. | ||||
|  * | ||||
|  * @param attach_size is the size of user data. | ||||
|  * | ||||
|  * @return the allocated device object, or RT_NULL when failed. | ||||
|  */ | ||||
| rt_device_t rt_device_create(int type, int attach_size) | ||||
| { | ||||
|     int size; | ||||
|     rt_device_t device; | ||||
|  | ||||
|     size = RT_ALIGN(sizeof(struct rt_device), RT_ALIGN_SIZE); | ||||
|     attach_size = RT_ALIGN(attach_size, RT_ALIGN_SIZE); | ||||
|     /* use the total size */ | ||||
|     size += attach_size; | ||||
|  | ||||
|     device = (rt_device_t)rt_malloc(size); | ||||
|     if (device) | ||||
|     { | ||||
|         rt_memset(device, 0x0, sizeof(struct rt_device)); | ||||
|         device->type = (enum rt_device_class_type)type; | ||||
|     } | ||||
|  | ||||
|     return device; | ||||
| } | ||||
| RTM_EXPORT(rt_device_create); | ||||
|  | ||||
| /** | ||||
|  * @brief This function destroy the specific device object. | ||||
|  * | ||||
|  * @param dev is a specific device object. | ||||
|  */ | ||||
| void rt_device_destroy(rt_device_t dev) | ||||
| { | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); | ||||
|     RT_ASSERT(rt_object_is_systemobject(&dev->parent) == RT_FALSE); | ||||
|  | ||||
|     rt_object_detach(&(dev->parent)); | ||||
|  | ||||
|     /* release this device object */ | ||||
|     rt_free(dev); | ||||
| } | ||||
| RTM_EXPORT(rt_device_destroy); | ||||
| #endif /* RT_USING_HEAP */ | ||||
|  | ||||
| /** | ||||
|  * @brief This function will initialize the specified device. | ||||
|  * | ||||
|  * @param dev is the pointer of device driver structure. | ||||
|  * | ||||
|  * @return the result, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_device_init(rt_device_t dev) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|  | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|  | ||||
|     /* get device_init handler */ | ||||
|     if (device_init != RT_NULL) | ||||
|     { | ||||
|         if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED)) | ||||
|         { | ||||
|             result = device_init(dev); | ||||
|             if (result != RT_EOK) | ||||
|             { | ||||
|                 LOG_E("To initialize device:%s failed. The error code is %d", | ||||
|                       dev->parent.name, result); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 dev->flag |= RT_DEVICE_FLAG_ACTIVATED; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief This function will open a device. | ||||
|  * | ||||
|  * @param dev is the pointer of device driver structure. | ||||
|  * | ||||
|  * @param oflag is the flags for device open. | ||||
|  * | ||||
|  * @return the result, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); | ||||
|  | ||||
|     /* if device is not initialized, initialize it. */ | ||||
|     if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED)) | ||||
|     { | ||||
|         if (device_init != RT_NULL) | ||||
|         { | ||||
|             result = device_init(dev); | ||||
|             if (result != RT_EOK) | ||||
|             { | ||||
|                 LOG_E("To initialize device:%s failed. The error code is %d", | ||||
|                       dev->parent.name, result); | ||||
|  | ||||
|                 return result; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         dev->flag |= RT_DEVICE_FLAG_ACTIVATED; | ||||
|     } | ||||
|  | ||||
|     /* device is a stand alone device and opened */ | ||||
|     if ((dev->flag & RT_DEVICE_FLAG_STANDALONE) && | ||||
|         (dev->open_flag & RT_DEVICE_OFLAG_OPEN)) | ||||
|     { | ||||
|         return -RT_EBUSY; | ||||
|     } | ||||
|  | ||||
|     /* device is not opened or opened by other oflag, call device_open interface */ | ||||
|     if (!(dev->open_flag & RT_DEVICE_OFLAG_OPEN) || | ||||
|          ((dev->open_flag & RT_DEVICE_OFLAG_MASK) != (oflag & RT_DEVICE_OFLAG_MASK))) | ||||
|     { | ||||
|         if (device_open != RT_NULL) | ||||
|         { | ||||
|             result = device_open(dev, oflag); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             /* set open flag */ | ||||
|             dev->open_flag = (oflag & RT_DEVICE_OFLAG_MASK); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* set open flag */ | ||||
|     if (result == RT_EOK || result == -RT_ENOSYS) | ||||
|     { | ||||
|         dev->open_flag |= RT_DEVICE_OFLAG_OPEN; | ||||
|  | ||||
|         dev->ref_count++; | ||||
|         /* don't let bad things happen silently. If you are bitten by this assert, | ||||
|         * please set the ref_count to a bigger type. */ | ||||
|         RT_ASSERT(dev->ref_count != 0); | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
| RTM_EXPORT(rt_device_open); | ||||
|  | ||||
| /** | ||||
|  * @brief This function will close a device. | ||||
|  * | ||||
|  * @param dev is the pointer of device driver structure. | ||||
|  * | ||||
|  * @return the result, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_device_close(rt_device_t dev) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); | ||||
|  | ||||
|     if (dev->ref_count == 0) | ||||
|         return -RT_ERROR; | ||||
|  | ||||
|     dev->ref_count--; | ||||
|  | ||||
|     if (dev->ref_count != 0) | ||||
|         return RT_EOK; | ||||
|  | ||||
|     /* call device_close interface */ | ||||
|     if (device_close != RT_NULL) | ||||
|     { | ||||
|         result = device_close(dev); | ||||
|     } | ||||
|  | ||||
|     /* set open flag */ | ||||
|     if (result == RT_EOK || result == -RT_ENOSYS) | ||||
|         dev->open_flag = RT_DEVICE_OFLAG_CLOSE; | ||||
|  | ||||
|     return result; | ||||
| } | ||||
| RTM_EXPORT(rt_device_close); | ||||
|  | ||||
| /** | ||||
|  * @brief This function will read some data from a device. | ||||
|  * | ||||
|  * @param dev is the pointer of device driver structure. | ||||
|  * | ||||
|  * @param pos is the position when reading. | ||||
|  * | ||||
|  * @param buffer is a data buffer to save the read data. | ||||
|  * | ||||
|  * @param size is the size of buffer. | ||||
|  * | ||||
|  * @return the actually read size on successful, otherwise 0 will be returned. | ||||
|  * | ||||
|  * @note the unit of size/pos is a block for block device. | ||||
|  */ | ||||
| rt_ssize_t rt_device_read(rt_device_t dev, | ||||
|                          rt_off_t    pos, | ||||
|                          void       *buffer, | ||||
|                          rt_size_t   size) | ||||
| { | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); | ||||
|  | ||||
|     if (dev->ref_count == 0) | ||||
|     { | ||||
|         rt_set_errno(-RT_ERROR); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     /* call device_read interface */ | ||||
|     if (device_read != RT_NULL) | ||||
|     { | ||||
|         return device_read(dev, pos, buffer, size); | ||||
|     } | ||||
|  | ||||
|     /* set error code */ | ||||
|     rt_set_errno(-RT_ENOSYS); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| RTM_EXPORT(rt_device_read); | ||||
|  | ||||
| /** | ||||
|  * @brief This function will write some data to a device. | ||||
|  * | ||||
|  * @param dev is the pointer of device driver structure. | ||||
|  * | ||||
|  * @param pos is the position when writing. | ||||
|  * | ||||
|  * @param buffer is the data buffer to be written to device. | ||||
|  * | ||||
|  * @param size is the size of buffer. | ||||
|  * | ||||
|  * @return the actually written size on successful, otherwise 0 will be returned. | ||||
|  * | ||||
|  * @note the unit of size/pos is a block for block device. | ||||
|  */ | ||||
| rt_ssize_t rt_device_write(rt_device_t dev, | ||||
|                           rt_off_t    pos, | ||||
|                           const void *buffer, | ||||
|                           rt_size_t   size) | ||||
| { | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); | ||||
|  | ||||
|     if (dev->ref_count == 0) | ||||
|     { | ||||
|         rt_set_errno(-RT_ERROR); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     /* call device_write interface */ | ||||
|     if (device_write != RT_NULL) | ||||
|     { | ||||
|         return device_write(dev, pos, buffer, size); | ||||
|     } | ||||
|  | ||||
|     /* set error code */ | ||||
|     rt_set_errno(-RT_ENOSYS); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| RTM_EXPORT(rt_device_write); | ||||
|  | ||||
| /** | ||||
|  * @brief This function will perform a variety of control functions on devices. | ||||
|  * | ||||
|  * @param dev is the pointer of device driver structure. | ||||
|  * | ||||
|  * @param cmd is the command sent to device. | ||||
|  * | ||||
|  * @param arg is the argument of command. | ||||
|  * | ||||
|  * @return the result, -RT_ENOSYS for failed. | ||||
|  */ | ||||
| rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg) | ||||
| { | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); | ||||
|  | ||||
|     /* call device_write interface */ | ||||
|     if (device_control != RT_NULL) | ||||
|     { | ||||
|         return device_control(dev, cmd, arg); | ||||
|     } | ||||
|  | ||||
|     return -RT_ENOSYS; | ||||
| } | ||||
| RTM_EXPORT(rt_device_control); | ||||
|  | ||||
| /** | ||||
|  * @brief This function will set the reception indication callback function. This callback function | ||||
|  *        is invoked when this device receives data. | ||||
|  * | ||||
|  * @param dev is the pointer of device driver structure. | ||||
|  * | ||||
|  * @param rx_ind is the indication callback function. | ||||
|  * | ||||
|  * @return RT_EOK | ||||
|  */ | ||||
| rt_err_t rt_device_set_rx_indicate(rt_device_t dev, | ||||
|                                    rt_err_t (*rx_ind)(rt_device_t dev, | ||||
|                                    rt_size_t size)) | ||||
| { | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); | ||||
|  | ||||
|     dev->rx_indicate = rx_ind; | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
| RTM_EXPORT(rt_device_set_rx_indicate); | ||||
|  | ||||
| /** | ||||
|  * @brief This function will set a callback function. The callback function | ||||
|  *        will be called when device has written data to physical hardware. | ||||
|  * | ||||
|  * @param dev is the pointer of device driver structure. | ||||
|  * | ||||
|  * @param tx_done is the indication callback function. | ||||
|  * | ||||
|  * @return RT_EOK | ||||
|  */ | ||||
| rt_err_t rt_device_set_tx_complete(rt_device_t dev, | ||||
|                                    rt_err_t (*tx_done)(rt_device_t dev, | ||||
|                                    void *buffer)) | ||||
| { | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); | ||||
|  | ||||
|     dev->tx_complete = tx_done; | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
| RTM_EXPORT(rt_device_set_tx_complete); | ||||
|  | ||||
| #endif /* RT_USING_DEVICE */ | ||||
							
								
								
									
										469
									
								
								riscv/rtthread/components/drivers/core/dm.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										469
									
								
								riscv/rtthread/components/drivers/core/dm.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,469 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2024, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2023-04-20     ErikChan     the first version | ||||
|  */ | ||||
|  | ||||
| #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 | ||||
| static int rti_secondary_cpu_start(void) | ||||
| { | ||||
|     return 0; | ||||
| } | ||||
| INIT_EXPORT(rti_secondary_cpu_start, "6.end"); | ||||
|  | ||||
| static int rti_secondary_cpu_end(void) | ||||
| { | ||||
|     return 0; | ||||
| } | ||||
| INIT_EXPORT(rti_secondary_cpu_end, "7.end"); | ||||
|  | ||||
| void rt_dm_secondary_cpu_init(void) | ||||
| { | ||||
| #ifdef RT_DEBUGING_AUTO_INIT | ||||
|     int result; | ||||
|     const struct rt_init_desc *desc; | ||||
|  | ||||
|     rt_kprintf("do secondary cpu initialization.\n"); | ||||
|     for (desc = &__rt_init_desc_rti_secondary_cpu_start; desc < &__rt_init_desc_rti_secondary_cpu_end; ++desc) | ||||
|     { | ||||
|         rt_kprintf("initialize %s", desc->fn_name); | ||||
|         result = desc->fn(); | ||||
|         rt_kprintf(":%d done\n", result); | ||||
|     } | ||||
| #else | ||||
|     volatile const init_fn_t *fn_ptr; | ||||
|  | ||||
|     for (fn_ptr = &__rt_init_rti_secondary_cpu_start; fn_ptr < &__rt_init_rti_secondary_cpu_end; ++fn_ptr) | ||||
|     { | ||||
|         (*fn_ptr)(); | ||||
|     } | ||||
| #endif /* RT_DEBUGING_AUTO_INIT */ | ||||
| } | ||||
| #endif /* RT_USING_SMP */ | ||||
|  | ||||
| struct prefix_track | ||||
| { | ||||
|     rt_list_t list; | ||||
|  | ||||
|     int uid; | ||||
|     const char *prefix; | ||||
| }; | ||||
| static struct rt_spinlock _prefix_nodes_lock = { 0 }; | ||||
| static rt_list_t _prefix_nodes = RT_LIST_OBJECT_INIT(_prefix_nodes); | ||||
|  | ||||
| int rt_dm_dev_set_name_auto(rt_device_t dev, const char *prefix) | ||||
| { | ||||
|     int uid = -1; | ||||
|     struct prefix_track *pt = RT_NULL; | ||||
|  | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|     RT_ASSERT(prefix != RT_NULL); | ||||
|  | ||||
|     RT_DEBUG_NOT_IN_INTERRUPT; | ||||
|  | ||||
|     rt_spin_lock(&_prefix_nodes_lock); | ||||
|  | ||||
|     rt_list_for_each_entry(pt, &_prefix_nodes, list) | ||||
|     { | ||||
|         /* caller always input constants string, check ptr is faster */ | ||||
|         if (pt->prefix == prefix || !rt_strcmp(pt->prefix, prefix)) | ||||
|         { | ||||
|             uid = ++pt->uid; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     rt_spin_unlock(&_prefix_nodes_lock); | ||||
|  | ||||
|     if (uid < 0) | ||||
|     { | ||||
|         pt = rt_malloc(sizeof(*pt)); | ||||
|  | ||||
|         if (!pt) | ||||
|         { | ||||
|             return -RT_ENOMEM; | ||||
|         } | ||||
|  | ||||
|         rt_list_init(&pt->list); | ||||
|  | ||||
|         pt->uid = uid = 0; | ||||
|         pt->prefix = prefix; | ||||
|  | ||||
|         rt_spin_lock(&_prefix_nodes_lock); | ||||
|  | ||||
|         rt_list_insert_before(&_prefix_nodes, &pt->list); | ||||
|  | ||||
|         rt_spin_unlock(&_prefix_nodes_lock); | ||||
|     } | ||||
|  | ||||
|     return rt_dm_dev_set_name(dev, "%s%u", prefix, uid); | ||||
| } | ||||
|  | ||||
| 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_dev_get_name(dev); | ||||
|     len = rt_strlen(name) - 1; | ||||
|     name += len; | ||||
|  | ||||
|     while (len --> 0) | ||||
|     { | ||||
|         if (*name < '0' || *name > '9') | ||||
|         { | ||||
|             while (*(++name)) | ||||
|             { | ||||
|                 id *= 10; | ||||
|                 id += *name - '0'; | ||||
|             } | ||||
|  | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         --name; | ||||
|     } | ||||
|  | ||||
|     return id; | ||||
| } | ||||
|  | ||||
| int rt_dm_dev_set_name(rt_device_t dev, const char *format, ...) | ||||
| { | ||||
|     int n; | ||||
|     va_list arg_ptr; | ||||
|  | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|     RT_ASSERT(format != RT_NULL); | ||||
|  | ||||
|     va_start(arg_ptr, format); | ||||
|     n = rt_vsnprintf(dev->parent.name, RT_NAME_MAX, format, arg_ptr); | ||||
|     va_end(arg_ptr); | ||||
|  | ||||
|     return n; | ||||
| } | ||||
|  | ||||
| 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); | ||||
|  | ||||
| #if defined(RT_USING_OFW) && defined(RT_USING_PIC) | ||||
|     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); | ||||
|  | ||||
| #if defined(RT_USING_OFW) && defined(RT_USING_PIC) | ||||
|     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); | ||||
|  | ||||
| #if defined(RT_USING_OFW) && defined(RT_USING_PIC) | ||||
|     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 = RT_NULL; | ||||
|  | ||||
|     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; | ||||
| } | ||||
|  | ||||
							
								
								
									
										53
									
								
								riscv/rtthread/components/drivers/core/driver.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										53
									
								
								riscv/rtthread/components/drivers/core/driver.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include <drivers/core/bus.h> | ||||
|  | ||||
| #if defined(RT_USING_POSIX_DEVIO) | ||||
| #include <rtdevice.h> /* for wqueue_init */ | ||||
| #endif | ||||
|  | ||||
| /** | ||||
|  * This function attach a driver to bus | ||||
|  * | ||||
|  * @param drv the driver to be attached | ||||
|  */ | ||||
| rt_err_t rt_driver_register(rt_driver_t drv) | ||||
| { | ||||
|     rt_err_t ret; | ||||
|     struct rt_bus *bus = RT_NULL; | ||||
|  | ||||
|     RT_ASSERT(drv != RT_NULL); | ||||
|  | ||||
|     if (drv->bus) | ||||
|     { | ||||
|         bus = drv->bus; | ||||
|         ret = rt_bus_add_driver(bus, drv); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ret = -RT_EINVAL; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
| RTM_EXPORT(rt_driver_register); | ||||
|  | ||||
| /** | ||||
|  * This function remove driver from system. | ||||
|  * | ||||
|  * @param drv the driver to be removed | ||||
|  */ | ||||
| rt_err_t rt_driver_unregister(rt_driver_t drv) | ||||
| { | ||||
|     rt_err_t ret; | ||||
|  | ||||
|     ret = rt_bus_remove_driver(drv); | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
| RTM_EXPORT(rt_driver_register); | ||||
							
								
								
									
										156
									
								
								riscv/rtthread/components/drivers/core/platform.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										156
									
								
								riscv/rtthread/components/drivers/core/platform.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,156 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2021, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2023-04-12     ErikChan      the first version | ||||
|  * 2023-10-13     zmshahaha    distinguish ofw and none-ofw situation | ||||
|  */ | ||||
|  | ||||
| #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> | ||||
|  | ||||
| static struct rt_bus platform_bus; | ||||
|  | ||||
| /** | ||||
|  *  @brief This function create a platform device. | ||||
|  * | ||||
|  *  @param name is name of the platform device. | ||||
|  * | ||||
|  *  @return a new platform device. | ||||
|  */ | ||||
| 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; | ||||
|  | ||||
|     return pdev; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  *  @brief This function register a rt_driver to platform bus. | ||||
|  * | ||||
|  *  @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| 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); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  *  @brief This function register a rt_device to platform bus. | ||||
|  * | ||||
|  *  @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_platform_device_register(struct rt_platform_device *pdev) | ||||
| { | ||||
|     RT_ASSERT(pdev != RT_NULL); | ||||
|  | ||||
|     return rt_bus_add_device(&platform_bus, &pdev->parent); | ||||
| } | ||||
|  | ||||
| static rt_bool_t platform_match(rt_driver_t drv, rt_device_t dev) | ||||
| { | ||||
|     struct rt_platform_driver *pdrv = rt_container_of(drv, struct rt_platform_driver, parent); | ||||
|     struct rt_platform_device *pdev = rt_container_of(dev, struct rt_platform_device, parent); | ||||
|  | ||||
| #ifdef RT_USING_OFW | ||||
|     struct rt_ofw_node *np = dev->ofw_node; | ||||
|  | ||||
|     /* 1、match with ofw node */ | ||||
|     if (np) | ||||
|     { | ||||
|         pdev->id = rt_ofw_node_match(np, pdrv->ids); | ||||
|  | ||||
|         if (pdev->id) | ||||
|         { | ||||
|             return RT_TRUE; | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     /* 2、match with name */ | ||||
|     if (pdev->name && pdrv->name) | ||||
|     { | ||||
|         if (pdev->name == pdrv->name) | ||||
|         { | ||||
|             return RT_TRUE; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return !rt_strcmp(pdrv->name, pdev->name); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return RT_FALSE; | ||||
| } | ||||
|  | ||||
| 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 | ||||
|     struct rt_ofw_node *np = dev->ofw_node; | ||||
| #endif | ||||
|  | ||||
|     err = pdrv->probe(pdev); | ||||
|  | ||||
|     if (!err) | ||||
|     { | ||||
| #ifdef RT_USING_OFW | ||||
|         if (np) | ||||
|         { | ||||
|             rt_ofw_node_set_flag(np, RT_OFW_F_READLY); | ||||
|         } | ||||
| #endif | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         if (err == -RT_ENOMEM) | ||||
|         { | ||||
|             LOG_W("System not memory in driver %s", pdrv->name); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| static struct rt_bus platform_bus = | ||||
| { | ||||
|     .name = "platform", | ||||
|     .match = platform_match, | ||||
|     .probe = platform_probe, | ||||
| }; | ||||
|  | ||||
| static int platform_bus_init(void) | ||||
| { | ||||
|     rt_bus_register(&platform_bus); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| INIT_CORE_EXPORT(platform_bus_init); | ||||
							
								
								
									
										234
									
								
								riscv/rtthread/components/drivers/core/platform_ofw.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										234
									
								
								riscv/rtthread/components/drivers/core/platform_ofw.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,234 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2024, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2023-06-04     GuEe-GUI     the first version | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
|  | ||||
| #define DBG_TAG "drv.platform" | ||||
| #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", }, | ||||
| #ifdef RT_USING_MFD | ||||
|     { .compatible = "simple-mfd", }, | ||||
| #endif | ||||
| #ifdef RT_USING_ISA | ||||
|     { .compatible = "isa", }, | ||||
| #endif | ||||
| #ifdef RT_USING_AMBA_BUS | ||||
|     /* | ||||
|      * Maybe ARM has replaced it with compatible: "arm,primecell" and will not | ||||
|      * used anymore in the future. | ||||
|      */ | ||||
|     { .compatible = "arm,amba-bus", }, | ||||
| #endif | ||||
|     { /* 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; | ||||
|     struct rt_platform_device *pdev; | ||||
|  | ||||
|     rt_ofw_foreach_available_child_node(parent_np, np) | ||||
|     { | ||||
|         const char *name; | ||||
|         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)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         compat_prop = rt_ofw_get_prop(np, "compatible", RT_NULL); | ||||
|         name = rt_ofw_node_name(np); | ||||
|  | ||||
|         /* Not have name and compatible */ | ||||
|         if (!compat_prop && (name == (const char *)"<NULL>" || !rt_strcmp(name, "<NULL>"))) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         id = rt_ofw_prop_match(compat_prop, platform_ofw_ids); | ||||
|  | ||||
|         if (id && np->child) | ||||
|         { | ||||
|             /* scan next level */ | ||||
|             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 = alloc_ofw_platform_device(np); | ||||
|  | ||||
|         if (!pdev) | ||||
|         { | ||||
|             rt_ofw_node_put(np); | ||||
|             err = -RT_ENOMEM; | ||||
|  | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         pdev->dev_id = ofw_alias_node_id(np); | ||||
|         LOG_D("%s register to bus", np->full_name); | ||||
|  | ||||
|         rt_platform_device_register(pdev); | ||||
|     } | ||||
|  | ||||
|     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 *node; | ||||
|  | ||||
|     if (ofw_node_root) | ||||
|     { | ||||
|         err = platform_ofw_device_probe_once(ofw_node_root); | ||||
|  | ||||
|         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 | ||||
|     { | ||||
|         err = -RT_ENOSYS; | ||||
|     } | ||||
|  | ||||
|     return (int)err; | ||||
| } | ||||
| INIT_PLATFORM_EXPORT(platform_ofw_device_probe); | ||||
		Reference in New Issue
	
	Block a user