]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/uwb/uwbd.c
OMAP3: clock: Camera module doesn't have IDLEST bit
[linux-2.6-omap-h63xx.git] / drivers / uwb / uwbd.c
index 78908416e42c9ab88ba3b1e0a3579f4ea4966f8b..57bd6bfef37e95cca10ec3c2133e7f19f7d7c28a 100644 (file)
  *
  * 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>
 
+#include "uwb-internal.h"
 
-/**
+/*
  * UWBD Event handler function signature
  *
  * Return !0 if the event needs not to be freed (ie the handler
@@ -101,9 +97,12 @@ struct uwbd_event {
        const char *name;
 };
 
-/** Table of handlers for and properties of the UWBD Radio Control Events */
-static
-struct uwbd_event uwbd_events[] = {
+/* Table of handlers for and properties of the UWBD Radio Control Events */
+static struct uwbd_event uwbd_urc_events[] = {
+       [UWB_RC_EVT_IE_RCV] = {
+               .handler = uwbd_evt_handle_rc_ie_rcv,
+               .name = "IE_RECEIVED"
+       },
        [UWB_RC_EVT_BEACON] = {
                .handler = uwbd_evt_handle_rc_beacon,
                .name = "BEACON_RECEIVED"
@@ -142,23 +141,15 @@ struct uwbd_evt_type_handler {
        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)
+/* Table of handlers for each UWBD Event type. */
+static struct uwbd_evt_type_handler uwbd_urc_evt_type_handlers[] = {
+       [UWB_RC_CET_GENERAL] = {
+               .name        = "URC",
+               .uwbd_events = uwbd_urc_events,
+               .size        = ARRAY_SIZE(uwbd_urc_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,
@@ -166,9 +157,7 @@ static const struct uwbd_event uwbd_message_handlers[] = {
        },
 };
 
-static DEFINE_MUTEX(uwbd_event_mutex);
-
-/**
+/*
  * Handle an URC event passed to the UWB Daemon
  *
  * @evt: the event to handle
@@ -188,6 +177,7 @@ static DEFINE_MUTEX(uwbd_event_mutex);
 static
 int uwbd_event_handle_urc(struct uwb_event *evt)
 {
+       int result = -EINVAL;
        struct uwbd_evt_type_handler *type_table;
        uwbd_evt_handler_f handler;
        u8 type, context;
@@ -197,26 +187,24 @@ int uwbd_event_handle_urc(struct uwb_event *evt)
        event = le16_to_cpu(evt->notif.rceb->wEvent);
        context = evt->notif.rceb->bEventContext;
 
-       if (type > uwbd_evt_type_handlers_len) {
-               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) {
-               printk(KERN_ERR "UWBD: event type %u: unknown\n", type);
-               return -EINVAL;
-       }
-       if (event > type_table->size) {
-               printk(KERN_ERR "UWBD: event %s[%u]: unknown (too high)\n",
-                      type_table->name, event);
-               return -EINVAL;
-       }
+       if (type > ARRAY_SIZE(uwbd_urc_evt_type_handlers))
+               goto out;
+       type_table = &uwbd_urc_evt_type_handlers[type];
+       if (type_table->uwbd_events == NULL)
+               goto out;
+       if (event > type_table->size)
+               goto out;
        handler = type_table->uwbd_events[event].handler;
-       if (handler == NULL) {
-               printk(KERN_ERR "UWBD: event %s[%u]: unknown\n", type_table->name, event);
-               return -EINVAL;
-       }
-       return (*handler)(evt);
+       if (handler == NULL)
+               goto out;
+
+       result = (*handler)(evt);
+out:
+       if (result < 0)
+               dev_err(&evt->rc->uwb_dev.dev,
+                       "UWBD: event 0x%02x/%04x/%02x, handling failed: %d\n",
+                       type, event, context, result);
+       return result;
 }
 
 static void uwbd_event_handle_message(struct uwb_event *evt)
@@ -231,19 +219,10 @@ static void uwbd_event_handle_message(struct uwb_event *evt)
                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)
@@ -271,20 +250,6 @@ static void uwbd_event_handle(struct uwb_event *evt)
 
        __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
@@ -298,65 +263,58 @@ static DEFINE_SPINLOCK(uwbd_event_list_lock);
  * 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)
+static int uwbd(void *param)
 {
+       struct uwb_rc *rc = param;
        unsigned long flags;
-       struct list_head list = LIST_HEAD_INIT(list);
-       struct uwb_event *evt, *nxt;
+       struct uwb_event *evt;
        int should_stop = 0;
+
        while (1) {
                wait_event_interruptible_timeout(
-                       uwbd_wq,
-                       !list_empty(&uwbd_event_list)
+                       rc->uwbd.wq,
+                       !list_empty(&rc->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) {
+               spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
+               if (!list_empty(&rc->uwbd.event_list)) {
+                       evt = list_first_entry(&rc->uwbd.event_list, struct uwb_event, list_node);
                        list_del(&evt->list_node);
+               } else
+                       evt = NULL;
+               spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags);
+
+               if (evt) {
                        uwbd_event_handle(evt);
                        kfree(evt);
                }
-               mutex_unlock(&uwbd_event_mutex);
 
-               uwb_beca_purge();       /* Purge devices that left */
+               uwb_beca_purge(rc);     /* Purge devices that left */
        }
        return 0;
 }
 
 
 /** Start the UWB daemon */
-void uwbd_start(void)
+void uwbd_start(struct uwb_rc *rc)
 {
-       uwbd_task = kthread_run(uwbd, NULL, "uwbd");
-       if (uwbd_task == NULL)
+       rc->uwbd.task = kthread_run(uwbd, rc, "uwbd");
+       if (rc->uwbd.task == NULL)
                printk(KERN_ERR "UWB: Cannot start management daemon; "
                       "UWB won't work\n");
        else
-               uwbd_pid = uwbd_task->pid;
+               rc->uwbd.pid = rc->uwbd.task->pid;
 }
 
 /* Stop the UWB daemon and free any unprocessed events */
-void uwbd_stop(void)
+void uwbd_stop(struct uwb_rc *rc)
 {
-       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();
+       kthread_stop(rc->uwbd.task);
+       uwbd_flush(rc);
 }
 
 /*
@@ -373,18 +331,20 @@ void uwbd_stop(void)
  */
 void uwbd_event_queue(struct uwb_event *evt)
 {
+       struct uwb_rc *rc = evt->rc;
        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);
+
+       spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
+       if (rc->uwbd.pid != 0) {
+               list_add(&evt->list_node, &rc->uwbd.event_list);
+               wake_up_all(&rc->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);
+       spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags);
        return;
 }
 
@@ -392,10 +352,8 @@ 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) {
+       spin_lock_irq(&rc->uwbd.event_list_lock);
+       list_for_each_entry_safe(evt, nxt, &rc->uwbd.event_list, list_node) {
                if (evt->rc == rc) {
                        __uwb_rc_put(rc);
                        list_del(&evt->list_node);
@@ -404,7 +362,5 @@ void uwbd_flush(struct uwb_rc *rc)
                        kfree(evt);
                }
        }
-       spin_unlock_irq(&uwbd_event_list_lock);
-
-       mutex_unlock(&uwbd_event_mutex);
+       spin_unlock_irq(&rc->uwbd.event_list_lock);
 }