linux/drivers/staging/ozwpan/ozevent.c
<<
>>
Prefs
   1/* -----------------------------------------------------------------------------
   2 * Copyright (c) 2011 Ozmo Inc
   3 * Released under the GNU General Public License Version 2 (GPLv2).
   4 * -----------------------------------------------------------------------------
   5 */
   6#include "ozconfig.h"
   7#ifdef WANT_EVENT_TRACE
   8#include <linux/module.h>
   9#include <linux/debugfs.h>
  10#include <linux/jiffies.h>
  11#include <linux/uaccess.h>
  12#include "oztrace.h"
  13#include "ozevent.h"
  14#include "ozappif.h"
  15/*------------------------------------------------------------------------------
  16 * Although the event mask is logically part of the oz_evtdev structure, it is
  17 * needed outside of this file so define it separately to avoid the need to
  18 * export definition of struct oz_evtdev.
  19 */
  20u32 g_evt_mask;
  21/*------------------------------------------------------------------------------
  22 */
  23#define OZ_MAX_EVTS     2048    /* Must be power of 2 */
  24struct oz_evtdev {
  25        struct dentry *root_dir;
  26        int evt_in;
  27        int evt_out;
  28        int missed_events;
  29        int present;
  30        atomic_t users;
  31        spinlock_t lock;
  32        struct oz_event evts[OZ_MAX_EVTS];
  33};
  34
  35static struct oz_evtdev g_evtdev;
  36
  37/*------------------------------------------------------------------------------
  38 * Context: process
  39 */
  40void oz_event_init(void)
  41{
  42        /* Because g_evtdev is static external all fields initially zero so no
  43         * need to reinitialized those.
  44         */
  45        oz_trace("Event tracing initialized\n");
  46        spin_lock_init(&g_evtdev.lock);
  47        atomic_set(&g_evtdev.users, 0);
  48}
  49/*------------------------------------------------------------------------------
  50 * Context: process
  51 */
  52void oz_event_term(void)
  53{
  54        oz_trace("Event tracing terminated\n");
  55}
  56/*------------------------------------------------------------------------------
  57 * Context: any
  58 */
  59void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4)
  60{
  61        unsigned long irqstate;
  62        int ix;
  63        spin_lock_irqsave(&g_evtdev.lock, irqstate);
  64        ix = (g_evtdev.evt_in + 1) & (OZ_MAX_EVTS - 1);
  65        if (ix != g_evtdev.evt_out) {
  66                struct oz_event *e = &g_evtdev.evts[g_evtdev.evt_in];
  67                e->jiffies = jiffies;
  68                e->evt = evt;
  69                e->ctx1 = ctx1;
  70                e->ctx2 = ctx2;
  71                e->ctx3 = (__u32)(unsigned long)ctx3;
  72                e->ctx4 = ctx4;
  73                g_evtdev.evt_in = ix;
  74        } else {
  75                g_evtdev.missed_events++;
  76        }
  77        spin_unlock_irqrestore(&g_evtdev.lock, irqstate);
  78}
  79/*------------------------------------------------------------------------------
  80 * Context: process
  81 */
  82static void oz_events_clear(struct oz_evtdev *dev)
  83{
  84        unsigned long irqstate;
  85        oz_trace("Clearing events\n");
  86        spin_lock_irqsave(&dev->lock, irqstate);
  87        dev->evt_in = dev->evt_out = 0;
  88        dev->missed_events = 0;
  89        spin_unlock_irqrestore(&dev->lock, irqstate);
  90}
  91#ifdef CONFIG_DEBUG_FS
  92/*------------------------------------------------------------------------------
  93 * Context: process
  94 */
  95int oz_events_open(struct inode *inode, struct file *filp)
  96{
  97        oz_trace("oz_evt_open()\n");
  98        oz_trace("Open flags: 0x%x\n", filp->f_flags);
  99        if (atomic_add_return(1, &g_evtdev.users) == 1) {
 100                oz_events_clear(&g_evtdev);
 101                return nonseekable_open(inode, filp);
 102        } else {
 103                atomic_dec(&g_evtdev.users);
 104                return -EBUSY;
 105        }
 106}
 107/*------------------------------------------------------------------------------
 108 * Context: process
 109 */
 110int oz_events_release(struct inode *inode, struct file *filp)
 111{
 112        oz_events_clear(&g_evtdev);
 113        atomic_dec(&g_evtdev.users);
 114        g_evt_mask = 0;
 115        oz_trace("oz_evt_release()\n");
 116        return 0;
 117}
 118/*------------------------------------------------------------------------------
 119 * Context: process
 120 */
 121ssize_t oz_events_read(struct file *filp, char __user *buf, size_t count,
 122                loff_t *fpos)
 123{
 124        struct oz_evtdev *dev = &g_evtdev;
 125        int rc = 0;
 126        int nb_evts = count / sizeof(struct oz_event);
 127        int n;
 128        int sz;
 129
 130        n = dev->evt_in - dev->evt_out;
 131        if (n < 0)
 132                n += OZ_MAX_EVTS;
 133        if (nb_evts > n)
 134                nb_evts = n;
 135        if (nb_evts == 0)
 136                goto out;
 137        n = OZ_MAX_EVTS - dev->evt_out;
 138        if (n > nb_evts)
 139                n = nb_evts;
 140        sz = n * sizeof(struct oz_event);
 141        if (copy_to_user(buf, &dev->evts[dev->evt_out], sz)) {
 142                rc = -EFAULT;
 143                goto out;
 144        }
 145        if (n == nb_evts)
 146                goto out2;
 147        n = nb_evts - n;
 148        if (copy_to_user(buf + sz, dev->evts, n * sizeof(struct oz_event))) {
 149                rc = -EFAULT;
 150                goto out;
 151        }
 152out2:
 153        dev->evt_out = (dev->evt_out + nb_evts) & (OZ_MAX_EVTS - 1);
 154        rc = nb_evts * sizeof(struct oz_event);
 155out:
 156        return rc;
 157}
 158/*------------------------------------------------------------------------------
 159 */
 160const struct file_operations oz_events_fops = {
 161        .owner =        THIS_MODULE,
 162        .open =         oz_events_open,
 163        .release =      oz_events_release,
 164        .read =         oz_events_read,
 165};
 166/*------------------------------------------------------------------------------
 167 * Context: process
 168 */
 169void oz_debugfs_init(void)
 170{
 171        struct dentry *parent;
 172
 173        parent = debugfs_create_dir("ozwpan", NULL);
 174        if (parent  == NULL) {
 175                oz_trace("Failed to create debugfs directory ozmo\n");
 176                return;
 177        } else {
 178                g_evtdev.root_dir = parent;
 179                if (debugfs_create_file("events", S_IRUSR, parent, NULL,
 180                                                &oz_events_fops) == NULL)
 181                        oz_trace("Failed to create file ozmo/events\n");
 182                if (debugfs_create_x32("event_mask", S_IRUSR | S_IWUSR, parent,
 183                                                        &g_evt_mask) == NULL)
 184                        oz_trace("Failed to create file ozmo/event_mask\n");
 185        }
 186}
 187/*------------------------------------------------------------------------------
 188 * Context: process
 189 */
 190void oz_debugfs_remove(void)
 191{
 192        debugfs_remove_recursive(g_evtdev.root_dir);
 193}
 194#endif /* CONFIG_DEBUG_FS */
 195#endif /* WANT_EVENT_TRACE */
 196