- update to 2.6.1-rc2 -- first cut.
[linux-flexiantxendom0-3.2.10.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 extern struct proc_dir_entry *proc_rtas;
119
120 static struct rtas_sensors sensors;
121 static struct device_node *rtas_node = NULL;
122 static unsigned long power_on_time = 0; /* Save the time the user set */
123 static char progress_led[MAX_LINELENGTH];
124
125 static unsigned long rtas_tone_frequency = 1000;
126 static unsigned long rtas_tone_volume = 0;
127
128 /* ****************STRUCTS******************************************* */
129 struct individual_sensor {
130         unsigned int token;
131         unsigned int quant;
132 };
133
134 struct rtas_sensors {
135         struct individual_sensor sensor[MAX_SENSORS];
136         unsigned int quant;
137 };
138
139 /* ****************************************************************** */
140 /* Declarations */
141 static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off,
142                 int count, int *eof, void *data);
143 static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, 
144                 size_t count, loff_t *ppos);
145 static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, 
146                 size_t count, loff_t *ppos);
147 static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
148                 size_t count, loff_t *ppos);
149 static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
150                 size_t count, loff_t *ppos);
151 static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
152                 size_t count, loff_t *ppos);
153 static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
154                 size_t count, loff_t *ppos);
155
156 static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
157                 size_t count, loff_t *ppos);
158 static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
159                 size_t count, loff_t *ppos);
160 static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
161                 size_t count, loff_t *ppos);
162 static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
163                 size_t count, loff_t *ppos);
164
165 struct file_operations ppc_rtas_poweron_operations = {
166         .read =         ppc_rtas_poweron_read,
167         .write =        ppc_rtas_poweron_write
168 };
169 struct file_operations ppc_rtas_progress_operations = {
170         .read =         ppc_rtas_progress_read,
171         .write =        ppc_rtas_progress_write
172 };
173
174 struct file_operations ppc_rtas_clock_operations = {
175         .read =         ppc_rtas_clock_read,
176         .write =        ppc_rtas_clock_write
177 };
178
179 struct file_operations ppc_rtas_tone_freq_operations = {
180         .read =         ppc_rtas_tone_freq_read,
181         .write =        ppc_rtas_tone_freq_write
182 };
183 struct file_operations ppc_rtas_tone_volume_operations = {
184         .read =         ppc_rtas_tone_volume_read,
185         .write =        ppc_rtas_tone_volume_write
186 };
187
188 int ppc_rtas_find_all_sensors (void);
189 int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
190                 int error, char * buf);
191 char * ppc_rtas_process_error(int error);
192 int get_location_code(struct individual_sensor s, char * buf);
193 int check_location_string (char *c, char * buf);
194 int check_location (char *c, int idx, char * buf);
195
196 /* ****************************************************************** */
197 /* MAIN                                                               */
198 /* ****************************************************************** */
199 void proc_rtas_init(void)
200 {
201         struct proc_dir_entry *entry;
202
203         rtas_node = find_devices("rtas");
204         if ((rtas_node == NULL) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) {
205                 return;
206         }
207         
208         if (proc_rtas == NULL) {
209                 proc_rtas = proc_mkdir("rtas", 0);
210         }
211
212         if (proc_rtas == NULL) {
213                 printk(KERN_ERR "Failed to create /proc/rtas in proc_rtas_init\n");
214                 return;
215         }
216
217         /* /proc/rtas entries */
218
219         entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, proc_rtas);
220         if (entry) entry->proc_fops = &ppc_rtas_progress_operations;
221
222         entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, proc_rtas); 
223         if (entry) entry->proc_fops = &ppc_rtas_clock_operations;
224
225         entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, proc_rtas); 
226         if (entry) entry->proc_fops = &ppc_rtas_poweron_operations;
227
228         create_proc_read_entry("sensors", S_IRUGO, proc_rtas, 
229                         ppc_rtas_sensor_read, NULL);
230         
231         entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, proc_rtas); 
232         if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations;
233
234         entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas); 
235         if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations;
236 }
237
238 /* ****************************************************************** */
239 /* POWER-ON-TIME                                                      */
240 /* ****************************************************************** */
241 static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
242                 size_t count, loff_t *ppos)
243 {
244         struct rtc_time tm;
245         unsigned long nowtime;
246         char *dest;
247         int error;
248
249         nowtime = simple_strtoul(buf, &dest, 10);
250         if (*dest != '\0' && *dest != '\n') {
251                 printk("ppc_rtas_poweron_write: Invalid time\n");
252                 return count;
253         }
254         power_on_time = nowtime; /* save the time */
255
256         to_tm(nowtime, &tm);
257
258         error = rtas_call(rtas_token("set-time-for-power-on"), 7, 1, NULL, 
259                         tm.tm_year, tm.tm_mon, tm.tm_mday, 
260                         tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */);
261         if (error != 0)
262                 printk(KERN_WARNING "error: setting poweron time returned: %s\n", 
263                                 ppc_rtas_process_error(error));
264         return count;
265 }
266 /* ****************************************************************** */
267 static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
268                 size_t count, loff_t *ppos)
269 {
270         int n;
271         if (power_on_time == 0)
272                 n = sprintf(buf, "Power on time not set\n");
273         else
274                 n = sprintf(buf, "%lu\n", power_on_time);
275
276         if (*ppos >= strlen(buf))
277                 return 0;
278         if (n > strlen(buf) - *ppos)
279                 n = strlen(buf) - *ppos;
280         if (n > count)
281                 n = count;
282         *ppos += n;
283         return n;
284 }
285
286 /* ****************************************************************** */
287 /* PROGRESS                                                           */
288 /* ****************************************************************** */
289 static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
290                 size_t count, loff_t *ppos)
291 {
292         unsigned long hex;
293
294         strcpy(progress_led, buf); /* save the string */
295         /* Lets see if the user passed hexdigits */
296         hex = simple_strtoul(buf, NULL, 10);
297         
298         ppc_md.progress ((char *)buf, hex);
299         return count;
300
301         /* clear the line */ /* ppc_md.progress("                   ", 0xffff);*/
302 }
303 /* ****************************************************************** */
304 static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
305                 size_t count, loff_t *ppos)
306 {
307         int n = 0;
308         if (progress_led != NULL)
309                 n = sprintf (buf, "%s\n", progress_led);
310         if (*ppos >= strlen(buf))
311                 return 0;
312         if (n > strlen(buf) - *ppos)
313                 n = strlen(buf) - *ppos;
314         if (n > count)
315                 n = count;
316         *ppos += n;
317         return n;
318 }
319
320 /* ****************************************************************** */
321 /* CLOCK                                                              */
322 /* ****************************************************************** */
323 static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, 
324                 size_t count, loff_t *ppos)
325 {
326         struct rtc_time tm;
327         unsigned long nowtime;
328         char *dest;
329         int error;
330
331         nowtime = simple_strtoul(buf, &dest, 10);
332         if (*dest != '\0' && *dest != '\n') {
333                 printk("ppc_rtas_clock_write: Invalid time\n");
334                 return count;
335         }
336
337         to_tm(nowtime, &tm);
338         error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL, 
339                         tm.tm_year, tm.tm_mon, tm.tm_mday, 
340                         tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
341         if (error != 0)
342                 printk(KERN_WARNING "error: setting the clock returned: %s\n", 
343                                 ppc_rtas_process_error(error));
344         return count;
345 }
346 /* ****************************************************************** */
347 static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, 
348                 size_t count, loff_t *ppos)
349 {
350         unsigned int year, mon, day, hour, min, sec;
351         unsigned long *ret = kmalloc(4*8, GFP_KERNEL);
352         int n, error;
353
354         error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
355         
356         year = ret[0]; mon  = ret[1]; day  = ret[2];
357         hour = ret[3]; min  = ret[4]; sec  = ret[5];
358
359         if (error != 0){
360                 printk(KERN_WARNING "error: reading the clock returned: %s\n", 
361                                 ppc_rtas_process_error(error));
362                 n = sprintf (buf, "0");
363         } else { 
364                 n = sprintf (buf, "%lu\n", mktime(year, mon, day, hour, min, sec));
365         }
366         kfree(ret);
367
368         if (*ppos >= strlen(buf))
369                 return 0;
370         if (n > strlen(buf) - *ppos)
371                 n = strlen(buf) - *ppos;
372         if (n > count)
373                 n = count;
374         *ppos += n;
375         return n;
376 }
377
378 /* ****************************************************************** */
379 /* SENSOR STUFF                                                       */
380 /* ****************************************************************** */
381 static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off,
382                 int count, int *eof, void *data)
383 {
384         int i,j,n;
385         unsigned long ret;
386         int state, error;
387         char *buffer;
388         int get_sensor_state = rtas_token("get-sensor-state");
389
390         if (count < 0)
391                 return -EINVAL;
392
393         /* May not be enough */
394         buffer = kmalloc(MAX_LINELENGTH*MAX_SENSORS, GFP_KERNEL);
395
396         if (!buffer)
397                 return -ENOMEM;
398
399         memset(buffer, 0, MAX_LINELENGTH*MAX_SENSORS);
400
401         n  = sprintf ( buffer  , "RTAS (RunTime Abstraction Services) Sensor Information\n");
402         n += sprintf ( buffer+n, "Sensor\t\tValue\t\tCondition\tLocation\n");
403         n += sprintf ( buffer+n, "********************************************************\n");
404
405         if (ppc_rtas_find_all_sensors() != 0) {
406                 n += sprintf ( buffer+n, "\nNo sensors are available\n");
407                 goto return_string;
408         }
409
410         for (i=0; i<sensors.quant; i++) {
411                 j = sensors.sensor[i].quant;
412                 /* A sensor may have multiple instances */
413                 while (j >= 0) {
414
415                         error = rtas_call(get_sensor_state, 2, 2, &ret, 
416                                           sensors.sensor[i].token, 
417                                           sensors.sensor[i].quant - j);
418
419                         state = (int) ret;
420                         n += ppc_rtas_process_sensor(sensors.sensor[i], state, 
421                                                      error, buffer+n );
422                         n += sprintf (buffer+n, "\n");
423                         j--;
424                 } /* while */
425         } /* for */
426
427 return_string:
428         if (off >= strlen(buffer)) {
429                 *eof = 1;
430                 kfree(buffer);
431                 return 0;
432         }
433         if (n > strlen(buffer) - off)
434                 n = strlen(buffer) - off;
435         if (n > count)
436                 n = count;
437         else
438                 *eof = 1;
439
440         memcpy(buf, buffer + off, n);
441         *start = buf;
442         kfree(buffer);
443         return n;
444 }
445
446 /* ****************************************************************** */
447
448 int ppc_rtas_find_all_sensors (void)
449 {
450         unsigned int *utmp;
451         int len, i;
452
453         utmp = (unsigned int *) get_property(rtas_node, "rtas-sensors", &len);
454         if (utmp == NULL) {
455                 printk (KERN_ERR "error: could not get rtas-sensors\n");
456                 return 1;
457         }
458
459         sensors.quant = len / 8;      /* int + int */
460
461         for (i=0; i<sensors.quant; i++) {
462                 sensors.sensor[i].token = *utmp++;
463                 sensors.sensor[i].quant = *utmp++;
464         }
465         return 0;
466 }
467
468 /* ****************************************************************** */
469 /*
470  * Builds a string of what rtas returned
471  */
472 char * ppc_rtas_process_error(int error)
473 {
474         switch (error) {
475                 case SENSOR_CRITICAL_HIGH:
476                         return "(critical high)";
477                 case SENSOR_WARNING_HIGH:
478                         return "(warning high)";
479                 case SENSOR_NORMAL:
480                         return "(normal)";
481                 case SENSOR_WARNING_LOW:
482                         return "(warning low)";
483                 case SENSOR_CRITICAL_LOW:
484                         return "(critical low)";
485                 case SENSOR_SUCCESS:
486                         return "(read ok)";
487                 case SENSOR_HW_ERROR:
488                         return "(hardware error)";
489                 case SENSOR_BUSY:
490                         return "(busy)";
491                 case SENSOR_NOT_EXIST:
492                         return "(non existant)";
493                 case SENSOR_DR_ENTITY:
494                         return "(dr entity removed)";
495                 default:
496                         return "(UNKNOWN)";
497         }
498 }
499
500 /* ****************************************************************** */
501 /*
502  * Builds a string out of what the sensor said
503  */
504
505 int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
506                 int error, char * buf) 
507 {
508         /* Defined return vales */
509         const char * key_switch[]        = { "Off\t", "Normal\t", "Secure\t", 
510                                                 "Maintenance" };
511         const char * enclosure_switch[]  = { "Closed", "Open" };
512         const char * lid_status[]        = { " ", "Open", "Closed" };
513         const char * power_source[]      = { "AC\t", "Battery", 
514                                                 "AC & Battery" };
515         const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" };
516         const char * epow_sensor[]       = { 
517                 "EPOW Reset", "Cooling warning", "Power warning",
518                 "System shutdown", "System halt", "EPOW main enclosure",
519                 "EPOW power off" };
520         const char * battery_cyclestate[]  = { "None", "In progress", 
521                                                 "Requested" };
522         const char * battery_charging[]    = { "Charging", "Discharching", 
523                                                 "No current flow" };
524         const char * ibm_drconnector[]     = { "Empty", "Present", "Unusable", 
525                                                 "Exchange" };
526         const char * ibm_intqueue[]        = { "Disabled", "Enabled" };
527
528         int have_strings = 0;
529         int num_states = 0;
530         int temperature = 0;
531         int unknown = 0;
532         int n = 0;
533
534         /* What kind of sensor do we have here? */
535         
536         switch (s.token) {
537                 case KEY_SWITCH:
538                         n += sprintf(buf+n, "Key switch:\t");
539                         num_states = sizeof(key_switch) / sizeof(char *);
540                         if (state < num_states) {
541                                 n += sprintf(buf+n, "%s\t", key_switch[state]);
542                                 have_strings = 1;
543                         }
544                         break;
545                 case ENCLOSURE_SWITCH:
546                         n += sprintf(buf+n, "Enclosure switch:\t");
547                         num_states = sizeof(enclosure_switch) / sizeof(char *);
548                         if (state < num_states) {
549                                 n += sprintf(buf+n, "%s\t", 
550                                                 enclosure_switch[state]);
551                                 have_strings = 1;
552                         }
553                         break;
554                 case THERMAL_SENSOR:
555                         n += sprintf(buf+n, "Temp. (°C/°F):\t");
556                         temperature = 1;
557                         break;
558                 case LID_STATUS:
559                         n += sprintf(buf+n, "Lid status:\t");
560                         num_states = sizeof(lid_status) / sizeof(char *);
561                         if (state < num_states) {
562                                 n += sprintf(buf+n, "%s\t", lid_status[state]);
563                                 have_strings = 1;
564                         }
565                         break;
566                 case POWER_SOURCE:
567                         n += sprintf(buf+n, "Power source:\t");
568                         num_states = sizeof(power_source) / sizeof(char *);
569                         if (state < num_states) {
570                                 n += sprintf(buf+n, "%s\t", 
571                                                 power_source[state]);
572                                 have_strings = 1;
573                         }
574                         break;
575                 case BATTERY_VOLTAGE:
576                         n += sprintf(buf+n, "Battery voltage:\t");
577                         break;
578                 case BATTERY_REMAINING:
579                         n += sprintf(buf+n, "Battery remaining:\t");
580                         num_states = sizeof(battery_remaining) / sizeof(char *);
581                         if (state < num_states)
582                         {
583                                 n += sprintf(buf+n, "%s\t", 
584                                                 battery_remaining[state]);
585                                 have_strings = 1;
586                         }
587                         break;
588                 case BATTERY_PERCENTAGE:
589                         n += sprintf(buf+n, "Battery percentage:\t");
590                         break;
591                 case EPOW_SENSOR:
592                         n += sprintf(buf+n, "EPOW Sensor:\t");
593                         num_states = sizeof(epow_sensor) / sizeof(char *);
594                         if (state < num_states) {
595                                 n += sprintf(buf+n, "%s\t", epow_sensor[state]);
596                                 have_strings = 1;
597                         }
598                         break;
599                 case BATTERY_CYCLESTATE:
600                         n += sprintf(buf+n, "Battery cyclestate:\t");
601                         num_states = sizeof(battery_cyclestate) / 
602                                         sizeof(char *);
603                         if (state < num_states) {
604                                 n += sprintf(buf+n, "%s\t", 
605                                                 battery_cyclestate[state]);
606                                 have_strings = 1;
607                         }
608                         break;
609                 case BATTERY_CHARGING:
610                         n += sprintf(buf+n, "Battery Charging:\t");
611                         num_states = sizeof(battery_charging) / sizeof(char *);
612                         if (state < num_states) {
613                                 n += sprintf(buf+n, "%s\t", 
614                                                 battery_charging[state]);
615                                 have_strings = 1;
616                         }
617                         break;
618                 case IBM_SURVEILLANCE:
619                         n += sprintf(buf+n, "Surveillance:\t");
620                         break;
621                 case IBM_FANRPM:
622                         n += sprintf(buf+n, "Fan (rpm):\t");
623                         break;
624                 case IBM_VOLTAGE:
625                         n += sprintf(buf+n, "Voltage (mv):\t");
626                         break;
627                 case IBM_DRCONNECTOR:
628                         n += sprintf(buf+n, "DR connector:\t");
629                         num_states = sizeof(ibm_drconnector) / sizeof(char *);
630                         if (state < num_states) {
631                                 n += sprintf(buf+n, "%s\t", 
632                                                 ibm_drconnector[state]);
633                                 have_strings = 1;
634                         }
635                         break;
636                 case IBM_POWERSUPPLY:
637                         n += sprintf(buf+n, "Powersupply:\t");
638                         break;
639                 case IBM_INTQUEUE:
640                         n += sprintf(buf+n, "Interrupt queue:\t");
641                         num_states = sizeof(ibm_intqueue) / sizeof(char *);
642                         if (state < num_states) {
643                                 n += sprintf(buf+n, "%s\t", 
644                                                 ibm_intqueue[state]);
645                                 have_strings = 1;
646                         }
647                         break;
648                 default:
649                         n += sprintf(buf+n,  "Unkown sensor (type %d), ignoring it\n",
650                                         s.token);
651                         unknown = 1;
652                         have_strings = 1;
653                         break;
654         }
655         if (have_strings == 0) {
656                 if (temperature) {
657                         n += sprintf(buf+n, "%4d /%4d\t", state, cel_to_fahr(state));
658                 } else
659                         n += sprintf(buf+n, "%10d\t", state);
660         }
661         if (unknown == 0) {
662                 n += sprintf ( buf+n, "%s\t", ppc_rtas_process_error(error));
663                 n += get_location_code(s, buf+n);
664         }
665         return n;
666 }
667
668 /* ****************************************************************** */
669
670 int check_location (char *c, int idx, char * buf)
671 {
672         int n = 0;
673
674         switch (*(c+idx)) {
675                 case LOC_PLANAR:
676                         n += sprintf ( buf, "Planar #%c", *(c+idx+1));
677                         break;
678                 case LOC_CPU:
679                         n += sprintf ( buf, "CPU #%c", *(c+idx+1));
680                         break;
681                 case LOC_FAN:
682                         n += sprintf ( buf, "Fan #%c", *(c+idx+1));
683                         break;
684                 case LOC_RACKMOUNTED:
685                         n += sprintf ( buf, "Rack #%c", *(c+idx+1));
686                         break;
687                 case LOC_VOLTAGE:
688                         n += sprintf ( buf, "Voltage #%c", *(c+idx+1));
689                         break;
690                 case LOC_LCD:
691                         n += sprintf ( buf, "LCD #%c", *(c+idx+1));
692                         break;
693                 case '.':
694                         n += sprintf ( buf, "- %c", *(c+idx+1));
695                 default:
696                         n += sprintf ( buf, "Unknown location");
697                         break;
698         }
699         return n;
700 }
701
702
703 /* ****************************************************************** */
704 /* 
705  * Format: 
706  * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ]
707  * the '.' may be an abbrevation
708  */
709 int check_location_string (char *c, char *buf)
710 {
711         int n=0,i=0;
712
713         while (c[i]) {
714                 if (isalpha(c[i]) || c[i] == '.') {
715                          n += check_location(c, i, buf+n);
716                 }
717                 else if (c[i] == '/' || c[i] == '-')
718                         n += sprintf(buf+n, " at ");
719                 i++;
720         }
721         return n;
722 }
723
724
725 /* ****************************************************************** */
726
727 int get_location_code(struct individual_sensor s, char * buffer)
728 {
729         char rstr[512], tmp[10], tmp2[10];
730         int n=0, i=0, llen, len;
731         /* char *buf = kmalloc(MAX_LINELENGTH, GFP_KERNEL); */
732         char *ret;
733
734         static int pos = 0; /* remember position where buffer was */
735
736         /* construct the sensor number like 0003 */
737         /* fill with zeros */
738         n = sprintf(tmp, "%d", s.token);
739         len = strlen(tmp);
740         while (strlen(tmp) < 4)
741                 n += sprintf (tmp+n, "0");
742         
743         /* invert the string */
744         while (tmp[i]) {
745                 if (i<len)
746                         tmp2[4-len+i] = tmp[i];
747                 else
748                         tmp2[3-i] = tmp[i];
749                 i++;
750         }
751         tmp2[4] = '\0';
752
753         sprintf (rstr, SENSOR_PREFIX"%s", tmp2);
754
755         ret = (char *) get_property(rtas_node, rstr, &llen);
756
757         n=0;
758         if (ret == NULL || ret[0] == '\0') {
759                 n += sprintf ( buffer+n, "--- ");/* does not have a location */
760         } else {
761                 char t[50];
762                 ret += pos;
763
764                 n += check_location_string(ret, buffer + n);
765                 n += sprintf ( buffer+n, " ");
766                 /* see how many characters we have printed */
767                 sprintf ( t, "%s ", ret);
768
769                 pos += strlen(t);
770                 if (pos >= llen) pos=0;
771         }
772         return n;
773 }
774 /* ****************************************************************** */
775 /* INDICATORS - Tone Frequency                                        */
776 /* ****************************************************************** */
777 static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
778                 size_t count, loff_t *ppos)
779 {
780         unsigned long freq;
781         char *dest;
782         int error;
783         freq = simple_strtoul(buf, &dest, 10);
784         if (*dest != '\0' && *dest != '\n') {
785                 printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n");
786                 return count;
787         }
788         if (freq < 0) freq = 0;
789         rtas_tone_frequency = freq; /* save it for later */
790         error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
791                         TONE_FREQUENCY, 0, freq);
792         if (error != 0)
793                 printk(KERN_WARNING "error: setting tone frequency returned: %s\n", 
794                                 ppc_rtas_process_error(error));
795         return count;
796 }
797 /* ****************************************************************** */
798 static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
799                 size_t count, loff_t *ppos)
800 {
801         int n;
802         n = sprintf(buf, "%lu\n", rtas_tone_frequency);
803
804         if (*ppos >= strlen(buf))
805                 return 0;
806         if (n > strlen(buf) - *ppos)
807                 n = strlen(buf) - *ppos;
808         if (n > count)
809                 n = count;
810         *ppos += n;
811         return n;
812 }
813 /* ****************************************************************** */
814 /* INDICATORS - Tone Volume                                           */
815 /* ****************************************************************** */
816 static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
817                 size_t count, loff_t *ppos)
818 {
819         unsigned long volume;
820         char *dest;
821         int error;
822         volume = simple_strtoul(buf, &dest, 10);
823         if (*dest != '\0' && *dest != '\n') {
824                 printk("ppc_rtas_tone_volume_write: Invalid tone volume\n");
825                 return count;
826         }
827         if (volume < 0) volume = 0;
828         if (volume > 100) volume = 100;
829         
830         rtas_tone_volume = volume; /* save it for later */
831         error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
832                         TONE_VOLUME, 0, volume);
833         if (error != 0)
834                 printk(KERN_WARNING "error: setting tone volume returned: %s\n", 
835                                 ppc_rtas_process_error(error));
836         return count;
837 }
838 /* ****************************************************************** */
839 static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
840                 size_t count, loff_t *ppos)
841 {
842         int n;
843         n = sprintf(buf, "%lu\n", rtas_tone_volume);
844
845         if (*ppos >= strlen(buf))
846                 return 0;
847         if (n > strlen(buf) - *ppos)
848                 n = strlen(buf) - *ppos;
849         if (n > count)
850                 n = count;
851         *ppos += n;
852         return n;
853 }