diff options
Diffstat (limited to 'drivers/staging/ozwpan/ozevent.c')
| -rw-r--r-- | drivers/staging/ozwpan/ozevent.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/drivers/staging/ozwpan/ozevent.c b/drivers/staging/ozwpan/ozevent.c new file mode 100644 index 00000000..77e86753 --- /dev/null +++ b/drivers/staging/ozwpan/ozevent.c @@ -0,0 +1,195 @@ +/* ----------------------------------------------------------------------------- + * Copyright (c) 2011 Ozmo Inc + * Released under the GNU General Public License Version 2 (GPLv2). + * ----------------------------------------------------------------------------- + */ +#include "ozconfig.h" +#ifdef WANT_EVENT_TRACE +#include <linux/module.h> +#include <linux/debugfs.h> +#include <linux/jiffies.h> +#include <linux/uaccess.h> +#include "oztrace.h" +#include "ozevent.h" +#include "ozappif.h" +/*------------------------------------------------------------------------------ + * Although the event mask is logically part of the oz_evtdev structure, it is + * needed outside of this file so define it separately to avoid the need to + * export definition of struct oz_evtdev. + */ +u32 g_evt_mask; +/*------------------------------------------------------------------------------ + */ +#define OZ_MAX_EVTS 2048 /* Must be power of 2 */ +struct oz_evtdev { + struct dentry *root_dir; + int evt_in; + int evt_out; + int missed_events; + int present; + atomic_t users; + spinlock_t lock; + struct oz_event evts[OZ_MAX_EVTS]; +}; + +static struct oz_evtdev g_evtdev; + +/*------------------------------------------------------------------------------ + * Context: process + */ +void oz_event_init(void) +{ + /* Because g_evtdev is static external all fields initially zero so no + * need to reinitialized those. + */ + oz_trace("Event tracing initialized\n"); + spin_lock_init(&g_evtdev.lock); + atomic_set(&g_evtdev.users, 0); +} +/*------------------------------------------------------------------------------ + * Context: process + */ +void oz_event_term(void) +{ + oz_trace("Event tracing terminated\n"); +} +/*------------------------------------------------------------------------------ + * Context: any + */ +void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4) +{ + unsigned long irqstate; + int ix; + spin_lock_irqsave(&g_evtdev.lock, irqstate); + ix = (g_evtdev.evt_in + 1) & (OZ_MAX_EVTS - 1); + if (ix != g_evtdev.evt_out) { + struct oz_event *e = &g_evtdev.evts[g_evtdev.evt_in]; + e->jiffies = jiffies; + e->evt = evt; + e->ctx1 = ctx1; + e->ctx2 = ctx2; + e->ctx3 = (__u32)(unsigned long)ctx3; + e->ctx4 = ctx4; + g_evtdev.evt_in = ix; + } else { + g_evtdev.missed_events++; + } + spin_unlock_irqrestore(&g_evtdev.lock, irqstate); +} +/*------------------------------------------------------------------------------ + * Context: process + */ +#ifdef CONFIG_DEBUG_FS +static void oz_events_clear(struct oz_evtdev *dev) +{ + unsigned long irqstate; + oz_trace("Clearing events\n"); + spin_lock_irqsave(&dev->lock, irqstate); + dev->evt_in = dev->evt_out = 0; + dev->missed_events = 0; + spin_unlock_irqrestore(&dev->lock, irqstate); +} +/*------------------------------------------------------------------------------ + * Context: process + */ +static int oz_events_open(struct inode *inode, struct file *filp) +{ + oz_trace("oz_evt_open()\n"); + oz_trace("Open flags: 0x%x\n", filp->f_flags); + if (atomic_add_return(1, &g_evtdev.users) == 1) { + oz_events_clear(&g_evtdev); + return nonseekable_open(inode, filp); + } else { + atomic_dec(&g_evtdev.users); + return -EBUSY; + } +} +/*------------------------------------------------------------------------------ + * Context: process + */ +static int oz_events_release(struct inode *inode, struct file *filp) +{ + oz_events_clear(&g_evtdev); + atomic_dec(&g_evtdev.users); + g_evt_mask = 0; + oz_trace("oz_evt_release()\n"); + return 0; +} +/*------------------------------------------------------------------------------ + * Context: process + */ +static ssize_t oz_events_read(struct file *filp, char __user *buf, size_t count, + loff_t *fpos) +{ + struct oz_evtdev *dev = &g_evtdev; + int rc = 0; + int nb_evts = count / sizeof(struct oz_event); + int n; + int sz; + + n = dev->evt_in - dev->evt_out; + if (n < 0) + n += OZ_MAX_EVTS; + if (nb_evts > n) + nb_evts = n; + if (nb_evts == 0) + goto out; + n = OZ_MAX_EVTS - dev->evt_out; + if (n > nb_evts) + n = nb_evts; + sz = n * sizeof(struct oz_event); + if (copy_to_user(buf, &dev->evts[dev->evt_out], sz)) { + rc = -EFAULT; + goto out; + } + if (n == nb_evts) + goto out2; + n = nb_evts - n; + if (copy_to_user(buf + sz, dev->evts, n * sizeof(struct oz_event))) { + rc = -EFAULT; + goto out; + } +out2: + dev->evt_out = (dev->evt_out + nb_evts) & (OZ_MAX_EVTS - 1); + rc = nb_evts * sizeof(struct oz_event); +out: + return rc; +} +/*------------------------------------------------------------------------------ + */ +static const struct file_operations oz_events_fops = { + .owner = THIS_MODULE, + .open = oz_events_open, + .release = oz_events_release, + .read = oz_events_read, +}; +/*------------------------------------------------------------------------------ + * Context: process + */ +void oz_debugfs_init(void) +{ + struct dentry *parent; + + parent = debugfs_create_dir("ozwpan", NULL); + if (parent == NULL) { + oz_trace("Failed to create debugfs directory ozmo\n"); + return; + } else { + g_evtdev.root_dir = parent; + if (debugfs_create_file("events", S_IRUSR, parent, NULL, + &oz_events_fops) == NULL) + oz_trace("Failed to create file ozmo/events\n"); + if (debugfs_create_x32("event_mask", S_IRUSR | S_IWUSR, parent, + &g_evt_mask) == NULL) + oz_trace("Failed to create file ozmo/event_mask\n"); + } +} +/*------------------------------------------------------------------------------ + * Context: process + */ +void oz_debugfs_remove(void) +{ + debugfs_remove_recursive(g_evtdev.root_dir); +} +#endif /* CONFIG_DEBUG_FS */ +#endif /* WANT_EVENT_TRACE */ |
