1/* $Id: power.c,v 1.1.1.1 2008/10/15 03:26:19 james26_jang 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 20static unsigned long power_reg = 0UL; 21#define POWER_SYSTEM_OFF (1 << 0) 22#define POWER_COURTESY_OFF (1 << 1) 23 24static DECLARE_WAIT_QUEUE_HEAD(powerd_wait); 25static int button_pressed; 26 27static 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 36extern void machine_halt(void); 37extern void machine_alt_power_off(void); 38static void (*poweroff_method)(void) = machine_alt_power_off; 39 40extern int serial_console; 41 42void machine_power_off(void) 43{ 44 if (!serial_console) { 45#ifdef CONFIG_PCI 46 if (power_reg != 0UL) { 47 /* Both register bits seem to have the 48 * same effect, so until I figure out 49 * what the difference is... 50 */ 51 writel(POWER_COURTESY_OFF | POWER_SYSTEM_OFF, power_reg); 52 } else 53#endif /* CONFIG_PCI */ 54 if (poweroff_method != NULL) { 55 poweroff_method(); 56 /* not reached */ 57 } 58 } 59 machine_halt(); 60} 61 62#ifdef CONFIG_PCI 63static int powerd(void *__unused) 64{ 65 static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; 66 char *argv[] = { "/sbin/shutdown", "-h", "now", NULL }; 67 68 daemonize(); 69 sprintf(current->comm, "powerd"); 70 71again: 72 while (button_pressed == 0) { 73 spin_lock_irq(¤t->sigmask_lock); 74 flush_signals(current); 75 spin_unlock_irq(¤t->sigmask_lock); 76 interruptible_sleep_on(&powerd_wait); 77 } 78 79 /* Ok, down we go... */ 80 if (execve("/sbin/shutdown", argv, envp) < 0) { 81 printk("powerd: shutdown execution failed\n"); 82 button_pressed = 0; 83 goto again; 84 } 85 return 0; 86} 87 88void __init power_init(void) 89{ 90 struct linux_ebus *ebus; 91 struct linux_ebus_device *edev; 92 static int invoked; 93 94 if (invoked) 95 return; 96 invoked = 1; 97 98 for_each_ebus(ebus) { 99 for_each_ebusdev(edev, ebus) { 100 if (!strcmp(edev->prom_name, "power")) 101 goto found; 102 } 103 } 104 return; 105 106found: 107 power_reg = (unsigned long)ioremap(edev->resource[0].start, 0x4); 108 printk("power: Control reg at %016lx ... ", power_reg); 109 poweroff_method = machine_halt; /* able to use the standard poweroff */ 110 if (edev->irqs[0] != PCI_IRQ_NONE) { 111 if (kernel_thread(powerd, 0, CLONE_FS) < 0) { 112 printk("Failed to start power daemon.\n"); 113 return; 114 } 115 printk("powerd running.\n"); 116 117 if (request_irq(edev->irqs[0], 118 power_handler, SA_SHIRQ, "power", 119 (void *) power_reg) < 0) 120 printk("power: Error, cannot register IRQ handler.\n"); 121 } else { 122 printk("not using powerd.\n"); 123 } 124} 125#endif /* CONFIG_PCI */ 126