2 * arch/ppc64/kernel/rtas-proc.c
3 * Copyright (C) 2000 Tilmann Bitterberg
4 * (tilmann@bitterberg.de)
6 * RTAS (Runtime Abstraction Services) stuff
7 * Intention is to provide a clean user interface
11 * Split off a header file and maybe move it to a different
12 * location. Write Documentation on what the /proc/rtas/ entries
16 #include <linux/errno.h>
17 #include <linux/sched.h>
18 #include <linux/proc_fs.h>
19 #include <linux/stat.h>
20 #include <linux/ctype.h>
21 #include <linux/time.h>
22 #include <linux/string.h>
24 #include <asm/uaccess.h>
25 #include <asm/bitops.h>
26 #include <asm/processor.h>
30 #include <asm/machdep.h> /* for ppc_md */
33 /* Token for Sensors */
34 #define KEY_SWITCH 0x0001
35 #define ENCLOSURE_SWITCH 0x0002
36 #define THERMAL_SENSOR 0x0003
37 #define LID_STATUS 0x0004
38 #define POWER_SOURCE 0x0005
39 #define BATTERY_VOLTAGE 0x0006
40 #define BATTERY_REMAINING 0x0007
41 #define BATTERY_PERCENTAGE 0x0008
42 #define EPOW_SENSOR 0x0009
43 #define BATTERY_CYCLESTATE 0x000a
44 #define BATTERY_CHARGING 0x000b
46 /* IBM specific sensors */
47 #define IBM_SURVEILLANCE 0x2328 /* 9000 */
48 #define IBM_FANRPM 0x2329 /* 9001 */
49 #define IBM_VOLTAGE 0x232a /* 9002 */
50 #define IBM_DRCONNECTOR 0x232b /* 9003 */
51 #define IBM_POWERSUPPLY 0x232c /* 9004 */
52 #define IBM_INTQUEUE 0x232d /* 9005 */
54 /* Status return values */
55 #define SENSOR_CRITICAL_HIGH 13
56 #define SENSOR_WARNING_HIGH 12
57 #define SENSOR_NORMAL 11
58 #define SENSOR_WARNING_LOW 10
59 #define SENSOR_CRITICAL_LOW 9
60 #define SENSOR_SUCCESS 0
61 #define SENSOR_HW_ERROR -1
62 #define SENSOR_BUSY -2
63 #define SENSOR_NOT_EXIST -3
64 #define SENSOR_DR_ENTITY -9000
67 #define LOC_SCSI_DEV_ADDR 'A'
68 #define LOC_SCSI_DEV_LOC 'B'
70 #define LOC_DISKETTE 'D'
71 #define LOC_ETHERNET 'E'
73 #define LOC_GRAPHICS 'G'
74 /* reserved / not used 'H' */
75 #define LOC_IO_ADAPTER 'I'
76 /* reserved / not used 'J' */
77 #define LOC_KEYBOARD 'K'
79 #define LOC_MEMORY 'M'
80 #define LOC_NV_MEMORY 'N'
82 #define LOC_PLANAR 'P'
83 #define LOC_OTHER_IO 'Q'
84 #define LOC_PARALLEL 'R'
85 #define LOC_SERIAL 'S'
86 #define LOC_DEAD_RING 'T'
87 #define LOC_RACKMOUNTED 'U' /* for _u_nit is rack mounted */
88 #define LOC_VOLTAGE 'V'
89 #define LOC_SWITCH_ADAPTER 'W'
91 #define LOC_FIRMWARE 'Y'
94 /* Tokens for indicators */
95 #define TONE_FREQUENCY 0x0001 /* 0 - 1000 (HZ)*/
96 #define TONE_VOLUME 0x0002 /* 0 - 100 (%) */
97 #define SYSTEM_POWER_STATE 0x0003
98 #define WARNING_LIGHT 0x0004
99 #define DISK_ACTIVITY_LIGHT 0x0005
100 #define HEX_DISPLAY_UNIT 0x0006
101 #define BATTERY_WARNING_TIME 0x0007
102 #define CONDITION_CYCLE_REQUEST 0x0008
103 #define SURVEILLANCE_INDICATOR 0x2328 /* 9000 */
104 #define DR_ACTION 0x2329 /* 9001 */
105 #define DR_INDICATOR 0x232a /* 9002 */
106 /* 9003 - 9004: Vendor specific */
107 #define GLOBAL_INTERRUPT_QUEUE 0x232d /* 9005 */
108 /* 9006 - 9999: Vendor specific */
111 #define MAX_SENSORS 17 /* I only know of 17 sensors */
112 #define MAX_LINELENGTH 256
113 #define SENSOR_PREFIX "ibm,sensor-"
114 #define cel_to_fahr(x) ((x*9/5)+32)
118 static struct proc_dir_entry *proc_rtas;
119 static struct rtas_sensors sensors;
120 static struct device_node *rtas_node;
121 static unsigned long power_on_time = 0; /* Save the time the user set */
122 static char progress_led[MAX_LINELENGTH];
124 static unsigned long rtas_tone_frequency = 1000;
125 static unsigned long rtas_tone_volume = 0;
127 /* ****************STRUCTS******************************************* */
128 struct individual_sensor {
133 struct rtas_sensors {
134 struct individual_sensor sensor[MAX_SENSORS];
138 /* ****************************************************************** */
140 static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off,
141 int count, int *eof, void *data);
142 static ssize_t ppc_rtas_clock_read(struct file * file, char * buf,
143 size_t count, loff_t *ppos);
144 static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf,
145 size_t count, loff_t *ppos);
146 static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
147 size_t count, loff_t *ppos);
148 static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
149 size_t count, loff_t *ppos);
150 static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
151 size_t count, loff_t *ppos);
152 static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
153 size_t count, loff_t *ppos);
155 static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
156 size_t count, loff_t *ppos);
157 static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
158 size_t count, loff_t *ppos);
159 static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
160 size_t count, loff_t *ppos);
161 static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
162 size_t count, loff_t *ppos);
164 struct file_operations ppc_rtas_poweron_operations = {
165 .read = ppc_rtas_poweron_read,
166 .write = ppc_rtas_poweron_write
168 struct file_operations ppc_rtas_progress_operations = {
169 .read = ppc_rtas_progress_read,
170 .write = ppc_rtas_progress_write
173 struct file_operations ppc_rtas_clock_operations = {
174 .read = ppc_rtas_clock_read,
175 .write = ppc_rtas_clock_write
178 struct file_operations ppc_rtas_tone_freq_operations = {
179 .read = ppc_rtas_tone_freq_read,
180 .write = ppc_rtas_tone_freq_write
182 struct file_operations ppc_rtas_tone_volume_operations = {
183 .read = ppc_rtas_tone_volume_read,
184 .write = ppc_rtas_tone_volume_write
187 int ppc_rtas_find_all_sensors (void);
188 int ppc_rtas_process_sensor(struct individual_sensor s, int state,
189 int error, char * buf);
190 char * ppc_rtas_process_error(int error);
191 int get_location_code(struct individual_sensor s, char * buf);
192 int check_location_string (char *c, char * buf);
193 int check_location (char *c, int idx, char * buf);
195 /* ****************************************************************** */
197 /* ****************************************************************** */
198 void proc_rtas_init(void)
200 struct proc_dir_entry *entry;
202 rtas_node = find_devices("rtas");
203 if ((rtas_node == 0) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) {
207 proc_rtas = proc_mkdir("rtas", 0);
211 /* /proc/rtas entries */
213 entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, proc_rtas);
214 if (entry) entry->proc_fops = &ppc_rtas_progress_operations;
216 entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, proc_rtas);
217 if (entry) entry->proc_fops = &ppc_rtas_clock_operations;
219 entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, proc_rtas);
220 if (entry) entry->proc_fops = &ppc_rtas_poweron_operations;
222 create_proc_read_entry("sensors", S_IRUGO, proc_rtas,
223 ppc_rtas_sensor_read, NULL);
225 entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, proc_rtas);
226 if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations;
228 entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas);
229 if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations;
232 /* ****************************************************************** */
234 /* ****************************************************************** */
235 static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
236 size_t count, loff_t *ppos)
239 unsigned long nowtime;
243 nowtime = simple_strtoul(buf, &dest, 10);
244 if (*dest != '\0' && *dest != '\n') {
245 printk("ppc_rtas_poweron_write: Invalid time\n");
248 power_on_time = nowtime; /* save the time */
252 error = rtas_call(rtas_token("set-time-for-power-on"), 7, 1, NULL,
253 tm.tm_year, tm.tm_mon, tm.tm_mday,
254 tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */);
256 printk(KERN_WARNING "error: setting poweron time returned: %s\n",
257 ppc_rtas_process_error(error));
260 /* ****************************************************************** */
261 static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
262 size_t count, loff_t *ppos)
265 if (power_on_time == 0)
266 n = sprintf(buf, "Power on time not set\n");
268 n = sprintf(buf, "%lu\n", power_on_time);
270 if (*ppos >= strlen(buf))
272 if (n > strlen(buf) - *ppos)
273 n = strlen(buf) - *ppos;
280 /* ****************************************************************** */
282 /* ****************************************************************** */
283 static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
284 size_t count, loff_t *ppos)
288 strcpy(progress_led, buf); /* save the string */
289 /* Lets see if the user passed hexdigits */
290 hex = simple_strtoul(buf, NULL, 10);
292 ppc_md.progress ((char *)buf, hex);
295 /* clear the line */ /* ppc_md.progress(" ", 0xffff);*/
297 /* ****************************************************************** */
298 static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
299 size_t count, loff_t *ppos)
302 if (progress_led != NULL)
303 n = sprintf (buf, "%s\n", progress_led);
304 if (*ppos >= strlen(buf))
306 if (n > strlen(buf) - *ppos)
307 n = strlen(buf) - *ppos;
314 /* ****************************************************************** */
316 /* ****************************************************************** */
317 static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf,
318 size_t count, loff_t *ppos)
321 unsigned long nowtime;
325 nowtime = simple_strtoul(buf, &dest, 10);
326 if (*dest != '\0' && *dest != '\n') {
327 printk("ppc_rtas_clock_write: Invalid time\n");
332 error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL,
333 tm.tm_year, tm.tm_mon, tm.tm_mday,
334 tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
336 printk(KERN_WARNING "error: setting the clock returned: %s\n",
337 ppc_rtas_process_error(error));
340 /* ****************************************************************** */
341 static ssize_t ppc_rtas_clock_read(struct file * file, char * buf,
342 size_t count, loff_t *ppos)
344 unsigned int year, mon, day, hour, min, sec;
345 unsigned long *ret = kmalloc(4*8, GFP_KERNEL);
348 error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
350 year = ret[0]; mon = ret[1]; day = ret[2];
351 hour = ret[3]; min = ret[4]; sec = ret[5];
354 printk(KERN_WARNING "error: reading the clock returned: %s\n",
355 ppc_rtas_process_error(error));
356 n = sprintf (buf, "0");
358 n = sprintf (buf, "%lu\n", mktime(year, mon, day, hour, min, sec));
362 if (*ppos >= strlen(buf))
364 if (n > strlen(buf) - *ppos)
365 n = strlen(buf) - *ppos;
372 /* ****************************************************************** */
374 /* ****************************************************************** */
375 static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off,
376 int count, int *eof, void *data)
382 int get_sensor_state = rtas_token("get-sensor-state");
387 /* May not be enough */
388 buffer = kmalloc(MAX_LINELENGTH*MAX_SENSORS, GFP_KERNEL);
393 memset(buffer, 0, MAX_LINELENGTH*MAX_SENSORS);
395 n = sprintf ( buffer , "RTAS (RunTime Abstraction Services) Sensor Information\n");
396 n += sprintf ( buffer+n, "Sensor\t\tValue\t\tCondition\tLocation\n");
397 n += sprintf ( buffer+n, "********************************************************\n");
399 if (ppc_rtas_find_all_sensors() != 0) {
400 n += sprintf ( buffer+n, "\nNo sensors are available\n");
404 for (i=0; i<sensors.quant; i++) {
405 j = sensors.sensor[i].quant;
406 /* A sensor may have multiple instances */
408 error = rtas_call(get_sensor_state, 2, 2, &ret,
409 sensors.sensor[i].token, sensors.sensor[i].quant-j);
411 n += ppc_rtas_process_sensor(sensors.sensor[i], state, error, buffer+n );
412 n += sprintf (buffer+n, "\n");
418 if (off >= strlen(buffer)) {
423 if (n > strlen(buffer) - off)
424 n = strlen(buffer) - off;
429 memcpy(buf, buffer + off, n);
435 /* ****************************************************************** */
437 int ppc_rtas_find_all_sensors (void)
442 utmp = (unsigned long *) get_property(rtas_node, "rtas-sensors", &len);
444 printk (KERN_ERR "error: could not get rtas-sensors\n");
448 sensors.quant = len / 8; /* int + int */
450 for (i=0, j=0; j<sensors.quant; i+=2, j++) {
451 sensors.sensor[j].token = utmp[i];
452 sensors.sensor[j].quant = utmp[i+1];
457 /* ****************************************************************** */
459 * Builds a string of what rtas returned
461 char * ppc_rtas_process_error(int error)
464 case SENSOR_CRITICAL_HIGH:
465 return "(critical high)";
466 case SENSOR_WARNING_HIGH:
467 return "(warning high)";
470 case SENSOR_WARNING_LOW:
471 return "(warning low)";
472 case SENSOR_CRITICAL_LOW:
473 return "(critical low)";
476 case SENSOR_HW_ERROR:
477 return "(hardware error)";
480 case SENSOR_NOT_EXIST:
481 return "(non existant)";
482 case SENSOR_DR_ENTITY:
483 return "(dr entity removed)";
489 /* ****************************************************************** */
491 * Builds a string out of what the sensor said
494 int ppc_rtas_process_sensor(struct individual_sensor s, int state,
495 int error, char * buf)
497 /* Defined return vales */
498 const char * key_switch[] = { "Off\t", "Normal\t", "Secure\t", "Mainenance" };
499 const char * enclosure_switch[] = { "Closed", "Open" };
500 const char * lid_status[] = { " ", "Open", "Closed" };
501 const char * power_source[] = { "AC\t", "Battery", "AC & Battery" };
502 const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" };
503 const char * epow_sensor[] = {
504 "EPOW Reset", "Cooling warning", "Power warning",
505 "System shutdown", "System halt", "EPOW main enclosure",
507 const char * battery_cyclestate[] = { "None", "In progress", "Requested" };
508 const char * battery_charging[] = { "Charging", "Discharching", "No current flow" };
509 const char * ibm_drconnector[] = { "Empty", "Present" };
510 const char * ibm_intqueue[] = { "Disabled", "Enabled" };
512 int have_strings = 0;
517 /* What kind of sensor do we have here? */
520 n += sprintf(buf+n, "Key switch:\t");
521 n += sprintf(buf+n, "%s\t", key_switch[state]);
524 case ENCLOSURE_SWITCH:
525 n += sprintf(buf+n, "Enclosure switch:\t");
526 n += sprintf(buf+n, "%s\t", enclosure_switch[state]);
530 n += sprintf(buf+n, "Temp. (°C/°F):\t");
534 n += sprintf(buf+n, "Lid status:\t");
535 n += sprintf(buf+n, "%s\t", lid_status[state]);
539 n += sprintf(buf+n, "Power source:\t");
540 n += sprintf(buf+n, "%s\t", power_source[state]);
543 case BATTERY_VOLTAGE:
544 n += sprintf(buf+n, "Battery voltage:\t");
546 case BATTERY_REMAINING:
547 n += sprintf(buf+n, "Battery remaining:\t");
548 n += sprintf(buf+n, "%s\t", battery_remaining[state]);
551 case BATTERY_PERCENTAGE:
552 n += sprintf(buf+n, "Battery percentage:\t");
555 n += sprintf(buf+n, "EPOW Sensor:\t");
556 n += sprintf(buf+n, "%s\t", epow_sensor[state]);
559 case BATTERY_CYCLESTATE:
560 n += sprintf(buf+n, "Battery cyclestate:\t");
561 n += sprintf(buf+n, "%s\t", battery_cyclestate[state]);
564 case BATTERY_CHARGING:
565 n += sprintf(buf+n, "Battery Charging:\t");
566 n += sprintf(buf+n, "%s\t", battery_charging[state]);
569 case IBM_SURVEILLANCE:
570 n += sprintf(buf+n, "Surveillance:\t");
573 n += sprintf(buf+n, "Fan (rpm):\t");
576 n += sprintf(buf+n, "Voltage (mv):\t");
578 case IBM_DRCONNECTOR:
579 n += sprintf(buf+n, "DR connector:\t");
580 n += sprintf(buf+n, "%s\t", ibm_drconnector[state]);
583 case IBM_POWERSUPPLY:
584 n += sprintf(buf+n, "Powersupply:\t");
587 n += sprintf(buf+n, "Interrupt queue:\t");
588 n += sprintf(buf+n, "%s\t", ibm_intqueue[state]);
592 n += sprintf(buf+n, "Unkown sensor (type %d), ignoring it\n",
598 if (have_strings == 0) {
600 n += sprintf(buf+n, "%4d /%4d\t", state, cel_to_fahr(state));
602 n += sprintf(buf+n, "%10d\t", state);
605 n += sprintf ( buf+n, "%s\t", ppc_rtas_process_error(error));
606 n += get_location_code(s, buf+n);
611 /* ****************************************************************** */
613 int check_location (char *c, int idx, char * buf)
619 n += sprintf ( buf, "Planar #%c", *(c+idx+1));
622 n += sprintf ( buf, "CPU #%c", *(c+idx+1));
625 n += sprintf ( buf, "Fan #%c", *(c+idx+1));
627 case LOC_RACKMOUNTED:
628 n += sprintf ( buf, "Rack #%c", *(c+idx+1));
631 n += sprintf ( buf, "Voltage #%c", *(c+idx+1));
634 n += sprintf ( buf, "LCD #%c", *(c+idx+1));
637 n += sprintf ( buf, "- %c", *(c+idx+1));
639 n += sprintf ( buf, "Unknown location");
646 /* ****************************************************************** */
649 * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ]
650 * the '.' may be an abbrevation
652 int check_location_string (char *c, char *buf)
657 if (isalpha(c[i]) || c[i] == '.') {
658 n += check_location(c, i, buf+n);
660 else if (c[i] == '/' || c[i] == '-')
661 n += sprintf(buf+n, " at ");
668 /* ****************************************************************** */
670 int get_location_code(struct individual_sensor s, char * buffer)
672 char rstr[512], tmp[10], tmp2[10];
673 int n=0, i=0, llen, len;
674 /* char *buf = kmalloc(MAX_LINELENGTH, GFP_KERNEL); */
677 static int pos = 0; /* remember position where buffer was */
679 /* construct the sensor number like 0003 */
680 /* fill with zeros */
681 n = sprintf(tmp, "%d", s.token);
683 while (strlen(tmp) < 4)
684 n += sprintf (tmp+n, "0");
686 /* invert the string */
689 tmp2[4-len+i] = tmp[i];
696 sprintf (rstr, SENSOR_PREFIX"%s", tmp2);
698 ret = (char *) get_property(rtas_node, rstr, &llen);
702 n += sprintf ( buffer+n, "--- ");/* does not have a location */
707 n += check_location_string(ret, buffer + n);
708 n += sprintf ( buffer+n, " ");
709 /* see how many characters we have printed */
710 sprintf ( t, "%s ", ret);
713 if (pos >= llen) pos=0;
717 /* ****************************************************************** */
718 /* INDICATORS - Tone Frequency */
719 /* ****************************************************************** */
720 static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
721 size_t count, loff_t *ppos)
726 freq = simple_strtoul(buf, &dest, 10);
727 if (*dest != '\0' && *dest != '\n') {
728 printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n");
731 if (freq < 0) freq = 0;
732 rtas_tone_frequency = freq; /* save it for later */
733 error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
734 TONE_FREQUENCY, 0, freq);
736 printk(KERN_WARNING "error: setting tone frequency returned: %s\n",
737 ppc_rtas_process_error(error));
740 /* ****************************************************************** */
741 static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
742 size_t count, loff_t *ppos)
745 n = sprintf(buf, "%lu\n", rtas_tone_frequency);
747 if (*ppos >= strlen(buf))
749 if (n > strlen(buf) - *ppos)
750 n = strlen(buf) - *ppos;
756 /* ****************************************************************** */
757 /* INDICATORS - Tone Volume */
758 /* ****************************************************************** */
759 static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
760 size_t count, loff_t *ppos)
762 unsigned long volume;
765 volume = simple_strtoul(buf, &dest, 10);
766 if (*dest != '\0' && *dest != '\n') {
767 printk("ppc_rtas_tone_volume_write: Invalid tone volume\n");
770 if (volume < 0) volume = 0;
771 if (volume > 100) volume = 100;
773 rtas_tone_volume = volume; /* save it for later */
774 error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
775 TONE_VOLUME, 0, volume);
777 printk(KERN_WARNING "error: setting tone volume returned: %s\n",
778 ppc_rtas_process_error(error));
781 /* ****************************************************************** */
782 static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
783 size_t count, loff_t *ppos)
786 n = sprintf(buf, "%lu\n", rtas_tone_volume);
788 if (*ppos >= strlen(buf))
790 if (n > strlen(buf) - *ppos)
791 n = strlen(buf) - *ppos;