]> nv-tegra.nvidia Code Review - linux-2.6.git/commitdiff
uwb: add the UWB stack (core files)
authorInaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
Wed, 17 Sep 2008 15:34:06 +0000 (16:34 +0100)
committerDavid Vrabel <dv02@dv02pc01.europe.root.pri>
Wed, 17 Sep 2008 15:54:23 +0000 (16:54 +0100)
UWB device and radio controller device and event management.

Signed-off-by: David Vrabel <david.vrabel@csr.com>
drivers/uwb/driver.c [new file with mode: 0644]
drivers/uwb/lc-dev.c [new file with mode: 0644]
drivers/uwb/lc-rc.c [new file with mode: 0644]
drivers/uwb/pal.c [new file with mode: 0644]
drivers/uwb/uwb-internal.h [new file with mode: 0644]
drivers/uwb/uwbd.c [new file with mode: 0644]

diff --git a/drivers/uwb/driver.c b/drivers/uwb/driver.c
new file mode 100644 (file)
index 0000000..7eee8e4
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Ultra Wide Band
+ * Driver initialization, etc
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * FIXME: docs
+ *
+ * Life cycle: FIXME: explain
+ *
+ *  UWB radio controller:
+ *
+ *    1. alloc a uwb_rc, zero it
+ *    2. call uwb_rc_init() on it to set it up + ops (won't do any
+ *       kind of allocation)
+ *    3. register (now it is owned by the UWB stack--deregister before
+ *       freeing/destroying).
+ *    4. It lives on it's own now (UWB stack handles)--when it
+ *       disconnects, call unregister()
+ *    5. free it.
+ *
+ *    Make sure you have a reference to the uwb_rc before calling
+ *    any of the UWB API functions.
+ *
+ * TODO:
+ *
+ * 1. Locking and life cycle management is crappy still. All entry
+ *    points to the UWB HCD API assume you have a reference on the
+ *    uwb_rc structure and that it won't go away. They mutex lock it
+ *    before doing anything.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/random.h>
+#include <linux/uwb/debug.h>
+#include "uwb-internal.h"
+
+
+/* UWB stack attributes (or 'global' constants) */
+
+
+/**
+ * If a beacon dissapears for longer than this, then we consider the
+ * device who was represented by that beacon to be gone.
+ *
+ * ECMA-368[17.2.3, last para] establishes that a device must not
+ * consider a device to be its neighbour if he doesn't receive a beacon
+ * for more than mMaxLostBeacons. mMaxLostBeacons is defined in
+ * ECMA-368[17.16] as 3; because we can get only one beacon per
+ * superframe, that'd be 3 * 65ms = 195 ~ 200 ms. Let's give it time
+ * for jitter and stuff and make it 500 ms.
+ */
+unsigned long beacon_timeout_ms = 500;
+
+static
+ssize_t beacon_timeout_ms_show(struct class *class, char *buf)
+{
+       return scnprintf(buf, PAGE_SIZE, "%lu\n", beacon_timeout_ms);
+}
+
+static
+ssize_t beacon_timeout_ms_store(struct class *class,
+                               const char *buf, size_t size)
+{
+       unsigned long bt;
+       ssize_t result;
+       result = sscanf(buf, "%lu", &bt);
+       if (result != 1)
+               return -EINVAL;
+       beacon_timeout_ms = bt;
+       return size;
+}
+
+static struct class_attribute uwb_class_attrs[] = {
+       __ATTR(beacon_timeout_ms, S_IWUSR | S_IRUGO,
+              beacon_timeout_ms_show, beacon_timeout_ms_store),
+       __ATTR_NULL,
+};
+
+/** Device model classes */
+struct class uwb_rc_class = {
+       .name        = "uwb_rc",
+       .class_attrs = uwb_class_attrs,
+};
+
+
+static int __init uwb_subsys_init(void)
+{
+       int result = 0;
+
+       result = uwb_est_create();
+       if (result < 0) {
+               printk(KERN_ERR "uwb: Can't initialize EST subsystem\n");
+               goto error_est_init;
+       }
+
+       result = class_register(&uwb_rc_class);
+       if (result < 0)
+               goto error_uwb_rc_class_register;
+       uwbd_start();
+       return 0;
+
+error_uwb_rc_class_register:
+       uwb_est_destroy();
+error_est_init:
+       return result;
+}
+module_init(uwb_subsys_init);
+
+static void __exit uwb_subsys_exit(void)
+{
+       uwbd_stop();
+       class_unregister(&uwb_rc_class);
+       uwb_est_destroy();
+       return;
+}
+module_exit(uwb_subsys_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Ultra Wide Band core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/lc-dev.c b/drivers/uwb/lc-dev.c
new file mode 100644 (file)
index 0000000..a6cb8ad
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+ * Ultra Wide Band
+ * Life cycle of devices
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * FIXME: docs
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/random.h>
+#include "uwb-internal.h"
+
+#define D_LOCAL 1
+#include <linux/uwb/debug.h>
+
+
+/* We initialize addresses to 0xff (invalid, as it is bcast) */
+static inline void uwb_dev_addr_init(struct uwb_dev_addr *addr)
+{
+       memset(&addr->data, 0xff, sizeof(addr->data));
+}
+
+static inline void uwb_mac_addr_init(struct uwb_mac_addr *addr)
+{
+       memset(&addr->data, 0xff, sizeof(addr->data));
+}
+
+/* @returns !0 if a device @addr is a broadcast address */
+static inline int uwb_dev_addr_bcast(const struct uwb_dev_addr *addr)
+{
+       static const struct uwb_dev_addr bcast = { .data = { 0xff, 0xff } };
+       return !uwb_dev_addr_cmp(addr, &bcast);
+}
+
+/*
+ * Add callback @new to be called when an event occurs in @rc.
+ */
+int uwb_notifs_register(struct uwb_rc *rc, struct uwb_notifs_handler *new)
+{
+       if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
+               return -ERESTARTSYS;
+       list_add(&new->list_node, &rc->notifs_chain.list);
+       mutex_unlock(&rc->notifs_chain.mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_notifs_register);
+
+/*
+ * Remove event handler (callback)
+ */
+int uwb_notifs_deregister(struct uwb_rc *rc, struct uwb_notifs_handler *entry)
+{
+       if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
+               return -ERESTARTSYS;
+       list_del(&entry->list_node);
+       mutex_unlock(&rc->notifs_chain.mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_notifs_deregister);
+
+/*
+ * Notify all event handlers of a given event on @rc
+ *
+ * We are called with a valid reference to the device, or NULL if the
+ * event is not for a particular event (e.g., a BG join event).
+ */
+void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event)
+{
+       struct uwb_notifs_handler *handler;
+       if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
+               return;
+       if (!list_empty(&rc->notifs_chain.list)) {
+               list_for_each_entry(handler, &rc->notifs_chain.list, list_node) {
+                       handler->cb(handler->data, uwb_dev, event);
+               }
+       }
+       mutex_unlock(&rc->notifs_chain.mutex);
+}
+
+/*
+ * Release the backing device of a uwb_dev that has been dynamically allocated.
+ */
+static void uwb_dev_sys_release(struct device *dev)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+
+       d_fnstart(4, NULL, "(dev %p uwb_dev %p)\n", dev, uwb_dev);
+       uwb_bce_put(uwb_dev->bce);
+       d_printf(0, &uwb_dev->dev, "uwb_dev %p freed\n", uwb_dev);
+       memset(uwb_dev, 0x69, sizeof(*uwb_dev));
+       kfree(uwb_dev);
+       d_fnend(4, NULL, "(dev %p uwb_dev %p) = void\n", dev, uwb_dev);
+}
+
+/*
+ * Initialize a UWB device instance
+ *
+ * Alloc, zero and call this function.
+ */
+void uwb_dev_init(struct uwb_dev *uwb_dev)
+{
+       mutex_init(&uwb_dev->mutex);
+       device_initialize(&uwb_dev->dev);
+       uwb_dev->dev.release = uwb_dev_sys_release;
+       uwb_dev_addr_init(&uwb_dev->dev_addr);
+       uwb_mac_addr_init(&uwb_dev->mac_addr);
+       bitmap_fill(uwb_dev->streams, UWB_NUM_GLOBAL_STREAMS);
+}
+
+static ssize_t uwb_dev_EUI_48_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       char addr[UWB_ADDR_STRSIZE];
+
+       uwb_mac_addr_print(addr, sizeof(addr), &uwb_dev->mac_addr);
+       return sprintf(buf, "%s\n", addr);
+}
+static DEVICE_ATTR(EUI_48, S_IRUGO, uwb_dev_EUI_48_show, NULL);
+
+static ssize_t uwb_dev_DevAddr_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       char addr[UWB_ADDR_STRSIZE];
+
+       uwb_dev_addr_print(addr, sizeof(addr), &uwb_dev->dev_addr);
+       return sprintf(buf, "%s\n", addr);
+}
+static DEVICE_ATTR(DevAddr, S_IRUGO, uwb_dev_DevAddr_show, NULL);
+
+/*
+ * Show the BPST of this device.
+ *
+ * Calculated from the receive time of the device's beacon and it's
+ * slot number.
+ */
+static ssize_t uwb_dev_BPST_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       struct uwb_beca_e *bce;
+       struct uwb_beacon_frame *bf;
+       u16 bpst;
+
+       bce = uwb_dev->bce;
+       mutex_lock(&bce->mutex);
+       bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo;
+       bpst = bce->be->wBPSTOffset
+               - (u16)(bf->Beacon_Slot_Number * UWB_BEACON_SLOT_LENGTH_US);
+       mutex_unlock(&bce->mutex);
+
+       return sprintf(buf, "%d\n", bpst);
+}
+static DEVICE_ATTR(BPST, S_IRUGO, uwb_dev_BPST_show, NULL);
+
+/*
+ * Show the IEs a device is beaconing
+ *
+ * We need to access the beacon cache, so we just lock it really
+ * quick, print the IEs and unlock.
+ *
+ * We have a reference on the cache entry, so that should be
+ * quite safe.
+ */
+static ssize_t uwb_dev_IEs_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+
+       return uwb_bce_print_IEs(uwb_dev, uwb_dev->bce, buf, PAGE_SIZE);
+}
+static DEVICE_ATTR(IEs, S_IRUGO | S_IWUSR, uwb_dev_IEs_show, NULL);
+
+static ssize_t uwb_dev_LQE_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       struct uwb_beca_e *bce = uwb_dev->bce;
+       size_t result;
+
+       mutex_lock(&bce->mutex);
+       result = stats_show(&uwb_dev->bce->lqe_stats, buf);
+       mutex_unlock(&bce->mutex);
+       return result;
+}
+
+static ssize_t uwb_dev_LQE_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t size)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       struct uwb_beca_e *bce = uwb_dev->bce;
+       ssize_t result;
+
+       mutex_lock(&bce->mutex);
+       result = stats_store(&uwb_dev->bce->lqe_stats, buf, size);
+       mutex_unlock(&bce->mutex);
+       return result;
+}
+static DEVICE_ATTR(LQE, S_IRUGO | S_IWUSR, uwb_dev_LQE_show, uwb_dev_LQE_store);
+
+static ssize_t uwb_dev_RSSI_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       struct uwb_beca_e *bce = uwb_dev->bce;
+       size_t result;
+
+       mutex_lock(&bce->mutex);
+       result = stats_show(&uwb_dev->bce->rssi_stats, buf);
+       mutex_unlock(&bce->mutex);
+       return result;
+}
+
+static ssize_t uwb_dev_RSSI_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t size)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       struct uwb_beca_e *bce = uwb_dev->bce;
+       ssize_t result;
+
+       mutex_lock(&bce->mutex);
+       result = stats_store(&uwb_dev->bce->rssi_stats, buf, size);
+       mutex_unlock(&bce->mutex);
+       return result;
+}
+static DEVICE_ATTR(RSSI, S_IRUGO | S_IWUSR, uwb_dev_RSSI_show, uwb_dev_RSSI_store);
+
+
+static struct attribute *dev_attrs[] = {
+       &dev_attr_EUI_48.attr,
+       &dev_attr_DevAddr.attr,
+       &dev_attr_BPST.attr,
+       &dev_attr_IEs.attr,
+       &dev_attr_LQE.attr,
+       &dev_attr_RSSI.attr,
+       NULL,
+};
+
+static struct attribute_group dev_attr_group = {
+       .attrs = dev_attrs,
+};
+
+static struct attribute_group *groups[] = {
+       &dev_attr_group,
+       NULL,
+};
+
+/**
+ * Device SYSFS registration
+ *
+ *
+ */
+static int __uwb_dev_sys_add(struct uwb_dev *uwb_dev, struct device *parent_dev)
+{
+       int result;
+       struct device *dev;
+
+       d_fnstart(4, NULL, "(uwb_dev %p parent_dev %p)\n", uwb_dev, parent_dev);
+       BUG_ON(parent_dev == NULL);
+
+       dev = &uwb_dev->dev;
+       /* Device sysfs files are only useful for neighbor devices not
+          local radio controllers. */
+       if (&uwb_dev->rc->uwb_dev != uwb_dev)
+               dev->groups = groups;
+       dev->parent = parent_dev;
+       dev_set_drvdata(dev, uwb_dev);
+
+       result = device_add(dev);
+       d_fnend(4, NULL, "(uwb_dev %p parent_dev %p) = %d\n", uwb_dev, parent_dev, result);
+       return result;
+}
+
+
+static void __uwb_dev_sys_rm(struct uwb_dev *uwb_dev)
+{
+       d_fnstart(4, NULL, "(uwb_dev %p)\n", uwb_dev);
+       dev_set_drvdata(&uwb_dev->dev, NULL);
+       device_del(&uwb_dev->dev);
+       d_fnend(4, NULL, "(uwb_dev %p) = void\n", uwb_dev);
+}
+
+
+/**
+ * Register and initialize a new UWB device
+ *
+ * Did you call uwb_dev_init() on it?
+ *
+ * @parent_rc: is the parent radio controller who has the link to the
+ *             device. When registering the UWB device that is a UWB
+ *             Radio Controller, we point back to it.
+ *
+ * If registering the device that is part of a radio, caller has set
+ * rc->uwb_dev->dev. Otherwise it is to be left NULL--a new one will
+ * be allocated.
+ */
+int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev,
+               struct uwb_rc *parent_rc)
+{
+       int result;
+       struct device *dev;
+
+       BUG_ON(uwb_dev == NULL);
+       BUG_ON(parent_dev == NULL);
+       BUG_ON(parent_rc == NULL);
+
+       mutex_lock(&uwb_dev->mutex);
+       dev = &uwb_dev->dev;
+       uwb_dev->rc = parent_rc;
+       result = __uwb_dev_sys_add(uwb_dev, parent_dev);
+       if (result < 0)
+               printk(KERN_ERR "UWB: unable to register dev %s with sysfs: %d\n",
+                      dev_name(dev), result);
+       mutex_unlock(&uwb_dev->mutex);
+       return result;
+}
+
+
+void uwb_dev_rm(struct uwb_dev *uwb_dev)
+{
+       mutex_lock(&uwb_dev->mutex);
+       __uwb_dev_sys_rm(uwb_dev);
+       mutex_unlock(&uwb_dev->mutex);
+}
+
+
+static
+int __uwb_dev_try_get(struct device *dev, void *__target_uwb_dev)
+{
+       struct uwb_dev *target_uwb_dev = __target_uwb_dev;
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       if (uwb_dev == target_uwb_dev) {
+               uwb_dev_get(uwb_dev);
+               return 1;
+       } else
+               return 0;
+}
+
+
+/**
+ * Given a UWB device descriptor, validate and refcount it
+ *
+ * @returns NULL if the device does not exist or is quiescing; the ptr to
+ *               it otherwise.
+ */
+struct uwb_dev *uwb_dev_try_get(struct uwb_rc *rc, struct uwb_dev *uwb_dev)
+{
+       if (uwb_dev_for_each(rc, __uwb_dev_try_get, uwb_dev))
+               return uwb_dev;
+       else
+               return NULL;
+}
+EXPORT_SYMBOL_GPL(uwb_dev_try_get);
+
+
+/**
+ * Remove a device from the system [grunt for other functions]
+ */
+int __uwb_dev_offair(struct uwb_dev *uwb_dev, struct uwb_rc *rc)
+{
+       struct device *dev = &uwb_dev->dev;
+       char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
+
+       d_fnstart(3, NULL, "(dev %p [uwb_dev %p], uwb_rc %p)\n", dev, uwb_dev, rc);
+       uwb_mac_addr_print(macbuf, sizeof(macbuf), &uwb_dev->mac_addr);
+       uwb_dev_addr_print(devbuf, sizeof(devbuf), &uwb_dev->dev_addr);
+       dev_info(dev, "uwb device (mac %s dev %s) disconnected from %s %s\n",
+                macbuf, devbuf,
+                rc ? rc->uwb_dev.dev.parent->bus->name : "n/a",
+                rc ? dev_name(rc->uwb_dev.dev.parent) : "");
+       uwb_dev_rm(uwb_dev);
+       uwb_dev_put(uwb_dev);   /* for the creation in _onair() */
+       d_fnend(3, NULL, "(dev %p [uwb_dev %p], uwb_rc %p) = 0\n", dev, uwb_dev, rc);
+       return 0;
+}
+
+
+/**
+ * A device went off the air, clean up after it!
+ *
+ * This is called by the UWB Daemon (through the beacon purge function
+ * uwb_bcn_cache_purge) when it is detected that a device has been in
+ * radio silence for a while.
+ *
+ * If this device is actually a local radio controller we don't need
+ * to go through the offair process, as it is not registered as that.
+ *
+ * NOTE: uwb_bcn_cache.mutex is held!
+ */
+void uwbd_dev_offair(struct uwb_beca_e *bce)
+{
+       struct uwb_dev *uwb_dev;
+
+       uwb_dev = bce->uwb_dev;
+       if (uwb_dev) {
+               uwb_notify(uwb_dev->rc, uwb_dev, UWB_NOTIF_OFFAIR);
+               __uwb_dev_offair(uwb_dev, uwb_dev->rc);
+       }
+}
+
+
+/**
+ * A device went on the air, start it up!
+ *
+ * This is called by the UWB Daemon when it is detected that a device
+ * has popped up in the radio range of the radio controller.
+ *
+ * It will just create the freaking device, register the beacon and
+ * stuff and yatla, done.
+ *
+ *
+ * NOTE: uwb_beca.mutex is held, bce->mutex is held
+ */
+void uwbd_dev_onair(struct uwb_rc *rc, struct uwb_beca_e *bce)
+{
+       int result;
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_dev *uwb_dev;
+       char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
+
+       uwb_mac_addr_print(macbuf, sizeof(macbuf), bce->mac_addr);
+       uwb_dev_addr_print(devbuf, sizeof(devbuf), &bce->dev_addr);
+       uwb_dev = kcalloc(1, sizeof(*uwb_dev), GFP_KERNEL);
+       if (uwb_dev == NULL) {
+               dev_err(dev, "new device %s: Cannot allocate memory\n",
+                       macbuf);
+               return;
+       }
+       uwb_dev_init(uwb_dev);          /* This sets refcnt to one, we own it */
+       uwb_dev->mac_addr = *bce->mac_addr;
+       uwb_dev->dev_addr = bce->dev_addr;
+       dev_set_name(&uwb_dev->dev, macbuf);
+       result = uwb_dev_add(uwb_dev, &rc->uwb_dev.dev, rc);
+       if (result < 0) {
+               dev_err(dev, "new device %s: cannot instantiate device\n",
+                       macbuf);
+               goto error_dev_add;
+       }
+       /* plug the beacon cache */
+       bce->uwb_dev = uwb_dev;
+       uwb_dev->bce = bce;
+       uwb_bce_get(bce);               /* released in uwb_dev_sys_release() */
+       dev_info(dev, "uwb device (mac %s dev %s) connected to %s %s\n",
+                macbuf, devbuf, rc->uwb_dev.dev.parent->bus->name,
+                dev_name(rc->uwb_dev.dev.parent));
+       uwb_notify(rc, uwb_dev, UWB_NOTIF_ONAIR);
+       return;
+
+error_dev_add:
+       kfree(uwb_dev);
+       return;
+}
+
+/**
+ * Iterate over the list of UWB devices, calling a @function on each
+ *
+ * See docs for bus_for_each()....
+ *
+ * @rc:       radio controller for the devices.
+ * @function: function to call.
+ * @priv:     data to pass to @function.
+ * @returns:  0 if no invocation of function() returned a value
+ *            different to zero. That value otherwise.
+ */
+int uwb_dev_for_each(struct uwb_rc *rc, uwb_dev_for_each_f function, void *priv)
+{
+       return device_for_each_child(&rc->uwb_dev.dev, priv, function);
+}
+EXPORT_SYMBOL_GPL(uwb_dev_for_each);
diff --git a/drivers/uwb/lc-rc.c b/drivers/uwb/lc-rc.c
new file mode 100644 (file)
index 0000000..a21c96b
--- /dev/null
@@ -0,0 +1,501 @@
+/*
+ * Ultra Wide Band
+ * Life cycle of radio controllers
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * FIXME: docs
+ *
+ * A UWB radio controller is also a UWB device, so it embeds one...
+ *
+ * List of RCs comes from the 'struct class uwb_rc_class'.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/random.h>
+#include <linux/kdev_t.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+
+#define D_LOCAL 1
+#include <linux/uwb/debug.h>
+#include "uwb-internal.h"
+
+static int uwb_rc_index_match(struct device *dev, void *data)
+{
+       int *index = data;
+       struct uwb_rc *rc = dev_get_drvdata(dev);
+
+       if (rc->index == *index)
+               return 1;
+       return 0;
+}
+
+static struct uwb_rc *uwb_rc_find_by_index(int index)
+{
+       struct device *dev;
+       struct uwb_rc *rc = NULL;
+
+       dev = class_find_device(&uwb_rc_class, NULL, &index, uwb_rc_index_match);
+       if (dev)
+               rc = dev_get_drvdata(dev);
+       return rc;
+}
+
+static int uwb_rc_new_index(void)
+{
+       int index = 0;
+
+       for (;;) {
+               if (!uwb_rc_find_by_index(index))
+                       return index;
+               if (++index < 0)
+                       index = 0;
+       }
+}
+
+/**
+ * Release the backing device of a uwb_rc that has been dynamically allocated.
+ */
+static void uwb_rc_sys_release(struct device *dev)
+{
+       struct uwb_dev *uwb_dev = container_of(dev, struct uwb_dev, dev);
+       struct uwb_rc *rc = container_of(uwb_dev, struct uwb_rc, uwb_dev);
+
+       uwb_rc_neh_destroy(rc);
+       uwb_rc_ie_release(rc);
+       d_printf(1, dev, "freed uwb_rc %p\n", rc);
+       kfree(rc);
+}
+
+
+void uwb_rc_init(struct uwb_rc *rc)
+{
+       struct uwb_dev *uwb_dev = &rc->uwb_dev;
+
+       uwb_dev_init(uwb_dev);
+       rc->uwb_dev.dev.class = &uwb_rc_class;
+       rc->uwb_dev.dev.release = uwb_rc_sys_release;
+       uwb_rc_neh_create(rc);
+       rc->beaconing = -1;
+       rc->scan_type = UWB_SCAN_DISABLED;
+       INIT_LIST_HEAD(&rc->notifs_chain.list);
+       mutex_init(&rc->notifs_chain.mutex);
+       uwb_drp_avail_init(rc);
+       uwb_rc_ie_init(rc);
+       uwb_rsv_init(rc);
+       uwb_rc_pal_init(rc);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_init);
+
+
+struct uwb_rc *uwb_rc_alloc(void)
+{
+       struct uwb_rc *rc;
+       rc = kzalloc(sizeof(*rc), GFP_KERNEL);
+       if (rc == NULL)
+               return NULL;
+       uwb_rc_init(rc);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_alloc);
+
+static struct attribute *rc_attrs[] = {
+               &dev_attr_mac_address.attr,
+               &dev_attr_scan.attr,
+               &dev_attr_beacon.attr,
+               NULL,
+};
+
+static struct attribute_group rc_attr_group = {
+       .attrs = rc_attrs,
+};
+
+/*
+ * Registration of sysfs specific stuff
+ */
+static int uwb_rc_sys_add(struct uwb_rc *rc)
+{
+       return sysfs_create_group(&rc->uwb_dev.dev.kobj, &rc_attr_group);
+}
+
+
+static void __uwb_rc_sys_rm(struct uwb_rc *rc)
+{
+       sysfs_remove_group(&rc->uwb_dev.dev.kobj, &rc_attr_group);
+}
+
+/**
+ * uwb_rc_mac_addr_setup - get an RC's EUI-48 address or set it
+ * @rc:  the radio controller.
+ *
+ * If the EUI-48 address is 00:00:00:00:00:00 or FF:FF:FF:FF:FF:FF
+ * then a random locally administered EUI-48 is generated and set on
+ * the device.  The probability of address collisions is sufficiently
+ * unlikely (1/2^40 = 9.1e-13) that they're not checked for.
+ */
+static
+int uwb_rc_mac_addr_setup(struct uwb_rc *rc)
+{
+       int result;
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_dev *uwb_dev = &rc->uwb_dev;
+       char devname[UWB_ADDR_STRSIZE];
+       struct uwb_mac_addr addr;
+
+       result = uwb_rc_mac_addr_get(rc, &addr);
+       if (result < 0) {
+               dev_err(dev, "cannot retrieve UWB EUI-48 address: %d\n", result);
+               return result;
+       }
+
+       if (uwb_mac_addr_unset(&addr) || uwb_mac_addr_bcast(&addr)) {
+               addr.data[0] = 0x02; /* locally adminstered and unicast */
+               get_random_bytes(&addr.data[1], sizeof(addr.data)-1);
+
+               result = uwb_rc_mac_addr_set(rc, &addr);
+               if (result < 0) {
+                       uwb_mac_addr_print(devname, sizeof(devname), &addr);
+                       dev_err(dev, "cannot set EUI-48 address %s: %d\n",
+                               devname, result);
+                       return result;
+               }
+       }
+       uwb_dev->mac_addr = addr;
+       return 0;
+}
+
+
+
+static int uwb_rc_setup(struct uwb_rc *rc)
+{
+       int result;
+       struct device *dev = &rc->uwb_dev.dev;
+
+       result = uwb_rc_reset(rc);
+       if (result < 0) {
+               dev_err(dev, "cannot reset UWB radio: %d\n", result);
+               goto error;
+       }
+       result = uwb_rc_mac_addr_setup(rc);
+       if (result < 0) {
+               dev_err(dev, "cannot setup UWB MAC address: %d\n", result);
+               goto error;
+       }
+       result = uwb_rc_dev_addr_assign(rc);
+       if (result < 0) {
+               dev_err(dev, "cannot assign UWB DevAddr: %d\n", result);
+               goto error;
+       }
+       result = uwb_rc_ie_setup(rc);
+       if (result < 0) {
+               dev_err(dev, "cannot setup IE subsystem: %d\n", result);
+               goto error_ie_setup;
+       }
+       result = uwb_rc_set_identification_ie(rc);
+       if (result < 0) {
+               dev_err(dev, "cannot set Identification IE: %d\n",
+                       result);
+               goto error_set_id_ie;
+       }
+       result = uwb_rsv_setup(rc);
+       if (result < 0) {
+               dev_err(dev, "cannot setup reservation subsystem: %d\n", result);
+               goto error_rsv_setup;
+       }
+       uwb_dbg_add_rc(rc);
+       return 0;
+
+error_rsv_setup:
+       uwb_rc_ie_release(rc);
+error_ie_setup:
+error:
+       return result;
+}
+
+
+/**
+ * Register a new UWB radio controller
+ *
+ * Did you call uwb_rc_init() on your rc?
+ *
+ * We assume that this is being called with a > 0 refcount on
+ * it [through ops->{get|put}_device(). We'll take our own, though.
+ *
+ * @parent_dev is our real device, the one that provides the actual UWB device
+ */
+int uwb_rc_add(struct uwb_rc *rc, struct device *parent_dev, void *priv)
+{
+       int result;
+       struct device *dev;
+       char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
+
+       rc->index = uwb_rc_new_index();
+
+       dev = &rc->uwb_dev.dev;
+       dev_set_name(dev, "uwb%d", rc->index);
+
+       rc->priv = priv;
+
+       result = rc->start(rc);
+       if (result < 0)
+               goto error_rc_start;
+
+       result = uwb_rc_setup(rc);
+       if (result < 0) {
+               dev_err(dev, "cannot setup UWB radio controller: %d\n", result);
+               goto error_rc_setup;
+       }
+
+       result = uwb_dev_add(&rc->uwb_dev, parent_dev, rc);
+       if (result < 0 && result != -EADDRNOTAVAIL)
+               goto error_dev_add;
+
+       result = uwb_rc_sys_add(rc);
+       if (result < 0) {
+               dev_err(parent_dev, "cannot register UWB radio controller "
+                       "dev attributes: %d\n", result);
+               goto error_sys_add;
+       }
+
+       uwb_mac_addr_print(macbuf, sizeof(macbuf), &rc->uwb_dev.mac_addr);
+       uwb_dev_addr_print(devbuf, sizeof(devbuf), &rc->uwb_dev.dev_addr);
+       dev_info(dev,
+                "new uwb radio controller (mac %s dev %s) on %s %s\n",
+                macbuf, devbuf, parent_dev->bus->name, dev_name(parent_dev));
+       rc->ready = 1;
+       return 0;
+
+error_sys_add:
+       uwb_dev_rm(&rc->uwb_dev);
+error_dev_add:
+error_rc_setup:
+       rc->stop(rc);
+       uwbd_flush(rc);
+error_rc_start:
+       return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_add);
+
+
+static int uwb_dev_offair_helper(struct device *dev, void *priv)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+
+       return __uwb_dev_offair(uwb_dev, uwb_dev->rc);
+}
+
+/*
+ * Remove a Radio Controller; stop beaconing/scanning, disconnect all children
+ */
+void uwb_rc_rm(struct uwb_rc *rc)
+{
+       rc->ready = 0;
+
+       uwb_dbg_del_rc(rc);
+       uwb_rsv_cleanup(rc);
+       uwb_rc_ie_rm(rc, UWB_IDENTIFICATION_IE);
+       if (rc->beaconing >= 0)
+               uwb_rc_beacon(rc, -1, 0);
+       if (rc->scan_type != UWB_SCAN_DISABLED)
+               uwb_rc_scan(rc, rc->scanning, UWB_SCAN_DISABLED, 0);
+       uwb_rc_reset(rc);
+
+       rc->stop(rc);
+       uwbd_flush(rc);
+
+       uwb_dev_lock(&rc->uwb_dev);
+       rc->priv = NULL;
+       rc->cmd = NULL;
+       uwb_dev_unlock(&rc->uwb_dev);
+       mutex_lock(&uwb_beca.mutex);
+       uwb_dev_for_each(rc, uwb_dev_offair_helper, NULL);
+       __uwb_rc_sys_rm(rc);
+       mutex_unlock(&uwb_beca.mutex);
+       uwb_dev_rm(&rc->uwb_dev);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_rm);
+
+static int find_rc_try_get(struct device *dev, void *data)
+{
+       struct uwb_rc *target_rc = data;
+       struct uwb_rc *rc = dev_get_drvdata(dev);
+
+       if (rc == NULL) {
+               WARN_ON(1);
+               return 0;
+       }
+       if (rc == target_rc) {
+               if (rc->ready == 0)
+                       return 0;
+               else
+                       return 1;
+       }
+       return 0;
+}
+
+/**
+ * Given a radio controller descriptor, validate and refcount it
+ *
+ * @returns NULL if the rc does not exist or is quiescing; the ptr to
+ *               it otherwise.
+ */
+struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *target_rc)
+{
+       struct device *dev;
+       struct uwb_rc *rc = NULL;
+
+       dev = class_find_device(&uwb_rc_class, NULL, target_rc,
+                               find_rc_try_get);
+       if (dev) {
+               rc = dev_get_drvdata(dev);
+               __uwb_rc_get(rc);
+       }
+       return rc;
+}
+EXPORT_SYMBOL_GPL(__uwb_rc_try_get);
+
+/*
+ * RC get for external refcount acquirers...
+ *
+ * Increments the refcount of the device and it's backend modules
+ */
+static inline struct uwb_rc *uwb_rc_get(struct uwb_rc *rc)
+{
+       if (rc->ready == 0)
+               return NULL;
+       uwb_dev_get(&rc->uwb_dev);
+       return rc;
+}
+
+static int find_rc_grandpa(struct device *dev, void *data)
+{
+       struct device *grandpa_dev = data;
+       struct uwb_rc *rc = dev_get_drvdata(dev);
+
+       if (rc->uwb_dev.dev.parent->parent == grandpa_dev) {
+               rc = uwb_rc_get(rc);
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * Locate and refcount a radio controller given a common grand-parent
+ *
+ * @grandpa_dev  Pointer to the 'grandparent' device structure.
+ * @returns NULL If the rc does not exist or is quiescing; the ptr to
+ *               it otherwise, properly referenced.
+ *
+ * The Radio Control interface (or the UWB Radio Controller) is always
+ * an interface of a device. The parent is the interface, the
+ * grandparent is the device that encapsulates the interface.
+ *
+ * There is no need to lock around as the "grandpa" would be
+ * refcounted by the target, and to remove the referemes, the
+ * uwb_rc_class->sem would have to be taken--we hold it, ergo we
+ * should be safe.
+ */
+struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *grandpa_dev)
+{
+       struct device *dev;
+       struct uwb_rc *rc = NULL;
+
+       dev = class_find_device(&uwb_rc_class, NULL, (void *)grandpa_dev,
+                               find_rc_grandpa);
+       if (dev)
+               rc = dev_get_drvdata(dev);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_get_by_grandpa);
+
+/**
+ * Find a radio controller by device address
+ *
+ * @returns the pointer to the radio controller, properly referenced
+ */
+static int find_rc_dev(struct device *dev, void *data)
+{
+       struct uwb_dev_addr *addr = data;
+       struct uwb_rc *rc = dev_get_drvdata(dev);
+
+       if (rc == NULL) {
+               WARN_ON(1);
+               return 0;
+       }
+       if (!uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, addr)) {
+               rc = uwb_rc_get(rc);
+               return 1;
+       }
+       return 0;
+}
+
+struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *addr)
+{
+       struct device *dev;
+       struct uwb_rc *rc = NULL;
+
+       dev = class_find_device(&uwb_rc_class, NULL, (void *)addr,
+                               find_rc_dev);
+       if (dev)
+               rc = dev_get_drvdata(dev);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_get_by_dev);
+
+/**
+ * Drop a reference on a radio controller
+ *
+ * This is the version that should be done by entities external to the
+ * UWB Radio Control stack (ie: clients of the API).
+ */
+void uwb_rc_put(struct uwb_rc *rc)
+{
+       __uwb_rc_put(rc);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_put);
+
+/*
+ *
+ *
+ */
+ssize_t uwb_rc_print_IEs(struct uwb_rc *uwb_rc, char *buf, size_t size)
+{
+       ssize_t result;
+       struct uwb_rc_evt_get_ie *ie_info;
+       struct uwb_buf_ctx ctx;
+
+       result = uwb_rc_get_ie(uwb_rc, &ie_info);
+       if (result < 0)
+               goto error_get_ie;
+       ctx.buf = buf;
+       ctx.size = size;
+       ctx.bytes = 0;
+       uwb_ie_for_each(&uwb_rc->uwb_dev, uwb_ie_dump_hex, &ctx,
+                       ie_info->IEData, result - sizeof(*ie_info));
+       result = ctx.bytes;
+       kfree(ie_info);
+error_get_ie:
+       return result;
+}
+
diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c
new file mode 100644 (file)
index 0000000..5508993
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * UWB PAL support.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/uwb.h>
+
+#include "uwb-internal.h"
+
+/**
+ * uwb_pal_init - initialize a UWB PAL
+ * @pal: the PAL to initialize
+ */
+void uwb_pal_init(struct uwb_pal *pal)
+{
+       INIT_LIST_HEAD(&pal->node);
+}
+EXPORT_SYMBOL_GPL(uwb_pal_init);
+
+/**
+ * uwb_pal_register - register a UWB PAL
+ * @rc: the radio controller the PAL will be using
+ * @pal: the PAL
+ *
+ * The PAL must be initialized with uwb_pal_init().
+ */
+int uwb_pal_register(struct uwb_rc *rc, struct uwb_pal *pal)
+{
+       spin_lock(&rc->pal_lock);
+       list_add(&pal->node, &rc->pals);
+       spin_unlock(&rc->pal_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_pal_register);
+
+/**
+ * uwb_pal_register - unregister a UWB PAL
+ * @rc: the radio controller the PAL was using
+ * @pal: the PAL
+ */
+void uwb_pal_unregister(struct uwb_rc *rc, struct uwb_pal *pal)
+{
+       spin_lock(&rc->pal_lock);
+       list_del(&pal->node);
+       spin_unlock(&rc->pal_lock);
+}
+EXPORT_SYMBOL_GPL(uwb_pal_unregister);
+
+/**
+ * uwb_rc_pal_init - initialize the PAL related parts of a radio controller
+ * @rc: the radio controller
+ */
+void uwb_rc_pal_init(struct uwb_rc *rc)
+{
+       spin_lock_init(&rc->pal_lock);
+       INIT_LIST_HEAD(&rc->pals);
+}
diff --git a/drivers/uwb/uwb-internal.h b/drivers/uwb/uwb-internal.h
new file mode 100644 (file)
index 0000000..4f525a8
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Ultra Wide Band
+ * UWB internal API
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * This contains most of the internal API for UWB. This is stuff used
+ * across the stack that of course, is of no interest to the rest.
+ *
+ * Some parts might end up going public (like uwb_rc_*())...
+ */
+
+#ifndef __UWB_INTERNAL_H__
+#define __UWB_INTERNAL_H__
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/uwb.h>
+#include <linux/mutex.h>
+
+struct uwb_beca_e;
+
+/* General device API */
+extern void uwb_dev_init(struct uwb_dev *uwb_dev);
+extern int __uwb_dev_offair(struct uwb_dev *, struct uwb_rc *);
+extern int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev,
+                      struct uwb_rc *parent_rc);
+extern void uwb_dev_rm(struct uwb_dev *uwb_dev);
+extern void uwbd_dev_onair(struct uwb_rc *, struct uwb_beca_e *);
+extern void uwbd_dev_offair(struct uwb_beca_e *);
+void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event);
+
+/* General UWB Radio Controller Internal API */
+extern struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *);
+static inline struct uwb_rc *__uwb_rc_get(struct uwb_rc *rc)
+{
+       uwb_dev_get(&rc->uwb_dev);
+       return rc;
+}
+
+static inline void __uwb_rc_put(struct uwb_rc *rc)
+{
+       uwb_dev_put(&rc->uwb_dev);
+}
+
+extern int uwb_rc_reset(struct uwb_rc *rc);
+extern int uwb_rc_beacon(struct uwb_rc *rc,
+                        int channel, unsigned bpst_offset);
+extern int uwb_rc_scan(struct uwb_rc *rc,
+                      unsigned channel, enum uwb_scan_type type,
+                      unsigned bpst_offset);
+extern int uwb_rc_send_all_drp_ie(struct uwb_rc *rc);
+extern ssize_t uwb_rc_print_IEs(struct uwb_rc *rc, char *, size_t);
+extern void uwb_rc_ie_init(struct uwb_rc *);
+extern void uwb_rc_ie_init(struct uwb_rc *);
+extern ssize_t uwb_rc_ie_setup(struct uwb_rc *);
+extern void uwb_rc_ie_release(struct uwb_rc *);
+extern int uwb_rc_ie_add(struct uwb_rc *,
+                        const struct uwb_ie_hdr *, size_t);
+extern int uwb_rc_ie_rm(struct uwb_rc *, enum uwb_ie);
+extern int uwb_rc_set_identification_ie(struct uwb_rc *);
+
+extern const char *uwb_rc_strerror(unsigned code);
+
+/*
+ * Time to wait for a response to an RC command.
+ *
+ * Some commands can take a long time to response. e.g., START_BEACON
+ * may scan for several superframes before joining an existing beacon
+ * group and this can take around 600 ms.
+ */
+#define UWB_RC_CMD_TIMEOUT_MS 1000 /* ms */
+
+/*
+ * Notification/Event Handlers
+ */
+
+struct uwb_rc_neh;
+
+void uwb_rc_neh_create(struct uwb_rc *rc);
+void uwb_rc_neh_destroy(struct uwb_rc *rc);
+
+struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd,
+                                 u8 expected_type, u16 expected_event,
+                                 uwb_rc_cmd_cb_f cb, void *arg);
+void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh);
+void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh);
+void uwb_rc_neh_put(struct uwb_rc_neh *neh);
+
+/* Event size tables */
+extern int uwb_est_create(void);
+extern void uwb_est_destroy(void);
+
+
+/*
+ * UWB Events & management daemon
+ */
+
+/**
+ * enum uwb_event_type - types of UWB management daemon events
+ *
+ * The UWB management daemon (uwbd) can receive two types of events:
+ *   UWB_EVT_TYPE_NOTIF - notification from the radio controller.
+ *   UWB_EVT_TYPE_MSG   - a simple message.
+ */
+enum uwb_event_type {
+       UWB_EVT_TYPE_NOTIF,
+       UWB_EVT_TYPE_MSG,
+};
+
+/**
+ * struct uwb_event_notif - an event for a radio controller notification
+ * @size: Size of the buffer (ie: Guaranteed to contain at least
+ *        a full 'struct uwb_rceb')
+ * @rceb: Pointer to a kmalloced() event payload
+ */
+struct uwb_event_notif {
+       size_t size;
+       struct uwb_rceb *rceb;
+};
+
+/**
+ * enum uwb_event_message - an event for a message for asynchronous processing
+ *
+ * UWB_EVT_MSG_RESET - reset the radio controller and all PAL hardware.
+ */
+enum uwb_event_message {
+       UWB_EVT_MSG_RESET,
+};
+
+/**
+ * UWB Event
+ * @rc:         Radio controller that emitted the event (referenced)
+ * @ts_jiffies: Timestamp, when was it received
+ * @type:       This event's type.
+ */
+struct uwb_event {
+       struct list_head list_node;
+       struct uwb_rc *rc;
+       unsigned long ts_jiffies;
+       enum uwb_event_type type;
+       union {
+               struct uwb_event_notif notif;
+               enum uwb_event_message message;
+       };
+};
+
+extern void uwbd_start(void);
+extern void uwbd_stop(void);
+extern struct uwb_event *uwb_event_alloc(size_t, gfp_t gfp_mask);
+extern void uwbd_event_queue(struct uwb_event *);
+void uwbd_flush(struct uwb_rc *rc);
+
+/* UWB event handlers */
+extern int uwbd_evt_handle_rc_beacon(struct uwb_event *);
+extern int uwbd_evt_handle_rc_beacon_size(struct uwb_event *);
+extern int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *);
+extern int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *);
+extern int uwbd_evt_handle_rc_drp(struct uwb_event *);
+extern int uwbd_evt_handle_rc_drp_avail(struct uwb_event *);
+
+int uwbd_msg_handle_reset(struct uwb_event *evt);
+
+
+/*
+ * Address management
+ */
+int uwb_rc_dev_addr_assign(struct uwb_rc *rc);
+int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt);
+
+/*
+ * UWB Beacon Cache
+ *
+ * Each beacon we received is kept in a cache--when we receive that
+ * beacon consistently, that means there is a new device that we have
+ * to add to the system.
+ */
+
+extern unsigned long beacon_timeout_ms;
+
+/** Beacon cache list */
+struct uwb_beca {
+       struct list_head list;
+       size_t entries;
+       struct mutex mutex;
+};
+
+extern struct uwb_beca uwb_beca;
+
+/**
+ * Beacon cache entry
+ *
+ * @jiffies_refresh: last time a beacon was  received that refreshed
+ *                   this cache entry.
+ * @uwb_dev: device connected to this beacon. This pointer is not
+ *           safe, you need to get it with uwb_dev_try_get()
+ *
+ * @hits: how many time we have seen this beacon since last time we
+ *        cleared it
+ */
+struct uwb_beca_e {
+       struct mutex mutex;
+       struct kref refcnt;
+       struct list_head node;
+       struct uwb_mac_addr *mac_addr;
+       struct uwb_dev_addr dev_addr;
+       u8 hits;
+       unsigned long ts_jiffies;
+       struct uwb_dev *uwb_dev;
+       struct uwb_rc_evt_beacon *be;
+       struct stats lqe_stats, rssi_stats;     /* radio statistics */
+};
+struct uwb_beacon_frame;
+extern ssize_t uwb_bce_print_IEs(struct uwb_dev *, struct uwb_beca_e *,
+                                char *, size_t);
+extern struct uwb_beca_e *__uwb_beca_add(struct uwb_rc_evt_beacon *,
+                                        struct uwb_beacon_frame *,
+                                        unsigned long);
+
+extern void uwb_bce_kfree(struct kref *_bce);
+static inline void uwb_bce_get(struct uwb_beca_e *bce)
+{
+       kref_get(&bce->refcnt);
+}
+static inline void uwb_bce_put(struct uwb_beca_e *bce)
+{
+       kref_put(&bce->refcnt, uwb_bce_kfree);
+}
+extern void uwb_beca_purge(void);
+extern void uwb_beca_release(void);
+
+struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
+                                      const struct uwb_dev_addr *devaddr);
+struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
+                                      const struct uwb_mac_addr *macaddr);
+
+/* -- UWB Sysfs representation */
+extern struct class uwb_rc_class;
+extern struct device_attribute dev_attr_mac_address;
+extern struct device_attribute dev_attr_beacon;
+extern struct device_attribute dev_attr_scan;
+
+/* -- DRP Bandwidth allocator: bandwidth allocations, reservations, DRP */
+void uwb_rsv_init(struct uwb_rc *rc);
+int uwb_rsv_setup(struct uwb_rc *rc);
+void uwb_rsv_cleanup(struct uwb_rc *rc);
+
+void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state);
+void uwb_rsv_remove(struct uwb_rsv *rsv);
+struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src,
+                            struct uwb_ie_drp *drp_ie);
+void uwb_rsv_sched_update(struct uwb_rc *rc);
+
+void uwb_drp_handle_timeout(struct uwb_rsv *rsv);
+int uwb_drp_ie_update(struct uwb_rsv *rsv);
+void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie);
+
+void uwb_drp_avail_init(struct uwb_rc *rc);
+int  uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas);
+void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas);
+void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas);
+void uwb_drp_avail_ie_update(struct uwb_rc *rc);
+
+/* -- PAL support */
+void uwb_rc_pal_init(struct uwb_rc *rc);
+
+/* -- Misc */
+
+extern ssize_t uwb_mac_frame_hdr_print(char *, size_t,
+                                      const struct uwb_mac_frame_hdr *);
+
+/* -- Debug interface */
+void uwb_dbg_init(void);
+void uwb_dbg_exit(void);
+void uwb_dbg_add_rc(struct uwb_rc *rc);
+void uwb_dbg_del_rc(struct uwb_rc *rc);
+
+/* Workarounds for version specific stuff */
+
+static inline void uwb_dev_lock(struct uwb_dev *uwb_dev)
+{
+       down(&uwb_dev->dev.sem);
+}
+
+static inline void uwb_dev_unlock(struct uwb_dev *uwb_dev)
+{
+       up(&uwb_dev->dev.sem);
+}
+
+#endif /* #ifndef __UWB_INTERNAL_H__ */
diff --git a/drivers/uwb/uwbd.c b/drivers/uwb/uwbd.c
new file mode 100644 (file)
index 0000000..b3673d6
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * Ultra Wide Band
+ * Neighborhood Management Daemon
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * This daemon takes care of maintaing information that describes the
+ * UWB neighborhood that the radios in this machine can see. It also
+ * keeps a tab of which devices are visible, makes sure each HC sits
+ * on a different channel to avoid interfering, etc.
+ *
+ * Different drivers (radio controller, device, any API in general)
+ * communicate with this daemon through an event queue. Daemon wakes
+ * up, takes a list of events and handles them one by one; handling
+ * function is extracted from a table based on the event's type and
+ * subtype. Events are freed only if the handling function says so.
+ *
+ *   . Lock protecting the event list has to be an spinlock and locked
+ *     with IRQSAVE because it might be called from an interrupt
+ *     context (ie: when events arrive and the notification drops
+ *     down from the ISR).
+ *
+ *   . UWB radio controller drivers queue events to the daemon using
+ *     uwbd_event_queue(). They just get the event, chew it to make it
+ *     look like UWBD likes it and pass it in a buffer allocated with
+ *     uwb_event_alloc().
+ *
+ * EVENTS
+ *
+ * Events have a type, a subtype, a lenght, some other stuff and the
+ * data blob, which depends on the event. The header is 'struct
+ * uwb_event'; for payloads, see 'struct uwbd_evt_*'.
+ *
+ * EVENT HANDLER TABLES
+ *
+ * To find a handling function for an event, the type is used to index
+ * a subtype-table in the type-table. The subtype-table is indexed
+ * with the subtype to get the function that handles the event. Start
+ * with the main type-table 'uwbd_evt_type_handler'.
+ *
+ * DEVICES
+ *
+ * Devices are created when a bunch of beacons have been received and
+ * it is stablished that the device has stable radio presence. CREATED
+ * only, not configured. Devices are ONLY configured when an
+ * Application-Specific IE Probe is receieved, in which the device
+ * declares which Protocol ID it groks. Then the device is CONFIGURED
+ * (and the driver->probe() stuff of the device model is invoked).
+ *
+ * Devices are considered disconnected when a certain number of
+ * beacons are not received in an amount of time.
+ *
+ * Handler functions are called normally uwbd_evt_handle_*().
+ */
+
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/freezer.h>
+#include "uwb-internal.h"
+
+#define D_LOCAL 1
+#include <linux/uwb/debug.h>
+
+
+/**
+ * UWBD Event handler function signature
+ *
+ * Return !0 if the event needs not to be freed (ie the handler
+ * takes/took care of it). 0 means the daemon code will free the
+ * event.
+ *
+ * @evt->rc is already referenced and guaranteed to exist. See
+ * uwb_evt_handle().
+ */
+typedef int (*uwbd_evt_handler_f)(struct uwb_event *);
+
+/**
+ * Properties of a UWBD event
+ *
+ * @handler:    the function that will handle this event
+ * @name:       text name of event
+ */
+struct uwbd_event {
+       uwbd_evt_handler_f handler;
+       const char *name;
+};
+
+/** Table of handlers for and properties of the UWBD Radio Control Events */
+static
+struct uwbd_event uwbd_events[] = {
+       [UWB_RC_EVT_BEACON] = {
+               .handler = uwbd_evt_handle_rc_beacon,
+               .name = "BEACON_RECEIVED"
+       },
+       [UWB_RC_EVT_BEACON_SIZE] = {
+               .handler = uwbd_evt_handle_rc_beacon_size,
+               .name = "BEACON_SIZE_CHANGE"
+       },
+       [UWB_RC_EVT_BPOIE_CHANGE] = {
+               .handler = uwbd_evt_handle_rc_bpoie_change,
+               .name = "BPOIE_CHANGE"
+       },
+       [UWB_RC_EVT_BP_SLOT_CHANGE] = {
+               .handler = uwbd_evt_handle_rc_bp_slot_change,
+               .name = "BP_SLOT_CHANGE"
+       },
+       [UWB_RC_EVT_DRP_AVAIL] = {
+               .handler = uwbd_evt_handle_rc_drp_avail,
+               .name = "DRP_AVAILABILITY_CHANGE"
+       },
+       [UWB_RC_EVT_DRP] = {
+               .handler = uwbd_evt_handle_rc_drp,
+               .name = "DRP"
+       },
+       [UWB_RC_EVT_DEV_ADDR_CONFLICT] = {
+               .handler = uwbd_evt_handle_rc_dev_addr_conflict,
+               .name = "DEV_ADDR_CONFLICT",
+       },
+};
+
+
+
+struct uwbd_evt_type_handler {
+       const char *name;
+       struct uwbd_event *uwbd_events;
+       size_t size;
+};
+
+#define UWBD_EVT_TYPE_HANDLER(n,a) {           \
+       .name = (n),                            \
+       .uwbd_events = (a),                     \
+       .size = sizeof(a)/sizeof((a)[0])        \
+}
+
+
+/** Table of handlers for each UWBD Event type. */
+static
+struct uwbd_evt_type_handler uwbd_evt_type_handlers[] = {
+       [UWB_RC_CET_GENERAL] = UWBD_EVT_TYPE_HANDLER("RC", uwbd_events)
+};
+
+static const
+size_t uwbd_evt_type_handlers_len =
+       sizeof(uwbd_evt_type_handlers) / sizeof(uwbd_evt_type_handlers[0]);
+
+static const struct uwbd_event uwbd_message_handlers[] = {
+       [UWB_EVT_MSG_RESET] = {
+               .handler = uwbd_msg_handle_reset,
+               .name = "reset",
+       },
+};
+
+static DEFINE_MUTEX(uwbd_event_mutex);
+
+/**
+ * Handle an URC event passed to the UWB Daemon
+ *
+ * @evt: the event to handle
+ * @returns: 0 if the event can be kfreed, !0 on the contrary
+ *           (somebody else took ownership) [coincidentally, returning
+ *           a <0 errno code will free it :)].
+ *
+ * Looks up the two indirection tables (one for the type, one for the
+ * subtype) to decide which function handles it and then calls the
+ * handler.
+ *
+ * The event structure passed to the event handler has the radio
+ * controller in @evt->rc referenced. The reference will be dropped
+ * once the handler returns, so if it needs it for longer (async),
+ * it'll need to take another one.
+ */
+static
+int uwbd_event_handle_urc(struct uwb_event *evt)
+{
+       int result;
+       struct uwbd_evt_type_handler *type_table;
+       uwbd_evt_handler_f handler;
+       u8 type, context;
+       u16 event;
+
+       type = evt->notif.rceb->bEventType;
+       event = le16_to_cpu(evt->notif.rceb->wEvent);
+       context = evt->notif.rceb->bEventContext;
+
+       if (type > uwbd_evt_type_handlers_len) {
+               if (printk_ratelimit())
+                       printk(KERN_ERR "UWBD: event type %u: unknown "
+                              "(too high)\n", type);
+               return -EINVAL;
+       }
+       type_table = &uwbd_evt_type_handlers[type];
+       if (type_table->uwbd_events == NULL) {
+               if (printk_ratelimit())
+                       printk(KERN_ERR "UWBD: event type %u: unknown\n", type);
+               return -EINVAL;
+       }
+       if (event > type_table->size) {
+               if (printk_ratelimit())
+                       printk(KERN_ERR "UWBD: event %s[%u]: "
+                              "unknown (too high)\n", type_table->name, event);
+               return -EINVAL;
+       }
+       handler = type_table->uwbd_events[event].handler;
+       if (handler == NULL) {
+               if (printk_ratelimit())
+                       printk(KERN_ERR "UWBD: event %s[%u]: unknown\n",
+                              type_table->name, event);
+               return -EINVAL;
+       }
+       d_printf(3, NULL, "processing 0x%02x/%04x/%02x, %zu bytes\n",
+                type, event, context, evt->notif.size);
+       result = (*handler)(evt);
+       if (result < 0) {
+               if (printk_ratelimit())
+                       printk(KERN_ERR "UWBD: event 0x%02x/%04x/%02x, "
+                              "table %s[%u]: handling failed: %d\n",
+                              type, event, context, type_table->name,
+                              event, result);
+       }
+       return result;
+}
+
+static void uwbd_event_handle_message(struct uwb_event *evt)
+{
+       struct uwb_rc *rc;
+       int result;
+
+       rc = evt->rc;
+
+       if (evt->message < 0 || evt->message >= ARRAY_SIZE(uwbd_message_handlers)) {
+               dev_err(&rc->uwb_dev.dev, "UWBD: invalid message type %d\n", evt->message);
+               return;
+       }
+
+       /* If this is a reset event we need to drop the
+        * uwbd_event_mutex or it deadlocks when the reset handler
+        * attempts to flush the uwbd events. */
+       if (evt->message == UWB_EVT_MSG_RESET)
+               mutex_unlock(&uwbd_event_mutex);
+
+       result = uwbd_message_handlers[evt->message].handler(evt);
+       if (result < 0)
+               dev_err(&rc->uwb_dev.dev, "UWBD: '%s' message failed: %d\n",
+                       uwbd_message_handlers[evt->message].name, result);
+
+       if (evt->message == UWB_EVT_MSG_RESET)
+               mutex_lock(&uwbd_event_mutex);
+}
+
+static void uwbd_event_handle(struct uwb_event *evt)
+{
+       struct uwb_rc *rc;
+       int should_keep;
+
+       rc = evt->rc;
+
+       if (rc->ready) {
+               switch (evt->type) {
+               case UWB_EVT_TYPE_NOTIF:
+                       should_keep = uwbd_event_handle_urc(evt);
+                       if (should_keep <= 0)
+                               kfree(evt->notif.rceb);
+                       break;
+               case UWB_EVT_TYPE_MSG:
+                       uwbd_event_handle_message(evt);
+                       break;
+               default:
+                       dev_err(&rc->uwb_dev.dev, "UWBD: invalid event type %d\n", evt->type);
+                       break;
+               }
+       }
+
+       __uwb_rc_put(rc);       /* for the __uwb_rc_get() in uwb_rc_notif_cb() */
+}
+/* The UWB Daemon */
+
+
+/** Daemon's PID: used to decide if we can queue or not */
+static int uwbd_pid;
+/** Daemon's task struct for managing the kthread */
+static struct task_struct *uwbd_task;
+/** Daemon's waitqueue for waiting for new events */
+static DECLARE_WAIT_QUEUE_HEAD(uwbd_wq);
+/** Daemon's list of events; we queue/dequeue here */
+static struct list_head uwbd_event_list = LIST_HEAD_INIT(uwbd_event_list);
+/** Daemon's list lock to protect concurent access */
+static DEFINE_SPINLOCK(uwbd_event_list_lock);
+
+
+/**
+ * UWB Daemon
+ *
+ * Listens to all UWB notifications and takes care to track the state
+ * of the UWB neighboorhood for the kernel. When we do a run, we
+ * spinlock, move the list to a private copy and release the
+ * lock. Hold it as little as possible. Not a conflict: it is
+ * guaranteed we own the events in the private list.
+ *
+ * FIXME: should change so we don't have a 1HZ timer all the time, but
+ *        only if there are devices.
+ */
+static int uwbd(void *unused)
+{
+       unsigned long flags;
+       struct list_head list = LIST_HEAD_INIT(list);
+       struct uwb_event *evt, *nxt;
+       int should_stop = 0;
+       while (1) {
+               wait_event_interruptible_timeout(
+                       uwbd_wq,
+                       !list_empty(&uwbd_event_list)
+                         || (should_stop = kthread_should_stop()),
+                       HZ);
+               if (should_stop)
+                       break;
+               try_to_freeze();
+
+               mutex_lock(&uwbd_event_mutex);
+               spin_lock_irqsave(&uwbd_event_list_lock, flags);
+               list_splice_init(&uwbd_event_list, &list);
+               spin_unlock_irqrestore(&uwbd_event_list_lock, flags);
+               list_for_each_entry_safe(evt, nxt, &list, list_node) {
+                       list_del(&evt->list_node);
+                       uwbd_event_handle(evt);
+                       kfree(evt);
+               }
+               mutex_unlock(&uwbd_event_mutex);
+
+               uwb_beca_purge();       /* Purge devices that left */
+       }
+       return 0;
+}
+
+
+/** Start the UWB daemon */
+void uwbd_start(void)
+{
+       uwbd_task = kthread_run(uwbd, NULL, "uwbd");
+       if (uwbd_task == NULL)
+               printk(KERN_ERR "UWB: Cannot start management daemon; "
+                      "UWB won't work\n");
+       else
+               uwbd_pid = uwbd_task->pid;
+}
+
+/* Stop the UWB daemon and free any unprocessed events */
+void uwbd_stop(void)
+{
+       unsigned long flags;
+       struct uwb_event *evt, *nxt;
+       kthread_stop(uwbd_task);
+       spin_lock_irqsave(&uwbd_event_list_lock, flags);
+       uwbd_pid = 0;
+       list_for_each_entry_safe(evt, nxt, &uwbd_event_list, list_node) {
+               if (evt->type == UWB_EVT_TYPE_NOTIF)
+                       kfree(evt->notif.rceb);
+               kfree(evt);
+       }
+       spin_unlock_irqrestore(&uwbd_event_list_lock, flags);
+       uwb_beca_release();
+}
+
+/*
+ * Queue an event for the management daemon
+ *
+ * When some lower layer receives an event, it uses this function to
+ * push it forward to the UWB daemon.
+ *
+ * Once you pass the event, you don't own it any more, but the daemon
+ * does. It will uwb_event_free() it when done, so make sure you
+ * uwb_event_alloc()ed it or bad things will happen.
+ *
+ * If the daemon is not running, we just free the event.
+ */
+void uwbd_event_queue(struct uwb_event *evt)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&uwbd_event_list_lock, flags);
+       if (uwbd_pid != 0) {
+               list_add(&evt->list_node, &uwbd_event_list);
+               wake_up_all(&uwbd_wq);
+       } else {
+               __uwb_rc_put(evt->rc);
+               if (evt->type == UWB_EVT_TYPE_NOTIF)
+                       kfree(evt->notif.rceb);
+               kfree(evt);
+       }
+       spin_unlock_irqrestore(&uwbd_event_list_lock, flags);
+       return;
+}
+
+void uwbd_flush(struct uwb_rc *rc)
+{
+       struct uwb_event *evt, *nxt;
+
+       mutex_lock(&uwbd_event_mutex);
+
+       spin_lock_irq(&uwbd_event_list_lock);
+       list_for_each_entry_safe(evt, nxt, &uwbd_event_list, list_node) {
+               if (evt->rc == rc) {
+                       __uwb_rc_put(rc);
+                       list_del(&evt->list_node);
+                       if (evt->type == UWB_EVT_TYPE_NOTIF)
+                               kfree(evt->notif.rceb);
+                       kfree(evt);
+               }
+       }
+       spin_unlock_irq(&uwbd_event_list_lock);
+
+       mutex_unlock(&uwbd_event_mutex);
+}