uwb: add the UWB stack (debug support)
[pandora-kernel.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
109 static int cmd_rsv_establish(struct uwb_rc *rc,
110                              struct uwb_dbg_cmd_rsv_establish *cmd)
111 {
112         struct uwb_mac_addr macaddr;
113         struct uwb_rsv *rsv;
114         struct uwb_dev *target;
115         int ret;
116
117         memcpy(&macaddr, cmd->target, sizeof(macaddr));
118         target = uwb_dev_get_by_macaddr(rc, &macaddr);
119         if (target == NULL)
120                 return -ENODEV;
121
122         rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, NULL);
123         if (rsv == NULL) {
124                 uwb_dev_put(target);
125                 return -ENOMEM;
126         }
127
128         rsv->owner       = &rc->uwb_dev;
129         rsv->target.type = UWB_RSV_TARGET_DEV;
130         rsv->target.dev  = target;
131         rsv->type        = cmd->type;
132         rsv->max_mas     = cmd->max_mas;
133         rsv->min_mas     = cmd->min_mas;
134         rsv->sparsity    = cmd->sparsity;
135
136         ret = uwb_rsv_establish(rsv);
137         if (ret)
138                 uwb_rsv_destroy(rsv);
139         else
140                 list_add_tail(&rsv->pal_node, &rc->dbg->rsvs);
141
142         return ret;
143 }
144
145 static int cmd_rsv_terminate(struct uwb_rc *rc,
146                              struct uwb_dbg_cmd_rsv_terminate *cmd)
147 {
148         struct uwb_rsv *rsv, *found = NULL;
149         int i = 0;
150
151         list_for_each_entry(rsv, &rc->dbg->rsvs, pal_node) {
152                 if (i == cmd->index) {
153                         found = rsv;
154                         break;
155                 }
156         }
157         if (!found)
158                 return -EINVAL;
159
160         list_del(&found->pal_node);
161         uwb_rsv_terminate(found);
162
163         return 0;
164 }
165
166 static int command_open(struct inode *inode, struct file *file)
167 {
168         file->private_data = inode->i_private;
169
170         return 0;
171 }
172
173 static ssize_t command_write(struct file *file, const char __user *buf,
174                          size_t len, loff_t *off)
175 {
176         struct uwb_rc *rc = file->private_data;
177         struct uwb_dbg_cmd cmd;
178         int ret;
179
180         if (len != sizeof(struct uwb_dbg_cmd))
181                 return -EINVAL;
182
183         if (copy_from_user(&cmd, buf, len) != 0)
184                 return -EFAULT;
185
186         switch (cmd.type) {
187         case UWB_DBG_CMD_RSV_ESTABLISH:
188                 ret = cmd_rsv_establish(rc, &cmd.rsv_establish);
189                 break;
190         case UWB_DBG_CMD_RSV_TERMINATE:
191                 ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate);
192                 break;
193         default:
194                 return -EINVAL;
195         }
196
197         return ret < 0 ? ret : len;
198 }
199
200 static struct file_operations command_fops = {
201         .open   = command_open,
202         .write  = command_write,
203         .read   = NULL,
204         .llseek = no_llseek,
205         .owner  = THIS_MODULE,
206 };
207
208 static int reservations_print(struct seq_file *s, void *p)
209 {
210         struct uwb_rc *rc = s->private;
211         struct uwb_rsv *rsv;
212
213         mutex_lock(&rc->rsvs_mutex);
214
215         list_for_each_entry(rsv, &rc->reservations, rc_node) {
216                 struct uwb_dev_addr devaddr;
217                 char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
218                 bool is_owner;
219                 char buf[72];
220
221                 uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
222                 if (rsv->target.type == UWB_RSV_TARGET_DEV) {
223                         devaddr = rsv->target.dev->dev_addr;
224                         is_owner = &rc->uwb_dev == rsv->owner;
225                 } else {
226                         devaddr = rsv->target.devaddr;
227                         is_owner = true;
228                 }
229                 uwb_dev_addr_print(target, sizeof(target), &devaddr);
230
231                 seq_printf(s, "%c %s -> %s: %s\n",
232                            is_owner ? 'O' : 'T',
233                            owner, target, uwb_rsv_state_str(rsv->state));
234                 seq_printf(s, "  stream: %d  type: %s\n",
235                            rsv->stream, uwb_rsv_type_str(rsv->type));
236                 bitmap_scnprintf(buf, sizeof(buf), rsv->mas.bm, UWB_NUM_MAS);
237                 seq_printf(s, "  %s\n", buf);
238         }
239
240         mutex_unlock(&rc->rsvs_mutex);
241
242         return 0;
243 }
244
245 static int reservations_open(struct inode *inode, struct file *file)
246 {
247         return single_open(file, reservations_print, inode->i_private);
248 }
249
250 static struct file_operations reservations_fops = {
251         .open    = reservations_open,
252         .read    = seq_read,
253         .llseek  = seq_lseek,
254         .release = single_release,
255         .owner   = THIS_MODULE,
256 };
257
258 static int drp_avail_print(struct seq_file *s, void *p)
259 {
260         struct uwb_rc *rc = s->private;
261         char buf[72];
262
263         bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.global, UWB_NUM_MAS);
264         seq_printf(s, "global:  %s\n", buf);
265         bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.local, UWB_NUM_MAS);
266         seq_printf(s, "local:   %s\n", buf);
267         bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.pending, UWB_NUM_MAS);
268         seq_printf(s, "pending: %s\n", buf);
269
270         return 0;
271 }
272
273 static int drp_avail_open(struct inode *inode, struct file *file)
274 {
275         return single_open(file, drp_avail_print, inode->i_private);
276 }
277
278 static struct file_operations drp_avail_fops = {
279         .open    = drp_avail_open,
280         .read    = seq_read,
281         .llseek  = seq_lseek,
282         .release = single_release,
283         .owner   = THIS_MODULE,
284 };
285
286 static void uwb_dbg_new_rsv(struct uwb_rsv *rsv)
287 {
288         struct uwb_rc *rc = rsv->rc;
289
290         if (rc->dbg->accept)
291                 uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, NULL);
292 }
293
294 /**
295  * uwb_dbg_add_rc - add a debug interface for a radio controller
296  * @rc: the radio controller
297  */
298 void uwb_dbg_add_rc(struct uwb_rc *rc)
299 {
300         rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL);
301         if (rc->dbg == NULL)
302                 return;
303
304         INIT_LIST_HEAD(&rc->dbg->rsvs);
305
306         uwb_pal_init(&rc->dbg->pal);
307         rc->dbg->pal.new_rsv = uwb_dbg_new_rsv;
308         uwb_pal_register(rc, &rc->dbg->pal);
309         if (root_dir) {
310                 rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev),
311                                                      root_dir);
312                 rc->dbg->command_f = debugfs_create_file("command", 0200,
313                                                          rc->dbg->root_d, rc,
314                                                          &command_fops);
315                 rc->dbg->reservations_f = debugfs_create_file("reservations", 0444,
316                                                               rc->dbg->root_d, rc,
317                                                               &reservations_fops);
318                 rc->dbg->accept_f = debugfs_create_bool("accept", 0644,
319                                                         rc->dbg->root_d,
320                                                         &rc->dbg->accept);
321                 rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444,
322                                                            rc->dbg->root_d, rc,
323                                                            &drp_avail_fops);
324         }
325 }
326
327 /**
328  * uwb_dbg_add_rc - remove a radio controller's debug interface
329  * @rc: the radio controller
330  */
331 void uwb_dbg_del_rc(struct uwb_rc *rc)
332 {
333         struct uwb_rsv *rsv, *t;
334
335         if (rc->dbg == NULL)
336                 return;
337
338         list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) {
339                 uwb_rsv_destroy(rsv);
340         }
341
342         uwb_pal_unregister(rc, &rc->dbg->pal);
343
344         if (root_dir) {
345                 debugfs_remove(rc->dbg->drp_avail_f);
346                 debugfs_remove(rc->dbg->accept_f);
347                 debugfs_remove(rc->dbg->reservations_f);
348                 debugfs_remove(rc->dbg->command_f);
349                 debugfs_remove(rc->dbg->root_d);
350         }
351 }
352
353 /**
354  * uwb_dbg_exit - initialize the debug interface sub-module
355  */
356 void uwb_dbg_init(void)
357 {
358         root_dir = debugfs_create_dir("uwb", NULL);
359 }
360
361 /**
362  * uwb_dbg_exit - clean-up the debug interface sub-module
363  */
364 void uwb_dbg_exit(void)
365 {
366         debugfs_remove(root_dir);
367 }