23e54da8b8e4ce587b3a34a4bda22ac23e72dfe4
[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 #define FRAME_PAGE_COUNT 2040
47
48 struct pdumpfs_frame {
49         struct pdumpfs_frame *next;
50
51         u32 pid;
52         u32 number;
53
54         size_t offset;
55         int page_count;
56         unsigned long pages[FRAME_PAGE_COUNT];
57 };
58
59 #define MAX_FRAME_COUNT_HARD 1024
60 static u32 frame_count_max = CONFIG_PVR_PDUMP_INITIAL_MAX_FRAME_COUNT;
61 static u32 frame_count;
62
63 static struct pdumpfs_frame *frame_init;
64 static struct pdumpfs_frame *frame_stream;
65 static struct pdumpfs_frame *frame_current;
66
67 static struct pdumpfs_frame *frame_current_debugfs;
68 static int frame_current_open_count;
69 static int frame_stream_open_count;
70
71 static loff_t stream_start;
72 static loff_t stream_f_pos;
73 static loff_t stream_end;
74
75 static struct pdumpfs_frame *
76 frame_create(void)
77 {
78         struct pdumpfs_frame *frame =
79                 kmalloc(sizeof(struct pdumpfs_frame), GFP_KERNEL);
80         if (!frame)
81                 return NULL;
82
83         memset(frame, 0, sizeof(struct pdumpfs_frame));
84
85         return frame;
86 }
87
88 static void
89 frame_destroy(struct pdumpfs_frame *frame)
90 {
91         int i;
92
93         if (!frame)
94                 return;
95
96         for (i = 0; i < frame->page_count; i++)
97                 free_page(frame->pages[i]);
98
99         kfree(frame);
100 }
101
102 static void
103 frame_destroy_all(void)
104 {
105         /* detach from possible clones */
106         if (frame_current_debugfs &&
107             ((frame_current_debugfs == frame_init) ||
108              (frame_current_debugfs == frame_current) ||
109              frame_current_debugfs->next))
110                 frame_current_debugfs = NULL;
111
112         frame_current = NULL;
113
114         frame_destroy(frame_init);
115         frame_init = NULL;
116
117         frame_destroy(frame_current_debugfs);
118         frame_current_debugfs = NULL;
119
120         while (frame_stream) {
121                 struct pdumpfs_frame *frame = frame_stream;
122
123                 frame_stream = frame->next;
124
125                 frame_destroy(frame);
126                 frame_count--;
127         }
128
129         stream_start = 0;
130         stream_f_pos = 0;
131         stream_end = 0;
132 }
133
134 static void
135 frame_cull_first(void)
136 {
137         struct pdumpfs_frame *frame = frame_stream;
138
139         frame_stream = frame->next;
140         frame->next = NULL;
141
142         if (frame_stream_open_count)
143                 stream_start += frame->offset;
144         else
145                 stream_end -= frame->offset;
146
147         /*
148          * we cannot have frames vanish in the middle of reading
149          * them through debugfs
150          */
151         if (frame != frame_current_debugfs)
152                 frame_destroy(frame);
153
154         frame_count--;
155 }
156
157 static void
158 frame_cull(void)
159 {
160
161         if (!frame_stream_open_count) {
162                 while (frame_count > frame_count_max)
163                         frame_cull_first();
164         } else {
165                 while (((stream_start + frame_stream->offset) < stream_f_pos) ||
166                        (frame_count > MAX_FRAME_COUNT_HARD))
167                         frame_cull_first();
168         }
169 }
170
171 static int
172 frame_new(u32 pid, u32 number)
173 {
174         struct pdumpfs_frame *frame = frame_create();
175
176         if (!frame) {
177                 pr_err("%s: Failed to create frame.\n", __func__);
178                 return -ENOMEM;
179         }
180
181         frame->pid = pid;
182         frame->number = number;
183
184         if (!frame_init)
185                 frame_init = frame;
186         else {
187                 if (frame_current != frame_init)
188                         frame_current->next = frame;
189                 else
190                         frame_stream = frame;
191                 frame_count++;
192         }
193
194         frame_current = frame;
195
196         frame_cull();
197
198         return 0;
199 }
200
201 void
202 pdumpfs_frame_set(u32 pid, u32 frame)
203 {
204         mutex_lock(pdumpfs_mutex);
205
206         frame_new(pid, frame);
207
208         mutex_unlock(pdumpfs_mutex);
209 }
210
211 bool
212 pdumpfs_capture_enabled(void)
213 {
214         bool ret;
215
216         mutex_lock(pdumpfs_mutex);
217
218         if (pdumpfs_mode == PDUMPFS_MODE_FULL)
219                 ret = true;
220         else
221                 ret = false;
222
223         mutex_unlock(pdumpfs_mutex);
224
225         return ret;
226 }
227
228 bool
229 pdumpfs_flags_check(u32 flags)
230 {
231         bool ret;
232
233         if (flags & PDUMP_FLAGS_NEVER)
234                 return false;
235
236         mutex_lock(pdumpfs_mutex);
237
238         if (pdumpfs_mode == PDUMPFS_MODE_FULL)
239                 ret = true;
240         else if ((pdumpfs_mode == PDUMPFS_MODE_STANDARD) &&
241                  (flags & PDUMP_FLAGS_CONTINUOUS))
242                 ret = true;
243         else
244                 ret = false;
245
246         mutex_unlock(pdumpfs_mutex);
247
248         return ret;
249 }
250
251 static size_t
252 pdumpfs_frame_write_low(void *buffer, size_t size, bool from_user)
253 {
254         struct pdumpfs_frame *frame = frame_current;
255         size_t ret = 0;
256
257         while (size) {
258                 size_t count = size;
259                 size_t offset = frame->offset & ~PAGE_MASK;
260                 unsigned long page;
261
262                 if (!offset) {
263                         if (frame->page_count >= FRAME_PAGE_COUNT) {
264                                 pr_err("%s: Frame size overrun.\n", __func__);
265                                 return -ENOMEM;
266                         }
267
268                         page = __get_free_page(GFP_KERNEL);
269                         if (!page) {
270                                 pr_err("%s: failed to get free page.\n",
271                                        __func__);
272                                 return -ENOMEM;
273                         }
274
275                         frame->pages[frame->page_count] = page;
276                         frame->page_count++;
277                 } else
278                         page =
279                                 frame->pages[frame->page_count - 1];
280
281                 if (count > (PAGE_SIZE - offset))
282                         count = PAGE_SIZE - offset;
283
284                 if (from_user) {
285                         if (copy_from_user(((u8 *) page) + offset,
286                                            (void __user __force *) buffer,
287                                            count))
288                                 return -EINVAL;
289                 } else
290                         memcpy(((u8 *) page) + offset, buffer, count);
291
292                 buffer += count;
293                 size -= count;
294                 ret += count;
295                 frame->offset += count;
296         }
297         return ret;
298 }
299
300 static size_t
301 pdumpfs_frame_write(void *buffer, size_t size, bool from_user)
302 {
303         size_t ret;
304
305         if ((frame_current->offset + size) > (PAGE_SIZE * FRAME_PAGE_COUNT)) {
306                 u32 pid = OSGetCurrentProcessIDKM();
307                 struct task_struct *task;
308
309                 pr_err("Frame overrun!!!\n");
310
311                 ret = frame_new(pid, -1);
312                 if (ret)
313                         return ret;
314
315                 rcu_read_lock();
316                 task = pid_task(find_vpid(pid), PIDTYPE_PID);
317
318 #define FRAME_OVERRUN_MESSAGE "-- Starting forced frame caused by "
319                 pdumpfs_frame_write_low(FRAME_OVERRUN_MESSAGE,
320                                         sizeof(FRAME_OVERRUN_MESSAGE), false);
321                 pdumpfs_frame_write_low(task->comm, strlen(task->comm), false);
322                 pdumpfs_frame_write_low("\r\n", 2, false);
323
324                 pr_err("%s: Frame size overrun, caused by %d (%s)\n",
325                        __func__, pid, task->comm);
326
327                 rcu_read_unlock();
328         }
329
330         return pdumpfs_frame_write_low(buffer, size, from_user);
331 }
332
333 enum PVRSRV_ERROR
334 pdumpfs_write_data(void *buffer, size_t size, bool from_user)
335 {
336         mutex_lock(pdumpfs_mutex);
337
338         size = pdumpfs_frame_write(buffer, size, from_user);
339         if ((size > 0) && (frame_current != frame_init))
340                 stream_end += size;
341
342         mutex_unlock(pdumpfs_mutex);
343
344         if ((size >= 0) || (size == -ENOMEM))
345                 return PVRSRV_OK;
346         else
347                 return PVRSRV_ERROR_GENERIC;
348 }
349
350 void
351 pdumpfs_write_string(char *string)
352 {
353         size_t size;
354
355         mutex_lock(pdumpfs_mutex);
356
357         size = pdumpfs_frame_write(string, strlen(string), false);
358         if ((size > 0) && (frame_current != frame_init))
359                 stream_end += size;
360
361         mutex_unlock(pdumpfs_mutex);
362 }
363
364 /*
365  * DebugFS entries.
366  */
367 static const struct {
368         char *name;
369         enum pdumpfs_mode mode;
370 } pdumpfs_modes[] = {
371         {"disabled",   PDUMPFS_MODE_DISABLED},
372         {"standard",   PDUMPFS_MODE_STANDARD},
373         {"full",       PDUMPFS_MODE_FULL},
374         {NULL, PDUMPFS_MODE_DISABLED}
375 };
376
377 static ssize_t
378 pdumpfs_mode_read(struct file *filp, char __user *buf, size_t size,
379                   loff_t *f_pos)
380 {
381         char tmp[16];
382         int i;
383
384         tmp[0] = 0;
385
386         mutex_lock(pdumpfs_mutex);
387
388         for (i = 0; pdumpfs_modes[i].name; i++)
389                 if (pdumpfs_modes[i].mode == pdumpfs_mode)
390                         snprintf(tmp, sizeof(tmp), "%s\n",
391                                  pdumpfs_modes[i].name);
392
393         mutex_unlock(pdumpfs_mutex);
394
395         if (strlen(tmp) < *f_pos)
396                 return 0;
397
398         if ((strlen(tmp) + 1) < (*f_pos + size))
399                 size = strlen(tmp) + 1 - *f_pos;
400
401         if (copy_to_user(buf, tmp + *f_pos, size))
402                 return -EFAULT;
403
404         *f_pos += size;
405         return size;
406 }
407
408 static ssize_t
409 pdumpfs_mode_write(struct file *filp, const char __user *buf, size_t size,
410                    loff_t *f_pos)
411 {
412         static char tmp[16];
413         int i;
414
415         if (*f_pos > sizeof(tmp))
416                 return -EINVAL;
417
418         if (size > (sizeof(tmp) - *f_pos))
419                 size = sizeof(tmp) - *f_pos;
420
421         if (copy_from_user(tmp + *f_pos, buf, size))
422                 return -EFAULT;
423
424         *f_pos += size;
425
426         mutex_lock(pdumpfs_mutex);
427
428         for (i = 0; pdumpfs_modes[i].name; i++)
429                 if (!strnicmp(tmp, pdumpfs_modes[i].name,
430                               strlen(pdumpfs_modes[i].name))) {
431                         pdumpfs_mode = pdumpfs_modes[i].mode;
432                         mutex_unlock(pdumpfs_mutex);
433                         return size;
434                 }
435
436         mutex_unlock(pdumpfs_mutex);
437         return -EINVAL;
438 }
439
440 static const struct file_operations pdumpfs_mode_fops = {
441         .owner = THIS_MODULE,
442         .llseek = no_llseek,
443         .read = pdumpfs_mode_read,
444         .write = pdumpfs_mode_write,
445 };
446
447 static ssize_t
448 pdumpfs_modes_possible_read(struct file *filp, char __user *buf, size_t size,
449                             loff_t *f_pos)
450 {
451         unsigned int i, skip = *f_pos, pos = 0;
452
453         for (i = 0; pdumpfs_modes[i].name; i++) {
454                 if (i) { /* space */
455                         if (skip)
456                                 skip--;
457                         else if (size > pos) {
458                                 if (copy_to_user(buf + pos, " ", 1))
459                                         return -EFAULT;
460                                 pos++;
461                         }
462                 }
463
464                 if (size) {
465                         int len = strlen(pdumpfs_modes[i].name);
466
467                         if (skip >= len) {
468                                 skip -= len;
469                         } else if (size > pos) {
470                                 len = min(len - skip, size - pos);
471
472                                 if (copy_to_user(buf + pos,
473                                                  pdumpfs_modes[i].name + skip,
474                                                  len))
475                                         return -EFAULT;
476
477                                 skip = 0;
478                                 pos += len;
479                         }
480                 }
481         }
482
483         *f_pos += pos;
484         return pos;
485 }
486
487 static const struct file_operations pdumpfs_modes_possible_fops = {
488         .owner = THIS_MODULE,
489         .llseek = no_llseek,
490         .read = pdumpfs_modes_possible_read,
491 };
492
493 static ssize_t
494 pdumpfs_frame_count_max_read(struct file *filp, char __user *buf, size_t size,
495                              loff_t *f_pos)
496 {
497         char tmp[16];
498
499         tmp[0] = 0;
500
501         mutex_lock(pdumpfs_mutex);
502         snprintf(tmp, sizeof(tmp), "%d", frame_count_max);
503         mutex_unlock(pdumpfs_mutex);
504
505         if (strlen(tmp) < *f_pos)
506                 return 0;
507
508         if ((strlen(tmp) + 1) < (*f_pos + size))
509                 size = strlen(tmp) + 1 - *f_pos;
510
511         if (copy_to_user(buf, tmp + *f_pos, size))
512                 return -EFAULT;
513
514         *f_pos += size;
515         return size;
516 }
517
518 static ssize_t
519 pdumpfs_frame_count_max_write(struct file *filp, const char __user *buf,
520                               size_t size, loff_t *f_pos)
521 {
522         static char tmp[16];
523         unsigned long result = 0;
524
525         if (*f_pos > sizeof(tmp))
526                 return -EINVAL;
527
528         if (size > (sizeof(tmp) - *f_pos))
529                 size = sizeof(tmp) - *f_pos;
530
531         if (copy_from_user(tmp + *f_pos, buf, size))
532                 return -EFAULT;
533
534         tmp[size] = 0;
535
536         mutex_lock(pdumpfs_mutex);
537
538         if (!strict_strtoul(tmp, 0, &result)) {
539                 if (result > 1024)
540                         result = 1024;
541                 if (!result)
542                         result = 1;
543                 frame_count_max = result;
544         }
545
546         mutex_unlock(pdumpfs_mutex);
547
548         *f_pos += size;
549         return size;
550 }
551
552 static const struct file_operations pdumpfs_frame_count_max_fops = {
553         .owner = THIS_MODULE,
554         .llseek = no_llseek,
555         .read = pdumpfs_frame_count_max_read,
556         .write = pdumpfs_frame_count_max_write,
557 };
558
559 static ssize_t
560 pdumpfs_frame_read_single(struct pdumpfs_frame *frame, char __user *buf,
561                           size_t size, loff_t f_pos)
562 {
563         int page;
564         size_t offset;
565
566         if (f_pos >= frame->offset)
567                 return 0;
568
569         if (size > (frame->offset - f_pos))
570                 size = frame->offset - f_pos;
571
572         page = f_pos / PAGE_SIZE;
573         offset = f_pos % PAGE_SIZE;
574
575         if (size > (PAGE_SIZE - offset))
576                 size = PAGE_SIZE - offset;
577
578         if (copy_to_user(buf, ((u8 *) frame->pages[page]) + offset, size))
579                 return -EFAULT;
580
581         return size;
582 }
583
584 static loff_t
585 pdumpfs_llseek_helper(struct file *filp, loff_t offset, int whence, loff_t max)
586 {
587         loff_t f_pos;
588
589         switch (whence) {
590         case SEEK_SET:
591                 if ((offset > max) || (offset < 0))
592                         f_pos = -EINVAL;
593                 else
594                         f_pos = offset;
595                 break;
596         case SEEK_CUR:
597                 if (((filp->f_pos + offset) > max) ||
598                     ((filp->f_pos + offset) < 0))
599                         f_pos = -EINVAL;
600                 else
601                         f_pos = filp->f_pos + offset;
602                 break;
603         case SEEK_END:
604                 if ((offset > 0) ||
605                     (offset < -max))
606                         f_pos = -EINVAL;
607                 else
608                         f_pos = max + offset;
609                 break;
610         default:
611                 f_pos = -EINVAL;
612                 break;
613         }
614
615         if (f_pos >= 0)
616                 filp->f_pos = f_pos;
617
618         return f_pos;
619 }
620
621 static loff_t
622 pdumpfs_init_llseek(struct file *filp, loff_t offset, int whence)
623 {
624         loff_t f_pos;
625
626         mutex_lock(pdumpfs_mutex);
627
628         f_pos = pdumpfs_llseek_helper(filp, offset, whence, frame_init->offset);
629
630         mutex_unlock(pdumpfs_mutex);
631
632         return f_pos;
633 }
634
635 static ssize_t
636 pdumpfs_init_read(struct file *filp, char __user *buf, size_t size,
637                   loff_t *f_pos)
638 {
639         mutex_lock(pdumpfs_mutex);
640
641         size = pdumpfs_frame_read_single(frame_init,
642                                          buf, size, *f_pos);
643
644         mutex_unlock(pdumpfs_mutex);
645
646         if (size > 0)
647                 *f_pos += size;
648         return size;
649 }
650
651 static const struct file_operations pdumpfs_init_fops = {
652         .owner = THIS_MODULE,
653         .llseek = pdumpfs_init_llseek,
654         .read = pdumpfs_init_read,
655 };
656
657 /*
658  * We need to make sure that our frame doesn't vanish while we are still
659  * reading it: so reference this frame again.
660  */
661 static int
662 pdumpfs_current_open(struct inode *inode, struct file *filp)
663 {
664         mutex_lock(pdumpfs_mutex);
665
666         if (!frame_current_open_count)
667                 frame_current_debugfs = frame_current;
668
669         frame_current_open_count++;
670
671         mutex_unlock(pdumpfs_mutex);
672         return 0;
673 }
674
675 static int
676 pdumpfs_current_release(struct inode *inode, struct file *filp)
677 {
678         mutex_lock(pdumpfs_mutex);
679
680         frame_current_open_count--;
681
682         if (!frame_current_open_count) {
683                 if ((frame_current_debugfs != frame_init) &&
684                     (frame_current_debugfs != frame_current) &&
685                     !frame_current_debugfs->next)
686                         frame_destroy(frame_current_debugfs);
687                 frame_current_debugfs = NULL;
688         }
689
690         mutex_unlock(pdumpfs_mutex);
691         return 0;
692 }
693
694 static loff_t
695 pdumpfs_current_llseek(struct file *filp, loff_t offset, int whence)
696 {
697         loff_t f_pos;
698
699         mutex_lock(pdumpfs_mutex);
700
701         f_pos = pdumpfs_llseek_helper(filp, offset, whence,
702                                       frame_current_debugfs->offset);
703
704         mutex_unlock(pdumpfs_mutex);
705
706         return f_pos;
707 }
708
709 static ssize_t
710 pdumpfs_current_read(struct file *filp, char __user *buf, size_t size,
711                      loff_t *f_pos)
712 {
713         mutex_lock(pdumpfs_mutex);
714
715         if (frame_current_debugfs->offset)
716                 size = pdumpfs_frame_read_single(frame_current_debugfs,
717                                                  buf, size, *f_pos);
718         else
719                 size = 0;
720
721         mutex_unlock(pdumpfs_mutex);
722
723         if (size > 0)
724                 *f_pos += size;
725         return size;
726 }
727
728 static const struct file_operations pdumpfs_current_fops = {
729         .owner = THIS_MODULE,
730         .llseek = pdumpfs_current_llseek,
731         .read = pdumpfs_current_read,
732         .open = pdumpfs_current_open,
733         .release = pdumpfs_current_release,
734 };
735
736 /*
737  * So we can track when we can alter stream offsets.
738  */
739 static int
740 pdumpfs_stream_open(struct inode *inode, struct file *filp)
741 {
742         int ret;
743
744         mutex_lock(pdumpfs_mutex);
745
746         if (frame_stream_open_count)
747                 ret = -EUSERS;
748         else {
749                 frame_stream_open_count++;
750                 ret = 0;
751         }
752
753         mutex_unlock(pdumpfs_mutex);
754         return ret;
755 }
756
757 static int
758 pdumpfs_stream_release(struct inode *inode, struct file *filp)
759 {
760         mutex_lock(pdumpfs_mutex);
761
762         frame_stream_open_count--;
763
764         /* fix the damage done while it was open */
765         if (!frame_stream_open_count) {
766                 stream_end -= stream_start;
767                 stream_start = 0;
768                 stream_f_pos = 0;
769         }
770
771         mutex_unlock(pdumpfs_mutex);
772         return 0;
773 }
774
775 static ssize_t
776 pdumpfs_stream_buffer_clear(char __user *buf, size_t size)
777 {
778         char tmp[80];
779
780         memset(tmp, '.', sizeof(tmp) - 1);
781         tmp[sizeof(tmp) - 1] = '\n';
782
783         if (size >= sizeof(tmp)) {
784                 int i;
785
786                 for (i = 0; (i  + sizeof(tmp)) < size; i += sizeof(tmp))
787                         if (copy_to_user(buf + i, tmp, sizeof(tmp)))
788                                 return -EFAULT;
789                 return i;
790         } else {
791                 if (copy_to_user(buf, tmp + sizeof(tmp) - size, size))
792                         return -EFAULT;
793                 return size;
794         }
795 }
796
797 static ssize_t
798 pdumpfs_stream_buffer_fill(struct pdumpfs_frame *frame,
799                            char __user *buf, size_t offset, size_t size)
800 {
801         int page = offset / PAGE_SIZE;
802
803         if (size > (frame->offset - offset))
804                 size = frame->offset - offset;
805
806         offset %= PAGE_SIZE;
807
808         if (size > (PAGE_SIZE - offset))
809                 size = PAGE_SIZE - offset;
810
811         if (copy_to_user(buf, ((u8 *) frame->pages[page]) + offset, size))
812                 return -EFAULT;
813
814         stream_f_pos += size;
815
816         return size;
817 }
818
819 static loff_t
820 pdumpfs_stream_llseek(struct file *filp, loff_t offset, int whence)
821 {
822         loff_t f_pos;
823
824         mutex_lock(pdumpfs_mutex);
825
826         switch (whence) {
827         case SEEK_SET:
828                 if ((offset > stream_end) || (offset < stream_start))
829                         f_pos = -EINVAL;
830                 else
831                         f_pos = offset;
832                 break;
833         case SEEK_CUR:
834                 if (((filp->f_pos + offset) > stream_end) ||
835                     ((filp->f_pos + offset) < stream_start))
836                         f_pos = -EINVAL;
837                 else
838                         f_pos = filp->f_pos + offset;
839                 break;
840         case SEEK_END:
841                 if ((offset > 0) ||
842                     (offset < (stream_start - stream_end)))
843                         f_pos = -EINVAL;
844                 else
845                         f_pos = stream_end + offset;
846                 break;
847         default:
848                 f_pos = -EINVAL;
849                 break;
850         }
851
852         if (f_pos >= 0) {
853                 filp->f_pos = f_pos;
854                 stream_f_pos = f_pos;
855         }
856
857         mutex_unlock(pdumpfs_mutex);
858
859         return f_pos;
860 }
861
862 static ssize_t
863 pdumpfs_stream_read(struct file *filp, char __user *buf, size_t size,
864                     loff_t *f_pos)
865 {
866         size_t ret = 0;
867
868         mutex_lock(pdumpfs_mutex);
869
870         if ((stream_end <= 0) || (*f_pos >= stream_end))
871                 ret = 0;
872         else if (*f_pos < stream_start) {
873                 if (size > (stream_start - *f_pos))
874                         size = stream_start - *f_pos;
875                 ret = pdumpfs_stream_buffer_clear(buf, size);
876         } else {
877                 loff_t start = stream_start;
878                 struct pdumpfs_frame *frame = frame_stream;
879
880                 /* skip frames that are before our offset */
881                 while ((start + frame->offset) <= *f_pos) {
882                         start += frame->offset;
883                         frame = frame->next;
884                 }
885
886                 ret = pdumpfs_stream_buffer_fill(frame, buf, *f_pos - start,
887                                                  size);
888         }
889
890         if (ret > 0)
891                 *f_pos += ret;
892         mutex_unlock(pdumpfs_mutex);
893         return ret;
894 }
895
896 static const struct file_operations pdumpfs_stream_fops = {
897         .owner = THIS_MODULE,
898         .llseek = pdumpfs_stream_llseek,
899         .read = pdumpfs_stream_read,
900         .open = pdumpfs_stream_open,
901         .release = pdumpfs_stream_release,
902 };
903
904 static struct dentry *pdumpfs_dir;
905
906 static void
907 pdumpfs_file_create(const char *name, mode_t mode,
908                     const struct file_operations *fops)
909 {
910         struct dentry *tmp = NULL;
911
912         tmp = debugfs_create_file(name, mode, pdumpfs_dir, NULL, fops);
913         if (!tmp)
914                 pr_err("%s: failed to create pvr/%s file.\n", __func__, name);
915 }
916
917 static int
918 pdumpfs_fs_init(void)
919 {
920         if (!pvr_debugfs_dir) {
921                 pr_err("%s: debugfs pvr/ directory does not exist.\n",
922                        __func__);
923                 return -ENOENT;
924         }
925
926         pdumpfs_dir = debugfs_create_dir("pdump", pvr_debugfs_dir);
927         if (!pdumpfs_dir) {
928                 pr_err("%s: failed to create top level directory.\n",
929                        __func__);
930                 return -ENOENT;
931         }
932
933         pdumpfs_file_create("mode", S_IRUSR | S_IWUSR,
934                             &pdumpfs_mode_fops);
935         pdumpfs_file_create("modes_possible", S_IRUSR,
936                             &pdumpfs_modes_possible_fops);
937
938         pdumpfs_file_create("frame_count_max", S_IRUSR | S_IWUSR,
939                             &pdumpfs_frame_count_max_fops);
940
941         pdumpfs_file_create("init_frame", S_IRUSR,
942                             &pdumpfs_init_fops);
943         pdumpfs_file_create("current_frame", S_IRUSR,
944                             &pdumpfs_current_fops);
945         pdumpfs_file_create("stream_frames", S_IRUSR,
946                             &pdumpfs_stream_fops);
947
948         return 0;
949 }
950
951 static void
952 pdumpfs_fs_destroy(void)
953 {
954         if (pdumpfs_dir)
955                 debugfs_remove_recursive(pdumpfs_dir);
956 }
957
958 int
959 pdumpfs_init(void)
960 {
961         int ret;
962
963         mutex_init(pdumpfs_mutex);
964
965         ret = frame_new(0, 0);
966         if (ret < 0)
967                 return ret;
968
969         pdumpfs_fs_init();
970
971         return 0;
972 }
973
974 void
975 pdumpfs_cleanup(void)
976 {
977         pdumpfs_fs_destroy();
978
979         frame_destroy_all();
980 }