File: /usr/src/linux/arch/sparc64/kernel/power.c

1     /* $Id: power.c,v 1.9 2001/06/08 02:28:22 davem Exp $
2      * power.c: Power management driver.
3      *
4      * Copyright (C) 1999 David S. Miller (davem@redhat.com)
5      */
6     
7     #include <linux/config.h>
8     #include <linux/kernel.h>
9     #include <linux/init.h>
10     #include <linux/sched.h>
11     #include <linux/signal.h>
12     #include <linux/delay.h>
13     
14     #include <asm/ebus.h>
15     
16     #define __KERNEL_SYSCALLS__
17     #include <linux/unistd.h>
18     
19     #ifdef CONFIG_PCI
20     static unsigned long power_reg = 0UL;
21     #define POWER_SYSTEM_OFF (1 << 0)
22     #define POWER_COURTESY_OFF (1 << 1)
23     
24     static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
25     static int button_pressed = 0;
26     
27     static void power_handler(int irq, void *dev_id, struct pt_regs *regs)
28     {
29     	if (button_pressed == 0) {
30     		wake_up(&powerd_wait);
31     		button_pressed = 1;
32     	}
33     }
34     #endif /* CONFIG_PCI */
35     
36     extern void machine_halt(void);
37     
38     extern int serial_console;
39     
40     void machine_power_off(void)
41     {
42     #ifdef CONFIG_PCI
43     	if (power_reg != 0UL && !serial_console) {
44     		/* Both register bits seem to have the
45     		 * same effect, so until I figure out
46     		 * what the difference is...
47     		 */
48     		writel(POWER_COURTESY_OFF | POWER_SYSTEM_OFF, power_reg);
49     	}
50     #endif /* CONFIG_PCI */
51     	machine_halt();
52     }
53     
54     #ifdef CONFIG_PCI
55     static int powerd(void *__unused)
56     {
57     	static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
58     	char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
59     
60     	daemonize();
61     	sprintf(current->comm, "powerd");
62     
63     again:
64     	while(button_pressed == 0) {
65     		spin_lock_irq(&current->sigmask_lock);
66     		flush_signals(current);
67     		spin_unlock_irq(&current->sigmask_lock);
68     		interruptible_sleep_on(&powerd_wait);
69     	}
70     
71     	/* Ok, down we go... */
72     	if (execve("/sbin/shutdown", argv, envp) < 0) {
73     		printk("powerd: shutdown execution failed\n");
74     		button_pressed = 0;
75     		goto again;
76     	}
77     	return 0;
78     }
79     
80     void __init power_init(void)
81     {
82     	struct linux_ebus *ebus;
83     	struct linux_ebus_device *edev;
84     	static int invoked = 0;
85     
86     	if (invoked)
87     		return;
88     	invoked = 1;
89     
90     	for_each_ebus(ebus) {
91     		for_each_ebusdev(edev, ebus) {
92     			if (!strcmp(edev->prom_name, "power"))
93     				goto found;
94     		}
95     	}
96     	return;
97     
98     found:
99     	power_reg = (unsigned long)ioremap(edev->resource[0].start, 0x4);
100     	printk("power: Control reg at %016lx ... ", power_reg);
101     	if (kernel_thread(powerd, 0, CLONE_FS) < 0) {
102     		printk("Failed to start power daemon.\n");
103     		return;
104     	}
105     	printk("powerd running.\n");
106     	if (edev->irqs[0] != 0) {
107     		if (request_irq(edev->irqs[0],
108     				power_handler, SA_SHIRQ, "power",
109     				(void *) power_reg) < 0)
110     			printk("power: Error, cannot register IRQ handler.\n");
111     	}
112     }
113     #endif /* CONFIG_PCI */
114