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