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