patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / arch / ppc64 / kernel / rtas-proc.c
1 /*
2  *   arch/ppc64/kernel/rtas-proc.c
3  *   Copyright (C) 2000 Tilmann Bitterberg
4  *   (tilmann@bitterberg.de)
5  *
6  *   RTAS (Runtime Abstraction Services) stuff
7  *   Intention is to provide a clean user interface
8  *   to use the RTAS.
9  *
10  *   TODO:
11  *   Split off a header file and maybe move it to a different
12  *   location. Write Documentation on what the /proc/rtas/ entries
13  *   actually do.
14  */
15
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>
23 #include <linux/init.h>
24
25 #include <asm/uaccess.h>
26 #include <asm/bitops.h>
27 #include <asm/processor.h>
28 #include <asm/io.h>
29 #include <asm/prom.h>
30 #include <asm/rtas.h>
31 #include <asm/machdep.h> /* for ppc_md */
32 #include <asm/time.h>
33
34 /* Token for Sensors */
35 #define KEY_SWITCH              0x0001
36 #define ENCLOSURE_SWITCH        0x0002
37 #define THERMAL_SENSOR          0x0003
38 #define LID_STATUS              0x0004
39 #define POWER_SOURCE            0x0005
40 #define BATTERY_VOLTAGE         0x0006
41 #define BATTERY_REMAINING       0x0007
42 #define BATTERY_PERCENTAGE      0x0008
43 #define EPOW_SENSOR             0x0009
44 #define BATTERY_CYCLESTATE      0x000a
45 #define BATTERY_CHARGING        0x000b
46
47 /* IBM specific sensors */
48 #define IBM_SURVEILLANCE        0x2328 /* 9000 */
49 #define IBM_FANRPM              0x2329 /* 9001 */
50 #define IBM_VOLTAGE             0x232a /* 9002 */
51 #define IBM_DRCONNECTOR         0x232b /* 9003 */
52 #define IBM_POWERSUPPLY         0x232c /* 9004 */
53 #define IBM_INTQUEUE            0x232d /* 9005 */
54
55 /* Status return values */
56 #define SENSOR_CRITICAL_HIGH    13
57 #define SENSOR_WARNING_HIGH     12
58 #define SENSOR_NORMAL           11
59 #define SENSOR_WARNING_LOW      10
60 #define SENSOR_CRITICAL_LOW      9
61 #define SENSOR_SUCCESS           0
62 #define SENSOR_HW_ERROR         -1
63 #define SENSOR_BUSY             -2
64 #define SENSOR_NOT_EXIST        -3
65 #define SENSOR_DR_ENTITY        -9000
66
67 /* Location Codes */
68 #define LOC_SCSI_DEV_ADDR       'A'
69 #define LOC_SCSI_DEV_LOC        'B'
70 #define LOC_CPU                 'C'
71 #define LOC_DISKETTE            'D'
72 #define LOC_ETHERNET            'E'
73 #define LOC_FAN                 'F'
74 #define LOC_GRAPHICS            'G'
75 /* reserved / not used          'H' */
76 #define LOC_IO_ADAPTER          'I'
77 /* reserved / not used          'J' */
78 #define LOC_KEYBOARD            'K'
79 #define LOC_LCD                 'L'
80 #define LOC_MEMORY              'M'
81 #define LOC_NV_MEMORY           'N'
82 #define LOC_MOUSE               'O'
83 #define LOC_PLANAR              'P'
84 #define LOC_OTHER_IO            'Q'
85 #define LOC_PARALLEL            'R'
86 #define LOC_SERIAL              'S'
87 #define LOC_DEAD_RING           'T'
88 #define LOC_RACKMOUNTED         'U' /* for _u_nit is rack mounted */
89 #define LOC_VOLTAGE             'V'
90 #define LOC_SWITCH_ADAPTER      'W'
91 #define LOC_OTHER               'X'
92 #define LOC_FIRMWARE            'Y'
93 #define LOC_SCSI                'Z'
94
95 /* Tokens for indicators */
96 #define TONE_FREQUENCY          0x0001 /* 0 - 1000 (HZ)*/
97 #define TONE_VOLUME             0x0002 /* 0 - 100 (%) */
98 #define SYSTEM_POWER_STATE      0x0003 
99 #define WARNING_LIGHT           0x0004
100 #define DISK_ACTIVITY_LIGHT     0x0005
101 #define HEX_DISPLAY_UNIT        0x0006
102 #define BATTERY_WARNING_TIME    0x0007
103 #define CONDITION_CYCLE_REQUEST 0x0008
104 #define SURVEILLANCE_INDICATOR  0x2328 /* 9000 */
105 #define DR_ACTION               0x2329 /* 9001 */
106 #define DR_INDICATOR            0x232a /* 9002 */
107 /* 9003 - 9004: Vendor specific */
108 #define GLOBAL_INTERRUPT_QUEUE  0x232d /* 9005 */
109 /* 9006 - 9999: Vendor specific */
110
111 /* other */
112 #define MAX_SENSORS              17  /* I only know of 17 sensors */    
113 #define MAX_LINELENGTH          256
114 #define SENSOR_PREFIX           "ibm,sensor-"
115 #define cel_to_fahr(x)          ((x*9/5)+32)
116
117
118 /* Globals */
119 static struct rtas_sensors sensors;
120 static struct device_node *rtas_node = NULL;
121 static unsigned long power_on_time = 0; /* Save the time the user set */
122 static char progress_led[MAX_LINELENGTH];
123
124 static unsigned long rtas_tone_frequency = 1000;
125 static unsigned long rtas_tone_volume = 0;
126
127 /* ****************STRUCTS******************************************* */
128 struct individual_sensor {
129         unsigned int token;
130         unsigned int quant;
131 };
132
133 struct rtas_sensors {
134         struct individual_sensor sensor[MAX_SENSORS];
135         unsigned int quant;
136 };
137
138 /* ****************************************************************** */
139 /* Declarations */
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);
154
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);
163 static ssize_t ppc_rtas_rmo_buf_read(struct file *file, char *buf,
164                                     size_t count, loff_t *ppos);
165
166 struct file_operations ppc_rtas_poweron_operations = {
167         .read =         ppc_rtas_poweron_read,
168         .write =        ppc_rtas_poweron_write
169 };
170 struct file_operations ppc_rtas_progress_operations = {
171         .read =         ppc_rtas_progress_read,
172         .write =        ppc_rtas_progress_write
173 };
174
175 struct file_operations ppc_rtas_clock_operations = {
176         .read =         ppc_rtas_clock_read,
177         .write =        ppc_rtas_clock_write
178 };
179
180 struct file_operations ppc_rtas_tone_freq_operations = {
181         .read =         ppc_rtas_tone_freq_read,
182         .write =        ppc_rtas_tone_freq_write
183 };
184 struct file_operations ppc_rtas_tone_volume_operations = {
185         .read =         ppc_rtas_tone_volume_read,
186         .write =        ppc_rtas_tone_volume_write
187 };
188
189 static struct file_operations ppc_rtas_rmo_buf_ops = {
190         .read =         ppc_rtas_rmo_buf_read,
191 };
192
193 int ppc_rtas_find_all_sensors (void);
194 int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
195                 int error, char * buf);
196 char * ppc_rtas_process_error(int error);
197 int get_location_code(struct individual_sensor s, char * buf);
198 int check_location_string (char *c, char * buf);
199 int check_location (char *c, int idx, char * buf);
200
201 static int __init proc_rtas_init(void)
202 {
203         struct proc_dir_entry *entry;
204
205         if (!(systemcfg->platform & PLATFORM_PSERIES))
206                 return 1;
207
208         rtas_node = of_find_node_by_name(NULL, "rtas");
209         if (rtas_node == NULL)
210                 return 1;
211
212         entry = create_proc_entry("ppc64/rtas/progress", S_IRUGO|S_IWUSR, NULL);
213         if (entry)
214                 entry->proc_fops = &ppc_rtas_progress_operations;
215
216         entry = create_proc_entry("ppc64/rtas/clock", S_IRUGO|S_IWUSR, NULL);
217         if (entry)
218                 entry->proc_fops = &ppc_rtas_clock_operations;
219
220         entry = create_proc_entry("ppc64/rtas/poweron", S_IWUSR|S_IRUGO, NULL);
221         if (entry)
222                 entry->proc_fops = &ppc_rtas_poweron_operations;
223
224         create_proc_read_entry("ppc64/rtas/sensors", S_IRUGO, NULL,
225                                ppc_rtas_sensor_read, NULL);
226
227         entry = create_proc_entry("ppc64/rtas/frequency", S_IWUSR|S_IRUGO,
228                                   NULL);
229         if (entry)
230                 entry->proc_fops = &ppc_rtas_tone_freq_operations;
231
232         entry = create_proc_entry("ppc64/rtas/volume", S_IWUSR|S_IRUGO, NULL);
233         if (entry)
234                 entry->proc_fops = &ppc_rtas_tone_volume_operations;
235
236         entry = create_proc_entry("ppc64/rtas/rmo_buffer", S_IRUSR, NULL);
237         if (entry)
238                 entry->proc_fops = &ppc_rtas_rmo_buf_ops;
239
240         return 0;
241 }
242
243 __initcall(proc_rtas_init);
244
245 /* ****************************************************************** */
246 /* POWER-ON-TIME                                                      */
247 /* ****************************************************************** */
248 static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
249                 size_t count, loff_t *ppos)
250 {
251         char stkbuf[40];  /* its small, its on stack */
252         struct rtc_time tm;
253         unsigned long nowtime;
254         char *dest;
255         int error;
256
257         if (39 < count) count = 39;
258         if (copy_from_user (stkbuf, buf, count)) {
259                 return -EFAULT;
260         }
261         stkbuf[count] = 0;
262         nowtime = simple_strtoul(stkbuf, &dest, 10);
263         if (*dest != '\0' && *dest != '\n') {
264                 printk("ppc_rtas_poweron_write: Invalid time\n");
265                 return count;
266         }
267         power_on_time = nowtime; /* save the time */
268
269         to_tm(nowtime, &tm);
270
271         error = rtas_call(rtas_token("set-time-for-power-on"), 7, 1, NULL, 
272                         tm.tm_year, tm.tm_mon, tm.tm_mday, 
273                         tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */);
274         if (error != 0)
275                 printk(KERN_WARNING "error: setting poweron time returned: %s\n", 
276                                 ppc_rtas_process_error(error));
277         return count;
278 }
279 /* ****************************************************************** */
280 static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
281                 size_t count, loff_t *ppos)
282 {
283         char stkbuf[40];  /* its small, its on stack */
284         int n, sn;
285         if (power_on_time == 0)
286                 n = scnprintf(stkbuf,sizeof(stkbuf),"Power on time not set\n");
287         else
288                 n = scnprintf(stkbuf,sizeof(stkbuf),"%lu\n",power_on_time);
289
290         sn = strlen (stkbuf) +1;
291         if (*ppos >= sn)
292                 return 0;
293         if (n > sn - *ppos)
294                 n = sn - *ppos;
295         if (n > count)
296                 n = count;
297         if (copy_to_user (buf, stkbuf + (*ppos), n)) {
298                 return -EFAULT;
299         }
300         *ppos += n;
301         return n;
302 }
303
304 /* ****************************************************************** */
305 /* PROGRESS                                                           */
306 /* ****************************************************************** */
307 static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
308                 size_t count, loff_t *ppos)
309 {
310         unsigned long hex;
311
312         if (count >= MAX_LINELENGTH) count = MAX_LINELENGTH -1;
313         if (copy_from_user (progress_led, buf, count)) { /* save the string */
314                 return -EFAULT;
315         }
316         progress_led[count] = 0;
317
318         /* Lets see if the user passed hexdigits */
319         hex = simple_strtoul(progress_led, NULL, 10);
320
321         ppc_md.progress ((char *)progress_led, hex);
322         return count;
323
324         /* clear the line */ /* ppc_md.progress("                   ", 0xffff);*/
325 }
326 /* ****************************************************************** */
327 static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
328                 size_t count, loff_t *ppos)
329 {
330         int sn, n = 0;
331         char *tmpbuf;
332
333         if (progress_led == NULL) return 0;
334
335         tmpbuf = kmalloc (MAX_LINELENGTH, GFP_KERNEL);
336         if (!tmpbuf) {
337                 printk(KERN_ERR "error: kmalloc failed\n");
338                 return -ENOMEM;
339         }
340         n = sprintf (tmpbuf, "%s\n", progress_led);
341
342         sn = strlen (tmpbuf) +1;
343         if (*ppos >= sn) {
344                 kfree (tmpbuf);
345                 return 0;
346         }
347         if (n > sn - *ppos)
348                 n = sn - *ppos;
349         if (n > count)
350                 n = count;
351         if (copy_to_user (buf, tmpbuf + (*ppos), n)) {
352                 kfree (tmpbuf);
353                 return -EFAULT;
354         }
355         kfree (tmpbuf);
356         *ppos += n;
357         return n;
358 }
359
360 /* ****************************************************************** */
361 /* CLOCK                                                              */
362 /* ****************************************************************** */
363 static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, 
364                 size_t count, loff_t *ppos)
365 {
366         char stkbuf[40];  /* its small, its on stack */
367         struct rtc_time tm;
368         unsigned long nowtime;
369         char *dest;
370         int error;
371
372         if (39 < count) count = 39;
373         if (copy_from_user (stkbuf, buf, count)) {
374                 return -EFAULT;
375         }
376         stkbuf[count] = 0;
377         nowtime = simple_strtoul(stkbuf, &dest, 10);
378         if (*dest != '\0' && *dest != '\n') {
379                 printk("ppc_rtas_clock_write: Invalid time\n");
380                 return count;
381         }
382
383         to_tm(nowtime, &tm);
384         error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL, 
385                         tm.tm_year, tm.tm_mon, tm.tm_mday, 
386                         tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
387         if (error != 0)
388                 printk(KERN_WARNING "error: setting the clock returned: %s\n", 
389                                 ppc_rtas_process_error(error));
390         return count;
391 }
392 /* ****************************************************************** */
393 static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, 
394                 size_t count, loff_t *ppos)
395 {
396         unsigned int year, mon, day, hour, min, sec;
397         unsigned long *ret = kmalloc(4*8, GFP_KERNEL);
398         int n, sn, error;
399         char stkbuf[40];  /* its small, its on stack */
400
401         error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
402         
403         year = ret[0]; mon  = ret[1]; day  = ret[2];
404         hour = ret[3]; min  = ret[4]; sec  = ret[5];
405
406         if (error != 0){
407                 printk(KERN_WARNING "error: reading the clock returned: %s\n", 
408                                 ppc_rtas_process_error(error));
409                 n = scnprintf (stkbuf, sizeof(stkbuf), "0");
410         } else { 
411                 n = scnprintf (stkbuf, sizeof(stkbuf), "%lu\n",
412                                 mktime(year, mon, day, hour, min, sec));
413         }
414         kfree(ret);
415
416         sn = strlen (stkbuf) +1;
417         if (*ppos >= sn)
418                 return 0;
419         if (n > sn - *ppos)
420                 n = sn - *ppos;
421         if (n > count)
422                 n = count;
423         if (copy_to_user (buf, stkbuf + (*ppos), n)) {
424                 return -EFAULT;
425         }
426         *ppos += n;
427         return n;
428 }
429
430 /* ****************************************************************** */
431 /* SENSOR STUFF                                                       */
432 /* ****************************************************************** */
433 static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off,
434                 int count, int *eof, void *data)
435 {
436         int i,j,n;
437         unsigned long ret;
438         int state, error;
439         char *buffer;
440         int get_sensor_state = rtas_token("get-sensor-state");
441
442         if (count < 0)
443                 return -EINVAL;
444
445         /* May not be enough */
446         buffer = kmalloc(MAX_LINELENGTH*MAX_SENSORS, GFP_KERNEL);
447
448         if (!buffer)
449                 return -ENOMEM;
450
451         memset(buffer, 0, MAX_LINELENGTH*MAX_SENSORS);
452
453         n  = sprintf ( buffer  , "RTAS (RunTime Abstraction Services) Sensor Information\n");
454         n += sprintf ( buffer+n, "Sensor\t\tValue\t\tCondition\tLocation\n");
455         n += sprintf ( buffer+n, "********************************************************\n");
456
457         if (ppc_rtas_find_all_sensors() != 0) {
458                 n += sprintf ( buffer+n, "\nNo sensors are available\n");
459                 goto return_string;
460         }
461
462         for (i=0; i<sensors.quant; i++) {
463                 j = sensors.sensor[i].quant;
464                 /* A sensor may have multiple instances */
465                 while (j >= 0) {
466
467                         error = rtas_call(get_sensor_state, 2, 2, &ret, 
468                                           sensors.sensor[i].token, 
469                                           sensors.sensor[i].quant - j);
470
471                         state = (int) ret;
472                         n += ppc_rtas_process_sensor(sensors.sensor[i], state, 
473                                                      error, buffer+n );
474                         n += sprintf (buffer+n, "\n");
475                         j--;
476                 } /* while */
477         } /* for */
478
479 return_string:
480         if (off >= strlen(buffer)) {
481                 *eof = 1;
482                 kfree(buffer);
483                 return 0;
484         }
485         if (n > strlen(buffer) - off)
486                 n = strlen(buffer) - off;
487         if (n > count)
488                 n = count;
489         else
490                 *eof = 1;
491
492         memcpy(buf, buffer + off, n);
493         *start = buf;
494         kfree(buffer);
495         return n;
496 }
497
498 /* ****************************************************************** */
499
500 int ppc_rtas_find_all_sensors (void)
501 {
502         unsigned int *utmp;
503         int len, i;
504
505         utmp = (unsigned int *) get_property(rtas_node, "rtas-sensors", &len);
506         if (utmp == NULL) {
507                 printk (KERN_ERR "error: could not get rtas-sensors\n");
508                 return 1;
509         }
510
511         sensors.quant = len / 8;      /* int + int */
512
513         for (i=0; i<sensors.quant; i++) {
514                 sensors.sensor[i].token = *utmp++;
515                 sensors.sensor[i].quant = *utmp++;
516         }
517         return 0;
518 }
519
520 /* ****************************************************************** */
521 /*
522  * Builds a string of what rtas returned
523  */
524 char * ppc_rtas_process_error(int error)
525 {
526         switch (error) {
527                 case SENSOR_CRITICAL_HIGH:
528                         return "(critical high)";
529                 case SENSOR_WARNING_HIGH:
530                         return "(warning high)";
531                 case SENSOR_NORMAL:
532                         return "(normal)";
533                 case SENSOR_WARNING_LOW:
534                         return "(warning low)";
535                 case SENSOR_CRITICAL_LOW:
536                         return "(critical low)";
537                 case SENSOR_SUCCESS:
538                         return "(read ok)";
539                 case SENSOR_HW_ERROR:
540                         return "(hardware error)";
541                 case SENSOR_BUSY:
542                         return "(busy)";
543                 case SENSOR_NOT_EXIST:
544                         return "(non existent)";
545                 case SENSOR_DR_ENTITY:
546                         return "(dr entity removed)";
547                 default:
548                         return "(UNKNOWN)";
549         }
550 }
551
552 /* ****************************************************************** */
553 /*
554  * Builds a string out of what the sensor said
555  */
556
557 int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
558                 int error, char * buf) 
559 {
560         /* Defined return vales */
561         const char * key_switch[]        = { "Off\t", "Normal\t", "Secure\t", 
562                                                 "Maintenance" };
563         const char * enclosure_switch[]  = { "Closed", "Open" };
564         const char * lid_status[]        = { " ", "Open", "Closed" };
565         const char * power_source[]      = { "AC\t", "Battery", 
566                                                 "AC & Battery" };
567         const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" };
568         const char * epow_sensor[]       = { 
569                 "EPOW Reset", "Cooling warning", "Power warning",
570                 "System shutdown", "System halt", "EPOW main enclosure",
571                 "EPOW power off" };
572         const char * battery_cyclestate[]  = { "None", "In progress", 
573                                                 "Requested" };
574         const char * battery_charging[]    = { "Charging", "Discharching", 
575                                                 "No current flow" };
576         const char * ibm_drconnector[]     = { "Empty", "Present", "Unusable", 
577                                                 "Exchange" };
578         const char * ibm_intqueue[]        = { "Disabled", "Enabled" };
579
580         int have_strings = 0;
581         int num_states = 0;
582         int temperature = 0;
583         int unknown = 0;
584         int n = 0;
585
586         /* What kind of sensor do we have here? */
587         
588         switch (s.token) {
589                 case KEY_SWITCH:
590                         n += sprintf(buf+n, "Key switch:\t");
591                         num_states = sizeof(key_switch) / sizeof(char *);
592                         if (state < num_states) {
593                                 n += sprintf(buf+n, "%s\t", key_switch[state]);
594                                 have_strings = 1;
595                         }
596                         break;
597                 case ENCLOSURE_SWITCH:
598                         n += sprintf(buf+n, "Enclosure switch:\t");
599                         num_states = sizeof(enclosure_switch) / sizeof(char *);
600                         if (state < num_states) {
601                                 n += sprintf(buf+n, "%s\t", 
602                                                 enclosure_switch[state]);
603                                 have_strings = 1;
604                         }
605                         break;
606                 case THERMAL_SENSOR:
607                         n += sprintf(buf+n, "Temp. (°C/°F):\t");
608                         temperature = 1;
609                         break;
610                 case LID_STATUS:
611                         n += sprintf(buf+n, "Lid status:\t");
612                         num_states = sizeof(lid_status) / sizeof(char *);
613                         if (state < num_states) {
614                                 n += sprintf(buf+n, "%s\t", lid_status[state]);
615                                 have_strings = 1;
616                         }
617                         break;
618                 case POWER_SOURCE:
619                         n += sprintf(buf+n, "Power source:\t");
620                         num_states = sizeof(power_source) / sizeof(char *);
621                         if (state < num_states) {
622                                 n += sprintf(buf+n, "%s\t", 
623                                                 power_source[state]);
624                                 have_strings = 1;
625                         }
626                         break;
627                 case BATTERY_VOLTAGE:
628                         n += sprintf(buf+n, "Battery voltage:\t");
629                         break;
630                 case BATTERY_REMAINING:
631                         n += sprintf(buf+n, "Battery remaining:\t");
632                         num_states = sizeof(battery_remaining) / sizeof(char *);
633                         if (state < num_states)
634                         {
635                                 n += sprintf(buf+n, "%s\t", 
636                                                 battery_remaining[state]);
637                                 have_strings = 1;
638                         }
639                         break;
640                 case BATTERY_PERCENTAGE:
641                         n += sprintf(buf+n, "Battery percentage:\t");
642                         break;
643                 case EPOW_SENSOR:
644                         n += sprintf(buf+n, "EPOW Sensor:\t");
645                         num_states = sizeof(epow_sensor) / sizeof(char *);
646                         if (state < num_states) {
647                                 n += sprintf(buf+n, "%s\t", epow_sensor[state]);
648                                 have_strings = 1;
649                         }
650                         break;
651                 case BATTERY_CYCLESTATE:
652                         n += sprintf(buf+n, "Battery cyclestate:\t");
653                         num_states = sizeof(battery_cyclestate) / 
654                                         sizeof(char *);
655                         if (state < num_states) {
656                                 n += sprintf(buf+n, "%s\t", 
657                                                 battery_cyclestate[state]);
658                                 have_strings = 1;
659                         }
660                         break;
661                 case BATTERY_CHARGING:
662                         n += sprintf(buf+n, "Battery Charging:\t");
663                         num_states = sizeof(battery_charging) / sizeof(char *);
664                         if (state < num_states) {
665                                 n += sprintf(buf+n, "%s\t", 
666                                                 battery_charging[state]);
667                                 have_strings = 1;
668                         }
669                         break;
670                 case IBM_SURVEILLANCE:
671                         n += sprintf(buf+n, "Surveillance:\t");
672                         break;
673                 case IBM_FANRPM:
674                         n += sprintf(buf+n, "Fan (rpm):\t");
675                         break;
676                 case IBM_VOLTAGE:
677                         n += sprintf(buf+n, "Voltage (mv):\t");
678                         break;
679                 case IBM_DRCONNECTOR:
680                         n += sprintf(buf+n, "DR connector:\t");
681                         num_states = sizeof(ibm_drconnector) / sizeof(char *);
682                         if (state < num_states) {
683                                 n += sprintf(buf+n, "%s\t", 
684                                                 ibm_drconnector[state]);
685                                 have_strings = 1;
686                         }
687                         break;
688                 case IBM_POWERSUPPLY:
689                         n += sprintf(buf+n, "Powersupply:\t");
690                         break;
691                 case IBM_INTQUEUE:
692                         n += sprintf(buf+n, "Interrupt queue:\t");
693                         num_states = sizeof(ibm_intqueue) / sizeof(char *);
694                         if (state < num_states) {
695                                 n += sprintf(buf+n, "%s\t", 
696                                                 ibm_intqueue[state]);
697                                 have_strings = 1;
698                         }
699                         break;
700                 default:
701                         n += sprintf(buf+n,  "Unknown sensor (type %d), ignoring it\n",
702                                         s.token);
703                         unknown = 1;
704                         have_strings = 1;
705                         break;
706         }
707         if (have_strings == 0) {
708                 if (temperature) {
709                         n += sprintf(buf+n, "%4d /%4d\t", state, cel_to_fahr(state));
710                 } else
711                         n += sprintf(buf+n, "%10d\t", state);
712         }
713         if (unknown == 0) {
714                 n += sprintf ( buf+n, "%s\t", ppc_rtas_process_error(error));
715                 n += get_location_code(s, buf+n);
716         }
717         return n;
718 }
719
720 /* ****************************************************************** */
721
722 int check_location (char *c, int idx, char * buf)
723 {
724         int n = 0;
725
726         switch (*(c+idx)) {
727                 case LOC_PLANAR:
728                         n += sprintf ( buf, "Planar #%c", *(c+idx+1));
729                         break;
730                 case LOC_CPU:
731                         n += sprintf ( buf, "CPU #%c", *(c+idx+1));
732                         break;
733                 case LOC_FAN:
734                         n += sprintf ( buf, "Fan #%c", *(c+idx+1));
735                         break;
736                 case LOC_RACKMOUNTED:
737                         n += sprintf ( buf, "Rack #%c", *(c+idx+1));
738                         break;
739                 case LOC_VOLTAGE:
740                         n += sprintf ( buf, "Voltage #%c", *(c+idx+1));
741                         break;
742                 case LOC_LCD:
743                         n += sprintf ( buf, "LCD #%c", *(c+idx+1));
744                         break;
745                 case '.':
746                         n += sprintf ( buf, "- %c", *(c+idx+1));
747                 default:
748                         n += sprintf ( buf, "Unknown location");
749                         break;
750         }
751         return n;
752 }
753
754
755 /* ****************************************************************** */
756 /* 
757  * Format: 
758  * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ]
759  * the '.' may be an abbrevation
760  */
761 int check_location_string (char *c, char *buf)
762 {
763         int n=0,i=0;
764
765         while (c[i]) {
766                 if (isalpha(c[i]) || c[i] == '.') {
767                          n += check_location(c, i, buf+n);
768                 }
769                 else if (c[i] == '/' || c[i] == '-')
770                         n += sprintf(buf+n, " at ");
771                 i++;
772         }
773         return n;
774 }
775
776
777 /* ****************************************************************** */
778
779 int get_location_code(struct individual_sensor s, char * buffer)
780 {
781         char rstr[512], tmp[10], tmp2[10];
782         int n=0, i=0, llen, len;
783         /* char *buf = kmalloc(MAX_LINELENGTH, GFP_KERNEL); */
784         char *ret;
785
786         static int pos = 0; /* remember position where buffer was */
787
788         /* construct the sensor number like 0003 */
789         /* fill with zeros */
790         n = sprintf(tmp, "%d", s.token);
791         len = strlen(tmp);
792         while (strlen(tmp) < 4)
793                 n += sprintf (tmp+n, "0");
794         
795         /* invert the string */
796         while (tmp[i]) {
797                 if (i<len)
798                         tmp2[4-len+i] = tmp[i];
799                 else
800                         tmp2[3-i] = tmp[i];
801                 i++;
802         }
803         tmp2[4] = '\0';
804
805         sprintf (rstr, SENSOR_PREFIX"%s", tmp2);
806
807         ret = (char *) get_property(rtas_node, rstr, &llen);
808
809         n=0;
810         if (ret == NULL || ret[0] == '\0') {
811                 n += sprintf ( buffer+n, "--- ");/* does not have a location */
812         } else {
813                 char t[50];
814                 ret += pos;
815
816                 n += check_location_string(ret, buffer + n);
817                 n += sprintf ( buffer+n, " ");
818                 /* see how many characters we have printed */
819                 scnprintf(t, sizeof(t), "%s ", ret);
820
821                 pos += strlen(t);
822                 if (pos >= llen) pos=0;
823         }
824         return n;
825 }
826 /* ****************************************************************** */
827 /* INDICATORS - Tone Frequency                                        */
828 /* ****************************************************************** */
829 static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
830                 size_t count, loff_t *ppos)
831 {
832         char stkbuf[40];  /* its small, its on stack */
833         unsigned long freq;
834         char *dest;
835         int error;
836
837         if (39 < count) count = 39;
838         if (copy_from_user (stkbuf, buf, count)) {
839                 return -EFAULT;
840         }
841         stkbuf[count] = 0;
842         freq = simple_strtoul(stkbuf, &dest, 10);
843         if (*dest != '\0' && *dest != '\n') {
844                 printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n");
845                 return count;
846         }
847         if (freq < 0) freq = 0;
848         rtas_tone_frequency = freq; /* save it for later */
849         error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
850                         TONE_FREQUENCY, 0, freq);
851         if (error != 0)
852                 printk(KERN_WARNING "error: setting tone frequency returned: %s\n", 
853                                 ppc_rtas_process_error(error));
854         return count;
855 }
856 /* ****************************************************************** */
857 static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
858                 size_t count, loff_t *ppos)
859 {
860         int n, sn;
861         char stkbuf[40];  /* its small, its on stack */
862
863         n = scnprintf(stkbuf, 40, "%lu\n", rtas_tone_frequency);
864
865         sn = strlen (stkbuf) +1;
866         if (*ppos >= sn)
867                 return 0;
868         if (n > sn - *ppos)
869                 n = sn - *ppos;
870         if (n > count)
871                 n = count;
872         if (copy_to_user (buf, stkbuf + (*ppos), n)) {
873                 return -EFAULT;
874         }
875         *ppos += n;
876         return n;
877 }
878 /* ****************************************************************** */
879 /* INDICATORS - Tone Volume                                           */
880 /* ****************************************************************** */
881 static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
882                 size_t count, loff_t *ppos)
883 {
884         char stkbuf[40];  /* its small, its on stack */
885         unsigned long volume;
886         char *dest;
887         int error;
888
889         if (39 < count) count = 39;
890         if (copy_from_user (stkbuf, buf, count)) {
891                 return -EFAULT;
892         }
893         stkbuf[count] = 0;
894         volume = simple_strtoul(stkbuf, &dest, 10);
895         if (*dest != '\0' && *dest != '\n') {
896                 printk("ppc_rtas_tone_volume_write: Invalid tone volume\n");
897                 return count;
898         }
899         if (volume < 0) volume = 0;
900         if (volume > 100) volume = 100;
901         
902         rtas_tone_volume = volume; /* save it for later */
903         error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
904                         TONE_VOLUME, 0, volume);
905         if (error != 0)
906                 printk(KERN_WARNING "error: setting tone volume returned: %s\n", 
907                                 ppc_rtas_process_error(error));
908         return count;
909 }
910 /* ****************************************************************** */
911 static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
912                 size_t count, loff_t *ppos)
913 {
914         int n, sn;
915         char stkbuf[40];  /* its small, its on stack */
916
917         n = scnprintf(stkbuf, 40, "%lu\n", rtas_tone_volume);
918
919         sn = strlen (stkbuf) +1;
920         if (*ppos >= sn)
921                 return 0;
922         if (n > sn - *ppos)
923                 n = sn - *ppos;
924         if (n > count)
925                 n = count;
926         if (copy_to_user (buf, stkbuf + (*ppos), n)) {
927                 return -EFAULT;
928         }
929         *ppos += n;
930         return n;
931 }
932
933 #define RMO_READ_BUF_MAX 30
934
935 /* RTAS Userspace access */
936 static ssize_t ppc_rtas_rmo_buf_read(struct file *file, char __user *buf,
937                                     size_t count, loff_t *ppos)
938 {
939         char kbuf[RMO_READ_BUF_MAX];
940         int n;
941
942         n = sprintf(kbuf, "%016lx %x\n", rtas_rmo_buf, RTAS_RMOBUF_MAX);
943         if (n > count)
944                 n = count;
945
946         if (ppos && *ppos != 0)
947                 return 0;
948
949         if (copy_to_user(buf, kbuf, n))
950                 return -EFAULT;
951
952         if (ppos)
953                 *ppos = n;
954         
955         return n;
956 }