[PATCH] Merge headphone and speaker volume controls for Panasonic R4 laptop
[deliverable/linux.git] / arch / um / drivers / mconsole_kern.c
CommitLineData
1da177e4
LT
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
3 * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
4 * Licensed under the GPL
5 */
6
7#include "linux/kernel.h"
8#include "linux/slab.h"
9#include "linux/init.h"
10#include "linux/notifier.h"
11#include "linux/reboot.h"
12#include "linux/utsname.h"
13#include "linux/ctype.h"
14#include "linux/interrupt.h"
15#include "linux/sysrq.h"
16#include "linux/workqueue.h"
17#include "linux/module.h"
18#include "linux/file.h"
19#include "linux/fs.h"
20#include "linux/namei.h"
21#include "linux/proc_fs.h"
22#include "linux/syscalls.h"
02dea087
JD
23#include "linux/list.h"
24#include "linux/mm.h"
6f517d3f 25#include "linux/console.h"
1da177e4
LT
26#include "asm/irq.h"
27#include "asm/uaccess.h"
28#include "user_util.h"
29#include "kern_util.h"
30#include "kern.h"
31#include "mconsole.h"
32#include "mconsole_kern.h"
33#include "irq_user.h"
34#include "init.h"
35#include "os.h"
36#include "umid.h"
37#include "irq_kern.h"
3eddddcf 38#include "choose-mode.h"
1da177e4 39
d50084a2 40static int do_unlink_socket(struct notifier_block *notifier,
1da177e4
LT
41 unsigned long what, void *data)
42{
43 return(mconsole_unlink_socket());
44}
45
46
47static struct notifier_block reboot_notifier = {
48 .notifier_call = do_unlink_socket,
49 .priority = 0,
50};
51
d50084a2 52/* Safe without explicit locking for now. Tasklets provide their own
1da177e4
LT
53 * locking, and the interrupt handler is safe because it can't interrupt
54 * itself and it can only happen on CPU 0.
55 */
56
9010772c 57static LIST_HEAD(mc_requests);
1da177e4
LT
58
59static void mc_work_proc(void *unused)
60{
61 struct mconsole_entry *req;
62 unsigned long flags;
63
64 while(!list_empty(&mc_requests)){
dbdb4c06 65 local_irq_save(flags);
d50084a2 66 req = list_entry(mc_requests.next, struct mconsole_entry,
1da177e4
LT
67 list);
68 list_del(&req->list);
69 local_irq_restore(flags);
70 req->request.cmd->handler(&req->request);
71 kfree(req);
72 }
73}
74
9010772c 75static DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
1da177e4 76
7bea96fd 77static irqreturn_t mconsole_interrupt(int irq, void *dev_id)
1da177e4
LT
78{
79 /* long to avoid size mismatch warnings from gcc */
80 long fd;
81 struct mconsole_entry *new;
82 struct mc_request req;
83
84 fd = (long) dev_id;
85 while (mconsole_get_request(fd, &req)){
86 if(req.cmd->context == MCONSOLE_INTR)
87 (*req.cmd->handler)(&req);
88 else {
60baa158 89 new = kmalloc(sizeof(*new), GFP_NOWAIT);
1da177e4
LT
90 if(new == NULL)
91 mconsole_reply(&req, "Out of memory", 1, 0);
92 else {
93 new->request = req;
94 list_add(&new->list, &mc_requests);
95 }
96 }
97 }
98 if(!list_empty(&mc_requests))
99 schedule_work(&mconsole_work);
100 reactivate_fd(fd, MCONSOLE_IRQ);
101 return(IRQ_HANDLED);
102}
103
104void mconsole_version(struct mc_request *req)
105{
106 char version[256];
107
e9ff3990
SH
108 sprintf(version, "%s %s %s %s %s", utsname()->sysname,
109 utsname()->nodename, utsname()->release,
110 utsname()->version, utsname()->machine);
1da177e4
LT
111 mconsole_reply(req, version, 0, 0);
112}
113
114void mconsole_log(struct mc_request *req)
115{
116 int len;
117 char *ptr = req->request.data;
118
119 ptr += strlen("log ");
120
121 len = req->len - (ptr - req->request.data);
122 printk("%.*s", len, ptr);
123 mconsole_reply(req, "", 0, 0);
124}
125
126/* This is a more convoluted version of mconsole_proc, which has some stability
127 * problems; however, we need it fixed, because it is expected that UML users
128 * mount HPPFS instead of procfs on /proc. And we want mconsole_proc to still
129 * show the real procfs content, not the ones from hppfs.*/
130#if 0
131void mconsole_proc(struct mc_request *req)
132{
133 struct nameidata nd;
134 struct file_system_type *proc;
135 struct super_block *super;
136 struct file *file;
137 int n, err;
138 char *ptr = req->request.data, *buf;
139
140 ptr += strlen("proc");
141 while(isspace(*ptr)) ptr++;
142
143 proc = get_fs_type("proc");
144 if(proc == NULL){
145 mconsole_reply(req, "procfs not registered", 1, 0);
146 goto out;
147 }
148
149 super = (*proc->get_sb)(proc, 0, NULL, NULL);
150 put_filesystem(proc);
151 if(super == NULL){
152 mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
153 goto out;
154 }
155 up_write(&super->s_umount);
156
157 nd.dentry = super->s_root;
158 nd.mnt = NULL;
159 nd.flags = O_RDONLY + 1;
160 nd.last_type = LAST_ROOT;
161
162 /* START: it was experienced that the stability problems are closed
163 * if commenting out these two calls + the below read cycle. To
164 * make UML crash again, it was enough to readd either one.*/
165 err = link_path_walk(ptr, &nd);
166 if(err){
167 mconsole_reply(req, "Failed to look up file", 1, 0);
168 goto out_kill;
169 }
170
171 file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
172 if(IS_ERR(file)){
173 mconsole_reply(req, "Failed to open file", 1, 0);
174 goto out_kill;
175 }
176 /*END*/
177
178 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
179 if(buf == NULL){
180 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
181 goto out_fput;
182 }
183
184 if((file->f_op != NULL) && (file->f_op->read != NULL)){
185 do {
186 n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1,
187 &file->f_pos);
188 if(n >= 0){
189 buf[n] = '\0';
190 mconsole_reply(req, buf, 0, (n > 0));
191 }
192 else {
193 mconsole_reply(req, "Read of file failed",
194 1, 0);
195 goto out_free;
196 }
197 } while(n > 0);
198 }
199 else mconsole_reply(req, "", 0, 0);
200
201 out_free:
202 kfree(buf);
203 out_fput:
204 fput(file);
205 out_kill:
206 deactivate_super(super);
207 out: ;
208}
209#endif
210
211void mconsole_proc(struct mc_request *req)
212{
213 char path[64];
214 char *buf;
215 int len;
216 int fd;
217 int first_chunk = 1;
218 char *ptr = req->request.data;
219
220 ptr += strlen("proc");
221 while(isspace(*ptr)) ptr++;
222 snprintf(path, sizeof(path), "/proc/%s", ptr);
223
224 fd = sys_open(path, 0, 0);
225 if (fd < 0) {
226 mconsole_reply(req, "Failed to open file", 1, 0);
227 printk("open %s: %d\n",path,fd);
228 goto out;
229 }
230
231 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
232 if(buf == NULL){
233 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
234 goto out_close;
235 }
236
237 for (;;) {
238 len = sys_read(fd, buf, PAGE_SIZE-1);
239 if (len < 0) {
240 mconsole_reply(req, "Read of file failed", 1, 0);
241 goto out_free;
242 }
243 /*Begin the file content on his own line.*/
244 if (first_chunk) {
245 mconsole_reply(req, "\n", 0, 1);
246 first_chunk = 0;
247 }
248 if (len == PAGE_SIZE-1) {
249 buf[len] = '\0';
250 mconsole_reply(req, buf, 0, 1);
251 } else {
252 buf[len] = '\0';
253 mconsole_reply(req, buf, 0, 0);
254 break;
255 }
256 }
257
258 out_free:
259 kfree(buf);
260 out_close:
261 sys_close(fd);
262 out:
263 /* nothing */;
264}
265
266#define UML_MCONSOLE_HELPTEXT \
267"Commands: \n\
268 version - Get kernel version \n\
269 help - Print this message \n\
270 halt - Halt UML \n\
271 reboot - Reboot UML \n\
272 config <dev>=<config> - Add a new device to UML; \n\
273 same syntax as command line \n\
274 config <dev> - Query the configuration of a device \n\
275 remove <dev> - Remove a device from UML \n\
276 sysrq <letter> - Performs the SysRq action controlled by the letter \n\
db805812 277 cad - invoke the Ctrl-Alt-Del handler \n\
1da177e4
LT
278 stop - pause the UML; it will do nothing until it receives a 'go' \n\
279 go - continue the UML after a 'stop' \n\
280 log <string> - make UML enter <string> into the kernel log\n\
281 proc <file> - returns the contents of the UML's /proc/<file>\n\
3eddddcf 282 stack <pid> - returns the stack of the specified pid\n\
1da177e4
LT
283"
284
285void mconsole_help(struct mc_request *req)
286{
287 mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0);
288}
289
290void mconsole_halt(struct mc_request *req)
291{
292 mconsole_reply(req, "", 0, 0);
293 machine_halt();
294}
295
296void mconsole_reboot(struct mc_request *req)
297{
298 mconsole_reply(req, "", 0, 0);
299 machine_restart(NULL);
300}
301
1da177e4
LT
302void mconsole_cad(struct mc_request *req)
303{
304 mconsole_reply(req, "", 0, 0);
305 ctrl_alt_del();
306}
307
308void mconsole_go(struct mc_request *req)
309{
310 mconsole_reply(req, "Not stopped", 1, 0);
311}
312
313void mconsole_stop(struct mc_request *req)
314{
315 deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
316 os_set_fd_block(req->originating_fd, 1);
317 mconsole_reply(req, "", 0, 0);
318 while(mconsole_get_request(req->originating_fd, req)){
319 if(req->cmd->handler == mconsole_go) break;
320 (*req->cmd->handler)(req);
321 }
322 os_set_fd_block(req->originating_fd, 0);
323 reactivate_fd(req->originating_fd, MCONSOLE_IRQ);
324 mconsole_reply(req, "", 0, 0);
325}
326
327/* This list is populated by __initcall routines. */
328
42947cb9 329static LIST_HEAD(mconsole_devices);
1da177e4
LT
330
331void mconsole_register_dev(struct mc_device *new)
332{
333 list_add(&new->list, &mconsole_devices);
334}
335
336static struct mc_device *mconsole_find_dev(char *name)
337{
338 struct list_head *ele;
339 struct mc_device *dev;
340
341 list_for_each(ele, &mconsole_devices){
342 dev = list_entry(ele, struct mc_device, list);
343 if(!strncmp(name, dev->name, strlen(dev->name)))
344 return(dev);
345 }
346 return(NULL);
347}
348
02dea087
JD
349#define UNPLUGGED_PER_PAGE \
350 ((PAGE_SIZE - sizeof(struct list_head)) / sizeof(unsigned long))
351
352struct unplugged_pages {
353 struct list_head list;
354 void *pages[UNPLUGGED_PER_PAGE];
355};
356
357static unsigned long long unplugged_pages_count = 0;
358static struct list_head unplugged_pages = LIST_HEAD_INIT(unplugged_pages);
359static int unplug_index = UNPLUGGED_PER_PAGE;
360
361static int mem_config(char *str)
362{
363 unsigned long long diff;
364 int err = -EINVAL, i, add;
365 char *ret;
366
367 if(str[0] != '=')
368 goto out;
369
370 str++;
371 if(str[0] == '-')
372 add = 0;
373 else if(str[0] == '+'){
374 add = 1;
375 }
376 else goto out;
377
378 str++;
379 diff = memparse(str, &ret);
380 if(*ret != '\0')
381 goto out;
382
383 diff /= PAGE_SIZE;
384
385 for(i = 0; i < diff; i++){
386 struct unplugged_pages *unplugged;
387 void *addr;
388
389 if(add){
390 if(list_empty(&unplugged_pages))
391 break;
392
393 unplugged = list_entry(unplugged_pages.next,
394 struct unplugged_pages, list);
395 if(unplug_index > 0)
396 addr = unplugged->pages[--unplug_index];
397 else {
398 list_del(&unplugged->list);
399 addr = unplugged;
400 unplug_index = UNPLUGGED_PER_PAGE;
401 }
402
403 free_page((unsigned long) addr);
404 unplugged_pages_count--;
405 }
406 else {
407 struct page *page;
408
409 page = alloc_page(GFP_ATOMIC);
410 if(page == NULL)
411 break;
412
413 unplugged = page_address(page);
414 if(unplug_index == UNPLUGGED_PER_PAGE){
02dea087
JD
415 list_add(&unplugged->list, &unplugged_pages);
416 unplug_index = 0;
417 }
418 else {
419 struct list_head *entry = unplugged_pages.next;
420 addr = unplugged;
421
422 unplugged = list_entry(entry,
423 struct unplugged_pages,
424 list);
425 unplugged->pages[unplug_index++] = addr;
426 err = os_drop_memory(addr, PAGE_SIZE);
427 if(err)
428 printk("Failed to release memory - "
429 "errno = %d\n", err);
430 }
431
432 unplugged_pages_count++;
433 }
434 }
435
436 err = 0;
437out:
438 return err;
439}
440
441static int mem_get_config(char *name, char *str, int size, char **error_out)
442{
443 char buf[sizeof("18446744073709551615")];
444 int len = 0;
445
446 sprintf(buf, "%ld", uml_physmem);
447 CONFIG_CHUNK(str, size, len, buf, 1);
448
449 return len;
450}
451
452static int mem_id(char **str, int *start_out, int *end_out)
453{
454 *start_out = 0;
455 *end_out = 0;
456
457 return 0;
458}
459
460static int mem_remove(int n)
461{
462 return -EBUSY;
463}
464
465static struct mc_device mem_mc = {
466 .name = "mem",
467 .config = mem_config,
468 .get_config = mem_get_config,
469 .id = mem_id,
470 .remove = mem_remove,
471};
472
473static int mem_mc_init(void)
474{
475 if(can_drop_memory())
476 mconsole_register_dev(&mem_mc);
477 else printk("Can't release memory to the host - memory hotplug won't "
478 "be supported\n");
479 return 0;
480}
481
482__initcall(mem_mc_init);
483
1da177e4
LT
484#define CONFIG_BUF_SIZE 64
485
d50084a2 486static void mconsole_get_config(int (*get_config)(char *, char *, int,
1da177e4
LT
487 char **),
488 struct mc_request *req, char *name)
489{
490 char default_buf[CONFIG_BUF_SIZE], *error, *buf;
491 int n, size;
492
493 if(get_config == NULL){
494 mconsole_reply(req, "No get_config routine defined", 1, 0);
495 return;
496 }
497
498 error = NULL;
91b165c0 499 size = ARRAY_SIZE(default_buf);
1da177e4
LT
500 buf = default_buf;
501
502 while(1){
503 n = (*get_config)(name, buf, size, &error);
504 if(error != NULL){
505 mconsole_reply(req, error, 1, 0);
506 goto out;
507 }
508
509 if(n <= size){
510 mconsole_reply(req, buf, 0, 0);
511 goto out;
512 }
513
514 if(buf != default_buf)
515 kfree(buf);
516
517 size = n;
518 buf = kmalloc(size, GFP_KERNEL);
519 if(buf == NULL){
520 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
521 return;
522 }
523 }
524 out:
525 if(buf != default_buf)
526 kfree(buf);
1da177e4
LT
527}
528
529void mconsole_config(struct mc_request *req)
530{
531 struct mc_device *dev;
532 char *ptr = req->request.data, *name;
533 int err;
534
535 ptr += strlen("config");
536 while(isspace(*ptr)) ptr++;
537 dev = mconsole_find_dev(ptr);
538 if(dev == NULL){
539 mconsole_reply(req, "Bad configuration option", 1, 0);
540 return;
541 }
542
543 name = &ptr[strlen(dev->name)];
544 ptr = name;
545 while((*ptr != '=') && (*ptr != '\0'))
546 ptr++;
547
548 if(*ptr == '='){
549 err = (*dev->config)(name);
550 mconsole_reply(req, "", err, 0);
551 }
552 else mconsole_get_config(dev->get_config, req, name);
553}
554
555void mconsole_remove(struct mc_request *req)
556{
d50084a2 557 struct mc_device *dev;
29d56cfe 558 char *ptr = req->request.data, *err_msg = "";
3a331a51 559 char error[256];
29d56cfe 560 int err, start, end, n;
1da177e4
LT
561
562 ptr += strlen("remove");
563 while(isspace(*ptr)) ptr++;
564 dev = mconsole_find_dev(ptr);
565 if(dev == NULL){
566 mconsole_reply(req, "Bad remove option", 1, 0);
567 return;
568 }
29d56cfe 569
3a331a51
JD
570 ptr = &ptr[strlen(dev->name)];
571
572 err = 1;
573 n = (*dev->id)(&ptr, &start, &end);
574 if(n < 0){
575 err_msg = "Couldn't parse device number";
576 goto out;
577 }
578 else if((n < start) || (n > end)){
579 sprintf(error, "Invalid device number - must be between "
580 "%d and %d", start, end);
581 err_msg = error;
582 goto out;
583 }
29d56cfe
JD
584
585 err = (*dev->remove)(n);
3a331a51
JD
586 switch(err){
587 case -ENODEV:
588 err_msg = "Device doesn't exist";
589 break;
590 case -EBUSY:
591 err_msg = "Device is currently open";
592 break;
593 default:
594 break;
595 }
596out:
29d56cfe 597 mconsole_reply(req, err_msg, err, 0);
1da177e4
LT
598}
599
f92afe56
JD
600struct mconsole_output {
601 struct list_head list;
602 struct mc_request *req;
603};
604
6f517d3f
JD
605static DEFINE_SPINLOCK(console_lock);
606static LIST_HEAD(clients);
607static char console_buf[MCONSOLE_MAX_DATA];
608static int console_index = 0;
609
610static void console_write(struct console *console, const char *string,
611 unsigned len)
612{
613 struct list_head *ele;
614 int n;
615
616 if(list_empty(&clients))
617 return;
618
619 while(1){
6dad2d3f 620 n = min((size_t) len, ARRAY_SIZE(console_buf) - console_index);
6f517d3f
JD
621 strncpy(&console_buf[console_index], string, n);
622 console_index += n;
623 string += n;
624 len -= n;
625 if(len == 0)
626 return;
627
628 list_for_each(ele, &clients){
f92afe56 629 struct mconsole_output *entry;
6f517d3f 630
f92afe56
JD
631 entry = list_entry(ele, struct mconsole_output, list);
632 mconsole_reply_len(entry->req, console_buf,
6f517d3f
JD
633 console_index, 0, 1);
634 }
635
636 console_index = 0;
637 }
638}
639
640static struct console mc_console = { .name = "mc",
641 .write = console_write,
a174b30e 642 .flags = CON_ENABLED,
6f517d3f
JD
643 .index = -1 };
644
645static int mc_add_console(void)
646{
647 register_console(&mc_console);
648 return 0;
649}
650
651late_initcall(mc_add_console);
652
653static void with_console(struct mc_request *req, void (*proc)(void *),
654 void *arg)
655{
f92afe56 656 struct mconsole_output entry;
6f517d3f
JD
657 unsigned long flags;
658
f92afe56 659 entry.req = req;
6f517d3f
JD
660 list_add(&entry.list, &clients);
661 spin_lock_irqsave(&console_lock, flags);
662
663 (*proc)(arg);
664
665 mconsole_reply_len(req, console_buf, console_index, 0, 0);
666 console_index = 0;
667
668 spin_unlock_irqrestore(&console_lock, flags);
669 list_del(&entry.list);
670}
671
4111b025
JD
672#ifdef CONFIG_MAGIC_SYSRQ
673static void sysrq_proc(void *arg)
674{
675 char *op = arg;
7bea96fd
AV
676 struct pt_regs *old_regs = set_irq_regs(&current->thread.regs);
677 handle_sysrq(*op, NULL);
678 set_irq_regs(old_regs);
4111b025
JD
679}
680
681void mconsole_sysrq(struct mc_request *req)
682{
683 char *ptr = req->request.data;
684
685 ptr += strlen("sysrq");
686 while(isspace(*ptr)) ptr++;
687
688 /* With 'b', the system will shut down without a chance to reply,
689 * so in this case, we reply first.
690 */
691 if(*ptr == 'b')
692 mconsole_reply(req, "", 0, 0);
693
694 with_console(req, sysrq_proc, ptr);
695}
696#else
697void mconsole_sysrq(struct mc_request *req)
698{
699 mconsole_reply(req, "Sysrq not compiled in", 1, 0);
700}
701#endif
702
42947cb9
PBG
703#ifdef CONFIG_MODE_SKAS
704
6f517d3f
JD
705static void stack_proc(void *arg)
706{
707 struct task_struct *from = current, *to = arg;
708
709 to->thread.saved_task = from;
710 switch_to(from, to, from);
711}
712
3eddddcf
JD
713/* Mconsole stack trace
714 * Added by Allan Graves, Jeff Dike
715 * Dumps a stacks registers to the linux console.
716 * Usage stack <pid>.
717 */
42947cb9 718static void do_stack_trace(struct mc_request *req)
3eddddcf 719{
3a331a51
JD
720 char *ptr = req->request.data;
721 int pid_requested= -1;
6f517d3f 722 struct task_struct *from = NULL;
3eddddcf
JD
723 struct task_struct *to = NULL;
724
3a331a51
JD
725 /* Would be nice:
726 * 1) Send showregs output to mconsole.
3eddddcf
JD
727 * 2) Add a way to stack dump all pids.
728 */
729
3a331a51
JD
730 ptr += strlen("stack");
731 while(isspace(*ptr)) ptr++;
3eddddcf 732
3a331a51
JD
733 /* Should really check for multiple pids or reject bad args here */
734 /* What do the arguments in mconsole_reply mean? */
735 if(sscanf(ptr, "%d", &pid_requested) == 0){
736 mconsole_reply(req, "Please specify a pid", 1, 0);
737 return;
738 }
3eddddcf 739
6f517d3f 740 from = current;
3eddddcf 741
6f517d3f 742 to = find_task_by_pid(pid_requested);
3a331a51
JD
743 if((to == NULL) || (pid_requested == 0)) {
744 mconsole_reply(req, "Couldn't find that pid", 1, 0);
745 return;
746 }
6f517d3f 747 with_console(req, stack_proc, to);
3eddddcf 748}
42947cb9 749#endif /* CONFIG_MODE_SKAS */
3eddddcf
JD
750
751void mconsole_stack(struct mc_request *req)
752{
753 /* This command doesn't work in TT mode, so let's check and then
754 * get out of here
755 */
756 CHOOSE_MODE(mconsole_reply(req, "Sorry, this doesn't work in TT mode",
757 1, 0),
42947cb9 758 do_stack_trace(req));
3eddddcf
JD
759}
760
1da177e4
LT
761/* Changed by mconsole_setup, which is __setup, and called before SMP is
762 * active.
763 */
d50084a2 764static char *notify_socket = NULL;
1da177e4 765
9010772c 766static int mconsole_init(void)
1da177e4
LT
767{
768 /* long to avoid size mismatch warnings from gcc */
769 long sock;
770 int err;
771 char file[256];
772
773 if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
774 snprintf(mconsole_socket_name, sizeof(file), "%s", file);
775
776 sock = os_create_unix_socket(file, sizeof(file), 1);
777 if (sock < 0){
778 printk("Failed to initialize management console\n");
779 return(1);
780 }
781
782 register_reboot_notifier(&reboot_notifier);
783
784 err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
bd6aa650 785 IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
1da177e4
LT
786 "mconsole", (void *)sock);
787 if (err){
788 printk("Failed to get IRQ for management console\n");
789 return(1);
790 }
791
792 if(notify_socket != NULL){
970d6e3a 793 notify_socket = kstrdup(notify_socket, GFP_KERNEL);
1da177e4
LT
794 if(notify_socket != NULL)
795 mconsole_notify(notify_socket, MCONSOLE_SOCKET,
d50084a2 796 mconsole_socket_name,
1da177e4
LT
797 strlen(mconsole_socket_name) + 1);
798 else printk(KERN_ERR "mconsole_setup failed to strdup "
799 "string\n");
800 }
801
d50084a2 802 printk("mconsole (version %d) initialized on %s\n",
1da177e4
LT
803 MCONSOLE_VERSION, mconsole_socket_name);
804 return(0);
805}
806
807__initcall(mconsole_init);
808
809static int write_proc_mconsole(struct file *file, const char __user *buffer,
810 unsigned long count, void *data)
811{
812 char *buf;
813
814 buf = kmalloc(count + 1, GFP_KERNEL);
d50084a2 815 if(buf == NULL)
1da177e4
LT
816 return(-ENOMEM);
817
818 if(copy_from_user(buf, buffer, count)){
819 count = -EFAULT;
820 goto out;
821 }
822
823 buf[count] = '\0';
824
825 mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
826 out:
827 kfree(buf);
828 return(count);
829}
830
831static int create_proc_mconsole(void)
832{
833 struct proc_dir_entry *ent;
834
835 if(notify_socket == NULL) return(0);
836
837 ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL);
838 if(ent == NULL){
30f417c6 839 printk(KERN_INFO "create_proc_mconsole : create_proc_entry failed\n");
1da177e4
LT
840 return(0);
841 }
842
843 ent->read_proc = NULL;
844 ent->write_proc = write_proc_mconsole;
845 return(0);
846}
847
848static DEFINE_SPINLOCK(notify_spinlock);
849
850void lock_notify(void)
851{
852 spin_lock(&notify_spinlock);
853}
854
855void unlock_notify(void)
856{
857 spin_unlock(&notify_spinlock);
858}
859
860__initcall(create_proc_mconsole);
861
862#define NOTIFY "=notify:"
863
864static int mconsole_setup(char *str)
865{
866 if(!strncmp(str, NOTIFY, strlen(NOTIFY))){
867 str += strlen(NOTIFY);
868 notify_socket = str;
869 }
870 else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str);
871 return(1);
872}
873
874__setup("mconsole", mconsole_setup);
875
876__uml_help(mconsole_setup,
877"mconsole=notify:<socket>\n"
878" Requests that the mconsole driver send a message to the named Unix\n"
879" socket containing the name of the mconsole socket. This also serves\n"
880" to notify outside processes when UML has booted far enough to respond\n"
881" to mconsole requests.\n\n"
882);
883
884static int notify_panic(struct notifier_block *self, unsigned long unused1,
885 void *ptr)
886{
887 char *message = ptr;
888
889 if(notify_socket == NULL) return(0);
890
d50084a2 891 mconsole_notify(notify_socket, MCONSOLE_PANIC, message,
1da177e4
LT
892 strlen(message) + 1);
893 return(0);
894}
895
896static struct notifier_block panic_exit_notifier = {
897 .notifier_call = notify_panic,
898 .next = NULL,
899 .priority = 1
900};
901
902static int add_notifier(void)
903{
e041c683
AS
904 atomic_notifier_chain_register(&panic_notifier_list,
905 &panic_exit_notifier);
1da177e4
LT
906 return(0);
907}
908
909__initcall(add_notifier);
910
911char *mconsole_notify_socket(void)
912{
913 return(notify_socket);
914}
915
916EXPORT_SYMBOL(mconsole_notify_socket);
This page took 0.272876 seconds and 5 git commands to generate.