gpu: pvr: pdumpfs: add Kconfig and debugfs pdump mode handling
[sgx.git] / pvr / pvr_pdumpfs.c
1 /*
2  * Copyright (c) 2010-2011 by Luc Verhaegen <libv@codethink.co.uk>
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */
18
19 #include <linux/mutex.h>
20 #include <linux/uaccess.h>
21 #include <linux/debugfs.h>
22
23 #include "img_defs.h"
24 #include "services_headers.h"
25 #include "pvr_pdump.h"
26 #include "pvr_pdumpfs.h"
27
28 static struct mutex pdumpfs_mutex[1];
29
30 enum pdumpfs_mode {
31         PDUMPFS_MODE_DISABLED,
32         PDUMPFS_MODE_STANDARD,
33         PDUMPFS_MODE_FULL,
34 };
35
36 static enum pdumpfs_mode pdumpfs_mode =
37 #if defined(CONFIG_PVR_PDUMP_MODE_STANDARD)
38         PDUMPFS_MODE_STANDARD
39 #elif defined(CONFIG_PVR_PDUMP_MODE_FULL)
40         PDUMPFS_MODE_FULL
41 #else
42         PDUMPFS_MODE_DISABLED
43 #endif
44         ;
45
46 static u32 pdumpfs_frame_number;
47
48 void
49 pdumpfs_frame_set(u32 frame)
50 {
51         mutex_lock(pdumpfs_mutex);
52
53         pdumpfs_frame_number = frame;
54
55         mutex_unlock(pdumpfs_mutex);
56 }
57
58 bool
59 pdumpfs_capture_enabled(void)
60 {
61         bool ret;
62
63         mutex_lock(pdumpfs_mutex);
64
65         if (pdumpfs_mode == PDUMPFS_MODE_FULL)
66                 ret = true;
67         else
68                 ret = false;
69
70         mutex_unlock(pdumpfs_mutex);
71
72         return ret;
73 }
74
75 bool
76 pdumpfs_flags_check(u32 flags)
77 {
78         bool ret;
79
80         if (flags & PDUMP_FLAGS_NEVER)
81                 return false;
82
83         mutex_lock(pdumpfs_mutex);
84
85         if (pdumpfs_mode == PDUMPFS_MODE_FULL)
86                 ret = true;
87         else if ((pdumpfs_mode == PDUMPFS_MODE_STANDARD) &&
88                  (flags & PDUMP_FLAGS_CONTINUOUS))
89                 ret = true;
90         else
91                 ret = false;
92
93         mutex_unlock(pdumpfs_mutex);
94
95         return ret;
96 }
97
98 enum PVRSRV_ERROR
99 pdumpfs_write_data(void *buffer, size_t size, bool from_user)
100 {
101         mutex_lock(pdumpfs_mutex);
102
103         mutex_unlock(pdumpfs_mutex);
104
105         return PVRSRV_OK;
106 }
107
108 void
109 pdumpfs_write_string(char *string)
110 {
111         mutex_lock(pdumpfs_mutex);
112
113         mutex_unlock(pdumpfs_mutex);
114 }
115
116 /*
117  * DebugFS entries.
118  */
119 static const struct {
120         char *name;
121         enum pdumpfs_mode mode;
122 } pdumpfs_modes[] = {
123         {"disabled",   PDUMPFS_MODE_DISABLED},
124         {"standard",   PDUMPFS_MODE_STANDARD},
125         {"full",       PDUMPFS_MODE_FULL},
126         {NULL, PDUMPFS_MODE_DISABLED}
127 };
128
129 static ssize_t
130 pdumpfs_mode_read(struct file *filp, char __user *buf, size_t size,
131                   loff_t *f_pos)
132 {
133         char tmp[16];
134         int i;
135
136         tmp[0] = 0;
137
138         mutex_lock(pdumpfs_mutex);
139
140         for (i = 0; pdumpfs_modes[i].name; i++)
141                 if (pdumpfs_modes[i].mode == pdumpfs_mode)
142                         snprintf(tmp, sizeof(tmp), "%s\n",
143                                  pdumpfs_modes[i].name);
144
145         mutex_unlock(pdumpfs_mutex);
146
147         if (strlen(tmp) < *f_pos)
148                 return 0;
149
150         if ((strlen(tmp) + 1) < (*f_pos + size))
151                 size = strlen(tmp) + 1 - *f_pos;
152
153         if (copy_to_user(buf, tmp + *f_pos, size))
154                 return -EFAULT;
155
156         *f_pos += size;
157         return size;
158 }
159
160 static ssize_t
161 pdumpfs_mode_write(struct file *filp, const char __user *buf, size_t size,
162                    loff_t *f_pos)
163 {
164         static char tmp[16];
165         int i;
166
167         if (*f_pos > sizeof(tmp))
168                 return -EINVAL;
169
170         if (size > (sizeof(tmp) - *f_pos))
171                 size = sizeof(tmp) - *f_pos;
172
173         if (copy_from_user(tmp + *f_pos, buf, size))
174                 return -EFAULT;
175
176         *f_pos += size;
177
178         mutex_lock(pdumpfs_mutex);
179
180         for (i = 0; pdumpfs_modes[i].name; i++)
181                 if (!strnicmp(tmp, pdumpfs_modes[i].name,
182                               strlen(pdumpfs_modes[i].name))) {
183                         pdumpfs_mode = pdumpfs_modes[i].mode;
184                         mutex_unlock(pdumpfs_mutex);
185                         return size;
186                 }
187
188         mutex_unlock(pdumpfs_mutex);
189         return -EINVAL;
190 }
191
192 static const struct file_operations pdumpfs_mode_fops = {
193         .owner = THIS_MODULE,
194         .llseek = no_llseek,
195         .read = pdumpfs_mode_read,
196         .write = pdumpfs_mode_write,
197 };
198
199 static ssize_t
200 pdumpfs_modes_possible_read(struct file *filp, char __user *buf, size_t size,
201                             loff_t *f_pos)
202 {
203         unsigned int i, skip = *f_pos, pos = 0;
204
205         for (i = 0; pdumpfs_modes[i].name; i++) {
206                 if (i) { /* space */
207                         if (skip)
208                                 skip--;
209                         else if (size > pos) {
210                                 if (copy_to_user(buf + pos, " ", 1))
211                                         return -EFAULT;
212                                 pos++;
213                         }
214                 }
215
216                 if (size) {
217                         int len = strlen(pdumpfs_modes[i].name);
218
219                         if (skip >= len) {
220                                 skip -= len;
221                         } else if (size > pos) {
222                                 len = min(len - skip, size - pos);
223
224                                 if (copy_to_user(buf + pos,
225                                                  pdumpfs_modes[i].name + skip,
226                                                  len))
227                                         return -EFAULT;
228
229                                 skip = 0;
230                                 pos += len;
231                         }
232                 }
233         }
234
235         *f_pos += pos;
236         return pos;
237 }
238
239 static const struct file_operations pdumpfs_modes_possible_fops = {
240         .owner = THIS_MODULE,
241         .llseek = no_llseek,
242         .read = pdumpfs_modes_possible_read,
243 };
244
245 static struct dentry *pdumpfs_dir;
246
247 static void
248 pdumpfs_file_create(const char *name, mode_t mode,
249                     const struct file_operations *fops)
250 {
251         struct dentry *tmp = NULL;
252
253         tmp = debugfs_create_file(name, mode, pdumpfs_dir, NULL, fops);
254         if (!tmp)
255                 pr_err("%s: failed to create pvr/%s file.\n", __func__, name);
256 }
257
258 static int
259 pdumpfs_fs_init(void)
260 {
261         if (!pvr_debugfs_dir) {
262                 pr_err("%s: debugfs pvr/ directory does not exist.\n",
263                        __func__);
264                 return -ENOENT;
265         }
266
267         pdumpfs_dir = debugfs_create_dir("pdump", pvr_debugfs_dir);
268         if (!pdumpfs_dir) {
269                 pr_err("%s: failed to create top level directory.\n",
270                        __func__);
271                 return -ENOENT;
272         }
273
274         pdumpfs_file_create("mode", S_IRUSR | S_IWUSR,
275                             &pdumpfs_mode_fops);
276         pdumpfs_file_create("modes_possible", S_IRUSR,
277                             &pdumpfs_modes_possible_fops);
278
279         return 0;
280 }
281
282 static void
283 pdumpfs_fs_destroy(void)
284 {
285         if (pdumpfs_dir)
286                 debugfs_remove_recursive(pdumpfs_dir);
287 }
288
289 int
290 pdumpfs_init(void)
291 {
292         mutex_init(pdumpfs_mutex);
293
294         pdumpfs_fs_init();
295
296         return 0;
297 }
298
299 void
300 pdumpfs_cleanup(void)
301 {
302         pdumpfs_fs_destroy();
303 }