13bce94fdSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * file.c - part of debugfs, a tiny little debug file system
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
61da177e4SLinus Torvalds * Copyright (C) 2004 IBM Inc.
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * debugfs is for people to use instead of /proc or /sys.
9e1b4fc7aSMauro Carvalho Chehab * See Documentation/filesystems/ for more details.
101da177e4SLinus Torvalds */
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds #include <linux/module.h>
131da177e4SLinus Torvalds #include <linux/fs.h>
141a087c6aSAlessandro Rubini #include <linux/seq_file.h>
151da177e4SLinus Torvalds #include <linux/pagemap.h>
161da177e4SLinus Torvalds #include <linux/debugfs.h>
1703e099fbSAlessandro Rubini #include <linux/io.h>
189fe2a701SSrivatsa Vaddagiri #include <linux/slab.h>
193a76e5e0SSeth Jennings #include <linux/atomic.h>
2098210b7fSArend van Spriel #include <linux/device.h>
2130332eeeSGeert Uytterhoeven #include <linux/pm_runtime.h>
22cfe39442SAl Viro #include <linux/poll.h>
235496197fSDavid Howells #include <linux/security.h>
249fd4dcecSNicolai Stange
259fd4dcecSNicolai Stange #include "internal.h"
261da177e4SLinus Torvalds
2749d200deSNicolai Stange struct poll_table_struct;
2849d200deSNicolai Stange
default_read_file(struct file * file,char __user * buf,size_t count,loff_t * ppos)291da177e4SLinus Torvalds static ssize_t default_read_file(struct file *file, char __user *buf,
301da177e4SLinus Torvalds size_t count, loff_t *ppos)
311da177e4SLinus Torvalds {
321da177e4SLinus Torvalds return 0;
331da177e4SLinus Torvalds }
341da177e4SLinus Torvalds
default_write_file(struct file * file,const char __user * buf,size_t count,loff_t * ppos)351da177e4SLinus Torvalds static ssize_t default_write_file(struct file *file, const char __user *buf,
361da177e4SLinus Torvalds size_t count, loff_t *ppos)
371da177e4SLinus Torvalds {
381da177e4SLinus Torvalds return count;
391da177e4SLinus Torvalds }
401da177e4SLinus Torvalds
419fd4dcecSNicolai Stange const struct file_operations debugfs_noop_file_operations = {
421da177e4SLinus Torvalds .read = default_read_file,
431da177e4SLinus Torvalds .write = default_write_file,
44234e3405SStephen Boyd .open = simple_open,
456038f373SArnd Bergmann .llseek = noop_llseek,
461da177e4SLinus Torvalds };
471da177e4SLinus Torvalds
489fd4dcecSNicolai Stange #define F_DENTRY(filp) ((filp)->f_path.dentry)
499fd4dcecSNicolai Stange
debugfs_real_fops(const struct file * filp)507c8d4698SNicolai Stange const struct file_operations *debugfs_real_fops(const struct file *filp)
517c8d4698SNicolai Stange {
527c8d4698SNicolai Stange struct debugfs_fsdata *fsd = F_DENTRY(filp)->d_fsdata;
53055ab8e3SNicolai Stange
547d39bc50SNicolai Stange if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) {
557d39bc50SNicolai Stange /*
567d39bc50SNicolai Stange * Urgh, we've been called w/o a protecting
577d39bc50SNicolai Stange * debugfs_file_get().
587d39bc50SNicolai Stange */
597d39bc50SNicolai Stange WARN_ON(1);
607d39bc50SNicolai Stange return NULL;
617d39bc50SNicolai Stange }
627d39bc50SNicolai Stange
637c8d4698SNicolai Stange return fsd->real_fops;
647c8d4698SNicolai Stange }
657c8d4698SNicolai Stange EXPORT_SYMBOL_GPL(debugfs_real_fops);
667c8d4698SNicolai Stange
67e9117a5aSNicolai Stange /**
68e9117a5aSNicolai Stange * debugfs_file_get - mark the beginning of file data access
69e9117a5aSNicolai Stange * @dentry: the dentry object whose data is being accessed.
70e9117a5aSNicolai Stange *
71e9117a5aSNicolai Stange * Up to a matching call to debugfs_file_put(), any successive call
72e9117a5aSNicolai Stange * into the file removing functions debugfs_remove() and
73e9117a5aSNicolai Stange * debugfs_remove_recursive() will block. Since associated private
74e9117a5aSNicolai Stange * file data may only get freed after a successful return of any of
75e9117a5aSNicolai Stange * the removal functions, you may safely access it after a successful
76e9117a5aSNicolai Stange * call to debugfs_file_get() without worrying about lifetime issues.
77e9117a5aSNicolai Stange *
78e9117a5aSNicolai Stange * If -%EIO is returned, the file has already been removed and thus,
79e9117a5aSNicolai Stange * it is not safe to access any of its data. If, on the other hand,
80e9117a5aSNicolai Stange * it is allowed to access the file data, zero is returned.
81e9117a5aSNicolai Stange */
debugfs_file_get(struct dentry * dentry)82e9117a5aSNicolai Stange int debugfs_file_get(struct dentry *dentry)
83e9117a5aSNicolai Stange {
847d39bc50SNicolai Stange struct debugfs_fsdata *fsd;
857d39bc50SNicolai Stange void *d_fsd;
86e9117a5aSNicolai Stange
87*c455b17aSJohannes Berg /*
88*c455b17aSJohannes Berg * This could only happen if some debugfs user erroneously calls
89*c455b17aSJohannes Berg * debugfs_file_get() on a dentry that isn't even a file, let
90*c455b17aSJohannes Berg * them know about it.
91*c455b17aSJohannes Berg */
92*c455b17aSJohannes Berg if (WARN_ON(!d_is_reg(dentry)))
93*c455b17aSJohannes Berg return -EINVAL;
94*c455b17aSJohannes Berg
957d39bc50SNicolai Stange d_fsd = READ_ONCE(dentry->d_fsdata);
967d39bc50SNicolai Stange if (!((unsigned long)d_fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) {
977d39bc50SNicolai Stange fsd = d_fsd;
987d39bc50SNicolai Stange } else {
997d39bc50SNicolai Stange fsd = kmalloc(sizeof(*fsd), GFP_KERNEL);
1007d39bc50SNicolai Stange if (!fsd)
1017d39bc50SNicolai Stange return -ENOMEM;
1027d39bc50SNicolai Stange
1037d39bc50SNicolai Stange fsd->real_fops = (void *)((unsigned long)d_fsd &
1047d39bc50SNicolai Stange ~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);
1057d39bc50SNicolai Stange refcount_set(&fsd->active_users, 1);
1067d39bc50SNicolai Stange init_completion(&fsd->active_users_drained);
1077d39bc50SNicolai Stange if (cmpxchg(&dentry->d_fsdata, d_fsd, fsd) != d_fsd) {
1087d39bc50SNicolai Stange kfree(fsd);
1097d39bc50SNicolai Stange fsd = READ_ONCE(dentry->d_fsdata);
1107d39bc50SNicolai Stange }
1117d39bc50SNicolai Stange }
1127d39bc50SNicolai Stange
1137d39bc50SNicolai Stange /*
1147d39bc50SNicolai Stange * In case of a successful cmpxchg() above, this check is
1157d39bc50SNicolai Stange * strictly necessary and must follow it, see the comment in
1167d39bc50SNicolai Stange * __debugfs_remove_file().
1177d39bc50SNicolai Stange * OTOH, if the cmpxchg() hasn't been executed or wasn't
1187d39bc50SNicolai Stange * successful, this serves the purpose of not starving
1197d39bc50SNicolai Stange * removers.
1207d39bc50SNicolai Stange */
121e9117a5aSNicolai Stange if (d_unlinked(dentry))
122e9117a5aSNicolai Stange return -EIO;
123e9117a5aSNicolai Stange
124e9117a5aSNicolai Stange if (!refcount_inc_not_zero(&fsd->active_users))
125e9117a5aSNicolai Stange return -EIO;
126e9117a5aSNicolai Stange
127e9117a5aSNicolai Stange return 0;
128e9117a5aSNicolai Stange }
129e9117a5aSNicolai Stange EXPORT_SYMBOL_GPL(debugfs_file_get);
130e9117a5aSNicolai Stange
131e9117a5aSNicolai Stange /**
132e9117a5aSNicolai Stange * debugfs_file_put - mark the end of file data access
133e9117a5aSNicolai Stange * @dentry: the dentry object formerly passed to
134e9117a5aSNicolai Stange * debugfs_file_get().
135e9117a5aSNicolai Stange *
136e9117a5aSNicolai Stange * Allow any ongoing concurrent call into debugfs_remove() or
137e9117a5aSNicolai Stange * debugfs_remove_recursive() blocked by a former call to
138e9117a5aSNicolai Stange * debugfs_file_get() to proceed and return to its caller.
139e9117a5aSNicolai Stange */
debugfs_file_put(struct dentry * dentry)140e9117a5aSNicolai Stange void debugfs_file_put(struct dentry *dentry)
141e9117a5aSNicolai Stange {
1427d39bc50SNicolai Stange struct debugfs_fsdata *fsd = READ_ONCE(dentry->d_fsdata);
143e9117a5aSNicolai Stange
144e9117a5aSNicolai Stange if (refcount_dec_and_test(&fsd->active_users))
145e9117a5aSNicolai Stange complete(&fsd->active_users_drained);
146e9117a5aSNicolai Stange }
147e9117a5aSNicolai Stange EXPORT_SYMBOL_GPL(debugfs_file_put);
148e9117a5aSNicolai Stange
1495496197fSDavid Howells /*
1505496197fSDavid Howells * Only permit access to world-readable files when the kernel is locked down.
1515496197fSDavid Howells * We also need to exclude any file that has ways to write or alter it as root
1525496197fSDavid Howells * can bypass the permissions check.
1535496197fSDavid Howells */
debugfs_locked_down(struct inode * inode,struct file * filp,const struct file_operations * real_fops)154a37f4958SEric Snowberg static int debugfs_locked_down(struct inode *inode,
1555496197fSDavid Howells struct file *filp,
1565496197fSDavid Howells const struct file_operations *real_fops)
1575496197fSDavid Howells {
158358fcf5dSMichal Suchanek if ((inode->i_mode & 07777 & ~0444) == 0 &&
1595496197fSDavid Howells !(filp->f_mode & FMODE_WRITE) &&
1605496197fSDavid Howells !real_fops->unlocked_ioctl &&
1615496197fSDavid Howells !real_fops->compat_ioctl &&
1625496197fSDavid Howells !real_fops->mmap)
163a37f4958SEric Snowberg return 0;
1645496197fSDavid Howells
165a37f4958SEric Snowberg if (security_locked_down(LOCKDOWN_DEBUGFS))
166a37f4958SEric Snowberg return -EPERM;
167a37f4958SEric Snowberg
168a37f4958SEric Snowberg return 0;
1695496197fSDavid Howells }
1705496197fSDavid Howells
open_proxy_open(struct inode * inode,struct file * filp)1719fd4dcecSNicolai Stange static int open_proxy_open(struct inode *inode, struct file *filp)
1729fd4dcecSNicolai Stange {
17369d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(filp);
1749fd4dcecSNicolai Stange const struct file_operations *real_fops = NULL;
1757d39bc50SNicolai Stange int r;
1769fd4dcecSNicolai Stange
1777d39bc50SNicolai Stange r = debugfs_file_get(dentry);
1787d39bc50SNicolai Stange if (r)
1797d39bc50SNicolai Stange return r == -EIO ? -ENOENT : r;
1809fd4dcecSNicolai Stange
18186f0e067SChristian Lamparter real_fops = debugfs_real_fops(filp);
1825496197fSDavid Howells
183a37f4958SEric Snowberg r = debugfs_locked_down(inode, filp, real_fops);
1845496197fSDavid Howells if (r)
1855496197fSDavid Howells goto out;
1865496197fSDavid Howells
187275678e7STaehee Yoo if (!fops_get(real_fops)) {
188e3b9fc7eSVladis Dronov #ifdef CONFIG_MODULES
189275678e7STaehee Yoo if (real_fops->owner &&
190112cedc8SSven Eckelmann real_fops->owner->state == MODULE_STATE_GOING) {
191112cedc8SSven Eckelmann r = -ENXIO;
192275678e7STaehee Yoo goto out;
193112cedc8SSven Eckelmann }
194275678e7STaehee Yoo #endif
195275678e7STaehee Yoo
1969fd4dcecSNicolai Stange /* Huh? Module did not clean up after itself at exit? */
1979fd4dcecSNicolai Stange WARN(1, "debugfs file owner did not clean up at exit: %pd",
1989fd4dcecSNicolai Stange dentry);
1999fd4dcecSNicolai Stange r = -ENXIO;
2009fd4dcecSNicolai Stange goto out;
2019fd4dcecSNicolai Stange }
2029fd4dcecSNicolai Stange replace_fops(filp, real_fops);
2039fd4dcecSNicolai Stange
2049fd4dcecSNicolai Stange if (real_fops->open)
2059fd4dcecSNicolai Stange r = real_fops->open(inode, filp);
2069fd4dcecSNicolai Stange
2079fd4dcecSNicolai Stange out:
20869d29f9eSNicolai Stange debugfs_file_put(dentry);
2099fd4dcecSNicolai Stange return r;
2109fd4dcecSNicolai Stange }
2119fd4dcecSNicolai Stange
2129fd4dcecSNicolai Stange const struct file_operations debugfs_open_proxy_file_operations = {
2139fd4dcecSNicolai Stange .open = open_proxy_open,
2149fd4dcecSNicolai Stange };
2159fd4dcecSNicolai Stange
21649d200deSNicolai Stange #define PROTO(args...) args
21749d200deSNicolai Stange #define ARGS(args...) args
21849d200deSNicolai Stange
21949d200deSNicolai Stange #define FULL_PROXY_FUNC(name, ret_type, filp, proto, args) \
22049d200deSNicolai Stange static ret_type full_proxy_ ## name(proto) \
22149d200deSNicolai Stange { \
22269d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(filp); \
223154b9d75SNicolai Stange const struct file_operations *real_fops; \
22449d200deSNicolai Stange ret_type r; \
22549d200deSNicolai Stange \
22669d29f9eSNicolai Stange r = debugfs_file_get(dentry); \
22769d29f9eSNicolai Stange if (unlikely(r)) \
22869d29f9eSNicolai Stange return r; \
229154b9d75SNicolai Stange real_fops = debugfs_real_fops(filp); \
23049d200deSNicolai Stange r = real_fops->name(args); \
23169d29f9eSNicolai Stange debugfs_file_put(dentry); \
23249d200deSNicolai Stange return r; \
23349d200deSNicolai Stange }
23449d200deSNicolai Stange
23549d200deSNicolai Stange FULL_PROXY_FUNC(llseek, loff_t, filp,
23649d200deSNicolai Stange PROTO(struct file *filp, loff_t offset, int whence),
23749d200deSNicolai Stange ARGS(filp, offset, whence));
23849d200deSNicolai Stange
23949d200deSNicolai Stange FULL_PROXY_FUNC(read, ssize_t, filp,
24049d200deSNicolai Stange PROTO(struct file *filp, char __user *buf, size_t size,
24149d200deSNicolai Stange loff_t *ppos),
24249d200deSNicolai Stange ARGS(filp, buf, size, ppos));
24349d200deSNicolai Stange
24449d200deSNicolai Stange FULL_PROXY_FUNC(write, ssize_t, filp,
24549d200deSNicolai Stange PROTO(struct file *filp, const char __user *buf, size_t size,
24649d200deSNicolai Stange loff_t *ppos),
24749d200deSNicolai Stange ARGS(filp, buf, size, ppos));
24849d200deSNicolai Stange
24949d200deSNicolai Stange FULL_PROXY_FUNC(unlocked_ioctl, long, filp,
25049d200deSNicolai Stange PROTO(struct file *filp, unsigned int cmd, unsigned long arg),
25149d200deSNicolai Stange ARGS(filp, cmd, arg));
25249d200deSNicolai Stange
full_proxy_poll(struct file * filp,struct poll_table_struct * wait)253076ccb76SAl Viro static __poll_t full_proxy_poll(struct file *filp,
25449d200deSNicolai Stange struct poll_table_struct *wait)
25549d200deSNicolai Stange {
25669d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(filp);
257e6c8adcaSAl Viro __poll_t r = 0;
258154b9d75SNicolai Stange const struct file_operations *real_fops;
25949d200deSNicolai Stange
26069d29f9eSNicolai Stange if (debugfs_file_get(dentry))
261a9a08845SLinus Torvalds return EPOLLHUP;
26249d200deSNicolai Stange
263154b9d75SNicolai Stange real_fops = debugfs_real_fops(filp);
26449d200deSNicolai Stange r = real_fops->poll(filp, wait);
26569d29f9eSNicolai Stange debugfs_file_put(dentry);
26649d200deSNicolai Stange return r;
26749d200deSNicolai Stange }
26849d200deSNicolai Stange
full_proxy_release(struct inode * inode,struct file * filp)26949d200deSNicolai Stange static int full_proxy_release(struct inode *inode, struct file *filp)
27049d200deSNicolai Stange {
27149d200deSNicolai Stange const struct dentry *dentry = F_DENTRY(filp);
27286f0e067SChristian Lamparter const struct file_operations *real_fops = debugfs_real_fops(filp);
27349d200deSNicolai Stange const struct file_operations *proxy_fops = filp->f_op;
27449d200deSNicolai Stange int r = 0;
27549d200deSNicolai Stange
27649d200deSNicolai Stange /*
27749d200deSNicolai Stange * We must not protect this against removal races here: the
27849d200deSNicolai Stange * original releaser should be called unconditionally in order
27949d200deSNicolai Stange * not to leak any resources. Releasers must not assume that
28049d200deSNicolai Stange * ->i_private is still being meaningful here.
28149d200deSNicolai Stange */
28249d200deSNicolai Stange if (real_fops->release)
28349d200deSNicolai Stange r = real_fops->release(inode, filp);
28449d200deSNicolai Stange
28549d200deSNicolai Stange replace_fops(filp, d_inode(dentry)->i_fop);
286c80a67bdSXu Wang kfree(proxy_fops);
28749d200deSNicolai Stange fops_put(real_fops);
288a1a9e5d2SEric Engestrom return r;
28949d200deSNicolai Stange }
29049d200deSNicolai Stange
__full_proxy_fops_init(struct file_operations * proxy_fops,const struct file_operations * real_fops)29149d200deSNicolai Stange static void __full_proxy_fops_init(struct file_operations *proxy_fops,
29249d200deSNicolai Stange const struct file_operations *real_fops)
29349d200deSNicolai Stange {
29449d200deSNicolai Stange proxy_fops->release = full_proxy_release;
29549d200deSNicolai Stange if (real_fops->llseek)
29649d200deSNicolai Stange proxy_fops->llseek = full_proxy_llseek;
29749d200deSNicolai Stange if (real_fops->read)
29849d200deSNicolai Stange proxy_fops->read = full_proxy_read;
29949d200deSNicolai Stange if (real_fops->write)
30049d200deSNicolai Stange proxy_fops->write = full_proxy_write;
30149d200deSNicolai Stange if (real_fops->poll)
30249d200deSNicolai Stange proxy_fops->poll = full_proxy_poll;
30349d200deSNicolai Stange if (real_fops->unlocked_ioctl)
30449d200deSNicolai Stange proxy_fops->unlocked_ioctl = full_proxy_unlocked_ioctl;
30549d200deSNicolai Stange }
30649d200deSNicolai Stange
full_proxy_open(struct inode * inode,struct file * filp)30749d200deSNicolai Stange static int full_proxy_open(struct inode *inode, struct file *filp)
30849d200deSNicolai Stange {
30969d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(filp);
31049d200deSNicolai Stange const struct file_operations *real_fops = NULL;
31149d200deSNicolai Stange struct file_operations *proxy_fops = NULL;
3127d39bc50SNicolai Stange int r;
31349d200deSNicolai Stange
3147d39bc50SNicolai Stange r = debugfs_file_get(dentry);
3157d39bc50SNicolai Stange if (r)
3167d39bc50SNicolai Stange return r == -EIO ? -ENOENT : r;
31749d200deSNicolai Stange
31886f0e067SChristian Lamparter real_fops = debugfs_real_fops(filp);
3195496197fSDavid Howells
320a37f4958SEric Snowberg r = debugfs_locked_down(inode, filp, real_fops);
3215496197fSDavid Howells if (r)
3225496197fSDavid Howells goto out;
3235496197fSDavid Howells
324275678e7STaehee Yoo if (!fops_get(real_fops)) {
325e3b9fc7eSVladis Dronov #ifdef CONFIG_MODULES
326275678e7STaehee Yoo if (real_fops->owner &&
327112cedc8SSven Eckelmann real_fops->owner->state == MODULE_STATE_GOING) {
328112cedc8SSven Eckelmann r = -ENXIO;
329275678e7STaehee Yoo goto out;
330112cedc8SSven Eckelmann }
331275678e7STaehee Yoo #endif
332275678e7STaehee Yoo
33349d200deSNicolai Stange /* Huh? Module did not cleanup after itself at exit? */
33449d200deSNicolai Stange WARN(1, "debugfs file owner did not clean up at exit: %pd",
33549d200deSNicolai Stange dentry);
33649d200deSNicolai Stange r = -ENXIO;
33749d200deSNicolai Stange goto out;
33849d200deSNicolai Stange }
33949d200deSNicolai Stange
34049d200deSNicolai Stange proxy_fops = kzalloc(sizeof(*proxy_fops), GFP_KERNEL);
34149d200deSNicolai Stange if (!proxy_fops) {
34249d200deSNicolai Stange r = -ENOMEM;
34349d200deSNicolai Stange goto free_proxy;
34449d200deSNicolai Stange }
34549d200deSNicolai Stange __full_proxy_fops_init(proxy_fops, real_fops);
34649d200deSNicolai Stange replace_fops(filp, proxy_fops);
34749d200deSNicolai Stange
34849d200deSNicolai Stange if (real_fops->open) {
34949d200deSNicolai Stange r = real_fops->open(inode, filp);
350b10e3e90SNicolai Stange if (r) {
351b10e3e90SNicolai Stange replace_fops(filp, d_inode(dentry)->i_fop);
352b10e3e90SNicolai Stange goto free_proxy;
353b10e3e90SNicolai Stange } else if (filp->f_op != proxy_fops) {
35449d200deSNicolai Stange /* No protection against file removal anymore. */
35549d200deSNicolai Stange WARN(1, "debugfs file owner replaced proxy fops: %pd",
35649d200deSNicolai Stange dentry);
35749d200deSNicolai Stange goto free_proxy;
35849d200deSNicolai Stange }
35949d200deSNicolai Stange }
36049d200deSNicolai Stange
36149d200deSNicolai Stange goto out;
36249d200deSNicolai Stange free_proxy:
36349d200deSNicolai Stange kfree(proxy_fops);
36449d200deSNicolai Stange fops_put(real_fops);
36549d200deSNicolai Stange out:
36669d29f9eSNicolai Stange debugfs_file_put(dentry);
36749d200deSNicolai Stange return r;
36849d200deSNicolai Stange }
36949d200deSNicolai Stange
37049d200deSNicolai Stange const struct file_operations debugfs_full_proxy_file_operations = {
37149d200deSNicolai Stange .open = full_proxy_open,
37249d200deSNicolai Stange };
37349d200deSNicolai Stange
debugfs_attr_read(struct file * file,char __user * buf,size_t len,loff_t * ppos)374c6468808SNicolai Stange ssize_t debugfs_attr_read(struct file *file, char __user *buf,
375c6468808SNicolai Stange size_t len, loff_t *ppos)
376c6468808SNicolai Stange {
37769d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(file);
378c6468808SNicolai Stange ssize_t ret;
379c6468808SNicolai Stange
38069d29f9eSNicolai Stange ret = debugfs_file_get(dentry);
38169d29f9eSNicolai Stange if (unlikely(ret))
38269d29f9eSNicolai Stange return ret;
383c6468808SNicolai Stange ret = simple_attr_read(file, buf, len, ppos);
38469d29f9eSNicolai Stange debugfs_file_put(dentry);
385c6468808SNicolai Stange return ret;
386c6468808SNicolai Stange }
387c6468808SNicolai Stange EXPORT_SYMBOL_GPL(debugfs_attr_read);
388c6468808SNicolai Stange
debugfs_attr_write_xsigned(struct file * file,const char __user * buf,size_t len,loff_t * ppos,bool is_signed)389d472cf79SAkinobu Mita static ssize_t debugfs_attr_write_xsigned(struct file *file, const char __user *buf,
390d472cf79SAkinobu Mita size_t len, loff_t *ppos, bool is_signed)
391c6468808SNicolai Stange {
39269d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(file);
393c6468808SNicolai Stange ssize_t ret;
394c6468808SNicolai Stange
39569d29f9eSNicolai Stange ret = debugfs_file_get(dentry);
39669d29f9eSNicolai Stange if (unlikely(ret))
39769d29f9eSNicolai Stange return ret;
398d472cf79SAkinobu Mita if (is_signed)
399d472cf79SAkinobu Mita ret = simple_attr_write_signed(file, buf, len, ppos);
400d472cf79SAkinobu Mita else
401c6468808SNicolai Stange ret = simple_attr_write(file, buf, len, ppos);
40269d29f9eSNicolai Stange debugfs_file_put(dentry);
403c6468808SNicolai Stange return ret;
404c6468808SNicolai Stange }
405d472cf79SAkinobu Mita
debugfs_attr_write(struct file * file,const char __user * buf,size_t len,loff_t * ppos)406d472cf79SAkinobu Mita ssize_t debugfs_attr_write(struct file *file, const char __user *buf,
407d472cf79SAkinobu Mita size_t len, loff_t *ppos)
408d472cf79SAkinobu Mita {
409d472cf79SAkinobu Mita return debugfs_attr_write_xsigned(file, buf, len, ppos, false);
410d472cf79SAkinobu Mita }
411c6468808SNicolai Stange EXPORT_SYMBOL_GPL(debugfs_attr_write);
412c6468808SNicolai Stange
debugfs_attr_write_signed(struct file * file,const char __user * buf,size_t len,loff_t * ppos)413d472cf79SAkinobu Mita ssize_t debugfs_attr_write_signed(struct file *file, const char __user *buf,
414d472cf79SAkinobu Mita size_t len, loff_t *ppos)
415d472cf79SAkinobu Mita {
416d472cf79SAkinobu Mita return debugfs_attr_write_xsigned(file, buf, len, ppos, true);
417d472cf79SAkinobu Mita }
418d472cf79SAkinobu Mita EXPORT_SYMBOL_GPL(debugfs_attr_write_signed);
419d472cf79SAkinobu Mita
debugfs_create_mode_unsafe(const char * name,umode_t mode,struct dentry * parent,void * value,const struct file_operations * fops,const struct file_operations * fops_ro,const struct file_operations * fops_wo)4204909f168SNicolai Stange static struct dentry *debugfs_create_mode_unsafe(const char *name, umode_t mode,
4214909f168SNicolai Stange struct dentry *parent, void *value,
4224909f168SNicolai Stange const struct file_operations *fops,
4234909f168SNicolai Stange const struct file_operations *fops_ro,
4244909f168SNicolai Stange const struct file_operations *fops_wo)
4254909f168SNicolai Stange {
4264909f168SNicolai Stange /* if there are no write bits set, make read only */
4274909f168SNicolai Stange if (!(mode & S_IWUGO))
4284909f168SNicolai Stange return debugfs_create_file_unsafe(name, mode, parent, value,
4294909f168SNicolai Stange fops_ro);
4304909f168SNicolai Stange /* if there are no read bits set, make write only */
4314909f168SNicolai Stange if (!(mode & S_IRUGO))
4324909f168SNicolai Stange return debugfs_create_file_unsafe(name, mode, parent, value,
4334909f168SNicolai Stange fops_wo);
4344909f168SNicolai Stange
4354909f168SNicolai Stange return debugfs_create_file_unsafe(name, mode, parent, value, fops);
4364909f168SNicolai Stange }
4374909f168SNicolai Stange
debugfs_u8_set(void * data,u64 val)4388b88b099SChristoph Hellwig static int debugfs_u8_set(void *data, u64 val)
439acaefc25SArnd Bergmann {
440acaefc25SArnd Bergmann *(u8 *)data = val;
4418b88b099SChristoph Hellwig return 0;
442acaefc25SArnd Bergmann }
debugfs_u8_get(void * data,u64 * val)4438b88b099SChristoph Hellwig static int debugfs_u8_get(void *data, u64 *val)
444acaefc25SArnd Bergmann {
4458b88b099SChristoph Hellwig *val = *(u8 *)data;
4468b88b099SChristoph Hellwig return 0;
447acaefc25SArnd Bergmann }
4484909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n");
4494909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%llu\n");
4504909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n");
4511da177e4SLinus Torvalds
4521da177e4SLinus Torvalds /**
4536468b3afSRandy Dunlap * debugfs_create_u8 - create a debugfs file that is used to read and write an unsigned 8-bit value
4541da177e4SLinus Torvalds * @name: a pointer to a string containing the name of the file to create.
4551da177e4SLinus Torvalds * @mode: the permission that the file should have
4561da177e4SLinus Torvalds * @parent: a pointer to the parent dentry for this file. This should be a
4576468b3afSRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the
4581da177e4SLinus Torvalds * file will be created in the root of the debugfs filesystem.
4591da177e4SLinus Torvalds * @value: a pointer to the variable that the file should read to and write
4601da177e4SLinus Torvalds * from.
4611da177e4SLinus Torvalds *
4621da177e4SLinus Torvalds * This function creates a file in debugfs with the given name that
4631da177e4SLinus Torvalds * contains the value of the variable @value. If the @mode variable is so
4641da177e4SLinus Torvalds * set, it can be read from, and written to.
4651da177e4SLinus Torvalds */
debugfs_create_u8(const char * name,umode_t mode,struct dentry * parent,u8 * value)4669655ac4aSGreg Kroah-Hartman void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent,
4679655ac4aSGreg Kroah-Hartman u8 *value)
4681da177e4SLinus Torvalds {
4699655ac4aSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
470b97f6799SStephen Boyd &fops_u8_ro, &fops_u8_wo);
4711da177e4SLinus Torvalds }
4721da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(debugfs_create_u8);
4731da177e4SLinus Torvalds
debugfs_u16_set(void * data,u64 val)4748b88b099SChristoph Hellwig static int debugfs_u16_set(void *data, u64 val)
475acaefc25SArnd Bergmann {
476acaefc25SArnd Bergmann *(u16 *)data = val;
4778b88b099SChristoph Hellwig return 0;
478acaefc25SArnd Bergmann }
debugfs_u16_get(void * data,u64 * val)4798b88b099SChristoph Hellwig static int debugfs_u16_get(void *data, u64 *val)
480acaefc25SArnd Bergmann {
4818b88b099SChristoph Hellwig *val = *(u16 *)data;
4828b88b099SChristoph Hellwig return 0;
483acaefc25SArnd Bergmann }
4844909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n");
4854909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%llu\n");
4864909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n");
487acaefc25SArnd Bergmann
4881da177e4SLinus Torvalds /**
4896468b3afSRandy Dunlap * debugfs_create_u16 - create a debugfs file that is used to read and write an unsigned 16-bit value
4901da177e4SLinus Torvalds * @name: a pointer to a string containing the name of the file to create.
4911da177e4SLinus Torvalds * @mode: the permission that the file should have
4921da177e4SLinus Torvalds * @parent: a pointer to the parent dentry for this file. This should be a
4936468b3afSRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the
4941da177e4SLinus Torvalds * file will be created in the root of the debugfs filesystem.
4951da177e4SLinus Torvalds * @value: a pointer to the variable that the file should read to and write
4961da177e4SLinus Torvalds * from.
4971da177e4SLinus Torvalds *
4981da177e4SLinus Torvalds * This function creates a file in debugfs with the given name that
4991da177e4SLinus Torvalds * contains the value of the variable @value. If the @mode variable is so
5001da177e4SLinus Torvalds * set, it can be read from, and written to.
5011da177e4SLinus Torvalds */
debugfs_create_u16(const char * name,umode_t mode,struct dentry * parent,u16 * value)502313f5dbbSGreg Kroah-Hartman void debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent,
503313f5dbbSGreg Kroah-Hartman u16 *value)
5041da177e4SLinus Torvalds {
505313f5dbbSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16,
506b97f6799SStephen Boyd &fops_u16_ro, &fops_u16_wo);
5071da177e4SLinus Torvalds }
5081da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(debugfs_create_u16);
5091da177e4SLinus Torvalds
debugfs_u32_set(void * data,u64 val)5108b88b099SChristoph Hellwig static int debugfs_u32_set(void *data, u64 val)
511acaefc25SArnd Bergmann {
512acaefc25SArnd Bergmann *(u32 *)data = val;
5138b88b099SChristoph Hellwig return 0;
514acaefc25SArnd Bergmann }
debugfs_u32_get(void * data,u64 * val)5158b88b099SChristoph Hellwig static int debugfs_u32_get(void *data, u64 *val)
516acaefc25SArnd Bergmann {
5178b88b099SChristoph Hellwig *val = *(u32 *)data;
5188b88b099SChristoph Hellwig return 0;
519acaefc25SArnd Bergmann }
5204909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n");
5214909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%llu\n");
5224909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n");
523acaefc25SArnd Bergmann
5241da177e4SLinus Torvalds /**
5256468b3afSRandy Dunlap * debugfs_create_u32 - create a debugfs file that is used to read and write an unsigned 32-bit value
5261da177e4SLinus Torvalds * @name: a pointer to a string containing the name of the file to create.
5271da177e4SLinus Torvalds * @mode: the permission that the file should have
5281da177e4SLinus Torvalds * @parent: a pointer to the parent dentry for this file. This should be a
5296468b3afSRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the
5301da177e4SLinus Torvalds * file will be created in the root of the debugfs filesystem.
5311da177e4SLinus Torvalds * @value: a pointer to the variable that the file should read to and write
5321da177e4SLinus Torvalds * from.
5331da177e4SLinus Torvalds *
5341da177e4SLinus Torvalds * This function creates a file in debugfs with the given name that
5351da177e4SLinus Torvalds * contains the value of the variable @value. If the @mode variable is so
5361da177e4SLinus Torvalds * set, it can be read from, and written to.
5371da177e4SLinus Torvalds */
debugfs_create_u32(const char * name,umode_t mode,struct dentry * parent,u32 * value)5382b07021aSGreg Kroah-Hartman void debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent,
5392b07021aSGreg Kroah-Hartman u32 *value)
5401da177e4SLinus Torvalds {
5412b07021aSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32,
542b97f6799SStephen Boyd &fops_u32_ro, &fops_u32_wo);
5431da177e4SLinus Torvalds }
5441da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(debugfs_create_u32);
5451da177e4SLinus Torvalds
debugfs_u64_set(void * data,u64 val)5468b88b099SChristoph Hellwig static int debugfs_u64_set(void *data, u64 val)
5478447891fSMichael Ellerman {
5488447891fSMichael Ellerman *(u64 *)data = val;
5498b88b099SChristoph Hellwig return 0;
5508447891fSMichael Ellerman }
5518447891fSMichael Ellerman
debugfs_u64_get(void * data,u64 * val)5528b88b099SChristoph Hellwig static int debugfs_u64_get(void *data, u64 *val)
5538447891fSMichael Ellerman {
5548b88b099SChristoph Hellwig *val = *(u64 *)data;
5558b88b099SChristoph Hellwig return 0;
5568447891fSMichael Ellerman }
5574909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
5584909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%llu\n");
5594909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
5608447891fSMichael Ellerman
5618447891fSMichael Ellerman /**
5628447891fSMichael Ellerman * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value
5638447891fSMichael Ellerman * @name: a pointer to a string containing the name of the file to create.
5648447891fSMichael Ellerman * @mode: the permission that the file should have
5658447891fSMichael Ellerman * @parent: a pointer to the parent dentry for this file. This should be a
5668447891fSMichael Ellerman * directory dentry if set. If this parameter is %NULL, then the
5678447891fSMichael Ellerman * file will be created in the root of the debugfs filesystem.
5688447891fSMichael Ellerman * @value: a pointer to the variable that the file should read to and write
5698447891fSMichael Ellerman * from.
5708447891fSMichael Ellerman *
5718447891fSMichael Ellerman * This function creates a file in debugfs with the given name that
5728447891fSMichael Ellerman * contains the value of the variable @value. If the @mode variable is so
5738447891fSMichael Ellerman * set, it can be read from, and written to.
5748447891fSMichael Ellerman */
debugfs_create_u64(const char * name,umode_t mode,struct dentry * parent,u64 * value)575ad26221fSGreg Kroah-Hartman void debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent,
576ad26221fSGreg Kroah-Hartman u64 *value)
5778447891fSMichael Ellerman {
578ad26221fSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64,
579b97f6799SStephen Boyd &fops_u64_ro, &fops_u64_wo);
5808447891fSMichael Ellerman }
5818447891fSMichael Ellerman EXPORT_SYMBOL_GPL(debugfs_create_u64);
5828447891fSMichael Ellerman
debugfs_ulong_set(void * data,u64 val)583c23fe831SViresh Kumar static int debugfs_ulong_set(void *data, u64 val)
584c23fe831SViresh Kumar {
585c23fe831SViresh Kumar *(unsigned long *)data = val;
586c23fe831SViresh Kumar return 0;
587c23fe831SViresh Kumar }
588c23fe831SViresh Kumar
debugfs_ulong_get(void * data,u64 * val)589c23fe831SViresh Kumar static int debugfs_ulong_get(void *data, u64 *val)
590c23fe831SViresh Kumar {
591c23fe831SViresh Kumar *val = *(unsigned long *)data;
592c23fe831SViresh Kumar return 0;
593c23fe831SViresh Kumar }
5944909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set,
5954909f168SNicolai Stange "%llu\n");
5964909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n");
5974909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n");
598c23fe831SViresh Kumar
599c23fe831SViresh Kumar /**
600c23fe831SViresh Kumar * debugfs_create_ulong - create a debugfs file that is used to read and write
601c23fe831SViresh Kumar * an unsigned long value.
602c23fe831SViresh Kumar * @name: a pointer to a string containing the name of the file to create.
603c23fe831SViresh Kumar * @mode: the permission that the file should have
604c23fe831SViresh Kumar * @parent: a pointer to the parent dentry for this file. This should be a
605c23fe831SViresh Kumar * directory dentry if set. If this parameter is %NULL, then the
606c23fe831SViresh Kumar * file will be created in the root of the debugfs filesystem.
607c23fe831SViresh Kumar * @value: a pointer to the variable that the file should read to and write
608c23fe831SViresh Kumar * from.
609c23fe831SViresh Kumar *
610c23fe831SViresh Kumar * This function creates a file in debugfs with the given name that
611c23fe831SViresh Kumar * contains the value of the variable @value. If the @mode variable is so
612c23fe831SViresh Kumar * set, it can be read from, and written to.
613c23fe831SViresh Kumar */
debugfs_create_ulong(const char * name,umode_t mode,struct dentry * parent,unsigned long * value)614fb05b14cSGreg Kroah-Hartman void debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent,
615fb05b14cSGreg Kroah-Hartman unsigned long *value)
616c23fe831SViresh Kumar {
617fb05b14cSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_ulong,
618fb05b14cSGreg Kroah-Hartman &fops_ulong_ro, &fops_ulong_wo);
619c23fe831SViresh Kumar }
620c23fe831SViresh Kumar EXPORT_SYMBOL_GPL(debugfs_create_ulong);
621c23fe831SViresh Kumar
6224909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n");
6234909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%02llx\n");
6244909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%02llx\n");
6252ebefc50SRobin Getz
6264909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set,
6274909f168SNicolai Stange "0x%04llx\n");
6284909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%04llx\n");
6294909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%04llx\n");
6302ebefc50SRobin Getz
6314909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set,
6324909f168SNicolai Stange "0x%08llx\n");
6334909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%08llx\n");
6344909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%08llx\n");
6352ebefc50SRobin Getz
6364909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set,
6374909f168SNicolai Stange "0x%016llx\n");
6384909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_ro, debugfs_u64_get, NULL, "0x%016llx\n");
6394909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n");
64015b0beaaSHuang Ying
641e6716b87SRandy Dunlap /*
64215b0beaaSHuang Ying * debugfs_create_x{8,16,32,64} - create a debugfs file that is used to read and write an unsigned {8,16,32,64}-bit value
643e6716b87SRandy Dunlap *
644e6716b87SRandy Dunlap * These functions are exactly the same as the above functions (but use a hex
645e6716b87SRandy Dunlap * output for the decimal challenged). For details look at the above unsigned
646e6716b87SRandy Dunlap * decimal functions.
647e6716b87SRandy Dunlap */
648e6716b87SRandy Dunlap
6492ebefc50SRobin Getz /**
6502ebefc50SRobin Getz * debugfs_create_x8 - create a debugfs file that is used to read and write an unsigned 8-bit value
651e6716b87SRandy Dunlap * @name: a pointer to a string containing the name of the file to create.
652e6716b87SRandy Dunlap * @mode: the permission that the file should have
653e6716b87SRandy Dunlap * @parent: a pointer to the parent dentry for this file. This should be a
654e6716b87SRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the
655e6716b87SRandy Dunlap * file will be created in the root of the debugfs filesystem.
656e6716b87SRandy Dunlap * @value: a pointer to the variable that the file should read to and write
657e6716b87SRandy Dunlap * from.
6582ebefc50SRobin Getz */
debugfs_create_x8(const char * name,umode_t mode,struct dentry * parent,u8 * value)659c7c11689SGreg Kroah-Hartman void debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent,
660c7c11689SGreg Kroah-Hartman u8 *value)
6612ebefc50SRobin Getz {
662c7c11689SGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
663b97f6799SStephen Boyd &fops_x8_ro, &fops_x8_wo);
6642ebefc50SRobin Getz }
6652ebefc50SRobin Getz EXPORT_SYMBOL_GPL(debugfs_create_x8);
6662ebefc50SRobin Getz
667e6716b87SRandy Dunlap /**
668e6716b87SRandy Dunlap * debugfs_create_x16 - create a debugfs file that is used to read and write an unsigned 16-bit value
669e6716b87SRandy Dunlap * @name: a pointer to a string containing the name of the file to create.
670e6716b87SRandy Dunlap * @mode: the permission that the file should have
671e6716b87SRandy Dunlap * @parent: a pointer to the parent dentry for this file. This should be a
672e6716b87SRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the
673e6716b87SRandy Dunlap * file will be created in the root of the debugfs filesystem.
674e6716b87SRandy Dunlap * @value: a pointer to the variable that the file should read to and write
675e6716b87SRandy Dunlap * from.
676e6716b87SRandy Dunlap */
debugfs_create_x16(const char * name,umode_t mode,struct dentry * parent,u16 * value)677e40d38f2SGreg Kroah-Hartman void debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent,
678e40d38f2SGreg Kroah-Hartman u16 *value)
6792ebefc50SRobin Getz {
680e40d38f2SGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16,
681b97f6799SStephen Boyd &fops_x16_ro, &fops_x16_wo);
6822ebefc50SRobin Getz }
6832ebefc50SRobin Getz EXPORT_SYMBOL_GPL(debugfs_create_x16);
6842ebefc50SRobin Getz
685e6716b87SRandy Dunlap /**
686e6716b87SRandy Dunlap * debugfs_create_x32 - create a debugfs file that is used to read and write an unsigned 32-bit value
687e6716b87SRandy Dunlap * @name: a pointer to a string containing the name of the file to create.
688e6716b87SRandy Dunlap * @mode: the permission that the file should have
689e6716b87SRandy Dunlap * @parent: a pointer to the parent dentry for this file. This should be a
690e6716b87SRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the
691e6716b87SRandy Dunlap * file will be created in the root of the debugfs filesystem.
692e6716b87SRandy Dunlap * @value: a pointer to the variable that the file should read to and write
693e6716b87SRandy Dunlap * from.
694e6716b87SRandy Dunlap */
debugfs_create_x32(const char * name,umode_t mode,struct dentry * parent,u32 * value)695f5cb0a7eSGreg Kroah-Hartman void debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent,
696f5cb0a7eSGreg Kroah-Hartman u32 *value)
6972ebefc50SRobin Getz {
698f5cb0a7eSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32,
699b97f6799SStephen Boyd &fops_x32_ro, &fops_x32_wo);
7002ebefc50SRobin Getz }
7012ebefc50SRobin Getz EXPORT_SYMBOL_GPL(debugfs_create_x32);
7022ebefc50SRobin Getz
70315b0beaaSHuang Ying /**
70415b0beaaSHuang Ying * debugfs_create_x64 - create a debugfs file that is used to read and write an unsigned 64-bit value
70515b0beaaSHuang Ying * @name: a pointer to a string containing the name of the file to create.
70615b0beaaSHuang Ying * @mode: the permission that the file should have
70715b0beaaSHuang Ying * @parent: a pointer to the parent dentry for this file. This should be a
70815b0beaaSHuang Ying * directory dentry if set. If this parameter is %NULL, then the
70915b0beaaSHuang Ying * file will be created in the root of the debugfs filesystem.
71015b0beaaSHuang Ying * @value: a pointer to the variable that the file should read to and write
71115b0beaaSHuang Ying * from.
71215b0beaaSHuang Ying */
debugfs_create_x64(const char * name,umode_t mode,struct dentry * parent,u64 * value)7130864c408SGreg Kroah-Hartman void debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent,
7140864c408SGreg Kroah-Hartman u64 *value)
71515b0beaaSHuang Ying {
7160864c408SGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64,
71782b7d4fbSStephen Boyd &fops_x64_ro, &fops_x64_wo);
71815b0beaaSHuang Ying }
71915b0beaaSHuang Ying EXPORT_SYMBOL_GPL(debugfs_create_x64);
72015b0beaaSHuang Ying
7215e078787SInaky Perez-Gonzalez
debugfs_size_t_set(void * data,u64 val)7225e078787SInaky Perez-Gonzalez static int debugfs_size_t_set(void *data, u64 val)
7235e078787SInaky Perez-Gonzalez {
7245e078787SInaky Perez-Gonzalez *(size_t *)data = val;
7255e078787SInaky Perez-Gonzalez return 0;
7265e078787SInaky Perez-Gonzalez }
debugfs_size_t_get(void * data,u64 * val)7275e078787SInaky Perez-Gonzalez static int debugfs_size_t_get(void *data, u64 *val)
7285e078787SInaky Perez-Gonzalez {
7295e078787SInaky Perez-Gonzalez *val = *(size_t *)data;
7305e078787SInaky Perez-Gonzalez return 0;
7315e078787SInaky Perez-Gonzalez }
7324909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t, debugfs_size_t_get, debugfs_size_t_set,
7335e078787SInaky Perez-Gonzalez "%llu\n"); /* %llu and %zu are more or less the same */
7344909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t_ro, debugfs_size_t_get, NULL, "%llu\n");
7354909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t_wo, NULL, debugfs_size_t_set, "%llu\n");
7365e078787SInaky Perez-Gonzalez
7375e078787SInaky Perez-Gonzalez /**
7385e078787SInaky Perez-Gonzalez * debugfs_create_size_t - create a debugfs file that is used to read and write an size_t value
7395e078787SInaky Perez-Gonzalez * @name: a pointer to a string containing the name of the file to create.
7405e078787SInaky Perez-Gonzalez * @mode: the permission that the file should have
7415e078787SInaky Perez-Gonzalez * @parent: a pointer to the parent dentry for this file. This should be a
7425e078787SInaky Perez-Gonzalez * directory dentry if set. If this parameter is %NULL, then the
7435e078787SInaky Perez-Gonzalez * file will be created in the root of the debugfs filesystem.
7445e078787SInaky Perez-Gonzalez * @value: a pointer to the variable that the file should read to and write
7455e078787SInaky Perez-Gonzalez * from.
7465e078787SInaky Perez-Gonzalez */
debugfs_create_size_t(const char * name,umode_t mode,struct dentry * parent,size_t * value)7478e580263SGreg Kroah-Hartman void debugfs_create_size_t(const char *name, umode_t mode,
7485e078787SInaky Perez-Gonzalez struct dentry *parent, size_t *value)
7495e078787SInaky Perez-Gonzalez {
7508e580263SGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_size_t,
7518e580263SGreg Kroah-Hartman &fops_size_t_ro, &fops_size_t_wo);
7525e078787SInaky Perez-Gonzalez }
7535e078787SInaky Perez-Gonzalez EXPORT_SYMBOL_GPL(debugfs_create_size_t);
7545e078787SInaky Perez-Gonzalez
debugfs_atomic_t_set(void * data,u64 val)7553a76e5e0SSeth Jennings static int debugfs_atomic_t_set(void *data, u64 val)
7563a76e5e0SSeth Jennings {
7573a76e5e0SSeth Jennings atomic_set((atomic_t *)data, val);
7583a76e5e0SSeth Jennings return 0;
7593a76e5e0SSeth Jennings }
debugfs_atomic_t_get(void * data,u64 * val)7603a76e5e0SSeth Jennings static int debugfs_atomic_t_get(void *data, u64 *val)
7613a76e5e0SSeth Jennings {
7623a76e5e0SSeth Jennings *val = atomic_read((atomic_t *)data);
7633a76e5e0SSeth Jennings return 0;
7643a76e5e0SSeth Jennings }
765d472cf79SAkinobu Mita DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic_t, debugfs_atomic_t_get,
7663a76e5e0SSeth Jennings debugfs_atomic_t_set, "%lld\n");
767d472cf79SAkinobu Mita DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic_t_ro, debugfs_atomic_t_get, NULL,
7684909f168SNicolai Stange "%lld\n");
769d472cf79SAkinobu Mita DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic_t_wo, NULL, debugfs_atomic_t_set,
7704909f168SNicolai Stange "%lld\n");
7713a76e5e0SSeth Jennings
7723a76e5e0SSeth Jennings /**
7733a76e5e0SSeth Jennings * debugfs_create_atomic_t - create a debugfs file that is used to read and
7743a76e5e0SSeth Jennings * write an atomic_t value
7753a76e5e0SSeth Jennings * @name: a pointer to a string containing the name of the file to create.
7763a76e5e0SSeth Jennings * @mode: the permission that the file should have
7773a76e5e0SSeth Jennings * @parent: a pointer to the parent dentry for this file. This should be a
7783a76e5e0SSeth Jennings * directory dentry if set. If this parameter is %NULL, then the
7793a76e5e0SSeth Jennings * file will be created in the root of the debugfs filesystem.
7803a76e5e0SSeth Jennings * @value: a pointer to the variable that the file should read to and write
7813a76e5e0SSeth Jennings * from.
7823a76e5e0SSeth Jennings */
debugfs_create_atomic_t(const char * name,umode_t mode,struct dentry * parent,atomic_t * value)7839927c6faSGreg Kroah-Hartman void debugfs_create_atomic_t(const char *name, umode_t mode,
7843a76e5e0SSeth Jennings struct dentry *parent, atomic_t *value)
7853a76e5e0SSeth Jennings {
7869927c6faSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic_t,
7879927c6faSGreg Kroah-Hartman &fops_atomic_t_ro, &fops_atomic_t_wo);
7883a76e5e0SSeth Jennings }
7893a76e5e0SSeth Jennings EXPORT_SYMBOL_GPL(debugfs_create_atomic_t);
7905e078787SInaky Perez-Gonzalez
debugfs_read_file_bool(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)7910642ef6fSRichard Fitzgerald ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf,
7921da177e4SLinus Torvalds size_t count, loff_t *ppos)
7931da177e4SLinus Torvalds {
794c8a9c285SRasmus Villemoes char buf[2];
7954d45f797SNicolai Stange bool val;
79669d29f9eSNicolai Stange int r;
79769d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(file);
7981da177e4SLinus Torvalds
79969d29f9eSNicolai Stange r = debugfs_file_get(dentry);
80069d29f9eSNicolai Stange if (unlikely(r))
8014d45f797SNicolai Stange return r;
80269d29f9eSNicolai Stange val = *(bool *)file->private_data;
80369d29f9eSNicolai Stange debugfs_file_put(dentry);
8044d45f797SNicolai Stange
8054d45f797SNicolai Stange if (val)
8061da177e4SLinus Torvalds buf[0] = 'Y';
8071da177e4SLinus Torvalds else
8081da177e4SLinus Torvalds buf[0] = 'N';
8091da177e4SLinus Torvalds buf[1] = '\n';
8101da177e4SLinus Torvalds return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
8111da177e4SLinus Torvalds }
8120642ef6fSRichard Fitzgerald EXPORT_SYMBOL_GPL(debugfs_read_file_bool);
8131da177e4SLinus Torvalds
debugfs_write_file_bool(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)8140642ef6fSRichard Fitzgerald ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf,
8151da177e4SLinus Torvalds size_t count, loff_t *ppos)
8161da177e4SLinus Torvalds {
8178705b48eSJonathan Cameron bool bv;
81869d29f9eSNicolai Stange int r;
819621a5f7aSViresh Kumar bool *val = file->private_data;
82069d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(file);
8211da177e4SLinus Torvalds
822964f8363SAndy Shevchenko r = kstrtobool_from_user(user_buf, count, &bv);
823964f8363SAndy Shevchenko if (!r) {
82469d29f9eSNicolai Stange r = debugfs_file_get(dentry);
82569d29f9eSNicolai Stange if (unlikely(r))
8264d45f797SNicolai Stange return r;
82769d29f9eSNicolai Stange *val = bv;
82869d29f9eSNicolai Stange debugfs_file_put(dentry);
8294d45f797SNicolai Stange }
8301da177e4SLinus Torvalds
8311da177e4SLinus Torvalds return count;
8321da177e4SLinus Torvalds }
8330642ef6fSRichard Fitzgerald EXPORT_SYMBOL_GPL(debugfs_write_file_bool);
8341da177e4SLinus Torvalds
8354b6f5d20SArjan van de Ven static const struct file_operations fops_bool = {
8360642ef6fSRichard Fitzgerald .read = debugfs_read_file_bool,
8370642ef6fSRichard Fitzgerald .write = debugfs_write_file_bool,
838234e3405SStephen Boyd .open = simple_open,
8396038f373SArnd Bergmann .llseek = default_llseek,
8401da177e4SLinus Torvalds };
8411da177e4SLinus Torvalds
8426713e8fbSStephen Boyd static const struct file_operations fops_bool_ro = {
8436713e8fbSStephen Boyd .read = debugfs_read_file_bool,
8446713e8fbSStephen Boyd .open = simple_open,
8456713e8fbSStephen Boyd .llseek = default_llseek,
8466713e8fbSStephen Boyd };
8476713e8fbSStephen Boyd
8486713e8fbSStephen Boyd static const struct file_operations fops_bool_wo = {
8496713e8fbSStephen Boyd .write = debugfs_write_file_bool,
8506713e8fbSStephen Boyd .open = simple_open,
8516713e8fbSStephen Boyd .llseek = default_llseek,
8526713e8fbSStephen Boyd };
8536713e8fbSStephen Boyd
8541da177e4SLinus Torvalds /**
8556468b3afSRandy Dunlap * debugfs_create_bool - create a debugfs file that is used to read and write a boolean value
8561da177e4SLinus Torvalds * @name: a pointer to a string containing the name of the file to create.
8571da177e4SLinus Torvalds * @mode: the permission that the file should have
8581da177e4SLinus Torvalds * @parent: a pointer to the parent dentry for this file. This should be a
8596468b3afSRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the
8601da177e4SLinus Torvalds * file will be created in the root of the debugfs filesystem.
8611da177e4SLinus Torvalds * @value: a pointer to the variable that the file should read to and write
8621da177e4SLinus Torvalds * from.
8631da177e4SLinus Torvalds *
8641da177e4SLinus Torvalds * This function creates a file in debugfs with the given name that
8651da177e4SLinus Torvalds * contains the value of the variable @value. If the @mode variable is so
8661da177e4SLinus Torvalds * set, it can be read from, and written to.
8671da177e4SLinus Torvalds */
debugfs_create_bool(const char * name,umode_t mode,struct dentry * parent,bool * value)868393b0638SGreg Kroah-Hartman void debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent,
869393b0638SGreg Kroah-Hartman bool *value)
8701da177e4SLinus Torvalds {
871393b0638SGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool,
8726713e8fbSStephen Boyd &fops_bool_ro, &fops_bool_wo);
8731da177e4SLinus Torvalds }
8741da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(debugfs_create_bool);
8751da177e4SLinus Torvalds
debugfs_read_file_str(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)8769af0440eSPeter Zijlstra ssize_t debugfs_read_file_str(struct file *file, char __user *user_buf,
8779af0440eSPeter Zijlstra size_t count, loff_t *ppos)
8789af0440eSPeter Zijlstra {
8799af0440eSPeter Zijlstra struct dentry *dentry = F_DENTRY(file);
8809af0440eSPeter Zijlstra char *str, *copy = NULL;
8819af0440eSPeter Zijlstra int copy_len, len;
8829af0440eSPeter Zijlstra ssize_t ret;
8839af0440eSPeter Zijlstra
8849af0440eSPeter Zijlstra ret = debugfs_file_get(dentry);
8859af0440eSPeter Zijlstra if (unlikely(ret))
8869af0440eSPeter Zijlstra return ret;
8879af0440eSPeter Zijlstra
8889af0440eSPeter Zijlstra str = *(char **)file->private_data;
8899af0440eSPeter Zijlstra len = strlen(str) + 1;
8909af0440eSPeter Zijlstra copy = kmalloc(len, GFP_KERNEL);
8919af0440eSPeter Zijlstra if (!copy) {
8929af0440eSPeter Zijlstra debugfs_file_put(dentry);
8939af0440eSPeter Zijlstra return -ENOMEM;
8949af0440eSPeter Zijlstra }
8959af0440eSPeter Zijlstra
8969af0440eSPeter Zijlstra copy_len = strscpy(copy, str, len);
8979af0440eSPeter Zijlstra debugfs_file_put(dentry);
8989af0440eSPeter Zijlstra if (copy_len < 0) {
8999af0440eSPeter Zijlstra kfree(copy);
9009af0440eSPeter Zijlstra return copy_len;
9019af0440eSPeter Zijlstra }
9029af0440eSPeter Zijlstra
9039af0440eSPeter Zijlstra copy[copy_len] = '\n';
9049af0440eSPeter Zijlstra
905f501b6a2SDietmar Eggemann ret = simple_read_from_buffer(user_buf, count, ppos, copy, len);
9069af0440eSPeter Zijlstra kfree(copy);
9079af0440eSPeter Zijlstra
9089af0440eSPeter Zijlstra return ret;
9099af0440eSPeter Zijlstra }
910d60b59b9SCristian Marussi EXPORT_SYMBOL_GPL(debugfs_create_str);
9119af0440eSPeter Zijlstra
debugfs_write_file_str(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)9129af0440eSPeter Zijlstra static ssize_t debugfs_write_file_str(struct file *file, const char __user *user_buf,
9139af0440eSPeter Zijlstra size_t count, loff_t *ppos)
9149af0440eSPeter Zijlstra {
91586b54881SMike Tipton struct dentry *dentry = F_DENTRY(file);
91686b54881SMike Tipton char *old, *new = NULL;
91786b54881SMike Tipton int pos = *ppos;
91886b54881SMike Tipton int r;
91986b54881SMike Tipton
92086b54881SMike Tipton r = debugfs_file_get(dentry);
92186b54881SMike Tipton if (unlikely(r))
92286b54881SMike Tipton return r;
92386b54881SMike Tipton
92486b54881SMike Tipton old = *(char **)file->private_data;
92586b54881SMike Tipton
92686b54881SMike Tipton /* only allow strict concatenation */
92786b54881SMike Tipton r = -EINVAL;
92886b54881SMike Tipton if (pos && pos != strlen(old))
92986b54881SMike Tipton goto error;
93086b54881SMike Tipton
93186b54881SMike Tipton r = -E2BIG;
93286b54881SMike Tipton if (pos + count + 1 > PAGE_SIZE)
93386b54881SMike Tipton goto error;
93486b54881SMike Tipton
93586b54881SMike Tipton r = -ENOMEM;
93686b54881SMike Tipton new = kmalloc(pos + count + 1, GFP_KERNEL);
93786b54881SMike Tipton if (!new)
93886b54881SMike Tipton goto error;
93986b54881SMike Tipton
94086b54881SMike Tipton if (pos)
94186b54881SMike Tipton memcpy(new, old, pos);
94286b54881SMike Tipton
94386b54881SMike Tipton r = -EFAULT;
94486b54881SMike Tipton if (copy_from_user(new + pos, user_buf, count))
94586b54881SMike Tipton goto error;
94686b54881SMike Tipton
94786b54881SMike Tipton new[pos + count] = '\0';
94886b54881SMike Tipton strim(new);
94986b54881SMike Tipton
950406d4244SMike Tipton rcu_assign_pointer(*(char __rcu **)file->private_data, new);
95186b54881SMike Tipton synchronize_rcu();
95286b54881SMike Tipton kfree(old);
95386b54881SMike Tipton
95486b54881SMike Tipton debugfs_file_put(dentry);
95586b54881SMike Tipton return count;
95686b54881SMike Tipton
95786b54881SMike Tipton error:
95886b54881SMike Tipton kfree(new);
95986b54881SMike Tipton debugfs_file_put(dentry);
96086b54881SMike Tipton return r;
9619af0440eSPeter Zijlstra }
9629af0440eSPeter Zijlstra
9639af0440eSPeter Zijlstra static const struct file_operations fops_str = {
9649af0440eSPeter Zijlstra .read = debugfs_read_file_str,
9659af0440eSPeter Zijlstra .write = debugfs_write_file_str,
9669af0440eSPeter Zijlstra .open = simple_open,
9679af0440eSPeter Zijlstra .llseek = default_llseek,
9689af0440eSPeter Zijlstra };
9699af0440eSPeter Zijlstra
9709af0440eSPeter Zijlstra static const struct file_operations fops_str_ro = {
9719af0440eSPeter Zijlstra .read = debugfs_read_file_str,
9729af0440eSPeter Zijlstra .open = simple_open,
9739af0440eSPeter Zijlstra .llseek = default_llseek,
9749af0440eSPeter Zijlstra };
9759af0440eSPeter Zijlstra
9769af0440eSPeter Zijlstra static const struct file_operations fops_str_wo = {
9779af0440eSPeter Zijlstra .write = debugfs_write_file_str,
9789af0440eSPeter Zijlstra .open = simple_open,
9799af0440eSPeter Zijlstra .llseek = default_llseek,
9809af0440eSPeter Zijlstra };
9819af0440eSPeter Zijlstra
9829af0440eSPeter Zijlstra /**
9839af0440eSPeter Zijlstra * debugfs_create_str - create a debugfs file that is used to read and write a string value
9849af0440eSPeter Zijlstra * @name: a pointer to a string containing the name of the file to create.
9859af0440eSPeter Zijlstra * @mode: the permission that the file should have
9869af0440eSPeter Zijlstra * @parent: a pointer to the parent dentry for this file. This should be a
9879af0440eSPeter Zijlstra * directory dentry if set. If this parameter is %NULL, then the
9889af0440eSPeter Zijlstra * file will be created in the root of the debugfs filesystem.
9899af0440eSPeter Zijlstra * @value: a pointer to the variable that the file should read to and write
9909af0440eSPeter Zijlstra * from.
9919af0440eSPeter Zijlstra *
9929af0440eSPeter Zijlstra * This function creates a file in debugfs with the given name that
9939af0440eSPeter Zijlstra * contains the value of the variable @value. If the @mode variable is so
9949af0440eSPeter Zijlstra * set, it can be read from, and written to.
9959af0440eSPeter Zijlstra */
debugfs_create_str(const char * name,umode_t mode,struct dentry * parent,char ** value)9969af0440eSPeter Zijlstra void debugfs_create_str(const char *name, umode_t mode,
9979af0440eSPeter Zijlstra struct dentry *parent, char **value)
9989af0440eSPeter Zijlstra {
9999af0440eSPeter Zijlstra debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str,
10009af0440eSPeter Zijlstra &fops_str_ro, &fops_str_wo);
10019af0440eSPeter Zijlstra }
10029af0440eSPeter Zijlstra
read_file_blob(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1003dd308bc3SMichael Ellerman static ssize_t read_file_blob(struct file *file, char __user *user_buf,
1004dd308bc3SMichael Ellerman size_t count, loff_t *ppos)
1005dd308bc3SMichael Ellerman {
1006dd308bc3SMichael Ellerman struct debugfs_blob_wrapper *blob = file->private_data;
100769d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(file);
100883b711cbSNicolai Stange ssize_t r;
100983b711cbSNicolai Stange
101069d29f9eSNicolai Stange r = debugfs_file_get(dentry);
101169d29f9eSNicolai Stange if (unlikely(r))
101269d29f9eSNicolai Stange return r;
101383b711cbSNicolai Stange r = simple_read_from_buffer(user_buf, count, ppos, blob->data,
1014dd308bc3SMichael Ellerman blob->size);
101569d29f9eSNicolai Stange debugfs_file_put(dentry);
101683b711cbSNicolai Stange return r;
1017dd308bc3SMichael Ellerman }
1018dd308bc3SMichael Ellerman
101900977a59SArjan van de Ven static const struct file_operations fops_blob = {
1020dd308bc3SMichael Ellerman .read = read_file_blob,
1021234e3405SStephen Boyd .open = simple_open,
10226038f373SArnd Bergmann .llseek = default_llseek,
1023dd308bc3SMichael Ellerman };
1024dd308bc3SMichael Ellerman
1025dd308bc3SMichael Ellerman /**
1026400ced61SJonathan Corbet * debugfs_create_blob - create a debugfs file that is used to read a binary blob
1027dd308bc3SMichael Ellerman * @name: a pointer to a string containing the name of the file to create.
1028d616f56dSWolfram Sang * @mode: the read permission that the file should have (other permissions are
1029d616f56dSWolfram Sang * masked out)
1030dd308bc3SMichael Ellerman * @parent: a pointer to the parent dentry for this file. This should be a
10316468b3afSRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the
1032dd308bc3SMichael Ellerman * file will be created in the root of the debugfs filesystem.
1033dd308bc3SMichael Ellerman * @blob: a pointer to a struct debugfs_blob_wrapper which contains a pointer
1034dd308bc3SMichael Ellerman * to the blob data and the size of the data.
1035dd308bc3SMichael Ellerman *
1036dd308bc3SMichael Ellerman * This function creates a file in debugfs with the given name that exports
1037dd308bc3SMichael Ellerman * @blob->data as a binary blob. If the @mode variable is so set it can be
1038dd308bc3SMichael Ellerman * read from. Writing is not supported.
1039dd308bc3SMichael Ellerman *
1040dd308bc3SMichael Ellerman * This function will return a pointer to a dentry if it succeeds. This
1041dd308bc3SMichael Ellerman * pointer must be passed to the debugfs_remove() function when the file is
1042dd308bc3SMichael Ellerman * to be removed (no automatic cleanup happens if your module is unloaded,
1043adc92dd4SDaniel W. S. Almeida * you are responsible here.) If an error occurs, ERR_PTR(-ERROR) will be
10449abb2499SRonald Tschalär * returned.
1045dd308bc3SMichael Ellerman *
1046adc92dd4SDaniel W. S. Almeida * If debugfs is not enabled in the kernel, the value ERR_PTR(-ENODEV) will
10479abb2499SRonald Tschalär * be returned.
1048dd308bc3SMichael Ellerman */
debugfs_create_blob(const char * name,umode_t mode,struct dentry * parent,struct debugfs_blob_wrapper * blob)1049f4ae40a6SAl Viro struct dentry *debugfs_create_blob(const char *name, umode_t mode,
1050dd308bc3SMichael Ellerman struct dentry *parent,
1051dd308bc3SMichael Ellerman struct debugfs_blob_wrapper *blob)
1052dd308bc3SMichael Ellerman {
1053d616f56dSWolfram Sang return debugfs_create_file_unsafe(name, mode & 0444, parent, blob, &fops_blob);
1054dd308bc3SMichael Ellerman }
1055dd308bc3SMichael Ellerman EXPORT_SYMBOL_GPL(debugfs_create_blob);
10561a087c6aSAlessandro Rubini
u32_format_array(char * buf,size_t bufsize,u32 * array,int array_size)1057e05e279eSLinus Torvalds static size_t u32_format_array(char *buf, size_t bufsize,
1058e05e279eSLinus Torvalds u32 *array, int array_size)
10599fe2a701SSrivatsa Vaddagiri {
10609fe2a701SSrivatsa Vaddagiri size_t ret = 0;
10619fe2a701SSrivatsa Vaddagiri
1062e05e279eSLinus Torvalds while (--array_size >= 0) {
10639fe2a701SSrivatsa Vaddagiri size_t len;
1064e05e279eSLinus Torvalds char term = array_size ? ' ' : '\n';
10659fe2a701SSrivatsa Vaddagiri
1066e05e279eSLinus Torvalds len = snprintf(buf, bufsize, "%u%c", *array++, term);
10679fe2a701SSrivatsa Vaddagiri ret += len;
10689fe2a701SSrivatsa Vaddagiri
10699fe2a701SSrivatsa Vaddagiri buf += len;
10709fe2a701SSrivatsa Vaddagiri bufsize -= len;
10719fe2a701SSrivatsa Vaddagiri }
10729fe2a701SSrivatsa Vaddagiri return ret;
10739fe2a701SSrivatsa Vaddagiri }
10749fe2a701SSrivatsa Vaddagiri
u32_array_open(struct inode * inode,struct file * file)107536048853SDavid Rientjes static int u32_array_open(struct inode *inode, struct file *file)
10769fe2a701SSrivatsa Vaddagiri {
1077a2b992c8SJakub Kicinski struct debugfs_u32_array *data = inode->i_private;
1078a2b992c8SJakub Kicinski int size, elements = data->n_elements;
1079e05e279eSLinus Torvalds char *buf;
10809fe2a701SSrivatsa Vaddagiri
1081e05e279eSLinus Torvalds /*
1082e05e279eSLinus Torvalds * Max size:
1083e05e279eSLinus Torvalds * - 10 digits + ' '/'\n' = 11 bytes per number
1084e05e279eSLinus Torvalds * - terminating NUL character
1085e05e279eSLinus Torvalds */
1086e05e279eSLinus Torvalds size = elements*11;
1087e05e279eSLinus Torvalds buf = kmalloc(size+1, GFP_KERNEL);
1088e05e279eSLinus Torvalds if (!buf)
108936048853SDavid Rientjes return -ENOMEM;
1090e05e279eSLinus Torvalds buf[size] = 0;
1091e05e279eSLinus Torvalds
1092e05e279eSLinus Torvalds file->private_data = buf;
1093a2b992c8SJakub Kicinski u32_format_array(buf, size, data->array, data->n_elements);
1094e05e279eSLinus Torvalds
109536048853SDavid Rientjes return nonseekable_open(inode, file);
10969fe2a701SSrivatsa Vaddagiri }
10979fe2a701SSrivatsa Vaddagiri
u32_array_read(struct file * file,char __user * buf,size_t len,loff_t * ppos)109836048853SDavid Rientjes static ssize_t u32_array_read(struct file *file, char __user *buf, size_t len,
109936048853SDavid Rientjes loff_t *ppos)
110036048853SDavid Rientjes {
110136048853SDavid Rientjes size_t size = strlen(file->private_data);
11029fe2a701SSrivatsa Vaddagiri
11039fe2a701SSrivatsa Vaddagiri return simple_read_from_buffer(buf, len, ppos,
11049fe2a701SSrivatsa Vaddagiri file->private_data, size);
11059fe2a701SSrivatsa Vaddagiri }
11069fe2a701SSrivatsa Vaddagiri
u32_array_release(struct inode * inode,struct file * file)11079fe2a701SSrivatsa Vaddagiri static int u32_array_release(struct inode *inode, struct file *file)
11089fe2a701SSrivatsa Vaddagiri {
11099fe2a701SSrivatsa Vaddagiri kfree(file->private_data);
11109fe2a701SSrivatsa Vaddagiri
11119fe2a701SSrivatsa Vaddagiri return 0;
11129fe2a701SSrivatsa Vaddagiri }
11139fe2a701SSrivatsa Vaddagiri
11149fe2a701SSrivatsa Vaddagiri static const struct file_operations u32_array_fops = {
11159fe2a701SSrivatsa Vaddagiri .owner = THIS_MODULE,
11169fe2a701SSrivatsa Vaddagiri .open = u32_array_open,
11179fe2a701SSrivatsa Vaddagiri .release = u32_array_release,
11189fe2a701SSrivatsa Vaddagiri .read = u32_array_read,
11199fe2a701SSrivatsa Vaddagiri .llseek = no_llseek,
11209fe2a701SSrivatsa Vaddagiri };
11219fe2a701SSrivatsa Vaddagiri
11229fe2a701SSrivatsa Vaddagiri /**
11239fe2a701SSrivatsa Vaddagiri * debugfs_create_u32_array - create a debugfs file that is used to read u32
11249fe2a701SSrivatsa Vaddagiri * array.
11259fe2a701SSrivatsa Vaddagiri * @name: a pointer to a string containing the name of the file to create.
11269fe2a701SSrivatsa Vaddagiri * @mode: the permission that the file should have.
11279fe2a701SSrivatsa Vaddagiri * @parent: a pointer to the parent dentry for this file. This should be a
11289fe2a701SSrivatsa Vaddagiri * directory dentry if set. If this parameter is %NULL, then the
11299fe2a701SSrivatsa Vaddagiri * file will be created in the root of the debugfs filesystem.
1130a2b992c8SJakub Kicinski * @array: wrapper struct containing data pointer and size of the array.
11319fe2a701SSrivatsa Vaddagiri *
11329fe2a701SSrivatsa Vaddagiri * This function creates a file in debugfs with the given name that exports
11339fe2a701SSrivatsa Vaddagiri * @array as data. If the @mode variable is so set it can be read from.
11349fe2a701SSrivatsa Vaddagiri * Writing is not supported. Seek within the file is also not supported.
11359fe2a701SSrivatsa Vaddagiri * Once array is created its size can not be changed.
11369fe2a701SSrivatsa Vaddagiri */
debugfs_create_u32_array(const char * name,umode_t mode,struct dentry * parent,struct debugfs_u32_array * array)1137c9c2c27dSGreg Kroah-Hartman void debugfs_create_u32_array(const char *name, umode_t mode,
1138a2b992c8SJakub Kicinski struct dentry *parent,
1139a2b992c8SJakub Kicinski struct debugfs_u32_array *array)
11409fe2a701SSrivatsa Vaddagiri {
1141a2b992c8SJakub Kicinski debugfs_create_file_unsafe(name, mode, parent, array, &u32_array_fops);
11429fe2a701SSrivatsa Vaddagiri }
11439fe2a701SSrivatsa Vaddagiri EXPORT_SYMBOL_GPL(debugfs_create_u32_array);
11449fe2a701SSrivatsa Vaddagiri
11453b85e4abSHeiko Carstens #ifdef CONFIG_HAS_IOMEM
11463b85e4abSHeiko Carstens
11471a087c6aSAlessandro Rubini /*
11481a087c6aSAlessandro Rubini * The regset32 stuff is used to print 32-bit registers using the
11491a087c6aSAlessandro Rubini * seq_file utilities. We offer printing a register set in an already-opened
11501a087c6aSAlessandro Rubini * sequential file or create a debugfs file that only prints a regset32.
11511a087c6aSAlessandro Rubini */
11521a087c6aSAlessandro Rubini
11531a087c6aSAlessandro Rubini /**
11541a087c6aSAlessandro Rubini * debugfs_print_regs32 - use seq_print to describe a set of registers
11551a087c6aSAlessandro Rubini * @s: the seq_file structure being used to generate output
11561a087c6aSAlessandro Rubini * @regs: an array if struct debugfs_reg32 structures
1157b5763accSRandy Dunlap * @nregs: the length of the above array
11581a087c6aSAlessandro Rubini * @base: the base address to be used in reading the registers
11591a087c6aSAlessandro Rubini * @prefix: a string to be prefixed to every output line
11601a087c6aSAlessandro Rubini *
11611a087c6aSAlessandro Rubini * This function outputs a text block describing the current values of
11621a087c6aSAlessandro Rubini * some 32-bit hardware registers. It is meant to be used within debugfs
11631a087c6aSAlessandro Rubini * files based on seq_file that need to show registers, intermixed with other
11641a087c6aSAlessandro Rubini * information. The prefix argument may be used to specify a leading string,
11651a087c6aSAlessandro Rubini * because some peripherals have several blocks of identical registers,
11661a087c6aSAlessandro Rubini * for example configuration of dma channels
11671a087c6aSAlessandro Rubini */
debugfs_print_regs32(struct seq_file * s,const struct debugfs_reg32 * regs,int nregs,void __iomem * base,char * prefix)11689761536eSJoe Perches void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
11691a087c6aSAlessandro Rubini int nregs, void __iomem *base, char *prefix)
11701a087c6aSAlessandro Rubini {
11719761536eSJoe Perches int i;
11721a087c6aSAlessandro Rubini
11731a087c6aSAlessandro Rubini for (i = 0; i < nregs; i++, regs++) {
11741a087c6aSAlessandro Rubini if (prefix)
11759761536eSJoe Perches seq_printf(s, "%s", prefix);
11769761536eSJoe Perches seq_printf(s, "%s = 0x%08x\n", regs->name,
11775858441cSDan Carpenter readl(base + regs->offset));
11789761536eSJoe Perches if (seq_has_overflowed(s))
11799761536eSJoe Perches break;
11801a087c6aSAlessandro Rubini }
11811a087c6aSAlessandro Rubini }
11821a087c6aSAlessandro Rubini EXPORT_SYMBOL_GPL(debugfs_print_regs32);
11831a087c6aSAlessandro Rubini
debugfs_regset32_show(struct seq_file * s,void * data)118419029f3fSChenXiaoSong static int debugfs_regset32_show(struct seq_file *s, void *data)
11851a087c6aSAlessandro Rubini {
11861a087c6aSAlessandro Rubini struct debugfs_regset32 *regset = s->private;
11871a087c6aSAlessandro Rubini
118830332eeeSGeert Uytterhoeven if (regset->dev)
118930332eeeSGeert Uytterhoeven pm_runtime_get_sync(regset->dev);
119030332eeeSGeert Uytterhoeven
11911a087c6aSAlessandro Rubini debugfs_print_regs32(s, regset->regs, regset->nregs, regset->base, "");
119230332eeeSGeert Uytterhoeven
119330332eeeSGeert Uytterhoeven if (regset->dev)
119430332eeeSGeert Uytterhoeven pm_runtime_put(regset->dev);
119530332eeeSGeert Uytterhoeven
11961a087c6aSAlessandro Rubini return 0;
11971a087c6aSAlessandro Rubini }
11981a087c6aSAlessandro Rubini
119919029f3fSChenXiaoSong DEFINE_SHOW_ATTRIBUTE(debugfs_regset32);
12001a087c6aSAlessandro Rubini
12011a087c6aSAlessandro Rubini /**
12021a087c6aSAlessandro Rubini * debugfs_create_regset32 - create a debugfs file that returns register values
12031a087c6aSAlessandro Rubini * @name: a pointer to a string containing the name of the file to create.
12041a087c6aSAlessandro Rubini * @mode: the permission that the file should have
12051a087c6aSAlessandro Rubini * @parent: a pointer to the parent dentry for this file. This should be a
12061a087c6aSAlessandro Rubini * directory dentry if set. If this parameter is %NULL, then the
12071a087c6aSAlessandro Rubini * file will be created in the root of the debugfs filesystem.
12081a087c6aSAlessandro Rubini * @regset: a pointer to a struct debugfs_regset32, which contains a pointer
12091a087c6aSAlessandro Rubini * to an array of register definitions, the array size and the base
12101a087c6aSAlessandro Rubini * address where the register bank is to be found.
12111a087c6aSAlessandro Rubini *
12121a087c6aSAlessandro Rubini * This function creates a file in debugfs with the given name that reports
12131a087c6aSAlessandro Rubini * the names and values of a set of 32-bit registers. If the @mode variable
12141a087c6aSAlessandro Rubini * is so set it can be read from. Writing is not supported.
12151a087c6aSAlessandro Rubini */
debugfs_create_regset32(const char * name,umode_t mode,struct dentry * parent,struct debugfs_regset32 * regset)1216ae91c925SGreg Kroah-Hartman void debugfs_create_regset32(const char *name, umode_t mode,
12171a087c6aSAlessandro Rubini struct dentry *parent,
12181a087c6aSAlessandro Rubini struct debugfs_regset32 *regset)
12191a087c6aSAlessandro Rubini {
122019029f3fSChenXiaoSong debugfs_create_file(name, mode, parent, regset, &debugfs_regset32_fops);
12211a087c6aSAlessandro Rubini }
12221a087c6aSAlessandro Rubini EXPORT_SYMBOL_GPL(debugfs_create_regset32);
12233b85e4abSHeiko Carstens
12243b85e4abSHeiko Carstens #endif /* CONFIG_HAS_IOMEM */
122598210b7fSArend van Spriel
122698210b7fSArend van Spriel struct debugfs_devm_entry {
122798210b7fSArend van Spriel int (*read)(struct seq_file *seq, void *data);
122898210b7fSArend van Spriel struct device *dev;
122998210b7fSArend van Spriel };
123098210b7fSArend van Spriel
debugfs_devm_entry_open(struct inode * inode,struct file * f)123198210b7fSArend van Spriel static int debugfs_devm_entry_open(struct inode *inode, struct file *f)
123298210b7fSArend van Spriel {
123398210b7fSArend van Spriel struct debugfs_devm_entry *entry = inode->i_private;
123498210b7fSArend van Spriel
123598210b7fSArend van Spriel return single_open(f, entry->read, entry->dev);
123698210b7fSArend van Spriel }
123798210b7fSArend van Spriel
123898210b7fSArend van Spriel static const struct file_operations debugfs_devm_entry_ops = {
123998210b7fSArend van Spriel .owner = THIS_MODULE,
124098210b7fSArend van Spriel .open = debugfs_devm_entry_open,
124198210b7fSArend van Spriel .release = single_release,
124298210b7fSArend van Spriel .read = seq_read,
124398210b7fSArend van Spriel .llseek = seq_lseek
124498210b7fSArend van Spriel };
124598210b7fSArend van Spriel
124698210b7fSArend van Spriel /**
124798210b7fSArend van Spriel * debugfs_create_devm_seqfile - create a debugfs file that is bound to device.
124898210b7fSArend van Spriel *
124998210b7fSArend van Spriel * @dev: device related to this debugfs file.
125098210b7fSArend van Spriel * @name: name of the debugfs file.
125198210b7fSArend van Spriel * @parent: a pointer to the parent dentry for this file. This should be a
125298210b7fSArend van Spriel * directory dentry if set. If this parameter is %NULL, then the
125398210b7fSArend van Spriel * file will be created in the root of the debugfs filesystem.
125498210b7fSArend van Spriel * @read_fn: function pointer called to print the seq_file content.
125598210b7fSArend van Spriel */
debugfs_create_devm_seqfile(struct device * dev,const char * name,struct dentry * parent,int (* read_fn)(struct seq_file * s,void * data))12560d519cbfSGreg Kroah-Hartman void debugfs_create_devm_seqfile(struct device *dev, const char *name,
125798210b7fSArend van Spriel struct dentry *parent,
12580d519cbfSGreg Kroah-Hartman int (*read_fn)(struct seq_file *s, void *data))
125998210b7fSArend van Spriel {
126098210b7fSArend van Spriel struct debugfs_devm_entry *entry;
126198210b7fSArend van Spriel
126298210b7fSArend van Spriel if (IS_ERR(parent))
12630d519cbfSGreg Kroah-Hartman return;
126498210b7fSArend van Spriel
126598210b7fSArend van Spriel entry = devm_kzalloc(dev, sizeof(*entry), GFP_KERNEL);
126698210b7fSArend van Spriel if (!entry)
12670d519cbfSGreg Kroah-Hartman return;
126898210b7fSArend van Spriel
126998210b7fSArend van Spriel entry->read = read_fn;
127098210b7fSArend van Spriel entry->dev = dev;
127198210b7fSArend van Spriel
12720d519cbfSGreg Kroah-Hartman debugfs_create_file(name, S_IRUGO, parent, entry,
127398210b7fSArend van Spriel &debugfs_devm_entry_ops);
127498210b7fSArend van Spriel }
127598210b7fSArend van Spriel EXPORT_SYMBOL_GPL(debugfs_create_devm_seqfile);
1276