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