Skip to content

[smart] select console device dynamically #8949

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 17, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions components/drivers/serial/serial_tty.c
Original file line number Diff line number Diff line change
@@ -402,3 +402,66 @@ static int _tty_workqueue_init(void)
return RT_EOK;
}
INIT_PREV_EXPORT(_tty_workqueue_init);

static rt_err_t _match_tty_iter(struct rt_object *obj, void *data)
{
rt_device_t target = *(rt_device_t *)data;
rt_device_t device = rt_container_of(obj, struct rt_device, parent);
if (device->type == RT_Device_Class_Char)
{
lwp_tty_t tp;
if (rt_strncmp(obj->name, "tty"TTY_NAME_PREFIX,
sizeof("tty"TTY_NAME_PREFIX) - 1) == 0)
{
struct serial_tty_context *softc;

tp = rt_container_of(device, struct lwp_tty, parent);
softc = tty_softc(tp);

if (&softc->parent->parent == target)
{
/* matched, early return */
*(rt_device_t *)data = device;
return 1;
}
}
}

return RT_EOK;
}

/**
* @brief The default console is only a backup device with lowest priority.
* It's always recommended to scratch the console from the boot arguments.
* And dont forget to register the device with a higher priority.
*/
static int _default_console_setup(void)
{
rt_err_t rc;
rt_device_t bakdev;
rt_device_t ttydev;

bakdev = rt_console_get_device();
if (!bakdev)
{
return -RT_ENOENT;
}

ttydev = bakdev;
rt_object_for_each(RT_Object_Class_Device, _match_tty_iter, &ttydev);

if (ttydev != bakdev)
{
LOG_I("Using /dev/%.*s as default console", RT_NAME_MAX, ttydev->parent.name);
lwp_console_register_backend(ttydev, LWP_CONSOLE_LOWEST_PRIOR);
rc = RT_EOK;
}
else
{
rc = -RT_EINVAL;
}

return rc;
}

INIT_COMPONENT_EXPORT(_default_console_setup);
29 changes: 1 addition & 28 deletions components/lwp/lwp.c
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
*/

#define DBG_TAG "lwp"
#define DBG_LVL DBG_WARNING
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

#include <rthw.h>
@@ -62,29 +62,6 @@ static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
extern char working_directory[];
#endif

/**
* @brief The default console is only a backup device with lowest priority.
* It's always recommended to scratch the console from the boot arguments.
* And dont forget to register the device with a higher priority.
*/
static rt_err_t lwp_default_console_setup(void)
{
rt_device_t bakdev = rt_device_find("ttyS0");
rt_err_t rc;

if (bakdev)
{
lwp_console_register_backend(bakdev, LWP_CONSOLE_LOWEST_PRIOR);
rc = RT_EOK;
}
else
{
rc = -RT_EINVAL;
}

return rc;
}

static int lwp_component_init(void)
{
int rc;
@@ -104,10 +81,6 @@ static int lwp_component_init(void)
{
LOG_E("%s: lwp_futex_init() failed", __func__);
}
else if ((rc = lwp_default_console_setup()) != RT_EOK)
{
LOG_E("%s: lwp_default_console_setup() failed", __func__);
}
return rc;
}
INIT_COMPONENT_EXPORT(lwp_component_init);
5 changes: 2 additions & 3 deletions components/lwp/terminal/terminal.h
Original file line number Diff line number Diff line change
@@ -212,9 +212,8 @@ void tty_rel_gone(struct lwp_tty *tp);
#define tty_lock_notrecused(tp) (rt_mutex_get_hold(tty_getlock(tp)) == 1)
#define tty_assert_locked(tp) RT_ASSERT(tty_lock_owned(tp))
#define tty_lock_assert(tp, option) \
(((option) == (MA_OWNED | MA_NOTRECURSED)) \
? (tty_lock_owned(tp) && tty_lock_notrecused(tp)) \
: rt_assert_handler("Operation not allowed", __func__, __LINE__))
RT_ASSERT(((option) == (MA_OWNED | MA_NOTRECURSED)) && \
(tty_lock_owned(tp) && tty_lock_notrecused(tp)))

/* System messages. */
int tty_checkoutq(struct lwp_tty *tp);
9 changes: 9 additions & 0 deletions include/rtdef.h
Original file line number Diff line number Diff line change
@@ -355,6 +355,15 @@ struct rt_object
};
typedef struct rt_object *rt_object_t; /**< Type for kernel objects. */

/**
* iterator of rt_object_for_each()
*
* data is the data passing in to rt_object_for_each(). iterator can return
* RT_EOK to continue the iteration; or any positive value to break the loop
* successfully; or any negative errno to break the loop on failure.
*/
typedef rt_err_t (*rt_object_iter_t)(rt_object_t object, void *data);

/**
* The object type can be one of the follows with specific
* macros enabled:
1 change: 1 addition & 0 deletions include/rtthread.h
Original file line number Diff line number Diff line change
@@ -75,6 +75,7 @@ rt_err_t rt_custom_object_destroy(rt_object_t obj);
#endif /* RT_USING_HEAP */
rt_bool_t rt_object_is_systemobject(rt_object_t object);
rt_uint8_t rt_object_get_type(rt_object_t object);
rt_err_t rt_object_for_each(rt_uint8_t type, rt_object_iter_t iter, void *data);
rt_object_t rt_object_find(const char *name, rt_uint8_t type);
rt_err_t rt_object_get_name(rt_object_t object, char *name, rt_uint8_t name_size);

67 changes: 58 additions & 9 deletions src/object.c
Original file line number Diff line number Diff line change
@@ -575,29 +575,32 @@ rt_uint8_t rt_object_get_type(rt_object_t object)
}

/**
* @brief This function will find specified name object from object
* @brief This function will iterate through each object from object
* container.
*
* @param name is the specified name of object.
*
* @param type is the type of object
* @param iter is the iterator
* @param data is the specified data passed to iterator
*
* @return the found object or RT_NULL if there is no this object
* in object container.
* @return RT_EOK on succeed, otherwise the error from `iter`
*
* @note this function shall not be invoked in interrupt status.
*/
rt_object_t rt_object_find(const char *name, rt_uint8_t type)
rt_err_t rt_object_for_each(rt_uint8_t type, rt_object_iter_t iter, void *data)
{
struct rt_object *object = RT_NULL;
struct rt_list_node *node = RT_NULL;
struct rt_object_information *information = RT_NULL;
rt_base_t level;
rt_err_t error;

information = rt_object_get_information((enum rt_object_class_type)type);

/* parameter check */
if ((name == RT_NULL) || (information == RT_NULL)) return RT_NULL;
if (information == RT_NULL)
{
return -RT_EINVAL;
}

/* which is invoke in interrupt status */
RT_DEBUG_NOT_IN_INTERRUPT;
@@ -609,16 +612,62 @@ rt_object_t rt_object_find(const char *name, rt_uint8_t type)
rt_list_for_each(node, &(information->object_list))
{
object = rt_list_entry(node, struct rt_object, list);
if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
if ((error = iter(object, data)) != RT_EOK)
{
rt_spin_unlock_irqrestore(&(information->spinlock), level);

return object;
return error >= 0 ? RT_EOK : error;
}
}

rt_spin_unlock_irqrestore(&(information->spinlock), level);

return RT_EOK;
}

static rt_err_t _match_name(struct rt_object *obj, void *data)
{
const char *name = *(const char **)data;
if (rt_strncmp(obj->name, name, RT_NAME_MAX) == 0)
{
*(rt_object_t *)data = obj;

/* notify an early break of loop, but not on error */
return 1;
}

return RT_EOK;
}

/**
* @brief This function will find specified name object from object
* container.
*
* @param name is the specified name of object.
*
* @param type is the type of object
*
* @return the found object or RT_NULL if there is no this object
* in object container.
*
* @note this function shall not be invoked in interrupt status.
*/
rt_object_t rt_object_find(const char *name, rt_uint8_t type)
{
void *data = (void *)name;

/* parameter check */
if (name == RT_NULL) return RT_NULL;

/* which is invoke in interrupt status */
RT_DEBUG_NOT_IN_INTERRUPT;

rt_object_for_each(type, _match_name, &data);
if (data != name)
{
return data;
}

return RT_NULL;
}