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/jiffies.h>
51#include <asm/uaccess.h>
52
53
54#define MODULE_VERS "1.0"
55#define MODULE_NAME "procfs_example"
56
57#define FOOBAR_LEN 8
58
59struct fb_data_t {
60	char name[FOOBAR_LEN + 1];
61	char value[FOOBAR_LEN + 1];
62};
63
64
65static struct proc_dir_entry *example_dir, *foo_file,
66	*bar_file, *jiffies_file, *symlink;
67
68
69struct fb_data_t foo_data, bar_data;
70
71
72static 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	len = sprintf(page, "jiffies = %ld\n",
79                      jiffies);
80
81	return len;
82}
83
84
85static int proc_read_foobar(char *page, char **start,
86			    off_t off, int count,
87			    int *eof, void *data)
88{
89	int len;
90	struct fb_data_t *fb_data = (struct fb_data_t *)data;
91
92	/* DON'T DO THAT - buffer overruns are bad */
93	len = sprintf(page, "%s = '%s'\n",
94		      fb_data->name, fb_data->value);
95
96	return len;
97}
98
99
100static int proc_write_foobar(struct file *file,
101			     const char *buffer,
102			     unsigned long count,
103			     void *data)
104{
105	int len;
106	struct fb_data_t *fb_data = (struct fb_data_t *)data;
107
108	if(count > FOOBAR_LEN)
109		len = FOOBAR_LEN;
110	else
111		len = count;
112
113	if(copy_from_user(fb_data->value, buffer, len))
114		return -EFAULT;
115
116	fb_data->value[len] = '\0';
117
118	return len;
119}
120
121
122static int __init init_procfs_example(void)
123{
124	int rv = 0;
125
126	/* create directory */
127	example_dir = proc_mkdir(MODULE_NAME, NULL);
128	if(example_dir == NULL) {
129		rv = -ENOMEM;
130		goto out;
131	}
132
133	example_dir->owner = THIS_MODULE;
134
135	/* create jiffies using convenience function */
136	jiffies_file = create_proc_read_entry("jiffies",
137					      0444, example_dir,
138					      proc_read_jiffies,
139					      NULL);
140	if(jiffies_file == NULL) {
141		rv  = -ENOMEM;
142		goto no_jiffies;
143	}
144
145	jiffies_file->owner = THIS_MODULE;
146
147	/* create foo and bar files using same callback
148	 * functions
149	 */
150	foo_file = create_proc_entry("foo", 0644, example_dir);
151	if(foo_file == NULL) {
152		rv = -ENOMEM;
153		goto no_foo;
154	}
155
156	strcpy(foo_data.name, "foo");
157	strcpy(foo_data.value, "foo");
158	foo_file->data = &foo_data;
159	foo_file->read_proc = proc_read_foobar;
160	foo_file->write_proc = proc_write_foobar;
161	foo_file->owner = THIS_MODULE;
162
163	bar_file = create_proc_entry("bar", 0644, example_dir);
164	if(bar_file == NULL) {
165		rv = -ENOMEM;
166		goto no_bar;
167	}
168
169	strcpy(bar_data.name, "bar");
170	strcpy(bar_data.value, "bar");
171	bar_file->data = &bar_data;
172	bar_file->read_proc = proc_read_foobar;
173	bar_file->write_proc = proc_write_foobar;
174	bar_file->owner = THIS_MODULE;
175
176	/* create symlink */
177	symlink = proc_symlink("jiffies_too", example_dir,
178			       "jiffies");
179	if(symlink == NULL) {
180		rv = -ENOMEM;
181		goto no_symlink;
182	}
183
184	symlink->owner = THIS_MODULE;
185
186	/* everything OK */
187	printk(KERN_INFO "%s %s initialised\n",
188	       MODULE_NAME, MODULE_VERS);
189	return 0;
190
191no_symlink:
192	remove_proc_entry("tty", example_dir);
193no_tty:
194	remove_proc_entry("bar", example_dir);
195no_bar:
196	remove_proc_entry("foo", example_dir);
197no_foo:
198	remove_proc_entry("jiffies", example_dir);
199no_jiffies:
200	remove_proc_entry(MODULE_NAME, NULL);
201out:
202	return rv;
203}
204
205
206static void __exit cleanup_procfs_example(void)
207{
208	remove_proc_entry("jiffies_too", example_dir);
209	remove_proc_entry("tty", example_dir);
210	remove_proc_entry("bar", example_dir);
211	remove_proc_entry("foo", example_dir);
212	remove_proc_entry("jiffies", example_dir);
213	remove_proc_entry(MODULE_NAME, NULL);
214
215	printk(KERN_INFO "%s %s removed\n",
216	       MODULE_NAME, MODULE_VERS);
217}
218
219
220module_init(init_procfs_example);
221module_exit(cleanup_procfs_example);
222
223MODULE_AUTHOR("Erik Mouw");
224MODULE_DESCRIPTION("procfs examples");
225