Linux 6.9-rc5
[sfrench/cifs-2.6.git] / arch / alpha / kernel / srm_env.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * srm_env.c - Access to SRM environment
4  *             variables through linux' procfs
5  *
6  * (C) 2001,2002,2006 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
7  *
8  * This driver is a modified version of Erik Mouw's example proc
9  * interface, so: thank you, Erik! He can be reached via email at
10  * <J.A.K.Mouw@its.tudelft.nl>. It is based on an idea
11  * provided by DEC^WCompaq^WIntel's "Jumpstart" CD. They
12  * included a patch like this as well. Thanks for idea!
13  */
14
15 #include <linux/kernel.h>
16 #include <linux/gfp.h>
17 #include <linux/module.h>
18 #include <linux/init.h>
19 #include <linux/proc_fs.h>
20 #include <linux/seq_file.h>
21 #include <asm/console.h>
22 #include <linux/uaccess.h>
23 #include <asm/machvec.h>
24
25 #define BASE_DIR        "srm_environment"       /* Subdir in /proc/             */
26 #define NAMED_DIR       "named_variables"       /* Subdir for known variables   */
27 #define NUMBERED_DIR    "numbered_variables"    /* Subdir for all variables     */
28 #define VERSION         "0.0.6"                 /* Module version               */
29 #define NAME            "srm_env"               /* Module name                  */
30
31 MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
32 MODULE_DESCRIPTION("Accessing Alpha SRM environment through procfs interface");
33 MODULE_LICENSE("GPL");
34
35 typedef struct _srm_env {
36         char                    *name;
37         unsigned long           id;
38 } srm_env_t;
39
40 static struct proc_dir_entry    *base_dir;
41 static struct proc_dir_entry    *named_dir;
42 static struct proc_dir_entry    *numbered_dir;
43
44 static srm_env_t        srm_named_entries[] = {
45         { "auto_action",        ENV_AUTO_ACTION         },
46         { "boot_dev",           ENV_BOOT_DEV            },
47         { "bootdef_dev",        ENV_BOOTDEF_DEV         },
48         { "booted_dev",         ENV_BOOTED_DEV          },
49         { "boot_file",          ENV_BOOT_FILE           },
50         { "booted_file",        ENV_BOOTED_FILE         },
51         { "boot_osflags",       ENV_BOOT_OSFLAGS        },
52         { "booted_osflags",     ENV_BOOTED_OSFLAGS      },
53         { "boot_reset",         ENV_BOOT_RESET          },
54         { "dump_dev",           ENV_DUMP_DEV            },
55         { "enable_audit",       ENV_ENABLE_AUDIT        },
56         { "license",            ENV_LICENSE             },
57         { "char_set",           ENV_CHAR_SET            },
58         { "language",           ENV_LANGUAGE            },
59         { "tty_dev",            ENV_TTY_DEV             },
60         { NULL,                 0                       },
61 };
62
63 static int srm_env_proc_show(struct seq_file *m, void *v)
64 {
65         unsigned long   ret;
66         unsigned long   id = (unsigned long)m->private;
67         char            *page;
68
69         page = (char *)__get_free_page(GFP_USER);
70         if (!page)
71                 return -ENOMEM;
72
73         ret = callback_getenv(id, page, PAGE_SIZE);
74
75         if ((ret >> 61) == 0) {
76                 seq_write(m, page, ret);
77                 ret = 0;
78         } else
79                 ret = -EFAULT;
80         free_page((unsigned long)page);
81         return ret;
82 }
83
84 static int srm_env_proc_open(struct inode *inode, struct file *file)
85 {
86         return single_open(file, srm_env_proc_show, pde_data(inode));
87 }
88
89 static ssize_t srm_env_proc_write(struct file *file, const char __user *buffer,
90                                   size_t count, loff_t *pos)
91 {
92         int res;
93         unsigned long   id = (unsigned long)pde_data(file_inode(file));
94         char            *buf = (char *) __get_free_page(GFP_USER);
95         unsigned long   ret1, ret2;
96
97         if (!buf)
98                 return -ENOMEM;
99
100         res = -EINVAL;
101         if (count >= PAGE_SIZE)
102                 goto out;
103
104         res = -EFAULT;
105         if (copy_from_user(buf, buffer, count))
106                 goto out;
107         buf[count] = '\0';
108
109         ret1 = callback_setenv(id, buf, count);
110         if ((ret1 >> 61) == 0) {
111                 do
112                         ret2 = callback_save_env();
113                 while((ret2 >> 61) == 1);
114                 res = (int) ret1;
115         }
116
117  out:
118         free_page((unsigned long)buf);
119         return res;
120 }
121
122 static const struct proc_ops srm_env_proc_ops = {
123         .proc_open      = srm_env_proc_open,
124         .proc_read      = seq_read,
125         .proc_lseek     = seq_lseek,
126         .proc_release   = single_release,
127         .proc_write     = srm_env_proc_write,
128 };
129
130 static int __init
131 srm_env_init(void)
132 {
133         srm_env_t       *entry;
134         unsigned long   var_num;
135
136         /*
137          * Check system
138          */
139         if (!alpha_using_srm) {
140                 printk(KERN_INFO "%s: This Alpha system doesn't "
141                                 "know about SRM (or you've booted "
142                                 "SRM->MILO->Linux, which gets "
143                                 "misdetected)...\n", __func__);
144                 return -ENODEV;
145         }
146
147         /*
148          * Create base directory
149          */
150         base_dir = proc_mkdir(BASE_DIR, NULL);
151         if (!base_dir) {
152                 printk(KERN_ERR "Couldn't create base dir /proc/%s\n",
153                                 BASE_DIR);
154                 return -ENOMEM;
155         }
156
157         /*
158          * Create per-name subdirectory
159          */
160         named_dir = proc_mkdir(NAMED_DIR, base_dir);
161         if (!named_dir) {
162                 printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
163                                 BASE_DIR, NAMED_DIR);
164                 goto cleanup;
165         }
166
167         /*
168          * Create per-number subdirectory
169          */
170         numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir);
171         if (!numbered_dir) {
172                 printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
173                                 BASE_DIR, NUMBERED_DIR);
174                 goto cleanup;
175
176         }
177
178         /*
179          * Create all named nodes
180          */
181         entry = srm_named_entries;
182         while (entry->name && entry->id) {
183                 if (!proc_create_data(entry->name, 0644, named_dir,
184                              &srm_env_proc_ops, (void *)entry->id))
185                         goto cleanup;
186                 entry++;
187         }
188
189         /*
190          * Create all numbered nodes
191          */
192         for (var_num = 0; var_num <= 255; var_num++) {
193                 char name[4];
194                 sprintf(name, "%ld", var_num);
195                 if (!proc_create_data(name, 0644, numbered_dir,
196                              &srm_env_proc_ops, (void *)var_num))
197                         goto cleanup;
198         }
199
200         printk(KERN_INFO "%s: version %s loaded successfully\n", NAME,
201                         VERSION);
202
203         return 0;
204
205 cleanup:
206         remove_proc_subtree(BASE_DIR, NULL);
207         return -ENOMEM;
208 }
209
210 static void __exit
211 srm_env_exit(void)
212 {
213         remove_proc_subtree(BASE_DIR, NULL);
214         printk(KERN_INFO "%s: unloaded successfully\n", NAME);
215 }
216
217 module_init(srm_env_init);
218 module_exit(srm_env_exit);