sonic-buildimage/platform/s3ip-sysfs/s3ip_sysfs_frame/switch.c

271 lines
7.3 KiB
C

/*
* switch.c
*
* This module create a kset in sysfs called /sys/s3ip
* Then other switch kobjects are created and assigned to this kset,
* such as "cpld", "fan", "psu", ...
*
* History
* [Version] [Date] [Description]
* * v1.0 2021-08-31 S3IP sysfs
*/
#include "switch.h"
#include "syseeprom_sysfs.h"
int g_switch_loglevel = 0;
#define SWITCH_INFO(fmt, args...) do { \
if (g_switch_loglevel & INFO) { \
printk(KERN_INFO "[SWITCH][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \
} \
} while (0)
#define SWITCH_ERR(fmt, args...) do { \
if (g_switch_loglevel & ERR) { \
printk(KERN_ERR "[SWITCH][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \
} \
} while (0)
#define SWITCH_DBG(fmt, args...) do { \
if (g_switch_loglevel & DBG) { \
printk(KERN_DEBUG "[SWITCH][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \
} \
} while (0)
struct syseeprom_s {
struct bin_attribute bin;
int creat_eeprom_bin_flag;
};
static struct s3ip_sysfs_syseeprom_drivers_s *g_syseeprom_drv = NULL;
static struct kset *switch_kset;
static struct syseeprom_s g_syseeprom;
static ssize_t switch_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
struct switch_attribute *attribute;
struct switch_obj *device;
attribute = to_switch_attr(attr);
device = to_switch_obj(kobj);
if (!attribute->show) {
return -ENOSYS;
}
return attribute->show(device, attribute, buf);
}
static ssize_t switch_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf,
size_t len)
{
struct switch_attribute *attribute;
struct switch_obj *obj;
attribute = to_switch_attr(attr);
obj = to_switch_obj(kobj);
if (!attribute->store) {
return -ENOSYS;
}
return attribute->store(obj, attribute, buf, len);
}
static const struct sysfs_ops switch_sysfs_ops = {
.show = switch_attr_show,
.store = switch_attr_store,
};
static void switch_obj_release(struct kobject *kobj)
{
struct switch_obj *obj;
obj = to_switch_obj(kobj);
kfree(obj);
return;
}
static struct kobj_type switch_ktype = {
.sysfs_ops = &switch_sysfs_ops,
.release = switch_obj_release,
.default_attrs = NULL,
};
static ssize_t syseeprom_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr,
char *buf, loff_t offset, size_t count)
{
ssize_t rd_len;
check_p(g_syseeprom_drv);
check_p(g_syseeprom_drv->read_syseeprom_data);
memset(buf, 0, count);
rd_len = g_syseeprom_drv->read_syseeprom_data(buf, offset, count);
if (rd_len < 0) {
SWITCH_ERR("read syseeprom data error, offset: 0x%llx, read len: %lu, ret: %ld.\n",
offset, count, rd_len);
return -EIO;
}
SWITCH_DBG("read syseeprom data success, offset:0x%llx, read len:%lu, really read len:%ld.\n",
offset, count, rd_len);
return rd_len;
}
static ssize_t syseeprom_write(struct file *filp, struct kobject *kobj, struct bin_attribute *attr,
char *buf, loff_t offset, size_t count)
{
ssize_t wr_len;
check_p(g_syseeprom_drv);
check_p(g_syseeprom_drv->write_syseeprom_data);
wr_len = g_syseeprom_drv->write_syseeprom_data(buf, offset, count);
if (wr_len < 0) {
SWITCH_ERR("write syseeprom data error, offset: 0x%llx, read len: %lu, ret: %ld.\n",
offset, count, wr_len);
return -EIO;
}
SWITCH_DBG("write syseeprom data success, offset:0x%llx, write len:%lu, really write len:%ld.\n",
offset, count, wr_len);
return wr_len;
}
static int syseeprom_create_eeprom_attrs(void)
{
int ret, eeprom_size;
eeprom_size = g_syseeprom_drv->get_syseeprom_size();
if (eeprom_size <= 0) {
SWITCH_ERR("syseeprom size: %d, invalid.\n", eeprom_size);
return -EINVAL;
}
sysfs_bin_attr_init(&g_syseeprom.bin);
g_syseeprom.bin.attr.name = "syseeprom";
g_syseeprom.bin.attr.mode = 0644;
g_syseeprom.bin.read = syseeprom_read;
g_syseeprom.bin.write = syseeprom_write;
g_syseeprom.bin.size = eeprom_size;
ret = sysfs_create_bin_file(&switch_kset->kobj, &g_syseeprom.bin);
if (ret) {
SWITCH_ERR("create syseeprom bin error, ret: %d. \n", ret);
return -EBADRQC;
}
SWITCH_DBG("create syseeprom bin file success, eeprom size:%d.\n", eeprom_size);
g_syseeprom.creat_eeprom_bin_flag = 1;
return 0;
}
static void syseeprom_remove_eeprom_attrs(void)
{
if (g_syseeprom.creat_eeprom_bin_flag) {
sysfs_remove_bin_file(&switch_kset->kobj, &g_syseeprom.bin);
g_syseeprom.creat_eeprom_bin_flag = 0;
}
return;
}
int s3ip_sysfs_syseeprom_drivers_register(struct s3ip_sysfs_syseeprom_drivers_s *drv)
{
int ret;
SWITCH_INFO("s3ip_sysfs_syseeprom_drivers_register...\n");
if (g_syseeprom_drv) {
SWITCH_ERR("g_syseeprom_drv is not NULL, can't register\n");
return -EPERM;
}
check_p(drv);
check_p(drv->get_syseeprom_size);
g_syseeprom_drv = drv;
ret = syseeprom_create_eeprom_attrs();
if (ret < 0) {
SWITCH_ERR("create syseeprom attributes failed, ret: %d\n", ret);
g_syseeprom_drv = NULL;
return ret;
}
SWITCH_INFO("s3ip_sysfs_syseeprom_drivers_register success.\n");
return 0;
}
void s3ip_sysfs_syseeprom_drivers_unregister(void)
{
if (g_syseeprom_drv) {
syseeprom_remove_eeprom_attrs();
g_syseeprom_drv = NULL;
SWITCH_DBG("s3ip_sysfs_syseeprom_drivers_unregister success.\n");
}
return;
}
struct switch_obj *switch_kobject_create(const char *name, struct kobject *parent)
{
struct switch_obj *obj;
int ret;
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
if (!obj) {
SWITCH_DBG("switch_kobject_create %s kzalloc error", name);
return NULL;
}
obj->kobj.kset = switch_kset;
ret = kobject_init_and_add(&obj->kobj, &switch_ktype, parent, "%s", name);
if (ret) {
kobject_put(&obj->kobj);
SWITCH_DBG("kobject_init_and_add %s error", name);
return NULL;
}
return obj;
}
void switch_kobject_delete(struct switch_obj **obj)
{
if (*obj) {
SWITCH_DBG("%s delete %s.\n", (*obj)->kobj.parent->name, (*obj)->kobj.name);
kobject_put(&((*obj)->kobj));
*obj = NULL;
}
}
static int __init switch_init(void)
{
SWITCH_INFO("switch_init...\n");
switch_kset = kset_create_and_add("s3ip", NULL, NULL);
if (!switch_kset) {
SWITCH_ERR("create switch_kset error.\n");
return -ENOMEM;
}
SWITCH_INFO("switch_init success.\n");
return 0;
}
static void __exit switch_exit(void)
{
if (switch_kset) {
kset_unregister(switch_kset);
}
SWITCH_INFO("switch_exit success.\n");
}
module_init(switch_init);
module_exit(switch_exit);
EXPORT_SYMBOL(s3ip_sysfs_syseeprom_drivers_register);
EXPORT_SYMBOL(s3ip_sysfs_syseeprom_drivers_unregister);
module_param(g_switch_loglevel, int, 0644);
MODULE_PARM_DESC(g_switch_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("sonic S3IP sysfs");
MODULE_DESCRIPTION("switch driver");