Browse Source

[smart] select console device dynamically (#8949)

* [smart] select console device dynamically

- Fixed compiler warning on terminal subsystem for
  `components/lwp/terminal/terminal.h`
- Updated default console setup to dynamically select an appropriate tty
  device based on the configured console device name.

Signed-off-by: Shell <smokewood@qq.com>

* fixup: remove useless codes

---------

Signed-off-by: Shell <smokewood@qq.com>
Shell 11 months ago
parent
commit
f2d6325b43

+ 63 - 0
components/drivers/serial/serial_tty.c

@@ -404,3 +404,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);

+ 1 - 28
components/lwp/lwp.c

@@ -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);

+ 2 - 3
components/lwp/terminal/terminal.h

@@ -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 - 0
include/rtdef.h

@@ -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 - 0
include/rtthread.h

@@ -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);
 

+ 58 - 9
src/object.c

@@ -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;
 }