Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *   Copyright (C) 2000 Tilmann Bitterberg
0004  *   (tilmann@bitterberg.de)
0005  *
0006  *   RTAS (Runtime Abstraction Services) stuff
0007  *   Intention is to provide a clean user interface
0008  *   to use the RTAS.
0009  *
0010  *   TODO:
0011  *   Split off a header file and maybe move it to a different
0012  *   location. Write Documentation on what the /proc/rtas/ entries
0013  *   actually do.
0014  */
0015 
0016 #include <linux/errno.h>
0017 #include <linux/sched.h>
0018 #include <linux/proc_fs.h>
0019 #include <linux/stat.h>
0020 #include <linux/ctype.h>
0021 #include <linux/time.h>
0022 #include <linux/string.h>
0023 #include <linux/init.h>
0024 #include <linux/seq_file.h>
0025 #include <linux/bitops.h>
0026 #include <linux/rtc.h>
0027 #include <linux/of.h>
0028 
0029 #include <linux/uaccess.h>
0030 #include <asm/processor.h>
0031 #include <asm/io.h>
0032 #include <asm/rtas.h>
0033 #include <asm/machdep.h> /* for ppc_md */
0034 #include <asm/time.h>
0035 
0036 /* Token for Sensors */
0037 #define KEY_SWITCH      0x0001
0038 #define ENCLOSURE_SWITCH    0x0002
0039 #define THERMAL_SENSOR      0x0003
0040 #define LID_STATUS      0x0004
0041 #define POWER_SOURCE        0x0005
0042 #define BATTERY_VOLTAGE     0x0006
0043 #define BATTERY_REMAINING   0x0007
0044 #define BATTERY_PERCENTAGE  0x0008
0045 #define EPOW_SENSOR     0x0009
0046 #define BATTERY_CYCLESTATE  0x000a
0047 #define BATTERY_CHARGING    0x000b
0048 
0049 /* IBM specific sensors */
0050 #define IBM_SURVEILLANCE    0x2328 /* 9000 */
0051 #define IBM_FANRPM      0x2329 /* 9001 */
0052 #define IBM_VOLTAGE     0x232a /* 9002 */
0053 #define IBM_DRCONNECTOR     0x232b /* 9003 */
0054 #define IBM_POWERSUPPLY     0x232c /* 9004 */
0055 
0056 /* Status return values */
0057 #define SENSOR_CRITICAL_HIGH    13
0058 #define SENSOR_WARNING_HIGH 12
0059 #define SENSOR_NORMAL       11
0060 #define SENSOR_WARNING_LOW  10
0061 #define SENSOR_CRITICAL_LOW  9
0062 #define SENSOR_SUCCESS       0
0063 #define SENSOR_HW_ERROR     -1
0064 #define SENSOR_BUSY     -2
0065 #define SENSOR_NOT_EXIST    -3
0066 #define SENSOR_DR_ENTITY    -9000
0067 
0068 /* Location Codes */
0069 #define LOC_SCSI_DEV_ADDR   'A'
0070 #define LOC_SCSI_DEV_LOC    'B'
0071 #define LOC_CPU         'C'
0072 #define LOC_DISKETTE        'D'
0073 #define LOC_ETHERNET        'E'
0074 #define LOC_FAN         'F'
0075 #define LOC_GRAPHICS        'G'
0076 /* reserved / not used      'H' */
0077 #define LOC_IO_ADAPTER      'I'
0078 /* reserved / not used      'J' */
0079 #define LOC_KEYBOARD        'K'
0080 #define LOC_LCD         'L'
0081 #define LOC_MEMORY      'M'
0082 #define LOC_NV_MEMORY       'N'
0083 #define LOC_MOUSE       'O'
0084 #define LOC_PLANAR      'P'
0085 #define LOC_OTHER_IO        'Q'
0086 #define LOC_PARALLEL        'R'
0087 #define LOC_SERIAL      'S'
0088 #define LOC_DEAD_RING       'T'
0089 #define LOC_RACKMOUNTED     'U' /* for _u_nit is rack mounted */
0090 #define LOC_VOLTAGE     'V'
0091 #define LOC_SWITCH_ADAPTER  'W'
0092 #define LOC_OTHER       'X'
0093 #define LOC_FIRMWARE        'Y'
0094 #define LOC_SCSI        'Z'
0095 
0096 /* Tokens for indicators */
0097 #define TONE_FREQUENCY      0x0001 /* 0 - 1000 (HZ)*/
0098 #define TONE_VOLUME     0x0002 /* 0 - 100 (%) */
0099 #define SYSTEM_POWER_STATE  0x0003 
0100 #define WARNING_LIGHT       0x0004
0101 #define DISK_ACTIVITY_LIGHT 0x0005
0102 #define HEX_DISPLAY_UNIT    0x0006
0103 #define BATTERY_WARNING_TIME    0x0007
0104 #define CONDITION_CYCLE_REQUEST 0x0008
0105 #define SURVEILLANCE_INDICATOR  0x2328 /* 9000 */
0106 #define DR_ACTION       0x2329 /* 9001 */
0107 #define DR_INDICATOR        0x232a /* 9002 */
0108 /* 9003 - 9004: Vendor specific */
0109 /* 9006 - 9999: Vendor specific */
0110 
0111 /* other */
0112 #define MAX_SENSORS      17  /* I only know of 17 sensors */    
0113 #define MAX_LINELENGTH          256
0114 #define SENSOR_PREFIX       "ibm,sensor-"
0115 #define cel_to_fahr(x)      ((x*9/5)+32)
0116 
0117 struct individual_sensor {
0118     unsigned int token;
0119     unsigned int quant;
0120 };
0121 
0122 struct rtas_sensors {
0123         struct individual_sensor sensor[MAX_SENSORS];
0124     unsigned int quant;
0125 };
0126 
0127 /* Globals */
0128 static struct rtas_sensors sensors;
0129 static struct device_node *rtas_node = NULL;
0130 static unsigned long power_on_time = 0; /* Save the time the user set */
0131 static char progress_led[MAX_LINELENGTH];
0132 
0133 static unsigned long rtas_tone_frequency = 1000;
0134 static unsigned long rtas_tone_volume = 0;
0135 
0136 /* ****************************************************************** */
0137 /* Declarations */
0138 static int ppc_rtas_sensors_show(struct seq_file *m, void *v);
0139 static int ppc_rtas_clock_show(struct seq_file *m, void *v);
0140 static ssize_t ppc_rtas_clock_write(struct file *file,
0141         const char __user *buf, size_t count, loff_t *ppos);
0142 static int ppc_rtas_progress_show(struct seq_file *m, void *v);
0143 static ssize_t ppc_rtas_progress_write(struct file *file,
0144         const char __user *buf, size_t count, loff_t *ppos);
0145 static int ppc_rtas_poweron_show(struct seq_file *m, void *v);
0146 static ssize_t ppc_rtas_poweron_write(struct file *file,
0147         const char __user *buf, size_t count, loff_t *ppos);
0148 
0149 static ssize_t ppc_rtas_tone_freq_write(struct file *file,
0150         const char __user *buf, size_t count, loff_t *ppos);
0151 static int ppc_rtas_tone_freq_show(struct seq_file *m, void *v);
0152 static ssize_t ppc_rtas_tone_volume_write(struct file *file,
0153         const char __user *buf, size_t count, loff_t *ppos);
0154 static int ppc_rtas_tone_volume_show(struct seq_file *m, void *v);
0155 static int ppc_rtas_rmo_buf_show(struct seq_file *m, void *v);
0156 
0157 static int poweron_open(struct inode *inode, struct file *file)
0158 {
0159     return single_open(file, ppc_rtas_poweron_show, NULL);
0160 }
0161 
0162 static const struct proc_ops ppc_rtas_poweron_proc_ops = {
0163     .proc_open  = poweron_open,
0164     .proc_read  = seq_read,
0165     .proc_lseek = seq_lseek,
0166     .proc_write = ppc_rtas_poweron_write,
0167     .proc_release   = single_release,
0168 };
0169 
0170 static int progress_open(struct inode *inode, struct file *file)
0171 {
0172     return single_open(file, ppc_rtas_progress_show, NULL);
0173 }
0174 
0175 static const struct proc_ops ppc_rtas_progress_proc_ops = {
0176     .proc_open  = progress_open,
0177     .proc_read  = seq_read,
0178     .proc_lseek = seq_lseek,
0179     .proc_write = ppc_rtas_progress_write,
0180     .proc_release   = single_release,
0181 };
0182 
0183 static int clock_open(struct inode *inode, struct file *file)
0184 {
0185     return single_open(file, ppc_rtas_clock_show, NULL);
0186 }
0187 
0188 static const struct proc_ops ppc_rtas_clock_proc_ops = {
0189     .proc_open  = clock_open,
0190     .proc_read  = seq_read,
0191     .proc_lseek = seq_lseek,
0192     .proc_write = ppc_rtas_clock_write,
0193     .proc_release   = single_release,
0194 };
0195 
0196 static int tone_freq_open(struct inode *inode, struct file *file)
0197 {
0198     return single_open(file, ppc_rtas_tone_freq_show, NULL);
0199 }
0200 
0201 static const struct proc_ops ppc_rtas_tone_freq_proc_ops = {
0202     .proc_open  = tone_freq_open,
0203     .proc_read  = seq_read,
0204     .proc_lseek = seq_lseek,
0205     .proc_write = ppc_rtas_tone_freq_write,
0206     .proc_release   = single_release,
0207 };
0208 
0209 static int tone_volume_open(struct inode *inode, struct file *file)
0210 {
0211     return single_open(file, ppc_rtas_tone_volume_show, NULL);
0212 }
0213 
0214 static const struct proc_ops ppc_rtas_tone_volume_proc_ops = {
0215     .proc_open  = tone_volume_open,
0216     .proc_read  = seq_read,
0217     .proc_lseek = seq_lseek,
0218     .proc_write = ppc_rtas_tone_volume_write,
0219     .proc_release   = single_release,
0220 };
0221 
0222 static int ppc_rtas_find_all_sensors(void);
0223 static void ppc_rtas_process_sensor(struct seq_file *m,
0224     struct individual_sensor *s, int state, int error, const char *loc);
0225 static char *ppc_rtas_process_error(int error);
0226 static void get_location_code(struct seq_file *m,
0227     struct individual_sensor *s, const char *loc);
0228 static void check_location_string(struct seq_file *m, const char *c);
0229 static void check_location(struct seq_file *m, const char *c);
0230 
0231 static int __init proc_rtas_init(void)
0232 {
0233     if (!machine_is(pseries))
0234         return -ENODEV;
0235 
0236     rtas_node = of_find_node_by_name(NULL, "rtas");
0237     if (rtas_node == NULL)
0238         return -ENODEV;
0239 
0240     proc_create("powerpc/rtas/progress", 0644, NULL,
0241             &ppc_rtas_progress_proc_ops);
0242     proc_create("powerpc/rtas/clock", 0644, NULL,
0243             &ppc_rtas_clock_proc_ops);
0244     proc_create("powerpc/rtas/poweron", 0644, NULL,
0245             &ppc_rtas_poweron_proc_ops);
0246     proc_create_single("powerpc/rtas/sensors", 0444, NULL,
0247             ppc_rtas_sensors_show);
0248     proc_create("powerpc/rtas/frequency", 0644, NULL,
0249             &ppc_rtas_tone_freq_proc_ops);
0250     proc_create("powerpc/rtas/volume", 0644, NULL,
0251             &ppc_rtas_tone_volume_proc_ops);
0252     proc_create_single("powerpc/rtas/rmo_buffer", 0400, NULL,
0253             ppc_rtas_rmo_buf_show);
0254     return 0;
0255 }
0256 
0257 __initcall(proc_rtas_init);
0258 
0259 static int parse_number(const char __user *p, size_t count, u64 *val)
0260 {
0261     char buf[40];
0262 
0263     if (count > 39)
0264         return -EINVAL;
0265 
0266     if (copy_from_user(buf, p, count))
0267         return -EFAULT;
0268 
0269     buf[count] = 0;
0270 
0271     return kstrtoull(buf, 10, val);
0272 }
0273 
0274 /* ****************************************************************** */
0275 /* POWER-ON-TIME                                                      */
0276 /* ****************************************************************** */
0277 static ssize_t ppc_rtas_poweron_write(struct file *file,
0278         const char __user *buf, size_t count, loff_t *ppos)
0279 {
0280     struct rtc_time tm;
0281     time64_t nowtime;
0282     int error = parse_number(buf, count, &nowtime);
0283     if (error)
0284         return error;
0285 
0286     power_on_time = nowtime; /* save the time */
0287 
0288     rtc_time64_to_tm(nowtime, &tm);
0289 
0290     error = rtas_call(rtas_token("set-time-for-power-on"), 7, 1, NULL, 
0291             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
0292             tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */);
0293     if (error)
0294         printk(KERN_WARNING "error: setting poweron time returned: %s\n", 
0295                 ppc_rtas_process_error(error));
0296     return count;
0297 }
0298 /* ****************************************************************** */
0299 static int ppc_rtas_poweron_show(struct seq_file *m, void *v)
0300 {
0301     if (power_on_time == 0)
0302         seq_printf(m, "Power on time not set\n");
0303     else
0304         seq_printf(m, "%lu\n",power_on_time);
0305     return 0;
0306 }
0307 
0308 /* ****************************************************************** */
0309 /* PROGRESS                                                           */
0310 /* ****************************************************************** */
0311 static ssize_t ppc_rtas_progress_write(struct file *file,
0312         const char __user *buf, size_t count, loff_t *ppos)
0313 {
0314     unsigned long hex;
0315 
0316     if (count >= MAX_LINELENGTH)
0317         count = MAX_LINELENGTH -1;
0318     if (copy_from_user(progress_led, buf, count)) { /* save the string */
0319         return -EFAULT;
0320     }
0321     progress_led[count] = 0;
0322 
0323     /* Lets see if the user passed hexdigits */
0324     hex = simple_strtoul(progress_led, NULL, 10);
0325 
0326     rtas_progress ((char *)progress_led, hex);
0327     return count;
0328 
0329     /* clear the line */
0330     /* rtas_progress("                   ", 0xffff);*/
0331 }
0332 /* ****************************************************************** */
0333 static int ppc_rtas_progress_show(struct seq_file *m, void *v)
0334 {
0335     if (progress_led[0])
0336         seq_printf(m, "%s\n", progress_led);
0337     return 0;
0338 }
0339 
0340 /* ****************************************************************** */
0341 /* CLOCK                                                              */
0342 /* ****************************************************************** */
0343 static ssize_t ppc_rtas_clock_write(struct file *file,
0344         const char __user *buf, size_t count, loff_t *ppos)
0345 {
0346     struct rtc_time tm;
0347     time64_t nowtime;
0348     int error = parse_number(buf, count, &nowtime);
0349     if (error)
0350         return error;
0351 
0352     rtc_time64_to_tm(nowtime, &tm);
0353     error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL, 
0354             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
0355             tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
0356     if (error)
0357         printk(KERN_WARNING "error: setting the clock returned: %s\n", 
0358                 ppc_rtas_process_error(error));
0359     return count;
0360 }
0361 /* ****************************************************************** */
0362 static int ppc_rtas_clock_show(struct seq_file *m, void *v)
0363 {
0364     int ret[8];
0365     int error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
0366 
0367     if (error) {
0368         printk(KERN_WARNING "error: reading the clock returned: %s\n", 
0369                 ppc_rtas_process_error(error));
0370         seq_printf(m, "0");
0371     } else { 
0372         unsigned int year, mon, day, hour, min, sec;
0373         year = ret[0]; mon  = ret[1]; day  = ret[2];
0374         hour = ret[3]; min  = ret[4]; sec  = ret[5];
0375         seq_printf(m, "%lld\n",
0376                 mktime64(year, mon, day, hour, min, sec));
0377     }
0378     return 0;
0379 }
0380 
0381 /* ****************************************************************** */
0382 /* SENSOR STUFF                                                       */
0383 /* ****************************************************************** */
0384 static int ppc_rtas_sensors_show(struct seq_file *m, void *v)
0385 {
0386     int i,j;
0387     int state, error;
0388     int get_sensor_state = rtas_token("get-sensor-state");
0389 
0390     seq_printf(m, "RTAS (RunTime Abstraction Services) Sensor Information\n");
0391     seq_printf(m, "Sensor\t\tValue\t\tCondition\tLocation\n");
0392     seq_printf(m, "********************************************************\n");
0393 
0394     if (ppc_rtas_find_all_sensors() != 0) {
0395         seq_printf(m, "\nNo sensors are available\n");
0396         return 0;
0397     }
0398 
0399     for (i=0; i<sensors.quant; i++) {
0400         struct individual_sensor *p = &sensors.sensor[i];
0401         char rstr[64];
0402         const char *loc;
0403         int llen, offs;
0404 
0405         sprintf (rstr, SENSOR_PREFIX"%04d", p->token);
0406         loc = of_get_property(rtas_node, rstr, &llen);
0407 
0408         /* A sensor may have multiple instances */
0409         for (j = 0, offs = 0; j <= p->quant; j++) {
0410             error = rtas_call(get_sensor_state, 2, 2, &state, 
0411                       p->token, j);
0412 
0413             ppc_rtas_process_sensor(m, p, state, error, loc);
0414             seq_putc(m, '\n');
0415             if (loc) {
0416                 offs += strlen(loc) + 1;
0417                 loc += strlen(loc) + 1;
0418                 if (offs >= llen)
0419                     loc = NULL;
0420             }
0421         }
0422     }
0423     return 0;
0424 }
0425 
0426 /* ****************************************************************** */
0427 
0428 static int ppc_rtas_find_all_sensors(void)
0429 {
0430     const unsigned int *utmp;
0431     int len, i;
0432 
0433     utmp = of_get_property(rtas_node, "rtas-sensors", &len);
0434     if (utmp == NULL) {
0435         printk (KERN_ERR "error: could not get rtas-sensors\n");
0436         return 1;
0437     }
0438 
0439     sensors.quant = len / 8;      /* int + int */
0440 
0441     for (i=0; i<sensors.quant; i++) {
0442         sensors.sensor[i].token = *utmp++;
0443         sensors.sensor[i].quant = *utmp++;
0444     }
0445     return 0;
0446 }
0447 
0448 /* ****************************************************************** */
0449 /*
0450  * Builds a string of what rtas returned
0451  */
0452 static char *ppc_rtas_process_error(int error)
0453 {
0454     switch (error) {
0455         case SENSOR_CRITICAL_HIGH:
0456             return "(critical high)";
0457         case SENSOR_WARNING_HIGH:
0458             return "(warning high)";
0459         case SENSOR_NORMAL:
0460             return "(normal)";
0461         case SENSOR_WARNING_LOW:
0462             return "(warning low)";
0463         case SENSOR_CRITICAL_LOW:
0464             return "(critical low)";
0465         case SENSOR_SUCCESS:
0466             return "(read ok)";
0467         case SENSOR_HW_ERROR:
0468             return "(hardware error)";
0469         case SENSOR_BUSY:
0470             return "(busy)";
0471         case SENSOR_NOT_EXIST:
0472             return "(non existent)";
0473         case SENSOR_DR_ENTITY:
0474             return "(dr entity removed)";
0475         default:
0476             return "(UNKNOWN)";
0477     }
0478 }
0479 
0480 /* ****************************************************************** */
0481 /*
0482  * Builds a string out of what the sensor said
0483  */
0484 
0485 static void ppc_rtas_process_sensor(struct seq_file *m,
0486     struct individual_sensor *s, int state, int error, const char *loc)
0487 {
0488     /* Defined return vales */
0489     const char * key_switch[]        = { "Off\t", "Normal\t", "Secure\t", 
0490                         "Maintenance" };
0491     const char * enclosure_switch[]  = { "Closed", "Open" };
0492     const char * lid_status[]        = { " ", "Open", "Closed" };
0493     const char * power_source[]      = { "AC\t", "Battery", 
0494                         "AC & Battery" };
0495     const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" };
0496     const char * epow_sensor[]       = { 
0497         "EPOW Reset", "Cooling warning", "Power warning",
0498         "System shutdown", "System halt", "EPOW main enclosure",
0499         "EPOW power off" };
0500     const char * battery_cyclestate[]  = { "None", "In progress", 
0501                         "Requested" };
0502     const char * battery_charging[]    = { "Charging", "Discharging",
0503                         "No current flow" };
0504     const char * ibm_drconnector[]     = { "Empty", "Present", "Unusable", 
0505                         "Exchange" };
0506 
0507     int have_strings = 0;
0508     int num_states = 0;
0509     int temperature = 0;
0510     int unknown = 0;
0511 
0512     /* What kind of sensor do we have here? */
0513     
0514     switch (s->token) {
0515         case KEY_SWITCH:
0516             seq_printf(m, "Key switch:\t");
0517             num_states = sizeof(key_switch) / sizeof(char *);
0518             if (state < num_states) {
0519                 seq_printf(m, "%s\t", key_switch[state]);
0520                 have_strings = 1;
0521             }
0522             break;
0523         case ENCLOSURE_SWITCH:
0524             seq_printf(m, "Enclosure switch:\t");
0525             num_states = sizeof(enclosure_switch) / sizeof(char *);
0526             if (state < num_states) {
0527                 seq_printf(m, "%s\t", 
0528                         enclosure_switch[state]);
0529                 have_strings = 1;
0530             }
0531             break;
0532         case THERMAL_SENSOR:
0533             seq_printf(m, "Temp. (C/F):\t");
0534             temperature = 1;
0535             break;
0536         case LID_STATUS:
0537             seq_printf(m, "Lid status:\t");
0538             num_states = sizeof(lid_status) / sizeof(char *);
0539             if (state < num_states) {
0540                 seq_printf(m, "%s\t", lid_status[state]);
0541                 have_strings = 1;
0542             }
0543             break;
0544         case POWER_SOURCE:
0545             seq_printf(m, "Power source:\t");
0546             num_states = sizeof(power_source) / sizeof(char *);
0547             if (state < num_states) {
0548                 seq_printf(m, "%s\t", 
0549                         power_source[state]);
0550                 have_strings = 1;
0551             }
0552             break;
0553         case BATTERY_VOLTAGE:
0554             seq_printf(m, "Battery voltage:\t");
0555             break;
0556         case BATTERY_REMAINING:
0557             seq_printf(m, "Battery remaining:\t");
0558             num_states = sizeof(battery_remaining) / sizeof(char *);
0559             if (state < num_states)
0560             {
0561                 seq_printf(m, "%s\t", 
0562                         battery_remaining[state]);
0563                 have_strings = 1;
0564             }
0565             break;
0566         case BATTERY_PERCENTAGE:
0567             seq_printf(m, "Battery percentage:\t");
0568             break;
0569         case EPOW_SENSOR:
0570             seq_printf(m, "EPOW Sensor:\t");
0571             num_states = sizeof(epow_sensor) / sizeof(char *);
0572             if (state < num_states) {
0573                 seq_printf(m, "%s\t", epow_sensor[state]);
0574                 have_strings = 1;
0575             }
0576             break;
0577         case BATTERY_CYCLESTATE:
0578             seq_printf(m, "Battery cyclestate:\t");
0579             num_states = sizeof(battery_cyclestate) / 
0580                         sizeof(char *);
0581             if (state < num_states) {
0582                 seq_printf(m, "%s\t", 
0583                         battery_cyclestate[state]);
0584                 have_strings = 1;
0585             }
0586             break;
0587         case BATTERY_CHARGING:
0588             seq_printf(m, "Battery Charging:\t");
0589             num_states = sizeof(battery_charging) / sizeof(char *);
0590             if (state < num_states) {
0591                 seq_printf(m, "%s\t", 
0592                         battery_charging[state]);
0593                 have_strings = 1;
0594             }
0595             break;
0596         case IBM_SURVEILLANCE:
0597             seq_printf(m, "Surveillance:\t");
0598             break;
0599         case IBM_FANRPM:
0600             seq_printf(m, "Fan (rpm):\t");
0601             break;
0602         case IBM_VOLTAGE:
0603             seq_printf(m, "Voltage (mv):\t");
0604             break;
0605         case IBM_DRCONNECTOR:
0606             seq_printf(m, "DR connector:\t");
0607             num_states = sizeof(ibm_drconnector) / sizeof(char *);
0608             if (state < num_states) {
0609                 seq_printf(m, "%s\t", 
0610                         ibm_drconnector[state]);
0611                 have_strings = 1;
0612             }
0613             break;
0614         case IBM_POWERSUPPLY:
0615             seq_printf(m, "Powersupply:\t");
0616             break;
0617         default:
0618             seq_printf(m,  "Unknown sensor (type %d), ignoring it\n",
0619                     s->token);
0620             unknown = 1;
0621             have_strings = 1;
0622             break;
0623     }
0624     if (have_strings == 0) {
0625         if (temperature) {
0626             seq_printf(m, "%4d /%4d\t", state, cel_to_fahr(state));
0627         } else
0628             seq_printf(m, "%10d\t", state);
0629     }
0630     if (unknown == 0) {
0631         seq_printf(m, "%s\t", ppc_rtas_process_error(error));
0632         get_location_code(m, s, loc);
0633     }
0634 }
0635 
0636 /* ****************************************************************** */
0637 
0638 static void check_location(struct seq_file *m, const char *c)
0639 {
0640     switch (c[0]) {
0641         case LOC_PLANAR:
0642             seq_printf(m, "Planar #%c", c[1]);
0643             break;
0644         case LOC_CPU:
0645             seq_printf(m, "CPU #%c", c[1]);
0646             break;
0647         case LOC_FAN:
0648             seq_printf(m, "Fan #%c", c[1]);
0649             break;
0650         case LOC_RACKMOUNTED:
0651             seq_printf(m, "Rack #%c", c[1]);
0652             break;
0653         case LOC_VOLTAGE:
0654             seq_printf(m, "Voltage #%c", c[1]);
0655             break;
0656         case LOC_LCD:
0657             seq_printf(m, "LCD #%c", c[1]);
0658             break;
0659         case '.':
0660             seq_printf(m, "- %c", c[1]);
0661             break;
0662         default:
0663             seq_printf(m, "Unknown location");
0664             break;
0665     }
0666 }
0667 
0668 
0669 /* ****************************************************************** */
0670 /* 
0671  * Format: 
0672  * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ]
0673  * the '.' may be an abbreviation
0674  */
0675 static void check_location_string(struct seq_file *m, const char *c)
0676 {
0677     while (*c) {
0678         if (isalpha(*c) || *c == '.')
0679             check_location(m, c);
0680         else if (*c == '/' || *c == '-')
0681             seq_printf(m, " at ");
0682         c++;
0683     }
0684 }
0685 
0686 
0687 /* ****************************************************************** */
0688 
0689 static void get_location_code(struct seq_file *m, struct individual_sensor *s,
0690         const char *loc)
0691 {
0692     if (!loc || !*loc) {
0693         seq_printf(m, "---");/* does not have a location */
0694     } else {
0695         check_location_string(m, loc);
0696     }
0697     seq_putc(m, ' ');
0698 }
0699 /* ****************************************************************** */
0700 /* INDICATORS - Tone Frequency                                        */
0701 /* ****************************************************************** */
0702 static ssize_t ppc_rtas_tone_freq_write(struct file *file,
0703         const char __user *buf, size_t count, loff_t *ppos)
0704 {
0705     u64 freq;
0706     int error = parse_number(buf, count, &freq);
0707     if (error)
0708         return error;
0709 
0710     rtas_tone_frequency = freq; /* save it for later */
0711     error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
0712             TONE_FREQUENCY, 0, freq);
0713     if (error)
0714         printk(KERN_WARNING "error: setting tone frequency returned: %s\n", 
0715                 ppc_rtas_process_error(error));
0716     return count;
0717 }
0718 /* ****************************************************************** */
0719 static int ppc_rtas_tone_freq_show(struct seq_file *m, void *v)
0720 {
0721     seq_printf(m, "%lu\n", rtas_tone_frequency);
0722     return 0;
0723 }
0724 /* ****************************************************************** */
0725 /* INDICATORS - Tone Volume                                           */
0726 /* ****************************************************************** */
0727 static ssize_t ppc_rtas_tone_volume_write(struct file *file,
0728         const char __user *buf, size_t count, loff_t *ppos)
0729 {
0730     u64 volume;
0731     int error = parse_number(buf, count, &volume);
0732     if (error)
0733         return error;
0734 
0735     if (volume > 100)
0736         volume = 100;
0737     
0738         rtas_tone_volume = volume; /* save it for later */
0739     error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
0740             TONE_VOLUME, 0, volume);
0741     if (error)
0742         printk(KERN_WARNING "error: setting tone volume returned: %s\n", 
0743                 ppc_rtas_process_error(error));
0744     return count;
0745 }
0746 /* ****************************************************************** */
0747 static int ppc_rtas_tone_volume_show(struct seq_file *m, void *v)
0748 {
0749     seq_printf(m, "%lu\n", rtas_tone_volume);
0750     return 0;
0751 }
0752 
0753 /**
0754  * ppc_rtas_rmo_buf_show() - Describe RTAS-addressable region for user space.
0755  *
0756  * Base + size description of a range of RTAS-addressable memory set
0757  * aside for user space to use as work area(s) for certain RTAS
0758  * functions. User space accesses this region via /dev/mem. Apart from
0759  * security policies, the kernel does not arbitrate or serialize
0760  * access to this region, and user space must ensure that concurrent
0761  * users do not interfere with each other.
0762  */
0763 static int ppc_rtas_rmo_buf_show(struct seq_file *m, void *v)
0764 {
0765     seq_printf(m, "%016lx %x\n", rtas_rmo_buf, RTAS_USER_REGION_SIZE);
0766     return 0;
0767 }