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 a modified version of Erik Mouw's example proc 8 * interface, so: thank you, Erik! He can be reached via email at 9 * <J.A.K.Mouw@its.tudelft.nl>. It is based on an idea 10 * provided by DEC^WCompaq^WIntel's "Jumpstart" CD. They 11 * included a patch like this as well. Thanks for idea! 12 * 13 * This program is free software; you can redistribute 14 * it and/or modify it under the terms of the GNU General 15 * Public License version 2 as published by the Free Software 16 * Foundation. 17 * 18 * This program is distributed in the hope that it will be 19 * useful, but WITHOUT ANY WARRANTY; without even the implied 20 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 21 * PURPOSE. See the GNU General Public License for more 22 * details. 23 * 24 * You should have received a copy of the GNU General Public 25 * License along with this program; if not, write to the 26 * Free Software Foundation, Inc., 59 Temple Place, 27 * Suite 330, Boston, MA 02111-1307 USA 28 * 29 */ 30 31 #include <linux/kernel.h> 32 #include <linux/gfp.h> 33 #include <linux/module.h> 34 #include <linux/init.h> 35 #include <linux/proc_fs.h> 36 #include <linux/seq_file.h> 37 #include <asm/console.h> 38 #include <asm/uaccess.h> 39 #include <asm/machvec.h> 40 41 #define BASE_DIR "srm_environment" /* Subdir in /proc/ */ 42 #define NAMED_DIR "named_variables" /* Subdir for known variables */ 43 #define NUMBERED_DIR "numbered_variables" /* Subdir for all variables */ 44 #define VERSION "0.0.6" /* Module version */ 45 #define NAME "srm_env" /* Module name */ 46 47 MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); 48 MODULE_DESCRIPTION("Accessing Alpha SRM environment through procfs interface"); 49 MODULE_LICENSE("GPL"); 50 51 typedef struct _srm_env { 52 char *name; 53 unsigned long id; 54 struct proc_dir_entry *proc_entry; 55 } srm_env_t; 56 57 static struct proc_dir_entry *base_dir; 58 static struct proc_dir_entry *named_dir; 59 static struct proc_dir_entry *numbered_dir; 60 static char number[256][4]; 61 62 static srm_env_t srm_named_entries[] = { 63 { "auto_action", ENV_AUTO_ACTION }, 64 { "boot_dev", ENV_BOOT_DEV }, 65 { "bootdef_dev", ENV_BOOTDEF_DEV }, 66 { "booted_dev", ENV_BOOTED_DEV }, 67 { "boot_file", ENV_BOOT_FILE }, 68 { "booted_file", ENV_BOOTED_FILE }, 69 { "boot_osflags", ENV_BOOT_OSFLAGS }, 70 { "booted_osflags", ENV_BOOTED_OSFLAGS }, 71 { "boot_reset", ENV_BOOT_RESET }, 72 { "dump_dev", ENV_DUMP_DEV }, 73 { "enable_audit", ENV_ENABLE_AUDIT }, 74 { "license", ENV_LICENSE }, 75 { "char_set", ENV_CHAR_SET }, 76 { "language", ENV_LANGUAGE }, 77 { "tty_dev", ENV_TTY_DEV }, 78 { NULL, 0 }, 79 }; 80 static srm_env_t srm_numbered_entries[256]; 81 82 83 static int srm_env_proc_show(struct seq_file *m, void *v) 84 { 85 unsigned long ret; 86 srm_env_t *entry; 87 char *page; 88 89 entry = m->private; 90 page = (char *)__get_free_page(GFP_USER); 91 if (!page) 92 return -ENOMEM; 93 94 ret = callback_getenv(entry->id, page, PAGE_SIZE); 95 96 if ((ret >> 61) == 0) { 97 seq_write(m, page, ret); 98 ret = 0; 99 } else 100 ret = -EFAULT; 101 free_page((unsigned long)page); 102 return ret; 103 } 104 105 static int srm_env_proc_open(struct inode *inode, struct file *file) 106 { 107 return single_open(file, srm_env_proc_show, PDE(inode)->data); 108 } 109 110 static ssize_t srm_env_proc_write(struct file *file, const char __user *buffer, 111 size_t count, loff_t *pos) 112 { 113 int res; 114 srm_env_t *entry = PDE(file->f_path.dentry->d_inode)->data; 115 char *buf = (char *) __get_free_page(GFP_USER); 116 unsigned long ret1, ret2; 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 const struct file_operations srm_env_proc_fops = { 144 .owner = THIS_MODULE, 145 .open = srm_env_proc_open, 146 .read = seq_read, 147 .llseek = seq_lseek, 148 .release = single_release, 149 .write = srm_env_proc_write, 150 }; 151 152 static void 153 srm_env_cleanup(void) 154 { 155 srm_env_t *entry; 156 unsigned long var_num; 157 158 if (base_dir) { 159 /* 160 * Remove named entries 161 */ 162 if (named_dir) { 163 entry = srm_named_entries; 164 while (entry->name != NULL && entry->id != 0) { 165 if (entry->proc_entry) { 166 remove_proc_entry(entry->name, 167 named_dir); 168 entry->proc_entry = NULL; 169 } 170 entry++; 171 } 172 remove_proc_entry(NAMED_DIR, base_dir); 173 } 174 175 /* 176 * Remove numbered entries 177 */ 178 if (numbered_dir) { 179 for (var_num = 0; var_num <= 255; var_num++) { 180 entry = &srm_numbered_entries[var_num]; 181 182 if (entry->proc_entry) { 183 remove_proc_entry(entry->name, 184 numbered_dir); 185 entry->proc_entry = NULL; 186 entry->name = NULL; 187 } 188 } 189 remove_proc_entry(NUMBERED_DIR, base_dir); 190 } 191 192 remove_proc_entry(BASE_DIR, NULL); 193 } 194 195 return; 196 } 197 198 static int __init 199 srm_env_init(void) 200 { 201 srm_env_t *entry; 202 unsigned long var_num; 203 204 /* 205 * Check system 206 */ 207 if (!alpha_using_srm) { 208 printk(KERN_INFO "%s: This Alpha system doesn't " 209 "know about SRM (or you've booted " 210 "SRM->MILO->Linux, which gets " 211 "misdetected)...\n", __func__); 212 return -ENODEV; 213 } 214 215 /* 216 * Init numbers 217 */ 218 for (var_num = 0; var_num <= 255; var_num++) 219 sprintf(number[var_num], "%ld", var_num); 220 221 /* 222 * Create base directory 223 */ 224 base_dir = proc_mkdir(BASE_DIR, NULL); 225 if (!base_dir) { 226 printk(KERN_ERR "Couldn't create base dir /proc/%s\n", 227 BASE_DIR); 228 goto cleanup; 229 } 230 231 /* 232 * Create per-name subdirectory 233 */ 234 named_dir = proc_mkdir(NAMED_DIR, base_dir); 235 if (!named_dir) { 236 printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", 237 BASE_DIR, NAMED_DIR); 238 goto cleanup; 239 } 240 241 /* 242 * Create per-number subdirectory 243 */ 244 numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir); 245 if (!numbered_dir) { 246 printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", 247 BASE_DIR, NUMBERED_DIR); 248 goto cleanup; 249 250 } 251 252 /* 253 * Create all named nodes 254 */ 255 entry = srm_named_entries; 256 while (entry->name && entry->id) { 257 entry->proc_entry = proc_create_data(entry->name, 0644, named_dir, 258 &srm_env_proc_fops, entry); 259 if (!entry->proc_entry) 260 goto cleanup; 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 = proc_create_data(entry->name, 0644, numbered_dir, 272 &srm_env_proc_fops, entry); 273 if (!entry->proc_entry) 274 goto cleanup; 275 276 entry->id = var_num; 277 } 278 279 printk(KERN_INFO "%s: version %s loaded successfully\n", NAME, 280 VERSION); 281 282 return 0; 283 284 cleanup: 285 srm_env_cleanup(); 286 287 return -ENOMEM; 288 } 289 290 static void __exit 291 srm_env_exit(void) 292 { 293 srm_env_cleanup(); 294 printk(KERN_INFO "%s: unloaded successfully\n", NAME); 295 296 return; 297 } 298 299 module_init(srm_env_init); 300 module_exit(srm_env_exit); 301