uwb: reference count reservations
[linux-2.6.git] / 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 command_open(struct inode *inode, struct file *file)
172 {
173         file->private_data = inode->i_private;
174
175         return 0;
176 }
177
178 static ssize_t command_write(struct file *file, const char __user *buf,
179                          size_t len, loff_t *off)
180 {
181         struct uwb_rc *rc = file->private_data;
182         struct uwb_dbg_cmd cmd;
183         int ret;
184
185         if (len != sizeof(struct uwb_dbg_cmd))
186                 return -EINVAL;
187
188         if (copy_from_user(&cmd, buf, len) != 0)
189                 return -EFAULT;
190
191         switch (cmd.type) {
192         case UWB_DBG_CMD_RSV_ESTABLISH:
193                 ret = cmd_rsv_establish(rc, &cmd.rsv_establish);
194                 break;
195         case UWB_DBG_CMD_RSV_TERMINATE:
196                 ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate);
197                 break;
198         default:
199                 return -EINVAL;
200         }
201
202         return ret < 0 ? ret : len;
203 }
204
205 static struct file_operations command_fops = {
206         .open   = command_open,
207         .write  = command_write,
208         .read   = NULL,
209         .llseek = no_llseek,
210         .owner  = THIS_MODULE,
211 };
212
213 static int reservations_print(struct seq_file *s, void *p)
214 {
215         struct uwb_rc *rc = s->private;
216         struct uwb_rsv *rsv;
217
218         mutex_lock(&rc->rsvs_mutex);
219
220         list_for_each_entry(rsv, &rc->reservations, rc_node) {
221                 struct uwb_dev_addr devaddr;
222                 char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
223                 bool is_owner;
224                 char buf[72];
225
226                 uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
227                 if (rsv->target.type == UWB_RSV_TARGET_DEV) {
228                         devaddr = rsv->target.dev->dev_addr;
229                         is_owner = &rc->uwb_dev == rsv->owner;
230                 } else {
231                         devaddr = rsv->target.devaddr;
232                         is_owner = true;
233                 }
234                 uwb_dev_addr_print(target, sizeof(target), &devaddr);
235
236                 seq_printf(s, "%c %s -> %s: %s\n",
237                            is_owner ? 'O' : 'T',
238                            owner, target, uwb_rsv_state_str(rsv->state));
239                 seq_printf(s, "  stream: %d  type: %s\n",
240                            rsv->stream, uwb_rsv_type_str(rsv->type));
241                 bitmap_scnprintf(buf, sizeof(buf), rsv->mas.bm, UWB_NUM_MAS);
242                 seq_printf(s, "  %s\n", buf);
243         }
244
245         mutex_unlock(&rc->rsvs_mutex);
246
247         return 0;
248 }
249
250 static int reservations_open(struct inode *inode, struct file *file)
251 {
252         return single_open(file, reservations_print, inode->i_private);
253 }
254
255 static struct file_operations reservations_fops = {
256         .open    = reservations_open,
257         .read    = seq_read,
258         .llseek  = seq_lseek,
259         .release = single_release,
260         .owner   = THIS_MODULE,
261 };
262
263 static int drp_avail_print(struct seq_file *s, void *p)
264 {
265         struct uwb_rc *rc = s->private;
266         char buf[72];
267
268         bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.global, UWB_NUM_MAS);
269         seq_printf(s, "global:  %s\n", buf);
270         bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.local, UWB_NUM_MAS);
271         seq_printf(s, "local:   %s\n", buf);
272         bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.pending, UWB_NUM_MAS);
273         seq_printf(s, "pending: %s\n", buf);
274
275         return 0;
276 }
277
278 static int drp_avail_open(struct inode *inode, struct file *file)
279 {
280         return single_open(file, drp_avail_print, inode->i_private);
281 }
282
283 static struct file_operations drp_avail_fops = {
284         .open    = drp_avail_open,
285         .read    = seq_read,
286         .llseek  = seq_lseek,
287         .release = single_release,
288         .owner   = THIS_MODULE,
289 };
290
291 static void uwb_dbg_new_rsv(struct uwb_rsv *rsv)
292 {
293         struct uwb_rc *rc = rsv->rc;
294
295         if (rc->dbg->accept) {
296                 list_add_tail(&rsv->pal_node, &rc->dbg->rsvs);
297                 uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, NULL);
298         }
299 }
300
301 /**
302  * uwb_dbg_add_rc - add a debug interface for a radio controller
303  * @rc: the radio controller
304  */
305 void uwb_dbg_add_rc(struct uwb_rc *rc)
306 {
307         rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL);
308         if (rc->dbg == NULL)
309                 return;
310
311         INIT_LIST_HEAD(&rc->dbg->rsvs);
312
313         uwb_pal_init(&rc->dbg->pal);
314         rc->dbg->pal.new_rsv = uwb_dbg_new_rsv;
315         uwb_pal_register(rc, &rc->dbg->pal);
316         if (root_dir) {
317                 rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev),
318                                                      root_dir);
319                 rc->dbg->command_f = debugfs_create_file("command", 0200,
320                                                          rc->dbg->root_d, rc,
321                                                          &command_fops);
322                 rc->dbg->reservations_f = debugfs_create_file("reservations", 0444,
323                                                               rc->dbg->root_d, rc,
324                                                               &reservations_fops);
325                 rc->dbg->accept_f = debugfs_create_bool("accept", 0644,
326                                                         rc->dbg->root_d,
327                                                         &rc->dbg->accept);
328                 rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444,
329                                                            rc->dbg->root_d, rc,
330                                                            &drp_avail_fops);
331         }
332 }
333
334 /**
335  * uwb_dbg_add_rc - remove a radio controller's debug interface
336  * @rc: the radio controller
337  */
338 void uwb_dbg_del_rc(struct uwb_rc *rc)
339 {
340         struct uwb_rsv *rsv, *t;
341
342         if (rc->dbg == NULL)
343                 return;
344
345         list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) {
346                 uwb_rsv_terminate(rsv);
347         }
348
349         uwb_pal_unregister(rc, &rc->dbg->pal);
350
351         if (root_dir) {
352                 debugfs_remove(rc->dbg->drp_avail_f);
353                 debugfs_remove(rc->dbg->accept_f);
354                 debugfs_remove(rc->dbg->reservations_f);
355                 debugfs_remove(rc->dbg->command_f);
356                 debugfs_remove(rc->dbg->root_d);
357         }
358 }
359
360 /**
361  * uwb_dbg_exit - initialize the debug interface sub-module
362  */
363 void uwb_dbg_init(void)
364 {
365         root_dir = debugfs_create_dir("uwb", NULL);
366 }
367
368 /**
369  * uwb_dbg_exit - clean-up the debug interface sub-module
370  */
371 void uwb_dbg_exit(void)
372 {
373         debugfs_remove(root_dir);
374 }