6f496bda20
* [device][platform] d6254qs d6556 platform porting [device][platform] sensor and status led support for d7032q28b d7254q28b d7264q28b d6254qs d6556 [device][platform] qos support for d7032q28b d7254q28b [device][platform] service configuration files for d7032q28b d7254q28b d7264q28b d6254qs d6556 * remove binary files and remove non-supported attributes in config.bcm * remove gpio-ich here. file a PR in sonic-linux-kernel instead. * remove unnecessary comments * add GPL license
1313 lines
36 KiB
C
1313 lines
36 KiB
C
/*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
/*****************************
|
|
Magnolia platform
|
|
******************************/
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/string.h>
|
|
#include <linux/init.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/device.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/types.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/version.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/kobject.h>
|
|
#include <linux/sysfs.h>
|
|
|
|
|
|
#define SHOW_ATTR_WARNING ("N/A")
|
|
#define SHOW_ATTR_NOTPRINT ("Not Available")
|
|
#define SHOW_ATTR_NOTSUPPORT ("Not Support")
|
|
|
|
#define INV_HWMID_MAX (10)
|
|
#define INV_HWMID_INIT (-1)
|
|
|
|
/*access userspace data to kernel space*/
|
|
#define ACC_R (0)
|
|
#define ACC_W (1)
|
|
|
|
#define TINY_BUF_SIZE (8)
|
|
#define MAX_PATH_SIZE (64)
|
|
#define MIN_ACC_SIZE (32)
|
|
#define MAX_ACC_SIZE (256)
|
|
|
|
/*
|
|
* LED definitions
|
|
*/
|
|
#define STATUS_LED_MODE_AUTO 0
|
|
#define STATUS_LED_MODE_DIAG 1
|
|
#define STATUS_LED_MODE_MANU 2
|
|
|
|
#define STATUS_LED_GRN0 10 // 0 - 000: off
|
|
#define STATUS_LED_GRN1 11 // 1 - 001: 0.5hz
|
|
#define STATUS_LED_GRN2 12 // 2 - 010: 1 hz
|
|
#define STATUS_LED_GRN3 13 // 3 - 011: 2 hz
|
|
#define STATUS_LED_GRN7 17 // 7 - 111: on
|
|
#define STATUS_LED_RED0 20 // 0 - 000: off
|
|
#define STATUS_LED_RED1 21 // 1 - 001: 0.5hz
|
|
#define STATUS_LED_RED2 22 // 2 - 010: 1 hz
|
|
#define STATUS_LED_RED3 23 // 3 - 011: 2 hz
|
|
#define STATUS_LED_RED7 27 // 7 - 111: on
|
|
#define STATUS_LED_INVALID 0 // Invalid
|
|
|
|
ssize_t status_led_change(const char *path1, const char *tmp1, const char *path2, const char *tmp2);
|
|
ssize_t status_led_grn(const char *freq);
|
|
ssize_t status_led_red(const char *freq);
|
|
ssize_t status_led_diag_mode_enable(void);
|
|
ssize_t status_led_diag_mode_disable(void);
|
|
int status_led_check_color(void);
|
|
int status_led_check_diag_mode(void);
|
|
|
|
#if 1
|
|
/* For timestamps in SYSFS_LOG */
|
|
#define SYSFS_LOG printk
|
|
#else
|
|
//#define SYSFS_LOG(fmt, args...) printk(KERN_WARNING "[SYSFS] %s/%d: " fmt, __func__, __LINE__, ##args)
|
|
#define SYSFS_LOG(fmt, args...) printk(KERN_WARNING "[p_thread] " fmt, ##args)
|
|
#endif
|
|
|
|
#define INV_PTHREAD_KERNEL_MODULE (1)
|
|
#define SWITCH_HEALTH_LED_CHANGE_VIA_GPIO (1)
|
|
|
|
/* inventec_class *********************************/
|
|
static struct kobject *status_kobj;
|
|
static struct kset *status_kset;
|
|
|
|
|
|
static struct mutex rw_lock;
|
|
|
|
static int hwm_psoc = INV_HWMID_INIT;
|
|
static int hwm_cpld = INV_HWMID_INIT;
|
|
|
|
int get_hwm_psoc(void)
|
|
{
|
|
return hwm_psoc;
|
|
}
|
|
|
|
int get_hwm_cpld(void)
|
|
{
|
|
return hwm_cpld;
|
|
}
|
|
|
|
static ssize_t access_user_space(const char *name, int mode, char *buf, size_t len, loff_t offset)
|
|
{
|
|
struct file *fp;
|
|
mm_segment_t fs;
|
|
loff_t pos = offset;
|
|
char *mark = NULL;
|
|
ssize_t vfs_ret = 0;
|
|
|
|
if (mode == ACC_R) {
|
|
fp = filp_open(name, O_RDONLY, S_IRUGO);
|
|
if (IS_ERR(fp))
|
|
return -ENODEV;
|
|
|
|
fs = get_fs();
|
|
set_fs(KERNEL_DS);
|
|
|
|
vfs_ret = vfs_read(fp, buf, len, &pos);
|
|
|
|
mark = strpbrk(buf, "\n");
|
|
if (mark)
|
|
*mark = '\0';
|
|
|
|
filp_close(fp, NULL);
|
|
set_fs(fs);
|
|
} else if (mode == ACC_W) {
|
|
fp = filp_open(name, O_WRONLY, S_IWUSR | S_IRUGO);
|
|
if (IS_ERR(fp))
|
|
return -ENODEV;
|
|
|
|
fs = get_fs();
|
|
set_fs(KERNEL_DS);
|
|
|
|
vfs_ret = vfs_write(fp, buf, len, &pos);
|
|
filp_close(fp, NULL);
|
|
set_fs(fs);
|
|
}
|
|
|
|
return vfs_ret;
|
|
}
|
|
|
|
int inventec_strtol(const char *sbufp, char **endp, unsigned int base)
|
|
{
|
|
char *endptr;
|
|
int value = simple_strtol(sbufp, &endptr, base);
|
|
if (value == 0 && sbufp == endptr) {
|
|
*endp = NULL;
|
|
return value;
|
|
}
|
|
*endp = (char*)1;
|
|
return value;
|
|
}
|
|
|
|
int inventec_singlechar_to_int(const char c)
|
|
{
|
|
if ((c >= '0') && (c <= '9')) {
|
|
return (c - '0');
|
|
}
|
|
else
|
|
if ((c >= 'a') && (c <= 'f')) {
|
|
return (c - 'a' + 10);
|
|
}
|
|
else
|
|
if ((c >= 'A') && (c <= 'F')) {
|
|
return (c - 'A' + 10);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int inventec_store_input(char *inputp, int count)
|
|
{
|
|
int i = 0;
|
|
while(inputp[i] != '\n' && inputp[i] != '\0' && i < count) {
|
|
i++;
|
|
}
|
|
inputp[i] = '\0';
|
|
return strlen(inputp);
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
* Time stamps for kernel log on yocto
|
|
*/
|
|
#include <linux/rtc.h>
|
|
|
|
void SYSFS_LOG(char *fmt, ...)
|
|
{
|
|
char buf[80], ts[32];
|
|
va_list args;
|
|
int hlen;
|
|
|
|
inventec_tmstmp(&ts[0]);
|
|
hlen = sprintf(buf, "[SYSFS] %s ", ts); // Do not edit this line
|
|
|
|
va_start(args, fmt);
|
|
vsprintf(&buf[hlen-1], fmt, args);
|
|
va_end(args);
|
|
printk(KERN_WARNING "[p_thread] %s\n", buf);
|
|
}
|
|
#endif
|
|
|
|
ssize_t
|
|
inventec_show_attr(char *buf_p, const char *invdevp)
|
|
{
|
|
int inv_len = MAX_ACC_SIZE; /* INV driver return max length */
|
|
char tmp_buf[MAX_ACC_SIZE];
|
|
char *str_negative = "-", *mark = NULL;
|
|
|
|
/* [Step2] Get data by uaccess */
|
|
memset(tmp_buf, 0, sizeof(tmp_buf));
|
|
mutex_lock(&rw_lock);
|
|
if (access_user_space(invdevp, ACC_R, tmp_buf, inv_len, 0) < 0) {
|
|
/* u_access fail */
|
|
mutex_unlock(&rw_lock);
|
|
return sprintf(buf_p, "%s\n", SHOW_ATTR_WARNING);
|
|
}
|
|
mutex_unlock(&rw_lock);
|
|
|
|
/* [Step3] Check return value
|
|
* - Ex: When transceiver not plugged
|
|
* => SWPS return error code "-202"
|
|
* => Pic8 need return "NA" (assume)
|
|
*/
|
|
if (strcspn(tmp_buf, str_negative) == 0) {
|
|
/* error case: <ex> "-202" */
|
|
return sprintf(buf_p, "%s\n", SHOW_ATTR_WARNING);
|
|
}
|
|
|
|
/* OK case:*/
|
|
mark = strpbrk(tmp_buf, "\n");
|
|
if (mark) { *mark = '\0'; }
|
|
|
|
return sprintf(buf_p, "%s\n", tmp_buf);
|
|
}
|
|
|
|
ssize_t
|
|
inventec_store_attr(const char *buf_p, size_t count, const char *invdevp)
|
|
{
|
|
ssize_t ret = 0;
|
|
|
|
/* [Step2] Get data by uaccess */
|
|
mutex_lock(&rw_lock);
|
|
if ((ret = access_user_space(invdevp, ACC_W, (char*)buf_p, count, 0)) < 0) {
|
|
/* u_access fail */
|
|
mutex_unlock(&rw_lock);
|
|
return -EINVAL;
|
|
}
|
|
mutex_unlock(&rw_lock);
|
|
|
|
/* OK case:*/
|
|
return ret;
|
|
}
|
|
|
|
int sysfs_detect_hwmon_index(void)
|
|
{
|
|
char hwmon_buf[MAX_ACC_SIZE];
|
|
char hwmon_path[MAX_PATH_SIZE];
|
|
int hwid = 0;
|
|
|
|
for (hwid = 0;
|
|
hwid < INV_HWMID_MAX && (hwm_psoc == INV_HWMID_INIT || hwm_cpld == INV_HWMID_INIT);
|
|
hwid++) {
|
|
memset(hwmon_buf, 0, sizeof(hwmon_buf));
|
|
sprintf(hwmon_path, "/sys/class/hwmon/hwmon%d/device/name", hwid);
|
|
|
|
inventec_show_attr(hwmon_buf, hwmon_path);
|
|
if (strncmp(hwmon_buf, "inv_psoc", 8) == 0) {
|
|
hwm_psoc = hwid;
|
|
}
|
|
else
|
|
if (strncmp(hwmon_buf, "inv_bmc", 7) == 0) {
|
|
hwm_psoc = hwid;
|
|
}
|
|
else
|
|
if (strncmp(hwmon_buf, "inv_cpld", 8) == 0) {
|
|
hwm_cpld = hwid;
|
|
}
|
|
}
|
|
if (hwid >= INV_HWMID_MAX) {
|
|
printk(KERN_ERR "[p_thread] detect hwmon index failed, psoc = %d, cpld = %d\n", hwm_psoc, hwm_cpld);
|
|
return -1;
|
|
}
|
|
printk(KERN_INFO "[p_thread] detect hwmon index success, psoc = %d, cpld = %d\n", hwm_psoc, hwm_cpld);
|
|
return 0;
|
|
}
|
|
|
|
static int __init
|
|
inventec_class_init(void)
|
|
{
|
|
mutex_init(&rw_lock);
|
|
|
|
#ifdef INV_PTHREAD_KERNEL_MODULE
|
|
if (sysfs_detect_hwmon_index() < 0) {
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
printk(KERN_INFO "[p_thread] [%s/%d] Module initial success.\n",__func__,__LINE__);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __exit
|
|
inventec_class_exit(void)
|
|
{
|
|
printk(KERN_INFO "[p_thread] [%s/%d] Remove module.\n",__func__,__LINE__);
|
|
}
|
|
|
|
/* fan device *************************************/
|
|
#define FAN_DEV_PATH_STATE "/sys/class/hwmon/hwmon%d/device/fan_gpi"
|
|
#define FAN_DEV_PATH_FAN1_INPUT "/sys/class/hwmon/hwmon%d/device/fan1_input"
|
|
#define FAN_DEV_PATH_FAN2_INPUT "/sys/class/hwmon/hwmon%d/device/fan2_input"
|
|
#define FAN_DEV_PATH_FAN3_INPUT "/sys/class/hwmon/hwmon%d/device/fan3_input"
|
|
#define FAN_DEV_PATH_FAN4_INPUT "/sys/class/hwmon/hwmon%d/device/fan4_input"
|
|
#define FAN_DEV_PATH_FAN5_INPUT "/sys/class/hwmon/hwmon%d/device/fan5_input"
|
|
#define FAN_DEV_PATH_FAN6_INPUT "/sys/class/hwmon/hwmon%d/device/fan6_input"
|
|
#define FAN_DEV_PATH_FAN7_INPUT "/sys/class/hwmon/hwmon%d/device/fan7_input"
|
|
#define FAN_DEV_PATH_FAN8_INPUT "/sys/class/hwmon/hwmon%d/device/fan8_input"
|
|
|
|
static char fan_dev_path_state[MAX_PATH_SIZE];
|
|
static char fan_dev_path_fan1_input[MAX_PATH_SIZE];
|
|
static char fan_dev_path_fan2_input[MAX_PATH_SIZE];
|
|
static char fan_dev_path_fan3_input[MAX_PATH_SIZE];
|
|
static char fan_dev_path_fan4_input[MAX_PATH_SIZE];
|
|
static char fan_dev_path_fan5_input[MAX_PATH_SIZE];
|
|
static char fan_dev_path_fan6_input[MAX_PATH_SIZE];
|
|
static char fan_dev_path_fan7_input[MAX_PATH_SIZE];
|
|
static char fan_dev_path_fan8_input[MAX_PATH_SIZE];
|
|
|
|
void sysfs_fan_path_init(void)
|
|
{
|
|
sprintf(&fan_dev_path_state[0], FAN_DEV_PATH_STATE, get_hwm_psoc());
|
|
sprintf(&fan_dev_path_fan1_input[0],FAN_DEV_PATH_FAN1_INPUT, get_hwm_psoc());
|
|
sprintf(&fan_dev_path_fan2_input[0],FAN_DEV_PATH_FAN2_INPUT, get_hwm_psoc());
|
|
sprintf(&fan_dev_path_fan3_input[0],FAN_DEV_PATH_FAN3_INPUT, get_hwm_psoc());
|
|
sprintf(&fan_dev_path_fan4_input[0],FAN_DEV_PATH_FAN4_INPUT, get_hwm_psoc());
|
|
sprintf(&fan_dev_path_fan5_input[0],FAN_DEV_PATH_FAN5_INPUT, get_hwm_psoc());
|
|
sprintf(&fan_dev_path_fan6_input[0],FAN_DEV_PATH_FAN6_INPUT, get_hwm_psoc());
|
|
sprintf(&fan_dev_path_fan7_input[0],FAN_DEV_PATH_FAN7_INPUT, get_hwm_psoc());
|
|
sprintf(&fan_dev_path_fan8_input[0],FAN_DEV_PATH_FAN8_INPUT, get_hwm_psoc());
|
|
}
|
|
|
|
#define FAN_STATE_NORMAL "normal"
|
|
#define FAN_STATE_FAULTY "faulty"
|
|
#define FAN_STATE_UNINSTALLED "uninstalled"
|
|
#define FAN_STATE_UNKNOW "unknown state"
|
|
#define FAN_STATE_INVALID "Invalid state value"
|
|
#define FAN_STATE_READ_ERROR "state read error"
|
|
|
|
#define FAN_LOG_UNINSTALLED "removed"
|
|
#define FAN_LOG_NORMAL "inserted"
|
|
|
|
//#define FAN_STATE_BIT_NORMAL 0
|
|
#define FAN_STATE_BIT_FAULTY 0
|
|
#define FAN_STATE_BIT_UNINSTALLED 1
|
|
#define FAN_STATE_BIT_UNKNOW 2
|
|
#define FAN_STATE_BIT_INVALID 3
|
|
#define FAN_STATE_BIT_READ_ERROR 4
|
|
|
|
static struct fans_tbl_s {
|
|
char *fan_name;
|
|
char *fan_front;
|
|
char *fan_rear;
|
|
unsigned int fan_state;
|
|
} fans_tbl[] = {
|
|
{"fan1", fan_dev_path_fan1_input,
|
|
fan_dev_path_fan2_input, 0},
|
|
{"fan2", fan_dev_path_fan3_input,
|
|
fan_dev_path_fan4_input, 0},
|
|
{"fan3", fan_dev_path_fan5_input,
|
|
fan_dev_path_fan6_input, 0},
|
|
{"fan4", fan_dev_path_fan7_input,
|
|
fan_dev_path_fan8_input, 0},
|
|
};
|
|
#define FAN_TBL_TOTAL ( sizeof(fans_tbl)/ sizeof(const struct fans_tbl_s) )
|
|
|
|
#define FAN_STATE_CHECK(i,b) (fans_tbl[i].fan_state & (1<<b))
|
|
#define FAN_STATE_SET(i,b) (fans_tbl[i].fan_state |= (1<<b))
|
|
#define FAN_STATE_CLEAR(i,b) (fans_tbl[i].fan_state &= ~(1<<b))
|
|
#define FAN_STATE_INIT(i) (fans_tbl[i].fan_state = 0)
|
|
|
|
static int
|
|
fans_faulty_log(int fan_id)
|
|
{
|
|
char buf[MAX_ACC_SIZE];
|
|
int pwm;
|
|
|
|
memset(&buf[0], 0, MAX_ACC_SIZE);
|
|
if (inventec_show_attr(buf, fans_tbl[fan_id].fan_front) < 0) {
|
|
if(!FAN_STATE_CHECK(fan_id, FAN_STATE_BIT_READ_ERROR)) {
|
|
FAN_STATE_SET(fan_id, FAN_STATE_BIT_READ_ERROR);
|
|
SYSFS_LOG("[p_thread] %s: front %s\n",fans_tbl[fan_id].fan_name,FAN_STATE_READ_ERROR);
|
|
}
|
|
return 1;
|
|
}
|
|
pwm = simple_strtol(buf, NULL, 10);
|
|
if (pwm <= 0) {
|
|
if(!FAN_STATE_CHECK(fan_id, FAN_STATE_BIT_FAULTY)) {
|
|
FAN_STATE_SET(fan_id, FAN_STATE_BIT_FAULTY);
|
|
//SYSFS_LOG("[p_thread] %s: %s\n",fans_tbl[fan_id].fan_name,FAN_STATE_FAULTY);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
memset(&buf[0], 0, MAX_ACC_SIZE);
|
|
if (inventec_show_attr(buf, fans_tbl[fan_id].fan_rear) < 0) {
|
|
if(!FAN_STATE_CHECK(fan_id, FAN_STATE_BIT_READ_ERROR)) {
|
|
FAN_STATE_SET(fan_id, FAN_STATE_BIT_READ_ERROR);
|
|
SYSFS_LOG("[p_thread] %s: rear %s\n",fans_tbl[fan_id].fan_name,FAN_STATE_READ_ERROR);
|
|
}
|
|
return 1;
|
|
}
|
|
pwm = simple_strtol(buf, NULL, 10);
|
|
if (pwm <= 0) {
|
|
if(!FAN_STATE_CHECK(fan_id, FAN_STATE_BIT_FAULTY)) {
|
|
FAN_STATE_SET(fan_id, FAN_STATE_BIT_FAULTY);
|
|
//SYSFS_LOG("[p_thread] %s: %s\n",fans_tbl[fan_id].fan_name,FAN_STATE_FAULTY);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
if(fans_tbl[fan_id].fan_state != 0) {
|
|
fans_tbl[fan_id].fan_state = 0;
|
|
SYSFS_LOG("[p_thread] %s: %s\n",fans_tbl[fan_id].fan_name,FAN_LOG_NORMAL);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* INV drivers mapping */
|
|
static int
|
|
fans_control_log(int fan_id)
|
|
{
|
|
char buf[MAX_ACC_SIZE];
|
|
unsigned int statebit2, statebit3, bitshift;
|
|
|
|
if (inventec_show_attr(buf, fan_dev_path_state) < 0) {
|
|
SYSFS_LOG("[p_thread] read fan_gpi failed\n");
|
|
return 1;
|
|
}
|
|
|
|
if (buf[0] != '0' || (buf[1] != 'x' && buf[1] != 'X')) {
|
|
SYSFS_LOG("[p_thread] %s/%d: %s %s\n",__func__,__LINE__,FAN_STATE_INVALID, buf);
|
|
return 1;
|
|
}
|
|
|
|
if ((statebit2 = inventec_singlechar_to_int(buf[2])) == -1) {
|
|
SYSFS_LOG("[p_thread] Error value read from %s\n", fan_dev_path_state);
|
|
return 1;
|
|
}
|
|
if (buf[2] == 'f' || buf[2] == 'F') statebit2 = 0;
|
|
|
|
if ((statebit3 = inventec_singlechar_to_int(buf[3])) == -1) {
|
|
SYSFS_LOG("[p_thread] Error value read from %s\n", fan_dev_path_state);
|
|
return 1;
|
|
}
|
|
|
|
bitshift = fan_id;
|
|
//SYSFS_LOG("[p_thread] 1: statebit2 = 0x%x statebit3 = 0x%x bitshift = 0x%x\n",statebit2,statebit3,bitshift);
|
|
if ((statebit2 & 1<<bitshift) && (statebit3 & 1<<bitshift)) {
|
|
if(!FAN_STATE_CHECK(fan_id, FAN_STATE_BIT_UNINSTALLED)) {
|
|
FAN_STATE_SET(fan_id, FAN_STATE_BIT_UNINSTALLED);
|
|
SYSFS_LOG("[p_thread] %s: %s\n",fans_tbl[fan_id].fan_name,FAN_LOG_UNINSTALLED);
|
|
}
|
|
return 1;
|
|
}
|
|
else
|
|
if (!(statebit2 & 1<<bitshift) && !(statebit3 & 1<<bitshift)) {
|
|
return fans_faulty_log(fan_id);
|
|
}
|
|
else {
|
|
if(!FAN_STATE_CHECK(fan_id, FAN_STATE_BIT_FAULTY)) {
|
|
FAN_STATE_SET(fan_id, FAN_STATE_BIT_FAULTY);
|
|
SYSFS_LOG("[p_thread] %s: %s\n",fans_tbl[fan_id].fan_name,FAN_STATE_FAULTY);
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int fans_control(void)
|
|
{
|
|
int i, ret = 0;
|
|
static int cd_shutdown = 5;
|
|
|
|
for (i = 0; i < FAN_TBL_TOTAL; i++) {
|
|
if(fans_control_log(i) == 1) {
|
|
ret++;
|
|
}
|
|
}
|
|
|
|
if (0 < ret && ret < FAN_TBL_TOTAL) {
|
|
status_led_red("2"); //1Hz
|
|
cd_shutdown = 5; //reset count down
|
|
}
|
|
|
|
if (ret == FAN_TBL_TOTAL) {
|
|
status_led_red("3"); //4Hz
|
|
if (cd_shutdown == 0) {
|
|
kobject_uevent(status_kobj, KOBJ_REMOVE);
|
|
}
|
|
else if (cd_shutdown > 0)
|
|
{
|
|
printk(KERN_ERR "[p_thread] All fans failed.\n");
|
|
printk(KERN_ERR "[p_thread] System shutdown immediately in %d seconds.\n", cd_shutdown);
|
|
}
|
|
cd_shutdown -= 1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* End of faninfo_device */
|
|
|
|
static int __init
|
|
fan_device_init(void)
|
|
{
|
|
#ifdef INV_PTHREAD_KERNEL_MODULE
|
|
sysfs_fan_path_init();
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void __exit
|
|
fan_device_exit(void)
|
|
{
|
|
printk(KERN_INFO "[p_thread] Remove fan module.\n");
|
|
}
|
|
|
|
/* psu device *************************************/
|
|
static unsigned int psu_voltin = 0;
|
|
#define PSU_VOLTIN_ACDC (70000)
|
|
|
|
/*
|
|
* normal/unpower/uninstall/fault are PSU states output from driver level
|
|
* checkpsu/error are defined by sysfs
|
|
*/
|
|
#define PSU_STATE_VAL_NORMAL (0)
|
|
#define PSU_STATE_VAL_UNPOWER (2)
|
|
#define PSU_STATE_VAL_FAULT (4)
|
|
#define PSU_STATE_VAL_UNINSTALL (7)
|
|
#define PSU_STATE_VAL_CHECKPSU (8)
|
|
#define PSU_STATE_VAL_ERROR (9)
|
|
|
|
#define PSU_STATE_NORMAL ("0 : normal")
|
|
#define PSU_STATE_UNPOWER ("2 : unpowered")
|
|
#define PSU_STATE_FAULT ("4 : fault")
|
|
#define PSU_STATE_UNINSTALL ("7 : not installed")
|
|
#define PSU_STATE_CHECKPSU ("8 : check psu")
|
|
#define PSU_STATE_ERROR ("9 : state error")
|
|
|
|
#define PSU_STATE_LEN_NORMAL (strlen(PSU_STATE_NORMAL))
|
|
#define PSU_STATE_LEN_UNPOWER (strlen(PSU_STATE_UNPOWER))
|
|
#define PSU_STATE_LEN_FAULT (strlen(PSU_STATE_FAULT))
|
|
#define PSU_STATE_LEN_UNINSTALL (strlen(PSU_STATE_UNINSTALL))
|
|
#define PSU_STATE_LEN_CHECKPSU (strlen(PSU_STATE_CHECKPSU))
|
|
|
|
typedef struct {
|
|
char *inv_dev_attrp;
|
|
char *inv_dev_pathp;
|
|
} psu_dev_t;
|
|
|
|
typedef struct {
|
|
const char *psu_name;
|
|
int psu_major;
|
|
dev_t psu_devt;
|
|
struct device *psu_dev_p;
|
|
psu_dev_t *psu_dev_namep;
|
|
int psu_dev_total;
|
|
char *psu_inv_pathp;
|
|
void *psu_tracking;
|
|
char *psu_currentin;
|
|
char *psu_currentout;
|
|
char *psu_powerin;
|
|
char *psu_powerout;
|
|
char *psu_voltin;
|
|
char *psu_voltout;
|
|
} psu_dev_group_t;
|
|
|
|
#define PSU_DEV_PATH_TEMPLATE "/sys/class/hwmon/hwmon%d/device/%s"
|
|
|
|
static char psu_dev_path_state[MAX_PATH_SIZE];
|
|
static char psu_dev_path_psu_voltin[MAX_PATH_SIZE];
|
|
#if 0
|
|
static char psu_dev_path_vendor[MAX_PATH_SIZE];
|
|
static char psu_dev_path_version[MAX_PATH_SIZE];
|
|
static char psu_dev_path_sn[MAX_PATH_SIZE];
|
|
static char psu_dev_path_temperature[MAX_PATH_SIZE];
|
|
static char psu_dev_path_fan_speed[MAX_PATH_SIZE];
|
|
static char psu_dev_path_fan_pwm[MAX_PATH_SIZE];
|
|
static char psu_dev_path_fan_faulty[MAX_PATH_SIZE];
|
|
static char psu_dev_path_psu_currentin[MAX_PATH_SIZE];
|
|
static char psu_dev_path_psu_currentout[MAX_PATH_SIZE];
|
|
static char psu_dev_path_psu_powerin[MAX_PATH_SIZE];
|
|
static char psu_dev_path_psu_powerout[MAX_PATH_SIZE];
|
|
static char psu_dev_path_psu_voltout[MAX_PATH_SIZE];
|
|
static char psu_dev_path_psu_pwm[MAX_PATH_SIZE];
|
|
static char psu_dev_path_psu_rpm[MAX_PATH_SIZE];
|
|
#endif
|
|
|
|
void sysfs_psu_path_init(void)
|
|
{
|
|
sprintf(&psu_dev_path_state[0], PSU_DEV_PATH_TEMPLATE, get_hwm_cpld(), "\%s" );
|
|
sprintf(&psu_dev_path_psu_voltin[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
#if 0
|
|
sprintf(&psu_dev_path_vendor[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
sprintf(&psu_dev_path_version[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
sprintf(&psu_dev_path_sn[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
sprintf(&psu_dev_path_temperature[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
sprintf(&psu_dev_path_fan_speed[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
sprintf(&psu_dev_path_fan_pwm[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
sprintf(&psu_dev_path_fan_faulty[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
sprintf(&psu_dev_path_psu_currentin[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
sprintf(&psu_dev_path_psu_currentout[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
sprintf(&psu_dev_path_psu_powerin[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
sprintf(&psu_dev_path_psu_powerout[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
sprintf(&psu_dev_path_psu_voltout[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
sprintf(&psu_dev_path_psu_pwm[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
sprintf(&psu_dev_path_psu_rpm[0], PSU_DEV_PATH_TEMPLATE, get_hwm_psoc(), "\%s" );
|
|
#endif
|
|
}
|
|
|
|
static psu_dev_t psu_dev_name[] = {
|
|
{ "state", psu_dev_path_state }, // Using cpld
|
|
{ "psu_voltin", psu_dev_path_psu_voltin },
|
|
#if 0
|
|
{ "vendor", psu_dev_path_vendor },
|
|
{ "version", psu_dev_path_version },
|
|
{ "sn", psu_dev_path_sn },
|
|
{ "temperature", psu_dev_path_temperature },
|
|
{ "fan_speed", psu_dev_path_fan_speed },
|
|
{ "fan_pwm", psu_dev_path_fan_pwm },
|
|
{ "fan_faulty", psu_dev_path_fan_faulty },
|
|
{ "psu_currentin", psu_dev_path_psu_currentin },
|
|
{ "psu_currentout", psu_dev_path_psu_currentout },
|
|
{ "psu_powerin", psu_dev_path_psu_powerin },
|
|
{ "psu_powerout", psu_dev_path_psu_powerout },
|
|
{ "psu_voltout", psu_dev_path_psu_voltout },
|
|
{ "psu_pwm", psu_dev_path_psu_pwm },
|
|
{ "psu_rpm", psu_dev_path_psu_rpm },
|
|
#endif
|
|
};
|
|
#define PSU_DEV_NAME_TOTAL ( sizeof(psu_dev_name) / sizeof(const psu_dev_t) )
|
|
|
|
static psu_dev_group_t psu_dev_group[] = {
|
|
{
|
|
.psu_name = "psu1",
|
|
.psu_dev_namep = &psu_dev_name[0],
|
|
.psu_dev_total = sizeof(psu_dev_name) / sizeof(const psu_dev_t),
|
|
},
|
|
{
|
|
.psu_name = "psu2",
|
|
.psu_dev_namep = &psu_dev_name[0],
|
|
.psu_dev_total = sizeof(psu_dev_name) / sizeof(const psu_dev_t),
|
|
},
|
|
};
|
|
#define PSU_DEV_GROUP_TOTAL ( sizeof(psu_dev_group)/ sizeof(const psu_dev_group_t) )
|
|
|
|
static char psu_state[4][MIN_ACC_SIZE];
|
|
|
|
static struct psu_wire_tbl_s {
|
|
char *psu_attr;
|
|
char *psu_name;
|
|
char *psu_wire;
|
|
char *psu_state;
|
|
} psu_wire_tbl[] = {
|
|
{ "state", "psu1", "psu0", psu_state[0] }, // Using cpld
|
|
{ "state", "psu2", "psu1", psu_state[1] },
|
|
{ "psu_voltin", "psu1", "psoc_psu1_vin", psu_state[2] },
|
|
{ "psu_voltin", "psu2", "psoc_psu2_vin", psu_state[3] },
|
|
};
|
|
#define PSU_WIRE_TBL_TOTAL ( sizeof(psu_wire_tbl)/ sizeof(const struct psu_wire_tbl_s) )
|
|
|
|
static char *
|
|
psu_attr_get_wirep(const char *psu_attrp, const char *psu_namep, char **psu_statepp)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < PSU_WIRE_TBL_TOTAL; i++) {
|
|
if (strncmp(psu_wire_tbl[i].psu_attr, psu_attrp, strlen(psu_attrp)) == 0 &&
|
|
strncmp(psu_wire_tbl[i].psu_name, psu_namep, strlen(psu_namep)) == 0) {
|
|
if (psu_statepp) {
|
|
*psu_statepp = psu_wire_tbl[i].psu_state;
|
|
}
|
|
return psu_wire_tbl[i].psu_wire;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int psu_check_state_normal(char *statep)
|
|
{
|
|
if (strstr(statep, "normal")) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#define PSU_ATTR_VOLTIN ("psu_voltin")
|
|
#define PSU_ATTR_VOLTIN_LEN (10)
|
|
|
|
/* Get PSU voltin for determon AC(110v) or DC(48v) */
|
|
void psu_get_voltin(void)
|
|
{
|
|
char acc_path[MAX_PATH_SIZE], volt[MIN_ACC_SIZE];
|
|
psu_dev_t *devnamep;
|
|
unsigned int voltin;
|
|
char *invwirep;
|
|
int i, j;
|
|
|
|
for (i = 0; i < PSU_DEV_GROUP_TOTAL; i++) {
|
|
//psu_dev_group[i].psu_name;
|
|
devnamep = psu_dev_group[i].psu_dev_namep;
|
|
for (j = 0; j < psu_dev_group[i].psu_dev_total; j++, devnamep++) {
|
|
if (strncmp(devnamep->inv_dev_attrp, PSU_ATTR_VOLTIN, PSU_ATTR_VOLTIN_LEN) == 0) {
|
|
invwirep = psu_attr_get_wirep(PSU_ATTR_VOLTIN, psu_dev_group[i].psu_name, NULL);
|
|
if (invwirep == NULL) {
|
|
printk(KERN_DEBUG "[p_thread] Invalid psuname: %s\n", psu_dev_group[i].psu_name);
|
|
continue;
|
|
}
|
|
sprintf(acc_path, devnamep->inv_dev_pathp, invwirep);
|
|
//printk(KERN_DEBUG "[p_thread] RYU: %s/%d: acc_path = %s\n",__func__,__LINE__,acc_path);
|
|
if (inventec_show_attr(volt, acc_path) <= 0) {
|
|
printk(KERN_DEBUG "[p_thread] Read %s failed\n", acc_path);
|
|
continue;
|
|
}
|
|
else {
|
|
voltin = simple_strtol(&volt[0], NULL, 10);
|
|
printk(KERN_DEBUG "[p_thread] Read %s %s = %u\n",acc_path,volt,voltin);
|
|
if (voltin > psu_voltin) {
|
|
psu_voltin = voltin;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SYSFS_LOG("[p_thread] PSU voltin = %u\n", psu_voltin);
|
|
}
|
|
|
|
#define PSU_ATTR_STATE ("state")
|
|
#define PSU_ATTR_STATE_LEN (5)
|
|
|
|
/* psus_control() by inv_thread */
|
|
int psus_control(int log_only)
|
|
{
|
|
char acc_path[MAX_PATH_SIZE], state[MIN_ACC_SIZE];
|
|
psu_dev_t *devnamep = NULL;
|
|
char *invwirep = NULL;
|
|
char *psu_statep = NULL;
|
|
int i, j, flag = 0;
|
|
|
|
for (i = 0; i < PSU_DEV_GROUP_TOTAL; i++) {
|
|
devnamep = psu_dev_group[i].psu_dev_namep;
|
|
for (j = 0; j < psu_dev_group[i].psu_dev_total; j++, devnamep++) {
|
|
if (strncmp(devnamep->inv_dev_attrp, PSU_ATTR_STATE, PSU_ATTR_STATE_LEN) == 0) {
|
|
invwirep = psu_attr_get_wirep(PSU_ATTR_STATE, psu_dev_group[i].psu_name, &psu_statep);
|
|
if (invwirep == NULL) {
|
|
printk(KERN_DEBUG "[p_thread] Invalid psuname: %s\n", psu_dev_group[i].psu_name);
|
|
continue;
|
|
}
|
|
sprintf(acc_path, devnamep->inv_dev_pathp, invwirep);
|
|
//printk(KERN_INFO "[p_thread] RYU: %s/%d: acc_path = %s\n",__func__,__LINE__,acc_path);
|
|
if (inventec_show_attr(state, acc_path) <= 0) {
|
|
printk(KERN_DEBUG "[p_thread] Read %s failed\n", acc_path);
|
|
if (strncmp(psu_statep, PSU_STATE_ERROR, strlen(PSU_STATE_ERROR)) != 0) {
|
|
strcpy(psu_statep, PSU_STATE_ERROR);
|
|
SYSFS_LOG("[p_thread] %s: %s\n",psu_dev_group[i].psu_name,PSU_STATE_ERROR);
|
|
}
|
|
flag = 1;
|
|
}
|
|
else
|
|
if (strstr(state, "normal")) {
|
|
//printk(KERN_INFO "[p_thread] %s: %s\n", psu_dev_group[i].psu_name, state);
|
|
if (strncmp(psu_statep, state, strlen(state)) != 0) {
|
|
strcpy(psu_statep, state);
|
|
SYSFS_LOG("[p_thread] %s: %s\n",psu_dev_group[i].psu_name,state);
|
|
}
|
|
}
|
|
else
|
|
if (psu_voltin > PSU_VOLTIN_ACDC) { /* AC PSUS */
|
|
//printk(KERN_INFO "[p_thread] RYU: %s: %s\n", psu_dev_group[i].psu_name, state);
|
|
if (strncmp(psu_statep, state, strlen(state)) != 0) {
|
|
strcpy(psu_statep, state);
|
|
SYSFS_LOG("[p_thread] %s: %s\n",psu_dev_group[i].psu_name,state);
|
|
}
|
|
flag = 1;
|
|
}
|
|
else { /* DC PSUS */
|
|
if (strncmp(psu_statep, PSU_STATE_CHECKPSU, PSU_STATE_LEN_CHECKPSU) != 0) {
|
|
strcpy(psu_statep, PSU_STATE_CHECKPSU);
|
|
SYSFS_LOG("[p_thread] %s: %s\n",psu_dev_group[i].psu_name,PSU_STATE_CHECKPSU);
|
|
}
|
|
flag = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (log_only) {
|
|
return 0;
|
|
}
|
|
|
|
//SYSFS_LOG("[p_thread] RYU: %s: flag = %d\n",psu_wire_tbl[i].psu_name,flag);
|
|
if (flag == 1) {
|
|
status_led_grn("3");
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* End of psuinfo_device */
|
|
|
|
static int __init
|
|
psu_device_init(void)
|
|
{
|
|
#ifdef INV_PTHREAD_KERNEL_MODULE
|
|
sysfs_psu_path_init();
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void __exit
|
|
psu_device_exit(void)
|
|
{
|
|
printk(KERN_INFO "[p_thread] Remove psu module.\n");
|
|
}
|
|
|
|
/* led device *************************************/
|
|
#define STATUS_LED_GRN_PATH "/sys/class/hwmon/hwmon%d/device/grn_led"
|
|
#define STATUS_LED_RED_PATH "/sys/class/hwmon/hwmon%d/device/red_led"
|
|
|
|
#define FAN_LED_GRN1_PATH "/sys/class/hwmon/hwmon%d/device/fan_led_grn1"
|
|
#define FAN_LED_GRN2_PATH "/sys/class/hwmon/hwmon%d/device/fan_led_grn2"
|
|
#define FAN_LED_GRN3_PATH "/sys/class/hwmon/hwmon%d/device/fan_led_grn3"
|
|
#define FAN_LED_GRN4_PATH "/sys/class/hwmon/hwmon%d/device/fan_led_grn4"
|
|
#define FAN_LED_RED1_PATH "/sys/class/hwmon/hwmon%d/device/fan_led_red1"
|
|
#define FAN_LED_RED2_PATH "/sys/class/hwmon/hwmon%d/device/fan_led_red2"
|
|
#define FAN_LED_RED3_PATH "/sys/class/hwmon/hwmon%d/device/fan_led_red3"
|
|
#define FAN_LED_RED4_PATH "/sys/class/hwmon/hwmon%d/device/fan_led_red4"
|
|
|
|
#define HWMON_DEVICE_DIAG_PATH "/sys/class/hwmon/hwmon%d/device/diag"
|
|
#define HWMON_DEVICE_CTRL_PATH "/sys/class/hwmon/hwmon%d/device/ctl"
|
|
|
|
static char status_led_grn_path[MAX_PATH_SIZE];
|
|
static char status_led_red_path[MAX_PATH_SIZE];
|
|
static char fan_led_grn1_path[MAX_PATH_SIZE];
|
|
static char fan_led_grn2_path[MAX_PATH_SIZE];
|
|
static char fan_led_grn3_path[MAX_PATH_SIZE];
|
|
static char fan_led_grn4_path[MAX_PATH_SIZE];
|
|
static char fan_led_red1_path[MAX_PATH_SIZE];
|
|
static char fan_led_red2_path[MAX_PATH_SIZE];
|
|
static char fan_led_red3_path[MAX_PATH_SIZE];
|
|
static char fan_led_red4_path[MAX_PATH_SIZE];
|
|
static char hwmon_device_diag_path[MAX_PATH_SIZE];
|
|
static char hwmon_device_ctrl_path[MAX_PATH_SIZE];
|
|
|
|
void sysfs_led_path_init(void)
|
|
{
|
|
sprintf(&status_led_grn_path[0], STATUS_LED_GRN_PATH, get_hwm_cpld());
|
|
sprintf(&status_led_red_path[0], STATUS_LED_RED_PATH, get_hwm_cpld());
|
|
sprintf(&fan_led_grn1_path[0], FAN_LED_GRN1_PATH, get_hwm_psoc());
|
|
sprintf(&fan_led_grn2_path[0], FAN_LED_GRN2_PATH, get_hwm_psoc());
|
|
sprintf(&fan_led_grn3_path[0], FAN_LED_GRN3_PATH, get_hwm_psoc());
|
|
sprintf(&fan_led_grn4_path[0], FAN_LED_GRN4_PATH, get_hwm_psoc());
|
|
sprintf(&fan_led_red1_path[0], FAN_LED_RED1_PATH, get_hwm_psoc());
|
|
sprintf(&fan_led_red2_path[0], FAN_LED_RED2_PATH, get_hwm_psoc());
|
|
sprintf(&fan_led_red3_path[0], FAN_LED_RED3_PATH, get_hwm_psoc());
|
|
sprintf(&fan_led_red4_path[0], FAN_LED_RED4_PATH, get_hwm_psoc());
|
|
sprintf(&hwmon_device_diag_path[0], HWMON_DEVICE_DIAG_PATH, get_hwm_psoc());
|
|
sprintf(&hwmon_device_ctrl_path[0], HWMON_DEVICE_CTRL_PATH, get_hwm_cpld());
|
|
}
|
|
|
|
/* return 0/off 1/green 2/red */
|
|
int
|
|
status_led_check_color(void)
|
|
{
|
|
char tmpbuf[MIN_ACC_SIZE];
|
|
int ret = STATUS_LED_INVALID;
|
|
|
|
if (inventec_show_attr(&tmpbuf[0], status_led_grn_path) > 0) {
|
|
if (tmpbuf[0] == '0') {
|
|
ret = STATUS_LED_GRN0;
|
|
}
|
|
if (tmpbuf[0] == '1') {
|
|
ret = STATUS_LED_GRN1;
|
|
}
|
|
if (tmpbuf[0] == '2') {
|
|
ret = STATUS_LED_GRN2;
|
|
}
|
|
if (tmpbuf[0] == '3') {
|
|
ret = STATUS_LED_GRN3;
|
|
}
|
|
if (tmpbuf[0] == '7') {
|
|
ret = STATUS_LED_GRN7;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
if (inventec_show_attr(&tmpbuf[0], status_led_red_path) > 0) {
|
|
if (tmpbuf[0] == '0') {
|
|
ret = STATUS_LED_RED0;
|
|
}
|
|
if (tmpbuf[0] == '1') {
|
|
ret = STATUS_LED_RED1;
|
|
}
|
|
if (tmpbuf[0] == '2') {
|
|
ret = STATUS_LED_RED2;
|
|
}
|
|
if (tmpbuf[0] == '3') {
|
|
ret = STATUS_LED_RED3;
|
|
}
|
|
if (tmpbuf[0] == '7') {
|
|
ret = STATUS_LED_RED7;
|
|
}
|
|
return ret;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Store attr Section
|
|
*/
|
|
static DEFINE_MUTEX(diag_mutex);
|
|
|
|
ssize_t status_led_diag_mode_enable(void)
|
|
{
|
|
char tmp[MIN_ACC_SIZE];
|
|
ssize_t ret;
|
|
|
|
ret = inventec_show_attr(&tmp[0], hwmon_device_diag_path);
|
|
if (ret <= 0) {
|
|
return ret;
|
|
}
|
|
|
|
if (tmp[0] == '0') {
|
|
mutex_lock(&diag_mutex);
|
|
ret = inventec_store_attr("1", 1, hwmon_device_diag_path);
|
|
if (ret < 0) {
|
|
mutex_unlock(&diag_mutex);
|
|
return ret;
|
|
}
|
|
|
|
ret = inventec_store_attr("1", 1, hwmon_device_ctrl_path);
|
|
if (ret < 0) {
|
|
mutex_unlock(&diag_mutex);
|
|
return ret;
|
|
}
|
|
mutex_unlock(&diag_mutex);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
ssize_t status_led_diag_mode_disable(void)
|
|
{
|
|
char tmp[MIN_ACC_SIZE];
|
|
ssize_t ret;
|
|
|
|
ret = inventec_show_attr(&tmp[0], hwmon_device_diag_path);
|
|
if (ret <= 0) {
|
|
return ret;
|
|
}
|
|
|
|
if (tmp[0] == '1') {
|
|
mutex_lock(&diag_mutex);
|
|
ret = inventec_store_attr("0", 1, hwmon_device_diag_path);
|
|
if (ret < 0) {
|
|
mutex_unlock(&diag_mutex);
|
|
return 1;
|
|
}
|
|
|
|
ret = inventec_store_attr("1", 1, hwmon_device_ctrl_path);
|
|
if (ret < 0) {
|
|
mutex_unlock(&diag_mutex);
|
|
return 1;
|
|
}
|
|
mutex_unlock(&diag_mutex);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
ssize_t
|
|
status_led_change(const char *path1, const char *tmp1, const char *path2, const char *tmp2)
|
|
{
|
|
ssize_t ret;
|
|
|
|
ret = inventec_store_attr(tmp1, strlen(tmp1), path1);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
ret = inventec_store_attr(tmp2, strlen(tmp2), path2);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
if ((ret = status_led_diag_mode_enable()) <= 0) {
|
|
return ret;
|
|
}
|
|
ssleep(1);
|
|
if ((ret = status_led_diag_mode_disable()) <= 0) {
|
|
return ret;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
ssize_t
|
|
status_led_red(const char *freq)
|
|
{
|
|
ssize_t ret;
|
|
|
|
ret = inventec_store_attr("0", 1, &status_led_grn_path[0]);
|
|
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ret = inventec_store_attr(freq, strlen(freq), &status_led_red_path[0]);
|
|
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
if ((ret = status_led_diag_mode_enable()) <= 0) {
|
|
return ret;
|
|
}
|
|
ssleep(1);
|
|
if ((ret = status_led_diag_mode_disable()) <= 0) {
|
|
return ret;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
ssize_t
|
|
status_led_grn(const char *freq)
|
|
{
|
|
ssize_t ret;
|
|
|
|
ret = inventec_store_attr("0", 1, &status_led_red_path[0]);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
ret = inventec_store_attr(freq, strlen(freq), &status_led_grn_path[0]);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
if ((ret = status_led_diag_mode_enable()) <= 0) {
|
|
return ret;
|
|
}
|
|
ssleep(1);
|
|
if ((ret = status_led_diag_mode_disable()) <= 0) {
|
|
return ret;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int status_led_diag_mode = STATUS_LED_MODE_AUTO;
|
|
|
|
int status_led_check_diag_mode(void)
|
|
{
|
|
return status_led_diag_mode;
|
|
}
|
|
|
|
/* End of ledinfo_device */
|
|
|
|
static int __init
|
|
led_device_init(void)
|
|
{
|
|
#ifdef INV_PTHREAD_KERNEL_MODULE
|
|
sysfs_led_path_init();
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void __exit
|
|
led_device_exit(void)
|
|
{
|
|
printk(KERN_INFO "[p_thread] Remove led module.\n");
|
|
}
|
|
|
|
/* sensor device **********************************/
|
|
#define SENSOR_DEV_PATH_SWITCH_TEMP "/sys/class/hwmon/hwmon%d/device/switch_tmp"
|
|
|
|
static char sensor_dev_path_switch_temp[MAX_PATH_SIZE];
|
|
|
|
void sysfs_sensor_path_init(void)
|
|
{
|
|
sprintf(&sensor_dev_path_switch_temp[0], SENSOR_DEV_PATH_SWITCH_TEMP, get_hwm_psoc());
|
|
}
|
|
|
|
void switch_temp_update(void)
|
|
{
|
|
char buf[MIN_ACC_SIZE];
|
|
ssize_t count = inventec_show_attr(&buf[0], "proc/switch/temp");
|
|
if (count > 0) {
|
|
//printk(KERN_ERR "[p_thread] [STEMP] Switch temperature is out of range: %d\n", stemp);
|
|
inventec_store_attr(&buf[0], count, sensor_dev_path_switch_temp);
|
|
}
|
|
}
|
|
|
|
/**************************************************/
|
|
/* From system_device */
|
|
static int inv_pthread_control = 1;
|
|
|
|
int thread_control(void)
|
|
{
|
|
return inv_pthread_control;
|
|
}
|
|
|
|
void thread_control_set(int val)
|
|
{
|
|
inv_pthread_control = val;
|
|
}
|
|
/* End system_device */
|
|
|
|
#define THREAD_SLEEP_MINS (3)
|
|
#define THREAD_DELAY_MINS (THREAD_SLEEP_MINS + THREAD_SLEEP_MINS + 1)
|
|
|
|
extern void psu_get_voltin(void);
|
|
|
|
static struct task_struct *thread_st;
|
|
static int thread_data;
|
|
|
|
#ifdef SWITCH_HEALTH_LED_CHANGE_VIA_GPIO
|
|
void led_set_gpio_to_change_status_led(void)
|
|
{
|
|
ssize_t ret = inventec_store_attr("253", 3, "/sys/class/gpio/export");
|
|
if (ret < 0) {
|
|
SYSFS_LOG("[p_thread] Write 253 to /sys/class/gpio/export failed\n");
|
|
return;
|
|
}
|
|
|
|
printk("[p_thread] Write 253 to /sys/class/gpio/export\n");
|
|
|
|
ret = inventec_store_attr("out", 3, "/sys/class/gpio/gpio253/direction");
|
|
if (ret < 0) {
|
|
SYSFS_LOG("[p_thread] Write low to /sys/class/gpio/gpio253/direction failed\n");
|
|
return;
|
|
}
|
|
|
|
//pull high and then low
|
|
ret = inventec_store_attr("1", 1, "sys/class/gpio/gpio253/value");
|
|
if (ret < 0) {
|
|
SYSFS_LOG("[p_thread] Write 1 to sys/class/gpio/gpio253/value failed\n");
|
|
}
|
|
|
|
//pull low
|
|
ret = inventec_store_attr("0", 1, "sys/class/gpio/gpio253/value");
|
|
if (ret < 0) {
|
|
SYSFS_LOG("[p_thread] Write 0 to sys/class/gpio/gpio253/value failed\n");
|
|
}
|
|
|
|
SYSFS_LOG("[p_thread] Set gpio to support status led change successfully\n");
|
|
}
|
|
#endif
|
|
|
|
// Function executed by kernel thread
|
|
static int thread_fn(void *unused)
|
|
{
|
|
/* Delay for guarantee HW ready */
|
|
ssleep(THREAD_DELAY_MINS);
|
|
|
|
#ifndef INV_PTHREAD_KERNEL_MODULE
|
|
sysfs_led_path_init();
|
|
sysfs_fan_path_init();
|
|
sysfs_psu_path_init();
|
|
#endif
|
|
//sysfs_sensor_path_init();
|
|
|
|
/* Default status init */
|
|
status_led_grn("7");
|
|
|
|
psu_get_voltin();
|
|
|
|
#ifdef SWITCH_HEALTH_LED_CHANGE_VIA_GPIO
|
|
led_set_gpio_to_change_status_led();
|
|
#endif
|
|
|
|
while (1)
|
|
{
|
|
ssleep(THREAD_SLEEP_MINS);
|
|
|
|
if (thread_control() == 0) {
|
|
printk(KERN_INFO "[p_thread] %s/%d: Thread Stop by inv_pthread control\n",__func__,__LINE__);
|
|
break;
|
|
}
|
|
|
|
if (status_led_check_diag_mode() == STATUS_LED_MODE_MANU) {
|
|
/* status led in change color/freq mode, higher priority. Ignore fans sttaus */
|
|
continue;
|
|
}
|
|
|
|
//switch_temp_update();
|
|
|
|
if (fans_control() > 0) {
|
|
psus_control(1);
|
|
continue;
|
|
}
|
|
else
|
|
if (psus_control(0) > 0) {
|
|
continue;
|
|
}
|
|
|
|
if (status_led_check_color() != STATUS_LED_GRN7) { /* status led red, change it to green */
|
|
status_led_grn("7");
|
|
}
|
|
}
|
|
|
|
#ifndef INV_PTHREAD_KERNEL_MODULE
|
|
err_inv_pthread_fn_1:
|
|
#endif
|
|
do_exit(0);
|
|
printk(KERN_INFO "[p_thread] %s/%d: Thread Stopped\n",__func__,__LINE__);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static ssize_t s_show(struct kobject *kobj, struct attribute *attr, char *buf)
|
|
{
|
|
int fan_absence;
|
|
size_t count;
|
|
|
|
fan_absence = fans_control();
|
|
count += sprintf(&buf[count], "%d\n", fan_absence);
|
|
return count;
|
|
}
|
|
|
|
static ssize_t s_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count)
|
|
{
|
|
return count;
|
|
}
|
|
|
|
static struct attribute status_att = {
|
|
.name = "fan_absence",
|
|
.mode = 0777,
|
|
};
|
|
|
|
static const struct sysfs_ops status_ops = {
|
|
.show = s_show,
|
|
.store = s_store,
|
|
};
|
|
|
|
static struct kobj_type status_ktype = {
|
|
.sysfs_ops = &status_ops,
|
|
};
|
|
|
|
|
|
static int __init inv_pthread_init(void)
|
|
{
|
|
int retval;
|
|
|
|
status_kobj = kzalloc(sizeof(*status_kobj), GFP_KERNEL);
|
|
if(!status_kobj)
|
|
return PTR_ERR(status_kobj);
|
|
|
|
status_kset = kset_create_and_add("platform_status", NULL, kernel_kobj);
|
|
if(!status_kset)
|
|
return -1;
|
|
|
|
status_kobj->kset = status_kset;
|
|
|
|
retval = kobject_init_and_add(status_kobj, &status_ktype, NULL, "fan");
|
|
if(retval)
|
|
return retval;
|
|
|
|
retval = sysfs_create_file(status_kobj, &status_att);
|
|
|
|
|
|
inventec_class_init();
|
|
fan_device_init();
|
|
psu_device_init();
|
|
led_device_init();
|
|
|
|
thread_control_set(1);
|
|
|
|
printk(KERN_INFO "[p_thread] %s/%d: Creating Thread\n",__func__,__LINE__);
|
|
//Create the kernel thread with name 'inv_pthread'
|
|
thread_st = kthread_run(thread_fn, (void*)&thread_data, "inv_pthread");
|
|
if (thread_st)
|
|
printk(KERN_INFO "[p_thread] inv_pthread Created successfully\n");
|
|
else
|
|
printk(KERN_ERR "[p_thread] inv_pthread creation failed\n");
|
|
|
|
return retval;
|
|
}
|
|
|
|
static void __exit inv_pthread_exit(void)
|
|
{
|
|
thread_control_set(0);
|
|
/* Delay for guarantee thread exit */
|
|
ssleep(THREAD_DELAY_MINS);
|
|
|
|
fan_device_exit();
|
|
psu_device_exit();
|
|
led_device_exit();
|
|
inventec_class_exit();
|
|
|
|
sysfs_remove_file(status_kobj, &status_att);
|
|
kset_unregister(status_kset);
|
|
kobject_del(status_kobj);
|
|
|
|
printk(KERN_INFO "[p_thread] inv_pthread cleaning Up\n");
|
|
}
|
|
|
|
module_init(inv_pthread_init);
|
|
module_exit(inv_pthread_exit);
|
|
|
|
MODULE_AUTHOR("Robert <yu.robertxk@inventec.com>");
|
|
MODULE_DESCRIPTION("Inventec Platform Management Thread");
|
|
MODULE_VERSION("version 1.0");
|
|
MODULE_LICENSE("GPL");
|