x86/topology: Fix function name in documentation
[cris-mirror.git] / drivers / char / ipmi / ipmi_si_hotmod.c
blobfc03b9be2f3d3fccb2ae1efef0278b8fc67f2738
1 /*
2 * ipmi_si_hotmod.c
4 * Handling for dynamically adding/removing IPMI devices through
5 * a module parameter (and thus sysfs).
6 */
7 #include <linux/moduleparam.h>
8 #include <linux/ipmi.h>
9 #include "ipmi_si.h"
11 #define PFX "ipmi_hotmod: "
13 static int hotmod_handler(const char *val, const struct kernel_param *kp);
15 module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200);
16 MODULE_PARM_DESC(hotmod, "Add and remove interfaces. See"
17 " Documentation/IPMI.txt in the kernel sources for the"
18 " gory details.");
21 * Parms come in as <op1>[:op2[:op3...]]. ops are:
22 * add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]]
23 * Options are:
24 * rsp=<regspacing>
25 * rsi=<regsize>
26 * rsh=<regshift>
27 * irq=<irq>
28 * ipmb=<ipmb addr>
30 enum hotmod_op { HM_ADD, HM_REMOVE };
31 struct hotmod_vals {
32 const char *name;
33 const int val;
36 static const struct hotmod_vals hotmod_ops[] = {
37 { "add", HM_ADD },
38 { "remove", HM_REMOVE },
39 { NULL }
42 static const struct hotmod_vals hotmod_si[] = {
43 { "kcs", SI_KCS },
44 { "smic", SI_SMIC },
45 { "bt", SI_BT },
46 { NULL }
49 static const struct hotmod_vals hotmod_as[] = {
50 { "mem", IPMI_MEM_ADDR_SPACE },
51 { "i/o", IPMI_IO_ADDR_SPACE },
52 { NULL }
55 static int parse_str(const struct hotmod_vals *v, int *val, char *name,
56 char **curr)
58 char *s;
59 int i;
61 s = strchr(*curr, ',');
62 if (!s) {
63 pr_warn(PFX "No hotmod %s given.\n", name);
64 return -EINVAL;
66 *s = '\0';
67 s++;
68 for (i = 0; v[i].name; i++) {
69 if (strcmp(*curr, v[i].name) == 0) {
70 *val = v[i].val;
71 *curr = s;
72 return 0;
76 pr_warn(PFX "Invalid hotmod %s '%s'\n", name, *curr);
77 return -EINVAL;
80 static int check_hotmod_int_op(const char *curr, const char *option,
81 const char *name, int *val)
83 char *n;
85 if (strcmp(curr, name) == 0) {
86 if (!option) {
87 pr_warn(PFX "No option given for '%s'\n", curr);
88 return -EINVAL;
90 *val = simple_strtoul(option, &n, 0);
91 if ((*n != '\0') || (*option == '\0')) {
92 pr_warn(PFX "Bad option given for '%s'\n", curr);
93 return -EINVAL;
95 return 1;
97 return 0;
100 static int hotmod_handler(const char *val, const struct kernel_param *kp)
102 char *str = kstrdup(val, GFP_KERNEL);
103 int rv;
104 char *next, *curr, *s, *n, *o;
105 enum hotmod_op op;
106 enum si_type si_type;
107 int addr_space;
108 unsigned long addr;
109 int regspacing;
110 int regsize;
111 int regshift;
112 int irq;
113 int ipmb;
114 int ival;
115 int len;
117 if (!str)
118 return -ENOMEM;
120 /* Kill any trailing spaces, as we can get a "\n" from echo. */
121 len = strlen(str);
122 ival = len - 1;
123 while ((ival >= 0) && isspace(str[ival])) {
124 str[ival] = '\0';
125 ival--;
128 for (curr = str; curr; curr = next) {
129 regspacing = 1;
130 regsize = 1;
131 regshift = 0;
132 irq = 0;
133 ipmb = 0; /* Choose the default if not specified */
135 next = strchr(curr, ':');
136 if (next) {
137 *next = '\0';
138 next++;
141 rv = parse_str(hotmod_ops, &ival, "operation", &curr);
142 if (rv)
143 break;
144 op = ival;
146 rv = parse_str(hotmod_si, &ival, "interface type", &curr);
147 if (rv)
148 break;
149 si_type = ival;
151 rv = parse_str(hotmod_as, &addr_space, "address space", &curr);
152 if (rv)
153 break;
155 s = strchr(curr, ',');
156 if (s) {
157 *s = '\0';
158 s++;
160 addr = simple_strtoul(curr, &n, 0);
161 if ((*n != '\0') || (*curr == '\0')) {
162 pr_warn(PFX "Invalid hotmod address '%s'\n", curr);
163 break;
166 while (s) {
167 curr = s;
168 s = strchr(curr, ',');
169 if (s) {
170 *s = '\0';
171 s++;
173 o = strchr(curr, '=');
174 if (o) {
175 *o = '\0';
176 o++;
178 rv = check_hotmod_int_op(curr, o, "rsp", &regspacing);
179 if (rv < 0)
180 goto out;
181 else if (rv)
182 continue;
183 rv = check_hotmod_int_op(curr, o, "rsi", &regsize);
184 if (rv < 0)
185 goto out;
186 else if (rv)
187 continue;
188 rv = check_hotmod_int_op(curr, o, "rsh", &regshift);
189 if (rv < 0)
190 goto out;
191 else if (rv)
192 continue;
193 rv = check_hotmod_int_op(curr, o, "irq", &irq);
194 if (rv < 0)
195 goto out;
196 else if (rv)
197 continue;
198 rv = check_hotmod_int_op(curr, o, "ipmb", &ipmb);
199 if (rv < 0)
200 goto out;
201 else if (rv)
202 continue;
204 rv = -EINVAL;
205 pr_warn(PFX "Invalid hotmod option '%s'\n", curr);
206 goto out;
209 if (op == HM_ADD) {
210 struct si_sm_io io;
212 memset(&io, 0, sizeof(io));
213 io.addr_source = SI_HOTMOD;
214 io.si_type = si_type;
215 io.addr_data = addr;
216 io.addr_type = addr_space;
218 io.addr = NULL;
219 io.regspacing = regspacing;
220 if (!io.regspacing)
221 io.regspacing = DEFAULT_REGSPACING;
222 io.regsize = regsize;
223 if (!io.regsize)
224 io.regsize = DEFAULT_REGSIZE;
225 io.regshift = regshift;
226 io.irq = irq;
227 if (io.irq)
228 io.irq_setup = ipmi_std_irq_setup;
229 io.slave_addr = ipmb;
231 rv = ipmi_si_add_smi(&io);
232 if (rv)
233 goto out;
234 } else {
235 ipmi_si_remove_by_data(addr_space, si_type, addr);
238 rv = len;
239 out:
240 kfree(str);
241 return rv;