From 7524e91aa1773a5743a19ac7fa2c4fb292c44a63 Mon Sep 17 00:00:00 2001 From: mssonicbld <79238446+mssonicbld@users.noreply.github.com> Date: Mon, 9 Jan 2023 14:24:41 +0800 Subject: [PATCH] The FAN driver framework module complies with s3ip sysfs specification (#12888) (#13212) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why I did it Provide a Fan driver framework that complies with s3ip sysfs specification How I did it 1、 The framework module provides register and unregister interface and implementation. 2、 The framework will help you create the sysfs node How to verify it A demo driver base on this framework will display the sysfs node wich conform to the s3ip sysfs specification Co-authored-by: tianshangfei <31125751+tianshangfei@users.noreply.github.com> --- .../s3ip-sysfs/s3ip_sysfs_frame/fan_sysfs.c | 754 ++++++++++++++++++ .../s3ip_sysfs_frame/include/fan_sysfs.h | 26 + 2 files changed, 780 insertions(+) create mode 100755 platform/s3ip-sysfs/s3ip_sysfs_frame/fan_sysfs.c create mode 100755 platform/s3ip-sysfs/s3ip_sysfs_frame/include/fan_sysfs.h diff --git a/platform/s3ip-sysfs/s3ip_sysfs_frame/fan_sysfs.c b/platform/s3ip-sysfs/s3ip_sysfs_frame/fan_sysfs.c new file mode 100755 index 0000000000..b9602b9e20 --- /dev/null +++ b/platform/s3ip-sysfs/s3ip_sysfs_frame/fan_sysfs.c @@ -0,0 +1,754 @@ +/* + * fan_sysfs.c + * + * This module create fan kobjects and attributes in /sys/s3ip/fan + * + * History + * [Version] [Date] [Description] + * * v1.0 2021-08-31 S3IP sysfs + */ + +#include + +#include "switch.h" +#include "fan_sysfs.h" + +static int g_fan_loglevel = 0; + +#define FAN_INFO(fmt, args...) do { \ + if (g_fan_loglevel & INFO) { \ + printk(KERN_INFO "[FAN_SYSFS][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define FAN_ERR(fmt, args...) do { \ + if (g_fan_loglevel & ERR) { \ + printk(KERN_ERR "[FAN_SYSFS][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define FAN_DBG(fmt, args...) do { \ + if (g_fan_loglevel & DBG) { \ + printk(KERN_DEBUG "[FAN_SYSFS][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +struct motor_obj_s { + struct switch_obj *obj; +}; + +struct fan_obj_s { + unsigned int motor_number; + struct motor_obj_s *motor; + struct switch_obj *obj; +}; + +struct fan_s { + unsigned int fan_number; + struct fan_obj_s *fan; +}; + +static struct fan_s g_fan; +static struct switch_obj *g_fan_obj = NULL; +static struct s3ip_sysfs_fan_drivers_s *g_fan_drv = NULL; + +static ssize_t fan_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_fan.fan_number); +} + +static ssize_t fan_motor_number_show(struct switch_obj *obj, struct switch_attribute *attr, + char *buf) +{ + unsigned int index; + + index = obj->index; + FAN_DBG("fan_motor_number_show, fan index: %u\n", index); + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%u\n", g_fan.fan[index - 1].motor_number); +} + +static ssize_t fan_model_name_show(struct switch_obj *obj, struct switch_attribute *attr, + char *buf) +{ + unsigned int fan_index; + int ret; + + check_p(g_fan_drv); + check_p(g_fan_drv->get_fan_model_name); + + fan_index = obj->index; + FAN_DBG("fan index: %u\n", fan_index); + ret = g_fan_drv->get_fan_model_name(fan_index, buf, PAGE_SIZE); + if (ret < 0) { + FAN_ERR("get fan%u model name failed, ret: %d\n", fan_index, ret); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t fan_sn_show(struct switch_obj *obj, struct switch_attribute *attr, + char *buf) +{ + unsigned int fan_index; + int ret; + + check_p(g_fan_drv); + check_p(g_fan_drv->get_fan_serial_number); + + fan_index = obj->index; + FAN_DBG("fan index: %u\n", fan_index); + ret = g_fan_drv->get_fan_serial_number(fan_index, buf, PAGE_SIZE); + if (ret < 0) { + FAN_ERR("get fan%u serial number failed, ret: %d\n", fan_index, ret); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t fan_pn_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index; + int ret; + + check_p(g_fan_drv); + check_p(g_fan_drv->get_fan_part_number); + + fan_index = obj->index; + FAN_DBG("fan index: %u\n", fan_index); + ret = g_fan_drv->get_fan_part_number(fan_index, buf, PAGE_SIZE); + if (ret < 0) { + FAN_ERR("get fan%u part number failed, ret: %d\n", fan_index, ret); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t fan_hw_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index; + int ret; + + check_p(g_fan_drv); + check_p(g_fan_drv->get_fan_hardware_version); + + fan_index = obj->index; + FAN_DBG("fan index: %u\n", fan_index); + ret = g_fan_drv->get_fan_hardware_version(fan_index, buf, PAGE_SIZE); + if (ret < 0) { + FAN_ERR("get fan%u hardware version failed, ret: %d\n", fan_index, ret); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t fan_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index; + int ret; + + check_p(g_fan_drv); + check_p(g_fan_drv->get_fan_status); + + fan_index = obj->index; + FAN_DBG("fan index: %u\n", fan_index); + ret = g_fan_drv->get_fan_status(fan_index, buf, PAGE_SIZE); + if (ret < 0) { + FAN_ERR("get fan%u status failed, ret: %d\n", fan_index, ret); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t fan_led_status_show(struct switch_obj *obj, struct switch_attribute *attr, + char *buf) +{ + unsigned int fan_index; + int ret; + + check_p(g_fan_drv); + check_p(g_fan_drv->get_fan_led_status); + + fan_index = obj->index; + FAN_DBG("fan index: %u\n", fan_index); + ret = g_fan_drv->get_fan_led_status(fan_index, buf, PAGE_SIZE); + if (ret < 0) { + FAN_ERR("get fan%u led status failed, ret: %d\n", fan_index, ret); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t fan_led_status_store(struct switch_obj *obj, struct switch_attribute *attr, + const char *buf, size_t count) +{ + unsigned int fan_index; + int ret, led_status; + + check_p(g_fan_drv); + check_p(g_fan_drv->set_fan_led_status); + + fan_index = obj->index; + sscanf(buf, "%d", &led_status); + FAN_DBG("fan index: %u, led_status: %d\n", fan_index, led_status); + ret = g_fan_drv->set_fan_led_status(fan_index, led_status); + if (ret < 0) { + FAN_ERR("set fan%u led_status: %d failed, ret: %d\n", fan_index, led_status, ret); + return -EIO; + } + FAN_DBG("set fan%u led_status: %d success\n", fan_index, led_status); + return count; +} + +static ssize_t fan_motor_speed_show(struct switch_obj *obj, struct switch_attribute *attr, + char *buf) +{ + unsigned int fan_index, motor_index; + int ret; + struct switch_obj *p_obj; + + check_p(g_fan_drv); + check_p(g_fan_drv->get_fan_motor_speed); + + p_obj = to_switch_obj(obj->kobj.parent); + fan_index = p_obj->index; + motor_index = obj->index; + FAN_DBG("fan index: %u, motor index: %d\n", fan_index, motor_index); + ret = g_fan_drv->get_fan_motor_speed(fan_index, motor_index, buf, PAGE_SIZE); + if (ret < 0) { + FAN_ERR("get fan%u motor%u speed failed, ret: %d\n", fan_index, motor_index, ret); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t fan_motor_speed_tolerance_show(struct switch_obj *obj, + struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index, motor_index; + int ret; + struct switch_obj *p_obj; + + check_p(g_fan_drv); + check_p(g_fan_drv->get_fan_motor_speed_tolerance); + + p_obj = to_switch_obj(obj->kobj.parent); + fan_index = p_obj->index; + motor_index = obj->index; + FAN_DBG("fan index: %u, motor index: %d\n", fan_index, motor_index); + ret = g_fan_drv->get_fan_motor_speed_tolerance(fan_index, motor_index, buf, PAGE_SIZE); + if (ret < 0) { + FAN_ERR("get fan%u motor%u speed tolerance failed, ret: %d\n", + fan_index, motor_index, ret); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t fan_motor_speed_target_show(struct switch_obj *obj, struct switch_attribute *attr, + char *buf) +{ + unsigned int fan_index, motor_index; + int ret; + struct switch_obj *p_obj; + + check_p(g_fan_drv); + check_p(g_fan_drv->get_fan_motor_speed_target); + + p_obj = to_switch_obj(obj->kobj.parent); + fan_index = p_obj->index; + motor_index = obj->index; + FAN_DBG("fan index: %u, motor index: %d\n", fan_index, motor_index); + ret = g_fan_drv->get_fan_motor_speed_target(fan_index, motor_index, buf, PAGE_SIZE); + if (ret < 0) { + FAN_ERR("get fan%u motor%u speed target failed, ret: %d\n", fan_index, motor_index, ret); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t fan_motor_speed_max_show(struct switch_obj *obj, struct switch_attribute *attr, + char *buf) +{ + unsigned int fan_index, motor_index; + int ret; + struct switch_obj *p_obj; + + check_p(g_fan_drv); + check_p(g_fan_drv->get_fan_motor_speed_max); + + p_obj = to_switch_obj(obj->kobj.parent); + fan_index = p_obj->index; + motor_index = obj->index; + FAN_DBG("fan index: %u, motor index: %d\n", fan_index, motor_index); + ret = g_fan_drv->get_fan_motor_speed_max(fan_index, motor_index, buf, PAGE_SIZE); + if (ret < 0) { + FAN_ERR("get fan%u motor%u speed max threshold failed, ret: %d\n", + fan_index, motor_index, ret); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t fan_motor_speed_min_show(struct switch_obj *obj, struct switch_attribute *attr, + char *buf) +{ + unsigned int fan_index, motor_index; + int ret; + struct switch_obj *p_obj; + + check_p(g_fan_drv); + check_p(g_fan_drv->get_fan_motor_speed_min); + + p_obj = to_switch_obj(obj->kobj.parent); + fan_index = p_obj->index; + motor_index = obj->index; + FAN_DBG("fan index: %u, motor index: %d\n", fan_index, motor_index); + ret = g_fan_drv->get_fan_motor_speed_min(fan_index, motor_index, buf, PAGE_SIZE); + if (ret < 0) { + FAN_ERR("get fan%u motor%u speed min threshold failed, ret: %d\n", + fan_index, motor_index, ret); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR); + } + return ret; +} + +ssize_t fan_ratio_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index; + int ret; + + check_p(g_fan_drv); + check_p(g_fan_drv->get_fan_ratio); + + fan_index = obj->index; + FAN_DBG("fan index: %u\n", fan_index); + ret = g_fan_drv->get_fan_ratio(fan_index, buf, PAGE_SIZE); + if (ret < 0) { + FAN_ERR("get fan%u ratio failed, ret: %d\n", fan_index, ret); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t fan_ratio_store(struct switch_obj *obj, struct switch_attribute *attr, + const char* buf, size_t count) +{ + unsigned int fan_index; + int ret, ratio; + + check_p(g_fan_drv); + check_p(g_fan_drv->set_fan_ratio); + + fan_index = obj->index; + sscanf(buf, "%d", &ratio); + if (ratio < 0 || ratio > 100) { + FAN_ERR("param invalid, can not set ratio: %d.\n", ratio); + return -EINVAL; + } + FAN_DBG("fan index: %u, ratio: %d\n", fan_index, ratio); + ret = g_fan_drv->set_fan_ratio(fan_index, ratio); + if (ret < 0) { + FAN_ERR("set fan%u ratio: %d failed, ret: %d\n", fan_index, ratio, ret); + return -EIO; + } + FAN_DBG("set fan%u, ratio: %d success\n", fan_index, ratio); + return count; +} + +ssize_t fan_direction_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index; + int ret; + + check_p(g_fan_drv); + check_p(g_fan_drv->get_fan_direction); + + fan_index = obj->index; + FAN_DBG("fan index: %u\n", fan_index); + ret = g_fan_drv->get_fan_direction(fan_index, buf, PAGE_SIZE); + if (ret < 0) { + FAN_ERR("get fan%u direction failed, ret: %d\n", fan_index, ret); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR); + } + return ret; +} + +/************************************fan dir and attrs*******************************************/ +static struct switch_attribute fan_number_att = __ATTR(number, S_IRUGO, fan_number_show, NULL); + +static struct attribute *fan_dir_attrs[] = { + &fan_number_att.attr, + NULL, +}; + +static struct attribute_group fan_root_attr_group = { + .attrs = fan_dir_attrs, +}; + +/*******************************fan1 fan2 dir and attrs*******************************************/ +static struct switch_attribute fan_model_name_attr = __ATTR(model_name, S_IRUGO, fan_model_name_show, NULL); +static struct switch_attribute fan_sn_attr = __ATTR(serial_number, S_IRUGO, fan_sn_show, NULL); +static struct switch_attribute fan_pn_attr = __ATTR(part_number, S_IRUGO, fan_pn_show, NULL); +static struct switch_attribute fan_hw_attr = __ATTR(hardware_version, S_IRUGO, fan_hw_show, NULL); +static struct switch_attribute fan_num_motors_attr = __ATTR(motor_number, S_IRUGO, fan_motor_number_show, NULL); +static struct switch_attribute fan_status_attr = __ATTR(status, S_IRUGO, fan_status_show, NULL); +static struct switch_attribute fan_led_status_attr = __ATTR(led_status, S_IRUGO | S_IWUSR, fan_led_status_show, fan_led_status_store); +static struct switch_attribute fan_direction_attr = __ATTR(direction, S_IRUGO, fan_direction_show, NULL); +static struct switch_attribute fan_ratio_attr = __ATTR(ratio, S_IRUGO | S_IWUSR, fan_ratio_show, fan_ratio_store); + + +static struct attribute *fan_attrs[] = { + &fan_model_name_attr.attr, + &fan_sn_attr.attr, + &fan_pn_attr.attr, + &fan_hw_attr.attr, + &fan_num_motors_attr.attr, + &fan_status_attr.attr, + &fan_led_status_attr.attr, + &fan_direction_attr.attr, + &fan_ratio_attr.attr, + NULL, +}; + +static struct attribute_group fan_attr_group = { + .attrs = fan_attrs, +}; + +/*******************************motor1 motor2 dir and attrs*******************************************/ +static struct switch_attribute motor_speed_attr = __ATTR(speed, S_IRUGO, fan_motor_speed_show, NULL); +static struct switch_attribute motor_speed_tolerance_attr = __ATTR(speed_tolerance, S_IRUGO, fan_motor_speed_tolerance_show, NULL); +static struct switch_attribute motor_speed_target_attr = __ATTR(speed_target, S_IRUGO, fan_motor_speed_target_show, NULL); +static struct switch_attribute motor_speed_max_attr = __ATTR(speed_max, S_IRUGO, fan_motor_speed_max_show, NULL); +static struct switch_attribute motor_speed_min_attr = __ATTR(speed_min, S_IRUGO, fan_motor_speed_min_show, NULL); + +static struct attribute *motor_attrs[] = { + &motor_speed_attr.attr, + &motor_speed_tolerance_attr.attr, + &motor_speed_target_attr.attr, + &motor_speed_max_attr.attr, + &motor_speed_min_attr.attr, + NULL, +}; + +static struct attribute_group motor_attr_group = { + .attrs = motor_attrs, +}; + +static void fanindex_single_motor_remove_kobj_and_attrs(struct fan_obj_s *curr_fan, unsigned int motor_index) +{ + struct motor_obj_s *curr_motor; /* point to motor1 motor2...*/ + + curr_motor = &curr_fan->motor[motor_index - 1]; + if (curr_motor->obj) { + sysfs_remove_group(&curr_motor->obj->kobj, &motor_attr_group); + switch_kobject_delete(&curr_motor->obj); + FAN_DBG("delete fan%u motor%u dir and attrs success.\n", curr_fan->obj->index, + motor_index); + } + return; +} + +static int fanindex_single_motor_create_kobj_and_attrs(struct fan_obj_s *curr_fan, unsigned int motor_index) +{ + char name[8]; + struct motor_obj_s *curr_motor; /* point to motor1 motor2...*/ + + curr_motor = &curr_fan->motor[motor_index - 1]; + memset(name, 0, sizeof(name)); + snprintf(name, sizeof(name), "motor%u", motor_index); + curr_motor->obj = switch_kobject_create(name, &curr_fan->obj->kobj); + if (!curr_motor->obj) { + FAN_ERR("create fan%u, motor%u object error!\n", curr_fan->obj->index, motor_index); + return -ENOMEM; + } + + curr_motor->obj->index = motor_index; + if (sysfs_create_group(&curr_motor->obj->kobj, &motor_attr_group) != 0) { + FAN_ERR("create fan%u, motor%u attrs error.\n", curr_fan->obj->index, motor_index); + switch_kobject_delete(&curr_motor->obj); + return -EBADRQC; + } + FAN_DBG("create fan%u, motor%u dir and attrs success.\n", curr_fan->obj->index, motor_index); + return 0; +} + +/* create motor[1-n] directory and attributes in fan directory */ +static int fanindex_motor_create_kobj_and_attrs(struct fan_obj_s *curr_fan) +{ + unsigned int motor_index, i, motor_num; + + motor_num = curr_fan->motor_number; + curr_fan->motor = kzalloc(sizeof(struct motor_obj_s) * motor_num, GFP_KERNEL); + if (!curr_fan->motor) { + FAN_ERR("kzalloc motor error, fan index: %u, motor number: %d.\n", + curr_fan->obj->index, motor_num); + return -ENOMEM; + } + for(motor_index = 1; motor_index <= motor_num; motor_index++) { + if(fanindex_single_motor_create_kobj_and_attrs(curr_fan, motor_index) != 0 ) { + goto motor_error; + } + } + return 0; +motor_error: + for(i = motor_index; i > 0; i--) { + fanindex_single_motor_remove_kobj_and_attrs(curr_fan, i); + } + kfree(curr_fan->motor); + curr_fan->motor = NULL; + return -EBADRQC; +} + +/* delete motor[1-n] directory and attributes in fan directory */ +static void fanindex_motor_remove_kobj_and_attrs(struct fan_obj_s *curr_fan) +{ + unsigned int motor_index, motor_num; + + if (curr_fan->motor) { + motor_num = curr_fan->motor_number; + for(motor_index = motor_num; motor_index > 0; motor_index--) { + fanindex_single_motor_remove_kobj_and_attrs(curr_fan, motor_index); + } + kfree(curr_fan->motor); + curr_fan->motor = NULL; + } + + return; +} + +/* create motor[1-n] directory and attributes */ +static int fan_motor_create(void) +{ + int fan_num, motor_num; + unsigned int fan_index, i; + struct fan_obj_s *curr_fan; /* point to fan1 fan2...*/ + + fan_num = g_fan.fan_number; + if (fan_num <= 0) { + FAN_DBG("fan number: %d, skip to create motor* dirs and attrs.\n", fan_num); + return 0; + } + + check_p(g_fan_drv->get_fan_motor_number); + + for(fan_index = 1; fan_index <= fan_num; fan_index++) { + motor_num = g_fan_drv->get_fan_motor_number(fan_index); + if (motor_num <= 0) { + FAN_DBG("fan%u motor number: %d, don't need to create motor* dirs and attrs.\n", + fan_index, motor_num); + continue; + } + curr_fan = &g_fan.fan[fan_index - 1]; + curr_fan->motor_number = motor_num; + if(fanindex_motor_create_kobj_and_attrs(curr_fan) != 0) { + goto error; + } + } + return 0; +error: + for(i = fan_index; i > 0; i--) { + curr_fan = &g_fan.fan[i - 1]; + fanindex_motor_remove_kobj_and_attrs(curr_fan); + } + return -EBADRQC; +} + +/* delete motor[1-n] directory and attributes */ +static void fan_motor_remove(void) +{ + unsigned int fan_index; + struct fan_obj_s *curr_fan; + + if (g_fan.fan) { + for (fan_index = g_fan.fan_number; fan_index > 0; fan_index--) { + curr_fan = &g_fan.fan[fan_index - 1]; + fanindex_motor_remove_kobj_and_attrs(curr_fan); + curr_fan->motor_number = 0; + } + } + return; +} + +static int fan_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct fan_obj_s *curr_fan; + + curr_fan = &g_fan.fan[index - 1]; + if (curr_fan->obj) { + sysfs_remove_group(&curr_fan->obj->kobj, &fan_attr_group); + switch_kobject_delete(&curr_fan->obj); + FAN_DBG("delete fan%u dir and attrs success.\n", index); + } + return 0; +} + +static int fan_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) +{ + char name[8]; + struct fan_obj_s *curr_fan; + + curr_fan = &g_fan.fan[index - 1]; + memset(name, 0, sizeof(name)); + snprintf(name, sizeof(name), "fan%u", index); + curr_fan->obj = switch_kobject_create(name, parent); + if (!curr_fan->obj) { + FAN_ERR("create %s object error!\n", name); + return -ENOMEM; + } + + curr_fan->obj->index = index; + if (sysfs_create_group(&curr_fan->obj->kobj, &fan_attr_group) != 0) { + FAN_ERR("create %s attrs error.\n", name); + switch_kobject_delete(&curr_fan->obj); + return -EBADRQC; + } + FAN_DBG("create %s dir and attrs success.\n", name); + return 0; +} + +/* create fan[1-n] directory and attributes */ +static int fan_sub_create_kobj_and_attrs(struct kobject *parent, int fan_num) +{ + unsigned int fan_index, i; + + g_fan.fan = kzalloc(sizeof(struct fan_obj_s) * fan_num, GFP_KERNEL); + if (!g_fan.fan) { + FAN_ERR("kzalloc fan.fan error, fan number: %d.\n", fan_num); + return -ENOMEM; + } + + for(fan_index = 1; fan_index <= fan_num; fan_index++) { + if(fan_sub_single_create_kobj_and_attrs(parent, fan_index) != 0 ) { + goto error; + } + } + return 0; +error: + for(i = fan_index; i > 0; i--) { + fan_sub_single_remove_kobj_and_attrs(i); + } + kfree(g_fan.fan); + g_fan.fan = NULL; + return -EBADRQC; +} + +static int fan_sub_create(void) +{ + int ret; + + ret = fan_sub_create_kobj_and_attrs(&g_fan_obj->kobj, g_fan.fan_number); + return ret; +} + +/* delete fan[1-n] directory and attributes */ +static void fan_sub_remove(void) +{ + unsigned int fan_index; + + if (g_fan.fan) { + for (fan_index = g_fan.fan_number; fan_index > 0; fan_index--) { + fan_sub_single_remove_kobj_and_attrs(fan_index); + } + kfree(g_fan.fan); + g_fan.fan = NULL; + } + g_fan.fan_number = 0; + + return; +} + +/* create fan directory and number attributes */ +static int fan_root_create(void) +{ + g_fan_obj = switch_kobject_create("fan", NULL); + if (!g_fan_obj) { + FAN_ERR("switch_kobject_create fan error!\n"); + return -ENOMEM; + } + + if (sysfs_create_group(&g_fan_obj->kobj, &fan_root_attr_group) != 0) { + switch_kobject_delete(&g_fan_obj); + FAN_ERR("create fan dir attrs error!\n"); + return -EBADRQC; + } + return 0; +} + +/* delete fan directory and number attributes */ +static void fan_root_remove(void) +{ + if (g_fan_obj) { + sysfs_remove_group(&g_fan_obj->kobj, &fan_root_attr_group); + switch_kobject_delete(&g_fan_obj); + FAN_DBG("delete fan dir and attrs success.\n"); + } + return; +} + +int s3ip_sysfs_fan_drivers_register(struct s3ip_sysfs_fan_drivers_s *drv) +{ + int ret, fan_num; + + FAN_INFO("s3ip_sysfs_fan_drivers_register...\n"); + if (g_fan_drv) { + FAN_ERR("g_fan_drv is not NULL, can't register\n"); + return -EPERM; + } + + check_p(drv); + check_p(drv->get_fan_number); + g_fan_drv = drv; + + fan_num = g_fan_drv->get_fan_number(); + if (fan_num <= 0) { + FAN_ERR("fan number: %d, don't need to create fan dirs and attrs.\n", fan_num); + g_fan_drv = NULL; + return -EINVAL; + } + + memset(&g_fan, 0, sizeof(struct fan_s)); + g_fan.fan_number = fan_num; + ret = fan_root_create(); + if (ret < 0) { + FAN_ERR("create fan root dir and attrs failed, ret: %d\n", ret); + g_fan_drv = NULL; + return ret; + } + + ret = fan_sub_create(); + if (ret < 0) { + FAN_ERR("create fan sub dir and attrs failed, ret: %d\n", ret); + fan_root_remove(); + g_fan_drv = NULL; + return ret; + } + + ret = fan_motor_create(); + if (ret < 0) { + FAN_ERR("create fan motor dir and attrs failed, ret: %d\n", ret); + fan_sub_remove(); + fan_root_remove(); + g_fan_drv = NULL; + return ret; + } + FAN_INFO("s3ip_sysfs_fan_drivers_register success.\n"); + return 0; +} + +void s3ip_sysfs_fan_drivers_unregister(void) +{ + if (g_fan_drv) { + fan_motor_remove(); + fan_sub_remove(); + fan_root_remove(); + g_fan_drv = NULL; + FAN_DBG("s3ip_sysfs_fan_drivers_unregister success.\n"); + } + return; +} + +EXPORT_SYMBOL(s3ip_sysfs_fan_drivers_register); +EXPORT_SYMBOL(s3ip_sysfs_fan_drivers_unregister); +module_param(g_fan_loglevel, int, 0644); +MODULE_PARM_DESC(g_fan_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); diff --git a/platform/s3ip-sysfs/s3ip_sysfs_frame/include/fan_sysfs.h b/platform/s3ip-sysfs/s3ip_sysfs_frame/include/fan_sysfs.h new file mode 100755 index 0000000000..fbd5ea82ec --- /dev/null +++ b/platform/s3ip-sysfs/s3ip_sysfs_frame/include/fan_sysfs.h @@ -0,0 +1,26 @@ +#ifndef _FAN_SYSFS_H_ +#define _FAN_SYSFS_H_ + +struct s3ip_sysfs_fan_drivers_s { + int (*get_fan_number)(void); + int (*get_fan_motor_number)(unsigned int fan_index); + ssize_t (*get_fan_model_name)(unsigned int fan_index, char *buf, size_t count); + ssize_t (*get_fan_serial_number)(unsigned int fan_index, char *buf, size_t count); + ssize_t (*get_fan_part_number)(unsigned int fan_index, char *buf, size_t count); + ssize_t (*get_fan_hardware_version)(unsigned int fan_index, char *buf, size_t count); + ssize_t (*get_fan_status)(unsigned int fan_index, char *buf, size_t count); + ssize_t (*get_fan_led_status)(unsigned int fan_index, char *buf, size_t count); + int (*set_fan_led_status)(unsigned int fan_index, int status); + ssize_t (*get_fan_direction)(unsigned int fan_index, char *buf, size_t count); + ssize_t (*get_fan_motor_speed)(unsigned int fan_index, unsigned int motor_index, char *buf, size_t count); + ssize_t (*get_fan_motor_speed_tolerance)(unsigned int fan_index, unsigned int motor_index, char *buf, size_t count); + ssize_t (*get_fan_motor_speed_target)(unsigned int fan_index, unsigned int motor_index, char *buf, size_t count); + ssize_t (*get_fan_motor_speed_max)(unsigned int fan_index, unsigned int motor_index, char *buf, size_t count); + ssize_t (*get_fan_motor_speed_min)(unsigned int fan_index, unsigned int motor_index, char *buf, size_t count); + ssize_t (*get_fan_ratio)(unsigned int fan_index, char *buf, size_t count); + int (*set_fan_ratio)(unsigned int fan_index, int ratio); +}; + +extern int s3ip_sysfs_fan_drivers_register(struct s3ip_sysfs_fan_drivers_s *drv); +extern void s3ip_sysfs_fan_drivers_unregister(void); +#endif /*_FAN_SYSFS_H_ */