summaryrefslogtreecommitdiffstats
path: root/drivers/uwb/uwbd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/uwb/uwbd.c')
-rw-r--r--drivers/uwb/uwbd.c176
1 files changed, 66 insertions, 110 deletions
diff --git a/drivers/uwb/uwbd.c b/drivers/uwb/uwbd.c
index 78908416e42c..57bd6bfef37e 100644
--- a/drivers/uwb/uwbd.c
+++ b/drivers/uwb/uwbd.c
@@ -68,17 +68,13 @@
*
* 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);
}
OpenPOWER on IntegriCloud