diff options
Diffstat (limited to 'drivers/base/regmap/regmap-debugfs.c')
-rw-r--r-- | drivers/base/regmap/regmap-debugfs.c | 89 |
1 files changed, 83 insertions, 6 deletions
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 6f397476e27c..251eb70f83e7 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c | |||
@@ -11,10 +11,10 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/module.h> | ||
15 | #include <linux/mutex.h> | 14 | #include <linux/mutex.h> |
16 | #include <linux/debugfs.h> | 15 | #include <linux/debugfs.h> |
17 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
17 | #include <linux/device.h> | ||
18 | 18 | ||
19 | #include "internal.h" | 19 | #include "internal.h" |
20 | 20 | ||
@@ -27,12 +27,35 @@ static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size) | |||
27 | return strlen(buf); | 27 | return strlen(buf); |
28 | } | 28 | } |
29 | 29 | ||
30 | static int regmap_open_file(struct inode *inode, struct file *file) | 30 | static ssize_t regmap_name_read_file(struct file *file, |
31 | char __user *user_buf, size_t count, | ||
32 | loff_t *ppos) | ||
31 | { | 33 | { |
32 | file->private_data = inode->i_private; | 34 | struct regmap *map = file->private_data; |
33 | return 0; | 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; | ||
34 | } | 51 | } |
35 | 52 | ||
53 | static const struct file_operations regmap_name_fops = { | ||
54 | .open = simple_open, | ||
55 | .read = regmap_name_read_file, | ||
56 | .llseek = default_llseek, | ||
57 | }; | ||
58 | |||
36 | static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, | 59 | static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, |
37 | size_t count, loff_t *ppos) | 60 | size_t count, loff_t *ppos) |
38 | { | 61 | { |
@@ -103,9 +126,51 @@ out: | |||
103 | return ret; | 126 | return ret; |
104 | } | 127 | } |
105 | 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 | */ | ||
137 | static 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 | |||
106 | static const struct file_operations regmap_map_fops = { | 170 | static const struct file_operations regmap_map_fops = { |
107 | .open = regmap_open_file, | 171 | .open = simple_open, |
108 | .read = regmap_map_read_file, | 172 | .read = regmap_map_read_file, |
173 | .write = regmap_map_write_file, | ||
109 | .llseek = default_llseek, | 174 | .llseek = default_llseek, |
110 | }; | 175 | }; |
111 | 176 | ||
@@ -172,7 +237,7 @@ out: | |||
172 | } | 237 | } |
173 | 238 | ||
174 | static const struct file_operations regmap_access_fops = { | 239 | static const struct file_operations regmap_access_fops = { |
175 | .open = regmap_open_file, | 240 | .open = simple_open, |
176 | .read = regmap_access_read_file, | 241 | .read = regmap_access_read_file, |
177 | .llseek = default_llseek, | 242 | .llseek = default_llseek, |
178 | }; | 243 | }; |
@@ -186,12 +251,24 @@ void regmap_debugfs_init(struct regmap *map) | |||
186 | return; | 251 | return; |
187 | } | 252 | } |
188 | 253 | ||
254 | debugfs_create_file("name", 0400, map->debugfs, | ||
255 | map, ®map_name_fops); | ||
256 | |||
189 | if (map->max_register) { | 257 | if (map->max_register) { |
190 | debugfs_create_file("registers", 0400, map->debugfs, | 258 | debugfs_create_file("registers", 0400, map->debugfs, |
191 | map, ®map_map_fops); | 259 | map, ®map_map_fops); |
192 | debugfs_create_file("access", 0400, map->debugfs, | 260 | debugfs_create_file("access", 0400, map->debugfs, |
193 | map, ®map_access_fops); | 261 | map, ®map_access_fops); |
194 | } | 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 | } | ||
195 | } | 272 | } |
196 | 273 | ||
197 | void regmap_debugfs_exit(struct regmap *map) | 274 | void regmap_debugfs_exit(struct regmap *map) |