20094102.3+0m5
[sgx.git] / pvr / proc.c
1 /**********************************************************************
2  *
3  * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
4  * 
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  * 
9  * This program is distributed in the hope it will be useful but, except 
10  * as otherwise stated in writing, without any warranty; without even the 
11  * implied warranty of merchantability or fitness for a particular purpose. 
12  * See the GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17  * 
18  * The full GNU General Public License is included in this distribution in
19  * the file called "COPYING".
20  *
21  * Contact Information:
22  * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23  * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
24  *
25  ******************************************************************************/
26
27 #ifndef AUTOCONF_INCLUDED
28 #include <linux/config.h>
29 #endif
30
31 #include <linux/init.h>
32 #include <linux/module.h>
33 #include <linux/version.h>
34 #include <linux/fs.h>
35 #include <linux/proc_fs.h>
36
37 #include "services_headers.h"
38
39 #include "queue.h"
40 #include "resman.h"
41 #include "pvrmmap.h"
42 #include "pvr_debug.h"
43 #include "pvrversion.h"
44 #include "proc.h"
45
46 #ifdef DEBUG
47 int PVRDebugProcSetLevel(struct file *file, const char *buffer,
48                          unsigned long count, void *data);
49 int PVRDebugProcGetLevel(char *page, char **start, off_t off, int count,
50                          int *eof, void *data);
51
52 #endif
53
54 static struct proc_dir_entry *dir;
55
56 static off_t procDumpSysNodes(char *buf, size_t size, off_t off);
57 static off_t procDumpVersion(char *buf, size_t size, off_t off);
58
59 off_t printAppend(char *buffer, size_t size, off_t off, const char *format, ...)
60 {
61         int n;
62         int space = size - off;
63         va_list ap;
64
65         va_start(ap, format);
66
67         n = vsnprintf(buffer + off, space, format, ap);
68
69         va_end(ap);
70
71         if (n > space || n < 0) {
72                 return size;
73         } else {
74                 return off + n;
75         }
76 }
77
78 static int pvr_read_proc(char *page, char **start, off_t off,
79                          int count, int *eof, void *data)
80 {
81         pvr_read_proc_t *pprn = data;
82
83         off_t len = pprn(page, count, off);
84
85         if (len == END_OF_FILE) {
86                 len = 0;
87                 *eof = 1;
88         } else if (!len) {
89                 *start = (char *)0;
90         } else {
91                 *start = (char *)1;
92         }
93
94         return len;
95 }
96
97 int CreateProcEntry(const char *name, read_proc_t rhandler,
98                     write_proc_t whandler, void *data)
99 {
100         struct proc_dir_entry *file;
101         mode_t mode;
102
103         if (!dir) {
104                 PVR_DPF((PVR_DBG_ERROR,
105                          "CreateProcEntry: cannot make proc entry /proc/pvr/%s: no parent",
106                          name));
107                 return -ENOMEM;
108         }
109
110         mode = S_IFREG;
111
112         if (rhandler) {
113                 mode |= S_IRUGO;
114         }
115
116         if (whandler) {
117                 mode |= S_IWUSR;
118         }
119
120         file = create_proc_entry(name, mode, dir);
121
122         if (file) {
123                 file->owner = THIS_MODULE;
124                 file->read_proc = rhandler;
125                 file->write_proc = whandler;
126                 file->data = data;
127
128                 PVR_DPF((PVR_DBG_MESSAGE, "Created /proc/pvr/%s", name));
129
130                 return 0;
131         }
132
133         PVR_DPF((PVR_DBG_ERROR,
134                  "CreateProcEntry: cannot make proc entry /proc/pvr/%s: no memory",
135                  name));
136
137         return -ENOMEM;
138 }
139
140 int CreateProcReadEntry(const char *name, pvr_read_proc_t handler)
141 {
142         struct proc_dir_entry *file;
143
144         if (!dir) {
145                 PVR_DPF((PVR_DBG_ERROR,
146                          "CreateProcReadEntry: cannot make proc entry /proc/pvr/%s: no parent",
147                          name));
148
149                 return -ENOMEM;
150         }
151
152         file =
153             create_proc_read_entry(name, S_IFREG | S_IRUGO, dir, pvr_read_proc,
154                                    (void *)handler);
155
156         if (file) {
157                 file->owner = THIS_MODULE;
158
159                 return 0;
160         }
161
162         PVR_DPF((PVR_DBG_ERROR,
163                  "CreateProcReadEntry: cannot make proc entry /proc/pvr/%s: no memory",
164                  name));
165
166         return -ENOMEM;
167 }
168
169 int CreateProcEntries(void)
170 {
171         dir = proc_mkdir("pvr", NULL);
172
173         if (!dir) {
174                 PVR_DPF((PVR_DBG_ERROR,
175                          "CreateProcEntries: cannot make /proc/pvr directory"));
176
177                 return -ENOMEM;
178         }
179
180         if (CreateProcReadEntry("queue", QueuePrintQueues) ||
181             CreateProcReadEntry("version", procDumpVersion) ||
182             CreateProcReadEntry("nodes", procDumpSysNodes)) {
183                 PVR_DPF((PVR_DBG_ERROR,
184                          "CreateProcEntries: couldn't make /proc/pvr files"));
185
186                 return -ENOMEM;
187         }
188 #ifdef DEBUG
189         if (CreateProcEntry
190             ("debug_level", PVRDebugProcGetLevel, PVRDebugProcSetLevel, 0)) {
191                 PVR_DPF((PVR_DBG_ERROR,
192                          "CreateProcEntries: couldn't make /proc/pvr/debug_level"));
193
194                 return -ENOMEM;
195         }
196 #endif
197
198         return 0;
199 }
200
201 void RemoveProcEntry(const char *name)
202 {
203         if (dir) {
204                 remove_proc_entry(name, dir);
205         }
206
207         PVR_DPF((PVR_DBG_MESSAGE, "Removing /proc/pvr/%s", name));
208 }
209
210 void RemoveProcEntries(void)
211 {
212 #ifdef DEBUG
213         RemoveProcEntry("debug_level");
214 #endif
215         RemoveProcEntry("queue");
216         RemoveProcEntry("nodes");
217         RemoveProcEntry("version");
218
219         while (dir->subdir) {
220                 PVR_DPF((PVR_DBG_WARNING, "Belatedly removing /proc/pvr/%s",
221                          dir->subdir->name));
222
223                 RemoveProcEntry(dir->subdir->name);
224         }
225
226         remove_proc_entry("pvr", NULL);
227 }
228
229 static off_t procDumpVersion(char *buf, size_t size, off_t off)
230 {
231         SYS_DATA *psSysData;
232
233         if (off == 0) {
234                 return printAppend(buf, size, 0,
235                                    "Version %s (%s) %s\n",
236                                    PVRVERSION_STRING,
237                                    PVR_BUILD_TYPE, PVR_BUILD_DIR);
238         }
239
240         if (SysAcquireData(&psSysData) != PVRSRV_OK) {
241                 return PVRSRV_ERROR_GENERIC;
242         }
243
244         if (off == 1) {
245                 IMG_CHAR *pszSystemVersionString = "None";
246
247                 if (psSysData->pszVersionString) {
248                         pszSystemVersionString = psSysData->pszVersionString;
249                 }
250
251                 if (strlen(pszSystemVersionString)
252                     + strlen("System Version String: \n")
253                     + 1 > size) {
254                         return 0;
255                 }
256                 return printAppend(buf, size, 0,
257                                    "System Version String: %s\n",
258                                    pszSystemVersionString);
259         }
260
261         return END_OF_FILE;
262 }
263
264 static const char *deviceTypeToString(PVRSRV_DEVICE_TYPE deviceType)
265 {
266         switch (deviceType) {
267         default:
268                 {
269                         static char text[10];
270
271                         sprintf(text, "?%x", deviceType);
272
273                         return text;
274                 }
275         }
276 }
277
278 static const char *deviceClassToString(PVRSRV_DEVICE_CLASS deviceClass)
279 {
280         switch (deviceClass) {
281         case PVRSRV_DEVICE_CLASS_3D:
282                 {
283                         return "3D";
284                 }
285         case PVRSRV_DEVICE_CLASS_DISPLAY:
286                 {
287                         return "display";
288                 }
289         case PVRSRV_DEVICE_CLASS_BUFFER:
290                 {
291                         return "buffer";
292                 }
293         default:
294                 {
295                         static char text[10];
296
297                         sprintf(text, "?%x", deviceClass);
298                         return text;
299                 }
300         }
301 }
302
303 static
304 off_t procDumpSysNodes(char *buf, size_t size, off_t off)
305 {
306         SYS_DATA *psSysData;
307         PVRSRV_DEVICE_NODE *psDevNode;
308         off_t len;
309
310         if (size < 80) {
311                 return 0;
312         }
313
314         if (off == 0) {
315                 return printAppend(buf, size, 0,
316                                    "Registered nodes\n"
317                                    "Addr     Type     Class    Index Ref pvDev     Size Res\n");
318         }
319
320         if (SysAcquireData(&psSysData) != PVRSRV_OK) {
321                 return PVRSRV_ERROR_GENERIC;
322         }
323
324         for (psDevNode = psSysData->psDeviceNodeList;
325              --off && psDevNode; psDevNode = psDevNode->psNext) ;
326
327         if (!psDevNode) {
328                 return END_OF_FILE;
329         }
330
331         len = printAppend(buf, size, 0,
332                           "%p %-8s %-8s %4d  %2lu  %p  %3lu  %p\n",
333                           psDevNode,
334                           deviceTypeToString(psDevNode->sDevId.eDeviceType),
335                           deviceClassToString(psDevNode->sDevId.eDeviceClass),
336                           psDevNode->sDevId.eDeviceClass,
337                           psDevNode->ui32RefCount,
338                           psDevNode->pvDevice,
339                           psDevNode->ui32pvDeviceSize,
340                           psDevNode->hResManContext);
341         return (len);
342 }