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/config.h> 61 #include <linux/module.h> 62 #include <linux/init.h> 63 #include <linux/proc_fs.h> 64 #include <asm/console.h> 65 #include <asm/uaccess.h> 66 #include <asm/machvec.h> 67 68 #define BASE_DIR "srm_environment" /* Subdir in /proc/ */ 69 #define NAMED_DIR "named_variables" /* Subdir for known variables */ 70 #define NUMBERED_DIR "numbered_variables" /* Subdir for all variables */ 71 #define VERSION "0.0.5" /* Module version */ 72 #define NAME "srm_env" /* Module name */ 73 74 MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); 75 MODULE_DESCRIPTION("Accessing Alpha SRM environment through procfs interface"); 76 MODULE_LICENSE("GPL"); 77 78 typedef struct _srm_env { 79 char *name; 80 unsigned long id; 81 struct proc_dir_entry *proc_entry; 82 } srm_env_t; 83 84 static struct proc_dir_entry *base_dir; 85 static struct proc_dir_entry *named_dir; 86 static struct proc_dir_entry *numbered_dir; 87 static char number[256][4]; 88 89 static srm_env_t srm_named_entries[] = { 90 { "auto_action", ENV_AUTO_ACTION }, 91 { "boot_dev", ENV_BOOT_DEV }, 92 { "bootdef_dev", ENV_BOOTDEF_DEV }, 93 { "booted_dev", ENV_BOOTED_DEV }, 94 { "boot_file", ENV_BOOT_FILE }, 95 { "booted_file", ENV_BOOTED_FILE }, 96 { "boot_osflags", ENV_BOOT_OSFLAGS }, 97 { "booted_osflags", ENV_BOOTED_OSFLAGS }, 98 { "boot_reset", ENV_BOOT_RESET }, 99 { "dump_dev", ENV_DUMP_DEV }, 100 { "enable_audit", ENV_ENABLE_AUDIT }, 101 { "license", ENV_LICENSE }, 102 { "char_set", ENV_CHAR_SET }, 103 { "language", ENV_LANGUAGE }, 104 { "tty_dev", ENV_TTY_DEV }, 105 { NULL, 0 }, 106 }; 107 static srm_env_t srm_numbered_entries[256]; 108 109 110 111 static int 112 srm_env_read(char *page, char **start, off_t off, int count, int *eof, 113 void *data) 114 { 115 int nbytes; 116 unsigned long ret; 117 srm_env_t *entry; 118 119 if(off != 0) 120 return -EFAULT; 121 122 entry = (srm_env_t *) data; 123 ret = callback_getenv(entry->id, page, count); 124 125 if((ret >> 61) == 0) 126 nbytes = (int) ret; 127 else 128 nbytes = -EFAULT; 129 130 return nbytes; 131 } 132 133 134 static int 135 srm_env_write(struct file *file, const char __user *buffer, unsigned long count, 136 void *data) 137 { 138 int res; 139 srm_env_t *entry; 140 char *buf = (char *) __get_free_page(GFP_USER); 141 unsigned long ret1, ret2; 142 143 entry = (srm_env_t *) data; 144 145 if (!buf) 146 return -ENOMEM; 147 148 res = -EINVAL; 149 if (count >= PAGE_SIZE) 150 goto out; 151 152 res = -EFAULT; 153 if (copy_from_user(buf, buffer, count)) 154 goto out; 155 buf[count] = '\0'; 156 157 ret1 = callback_setenv(entry->id, buf, count); 158 if ((ret1 >> 61) == 0) { 159 do 160 ret2 = callback_save_env(); 161 while((ret2 >> 61) == 1); 162 res = (int) ret1; 163 } 164 165 out: 166 free_page((unsigned long)buf); 167 return res; 168 } 169 170 static void 171 srm_env_cleanup(void) 172 { 173 srm_env_t *entry; 174 unsigned long var_num; 175 176 if(base_dir) { 177 /* 178 * Remove named entries 179 */ 180 if(named_dir) { 181 entry = srm_named_entries; 182 while(entry->name != NULL && entry->id != 0) { 183 if(entry->proc_entry) { 184 remove_proc_entry(entry->name, 185 named_dir); 186 entry->proc_entry = NULL; 187 } 188 entry++; 189 } 190 remove_proc_entry(NAMED_DIR, base_dir); 191 } 192 193 /* 194 * Remove numbered entries 195 */ 196 if(numbered_dir) { 197 for(var_num = 0; var_num <= 255; var_num++) { 198 entry = &srm_numbered_entries[var_num]; 199 200 if(entry->proc_entry) { 201 remove_proc_entry(entry->name, 202 numbered_dir); 203 entry->proc_entry = NULL; 204 entry->name = NULL; 205 } 206 } 207 remove_proc_entry(NUMBERED_DIR, base_dir); 208 } 209 210 remove_proc_entry(BASE_DIR, NULL); 211 } 212 213 return; 214 } 215 216 217 static int __init 218 srm_env_init(void) 219 { 220 srm_env_t *entry; 221 unsigned long var_num; 222 223 /* 224 * Check system 225 */ 226 if(!alpha_using_srm) { 227 printk(KERN_INFO "%s: This Alpha system doesn't " 228 "know about SRM (or you've booted " 229 "SRM->MILO->Linux, which gets " 230 "misdetected)...\n", __FUNCTION__); 231 return -ENODEV; 232 } 233 234 /* 235 * Init numbers 236 */ 237 for(var_num = 0; var_num <= 255; var_num++) 238 sprintf(number[var_num], "%ld", var_num); 239 240 /* 241 * Create base directory 242 */ 243 base_dir = proc_mkdir(BASE_DIR, NULL); 244 if(base_dir == NULL) { 245 printk(KERN_ERR "Couldn't create base dir /proc/%s\n", 246 BASE_DIR); 247 goto cleanup; 248 } 249 base_dir->owner = THIS_MODULE; 250 251 /* 252 * Create per-name subdirectory 253 */ 254 named_dir = proc_mkdir(NAMED_DIR, base_dir); 255 if(named_dir == NULL) { 256 printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", 257 BASE_DIR, NAMED_DIR); 258 goto cleanup; 259 } 260 named_dir->owner = THIS_MODULE; 261 262 /* 263 * Create per-number subdirectory 264 */ 265 numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir); 266 if(numbered_dir == NULL) { 267 printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", 268 BASE_DIR, NUMBERED_DIR); 269 goto cleanup; 270 271 } 272 numbered_dir->owner = THIS_MODULE; 273 274 /* 275 * Create all named nodes 276 */ 277 entry = srm_named_entries; 278 while(entry->name != NULL && entry->id != 0) { 279 entry->proc_entry = create_proc_entry(entry->name, 280 0644, named_dir); 281 if(entry->proc_entry == NULL) 282 goto cleanup; 283 284 entry->proc_entry->data = (void *) entry; 285 entry->proc_entry->owner = THIS_MODULE; 286 entry->proc_entry->read_proc = srm_env_read; 287 entry->proc_entry->write_proc = srm_env_write; 288 289 entry++; 290 } 291 292 /* 293 * Create all numbered nodes 294 */ 295 for(var_num = 0; var_num <= 255; var_num++) { 296 entry = &srm_numbered_entries[var_num]; 297 entry->name = number[var_num]; 298 299 entry->proc_entry = create_proc_entry(entry->name, 300 0644, numbered_dir); 301 if(entry->proc_entry == NULL) 302 goto cleanup; 303 304 entry->id = var_num; 305 entry->proc_entry->data = (void *) entry; 306 entry->proc_entry->owner = THIS_MODULE; 307 entry->proc_entry->read_proc = srm_env_read; 308 entry->proc_entry->write_proc = srm_env_write; 309 } 310 311 printk(KERN_INFO "%s: version %s loaded successfully\n", NAME, 312 VERSION); 313 314 return 0; 315 316 cleanup: 317 srm_env_cleanup(); 318 319 return -ENOMEM; 320 } 321 322 323 static void __exit 324 srm_env_exit(void) 325 { 326 srm_env_cleanup(); 327 printk(KERN_INFO "%s: unloaded successfully\n", NAME); 328 329 return; 330 } 331 332 333 module_init(srm_env_init); 334 module_exit(srm_env_exit); 335 336