xref: /linux-6.15/fs/debugfs/file.c (revision 9761536e)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  file.c - part of debugfs, a tiny little debug file system
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  Copyright (C) 2004 Greg Kroah-Hartman <[email protected]>
51da177e4SLinus Torvalds  *  Copyright (C) 2004 IBM Inc.
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *	This program is free software; you can redistribute it and/or
81da177e4SLinus Torvalds  *	modify it under the terms of the GNU General Public License version
91da177e4SLinus Torvalds  *	2 as published by the Free Software Foundation.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  *  debugfs is for people to use instead of /proc or /sys.
12883ce42eSRobert P. J. Day  *  See Documentation/DocBook/filesystems for more details.
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  */
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds #include <linux/module.h>
171da177e4SLinus Torvalds #include <linux/fs.h>
181a087c6aSAlessandro Rubini #include <linux/seq_file.h>
191da177e4SLinus Torvalds #include <linux/pagemap.h>
2066f54963SPeter Oberparleiter #include <linux/namei.h>
211da177e4SLinus Torvalds #include <linux/debugfs.h>
2203e099fbSAlessandro Rubini #include <linux/io.h>
239fe2a701SSrivatsa Vaddagiri #include <linux/slab.h>
243a76e5e0SSeth Jennings #include <linux/atomic.h>
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds static ssize_t default_read_file(struct file *file, char __user *buf,
271da177e4SLinus Torvalds 				 size_t count, loff_t *ppos)
281da177e4SLinus Torvalds {
291da177e4SLinus Torvalds 	return 0;
301da177e4SLinus Torvalds }
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds static ssize_t default_write_file(struct file *file, const char __user *buf,
331da177e4SLinus Torvalds 				   size_t count, loff_t *ppos)
341da177e4SLinus Torvalds {
351da177e4SLinus Torvalds 	return count;
361da177e4SLinus Torvalds }
371da177e4SLinus Torvalds 
384b6f5d20SArjan van de Ven const struct file_operations debugfs_file_operations = {
391da177e4SLinus Torvalds 	.read =		default_read_file,
401da177e4SLinus Torvalds 	.write =	default_write_file,
41234e3405SStephen Boyd 	.open =		simple_open,
426038f373SArnd Bergmann 	.llseek =	noop_llseek,
431da177e4SLinus Torvalds };
441da177e4SLinus Torvalds 
4566f54963SPeter Oberparleiter static void *debugfs_follow_link(struct dentry *dentry, struct nameidata *nd)
4666f54963SPeter Oberparleiter {
4766f54963SPeter Oberparleiter 	nd_set_link(nd, dentry->d_inode->i_private);
4866f54963SPeter Oberparleiter 	return NULL;
4966f54963SPeter Oberparleiter }
5066f54963SPeter Oberparleiter 
5166f54963SPeter Oberparleiter const struct inode_operations debugfs_link_operations = {
5266f54963SPeter Oberparleiter 	.readlink       = generic_readlink,
5366f54963SPeter Oberparleiter 	.follow_link    = debugfs_follow_link,
5466f54963SPeter Oberparleiter };
5566f54963SPeter Oberparleiter 
568b88b099SChristoph Hellwig static int debugfs_u8_set(void *data, u64 val)
57acaefc25SArnd Bergmann {
58acaefc25SArnd Bergmann 	*(u8 *)data = val;
598b88b099SChristoph Hellwig 	return 0;
60acaefc25SArnd Bergmann }
618b88b099SChristoph Hellwig static int debugfs_u8_get(void *data, u64 *val)
62acaefc25SArnd Bergmann {
638b88b099SChristoph Hellwig 	*val = *(u8 *)data;
648b88b099SChristoph Hellwig 	return 0;
65acaefc25SArnd Bergmann }
66acaefc25SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n");
67e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%llu\n");
68e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n");
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds /**
716468b3afSRandy Dunlap  * debugfs_create_u8 - create a debugfs file that is used to read and write an unsigned 8-bit value
721da177e4SLinus Torvalds  * @name: a pointer to a string containing the name of the file to create.
731da177e4SLinus Torvalds  * @mode: the permission that the file should have
741da177e4SLinus Torvalds  * @parent: a pointer to the parent dentry for this file.  This should be a
756468b3afSRandy Dunlap  *          directory dentry if set.  If this parameter is %NULL, then the
761da177e4SLinus Torvalds  *          file will be created in the root of the debugfs filesystem.
771da177e4SLinus Torvalds  * @value: a pointer to the variable that the file should read to and write
781da177e4SLinus Torvalds  *         from.
791da177e4SLinus Torvalds  *
801da177e4SLinus Torvalds  * This function creates a file in debugfs with the given name that
811da177e4SLinus Torvalds  * contains the value of the variable @value.  If the @mode variable is so
821da177e4SLinus Torvalds  * set, it can be read from, and written to.
831da177e4SLinus Torvalds  *
841da177e4SLinus Torvalds  * This function will return a pointer to a dentry if it succeeds.  This
851da177e4SLinus Torvalds  * pointer must be passed to the debugfs_remove() function when the file is
861da177e4SLinus Torvalds  * to be removed (no automatic cleanup happens if your module is unloaded,
876468b3afSRandy Dunlap  * you are responsible here.)  If an error occurs, %NULL will be returned.
881da177e4SLinus Torvalds  *
896468b3afSRandy Dunlap  * If debugfs is not enabled in the kernel, the value -%ENODEV will be
901da177e4SLinus Torvalds  * returned.  It is not wise to check for this value, but rather, check for
916468b3afSRandy Dunlap  * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
921da177e4SLinus Torvalds  * code.
931da177e4SLinus Torvalds  */
94f4ae40a6SAl Viro struct dentry *debugfs_create_u8(const char *name, umode_t mode,
951da177e4SLinus Torvalds 				 struct dentry *parent, u8 *value)
961da177e4SLinus Torvalds {
97e4792aa3SRobin Getz 	/* if there are no write bits set, make read only */
98e4792aa3SRobin Getz 	if (!(mode & S_IWUGO))
99e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_u8_ro);
100e4792aa3SRobin Getz 	/* if there are no read bits set, make write only */
101e4792aa3SRobin Getz 	if (!(mode & S_IRUGO))
102e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_u8_wo);
103e4792aa3SRobin Getz 
1041da177e4SLinus Torvalds 	return debugfs_create_file(name, mode, parent, value, &fops_u8);
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(debugfs_create_u8);
1071da177e4SLinus Torvalds 
1088b88b099SChristoph Hellwig static int debugfs_u16_set(void *data, u64 val)
109acaefc25SArnd Bergmann {
110acaefc25SArnd Bergmann 	*(u16 *)data = val;
1118b88b099SChristoph Hellwig 	return 0;
112acaefc25SArnd Bergmann }
1138b88b099SChristoph Hellwig static int debugfs_u16_get(void *data, u64 *val)
114acaefc25SArnd Bergmann {
1158b88b099SChristoph Hellwig 	*val = *(u16 *)data;
1168b88b099SChristoph Hellwig 	return 0;
117acaefc25SArnd Bergmann }
118acaefc25SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n");
119e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%llu\n");
120e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n");
121acaefc25SArnd Bergmann 
1221da177e4SLinus Torvalds /**
1236468b3afSRandy Dunlap  * debugfs_create_u16 - create a debugfs file that is used to read and write an unsigned 16-bit value
1241da177e4SLinus Torvalds  * @name: a pointer to a string containing the name of the file to create.
1251da177e4SLinus Torvalds  * @mode: the permission that the file should have
1261da177e4SLinus Torvalds  * @parent: a pointer to the parent dentry for this file.  This should be a
1276468b3afSRandy Dunlap  *          directory dentry if set.  If this parameter is %NULL, then the
1281da177e4SLinus Torvalds  *          file will be created in the root of the debugfs filesystem.
1291da177e4SLinus Torvalds  * @value: a pointer to the variable that the file should read to and write
1301da177e4SLinus Torvalds  *         from.
1311da177e4SLinus Torvalds  *
1321da177e4SLinus Torvalds  * This function creates a file in debugfs with the given name that
1331da177e4SLinus Torvalds  * contains the value of the variable @value.  If the @mode variable is so
1341da177e4SLinus Torvalds  * set, it can be read from, and written to.
1351da177e4SLinus Torvalds  *
1361da177e4SLinus Torvalds  * This function will return a pointer to a dentry if it succeeds.  This
1371da177e4SLinus Torvalds  * pointer must be passed to the debugfs_remove() function when the file is
1381da177e4SLinus Torvalds  * to be removed (no automatic cleanup happens if your module is unloaded,
1396468b3afSRandy Dunlap  * you are responsible here.)  If an error occurs, %NULL will be returned.
1401da177e4SLinus Torvalds  *
1416468b3afSRandy Dunlap  * If debugfs is not enabled in the kernel, the value -%ENODEV will be
1421da177e4SLinus Torvalds  * returned.  It is not wise to check for this value, but rather, check for
1436468b3afSRandy Dunlap  * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
1441da177e4SLinus Torvalds  * code.
1451da177e4SLinus Torvalds  */
146f4ae40a6SAl Viro struct dentry *debugfs_create_u16(const char *name, umode_t mode,
1471da177e4SLinus Torvalds 				  struct dentry *parent, u16 *value)
1481da177e4SLinus Torvalds {
149e4792aa3SRobin Getz 	/* if there are no write bits set, make read only */
150e4792aa3SRobin Getz 	if (!(mode & S_IWUGO))
151e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_u16_ro);
152e4792aa3SRobin Getz 	/* if there are no read bits set, make write only */
153e4792aa3SRobin Getz 	if (!(mode & S_IRUGO))
154e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_u16_wo);
155e4792aa3SRobin Getz 
1561da177e4SLinus Torvalds 	return debugfs_create_file(name, mode, parent, value, &fops_u16);
1571da177e4SLinus Torvalds }
1581da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(debugfs_create_u16);
1591da177e4SLinus Torvalds 
1608b88b099SChristoph Hellwig static int debugfs_u32_set(void *data, u64 val)
161acaefc25SArnd Bergmann {
162acaefc25SArnd Bergmann 	*(u32 *)data = val;
1638b88b099SChristoph Hellwig 	return 0;
164acaefc25SArnd Bergmann }
1658b88b099SChristoph Hellwig static int debugfs_u32_get(void *data, u64 *val)
166acaefc25SArnd Bergmann {
1678b88b099SChristoph Hellwig 	*val = *(u32 *)data;
1688b88b099SChristoph Hellwig 	return 0;
169acaefc25SArnd Bergmann }
170acaefc25SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n");
171e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%llu\n");
172e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n");
173acaefc25SArnd Bergmann 
1741da177e4SLinus Torvalds /**
1756468b3afSRandy Dunlap  * debugfs_create_u32 - create a debugfs file that is used to read and write an unsigned 32-bit value
1761da177e4SLinus Torvalds  * @name: a pointer to a string containing the name of the file to create.
1771da177e4SLinus Torvalds  * @mode: the permission that the file should have
1781da177e4SLinus Torvalds  * @parent: a pointer to the parent dentry for this file.  This should be a
1796468b3afSRandy Dunlap  *          directory dentry if set.  If this parameter is %NULL, then the
1801da177e4SLinus Torvalds  *          file will be created in the root of the debugfs filesystem.
1811da177e4SLinus Torvalds  * @value: a pointer to the variable that the file should read to and write
1821da177e4SLinus Torvalds  *         from.
1831da177e4SLinus Torvalds  *
1841da177e4SLinus Torvalds  * This function creates a file in debugfs with the given name that
1851da177e4SLinus Torvalds  * contains the value of the variable @value.  If the @mode variable is so
1861da177e4SLinus Torvalds  * set, it can be read from, and written to.
1871da177e4SLinus Torvalds  *
1881da177e4SLinus Torvalds  * This function will return a pointer to a dentry if it succeeds.  This
1891da177e4SLinus Torvalds  * pointer must be passed to the debugfs_remove() function when the file is
1901da177e4SLinus Torvalds  * to be removed (no automatic cleanup happens if your module is unloaded,
1916468b3afSRandy Dunlap  * you are responsible here.)  If an error occurs, %NULL will be returned.
1921da177e4SLinus Torvalds  *
1936468b3afSRandy Dunlap  * If debugfs is not enabled in the kernel, the value -%ENODEV will be
1941da177e4SLinus Torvalds  * returned.  It is not wise to check for this value, but rather, check for
1956468b3afSRandy Dunlap  * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
1961da177e4SLinus Torvalds  * code.
1971da177e4SLinus Torvalds  */
198f4ae40a6SAl Viro struct dentry *debugfs_create_u32(const char *name, umode_t mode,
1991da177e4SLinus Torvalds 				 struct dentry *parent, u32 *value)
2001da177e4SLinus Torvalds {
201e4792aa3SRobin Getz 	/* if there are no write bits set, make read only */
202e4792aa3SRobin Getz 	if (!(mode & S_IWUGO))
203e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_u32_ro);
204e4792aa3SRobin Getz 	/* if there are no read bits set, make write only */
205e4792aa3SRobin Getz 	if (!(mode & S_IRUGO))
206e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_u32_wo);
207e4792aa3SRobin Getz 
2081da177e4SLinus Torvalds 	return debugfs_create_file(name, mode, parent, value, &fops_u32);
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(debugfs_create_u32);
2111da177e4SLinus Torvalds 
2128b88b099SChristoph Hellwig static int debugfs_u64_set(void *data, u64 val)
2138447891fSMichael Ellerman {
2148447891fSMichael Ellerman 	*(u64 *)data = val;
2158b88b099SChristoph Hellwig 	return 0;
2168447891fSMichael Ellerman }
2178447891fSMichael Ellerman 
2188b88b099SChristoph Hellwig static int debugfs_u64_get(void *data, u64 *val)
2198447891fSMichael Ellerman {
2208b88b099SChristoph Hellwig 	*val = *(u64 *)data;
2218b88b099SChristoph Hellwig 	return 0;
2228447891fSMichael Ellerman }
2238447891fSMichael Ellerman DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
224e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%llu\n");
225e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
2268447891fSMichael Ellerman 
2278447891fSMichael Ellerman /**
2288447891fSMichael Ellerman  * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value
2298447891fSMichael Ellerman  * @name: a pointer to a string containing the name of the file to create.
2308447891fSMichael Ellerman  * @mode: the permission that the file should have
2318447891fSMichael Ellerman  * @parent: a pointer to the parent dentry for this file.  This should be a
2328447891fSMichael Ellerman  *          directory dentry if set.  If this parameter is %NULL, then the
2338447891fSMichael Ellerman  *          file will be created in the root of the debugfs filesystem.
2348447891fSMichael Ellerman  * @value: a pointer to the variable that the file should read to and write
2358447891fSMichael Ellerman  *         from.
2368447891fSMichael Ellerman  *
2378447891fSMichael Ellerman  * This function creates a file in debugfs with the given name that
2388447891fSMichael Ellerman  * contains the value of the variable @value.  If the @mode variable is so
2398447891fSMichael Ellerman  * set, it can be read from, and written to.
2408447891fSMichael Ellerman  *
2418447891fSMichael Ellerman  * This function will return a pointer to a dentry if it succeeds.  This
2428447891fSMichael Ellerman  * pointer must be passed to the debugfs_remove() function when the file is
2438447891fSMichael Ellerman  * to be removed (no automatic cleanup happens if your module is unloaded,
2448447891fSMichael Ellerman  * you are responsible here.)  If an error occurs, %NULL will be returned.
2458447891fSMichael Ellerman  *
2468447891fSMichael Ellerman  * If debugfs is not enabled in the kernel, the value -%ENODEV will be
2478447891fSMichael Ellerman  * returned.  It is not wise to check for this value, but rather, check for
2488447891fSMichael Ellerman  * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
2498447891fSMichael Ellerman  * code.
2508447891fSMichael Ellerman  */
251f4ae40a6SAl Viro struct dentry *debugfs_create_u64(const char *name, umode_t mode,
2528447891fSMichael Ellerman 				 struct dentry *parent, u64 *value)
2538447891fSMichael Ellerman {
254e4792aa3SRobin Getz 	/* if there are no write bits set, make read only */
255e4792aa3SRobin Getz 	if (!(mode & S_IWUGO))
256e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_u64_ro);
257e4792aa3SRobin Getz 	/* if there are no read bits set, make write only */
258e4792aa3SRobin Getz 	if (!(mode & S_IRUGO))
259e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_u64_wo);
260e4792aa3SRobin Getz 
2618447891fSMichael Ellerman 	return debugfs_create_file(name, mode, parent, value, &fops_u64);
2628447891fSMichael Ellerman }
2638447891fSMichael Ellerman EXPORT_SYMBOL_GPL(debugfs_create_u64);
2648447891fSMichael Ellerman 
2652ebefc50SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n");
266e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%02llx\n");
267e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%02llx\n");
2682ebefc50SRobin Getz 
2692ebefc50SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n");
270e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%04llx\n");
271e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%04llx\n");
2722ebefc50SRobin Getz 
2732ebefc50SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n");
274e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%08llx\n");
275e4792aa3SRobin Getz DEFINE_SIMPLE_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%08llx\n");
2762ebefc50SRobin Getz 
27715b0beaaSHuang Ying DEFINE_SIMPLE_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n");
27815b0beaaSHuang Ying 
279e6716b87SRandy Dunlap /*
28015b0beaaSHuang 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
281e6716b87SRandy Dunlap  *
282e6716b87SRandy Dunlap  * These functions are exactly the same as the above functions (but use a hex
283e6716b87SRandy Dunlap  * output for the decimal challenged). For details look at the above unsigned
284e6716b87SRandy Dunlap  * decimal functions.
285e6716b87SRandy Dunlap  */
286e6716b87SRandy Dunlap 
2872ebefc50SRobin Getz /**
2882ebefc50SRobin Getz  * debugfs_create_x8 - create a debugfs file that is used to read and write an unsigned 8-bit value
289e6716b87SRandy Dunlap  * @name: a pointer to a string containing the name of the file to create.
290e6716b87SRandy Dunlap  * @mode: the permission that the file should have
291e6716b87SRandy Dunlap  * @parent: a pointer to the parent dentry for this file.  This should be a
292e6716b87SRandy Dunlap  *          directory dentry if set.  If this parameter is %NULL, then the
293e6716b87SRandy Dunlap  *          file will be created in the root of the debugfs filesystem.
294e6716b87SRandy Dunlap  * @value: a pointer to the variable that the file should read to and write
295e6716b87SRandy Dunlap  *         from.
2962ebefc50SRobin Getz  */
297f4ae40a6SAl Viro struct dentry *debugfs_create_x8(const char *name, umode_t mode,
2982ebefc50SRobin Getz 				 struct dentry *parent, u8 *value)
2992ebefc50SRobin Getz {
300e4792aa3SRobin Getz 	/* if there are no write bits set, make read only */
301e4792aa3SRobin Getz 	if (!(mode & S_IWUGO))
302e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_x8_ro);
303e4792aa3SRobin Getz 	/* if there are no read bits set, make write only */
304e4792aa3SRobin Getz 	if (!(mode & S_IRUGO))
305e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_x8_wo);
306e4792aa3SRobin Getz 
3072ebefc50SRobin Getz 	return debugfs_create_file(name, mode, parent, value, &fops_x8);
3082ebefc50SRobin Getz }
3092ebefc50SRobin Getz EXPORT_SYMBOL_GPL(debugfs_create_x8);
3102ebefc50SRobin Getz 
311e6716b87SRandy Dunlap /**
312e6716b87SRandy Dunlap  * debugfs_create_x16 - create a debugfs file that is used to read and write an unsigned 16-bit value
313e6716b87SRandy Dunlap  * @name: a pointer to a string containing the name of the file to create.
314e6716b87SRandy Dunlap  * @mode: the permission that the file should have
315e6716b87SRandy Dunlap  * @parent: a pointer to the parent dentry for this file.  This should be a
316e6716b87SRandy Dunlap  *          directory dentry if set.  If this parameter is %NULL, then the
317e6716b87SRandy Dunlap  *          file will be created in the root of the debugfs filesystem.
318e6716b87SRandy Dunlap  * @value: a pointer to the variable that the file should read to and write
319e6716b87SRandy Dunlap  *         from.
320e6716b87SRandy Dunlap  */
321f4ae40a6SAl Viro struct dentry *debugfs_create_x16(const char *name, umode_t mode,
3222ebefc50SRobin Getz 				 struct dentry *parent, u16 *value)
3232ebefc50SRobin Getz {
324e4792aa3SRobin Getz 	/* if there are no write bits set, make read only */
325e4792aa3SRobin Getz 	if (!(mode & S_IWUGO))
326e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_x16_ro);
327e4792aa3SRobin Getz 	/* if there are no read bits set, make write only */
328e4792aa3SRobin Getz 	if (!(mode & S_IRUGO))
329e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_x16_wo);
330e4792aa3SRobin Getz 
3312ebefc50SRobin Getz 	return debugfs_create_file(name, mode, parent, value, &fops_x16);
3322ebefc50SRobin Getz }
3332ebefc50SRobin Getz EXPORT_SYMBOL_GPL(debugfs_create_x16);
3342ebefc50SRobin Getz 
335e6716b87SRandy Dunlap /**
336e6716b87SRandy Dunlap  * debugfs_create_x32 - create a debugfs file that is used to read and write an unsigned 32-bit value
337e6716b87SRandy Dunlap  * @name: a pointer to a string containing the name of the file to create.
338e6716b87SRandy Dunlap  * @mode: the permission that the file should have
339e6716b87SRandy Dunlap  * @parent: a pointer to the parent dentry for this file.  This should be a
340e6716b87SRandy Dunlap  *          directory dentry if set.  If this parameter is %NULL, then the
341e6716b87SRandy Dunlap  *          file will be created in the root of the debugfs filesystem.
342e6716b87SRandy Dunlap  * @value: a pointer to the variable that the file should read to and write
343e6716b87SRandy Dunlap  *         from.
344e6716b87SRandy Dunlap  */
345f4ae40a6SAl Viro struct dentry *debugfs_create_x32(const char *name, umode_t mode,
3462ebefc50SRobin Getz 				 struct dentry *parent, u32 *value)
3472ebefc50SRobin Getz {
348e4792aa3SRobin Getz 	/* if there are no write bits set, make read only */
349e4792aa3SRobin Getz 	if (!(mode & S_IWUGO))
350e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_x32_ro);
351e4792aa3SRobin Getz 	/* if there are no read bits set, make write only */
352e4792aa3SRobin Getz 	if (!(mode & S_IRUGO))
353e4792aa3SRobin Getz 		return debugfs_create_file(name, mode, parent, value, &fops_x32_wo);
354e4792aa3SRobin Getz 
3552ebefc50SRobin Getz 	return debugfs_create_file(name, mode, parent, value, &fops_x32);
3562ebefc50SRobin Getz }
3572ebefc50SRobin Getz EXPORT_SYMBOL_GPL(debugfs_create_x32);
3582ebefc50SRobin Getz 
35915b0beaaSHuang Ying /**
36015b0beaaSHuang Ying  * debugfs_create_x64 - create a debugfs file that is used to read and write an unsigned 64-bit value
36115b0beaaSHuang Ying  * @name: a pointer to a string containing the name of the file to create.
36215b0beaaSHuang Ying  * @mode: the permission that the file should have
36315b0beaaSHuang Ying  * @parent: a pointer to the parent dentry for this file.  This should be a
36415b0beaaSHuang Ying  *          directory dentry if set.  If this parameter is %NULL, then the
36515b0beaaSHuang Ying  *          file will be created in the root of the debugfs filesystem.
36615b0beaaSHuang Ying  * @value: a pointer to the variable that the file should read to and write
36715b0beaaSHuang Ying  *         from.
36815b0beaaSHuang Ying  */
369f4ae40a6SAl Viro struct dentry *debugfs_create_x64(const char *name, umode_t mode,
37015b0beaaSHuang Ying 				 struct dentry *parent, u64 *value)
37115b0beaaSHuang Ying {
37215b0beaaSHuang Ying 	return debugfs_create_file(name, mode, parent, value, &fops_x64);
37315b0beaaSHuang Ying }
37415b0beaaSHuang Ying EXPORT_SYMBOL_GPL(debugfs_create_x64);
37515b0beaaSHuang Ying 
3765e078787SInaky Perez-Gonzalez 
3775e078787SInaky Perez-Gonzalez static int debugfs_size_t_set(void *data, u64 val)
3785e078787SInaky Perez-Gonzalez {
3795e078787SInaky Perez-Gonzalez 	*(size_t *)data = val;
3805e078787SInaky Perez-Gonzalez 	return 0;
3815e078787SInaky Perez-Gonzalez }
3825e078787SInaky Perez-Gonzalez static int debugfs_size_t_get(void *data, u64 *val)
3835e078787SInaky Perez-Gonzalez {
3845e078787SInaky Perez-Gonzalez 	*val = *(size_t *)data;
3855e078787SInaky Perez-Gonzalez 	return 0;
3865e078787SInaky Perez-Gonzalez }
3875e078787SInaky Perez-Gonzalez DEFINE_SIMPLE_ATTRIBUTE(fops_size_t, debugfs_size_t_get, debugfs_size_t_set,
3885e078787SInaky Perez-Gonzalez 			"%llu\n");	/* %llu and %zu are more or less the same */
3895e078787SInaky Perez-Gonzalez 
3905e078787SInaky Perez-Gonzalez /**
3915e078787SInaky Perez-Gonzalez  * debugfs_create_size_t - create a debugfs file that is used to read and write an size_t value
3925e078787SInaky Perez-Gonzalez  * @name: a pointer to a string containing the name of the file to create.
3935e078787SInaky Perez-Gonzalez  * @mode: the permission that the file should have
3945e078787SInaky Perez-Gonzalez  * @parent: a pointer to the parent dentry for this file.  This should be a
3955e078787SInaky Perez-Gonzalez  *          directory dentry if set.  If this parameter is %NULL, then the
3965e078787SInaky Perez-Gonzalez  *          file will be created in the root of the debugfs filesystem.
3975e078787SInaky Perez-Gonzalez  * @value: a pointer to the variable that the file should read to and write
3985e078787SInaky Perez-Gonzalez  *         from.
3995e078787SInaky Perez-Gonzalez  */
400f4ae40a6SAl Viro struct dentry *debugfs_create_size_t(const char *name, umode_t mode,
4015e078787SInaky Perez-Gonzalez 				     struct dentry *parent, size_t *value)
4025e078787SInaky Perez-Gonzalez {
4035e078787SInaky Perez-Gonzalez 	return debugfs_create_file(name, mode, parent, value, &fops_size_t);
4045e078787SInaky Perez-Gonzalez }
4055e078787SInaky Perez-Gonzalez EXPORT_SYMBOL_GPL(debugfs_create_size_t);
4065e078787SInaky Perez-Gonzalez 
4073a76e5e0SSeth Jennings static int debugfs_atomic_t_set(void *data, u64 val)
4083a76e5e0SSeth Jennings {
4093a76e5e0SSeth Jennings 	atomic_set((atomic_t *)data, val);
4103a76e5e0SSeth Jennings 	return 0;
4113a76e5e0SSeth Jennings }
4123a76e5e0SSeth Jennings static int debugfs_atomic_t_get(void *data, u64 *val)
4133a76e5e0SSeth Jennings {
4143a76e5e0SSeth Jennings 	*val = atomic_read((atomic_t *)data);
4153a76e5e0SSeth Jennings 	return 0;
4163a76e5e0SSeth Jennings }
4173a76e5e0SSeth Jennings DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get,
4183a76e5e0SSeth Jennings 			debugfs_atomic_t_set, "%lld\n");
4193a76e5e0SSeth Jennings DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, "%lld\n");
4203a76e5e0SSeth Jennings DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, "%lld\n");
4213a76e5e0SSeth Jennings 
4223a76e5e0SSeth Jennings /**
4233a76e5e0SSeth Jennings  * debugfs_create_atomic_t - create a debugfs file that is used to read and
4243a76e5e0SSeth Jennings  * write an atomic_t value
4253a76e5e0SSeth Jennings  * @name: a pointer to a string containing the name of the file to create.
4263a76e5e0SSeth Jennings  * @mode: the permission that the file should have
4273a76e5e0SSeth Jennings  * @parent: a pointer to the parent dentry for this file.  This should be a
4283a76e5e0SSeth Jennings  *          directory dentry if set.  If this parameter is %NULL, then the
4293a76e5e0SSeth Jennings  *          file will be created in the root of the debugfs filesystem.
4303a76e5e0SSeth Jennings  * @value: a pointer to the variable that the file should read to and write
4313a76e5e0SSeth Jennings  *         from.
4323a76e5e0SSeth Jennings  */
4333a76e5e0SSeth Jennings struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
4343a76e5e0SSeth Jennings 				 struct dentry *parent, atomic_t *value)
4353a76e5e0SSeth Jennings {
4363a76e5e0SSeth Jennings 	/* if there are no write bits set, make read only */
4373a76e5e0SSeth Jennings 	if (!(mode & S_IWUGO))
4383a76e5e0SSeth Jennings 		return debugfs_create_file(name, mode, parent, value,
4393a76e5e0SSeth Jennings 					&fops_atomic_t_ro);
4403a76e5e0SSeth Jennings 	/* if there are no read bits set, make write only */
4413a76e5e0SSeth Jennings 	if (!(mode & S_IRUGO))
4423a76e5e0SSeth Jennings 		return debugfs_create_file(name, mode, parent, value,
4433a76e5e0SSeth Jennings 					&fops_atomic_t_wo);
4443a76e5e0SSeth Jennings 
4453a76e5e0SSeth Jennings 	return debugfs_create_file(name, mode, parent, value, &fops_atomic_t);
4463a76e5e0SSeth Jennings }
4473a76e5e0SSeth Jennings EXPORT_SYMBOL_GPL(debugfs_create_atomic_t);
4485e078787SInaky Perez-Gonzalez 
4491da177e4SLinus Torvalds static ssize_t read_file_bool(struct file *file, char __user *user_buf,
4501da177e4SLinus Torvalds 			      size_t count, loff_t *ppos)
4511da177e4SLinus Torvalds {
4521da177e4SLinus Torvalds 	char buf[3];
4531da177e4SLinus Torvalds 	u32 *val = file->private_data;
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds 	if (*val)
4561da177e4SLinus Torvalds 		buf[0] = 'Y';
4571da177e4SLinus Torvalds 	else
4581da177e4SLinus Torvalds 		buf[0] = 'N';
4591da177e4SLinus Torvalds 	buf[1] = '\n';
4601da177e4SLinus Torvalds 	buf[2] = 0x00;
4611da177e4SLinus Torvalds 	return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
4621da177e4SLinus Torvalds }
4631da177e4SLinus Torvalds 
4641da177e4SLinus Torvalds static ssize_t write_file_bool(struct file *file, const char __user *user_buf,
4651da177e4SLinus Torvalds 			       size_t count, loff_t *ppos)
4661da177e4SLinus Torvalds {
4671da177e4SLinus Torvalds 	char buf[32];
468c42d2237SStephen Boyd 	size_t buf_size;
4698705b48eSJonathan Cameron 	bool bv;
4701da177e4SLinus Torvalds 	u32 *val = file->private_data;
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds 	buf_size = min(count, (sizeof(buf)-1));
4731da177e4SLinus Torvalds 	if (copy_from_user(buf, user_buf, buf_size))
4741da177e4SLinus Torvalds 		return -EFAULT;
4751da177e4SLinus Torvalds 
476a3b2c8c7SMathias Krause 	buf[buf_size] = '\0';
4778705b48eSJonathan Cameron 	if (strtobool(buf, &bv) == 0)
4788705b48eSJonathan Cameron 		*val = bv;
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds 	return count;
4811da177e4SLinus Torvalds }
4821da177e4SLinus Torvalds 
4834b6f5d20SArjan van de Ven static const struct file_operations fops_bool = {
4841da177e4SLinus Torvalds 	.read =		read_file_bool,
4851da177e4SLinus Torvalds 	.write =	write_file_bool,
486234e3405SStephen Boyd 	.open =		simple_open,
4876038f373SArnd Bergmann 	.llseek =	default_llseek,
4881da177e4SLinus Torvalds };
4891da177e4SLinus Torvalds 
4901da177e4SLinus Torvalds /**
4916468b3afSRandy Dunlap  * debugfs_create_bool - create a debugfs file that is used to read and write a boolean value
4921da177e4SLinus Torvalds  * @name: a pointer to a string containing the name of the file to create.
4931da177e4SLinus Torvalds  * @mode: the permission that the file should have
4941da177e4SLinus Torvalds  * @parent: a pointer to the parent dentry for this file.  This should be a
4956468b3afSRandy Dunlap  *          directory dentry if set.  If this parameter is %NULL, then the
4961da177e4SLinus Torvalds  *          file will be created in the root of the debugfs filesystem.
4971da177e4SLinus Torvalds  * @value: a pointer to the variable that the file should read to and write
4981da177e4SLinus Torvalds  *         from.
4991da177e4SLinus Torvalds  *
5001da177e4SLinus Torvalds  * This function creates a file in debugfs with the given name that
5011da177e4SLinus Torvalds  * contains the value of the variable @value.  If the @mode variable is so
5021da177e4SLinus Torvalds  * set, it can be read from, and written to.
5031da177e4SLinus Torvalds  *
5041da177e4SLinus Torvalds  * This function will return a pointer to a dentry if it succeeds.  This
5051da177e4SLinus Torvalds  * pointer must be passed to the debugfs_remove() function when the file is
5061da177e4SLinus Torvalds  * to be removed (no automatic cleanup happens if your module is unloaded,
5076468b3afSRandy Dunlap  * you are responsible here.)  If an error occurs, %NULL will be returned.
5081da177e4SLinus Torvalds  *
5096468b3afSRandy Dunlap  * If debugfs is not enabled in the kernel, the value -%ENODEV will be
5101da177e4SLinus Torvalds  * returned.  It is not wise to check for this value, but rather, check for
5116468b3afSRandy Dunlap  * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
5121da177e4SLinus Torvalds  * code.
5131da177e4SLinus Torvalds  */
514f4ae40a6SAl Viro struct dentry *debugfs_create_bool(const char *name, umode_t mode,
5151da177e4SLinus Torvalds 				   struct dentry *parent, u32 *value)
5161da177e4SLinus Torvalds {
5171da177e4SLinus Torvalds 	return debugfs_create_file(name, mode, parent, value, &fops_bool);
5181da177e4SLinus Torvalds }
5191da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(debugfs_create_bool);
5201da177e4SLinus Torvalds 
521dd308bc3SMichael Ellerman static ssize_t read_file_blob(struct file *file, char __user *user_buf,
522dd308bc3SMichael Ellerman 			      size_t count, loff_t *ppos)
523dd308bc3SMichael Ellerman {
524dd308bc3SMichael Ellerman 	struct debugfs_blob_wrapper *blob = file->private_data;
525dd308bc3SMichael Ellerman 	return simple_read_from_buffer(user_buf, count, ppos, blob->data,
526dd308bc3SMichael Ellerman 			blob->size);
527dd308bc3SMichael Ellerman }
528dd308bc3SMichael Ellerman 
52900977a59SArjan van de Ven static const struct file_operations fops_blob = {
530dd308bc3SMichael Ellerman 	.read =		read_file_blob,
531234e3405SStephen Boyd 	.open =		simple_open,
5326038f373SArnd Bergmann 	.llseek =	default_llseek,
533dd308bc3SMichael Ellerman };
534dd308bc3SMichael Ellerman 
535dd308bc3SMichael Ellerman /**
536400ced61SJonathan Corbet  * debugfs_create_blob - create a debugfs file that is used to read a binary blob
537dd308bc3SMichael Ellerman  * @name: a pointer to a string containing the name of the file to create.
538dd308bc3SMichael Ellerman  * @mode: the permission that the file should have
539dd308bc3SMichael Ellerman  * @parent: a pointer to the parent dentry for this file.  This should be a
5406468b3afSRandy Dunlap  *          directory dentry if set.  If this parameter is %NULL, then the
541dd308bc3SMichael Ellerman  *          file will be created in the root of the debugfs filesystem.
542dd308bc3SMichael Ellerman  * @blob: a pointer to a struct debugfs_blob_wrapper which contains a pointer
543dd308bc3SMichael Ellerman  *        to the blob data and the size of the data.
544dd308bc3SMichael Ellerman  *
545dd308bc3SMichael Ellerman  * This function creates a file in debugfs with the given name that exports
546dd308bc3SMichael Ellerman  * @blob->data as a binary blob. If the @mode variable is so set it can be
547dd308bc3SMichael Ellerman  * read from. Writing is not supported.
548dd308bc3SMichael Ellerman  *
549dd308bc3SMichael Ellerman  * This function will return a pointer to a dentry if it succeeds.  This
550dd308bc3SMichael Ellerman  * pointer must be passed to the debugfs_remove() function when the file is
551dd308bc3SMichael Ellerman  * to be removed (no automatic cleanup happens if your module is unloaded,
5526468b3afSRandy Dunlap  * you are responsible here.)  If an error occurs, %NULL will be returned.
553dd308bc3SMichael Ellerman  *
5546468b3afSRandy Dunlap  * If debugfs is not enabled in the kernel, the value -%ENODEV will be
555dd308bc3SMichael Ellerman  * returned.  It is not wise to check for this value, but rather, check for
5566468b3afSRandy Dunlap  * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
557dd308bc3SMichael Ellerman  * code.
558dd308bc3SMichael Ellerman  */
559f4ae40a6SAl Viro struct dentry *debugfs_create_blob(const char *name, umode_t mode,
560dd308bc3SMichael Ellerman 				   struct dentry *parent,
561dd308bc3SMichael Ellerman 				   struct debugfs_blob_wrapper *blob)
562dd308bc3SMichael Ellerman {
563dd308bc3SMichael Ellerman 	return debugfs_create_file(name, mode, parent, blob, &fops_blob);
564dd308bc3SMichael Ellerman }
565dd308bc3SMichael Ellerman EXPORT_SYMBOL_GPL(debugfs_create_blob);
5661a087c6aSAlessandro Rubini 
5679fe2a701SSrivatsa Vaddagiri struct array_data {
5689fe2a701SSrivatsa Vaddagiri 	void *array;
5699fe2a701SSrivatsa Vaddagiri 	u32 elements;
5709fe2a701SSrivatsa Vaddagiri };
5719fe2a701SSrivatsa Vaddagiri 
572e05e279eSLinus Torvalds static size_t u32_format_array(char *buf, size_t bufsize,
573e05e279eSLinus Torvalds 			       u32 *array, int array_size)
5749fe2a701SSrivatsa Vaddagiri {
5759fe2a701SSrivatsa Vaddagiri 	size_t ret = 0;
5769fe2a701SSrivatsa Vaddagiri 
577e05e279eSLinus Torvalds 	while (--array_size >= 0) {
5789fe2a701SSrivatsa Vaddagiri 		size_t len;
579e05e279eSLinus Torvalds 		char term = array_size ? ' ' : '\n';
5809fe2a701SSrivatsa Vaddagiri 
581e05e279eSLinus Torvalds 		len = snprintf(buf, bufsize, "%u%c", *array++, term);
5829fe2a701SSrivatsa Vaddagiri 		ret += len;
5839fe2a701SSrivatsa Vaddagiri 
5849fe2a701SSrivatsa Vaddagiri 		buf += len;
5859fe2a701SSrivatsa Vaddagiri 		bufsize -= len;
5869fe2a701SSrivatsa Vaddagiri 	}
5879fe2a701SSrivatsa Vaddagiri 	return ret;
5889fe2a701SSrivatsa Vaddagiri }
5899fe2a701SSrivatsa Vaddagiri 
59036048853SDavid Rientjes static int u32_array_open(struct inode *inode, struct file *file)
5919fe2a701SSrivatsa Vaddagiri {
5929fe2a701SSrivatsa Vaddagiri 	struct array_data *data = inode->i_private;
593e05e279eSLinus Torvalds 	int size, elements = data->elements;
594e05e279eSLinus Torvalds 	char *buf;
5959fe2a701SSrivatsa Vaddagiri 
596e05e279eSLinus Torvalds 	/*
597e05e279eSLinus Torvalds 	 * Max size:
598e05e279eSLinus Torvalds 	 *  - 10 digits + ' '/'\n' = 11 bytes per number
599e05e279eSLinus Torvalds 	 *  - terminating NUL character
600e05e279eSLinus Torvalds 	 */
601e05e279eSLinus Torvalds 	size = elements*11;
602e05e279eSLinus Torvalds 	buf = kmalloc(size+1, GFP_KERNEL);
603e05e279eSLinus Torvalds 	if (!buf)
60436048853SDavid Rientjes 		return -ENOMEM;
605e05e279eSLinus Torvalds 	buf[size] = 0;
606e05e279eSLinus Torvalds 
607e05e279eSLinus Torvalds 	file->private_data = buf;
608e05e279eSLinus Torvalds 	u32_format_array(buf, size, data->array, data->elements);
609e05e279eSLinus Torvalds 
61036048853SDavid Rientjes 	return nonseekable_open(inode, file);
6119fe2a701SSrivatsa Vaddagiri }
6129fe2a701SSrivatsa Vaddagiri 
61336048853SDavid Rientjes static ssize_t u32_array_read(struct file *file, char __user *buf, size_t len,
61436048853SDavid Rientjes 			      loff_t *ppos)
61536048853SDavid Rientjes {
61636048853SDavid Rientjes 	size_t size = strlen(file->private_data);
6179fe2a701SSrivatsa Vaddagiri 
6189fe2a701SSrivatsa Vaddagiri 	return simple_read_from_buffer(buf, len, ppos,
6199fe2a701SSrivatsa Vaddagiri 					file->private_data, size);
6209fe2a701SSrivatsa Vaddagiri }
6219fe2a701SSrivatsa Vaddagiri 
6229fe2a701SSrivatsa Vaddagiri static int u32_array_release(struct inode *inode, struct file *file)
6239fe2a701SSrivatsa Vaddagiri {
6249fe2a701SSrivatsa Vaddagiri 	kfree(file->private_data);
6259fe2a701SSrivatsa Vaddagiri 
6269fe2a701SSrivatsa Vaddagiri 	return 0;
6279fe2a701SSrivatsa Vaddagiri }
6289fe2a701SSrivatsa Vaddagiri 
6299fe2a701SSrivatsa Vaddagiri static const struct file_operations u32_array_fops = {
6309fe2a701SSrivatsa Vaddagiri 	.owner	 = THIS_MODULE,
6319fe2a701SSrivatsa Vaddagiri 	.open	 = u32_array_open,
6329fe2a701SSrivatsa Vaddagiri 	.release = u32_array_release,
6339fe2a701SSrivatsa Vaddagiri 	.read	 = u32_array_read,
6349fe2a701SSrivatsa Vaddagiri 	.llseek  = no_llseek,
6359fe2a701SSrivatsa Vaddagiri };
6369fe2a701SSrivatsa Vaddagiri 
6379fe2a701SSrivatsa Vaddagiri /**
6389fe2a701SSrivatsa Vaddagiri  * debugfs_create_u32_array - create a debugfs file that is used to read u32
6399fe2a701SSrivatsa Vaddagiri  * array.
6409fe2a701SSrivatsa Vaddagiri  * @name: a pointer to a string containing the name of the file to create.
6419fe2a701SSrivatsa Vaddagiri  * @mode: the permission that the file should have.
6429fe2a701SSrivatsa Vaddagiri  * @parent: a pointer to the parent dentry for this file.  This should be a
6439fe2a701SSrivatsa Vaddagiri  *          directory dentry if set.  If this parameter is %NULL, then the
6449fe2a701SSrivatsa Vaddagiri  *          file will be created in the root of the debugfs filesystem.
6459fe2a701SSrivatsa Vaddagiri  * @array: u32 array that provides data.
6469fe2a701SSrivatsa Vaddagiri  * @elements: total number of elements in the array.
6479fe2a701SSrivatsa Vaddagiri  *
6489fe2a701SSrivatsa Vaddagiri  * This function creates a file in debugfs with the given name that exports
6499fe2a701SSrivatsa Vaddagiri  * @array as data. If the @mode variable is so set it can be read from.
6509fe2a701SSrivatsa Vaddagiri  * Writing is not supported. Seek within the file is also not supported.
6519fe2a701SSrivatsa Vaddagiri  * Once array is created its size can not be changed.
6529fe2a701SSrivatsa Vaddagiri  *
6539fe2a701SSrivatsa Vaddagiri  * The function returns a pointer to dentry on success. If debugfs is not
6549fe2a701SSrivatsa Vaddagiri  * enabled in the kernel, the value -%ENODEV will be returned.
6559fe2a701SSrivatsa Vaddagiri  */
6569fe2a701SSrivatsa Vaddagiri struct dentry *debugfs_create_u32_array(const char *name, umode_t mode,
6579fe2a701SSrivatsa Vaddagiri 					    struct dentry *parent,
6589fe2a701SSrivatsa Vaddagiri 					    u32 *array, u32 elements)
6599fe2a701SSrivatsa Vaddagiri {
6609fe2a701SSrivatsa Vaddagiri 	struct array_data *data = kmalloc(sizeof(*data), GFP_KERNEL);
6619fe2a701SSrivatsa Vaddagiri 
6629fe2a701SSrivatsa Vaddagiri 	if (data == NULL)
6639fe2a701SSrivatsa Vaddagiri 		return NULL;
6649fe2a701SSrivatsa Vaddagiri 
6659fe2a701SSrivatsa Vaddagiri 	data->array = array;
6669fe2a701SSrivatsa Vaddagiri 	data->elements = elements;
6679fe2a701SSrivatsa Vaddagiri 
6689fe2a701SSrivatsa Vaddagiri 	return debugfs_create_file(name, mode, parent, data, &u32_array_fops);
6699fe2a701SSrivatsa Vaddagiri }
6709fe2a701SSrivatsa Vaddagiri EXPORT_SYMBOL_GPL(debugfs_create_u32_array);
6719fe2a701SSrivatsa Vaddagiri 
6723b85e4abSHeiko Carstens #ifdef CONFIG_HAS_IOMEM
6733b85e4abSHeiko Carstens 
6741a087c6aSAlessandro Rubini /*
6751a087c6aSAlessandro Rubini  * The regset32 stuff is used to print 32-bit registers using the
6761a087c6aSAlessandro Rubini  * seq_file utilities. We offer printing a register set in an already-opened
6771a087c6aSAlessandro Rubini  * sequential file or create a debugfs file that only prints a regset32.
6781a087c6aSAlessandro Rubini  */
6791a087c6aSAlessandro Rubini 
6801a087c6aSAlessandro Rubini /**
6811a087c6aSAlessandro Rubini  * debugfs_print_regs32 - use seq_print to describe a set of registers
6821a087c6aSAlessandro Rubini  * @s: the seq_file structure being used to generate output
6831a087c6aSAlessandro Rubini  * @regs: an array if struct debugfs_reg32 structures
684b5763accSRandy Dunlap  * @nregs: the length of the above array
6851a087c6aSAlessandro Rubini  * @base: the base address to be used in reading the registers
6861a087c6aSAlessandro Rubini  * @prefix: a string to be prefixed to every output line
6871a087c6aSAlessandro Rubini  *
6881a087c6aSAlessandro Rubini  * This function outputs a text block describing the current values of
6891a087c6aSAlessandro Rubini  * some 32-bit hardware registers. It is meant to be used within debugfs
6901a087c6aSAlessandro Rubini  * files based on seq_file that need to show registers, intermixed with other
6911a087c6aSAlessandro Rubini  * information. The prefix argument may be used to specify a leading string,
6921a087c6aSAlessandro Rubini  * because some peripherals have several blocks of identical registers,
6931a087c6aSAlessandro Rubini  * for example configuration of dma channels
6941a087c6aSAlessandro Rubini  */
695*9761536eSJoe Perches void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
6961a087c6aSAlessandro Rubini 			  int nregs, void __iomem *base, char *prefix)
6971a087c6aSAlessandro Rubini {
698*9761536eSJoe Perches 	int i;
6991a087c6aSAlessandro Rubini 
7001a087c6aSAlessandro Rubini 	for (i = 0; i < nregs; i++, regs++) {
7011a087c6aSAlessandro Rubini 		if (prefix)
702*9761536eSJoe Perches 			seq_printf(s, "%s", prefix);
703*9761536eSJoe Perches 		seq_printf(s, "%s = 0x%08x\n", regs->name,
7045858441cSDan Carpenter 			   readl(base + regs->offset));
705*9761536eSJoe Perches 		if (seq_has_overflowed(s))
706*9761536eSJoe Perches 			break;
7071a087c6aSAlessandro Rubini 	}
7081a087c6aSAlessandro Rubini }
7091a087c6aSAlessandro Rubini EXPORT_SYMBOL_GPL(debugfs_print_regs32);
7101a087c6aSAlessandro Rubini 
7111a087c6aSAlessandro Rubini static int debugfs_show_regset32(struct seq_file *s, void *data)
7121a087c6aSAlessandro Rubini {
7131a087c6aSAlessandro Rubini 	struct debugfs_regset32 *regset = s->private;
7141a087c6aSAlessandro Rubini 
7151a087c6aSAlessandro Rubini 	debugfs_print_regs32(s, regset->regs, regset->nregs, regset->base, "");
7161a087c6aSAlessandro Rubini 	return 0;
7171a087c6aSAlessandro Rubini }
7181a087c6aSAlessandro Rubini 
7191a087c6aSAlessandro Rubini static int debugfs_open_regset32(struct inode *inode, struct file *file)
7201a087c6aSAlessandro Rubini {
7211a087c6aSAlessandro Rubini 	return single_open(file, debugfs_show_regset32, inode->i_private);
7221a087c6aSAlessandro Rubini }
7231a087c6aSAlessandro Rubini 
7241a087c6aSAlessandro Rubini static const struct file_operations fops_regset32 = {
7251a087c6aSAlessandro Rubini 	.open =		debugfs_open_regset32,
7261a087c6aSAlessandro Rubini 	.read =		seq_read,
7271a087c6aSAlessandro Rubini 	.llseek =	seq_lseek,
7281a087c6aSAlessandro Rubini 	.release =	single_release,
7291a087c6aSAlessandro Rubini };
7301a087c6aSAlessandro Rubini 
7311a087c6aSAlessandro Rubini /**
7321a087c6aSAlessandro Rubini  * debugfs_create_regset32 - create a debugfs file that returns register values
7331a087c6aSAlessandro Rubini  * @name: a pointer to a string containing the name of the file to create.
7341a087c6aSAlessandro Rubini  * @mode: the permission that the file should have
7351a087c6aSAlessandro Rubini  * @parent: a pointer to the parent dentry for this file.  This should be a
7361a087c6aSAlessandro Rubini  *          directory dentry if set.  If this parameter is %NULL, then the
7371a087c6aSAlessandro Rubini  *          file will be created in the root of the debugfs filesystem.
7381a087c6aSAlessandro Rubini  * @regset: a pointer to a struct debugfs_regset32, which contains a pointer
7391a087c6aSAlessandro Rubini  *          to an array of register definitions, the array size and the base
7401a087c6aSAlessandro Rubini  *          address where the register bank is to be found.
7411a087c6aSAlessandro Rubini  *
7421a087c6aSAlessandro Rubini  * This function creates a file in debugfs with the given name that reports
7431a087c6aSAlessandro Rubini  * the names and values of a set of 32-bit registers. If the @mode variable
7441a087c6aSAlessandro Rubini  * is so set it can be read from. Writing is not supported.
7451a087c6aSAlessandro Rubini  *
7461a087c6aSAlessandro Rubini  * This function will return a pointer to a dentry if it succeeds.  This
7471a087c6aSAlessandro Rubini  * pointer must be passed to the debugfs_remove() function when the file is
7481a087c6aSAlessandro Rubini  * to be removed (no automatic cleanup happens if your module is unloaded,
7491a087c6aSAlessandro Rubini  * you are responsible here.)  If an error occurs, %NULL will be returned.
7501a087c6aSAlessandro Rubini  *
7511a087c6aSAlessandro Rubini  * If debugfs is not enabled in the kernel, the value -%ENODEV will be
7521a087c6aSAlessandro Rubini  * returned.  It is not wise to check for this value, but rather, check for
7531a087c6aSAlessandro Rubini  * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
7541a087c6aSAlessandro Rubini  * code.
7551a087c6aSAlessandro Rubini  */
75688187398SAl Viro struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
7571a087c6aSAlessandro Rubini 				       struct dentry *parent,
7581a087c6aSAlessandro Rubini 				       struct debugfs_regset32 *regset)
7591a087c6aSAlessandro Rubini {
7601a087c6aSAlessandro Rubini 	return debugfs_create_file(name, mode, parent, regset, &fops_regset32);
7611a087c6aSAlessandro Rubini }
7621a087c6aSAlessandro Rubini EXPORT_SYMBOL_GPL(debugfs_create_regset32);
7633b85e4abSHeiko Carstens 
7643b85e4abSHeiko Carstens #endif /* CONFIG_HAS_IOMEM */
765