xref: /linux/arch/alpha/kernel/srm_env.c (revision c35f2e49f88e72ffcb0cc6af2f93fe153fa88dd8)
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