⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 power.c

📁 该文件是rt_linux
💻 C
字号:
/* * linux/arch/parisc/kernel/power.c * HP PARISC soft power switch support driver * * Copyright (c) 2001-2002 Helge Deller <deller@gmx.de> * All rights reserved. * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions, and the following disclaimer, *    without modification. * 2. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL"). * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * * *  *  HINT: *  Support of the soft power switch button may be enabled or disabled at *  runtime through the "/proc/sys/kernel/power" procfs entry. */ #include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/notifier.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>#ifdef DEBUG# define DPRINTK(x) printk x#else# define DPRINTK(x) do { } while (0)#endif/* filename in /proc which can be used to enable/disable the power switch */#define SYSCTL_FILENAME		"sys/kernel/power"#define DIAG_CODE(code)		(0x14000000 + ((code)<<5))/* this will go to processor.h or any other place... *//* taken from PCXL ERS page 82 */#define MFCPU_X(rDiagReg, t_ch, t_th, code) \	(DIAG_CODE(code) + ((rDiagReg)<<21) + ((t_ch)<<16) + ((t_th)<<0) )	#define MTCPU(dr, gr)		MFCPU_X(dr, gr,  0, 0x12)       /* move value of gr to dr[dr] */#define MFCPU_C(dr, gr)		MFCPU_X(dr, gr,  0, 0x30)	/* for dr0 and dr8 only ! */#define MFCPU_T(dr, gr)		MFCPU_X(dr,  0, gr, 0xa0)	/* all dr except dr0 and dr8 */	#define __getDIAG(dr) ( { 			\        register unsigned long __res asm("r28");\	 __asm__ __volatile__ (			\		".word %1\n nop\n" : "=&r" (__res) : "i" (MFCPU_T(dr,28)) \	);					\	__res;					\} )static void deferred_poweroff(void *dummy){	extern int cad_pid;	/* from kernel/sys.c */	if (kill_proc(cad_pid, SIGINT, 1)) {		/* just in case killing init process failed */		machine_power_off();	}}/* * This function gets called from interrupt context. * As it's called within an interrupt, it wouldn't sync if we don't * use schedule_task(). */static void poweroff(void){	static int powering_off;	static struct tq_struct poweroff_tq = {		routine: deferred_poweroff,	};	if (powering_off)		return;	powering_off++;	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){	if (shutdown_timer == 0)		DPRINTK((KERN_INFO "Shutdown requested...\n"));	shutdown_timer++;		/* wait until the button was pressed for 1 second */	if (shutdown_timer == HZ) {		static char msg[] = "Shutting down...";		DPRINTK((KERN_INFO "%s\n", msg));#ifdef CONFIG_CHASSIS_LCD_LED		lcd_print(msg);#endif		poweroff();	}}/* main power switch tasklet struct (scheduled from time.c) */DECLARE_TASKLET_DISABLED(power_tasklet, NULL, 0);/* soft power switch enabled/disabled */#ifdef CONFIG_PROC_FSstatic int pwrsw_enabled = 1;#else#define pwrsw_enabled (1)#endif/* * On gecko style machines (e.g. 712/xx and 715/xx)  * the power switch status is stored in Bit 0 ("the highest bit") * of CPU diagnose register 25. *  */static void gecko_tasklet_func(unsigned long unused){	if (!pwrsw_enabled)		return;	if (__getDIAG(25) & 0x80000000) {		/* power switch button not pressed or released again */		/* Warning: Some machines do never reset this DIAG flag! */		shutdown_timer = 0;	} else {		process_shutdown();	}}/* * Check the power switch status which is read from the * real I/O location at soft_power_reg. * Bit 31 ("the lowest bit) is the status of the power switch. */static void polling_tasklet_func(unsigned long soft_power_reg){        unsigned long current_status;		if (!pwrsw_enabled)		return;	current_status = gsc_readl(soft_power_reg);	if (current_status & 0x1) {		/* power switch button not pressed */		shutdown_timer = 0;	} else {		process_shutdown();	}}/* * powerfail interruption handler (irq IRQ_FROM_REGION(CPU_IRQ_REGION)+2)  */#if 0static void powerfail_interrupt(int code, void *x, struct pt_regs *regs){	printk(KERN_CRIT "POWERFAIL INTERRUPTION !\n");	poweroff();}#endif/*  * /proc filesystem support  */#ifdef CONFIG_SYSCTLstatic 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 (!power_tasklet.func)		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 *//* parisc_panic_event() is called by the panic handler. * As soon as a panic occurs, our tasklets above will not be * executed any longer. This function then re-enables the  * soft-power switch and allows the user to switch off the system */static int parisc_panic_event(struct notifier_block *this,		unsigned long event, void *ptr){	/* re-enable the soft-power switch */	pdc_soft_power_button(0);	return NOTIFY_DONE;}static struct notifier_block parisc_panic_block = {	notifier_call: parisc_panic_event,	priority: INT_MAX,};static int __init power_init(void){	unsigned long ret;	unsigned long soft_power_reg = 0;#if 0	request_irq( IRQ_FROM_REGION(CPU_IRQ_REGION)+2, &powerfail_interrupt,		0, "powerfail", NULL);#endif	/* 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)		soft_power_reg = -1UL;		switch (soft_power_reg) {	case 0:		printk(KERN_INFO "Gecko-style soft power switch enabled.\n");			power_tasklet.func = gecko_tasklet_func;			break;				case -1UL:	printk(KERN_INFO "Soft power switch support not available.\n");			return -ENODEV;		default:	printk(KERN_INFO "Soft power switch enabled, polling @ 0x%08lx.\n",				soft_power_reg);			power_tasklet.data = soft_power_reg;			power_tasklet.func = polling_tasklet_func;	}	/* Register a call for panic conditions. */	notifier_chain_register(&panic_notifier_list, &parisc_panic_block);	power_create_procfs();	tasklet_enable(&power_tasklet);	return 0;}static void __exit power_exit(void){	if (!power_tasklet.func)		return;	tasklet_disable(&power_tasklet);	notifier_chain_unregister(&panic_notifier_list, &parisc_panic_block);	power_remove_procfs();	power_tasklet.func = NULL;	pdc_soft_power_button(0);}module_init(power_init);module_exit(power_exit);MODULE_AUTHOR("Helge Deller");MODULE_DESCRIPTION("Soft power switch driver");MODULE_LICENSE("Dual BSD/GPL");EXPORT_NO_SYMBOLS;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -