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