linux/drivers/base/regmap/regmap-debugfs.c
<<
>>
Prefs
   1/*
   2 * Register map access API - debugfs
   3 *
   4 * Copyright 2011 Wolfson Microelectronics plc
   5 *
   6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/slab.h>
  14#include <linux/mutex.h>
  15#include <linux/debugfs.h>
  16#include <linux/uaccess.h>
  17#include <linux/device.h>
  18
  19#include "internal.h"
  20
  21static struct dentry *regmap_debugfs_root;
  22
  23/* Calculate the length of a fixed format  */
  24static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size)
  25{
  26        snprintf(buf, buf_size, "%x", max_val);
  27        return strlen(buf);
  28}
  29
  30static ssize_t regmap_name_read_file(struct file *file,
  31                                     char __user *user_buf, size_t count,
  32                                     loff_t *ppos)
  33{
  34        struct regmap *map = file->private_data;
  35        int ret;
  36        char *buf;
  37
  38        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
  39        if (!buf)
  40                return -ENOMEM;
  41
  42        ret = snprintf(buf, PAGE_SIZE, "%s\n", map->dev->driver->name);
  43        if (ret < 0) {
  44                kfree(buf);
  45                return ret;
  46        }
  47
  48        ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
  49        kfree(buf);
  50        return ret;
  51}
  52
  53static const struct file_operations regmap_name_fops = {
  54        .open = simple_open,
  55        .read = regmap_name_read_file,
  56        .llseek = default_llseek,
  57};
  58
  59static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
  60                                    size_t count, loff_t *ppos)
  61{
  62        int reg_len, val_len, tot_len;
  63        size_t buf_pos = 0;
  64        loff_t p = 0;
  65        ssize_t ret;
  66        int i;
  67        struct regmap *map = file->private_data;
  68        char *buf;
  69        unsigned int val;
  70
  71        if (*ppos < 0 || !count)
  72                return -EINVAL;
  73
  74        buf = kmalloc(count, GFP_KERNEL);
  75        if (!buf)
  76                return -ENOMEM;
  77
  78        /* Calculate the length of a fixed format  */
  79        reg_len = regmap_calc_reg_len(map->max_register, buf, count);
  80        val_len = 2 * map->format.val_bytes;
  81        tot_len = reg_len + val_len + 3;      /* : \n */
  82
  83        for (i = 0; i < map->max_register + 1; i++) {
  84                if (!regmap_readable(map, i))
  85                        continue;
  86
  87                if (regmap_precious(map, i))
  88                        continue;
  89
  90                /* If we're in the region the user is trying to read */
  91                if (p >= *ppos) {
  92                        /* ...but not beyond it */
  93                        if (buf_pos >= count - 1 - tot_len)
  94                                break;
  95
  96                        /* Format the register */
  97                        snprintf(buf + buf_pos, count - buf_pos, "%.*x: ",
  98                                 reg_len, i);
  99                        buf_pos += reg_len + 2;
 100
 101                        /* Format the value, write all X if we can't read */
 102                        ret = regmap_read(map, i, &val);
 103                        if (ret == 0)
 104                                snprintf(buf + buf_pos, count - buf_pos,
 105                                         "%.*x", val_len, val);
 106                        else
 107                                memset(buf + buf_pos, 'X', val_len);
 108                        buf_pos += 2 * map->format.val_bytes;
 109
 110                        buf[buf_pos++] = '\n';
 111                }
 112                p += tot_len;
 113        }
 114
 115        ret = buf_pos;
 116
 117        if (copy_to_user(user_buf, buf, buf_pos)) {
 118                ret = -EFAULT;
 119                goto out;
 120        }
 121
 122        *ppos += buf_pos;
 123
 124out:
 125        kfree(buf);
 126        return ret;
 127}
 128
 129#undef REGMAP_ALLOW_WRITE_DEBUGFS
 130#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
 131/*
 132 * This can be dangerous especially when we have clients such as
 133 * PMICs, therefore don't provide any real compile time configuration option
 134 * for this feature, people who want to use this will need to modify
 135 * the source code directly.
 136 */
 137static ssize_t regmap_map_write_file(struct file *file,
 138                                     const char __user *user_buf,
 139                                     size_t count, loff_t *ppos)
 140{
 141        char buf[32];
 142        size_t buf_size;
 143        char *start = buf;
 144        unsigned long reg, value;
 145        struct regmap *map = file->private_data;
 146
 147        buf_size = min(count, (sizeof(buf)-1));
 148        if (copy_from_user(buf, user_buf, buf_size))
 149                return -EFAULT;
 150        buf[buf_size] = 0;
 151
 152        while (*start == ' ')
 153                start++;
 154        reg = simple_strtoul(start, &start, 16);
 155        while (*start == ' ')
 156                start++;
 157        if (strict_strtoul(start, 16, &value))
 158                return -EINVAL;
 159
 160        /* Userspace has been fiddling around behind the kernel's back */
 161        add_taint(TAINT_USER);
 162
 163        regmap_write(map, reg, value);
 164        return buf_size;
 165}
 166#else
 167#define regmap_map_write_file NULL
 168#endif
 169
 170static const struct file_operations regmap_map_fops = {
 171        .open = simple_open,
 172        .read = regmap_map_read_file,
 173        .write = regmap_map_write_file,
 174        .llseek = default_llseek,
 175};
 176
 177static ssize_t regmap_access_read_file(struct file *file,
 178                                       char __user *user_buf, size_t count,
 179                                       loff_t *ppos)
 180{
 181        int reg_len, tot_len;
 182        size_t buf_pos = 0;
 183        loff_t p = 0;
 184        ssize_t ret;
 185        int i;
 186        struct regmap *map = file->private_data;
 187        char *buf;
 188
 189        if (*ppos < 0 || !count)
 190                return -EINVAL;
 191
 192        buf = kmalloc(count, GFP_KERNEL);
 193        if (!buf)
 194                return -ENOMEM;
 195
 196        /* Calculate the length of a fixed format  */
 197        reg_len = regmap_calc_reg_len(map->max_register, buf, count);
 198        tot_len = reg_len + 10; /* ': R W V P\n' */
 199
 200        for (i = 0; i < map->max_register + 1; i++) {
 201                /* Ignore registers which are neither readable nor writable */
 202                if (!regmap_readable(map, i) && !regmap_writeable(map, i))
 203                        continue;
 204
 205                /* If we're in the region the user is trying to read */
 206                if (p >= *ppos) {
 207                        /* ...but not beyond it */
 208                        if (buf_pos >= count - 1 - tot_len)
 209                                break;
 210
 211                        /* Format the register */
 212                        snprintf(buf + buf_pos, count - buf_pos,
 213                                 "%.*x: %c %c %c %c\n",
 214                                 reg_len, i,
 215                                 regmap_readable(map, i) ? 'y' : 'n',
 216                                 regmap_writeable(map, i) ? 'y' : 'n',
 217                                 regmap_volatile(map, i) ? 'y' : 'n',
 218                                 regmap_precious(map, i) ? 'y' : 'n');
 219
 220                        buf_pos += tot_len;
 221                }
 222                p += tot_len;
 223        }
 224
 225        ret = buf_pos;
 226
 227        if (copy_to_user(user_buf, buf, buf_pos)) {
 228                ret = -EFAULT;
 229                goto out;
 230        }
 231
 232        *ppos += buf_pos;
 233
 234out:
 235        kfree(buf);
 236        return ret;
 237}
 238
 239static const struct file_operations regmap_access_fops = {
 240        .open = simple_open,
 241        .read = regmap_access_read_file,
 242        .llseek = default_llseek,
 243};
 244
 245void regmap_debugfs_init(struct regmap *map)
 246{
 247        map->debugfs = debugfs_create_dir(dev_name(map->dev),
 248                                          regmap_debugfs_root);
 249        if (!map->debugfs) {
 250                dev_warn(map->dev, "Failed to create debugfs directory\n");
 251                return;
 252        }
 253
 254        debugfs_create_file("name", 0400, map->debugfs,
 255                            map, &regmap_name_fops);
 256
 257        if (map->max_register) {
 258                debugfs_create_file("registers", 0400, map->debugfs,
 259                                    map, &regmap_map_fops);
 260                debugfs_create_file("access", 0400, map->debugfs,
 261                                    map, &regmap_access_fops);
 262        }
 263
 264        if (map->cache_type) {
 265                debugfs_create_bool("cache_only", 0400, map->debugfs,
 266                                    &map->cache_only);
 267                debugfs_create_bool("cache_dirty", 0400, map->debugfs,
 268                                    &map->cache_dirty);
 269                debugfs_create_bool("cache_bypass", 0400, map->debugfs,
 270                                    &map->cache_bypass);
 271        }
 272}
 273
 274void regmap_debugfs_exit(struct regmap *map)
 275{
 276        debugfs_remove_recursive(map->debugfs);
 277}
 278
 279void regmap_debugfs_initcall(void)
 280{
 281        regmap_debugfs_root = debugfs_create_dir("regmap", NULL);
 282        if (!regmap_debugfs_root) {
 283                pr_warn("regmap: Failed to create debugfs root\n");
 284                return;
 285        }
 286}
 287