1 /* 2 * srm_env.c - Access to SRM environment 3 * variables through linux' procfs 4 * 5 * Copyright (C) 2001-2002 Jan-Benedict Glaw <jbglaw@lug-owl.de> 6 * 7 * This driver is at all a modified version of Erik Mouw's 8 * Documentation/DocBook/procfs_example.c, so: thank 9 * you, Erik! He can be reached via email at 10 * <J.A.K.Mouw@its.tudelft.nl>. It is based on an idea 11 * provided by DEC^WCompaq^WIntel's "Jumpstart" CD. They 12 * included a patch like this as well. Thanks for idea! 13 * 14 * This program is free software; you can redistribute 15 * it and/or modify it under the terms of the GNU General 16 * Public License version 2 as published by the Free Software 17 * Foundation. 18 * 19 * This program is distributed in the hope that it will be 20 * useful, but WITHOUT ANY WARRANTY; without even the implied 21 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 22 * PURPOSE. See the GNU General Public License for more 23 * details. 24 * 25 * You should have received a copy of the GNU General Public 26 * License along with this program; if not, write to the 27 * Free Software Foundation, Inc., 59 Temple Place, 28 * Suite 330, Boston, MA 02111-1307 USA 29 * 30 */ 31 32 /* 33 * Changelog 34 * ~~~~~~~~~ 35 * 36 * Thu, 22 Aug 2002 15:10:43 +0200 37 * - Update Config.help entry. I got a number of emails asking 38 * me to tell their senders if they could make use of this 39 * piece of code... So: "SRM is something like BIOS for your 40 * Alpha" 41 * - Update code formatting a bit to better conform CodingStyle 42 * rules. 43 * - So this is v0.0.5, with no changes (except formatting) 44 * 45 * Wed, 22 May 2002 00:11:21 +0200 46 * - Fix typo on comment (SRC -> SRM) 47 * - Call this "Version 0.0.4" 48 * 49 * Tue, 9 Apr 2002 18:44:40 +0200 50 * - Implement access by variable name and additionally 51 * by number. This is done by creating two subdirectories 52 * where one holds all names (like the old directory 53 * did) and the other holding 256 files named like "0", 54 * "1" and so on. 55 * - Call this "Version 0.0.3" 56 * 57 */ 58 59 #include <linux/kernel.h> 60 #include <linux/module.h> 61 #include <linux/init.h> 62 #include <linux/proc_fs.h> 63 #include <asm/console.h> 64 #include <asm/uaccess.h> 65 #include <asm/machvec.h> 66 67 #define BASE_DIR "srm_environment" /* Subdir in /proc/ */ 68 #define NAMED_DIR "named_variables" /* Subdir for known variables */ 69 #define NUMBERED_DIR "numbered_variables" /* Subdir for all variables */ 70 #define VERSION "0.0.5" /* Module version */ 71 #define NAME "srm_env" /* Module name */ 72 73 MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); 74 MODULE_DESCRIPTION("Accessing Alpha SRM environment through procfs interface"); 75 MODULE_LICENSE("GPL"); 76 77 typedef struct _srm_env { 78 char *name; 79 unsigned long id; 80 struct proc_dir_entry *proc_entry; 81 } srm_env_t; 82 83 static struct proc_dir_entry *base_dir; 84 static struct proc_dir_entry *named_dir; 85 static struct proc_dir_entry *numbered_dir; 86 static char number[256][4]; 87 88 static srm_env_t srm_named_entries[] = { 89 { "auto_action", ENV_AUTO_ACTION }, 90 { "boot_dev", ENV_BOOT_DEV }, 91 { "bootdef_dev", ENV_BOOTDEF_DEV }, 92 { "booted_dev", ENV_BOOTED_DEV }, 93 { "boot_file", ENV_BOOT_FILE }, 94 { "booted_file", ENV_BOOTED_FILE }, 95 { "boot_osflags", ENV_BOOT_OSFLAGS }, 96 { "booted_osflags", ENV_BOOTED_OSFLAGS }, 97 { "boot_reset", ENV_BOOT_RESET }, 98 { "dump_dev", ENV_DUMP_DEV }, 99 { "enable_audit", ENV_ENABLE_AUDIT }, 100 { "license", ENV_LICENSE }, 101 { "char_set", ENV_CHAR_SET }, 102 { "language", ENV_LANGUAGE }, 103 { "tty_dev", ENV_TTY_DEV }, 104 { NULL, 0 }, 105 }; 106 static srm_env_t srm_numbered_entries[256]; 107 108 109 110 static int 111 srm_env_read(char *page, char **start, off_t off, int count, int *eof, 112 void *data) 113 { 114 int nbytes; 115 unsigned long ret; 116 srm_env_t *entry; 117 118 if(off != 0) 119 return -EFAULT; 120 121 entry = (srm_env_t *) data; 122 ret = callback_getenv(entry->id, page, count); 123 124 if((ret >> 61) == 0) 125 nbytes = (int) ret; 126 else 127 nbytes = -EFAULT; 128 129 return nbytes; 130 } 131 132 133 static int 134 srm_env_write(struct file *file, const char __user *buffer, unsigned long count, 135 void *data) 136 { 137 int res; 138 srm_env_t *entry; 139 char *buf = (char *) __get_free_page(GFP_USER); 140 unsigned long ret1, ret2; 141 142 entry = (srm_env_t *) data; 143 144 if (!buf) 145 return -ENOMEM; 146 147 res = -EINVAL; 148 if (count >= PAGE_SIZE) 149 goto out; 150 151 res = -EFAULT; 152 if (copy_from_user(buf, buffer, count)) 153 goto out; 154 buf[count] = '\0'; 155 156 ret1 = callback_setenv(entry->id, buf, count); 157 if ((ret1 >> 61) == 0) { 158 do 159 ret2 = callback_save_env(); 160 while((ret2 >> 61) == 1); 161 res = (int) ret1; 162 } 163 164 out: 165 free_page((unsigned long)buf); 166 return res; 167 } 168 169 static void 170 srm_env_cleanup(void) 171 { 172 srm_env_t *entry; 173 unsigned long var_num; 174 175 if(base_dir) { 176 /* 177 * Remove named entries 178 */ 179 if(named_dir) { 180 entry = srm_named_entries; 181 while(entry->name != NULL && entry->id != 0) { 182 if(entry->proc_entry) { 183 remove_proc_entry(entry->name, 184 named_dir); 185 entry->proc_entry = NULL; 186 } 187 entry++; 188 } 189 remove_proc_entry(NAMED_DIR, base_dir); 190 } 191 192 /* 193 * Remove numbered entries 194 */ 195 if(numbered_dir) { 196 for(var_num = 0; var_num <= 255; var_num++) { 197 entry = &srm_numbered_entries[var_num]; 198 199 if(entry->proc_entry) { 200 remove_proc_entry(entry->name, 201 numbered_dir); 202 entry->proc_entry = NULL; 203 entry->name = NULL; 204 } 205 } 206 remove_proc_entry(NUMBERED_DIR, base_dir); 207 } 208 209 remove_proc_entry(BASE_DIR, NULL); 210 } 211 212 return; 213 } 214 215 216 static int __init 217 srm_env_init(void) 218 { 219 srm_env_t *entry; 220 unsigned long var_num; 221 222 /* 223 * Check system 224 */ 225 if(!alpha_using_srm) { 226 printk(KERN_INFO "%s: This Alpha system doesn't " 227 "know about SRM (or you've booted " 228 "SRM->MILO->Linux, which gets " 229 "misdetected)...\n", __FUNCTION__); 230 return -ENODEV; 231 } 232 233 /* 234 * Init numbers 235 */ 236 for(var_num = 0; var_num <= 255; var_num++) 237 sprintf(number[var_num], "%ld", var_num); 238 239 /* 240 * Create base directory 241 */ 242 base_dir = proc_mkdir(BASE_DIR, NULL); 243 if(base_dir == NULL) { 244 printk(KERN_ERR "Couldn't create base dir /proc/%s\n", 245 BASE_DIR); 246 goto cleanup; 247 } 248 base_dir->owner = THIS_MODULE; 249 250 /* 251 * Create per-name subdirectory 252 */ 253 named_dir = proc_mkdir(NAMED_DIR, base_dir); 254 if(named_dir == NULL) { 255 printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", 256 BASE_DIR, NAMED_DIR); 257 goto cleanup; 258 } 259 named_dir->owner = THIS_MODULE; 260 261 /* 262 * Create per-number subdirectory 263 */ 264 numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir); 265 if(numbered_dir == NULL) { 266 printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", 267 BASE_DIR, NUMBERED_DIR); 268 goto cleanup; 269 270 } 271 numbered_dir->owner = THIS_MODULE; 272 273 /* 274 * Create all named nodes 275 */ 276 entry = srm_named_entries; 277 while(entry->name != NULL && entry->id != 0) { 278 entry->proc_entry = create_proc_entry(entry->name, 279 0644, named_dir); 280 if(entry->proc_entry == NULL) 281 goto cleanup; 282 283 entry->proc_entry->data = (void *) entry; 284 entry->proc_entry->owner = THIS_MODULE; 285 entry->proc_entry->read_proc = srm_env_read; 286 entry->proc_entry->write_proc = srm_env_write; 287 288 entry++; 289 } 290 291 /* 292 * Create all numbered nodes 293 */ 294 for(var_num = 0; var_num <= 255; var_num++) { 295 entry = &srm_numbered_entries[var_num]; 296 entry->name = number[var_num]; 297 298 entry->proc_entry = create_proc_entry(entry->name, 299 0644, numbered_dir); 300 if(entry->proc_entry == NULL) 301 goto cleanup; 302 303 entry->id = var_num; 304 entry->proc_entry->data = (void *) entry; 305 entry->proc_entry->owner = THIS_MODULE; 306 entry->proc_entry->read_proc = srm_env_read; 307 entry->proc_entry->write_proc = srm_env_write; 308 } 309 310 printk(KERN_INFO "%s: version %s loaded successfully\n", NAME, 311 VERSION); 312 313 return 0; 314 315 cleanup: 316 srm_env_cleanup(); 317 318 return -ENOMEM; 319 } 320 321 322 static void __exit 323 srm_env_exit(void) 324 { 325 srm_env_cleanup(); 326 printk(KERN_INFO "%s: unloaded successfully\n", NAME); 327 328 return; 329 } 330 331 332 module_init(srm_env_init); 333 module_exit(srm_env_exit); 334 335