uwb: add basic radio manager
[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 = 0;
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         case UWB_DBG_CMD_RADIO_START:
217                 ret = uwb_radio_start(&rc->dbg->pal);
218                 break;
219         case UWB_DBG_CMD_RADIO_STOP:
220                 uwb_radio_stop(&rc->dbg->pal);
221                 break;
222         default:
223                 return -EINVAL;
224         }
225
226         return ret < 0 ? ret : len;
227 }
228
229 static struct file_operations command_fops = {
230         .open   = command_open,
231         .write  = command_write,
232         .read   = NULL,
233         .llseek = no_llseek,
234         .owner  = THIS_MODULE,
235 };
236
237 static int reservations_print(struct seq_file *s, void *p)
238 {
239         struct uwb_rc *rc = s->private;
240         struct uwb_rsv *rsv;
241
242         mutex_lock(&rc->rsvs_mutex);
243
244         list_for_each_entry(rsv, &rc->reservations, rc_node) {
245                 struct uwb_dev_addr devaddr;
246                 char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
247                 bool is_owner;
248                 char buf[72];
249
250                 uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
251                 if (rsv->target.type == UWB_RSV_TARGET_DEV) {
252                         devaddr = rsv->target.dev->dev_addr;
253                         is_owner = &rc->uwb_dev == rsv->owner;
254                 } else {
255                         devaddr = rsv->target.devaddr;
256                         is_owner = true;
257                 }
258                 uwb_dev_addr_print(target, sizeof(target), &devaddr);
259
260                 seq_printf(s, "%c %s -> %s: %s\n",
261                            is_owner ? 'O' : 'T',
262                            owner, target, uwb_rsv_state_str(rsv->state));
263                 seq_printf(s, "  stream: %d  type: %s\n",
264                            rsv->stream, uwb_rsv_type_str(rsv->type));
265                 bitmap_scnprintf(buf, sizeof(buf), rsv->mas.bm, UWB_NUM_MAS);
266                 seq_printf(s, "  %s\n", buf);
267         }
268
269         mutex_unlock(&rc->rsvs_mutex);
270
271         return 0;
272 }
273
274 static int reservations_open(struct inode *inode, struct file *file)
275 {
276         return single_open(file, reservations_print, inode->i_private);
277 }
278
279 static struct file_operations reservations_fops = {
280         .open    = reservations_open,
281         .read    = seq_read,
282         .llseek  = seq_lseek,
283         .release = single_release,
284         .owner   = THIS_MODULE,
285 };
286
287 static int drp_avail_print(struct seq_file *s, void *p)
288 {
289         struct uwb_rc *rc = s->private;
290         char buf[72];
291
292         bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.global, UWB_NUM_MAS);
293         seq_printf(s, "global:  %s\n", buf);
294         bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.local, UWB_NUM_MAS);
295         seq_printf(s, "local:   %s\n", buf);
296         bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.pending, UWB_NUM_MAS);
297         seq_printf(s, "pending: %s\n", buf);
298
299         return 0;
300 }
301
302 static int drp_avail_open(struct inode *inode, struct file *file)
303 {
304         return single_open(file, drp_avail_print, inode->i_private);
305 }
306
307 static struct file_operations drp_avail_fops = {
308         .open    = drp_avail_open,
309         .read    = seq_read,
310         .llseek  = seq_lseek,
311         .release = single_release,
312         .owner   = THIS_MODULE,
313 };
314
315 static void uwb_dbg_channel_changed(struct uwb_pal *pal, int channel)
316 {
317         struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal);
318         struct device *dev = &pal->rc->uwb_dev.dev;
319
320         if (channel > 0)
321                 dev_info(dev, "debug: channel %d started\n", channel);
322         else
323                 dev_info(dev, "debug: channel stopped\n");
324 }
325
326 static void uwb_dbg_new_rsv(struct uwb_pal *pal, struct uwb_rsv *rsv)
327 {
328         struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal);
329
330         if (dbg->accept) {
331                 list_add_tail(&rsv->pal_node, &dbg->rsvs);
332                 uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, dbg);
333         }
334 }
335
336 /**
337  * uwb_dbg_add_rc - add a debug interface for a radio controller
338  * @rc: the radio controller
339  */
340 void uwb_dbg_add_rc(struct uwb_rc *rc)
341 {
342         rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL);
343         if (rc->dbg == NULL)
344                 return;
345
346         INIT_LIST_HEAD(&rc->dbg->rsvs);
347
348         uwb_pal_init(&rc->dbg->pal);
349         rc->dbg->pal.rc = rc;
350         rc->dbg->pal.channel_changed = uwb_dbg_channel_changed;
351         rc->dbg->pal.new_rsv = uwb_dbg_new_rsv;
352         uwb_pal_register(&rc->dbg->pal);
353
354         if (root_dir) {
355                 rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev),
356                                                      root_dir);
357                 rc->dbg->command_f = debugfs_create_file("command", 0200,
358                                                          rc->dbg->root_d, rc,
359                                                          &command_fops);
360                 rc->dbg->reservations_f = debugfs_create_file("reservations", 0444,
361                                                               rc->dbg->root_d, rc,
362                                                               &reservations_fops);
363                 rc->dbg->accept_f = debugfs_create_bool("accept", 0644,
364                                                         rc->dbg->root_d,
365                                                         &rc->dbg->accept);
366                 rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444,
367                                                            rc->dbg->root_d, rc,
368                                                            &drp_avail_fops);
369         }
370 }
371
372 /**
373  * uwb_dbg_del_rc - remove a radio controller's debug interface
374  * @rc: the radio controller
375  */
376 void uwb_dbg_del_rc(struct uwb_rc *rc)
377 {
378         struct uwb_rsv *rsv, *t;
379
380         if (rc->dbg == NULL)
381                 return;
382
383         list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) {
384                 uwb_rsv_terminate(rsv);
385         }
386
387         uwb_pal_unregister(&rc->dbg->pal);
388
389         if (root_dir) {
390                 debugfs_remove(rc->dbg->drp_avail_f);
391                 debugfs_remove(rc->dbg->accept_f);
392                 debugfs_remove(rc->dbg->reservations_f);
393                 debugfs_remove(rc->dbg->command_f);
394                 debugfs_remove(rc->dbg->root_d);
395         }
396 }
397
398 /**
399  * uwb_dbg_exit - initialize the debug interface sub-module
400  */
401 void uwb_dbg_init(void)
402 {
403         root_dir = debugfs_create_dir("uwb", NULL);
404 }
405
406 /**
407  * uwb_dbg_exit - clean-up the debug interface sub-module
408  */
409 void uwb_dbg_exit(void)
410 {
411         debugfs_remove(root_dir);
412 }