18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2000 Tilmann Bitterberg 48c2ecf20Sopenharmony_ci * (tilmann@bitterberg.de) 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * RTAS (Runtime Abstraction Services) stuff 78c2ecf20Sopenharmony_ci * Intention is to provide a clean user interface 88c2ecf20Sopenharmony_ci * to use the RTAS. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * TODO: 118c2ecf20Sopenharmony_ci * Split off a header file and maybe move it to a different 128c2ecf20Sopenharmony_ci * location. Write Documentation on what the /proc/rtas/ entries 138c2ecf20Sopenharmony_ci * actually do. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/errno.h> 178c2ecf20Sopenharmony_ci#include <linux/sched.h> 188c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 198c2ecf20Sopenharmony_ci#include <linux/stat.h> 208c2ecf20Sopenharmony_ci#include <linux/ctype.h> 218c2ecf20Sopenharmony_ci#include <linux/time.h> 228c2ecf20Sopenharmony_ci#include <linux/string.h> 238c2ecf20Sopenharmony_ci#include <linux/init.h> 248c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 258c2ecf20Sopenharmony_ci#include <linux/bitops.h> 268c2ecf20Sopenharmony_ci#include <linux/rtc.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 298c2ecf20Sopenharmony_ci#include <asm/processor.h> 308c2ecf20Sopenharmony_ci#include <asm/io.h> 318c2ecf20Sopenharmony_ci#include <asm/prom.h> 328c2ecf20Sopenharmony_ci#include <asm/rtas.h> 338c2ecf20Sopenharmony_ci#include <asm/machdep.h> /* for ppc_md */ 348c2ecf20Sopenharmony_ci#include <asm/time.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* Token for Sensors */ 378c2ecf20Sopenharmony_ci#define KEY_SWITCH 0x0001 388c2ecf20Sopenharmony_ci#define ENCLOSURE_SWITCH 0x0002 398c2ecf20Sopenharmony_ci#define THERMAL_SENSOR 0x0003 408c2ecf20Sopenharmony_ci#define LID_STATUS 0x0004 418c2ecf20Sopenharmony_ci#define POWER_SOURCE 0x0005 428c2ecf20Sopenharmony_ci#define BATTERY_VOLTAGE 0x0006 438c2ecf20Sopenharmony_ci#define BATTERY_REMAINING 0x0007 448c2ecf20Sopenharmony_ci#define BATTERY_PERCENTAGE 0x0008 458c2ecf20Sopenharmony_ci#define EPOW_SENSOR 0x0009 468c2ecf20Sopenharmony_ci#define BATTERY_CYCLESTATE 0x000a 478c2ecf20Sopenharmony_ci#define BATTERY_CHARGING 0x000b 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* IBM specific sensors */ 508c2ecf20Sopenharmony_ci#define IBM_SURVEILLANCE 0x2328 /* 9000 */ 518c2ecf20Sopenharmony_ci#define IBM_FANRPM 0x2329 /* 9001 */ 528c2ecf20Sopenharmony_ci#define IBM_VOLTAGE 0x232a /* 9002 */ 538c2ecf20Sopenharmony_ci#define IBM_DRCONNECTOR 0x232b /* 9003 */ 548c2ecf20Sopenharmony_ci#define IBM_POWERSUPPLY 0x232c /* 9004 */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* Status return values */ 578c2ecf20Sopenharmony_ci#define SENSOR_CRITICAL_HIGH 13 588c2ecf20Sopenharmony_ci#define SENSOR_WARNING_HIGH 12 598c2ecf20Sopenharmony_ci#define SENSOR_NORMAL 11 608c2ecf20Sopenharmony_ci#define SENSOR_WARNING_LOW 10 618c2ecf20Sopenharmony_ci#define SENSOR_CRITICAL_LOW 9 628c2ecf20Sopenharmony_ci#define SENSOR_SUCCESS 0 638c2ecf20Sopenharmony_ci#define SENSOR_HW_ERROR -1 648c2ecf20Sopenharmony_ci#define SENSOR_BUSY -2 658c2ecf20Sopenharmony_ci#define SENSOR_NOT_EXIST -3 668c2ecf20Sopenharmony_ci#define SENSOR_DR_ENTITY -9000 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Location Codes */ 698c2ecf20Sopenharmony_ci#define LOC_SCSI_DEV_ADDR 'A' 708c2ecf20Sopenharmony_ci#define LOC_SCSI_DEV_LOC 'B' 718c2ecf20Sopenharmony_ci#define LOC_CPU 'C' 728c2ecf20Sopenharmony_ci#define LOC_DISKETTE 'D' 738c2ecf20Sopenharmony_ci#define LOC_ETHERNET 'E' 748c2ecf20Sopenharmony_ci#define LOC_FAN 'F' 758c2ecf20Sopenharmony_ci#define LOC_GRAPHICS 'G' 768c2ecf20Sopenharmony_ci/* reserved / not used 'H' */ 778c2ecf20Sopenharmony_ci#define LOC_IO_ADAPTER 'I' 788c2ecf20Sopenharmony_ci/* reserved / not used 'J' */ 798c2ecf20Sopenharmony_ci#define LOC_KEYBOARD 'K' 808c2ecf20Sopenharmony_ci#define LOC_LCD 'L' 818c2ecf20Sopenharmony_ci#define LOC_MEMORY 'M' 828c2ecf20Sopenharmony_ci#define LOC_NV_MEMORY 'N' 838c2ecf20Sopenharmony_ci#define LOC_MOUSE 'O' 848c2ecf20Sopenharmony_ci#define LOC_PLANAR 'P' 858c2ecf20Sopenharmony_ci#define LOC_OTHER_IO 'Q' 868c2ecf20Sopenharmony_ci#define LOC_PARALLEL 'R' 878c2ecf20Sopenharmony_ci#define LOC_SERIAL 'S' 888c2ecf20Sopenharmony_ci#define LOC_DEAD_RING 'T' 898c2ecf20Sopenharmony_ci#define LOC_RACKMOUNTED 'U' /* for _u_nit is rack mounted */ 908c2ecf20Sopenharmony_ci#define LOC_VOLTAGE 'V' 918c2ecf20Sopenharmony_ci#define LOC_SWITCH_ADAPTER 'W' 928c2ecf20Sopenharmony_ci#define LOC_OTHER 'X' 938c2ecf20Sopenharmony_ci#define LOC_FIRMWARE 'Y' 948c2ecf20Sopenharmony_ci#define LOC_SCSI 'Z' 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* Tokens for indicators */ 978c2ecf20Sopenharmony_ci#define TONE_FREQUENCY 0x0001 /* 0 - 1000 (HZ)*/ 988c2ecf20Sopenharmony_ci#define TONE_VOLUME 0x0002 /* 0 - 100 (%) */ 998c2ecf20Sopenharmony_ci#define SYSTEM_POWER_STATE 0x0003 1008c2ecf20Sopenharmony_ci#define WARNING_LIGHT 0x0004 1018c2ecf20Sopenharmony_ci#define DISK_ACTIVITY_LIGHT 0x0005 1028c2ecf20Sopenharmony_ci#define HEX_DISPLAY_UNIT 0x0006 1038c2ecf20Sopenharmony_ci#define BATTERY_WARNING_TIME 0x0007 1048c2ecf20Sopenharmony_ci#define CONDITION_CYCLE_REQUEST 0x0008 1058c2ecf20Sopenharmony_ci#define SURVEILLANCE_INDICATOR 0x2328 /* 9000 */ 1068c2ecf20Sopenharmony_ci#define DR_ACTION 0x2329 /* 9001 */ 1078c2ecf20Sopenharmony_ci#define DR_INDICATOR 0x232a /* 9002 */ 1088c2ecf20Sopenharmony_ci/* 9003 - 9004: Vendor specific */ 1098c2ecf20Sopenharmony_ci/* 9006 - 9999: Vendor specific */ 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* other */ 1128c2ecf20Sopenharmony_ci#define MAX_SENSORS 17 /* I only know of 17 sensors */ 1138c2ecf20Sopenharmony_ci#define MAX_LINELENGTH 256 1148c2ecf20Sopenharmony_ci#define SENSOR_PREFIX "ibm,sensor-" 1158c2ecf20Sopenharmony_ci#define cel_to_fahr(x) ((x*9/5)+32) 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistruct individual_sensor { 1188c2ecf20Sopenharmony_ci unsigned int token; 1198c2ecf20Sopenharmony_ci unsigned int quant; 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistruct rtas_sensors { 1238c2ecf20Sopenharmony_ci struct individual_sensor sensor[MAX_SENSORS]; 1248c2ecf20Sopenharmony_ci unsigned int quant; 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* Globals */ 1288c2ecf20Sopenharmony_cistatic struct rtas_sensors sensors; 1298c2ecf20Sopenharmony_cistatic struct device_node *rtas_node = NULL; 1308c2ecf20Sopenharmony_cistatic unsigned long power_on_time = 0; /* Save the time the user set */ 1318c2ecf20Sopenharmony_cistatic char progress_led[MAX_LINELENGTH]; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic unsigned long rtas_tone_frequency = 1000; 1348c2ecf20Sopenharmony_cistatic unsigned long rtas_tone_volume = 0; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* ****************************************************************** */ 1378c2ecf20Sopenharmony_ci/* Declarations */ 1388c2ecf20Sopenharmony_cistatic int ppc_rtas_sensors_show(struct seq_file *m, void *v); 1398c2ecf20Sopenharmony_cistatic int ppc_rtas_clock_show(struct seq_file *m, void *v); 1408c2ecf20Sopenharmony_cistatic ssize_t ppc_rtas_clock_write(struct file *file, 1418c2ecf20Sopenharmony_ci const char __user *buf, size_t count, loff_t *ppos); 1428c2ecf20Sopenharmony_cistatic int ppc_rtas_progress_show(struct seq_file *m, void *v); 1438c2ecf20Sopenharmony_cistatic ssize_t ppc_rtas_progress_write(struct file *file, 1448c2ecf20Sopenharmony_ci const char __user *buf, size_t count, loff_t *ppos); 1458c2ecf20Sopenharmony_cistatic int ppc_rtas_poweron_show(struct seq_file *m, void *v); 1468c2ecf20Sopenharmony_cistatic ssize_t ppc_rtas_poweron_write(struct file *file, 1478c2ecf20Sopenharmony_ci const char __user *buf, size_t count, loff_t *ppos); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic ssize_t ppc_rtas_tone_freq_write(struct file *file, 1508c2ecf20Sopenharmony_ci const char __user *buf, size_t count, loff_t *ppos); 1518c2ecf20Sopenharmony_cistatic int ppc_rtas_tone_freq_show(struct seq_file *m, void *v); 1528c2ecf20Sopenharmony_cistatic ssize_t ppc_rtas_tone_volume_write(struct file *file, 1538c2ecf20Sopenharmony_ci const char __user *buf, size_t count, loff_t *ppos); 1548c2ecf20Sopenharmony_cistatic int ppc_rtas_tone_volume_show(struct seq_file *m, void *v); 1558c2ecf20Sopenharmony_cistatic int ppc_rtas_rmo_buf_show(struct seq_file *m, void *v); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int poweron_open(struct inode *inode, struct file *file) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci return single_open(file, ppc_rtas_poweron_show, NULL); 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic const struct proc_ops ppc_rtas_poweron_proc_ops = { 1638c2ecf20Sopenharmony_ci .proc_open = poweron_open, 1648c2ecf20Sopenharmony_ci .proc_read = seq_read, 1658c2ecf20Sopenharmony_ci .proc_lseek = seq_lseek, 1668c2ecf20Sopenharmony_ci .proc_write = ppc_rtas_poweron_write, 1678c2ecf20Sopenharmony_ci .proc_release = single_release, 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int progress_open(struct inode *inode, struct file *file) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci return single_open(file, ppc_rtas_progress_show, NULL); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic const struct proc_ops ppc_rtas_progress_proc_ops = { 1768c2ecf20Sopenharmony_ci .proc_open = progress_open, 1778c2ecf20Sopenharmony_ci .proc_read = seq_read, 1788c2ecf20Sopenharmony_ci .proc_lseek = seq_lseek, 1798c2ecf20Sopenharmony_ci .proc_write = ppc_rtas_progress_write, 1808c2ecf20Sopenharmony_ci .proc_release = single_release, 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int clock_open(struct inode *inode, struct file *file) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci return single_open(file, ppc_rtas_clock_show, NULL); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic const struct proc_ops ppc_rtas_clock_proc_ops = { 1898c2ecf20Sopenharmony_ci .proc_open = clock_open, 1908c2ecf20Sopenharmony_ci .proc_read = seq_read, 1918c2ecf20Sopenharmony_ci .proc_lseek = seq_lseek, 1928c2ecf20Sopenharmony_ci .proc_write = ppc_rtas_clock_write, 1938c2ecf20Sopenharmony_ci .proc_release = single_release, 1948c2ecf20Sopenharmony_ci}; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic int tone_freq_open(struct inode *inode, struct file *file) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci return single_open(file, ppc_rtas_tone_freq_show, NULL); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic const struct proc_ops ppc_rtas_tone_freq_proc_ops = { 2028c2ecf20Sopenharmony_ci .proc_open = tone_freq_open, 2038c2ecf20Sopenharmony_ci .proc_read = seq_read, 2048c2ecf20Sopenharmony_ci .proc_lseek = seq_lseek, 2058c2ecf20Sopenharmony_ci .proc_write = ppc_rtas_tone_freq_write, 2068c2ecf20Sopenharmony_ci .proc_release = single_release, 2078c2ecf20Sopenharmony_ci}; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int tone_volume_open(struct inode *inode, struct file *file) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci return single_open(file, ppc_rtas_tone_volume_show, NULL); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic const struct proc_ops ppc_rtas_tone_volume_proc_ops = { 2158c2ecf20Sopenharmony_ci .proc_open = tone_volume_open, 2168c2ecf20Sopenharmony_ci .proc_read = seq_read, 2178c2ecf20Sopenharmony_ci .proc_lseek = seq_lseek, 2188c2ecf20Sopenharmony_ci .proc_write = ppc_rtas_tone_volume_write, 2198c2ecf20Sopenharmony_ci .proc_release = single_release, 2208c2ecf20Sopenharmony_ci}; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic int ppc_rtas_find_all_sensors(void); 2238c2ecf20Sopenharmony_cistatic void ppc_rtas_process_sensor(struct seq_file *m, 2248c2ecf20Sopenharmony_ci struct individual_sensor *s, int state, int error, const char *loc); 2258c2ecf20Sopenharmony_cistatic char *ppc_rtas_process_error(int error); 2268c2ecf20Sopenharmony_cistatic void get_location_code(struct seq_file *m, 2278c2ecf20Sopenharmony_ci struct individual_sensor *s, const char *loc); 2288c2ecf20Sopenharmony_cistatic void check_location_string(struct seq_file *m, const char *c); 2298c2ecf20Sopenharmony_cistatic void check_location(struct seq_file *m, const char *c); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int __init proc_rtas_init(void) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci if (!machine_is(pseries)) 2348c2ecf20Sopenharmony_ci return -ENODEV; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci rtas_node = of_find_node_by_name(NULL, "rtas"); 2378c2ecf20Sopenharmony_ci if (rtas_node == NULL) 2388c2ecf20Sopenharmony_ci return -ENODEV; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci proc_create("powerpc/rtas/progress", 0644, NULL, 2418c2ecf20Sopenharmony_ci &ppc_rtas_progress_proc_ops); 2428c2ecf20Sopenharmony_ci proc_create("powerpc/rtas/clock", 0644, NULL, 2438c2ecf20Sopenharmony_ci &ppc_rtas_clock_proc_ops); 2448c2ecf20Sopenharmony_ci proc_create("powerpc/rtas/poweron", 0644, NULL, 2458c2ecf20Sopenharmony_ci &ppc_rtas_poweron_proc_ops); 2468c2ecf20Sopenharmony_ci proc_create_single("powerpc/rtas/sensors", 0444, NULL, 2478c2ecf20Sopenharmony_ci ppc_rtas_sensors_show); 2488c2ecf20Sopenharmony_ci proc_create("powerpc/rtas/frequency", 0644, NULL, 2498c2ecf20Sopenharmony_ci &ppc_rtas_tone_freq_proc_ops); 2508c2ecf20Sopenharmony_ci proc_create("powerpc/rtas/volume", 0644, NULL, 2518c2ecf20Sopenharmony_ci &ppc_rtas_tone_volume_proc_ops); 2528c2ecf20Sopenharmony_ci proc_create_single("powerpc/rtas/rmo_buffer", 0400, NULL, 2538c2ecf20Sopenharmony_ci ppc_rtas_rmo_buf_show); 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci__initcall(proc_rtas_init); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int parse_number(const char __user *p, size_t count, u64 *val) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci char buf[40]; 2628c2ecf20Sopenharmony_ci char *end; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (count > 39) 2658c2ecf20Sopenharmony_ci return -EINVAL; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (copy_from_user(buf, p, count)) 2688c2ecf20Sopenharmony_ci return -EFAULT; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci buf[count] = 0; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci *val = simple_strtoull(buf, &end, 10); 2738c2ecf20Sopenharmony_ci if (*end && *end != '\n') 2748c2ecf20Sopenharmony_ci return -EINVAL; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci return 0; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/* ****************************************************************** */ 2808c2ecf20Sopenharmony_ci/* POWER-ON-TIME */ 2818c2ecf20Sopenharmony_ci/* ****************************************************************** */ 2828c2ecf20Sopenharmony_cistatic ssize_t ppc_rtas_poweron_write(struct file *file, 2838c2ecf20Sopenharmony_ci const char __user *buf, size_t count, loff_t *ppos) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct rtc_time tm; 2868c2ecf20Sopenharmony_ci time64_t nowtime; 2878c2ecf20Sopenharmony_ci int error = parse_number(buf, count, &nowtime); 2888c2ecf20Sopenharmony_ci if (error) 2898c2ecf20Sopenharmony_ci return error; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci power_on_time = nowtime; /* save the time */ 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci rtc_time64_to_tm(nowtime, &tm); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci error = rtas_call(rtas_token("set-time-for-power-on"), 7, 1, NULL, 2968c2ecf20Sopenharmony_ci tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 2978c2ecf20Sopenharmony_ci tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */); 2988c2ecf20Sopenharmony_ci if (error) 2998c2ecf20Sopenharmony_ci printk(KERN_WARNING "error: setting poweron time returned: %s\n", 3008c2ecf20Sopenharmony_ci ppc_rtas_process_error(error)); 3018c2ecf20Sopenharmony_ci return count; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci/* ****************************************************************** */ 3048c2ecf20Sopenharmony_cistatic int ppc_rtas_poweron_show(struct seq_file *m, void *v) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci if (power_on_time == 0) 3078c2ecf20Sopenharmony_ci seq_printf(m, "Power on time not set\n"); 3088c2ecf20Sopenharmony_ci else 3098c2ecf20Sopenharmony_ci seq_printf(m, "%lu\n",power_on_time); 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/* ****************************************************************** */ 3148c2ecf20Sopenharmony_ci/* PROGRESS */ 3158c2ecf20Sopenharmony_ci/* ****************************************************************** */ 3168c2ecf20Sopenharmony_cistatic ssize_t ppc_rtas_progress_write(struct file *file, 3178c2ecf20Sopenharmony_ci const char __user *buf, size_t count, loff_t *ppos) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci unsigned long hex; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (count >= MAX_LINELENGTH) 3228c2ecf20Sopenharmony_ci count = MAX_LINELENGTH -1; 3238c2ecf20Sopenharmony_ci if (copy_from_user(progress_led, buf, count)) { /* save the string */ 3248c2ecf20Sopenharmony_ci return -EFAULT; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci progress_led[count] = 0; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* Lets see if the user passed hexdigits */ 3298c2ecf20Sopenharmony_ci hex = simple_strtoul(progress_led, NULL, 10); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci rtas_progress ((char *)progress_led, hex); 3328c2ecf20Sopenharmony_ci return count; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* clear the line */ 3358c2ecf20Sopenharmony_ci /* rtas_progress(" ", 0xffff);*/ 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci/* ****************************************************************** */ 3388c2ecf20Sopenharmony_cistatic int ppc_rtas_progress_show(struct seq_file *m, void *v) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci if (progress_led[0]) 3418c2ecf20Sopenharmony_ci seq_printf(m, "%s\n", progress_led); 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci/* ****************************************************************** */ 3468c2ecf20Sopenharmony_ci/* CLOCK */ 3478c2ecf20Sopenharmony_ci/* ****************************************************************** */ 3488c2ecf20Sopenharmony_cistatic ssize_t ppc_rtas_clock_write(struct file *file, 3498c2ecf20Sopenharmony_ci const char __user *buf, size_t count, loff_t *ppos) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct rtc_time tm; 3528c2ecf20Sopenharmony_ci time64_t nowtime; 3538c2ecf20Sopenharmony_ci int error = parse_number(buf, count, &nowtime); 3548c2ecf20Sopenharmony_ci if (error) 3558c2ecf20Sopenharmony_ci return error; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci rtc_time64_to_tm(nowtime, &tm); 3588c2ecf20Sopenharmony_ci error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL, 3598c2ecf20Sopenharmony_ci tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 3608c2ecf20Sopenharmony_ci tm.tm_hour, tm.tm_min, tm.tm_sec, 0); 3618c2ecf20Sopenharmony_ci if (error) 3628c2ecf20Sopenharmony_ci printk(KERN_WARNING "error: setting the clock returned: %s\n", 3638c2ecf20Sopenharmony_ci ppc_rtas_process_error(error)); 3648c2ecf20Sopenharmony_ci return count; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci/* ****************************************************************** */ 3678c2ecf20Sopenharmony_cistatic int ppc_rtas_clock_show(struct seq_file *m, void *v) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci int ret[8]; 3708c2ecf20Sopenharmony_ci int error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (error) { 3738c2ecf20Sopenharmony_ci printk(KERN_WARNING "error: reading the clock returned: %s\n", 3748c2ecf20Sopenharmony_ci ppc_rtas_process_error(error)); 3758c2ecf20Sopenharmony_ci seq_printf(m, "0"); 3768c2ecf20Sopenharmony_ci } else { 3778c2ecf20Sopenharmony_ci unsigned int year, mon, day, hour, min, sec; 3788c2ecf20Sopenharmony_ci year = ret[0]; mon = ret[1]; day = ret[2]; 3798c2ecf20Sopenharmony_ci hour = ret[3]; min = ret[4]; sec = ret[5]; 3808c2ecf20Sopenharmony_ci seq_printf(m, "%lld\n", 3818c2ecf20Sopenharmony_ci mktime64(year, mon, day, hour, min, sec)); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci/* ****************************************************************** */ 3878c2ecf20Sopenharmony_ci/* SENSOR STUFF */ 3888c2ecf20Sopenharmony_ci/* ****************************************************************** */ 3898c2ecf20Sopenharmony_cistatic int ppc_rtas_sensors_show(struct seq_file *m, void *v) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci int i,j; 3928c2ecf20Sopenharmony_ci int state, error; 3938c2ecf20Sopenharmony_ci int get_sensor_state = rtas_token("get-sensor-state"); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci seq_printf(m, "RTAS (RunTime Abstraction Services) Sensor Information\n"); 3968c2ecf20Sopenharmony_ci seq_printf(m, "Sensor\t\tValue\t\tCondition\tLocation\n"); 3978c2ecf20Sopenharmony_ci seq_printf(m, "********************************************************\n"); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (ppc_rtas_find_all_sensors() != 0) { 4008c2ecf20Sopenharmony_ci seq_printf(m, "\nNo sensors are available\n"); 4018c2ecf20Sopenharmony_ci return 0; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci for (i=0; i<sensors.quant; i++) { 4058c2ecf20Sopenharmony_ci struct individual_sensor *p = &sensors.sensor[i]; 4068c2ecf20Sopenharmony_ci char rstr[64]; 4078c2ecf20Sopenharmony_ci const char *loc; 4088c2ecf20Sopenharmony_ci int llen, offs; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci sprintf (rstr, SENSOR_PREFIX"%04d", p->token); 4118c2ecf20Sopenharmony_ci loc = of_get_property(rtas_node, rstr, &llen); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* A sensor may have multiple instances */ 4148c2ecf20Sopenharmony_ci for (j = 0, offs = 0; j <= p->quant; j++) { 4158c2ecf20Sopenharmony_ci error = rtas_call(get_sensor_state, 2, 2, &state, 4168c2ecf20Sopenharmony_ci p->token, j); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci ppc_rtas_process_sensor(m, p, state, error, loc); 4198c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 4208c2ecf20Sopenharmony_ci if (loc) { 4218c2ecf20Sopenharmony_ci offs += strlen(loc) + 1; 4228c2ecf20Sopenharmony_ci loc += strlen(loc) + 1; 4238c2ecf20Sopenharmony_ci if (offs >= llen) 4248c2ecf20Sopenharmony_ci loc = NULL; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci/* ****************************************************************** */ 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic int ppc_rtas_find_all_sensors(void) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci const unsigned int *utmp; 4368c2ecf20Sopenharmony_ci int len, i; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci utmp = of_get_property(rtas_node, "rtas-sensors", &len); 4398c2ecf20Sopenharmony_ci if (utmp == NULL) { 4408c2ecf20Sopenharmony_ci printk (KERN_ERR "error: could not get rtas-sensors\n"); 4418c2ecf20Sopenharmony_ci return 1; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci sensors.quant = len / 8; /* int + int */ 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci for (i=0; i<sensors.quant; i++) { 4478c2ecf20Sopenharmony_ci sensors.sensor[i].token = *utmp++; 4488c2ecf20Sopenharmony_ci sensors.sensor[i].quant = *utmp++; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci/* ****************************************************************** */ 4548c2ecf20Sopenharmony_ci/* 4558c2ecf20Sopenharmony_ci * Builds a string of what rtas returned 4568c2ecf20Sopenharmony_ci */ 4578c2ecf20Sopenharmony_cistatic char *ppc_rtas_process_error(int error) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci switch (error) { 4608c2ecf20Sopenharmony_ci case SENSOR_CRITICAL_HIGH: 4618c2ecf20Sopenharmony_ci return "(critical high)"; 4628c2ecf20Sopenharmony_ci case SENSOR_WARNING_HIGH: 4638c2ecf20Sopenharmony_ci return "(warning high)"; 4648c2ecf20Sopenharmony_ci case SENSOR_NORMAL: 4658c2ecf20Sopenharmony_ci return "(normal)"; 4668c2ecf20Sopenharmony_ci case SENSOR_WARNING_LOW: 4678c2ecf20Sopenharmony_ci return "(warning low)"; 4688c2ecf20Sopenharmony_ci case SENSOR_CRITICAL_LOW: 4698c2ecf20Sopenharmony_ci return "(critical low)"; 4708c2ecf20Sopenharmony_ci case SENSOR_SUCCESS: 4718c2ecf20Sopenharmony_ci return "(read ok)"; 4728c2ecf20Sopenharmony_ci case SENSOR_HW_ERROR: 4738c2ecf20Sopenharmony_ci return "(hardware error)"; 4748c2ecf20Sopenharmony_ci case SENSOR_BUSY: 4758c2ecf20Sopenharmony_ci return "(busy)"; 4768c2ecf20Sopenharmony_ci case SENSOR_NOT_EXIST: 4778c2ecf20Sopenharmony_ci return "(non existent)"; 4788c2ecf20Sopenharmony_ci case SENSOR_DR_ENTITY: 4798c2ecf20Sopenharmony_ci return "(dr entity removed)"; 4808c2ecf20Sopenharmony_ci default: 4818c2ecf20Sopenharmony_ci return "(UNKNOWN)"; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci/* ****************************************************************** */ 4868c2ecf20Sopenharmony_ci/* 4878c2ecf20Sopenharmony_ci * Builds a string out of what the sensor said 4888c2ecf20Sopenharmony_ci */ 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic void ppc_rtas_process_sensor(struct seq_file *m, 4918c2ecf20Sopenharmony_ci struct individual_sensor *s, int state, int error, const char *loc) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci /* Defined return vales */ 4948c2ecf20Sopenharmony_ci const char * key_switch[] = { "Off\t", "Normal\t", "Secure\t", 4958c2ecf20Sopenharmony_ci "Maintenance" }; 4968c2ecf20Sopenharmony_ci const char * enclosure_switch[] = { "Closed", "Open" }; 4978c2ecf20Sopenharmony_ci const char * lid_status[] = { " ", "Open", "Closed" }; 4988c2ecf20Sopenharmony_ci const char * power_source[] = { "AC\t", "Battery", 4998c2ecf20Sopenharmony_ci "AC & Battery" }; 5008c2ecf20Sopenharmony_ci const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" }; 5018c2ecf20Sopenharmony_ci const char * epow_sensor[] = { 5028c2ecf20Sopenharmony_ci "EPOW Reset", "Cooling warning", "Power warning", 5038c2ecf20Sopenharmony_ci "System shutdown", "System halt", "EPOW main enclosure", 5048c2ecf20Sopenharmony_ci "EPOW power off" }; 5058c2ecf20Sopenharmony_ci const char * battery_cyclestate[] = { "None", "In progress", 5068c2ecf20Sopenharmony_ci "Requested" }; 5078c2ecf20Sopenharmony_ci const char * battery_charging[] = { "Charging", "Discharging", 5088c2ecf20Sopenharmony_ci "No current flow" }; 5098c2ecf20Sopenharmony_ci const char * ibm_drconnector[] = { "Empty", "Present", "Unusable", 5108c2ecf20Sopenharmony_ci "Exchange" }; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci int have_strings = 0; 5138c2ecf20Sopenharmony_ci int num_states = 0; 5148c2ecf20Sopenharmony_ci int temperature = 0; 5158c2ecf20Sopenharmony_ci int unknown = 0; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* What kind of sensor do we have here? */ 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci switch (s->token) { 5208c2ecf20Sopenharmony_ci case KEY_SWITCH: 5218c2ecf20Sopenharmony_ci seq_printf(m, "Key switch:\t"); 5228c2ecf20Sopenharmony_ci num_states = sizeof(key_switch) / sizeof(char *); 5238c2ecf20Sopenharmony_ci if (state < num_states) { 5248c2ecf20Sopenharmony_ci seq_printf(m, "%s\t", key_switch[state]); 5258c2ecf20Sopenharmony_ci have_strings = 1; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci case ENCLOSURE_SWITCH: 5298c2ecf20Sopenharmony_ci seq_printf(m, "Enclosure switch:\t"); 5308c2ecf20Sopenharmony_ci num_states = sizeof(enclosure_switch) / sizeof(char *); 5318c2ecf20Sopenharmony_ci if (state < num_states) { 5328c2ecf20Sopenharmony_ci seq_printf(m, "%s\t", 5338c2ecf20Sopenharmony_ci enclosure_switch[state]); 5348c2ecf20Sopenharmony_ci have_strings = 1; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci case THERMAL_SENSOR: 5388c2ecf20Sopenharmony_ci seq_printf(m, "Temp. (C/F):\t"); 5398c2ecf20Sopenharmony_ci temperature = 1; 5408c2ecf20Sopenharmony_ci break; 5418c2ecf20Sopenharmony_ci case LID_STATUS: 5428c2ecf20Sopenharmony_ci seq_printf(m, "Lid status:\t"); 5438c2ecf20Sopenharmony_ci num_states = sizeof(lid_status) / sizeof(char *); 5448c2ecf20Sopenharmony_ci if (state < num_states) { 5458c2ecf20Sopenharmony_ci seq_printf(m, "%s\t", lid_status[state]); 5468c2ecf20Sopenharmony_ci have_strings = 1; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci break; 5498c2ecf20Sopenharmony_ci case POWER_SOURCE: 5508c2ecf20Sopenharmony_ci seq_printf(m, "Power source:\t"); 5518c2ecf20Sopenharmony_ci num_states = sizeof(power_source) / sizeof(char *); 5528c2ecf20Sopenharmony_ci if (state < num_states) { 5538c2ecf20Sopenharmony_ci seq_printf(m, "%s\t", 5548c2ecf20Sopenharmony_ci power_source[state]); 5558c2ecf20Sopenharmony_ci have_strings = 1; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci break; 5588c2ecf20Sopenharmony_ci case BATTERY_VOLTAGE: 5598c2ecf20Sopenharmony_ci seq_printf(m, "Battery voltage:\t"); 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci case BATTERY_REMAINING: 5628c2ecf20Sopenharmony_ci seq_printf(m, "Battery remaining:\t"); 5638c2ecf20Sopenharmony_ci num_states = sizeof(battery_remaining) / sizeof(char *); 5648c2ecf20Sopenharmony_ci if (state < num_states) 5658c2ecf20Sopenharmony_ci { 5668c2ecf20Sopenharmony_ci seq_printf(m, "%s\t", 5678c2ecf20Sopenharmony_ci battery_remaining[state]); 5688c2ecf20Sopenharmony_ci have_strings = 1; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci break; 5718c2ecf20Sopenharmony_ci case BATTERY_PERCENTAGE: 5728c2ecf20Sopenharmony_ci seq_printf(m, "Battery percentage:\t"); 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci case EPOW_SENSOR: 5758c2ecf20Sopenharmony_ci seq_printf(m, "EPOW Sensor:\t"); 5768c2ecf20Sopenharmony_ci num_states = sizeof(epow_sensor) / sizeof(char *); 5778c2ecf20Sopenharmony_ci if (state < num_states) { 5788c2ecf20Sopenharmony_ci seq_printf(m, "%s\t", epow_sensor[state]); 5798c2ecf20Sopenharmony_ci have_strings = 1; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci break; 5828c2ecf20Sopenharmony_ci case BATTERY_CYCLESTATE: 5838c2ecf20Sopenharmony_ci seq_printf(m, "Battery cyclestate:\t"); 5848c2ecf20Sopenharmony_ci num_states = sizeof(battery_cyclestate) / 5858c2ecf20Sopenharmony_ci sizeof(char *); 5868c2ecf20Sopenharmony_ci if (state < num_states) { 5878c2ecf20Sopenharmony_ci seq_printf(m, "%s\t", 5888c2ecf20Sopenharmony_ci battery_cyclestate[state]); 5898c2ecf20Sopenharmony_ci have_strings = 1; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci case BATTERY_CHARGING: 5938c2ecf20Sopenharmony_ci seq_printf(m, "Battery Charging:\t"); 5948c2ecf20Sopenharmony_ci num_states = sizeof(battery_charging) / sizeof(char *); 5958c2ecf20Sopenharmony_ci if (state < num_states) { 5968c2ecf20Sopenharmony_ci seq_printf(m, "%s\t", 5978c2ecf20Sopenharmony_ci battery_charging[state]); 5988c2ecf20Sopenharmony_ci have_strings = 1; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci break; 6018c2ecf20Sopenharmony_ci case IBM_SURVEILLANCE: 6028c2ecf20Sopenharmony_ci seq_printf(m, "Surveillance:\t"); 6038c2ecf20Sopenharmony_ci break; 6048c2ecf20Sopenharmony_ci case IBM_FANRPM: 6058c2ecf20Sopenharmony_ci seq_printf(m, "Fan (rpm):\t"); 6068c2ecf20Sopenharmony_ci break; 6078c2ecf20Sopenharmony_ci case IBM_VOLTAGE: 6088c2ecf20Sopenharmony_ci seq_printf(m, "Voltage (mv):\t"); 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci case IBM_DRCONNECTOR: 6118c2ecf20Sopenharmony_ci seq_printf(m, "DR connector:\t"); 6128c2ecf20Sopenharmony_ci num_states = sizeof(ibm_drconnector) / sizeof(char *); 6138c2ecf20Sopenharmony_ci if (state < num_states) { 6148c2ecf20Sopenharmony_ci seq_printf(m, "%s\t", 6158c2ecf20Sopenharmony_ci ibm_drconnector[state]); 6168c2ecf20Sopenharmony_ci have_strings = 1; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci break; 6198c2ecf20Sopenharmony_ci case IBM_POWERSUPPLY: 6208c2ecf20Sopenharmony_ci seq_printf(m, "Powersupply:\t"); 6218c2ecf20Sopenharmony_ci break; 6228c2ecf20Sopenharmony_ci default: 6238c2ecf20Sopenharmony_ci seq_printf(m, "Unknown sensor (type %d), ignoring it\n", 6248c2ecf20Sopenharmony_ci s->token); 6258c2ecf20Sopenharmony_ci unknown = 1; 6268c2ecf20Sopenharmony_ci have_strings = 1; 6278c2ecf20Sopenharmony_ci break; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci if (have_strings == 0) { 6308c2ecf20Sopenharmony_ci if (temperature) { 6318c2ecf20Sopenharmony_ci seq_printf(m, "%4d /%4d\t", state, cel_to_fahr(state)); 6328c2ecf20Sopenharmony_ci } else 6338c2ecf20Sopenharmony_ci seq_printf(m, "%10d\t", state); 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci if (unknown == 0) { 6368c2ecf20Sopenharmony_ci seq_printf(m, "%s\t", ppc_rtas_process_error(error)); 6378c2ecf20Sopenharmony_ci get_location_code(m, s, loc); 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci/* ****************************************************************** */ 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic void check_location(struct seq_file *m, const char *c) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci switch (c[0]) { 6468c2ecf20Sopenharmony_ci case LOC_PLANAR: 6478c2ecf20Sopenharmony_ci seq_printf(m, "Planar #%c", c[1]); 6488c2ecf20Sopenharmony_ci break; 6498c2ecf20Sopenharmony_ci case LOC_CPU: 6508c2ecf20Sopenharmony_ci seq_printf(m, "CPU #%c", c[1]); 6518c2ecf20Sopenharmony_ci break; 6528c2ecf20Sopenharmony_ci case LOC_FAN: 6538c2ecf20Sopenharmony_ci seq_printf(m, "Fan #%c", c[1]); 6548c2ecf20Sopenharmony_ci break; 6558c2ecf20Sopenharmony_ci case LOC_RACKMOUNTED: 6568c2ecf20Sopenharmony_ci seq_printf(m, "Rack #%c", c[1]); 6578c2ecf20Sopenharmony_ci break; 6588c2ecf20Sopenharmony_ci case LOC_VOLTAGE: 6598c2ecf20Sopenharmony_ci seq_printf(m, "Voltage #%c", c[1]); 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci case LOC_LCD: 6628c2ecf20Sopenharmony_ci seq_printf(m, "LCD #%c", c[1]); 6638c2ecf20Sopenharmony_ci break; 6648c2ecf20Sopenharmony_ci case '.': 6658c2ecf20Sopenharmony_ci seq_printf(m, "- %c", c[1]); 6668c2ecf20Sopenharmony_ci break; 6678c2ecf20Sopenharmony_ci default: 6688c2ecf20Sopenharmony_ci seq_printf(m, "Unknown location"); 6698c2ecf20Sopenharmony_ci break; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci/* ****************************************************************** */ 6758c2ecf20Sopenharmony_ci/* 6768c2ecf20Sopenharmony_ci * Format: 6778c2ecf20Sopenharmony_ci * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ] 6788c2ecf20Sopenharmony_ci * the '.' may be an abbreviation 6798c2ecf20Sopenharmony_ci */ 6808c2ecf20Sopenharmony_cistatic void check_location_string(struct seq_file *m, const char *c) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci while (*c) { 6838c2ecf20Sopenharmony_ci if (isalpha(*c) || *c == '.') 6848c2ecf20Sopenharmony_ci check_location(m, c); 6858c2ecf20Sopenharmony_ci else if (*c == '/' || *c == '-') 6868c2ecf20Sopenharmony_ci seq_printf(m, " at "); 6878c2ecf20Sopenharmony_ci c++; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci/* ****************************************************************** */ 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic void get_location_code(struct seq_file *m, struct individual_sensor *s, 6958c2ecf20Sopenharmony_ci const char *loc) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci if (!loc || !*loc) { 6988c2ecf20Sopenharmony_ci seq_printf(m, "---");/* does not have a location */ 6998c2ecf20Sopenharmony_ci } else { 7008c2ecf20Sopenharmony_ci check_location_string(m, loc); 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci seq_putc(m, ' '); 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci/* ****************************************************************** */ 7058c2ecf20Sopenharmony_ci/* INDICATORS - Tone Frequency */ 7068c2ecf20Sopenharmony_ci/* ****************************************************************** */ 7078c2ecf20Sopenharmony_cistatic ssize_t ppc_rtas_tone_freq_write(struct file *file, 7088c2ecf20Sopenharmony_ci const char __user *buf, size_t count, loff_t *ppos) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci u64 freq; 7118c2ecf20Sopenharmony_ci int error = parse_number(buf, count, &freq); 7128c2ecf20Sopenharmony_ci if (error) 7138c2ecf20Sopenharmony_ci return error; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci rtas_tone_frequency = freq; /* save it for later */ 7168c2ecf20Sopenharmony_ci error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL, 7178c2ecf20Sopenharmony_ci TONE_FREQUENCY, 0, freq); 7188c2ecf20Sopenharmony_ci if (error) 7198c2ecf20Sopenharmony_ci printk(KERN_WARNING "error: setting tone frequency returned: %s\n", 7208c2ecf20Sopenharmony_ci ppc_rtas_process_error(error)); 7218c2ecf20Sopenharmony_ci return count; 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci/* ****************************************************************** */ 7248c2ecf20Sopenharmony_cistatic int ppc_rtas_tone_freq_show(struct seq_file *m, void *v) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci seq_printf(m, "%lu\n", rtas_tone_frequency); 7278c2ecf20Sopenharmony_ci return 0; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci/* ****************************************************************** */ 7308c2ecf20Sopenharmony_ci/* INDICATORS - Tone Volume */ 7318c2ecf20Sopenharmony_ci/* ****************************************************************** */ 7328c2ecf20Sopenharmony_cistatic ssize_t ppc_rtas_tone_volume_write(struct file *file, 7338c2ecf20Sopenharmony_ci const char __user *buf, size_t count, loff_t *ppos) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci u64 volume; 7368c2ecf20Sopenharmony_ci int error = parse_number(buf, count, &volume); 7378c2ecf20Sopenharmony_ci if (error) 7388c2ecf20Sopenharmony_ci return error; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (volume > 100) 7418c2ecf20Sopenharmony_ci volume = 100; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci rtas_tone_volume = volume; /* save it for later */ 7448c2ecf20Sopenharmony_ci error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL, 7458c2ecf20Sopenharmony_ci TONE_VOLUME, 0, volume); 7468c2ecf20Sopenharmony_ci if (error) 7478c2ecf20Sopenharmony_ci printk(KERN_WARNING "error: setting tone volume returned: %s\n", 7488c2ecf20Sopenharmony_ci ppc_rtas_process_error(error)); 7498c2ecf20Sopenharmony_ci return count; 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci/* ****************************************************************** */ 7528c2ecf20Sopenharmony_cistatic int ppc_rtas_tone_volume_show(struct seq_file *m, void *v) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci seq_printf(m, "%lu\n", rtas_tone_volume); 7558c2ecf20Sopenharmony_ci return 0; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci#define RMO_READ_BUF_MAX 30 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci/* RTAS Userspace access */ 7618c2ecf20Sopenharmony_cistatic int ppc_rtas_rmo_buf_show(struct seq_file *m, void *v) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci seq_printf(m, "%016lx %x\n", rtas_rmo_buf, RTAS_RMOBUF_MAX); 7648c2ecf20Sopenharmony_ci return 0; 7658c2ecf20Sopenharmony_ci} 766