cleanup
[linux-2.4.21-pre4.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
24 #include <asm/uaccess.h>
25 #include <asm/bitops.h>
26 #include <asm/processor.h>
27 #include <asm/io.h>
28 #include <asm/prom.h>
29 #include <asm/rtas.h>
30 #include <asm/machdep.h> /* for ppc_md */
31 #include <asm/time.h>
32
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
45
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 */
53
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
65
66 /* Location Codes */
67 #define LOC_SCSI_DEV_ADDR       'A'
68 #define LOC_SCSI_DEV_LOC        'B'
69 #define LOC_CPU                 'C'
70 #define LOC_DISKETTE            'D'
71 #define LOC_ETHERNET            'E'
72 #define LOC_FAN                 'F'
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'
78 #define LOC_LCD                 'L'
79 #define LOC_MEMORY              'M'
80 #define LOC_NV_MEMORY           'N'
81 #define LOC_MOUSE               'O'
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'
90 #define LOC_OTHER               'X'
91 #define LOC_FIRMWARE            'Y'
92 #define LOC_SCSI                'Z'
93
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 */
109
110 /* other */
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)
115
116
117 /* Globals */
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];
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
164 struct file_operations ppc_rtas_poweron_operations = {
165         .read =         ppc_rtas_poweron_read,
166         .write =        ppc_rtas_poweron_write
167 };
168 struct file_operations ppc_rtas_progress_operations = {
169         .read =         ppc_rtas_progress_read,
170         .write =        ppc_rtas_progress_write
171 };
172
173 struct file_operations ppc_rtas_clock_operations = {
174         .read =         ppc_rtas_clock_read,
175         .write =        ppc_rtas_clock_write
176 };
177
178 struct file_operations ppc_rtas_tone_freq_operations = {
179         .read =         ppc_rtas_tone_freq_read,
180         .write =        ppc_rtas_tone_freq_write
181 };
182 struct file_operations ppc_rtas_tone_volume_operations = {
183         .read =         ppc_rtas_tone_volume_read,
184         .write =        ppc_rtas_tone_volume_write
185 };
186
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);
194
195 /* ****************************************************************** */
196 /* MAIN                                                               */
197 /* ****************************************************************** */
198 void proc_rtas_init(void)
199 {
200         struct proc_dir_entry *entry;
201
202         rtas_node = find_devices("rtas");
203         if ((rtas_node == 0) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) {
204                 return;
205         }
206         
207         proc_rtas = proc_mkdir("rtas", 0);
208         if (proc_rtas == 0)
209                 return;
210
211         /* /proc/rtas entries */
212
213         entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, proc_rtas);
214         if (entry) entry->proc_fops = &ppc_rtas_progress_operations;
215
216         entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, proc_rtas); 
217         if (entry) entry->proc_fops = &ppc_rtas_clock_operations;
218
219         entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, proc_rtas); 
220         if (entry) entry->proc_fops = &ppc_rtas_poweron_operations;
221
222         create_proc_read_entry("sensors", S_IRUGO, proc_rtas, 
223                         ppc_rtas_sensor_read, NULL);
224         
225         entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, proc_rtas); 
226         if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations;
227
228         entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas); 
229         if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations;
230 }
231
232 /* ****************************************************************** */
233 /* POWER-ON-TIME                                                      */
234 /* ****************************************************************** */
235 static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
236                 size_t count, loff_t *ppos)
237 {
238         struct rtc_time tm;
239         unsigned long nowtime;
240         char *dest;
241         int error;
242
243         nowtime = simple_strtoul(buf, &dest, 10);
244         if (*dest != '\0' && *dest != '\n') {
245                 printk("ppc_rtas_poweron_write: Invalid time\n");
246                 return count;
247         }
248         power_on_time = nowtime; /* save the time */
249
250         to_tm(nowtime, &tm);
251
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 */);
255         if (error != 0)
256                 printk(KERN_WARNING "error: setting poweron time returned: %s\n", 
257                                 ppc_rtas_process_error(error));
258         return count;
259 }
260 /* ****************************************************************** */
261 static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
262                 size_t count, loff_t *ppos)
263 {
264         int n;
265         if (power_on_time == 0)
266                 n = sprintf(buf, "Power on time not set\n");
267         else
268                 n = sprintf(buf, "%lu\n", power_on_time);
269
270         if (*ppos >= strlen(buf))
271                 return 0;
272         if (n > strlen(buf) - *ppos)
273                 n = strlen(buf) - *ppos;
274         if (n > count)
275                 n = count;
276         *ppos += n;
277         return n;
278 }
279
280 /* ****************************************************************** */
281 /* PROGRESS                                                           */
282 /* ****************************************************************** */
283 static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
284                 size_t count, loff_t *ppos)
285 {
286         unsigned long hex;
287
288         strcpy(progress_led, buf); /* save the string */
289         /* Lets see if the user passed hexdigits */
290         hex = simple_strtoul(buf, NULL, 10);
291         
292         ppc_md.progress ((char *)buf, hex);
293         return count;
294
295         /* clear the line */ /* ppc_md.progress("                   ", 0xffff);*/
296 }
297 /* ****************************************************************** */
298 static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
299                 size_t count, loff_t *ppos)
300 {
301         int n = 0;
302         if (progress_led != NULL)
303                 n = sprintf (buf, "%s\n", progress_led);
304         if (*ppos >= strlen(buf))
305                 return 0;
306         if (n > strlen(buf) - *ppos)
307                 n = strlen(buf) - *ppos;
308         if (n > count)
309                 n = count;
310         *ppos += n;
311         return n;
312 }
313
314 /* ****************************************************************** */
315 /* CLOCK                                                              */
316 /* ****************************************************************** */
317 static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, 
318                 size_t count, loff_t *ppos)
319 {
320         struct rtc_time tm;
321         unsigned long nowtime;
322         char *dest;
323         int error;
324
325         nowtime = simple_strtoul(buf, &dest, 10);
326         if (*dest != '\0' && *dest != '\n') {
327                 printk("ppc_rtas_clock_write: Invalid time\n");
328                 return count;
329         }
330
331         to_tm(nowtime, &tm);
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);
335         if (error != 0)
336                 printk(KERN_WARNING "error: setting the clock returned: %s\n", 
337                                 ppc_rtas_process_error(error));
338         return count;
339 }
340 /* ****************************************************************** */
341 static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, 
342                 size_t count, loff_t *ppos)
343 {
344         unsigned int year, mon, day, hour, min, sec;
345         unsigned long *ret = kmalloc(4*8, GFP_KERNEL);
346         int n, error;
347
348         error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
349         
350         year = ret[0]; mon  = ret[1]; day  = ret[2];
351         hour = ret[3]; min  = ret[4]; sec  = ret[5];
352
353         if (error != 0){
354                 printk(KERN_WARNING "error: reading the clock returned: %s\n", 
355                                 ppc_rtas_process_error(error));
356                 n = sprintf (buf, "0");
357         } else { 
358                 n = sprintf (buf, "%lu\n", mktime(year, mon, day, hour, min, sec));
359         }
360         kfree(ret);
361
362         if (*ppos >= strlen(buf))
363                 return 0;
364         if (n > strlen(buf) - *ppos)
365                 n = strlen(buf) - *ppos;
366         if (n > count)
367                 n = count;
368         *ppos += n;
369         return n;
370 }
371
372 /* ****************************************************************** */
373 /* SENSOR STUFF                                                       */
374 /* ****************************************************************** */
375 static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off,
376                 int count, int *eof, void *data)
377 {
378         int i,j,n;
379         unsigned long ret;
380         int state, error;
381         char *buffer;
382         int get_sensor_state = rtas_token("get-sensor-state");
383
384         if (count < 0)
385                 return -EINVAL;
386
387         /* May not be enough */
388         buffer = kmalloc(MAX_LINELENGTH*MAX_SENSORS, GFP_KERNEL);
389
390         if (!buffer)
391                 return -ENOMEM;
392
393         memset(buffer, 0, MAX_LINELENGTH*MAX_SENSORS);
394
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");
398
399         if (ppc_rtas_find_all_sensors() != 0) {
400                 n += sprintf ( buffer+n, "\nNo sensors are available\n");
401                 goto return_string;
402         }
403
404         for (i=0; i<sensors.quant; i++) {
405                 j = sensors.sensor[i].quant;
406                 /* A sensor may have multiple instances */
407                 while (j >= 0) {
408                         error = rtas_call(get_sensor_state, 2, 2, &ret, 
409                                   sensors.sensor[i].token, sensors.sensor[i].quant-j);
410                         state = (int) ret;
411                         n += ppc_rtas_process_sensor(sensors.sensor[i], state, error, buffer+n );
412                         n += sprintf (buffer+n, "\n");
413                         j--;
414                 } /* while */
415         } /* for */
416
417 return_string:
418         if (off >= strlen(buffer)) {
419                 *eof = 1;
420                 kfree(buffer);
421                 return 0;
422         }
423         if (n > strlen(buffer) - off)
424                 n = strlen(buffer) - off;
425         if (n > count)
426                 n = count;
427         else
428                 *eof = 1;
429         memcpy(buf, buffer + off, n);
430         *start = buf;
431         kfree(buffer);
432         return n;
433 }
434
435 /* ****************************************************************** */
436
437 int ppc_rtas_find_all_sensors (void)
438 {
439         unsigned long *utmp;
440         int len, i, j;
441
442         utmp = (unsigned long *) get_property(rtas_node, "rtas-sensors", &len);
443         if (utmp == NULL) {
444                 printk (KERN_ERR "error: could not get rtas-sensors\n");
445                 return 1;
446         }
447
448         sensors.quant = len / 8;      /* int + int */
449
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];
453         }
454         return 0;
455 }
456
457 /* ****************************************************************** */
458 /*
459  * Builds a string of what rtas returned
460  */
461 char * ppc_rtas_process_error(int error)
462 {
463         switch (error) {
464                 case SENSOR_CRITICAL_HIGH:
465                         return "(critical high)";
466                 case SENSOR_WARNING_HIGH:
467                         return "(warning high)";
468                 case SENSOR_NORMAL:
469                         return "(normal)";
470                 case SENSOR_WARNING_LOW:
471                         return "(warning low)";
472                 case SENSOR_CRITICAL_LOW:
473                         return "(critical low)";
474                 case SENSOR_SUCCESS:
475                         return "(read ok)";
476                 case SENSOR_HW_ERROR:
477                         return "(hardware error)";
478                 case SENSOR_BUSY:
479                         return "(busy)";
480                 case SENSOR_NOT_EXIST:
481                         return "(non existant)";
482                 case SENSOR_DR_ENTITY:
483                         return "(dr entity removed)";
484                 default:
485                         return "(UNKNOWN)";
486         }
487 }
488
489 /* ****************************************************************** */
490 /*
491  * Builds a string out of what the sensor said
492  */
493
494 int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
495                 int error, char * buf) 
496 {
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",
506                 "EPOW power off" };
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" };
511
512         int have_strings = 0;
513         int temperature = 0;
514         int unknown = 0;
515         int n = 0;
516
517         /* What kind of sensor do we have here? */
518         switch (s.token) {
519                 case KEY_SWITCH:
520                         n += sprintf(buf+n, "Key switch:\t");
521                         n += sprintf(buf+n, "%s\t", key_switch[state]);
522                         have_strings = 1;
523                         break;
524                 case ENCLOSURE_SWITCH:
525                         n += sprintf(buf+n, "Enclosure switch:\t");
526                         n += sprintf(buf+n, "%s\t", enclosure_switch[state]);
527                         have_strings = 1;
528                         break;
529                 case THERMAL_SENSOR:
530                         n += sprintf(buf+n, "Temp. (°C/°F):\t");
531                         temperature = 1;
532                         break;
533                 case LID_STATUS:
534                         n += sprintf(buf+n, "Lid status:\t");
535                         n += sprintf(buf+n, "%s\t", lid_status[state]);
536                         have_strings = 1;
537                         break;
538                 case POWER_SOURCE:
539                         n += sprintf(buf+n, "Power source:\t");
540                         n += sprintf(buf+n, "%s\t", power_source[state]);
541                         have_strings = 1;
542                         break;
543                 case BATTERY_VOLTAGE:
544                         n += sprintf(buf+n, "Battery voltage:\t");
545                         break;
546                 case BATTERY_REMAINING:
547                         n += sprintf(buf+n, "Battery remaining:\t");
548                         n += sprintf(buf+n, "%s\t", battery_remaining[state]);
549                         have_strings = 1;
550                         break;
551                 case BATTERY_PERCENTAGE:
552                         n += sprintf(buf+n, "Battery percentage:\t");
553                         break;
554                 case EPOW_SENSOR:
555                         n += sprintf(buf+n, "EPOW Sensor:\t");
556                         n += sprintf(buf+n, "%s\t", epow_sensor[state]);
557                         have_strings = 1;
558                         break;
559                 case BATTERY_CYCLESTATE:
560                         n += sprintf(buf+n, "Battery cyclestate:\t");
561                         n += sprintf(buf+n, "%s\t", battery_cyclestate[state]);
562                         have_strings = 1;
563                         break;
564                 case BATTERY_CHARGING:
565                         n += sprintf(buf+n, "Battery Charging:\t");
566                         n += sprintf(buf+n, "%s\t", battery_charging[state]);
567                         have_strings = 1;
568                         break;
569                 case IBM_SURVEILLANCE:
570                         n += sprintf(buf+n, "Surveillance:\t");
571                         break;
572                 case IBM_FANRPM:
573                         n += sprintf(buf+n, "Fan (rpm):\t");
574                         break;
575                 case IBM_VOLTAGE:
576                         n += sprintf(buf+n, "Voltage (mv):\t");
577                         break;
578                 case IBM_DRCONNECTOR:
579                         n += sprintf(buf+n, "DR connector:\t");
580                         n += sprintf(buf+n, "%s\t", ibm_drconnector[state]);
581                         have_strings = 1;
582                         break;
583                 case IBM_POWERSUPPLY:
584                         n += sprintf(buf+n, "Powersupply:\t");
585                         break;
586                 case IBM_INTQUEUE:
587                         n += sprintf(buf+n, "Interrupt queue:\t");
588                         n += sprintf(buf+n, "%s\t", ibm_intqueue[state]);
589                         have_strings = 1;
590                         break;
591                 default:
592                         n += sprintf(buf+n,  "Unkown sensor (type %d), ignoring it\n",
593                                         s.token);
594                         unknown = 1;
595                         have_strings = 1;
596                         break;
597         }
598         if (have_strings == 0) {
599                 if (temperature) {
600                         n += sprintf(buf+n, "%4d /%4d\t", state, cel_to_fahr(state));
601                 } else
602                         n += sprintf(buf+n, "%10d\t", state);
603         }
604         if (unknown == 0) {
605                 n += sprintf ( buf+n, "%s\t", ppc_rtas_process_error(error));
606                 n += get_location_code(s, buf+n);
607         }
608         return n;
609 }
610
611 /* ****************************************************************** */
612
613 int check_location (char *c, int idx, char * buf)
614 {
615         int n = 0;
616
617         switch (*(c+idx)) {
618                 case LOC_PLANAR:
619                         n += sprintf ( buf, "Planar #%c", *(c+idx+1));
620                         break;
621                 case LOC_CPU:
622                         n += sprintf ( buf, "CPU #%c", *(c+idx+1));
623                         break;
624                 case LOC_FAN:
625                         n += sprintf ( buf, "Fan #%c", *(c+idx+1));
626                         break;
627                 case LOC_RACKMOUNTED:
628                         n += sprintf ( buf, "Rack #%c", *(c+idx+1));
629                         break;
630                 case LOC_VOLTAGE:
631                         n += sprintf ( buf, "Voltage #%c", *(c+idx+1));
632                         break;
633                 case LOC_LCD:
634                         n += sprintf ( buf, "LCD #%c", *(c+idx+1));
635                         break;
636                 case '.':
637                         n += sprintf ( buf, "- %c", *(c+idx+1));
638                 default:
639                         n += sprintf ( buf, "Unknown location");
640                         break;
641         }
642         return n;
643 }
644
645
646 /* ****************************************************************** */
647 /* 
648  * Format: 
649  * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ]
650  * the '.' may be an abbrevation
651  */
652 int check_location_string (char *c, char *buf)
653 {
654         int n=0,i=0;
655
656         while (c[i]) {
657                 if (isalpha(c[i]) || c[i] == '.') {
658                          n += check_location(c, i, buf+n);
659                 }
660                 else if (c[i] == '/' || c[i] == '-')
661                         n += sprintf(buf+n, " at ");
662                 i++;
663         }
664         return n;
665 }
666
667
668 /* ****************************************************************** */
669
670 int get_location_code(struct individual_sensor s, char * buffer)
671 {
672         char rstr[512], tmp[10], tmp2[10];
673         int n=0, i=0, llen, len;
674         /* char *buf = kmalloc(MAX_LINELENGTH, GFP_KERNEL); */
675         char *ret;
676
677         static int pos = 0; /* remember position where buffer was */
678
679         /* construct the sensor number like 0003 */
680         /* fill with zeros */
681         n = sprintf(tmp, "%d", s.token);
682         len = strlen(tmp);
683         while (strlen(tmp) < 4)
684                 n += sprintf (tmp+n, "0");
685         
686         /* invert the string */
687         while (tmp[i]) {
688                 if (i<len)
689                         tmp2[4-len+i] = tmp[i];
690                 else
691                         tmp2[3-i] = tmp[i];
692                 i++;
693         }
694         tmp2[4] = '\0';
695
696         sprintf (rstr, SENSOR_PREFIX"%s", tmp2);
697
698         ret = (char *) get_property(rtas_node, rstr, &llen);
699
700         n=0;
701         if (ret[0] == '\0')
702                 n += sprintf ( buffer+n, "--- ");/* does not have a location */
703         else {
704                 char t[50];
705                 ret += pos;
706
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);
711
712                 pos += strlen(t);
713                 if (pos >= llen) pos=0;
714         }
715         return n;
716 }
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)
722 {
723         unsigned long freq;
724         char *dest;
725         int error;
726         freq = simple_strtoul(buf, &dest, 10);
727         if (*dest != '\0' && *dest != '\n') {
728                 printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n");
729                 return count;
730         }
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);
735         if (error != 0)
736                 printk(KERN_WARNING "error: setting tone frequency returned: %s\n", 
737                                 ppc_rtas_process_error(error));
738         return count;
739 }
740 /* ****************************************************************** */
741 static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
742                 size_t count, loff_t *ppos)
743 {
744         int n;
745         n = sprintf(buf, "%lu\n", rtas_tone_frequency);
746
747         if (*ppos >= strlen(buf))
748                 return 0;
749         if (n > strlen(buf) - *ppos)
750                 n = strlen(buf) - *ppos;
751         if (n > count)
752                 n = count;
753         *ppos += n;
754         return n;
755 }
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)
761 {
762         unsigned long volume;
763         char *dest;
764         int error;
765         volume = simple_strtoul(buf, &dest, 10);
766         if (*dest != '\0' && *dest != '\n') {
767                 printk("ppc_rtas_tone_volume_write: Invalid tone volume\n");
768                 return count;
769         }
770         if (volume < 0) volume = 0;
771         if (volume > 100) volume = 100;
772         
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);
776         if (error != 0)
777                 printk(KERN_WARNING "error: setting tone volume returned: %s\n", 
778                                 ppc_rtas_process_error(error));
779         return count;
780 }
781 /* ****************************************************************** */
782 static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
783                 size_t count, loff_t *ppos)
784 {
785         int n;
786         n = sprintf(buf, "%lu\n", rtas_tone_volume);
787
788         if (*ppos >= strlen(buf))
789                 return 0;
790         if (n > strlen(buf) - *ppos)
791                 n = strlen(buf) - *ppos;
792         if (n > count)
793                 n = count;
794         *ppos += n;
795         return n;
796 }