2 * Copyright (c) 2010-2011 by Luc Verhaegen <libv@codethink.co.uk>
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.
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.
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
19 #include <linux/mutex.h>
20 #include <linux/uaccess.h>
21 #include <linux/debugfs.h>
24 #include "services_headers.h"
25 #include "pvr_pdump.h"
26 #include "pvr_pdumpfs.h"
28 static struct mutex pdumpfs_mutex[1];
31 PDUMPFS_MODE_DISABLED,
32 PDUMPFS_MODE_STANDARD,
36 static enum pdumpfs_mode pdumpfs_mode =
37 #if defined(CONFIG_PVR_PDUMP_MODE_STANDARD)
39 #elif defined(CONFIG_PVR_PDUMP_MODE_FULL)
46 #define FRAME_PAGE_COUNT 2040
48 struct pdumpfs_frame {
49 struct pdumpfs_frame *next;
56 unsigned long pages[FRAME_PAGE_COUNT];
59 static u32 frame_count_max = CONFIG_PVR_PDUMP_INITIAL_MAX_FRAME_COUNT;
60 static u32 frame_count;
62 static struct pdumpfs_frame *frame_init;
63 static struct pdumpfs_frame *frame_stream;
64 static struct pdumpfs_frame *frame_current;
66 static struct pdumpfs_frame *
69 struct pdumpfs_frame *frame =
70 kmalloc(sizeof(struct pdumpfs_frame), GFP_KERNEL);
74 memset(frame, 0, sizeof(struct pdumpfs_frame));
80 frame_destroy(struct pdumpfs_frame *frame)
87 for (i = 0; i < frame->page_count; i++)
88 free_page(frame->pages[i]);
94 frame_destroy_all(void)
98 frame_destroy(frame_init);
101 while (frame_stream) {
102 struct pdumpfs_frame *frame = frame_stream;
104 frame_stream = frame->next;
106 frame_destroy(frame);
114 while (frame_count > frame_count_max) {
115 struct pdumpfs_frame *frame = frame_stream;
117 frame_stream = frame->next;
120 frame_destroy(frame);
126 frame_new(u32 pid, u32 number)
128 struct pdumpfs_frame *frame = frame_create();
131 pr_err("%s: Failed to create frame.\n", __func__);
136 frame->number = number;
141 if (frame_current != frame_init)
142 frame_current->next = frame;
144 frame_stream = frame;
148 frame_current = frame;
156 pdumpfs_frame_set(u32 pid, u32 frame)
158 mutex_lock(pdumpfs_mutex);
160 frame_new(pid, frame);
162 mutex_unlock(pdumpfs_mutex);
166 pdumpfs_capture_enabled(void)
170 mutex_lock(pdumpfs_mutex);
172 if (pdumpfs_mode == PDUMPFS_MODE_FULL)
177 mutex_unlock(pdumpfs_mutex);
183 pdumpfs_flags_check(u32 flags)
187 if (flags & PDUMP_FLAGS_NEVER)
190 mutex_lock(pdumpfs_mutex);
192 if (pdumpfs_mode == PDUMPFS_MODE_FULL)
194 else if ((pdumpfs_mode == PDUMPFS_MODE_STANDARD) &&
195 (flags & PDUMP_FLAGS_CONTINUOUS))
200 mutex_unlock(pdumpfs_mutex);
206 pdumpfs_frame_write_low(void *buffer, size_t size, bool from_user)
208 struct pdumpfs_frame *frame = frame_current;
213 size_t offset = frame->offset & ~PAGE_MASK;
217 if (frame->page_count >= FRAME_PAGE_COUNT) {
218 pr_err("%s: Frame size overrun.\n", __func__);
222 page = __get_free_page(GFP_KERNEL);
224 pr_err("%s: failed to get free page.\n",
229 frame->pages[frame->page_count] = page;
233 frame->pages[frame->page_count - 1];
235 if (count > (PAGE_SIZE - offset))
236 count = PAGE_SIZE - offset;
239 if (copy_from_user(((u8 *) page) + offset,
240 (void __user __force *) buffer,
244 memcpy(((u8 *) page) + offset, buffer, count);
249 frame->offset += count;
255 pdumpfs_frame_write(void *buffer, size_t size, bool from_user)
259 if ((frame_current->offset + size) > (PAGE_SIZE * FRAME_PAGE_COUNT)) {
260 u32 pid = OSGetCurrentProcessIDKM();
261 struct task_struct *task;
263 pr_err("Frame overrun!!!\n");
265 ret = frame_new(pid, -1);
270 task = pid_task(find_vpid(pid), PIDTYPE_PID);
272 #define FRAME_OVERRUN_MESSAGE "-- Starting forced frame caused by "
273 pdumpfs_frame_write_low(FRAME_OVERRUN_MESSAGE,
274 sizeof(FRAME_OVERRUN_MESSAGE), false);
275 pdumpfs_frame_write_low(task->comm, strlen(task->comm), false);
276 pdumpfs_frame_write_low("\r\n", 2, false);
278 pr_err("%s: Frame size overrun, caused by %d (%s)\n",
279 __func__, pid, task->comm);
284 return pdumpfs_frame_write_low(buffer, size, from_user);
288 pdumpfs_write_data(void *buffer, size_t size, bool from_user)
290 mutex_lock(pdumpfs_mutex);
292 size = pdumpfs_frame_write(buffer, size, from_user);
294 mutex_unlock(pdumpfs_mutex);
296 if ((size >= 0) || (size == -ENOMEM))
299 return PVRSRV_ERROR_GENERIC;
303 pdumpfs_write_string(char *string)
305 mutex_lock(pdumpfs_mutex);
307 pdumpfs_frame_write(string, strlen(string), false);
309 mutex_unlock(pdumpfs_mutex);
315 static const struct {
317 enum pdumpfs_mode mode;
318 } pdumpfs_modes[] = {
319 {"disabled", PDUMPFS_MODE_DISABLED},
320 {"standard", PDUMPFS_MODE_STANDARD},
321 {"full", PDUMPFS_MODE_FULL},
322 {NULL, PDUMPFS_MODE_DISABLED}
326 pdumpfs_mode_read(struct file *filp, char __user *buf, size_t size,
334 mutex_lock(pdumpfs_mutex);
336 for (i = 0; pdumpfs_modes[i].name; i++)
337 if (pdumpfs_modes[i].mode == pdumpfs_mode)
338 snprintf(tmp, sizeof(tmp), "%s\n",
339 pdumpfs_modes[i].name);
341 mutex_unlock(pdumpfs_mutex);
343 if (strlen(tmp) < *f_pos)
346 if ((strlen(tmp) + 1) < (*f_pos + size))
347 size = strlen(tmp) + 1 - *f_pos;
349 if (copy_to_user(buf, tmp + *f_pos, size))
357 pdumpfs_mode_write(struct file *filp, const char __user *buf, size_t size,
363 if (*f_pos > sizeof(tmp))
366 if (size > (sizeof(tmp) - *f_pos))
367 size = sizeof(tmp) - *f_pos;
369 if (copy_from_user(tmp + *f_pos, buf, size))
374 mutex_lock(pdumpfs_mutex);
376 for (i = 0; pdumpfs_modes[i].name; i++)
377 if (!strnicmp(tmp, pdumpfs_modes[i].name,
378 strlen(pdumpfs_modes[i].name))) {
379 pdumpfs_mode = pdumpfs_modes[i].mode;
380 mutex_unlock(pdumpfs_mutex);
384 mutex_unlock(pdumpfs_mutex);
388 static const struct file_operations pdumpfs_mode_fops = {
389 .owner = THIS_MODULE,
391 .read = pdumpfs_mode_read,
392 .write = pdumpfs_mode_write,
396 pdumpfs_modes_possible_read(struct file *filp, char __user *buf, size_t size,
399 unsigned int i, skip = *f_pos, pos = 0;
401 for (i = 0; pdumpfs_modes[i].name; i++) {
405 else if (size > pos) {
406 if (copy_to_user(buf + pos, " ", 1))
413 int len = strlen(pdumpfs_modes[i].name);
417 } else if (size > pos) {
418 len = min(len - skip, size - pos);
420 if (copy_to_user(buf + pos,
421 pdumpfs_modes[i].name + skip,
435 static const struct file_operations pdumpfs_modes_possible_fops = {
436 .owner = THIS_MODULE,
438 .read = pdumpfs_modes_possible_read,
442 pdumpfs_frame_count_max_read(struct file *filp, char __user *buf, size_t size,
449 mutex_lock(pdumpfs_mutex);
450 snprintf(tmp, sizeof(tmp), "%d", frame_count_max);
451 mutex_unlock(pdumpfs_mutex);
453 if (strlen(tmp) < *f_pos)
456 if ((strlen(tmp) + 1) < (*f_pos + size))
457 size = strlen(tmp) + 1 - *f_pos;
459 if (copy_to_user(buf, tmp + *f_pos, size))
467 pdumpfs_frame_count_max_write(struct file *filp, const char __user *buf,
468 size_t size, loff_t *f_pos)
471 unsigned long result = 0;
473 if (*f_pos > sizeof(tmp))
476 if (size > (sizeof(tmp) - *f_pos))
477 size = sizeof(tmp) - *f_pos;
479 if (copy_from_user(tmp + *f_pos, buf, size))
484 mutex_lock(pdumpfs_mutex);
486 if (!strict_strtoul(tmp, 0, &result)) {
491 frame_count_max = result;
494 mutex_unlock(pdumpfs_mutex);
500 static const struct file_operations pdumpfs_frame_count_max_fops = {
501 .owner = THIS_MODULE,
503 .read = pdumpfs_frame_count_max_read,
504 .write = pdumpfs_frame_count_max_write,
508 pdumpfs_frame_read_single(struct pdumpfs_frame *frame, char __user *buf,
509 size_t size, loff_t f_pos)
514 if (f_pos >= frame->offset)
517 if (size > (frame->offset - f_pos))
518 size = frame->offset - f_pos;
520 page = f_pos / PAGE_SIZE;
521 offset = f_pos % PAGE_SIZE;
523 if (size > (PAGE_SIZE - offset))
524 size = PAGE_SIZE - offset;
526 if (copy_to_user(buf, ((u8 *) frame->pages[page]) + offset, size))
533 pdumpfs_llseek_helper(struct file *filp, loff_t offset, int whence, loff_t max)
539 if ((offset > max) || (offset < 0))
545 if (((filp->f_pos + offset) > max) ||
546 ((filp->f_pos + offset) < 0))
549 f_pos = filp->f_pos + offset;
556 f_pos = max + offset;
570 pdumpfs_init_llseek(struct file *filp, loff_t offset, int whence)
574 mutex_lock(pdumpfs_mutex);
576 f_pos = pdumpfs_llseek_helper(filp, offset, whence, frame_init->offset);
578 mutex_unlock(pdumpfs_mutex);
584 pdumpfs_init_read(struct file *filp, char __user *buf, size_t size,
587 mutex_lock(pdumpfs_mutex);
589 size = pdumpfs_frame_read_single(frame_init,
592 mutex_unlock(pdumpfs_mutex);
599 static const struct file_operations pdumpfs_init_fops = {
600 .owner = THIS_MODULE,
601 .llseek = pdumpfs_init_llseek,
602 .read = pdumpfs_init_read,
605 static struct dentry *pdumpfs_dir;
608 pdumpfs_file_create(const char *name, mode_t mode,
609 const struct file_operations *fops)
611 struct dentry *tmp = NULL;
613 tmp = debugfs_create_file(name, mode, pdumpfs_dir, NULL, fops);
615 pr_err("%s: failed to create pvr/%s file.\n", __func__, name);
619 pdumpfs_fs_init(void)
621 if (!pvr_debugfs_dir) {
622 pr_err("%s: debugfs pvr/ directory does not exist.\n",
627 pdumpfs_dir = debugfs_create_dir("pdump", pvr_debugfs_dir);
629 pr_err("%s: failed to create top level directory.\n",
634 pdumpfs_file_create("mode", S_IRUSR | S_IWUSR,
636 pdumpfs_file_create("modes_possible", S_IRUSR,
637 &pdumpfs_modes_possible_fops);
639 pdumpfs_file_create("frame_count_max", S_IRUSR | S_IWUSR,
640 &pdumpfs_frame_count_max_fops);
642 pdumpfs_file_create("init_frame", S_IRUSR,
649 pdumpfs_fs_destroy(void)
652 debugfs_remove_recursive(pdumpfs_dir);
660 mutex_init(pdumpfs_mutex);
662 ret = frame_new(0, 0);
672 pdumpfs_cleanup(void)
674 pdumpfs_fs_destroy();