mirror of
https://github.com/nxp-imx/mwifiex.git
synced 2024-11-15 03:25:35 +00:00
33d9f8e4f3
Add initial MxM (multi-chip-multi-interface) wifi driver. The driver target is to support 88w8987/88w8997/88w9098, currently it only supports 88w8987. The MxM wifi driver is merged from below repo and applied some patches for block and build issues. ssh://git@bitbucket.sw.nxp.com/wcswrel/ rel-nxp-wifi-fp92-bt-fp85-linux-android-mxm4x17169-gpl.git The sdk only includes application, the driver already is merged into linux kernel. Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
545 lines
15 KiB
C
545 lines
15 KiB
C
/** @file mlanregclass.c
|
|
*
|
|
* @brief This files contains mlanutl regclass command handling.
|
|
*
|
|
*
|
|
* Copyright 2014-2020 NXP
|
|
*
|
|
* NXP CONFIDENTIAL
|
|
* The source code contained or described herein and all documents related to
|
|
* the source code (Materials) are owned by NXP, its
|
|
* suppliers and/or its licensors. Title to the Materials remains with NXP,
|
|
* its suppliers and/or its licensors. The Materials contain
|
|
* trade secrets and proprietary and confidential information of NXP, its
|
|
* suppliers and/or its licensors. The Materials are protected by worldwide copyright
|
|
* and trade secret laws and treaty provisions. No part of the Materials may be
|
|
* used, copied, reproduced, modified, published, uploaded, posted,
|
|
* transmitted, distributed, or disclosed in any way without NXP's prior
|
|
* express written permission.
|
|
*
|
|
* No license under any patent, copyright, trade secret or other intellectual
|
|
* property right is granted to or conferred upon you by disclosure or delivery
|
|
* of the Materials, either expressly, by implication, inducement, estoppel or
|
|
* otherwise. Any license under such intellectual property rights must be
|
|
* express and approved by NXP in writing.
|
|
*
|
|
*/
|
|
/************************************************************************
|
|
Change log:
|
|
08/11/2009: initial version
|
|
************************************************************************/
|
|
|
|
#include "mlanutl.h"
|
|
#include "mlanhostcmd.h"
|
|
#include "mlanoffload.h"
|
|
#include "mlanregclass.h"
|
|
|
|
/********************************************************
|
|
Local Variables
|
|
********************************************************/
|
|
|
|
/********************************************************
|
|
Global Variables
|
|
********************************************************/
|
|
|
|
/********************************************************
|
|
Local Functions
|
|
********************************************************/
|
|
|
|
/**
|
|
* @brief Convert reg domain number to string
|
|
*
|
|
* @param reg_domain Reg Domain
|
|
*
|
|
* @return Reg Domain type
|
|
*/
|
|
static char *
|
|
reg_domain_to_str(reg_domain_e reg_domain)
|
|
{
|
|
switch (reg_domain) {
|
|
case REGDOMAIN_FCC:
|
|
return "FCC";
|
|
|
|
case REGDOMAIN_ETSI:
|
|
return "ETSI";
|
|
|
|
case REGDOMAIN_MIC:
|
|
return "MIC";
|
|
|
|
case REGDOMAIN_OTHER:
|
|
return "MULTI";
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return "UNKN";
|
|
}
|
|
|
|
/**
|
|
* @brief Convert reg channel table number to string
|
|
*
|
|
* @param table_select Reg channel table
|
|
*
|
|
* @return Reg channel table type
|
|
*/
|
|
static char *
|
|
table_num_to_str(reg_chan_table_e table_select)
|
|
{
|
|
switch (table_select) {
|
|
case REGTABLE_USER:
|
|
return "User";
|
|
|
|
case REGTABLE_MULTIDOMAIN:
|
|
return "MultiDomain";
|
|
|
|
case REGTABLE_ESS:
|
|
return "ESS";
|
|
|
|
case REGTABLE_DEFAULT:
|
|
return "Default";
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return "UNKN";
|
|
}
|
|
|
|
/**
|
|
* @brief Regclass dump channel table
|
|
*
|
|
* @param argc Number of arguments
|
|
* @param argv A pointer to arguments array
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS--success, otherwise--fail
|
|
*/
|
|
static int
|
|
reg_class_dump_chan_table(int argc, char *argv[])
|
|
{
|
|
int ret = MLAN_STATUS_SUCCESS;
|
|
struct ifreq ifr;
|
|
t_u8 *buffer = NULL, *pos = NULL;
|
|
t_u32 cmd_len = 0, cmd_header_len;
|
|
struct eth_priv_cmd *cmd = NULL;
|
|
HostCmd_DS_GEN *hostcmd;
|
|
HostCmd_DS_REGCLASS_GET_CHAN_TABLE *get_table;
|
|
int idx;
|
|
t_u16 regLimits;
|
|
boolean invalid_cmd = FALSE;
|
|
|
|
printf("ERR:Cannot allocate buffer for command!\n");
|
|
if (argv[0] == NULL) {
|
|
invalid_cmd = TRUE;
|
|
} else {
|
|
|
|
cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD);
|
|
|
|
buffer = (t_u8 *)malloc(BUFFER_LENGTH);
|
|
if (buffer == NULL) {
|
|
fprintf(stderr, "Cannot alloc memory\n");
|
|
ret = ENOMEM;
|
|
goto done;
|
|
}
|
|
memset(buffer, 0, BUFFER_LENGTH);
|
|
|
|
cmd = (struct eth_priv_cmd *)
|
|
malloc(sizeof(struct eth_priv_cmd));
|
|
if (!cmd) {
|
|
printf("ERR:Cannot allocate buffer for command!\n");
|
|
ret = ENOMEM;
|
|
goto done;
|
|
}
|
|
|
|
/* Fill up buffer */
|
|
#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT
|
|
memset(cmd, 0, sizeof(struct eth_priv_cmd));
|
|
memcpy(&cmd->buf, &buffer, sizeof(buffer));
|
|
#else
|
|
cmd->buf = buffer;
|
|
#endif
|
|
cmd->used_len = 0;
|
|
cmd->total_len = BUFFER_LENGTH;
|
|
|
|
/* buffer = MRVL_CMD<cmd> */
|
|
strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP));
|
|
strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD,
|
|
strlen(HOSTCMD));
|
|
|
|
/* buffer = MRVL_CMD<cmd><hostcmd_size><HostCmd_DS_GEN><CMD_DS> */
|
|
hostcmd =
|
|
(HostCmd_DS_GEN *)(buffer + cmd_header_len +
|
|
sizeof(t_u32));
|
|
|
|
/* Point after host command header */
|
|
pos = (t_u8 *)hostcmd + S_DS_GEN;
|
|
|
|
cmd_len = S_DS_GEN + sizeof(HostCmd_DS_REGCLASS_GET_CHAN_TABLE);
|
|
hostcmd->command = cpu_to_le16(HostCmd_CMD_REGCLASS_CHAN_TABLE);
|
|
hostcmd->size = cpu_to_le16(cmd_len);
|
|
hostcmd->seq_num = 0;
|
|
hostcmd->result = 0;
|
|
|
|
get_table = (HostCmd_DS_REGCLASS_GET_CHAN_TABLE *)pos;
|
|
get_table->action = cpu_to_le16(HostCmd_ACT_GEN_GET);
|
|
|
|
if (reg_class_table_select(argv[0], (reg_chan_table_e *)
|
|
&get_table->table_select) == FALSE) {
|
|
invalid_cmd = TRUE;
|
|
}
|
|
}
|
|
|
|
if (invalid_cmd) {
|
|
printf("\nValid tables table; valid [user, md, ess, default]\n\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
get_table->table_select = cpu_to_le16((t_u16)(get_table->table_select));
|
|
|
|
/* Put buffer length */
|
|
memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32));
|
|
|
|
/* Initialize the ifr structure */
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name));
|
|
ifr.ifr_ifru.ifru_data = (void *)cmd;
|
|
/* Perform ioctl */
|
|
if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) {
|
|
perror("ioctl[regClassIoctl]");
|
|
printf("ERR:Command sending failed!\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
|
|
if (!le16_to_cpu(hostcmd->result)) {
|
|
printf("HOSTCMD_RESP: ReturnCode=%#04x, Result=%#04x\n",
|
|
le16_to_cpu(hostcmd->command),
|
|
le16_to_cpu(hostcmd->result));
|
|
} else {
|
|
printf("HOSTCMD failed: ReturnCode=%#04x, Result=%#04x\n",
|
|
le16_to_cpu(hostcmd->command),
|
|
le16_to_cpu(hostcmd->result));
|
|
}
|
|
|
|
get_table->table_select = le16_to_cpu(get_table->table_select);
|
|
get_table->chan = le32_to_cpu(get_table->chan);
|
|
|
|
printf("---------------------------------------");
|
|
printf("---------------------------------------\n");
|
|
printf("%35s: %s [%d]\n", "Channel Table",
|
|
table_num_to_str(get_table->table_select), (int)get_table->chan);
|
|
printf("---------------------------------------");
|
|
printf("---------------------------------------\n");
|
|
printf(" chn | freq | sfrq | sp | class | maxP | behavior limits\n");
|
|
printf("---------------------------------------");
|
|
printf("---------------------------------------\n");
|
|
|
|
for (idx = 0; (unsigned int)idx < get_table->chan; idx++) {
|
|
char regDisp[8];
|
|
|
|
sprintf(regDisp, "%4s-%02u",
|
|
reg_domain_to_str(get_table->chan_entry[idx].
|
|
reg_domain),
|
|
get_table->chan_entry[idx].regulatory_class);
|
|
|
|
printf(" %03u | %04u | %04u | %02u | %-8s | %02u |",
|
|
get_table->chan_entry[idx].chan_num,
|
|
(get_table->chan_entry[idx].start_freq +
|
|
(get_table->chan_entry[idx].chan_num * 5)),
|
|
le16_to_cpu(get_table->chan_entry[idx].start_freq),
|
|
le16_to_cpu(get_table->chan_entry[idx].chan_spacing),
|
|
regDisp, get_table->chan_entry[idx].max_tx_power);
|
|
|
|
regLimits = le16_to_cpu(get_table->chan_entry[idx].reg_limits);
|
|
|
|
if (regLimits & BLIMIT_NOMADIC)
|
|
printf(" nomadic");
|
|
if (regLimits & BLIMIT_INDOOR_ONLY)
|
|
printf(" indoor");
|
|
if (regLimits & BLIMIT_TPC)
|
|
printf(" tpc");
|
|
if (regLimits & BLIMIT_DFS)
|
|
printf(" dfs");
|
|
if (regLimits & BLIMIT_IBSS_PROHIBIT)
|
|
printf(" no_ibss");
|
|
if (regLimits & BLIMIT_FOUR_MS_CS)
|
|
printf(" 4ms_cs");
|
|
if (regLimits & BLIMIT_LIC_BASE_STA)
|
|
printf(" base_sta");
|
|
if (regLimits & BLIMIT_MOBILE_STA)
|
|
printf(" mobile");
|
|
if (regLimits & BLIMIT_PUBLIC_SAFETY)
|
|
printf(" safety");
|
|
if (regLimits & BLIMIT_ISM_BANDS)
|
|
printf(" ism");
|
|
|
|
printf("\n");
|
|
}
|
|
printf("---------------------------------------");
|
|
printf("---------------------------------------\n");
|
|
printf("\n");
|
|
|
|
done:
|
|
if (buffer)
|
|
free(buffer);
|
|
if (cmd)
|
|
free(cmd);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Regclass configure user table
|
|
*
|
|
* @param argc Number of arguments
|
|
* @param argv A pointer to arguments array
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS--success, otherwise--fail
|
|
*/
|
|
static int
|
|
reg_class_config_user_table(int argc, char *argv[])
|
|
{
|
|
int ret = MLAN_STATUS_SUCCESS;
|
|
struct ifreq ifr;
|
|
t_u8 *buffer = NULL, *pos = NULL;
|
|
t_u32 cmd_len = 0, cmd_header_len;
|
|
struct eth_priv_cmd *cmd = NULL;
|
|
HostCmd_DS_GEN *hostcmd;
|
|
HostCmd_DS_REGCLASS_CONFIG_USER_TABLE *cfg_user_table;
|
|
|
|
if (argv[0] == NULL) {
|
|
printf("\nCountry string not specified\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD);
|
|
|
|
buffer = (t_u8 *)malloc(BUFFER_LENGTH);
|
|
if (buffer == NULL) {
|
|
fprintf(stderr, "Cannot alloc memory\n");
|
|
ret = ENOMEM;
|
|
goto done;
|
|
}
|
|
memset(buffer, 0, BUFFER_LENGTH);
|
|
|
|
cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd));
|
|
if (!cmd) {
|
|
printf("ERR:Cannot allocate buffer for command!\n");
|
|
ret = ENOMEM;
|
|
goto done;
|
|
}
|
|
|
|
/* Fill up buffer */
|
|
#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT
|
|
memset(cmd, 0, sizeof(struct eth_priv_cmd));
|
|
memcpy(&cmd->buf, &buffer, sizeof(buffer));
|
|
#else
|
|
cmd->buf = buffer;
|
|
#endif
|
|
cmd->used_len = 0;
|
|
cmd->total_len = BUFFER_LENGTH;
|
|
|
|
/* buffer = MRVL_CMD<cmd> */
|
|
strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP));
|
|
strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD));
|
|
|
|
/* buffer = MRVL_CMD<cmd><hostcmd_size><HostCmd_DS_GEN><CMD_DS> */
|
|
hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32));
|
|
|
|
/* Point after host command header */
|
|
pos = (t_u8 *)hostcmd + S_DS_GEN;
|
|
|
|
cmd_len = S_DS_GEN + sizeof(HostCmd_DS_REGCLASS_CONFIG_USER_TABLE);
|
|
hostcmd->command = cpu_to_le16(HostCmd_CMD_REGCLASS_CONFIG_USER_TABLE);
|
|
hostcmd->size = cpu_to_le16(cmd_len);
|
|
hostcmd->seq_num = 0;
|
|
hostcmd->result = 0;
|
|
|
|
cfg_user_table = (HostCmd_DS_REGCLASS_CONFIG_USER_TABLE *)pos;
|
|
cfg_user_table->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
|
|
memcpy(cfg_user_table->regulatory_str,
|
|
argv[0],
|
|
MIN(strlen(argv[0]), sizeof(cfg_user_table->regulatory_str)));
|
|
|
|
/* Put buffer length */
|
|
memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32));
|
|
|
|
/* Initialize the ifr structure */
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name));
|
|
ifr.ifr_ifru.ifru_data = (void *)cmd;
|
|
/* Perform ioctl */
|
|
if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) {
|
|
perror("ioctl[regClassIoctl]");
|
|
printf("ERR:Command sending failed!\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
|
|
if (!le16_to_cpu(hostcmd->result)) {
|
|
printf("HOSTCMD_RESP: ReturnCode=%#04x, Result=%#04x\n",
|
|
le16_to_cpu(hostcmd->command),
|
|
le16_to_cpu(hostcmd->result));
|
|
} else {
|
|
printf("HOSTCMD failed: ReturnCode=%#04x, Result=%#04x\n",
|
|
le16_to_cpu(hostcmd->command),
|
|
le16_to_cpu(hostcmd->result));
|
|
}
|
|
|
|
done:
|
|
if (buffer)
|
|
free(buffer);
|
|
if (cmd)
|
|
free(cmd);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Issue regclass multi-domain command
|
|
*
|
|
* @param argc number of arguments
|
|
* @param argv A pointer to arguments array
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS--success, otherwise--fail
|
|
*/
|
|
static int
|
|
reg_class_multidomain(int argc, char *argv[])
|
|
{
|
|
int ret = MLAN_STATUS_SUCCESS;
|
|
struct ifreq ifr;
|
|
t_u8 *buffer = NULL, *pos = NULL;
|
|
t_u32 cmd_len = 0, cmd_header_len;
|
|
struct eth_priv_cmd *cmd = NULL;
|
|
HostCmd_DS_GEN *hostcmd;
|
|
HostCmd_DS_REGCLASS_MULTIDOMAIN_CONTROL *multidomain_ctrl;
|
|
boolean invalid_cmd = FALSE;
|
|
|
|
if (argv[0] == NULL) {
|
|
invalid_cmd = TRUE;
|
|
} else {
|
|
cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD);
|
|
|
|
buffer = (t_u8 *)malloc(BUFFER_LENGTH);
|
|
if (buffer == NULL) {
|
|
fprintf(stderr, "Cannot alloc memory\n");
|
|
ret = ENOMEM;
|
|
goto done;
|
|
}
|
|
memset(buffer, 0, BUFFER_LENGTH);
|
|
|
|
cmd = (struct eth_priv_cmd *)
|
|
malloc(sizeof(struct eth_priv_cmd));
|
|
if (!cmd) {
|
|
printf("ERR:Cannot allocate buffer for command!\n");
|
|
ret = ENOMEM;
|
|
goto done;
|
|
}
|
|
|
|
/* Fill up buffer */
|
|
#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT
|
|
memset(cmd, 0, sizeof(struct eth_priv_cmd));
|
|
memcpy(&cmd->buf, &buffer, sizeof(buffer));
|
|
#else
|
|
cmd->buf = buffer;
|
|
#endif
|
|
cmd->used_len = 0;
|
|
cmd->total_len = BUFFER_LENGTH;
|
|
|
|
/* buffer = MRVL_CMD<cmd> */
|
|
strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP));
|
|
strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD,
|
|
strlen(HOSTCMD));
|
|
|
|
/* buffer = MRVL_CMD<cmd><hostcmd_size><HostCmd_DS_GEN><CMD_DS> */
|
|
hostcmd =
|
|
(HostCmd_DS_GEN *)(buffer + cmd_header_len +
|
|
sizeof(t_u32));
|
|
|
|
/* Point after host command header */
|
|
pos = (t_u8 *)hostcmd + S_DS_GEN;
|
|
|
|
cmd_len =
|
|
S_DS_GEN +
|
|
sizeof(HostCmd_DS_REGCLASS_MULTIDOMAIN_CONTROL);
|
|
hostcmd->command =
|
|
cpu_to_le16(HostCmd_CMD_REGCLASS_MULTIDOMAIN_CONTROL);
|
|
hostcmd->size = cpu_to_le16(cmd_len);
|
|
hostcmd->seq_num = 0;
|
|
hostcmd->result = 0;
|
|
|
|
multidomain_ctrl =
|
|
(HostCmd_DS_REGCLASS_MULTIDOMAIN_CONTROL *)pos;
|
|
if (strcmp(argv[0], "on") == 0) {
|
|
multidomain_ctrl->multidomain_enable = 1;
|
|
} else if (strcmp(argv[0], "off") == 0) {
|
|
multidomain_ctrl->multidomain_enable = 0;
|
|
} else {
|
|
invalid_cmd = TRUE;
|
|
}
|
|
}
|
|
|
|
if (invalid_cmd) {
|
|
printf("\nUnknown multiDomain command; valid [on, off]\n\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
multidomain_ctrl->multidomain_enable =
|
|
cpu_to_le32(multidomain_ctrl->multidomain_enable);
|
|
|
|
/* Put buffer length */
|
|
memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32));
|
|
|
|
/* Initialize the ifr structure */
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name));
|
|
ifr.ifr_ifru.ifru_data = (void *)cmd;
|
|
/* Perform ioctl */
|
|
if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) {
|
|
perror("ioctl[regClass]");
|
|
printf("ERR:Command sending failed!\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
} else {
|
|
printf("\nMultiDomain: %s\n",
|
|
le32_to_cpu(multidomain_ctrl->multidomain_enable) ?
|
|
"Enabled" : "Disabled");
|
|
}
|
|
|
|
if (!le16_to_cpu(hostcmd->result)) {
|
|
printf("HOSTCMD_RESP: ReturnCode=%#04x, Result=%#04x\n",
|
|
le16_to_cpu(hostcmd->command),
|
|
le16_to_cpu(hostcmd->result));
|
|
} else {
|
|
printf("HOSTCMD failed: ReturnCode=%#04x, Result=%#04x\n",
|
|
le16_to_cpu(hostcmd->command),
|
|
le16_to_cpu(hostcmd->result));
|
|
}
|
|
|
|
done:
|
|
if (buffer)
|
|
free(buffer);
|
|
if (cmd)
|
|
free(cmd);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Issue a regclass command
|
|
*
|
|
* @param argc number of arguments
|
|
* @param argv A pointer to arguments array
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS--success, otherwise--fail
|
|
*/
|
|
int
|
|
process_regclass(int argc, char *argv[])
|
|
{
|
|
sub_cmd_exec_t sub_cmd[] = { {"table", 1, 1, reg_class_dump_chan_table},
|
|
{"multidomain", 1, 1, reg_class_multidomain},
|
|
{"country", 1, 1, reg_class_config_user_table}
|
|
};
|
|
|
|
return process_sub_cmd(sub_cmd, NELEMENTS(sub_cmd), argc, argv);
|
|
}
|