blob: 50578ba0061c7eb57571a94ffde98322a2ea2fdd [file] [log] [blame]
Chris Kelly56ff32f2012-02-20 21:12:27 +00001/* -----------------------------------------------------------------------------
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
Rupesh Gujare68a75f32012-03-29 13:11:50 +01008#include <linux/module.h>
9#include <linux/debugfs.h>
Chris Kelly56ff32f2012-02-20 21:12:27 +000010#include <linux/jiffies.h>
11#include <linux/uaccess.h>
12#include "oztrace.h"
13#include "ozevent.h"
Rupesh Gujare68a75f32012-03-29 13:11:50 +010014#include "ozappif.h"
Chris Kelly56ff32f2012-02-20 21:12:27 +000015/*------------------------------------------------------------------------------
Rupesh Gujare68a75f32012-03-29 13:11:50 +010016 * Although the event mask is logically part of the oz_evtdev structure, it is
Masanari Iidaba072752012-08-23 15:33:11 +090017 * needed outside of this file so define it separately to avoid the need to
Rupesh Gujare68a75f32012-03-29 13:11:50 +010018 * export definition of struct oz_evtdev.
Chris Kelly56ff32f2012-02-20 21:12:27 +000019 */
Rupesh Gujare68a75f32012-03-29 13:11:50 +010020u32 g_evt_mask;
Chris Kelly56ff32f2012-02-20 21:12:27 +000021/*------------------------------------------------------------------------------
22 */
23#define OZ_MAX_EVTS 2048 /* Must be power of 2 */
Rupesh Gujare68a75f32012-03-29 13:11:50 +010024struct 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
Chris Kelly56ff32f2012-02-20 21:12:27 +000037/*------------------------------------------------------------------------------
38 * Context: process
39 */
40void oz_event_init(void)
41{
Masanari Iidaba072752012-08-23 15:33:11 +090042 /* Because g_evtdev is static external all fields initially zero so no
43 * need to reinitialized those.
Rupesh Gujare68a75f32012-03-29 13:11:50 +010044 */
Chris Kelly56ff32f2012-02-20 21:12:27 +000045 oz_trace("Event tracing initialized\n");
Rupesh Gujare68a75f32012-03-29 13:11:50 +010046 spin_lock_init(&g_evtdev.lock);
47 atomic_set(&g_evtdev.users, 0);
Chris Kelly56ff32f2012-02-20 21:12:27 +000048}
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;
Rupesh Gujare68a75f32012-03-29 13:11:50 +010063 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];
Chris Kelly56ff32f2012-02-20 21:12:27 +000067 e->jiffies = jiffies;
68 e->evt = evt;
69 e->ctx1 = ctx1;
70 e->ctx2 = ctx2;
Rupesh Gujare68a75f32012-03-29 13:11:50 +010071 e->ctx3 = (__u32)(unsigned long)ctx3;
Chris Kelly56ff32f2012-02-20 21:12:27 +000072 e->ctx4 = ctx4;
Rupesh Gujare68a75f32012-03-29 13:11:50 +010073 g_evtdev.evt_in = ix;
Chris Kelly56ff32f2012-02-20 21:12:27 +000074 } else {
Rupesh Gujare68a75f32012-03-29 13:11:50 +010075 g_evtdev.missed_events++;
Chris Kelly56ff32f2012-02-20 21:12:27 +000076 }
Rupesh Gujare68a75f32012-03-29 13:11:50 +010077 spin_unlock_irqrestore(&g_evtdev.lock, irqstate);
Chris Kelly56ff32f2012-02-20 21:12:27 +000078}
79/*------------------------------------------------------------------------------
80 * Context: process
81 */
Sachin Kamat43f971eb2012-11-20 14:26:58 +053082#ifdef CONFIG_DEBUG_FS
Rupesh Gujare68a75f32012-03-29 13:11:50 +010083static void oz_events_clear(struct oz_evtdev *dev)
Chris Kelly56ff32f2012-02-20 21:12:27 +000084{
Rupesh Gujare68a75f32012-03-29 13:11:50 +010085 unsigned long irqstate;
86 oz_trace("Clearing events\n");
87 spin_lock_irqsave(&dev->lock, irqstate);
88 dev->evt_in = dev->evt_out = 0;
89 dev->missed_events = 0;
90 spin_unlock_irqrestore(&dev->lock, irqstate);
91}
Rupesh Gujare68a75f32012-03-29 13:11:50 +010092/*------------------------------------------------------------------------------
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;
Chris Kelly56ff32f2012-02-20 21:12:27 +0000105 }
Rupesh Gujare68a75f32012-03-29 13:11:50 +0100106}
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");
Chris Kelly56ff32f2012-02-20 21:12:27 +0000116 return 0;
117}
118/*------------------------------------------------------------------------------
119 * Context: process
120 */
Rupesh Gujare68a75f32012-03-29 13:11:50 +0100121ssize_t oz_events_read(struct file *filp, char __user *buf, size_t count,
122 loff_t *fpos)
Chris Kelly56ff32f2012-02-20 21:12:27 +0000123{
Rupesh Gujare68a75f32012-03-29 13:11:50 +0100124 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;
Chris Kelly56ff32f2012-02-20 21:12:27 +0000129
Rupesh Gujare68a75f32012-03-29 13:11:50 +0100130 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 */