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 } 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 srm_env_proc_show(struct seq_file *m, void *v) 83 { 84 unsigned long ret; 85 srm_env_t *entry; 86 char *page; 87 88 entry = m->private; 89 page = (char *)__get_free_page(GFP_USER); 90 if (!page) 91 return -ENOMEM; 92 93 ret = callback_getenv(entry->id, page, PAGE_SIZE); 94 95 if ((ret >> 61) == 0) { 96 seq_write(m, page, ret); 97 ret = 0; 98 } else 99 ret = -EFAULT; 100 free_page((unsigned long)page); 101 return ret; 102 } 103 104 static int srm_env_proc_open(struct inode *inode, struct file *file) 105 { 106 return single_open(file, srm_env_proc_show, PDE_DATA(inode)); 107 } 108 109 static ssize_t srm_env_proc_write(struct file *file, const char __user *buffer, 110 size_t count, loff_t *pos) 111 { 112 int res; 113 srm_env_t *entry = PDE_DATA(file_inode(file)); 114 char *buf = (char *) __get_free_page(GFP_USER); 115 unsigned long ret1, ret2; 116 117 if (!buf) 118 return -ENOMEM; 119 120 res = -EINVAL; 121 if (count >= PAGE_SIZE) 122 goto out; 123 124 res = -EFAULT; 125 if (copy_from_user(buf, buffer, count)) 126 goto out; 127 buf[count] = '\0'; 128 129 ret1 = callback_setenv(entry->id, buf, count); 130 if ((ret1 >> 61) == 0) { 131 do 132 ret2 = callback_save_env(); 133 while((ret2 >> 61) == 1); 134 res = (int) ret1; 135 } 136 137 out: 138 free_page((unsigned long)buf); 139 return res; 140 } 141 142 static const struct file_operations srm_env_proc_fops = { 143 .owner = THIS_MODULE, 144 .open = srm_env_proc_open, 145 .read = seq_read, 146 .llseek = seq_lseek, 147 .release = single_release, 148 .write = srm_env_proc_write, 149 }; 150 151 static int __init 152 srm_env_init(void) 153 { 154 srm_env_t *entry; 155 unsigned long var_num; 156 157 /* 158 * Check system 159 */ 160 if (!alpha_using_srm) { 161 printk(KERN_INFO "%s: This Alpha system doesn't " 162 "know about SRM (or you've booted " 163 "SRM->MILO->Linux, which gets " 164 "misdetected)...\n", __func__); 165 return -ENODEV; 166 } 167 168 /* 169 * Init numbers 170 */ 171 for (var_num = 0; var_num <= 255; var_num++) 172 sprintf(number[var_num], "%ld", var_num); 173 174 /* 175 * Create base directory 176 */ 177 base_dir = proc_mkdir(BASE_DIR, NULL); 178 if (!base_dir) { 179 printk(KERN_ERR "Couldn't create base dir /proc/%s\n", 180 BASE_DIR); 181 return -ENOMEM; 182 } 183 184 /* 185 * Create per-name subdirectory 186 */ 187 named_dir = proc_mkdir(NAMED_DIR, base_dir); 188 if (!named_dir) { 189 printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", 190 BASE_DIR, NAMED_DIR); 191 goto cleanup; 192 } 193 194 /* 195 * Create per-number subdirectory 196 */ 197 numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir); 198 if (!numbered_dir) { 199 printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", 200 BASE_DIR, NUMBERED_DIR); 201 goto cleanup; 202 203 } 204 205 /* 206 * Create all named nodes 207 */ 208 entry = srm_named_entries; 209 while (entry->name && entry->id) { 210 if (!proc_create_data(entry->name, 0644, named_dir, 211 &srm_env_proc_fops, entry)) 212 goto cleanup; 213 entry++; 214 } 215 216 /* 217 * Create all numbered nodes 218 */ 219 for (var_num = 0; var_num <= 255; var_num++) { 220 entry = &srm_numbered_entries[var_num]; 221 entry->name = number[var_num]; 222 223 if (!proc_create_data(entry->name, 0644, numbered_dir, 224 &srm_env_proc_fops, entry)) 225 goto cleanup; 226 227 entry->id = var_num; 228 } 229 230 printk(KERN_INFO "%s: version %s loaded successfully\n", NAME, 231 VERSION); 232 233 return 0; 234 235 cleanup: 236 remove_proc_subtree(BASE_DIR, NULL); 237 return -ENOMEM; 238 } 239 240 static void __exit 241 srm_env_exit(void) 242 { 243 remove_proc_subtree(BASE_DIR, NULL); 244 printk(KERN_INFO "%s: unloaded successfully\n", NAME); 245 246 return; 247 } 248 249 module_init(srm_env_init); 250 module_exit(srm_env_exit); 251