blob: 2e57b0db686310f5dcae9b04e89a0a39191c5171 [file] [log] [blame]
/*
* Copyright (c) 2019 The Linux Foundation. All rights reserved.
*
* 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.
*/
/**
* DOC: wlan_hdd_debugfs_config.c
*
* WLAN Host Device Driver implementation to update
* debugfs with ini configs
*/
#include "wlan_hdd_main.h"
#include "osif_psoc_sync.h"
#include "cfg_ucfg_api.h"
#include "wlan_hdd_debugfs_config.h"
#define DEBUGFS_CONFIG_BUF_SIZE (4096 * 8)
/**
* struct ini_config_buf - the buffer struct to save ini configs
* @len: buffer len
* @result: the pointer to buffer
*/
struct ini_config_buf {
ssize_t len;
uint8_t result[DEBUGFS_CONFIG_BUF_SIZE];
};
/**
* wlan_hdd_config_update() - Update userspace with local statistics buffer
* @buf: userspace buffer (to which data is being copied into)
* @count: max data that can be copied into buf
* @pos: offset (where data should be copied into)
* @ini_config: buffer structure for ini config info
*
* This function should copies ini configs into debugfs entry.
*
* Return: number of characters copied; 0 on no-copy
*/
static ssize_t wlan_hdd_config_update(char __user *buf, size_t count,
loff_t *pos,
struct ini_config_buf *ini_config)
{
ssize_t ret_cnt;
ret_cnt = simple_read_from_buffer(buf, count, pos, ini_config->result,
ini_config->len);
hdd_debug("ini config read req: count: %zu, pos: %lld", count, *pos);
return ret_cnt;
}
/**
* wlan_hdd_config_get() - Function to save ini config to buffer
* @hdd_ctx: hdd context used to register the debugfs file
* @ini_config: buffer structure for ini config info
*
* Return: Errno
*/
static int wlan_hdd_config_get(struct hdd_context *hdd_ctx,
struct ini_config_buf *ini_config)
{
QDF_STATUS status;
status = ucfg_cfg_ini_config_print(hdd_ctx->psoc, ini_config->result,
&ini_config->len,
DEBUGFS_CONFIG_BUF_SIZE);
return qdf_status_to_os_return(status);
}
/**
* __wlan_hdd_read_config_debugfs() - function to get ini conifg
* @file: file pointer
* @buf: buffer
* @count: count
* @pos: position pointer
*
* Return: Number of bytes read on success, error number otherwise
*/
static ssize_t __wlan_hdd_read_config_debugfs(struct file *file,
char __user *buf, size_t count,
loff_t *pos)
{
struct ini_config_buf *ini_config;
ssize_t err_size;
ini_config = (struct ini_config_buf *)file->private_data;
if (!ini_config)
return -ENOMEM;
err_size = wlan_hdd_config_update(buf, count, pos, ini_config);
return err_size;
}
/**
* wlan_hdd_read_config_debugfs() - wrapper function to get ini conifg
* @file: file pointer
* @buf: buffer
* @count: count
* @pos: position pointer
*
* Return: Number of bytes read on success, error number otherwise
*/
static ssize_t wlan_hdd_read_config_debugfs(struct file *file,
char __user *buf, size_t count,
loff_t *pos)
{
struct hdd_context *hdd_ctx = file_inode(file)->i_private;
struct osif_psoc_sync *psoc_sync;
ssize_t err_size;
err_size = wlan_hdd_validate_context(hdd_ctx);
if (err_size)
return err_size;
err_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy),
&psoc_sync);
if (err_size)
return err_size;
err_size = __wlan_hdd_read_config_debugfs(file, buf, count, pos);
osif_psoc_sync_op_stop(psoc_sync);
return err_size;
}
/**
* __wlan_hdd_open_config_debugfs() - function to open config debugfs
* @inode: Pointer to inode structure
* @file: file pointer
*
* Return: Errno
*/
static int __wlan_hdd_open_config_debugfs(struct inode *inode,
struct file *file)
{
struct hdd_context *hdd_ctx = file_inode(file)->i_private;
struct ini_config_buf *ini_config;
ssize_t errno;
void *buf;
buf = qdf_mem_malloc(sizeof(*ini_config));
if (!buf)
return -ENOMEM;
ini_config = (struct ini_config_buf *)buf;
errno = wlan_hdd_config_get(hdd_ctx, ini_config);
if (errno) {
qdf_mem_free(buf);
return errno;
}
file->private_data = buf;
return 0;
}
/**
* wlan_hdd_open_config_debugfs() - wrapper function to open config debugfs
* @inode: Pointer to inode structure
* @file: file pointer
*
* Return: Errno
*/
static int wlan_hdd_open_config_debugfs(struct inode *inode, struct file *file)
{
struct hdd_context *hdd_ctx = file_inode(file)->i_private;
struct osif_psoc_sync *psoc_sync;
ssize_t errno;
errno = wlan_hdd_validate_context(hdd_ctx);
if (errno)
return errno;
errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy),
&psoc_sync);
if (errno)
return errno;
errno = __wlan_hdd_open_config_debugfs(inode, file);
osif_psoc_sync_op_stop(psoc_sync);
return errno;
}
/**
* wlan_hdd_release_config_debugfs() - wrapper to release
* @inode: Pointer to inode structure
* @file: file pointer
*
* Return: Errno
*/
static int wlan_hdd_release_config_debugfs(struct inode *inode,
struct file *file)
{
qdf_mem_free(file->private_data);
file->private_data = NULL;
return 0;
}
static const struct file_operations fops_config_debugfs = {
.read = wlan_hdd_read_config_debugfs,
.open = wlan_hdd_open_config_debugfs,
.release = wlan_hdd_release_config_debugfs,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int hdd_debugfs_ini_config_init(struct hdd_context *hdd_ctx)
{
if (!debugfs_create_file("ini_config", 0444, qdf_debugfs_get_root(),
hdd_ctx, &fops_config_debugfs))
return -EINVAL;
return 0;
}
void hdd_debugfs_ini_config_deinit(struct hdd_context *hdd_ctx)
{
/*
* Config ini doesn't have a directory it is removed
* as part of qdf remove
*/
}