5 * Copyright (C) 2005-2006 Intel Corporation
6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
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.
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.
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
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>
35 #include <linux/uwb/debug-cmd.h>
37 #include "uwb-internal.h"
39 void dump_bytes(struct device *dev, const void *_buf, size_t rsize)
41 const char *buf = _buf;
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);
52 dev_info(dev, "%s\n", line);
54 printk(KERN_INFO "%s\n", line);
57 EXPORT_SYMBOL_GPL(dump_bytes);
62 * Per radio controller debugfs files (in uwb/uwbN/):
64 * command: Flexible command interface (see <linux/uwb/debug-cmd.h>).
66 * reservations: information on reservations.
68 * accept: Set to true (Y or 1) to accept reservation requests from
71 * drp_avail: DRP availability information.
78 struct list_head rsvs;
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;
88 static struct dentry *root_dir;
90 static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv)
92 struct uwb_dbg *dbg = rsv->pal_priv;
94 uwb_rsv_dump("debug", rsv);
96 if (rsv->state == UWB_RSV_STATE_NONE) {
97 spin_lock(&dbg->list_lock);
98 list_del(&rsv->pal_node);
99 spin_unlock(&dbg->list_lock);
100 uwb_rsv_destroy(rsv);
104 static int cmd_rsv_establish(struct uwb_rc *rc,
105 struct uwb_dbg_cmd_rsv_establish *cmd)
107 struct uwb_mac_addr macaddr;
109 struct uwb_dev *target;
112 memcpy(&macaddr, cmd->target, sizeof(macaddr));
113 target = uwb_dev_get_by_macaddr(rc, &macaddr);
117 rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, rc->dbg);
123 rsv->target.type = UWB_RSV_TARGET_DEV;
124 rsv->target.dev = target;
125 rsv->type = cmd->type;
126 rsv->max_mas = cmd->max_mas;
127 rsv->min_mas = cmd->min_mas;
128 rsv->max_interval = cmd->max_interval;
130 ret = uwb_rsv_establish(rsv);
132 uwb_rsv_destroy(rsv);
134 spin_lock(&(rc->dbg)->list_lock);
135 list_add_tail(&rsv->pal_node, &rc->dbg->rsvs);
136 spin_unlock(&(rc->dbg)->list_lock);
141 static int cmd_rsv_terminate(struct uwb_rc *rc,
142 struct uwb_dbg_cmd_rsv_terminate *cmd)
144 struct uwb_rsv *rsv, *found = NULL;
147 spin_lock(&(rc->dbg)->list_lock);
149 list_for_each_entry(rsv, &rc->dbg->rsvs, pal_node) {
150 if (i == cmd->index) {
158 spin_unlock(&(rc->dbg)->list_lock);
163 uwb_rsv_terminate(found);
169 static int cmd_ie_add(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_add)
171 return uwb_rc_ie_add(rc,
172 (const struct uwb_ie_hdr *) ie_to_add->data,
176 static int cmd_ie_rm(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_rm)
178 return uwb_rc_ie_rm(rc, ie_to_rm->data[0]);
181 static int command_open(struct inode *inode, struct file *file)
183 file->private_data = inode->i_private;
188 static ssize_t command_write(struct file *file, const char __user *buf,
189 size_t len, loff_t *off)
191 struct uwb_rc *rc = file->private_data;
192 struct uwb_dbg_cmd cmd;
195 if (len != sizeof(struct uwb_dbg_cmd))
198 if (copy_from_user(&cmd, buf, len) != 0)
202 case UWB_DBG_CMD_RSV_ESTABLISH:
203 ret = cmd_rsv_establish(rc, &cmd.rsv_establish);
205 case UWB_DBG_CMD_RSV_TERMINATE:
206 ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate);
208 case UWB_DBG_CMD_IE_ADD:
209 ret = cmd_ie_add(rc, &cmd.ie_add);
211 case UWB_DBG_CMD_IE_RM:
212 ret = cmd_ie_rm(rc, &cmd.ie_rm);
214 case UWB_DBG_CMD_RADIO_START:
215 ret = uwb_radio_start(&rc->dbg->pal);
217 case UWB_DBG_CMD_RADIO_STOP:
218 uwb_radio_stop(&rc->dbg->pal);
224 return ret < 0 ? ret : len;
227 static struct file_operations command_fops = {
228 .open = command_open,
229 .write = command_write,
232 .owner = THIS_MODULE,
235 static int reservations_print(struct seq_file *s, void *p)
237 struct uwb_rc *rc = s->private;
240 mutex_lock(&rc->rsvs_mutex);
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];
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;
253 devaddr = rsv->target.devaddr;
256 uwb_dev_addr_print(target, sizeof(target), &devaddr);
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);
267 mutex_unlock(&rc->rsvs_mutex);
272 static int reservations_open(struct inode *inode, struct file *file)
274 return single_open(file, reservations_print, inode->i_private);
277 static struct file_operations reservations_fops = {
278 .open = reservations_open,
281 .release = single_release,
282 .owner = THIS_MODULE,
285 static int drp_avail_print(struct seq_file *s, void *p)
287 struct uwb_rc *rc = s->private;
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);
300 static int drp_avail_open(struct inode *inode, struct file *file)
302 return single_open(file, drp_avail_print, inode->i_private);
305 static struct file_operations drp_avail_fops = {
306 .open = drp_avail_open,
309 .release = single_release,
310 .owner = THIS_MODULE,
313 static void uwb_dbg_channel_changed(struct uwb_pal *pal, int channel)
315 struct device *dev = &pal->rc->uwb_dev.dev;
318 dev_info(dev, "debug: channel %d started\n", channel);
320 dev_info(dev, "debug: channel stopped\n");
323 static void uwb_dbg_new_rsv(struct uwb_pal *pal, struct uwb_rsv *rsv)
325 struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal);
328 spin_lock(&dbg->list_lock);
329 list_add_tail(&rsv->pal_node, &dbg->rsvs);
330 spin_unlock(&dbg->list_lock);
331 uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, dbg);
336 * uwb_dbg_add_rc - add a debug interface for a radio controller
337 * @rc: the radio controller
339 void uwb_dbg_add_rc(struct uwb_rc *rc)
341 rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL);
345 INIT_LIST_HEAD(&rc->dbg->rsvs);
346 spin_lock_init(&(rc->dbg)->list_lock);
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);
355 rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev),
357 rc->dbg->command_f = debugfs_create_file("command", 0200,
360 rc->dbg->reservations_f = debugfs_create_file("reservations", 0444,
363 rc->dbg->accept_f = debugfs_create_bool("accept", 0644,
366 rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444,
373 * uwb_dbg_del_rc - remove a radio controller's debug interface
374 * @rc: the radio controller
376 void uwb_dbg_del_rc(struct uwb_rc *rc)
378 struct uwb_rsv *rsv, *t;
383 list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) {
384 uwb_rsv_terminate(rsv);
387 uwb_pal_unregister(&rc->dbg->pal);
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);
399 * uwb_dbg_exit - initialize the debug interface sub-module
401 void uwb_dbg_init(void)
403 root_dir = debugfs_create_dir("uwb", NULL);
407 * uwb_dbg_exit - clean-up the debug interface sub-module
409 void uwb_dbg_exit(void)
411 debugfs_remove(root_dir);
415 * uwb_dbg_create_pal_dir - create a debugfs directory for a PAL
418 struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal)
420 struct uwb_rc *rc = pal->rc;
422 if (root_dir && rc->dbg && rc->dbg->root_d && pal->name)
423 return debugfs_create_dir(pal->name, rc->dbg->root_d);