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