Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma
[profile/ivi/kernel-x86-ivi.git] / drivers / staging / ozwpan / ozevent.c
index 73703d3..7f66b4f 100644 (file)
@@ -5,29 +5,46 @@
  */
 #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 seperately to avoid the need to
+ * export definition of struct oz_evtdev.
  */
-unsigned long g_evt_mask = 0xffffffff;
+u32 g_evt_mask;
 /*------------------------------------------------------------------------------
  */
 #define OZ_MAX_EVTS    2048    /* Must be power of 2 */
-DEFINE_SPINLOCK(g_eventlock);
-static int g_evt_in;
-static int g_evt_out;
-static int g_missed_events;
-static struct oz_event g_events[OZ_MAX_EVTS];
+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 initally zero so no
+        * need to reinitialised those.
+        */
        oz_trace("Event tracing initialized\n");
-       g_evt_in = g_evt_out = 0;
-       g_missed_events = 0;
+       spin_lock_init(&g_evtdev.lock);
+       atomic_set(&g_evtdev.users, 0);
 }
 /*------------------------------------------------------------------------------
  * Context: process
@@ -43,74 +60,136 @@ void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4)
 {
        unsigned long irqstate;
        int ix;
-       spin_lock_irqsave(&g_eventlock, irqstate);
-       ix = (g_evt_in + 1) & (OZ_MAX_EVTS - 1);
-       if (ix != g_evt_out) {
-               struct oz_event *e = &g_events[g_evt_in];
+       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 = ctx3;
+               e->ctx3 = (__u32)(unsigned long)ctx3;
                e->ctx4 = ctx4;
-               g_evt_in = ix;
+               g_evtdev.evt_in = ix;
        } else {
-               g_missed_events++;
+               g_evtdev.missed_events++;
        }
-       spin_unlock_irqrestore(&g_eventlock, irqstate);
+       spin_unlock_irqrestore(&g_evtdev.lock, irqstate);
 }
 /*------------------------------------------------------------------------------
  * Context: process
  */
-int oz_events_copy(struct oz_evtlist __user *lst)
+static void oz_events_clear(struct oz_evtdev *dev)
 {
-       int first;
-       int ix;
-       struct hdr {
-               int count;
-               int missed;
-       } hdr;
-       ix = g_evt_out;
-       hdr.count = g_evt_in - ix;
-       if (hdr.count < 0)
-               hdr.count += OZ_MAX_EVTS;
-       if (hdr.count > OZ_EVT_LIST_SZ)
-               hdr.count = OZ_EVT_LIST_SZ;
-       hdr.missed = g_missed_events;
-       g_missed_events = 0;
-       if (copy_to_user((void __user *)lst, &hdr, sizeof(hdr)))
-               return -EFAULT;
-       first = OZ_MAX_EVTS - ix;
-       if (first > hdr.count)
-               first = hdr.count;
-       if (first) {
-               int sz = first*sizeof(struct oz_event);
-               void __user *p = (void __user *)lst->evts;
-               if (copy_to_user(p, &g_events[ix], sz))
-                       return -EFAULT;
-               if (hdr.count > first) {
-                       p = (void __user *)&lst->evts[first];
-                       sz = (hdr.count-first)*sizeof(struct oz_event);
-                       if (copy_to_user(p, g_events, sz))
-                               return -EFAULT;
-               }
+       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);
+}
+#ifdef CONFIG_DEBUG_FS
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+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;
        }
-       ix += hdr.count;
-       if (ix >= OZ_MAX_EVTS)
-               ix -= OZ_MAX_EVTS;
-       g_evt_out = ix;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+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
  */
-void oz_events_clear(void)
+ssize_t oz_events_read(struct file *filp, char __user *buf, size_t count,
+               loff_t *fpos)
 {
-       unsigned long irqstate;
-       spin_lock_irqsave(&g_eventlock, irqstate);
-       g_evt_in = g_evt_out = 0;
-       g_missed_events = 0;
-       spin_unlock_irqrestore(&g_eventlock, irqstate);
+       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;
 }
-#endif /* WANT_EVENT_TRACE */
+/*------------------------------------------------------------------------------
+ */
+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 */