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