[parisc-linux-cvs] /proc/sys/kernel/power support
Helge Deller
deller@gmx.de
Tue, 16 Apr 2002 01:39:46 +0200
--------------Boundary-00=_A2VM5F659Q64ZCWCBW98
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 8bit
On Tuesday 16 April 2002 01:40, Helge Deller wrote:
> CVSROOT: /var/cvs
> Module name: linux
> Changes by: deller 02/04/15 17:40:15
>
> Modified files:
> arch/parisc/kernel: lba_pci.c led.c power.c
>
> Log message:
> - allow to enable/disable the soft power switch at runtime
> through the /proc/sys/kernel/power procfs file
> - removed lots of debug code (at ggg's request),
> - added THIS_MODULE to led.c driver for proc entries
--------------Boundary-00=_A2VM5F659Q64ZCWCBW98
Content-Type: text/plain;
charset="iso-8859-1";
name="diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="diff"
Index: lba_pci.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/lba_pci.c,v
retrieving revision 1.52
diff -u -p -r1.52 lba_pci.c
--- lba_pci.c 2002/04/13 22:41:05 1.52
+++ lba_pci.c 2002/04/15 23:37:56
@@ -1237,7 +1237,7 @@ lba_hw_init(struct lba_device *d)
u32 stat;
u32 bus_reset; /* PDC_PAT_BUG */
-#if 1
+#if 0
printk(KERN_DEBUG "LBA %lx STAT_CTL %Lx ERROR_CFG %Lx STATUS %Lx DMA_CTL %Lx\n",
d->hba.base_addr,
READ_REG64(d->hba.base_addr + LBA_STAT_CTL),
Index: led.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/led.c,v
retrieving revision 1.26
diff -u -p -r1.26 led.c
--- led.c 2001/12/26 22:47:34 1.26
+++ led.c 2002/04/15 23:37:57
@@ -3,7 +3,7 @@
*
* (c) Copyright 2000 Red Hat Software
* (c) Copyright 2000 Helge Deller <hdeller@redhat.com>
- * (c) Copyright 2001 Helge Deller <deller@gmx.de>
+ * (c) Copyright 2001-2002 Helge Deller <deller@gmx.de>
* (c) Copyright 2001 Randolph Chung <tausq@debian.org>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,6 +17,7 @@
*/
#include <linux/config.h>
+#include <linux/module.h>
#include <linux/stddef.h> /* for offsetof() */
#include <linux/init.h>
#include <linux/types.h>
@@ -49,7 +50,7 @@ static int led_type = -1;
static int led_heartbeat = 1;
static int led_diskio = 1;
static int led_lanrxtx = 1;
-static char lcd_text[32] = {0};
+static char lcd_text[32];
#if 0
#define DPRINTK(x) printk x
@@ -97,13 +98,13 @@ struct pdc_chassis_lcd_info_ret_block {
static struct pdc_chassis_lcd_info_ret_block
lcd_info __attribute__((aligned(8))) =
{
- model:DISPLAY_MODEL_LCD,
- lcd_width:16,
- lcd_cmd_reg_addr:(char *) KITTYHAWK_LCD_CMD,
+ model: DISPLAY_MODEL_LCD,
+ lcd_width: 16,
+ lcd_cmd_reg_addr: (char *) KITTYHAWK_LCD_CMD,
lcd_data_reg_addr:(char *) KITTYHAWK_LCD_DATA,
- min_cmd_delay:40,
- reset_cmd1:0x80,
- reset_cmd2:0xc0,
+ min_cmd_delay: 40,
+ reset_cmd1: 0x80,
+ reset_cmd2: 0xc0,
};
@@ -227,12 +228,14 @@ static int __init led_create_procfs(void
proc_pdc_root = proc_mkdir("pdc", 0);
if (!proc_pdc_root) return -1;
+ proc_pdc_root->owner = THIS_MODULE;
ent = create_proc_entry("led", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root);
if (!ent) return -1;
ent->nlink = 1;
ent->data = (void *)LED_NOLCD; /* LED */
ent->read_proc = led_proc_read;
ent->write_proc = led_proc_write;
+ ent->owner = THIS_MODULE;
if (led_type == LED_HASLCD)
{
@@ -242,6 +245,7 @@ static int __init led_create_procfs(void
ent->data = (void *)LED_HASLCD; /* LCD */
ent->read_proc = led_proc_read;
ent->write_proc = led_proc_write;
+ ent->owner = THIS_MODULE;
}
return 0;
Index: power.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/power.c,v
retrieving revision 1.6
diff -u -p -r1.6 power.c
--- power.c 2002/04/06 22:14:57 1.6
+++ power.c 2002/04/15 23:37:57
@@ -1,43 +1,46 @@
/*
* linux/arch/parisc/kernel/power.c
- * HP PARISC powerfail and soft power switch support
+ * HP PARISC soft power switch support driver
*
- * Copyright (C) 2001 Helge Deller <deller@gmx.de>
+ * Copyright (C) 2001-2002 Helge Deller <deller@gmx.de>
*
+ *
+ * HINT:
+ * Support of the soft power switch button may be enabled or disabled at
+ * runtime through the "/proc/sys/kernel/power" procfs entry.
+ *
*/
/*
- * Status: EXPERIMENTAL
- *
* TODO:
* - use tasklets instead of calling it from the timer-interrupt function
* - after a special amount of time just turn the machine off (killing init may have failed!)
* - ....
*/
+#include <linux/config.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/reboot.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
#include <asm/gsc.h>
#include <asm/pdc.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/led.h>
+#include <asm/led.h>
+#include <asm/uaccess.h>
-
-/* For kernel debugging purposes it's sometimes better to have
- * the soft-power switch killing the power at once.
- * This may be reached by uncommenting the following line: */
-
-#undef POWERSWITCH_DISABLED
+/* filename in /proc which can be used to enable/disable the power switch */
+#define SYSCTL_FILENAME "sys/kernel/power"
-/* local time-counter for shutdown */
-static int shutdown_timer;
#define DIAG_CODE(code) (0x14000000 + ((code)<<5))
@@ -59,8 +62,6 @@ static int shutdown_timer;
} )
-
-
static void deferred_poweroff(void *dummy)
{
extern int cad_pid; /* kernel/sys.c */
@@ -88,6 +89,10 @@ static void poweroff(void)
schedule_task(&poweroff_tq);
}
+
+/* local time-counter for shutdown */
+static int shutdown_timer;
+
/* check, give feedback and start shutdown after one second */
static void process_shutdown(void)
{
@@ -108,6 +113,13 @@ static void process_shutdown(void)
}
+/* soft power switch enabled/disabled */
+#ifdef CONFIG_PROC_FS
+static int pwrsw_enabled = 1;
+#else
+#define pwrsw_enabled (0)
+#endif
+
/* soft power switch function ptr */
void (*check_soft_power)(void);
@@ -120,6 +132,9 @@ void (*check_soft_power)(void);
*/
static void check_soft_power_gecko(void)
{
+ if (!pwrsw_enabled)
+ return;
+
if (__getDIAG(25) & 0x80000000) {
/* power switch button not pressed or released again */
shutdown_timer = 0;
@@ -140,6 +155,9 @@ static unsigned long soft_power_reg;
static void check_soft_power_polling(void)
{
unsigned long current_status;
+
+ if (!pwrsw_enabled)
+ return;
current_status = gsc_readl(soft_power_reg);
if (current_status & 0x1) {
@@ -164,6 +182,91 @@ static void powerfail_interrupt(int code
+
+/*
+ * /proc filesystem support
+ */
+#ifdef CONFIG_SYSCTL
+static int power_proc_read(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ char *out = page;
+ int len;
+
+ out += sprintf(out, "Software power switch support: ");
+ out += sprintf(out, pwrsw_enabled ? "enabled (1)" : "disabled (0)" );
+ out += sprintf(out, "\n");
+
+ len = out - page - off;
+ if (len < count) {
+ *eof = 1;
+ if (len <= 0) return 0;
+ } else {
+ len = count;
+ }
+ *start = page + off;
+ return len;
+}
+
+static int power_proc_write(struct file *file, const char *buf,
+ unsigned long count, void *data)
+{
+ char *cur, lbuf[count];
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ memset(lbuf, 0, count);
+
+ copy_from_user(lbuf, buf, count);
+ cur = lbuf;
+
+ /* skip initial spaces */
+ while (*cur && isspace(*cur))
+ cur++;
+
+ switch (*cur) {
+ case '0': pwrsw_enabled = 0;
+ break;
+ case '1': pwrsw_enabled = 1;
+ break;
+ default: printk(KERN_CRIT "/proc/" SYSCTL_FILENAME
+ ": Parse error: only '0' or '1' allowed!\n");
+ return -EINVAL;
+ } /* switch() */
+
+ return count;
+}
+
+static struct proc_dir_entry *ent;
+
+static void __init power_create_procfs(void)
+{
+ if (!check_soft_power)
+ return;
+
+ ent = create_proc_entry(SYSCTL_FILENAME, S_IFREG|S_IRUGO|S_IWUSR, 0);
+ if (!ent) return;
+
+ ent->nlink = 1;
+ ent->read_proc = power_proc_read;
+ ent->write_proc = power_proc_write;
+ ent->owner = THIS_MODULE;
+}
+
+static void __exit power_remove_procfs(void)
+{
+ remove_proc_entry(SYSCTL_FILENAME, NULL);
+}
+
+#else
+#define power_create_procfs() do { } while (0)
+#define power_remove_procfs() do { } while (0)
+#endif /* CONFIG_SYSCTL */
+
+
+
+
static int __init power_init(void)
{
unsigned long ret;
@@ -173,29 +276,43 @@ static int __init power_init(void)
0, "powerfail", NULL);
#endif
-#if !defined(POWERSWITCH_DISABLED)
/* enable the soft power switch if possible */
ret = pdc_soft_power_info(&soft_power_reg);
if (ret == PDC_OK)
ret = pdc_soft_power_button(1);
if (ret != PDC_OK)
- return 0;
+ soft_power_reg = (unsigned long) -1;
switch ((long) soft_power_reg) {
- case 0: printk(KERN_INFO "Enabled gecko-style soft power switch.\n");
+ case 0: printk(KERN_INFO "Gecko-style soft power switch enabled.\n");
check_soft_power = check_soft_power_gecko;
break;
- case -1: printk(KERN_INFO "No soft power switch support.\n");
- break;
+ case -1: printk(KERN_INFO "Soft power switch support not available.\n");
+ return -ENODEV;
- default: printk(KERN_INFO "Enabled soft power switch (polling mode, io=0x%08lx).\n",
+ default: printk(KERN_INFO "Soft power switch enabled, polling @ 0x%08lx.\n",
soft_power_reg);
check_soft_power = check_soft_power_polling;
}
-#endif
+
+ power_create_procfs();
+
return 0;
}
+static void __exit power_exit(void)
+{
+ power_remove_procfs();
+ check_soft_power = NULL;
+}
+
module_init(power_init);
+module_exit(power_exit);
+
+MODULE_AUTHOR("Helge Deller");
+MODULE_DESCRIPTION("Soft power switch driver");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
--------------Boundary-00=_A2VM5F659Q64ZCWCBW98--