aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/uwb/i1480/i1480u-wlp/sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/uwb/i1480/i1480u-wlp/sysfs.c')
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/sysfs.c408
1 files changed, 408 insertions, 0 deletions
diff --git a/drivers/uwb/i1480/i1480u-wlp/sysfs.c b/drivers/uwb/i1480/i1480u-wlp/sysfs.c
new file mode 100644
index 000000000000..a1d8ca6ac935
--- /dev/null
+++ b/drivers/uwb/i1480/i1480u-wlp/sysfs.c
@@ -0,0 +1,408 @@
1/*
2 * WUSB Wire Adapter: WLP interface
3 * Sysfs interfaces
4 *
5 * Copyright (C) 2005-2006 Intel Corporation
6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 *
23 * FIXME: docs
24 */
25
26#include <linux/netdevice.h>
27#include <linux/etherdevice.h>
28#include <linux/uwb/debug.h>
29#include <linux/device.h>
30#include "i1480u-wlp.h"
31
32
33/**
34 *
35 * @dev: Class device from the net_device; assumed refcnted.
36 *
37 * Yes, I don't lock--we assume it is refcounted and I am getting a
38 * single byte value that is kind of atomic to read.
39 */
40ssize_t uwb_phy_rate_show(const struct wlp_options *options, char *buf)
41{
42 return sprintf(buf, "%u\n",
43 wlp_tx_hdr_phy_rate(&options->def_tx_hdr));
44}
45EXPORT_SYMBOL_GPL(uwb_phy_rate_show);
46
47
48ssize_t uwb_phy_rate_store(struct wlp_options *options,
49 const char *buf, size_t size)
50{
51 ssize_t result;
52 unsigned rate;
53
54 result = sscanf(buf, "%u\n", &rate);
55 if (result != 1) {
56 result = -EINVAL;
57 goto out;
58 }
59 result = -EINVAL;
60 if (rate >= UWB_PHY_RATE_INVALID)
61 goto out;
62 wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, rate);
63 result = 0;
64out:
65 return result < 0 ? result : size;
66}
67EXPORT_SYMBOL_GPL(uwb_phy_rate_store);
68
69
70ssize_t uwb_rts_cts_show(const struct wlp_options *options, char *buf)
71{
72 return sprintf(buf, "%u\n",
73 wlp_tx_hdr_rts_cts(&options->def_tx_hdr));
74}
75EXPORT_SYMBOL_GPL(uwb_rts_cts_show);
76
77
78ssize_t uwb_rts_cts_store(struct wlp_options *options,
79 const char *buf, size_t size)
80{
81 ssize_t result;
82 unsigned value;
83
84 result = sscanf(buf, "%u\n", &value);
85 if (result != 1) {
86 result = -EINVAL;
87 goto out;
88 }
89 result = -EINVAL;
90 wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, !!value);
91 result = 0;
92out:
93 return result < 0 ? result : size;
94}
95EXPORT_SYMBOL_GPL(uwb_rts_cts_store);
96
97
98ssize_t uwb_ack_policy_show(const struct wlp_options *options, char *buf)
99{
100 return sprintf(buf, "%u\n",
101 wlp_tx_hdr_ack_policy(&options->def_tx_hdr));
102}
103EXPORT_SYMBOL_GPL(uwb_ack_policy_show);
104
105
106ssize_t uwb_ack_policy_store(struct wlp_options *options,
107 const char *buf, size_t size)
108{
109 ssize_t result;
110 unsigned value;
111
112 result = sscanf(buf, "%u\n", &value);
113 if (result != 1 || value > UWB_ACK_B_REQ) {
114 result = -EINVAL;
115 goto out;
116 }
117 wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, value);
118 result = 0;
119out:
120 return result < 0 ? result : size;
121}
122EXPORT_SYMBOL_GPL(uwb_ack_policy_store);
123
124
125/**
126 * Show the PCA base priority.
127 *
128 * We can access without locking, as the value is (for now) orthogonal
129 * to other values.
130 */
131ssize_t uwb_pca_base_priority_show(const struct wlp_options *options,
132 char *buf)
133{
134 return sprintf(buf, "%u\n",
135 options->pca_base_priority);
136}
137EXPORT_SYMBOL_GPL(uwb_pca_base_priority_show);
138
139
140/**
141 * Set the PCA base priority.
142 *
143 * We can access without locking, as the value is (for now) orthogonal
144 * to other values.
145 */
146ssize_t uwb_pca_base_priority_store(struct wlp_options *options,
147 const char *buf, size_t size)
148{
149 ssize_t result = -EINVAL;
150 u8 pca_base_priority;
151
152 result = sscanf(buf, "%hhu\n", &pca_base_priority);
153 if (result != 1) {
154 result = -EINVAL;
155 goto out;
156 }
157 result = -EINVAL;
158 if (pca_base_priority >= 8)
159 goto out;
160 options->pca_base_priority = pca_base_priority;
161 /* Update TX header if we are currently using PCA. */
162 if (result >= 0 && (wlp_tx_hdr_delivery_id_type(&options->def_tx_hdr) & WLP_DRP) == 0)
163 wlp_tx_hdr_set_delivery_id_type(&options->def_tx_hdr, options->pca_base_priority);
164 result = 0;
165out:
166 return result < 0 ? result : size;
167}
168EXPORT_SYMBOL_GPL(uwb_pca_base_priority_store);
169
170/**
171 * Show current inflight values
172 *
173 * Will print the current MAX and THRESHOLD values for the basic flow
174 * control. In addition it will report how many times the TX queue needed
175 * to be restarted since the last time this query was made.
176 */
177static ssize_t wlp_tx_inflight_show(struct i1480u_tx_inflight *inflight,
178 char *buf)
179{
180 ssize_t result;
181 unsigned long sec_elapsed = (jiffies - inflight->restart_ts)/HZ;
182 unsigned long restart_count = atomic_read(&inflight->restart_count);
183
184 result = scnprintf(buf, PAGE_SIZE, "%lu %lu %d %lu %lu %lu\n"
185 "#read: threshold max inflight_count restarts "
186 "seconds restarts/sec\n"
187 "#write: threshold max\n",
188 inflight->threshold, inflight->max,
189 atomic_read(&inflight->count),
190 restart_count, sec_elapsed,
191 sec_elapsed == 0 ? 0 : restart_count/sec_elapsed);
192 inflight->restart_ts = jiffies;
193 atomic_set(&inflight->restart_count, 0);
194 return result;
195}
196
197static
198ssize_t wlp_tx_inflight_store(struct i1480u_tx_inflight *inflight,
199 const char *buf, size_t size)
200{
201 unsigned long in_threshold, in_max;
202 ssize_t result;
203 result = sscanf(buf, "%lu %lu", &in_threshold, &in_max);
204 if (result != 2)
205 return -EINVAL;
206 if (in_max <= in_threshold)
207 return -EINVAL;
208 inflight->max = in_max;
209 inflight->threshold = in_threshold;
210 return size;
211}
212/*
213 * Glue (or function adaptors) for accesing info on sysfs
214 *
215 * [we need this indirection because the PCI driver does almost the
216 * same]
217 *
218 * Linux 2.6.21 changed how 'struct netdevice' does attributes (from
219 * having a 'struct class_dev' to having a 'struct device'). That is
220 * quite of a pain.
221 *
222 * So we try to abstract that here. i1480u_SHOW() and i1480u_STORE()
223 * create adaptors for extracting the 'struct i1480u' from a 'struct
224 * dev' and calling a function for doing a sysfs operation (as we have
225 * them factorized already). i1480u_ATTR creates the attribute file
226 * (CLASS_DEVICE_ATTR or DEVICE_ATTR) and i1480u_ATTR_NAME produces a
227 * class_device_attr_NAME or device_attr_NAME (for group registration).
228 */
229#include <linux/version.h>
230
231#define i1480u_SHOW(name, fn, param) \
232static ssize_t i1480u_show_##name(struct device *dev, \
233 struct device_attribute *attr,\
234 char *buf) \
235{ \
236 struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \
237 return fn(&i1480u->param, buf); \
238}
239
240#define i1480u_STORE(name, fn, param) \
241static ssize_t i1480u_store_##name(struct device *dev, \
242 struct device_attribute *attr,\
243 const char *buf, size_t size)\
244{ \
245 struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \
246 return fn(&i1480u->param, buf, size); \
247}
248
249#define i1480u_ATTR(name, perm) static DEVICE_ATTR(name, perm, \
250 i1480u_show_##name,\
251 i1480u_store_##name)
252
253#define i1480u_ATTR_SHOW(name) static DEVICE_ATTR(name, \
254 S_IRUGO, \
255 i1480u_show_##name, NULL)
256
257#define i1480u_ATTR_NAME(a) (dev_attr_##a)
258
259
260/*
261 * Sysfs adaptors
262 */
263i1480u_SHOW(uwb_phy_rate, uwb_phy_rate_show, options);
264i1480u_STORE(uwb_phy_rate, uwb_phy_rate_store, options);
265i1480u_ATTR(uwb_phy_rate, S_IRUGO | S_IWUSR);
266
267i1480u_SHOW(uwb_rts_cts, uwb_rts_cts_show, options);
268i1480u_STORE(uwb_rts_cts, uwb_rts_cts_store, options);
269i1480u_ATTR(uwb_rts_cts, S_IRUGO | S_IWUSR);
270
271i1480u_SHOW(uwb_ack_policy, uwb_ack_policy_show, options);
272i1480u_STORE(uwb_ack_policy, uwb_ack_policy_store, options);
273i1480u_ATTR(uwb_ack_policy, S_IRUGO | S_IWUSR);
274
275i1480u_SHOW(uwb_pca_base_priority, uwb_pca_base_priority_show, options);
276i1480u_STORE(uwb_pca_base_priority, uwb_pca_base_priority_store, options);
277i1480u_ATTR(uwb_pca_base_priority, S_IRUGO | S_IWUSR);
278
279i1480u_SHOW(wlp_eda, wlp_eda_show, wlp);
280i1480u_STORE(wlp_eda, wlp_eda_store, wlp);
281i1480u_ATTR(wlp_eda, S_IRUGO | S_IWUSR);
282
283i1480u_SHOW(wlp_uuid, wlp_uuid_show, wlp);
284i1480u_STORE(wlp_uuid, wlp_uuid_store, wlp);
285i1480u_ATTR(wlp_uuid, S_IRUGO | S_IWUSR);
286
287i1480u_SHOW(wlp_dev_name, wlp_dev_name_show, wlp);
288i1480u_STORE(wlp_dev_name, wlp_dev_name_store, wlp);
289i1480u_ATTR(wlp_dev_name, S_IRUGO | S_IWUSR);
290
291i1480u_SHOW(wlp_dev_manufacturer, wlp_dev_manufacturer_show, wlp);
292i1480u_STORE(wlp_dev_manufacturer, wlp_dev_manufacturer_store, wlp);
293i1480u_ATTR(wlp_dev_manufacturer, S_IRUGO | S_IWUSR);
294
295i1480u_SHOW(wlp_dev_model_name, wlp_dev_model_name_show, wlp);
296i1480u_STORE(wlp_dev_model_name, wlp_dev_model_name_store, wlp);
297i1480u_ATTR(wlp_dev_model_name, S_IRUGO | S_IWUSR);
298
299i1480u_SHOW(wlp_dev_model_nr, wlp_dev_model_nr_show, wlp);
300i1480u_STORE(wlp_dev_model_nr, wlp_dev_model_nr_store, wlp);
301i1480u_ATTR(wlp_dev_model_nr, S_IRUGO | S_IWUSR);
302
303i1480u_SHOW(wlp_dev_serial, wlp_dev_serial_show, wlp);
304i1480u_STORE(wlp_dev_serial, wlp_dev_serial_store, wlp);
305i1480u_ATTR(wlp_dev_serial, S_IRUGO | S_IWUSR);
306
307i1480u_SHOW(wlp_dev_prim_category, wlp_dev_prim_category_show, wlp);
308i1480u_STORE(wlp_dev_prim_category, wlp_dev_prim_category_store, wlp);
309i1480u_ATTR(wlp_dev_prim_category, S_IRUGO | S_IWUSR);
310
311i1480u_SHOW(wlp_dev_prim_OUI, wlp_dev_prim_OUI_show, wlp);
312i1480u_STORE(wlp_dev_prim_OUI, wlp_dev_prim_OUI_store, wlp);
313i1480u_ATTR(wlp_dev_prim_OUI, S_IRUGO | S_IWUSR);
314
315i1480u_SHOW(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_show, wlp);
316i1480u_STORE(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_store, wlp);
317i1480u_ATTR(wlp_dev_prim_OUI_sub, S_IRUGO | S_IWUSR);
318
319i1480u_SHOW(wlp_dev_prim_subcat, wlp_dev_prim_subcat_show, wlp);
320i1480u_STORE(wlp_dev_prim_subcat, wlp_dev_prim_subcat_store, wlp);
321i1480u_ATTR(wlp_dev_prim_subcat, S_IRUGO | S_IWUSR);
322
323i1480u_SHOW(wlp_neighborhood, wlp_neighborhood_show, wlp);
324i1480u_ATTR_SHOW(wlp_neighborhood);
325
326i1480u_SHOW(wss_activate, wlp_wss_activate_show, wlp.wss);
327i1480u_STORE(wss_activate, wlp_wss_activate_store, wlp.wss);
328i1480u_ATTR(wss_activate, S_IRUGO | S_IWUSR);
329
330/*
331 * Show the (min, max, avg) Line Quality Estimate (LQE, in dB) as over
332 * the last 256 received WLP frames (ECMA-368 13.3).
333 *
334 * [the -7dB that have to be substracted from the LQI to make the LQE
335 * are already taken into account].
336 */
337i1480u_SHOW(wlp_lqe, stats_show, lqe_stats);
338i1480u_STORE(wlp_lqe, stats_store, lqe_stats);
339i1480u_ATTR(wlp_lqe, S_IRUGO | S_IWUSR);
340
341/*
342 * Show the Receive Signal Strength Indicator averaged over all the
343 * received WLP frames (ECMA-368 13.3). Still is not clear what
344 * this value is, but is kind of a percentage of the signal strength
345 * at the antenna.
346 */
347i1480u_SHOW(wlp_rssi, stats_show, rssi_stats);
348i1480u_STORE(wlp_rssi, stats_store, rssi_stats);
349i1480u_ATTR(wlp_rssi, S_IRUGO | S_IWUSR);
350
351/**
352 * We maintain a basic flow control counter. "count" how many TX URBs are
353 * outstanding. Only allow "max"
354 * TX URBs to be outstanding. If this value is reached the queue will be
355 * stopped. The queue will be restarted when there are
356 * "threshold" URBs outstanding.
357 */
358i1480u_SHOW(wlp_tx_inflight, wlp_tx_inflight_show, tx_inflight);
359i1480u_STORE(wlp_tx_inflight, wlp_tx_inflight_store, tx_inflight);
360i1480u_ATTR(wlp_tx_inflight, S_IRUGO | S_IWUSR);
361
362static struct attribute *i1480u_attrs[] = {
363 &i1480u_ATTR_NAME(uwb_phy_rate).attr,
364 &i1480u_ATTR_NAME(uwb_rts_cts).attr,
365 &i1480u_ATTR_NAME(uwb_ack_policy).attr,
366 &i1480u_ATTR_NAME(uwb_pca_base_priority).attr,
367 &i1480u_ATTR_NAME(wlp_lqe).attr,
368 &i1480u_ATTR_NAME(wlp_rssi).attr,
369 &i1480u_ATTR_NAME(wlp_eda).attr,
370 &i1480u_ATTR_NAME(wlp_uuid).attr,
371 &i1480u_ATTR_NAME(wlp_dev_name).attr,
372 &i1480u_ATTR_NAME(wlp_dev_manufacturer).attr,
373 &i1480u_ATTR_NAME(wlp_dev_model_name).attr,
374 &i1480u_ATTR_NAME(wlp_dev_model_nr).attr,
375 &i1480u_ATTR_NAME(wlp_dev_serial).attr,
376 &i1480u_ATTR_NAME(wlp_dev_prim_category).attr,
377 &i1480u_ATTR_NAME(wlp_dev_prim_OUI).attr,
378 &i1480u_ATTR_NAME(wlp_dev_prim_OUI_sub).attr,
379 &i1480u_ATTR_NAME(wlp_dev_prim_subcat).attr,
380 &i1480u_ATTR_NAME(wlp_neighborhood).attr,
381 &i1480u_ATTR_NAME(wss_activate).attr,
382 &i1480u_ATTR_NAME(wlp_tx_inflight).attr,
383 NULL,
384};
385
386static struct attribute_group i1480u_attr_group = {
387 .name = NULL, /* we want them in the same directory */
388 .attrs = i1480u_attrs,
389};
390
391int i1480u_sysfs_setup(struct i1480u *i1480u)
392{
393 int result;
394 struct device *dev = &i1480u->usb_iface->dev;
395 result = sysfs_create_group(&i1480u->net_dev->dev.kobj,
396 &i1480u_attr_group);
397 if (result < 0)
398 dev_err(dev, "cannot initialize sysfs attributes: %d\n",
399 result);
400 return result;
401}
402
403
404void i1480u_sysfs_release(struct i1480u *i1480u)
405{
406 sysfs_remove_group(&i1480u->net_dev->dev.kobj,
407 &i1480u_attr_group);
408}