diff options
Diffstat (limited to 'drivers/gpu/pvr/proc.c')
-rw-r--r-- | drivers/gpu/pvr/proc.c | 833 |
1 files changed, 833 insertions, 0 deletions
diff --git a/drivers/gpu/pvr/proc.c b/drivers/gpu/pvr/proc.c new file mode 100644 index 00000000000..74f313262b8 --- /dev/null +++ b/drivers/gpu/pvr/proc.c | |||
@@ -0,0 +1,833 @@ | |||
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 | #include <linux/seq_file.h> | ||
37 | |||
38 | #include "services_headers.h" | ||
39 | |||
40 | #include "queue.h" | ||
41 | #include "resman.h" | ||
42 | #include "pvrmmap.h" | ||
43 | #include "pvr_debug.h" | ||
44 | #include "pvrversion.h" | ||
45 | #include "proc.h" | ||
46 | #include "perproc.h" | ||
47 | #include "env_perproc.h" | ||
48 | #include "linkage.h" | ||
49 | |||
50 | #include "lists.h" | ||
51 | |||
52 | static struct proc_dir_entry * dir; | ||
53 | |||
54 | static const IMG_CHAR PVRProcDirRoot[] = "pvr"; | ||
55 | |||
56 | static IMG_INT pvr_proc_open(struct inode *inode,struct file *file); | ||
57 | static void *pvr_proc_seq_start (struct seq_file *m, loff_t *pos); | ||
58 | static void pvr_proc_seq_stop (struct seq_file *m, void *v); | ||
59 | static void *pvr_proc_seq_next (struct seq_file *m, void *v, loff_t *pos); | ||
60 | static int pvr_proc_seq_show (struct seq_file *m, void *v); | ||
61 | static ssize_t pvr_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos); | ||
62 | |||
63 | static struct file_operations pvr_proc_operations = | ||
64 | { | ||
65 | .open = pvr_proc_open, | ||
66 | .read = seq_read, | ||
67 | .write = pvr_proc_write, | ||
68 | .llseek = seq_lseek, | ||
69 | .release = seq_release, | ||
70 | }; | ||
71 | |||
72 | static struct seq_operations pvr_proc_seq_operations = | ||
73 | { | ||
74 | .start = pvr_proc_seq_start, | ||
75 | .next = pvr_proc_seq_next, | ||
76 | .stop = pvr_proc_seq_stop, | ||
77 | .show = pvr_proc_seq_show, | ||
78 | }; | ||
79 | |||
80 | static struct proc_dir_entry* g_pProcQueue; | ||
81 | static struct proc_dir_entry* g_pProcVersion; | ||
82 | static struct proc_dir_entry* g_pProcSysNodes; | ||
83 | |||
84 | #ifdef DEBUG | ||
85 | static struct proc_dir_entry* g_pProcDebugLevel; | ||
86 | #endif | ||
87 | |||
88 | #ifdef PVR_MANUAL_POWER_CONTROL | ||
89 | static struct proc_dir_entry* g_pProcPowerLevel; | ||
90 | #endif | ||
91 | |||
92 | |||
93 | static void ProcSeqShowVersion(struct seq_file *sfile,void* el); | ||
94 | |||
95 | static void ProcSeqShowSysNodes(struct seq_file *sfile,void* el); | ||
96 | static void* ProcSeqOff2ElementSysNodes(struct seq_file * sfile, loff_t off); | ||
97 | |||
98 | off_t printAppend(IMG_CHAR * buffer, size_t size, off_t off, const IMG_CHAR * format, ...) | ||
99 | { | ||
100 | IMG_INT n; | ||
101 | size_t space = size - (size_t)off; | ||
102 | va_list ap; | ||
103 | |||
104 | va_start (ap, format); | ||
105 | |||
106 | n = vsnprintf (buffer+off, space, format, ap); | ||
107 | |||
108 | va_end (ap); | ||
109 | |||
110 | if (n >= (IMG_INT)space || n < 0) | ||
111 | { | ||
112 | |||
113 | buffer[size - 1] = 0; | ||
114 | return (off_t)(size - 1); | ||
115 | } | ||
116 | else | ||
117 | { | ||
118 | return (off + (off_t)n); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | |||
123 | void* ProcSeq1ElementOff2Element(struct seq_file *sfile, loff_t off) | ||
124 | { | ||
125 | PVR_UNREFERENCED_PARAMETER(sfile); | ||
126 | |||
127 | if(!off) | ||
128 | return (void*)2; | ||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | |||
133 | void* ProcSeq1ElementHeaderOff2Element(struct seq_file *sfile, loff_t off) | ||
134 | { | ||
135 | PVR_UNREFERENCED_PARAMETER(sfile); | ||
136 | |||
137 | if(!off) | ||
138 | { | ||
139 | return PVR_PROC_SEQ_START_TOKEN; | ||
140 | } | ||
141 | |||
142 | |||
143 | if(off == 1) | ||
144 | return (void*)2; | ||
145 | |||
146 | return NULL; | ||
147 | } | ||
148 | |||
149 | |||
150 | static IMG_INT pvr_proc_open(struct inode *inode,struct file *file) | ||
151 | { | ||
152 | IMG_INT ret = seq_open(file, &pvr_proc_seq_operations); | ||
153 | |||
154 | struct seq_file *seq = (struct seq_file*)file->private_data; | ||
155 | struct proc_dir_entry* pvr_proc_entry = PDE(inode); | ||
156 | |||
157 | |||
158 | seq->private = pvr_proc_entry->data; | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | static ssize_t pvr_proc_write(struct file *file, const char __user *buffer, | ||
163 | size_t count, loff_t *ppos) | ||
164 | { | ||
165 | struct inode *inode = file->f_path.dentry->d_inode; | ||
166 | struct proc_dir_entry * dp; | ||
167 | |||
168 | PVR_UNREFERENCED_PARAMETER(ppos); | ||
169 | dp = PDE(inode); | ||
170 | |||
171 | if (!dp->write_proc) | ||
172 | return -EIO; | ||
173 | |||
174 | return dp->write_proc(file, buffer, count, dp->data); | ||
175 | } | ||
176 | |||
177 | |||
178 | static void *pvr_proc_seq_start (struct seq_file *proc_seq_file, loff_t *pos) | ||
179 | { | ||
180 | PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)proc_seq_file->private; | ||
181 | if(handlers->startstop != NULL) | ||
182 | handlers->startstop(proc_seq_file, IMG_TRUE); | ||
183 | return handlers->off2element(proc_seq_file, *pos); | ||
184 | } | ||
185 | |||
186 | static void pvr_proc_seq_stop (struct seq_file *proc_seq_file, void *v) | ||
187 | { | ||
188 | PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)proc_seq_file->private; | ||
189 | PVR_UNREFERENCED_PARAMETER(v); | ||
190 | |||
191 | if(handlers->startstop != NULL) | ||
192 | handlers->startstop(proc_seq_file, IMG_FALSE); | ||
193 | } | ||
194 | |||
195 | static void *pvr_proc_seq_next (struct seq_file *proc_seq_file, void *v, loff_t *pos) | ||
196 | { | ||
197 | PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)proc_seq_file->private; | ||
198 | (*pos)++; | ||
199 | if( handlers->next != NULL) | ||
200 | return handlers->next( proc_seq_file, v, *pos ); | ||
201 | return handlers->off2element(proc_seq_file, *pos); | ||
202 | } | ||
203 | |||
204 | static int pvr_proc_seq_show (struct seq_file *proc_seq_file, void *v) | ||
205 | { | ||
206 | PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)proc_seq_file->private; | ||
207 | handlers->show( proc_seq_file,v ); | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | |||
212 | |||
213 | static struct proc_dir_entry* CreateProcEntryInDirSeq( | ||
214 | struct proc_dir_entry *pdir, | ||
215 | const IMG_CHAR * name, | ||
216 | IMG_VOID* data, | ||
217 | pvr_next_proc_seq_t next_handler, | ||
218 | pvr_show_proc_seq_t show_handler, | ||
219 | pvr_off2element_proc_seq_t off2element_handler, | ||
220 | pvr_startstop_proc_seq_t startstop_handler, | ||
221 | write_proc_t whandler | ||
222 | ) | ||
223 | { | ||
224 | |||
225 | struct proc_dir_entry * file; | ||
226 | mode_t mode; | ||
227 | |||
228 | if (!dir) | ||
229 | { | ||
230 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntryInDirSeq: cannot make proc entry /proc/%s/%s: no parent", PVRProcDirRoot, name)); | ||
231 | return NULL; | ||
232 | } | ||
233 | |||
234 | mode = S_IFREG; | ||
235 | |||
236 | if (show_handler) | ||
237 | { | ||
238 | mode |= S_IRUGO; | ||
239 | } | ||
240 | |||
241 | if (whandler) | ||
242 | { | ||
243 | mode |= S_IWUSR; | ||
244 | } | ||
245 | |||
246 | file=create_proc_entry(name, mode, pdir); | ||
247 | |||
248 | if (file) | ||
249 | { | ||
250 | PVR_PROC_SEQ_HANDLERS *seq_handlers; | ||
251 | |||
252 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) | ||
253 | file->owner = THIS_MODULE; | ||
254 | #endif | ||
255 | |||
256 | file->proc_fops = &pvr_proc_operations; | ||
257 | file->write_proc = whandler; | ||
258 | |||
259 | |||
260 | file->data = kmalloc(sizeof(PVR_PROC_SEQ_HANDLERS), GFP_KERNEL); | ||
261 | if(file->data) | ||
262 | { | ||
263 | seq_handlers = (PVR_PROC_SEQ_HANDLERS*)file->data; | ||
264 | seq_handlers->next = next_handler; | ||
265 | seq_handlers->show = show_handler; | ||
266 | seq_handlers->off2element = off2element_handler; | ||
267 | seq_handlers->startstop = startstop_handler; | ||
268 | seq_handlers->data = data; | ||
269 | |||
270 | return file; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntryInDirSeq: cannot make proc entry /proc/%s/%s: no memory", PVRProcDirRoot, name)); | ||
275 | return NULL; | ||
276 | } | ||
277 | |||
278 | |||
279 | struct proc_dir_entry* CreateProcReadEntrySeq ( | ||
280 | const IMG_CHAR * name, | ||
281 | IMG_VOID* data, | ||
282 | pvr_next_proc_seq_t next_handler, | ||
283 | pvr_show_proc_seq_t show_handler, | ||
284 | pvr_off2element_proc_seq_t off2element_handler, | ||
285 | pvr_startstop_proc_seq_t startstop_handler | ||
286 | ) | ||
287 | { | ||
288 | return CreateProcEntrySeq(name, | ||
289 | data, | ||
290 | next_handler, | ||
291 | show_handler, | ||
292 | off2element_handler, | ||
293 | startstop_handler, | ||
294 | NULL); | ||
295 | } | ||
296 | |||
297 | struct proc_dir_entry* CreateProcEntrySeq ( | ||
298 | const IMG_CHAR * name, | ||
299 | IMG_VOID* data, | ||
300 | pvr_next_proc_seq_t next_handler, | ||
301 | pvr_show_proc_seq_t show_handler, | ||
302 | pvr_off2element_proc_seq_t off2element_handler, | ||
303 | pvr_startstop_proc_seq_t startstop_handler, | ||
304 | write_proc_t whandler | ||
305 | ) | ||
306 | { | ||
307 | return CreateProcEntryInDirSeq( | ||
308 | dir, | ||
309 | name, | ||
310 | data, | ||
311 | next_handler, | ||
312 | show_handler, | ||
313 | off2element_handler, | ||
314 | startstop_handler, | ||
315 | whandler | ||
316 | ); | ||
317 | } | ||
318 | |||
319 | |||
320 | |||
321 | struct proc_dir_entry* CreatePerProcessProcEntrySeq ( | ||
322 | const IMG_CHAR * name, | ||
323 | IMG_VOID* data, | ||
324 | pvr_next_proc_seq_t next_handler, | ||
325 | pvr_show_proc_seq_t show_handler, | ||
326 | pvr_off2element_proc_seq_t off2element_handler, | ||
327 | pvr_startstop_proc_seq_t startstop_handler, | ||
328 | write_proc_t whandler | ||
329 | ) | ||
330 | { | ||
331 | PVRSRV_ENV_PER_PROCESS_DATA *psPerProc; | ||
332 | IMG_UINT32 ui32PID; | ||
333 | |||
334 | if (!dir) | ||
335 | { | ||
336 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntrySeq: /proc/%s doesn't exist", PVRProcDirRoot)); | ||
337 | return NULL; | ||
338 | } | ||
339 | |||
340 | ui32PID = OSGetCurrentProcessIDKM(); | ||
341 | |||
342 | psPerProc = PVRSRVPerProcessPrivateData(ui32PID); | ||
343 | if (!psPerProc) | ||
344 | { | ||
345 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntrySeq: no per process data")); | ||
346 | |||
347 | return NULL; | ||
348 | } | ||
349 | |||
350 | if (!psPerProc->psProcDir) | ||
351 | { | ||
352 | IMG_CHAR dirname[16]; | ||
353 | IMG_INT ret; | ||
354 | |||
355 | ret = snprintf(dirname, sizeof(dirname), "%u", ui32PID); | ||
356 | |||
357 | if (ret <=0 || ret >= (IMG_INT)sizeof(dirname)) | ||
358 | { | ||
359 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntries: couldn't generate per process proc directory name \"%u\"", ui32PID)); | ||
360 | return NULL; | ||
361 | } | ||
362 | else | ||
363 | { | ||
364 | psPerProc->psProcDir = proc_mkdir(dirname, dir); | ||
365 | if (!psPerProc->psProcDir) | ||
366 | { | ||
367 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntries: couldn't create per process proc directory /proc/%s/%u", | ||
368 | PVRProcDirRoot, ui32PID)); | ||
369 | return NULL; | ||
370 | } | ||
371 | } | ||
372 | } | ||
373 | |||
374 | return CreateProcEntryInDirSeq(psPerProc->psProcDir, name, data, next_handler, | ||
375 | show_handler,off2element_handler,startstop_handler,whandler); | ||
376 | } | ||
377 | |||
378 | |||
379 | IMG_VOID RemoveProcEntrySeq( struct proc_dir_entry* proc_entry ) | ||
380 | { | ||
381 | if (dir) | ||
382 | { | ||
383 | void* data = proc_entry->data ; | ||
384 | PVR_DPF((PVR_DBG_MESSAGE, "Removing /proc/%s/%s", PVRProcDirRoot, proc_entry->name)); | ||
385 | |||
386 | remove_proc_entry(proc_entry->name, dir); | ||
387 | if( data) | ||
388 | kfree( data ); | ||
389 | |||
390 | } | ||
391 | } | ||
392 | |||
393 | IMG_VOID RemovePerProcessProcEntrySeq(struct proc_dir_entry* proc_entry) | ||
394 | { | ||
395 | PVRSRV_ENV_PER_PROCESS_DATA *psPerProc; | ||
396 | |||
397 | psPerProc = LinuxTerminatingProcessPrivateData(); | ||
398 | if (!psPerProc) | ||
399 | { | ||
400 | psPerProc = PVRSRVFindPerProcessPrivateData(); | ||
401 | if (!psPerProc) | ||
402 | { | ||
403 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntries: can't " | ||
404 | "remove %s, no per process data", proc_entry->name)); | ||
405 | return; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | if (psPerProc->psProcDir) | ||
410 | { | ||
411 | void* data = proc_entry->data ; | ||
412 | PVR_DPF((PVR_DBG_MESSAGE, "Removing proc entry %s from %s", proc_entry->name, psPerProc->psProcDir->name)); | ||
413 | |||
414 | remove_proc_entry(proc_entry->name, psPerProc->psProcDir); | ||
415 | if(data) | ||
416 | kfree( data ); | ||
417 | } | ||
418 | } | ||
419 | |||
420 | static IMG_INT pvr_read_proc(IMG_CHAR *page, IMG_CHAR **start, off_t off, | ||
421 | IMG_INT count, IMG_INT *eof, IMG_VOID *data) | ||
422 | { | ||
423 | |||
424 | pvr_read_proc_t *pprn = (pvr_read_proc_t *)data; | ||
425 | |||
426 | off_t len = pprn (page, (size_t)count, off); | ||
427 | |||
428 | if (len == END_OF_FILE) | ||
429 | { | ||
430 | len = 0; | ||
431 | *eof = 1; | ||
432 | } | ||
433 | else if (!len) | ||
434 | { | ||
435 | *start = (IMG_CHAR *) 0; | ||
436 | } | ||
437 | else | ||
438 | { | ||
439 | *start = (IMG_CHAR *) 1; | ||
440 | } | ||
441 | |||
442 | return len; | ||
443 | } | ||
444 | |||
445 | |||
446 | static IMG_INT CreateProcEntryInDir(struct proc_dir_entry *pdir, const IMG_CHAR * name, read_proc_t rhandler, write_proc_t whandler, IMG_VOID *data) | ||
447 | { | ||
448 | struct proc_dir_entry * file; | ||
449 | mode_t mode; | ||
450 | |||
451 | if (!pdir) | ||
452 | { | ||
453 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntryInDir: parent directory doesn't exist")); | ||
454 | |||
455 | return -ENOMEM; | ||
456 | } | ||
457 | |||
458 | mode = S_IFREG; | ||
459 | |||
460 | if (rhandler) | ||
461 | { | ||
462 | mode |= S_IRUGO; | ||
463 | } | ||
464 | |||
465 | if (whandler) | ||
466 | { | ||
467 | mode |= S_IWUSR; | ||
468 | } | ||
469 | |||
470 | file = create_proc_entry(name, mode, pdir); | ||
471 | |||
472 | if (file) | ||
473 | { | ||
474 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) | ||
475 | file->owner = THIS_MODULE; | ||
476 | #endif | ||
477 | file->read_proc = rhandler; | ||
478 | file->write_proc = whandler; | ||
479 | file->data = data; | ||
480 | |||
481 | PVR_DPF((PVR_DBG_MESSAGE, "Created proc entry %s in %s", name, pdir->name)); | ||
482 | |||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntry: cannot create proc entry %s in %s", name, pdir->name)); | ||
487 | |||
488 | return -ENOMEM; | ||
489 | } | ||
490 | |||
491 | |||
492 | IMG_INT CreateProcEntry(const IMG_CHAR * name, read_proc_t rhandler, write_proc_t whandler, IMG_VOID *data) | ||
493 | { | ||
494 | return CreateProcEntryInDir(dir, name, rhandler, whandler, data); | ||
495 | } | ||
496 | |||
497 | |||
498 | IMG_INT CreatePerProcessProcEntry(const IMG_CHAR * name, read_proc_t rhandler, write_proc_t whandler, IMG_VOID *data) | ||
499 | { | ||
500 | PVRSRV_ENV_PER_PROCESS_DATA *psPerProc; | ||
501 | IMG_UINT32 ui32PID; | ||
502 | |||
503 | if (!dir) | ||
504 | { | ||
505 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntries: /proc/%s doesn't exist", PVRProcDirRoot)); | ||
506 | |||
507 | return -ENOMEM; | ||
508 | } | ||
509 | |||
510 | ui32PID = OSGetCurrentProcessIDKM(); | ||
511 | |||
512 | psPerProc = PVRSRVPerProcessPrivateData(ui32PID); | ||
513 | if (!psPerProc) | ||
514 | { | ||
515 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntries: no per process data")); | ||
516 | |||
517 | return -ENOMEM; | ||
518 | } | ||
519 | |||
520 | if (!psPerProc->psProcDir) | ||
521 | { | ||
522 | IMG_CHAR dirname[16]; | ||
523 | IMG_INT ret; | ||
524 | |||
525 | ret = snprintf(dirname, sizeof(dirname), "%u", ui32PID); | ||
526 | |||
527 | if (ret <=0 || ret >= (IMG_INT)sizeof(dirname)) | ||
528 | { | ||
529 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntries: couldn't generate per process proc directory name \"%u\"", ui32PID)); | ||
530 | |||
531 | return -ENOMEM; | ||
532 | } | ||
533 | else | ||
534 | { | ||
535 | psPerProc->psProcDir = proc_mkdir(dirname, dir); | ||
536 | if (!psPerProc->psProcDir) | ||
537 | { | ||
538 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntries: couldn't create per process proc directory /proc/%s/%u", PVRProcDirRoot, ui32PID)); | ||
539 | |||
540 | return -ENOMEM; | ||
541 | } | ||
542 | } | ||
543 | } | ||
544 | |||
545 | return CreateProcEntryInDir(psPerProc->psProcDir, name, rhandler, whandler, data); | ||
546 | } | ||
547 | |||
548 | |||
549 | IMG_INT CreateProcReadEntry(const IMG_CHAR * name, pvr_read_proc_t handler) | ||
550 | { | ||
551 | struct proc_dir_entry * file; | ||
552 | |||
553 | if (!dir) | ||
554 | { | ||
555 | PVR_DPF((PVR_DBG_ERROR, "CreateProcReadEntry: cannot make proc entry /proc/%s/%s: no parent", PVRProcDirRoot, name)); | ||
556 | |||
557 | return -ENOMEM; | ||
558 | } | ||
559 | |||
560 | |||
561 | file = create_proc_read_entry (name, S_IFREG | S_IRUGO, dir, pvr_read_proc, (IMG_VOID *)handler); | ||
562 | |||
563 | if (file) | ||
564 | { | ||
565 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) | ||
566 | file->owner = THIS_MODULE; | ||
567 | #endif | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | PVR_DPF((PVR_DBG_ERROR, "CreateProcReadEntry: cannot make proc entry /proc/%s/%s: no memory", PVRProcDirRoot, name)); | ||
572 | |||
573 | return -ENOMEM; | ||
574 | } | ||
575 | |||
576 | |||
577 | IMG_INT CreateProcEntries(IMG_VOID) | ||
578 | { | ||
579 | dir = proc_mkdir (PVRProcDirRoot, NULL); | ||
580 | |||
581 | if (!dir) | ||
582 | { | ||
583 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntries: cannot make /proc/%s directory", PVRProcDirRoot)); | ||
584 | |||
585 | return -ENOMEM; | ||
586 | } | ||
587 | |||
588 | g_pProcQueue = CreateProcReadEntrySeq("queue", NULL, NULL, ProcSeqShowQueue, ProcSeqOff2ElementQueue, NULL); | ||
589 | g_pProcVersion = CreateProcReadEntrySeq("version", NULL, NULL, ProcSeqShowVersion, ProcSeq1ElementHeaderOff2Element, NULL); | ||
590 | g_pProcSysNodes = CreateProcReadEntrySeq("nodes", NULL, NULL, ProcSeqShowSysNodes, ProcSeqOff2ElementSysNodes, NULL); | ||
591 | |||
592 | if(!g_pProcQueue || !g_pProcVersion || !g_pProcSysNodes) | ||
593 | { | ||
594 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntries: couldn't make /proc/%s files", PVRProcDirRoot)); | ||
595 | |||
596 | return -ENOMEM; | ||
597 | } | ||
598 | |||
599 | |||
600 | #ifdef DEBUG | ||
601 | |||
602 | g_pProcDebugLevel = CreateProcEntrySeq("debug_level", NULL, NULL, | ||
603 | ProcSeqShowDebugLevel, | ||
604 | ProcSeq1ElementOff2Element, NULL, | ||
605 | (IMG_VOID*)PVRDebugProcSetLevel); | ||
606 | if(!g_pProcDebugLevel) | ||
607 | { | ||
608 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntries: couldn't make /proc/%s/debug_level", PVRProcDirRoot)); | ||
609 | |||
610 | return -ENOMEM; | ||
611 | } | ||
612 | |||
613 | #ifdef PVR_MANUAL_POWER_CONTROL | ||
614 | g_pProcPowerLevel = CreateProcEntrySeq("power_control", NULL, NULL, | ||
615 | ProcSeqShowPowerLevel, | ||
616 | ProcSeq1ElementOff2Element, NULL, | ||
617 | PVRProcSetPowerLevel); | ||
618 | if(!g_pProcPowerLevel) | ||
619 | { | ||
620 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntries: couldn't make /proc/%s/power_control", PVRProcDirRoot)); | ||
621 | |||
622 | return -ENOMEM; | ||
623 | } | ||
624 | #endif | ||
625 | #endif | ||
626 | |||
627 | return 0; | ||
628 | } | ||
629 | |||
630 | |||
631 | IMG_VOID RemoveProcEntry(const IMG_CHAR * name) | ||
632 | { | ||
633 | if (dir) | ||
634 | { | ||
635 | remove_proc_entry(name, dir); | ||
636 | PVR_DPF((PVR_DBG_MESSAGE, "Removing /proc/%s/%s", PVRProcDirRoot, name)); | ||
637 | } | ||
638 | } | ||
639 | |||
640 | |||
641 | IMG_VOID RemovePerProcessProcEntry(const IMG_CHAR *name) | ||
642 | { | ||
643 | PVRSRV_ENV_PER_PROCESS_DATA *psPerProc; | ||
644 | |||
645 | psPerProc = LinuxTerminatingProcessPrivateData(); | ||
646 | if (!psPerProc) | ||
647 | { | ||
648 | psPerProc = PVRSRVFindPerProcessPrivateData(); | ||
649 | if (!psPerProc) | ||
650 | { | ||
651 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntries: can't " | ||
652 | "remove %s, no per process data", name)); | ||
653 | return; | ||
654 | } | ||
655 | } | ||
656 | |||
657 | if (psPerProc->psProcDir) | ||
658 | { | ||
659 | remove_proc_entry(name, psPerProc->psProcDir); | ||
660 | |||
661 | PVR_DPF((PVR_DBG_MESSAGE, "Removing proc entry %s from %s", name, psPerProc->psProcDir->name)); | ||
662 | } | ||
663 | } | ||
664 | |||
665 | |||
666 | IMG_VOID RemovePerProcessProcDir(PVRSRV_ENV_PER_PROCESS_DATA *psPerProc) | ||
667 | { | ||
668 | if (psPerProc->psProcDir) | ||
669 | { | ||
670 | while (psPerProc->psProcDir->subdir) | ||
671 | { | ||
672 | PVR_DPF((PVR_DBG_WARNING, "Belatedly removing /proc/%s/%s/%s", PVRProcDirRoot, psPerProc->psProcDir->name, psPerProc->psProcDir->subdir->name)); | ||
673 | |||
674 | RemoveProcEntry(psPerProc->psProcDir->subdir->name); | ||
675 | } | ||
676 | RemoveProcEntry(psPerProc->psProcDir->name); | ||
677 | } | ||
678 | } | ||
679 | |||
680 | IMG_VOID RemoveProcEntries(IMG_VOID) | ||
681 | { | ||
682 | #ifdef DEBUG | ||
683 | RemoveProcEntrySeq( g_pProcDebugLevel ); | ||
684 | #ifdef PVR_MANUAL_POWER_CONTROL | ||
685 | RemoveProcEntrySeq( g_pProcPowerLevel ); | ||
686 | #endif | ||
687 | #endif | ||
688 | |||
689 | RemoveProcEntrySeq(g_pProcQueue); | ||
690 | RemoveProcEntrySeq(g_pProcVersion); | ||
691 | RemoveProcEntrySeq(g_pProcSysNodes); | ||
692 | |||
693 | while (dir->subdir) | ||
694 | { | ||
695 | PVR_DPF((PVR_DBG_WARNING, "Belatedly removing /proc/%s/%s", PVRProcDirRoot, dir->subdir->name)); | ||
696 | |||
697 | RemoveProcEntry(dir->subdir->name); | ||
698 | } | ||
699 | |||
700 | remove_proc_entry(PVRProcDirRoot, NULL); | ||
701 | } | ||
702 | |||
703 | static void ProcSeqShowVersion(struct seq_file *sfile,void* el) | ||
704 | { | ||
705 | SYS_DATA * psSysData; | ||
706 | IMG_CHAR *pszSystemVersionString = "None"; | ||
707 | |||
708 | if(el == PVR_PROC_SEQ_START_TOKEN) | ||
709 | { | ||
710 | seq_printf( sfile, | ||
711 | "Version %s (%s) %s\n", | ||
712 | PVRVERSION_STRING, | ||
713 | PVR_BUILD_TYPE, PVR_BUILD_DIR); | ||
714 | return; | ||
715 | } | ||
716 | |||
717 | SysAcquireData(&psSysData); | ||
718 | |||
719 | if(psSysData->pszVersionString) | ||
720 | { | ||
721 | pszSystemVersionString = psSysData->pszVersionString; | ||
722 | } | ||
723 | |||
724 | seq_printf( sfile, "System Version String: %s\n", pszSystemVersionString); | ||
725 | } | ||
726 | |||
727 | static const IMG_CHAR *deviceTypeToString(PVRSRV_DEVICE_TYPE deviceType) | ||
728 | { | ||
729 | switch (deviceType) | ||
730 | { | ||
731 | default: | ||
732 | { | ||
733 | static IMG_CHAR text[10]; | ||
734 | |||
735 | sprintf(text, "?%x", (IMG_UINT)deviceType); | ||
736 | |||
737 | return text; | ||
738 | } | ||
739 | } | ||
740 | } | ||
741 | |||
742 | |||
743 | static const IMG_CHAR *deviceClassToString(PVRSRV_DEVICE_CLASS deviceClass) | ||
744 | { | ||
745 | switch (deviceClass) | ||
746 | { | ||
747 | case PVRSRV_DEVICE_CLASS_3D: | ||
748 | { | ||
749 | return "3D"; | ||
750 | } | ||
751 | case PVRSRV_DEVICE_CLASS_DISPLAY: | ||
752 | { | ||
753 | return "display"; | ||
754 | } | ||
755 | case PVRSRV_DEVICE_CLASS_BUFFER: | ||
756 | { | ||
757 | return "buffer"; | ||
758 | } | ||
759 | default: | ||
760 | { | ||
761 | static IMG_CHAR text[10]; | ||
762 | |||
763 | sprintf(text, "?%x", (IMG_UINT)deviceClass); | ||
764 | return text; | ||
765 | } | ||
766 | } | ||
767 | } | ||
768 | |||
769 | static IMG_VOID* DecOffPsDev_AnyVaCb(PVRSRV_DEVICE_NODE *psNode, va_list va) | ||
770 | { | ||
771 | off_t *pOff = va_arg(va, off_t*); | ||
772 | if (--(*pOff)) | ||
773 | { | ||
774 | return IMG_NULL; | ||
775 | } | ||
776 | else | ||
777 | { | ||
778 | return psNode; | ||
779 | } | ||
780 | } | ||
781 | |||
782 | static void ProcSeqShowSysNodes(struct seq_file *sfile,void* el) | ||
783 | { | ||
784 | SYS_DATA * psSysData; | ||
785 | PVRSRV_DEVICE_NODE *psDevNode = (PVRSRV_DEVICE_NODE*)el; | ||
786 | |||
787 | if(el == PVR_PROC_SEQ_START_TOKEN) | ||
788 | { | ||
789 | seq_printf( sfile, | ||
790 | "Registered nodes\n" | ||
791 | "Addr Type Class Index Ref pvDev Size Res\n"); | ||
792 | return; | ||
793 | } | ||
794 | |||
795 | SysAcquireData(&psSysData); | ||
796 | |||
797 | seq_printf( sfile, | ||
798 | "%p %-8s %-8s %4d %2u %p %3u %p\n", | ||
799 | psDevNode, | ||
800 | deviceTypeToString(psDevNode->sDevId.eDeviceType), | ||
801 | deviceClassToString(psDevNode->sDevId.eDeviceClass), | ||
802 | psDevNode->sDevId.eDeviceClass, | ||
803 | psDevNode->ui32RefCount, | ||
804 | psDevNode->pvDevice, | ||
805 | psDevNode->ui32pvDeviceSize, | ||
806 | psDevNode->hResManContext); | ||
807 | |||
808 | } | ||
809 | |||
810 | static void* ProcSeqOff2ElementSysNodes(struct seq_file * sfile, loff_t off) | ||
811 | { | ||
812 | SYS_DATA *psSysData; | ||
813 | PVRSRV_DEVICE_NODE *psDevNode; | ||
814 | |||
815 | PVR_UNREFERENCED_PARAMETER(sfile); | ||
816 | |||
817 | if(!off) | ||
818 | { | ||
819 | return PVR_PROC_SEQ_START_TOKEN; | ||
820 | } | ||
821 | |||
822 | SysAcquireData(&psSysData); | ||
823 | |||
824 | |||
825 | psDevNode = (PVRSRV_DEVICE_NODE*) | ||
826 | List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, | ||
827 | DecOffPsDev_AnyVaCb, | ||
828 | &off); | ||
829 | |||
830 | |||
831 | return (void*)psDevNode; | ||
832 | } | ||
833 | |||