aff95158创建于 2025年12月23日历史提交
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 */

#define SWITCH_PERMISSION 0666

#include "securec.h"

#include "ka_dfx_pub.h"
#include "ka_base_pub.h"
#include "ka_errno_pub.h"
#include "ka_fs_pub.h"
#include "ka_kernel_def_pub.h"
#include "ka_net_pub.h"

#define BUFFER_SIZE 50

#define TD_PRINT_ERR(fmt, ...) ka_dfx_printk(KERN_ERR "[ts_debug][ERROR]<%s:%d> " \
    fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define TD_PRINT_INFO(fmt, ...) ka_dfx_printk(KERN_INFO "[ts_debug][INFO]<%s:%d> " \
    fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)

static int debug_mode = 0;
static ka_proc_dir_entry_t *ent;

static ssize_t debug_proc_write(ka_file_t *file, const char __user *ubuf, size_t count, loff_t *ppos)
{
    int ret;
    char kernel_buf[BUFFER_SIZE] = { 0 };
    if (*ppos < 0) {
        TD_PRINT_ERR("ppos's initial value error,ppos's value can't be negative\n");
        return -EFAULT;
    } else if (*ppos > 0) {
        TD_PRINT_ERR("ppos's initial value error,ppos greater than zero\n");
        return -EFAULT;
    }
    if (ubuf == NULL) {
        TD_PRINT_ERR("ubuf is NULL\n");
        return -EFAULT;
    }
    if (count > BUFFER_SIZE) {
        TD_PRINT_ERR("size of write content must less than 50\n");
        return -EFAULT;
    }
    ret = ka_base_copy_from_user(kernel_buf, ubuf, count);
    if (ret != 0) {
        TD_PRINT_ERR("kernel copy from user failed\n");
        return -EFAULT;
    }
    ret = sscanf_s(kernel_buf, "%d", &debug_mode);
    if (ret != 1) {
        TD_PRINT_ERR("kernel sscanf execute failed\n");
        return -EFAULT;
    }
    return count;
}
static ssize_t debug_proc_read(ka_file_t *file, char __user *ubuf, size_t count, loff_t *ppos)
{
    char kernel_buf[BUFFER_SIZE] = { 0 };
    int len = 0;
    if (*ppos > 0) {
        return 0;
    }
    if (ubuf == NULL) {
        TD_PRINT_ERR("ubuf is NULL\n");
        return -EFAULT;
    }
    len += sprintf_s(kernel_buf, sizeof(kernel_buf), "debug_switch_status = %d\n", debug_mode);
    if (len < 0) {
        TD_PRINT_ERR("sprintf_s failed, ret = %d\n", len);
        return -EFAULT;
    }
    if (ka_base_copy_to_user(ubuf, kernel_buf, len)) {
        TD_PRINT_ERR("copy to user Failed\n");
        return -EFAULT;
    }
    *ppos += len;
    return len;
}

static ssize_t __attribute__((unused)) debug_proc_read_iter(ka_kiocb_t *iocb, ka_iov_iter_t *iter)
{
    char kernel_buf[BUFFER_SIZE] = { 0 };
    int len;
    if (iocb == NULL || iter == NULL) {
        TD_PRINT_ERR("iocb or iter is NULL\n");
        return -EFAULT;
    }
    if (ka_net_get_ki_pos(iocb) > 0) {
        return 0;
    }

    len = sprintf_s(kernel_buf, sizeof(kernel_buf), "debug_switch_status = %d\n", debug_mode);
    if (len < 0) {
        TD_PRINT_ERR("sprintf_s failed, ret = %d\n", len);
        return -EFAULT;
    }
    if (!ka_net_copy_to_iter(kernel_buf, len, iter)) {
        TD_PRINT_ERR("copy to user Failed\n");
        return -EFAULT;
    }
    ka_net_set_ki_pos(iocb, ka_net_get_ki_pos(iocb)+len);
    return len;
}

ka_procfs_ops_t debug_switch_ops = {
    ka_fs_init_pf_read(debug_proc_read)
    ka_fs_init_pf_write(debug_proc_write)
    ka_fs_init_pf_read_iter(debug_proc_read_iter)
};

static int debug_switch_init(void)
{
    ent = ka_fs_proc_create("debug_switch", SWITCH_PERMISSION, NULL, &debug_switch_ops);
    if (!ent) {
        TD_PRINT_ERR("Failed to create proc entry\n");
        return -ENOMEM;
    }
    TD_PRINT_INFO("debug_switch_created!\n");
    return 0;
}

static void debug_switch_exit(void)
{
    ka_fs_proc_remove(ent);
    TD_PRINT_INFO("debug_switch_destroyed!\n");
}

#define PCI_VENDOR_ID_HUAWEI 0x19e5

static const struct pci_device_id g_debug_switch_tbl[] = {
    {KA_PCI_VDEVICE(HUAWEI, 0xd802), 0},
    {KA_PCI_VDEVICE(HUAWEI, 0xd803), 0},
    {KA_PCI_VDEVICE(HUAWEI, 0xd500), 0},
    {}
};
KA_MODULE_DEVICE_TABLE(pci, g_debug_switch_tbl);

ka_module_init(debug_switch_init);
ka_module_exit(debug_switch_exit);

KA_MODULE_DESCRIPTION("ts debug channel switch");
KA_MODULE_LICENSE("GPL");
KA_MODULE_AUTHOR("Huawei Tech. Co., LTD.");