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