[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--