summaryrefslogtreecommitdiffstats
path: root/drivers/staging/brcm80211/sys/wlc_event.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/brcm80211/sys/wlc_event.c')
-rw-r--r--drivers/staging/brcm80211/sys/wlc_event.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/drivers/staging/brcm80211/sys/wlc_event.c b/drivers/staging/brcm80211/sys/wlc_event.c
new file mode 100644
index 0000000..7e1bf0e
--- /dev/null
+++ b/drivers/staging/brcm80211/sys/wlc_event.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <bcmdefs.h>
+#include <linuxver.h>
+#include <bcmutils.h>
+#include <siutils.h>
+#include <wlioctl.h>
+#include <wlc_cfg.h>
+#include <wlc_pub.h>
+#include <wlc_key.h>
+#include <wl_export.h>
+#include <wlc_event.h>
+
+#include <d11.h>
+#include <wlc_rate.h>
+#include <wlc_mac80211.h>
+#ifdef MSGTRACE
+#include <msgtrace.h>
+#endif
+
+/* Local prototypes */
+static void wlc_timer_cb(void *arg);
+
+/* Private data structures */
+struct wlc_eventq {
+ wlc_event_t *head;
+ wlc_event_t *tail;
+ struct wlc_info *wlc;
+ void *wl;
+ wlc_pub_t *pub;
+ bool tpending;
+ bool workpending;
+ struct wl_timer *timer;
+ wlc_eventq_cb_t cb;
+ u8 event_inds_mask[broken_roundup(WLC_E_LAST, NBBY) / NBBY];
+};
+
+/*
+ * Export functions
+ */
+wlc_eventq_t *wlc_eventq_attach(wlc_pub_t *pub, struct wlc_info *wlc, void *wl,
+ wlc_eventq_cb_t cb)
+{
+ wlc_eventq_t *eq;
+
+ eq = kzalloc(sizeof(wlc_eventq_t), GFP_ATOMIC);
+ if (eq == NULL)
+ return NULL;
+
+ eq->cb = cb;
+ eq->wlc = wlc;
+ eq->wl = wl;
+ eq->pub = pub;
+
+ eq->timer = wl_init_timer(eq->wl, wlc_timer_cb, eq, "eventq");
+ if (!eq->timer) {
+ WL_ERROR(("wl%d: wlc_eventq_attach: timer failed\n",
+ pub->unit));
+ kfree(eq);
+ return NULL;
+ }
+
+ return eq;
+}
+
+int wlc_eventq_detach(wlc_eventq_t *eq)
+{
+ /* Clean up pending events */
+ wlc_eventq_down(eq);
+
+ if (eq->timer) {
+ if (eq->tpending) {
+ wl_del_timer(eq->wl, eq->timer);
+ eq->tpending = false;
+ }
+ wl_free_timer(eq->wl, eq->timer);
+ eq->timer = NULL;
+ }
+
+ ASSERT(wlc_eventq_avail(eq) == false);
+ kfree(eq);
+ return 0;
+}
+
+int wlc_eventq_down(wlc_eventq_t *eq)
+{
+ int callbacks = 0;
+ if (eq->tpending && !eq->workpending) {
+ if (!wl_del_timer(eq->wl, eq->timer))
+ callbacks++;
+
+ ASSERT(wlc_eventq_avail(eq) == true);
+ ASSERT(eq->workpending == false);
+ eq->workpending = true;
+ if (eq->cb)
+ eq->cb(eq->wlc);
+
+ ASSERT(eq->workpending == true);
+ eq->workpending = false;
+ eq->tpending = false;
+ } else {
+ ASSERT(eq->workpending || wlc_eventq_avail(eq) == false);
+ }
+ return callbacks;
+}
+
+wlc_event_t *wlc_event_alloc(wlc_eventq_t *eq)
+{
+ wlc_event_t *e;
+
+ e = kzalloc(sizeof(wlc_event_t), GFP_ATOMIC);
+
+ if (e == NULL)
+ return NULL;
+
+ return e;
+}
+
+void wlc_event_free(wlc_eventq_t *eq, wlc_event_t *e)
+{
+ ASSERT(e->data == NULL);
+ ASSERT(e->next == NULL);
+ kfree(e);
+}
+
+void wlc_eventq_enq(wlc_eventq_t *eq, wlc_event_t *e)
+{
+ ASSERT(e->next == NULL);
+ e->next = NULL;
+
+ if (eq->tail) {
+ eq->tail->next = e;
+ eq->tail = e;
+ } else
+ eq->head = eq->tail = e;
+
+ if (!eq->tpending) {
+ eq->tpending = true;
+ /* Use a zero-delay timer to trigger
+ * delayed processing of the event.
+ */
+ wl_add_timer(eq->wl, eq->timer, 0, 0);
+ }
+}
+
+wlc_event_t *wlc_eventq_deq(wlc_eventq_t *eq)
+{
+ wlc_event_t *e;
+
+ e = eq->head;
+ if (e) {
+ eq->head = e->next;
+ e->next = NULL;
+
+ if (eq->head == NULL)
+ eq->tail = eq->head;
+ }
+ return e;
+}
+
+wlc_event_t *wlc_eventq_next(wlc_eventq_t *eq, wlc_event_t *e)
+{
+#ifdef BCMDBG
+ wlc_event_t *etmp;
+
+ for (etmp = eq->head; etmp; etmp = etmp->next) {
+ if (etmp == e)
+ break;
+ }
+ ASSERT(etmp != NULL);
+#endif
+
+ return e->next;
+}
+
+int wlc_eventq_cnt(wlc_eventq_t *eq)
+{
+ wlc_event_t *etmp;
+ int cnt = 0;
+
+ for (etmp = eq->head; etmp; etmp = etmp->next)
+ cnt++;
+
+ return cnt;
+}
+
+bool wlc_eventq_avail(wlc_eventq_t *eq)
+{
+ return (eq->head != NULL);
+}
+
+/*
+ * Local Functions
+ */
+static void wlc_timer_cb(void *arg)
+{
+ struct wlc_eventq *eq = (struct wlc_eventq *)arg;
+
+ ASSERT(eq->tpending == true);
+ ASSERT(wlc_eventq_avail(eq) == true);
+ ASSERT(eq->workpending == false);
+ eq->workpending = true;
+
+ if (eq->cb)
+ eq->cb(eq->wlc);
+
+ ASSERT(wlc_eventq_avail(eq) == false);
+ ASSERT(eq->tpending == true);
+ eq->workpending = false;
+ eq->tpending = false;
+}
OpenPOWER on IntegriCloud