1 /*
2  * Copyright (c) 2020, The Linux Foundation. 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_suspend_resume.c
19  *
20  * implementation for creating sysfs file wlan_suspend/wlan_resume
21  */
22 
23 #include <wlan_hdd_includes.h>
24 #include "osif_vdev_sync.h"
25 #include "wlan_hdd_power.h"
26 #include "wlan_hdd_sysfs.h"
27 #include "wlan_hdd_sysfs_suspend_resume.h"
28 
__hdd_sysfs_suspend_store(struct net_device * net_dev,const char * buf,size_t count)29 static ssize_t __hdd_sysfs_suspend_store(
30 		struct net_device *net_dev,
31 		const char *buf, size_t count)
32 {
33 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev);
34 	struct hdd_context *hdd_ctx;
35 	char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1];
36 	char *sptr, *token;
37 	int ret, pause_setting, resume_setting;
38 
39 	if (hdd_validate_adapter(adapter))
40 		return -EINVAL;
41 
42 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
43 	ret = wlan_hdd_validate_context(hdd_ctx);
44 	if (ret != 0)
45 		return ret;
46 
47 	if (!wlan_hdd_validate_modules_state(hdd_ctx))
48 		return -EINVAL;
49 
50 	ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local),
51 					      buf, count);
52 	if (ret) {
53 		hdd_err_rl("invalid input");
54 		return ret;
55 	}
56 
57 	hdd_nofl_info("wlan_suspend: count %zu buf_local:(%s) net_devname %s",
58 		      count, buf_local, net_dev->name);
59 
60 	sptr = buf_local;
61 	/* Get pause_setting */
62 	token = strsep(&sptr, " ");
63 	if (!token)
64 		return -EINVAL;
65 	if (kstrtou32(token, 0, &pause_setting))
66 		return -EINVAL;
67 
68 	/* Get resume_setting */
69 	token = strsep(&sptr, " ");
70 	if (!token)
71 		return -EINVAL;
72 	if (kstrtou32(token, 0, &resume_setting))
73 		return -EINVAL;
74 
75 	hdd_nofl_info("wlan_suspend: pause_setting %d, resume_setting %d",
76 		      pause_setting, resume_setting);
77 	ret = hdd_wlan_fake_apps_suspend(hdd_ctx->wiphy, net_dev,
78 					 pause_setting, resume_setting);
79 	if (ret != 0) {
80 		hdd_err_rl("suspend test failed");
81 		return -EINVAL;
82 	}
83 
84 	return count;
85 }
86 
hdd_sysfs_suspend_store(struct device * dev,struct device_attribute * attr,char const * buf,size_t count)87 static ssize_t hdd_sysfs_suspend_store(struct device *dev,
88 				       struct device_attribute *attr,
89 				       char const *buf, size_t count)
90 {
91 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
92 	struct osif_vdev_sync *vdev_sync;
93 	ssize_t errno_size;
94 
95 	errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
96 	if (errno_size)
97 		return errno_size;
98 
99 	errno_size = __hdd_sysfs_suspend_store(
100 				net_dev, buf, count);
101 	if (errno_size < 0)
102 		hdd_err_rl("errno_size %zd", errno_size);
103 
104 	osif_vdev_sync_op_stop(vdev_sync);
105 
106 	return errno_size;
107 }
108 
109 static DEVICE_ATTR(wlan_suspend, 0220,
110 		   NULL, hdd_sysfs_suspend_store);
111 
hdd_sysfs_suspend_create(struct hdd_adapter * adapter)112 int hdd_sysfs_suspend_create(struct hdd_adapter *adapter)
113 {
114 	int error;
115 
116 	error = device_create_file(&adapter->dev->dev, &dev_attr_wlan_suspend);
117 	if (error)
118 		hdd_err("could not create wlan_suspend sysfs file");
119 
120 	return error;
121 }
122 
hdd_sysfs_suspend_destroy(struct hdd_adapter * adapter)123 void hdd_sysfs_suspend_destroy(struct hdd_adapter *adapter)
124 {
125 	device_remove_file(&adapter->dev->dev, &dev_attr_wlan_suspend);
126 }
127 
__hdd_sysfs_resume_store(struct net_device * net_dev,const char * buf,size_t count)128 static ssize_t __hdd_sysfs_resume_store(
129 		struct net_device *net_dev,
130 		const char *buf, size_t count)
131 {
132 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev);
133 	struct hdd_context *hdd_ctx;
134 	int ret;
135 
136 	if (hdd_validate_adapter(adapter))
137 		return -EINVAL;
138 
139 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
140 	ret = wlan_hdd_validate_context(hdd_ctx);
141 	if (ret != 0)
142 		return ret;
143 
144 	if (!wlan_hdd_validate_modules_state(hdd_ctx))
145 		return -EINVAL;
146 
147 	ret = hdd_wlan_fake_apps_resume(hdd_ctx->wiphy, net_dev);
148 	if (ret != 0) {
149 		hdd_err_rl("resume test failed");
150 		return -EINVAL;
151 	}
152 
153 	return count;
154 }
155 
hdd_sysfs_resume_store(struct device * dev,struct device_attribute * attr,char const * buf,size_t count)156 static ssize_t hdd_sysfs_resume_store(struct device *dev,
157 				      struct device_attribute *attr,
158 				      char const *buf, size_t count)
159 {
160 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
161 	struct osif_vdev_sync *vdev_sync;
162 	ssize_t errno_size;
163 
164 	errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
165 	if (errno_size)
166 		return errno_size;
167 
168 	errno_size = __hdd_sysfs_resume_store(
169 				net_dev, buf, count);
170 	if (errno_size < 0)
171 		hdd_err_rl("errno_size %zd", errno_size);
172 
173 	osif_vdev_sync_op_stop(vdev_sync);
174 
175 	return errno_size;
176 }
177 
178 static DEVICE_ATTR(wlan_resume, 0220,
179 		   NULL, hdd_sysfs_resume_store);
180 
hdd_sysfs_resume_create(struct hdd_adapter * adapter)181 int hdd_sysfs_resume_create(struct hdd_adapter *adapter)
182 {
183 	int error;
184 
185 	error = device_create_file(&adapter->dev->dev, &dev_attr_wlan_resume);
186 	if (error)
187 		hdd_err("could not create wlan_resume sysfs file");
188 
189 	return error;
190 }
191 
hdd_sysfs_resume_destroy(struct hdd_adapter * adapter)192 void hdd_sysfs_resume_destroy(struct hdd_adapter *adapter)
193 {
194 	device_remove_file(&adapter->dev->dev, &dev_attr_wlan_resume);
195 }
196