Skip to content
This repository
Newer
Older
100644 329 lines (280 sloc) 10.543 kb
009f34b4 »
2010-06-29 added readme and copyright
1 /* Copyright (c) 2010: Michal Kottman */
2
5fa46ef1 »
2010-06-29 fix headers for compilation on pre-2.6.34 kernels
3 #include <linux/module.h>
4 #include <linux/kernel.h>
f93145e3 »
2010-06-27 initial commit
5 #include <linux/proc_fs.h>
b8a5655e »
2010-10-01 added parsing of parameters
6 #include <linux/slab.h>
5fa46ef1 »
2010-06-29 fix headers for compilation on pre-2.6.34 kernels
7 #include <asm/uaccess.h>
8 #include <acpi/acpi.h>
f93145e3 »
2010-06-27 initial commit
9
10 MODULE_LICENSE("GPL");
11
9ed1c8ae »
2011-10-10 Protect against buffer overflow on sprintf
12 #define BUFFER_SIZE 256
13
f93145e3 »
2010-06-27 initial commit
14 extern struct proc_dir_entry *acpi_root_dir;
15
9ed1c8ae »
2011-10-10 Protect against buffer overflow on sprintf
16 static char result_buffer[BUFFER_SIZE];
f93145e3 »
2010-06-27 initial commit
17
9ed1c8ae »
2011-10-10 Protect against buffer overflow on sprintf
18 static u8 temporary_buffer[BUFFER_SIZE];
a8a9c195 »
2010-06-29 /proc/acpi/call now returns the status of last operation
19
e04d9e87 »
2011-10-22 Convert result_buffer macros to functions
20 static size_t get_avail_bytes(void) {
21 return BUFFER_SIZE - strlen(result_buffer);
22 }
ce867491 »
2011-10-22 Set the right return type for get_buffer_end
23 static char *get_buffer_end(void) {
e04d9e87 »
2011-10-22 Convert result_buffer macros to functions
24 return result_buffer + strlen(result_buffer);
25 }
1f315312 »
2011-10-21 Put result stringifying in a separate function
26 /** Appends the contents of an acpi_object to the result buffer
3a637ead »
2011-10-22 acpi_result_to_string: write to first available buffer space
27 @param result An acpi object holding result data
b916f998 »
2011-10-22 acpi_result_to_string: Return 0 on success, and higher on failure
28 @returns 0 if the result could fully be saved, a higher value otherwise
1f315312 »
2011-10-21 Put result stringifying in a separate function
29 */
b916f998 »
2011-10-22 acpi_result_to_string: Return 0 on success, and higher on failure
30 static int acpi_result_to_string(union acpi_object *result) {
3a637ead »
2011-10-22 acpi_result_to_string: write to first available buffer space
31 if (result->type == ACPI_TYPE_INTEGER) {
e04d9e87 »
2011-10-22 Convert result_buffer macros to functions
32 snprintf(get_buffer_end(), get_avail_bytes(),
b916f998 »
2011-10-22 acpi_result_to_string: Return 0 on success, and higher on failure
33 "0x%x", (int)result->integer.value);
1f315312 »
2011-10-21 Put result stringifying in a separate function
34 } else if (result->type == ACPI_TYPE_STRING) {
e04d9e87 »
2011-10-22 Convert result_buffer macros to functions
35 snprintf(get_buffer_end(), get_avail_bytes(),
b916f998 »
2011-10-22 acpi_result_to_string: Return 0 on success, and higher on failure
36 "\"%*s\"", result->string.length, result->string.pointer);
1f315312 »
2011-10-21 Put result stringifying in a separate function
37 } else if (result->type == ACPI_TYPE_BUFFER) {
38 int i;
39 // do not store more than data if it does not fit. The first element is
40 // just 4 chars, but there is also two bytes from the curly brackets
b3f863c4 »
2011-10-22 Optimization: use min() macro for defining show_values
41 int show_values = min(result->buffer.length, get_avail_bytes() / 6);
1f315312 »
2011-10-21 Put result stringifying in a separate function
42
e04d9e87 »
2011-10-22 Convert result_buffer macros to functions
43 sprintf(get_buffer_end(), "{");
1f315312 »
2011-10-21 Put result stringifying in a separate function
44 for (i = 0; i < show_values; i++)
e04d9e87 »
2011-10-22 Convert result_buffer macros to functions
45 sprintf(get_buffer_end(),
1f315312 »
2011-10-21 Put result stringifying in a separate function
46 i == 0 ? "0x%02x" : ", 0x%02x", result->buffer.pointer[i]);
3a637ead »
2011-10-22 acpi_result_to_string: write to first available buffer space
47
b0e0d20f »
2011-10-22 Fix possibly overwriting the null terminator on the end of type buffer
48 if (result->buffer.length > show_values) {
49 // if data was truncated, show a trailing comma if there is space
50 snprintf(get_buffer_end(), get_avail_bytes(), ",");
ab2df236 »
2011-10-22 acpi_result_to_string: return immediately on errors
51 return 1;
b916f998 »
2011-10-22 acpi_result_to_string: Return 0 on success, and higher on failure
52 } else {
b0e0d20f »
2011-10-22 Fix possibly overwriting the null terminator on the end of type buffer
53 // in case show_values == 0, but the buffer is too small to hold
52993eb5 »
2011-10-22 acpi_result_to_string: Fix possible buffer overflow (by 1)
54 // more values (i.e. the buffer cannot have anything more than "{")
e04d9e87 »
2011-10-22 Convert result_buffer macros to functions
55 snprintf(get_buffer_end(), get_avail_bytes(), "}");
b916f998 »
2011-10-22 acpi_result_to_string: Return 0 on success, and higher on failure
56 }
7c47a9aa »
2011-10-22 Add support for serializing package result types
57 } else if (result->type == ACPI_TYPE_PACKAGE) {
58 int i;
e04d9e87 »
2011-10-22 Convert result_buffer macros to functions
59 sprintf(get_buffer_end(), "[");
7c47a9aa »
2011-10-22 Add support for serializing package result types
60 for (i=0; i<result->package.count; i++) {
ab2df236 »
2011-10-22 acpi_result_to_string: return immediately on errors
61 if (i > 0)
e04d9e87 »
2011-10-22 Convert result_buffer macros to functions
62 snprintf(get_buffer_end(), get_avail_bytes(), ", ");
ab2df236 »
2011-10-22 acpi_result_to_string: return immediately on errors
63
64 // abort if there is no more space available
e04d9e87 »
2011-10-22 Convert result_buffer macros to functions
65 if (!get_avail_bytes() || acpi_result_to_string(&result->package.elements[i]))
ab2df236 »
2011-10-22 acpi_result_to_string: return immediately on errors
66 return 1;
7c47a9aa »
2011-10-22 Add support for serializing package result types
67 }
e04d9e87 »
2011-10-22 Convert result_buffer macros to functions
68 snprintf(get_buffer_end(), get_avail_bytes(), "]");
1f315312 »
2011-10-21 Put result stringifying in a separate function
69 } else {
e04d9e87 »
2011-10-22 Convert result_buffer macros to functions
70 snprintf(get_buffer_end(), get_avail_bytes(),
b916f998 »
2011-10-22 acpi_result_to_string: Return 0 on success, and higher on failure
71 "Object type 0x%x\n", result->type);
1f315312 »
2011-10-21 Put result stringifying in a separate function
72 }
b916f998 »
2011-10-22 acpi_result_to_string: Return 0 on success, and higher on failure
73
ab2df236 »
2011-10-22 acpi_result_to_string: return immediately on errors
74 // return 0 if there are still bytes available, 1 otherwise
e04d9e87 »
2011-10-22 Convert result_buffer macros to functions
75 return !get_avail_bytes();
1f315312 »
2011-10-21 Put result stringifying in a separate function
76 }
77
e5931ce3 »
2010-10-01 added some comments
78 /**
79 @param method The full name of ACPI method to call
b8a5655e »
2010-10-01 added parsing of parameters
80 @param argc The number of parameters
81 @param argv A pre-allocated array of arguments of type acpi_object
e5931ce3 »
2010-10-01 added some comments
82 */
b8a5655e »
2010-10-01 added parsing of parameters
83 static void do_acpi_call(const char * method, int argc, union acpi_object *argv)
f93145e3 »
2010-06-27 initial commit
84 {
85 acpi_status status;
86 acpi_handle handle;
b7184447 »
2010-10-11 added support for buffer parameters
87 struct acpi_object_list arg;
f93145e3 »
2010-06-27 initial commit
88 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
89
90 printk(KERN_INFO "acpi_call: Calling %s\n", method);
91
e5931ce3 »
2010-10-01 added some comments
92 // get the handle of the method, must be a fully qualified path
93 status = acpi_get_handle(NULL, (acpi_string) method, &handle);
f93145e3 »
2010-06-27 initial commit
94
95 if (ACPI_FAILURE(status))
96 {
9ed1c8ae »
2011-10-10 Protect against buffer overflow on sprintf
97 snprintf(result_buffer, BUFFER_SIZE, "Error: %s", acpi_format_exception(status));
33335ac6 »
2010-10-09 Added load target to Makefile.
98 printk(KERN_ERR "acpi_call: Cannot get handle: %s\n", result_buffer);
a8a9c195 »
2010-06-29 /proc/acpi/call now returns the status of last operation
99 return;
f93145e3 »
2010-06-27 initial commit
100 }
101
b8a5655e »
2010-10-01 added parsing of parameters
102 // prepare parameters
b7184447 »
2010-10-11 added support for buffer parameters
103 arg.count = argc;
104 arg.pointer = argv;
f93145e3 »
2010-06-27 initial commit
105
e5931ce3 »
2010-10-01 added some comments
106 // call the method
b7184447 »
2010-10-11 added support for buffer parameters
107 status = acpi_evaluate_object(handle, NULL, &arg, &buffer);
f93145e3 »
2010-06-27 initial commit
108 if (ACPI_FAILURE(status))
109 {
9ed1c8ae »
2011-10-10 Protect against buffer overflow on sprintf
110 snprintf(result_buffer, BUFFER_SIZE, "Error: %s", acpi_format_exception(status));
7b41b2c3 »
2010-10-11 Merge git://github.com/peberlein/acpi_call
111 printk(KERN_ERR "acpi_call: Method call failed: %s\n", result_buffer);
a8a9c195 »
2010-06-29 /proc/acpi/call now returns the status of last operation
112 return;
f93145e3 »
2010-06-27 initial commit
113 }
3a637ead »
2011-10-22 acpi_result_to_string: write to first available buffer space
114
115 // reset the result buffer
116 *result_buffer = '\0';
1f315312 »
2011-10-21 Put result stringifying in a separate function
117 acpi_result_to_string(buffer.pointer);
f93145e3 »
2010-06-27 initial commit
118 kfree(buffer.pointer);
119
33335ac6 »
2010-10-09 Added load target to Makefile.
120 printk(KERN_INFO "acpi_call: Call successful: %s\n", result_buffer);
f93145e3 »
2010-06-27 initial commit
121 }
122
7b41b2c3 »
2010-10-11 Merge git://github.com/peberlein/acpi_call
123 /** Decodes 2 hex characters to an u8 int
b7184447 »
2010-10-11 added support for buffer parameters
124 */
125 u8 decodeHex(char *hex) {
126 char buf[3] = { hex[0], hex[1], 0};
127 return (u8) simple_strtoul(buf, NULL, 16);
128 }
129
b8a5655e »
2010-10-01 added parsing of parameters
130 /** Parses method name and arguments
131 @param input Input string to be parsed. Modified in the process.
132 @param nargs Set to number of arguments parsed (output)
133 @param args
134 */
135 static char *parse_acpi_args(char *input, int *nargs, union acpi_object **args)
136 {
137 char *s = input;
138
139 *nargs = 0;
140 *args = NULL;
141
142 // the method name is separated from the arguments by a space
33335ac6 »
2010-10-09 Added load target to Makefile.
143 while (*s && *s != ' ')
7b41b2c3 »
2010-10-11 Merge git://github.com/peberlein/acpi_call
144 s++;
b8a5655e »
2010-10-01 added parsing of parameters
145 // if no space is found, return 0 arguments
146 if (*s == 0)
147 return input;
33335ac6 »
2010-10-09 Added load target to Makefile.
148
b8a5655e »
2010-10-01 added parsing of parameters
149 *args = (union acpi_object *) kmalloc(16 * sizeof(union acpi_object), GFP_KERNEL);
150
151 while (*s) {
152 if (*s == ' ') {
7b41b2c3 »
2010-10-11 Merge git://github.com/peberlein/acpi_call
153 if (*nargs == 0)
154 *s = 0; // change first space to nul
b8a5655e »
2010-10-01 added parsing of parameters
155 ++ *nargs;
156 ++ s;
157 } else {
158 union acpi_object *arg = (*args) + (*nargs - 1);
159 if (*s == '"') {
160 // decode string
161 arg->type = ACPI_TYPE_STRING;
162 arg->string.pointer = ++s;
163 arg->string.length = 0;
3db318cf »
2010-10-11 a small fix for the previous merge
164 while (*s && *s++ != '"')
b8a5655e »
2010-10-01 added parsing of parameters
165 arg->string.length ++;
166 // skip the last "
167 ++s;
b7184447 »
2010-10-11 added support for buffer parameters
168 } else if (*s == 'b') {
7b41b2c3 »
2010-10-11 Merge git://github.com/peberlein/acpi_call
169 // decode buffer - bXXXX
b7184447 »
2010-10-11 added support for buffer parameters
170 char *p = ++s;
171 int len = 0, i;
172 u8 *buf = NULL;
173
174 while (*p && *p!=' ')
175 p++;
176
177 len = p - s;
178 if (len % 2 == 1) {
179 printk(KERN_ERR "acpi_call: buffer arg%d is not multiple of 8 bits\n", *nargs);
180 return NULL;
181 }
182 len /= 2;
183
184 buf = (u8*) kmalloc(len, GFP_KERNEL);
185 for (i=0; i<len; i++) {
186 buf[i] = decodeHex(s + i*2);
187 }
188 s = p;
189
190 arg->type = ACPI_TYPE_BUFFER;
191 arg->buffer.pointer = buf;
192 arg->buffer.length = len;
7b41b2c3 »
2010-10-11 Merge git://github.com/peberlein/acpi_call
193 } else if (*s == '{') {
194 // decode buffer - { b1, b2 ...}
195 u8 *buf = temporary_buffer;
196 arg->type = ACPI_TYPE_BUFFER;
197 arg->buffer.pointer = buf;
198 arg->buffer.length = 0;
199 while (*s && *s++ != '}') {
6b2c68c7 »
2011-10-11 parse_acpi_args: show duplicate arg error only once
200 if (buf >= temporary_buffer + sizeof(temporary_buffer)) {
201 printk(KERN_ERR "acpi_call: buffer arg%d is truncated because the buffer is full\n", *nargs);
202 // clear remaining arguments
203 while (*s && *s != '}')
204 ++s;
205 break;
206 }
7b41b2c3 »
2010-10-11 Merge git://github.com/peberlein/acpi_call
207 else if (*s >= '0' && *s <= '9') {
208 // decode integer into buffer
209 arg->buffer.length ++;
210 if (s[0] == '0' && s[1] == 'x')
211 *buf++ = simple_strtol(s+2, 0, 16);
212 else
213 *buf++ = simple_strtol(s, 0, 10);
214 }
215 // skip until space or comma or '}'
216 while (*s && *s != ' ' && *s != ',' && *s != '}')
217 ++s;
218 }
219 // store the result in new allocated buffer
220 buf = (u8*) kmalloc(arg->buffer.length, GFP_KERNEL);
221 memcpy(buf, temporary_buffer, arg->buffer.length);
222 arg->buffer.pointer = buf;
b8a5655e »
2010-10-01 added parsing of parameters
223 } else {
224 // decode integer, N or 0xN
225 arg->type = ACPI_TYPE_INTEGER;
226 if (s[0] == '0' && s[1] == 'x') {
227 arg->integer.value = simple_strtol(s+2, 0, 16);
228 } else {
229 arg->integer.value = simple_strtol(s, 0, 10);
230 }
231 while (*s && *s != ' ') {
232 ++s;
233 }
234 }
235 }
236 }
237
238 return input;
239 }
240
e5931ce3 »
2010-10-01 added some comments
241 /** procfs write callback. Called when writing into /proc/acpi/call.
242 */
f93145e3 »
2010-06-27 initial commit
243 static int acpi_proc_write( struct file *filp, const char __user *buff,
a8a9c195 »
2010-06-29 /proc/acpi/call now returns the status of last operation
244 unsigned long len, void *data )
f93145e3 »
2010-06-27 initial commit
245 {
b7c4e670 »
2011-10-11 parse_acpi_args: respect BUFFER_SIZE, do not hardcode it
246 char input[2 * BUFFER_SIZE] = { '\0' };
b8a5655e »
2010-10-01 added parsing of parameters
247 union acpi_object *args;
b7184447 »
2010-10-11 added support for buffer parameters
248 int nargs, i;
b8a5655e »
2010-10-01 added parsing of parameters
249 char *method;
f93145e3 »
2010-06-27 initial commit
250
251 if (len > sizeof(input) - 1) {
252 printk(KERN_ERR "acpi_call: Input too long! (%lu)\n", len);
253 return -ENOSPC;
254 }
255
256 if (copy_from_user( input, buff, len )) {
257 return -EFAULT;
258 }
259 input[len] = '\0';
260 if (input[len-1] == '\n')
261 input[len-1] = '\0';
262
b8a5655e »
2010-10-01 added parsing of parameters
263 method = parse_acpi_args(input, &nargs, &args);
b7184447 »
2010-10-11 added support for buffer parameters
264 if (method) {
265 do_acpi_call(method, nargs, args);
266 if (args) {
267 for (i=0; i<nargs; i++)
268 if (args[i].type == ACPI_TYPE_BUFFER)
269 kfree(args[i].buffer.pointer);
270 kfree(args);
271 }
b8a5655e »
2010-10-01 added parsing of parameters
272 }
273
a8a9c195 »
2010-06-29 /proc/acpi/call now returns the status of last operation
274 return len;
f93145e3 »
2010-06-27 initial commit
275 }
276
e5931ce3 »
2010-10-01 added some comments
277 /** procfs 'call' read callback. Called when reading the content of /proc/acpi/call.
278 Returns the last call status:
279 - "not called" when no call was previously issued
280 - "failed" if the call failed
281 - "ok" if the call succeeded
282 */
a8a9c195 »
2010-06-29 /proc/acpi/call now returns the status of last operation
283 static int acpi_proc_read(char *page, char **start, off_t off,
284 int count, int *eof, void *data)
285 {
286 int len = 0;
287
288 if (off > 0) {
289 *eof = 1;
290 return 0;
291 }
292
33335ac6 »
2010-10-09 Added load target to Makefile.
293 len = strlen(result_buffer);
294 memcpy(page, result_buffer, len + 1);
295 strcpy(result_buffer, "not called");
a8a9c195 »
2010-06-29 /proc/acpi/call now returns the status of last operation
296
297 return len;
298 }
f93145e3 »
2010-06-27 initial commit
299
e5931ce3 »
2010-10-01 added some comments
300 /** module initialization function */
f93145e3 »
2010-06-27 initial commit
301 static int __init init_acpi_call(void)
302 {
3c842f4b »
2011-09-17 Make /proc/acpi/call not world-writable
303 struct proc_dir_entry *acpi_entry = create_proc_entry("call", 0660, acpi_root_dir);
a8a9c195 »
2010-06-29 /proc/acpi/call now returns the status of last operation
304
33335ac6 »
2010-10-09 Added load target to Makefile.
305 strcpy(result_buffer, "not called");
a8a9c195 »
2010-06-29 /proc/acpi/call now returns the status of last operation
306
f93145e3 »
2010-06-27 initial commit
307 if (acpi_entry == NULL) {
308 printk(KERN_ERR "acpi_call: Couldn't create proc entry\n");
309 return -ENOMEM;
310 }
a8a9c195 »
2010-06-29 /proc/acpi/call now returns the status of last operation
311
f93145e3 »
2010-06-27 initial commit
312 acpi_entry->write_proc = acpi_proc_write;
a8a9c195 »
2010-06-29 /proc/acpi/call now returns the status of last operation
313 acpi_entry->read_proc = acpi_proc_read;
f93145e3 »
2010-06-27 initial commit
314 printk(KERN_INFO "acpi_call: Module loaded successfully\n");
315
316 return 0;
317 }
318
9ceb2527 »
2011-10-18 Print message when unloading, add __exit macro
319 static void __exit unload_acpi_call(void)
f93145e3 »
2010-06-27 initial commit
320 {
321 remove_proc_entry("call", acpi_root_dir);
9ceb2527 »
2011-10-18 Print message when unloading, add __exit macro
322 printk(KERN_INFO "acpi_call: Module unloaded successfully\n");
f93145e3 »
2010-06-27 initial commit
323 }
324
325 module_init(init_acpi_call);
326 module_exit(unload_acpi_call);
327
328
Something went wrong with that request. Please try again.