Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / arch / alpha / kernel / srm_env.c
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
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);