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