1 /*
2 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /**
18 * DOC: wlan_hdd_sysfs_get_freq_for_pwr.c
19 *
20 * implementation for creating sysfs file valid_freq
21 */
22
23 #include <wlan_hdd_includes.h>
24 #include "osif_vdev_sync.h"
25 #include <wlan_hdd_sysfs.h>
26 #include "wlan_hdd_sysfs_get_freq_for_pwr.h"
27 #include "osif_psoc_sync.h"
28 #include "reg_services_public_struct.h"
29 #include <wma_api.h>
30
31 static ssize_t
__hdd_sysfs_power_level_store(struct hdd_context * hdd_ctx,char const * buf,size_t count)32 __hdd_sysfs_power_level_store(struct hdd_context *hdd_ctx,
33 char const *buf, size_t count)
34 {
35 char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1];
36 char *sptr, *token;
37 int ret;
38
39 ret = wlan_hdd_validate_context(hdd_ctx);
40 if (ret != 0)
41 return ret;
42
43 if (!wlan_hdd_validate_modules_state(hdd_ctx))
44 return -EINVAL;
45
46 ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local),
47 buf, count);
48 if (ret) {
49 hdd_err_rl("invalid input");
50 return ret;
51 }
52 sptr = buf_local;
53 token = strsep(&sptr, " ");
54 if (!token)
55 return -EINVAL;
56
57 if (!strncasecmp(token, "VLP", strlen("VLP")))
58 hdd_ctx->power_type = REG_VERY_LOW_POWER_AP;
59 else if (!strncasecmp(token, "LP", strlen("LP")))
60 hdd_ctx->power_type = REG_INDOOR_AP;
61 else if (!strncasecmp(token, "SP", strlen("SP")))
62 hdd_ctx->power_type = REG_STANDARD_POWER_AP;
63 else
64 hdd_ctx->power_type = REG_MAX_SUPP_AP_TYPE;
65
66 hdd_debug("power level %s(%d)", token,
67 hdd_ctx->power_type);
68
69 return count;
70 }
71
72 static ssize_t
wlan_hdd_sysfs_power_store(struct kobject * kobj,struct kobj_attribute * attr,char const * buf,size_t count)73 wlan_hdd_sysfs_power_store(struct kobject *kobj,
74 struct kobj_attribute *attr,
75 char const *buf, size_t count)
76 {
77 struct osif_psoc_sync *psoc_sync;
78 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
79 ssize_t err_size;
80
81 if (wlan_hdd_validate_context(hdd_ctx))
82 return 0;
83
84 err_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy),
85 &psoc_sync);
86 if (err_size)
87 return err_size;
88
89 err_size = __hdd_sysfs_power_level_store(hdd_ctx, buf, count);
90 osif_psoc_sync_op_stop(psoc_sync);
91
92 return err_size;
93 }
94
95 static ssize_t
__wlan_hdd_sysfs_freq_show(struct hdd_context * hdd_ctx,struct kobj_attribute * attr,char * buf)96 __wlan_hdd_sysfs_freq_show(struct hdd_context *hdd_ctx,
97 struct kobj_attribute *attr, char *buf)
98 {
99 int ret = 0;
100 struct regulatory_channel *chan_list;
101 uint32_t len_6g =
102 NUM_6GHZ_CHANNELS * sizeof(struct regulatory_channel);
103 QDF_STATUS status;
104 uint32_t i;
105
106 ret = wlan_hdd_validate_context(hdd_ctx);
107 if (ret != 0)
108 return ret;
109
110 if (!wlan_hdd_validate_modules_state(hdd_ctx))
111 return -EINVAL;
112
113 ret = scnprintf(buf, PAGE_SIZE, "freq list for power type %s\n",
114 wlan_reg_get_power_string(hdd_ctx->power_type));
115
116 if (!strcmp(wlan_reg_get_power_string(hdd_ctx->power_type), "INVALID"))
117 return -EINVAL;
118
119 chan_list = qdf_mem_malloc(len_6g);
120 if (!chan_list)
121 return -ENOMEM;
122
123 status = wlan_reg_get_6g_ap_master_chan_list(
124 hdd_ctx->pdev,
125 hdd_ctx->power_type,
126 chan_list);
127
128 for (i = 0; i < NUM_6GHZ_CHANNELS; i++) {
129 if ((chan_list[i].state != CHANNEL_STATE_DISABLE) &&
130 !(chan_list[i].chan_flags & REGULATORY_CHAN_DISABLED)) {
131 if ((PAGE_SIZE - ret) <= 0)
132 goto err;
133 ret += scnprintf(buf + ret, PAGE_SIZE - ret,
134 "%d ", chan_list[i].center_freq);
135 }
136 }
137
138 err:
139 qdf_mem_free(chan_list);
140 return ret;
141 }
142
wlan_hdd_sysfs_freq_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)143 static ssize_t wlan_hdd_sysfs_freq_show(struct kobject *kobj,
144 struct kobj_attribute *attr,
145 char *buf)
146 {
147 struct osif_psoc_sync *psoc_sync;
148 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
149 ssize_t err_size;
150 int ret;
151
152 ret = wlan_hdd_validate_context(hdd_ctx);
153 if (ret != 0)
154 return ret;
155
156 err_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy),
157 &psoc_sync);
158 if (err_size)
159 return err_size;
160
161 err_size = __wlan_hdd_sysfs_freq_show(hdd_ctx, attr, buf);
162
163 osif_psoc_sync_op_stop(psoc_sync);
164
165 return err_size;
166 }
167
168 static struct kobj_attribute valid_freq_attribute =
169 __ATTR(valid_freq, 0664, wlan_hdd_sysfs_freq_show, wlan_hdd_sysfs_power_store);
170
hdd_sysfs_get_valid_freq_for_power_create(struct kobject * driver_kobject)171 int hdd_sysfs_get_valid_freq_for_power_create(struct kobject *driver_kobject)
172 {
173 int error;
174
175 error = sysfs_create_file(driver_kobject, &valid_freq_attribute.attr);
176 if (error)
177 hdd_err("could not create valid_freq sysfs file");
178
179 return error;
180 }
181
182 void
hdd_sysfs_get_valid_freq_for_power_destroy(struct kobject * driver_kobject)183 hdd_sysfs_get_valid_freq_for_power_destroy(struct kobject *driver_kobject)
184 {
185 if (!driver_kobject) {
186 hdd_err("could not get driver kobject!");
187 return;
188 }
189 sysfs_remove_file(driver_kobject, &valid_freq_attribute.attr);
190 }
191