7524e91aa1
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>
755 lines
23 KiB
C
Executable File
755 lines
23 KiB
C
Executable File
/*
|
|
* 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 <linux/slab.h>
|
|
|
|
#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");
|