xref: /openbmc/linux/arch/powerpc/kernel/rtas-proc.c (revision 08273c9f)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2f4fcbbe9SPaul Mackerras /*
3f4fcbbe9SPaul Mackerras  *   Copyright (C) 2000 Tilmann Bitterberg
4f4fcbbe9SPaul Mackerras  *   (tilmann@bitterberg.de)
5f4fcbbe9SPaul Mackerras  *
6f4fcbbe9SPaul Mackerras  *   RTAS (Runtime Abstraction Services) stuff
7f4fcbbe9SPaul Mackerras  *   Intention is to provide a clean user interface
8f4fcbbe9SPaul Mackerras  *   to use the RTAS.
9f4fcbbe9SPaul Mackerras  *
10f4fcbbe9SPaul Mackerras  *   TODO:
11f4fcbbe9SPaul Mackerras  *   Split off a header file and maybe move it to a different
12f4fcbbe9SPaul Mackerras  *   location. Write Documentation on what the /proc/rtas/ entries
13f4fcbbe9SPaul Mackerras  *   actually do.
14f4fcbbe9SPaul Mackerras  */
15f4fcbbe9SPaul Mackerras 
16f4fcbbe9SPaul Mackerras #include <linux/errno.h>
17f4fcbbe9SPaul Mackerras #include <linux/sched.h>
18f4fcbbe9SPaul Mackerras #include <linux/proc_fs.h>
19f4fcbbe9SPaul Mackerras #include <linux/stat.h>
20f4fcbbe9SPaul Mackerras #include <linux/ctype.h>
21f4fcbbe9SPaul Mackerras #include <linux/time.h>
22f4fcbbe9SPaul Mackerras #include <linux/string.h>
23f4fcbbe9SPaul Mackerras #include <linux/init.h>
24f4fcbbe9SPaul Mackerras #include <linux/seq_file.h>
25f4fcbbe9SPaul Mackerras #include <linux/bitops.h>
26f4fcbbe9SPaul Mackerras #include <linux/rtc.h>
27e6f6390aSChristophe Leroy #include <linux/of.h>
28f4fcbbe9SPaul Mackerras 
297c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
30f4fcbbe9SPaul Mackerras #include <asm/processor.h>
31f4fcbbe9SPaul Mackerras #include <asm/io.h>
32f4fcbbe9SPaul Mackerras #include <asm/rtas.h>
33f4fcbbe9SPaul Mackerras #include <asm/machdep.h> /* for ppc_md */
34f4fcbbe9SPaul Mackerras #include <asm/time.h>
35f4fcbbe9SPaul Mackerras 
36f4fcbbe9SPaul Mackerras /* Token for Sensors */
37f4fcbbe9SPaul Mackerras #define KEY_SWITCH		0x0001
38f4fcbbe9SPaul Mackerras #define ENCLOSURE_SWITCH	0x0002
39f4fcbbe9SPaul Mackerras #define THERMAL_SENSOR		0x0003
40f4fcbbe9SPaul Mackerras #define LID_STATUS		0x0004
41f4fcbbe9SPaul Mackerras #define POWER_SOURCE		0x0005
42f4fcbbe9SPaul Mackerras #define BATTERY_VOLTAGE		0x0006
43f4fcbbe9SPaul Mackerras #define BATTERY_REMAINING	0x0007
44f4fcbbe9SPaul Mackerras #define BATTERY_PERCENTAGE	0x0008
45f4fcbbe9SPaul Mackerras #define EPOW_SENSOR		0x0009
46f4fcbbe9SPaul Mackerras #define BATTERY_CYCLESTATE	0x000a
47f4fcbbe9SPaul Mackerras #define BATTERY_CHARGING	0x000b
48f4fcbbe9SPaul Mackerras 
49f4fcbbe9SPaul Mackerras /* IBM specific sensors */
50f4fcbbe9SPaul Mackerras #define IBM_SURVEILLANCE	0x2328 /* 9000 */
51f4fcbbe9SPaul Mackerras #define IBM_FANRPM		0x2329 /* 9001 */
52f4fcbbe9SPaul Mackerras #define IBM_VOLTAGE		0x232a /* 9002 */
53f4fcbbe9SPaul Mackerras #define IBM_DRCONNECTOR		0x232b /* 9003 */
54f4fcbbe9SPaul Mackerras #define IBM_POWERSUPPLY		0x232c /* 9004 */
55f4fcbbe9SPaul Mackerras 
56f4fcbbe9SPaul Mackerras /* Status return values */
57f4fcbbe9SPaul Mackerras #define SENSOR_CRITICAL_HIGH	13
58f4fcbbe9SPaul Mackerras #define SENSOR_WARNING_HIGH	12
59f4fcbbe9SPaul Mackerras #define SENSOR_NORMAL		11
60f4fcbbe9SPaul Mackerras #define SENSOR_WARNING_LOW	10
61f4fcbbe9SPaul Mackerras #define SENSOR_CRITICAL_LOW	 9
62f4fcbbe9SPaul Mackerras #define SENSOR_SUCCESS		 0
63f4fcbbe9SPaul Mackerras #define SENSOR_HW_ERROR		-1
64f4fcbbe9SPaul Mackerras #define SENSOR_BUSY		-2
65f4fcbbe9SPaul Mackerras #define SENSOR_NOT_EXIST	-3
66f4fcbbe9SPaul Mackerras #define SENSOR_DR_ENTITY	-9000
67f4fcbbe9SPaul Mackerras 
68f4fcbbe9SPaul Mackerras /* Location Codes */
69f4fcbbe9SPaul Mackerras #define LOC_SCSI_DEV_ADDR	'A'
70f4fcbbe9SPaul Mackerras #define LOC_SCSI_DEV_LOC	'B'
71f4fcbbe9SPaul Mackerras #define LOC_CPU			'C'
72f4fcbbe9SPaul Mackerras #define LOC_DISKETTE		'D'
73f4fcbbe9SPaul Mackerras #define LOC_ETHERNET		'E'
74f4fcbbe9SPaul Mackerras #define LOC_FAN			'F'
75f4fcbbe9SPaul Mackerras #define LOC_GRAPHICS		'G'
76f4fcbbe9SPaul Mackerras /* reserved / not used		'H' */
77f4fcbbe9SPaul Mackerras #define LOC_IO_ADAPTER		'I'
78f4fcbbe9SPaul Mackerras /* reserved / not used		'J' */
79f4fcbbe9SPaul Mackerras #define LOC_KEYBOARD		'K'
80f4fcbbe9SPaul Mackerras #define LOC_LCD			'L'
81f4fcbbe9SPaul Mackerras #define LOC_MEMORY		'M'
82f4fcbbe9SPaul Mackerras #define LOC_NV_MEMORY		'N'
83f4fcbbe9SPaul Mackerras #define LOC_MOUSE		'O'
84f4fcbbe9SPaul Mackerras #define LOC_PLANAR		'P'
85f4fcbbe9SPaul Mackerras #define LOC_OTHER_IO		'Q'
86f4fcbbe9SPaul Mackerras #define LOC_PARALLEL		'R'
87f4fcbbe9SPaul Mackerras #define LOC_SERIAL		'S'
88f4fcbbe9SPaul Mackerras #define LOC_DEAD_RING		'T'
89f4fcbbe9SPaul Mackerras #define LOC_RACKMOUNTED		'U' /* for _u_nit is rack mounted */
90f4fcbbe9SPaul Mackerras #define LOC_VOLTAGE		'V'
91f4fcbbe9SPaul Mackerras #define LOC_SWITCH_ADAPTER	'W'
92f4fcbbe9SPaul Mackerras #define LOC_OTHER		'X'
93f4fcbbe9SPaul Mackerras #define LOC_FIRMWARE		'Y'
94f4fcbbe9SPaul Mackerras #define LOC_SCSI		'Z'
95f4fcbbe9SPaul Mackerras 
96f4fcbbe9SPaul Mackerras /* Tokens for indicators */
97f4fcbbe9SPaul Mackerras #define TONE_FREQUENCY		0x0001 /* 0 - 1000 (HZ)*/
98f4fcbbe9SPaul Mackerras #define TONE_VOLUME		0x0002 /* 0 - 100 (%) */
99f4fcbbe9SPaul Mackerras #define SYSTEM_POWER_STATE	0x0003
100f4fcbbe9SPaul Mackerras #define WARNING_LIGHT		0x0004
101f4fcbbe9SPaul Mackerras #define DISK_ACTIVITY_LIGHT	0x0005
102f4fcbbe9SPaul Mackerras #define HEX_DISPLAY_UNIT	0x0006
103f4fcbbe9SPaul Mackerras #define BATTERY_WARNING_TIME	0x0007
104f4fcbbe9SPaul Mackerras #define CONDITION_CYCLE_REQUEST	0x0008
105f4fcbbe9SPaul Mackerras #define SURVEILLANCE_INDICATOR	0x2328 /* 9000 */
106f4fcbbe9SPaul Mackerras #define DR_ACTION		0x2329 /* 9001 */
107f4fcbbe9SPaul Mackerras #define DR_INDICATOR		0x232a /* 9002 */
108f4fcbbe9SPaul Mackerras /* 9003 - 9004: Vendor specific */
109f4fcbbe9SPaul Mackerras /* 9006 - 9999: Vendor specific */
110f4fcbbe9SPaul Mackerras 
111f4fcbbe9SPaul Mackerras /* other */
112f4fcbbe9SPaul Mackerras #define MAX_SENSORS		 17  /* I only know of 17 sensors */
113f4fcbbe9SPaul Mackerras #define MAX_LINELENGTH          256
114f4fcbbe9SPaul Mackerras #define SENSOR_PREFIX		"ibm,sensor-"
115f4fcbbe9SPaul Mackerras #define cel_to_fahr(x)		((x*9/5)+32)
116f4fcbbe9SPaul Mackerras 
117f4fcbbe9SPaul Mackerras struct individual_sensor {
118f4fcbbe9SPaul Mackerras 	unsigned int token;
119f4fcbbe9SPaul Mackerras 	unsigned int quant;
120f4fcbbe9SPaul Mackerras };
121f4fcbbe9SPaul Mackerras 
122f4fcbbe9SPaul Mackerras struct rtas_sensors {
123f4fcbbe9SPaul Mackerras         struct individual_sensor sensor[MAX_SENSORS];
124f4fcbbe9SPaul Mackerras 	unsigned int quant;
125f4fcbbe9SPaul Mackerras };
126f4fcbbe9SPaul Mackerras 
127ecaf5fa0SAnton Blanchard /* Globals */
128ecaf5fa0SAnton Blanchard static struct rtas_sensors sensors;
129ecaf5fa0SAnton Blanchard static struct device_node *rtas_node = NULL;
130ecaf5fa0SAnton Blanchard static unsigned long power_on_time = 0; /* Save the time the user set */
131ecaf5fa0SAnton Blanchard static char progress_led[MAX_LINELENGTH];
132ecaf5fa0SAnton Blanchard 
133ecaf5fa0SAnton Blanchard static unsigned long rtas_tone_frequency = 1000;
134ecaf5fa0SAnton Blanchard static unsigned long rtas_tone_volume = 0;
135ecaf5fa0SAnton Blanchard 
136f4fcbbe9SPaul Mackerras /* ****************************************************************** */
137f4fcbbe9SPaul Mackerras /* Declarations */
138f4fcbbe9SPaul Mackerras static int ppc_rtas_sensors_show(struct seq_file *m, void *v);
139f4fcbbe9SPaul Mackerras static int ppc_rtas_clock_show(struct seq_file *m, void *v);
140f4fcbbe9SPaul Mackerras static ssize_t ppc_rtas_clock_write(struct file *file,
141f4fcbbe9SPaul Mackerras 		const char __user *buf, size_t count, loff_t *ppos);
142f4fcbbe9SPaul Mackerras static int ppc_rtas_progress_show(struct seq_file *m, void *v);
143f4fcbbe9SPaul Mackerras static ssize_t ppc_rtas_progress_write(struct file *file,
144f4fcbbe9SPaul Mackerras 		const char __user *buf, size_t count, loff_t *ppos);
145f4fcbbe9SPaul Mackerras static int ppc_rtas_poweron_show(struct seq_file *m, void *v);
146f4fcbbe9SPaul Mackerras static ssize_t ppc_rtas_poweron_write(struct file *file,
147f4fcbbe9SPaul Mackerras 		const char __user *buf, size_t count, loff_t *ppos);
148f4fcbbe9SPaul Mackerras 
149f4fcbbe9SPaul Mackerras static ssize_t ppc_rtas_tone_freq_write(struct file *file,
150f4fcbbe9SPaul Mackerras 		const char __user *buf, size_t count, loff_t *ppos);
151f4fcbbe9SPaul Mackerras static int ppc_rtas_tone_freq_show(struct seq_file *m, void *v);
152f4fcbbe9SPaul Mackerras static ssize_t ppc_rtas_tone_volume_write(struct file *file,
153f4fcbbe9SPaul Mackerras 		const char __user *buf, size_t count, loff_t *ppos);
154f4fcbbe9SPaul Mackerras static int ppc_rtas_tone_volume_show(struct seq_file *m, void *v);
155f4fcbbe9SPaul Mackerras static int ppc_rtas_rmo_buf_show(struct seq_file *m, void *v);
156f4fcbbe9SPaul Mackerras 
poweron_open(struct inode * inode,struct file * file)157f4fcbbe9SPaul Mackerras static int poweron_open(struct inode *inode, struct file *file)
158f4fcbbe9SPaul Mackerras {
159f4fcbbe9SPaul Mackerras 	return single_open(file, ppc_rtas_poweron_show, NULL);
160f4fcbbe9SPaul Mackerras }
161f4fcbbe9SPaul Mackerras 
16297a32539SAlexey Dobriyan static const struct proc_ops ppc_rtas_poweron_proc_ops = {
16397a32539SAlexey Dobriyan 	.proc_open	= poweron_open,
16497a32539SAlexey Dobriyan 	.proc_read	= seq_read,
16597a32539SAlexey Dobriyan 	.proc_lseek	= seq_lseek,
16697a32539SAlexey Dobriyan 	.proc_write	= ppc_rtas_poweron_write,
16797a32539SAlexey Dobriyan 	.proc_release	= single_release,
168f4fcbbe9SPaul Mackerras };
169f4fcbbe9SPaul Mackerras 
progress_open(struct inode * inode,struct file * file)170f4fcbbe9SPaul Mackerras static int progress_open(struct inode *inode, struct file *file)
171f4fcbbe9SPaul Mackerras {
172f4fcbbe9SPaul Mackerras 	return single_open(file, ppc_rtas_progress_show, NULL);
173f4fcbbe9SPaul Mackerras }
174f4fcbbe9SPaul Mackerras 
17597a32539SAlexey Dobriyan static const struct proc_ops ppc_rtas_progress_proc_ops = {
17697a32539SAlexey Dobriyan 	.proc_open	= progress_open,
17797a32539SAlexey Dobriyan 	.proc_read	= seq_read,
17897a32539SAlexey Dobriyan 	.proc_lseek	= seq_lseek,
17997a32539SAlexey Dobriyan 	.proc_write	= ppc_rtas_progress_write,
18097a32539SAlexey Dobriyan 	.proc_release	= single_release,
181f4fcbbe9SPaul Mackerras };
182f4fcbbe9SPaul Mackerras 
clock_open(struct inode * inode,struct file * file)183f4fcbbe9SPaul Mackerras static int clock_open(struct inode *inode, struct file *file)
184f4fcbbe9SPaul Mackerras {
185f4fcbbe9SPaul Mackerras 	return single_open(file, ppc_rtas_clock_show, NULL);
186f4fcbbe9SPaul Mackerras }
187f4fcbbe9SPaul Mackerras 
18897a32539SAlexey Dobriyan static const struct proc_ops ppc_rtas_clock_proc_ops = {
18997a32539SAlexey Dobriyan 	.proc_open	= clock_open,
19097a32539SAlexey Dobriyan 	.proc_read	= seq_read,
19197a32539SAlexey Dobriyan 	.proc_lseek	= seq_lseek,
19297a32539SAlexey Dobriyan 	.proc_write	= ppc_rtas_clock_write,
19397a32539SAlexey Dobriyan 	.proc_release	= single_release,
194f4fcbbe9SPaul Mackerras };
195f4fcbbe9SPaul Mackerras 
tone_freq_open(struct inode * inode,struct file * file)196f4fcbbe9SPaul Mackerras static int tone_freq_open(struct inode *inode, struct file *file)
197f4fcbbe9SPaul Mackerras {
198f4fcbbe9SPaul Mackerras 	return single_open(file, ppc_rtas_tone_freq_show, NULL);
199f4fcbbe9SPaul Mackerras }
200f4fcbbe9SPaul Mackerras 
20197a32539SAlexey Dobriyan static const struct proc_ops ppc_rtas_tone_freq_proc_ops = {
20297a32539SAlexey Dobriyan 	.proc_open	= tone_freq_open,
20397a32539SAlexey Dobriyan 	.proc_read	= seq_read,
20497a32539SAlexey Dobriyan 	.proc_lseek	= seq_lseek,
20597a32539SAlexey Dobriyan 	.proc_write	= ppc_rtas_tone_freq_write,
20697a32539SAlexey Dobriyan 	.proc_release	= single_release,
207f4fcbbe9SPaul Mackerras };
208f4fcbbe9SPaul Mackerras 
tone_volume_open(struct inode * inode,struct file * file)209f4fcbbe9SPaul Mackerras static int tone_volume_open(struct inode *inode, struct file *file)
210f4fcbbe9SPaul Mackerras {
211f4fcbbe9SPaul Mackerras 	return single_open(file, ppc_rtas_tone_volume_show, NULL);
212f4fcbbe9SPaul Mackerras }
213f4fcbbe9SPaul Mackerras 
21497a32539SAlexey Dobriyan static const struct proc_ops ppc_rtas_tone_volume_proc_ops = {
21597a32539SAlexey Dobriyan 	.proc_open	= tone_volume_open,
21697a32539SAlexey Dobriyan 	.proc_read	= seq_read,
21797a32539SAlexey Dobriyan 	.proc_lseek	= seq_lseek,
21897a32539SAlexey Dobriyan 	.proc_write	= ppc_rtas_tone_volume_write,
21997a32539SAlexey Dobriyan 	.proc_release	= single_release,
220f4fcbbe9SPaul Mackerras };
221f4fcbbe9SPaul Mackerras 
222f4fcbbe9SPaul Mackerras static int ppc_rtas_find_all_sensors(void);
223f4fcbbe9SPaul Mackerras static void ppc_rtas_process_sensor(struct seq_file *m,
224a7f67bdfSJeremy Kerr 	struct individual_sensor *s, int state, int error, const char *loc);
225f4fcbbe9SPaul Mackerras static char *ppc_rtas_process_error(int error);
226f4fcbbe9SPaul Mackerras static void get_location_code(struct seq_file *m,
227a7f67bdfSJeremy Kerr 	struct individual_sensor *s, const char *loc);
228a7f67bdfSJeremy Kerr static void check_location_string(struct seq_file *m, const char *c);
229a7f67bdfSJeremy Kerr static void check_location(struct seq_file *m, const char *c);
230f4fcbbe9SPaul Mackerras 
proc_rtas_init(void)231f4fcbbe9SPaul Mackerras static int __init proc_rtas_init(void)
232f4fcbbe9SPaul Mackerras {
233e8222502SBenjamin Herrenschmidt 	if (!machine_is(pseries))
23449c28e4eSAnton Blanchard 		return -ENODEV;
235f4fcbbe9SPaul Mackerras 
236f4fcbbe9SPaul Mackerras 	rtas_node = of_find_node_by_name(NULL, "rtas");
237f4fcbbe9SPaul Mackerras 	if (rtas_node == NULL)
23849c28e4eSAnton Blanchard 		return -ENODEV;
239f4fcbbe9SPaul Mackerras 
24057ad583fSRussell Currey 	proc_create("powerpc/rtas/progress", 0644, NULL,
24197a32539SAlexey Dobriyan 		    &ppc_rtas_progress_proc_ops);
24257ad583fSRussell Currey 	proc_create("powerpc/rtas/clock", 0644, NULL,
24397a32539SAlexey Dobriyan 		    &ppc_rtas_clock_proc_ops);
24457ad583fSRussell Currey 	proc_create("powerpc/rtas/poweron", 0644, NULL,
24597a32539SAlexey Dobriyan 		    &ppc_rtas_poweron_proc_ops);
2463f3942acSChristoph Hellwig 	proc_create_single("powerpc/rtas/sensors", 0444, NULL,
2473f3942acSChristoph Hellwig 			ppc_rtas_sensors_show);
24857ad583fSRussell Currey 	proc_create("powerpc/rtas/frequency", 0644, NULL,
24997a32539SAlexey Dobriyan 		    &ppc_rtas_tone_freq_proc_ops);
25057ad583fSRussell Currey 	proc_create("powerpc/rtas/volume", 0644, NULL,
25197a32539SAlexey Dobriyan 		    &ppc_rtas_tone_volume_proc_ops);
2523f3942acSChristoph Hellwig 	proc_create_single("powerpc/rtas/rmo_buffer", 0400, NULL,
2533f3942acSChristoph Hellwig 			ppc_rtas_rmo_buf_show);
254f4fcbbe9SPaul Mackerras 	return 0;
255f4fcbbe9SPaul Mackerras }
256f4fcbbe9SPaul Mackerras 
257f4fcbbe9SPaul Mackerras __initcall(proc_rtas_init);
258f4fcbbe9SPaul Mackerras 
parse_number(const char __user * p,size_t count,u64 * val)2592dc20f45SArnd Bergmann static int parse_number(const char __user *p, size_t count, u64 *val)
260f4fcbbe9SPaul Mackerras {
261f4fcbbe9SPaul Mackerras 	char buf[40];
262f4fcbbe9SPaul Mackerras 
263f4fcbbe9SPaul Mackerras 	if (count > 39)
264f4fcbbe9SPaul Mackerras 		return -EINVAL;
265f4fcbbe9SPaul Mackerras 
266f4fcbbe9SPaul Mackerras 	if (copy_from_user(buf, p, count))
267f4fcbbe9SPaul Mackerras 		return -EFAULT;
268f4fcbbe9SPaul Mackerras 
269f4fcbbe9SPaul Mackerras 	buf[count] = 0;
270f4fcbbe9SPaul Mackerras 
27108d61b46SChen Huang 	return kstrtoull(buf, 10, val);
272f4fcbbe9SPaul Mackerras }
273f4fcbbe9SPaul Mackerras 
274f4fcbbe9SPaul Mackerras /* ****************************************************************** */
275f4fcbbe9SPaul Mackerras /* POWER-ON-TIME                                                      */
276f4fcbbe9SPaul Mackerras /* ****************************************************************** */
ppc_rtas_poweron_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)277f4fcbbe9SPaul Mackerras static ssize_t ppc_rtas_poweron_write(struct file *file,
278f4fcbbe9SPaul Mackerras 		const char __user *buf, size_t count, loff_t *ppos)
279f4fcbbe9SPaul Mackerras {
280f4fcbbe9SPaul Mackerras 	struct rtc_time tm;
2812dc20f45SArnd Bergmann 	time64_t nowtime;
282f4fcbbe9SPaul Mackerras 	int error = parse_number(buf, count, &nowtime);
283f4fcbbe9SPaul Mackerras 	if (error)
284f4fcbbe9SPaul Mackerras 		return error;
285f4fcbbe9SPaul Mackerras 
286f4fcbbe9SPaul Mackerras 	power_on_time = nowtime; /* save the time */
287f4fcbbe9SPaul Mackerras 
2882dc20f45SArnd Bergmann 	rtc_time64_to_tm(nowtime, &tm);
289f4fcbbe9SPaul Mackerras 
290*08273c9fSNathan Lynch 	error = rtas_call(rtas_function_token(RTAS_FN_SET_TIME_FOR_POWER_ON), 7, 1, NULL,
2912dc20f45SArnd Bergmann 			  tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
292f4fcbbe9SPaul Mackerras 			  tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */);
293f4fcbbe9SPaul Mackerras 	if (error)
294f4fcbbe9SPaul Mackerras 		printk(KERN_WARNING "error: setting poweron time returned: %s\n",
295f4fcbbe9SPaul Mackerras 				ppc_rtas_process_error(error));
296f4fcbbe9SPaul Mackerras 	return count;
297f4fcbbe9SPaul Mackerras }
298f4fcbbe9SPaul Mackerras /* ****************************************************************** */
ppc_rtas_poweron_show(struct seq_file * m,void * v)299f4fcbbe9SPaul Mackerras static int ppc_rtas_poweron_show(struct seq_file *m, void *v)
300f4fcbbe9SPaul Mackerras {
301f4fcbbe9SPaul Mackerras 	if (power_on_time == 0)
302f4fcbbe9SPaul Mackerras 		seq_printf(m, "Power on time not set\n");
303f4fcbbe9SPaul Mackerras 	else
304f4fcbbe9SPaul Mackerras 		seq_printf(m, "%lu\n",power_on_time);
305f4fcbbe9SPaul Mackerras 	return 0;
306f4fcbbe9SPaul Mackerras }
307f4fcbbe9SPaul Mackerras 
308f4fcbbe9SPaul Mackerras /* ****************************************************************** */
309f4fcbbe9SPaul Mackerras /* PROGRESS                                                           */
310f4fcbbe9SPaul Mackerras /* ****************************************************************** */
ppc_rtas_progress_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)311f4fcbbe9SPaul Mackerras static ssize_t ppc_rtas_progress_write(struct file *file,
312f4fcbbe9SPaul Mackerras 		const char __user *buf, size_t count, loff_t *ppos)
313f4fcbbe9SPaul Mackerras {
314f4fcbbe9SPaul Mackerras 	unsigned long hex;
315f4fcbbe9SPaul Mackerras 
316f4fcbbe9SPaul Mackerras 	if (count >= MAX_LINELENGTH)
317f4fcbbe9SPaul Mackerras 		count = MAX_LINELENGTH -1;
318f4fcbbe9SPaul Mackerras 	if (copy_from_user(progress_led, buf, count)) { /* save the string */
319f4fcbbe9SPaul Mackerras 		return -EFAULT;
320f4fcbbe9SPaul Mackerras 	}
321f4fcbbe9SPaul Mackerras 	progress_led[count] = 0;
322f4fcbbe9SPaul Mackerras 
323f4fcbbe9SPaul Mackerras 	/* Lets see if the user passed hexdigits */
324f4fcbbe9SPaul Mackerras 	hex = simple_strtoul(progress_led, NULL, 10);
325f4fcbbe9SPaul Mackerras 
326f4fcbbe9SPaul Mackerras 	rtas_progress ((char *)progress_led, hex);
327f4fcbbe9SPaul Mackerras 	return count;
328f4fcbbe9SPaul Mackerras 
329f4fcbbe9SPaul Mackerras 	/* clear the line */
330f4fcbbe9SPaul Mackerras 	/* rtas_progress("                   ", 0xffff);*/
331f4fcbbe9SPaul Mackerras }
332f4fcbbe9SPaul Mackerras /* ****************************************************************** */
ppc_rtas_progress_show(struct seq_file * m,void * v)333f4fcbbe9SPaul Mackerras static int ppc_rtas_progress_show(struct seq_file *m, void *v)
334f4fcbbe9SPaul Mackerras {
3359a6b5070SSegher Boessenkool 	if (progress_led[0])
336f4fcbbe9SPaul Mackerras 		seq_printf(m, "%s\n", progress_led);
337f4fcbbe9SPaul Mackerras 	return 0;
338f4fcbbe9SPaul Mackerras }
339f4fcbbe9SPaul Mackerras 
340f4fcbbe9SPaul Mackerras /* ****************************************************************** */
341f4fcbbe9SPaul Mackerras /* CLOCK                                                              */
342f4fcbbe9SPaul Mackerras /* ****************************************************************** */
ppc_rtas_clock_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)343f4fcbbe9SPaul Mackerras static ssize_t ppc_rtas_clock_write(struct file *file,
344f4fcbbe9SPaul Mackerras 		const char __user *buf, size_t count, loff_t *ppos)
345f4fcbbe9SPaul Mackerras {
346f4fcbbe9SPaul Mackerras 	struct rtc_time tm;
3472dc20f45SArnd Bergmann 	time64_t nowtime;
348f4fcbbe9SPaul Mackerras 	int error = parse_number(buf, count, &nowtime);
349f4fcbbe9SPaul Mackerras 	if (error)
350f4fcbbe9SPaul Mackerras 		return error;
351f4fcbbe9SPaul Mackerras 
3522dc20f45SArnd Bergmann 	rtc_time64_to_tm(nowtime, &tm);
353*08273c9fSNathan Lynch 	error = rtas_call(rtas_function_token(RTAS_FN_SET_TIME_OF_DAY), 7, 1, NULL,
3542dc20f45SArnd Bergmann 			  tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
355f4fcbbe9SPaul Mackerras 			  tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
356f4fcbbe9SPaul Mackerras 	if (error)
357f4fcbbe9SPaul Mackerras 		printk(KERN_WARNING "error: setting the clock returned: %s\n",
358f4fcbbe9SPaul Mackerras 				ppc_rtas_process_error(error));
359f4fcbbe9SPaul Mackerras 	return count;
360f4fcbbe9SPaul Mackerras }
361f4fcbbe9SPaul Mackerras /* ****************************************************************** */
ppc_rtas_clock_show(struct seq_file * m,void * v)362f4fcbbe9SPaul Mackerras static int ppc_rtas_clock_show(struct seq_file *m, void *v)
363f4fcbbe9SPaul Mackerras {
364f4fcbbe9SPaul Mackerras 	int ret[8];
365*08273c9fSNathan Lynch 	int error = rtas_call(rtas_function_token(RTAS_FN_GET_TIME_OF_DAY), 0, 8, ret);
366f4fcbbe9SPaul Mackerras 
367f4fcbbe9SPaul Mackerras 	if (error) {
368f4fcbbe9SPaul Mackerras 		printk(KERN_WARNING "error: reading the clock returned: %s\n",
369f4fcbbe9SPaul Mackerras 				ppc_rtas_process_error(error));
370f4fcbbe9SPaul Mackerras 		seq_printf(m, "0");
371f4fcbbe9SPaul Mackerras 	} else {
372f4fcbbe9SPaul Mackerras 		unsigned int year, mon, day, hour, min, sec;
373f4fcbbe9SPaul Mackerras 		year = ret[0]; mon  = ret[1]; day  = ret[2];
374f4fcbbe9SPaul Mackerras 		hour = ret[3]; min  = ret[4]; sec  = ret[5];
3752dc20f45SArnd Bergmann 		seq_printf(m, "%lld\n",
3762dc20f45SArnd Bergmann 				mktime64(year, mon, day, hour, min, sec));
377f4fcbbe9SPaul Mackerras 	}
378f4fcbbe9SPaul Mackerras 	return 0;
379f4fcbbe9SPaul Mackerras }
380f4fcbbe9SPaul Mackerras 
381f4fcbbe9SPaul Mackerras /* ****************************************************************** */
382f4fcbbe9SPaul Mackerras /* SENSOR STUFF                                                       */
383f4fcbbe9SPaul Mackerras /* ****************************************************************** */
ppc_rtas_sensors_show(struct seq_file * m,void * v)384f4fcbbe9SPaul Mackerras static int ppc_rtas_sensors_show(struct seq_file *m, void *v)
385f4fcbbe9SPaul Mackerras {
386f4fcbbe9SPaul Mackerras 	int i,j;
387f4fcbbe9SPaul Mackerras 	int state, error;
388*08273c9fSNathan Lynch 	int get_sensor_state = rtas_function_token(RTAS_FN_GET_SENSOR_STATE);
389f4fcbbe9SPaul Mackerras 
390f4fcbbe9SPaul Mackerras 	seq_printf(m, "RTAS (RunTime Abstraction Services) Sensor Information\n");
391f4fcbbe9SPaul Mackerras 	seq_printf(m, "Sensor\t\tValue\t\tCondition\tLocation\n");
392f4fcbbe9SPaul Mackerras 	seq_printf(m, "********************************************************\n");
393f4fcbbe9SPaul Mackerras 
394f4fcbbe9SPaul Mackerras 	if (ppc_rtas_find_all_sensors() != 0) {
395f4fcbbe9SPaul Mackerras 		seq_printf(m, "\nNo sensors are available\n");
396f4fcbbe9SPaul Mackerras 		return 0;
397f4fcbbe9SPaul Mackerras 	}
398f4fcbbe9SPaul Mackerras 
399f4fcbbe9SPaul Mackerras 	for (i=0; i<sensors.quant; i++) {
400f4fcbbe9SPaul Mackerras 		struct individual_sensor *p = &sensors.sensor[i];
401f4fcbbe9SPaul Mackerras 		char rstr[64];
402a7f67bdfSJeremy Kerr 		const char *loc;
403f4fcbbe9SPaul Mackerras 		int llen, offs;
404f4fcbbe9SPaul Mackerras 
405f4fcbbe9SPaul Mackerras 		sprintf (rstr, SENSOR_PREFIX"%04d", p->token);
406e2eb6392SStephen Rothwell 		loc = of_get_property(rtas_node, rstr, &llen);
407f4fcbbe9SPaul Mackerras 
408f4fcbbe9SPaul Mackerras 		/* A sensor may have multiple instances */
409f4fcbbe9SPaul Mackerras 		for (j = 0, offs = 0; j <= p->quant; j++) {
410f4fcbbe9SPaul Mackerras 			error =	rtas_call(get_sensor_state, 2, 2, &state,
411f4fcbbe9SPaul Mackerras 				  	  p->token, j);
412f4fcbbe9SPaul Mackerras 
413f4fcbbe9SPaul Mackerras 			ppc_rtas_process_sensor(m, p, state, error, loc);
414f4fcbbe9SPaul Mackerras 			seq_putc(m, '\n');
415f4fcbbe9SPaul Mackerras 			if (loc) {
416f4fcbbe9SPaul Mackerras 				offs += strlen(loc) + 1;
417f4fcbbe9SPaul Mackerras 				loc += strlen(loc) + 1;
418f4fcbbe9SPaul Mackerras 				if (offs >= llen)
419f4fcbbe9SPaul Mackerras 					loc = NULL;
420f4fcbbe9SPaul Mackerras 			}
421f4fcbbe9SPaul Mackerras 		}
422f4fcbbe9SPaul Mackerras 	}
423f4fcbbe9SPaul Mackerras 	return 0;
424f4fcbbe9SPaul Mackerras }
425f4fcbbe9SPaul Mackerras 
426f4fcbbe9SPaul Mackerras /* ****************************************************************** */
427f4fcbbe9SPaul Mackerras 
ppc_rtas_find_all_sensors(void)428f4fcbbe9SPaul Mackerras static int ppc_rtas_find_all_sensors(void)
429f4fcbbe9SPaul Mackerras {
430a7f67bdfSJeremy Kerr 	const unsigned int *utmp;
431f4fcbbe9SPaul Mackerras 	int len, i;
432f4fcbbe9SPaul Mackerras 
433e2eb6392SStephen Rothwell 	utmp = of_get_property(rtas_node, "rtas-sensors", &len);
434f4fcbbe9SPaul Mackerras 	if (utmp == NULL) {
435f4fcbbe9SPaul Mackerras 		printk (KERN_ERR "error: could not get rtas-sensors\n");
436f4fcbbe9SPaul Mackerras 		return 1;
437f4fcbbe9SPaul Mackerras 	}
438f4fcbbe9SPaul Mackerras 
439f4fcbbe9SPaul Mackerras 	sensors.quant = len / 8;      /* int + int */
440f4fcbbe9SPaul Mackerras 
441f4fcbbe9SPaul Mackerras 	for (i=0; i<sensors.quant; i++) {
442f4fcbbe9SPaul Mackerras 		sensors.sensor[i].token = *utmp++;
443f4fcbbe9SPaul Mackerras 		sensors.sensor[i].quant = *utmp++;
444f4fcbbe9SPaul Mackerras 	}
445f4fcbbe9SPaul Mackerras 	return 0;
446f4fcbbe9SPaul Mackerras }
447f4fcbbe9SPaul Mackerras 
448f4fcbbe9SPaul Mackerras /* ****************************************************************** */
449f4fcbbe9SPaul Mackerras /*
450f4fcbbe9SPaul Mackerras  * Builds a string of what rtas returned
451f4fcbbe9SPaul Mackerras  */
ppc_rtas_process_error(int error)452f4fcbbe9SPaul Mackerras static char *ppc_rtas_process_error(int error)
453f4fcbbe9SPaul Mackerras {
454f4fcbbe9SPaul Mackerras 	switch (error) {
455f4fcbbe9SPaul Mackerras 		case SENSOR_CRITICAL_HIGH:
456f4fcbbe9SPaul Mackerras 			return "(critical high)";
457f4fcbbe9SPaul Mackerras 		case SENSOR_WARNING_HIGH:
458f4fcbbe9SPaul Mackerras 			return "(warning high)";
459f4fcbbe9SPaul Mackerras 		case SENSOR_NORMAL:
460f4fcbbe9SPaul Mackerras 			return "(normal)";
461f4fcbbe9SPaul Mackerras 		case SENSOR_WARNING_LOW:
462f4fcbbe9SPaul Mackerras 			return "(warning low)";
463f4fcbbe9SPaul Mackerras 		case SENSOR_CRITICAL_LOW:
464f4fcbbe9SPaul Mackerras 			return "(critical low)";
465f4fcbbe9SPaul Mackerras 		case SENSOR_SUCCESS:
466f4fcbbe9SPaul Mackerras 			return "(read ok)";
467f4fcbbe9SPaul Mackerras 		case SENSOR_HW_ERROR:
468f4fcbbe9SPaul Mackerras 			return "(hardware error)";
469f4fcbbe9SPaul Mackerras 		case SENSOR_BUSY:
470f4fcbbe9SPaul Mackerras 			return "(busy)";
471f4fcbbe9SPaul Mackerras 		case SENSOR_NOT_EXIST:
472f4fcbbe9SPaul Mackerras 			return "(non existent)";
473f4fcbbe9SPaul Mackerras 		case SENSOR_DR_ENTITY:
474f4fcbbe9SPaul Mackerras 			return "(dr entity removed)";
475f4fcbbe9SPaul Mackerras 		default:
476f4fcbbe9SPaul Mackerras 			return "(UNKNOWN)";
477f4fcbbe9SPaul Mackerras 	}
478f4fcbbe9SPaul Mackerras }
479f4fcbbe9SPaul Mackerras 
480f4fcbbe9SPaul Mackerras /* ****************************************************************** */
481f4fcbbe9SPaul Mackerras /*
482f4fcbbe9SPaul Mackerras  * Builds a string out of what the sensor said
483f4fcbbe9SPaul Mackerras  */
484f4fcbbe9SPaul Mackerras 
ppc_rtas_process_sensor(struct seq_file * m,struct individual_sensor * s,int state,int error,const char * loc)485f4fcbbe9SPaul Mackerras static void ppc_rtas_process_sensor(struct seq_file *m,
486a7f67bdfSJeremy Kerr 	struct individual_sensor *s, int state, int error, const char *loc)
487f4fcbbe9SPaul Mackerras {
488f4fcbbe9SPaul Mackerras 	/* Defined return vales */
489f4fcbbe9SPaul Mackerras 	const char * key_switch[]        = { "Off\t", "Normal\t", "Secure\t",
490f4fcbbe9SPaul Mackerras 						"Maintenance" };
491f4fcbbe9SPaul Mackerras 	const char * enclosure_switch[]  = { "Closed", "Open" };
492f4fcbbe9SPaul Mackerras 	const char * lid_status[]        = { " ", "Open", "Closed" };
493f4fcbbe9SPaul Mackerras 	const char * power_source[]      = { "AC\t", "Battery",
494f4fcbbe9SPaul Mackerras 		  				"AC & Battery" };
495f4fcbbe9SPaul Mackerras 	const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" };
496f4fcbbe9SPaul Mackerras 	const char * epow_sensor[]       = {
497f4fcbbe9SPaul Mackerras 		"EPOW Reset", "Cooling warning", "Power warning",
498f4fcbbe9SPaul Mackerras 		"System shutdown", "System halt", "EPOW main enclosure",
499f4fcbbe9SPaul Mackerras 		"EPOW power off" };
500f4fcbbe9SPaul Mackerras 	const char * battery_cyclestate[]  = { "None", "In progress",
501f4fcbbe9SPaul Mackerras 						"Requested" };
502ba01b058SColin Ian King 	const char * battery_charging[]    = { "Charging", "Discharging",
503f4fcbbe9SPaul Mackerras 						"No current flow" };
504f4fcbbe9SPaul Mackerras 	const char * ibm_drconnector[]     = { "Empty", "Present", "Unusable",
505f4fcbbe9SPaul Mackerras 						"Exchange" };
506f4fcbbe9SPaul Mackerras 
507f4fcbbe9SPaul Mackerras 	int have_strings = 0;
508f4fcbbe9SPaul Mackerras 	int num_states = 0;
509f4fcbbe9SPaul Mackerras 	int temperature = 0;
510f4fcbbe9SPaul Mackerras 	int unknown = 0;
511f4fcbbe9SPaul Mackerras 
512f4fcbbe9SPaul Mackerras 	/* What kind of sensor do we have here? */
513f4fcbbe9SPaul Mackerras 
514f4fcbbe9SPaul Mackerras 	switch (s->token) {
515f4fcbbe9SPaul Mackerras 		case KEY_SWITCH:
516f4fcbbe9SPaul Mackerras 			seq_printf(m, "Key switch:\t");
517f4fcbbe9SPaul Mackerras 			num_states = sizeof(key_switch) / sizeof(char *);
518f4fcbbe9SPaul Mackerras 			if (state < num_states) {
519f4fcbbe9SPaul Mackerras 				seq_printf(m, "%s\t", key_switch[state]);
520f4fcbbe9SPaul Mackerras 				have_strings = 1;
521f4fcbbe9SPaul Mackerras 			}
522f4fcbbe9SPaul Mackerras 			break;
523f4fcbbe9SPaul Mackerras 		case ENCLOSURE_SWITCH:
524f4fcbbe9SPaul Mackerras 			seq_printf(m, "Enclosure switch:\t");
525f4fcbbe9SPaul Mackerras 			num_states = sizeof(enclosure_switch) / sizeof(char *);
526f4fcbbe9SPaul Mackerras 			if (state < num_states) {
527f4fcbbe9SPaul Mackerras 				seq_printf(m, "%s\t",
528f4fcbbe9SPaul Mackerras 						enclosure_switch[state]);
529f4fcbbe9SPaul Mackerras 				have_strings = 1;
530f4fcbbe9SPaul Mackerras 			}
531f4fcbbe9SPaul Mackerras 			break;
532f4fcbbe9SPaul Mackerras 		case THERMAL_SENSOR:
533f4fcbbe9SPaul Mackerras 			seq_printf(m, "Temp. (C/F):\t");
534f4fcbbe9SPaul Mackerras 			temperature = 1;
535f4fcbbe9SPaul Mackerras 			break;
536f4fcbbe9SPaul Mackerras 		case LID_STATUS:
537f4fcbbe9SPaul Mackerras 			seq_printf(m, "Lid status:\t");
538f4fcbbe9SPaul Mackerras 			num_states = sizeof(lid_status) / sizeof(char *);
539f4fcbbe9SPaul Mackerras 			if (state < num_states) {
540f4fcbbe9SPaul Mackerras 				seq_printf(m, "%s\t", lid_status[state]);
541f4fcbbe9SPaul Mackerras 				have_strings = 1;
542f4fcbbe9SPaul Mackerras 			}
543f4fcbbe9SPaul Mackerras 			break;
544f4fcbbe9SPaul Mackerras 		case POWER_SOURCE:
545f4fcbbe9SPaul Mackerras 			seq_printf(m, "Power source:\t");
546f4fcbbe9SPaul Mackerras 			num_states = sizeof(power_source) / sizeof(char *);
547f4fcbbe9SPaul Mackerras 			if (state < num_states) {
548f4fcbbe9SPaul Mackerras 				seq_printf(m, "%s\t",
549f4fcbbe9SPaul Mackerras 						power_source[state]);
550f4fcbbe9SPaul Mackerras 				have_strings = 1;
551f4fcbbe9SPaul Mackerras 			}
552f4fcbbe9SPaul Mackerras 			break;
553f4fcbbe9SPaul Mackerras 		case BATTERY_VOLTAGE:
554f4fcbbe9SPaul Mackerras 			seq_printf(m, "Battery voltage:\t");
555f4fcbbe9SPaul Mackerras 			break;
556f4fcbbe9SPaul Mackerras 		case BATTERY_REMAINING:
557f4fcbbe9SPaul Mackerras 			seq_printf(m, "Battery remaining:\t");
558f4fcbbe9SPaul Mackerras 			num_states = sizeof(battery_remaining) / sizeof(char *);
559f4fcbbe9SPaul Mackerras 			if (state < num_states)
560f4fcbbe9SPaul Mackerras 			{
561f4fcbbe9SPaul Mackerras 				seq_printf(m, "%s\t",
562f4fcbbe9SPaul Mackerras 						battery_remaining[state]);
563f4fcbbe9SPaul Mackerras 				have_strings = 1;
564f4fcbbe9SPaul Mackerras 			}
565f4fcbbe9SPaul Mackerras 			break;
566f4fcbbe9SPaul Mackerras 		case BATTERY_PERCENTAGE:
567f4fcbbe9SPaul Mackerras 			seq_printf(m, "Battery percentage:\t");
568f4fcbbe9SPaul Mackerras 			break;
569f4fcbbe9SPaul Mackerras 		case EPOW_SENSOR:
570f4fcbbe9SPaul Mackerras 			seq_printf(m, "EPOW Sensor:\t");
571f4fcbbe9SPaul Mackerras 			num_states = sizeof(epow_sensor) / sizeof(char *);
572f4fcbbe9SPaul Mackerras 			if (state < num_states) {
573f4fcbbe9SPaul Mackerras 				seq_printf(m, "%s\t", epow_sensor[state]);
574f4fcbbe9SPaul Mackerras 				have_strings = 1;
575f4fcbbe9SPaul Mackerras 			}
576f4fcbbe9SPaul Mackerras 			break;
577f4fcbbe9SPaul Mackerras 		case BATTERY_CYCLESTATE:
578f4fcbbe9SPaul Mackerras 			seq_printf(m, "Battery cyclestate:\t");
579f4fcbbe9SPaul Mackerras 			num_states = sizeof(battery_cyclestate) /
580f4fcbbe9SPaul Mackerras 				     	sizeof(char *);
581f4fcbbe9SPaul Mackerras 			if (state < num_states) {
582f4fcbbe9SPaul Mackerras 				seq_printf(m, "%s\t",
583f4fcbbe9SPaul Mackerras 						battery_cyclestate[state]);
584f4fcbbe9SPaul Mackerras 				have_strings = 1;
585f4fcbbe9SPaul Mackerras 			}
586f4fcbbe9SPaul Mackerras 			break;
587f4fcbbe9SPaul Mackerras 		case BATTERY_CHARGING:
588f4fcbbe9SPaul Mackerras 			seq_printf(m, "Battery Charging:\t");
589f4fcbbe9SPaul Mackerras 			num_states = sizeof(battery_charging) / sizeof(char *);
590f4fcbbe9SPaul Mackerras 			if (state < num_states) {
591f4fcbbe9SPaul Mackerras 				seq_printf(m, "%s\t",
592f4fcbbe9SPaul Mackerras 						battery_charging[state]);
593f4fcbbe9SPaul Mackerras 				have_strings = 1;
594f4fcbbe9SPaul Mackerras 			}
595f4fcbbe9SPaul Mackerras 			break;
596f4fcbbe9SPaul Mackerras 		case IBM_SURVEILLANCE:
597f4fcbbe9SPaul Mackerras 			seq_printf(m, "Surveillance:\t");
598f4fcbbe9SPaul Mackerras 			break;
599f4fcbbe9SPaul Mackerras 		case IBM_FANRPM:
600f4fcbbe9SPaul Mackerras 			seq_printf(m, "Fan (rpm):\t");
601f4fcbbe9SPaul Mackerras 			break;
602f4fcbbe9SPaul Mackerras 		case IBM_VOLTAGE:
603f4fcbbe9SPaul Mackerras 			seq_printf(m, "Voltage (mv):\t");
604f4fcbbe9SPaul Mackerras 			break;
605f4fcbbe9SPaul Mackerras 		case IBM_DRCONNECTOR:
606f4fcbbe9SPaul Mackerras 			seq_printf(m, "DR connector:\t");
607f4fcbbe9SPaul Mackerras 			num_states = sizeof(ibm_drconnector) / sizeof(char *);
608f4fcbbe9SPaul Mackerras 			if (state < num_states) {
609f4fcbbe9SPaul Mackerras 				seq_printf(m, "%s\t",
610f4fcbbe9SPaul Mackerras 						ibm_drconnector[state]);
611f4fcbbe9SPaul Mackerras 				have_strings = 1;
612f4fcbbe9SPaul Mackerras 			}
613f4fcbbe9SPaul Mackerras 			break;
614f4fcbbe9SPaul Mackerras 		case IBM_POWERSUPPLY:
615f4fcbbe9SPaul Mackerras 			seq_printf(m, "Powersupply:\t");
616f4fcbbe9SPaul Mackerras 			break;
617f4fcbbe9SPaul Mackerras 		default:
618f4fcbbe9SPaul Mackerras 			seq_printf(m,  "Unknown sensor (type %d), ignoring it\n",
619f4fcbbe9SPaul Mackerras 					s->token);
620f4fcbbe9SPaul Mackerras 			unknown = 1;
621f4fcbbe9SPaul Mackerras 			have_strings = 1;
622f4fcbbe9SPaul Mackerras 			break;
623f4fcbbe9SPaul Mackerras 	}
624f4fcbbe9SPaul Mackerras 	if (have_strings == 0) {
625f4fcbbe9SPaul Mackerras 		if (temperature) {
626f4fcbbe9SPaul Mackerras 			seq_printf(m, "%4d /%4d\t", state, cel_to_fahr(state));
627f4fcbbe9SPaul Mackerras 		} else
628f4fcbbe9SPaul Mackerras 			seq_printf(m, "%10d\t", state);
629f4fcbbe9SPaul Mackerras 	}
630f4fcbbe9SPaul Mackerras 	if (unknown == 0) {
631f4fcbbe9SPaul Mackerras 		seq_printf(m, "%s\t", ppc_rtas_process_error(error));
632f4fcbbe9SPaul Mackerras 		get_location_code(m, s, loc);
633f4fcbbe9SPaul Mackerras 	}
634f4fcbbe9SPaul Mackerras }
635f4fcbbe9SPaul Mackerras 
636f4fcbbe9SPaul Mackerras /* ****************************************************************** */
637f4fcbbe9SPaul Mackerras 
check_location(struct seq_file * m,const char * c)638a7f67bdfSJeremy Kerr static void check_location(struct seq_file *m, const char *c)
639f4fcbbe9SPaul Mackerras {
640f4fcbbe9SPaul Mackerras 	switch (c[0]) {
641f4fcbbe9SPaul Mackerras 		case LOC_PLANAR:
642f4fcbbe9SPaul Mackerras 			seq_printf(m, "Planar #%c", c[1]);
643f4fcbbe9SPaul Mackerras 			break;
644f4fcbbe9SPaul Mackerras 		case LOC_CPU:
645f4fcbbe9SPaul Mackerras 			seq_printf(m, "CPU #%c", c[1]);
646f4fcbbe9SPaul Mackerras 			break;
647f4fcbbe9SPaul Mackerras 		case LOC_FAN:
648f4fcbbe9SPaul Mackerras 			seq_printf(m, "Fan #%c", c[1]);
649f4fcbbe9SPaul Mackerras 			break;
650f4fcbbe9SPaul Mackerras 		case LOC_RACKMOUNTED:
651f4fcbbe9SPaul Mackerras 			seq_printf(m, "Rack #%c", c[1]);
652f4fcbbe9SPaul Mackerras 			break;
653f4fcbbe9SPaul Mackerras 		case LOC_VOLTAGE:
654f4fcbbe9SPaul Mackerras 			seq_printf(m, "Voltage #%c", c[1]);
655f4fcbbe9SPaul Mackerras 			break;
656f4fcbbe9SPaul Mackerras 		case LOC_LCD:
657f4fcbbe9SPaul Mackerras 			seq_printf(m, "LCD #%c", c[1]);
658f4fcbbe9SPaul Mackerras 			break;
659f4fcbbe9SPaul Mackerras 		case '.':
660f4fcbbe9SPaul Mackerras 			seq_printf(m, "- %c", c[1]);
661f4fcbbe9SPaul Mackerras 			break;
662f4fcbbe9SPaul Mackerras 		default:
663f4fcbbe9SPaul Mackerras 			seq_printf(m, "Unknown location");
664f4fcbbe9SPaul Mackerras 			break;
665f4fcbbe9SPaul Mackerras 	}
666f4fcbbe9SPaul Mackerras }
667f4fcbbe9SPaul Mackerras 
668f4fcbbe9SPaul Mackerras 
669f4fcbbe9SPaul Mackerras /* ****************************************************************** */
670f4fcbbe9SPaul Mackerras /*
671f4fcbbe9SPaul Mackerras  * Format:
672f4fcbbe9SPaul Mackerras  * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ]
673027dfac6SMichael Ellerman  * the '.' may be an abbreviation
674f4fcbbe9SPaul Mackerras  */
check_location_string(struct seq_file * m,const char * c)675a7f67bdfSJeremy Kerr static void check_location_string(struct seq_file *m, const char *c)
676f4fcbbe9SPaul Mackerras {
677f4fcbbe9SPaul Mackerras 	while (*c) {
678f4fcbbe9SPaul Mackerras 		if (isalpha(*c) || *c == '.')
679f4fcbbe9SPaul Mackerras 			check_location(m, c);
680f4fcbbe9SPaul Mackerras 		else if (*c == '/' || *c == '-')
681f4fcbbe9SPaul Mackerras 			seq_printf(m, " at ");
682f4fcbbe9SPaul Mackerras 		c++;
683f4fcbbe9SPaul Mackerras 	}
684f4fcbbe9SPaul Mackerras }
685f4fcbbe9SPaul Mackerras 
686f4fcbbe9SPaul Mackerras 
687f4fcbbe9SPaul Mackerras /* ****************************************************************** */
688f4fcbbe9SPaul Mackerras 
get_location_code(struct seq_file * m,struct individual_sensor * s,const char * loc)689a7f67bdfSJeremy Kerr static void get_location_code(struct seq_file *m, struct individual_sensor *s,
690a7f67bdfSJeremy Kerr 		const char *loc)
691f4fcbbe9SPaul Mackerras {
692f4fcbbe9SPaul Mackerras 	if (!loc || !*loc) {
693f4fcbbe9SPaul Mackerras 		seq_printf(m, "---");/* does not have a location */
694f4fcbbe9SPaul Mackerras 	} else {
695f4fcbbe9SPaul Mackerras 		check_location_string(m, loc);
696f4fcbbe9SPaul Mackerras 	}
697f4fcbbe9SPaul Mackerras 	seq_putc(m, ' ');
698f4fcbbe9SPaul Mackerras }
699f4fcbbe9SPaul Mackerras /* ****************************************************************** */
700f4fcbbe9SPaul Mackerras /* INDICATORS - Tone Frequency                                        */
701f4fcbbe9SPaul Mackerras /* ****************************************************************** */
ppc_rtas_tone_freq_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)702f4fcbbe9SPaul Mackerras static ssize_t ppc_rtas_tone_freq_write(struct file *file,
703f4fcbbe9SPaul Mackerras 		const char __user *buf, size_t count, loff_t *ppos)
704f4fcbbe9SPaul Mackerras {
7052dc20f45SArnd Bergmann 	u64 freq;
706f4fcbbe9SPaul Mackerras 	int error = parse_number(buf, count, &freq);
707f4fcbbe9SPaul Mackerras 	if (error)
708f4fcbbe9SPaul Mackerras 		return error;
709f4fcbbe9SPaul Mackerras 
710f4fcbbe9SPaul Mackerras 	rtas_tone_frequency = freq; /* save it for later */
711*08273c9fSNathan Lynch 	error = rtas_call(rtas_function_token(RTAS_FN_SET_INDICATOR), 3, 1, NULL,
712f4fcbbe9SPaul Mackerras 			  TONE_FREQUENCY, 0, freq);
713f4fcbbe9SPaul Mackerras 	if (error)
714f4fcbbe9SPaul Mackerras 		printk(KERN_WARNING "error: setting tone frequency returned: %s\n",
715f4fcbbe9SPaul Mackerras 				ppc_rtas_process_error(error));
716f4fcbbe9SPaul Mackerras 	return count;
717f4fcbbe9SPaul Mackerras }
718f4fcbbe9SPaul Mackerras /* ****************************************************************** */
ppc_rtas_tone_freq_show(struct seq_file * m,void * v)719f4fcbbe9SPaul Mackerras static int ppc_rtas_tone_freq_show(struct seq_file *m, void *v)
720f4fcbbe9SPaul Mackerras {
721f4fcbbe9SPaul Mackerras 	seq_printf(m, "%lu\n", rtas_tone_frequency);
722f4fcbbe9SPaul Mackerras 	return 0;
723f4fcbbe9SPaul Mackerras }
724f4fcbbe9SPaul Mackerras /* ****************************************************************** */
725f4fcbbe9SPaul Mackerras /* INDICATORS - Tone Volume                                           */
726f4fcbbe9SPaul Mackerras /* ****************************************************************** */
ppc_rtas_tone_volume_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)727f4fcbbe9SPaul Mackerras static ssize_t ppc_rtas_tone_volume_write(struct file *file,
728f4fcbbe9SPaul Mackerras 		const char __user *buf, size_t count, loff_t *ppos)
729f4fcbbe9SPaul Mackerras {
7302dc20f45SArnd Bergmann 	u64 volume;
731f4fcbbe9SPaul Mackerras 	int error = parse_number(buf, count, &volume);
732f4fcbbe9SPaul Mackerras 	if (error)
733f4fcbbe9SPaul Mackerras 		return error;
734f4fcbbe9SPaul Mackerras 
735f4fcbbe9SPaul Mackerras 	if (volume > 100)
736f4fcbbe9SPaul Mackerras 		volume = 100;
737f4fcbbe9SPaul Mackerras 
738f4fcbbe9SPaul Mackerras         rtas_tone_volume = volume; /* save it for later */
739*08273c9fSNathan Lynch 	error = rtas_call(rtas_function_token(RTAS_FN_SET_INDICATOR), 3, 1, NULL,
740f4fcbbe9SPaul Mackerras 			  TONE_VOLUME, 0, volume);
741f4fcbbe9SPaul Mackerras 	if (error)
742f4fcbbe9SPaul Mackerras 		printk(KERN_WARNING "error: setting tone volume returned: %s\n",
743f4fcbbe9SPaul Mackerras 				ppc_rtas_process_error(error));
744f4fcbbe9SPaul Mackerras 	return count;
745f4fcbbe9SPaul Mackerras }
746f4fcbbe9SPaul Mackerras /* ****************************************************************** */
ppc_rtas_tone_volume_show(struct seq_file * m,void * v)747f4fcbbe9SPaul Mackerras static int ppc_rtas_tone_volume_show(struct seq_file *m, void *v)
748f4fcbbe9SPaul Mackerras {
749f4fcbbe9SPaul Mackerras 	seq_printf(m, "%lu\n", rtas_tone_volume);
750f4fcbbe9SPaul Mackerras 	return 0;
751f4fcbbe9SPaul Mackerras }
752f4fcbbe9SPaul Mackerras 
753c13ff6f3SNathan Lynch /**
754c13ff6f3SNathan Lynch  * ppc_rtas_rmo_buf_show() - Describe RTAS-addressable region for user space.
755c13ff6f3SNathan Lynch  *
756c13ff6f3SNathan Lynch  * Base + size description of a range of RTAS-addressable memory set
757c13ff6f3SNathan Lynch  * aside for user space to use as work area(s) for certain RTAS
758c13ff6f3SNathan Lynch  * functions. User space accesses this region via /dev/mem. Apart from
759c13ff6f3SNathan Lynch  * security policies, the kernel does not arbitrate or serialize
760c13ff6f3SNathan Lynch  * access to this region, and user space must ensure that concurrent
761c13ff6f3SNathan Lynch  * users do not interfere with each other.
762c13ff6f3SNathan Lynch  */
ppc_rtas_rmo_buf_show(struct seq_file * m,void * v)763f4fcbbe9SPaul Mackerras static int ppc_rtas_rmo_buf_show(struct seq_file *m, void *v)
764f4fcbbe9SPaul Mackerras {
765e5d56763SNathan Lynch 	seq_printf(m, "%016lx %x\n", rtas_rmo_buf, RTAS_USER_REGION_SIZE);
766f4fcbbe9SPaul Mackerras 	return 0;
767f4fcbbe9SPaul Mackerras }
768