This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit b30f866f8016c53e5299ade0dbff3e2ef60b89b1
Author: wangjianyu3 <[email protected]>
AuthorDate: Tue Nov 7 20:10:19 2023 +0800

    Thermal: Add procfs file nodes
    
    Signed-off-by: wangjianyu3 <[email protected]>
---
 drivers/thermal/Kconfig          |   7 +
 drivers/thermal/Make.defs        |   4 +
 drivers/thermal/thermal_core.c   |   9 +
 drivers/thermal/thermal_core.h   |   7 +
 drivers/thermal/thermal_procfs.c | 343 +++++++++++++++++++++++++++++++++++++++
 fs/procfs/fs_procfs.c            |   6 +
 6 files changed, 376 insertions(+)

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index d02327b6eb..4f795a97b2 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -30,4 +30,11 @@ config THERMAL_CDEV_CPUFREQ
        ---help---
                Enable thermal cpufreq cooling device.
 
+config THERMAL_PROCFS
+       bool "Thermal PROCFS support"
+       default n
+       depends on FS_PROCFS
+       ---help---
+               Enable thermal procfs.
+
 endif # THERMAL
diff --git a/drivers/thermal/Make.defs b/drivers/thermal/Make.defs
index fe2e806860..9e95fe4cfe 100644
--- a/drivers/thermal/Make.defs
+++ b/drivers/thermal/Make.defs
@@ -32,6 +32,10 @@ ifeq ($(CONFIG_THERMAL_CDEV_CPUFREQ),y)
 CSRCS += thermal_cpufreq_cooling.c
 endif
 
+ifeq ($(CONFIG_THERMAL_PROCFS),y)
+CSRCS += thermal_procfs.c
+endif
+
 DEPPATH += --dep-path thermal
 VPATH += thermal
 
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index ec8c5a80ce..741bd9a84a 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -741,6 +741,10 @@ thermal_zone_device_register(FAR const char *name,
       device_bind(zdev, cdev);
     }
 
+#ifdef CONFIG_THERMAL_PROCFS
+  thermal_zone_procfs_register(zdev);
+#endif
+
   nxmutex_unlock(&g_thermal_lock);
 
   thinfo("Registered zone device %s\n", zdev->name);
@@ -780,6 +784,11 @@ void thermal_zone_device_unregister(FAR struct 
thermal_zone_device_s *zdev)
     }
 
   list_delete(&zdev->node);
+
+#ifdef CONFIG_THERMAL_PROCFS
+  thermal_zone_procfs_unregister(zdev);
+#endif
+
   zone_set_governor(zdev, NULL);
   kmm_free(zdev);
   nxmutex_unlock(&g_thermal_lock);
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index 46537dff7d..8b7bcc37f5 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -82,4 +82,11 @@ int thermal_zone_get_trip_hyst(FAR struct 
thermal_zone_device_s *zdev,
 
 int thermal_register_step_wise_governor(void);
 
+/* ProcFS */
+
+#ifdef CONFIG_THERMAL_PROCFS
+int thermal_zone_procfs_register(FAR struct thermal_zone_device_s *zdev);
+void thermal_zone_procfs_unregister(FAR struct thermal_zone_device_s *zdev);
+#endif
+
 #endif /* __DRIVERS_THERMAL_THERMAL_CORE_H */
diff --git a/drivers/thermal/thermal_procfs.c b/drivers/thermal/thermal_procfs.c
new file mode 100644
index 0000000000..67b018584d
--- /dev/null
+++ b/drivers/thermal/thermal_procfs.c
@@ -0,0 +1,343 @@
+/****************************************************************************
+ * drivers/thermal/thermal_procfs.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/list.h>
+#include <nuttx/fs/procfs.h>
+#include <nuttx/kmalloc.h>
+
+#include <assert.h>
+#include <sys/stat.h>
+
+#include "thermal_core.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct thermal_procfs_s
+{
+  struct procfs_file_s base;
+  FAR struct thermal_zone_device_s *zdev;
+  struct list_node node;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Procfs operations */
+
+static int     thermal_procfs_open     (FAR struct file *filep,
+                                        FAR const char *relpath,
+                                        int oflags, mode_t mode);
+static int     thermal_procfs_close    (FAR struct file *filep);
+static ssize_t thermal_procfs_read     (FAR struct file *filep,
+                                        FAR char *buffer,
+                                        size_t buflen);
+static ssize_t thermal_procfs_write    (FAR struct file *filep,
+                                        FAR const char *buffer,
+                                        size_t buflen);
+static int     thermal_procfs_dup      (FAR const struct file *oldp,
+                                        FAR struct file *newp);
+static int     thermal_procfs_opendir  (FAR const char *relpath,
+                                        FAR struct fs_dirent_s **dir);
+static int     thermal_procfs_closedir (FAR struct fs_dirent_s *dir);
+static int     thermal_procfs_readdir  (FAR struct fs_dirent_s *dir,
+                                        FAR struct dirent *entry);
+static int     thermal_procfs_rewinddir(FAR struct fs_dirent_s *dir);
+static int     thermal_procfs_stat     (FAR const char *relpath,
+                                        FAR struct stat *buf);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct list_node
+g_thermal_procfs_list = LIST_INITIAL_VALUE(g_thermal_procfs_list);
+static mutex_t g_thermal_procfs_lock = NXMUTEX_INITIALIZER;
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+const struct procfs_operations g_thermal_operations =
+{
+  .open      = thermal_procfs_open,
+  .close     = thermal_procfs_close,
+  .read      = thermal_procfs_read,
+  .write     = thermal_procfs_write,
+  .poll      = NULL,
+  .dup       = thermal_procfs_dup,
+  .opendir   = thermal_procfs_opendir,
+  .closedir  = thermal_procfs_closedir,
+  .readdir   = thermal_procfs_readdir,
+  .rewinddir = thermal_procfs_rewinddir,
+  .stat      = thermal_procfs_stat,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int thermal_procfs_open(FAR struct file *filep,
+                               FAR const char *relpath,
+                               int oflags, mode_t mode)
+{
+  FAR struct thermal_procfs_s *child;
+
+  relpath += strlen("thermal/");
+  nxmutex_lock(&g_thermal_procfs_lock);
+
+  list_for_every_entry(&g_thermal_procfs_list, child,
+                       struct thermal_procfs_s, node)
+    {
+      if (!strcmp(child->zdev->name, relpath))
+        {
+          filep->f_priv = child;
+          nxmutex_unlock(&g_thermal_procfs_lock);
+          return OK;
+        }
+    }
+
+  nxmutex_unlock(&g_thermal_procfs_lock);
+  return -ENOENT;
+}
+
+static int thermal_procfs_close(FAR struct file *filep)
+{
+  filep->f_priv = NULL;
+  return OK;
+}
+
+static ssize_t thermal_procfs_read(FAR struct file *filep,
+                                   FAR char *buffer,
+                                   size_t buflen)
+{
+  FAR struct thermal_procfs_s *p = filep->f_priv;
+  FAR struct thermal_instance_s *ins;
+  off_t offset = filep->f_pos;
+  unsigned int current;
+
+  list_for_every_entry(&p->zdev->instance_list, ins,
+                       struct thermal_instance_s, zdev_node)
+    {
+      ins->cdev->ops->get_state(ins->cdev, &current);
+      procfs_sprintf(buffer, buflen, &offset,
+                     "z:%s t:%d t:%d h:%u l:%u c:%s s:%u|%u\n",
+                     ins->zdev->name,
+                     ins->zdev->temperature,
+                     ins->trip,
+                     ins->upper,
+                     ins->lower,
+                     ins->cdev->name,
+                     current,
+                     ins->target);
+    }
+
+  if (offset < 0)
+    {
+      offset = -offset;
+    }
+  else
+    {
+      offset = 0;
+    }
+
+  filep->f_pos += offset;
+  return offset;
+}
+
+static ssize_t thermal_procfs_write(FAR struct file *filep,
+                                    FAR const char *buffer,
+                                    size_t buflen)
+{
+  FAR struct thermal_procfs_s *p = filep->f_priv;
+
+  thermal_zone_enable(p->zdev, atoi(buffer) ? true : false);
+  return buflen;
+}
+
+static int thermal_procfs_dup(FAR const struct file *oldp,
+                              FAR struct file *newp)
+{
+  newp->f_priv = oldp->f_priv;
+  return OK;
+}
+
+static int thermal_procfs_opendir(FAR const char *relpath,
+                                  FAR struct fs_dirent_s **dir)
+{
+  FAR struct procfs_dir_priv_s *level1;
+
+  level1 = kmm_zalloc(sizeof(struct procfs_dir_priv_s));
+  if (level1 == NULL)
+    {
+      *dir = NULL;
+      return -ENOMEM;
+    }
+
+  level1->level = 1;
+
+  nxmutex_lock(&g_thermal_procfs_lock);
+  level1->nentries = list_length(&g_thermal_procfs_list);
+  nxmutex_unlock(&g_thermal_procfs_lock);
+
+  *dir = (FAR struct fs_dirent_s *)level1;
+  return OK;
+}
+
+static int thermal_procfs_closedir(FAR struct fs_dirent_s *dir)
+{
+  kmm_free(dir);
+  return OK;
+}
+
+static int thermal_procfs_readdir(FAR struct fs_dirent_s *dir,
+                                  FAR struct dirent *entry)
+{
+  FAR struct procfs_dir_priv_s *level1;
+  FAR struct thermal_procfs_s *child;
+  int index = 0;
+
+  DEBUGASSERT(dir);
+  level1 = (FAR struct procfs_dir_priv_s *)dir;
+
+  if (level1->index >= level1->nentries)
+    {
+      /* We signal the end of the directory by returning the special
+       * error -ENOENT
+       */
+
+      return -ENOENT;
+    }
+
+  nxmutex_lock(&g_thermal_procfs_lock);
+
+  list_for_every_entry(&g_thermal_procfs_list, child,
+                       struct thermal_procfs_s, node)
+    {
+      if (index == level1->index)
+        {
+          entry->d_type = DTYPE_FILE;
+
+          strlcpy(entry->d_name, child->zdev->name, NAME_MAX);
+          level1->index++;
+          nxmutex_unlock(&g_thermal_procfs_lock);
+          return OK;
+        }
+
+      index++;
+    }
+
+  nxmutex_unlock(&g_thermal_procfs_lock);
+  return -ENOENT;
+}
+
+static int thermal_procfs_rewinddir(FAR struct fs_dirent_s *dir)
+{
+  FAR struct procfs_dir_priv_s *level1;
+
+  DEBUGASSERT(dir);
+  level1 = (FAR struct procfs_dir_priv_s *)dir;
+  level1->index = 0;
+  return OK;
+}
+
+static int thermal_procfs_stat(FAR const char *relpath,
+                               FAR struct stat *buf)
+{
+  FAR struct thermal_procfs_s *child;
+
+  memset(buf, 0, sizeof(struct stat));
+
+  if (strcmp(relpath, "thermal") == 0 || strcmp(relpath, "thermal/") == 0)
+    {
+      buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR;
+      return OK;
+    }
+  else
+    {
+      relpath += strlen("thermal/");
+
+      nxmutex_lock(&g_thermal_procfs_lock);
+
+      list_for_every_entry(&g_thermal_procfs_list, child,
+                           struct thermal_procfs_s, node)
+        {
+          if (!strcmp(child->zdev->name, relpath))
+            {
+              buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR;
+              nxmutex_unlock(&g_thermal_procfs_lock);
+              return OK;
+            }
+        }
+
+      nxmutex_unlock(&g_thermal_procfs_lock);
+    }
+
+  return -ENOENT;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int thermal_zone_procfs_register(FAR struct thermal_zone_device_s *zdev)
+{
+  FAR struct thermal_procfs_s *p;
+
+  p = kmm_zalloc(sizeof(struct thermal_procfs_s));
+  if (!p)
+    {
+      nxmutex_unlock(&g_thermal_procfs_lock);
+      return -ENOMEM;
+    }
+
+  p->zdev  = zdev;
+
+  nxmutex_lock(&g_thermal_procfs_lock);
+  list_add_tail(&g_thermal_procfs_list, &p->node);
+  nxmutex_unlock(&g_thermal_procfs_lock);
+  return OK;
+}
+
+void thermal_zone_procfs_unregister(FAR struct thermal_zone_device_s *zdev)
+{
+  FAR struct thermal_procfs_s *p;
+
+  nxmutex_lock(&g_thermal_procfs_lock);
+
+  list_for_every_entry(&g_thermal_procfs_list, p,
+                       FAR struct thermal_procfs_s, node)
+    {
+      if (p->zdev == zdev)
+        {
+          list_delete(&p->node);
+          kmm_free(p);
+          break;
+        }
+    }
+
+  nxmutex_unlock(&g_thermal_procfs_lock);
+}
diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c
index 75a46b0a96..c66fed8a27 100644
--- a/fs/procfs/fs_procfs.c
+++ b/fs/procfs/fs_procfs.c
@@ -67,6 +67,7 @@ extern const struct procfs_operations g_module_operations;
 extern const struct procfs_operations g_pm_operations;
 extern const struct procfs_operations g_proc_operations;
 extern const struct procfs_operations g_tcbinfo_operations;
+extern const struct procfs_operations g_thermal_operations;
 extern const struct procfs_operations g_uptime_operations;
 extern const struct procfs_operations g_version_operations;
 extern const struct procfs_operations g_pressure_operations;
@@ -192,6 +193,11 @@ static const struct procfs_entry_s g_procfs_entries[] =
   { "tcbinfo",      &g_tcbinfo_operations,  PROCFS_FILE_TYPE   },
 #endif
 
+#ifdef CONFIG_THERMAL_PROCFS
+  { "thermal",      &g_thermal_operations,  PROCFS_DIR_TYPE    },
+  { "thermal/**",   &g_thermal_operations,  PROCFS_UNKOWN_TYPE },
+#endif
+
 #ifndef CONFIG_FS_PROCFS_EXCLUDE_UPTIME
   { "uptime",       &g_uptime_operations,   PROCFS_FILE_TYPE   },
 #endif

Reply via email to