linux-old/arch/ppc64/kernel/rtas-proc.c
<<
>>
Prefs
   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 */
 118static struct rtas_sensors sensors;
 119static struct device_node *rtas_node = NULL;
 120static unsigned long power_on_time = 0; /* Save the time the user set */
 121static char progress_led[MAX_LINELENGTH];
 122
 123static unsigned long rtas_tone_frequency = 1000;
 124static unsigned long rtas_tone_volume = 0;
 125static unsigned int open_token = 0;
 126
 127static int set_time_for_power_on = RTAS_UNKNOWN_SERVICE;
 128static int set_time_of_day = RTAS_UNKNOWN_SERVICE;
 129static int get_sensor_state = RTAS_UNKNOWN_SERVICE;
 130static int set_indicator = RTAS_UNKNOWN_SERVICE;
 131
 132extern struct proc_dir_entry *proc_ppc64_root;
 133extern struct proc_dir_entry *rtas_proc_dir;
 134extern spinlock_t proc_ppc64_lock;
 135
 136/* ****************STRUCTS******************************************* */
 137struct individual_sensor {
 138        unsigned int token;
 139        unsigned int quant;
 140};
 141
 142struct rtas_sensors {
 143        struct individual_sensor sensor[MAX_SENSORS];
 144        unsigned int quant;
 145};
 146
 147/* ****************************************************************** */
 148/* Declarations */
 149static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off,
 150                int count, int *eof, void *data);
 151static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, 
 152                size_t count, loff_t *ppos);
 153static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, 
 154                size_t count, loff_t *ppos);
 155static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
 156                size_t count, loff_t *ppos);
 157static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
 158                size_t count, loff_t *ppos);
 159static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
 160                size_t count, loff_t *ppos);
 161static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
 162                size_t count, loff_t *ppos);
 163
 164static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
 165                size_t count, loff_t *ppos);
 166static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
 167                size_t count, loff_t *ppos);
 168static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
 169                size_t count, loff_t *ppos);
 170static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
 171                size_t count, loff_t *ppos);
 172static int ppc_rtas_errinjct_open(struct inode *inode, struct file *file);
 173static int ppc_rtas_errinjct_release(struct inode *inode, struct file *file);
 174static ssize_t ppc_rtas_errinjct_write(struct file * file, const char * buf,
 175                                   size_t count, loff_t *ppos);
 176static ssize_t ppc_rtas_errinjct_read(struct file *file, char *buf,
 177                                      size_t count, loff_t *ppos);
 178
 179struct file_operations ppc_rtas_poweron_operations = {
 180        .read =         ppc_rtas_poweron_read,
 181        .write =        ppc_rtas_poweron_write
 182};
 183struct file_operations ppc_rtas_progress_operations = {
 184        .read =         ppc_rtas_progress_read,
 185        .write =        ppc_rtas_progress_write
 186};
 187
 188struct file_operations ppc_rtas_clock_operations = {
 189        .read =         ppc_rtas_clock_read,
 190        .write =        ppc_rtas_clock_write
 191};
 192
 193struct file_operations ppc_rtas_tone_freq_operations = {
 194        .read =         ppc_rtas_tone_freq_read,
 195        .write =        ppc_rtas_tone_freq_write
 196};
 197struct file_operations ppc_rtas_tone_volume_operations = {
 198        .read =         ppc_rtas_tone_volume_read,
 199        .write =        ppc_rtas_tone_volume_write
 200};
 201
 202struct 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
 209int ppc_rtas_find_all_sensors (void);
 210int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
 211                int error, char * buf);
 212char * ppc_rtas_process_error(int error);
 213int get_location_code(struct individual_sensor s, char * buf);
 214int check_location_string (char *c, char * buf);
 215int check_location (char *c, int idx, char * buf);
 216
 217/* ****************************************************************** */
 218/* MAIN                                                               */
 219/* ****************************************************************** */
 220void 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/* ****************************************************************** */
 302static 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/* ****************************************************************** */
 335static 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/* ****************************************************************** */
 363static 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/* ****************************************************************** */
 384static 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/* ****************************************************************** */
 421static 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/* ****************************************************************** */
 452static 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/* ****************************************************************** */
 493static 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
 538return_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
 559int 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 */
 583char * 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
 616int 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
 743int 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 */
 782int 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
 800int 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/* ****************************************************************** */
 850static 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/* ****************************************************************** */
 879static 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/* ****************************************************************** */
 904static 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/* ****************************************************************** */
 935static 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/* ****************************************************************** */
 960static 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
 979static 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
1054static 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
1066static 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}
1107
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.