luckfox-pico-sdk/sysdrv/drv_ko/wifi/ssv6115/utils/debugfs.c
luckfox-eng29 8f34c2760d project:build.sh: Added fastboot support; custom modifications to U-Boot and kernel implemented using patches.
project:cfg:BoardConfig_IPC: Added fastboot BoardConfig file and firmware post-scripts, distinguishing between
the BoardConfigs for Luckfox Pico Pro and Luckfox Pico Max. project:app: Added fastboot_client and rk_smart_door
for quick boot applications; updated rkipc app to adapt to the latest media library. media:samples: Added more
usage examples. media:rockit: Fixed bugs; removed support for retrieving data frames from VPSS. media:isp:
Updated rkaiq library and related tools to support connection to RKISP_Tuner. sysdrv:Makefile: Added support for
compiling drv_ko on Luckfox Pico Ultra W using Ubuntu; added support for custom root filesystem.
sysdrv:tools:board: Updated Buildroot optional mirror sources, updated some software versions, and stored device
tree files and configuration files that undergo multiple modifications for U-Boot and kernel separately.
sysdrv:source:mcu: Used RISC-V MCU SDK with RT-Thread system, mainly for initializing camera AE during quick
boot. sysdrv:source:uboot: Added support for fastboot; added high baud rate DDR bin for serial firmware upgrades.
sysdrv:source:kernel: Upgraded to version 5.10.160; increased NPU frequency for RV1106G3; added support for
fastboot.

Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
2024-10-14 09:47:04 +08:00

320 lines
9.4 KiB
C

/*
* Copyright (c) 2015 iComm-semi Ltd.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/proc_fs.h> /* for proc_mkdir, create */
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h> /* for copy_from_user */
#include <linux/errno.h>
#include <linux/fs.h>
//#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h>
#include <linux/ctype.h> /* for isalpha & isdigit */
#include <linux/netdevice.h>
#include "debugfs.h"
#include "ssv_debug.h"
MODULE_AUTHOR("iComm-semi, Ltd");
MODULE_DESCRIPTION("Shared library for SSV wireless LAN cards.");
MODULE_LICENSE("Dual BSD/GPL");
/* for debug */
static struct proc_dir_entry *__ssv_procfs;
#define READ_CHUNK 32
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
#define PDE_DATA(inode) ({ \
struct proc_dir_entry *dp = PDE(inode); \
data = dp->data; })
#endif
extern struct ssv_cmd_table cmd_table[];
void ssv_snprintf_res(struct ssv_cmd_data *cmd_data, const char *fmt, ... )
{
char *buf_head;
int buf_left;
va_list args;
char *ssv6xxx_result_buf = cmd_data->ssv6xxx_result_buf;
ssv6xxx_result_buf = cmd_data->ssv6xxx_result_buf;
// buf end reached
if (cmd_data->rsbuf_len >= (cmd_data->rsbuf_size -1))
return;
buf_head = ssv6xxx_result_buf + cmd_data->rsbuf_len;
buf_left = cmd_data->rsbuf_size - cmd_data->rsbuf_len;
va_start(args, fmt);
cmd_data->rsbuf_len += vsnprintf(buf_head, buf_left, fmt, args);
va_end(args);
// No need for protection here. If vsnprint use more
// than buf_left. It will put 0x0 at last byte automatically
// when overflow and stop copy,
}
static int ssv_cmd_submit(struct ssv_cmd_data *cmd_data, char *cmd)
{
struct ssv_cmd_table *sc_tbl;
char *pch, ch;
int ret, bf_size;
char *sg_cmd_buffer;
char *sg_argv[CLI_ARG_SIZE];
u32 sg_argc;
if (cmd_data->cmd_in_proc)
return -1;
sg_cmd_buffer = cmd;
for (sg_argc = 0, ch = 0, pch = sg_cmd_buffer;
(*pch!=0x00) && (sg_argc<CLI_ARG_SIZE); pch++ )
{
// if (*pch == 0x0a || *pch == 0x0d)
// *pch = ' ';
if ( (ch==0) && (*pch!=' ') )
{
ch = 1;
sg_argv[sg_argc] = pch;
}
if ( (ch==1) && (*pch==' ') )
{
*pch = 0x00;
ch = 0;
sg_argc ++;
}
}
if ( ch == 1)
{
sg_argc ++;
}
else if ( sg_argc > 0 )
{
*(pch-1) = ' ';
}
if ( sg_argc > 0 )
{
/* Dispatch command */
for( sc_tbl=cmd_table; sc_tbl->cmd; sc_tbl ++ )
{
if ( !strcmp(sg_argv[0], sc_tbl->cmd) )
{
//struct ssv_softc *sc;
//sc = container_of(cmd_data, struct ssv_softc, cmd_data);
#if 0
if (sc_tbl->cmd_func_ptr != ssv_cmd_cfg) {
cmd_data->ssv6xxx_result_buf = (char *)kzalloc(128, GFP_KERNEL);
if (!cmd_data->ssv6xxx_result_buf)
return -EFAULT;
cmd_data->ssv6xxx_result_buf[0] = 0x00;
ssv_snprintf_res(cmd_data, "The command is not found\n");
return -1;
}
#endif
cmd_data->ssv6xxx_result_buf = (char *)kzalloc(sc_tbl->result_buffer_size, GFP_KERNEL);
if (!cmd_data->ssv6xxx_result_buf)
return -EFAULT;
cmd_data->ssv6xxx_result_buf[0] = 0x00;
cmd_data->rsbuf_len = 0;
cmd_data->rsbuf_size = sc_tbl->result_buffer_size;
cmd_data->cmd_in_proc = true;
ret = sc_tbl->cmd_func_ptr(/* sc */cmd_data, sg_argc, sg_argv);
if (ret < 0) {
strcpy(cmd_data->ssv6xxx_result_buf, "Invalid command !\n");
}
bf_size = strlen(cmd_data->ssv6xxx_result_buf);
if ((sc_tbl->result_buffer_size -1) <= bf_size){
cmd_data->rsbuf_len = 0;
ssv_snprintf_res(cmd_data,
"\nALLOCATED BUFFER %d <= BUFFER USED +1 %d, OVERFLOW!!\n\n",
sc_tbl->result_buffer_size, bf_size+1);
} else {
ssv_snprintf_res(cmd_data, "\nALLOCATED BUFFER %d , BUFFER USED %d\n\n",
sc_tbl->result_buffer_size, bf_size);
}
return 0;
}
}
cmd_data->ssv6xxx_result_buf = (char *)kzalloc(64, GFP_KERNEL);
if (!cmd_data->ssv6xxx_result_buf)
return -EFAULT;
cmd_data->ssv6xxx_result_buf[0] = 0x00;
cmd_data->rsbuf_len = 0;
cmd_data->rsbuf_size = 64;
cmd_data->cmd_in_proc = true;
ssv_snprintf_res(cmd_data, "Command not found !\n");
return -EFAULT;
} else {
cmd_data->ssv6xxx_result_buf = (char *)kzalloc(64, GFP_KERNEL);
if (!cmd_data->ssv6xxx_result_buf)
return -EFAULT;
cmd_data->ssv6xxx_result_buf[0] = 0x00;
cmd_data->rsbuf_len = 0;
cmd_data->rsbuf_size = 64;
cmd_data->cmd_in_proc = true;
ssv_snprintf_res(cmd_data, "./cli -h\n");
}
return 0;
}
static int ssv6xxx_cmd_file_open(struct inode *inode, struct file *filp)
{
void *data = PDE_DATA(inode);
filp->private_data = data;
return 0;
}
static ssize_t ssv6xxx_cmd_file_read(struct file *filp, char __user *buffer,
size_t count, loff_t *ppos)
{
char *ssv6xxx_result_buf;
struct ssv_cmd_data *cmd_data = filp->private_data;
int len;
int ret = 0;
if (!(cmd_data->cmd_in_proc)){
goto out;
}
ssv6xxx_result_buf = cmd_data->ssv6xxx_result_buf;
cmd_data->cmd_in_proc = false;
if (!ssv6xxx_result_buf){
goto out;
}
cmd_data->ssv6xxx_result_buf = NULL;
if (*ppos != 0){
goto free;
}
if (cmd_data->rsbuf_size < cmd_data->rsbuf_len)
cmd_data->rsbuf_len = cmd_data->rsbuf_size-1;
len = cmd_data->rsbuf_len + 1;
if (len == 1){
goto free;
}
if (copy_to_user(buffer, ssv6xxx_result_buf, len)){
ret = -EFAULT;
goto free;
}
ret = len;
free:
kfree(ssv6xxx_result_buf);
out:
return ret;
}
static ssize_t ssv6xxx_cmd_file_write(struct file *filp, const char __user *buffer,
size_t count, loff_t *ppos)
{
char *ssv6xxx_cmd_buf = NULL;
//struct ssv_cmd_data *cmd_data = filp->private_data;
if (*ppos != 0 || count > 255)
return 0;
ssv6xxx_cmd_buf = (char *)kzalloc(count, GFP_KERNEL);
if (!ssv6xxx_cmd_buf)
return 0;
ssv6xxx_cmd_buf[0] = 0x00;
if (copy_from_user(ssv6xxx_cmd_buf, buffer, count))
return -EFAULT;
ssv6xxx_cmd_buf[count-1] = 0x00;
ssv_cmd_submit((struct ssv_cmd_data *)filp->private_data, ssv6xxx_cmd_buf);
kfree(ssv6xxx_cmd_buf);
return count;
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0))
static struct file_operations ssv6xxx_cmd_fops = {
.owner = THIS_MODULE,
.open = ssv6xxx_cmd_file_open,
.read = ssv6xxx_cmd_file_read,
.write = ssv6xxx_cmd_file_write,
};
#else
static struct proc_ops ssv6xxx_cmd_fops = {
.proc_open = ssv6xxx_cmd_file_open,
.proc_read = ssv6xxx_cmd_file_read,
.proc_write = ssv6xxx_cmd_file_write,
};
#endif
int ssv_init_cli(const char *dev_name, struct ssv_cmd_data *cmd_data)
{
struct proc_dir_entry *proc_file_entry;
__ssv_procfs = proc_mkdir(PROC_DIR_ENTRY, NULL);
if (!__ssv_procfs)
return -ENOMEM;
// Create directory for each device. Then create following proc entries under it.
cmd_data->proc_dev_entry = proc_mkdir(dev_name, __ssv_procfs);
if (!cmd_data->proc_dev_entry)
SSV_LOG_DBG("KERN_ERR" "Failed to create %s dev directory for CLI. \n", dev_name);
proc_file_entry = proc_create_data(PROC_SSV_CMD_ENTRY, S_IRUGO|S_IWUGO,
cmd_data->proc_dev_entry, &ssv6xxx_cmd_fops, cmd_data);
if (proc_file_entry == NULL)
SSV_LOG_DBG("Failed to create %s for CLI.\n", PROC_SSV_CMD_ENTRY);
return 0;
}
EXPORT_SYMBOL(ssv_init_cli);
void ssv_deinit_cli(const char *dev_name, struct ssv_cmd_data *cmd_data)
{
remove_proc_entry(PROC_SSV_CMD_ENTRY, cmd_data->proc_dev_entry);
remove_proc_entry(dev_name, __ssv_procfs);
/* Remove dev directory must be last */
remove_proc_entry(PROC_DIR_ENTRY, NULL);
}
EXPORT_SYMBOL(ssv_deinit_cli);