• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/uwb/
1
2
3#include <linux/spinlock.h>
4#include <linux/module.h>
5#include <linux/slab.h>
6#include <linux/notifier.h>
7#include <linux/device.h>
8#include <linux/debugfs.h>
9#include <linux/uaccess.h>
10#include <linux/seq_file.h>
11
12#include <linux/uwb/debug-cmd.h>
13
14#include "uwb-internal.h"
15
16/*
17 * Debug interface
18 *
19 * Per radio controller debugfs files (in uwb/uwbN/):
20 *
21 * command: Flexible command interface (see <linux/uwb/debug-cmd.h>).
22 *
23 * reservations: information on reservations.
24 *
25 * accept: Set to true (Y or 1) to accept reservation requests from
26 * peers.
27 *
28 * drp_avail: DRP availability information.
29 */
30
31struct uwb_dbg {
32	struct uwb_pal pal;
33
34	u32 accept;
35	struct list_head rsvs;
36
37	struct dentry *root_d;
38	struct dentry *command_f;
39	struct dentry *reservations_f;
40	struct dentry *accept_f;
41	struct dentry *drp_avail_f;
42	spinlock_t list_lock;
43};
44
45static struct dentry *root_dir;
46
47static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv)
48{
49	struct uwb_dbg *dbg = rsv->pal_priv;
50
51	uwb_rsv_dump("debug", rsv);
52
53	if (rsv->state == UWB_RSV_STATE_NONE) {
54		spin_lock(&dbg->list_lock);
55		list_del(&rsv->pal_node);
56		spin_unlock(&dbg->list_lock);
57		uwb_rsv_destroy(rsv);
58	}
59}
60
61static int cmd_rsv_establish(struct uwb_rc *rc,
62			     struct uwb_dbg_cmd_rsv_establish *cmd)
63{
64	struct uwb_mac_addr macaddr;
65	struct uwb_rsv *rsv;
66	struct uwb_dev *target;
67	int ret;
68
69	memcpy(&macaddr, cmd->target, sizeof(macaddr));
70	target = uwb_dev_get_by_macaddr(rc, &macaddr);
71	if (target == NULL)
72		return -ENODEV;
73
74	rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, rc->dbg);
75	if (rsv == NULL) {
76		uwb_dev_put(target);
77		return -ENOMEM;
78	}
79
80	rsv->target.type  = UWB_RSV_TARGET_DEV;
81	rsv->target.dev   = target;
82	rsv->type         = cmd->type;
83	rsv->max_mas      = cmd->max_mas;
84	rsv->min_mas      = cmd->min_mas;
85	rsv->max_interval = cmd->max_interval;
86
87	ret = uwb_rsv_establish(rsv);
88	if (ret)
89		uwb_rsv_destroy(rsv);
90	else {
91		spin_lock(&(rc->dbg)->list_lock);
92		list_add_tail(&rsv->pal_node, &rc->dbg->rsvs);
93		spin_unlock(&(rc->dbg)->list_lock);
94	}
95	return ret;
96}
97
98static int cmd_rsv_terminate(struct uwb_rc *rc,
99			     struct uwb_dbg_cmd_rsv_terminate *cmd)
100{
101	struct uwb_rsv *rsv, *found = NULL;
102	int i = 0;
103
104	spin_lock(&(rc->dbg)->list_lock);
105
106	list_for_each_entry(rsv, &rc->dbg->rsvs, pal_node) {
107		if (i == cmd->index) {
108			found = rsv;
109			uwb_rsv_get(found);
110			break;
111		}
112		i++;
113	}
114
115	spin_unlock(&(rc->dbg)->list_lock);
116
117	if (!found)
118		return -EINVAL;
119
120	uwb_rsv_terminate(found);
121	uwb_rsv_put(found);
122
123	return 0;
124}
125
126static int cmd_ie_add(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_add)
127{
128	return uwb_rc_ie_add(rc,
129			     (const struct uwb_ie_hdr *) ie_to_add->data,
130			     ie_to_add->len);
131}
132
133static int cmd_ie_rm(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_rm)
134{
135	return uwb_rc_ie_rm(rc, ie_to_rm->data[0]);
136}
137
138static int command_open(struct inode *inode, struct file *file)
139{
140	file->private_data = inode->i_private;
141
142	return 0;
143}
144
145static ssize_t command_write(struct file *file, const char __user *buf,
146			 size_t len, loff_t *off)
147{
148	struct uwb_rc *rc = file->private_data;
149	struct uwb_dbg_cmd cmd;
150	int ret = 0;
151
152	if (len != sizeof(struct uwb_dbg_cmd))
153		return -EINVAL;
154
155	if (copy_from_user(&cmd, buf, len) != 0)
156		return -EFAULT;
157
158	switch (cmd.type) {
159	case UWB_DBG_CMD_RSV_ESTABLISH:
160		ret = cmd_rsv_establish(rc, &cmd.rsv_establish);
161		break;
162	case UWB_DBG_CMD_RSV_TERMINATE:
163		ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate);
164		break;
165	case UWB_DBG_CMD_IE_ADD:
166		ret = cmd_ie_add(rc, &cmd.ie_add);
167		break;
168	case UWB_DBG_CMD_IE_RM:
169		ret = cmd_ie_rm(rc, &cmd.ie_rm);
170		break;
171	case UWB_DBG_CMD_RADIO_START:
172		ret = uwb_radio_start(&rc->dbg->pal);
173		break;
174	case UWB_DBG_CMD_RADIO_STOP:
175		uwb_radio_stop(&rc->dbg->pal);
176		break;
177	default:
178		return -EINVAL;
179	}
180
181	return ret < 0 ? ret : len;
182}
183
184static const struct file_operations command_fops = {
185	.open   = command_open,
186	.write  = command_write,
187	.read   = NULL,
188	.llseek = no_llseek,
189	.owner  = THIS_MODULE,
190};
191
192static int reservations_print(struct seq_file *s, void *p)
193{
194	struct uwb_rc *rc = s->private;
195	struct uwb_rsv *rsv;
196
197	mutex_lock(&rc->rsvs_mutex);
198
199	list_for_each_entry(rsv, &rc->reservations, rc_node) {
200		struct uwb_dev_addr devaddr;
201		char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
202		bool is_owner;
203		char buf[72];
204
205		uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
206		if (rsv->target.type == UWB_RSV_TARGET_DEV) {
207			devaddr = rsv->target.dev->dev_addr;
208			is_owner = &rc->uwb_dev == rsv->owner;
209		} else {
210			devaddr = rsv->target.devaddr;
211			is_owner = true;
212		}
213		uwb_dev_addr_print(target, sizeof(target), &devaddr);
214
215		seq_printf(s, "%c %s -> %s: %s\n",
216			   is_owner ? 'O' : 'T',
217			   owner, target, uwb_rsv_state_str(rsv->state));
218		seq_printf(s, "  stream: %d  type: %s\n",
219			   rsv->stream, uwb_rsv_type_str(rsv->type));
220		bitmap_scnprintf(buf, sizeof(buf), rsv->mas.bm, UWB_NUM_MAS);
221		seq_printf(s, "  %s\n", buf);
222	}
223
224	mutex_unlock(&rc->rsvs_mutex);
225
226	return 0;
227}
228
229static int reservations_open(struct inode *inode, struct file *file)
230{
231	return single_open(file, reservations_print, inode->i_private);
232}
233
234static const struct file_operations reservations_fops = {
235	.open    = reservations_open,
236	.read    = seq_read,
237	.llseek  = seq_lseek,
238	.release = single_release,
239	.owner   = THIS_MODULE,
240};
241
242static int drp_avail_print(struct seq_file *s, void *p)
243{
244	struct uwb_rc *rc = s->private;
245	char buf[72];
246
247	bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.global, UWB_NUM_MAS);
248	seq_printf(s, "global:  %s\n", buf);
249	bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.local, UWB_NUM_MAS);
250	seq_printf(s, "local:   %s\n", buf);
251	bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.pending, UWB_NUM_MAS);
252	seq_printf(s, "pending: %s\n", buf);
253
254	return 0;
255}
256
257static int drp_avail_open(struct inode *inode, struct file *file)
258{
259	return single_open(file, drp_avail_print, inode->i_private);
260}
261
262static const struct file_operations drp_avail_fops = {
263	.open    = drp_avail_open,
264	.read    = seq_read,
265	.llseek  = seq_lseek,
266	.release = single_release,
267	.owner   = THIS_MODULE,
268};
269
270static void uwb_dbg_channel_changed(struct uwb_pal *pal, int channel)
271{
272	struct device *dev = &pal->rc->uwb_dev.dev;
273
274	if (channel > 0)
275		dev_info(dev, "debug: channel %d started\n", channel);
276	else
277		dev_info(dev, "debug: channel stopped\n");
278}
279
280static void uwb_dbg_new_rsv(struct uwb_pal *pal, struct uwb_rsv *rsv)
281{
282	struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal);
283
284	if (dbg->accept) {
285		spin_lock(&dbg->list_lock);
286		list_add_tail(&rsv->pal_node, &dbg->rsvs);
287		spin_unlock(&dbg->list_lock);
288		uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, dbg);
289	}
290}
291
292/**
293 * uwb_dbg_add_rc - add a debug interface for a radio controller
294 * @rc: the radio controller
295 */
296void uwb_dbg_add_rc(struct uwb_rc *rc)
297{
298	rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL);
299	if (rc->dbg == NULL)
300		return;
301
302	INIT_LIST_HEAD(&rc->dbg->rsvs);
303	spin_lock_init(&(rc->dbg)->list_lock);
304
305	uwb_pal_init(&rc->dbg->pal);
306	rc->dbg->pal.rc = rc;
307	rc->dbg->pal.channel_changed = uwb_dbg_channel_changed;
308	rc->dbg->pal.new_rsv = uwb_dbg_new_rsv;
309	uwb_pal_register(&rc->dbg->pal);
310
311	if (root_dir) {
312		rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev),
313						     root_dir);
314		rc->dbg->command_f = debugfs_create_file("command", 0200,
315							 rc->dbg->root_d, rc,
316							 &command_fops);
317		rc->dbg->reservations_f = debugfs_create_file("reservations", 0444,
318							      rc->dbg->root_d, rc,
319							      &reservations_fops);
320		rc->dbg->accept_f = debugfs_create_bool("accept", 0644,
321							rc->dbg->root_d,
322							&rc->dbg->accept);
323		rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444,
324							   rc->dbg->root_d, rc,
325							   &drp_avail_fops);
326	}
327}
328
329/**
330 * uwb_dbg_del_rc - remove a radio controller's debug interface
331 * @rc: the radio controller
332 */
333void uwb_dbg_del_rc(struct uwb_rc *rc)
334{
335	struct uwb_rsv *rsv, *t;
336
337	if (rc->dbg == NULL)
338		return;
339
340	list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) {
341		uwb_rsv_terminate(rsv);
342	}
343
344	uwb_pal_unregister(&rc->dbg->pal);
345
346	if (root_dir) {
347		debugfs_remove(rc->dbg->drp_avail_f);
348		debugfs_remove(rc->dbg->accept_f);
349		debugfs_remove(rc->dbg->reservations_f);
350		debugfs_remove(rc->dbg->command_f);
351		debugfs_remove(rc->dbg->root_d);
352	}
353}
354
355/**
356 * uwb_dbg_exit - initialize the debug interface sub-module
357 */
358void uwb_dbg_init(void)
359{
360	root_dir = debugfs_create_dir("uwb", NULL);
361}
362
363/**
364 * uwb_dbg_exit - clean-up the debug interface sub-module
365 */
366void uwb_dbg_exit(void)
367{
368	debugfs_remove(root_dir);
369}
370
371/**
372 * uwb_dbg_create_pal_dir - create a debugfs directory for a PAL
373 * @pal: The PAL.
374 */
375struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal)
376{
377	struct uwb_rc *rc = pal->rc;
378
379	if (root_dir && rc->dbg && rc->dbg->root_d && pal->name)
380		return debugfs_create_dir(pal->name, rc->dbg->root_d);
381	return NULL;
382}
383