|
@@ -20,6 +20,7 @@
|
|
|
#include <linux/namei.h>
|
|
|
#include <linux/debugfs.h>
|
|
|
#include <linux/io.h>
|
|
|
+#include <linux/slab.h>
|
|
|
|
|
|
static ssize_t default_read_file(struct file *file, char __user *buf,
|
|
|
size_t count, loff_t *ppos)
|
|
@@ -520,6 +521,133 @@ struct dentry *debugfs_create_blob(const char *name, umode_t mode,
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(debugfs_create_blob);
|
|
|
|
|
|
+struct array_data {
|
|
|
+ void *array;
|
|
|
+ u32 elements;
|
|
|
+};
|
|
|
+
|
|
|
+static int u32_array_open(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ file->private_data = NULL;
|
|
|
+ return nonseekable_open(inode, file);
|
|
|
+}
|
|
|
+
|
|
|
+static size_t format_array(char *buf, size_t bufsize, const char *fmt,
|
|
|
+ u32 *array, u32 array_size)
|
|
|
+{
|
|
|
+ size_t ret = 0;
|
|
|
+ u32 i;
|
|
|
+
|
|
|
+ for (i = 0; i < array_size; i++) {
|
|
|
+ size_t len;
|
|
|
+
|
|
|
+ len = snprintf(buf, bufsize, fmt, array[i]);
|
|
|
+ len++; /* ' ' or '\n' */
|
|
|
+ ret += len;
|
|
|
+
|
|
|
+ if (buf) {
|
|
|
+ buf += len;
|
|
|
+ bufsize -= len;
|
|
|
+ buf[-1] = (i == array_size-1) ? '\n' : ' ';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ret++; /* \0 */
|
|
|
+ if (buf)
|
|
|
+ *buf = '\0';
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static char *format_array_alloc(const char *fmt, u32 *array,
|
|
|
+ u32 array_size)
|
|
|
+{
|
|
|
+ size_t len = format_array(NULL, 0, fmt, array, array_size);
|
|
|
+ char *ret;
|
|
|
+
|
|
|
+ ret = kmalloc(len, GFP_KERNEL);
|
|
|
+ if (ret == NULL)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ format_array(ret, len, fmt, array, array_size);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t u32_array_read(struct file *file, char __user *buf, size_t len,
|
|
|
+ loff_t *ppos)
|
|
|
+{
|
|
|
+ struct inode *inode = file->f_path.dentry->d_inode;
|
|
|
+ struct array_data *data = inode->i_private;
|
|
|
+ size_t size;
|
|
|
+
|
|
|
+ if (*ppos == 0) {
|
|
|
+ if (file->private_data) {
|
|
|
+ kfree(file->private_data);
|
|
|
+ file->private_data = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ file->private_data = format_array_alloc("%u", data->array,
|
|
|
+ data->elements);
|
|
|
+ }
|
|
|
+
|
|
|
+ size = 0;
|
|
|
+ if (file->private_data)
|
|
|
+ size = strlen(file->private_data);
|
|
|
+
|
|
|
+ return simple_read_from_buffer(buf, len, ppos,
|
|
|
+ file->private_data, size);
|
|
|
+}
|
|
|
+
|
|
|
+static int u32_array_release(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ kfree(file->private_data);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct file_operations u32_array_fops = {
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+ .open = u32_array_open,
|
|
|
+ .release = u32_array_release,
|
|
|
+ .read = u32_array_read,
|
|
|
+ .llseek = no_llseek,
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * debugfs_create_u32_array - create a debugfs file that is used to read u32
|
|
|
+ * array.
|
|
|
+ * @name: a pointer to a string containing the name of the file to create.
|
|
|
+ * @mode: the permission that the file should have.
|
|
|
+ * @parent: a pointer to the parent dentry for this file. This should be a
|
|
|
+ * directory dentry if set. If this parameter is %NULL, then the
|
|
|
+ * file will be created in the root of the debugfs filesystem.
|
|
|
+ * @array: u32 array that provides data.
|
|
|
+ * @elements: total number of elements in the array.
|
|
|
+ *
|
|
|
+ * This function creates a file in debugfs with the given name that exports
|
|
|
+ * @array as data. If the @mode variable is so set it can be read from.
|
|
|
+ * Writing is not supported. Seek within the file is also not supported.
|
|
|
+ * Once array is created its size can not be changed.
|
|
|
+ *
|
|
|
+ * The function returns a pointer to dentry on success. If debugfs is not
|
|
|
+ * enabled in the kernel, the value -%ENODEV will be returned.
|
|
|
+ */
|
|
|
+struct dentry *debugfs_create_u32_array(const char *name, umode_t mode,
|
|
|
+ struct dentry *parent,
|
|
|
+ u32 *array, u32 elements)
|
|
|
+{
|
|
|
+ struct array_data *data = kmalloc(sizeof(*data), GFP_KERNEL);
|
|
|
+
|
|
|
+ if (data == NULL)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ data->array = array;
|
|
|
+ data->elements = elements;
|
|
|
+
|
|
|
+ return debugfs_create_file(name, mode, parent, data, &u32_array_fops);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(debugfs_create_u32_array);
|
|
|
+
|
|
|
#ifdef CONFIG_HAS_IOMEM
|
|
|
|
|
|
/*
|