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