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