1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * srm_env.c - Access to SRM environment 3*1da177e4SLinus Torvalds * variables through linux' procfs 4*1da177e4SLinus Torvalds * 5*1da177e4SLinus Torvalds * Copyright (C) 2001-2002 Jan-Benedict Glaw <jbglaw@lug-owl.de> 6*1da177e4SLinus Torvalds * 7*1da177e4SLinus Torvalds * This driver is at all a modified version of Erik Mouw's 8*1da177e4SLinus Torvalds * Documentation/DocBook/procfs_example.c, so: thank 9*1da177e4SLinus Torvalds * you, Erik! He can be reached via email at 10*1da177e4SLinus Torvalds * <J.A.K.Mouw@its.tudelft.nl>. It is based on an idea 11*1da177e4SLinus Torvalds * provided by DEC^WCompaq^WIntel's "Jumpstart" CD. They 12*1da177e4SLinus Torvalds * included a patch like this as well. Thanks for idea! 13*1da177e4SLinus Torvalds * 14*1da177e4SLinus Torvalds * This program is free software; you can redistribute 15*1da177e4SLinus Torvalds * it and/or modify it under the terms of the GNU General 16*1da177e4SLinus Torvalds * Public License version 2 as published by the Free Software 17*1da177e4SLinus Torvalds * Foundation. 18*1da177e4SLinus Torvalds * 19*1da177e4SLinus Torvalds * This program is distributed in the hope that it will be 20*1da177e4SLinus Torvalds * useful, but WITHOUT ANY WARRANTY; without even the implied 21*1da177e4SLinus Torvalds * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 22*1da177e4SLinus Torvalds * PURPOSE. See the GNU General Public License for more 23*1da177e4SLinus Torvalds * details. 24*1da177e4SLinus Torvalds * 25*1da177e4SLinus Torvalds * You should have received a copy of the GNU General Public 26*1da177e4SLinus Torvalds * License along with this program; if not, write to the 27*1da177e4SLinus Torvalds * Free Software Foundation, Inc., 59 Temple Place, 28*1da177e4SLinus Torvalds * Suite 330, Boston, MA 02111-1307 USA 29*1da177e4SLinus Torvalds * 30*1da177e4SLinus Torvalds */ 31*1da177e4SLinus Torvalds 32*1da177e4SLinus Torvalds /* 33*1da177e4SLinus Torvalds * Changelog 34*1da177e4SLinus Torvalds * ~~~~~~~~~ 35*1da177e4SLinus Torvalds * 36*1da177e4SLinus Torvalds * Thu, 22 Aug 2002 15:10:43 +0200 37*1da177e4SLinus Torvalds * - Update Config.help entry. I got a number of emails asking 38*1da177e4SLinus Torvalds * me to tell their senders if they could make use of this 39*1da177e4SLinus Torvalds * piece of code... So: "SRM is something like BIOS for your 40*1da177e4SLinus Torvalds * Alpha" 41*1da177e4SLinus Torvalds * - Update code formatting a bit to better conform CodingStyle 42*1da177e4SLinus Torvalds * rules. 43*1da177e4SLinus Torvalds * - So this is v0.0.5, with no changes (except formatting) 44*1da177e4SLinus Torvalds * 45*1da177e4SLinus Torvalds * Wed, 22 May 2002 00:11:21 +0200 46*1da177e4SLinus Torvalds * - Fix typo on comment (SRC -> SRM) 47*1da177e4SLinus Torvalds * - Call this "Version 0.0.4" 48*1da177e4SLinus Torvalds * 49*1da177e4SLinus Torvalds * Tue, 9 Apr 2002 18:44:40 +0200 50*1da177e4SLinus Torvalds * - Implement access by variable name and additionally 51*1da177e4SLinus Torvalds * by number. This is done by creating two subdirectories 52*1da177e4SLinus Torvalds * where one holds all names (like the old directory 53*1da177e4SLinus Torvalds * did) and the other holding 256 files named like "0", 54*1da177e4SLinus Torvalds * "1" and so on. 55*1da177e4SLinus Torvalds * - Call this "Version 0.0.3" 56*1da177e4SLinus Torvalds * 57*1da177e4SLinus Torvalds */ 58*1da177e4SLinus Torvalds 59*1da177e4SLinus Torvalds #include <linux/kernel.h> 60*1da177e4SLinus Torvalds #include <linux/config.h> 61*1da177e4SLinus Torvalds #include <linux/module.h> 62*1da177e4SLinus Torvalds #include <linux/init.h> 63*1da177e4SLinus Torvalds #include <linux/proc_fs.h> 64*1da177e4SLinus Torvalds #include <asm/console.h> 65*1da177e4SLinus Torvalds #include <asm/uaccess.h> 66*1da177e4SLinus Torvalds #include <asm/machvec.h> 67*1da177e4SLinus Torvalds 68*1da177e4SLinus Torvalds #define BASE_DIR "srm_environment" /* Subdir in /proc/ */ 69*1da177e4SLinus Torvalds #define NAMED_DIR "named_variables" /* Subdir for known variables */ 70*1da177e4SLinus Torvalds #define NUMBERED_DIR "numbered_variables" /* Subdir for all variables */ 71*1da177e4SLinus Torvalds #define VERSION "0.0.5" /* Module version */ 72*1da177e4SLinus Torvalds #define NAME "srm_env" /* Module name */ 73*1da177e4SLinus Torvalds 74*1da177e4SLinus Torvalds MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); 75*1da177e4SLinus Torvalds MODULE_DESCRIPTION("Accessing Alpha SRM environment through procfs interface"); 76*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 77*1da177e4SLinus Torvalds 78*1da177e4SLinus Torvalds typedef struct _srm_env { 79*1da177e4SLinus Torvalds char *name; 80*1da177e4SLinus Torvalds unsigned long id; 81*1da177e4SLinus Torvalds struct proc_dir_entry *proc_entry; 82*1da177e4SLinus Torvalds } srm_env_t; 83*1da177e4SLinus Torvalds 84*1da177e4SLinus Torvalds static struct proc_dir_entry *base_dir; 85*1da177e4SLinus Torvalds static struct proc_dir_entry *named_dir; 86*1da177e4SLinus Torvalds static struct proc_dir_entry *numbered_dir; 87*1da177e4SLinus Torvalds static char number[256][4]; 88*1da177e4SLinus Torvalds 89*1da177e4SLinus Torvalds static srm_env_t srm_named_entries[] = { 90*1da177e4SLinus Torvalds { "auto_action", ENV_AUTO_ACTION }, 91*1da177e4SLinus Torvalds { "boot_dev", ENV_BOOT_DEV }, 92*1da177e4SLinus Torvalds { "bootdef_dev", ENV_BOOTDEF_DEV }, 93*1da177e4SLinus Torvalds { "booted_dev", ENV_BOOTED_DEV }, 94*1da177e4SLinus Torvalds { "boot_file", ENV_BOOT_FILE }, 95*1da177e4SLinus Torvalds { "booted_file", ENV_BOOTED_FILE }, 96*1da177e4SLinus Torvalds { "boot_osflags", ENV_BOOT_OSFLAGS }, 97*1da177e4SLinus Torvalds { "booted_osflags", ENV_BOOTED_OSFLAGS }, 98*1da177e4SLinus Torvalds { "boot_reset", ENV_BOOT_RESET }, 99*1da177e4SLinus Torvalds { "dump_dev", ENV_DUMP_DEV }, 100*1da177e4SLinus Torvalds { "enable_audit", ENV_ENABLE_AUDIT }, 101*1da177e4SLinus Torvalds { "license", ENV_LICENSE }, 102*1da177e4SLinus Torvalds { "char_set", ENV_CHAR_SET }, 103*1da177e4SLinus Torvalds { "language", ENV_LANGUAGE }, 104*1da177e4SLinus Torvalds { "tty_dev", ENV_TTY_DEV }, 105*1da177e4SLinus Torvalds { NULL, 0 }, 106*1da177e4SLinus Torvalds }; 107*1da177e4SLinus Torvalds static srm_env_t srm_numbered_entries[256]; 108*1da177e4SLinus Torvalds 109*1da177e4SLinus Torvalds 110*1da177e4SLinus Torvalds 111*1da177e4SLinus Torvalds static int 112*1da177e4SLinus Torvalds srm_env_read(char *page, char **start, off_t off, int count, int *eof, 113*1da177e4SLinus Torvalds void *data) 114*1da177e4SLinus Torvalds { 115*1da177e4SLinus Torvalds int nbytes; 116*1da177e4SLinus Torvalds unsigned long ret; 117*1da177e4SLinus Torvalds srm_env_t *entry; 118*1da177e4SLinus Torvalds 119*1da177e4SLinus Torvalds if(off != 0) 120*1da177e4SLinus Torvalds return -EFAULT; 121*1da177e4SLinus Torvalds 122*1da177e4SLinus Torvalds entry = (srm_env_t *) data; 123*1da177e4SLinus Torvalds ret = callback_getenv(entry->id, page, count); 124*1da177e4SLinus Torvalds 125*1da177e4SLinus Torvalds if((ret >> 61) == 0) 126*1da177e4SLinus Torvalds nbytes = (int) ret; 127*1da177e4SLinus Torvalds else 128*1da177e4SLinus Torvalds nbytes = -EFAULT; 129*1da177e4SLinus Torvalds 130*1da177e4SLinus Torvalds return nbytes; 131*1da177e4SLinus Torvalds } 132*1da177e4SLinus Torvalds 133*1da177e4SLinus Torvalds 134*1da177e4SLinus Torvalds static int 135*1da177e4SLinus Torvalds srm_env_write(struct file *file, const char __user *buffer, unsigned long count, 136*1da177e4SLinus Torvalds void *data) 137*1da177e4SLinus Torvalds { 138*1da177e4SLinus Torvalds int res; 139*1da177e4SLinus Torvalds srm_env_t *entry; 140*1da177e4SLinus Torvalds char *buf = (char *) __get_free_page(GFP_USER); 141*1da177e4SLinus Torvalds unsigned long ret1, ret2; 142*1da177e4SLinus Torvalds 143*1da177e4SLinus Torvalds entry = (srm_env_t *) data; 144*1da177e4SLinus Torvalds 145*1da177e4SLinus Torvalds if (!buf) 146*1da177e4SLinus Torvalds return -ENOMEM; 147*1da177e4SLinus Torvalds 148*1da177e4SLinus Torvalds res = -EINVAL; 149*1da177e4SLinus Torvalds if (count >= PAGE_SIZE) 150*1da177e4SLinus Torvalds goto out; 151*1da177e4SLinus Torvalds 152*1da177e4SLinus Torvalds res = -EFAULT; 153*1da177e4SLinus Torvalds if (copy_from_user(buf, buffer, count)) 154*1da177e4SLinus Torvalds goto out; 155*1da177e4SLinus Torvalds buf[count] = '\0'; 156*1da177e4SLinus Torvalds 157*1da177e4SLinus Torvalds ret1 = callback_setenv(entry->id, buf, count); 158*1da177e4SLinus Torvalds if ((ret1 >> 61) == 0) { 159*1da177e4SLinus Torvalds do 160*1da177e4SLinus Torvalds ret2 = callback_save_env(); 161*1da177e4SLinus Torvalds while((ret2 >> 61) == 1); 162*1da177e4SLinus Torvalds res = (int) ret1; 163*1da177e4SLinus Torvalds } 164*1da177e4SLinus Torvalds 165*1da177e4SLinus Torvalds out: 166*1da177e4SLinus Torvalds free_page((unsigned long)buf); 167*1da177e4SLinus Torvalds return res; 168*1da177e4SLinus Torvalds } 169*1da177e4SLinus Torvalds 170*1da177e4SLinus Torvalds static void 171*1da177e4SLinus Torvalds srm_env_cleanup(void) 172*1da177e4SLinus Torvalds { 173*1da177e4SLinus Torvalds srm_env_t *entry; 174*1da177e4SLinus Torvalds unsigned long var_num; 175*1da177e4SLinus Torvalds 176*1da177e4SLinus Torvalds if(base_dir) { 177*1da177e4SLinus Torvalds /* 178*1da177e4SLinus Torvalds * Remove named entries 179*1da177e4SLinus Torvalds */ 180*1da177e4SLinus Torvalds if(named_dir) { 181*1da177e4SLinus Torvalds entry = srm_named_entries; 182*1da177e4SLinus Torvalds while(entry->name != NULL && entry->id != 0) { 183*1da177e4SLinus Torvalds if(entry->proc_entry) { 184*1da177e4SLinus Torvalds remove_proc_entry(entry->name, 185*1da177e4SLinus Torvalds named_dir); 186*1da177e4SLinus Torvalds entry->proc_entry = NULL; 187*1da177e4SLinus Torvalds } 188*1da177e4SLinus Torvalds entry++; 189*1da177e4SLinus Torvalds } 190*1da177e4SLinus Torvalds remove_proc_entry(NAMED_DIR, base_dir); 191*1da177e4SLinus Torvalds } 192*1da177e4SLinus Torvalds 193*1da177e4SLinus Torvalds /* 194*1da177e4SLinus Torvalds * Remove numbered entries 195*1da177e4SLinus Torvalds */ 196*1da177e4SLinus Torvalds if(numbered_dir) { 197*1da177e4SLinus Torvalds for(var_num = 0; var_num <= 255; var_num++) { 198*1da177e4SLinus Torvalds entry = &srm_numbered_entries[var_num]; 199*1da177e4SLinus Torvalds 200*1da177e4SLinus Torvalds if(entry->proc_entry) { 201*1da177e4SLinus Torvalds remove_proc_entry(entry->name, 202*1da177e4SLinus Torvalds numbered_dir); 203*1da177e4SLinus Torvalds entry->proc_entry = NULL; 204*1da177e4SLinus Torvalds entry->name = NULL; 205*1da177e4SLinus Torvalds } 206*1da177e4SLinus Torvalds } 207*1da177e4SLinus Torvalds remove_proc_entry(NUMBERED_DIR, base_dir); 208*1da177e4SLinus Torvalds } 209*1da177e4SLinus Torvalds 210*1da177e4SLinus Torvalds remove_proc_entry(BASE_DIR, NULL); 211*1da177e4SLinus Torvalds } 212*1da177e4SLinus Torvalds 213*1da177e4SLinus Torvalds return; 214*1da177e4SLinus Torvalds } 215*1da177e4SLinus Torvalds 216*1da177e4SLinus Torvalds 217*1da177e4SLinus Torvalds static int __init 218*1da177e4SLinus Torvalds srm_env_init(void) 219*1da177e4SLinus Torvalds { 220*1da177e4SLinus Torvalds srm_env_t *entry; 221*1da177e4SLinus Torvalds unsigned long var_num; 222*1da177e4SLinus Torvalds 223*1da177e4SLinus Torvalds /* 224*1da177e4SLinus Torvalds * Check system 225*1da177e4SLinus Torvalds */ 226*1da177e4SLinus Torvalds if(!alpha_using_srm) { 227*1da177e4SLinus Torvalds printk(KERN_INFO "%s: This Alpha system doesn't " 228*1da177e4SLinus Torvalds "know about SRM (or you've booted " 229*1da177e4SLinus Torvalds "SRM->MILO->Linux, which gets " 230*1da177e4SLinus Torvalds "misdetected)...\n", __FUNCTION__); 231*1da177e4SLinus Torvalds return -ENODEV; 232*1da177e4SLinus Torvalds } 233*1da177e4SLinus Torvalds 234*1da177e4SLinus Torvalds /* 235*1da177e4SLinus Torvalds * Init numbers 236*1da177e4SLinus Torvalds */ 237*1da177e4SLinus Torvalds for(var_num = 0; var_num <= 255; var_num++) 238*1da177e4SLinus Torvalds sprintf(number[var_num], "%ld", var_num); 239*1da177e4SLinus Torvalds 240*1da177e4SLinus Torvalds /* 241*1da177e4SLinus Torvalds * Create base directory 242*1da177e4SLinus Torvalds */ 243*1da177e4SLinus Torvalds base_dir = proc_mkdir(BASE_DIR, NULL); 244*1da177e4SLinus Torvalds if(base_dir == NULL) { 245*1da177e4SLinus Torvalds printk(KERN_ERR "Couldn't create base dir /proc/%s\n", 246*1da177e4SLinus Torvalds BASE_DIR); 247*1da177e4SLinus Torvalds goto cleanup; 248*1da177e4SLinus Torvalds } 249*1da177e4SLinus Torvalds base_dir->owner = THIS_MODULE; 250*1da177e4SLinus Torvalds 251*1da177e4SLinus Torvalds /* 252*1da177e4SLinus Torvalds * Create per-name subdirectory 253*1da177e4SLinus Torvalds */ 254*1da177e4SLinus Torvalds named_dir = proc_mkdir(NAMED_DIR, base_dir); 255*1da177e4SLinus Torvalds if(named_dir == NULL) { 256*1da177e4SLinus Torvalds printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", 257*1da177e4SLinus Torvalds BASE_DIR, NAMED_DIR); 258*1da177e4SLinus Torvalds goto cleanup; 259*1da177e4SLinus Torvalds } 260*1da177e4SLinus Torvalds named_dir->owner = THIS_MODULE; 261*1da177e4SLinus Torvalds 262*1da177e4SLinus Torvalds /* 263*1da177e4SLinus Torvalds * Create per-number subdirectory 264*1da177e4SLinus Torvalds */ 265*1da177e4SLinus Torvalds numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir); 266*1da177e4SLinus Torvalds if(numbered_dir == NULL) { 267*1da177e4SLinus Torvalds printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", 268*1da177e4SLinus Torvalds BASE_DIR, NUMBERED_DIR); 269*1da177e4SLinus Torvalds goto cleanup; 270*1da177e4SLinus Torvalds 271*1da177e4SLinus Torvalds } 272*1da177e4SLinus Torvalds numbered_dir->owner = THIS_MODULE; 273*1da177e4SLinus Torvalds 274*1da177e4SLinus Torvalds /* 275*1da177e4SLinus Torvalds * Create all named nodes 276*1da177e4SLinus Torvalds */ 277*1da177e4SLinus Torvalds entry = srm_named_entries; 278*1da177e4SLinus Torvalds while(entry->name != NULL && entry->id != 0) { 279*1da177e4SLinus Torvalds entry->proc_entry = create_proc_entry(entry->name, 280*1da177e4SLinus Torvalds 0644, named_dir); 281*1da177e4SLinus Torvalds if(entry->proc_entry == NULL) 282*1da177e4SLinus Torvalds goto cleanup; 283*1da177e4SLinus Torvalds 284*1da177e4SLinus Torvalds entry->proc_entry->data = (void *) entry; 285*1da177e4SLinus Torvalds entry->proc_entry->owner = THIS_MODULE; 286*1da177e4SLinus Torvalds entry->proc_entry->read_proc = srm_env_read; 287*1da177e4SLinus Torvalds entry->proc_entry->write_proc = srm_env_write; 288*1da177e4SLinus Torvalds 289*1da177e4SLinus Torvalds entry++; 290*1da177e4SLinus Torvalds } 291*1da177e4SLinus Torvalds 292*1da177e4SLinus Torvalds /* 293*1da177e4SLinus Torvalds * Create all numbered nodes 294*1da177e4SLinus Torvalds */ 295*1da177e4SLinus Torvalds for(var_num = 0; var_num <= 255; var_num++) { 296*1da177e4SLinus Torvalds entry = &srm_numbered_entries[var_num]; 297*1da177e4SLinus Torvalds entry->name = number[var_num]; 298*1da177e4SLinus Torvalds 299*1da177e4SLinus Torvalds entry->proc_entry = create_proc_entry(entry->name, 300*1da177e4SLinus Torvalds 0644, numbered_dir); 301*1da177e4SLinus Torvalds if(entry->proc_entry == NULL) 302*1da177e4SLinus Torvalds goto cleanup; 303*1da177e4SLinus Torvalds 304*1da177e4SLinus Torvalds entry->id = var_num; 305*1da177e4SLinus Torvalds entry->proc_entry->data = (void *) entry; 306*1da177e4SLinus Torvalds entry->proc_entry->owner = THIS_MODULE; 307*1da177e4SLinus Torvalds entry->proc_entry->read_proc = srm_env_read; 308*1da177e4SLinus Torvalds entry->proc_entry->write_proc = srm_env_write; 309*1da177e4SLinus Torvalds } 310*1da177e4SLinus Torvalds 311*1da177e4SLinus Torvalds printk(KERN_INFO "%s: version %s loaded successfully\n", NAME, 312*1da177e4SLinus Torvalds VERSION); 313*1da177e4SLinus Torvalds 314*1da177e4SLinus Torvalds return 0; 315*1da177e4SLinus Torvalds 316*1da177e4SLinus Torvalds cleanup: 317*1da177e4SLinus Torvalds srm_env_cleanup(); 318*1da177e4SLinus Torvalds 319*1da177e4SLinus Torvalds return -ENOMEM; 320*1da177e4SLinus Torvalds } 321*1da177e4SLinus Torvalds 322*1da177e4SLinus Torvalds 323*1da177e4SLinus Torvalds static void __exit 324*1da177e4SLinus Torvalds srm_env_exit(void) 325*1da177e4SLinus Torvalds { 326*1da177e4SLinus Torvalds srm_env_cleanup(); 327*1da177e4SLinus Torvalds printk(KERN_INFO "%s: unloaded successfully\n", NAME); 328*1da177e4SLinus Torvalds 329*1da177e4SLinus Torvalds return; 330*1da177e4SLinus Torvalds } 331*1da177e4SLinus Torvalds 332*1da177e4SLinus Torvalds 333*1da177e4SLinus Torvalds module_init(srm_env_init); 334*1da177e4SLinus Torvalds module_exit(srm_env_exit); 335*1da177e4SLinus Torvalds 336