|
@@ -55,6 +55,8 @@
|
|
|
#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
|
|
|
#endif
|
|
|
|
|
|
+#define SIZE_OF_WIFI6E_CHAN_LIST 512
|
|
|
+
|
|
|
/*
|
|
|
* Size of Driver command strings from upper layer
|
|
|
*/
|
|
@@ -2646,6 +2648,102 @@ static int drv_cmd_set_wmmps(struct wlan_hdd_link_info *link_info,
|
|
|
return hdd_wmmps_helper(link_info->adapter, command);
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_BAND_6GHZ
|
|
|
+/**
|
|
|
+ * drv_cmd_get_wifi6e_channels() - Handler for GET_WIFI6E_CHANNELS driver
|
|
|
+ * command
|
|
|
+ * @link_info: Link info pointer in adapter
|
|
|
+ * @hdd_ctx: pointer to hdd context
|
|
|
+ * @command: command name
|
|
|
+ * @command_len: command buffer length
|
|
|
+ * @priv_data: output pointer to hold current country code
|
|
|
+ *
|
|
|
+ * Return: On success 0, negative value on error.
|
|
|
+ */
|
|
|
+static int drv_cmd_get_wifi6e_channels(struct wlan_hdd_link_info *link_info,
|
|
|
+ struct hdd_context *hdd_ctx,
|
|
|
+ uint8_t *command,
|
|
|
+ uint8_t command_len,
|
|
|
+ struct hdd_priv_data *priv_data)
|
|
|
+{
|
|
|
+ uint8_t power_type;
|
|
|
+ char extra[SIZE_OF_WIFI6E_CHAN_LIST] = {0};
|
|
|
+ int i, ret, copied_length = 0;
|
|
|
+ enum channel_state state;
|
|
|
+ struct regulatory_channel *chan_list;
|
|
|
+ size_t max_buf_len = QDF_MIN(priv_data->total_len,
|
|
|
+ SIZE_OF_WIFI6E_CHAN_LIST);
|
|
|
+ QDF_STATUS status;
|
|
|
+
|
|
|
+ if (wlan_hdd_validate_context(hdd_ctx))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ ret = kstrtou8(command + command_len + 1, 10, &power_type);
|
|
|
+ if (ret) {
|
|
|
+ hdd_err("error %d parsing userspace 6 GHz power type parameter",
|
|
|
+ ret);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (power_type) {
|
|
|
+ case 0:
|
|
|
+ power_type = REG_CLI_DEF_LPI;
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ power_type = REG_CLI_DEF_VLP;
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ power_type = REG_CLI_DEF_SP;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ hdd_err("The power type : %u, is incorrect", power_type);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ chan_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(*chan_list));
|
|
|
+ if (!chan_list)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ status = wlan_reg_get_pwrmode_chan_list(hdd_ctx->pdev, chan_list,
|
|
|
+ power_type);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ hdd_err("Failed to get wifi6e channel list for given power type %u",
|
|
|
+ power_type);
|
|
|
+ ret = qdf_status_to_os_return(status);
|
|
|
+ goto free;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < NUM_6GHZ_CHANNELS && copied_length < max_buf_len - 1;
|
|
|
+ i++) {
|
|
|
+ state = chan_list[i + MIN_6GHZ_CHANNEL].state;
|
|
|
+ if (state == CHANNEL_STATE_INVALID ||
|
|
|
+ state == CHANNEL_STATE_DISABLE)
|
|
|
+ continue;
|
|
|
+ copied_length += scnprintf(extra + copied_length,
|
|
|
+ max_buf_len - copied_length, "%u ",
|
|
|
+ chan_list[i + MIN_6GHZ_CHANNEL].chan_num);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (copied_length == 0) {
|
|
|
+ hdd_err("No Channel List found for given power type %u",
|
|
|
+ power_type);
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto free;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (copy_to_user(priv_data->buf, &extra, copied_length + 1)) {
|
|
|
+ hdd_err("failed to copy data to user buffer");
|
|
|
+ ret = -EFAULT;
|
|
|
+ goto free;
|
|
|
+ }
|
|
|
+
|
|
|
+ hdd_debug("Power type = %u, Data = %s", power_type, extra);
|
|
|
+free:
|
|
|
+ qdf_mem_free(chan_list);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
static inline int __drv_cmd_country(struct wlan_hdd_link_info *link_info,
|
|
|
struct hdd_context *hdd_ctx,
|
|
|
uint8_t *command,
|
|
@@ -7342,6 +7440,9 @@ static const struct hdd_drv_cmd hdd_drv_cmds[] = {
|
|
|
{"BTCOEXSCAN-START", drv_cmd_dummy, false},
|
|
|
{"BTCOEXSCAN-STOP", drv_cmd_dummy, false},
|
|
|
{"GET_SOFTAP_LINK_SPEED", drv_cmd_get_sap_go_linkspeed, true},
|
|
|
+#ifdef CONFIG_BAND_6GHZ
|
|
|
+ {"GET_WIFI6E_CHANNELS", drv_cmd_get_wifi6e_channels, true},
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
/**
|