• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
20 u32 g_evt_mask;
21 /*------------------------------------------------------------------------------
22  */
23 #define OZ_MAX_EVTS	2048	/* Must be power of 2 */
24 struct 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 
35 static struct oz_evtdev g_evtdev;
36 
37 /*------------------------------------------------------------------------------
38  * Context: process
39  */
oz_event_init(void)40 void 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  */
oz_event_term(void)52 void oz_event_term(void)
53 {
54 	oz_trace("Event tracing terminated\n");
55 }
56 /*------------------------------------------------------------------------------
57  * Context: any
58  */
oz_event_log2(u8 evt,u8 ctx1,u16 ctx2,void * ctx3,unsigned ctx4)59 void 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  */
82 #ifdef CONFIG_DEBUG_FS
oz_events_clear(struct oz_evtdev * dev)83 static void oz_events_clear(struct oz_evtdev *dev)
84 {
85 	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 }
92 /*------------------------------------------------------------------------------
93  * Context: process
94  */
oz_events_open(struct inode * inode,struct file * filp)95 static int 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  */
oz_events_release(struct inode * inode,struct file * filp)110 static int 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  */
oz_events_read(struct file * filp,char __user * buf,size_t count,loff_t * fpos)121 static ssize_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 	}
152 out2:
153 	dev->evt_out = (dev->evt_out + nb_evts) & (OZ_MAX_EVTS - 1);
154 	rc = nb_evts * sizeof(struct oz_event);
155 out:
156 	return rc;
157 }
158 /*------------------------------------------------------------------------------
159  */
160 static const 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  */
oz_debugfs_init(void)169 void 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  */
oz_debugfs_remove(void)190 void 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