1 /*
2  * procfs_example.c: an example proc interface
3  *
4  * Copyright (C) 2001, Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
5  *
6  * This file accompanies the procfs-guide in the Linux kernel
7  * source. Its main use is to demonstrate the concepts and
8  * functions described in the guide.
9  *
10  * This software has been developed while working on the LART
11  * computing board (http://www.lart.tudelft.nl/), which is
12  * sponsored by the Mobile Multi-media Communications
13  * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications
14  * (http://www.ubicom.tudelft.nl/) projects.
15  *
16  * The author can be reached at:
17  *
18  *  Erik Mouw
19  *  Information and Communication Theory Group
20  *  Faculty of Information Technology and Systems
21  *  Delft University of Technology
22  *  P.O. Box 5031
23  *  2600 GA Delft
24  *  The Netherlands
25  *
26  *
27  * This program is free software; you can redistribute
28  * it and/or modify it under the terms of the GNU General
29  * Public License as published by the Free Software
30  * Foundation; either version 2 of the License, or (at your
31  * option) any later version.
32  *
33  * This program is distributed in the hope that it will be
34  * useful, but WITHOUT ANY WARRANTY; without even the implied
35  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
36  * PURPOSE.  See the GNU General Public License for more
37  * details.
38  *
39  * You should have received a copy of the GNU General Public
40  * License along with this program; if not, write to the
41  * Free Software Foundation, Inc., 59 Temple Place,
42  * Suite 330, Boston, MA  02111-1307  USA
43  *
44  */
45 
46 #include <linux/module.h>
47 #include <linux/kernel.h>
48 #include <linux/init.h>
49 #include <linux/proc_fs.h>
50 #include <linux/sched.h>
51 #include <asm/uaccess.h>
52 
53 
54 #define MODULE_VERSION "1.0"
55 #define MODULE_NAME "procfs_example"
56 
57 #define FOOBAR_LEN 8
58 
59 struct fb_data_t {
60 	char name[FOOBAR_LEN + 1];
61 	char value[FOOBAR_LEN + 1];
62 };
63 
64 
65 static struct proc_dir_entry *example_dir, *foo_file,
66 	*bar_file, *jiffies_file, *tty_device, *symlink;
67 
68 
69 struct fb_data_t foo_data, bar_data;
70 
71 
proc_read_jiffies(char * page,char ** start,off_t off,int count,int * eof,void * data)72 static int proc_read_jiffies(char *page, char **start,
73 			     off_t off, int count,
74 			     int *eof, void *data)
75 {
76 	int len;
77 
78 	MOD_INC_USE_COUNT;
79 
80 	len = sprintf(page, "jiffies = %ld\n",
81                       jiffies);
82 
83 	MOD_DEC_USE_COUNT;
84 
85 	return len;
86 }
87 
88 
proc_read_foobar(char * page,char ** start,off_t off,int count,int * eof,void * data)89 static int proc_read_foobar(char *page, char **start,
90 			    off_t off, int count,
91 			    int *eof, void *data)
92 {
93 	int len;
94 	struct fb_data_t *fb_data = (struct fb_data_t *)data;
95 
96 	MOD_INC_USE_COUNT;
97 
98 	len = sprintf(page, "%s = '%s'\n",
99 		      fb_data->name, fb_data->value);
100 
101 	MOD_DEC_USE_COUNT;
102 
103 	return len;
104 }
105 
106 
proc_write_foobar(struct file * file,const char * buffer,unsigned long count,void * data)107 static int proc_write_foobar(struct file *file,
108 			     const char *buffer,
109 			     unsigned long count,
110 			     void *data)
111 {
112 	int len;
113 	struct fb_data_t *fb_data = (struct fb_data_t *)data;
114 
115 	MOD_INC_USE_COUNT;
116 
117 	if(count > FOOBAR_LEN)
118 		len = FOOBAR_LEN;
119 	else
120 		len = count;
121 
122 	if(copy_from_user(fb_data->value, buffer, len)) {
123 		MOD_DEC_USE_COUNT;
124 		return -EFAULT;
125 	}
126 
127 	fb_data->value[len] = '\0';
128 
129 	MOD_DEC_USE_COUNT;
130 
131 	return len;
132 }
133 
134 
init_procfs_example(void)135 static int __init init_procfs_example(void)
136 {
137 	int rv = 0;
138 
139 	/* create directory */
140 	example_dir = proc_mkdir(MODULE_NAME, NULL);
141 	if(example_dir == NULL) {
142 		rv = -ENOMEM;
143 		goto out;
144 	}
145 
146 	example_dir->owner = THIS_MODULE;
147 
148 	/* create jiffies using convenience function */
149 	jiffies_file = create_proc_read_entry("jiffies",
150 					      0444, example_dir,
151 					      proc_read_jiffies,
152 					      NULL);
153 	if(jiffies_file == NULL) {
154 		rv  = -ENOMEM;
155 		goto no_jiffies;
156 	}
157 
158 	jiffies_file->owner = THIS_MODULE;
159 
160 	/* create foo and bar files using same callback
161 	 * functions
162 	 */
163 	foo_file = create_proc_entry("foo", 0644, example_dir);
164 	if(foo_file == NULL) {
165 		rv = -ENOMEM;
166 		goto no_foo;
167 	}
168 
169 	strcpy(foo_data.name, "foo");
170 	strcpy(foo_data.value, "foo");
171 	foo_file->data = &foo_data;
172 	foo_file->read_proc = proc_read_foobar;
173 	foo_file->write_proc = proc_write_foobar;
174 	foo_file->owner = THIS_MODULE;
175 
176 	bar_file = create_proc_entry("bar", 0644, example_dir);
177 	if(bar_file == NULL) {
178 		rv = -ENOMEM;
179 		goto no_bar;
180 	}
181 
182 	strcpy(bar_data.name, "bar");
183 	strcpy(bar_data.value, "bar");
184 	bar_file->data = &bar_data;
185 	bar_file->read_proc = proc_read_foobar;
186 	bar_file->write_proc = proc_write_foobar;
187 	bar_file->owner = THIS_MODULE;
188 
189 	/* create tty device */
190 	tty_device = proc_mknod("tty", S_IFCHR | 0666,
191 				example_dir, MKDEV(5, 0));
192 	if(tty_device == NULL) {
193 		rv = -ENOMEM;
194 		goto no_tty;
195 	}
196 
197 	tty_device->owner = THIS_MODULE;
198 
199 	/* create symlink */
200 	symlink = proc_symlink("jiffies_too", example_dir,
201 			       "jiffies");
202 	if(symlink == NULL) {
203 		rv = -ENOMEM;
204 		goto no_symlink;
205 	}
206 
207 	symlink->owner = THIS_MODULE;
208 
209 	/* everything OK */
210 	printk(KERN_INFO "%s %s initialised\n",
211 	       MODULE_NAME, MODULE_VERSION);
212 	return 0;
213 
214 no_symlink:
215 	remove_proc_entry("tty", example_dir);
216 no_tty:
217 	remove_proc_entry("bar", example_dir);
218 no_bar:
219 	remove_proc_entry("foo", example_dir);
220 no_foo:
221 	remove_proc_entry("jiffies", example_dir);
222 no_jiffies:
223 	remove_proc_entry(MODULE_NAME, NULL);
224 out:
225 	return rv;
226 }
227 
228 
cleanup_procfs_example(void)229 static void __exit cleanup_procfs_example(void)
230 {
231 	remove_proc_entry("jiffies_too", example_dir);
232 	remove_proc_entry("tty", example_dir);
233 	remove_proc_entry("bar", example_dir);
234 	remove_proc_entry("foo", example_dir);
235 	remove_proc_entry("jiffies", example_dir);
236 	remove_proc_entry(MODULE_NAME, NULL);
237 
238 	printk(KERN_INFO "%s %s removed\n",
239 	       MODULE_NAME, MODULE_VERSION);
240 }
241 
242 
243 module_init(init_procfs_example);
244 module_exit(cleanup_procfs_example);
245 
246 MODULE_AUTHOR("Erik Mouw");
247 MODULE_DESCRIPTION("procfs examples");
248 
249 EXPORT_NO_SYMBOLS;
250