cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rtas-proc.c (22169B)


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