diff options
Diffstat (limited to 'sgx_km/eurasia_km/services4/srvkm/env/linux/proc.c')
-rw-r--r-- | sgx_km/eurasia_km/services4/srvkm/env/linux/proc.c | 1059 |
1 files changed, 1059 insertions, 0 deletions
diff --git a/sgx_km/eurasia_km/services4/srvkm/env/linux/proc.c b/sgx_km/eurasia_km/services4/srvkm/env/linux/proc.c new file mode 100644 index 0000000..0f954c1 --- /dev/null +++ b/sgx_km/eurasia_km/services4/srvkm/env/linux/proc.c | |||
@@ -0,0 +1,1059 @@ | |||
1 | /*************************************************************************/ /*! | ||
2 | @Title Proc files implementation. | ||
3 | @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved | ||
4 | @Description Functions for creating and reading proc filesystem entries. | ||
5 | Proc filesystem support must be built into the kernel for | ||
6 | these functions to be any use. | ||
7 | @License Dual MIT/GPLv2 | ||
8 | |||
9 | The contents of this file are subject to the MIT license as set out below. | ||
10 | |||
11 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
12 | of this software and associated documentation files (the "Software"), to deal | ||
13 | in the Software without restriction, including without limitation the rights | ||
14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
15 | copies of the Software, and to permit persons to whom the Software is | ||
16 | furnished to do so, subject to the following conditions: | ||
17 | |||
18 | The above copyright notice and this permission notice shall be included in | ||
19 | all copies or substantial portions of the Software. | ||
20 | |||
21 | Alternatively, the contents of this file may be used under the terms of | ||
22 | the GNU General Public License Version 2 ("GPL") in which case the provisions | ||
23 | of GPL are applicable instead of those above. | ||
24 | |||
25 | If you wish to allow use of your version of this file only under the terms of | ||
26 | GPL, and not to allow others to use your version of this file under the terms | ||
27 | of the MIT license, indicate your decision by deleting the provisions above | ||
28 | and replace them with the notice and other provisions required by GPL as set | ||
29 | out in the file called "GPL-COPYING" included in this distribution. If you do | ||
30 | not delete the provisions above, a recipient may use your version of this file | ||
31 | under the terms of either the MIT license or GPL. | ||
32 | |||
33 | This License is also included in this distribution in the file called | ||
34 | "MIT-COPYING". | ||
35 | |||
36 | EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS | ||
37 | PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING | ||
38 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | ||
39 | PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR | ||
40 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
41 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
42 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
43 | */ /**************************************************************************/ | ||
44 | |||
45 | #include <linux/version.h> | ||
46 | |||
47 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)) | ||
48 | #ifndef AUTOCONF_INCLUDED | ||
49 | #include <linux/config.h> | ||
50 | #endif | ||
51 | #endif | ||
52 | |||
53 | #include <linux/init.h> | ||
54 | #include <linux/module.h> | ||
55 | #include <linux/fs.h> | ||
56 | #include <linux/proc_fs.h> | ||
57 | #include <linux/seq_file.h> | ||
58 | |||
59 | #include "services_headers.h" | ||
60 | |||
61 | #include "queue.h" | ||
62 | #include "resman.h" | ||
63 | #include "pvrmmap.h" | ||
64 | #include "pvr_debug.h" | ||
65 | #include "pvrversion.h" | ||
66 | #include "proc.h" | ||
67 | #include "perproc.h" | ||
68 | #include "env_perproc.h" | ||
69 | #include "linkage.h" | ||
70 | |||
71 | #include "lists.h" | ||
72 | |||
73 | struct pvr_proc_dir_entry { | ||
74 | struct proc_dir_entry *pde; | ||
75 | |||
76 | pvr_next_proc_seq_t *next; | ||
77 | pvr_show_proc_seq_t *show; | ||
78 | pvr_off2element_proc_seq_t *off2element; | ||
79 | pvr_startstop_proc_seq_t *startstop; | ||
80 | |||
81 | pvr_proc_write_t *write; | ||
82 | |||
83 | IMG_VOID *data; | ||
84 | }; | ||
85 | |||
86 | // The proc entry for our /proc/pvr directory | ||
87 | static struct proc_dir_entry * dir; | ||
88 | |||
89 | static const IMG_CHAR PVRProcDirRoot[] = "pvr"; | ||
90 | |||
91 | static IMG_INT pvr_proc_open(struct inode *inode,struct file *file); | ||
92 | static ssize_t pvr_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos); | ||
93 | |||
94 | static struct file_operations pvr_proc_operations = | ||
95 | { | ||
96 | .open = pvr_proc_open, | ||
97 | .read = seq_read, | ||
98 | .write = pvr_proc_write, | ||
99 | .llseek = seq_lseek, | ||
100 | .release = seq_release, | ||
101 | }; | ||
102 | |||
103 | static void *pvr_proc_seq_start (struct seq_file *m, loff_t *pos); | ||
104 | static void *pvr_proc_seq_next (struct seq_file *m, void *v, loff_t *pos); | ||
105 | static void pvr_proc_seq_stop (struct seq_file *m, void *v); | ||
106 | static int pvr_proc_seq_show (struct seq_file *m, void *v); | ||
107 | |||
108 | static struct seq_operations pvr_proc_seq_operations = | ||
109 | { | ||
110 | .start = pvr_proc_seq_start, | ||
111 | .next = pvr_proc_seq_next, | ||
112 | .stop = pvr_proc_seq_stop, | ||
113 | .show = pvr_proc_seq_show, | ||
114 | }; | ||
115 | |||
116 | #if defined(SUPPORT_PVRSRV_DEVICE_CLASS) | ||
117 | static struct pvr_proc_dir_entry* g_pProcQueue; | ||
118 | #endif | ||
119 | static struct pvr_proc_dir_entry* g_pProcVersion; | ||
120 | static struct pvr_proc_dir_entry* g_pProcSysNodes; | ||
121 | |||
122 | #ifdef DEBUG | ||
123 | static struct pvr_proc_dir_entry* g_pProcDebugLevel; | ||
124 | #endif | ||
125 | |||
126 | #ifdef PVR_MANUAL_POWER_CONTROL | ||
127 | static struct pvr_proc_dir_entry* g_pProcPowerLevel; | ||
128 | #endif | ||
129 | |||
130 | |||
131 | static void ProcSeqShowVersion(struct seq_file *sfile,void* el); | ||
132 | |||
133 | static void ProcSeqShowSysNodes(struct seq_file *sfile,void* el); | ||
134 | static void* ProcSeqOff2ElementSysNodes(struct seq_file * sfile, loff_t off); | ||
135 | |||
136 | |||
137 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) | ||
138 | #define PDE_DATA(x) PDE(x)->data; | ||
139 | #endif | ||
140 | |||
141 | #ifdef DEBUG | ||
142 | |||
143 | /*! | ||
144 | ****************************************************************************** | ||
145 | |||
146 | @Function : ProcSeq1ElementOff2Element | ||
147 | |||
148 | @Description | ||
149 | |||
150 | Heleper Offset -> Element function for /proc files with only one entry | ||
151 | without header. | ||
152 | |||
153 | @Input sfile : seq_file object related to /proc/ file | ||
154 | |||
155 | @Input off : the offset into the buffer (id of object) | ||
156 | |||
157 | @Return : Pointer to element to be shown. | ||
158 | |||
159 | *****************************************************************************/ | ||
160 | static void* ProcSeq1ElementOff2Element(struct seq_file *sfile, loff_t off) | ||
161 | { | ||
162 | PVR_UNREFERENCED_PARAMETER(sfile); | ||
163 | // Return anything that is not PVR_RPOC_SEQ_START_TOKEN and NULL | ||
164 | if(!off) | ||
165 | return (void*)2; | ||
166 | return NULL; | ||
167 | } | ||
168 | |||
169 | #endif | ||
170 | |||
171 | /*! | ||
172 | ****************************************************************************** | ||
173 | |||
174 | @Function : ProcSeq1ElementHeaderOff2Element | ||
175 | |||
176 | @Description | ||
177 | |||
178 | Heleper Offset -> Element function for /proc files with only one entry | ||
179 | with header. | ||
180 | |||
181 | @Input sfile : seq_file object related to /proc/ file | ||
182 | |||
183 | @Input off : the offset into the buffer (id of object) | ||
184 | |||
185 | @Return : Pointer to element to be shown. | ||
186 | |||
187 | *****************************************************************************/ | ||
188 | static void* ProcSeq1ElementHeaderOff2Element(struct seq_file *sfile, loff_t off) | ||
189 | { | ||
190 | PVR_UNREFERENCED_PARAMETER(sfile); | ||
191 | |||
192 | if(!off) | ||
193 | { | ||
194 | return PVR_PROC_SEQ_START_TOKEN; | ||
195 | } | ||
196 | |||
197 | // Return anything that is not PVR_RPOC_SEQ_START_TOKEN and NULL | ||
198 | if(off == 1) | ||
199 | return (void*)2; | ||
200 | |||
201 | return NULL; | ||
202 | } | ||
203 | |||
204 | |||
205 | /*! | ||
206 | ****************************************************************************** | ||
207 | |||
208 | @Function : pvr_proc_open | ||
209 | |||
210 | @Description | ||
211 | File opening function passed to proc_dir_entry->proc_fops for /proc entries | ||
212 | created by CreateProcReadEntrySeq. | ||
213 | |||
214 | @Input inode : inode entry of opened /proc file | ||
215 | |||
216 | @Input file : file entry of opened /proc file | ||
217 | |||
218 | @Return : 0 if no errors | ||
219 | |||
220 | *****************************************************************************/ | ||
221 | static IMG_INT pvr_proc_open(struct inode *inode,struct file *file) | ||
222 | { | ||
223 | IMG_INT ret = seq_open(file, &pvr_proc_seq_operations); | ||
224 | |||
225 | struct seq_file *seq = (struct seq_file*)file->private_data; | ||
226 | struct pvr_proc_dir_entry* ppde = PDE_DATA(inode); | ||
227 | |||
228 | /* Add pointer to handlers to seq_file structure */ | ||
229 | seq->private = ppde; | ||
230 | return ret; | ||
231 | } | ||
232 | |||
233 | /*! | ||
234 | ****************************************************************************** | ||
235 | |||
236 | @Function : pvr_proc_write | ||
237 | |||
238 | @Description | ||
239 | File writing function passed to proc_dir_entry->proc_fops for /proc files. | ||
240 | It's exacly the same function that is used as default one (->fs/proc/generic.c), | ||
241 | it calls proc_dir_entry->write_proc for writing procedure. | ||
242 | |||
243 | *****************************************************************************/ | ||
244 | static ssize_t pvr_proc_write(struct file *file, const char __user *buffer, | ||
245 | size_t count, loff_t *ppos) | ||
246 | { | ||
247 | struct inode *inode = file->f_path.dentry->d_inode; | ||
248 | struct pvr_proc_dir_entry * ppde; | ||
249 | |||
250 | PVR_UNREFERENCED_PARAMETER(ppos); | ||
251 | ppde = PDE_DATA(inode); | ||
252 | |||
253 | if (!ppde->write) | ||
254 | return -EIO; | ||
255 | |||
256 | return ppde->write(file, buffer, count, ppde->data); | ||
257 | } | ||
258 | |||
259 | |||
260 | /*! | ||
261 | ****************************************************************************** | ||
262 | |||
263 | @Function : pvr_proc_seq_start | ||
264 | |||
265 | @Description | ||
266 | Seq_file start function. Detailed description of seq_file workflow can | ||
267 | be found here: http://tldp.org/LDP/lkmpg/2.6/html/x861.html. | ||
268 | This function ises off2element handler. | ||
269 | |||
270 | @Input proc_seq_file : sequence file entry | ||
271 | |||
272 | @Input pos : offset within file (id of entry) | ||
273 | |||
274 | @Return : Pointer to element from we start enumeration (0 ends it) | ||
275 | |||
276 | *****************************************************************************/ | ||
277 | static void *pvr_proc_seq_start (struct seq_file *proc_seq_file, loff_t *pos) | ||
278 | { | ||
279 | struct pvr_proc_dir_entry *ppde = (struct pvr_proc_dir_entry*)proc_seq_file->private; | ||
280 | if(ppde->startstop != NULL) | ||
281 | ppde->startstop(proc_seq_file, IMG_TRUE); | ||
282 | return ppde->off2element(proc_seq_file, *pos); | ||
283 | } | ||
284 | |||
285 | /*! | ||
286 | ****************************************************************************** | ||
287 | |||
288 | @Function : pvr_proc_seq_stop | ||
289 | |||
290 | @Description | ||
291 | Seq_file stop function. Detailed description of seq_file workflow can | ||
292 | be found here: http://tldp.org/LDP/lkmpg/2.6/html/x861.html. | ||
293 | |||
294 | @Input proc_seq_file : sequence file entry | ||
295 | |||
296 | @Input v : current element pointer | ||
297 | |||
298 | *****************************************************************************/ | ||
299 | static void pvr_proc_seq_stop (struct seq_file *proc_seq_file, void *v) | ||
300 | { | ||
301 | struct pvr_proc_dir_entry *ppde = (struct pvr_proc_dir_entry*)proc_seq_file->private; | ||
302 | PVR_UNREFERENCED_PARAMETER(v); | ||
303 | |||
304 | if(ppde->startstop != NULL) | ||
305 | ppde->startstop(proc_seq_file, IMG_FALSE); | ||
306 | } | ||
307 | |||
308 | /*! | ||
309 | ****************************************************************************** | ||
310 | |||
311 | @Function : pvr_proc_seq_next | ||
312 | |||
313 | @Description | ||
314 | Seq_file next element function. Detailed description of seq_file workflow can | ||
315 | be found here: http://tldp.org/LDP/lkmpg/2.6/html/x861.html. | ||
316 | It uses supplied 'next' handler for fetching next element (or 0 if there is no one) | ||
317 | |||
318 | @Input proc_seq_file : sequence file entry | ||
319 | |||
320 | @Input pos : offset within file (id of entry) | ||
321 | |||
322 | @Input v : current element pointer | ||
323 | |||
324 | @Return : next element pointer (or 0 if end) | ||
325 | |||
326 | *****************************************************************************/ | ||
327 | static void *pvr_proc_seq_next (struct seq_file *proc_seq_file, void *v, loff_t *pos) | ||
328 | { | ||
329 | struct pvr_proc_dir_entry *ppde = (struct pvr_proc_dir_entry*)proc_seq_file->private; | ||
330 | (*pos)++; | ||
331 | if(ppde->next != NULL) | ||
332 | return ppde->next( proc_seq_file, v, *pos ); | ||
333 | return ppde->off2element(proc_seq_file, *pos); | ||
334 | } | ||
335 | |||
336 | /*! | ||
337 | ****************************************************************************** | ||
338 | |||
339 | @Function : pvr_proc_seq_show | ||
340 | |||
341 | @Description | ||
342 | Seq_file show element function. Detailed description of seq_file workflow can | ||
343 | be found here: http://tldp.org/LDP/lkmpg/2.6/html/x861.html. | ||
344 | It call proper 'show' handler to show (dump) current element using seq_* functions | ||
345 | |||
346 | @Input proc_seq_file : sequence file entry | ||
347 | |||
348 | @Input v : current element pointer | ||
349 | |||
350 | @Return : 0 if everything is OK | ||
351 | |||
352 | *****************************************************************************/ | ||
353 | static int pvr_proc_seq_show (struct seq_file *proc_seq_file, void *v) | ||
354 | { | ||
355 | struct pvr_proc_dir_entry *ppde = (struct pvr_proc_dir_entry*)proc_seq_file->private; | ||
356 | ppde->show( proc_seq_file,v ); | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | |||
361 | |||
362 | /*! | ||
363 | ****************************************************************************** | ||
364 | |||
365 | @Function : CreateProcEntryInDirSeq | ||
366 | |||
367 | @Description | ||
368 | |||
369 | Create a file under the given directory. These dynamic files can be used at | ||
370 | runtime to get or set information about the device. Whis version uses seq_file | ||
371 | interface | ||
372 | |||
373 | @Input pdir : parent directory | ||
374 | |||
375 | @Input name : the name of the file to create | ||
376 | |||
377 | @Input data : aditional data that will be passed to handlers | ||
378 | |||
379 | @Input next_handler : the function to call to provide the next element. OPTIONAL, if not | ||
380 | supplied, then off2element function is used instead | ||
381 | |||
382 | @Input show_handler : the function to call to show element | ||
383 | |||
384 | @Input off2element_handler : the function to call when it is needed to translate offest to element | ||
385 | |||
386 | @Input startstop_handler : the function to call when output memory page starts or stops. OPTIONAL. | ||
387 | |||
388 | @Input whandler : the function to interpret writes from the user | ||
389 | |||
390 | @Return Ptr to proc entry , 0 for failure | ||
391 | |||
392 | |||
393 | *****************************************************************************/ | ||
394 | static struct pvr_proc_dir_entry* CreateProcEntryInDirSeq(struct proc_dir_entry *pdir, | ||
395 | const IMG_CHAR * name, | ||
396 | IMG_VOID* data, | ||
397 | pvr_next_proc_seq_t next_handler, | ||
398 | pvr_show_proc_seq_t show_handler, | ||
399 | pvr_off2element_proc_seq_t off2element_handler, | ||
400 | pvr_startstop_proc_seq_t startstop_handler, | ||
401 | pvr_proc_write_t whandler) | ||
402 | { | ||
403 | |||
404 | struct pvr_proc_dir_entry * ppde; | ||
405 | mode_t mode; | ||
406 | |||
407 | if (!dir) | ||
408 | { | ||
409 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntryInDirSeq: cannot make proc entry /proc/%s/%s: no parent", PVRProcDirRoot, name)); | ||
410 | return NULL; | ||
411 | } | ||
412 | |||
413 | mode = S_IFREG; | ||
414 | |||
415 | if (show_handler) | ||
416 | { | ||
417 | mode |= S_IRUGO; | ||
418 | } | ||
419 | |||
420 | if (whandler) | ||
421 | { | ||
422 | mode |= S_IWUSR; | ||
423 | } | ||
424 | |||
425 | ppde = kmalloc(sizeof(struct pvr_proc_dir_entry), GFP_KERNEL); | ||
426 | if (!ppde) | ||
427 | { | ||
428 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntryInDirSeq: cannot make proc entry /proc/%s/%s: no memory", PVRProcDirRoot, name)); | ||
429 | return NULL; | ||
430 | } | ||
431 | |||
432 | ppde->next = next_handler; | ||
433 | ppde->show = show_handler; | ||
434 | ppde->off2element = off2element_handler; | ||
435 | ppde->startstop = startstop_handler; | ||
436 | ppde->write = whandler; | ||
437 | ppde->data = data; | ||
438 | |||
439 | ppde->pde=proc_create_data(name, mode, pdir, &pvr_proc_operations, ppde); | ||
440 | |||
441 | if (!ppde->pde) | ||
442 | { | ||
443 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntryInDirSeq: cannot make proc entry /proc/%s/%s: proc_create_data failed", PVRProcDirRoot, name)); | ||
444 | kfree(ppde); | ||
445 | return NULL; | ||
446 | } | ||
447 | return ppde; | ||
448 | } | ||
449 | |||
450 | |||
451 | /*! | ||
452 | ****************************************************************************** | ||
453 | |||
454 | @Function : CreateProcReadEntrySeq | ||
455 | |||
456 | @Description | ||
457 | |||
458 | Create a file under /proc/pvr. These dynamic files can be used at runtime | ||
459 | to get information about the device. Creation WILL fail if proc support is | ||
460 | not compiled into the kernel. That said, the Linux kernel is not even happy | ||
461 | to build without /proc support these days. This version uses seq_file structure | ||
462 | for handling content generation. | ||
463 | |||
464 | @Input name : the name of the file to create | ||
465 | |||
466 | @Input data : aditional data that will be passed to handlers | ||
467 | |||
468 | @Input next_handler : the function to call to provide the next element. OPTIONAL, if not | ||
469 | supplied, then off2element function is used instead | ||
470 | |||
471 | @Input show_handler : the function to call to show element | ||
472 | |||
473 | @Input off2element_handler : the function to call when it is needed to translate offest to element | ||
474 | |||
475 | @Input startstop_handler : the function to call when output memory page starts or stops. OPTIONAL. | ||
476 | |||
477 | @Return Ptr to proc entry , 0 for failure | ||
478 | |||
479 | *****************************************************************************/ | ||
480 | struct pvr_proc_dir_entry* CreateProcReadEntrySeq (const IMG_CHAR * name, | ||
481 | IMG_VOID* data, | ||
482 | pvr_next_proc_seq_t next_handler, | ||
483 | pvr_show_proc_seq_t show_handler, | ||
484 | pvr_off2element_proc_seq_t off2element_handler, | ||
485 | pvr_startstop_proc_seq_t startstop_handler) | ||
486 | { | ||
487 | return CreateProcEntrySeq(name, | ||
488 | data, | ||
489 | next_handler, | ||
490 | show_handler, | ||
491 | off2element_handler, | ||
492 | startstop_handler, | ||
493 | NULL); | ||
494 | } | ||
495 | |||
496 | /*! | ||
497 | ****************************************************************************** | ||
498 | |||
499 | @Function : CreateProcEntrySeq | ||
500 | |||
501 | @Description | ||
502 | |||
503 | @Description | ||
504 | |||
505 | Create a file under /proc/pvr. These dynamic files can be used at runtime | ||
506 | to get information about the device. Creation WILL fail if proc support is | ||
507 | not compiled into the kernel. That said, the Linux kernel is not even happy | ||
508 | to build without /proc support these days. This version uses seq_file structure | ||
509 | for handling content generation and is fuller than CreateProcReadEntrySeq (it | ||
510 | supports write access); | ||
511 | |||
512 | @Input name : the name of the file to create | ||
513 | |||
514 | @Input data : aditional data that will be passed to handlers | ||
515 | |||
516 | @Input next_handler : the function to call to provide the next element. OPTIONAL, if not | ||
517 | supplied, then off2element function is used instead | ||
518 | |||
519 | @Input show_handler : the function to call to show element | ||
520 | |||
521 | @Input off2element_handler : the function to call when it is needed to translate offest to element | ||
522 | |||
523 | @Input startstop_handler : the function to call when output memory page starts or stops. OPTIONAL. | ||
524 | |||
525 | @Input whandler : the function to interpret writes from the user | ||
526 | |||
527 | @Return Ptr to proc entry , 0 for failure | ||
528 | |||
529 | *****************************************************************************/ | ||
530 | struct pvr_proc_dir_entry* CreateProcEntrySeq (const IMG_CHAR * name, | ||
531 | IMG_VOID* data, | ||
532 | pvr_next_proc_seq_t next_handler, | ||
533 | pvr_show_proc_seq_t show_handler, | ||
534 | pvr_off2element_proc_seq_t off2element_handler, | ||
535 | pvr_startstop_proc_seq_t startstop_handler, | ||
536 | pvr_proc_write_t whandler) | ||
537 | { | ||
538 | return CreateProcEntryInDirSeq(dir, | ||
539 | name, | ||
540 | data, | ||
541 | next_handler, | ||
542 | show_handler, | ||
543 | off2element_handler, | ||
544 | startstop_handler, | ||
545 | whandler); | ||
546 | } | ||
547 | |||
548 | |||
549 | |||
550 | /*! | ||
551 | ****************************************************************************** | ||
552 | |||
553 | @Function : CreatePerProcessProcEntrySeq | ||
554 | |||
555 | @Description | ||
556 | |||
557 | Create a file under /proc/pvr/<current process ID>. Apart from the | ||
558 | directory where the file is created, this works the same way as | ||
559 | CreateProcEntry. It's seq_file version. | ||
560 | |||
561 | |||
562 | |||
563 | @Input name : the name of the file to create | ||
564 | |||
565 | @Input data : aditional data that will be passed to handlers | ||
566 | |||
567 | @Input next_handler : the function to call to provide the next element. OPTIONAL, if not | ||
568 | supplied, then off2element function is used instead | ||
569 | |||
570 | @Input show_handler : the function to call to show element | ||
571 | |||
572 | @Input off2element_handler : the function to call when it is needed to translate offest to element | ||
573 | |||
574 | @Input startstop_handler : the function to call when output memory page starts or stops. OPTIONAL. | ||
575 | |||
576 | @Input whandler : the function to interpret writes from the user | ||
577 | |||
578 | @Return Ptr to proc entry , 0 for failure | ||
579 | |||
580 | *****************************************************************************/ | ||
581 | struct pvr_proc_dir_entry* CreatePerProcessProcEntrySeq (const IMG_CHAR * name, | ||
582 | IMG_VOID* data, | ||
583 | pvr_next_proc_seq_t next_handler, | ||
584 | pvr_show_proc_seq_t show_handler, | ||
585 | pvr_off2element_proc_seq_t off2element_handler, | ||
586 | pvr_startstop_proc_seq_t startstop_handler, | ||
587 | pvr_proc_write_t whandler) | ||
588 | { | ||
589 | PVRSRV_ENV_PER_PROCESS_DATA *psPerProc; | ||
590 | IMG_UINT32 ui32PID; | ||
591 | |||
592 | if (!dir) | ||
593 | { | ||
594 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntrySeq: /proc/%s doesn't exist", PVRProcDirRoot)); | ||
595 | return NULL; | ||
596 | } | ||
597 | |||
598 | ui32PID = OSGetCurrentProcessIDKM(); | ||
599 | |||
600 | psPerProc = PVRSRVPerProcessPrivateData(ui32PID); | ||
601 | if (!psPerProc) | ||
602 | { | ||
603 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntrySeq: no per process data")); | ||
604 | return NULL; | ||
605 | } | ||
606 | |||
607 | if (!psPerProc->psProcDir) | ||
608 | { | ||
609 | IMG_CHAR dirname[16]; | ||
610 | IMG_INT ret; | ||
611 | |||
612 | ret = snprintf(dirname, sizeof(dirname), "%u", ui32PID); | ||
613 | |||
614 | if (ret <=0 || ret >= (IMG_INT)sizeof(dirname)) | ||
615 | { | ||
616 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntries: couldn't generate per process proc directory name \"%u\"", ui32PID)); | ||
617 | return NULL; | ||
618 | } | ||
619 | else | ||
620 | { | ||
621 | psPerProc->psProcDir = proc_mkdir(dirname, dir); | ||
622 | if (!psPerProc->psProcDir) | ||
623 | { | ||
624 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntries: couldn't create per process proc directory /proc/%s/%u", | ||
625 | PVRProcDirRoot, ui32PID)); | ||
626 | return NULL; | ||
627 | } | ||
628 | } | ||
629 | } | ||
630 | |||
631 | return CreateProcEntryInDirSeq(psPerProc->psProcDir, name, data, next_handler, | ||
632 | show_handler,off2element_handler,startstop_handler,whandler); | ||
633 | } | ||
634 | |||
635 | |||
636 | /*! | ||
637 | ****************************************************************************** | ||
638 | |||
639 | @Function : CreateProcEntries | ||
640 | |||
641 | @Description | ||
642 | |||
643 | Create a directory /proc/pvr and the necessary entries within it. These | ||
644 | dynamic files can be used at runtime to get information about the device. | ||
645 | Creation might fail if proc support is not compiled into the kernel or if | ||
646 | there is no memory | ||
647 | |||
648 | @Input none | ||
649 | |||
650 | @Return nothing | ||
651 | |||
652 | *****************************************************************************/ | ||
653 | IMG_INT CreateProcEntries(IMG_VOID) | ||
654 | { | ||
655 | dir = proc_mkdir (PVRProcDirRoot, NULL); | ||
656 | |||
657 | if (!dir) | ||
658 | { | ||
659 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntries: cannot make /proc/%s directory", PVRProcDirRoot)); | ||
660 | |||
661 | return -ENOMEM; | ||
662 | } | ||
663 | |||
664 | #if defined(SUPPORT_PVRSRV_DEVICE_CLASS) | ||
665 | g_pProcQueue = CreateProcReadEntrySeq("queue", NULL, NULL, ProcSeqShowQueue, ProcSeqOff2ElementQueue, NULL); | ||
666 | #endif | ||
667 | g_pProcVersion = CreateProcReadEntrySeq("version", NULL, NULL, ProcSeqShowVersion, ProcSeq1ElementHeaderOff2Element, NULL); | ||
668 | g_pProcSysNodes = CreateProcReadEntrySeq("nodes", NULL, NULL, ProcSeqShowSysNodes, ProcSeqOff2ElementSysNodes, NULL); | ||
669 | |||
670 | if(!g_pProcVersion || !g_pProcSysNodes | ||
671 | #if defined(SUPPORT_PVRSRV_DEVICE_CLASS) | ||
672 | || !g_pProcQueue | ||
673 | #endif | ||
674 | ) | ||
675 | { | ||
676 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntries: couldn't make /proc/%s files", PVRProcDirRoot)); | ||
677 | |||
678 | return -ENOMEM; | ||
679 | } | ||
680 | |||
681 | |||
682 | #ifdef DEBUG | ||
683 | |||
684 | g_pProcDebugLevel = CreateProcEntrySeq("debug_level", NULL, NULL, | ||
685 | ProcSeqShowDebugLevel, | ||
686 | ProcSeq1ElementOff2Element, NULL, | ||
687 | (IMG_VOID*)PVRDebugProcSetLevel); | ||
688 | if(!g_pProcDebugLevel) | ||
689 | { | ||
690 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntries: couldn't make /proc/%s/debug_level", PVRProcDirRoot)); | ||
691 | |||
692 | return -ENOMEM; | ||
693 | } | ||
694 | |||
695 | #ifdef PVR_MANUAL_POWER_CONTROL | ||
696 | g_pProcPowerLevel = CreateProcEntrySeq("power_control", NULL, NULL, | ||
697 | ProcSeqShowPowerLevel, | ||
698 | ProcSeq1ElementOff2Element, NULL, | ||
699 | PVRProcSetPowerLevel); | ||
700 | if(!g_pProcPowerLevel) | ||
701 | { | ||
702 | PVR_DPF((PVR_DBG_ERROR, "CreateProcEntries: couldn't make /proc/%s/power_control", PVRProcDirRoot)); | ||
703 | |||
704 | return -ENOMEM; | ||
705 | } | ||
706 | #endif | ||
707 | #endif | ||
708 | |||
709 | return 0; | ||
710 | } | ||
711 | |||
712 | |||
713 | /*! | ||
714 | ****************************************************************************** | ||
715 | |||
716 | @Function : RemoveProcEntrySeq | ||
717 | |||
718 | @Description | ||
719 | |||
720 | Remove a single node (created using *Seq function) under /proc/pvr. | ||
721 | |||
722 | @Input proc_entry : structure returned by Create function. | ||
723 | |||
724 | @Return nothing | ||
725 | |||
726 | *****************************************************************************/ | ||
727 | IMG_VOID RemoveProcEntrySeq(struct pvr_proc_dir_entry* ppde) | ||
728 | { | ||
729 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) | ||
730 | remove_proc_entry(ppde->pde->name, dir); | ||
731 | #else | ||
732 | proc_remove(ppde->pde); | ||
733 | #endif | ||
734 | kfree(ppde); | ||
735 | } | ||
736 | |||
737 | |||
738 | /*! | ||
739 | ****************************************************************************** | ||
740 | |||
741 | @Function : RemovePerProcessProcEntrySeq | ||
742 | |||
743 | @Description | ||
744 | |||
745 | Remove a single node under the per process proc directory (created by *Seq function). | ||
746 | |||
747 | Remove a single node (created using *Seq function) under /proc/pvr. | ||
748 | |||
749 | @Input proc_entry : structure returned by Create function. | ||
750 | |||
751 | @Return nothing | ||
752 | |||
753 | *****************************************************************************/ | ||
754 | IMG_VOID RemovePerProcessProcEntrySeq(struct pvr_proc_dir_entry* ppde) | ||
755 | { | ||
756 | PVRSRV_ENV_PER_PROCESS_DATA *psPerProc; | ||
757 | |||
758 | psPerProc = LinuxTerminatingProcessPrivateData(); | ||
759 | if (!psPerProc) | ||
760 | { | ||
761 | psPerProc = PVRSRVFindPerProcessPrivateData(); | ||
762 | if (!psPerProc) | ||
763 | { | ||
764 | PVR_DPF((PVR_DBG_ERROR, "CreatePerProcessProcEntries: can't remove proc entry, no per process data")); | ||
765 | return; | ||
766 | } | ||
767 | } | ||
768 | |||
769 | if (psPerProc->psProcDir) | ||
770 | { | ||
771 | PVR_DPF((PVR_DBG_MESSAGE, "Removing per-process proc entry")); | ||
772 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) | ||
773 | remove_proc_entry(ppde->pde->name, psPerProc->psProcDir); | ||
774 | #else | ||
775 | proc_remove(ppde->pde); | ||
776 | #endif | ||
777 | kfree(ppde); | ||
778 | } | ||
779 | } | ||
780 | |||
781 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) | ||
782 | /*! | ||
783 | ****************************************************************************** | ||
784 | |||
785 | @Function : RemoveProcEntry | ||
786 | |||
787 | @Description | ||
788 | |||
789 | Remove a single node under /proc/pvr. | ||
790 | |||
791 | @Input name : the name of the node to remove | ||
792 | |||
793 | @Return nothing | ||
794 | |||
795 | *****************************************************************************/ | ||
796 | static IMG_VOID RemoveProcEntry(const IMG_CHAR * name) | ||
797 | { | ||
798 | if (dir) | ||
799 | { | ||
800 | remove_proc_entry(name, dir); | ||
801 | PVR_DPF((PVR_DBG_MESSAGE, "Removing /proc/%s/%s", PVRProcDirRoot, name)); | ||
802 | } | ||
803 | } | ||
804 | |||
805 | |||
806 | /*! | ||
807 | ****************************************************************************** | ||
808 | |||
809 | @Function : RemovePerProcessProcDir | ||
810 | |||
811 | @Description | ||
812 | |||
813 | Remove the per process directorty under /proc/pvr. | ||
814 | |||
815 | @Input psPerProc : environment specific per process data | ||
816 | |||
817 | @Return nothing | ||
818 | |||
819 | *****************************************************************************/ | ||
820 | IMG_VOID RemovePerProcessProcDir(PVRSRV_ENV_PER_PROCESS_DATA *psPerProc) | ||
821 | { | ||
822 | if (psPerProc->psProcDir) | ||
823 | { | ||
824 | while (psPerProc->psProcDir->subdir) | ||
825 | { | ||
826 | PVR_DPF((PVR_DBG_WARNING, "Belatedly removing /proc/%s/%s/%s", PVRProcDirRoot, psPerProc->psProcDir->name, psPerProc->psProcDir->subdir->name)); | ||
827 | |||
828 | RemoveProcEntry(psPerProc->psProcDir->subdir->name); | ||
829 | } | ||
830 | RemoveProcEntry(psPerProc->psProcDir->name); | ||
831 | } | ||
832 | } | ||
833 | #else | ||
834 | IMG_VOID RemovePerProcessProcDir(PVRSRV_ENV_PER_PROCESS_DATA *psPerProc) | ||
835 | { | ||
836 | proc_remove(psPerProc->psProcDir); | ||
837 | } | ||
838 | #endif | ||
839 | /*! | ||
840 | ****************************************************************************** | ||
841 | |||
842 | @Function : RemoveProcEntries | ||
843 | |||
844 | Description | ||
845 | |||
846 | Proc filesystem entry deletion - Remove all proc filesystem entries for | ||
847 | the driver. | ||
848 | |||
849 | @Input none | ||
850 | |||
851 | @Return nothing | ||
852 | |||
853 | *****************************************************************************/ | ||
854 | IMG_VOID RemoveProcEntries(IMG_VOID) | ||
855 | { | ||
856 | #ifdef DEBUG | ||
857 | RemoveProcEntrySeq( g_pProcDebugLevel ); | ||
858 | #ifdef PVR_MANUAL_POWER_CONTROL | ||
859 | RemoveProcEntrySeq( g_pProcPowerLevel ); | ||
860 | #endif /* PVR_MANUAL_POWER_CONTROL */ | ||
861 | #endif | ||
862 | |||
863 | #if defined(SUPPORT_PVRSRV_DEVICE_CLASS) | ||
864 | RemoveProcEntrySeq(g_pProcQueue); | ||
865 | #endif | ||
866 | RemoveProcEntrySeq(g_pProcVersion); | ||
867 | RemoveProcEntrySeq(g_pProcSysNodes); | ||
868 | |||
869 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) | ||
870 | while (dir->subdir) | ||
871 | { | ||
872 | PVR_DPF((PVR_DBG_WARNING, "Belatedly removing /proc/%s/%s", PVRProcDirRoot, dir->subdir->name)); | ||
873 | |||
874 | RemoveProcEntry(dir->subdir->name); | ||
875 | } | ||
876 | remove_proc_entry(PVRProcDirRoot, NULL); | ||
877 | #else | ||
878 | proc_remove(dir); | ||
879 | #endif | ||
880 | |||
881 | } | ||
882 | |||
883 | /*************************************************************************/ /*! | ||
884 | @Function PVRProcGetData | ||
885 | @Description Extract data from PVR proc object. | ||
886 | @Input pointer to pvr_proc_dir_entr object | ||
887 | @Return pointer to data object passed in to Proc create function. | ||
888 | */ /**************************************************************************/ | ||
889 | void *PVRProcGetData(struct pvr_proc_dir_entry *ppde) | ||
890 | { | ||
891 | return ppde->data; | ||
892 | } | ||
893 | |||
894 | /***************************************************************************** | ||
895 | FUNCTION : ProcSeqShowVersion | ||
896 | |||
897 | PURPOSE : Print the content of version to /proc file | ||
898 | |||
899 | PARAMETERS : sfile - /proc seq_file | ||
900 | el - Element to print | ||
901 | *****************************************************************************/ | ||
902 | static void ProcSeqShowVersion(struct seq_file *sfile, void* el) | ||
903 | { | ||
904 | SYS_DATA *psSysData; | ||
905 | IMG_CHAR *pszSystemVersionString = "None"; | ||
906 | |||
907 | if(el == PVR_PROC_SEQ_START_TOKEN) | ||
908 | { | ||
909 | seq_printf(sfile, | ||
910 | "Version %s (%s) %s\n", | ||
911 | PVRVERSION_STRING, | ||
912 | PVR_BUILD_TYPE, PVR_BUILD_DIR); | ||
913 | return; | ||
914 | } | ||
915 | |||
916 | psSysData = SysAcquireDataNoCheck(); | ||
917 | #if defined(SUPPORT_TI_VERSION_STRING) | ||
918 | if(psSysData != IMG_NULL && psSysData->szTIVersion != IMG_NULL) | ||
919 | { | ||
920 | seq_printf( sfile, "UM Services Version: %s\n", | ||
921 | psSysData->szTIVersion); | ||
922 | } | ||
923 | #endif | ||
924 | if(psSysData != IMG_NULL && psSysData->pszVersionString != IMG_NULL) | ||
925 | { | ||
926 | pszSystemVersionString = psSysData->pszVersionString; | ||
927 | } | ||
928 | |||
929 | seq_printf( sfile, "System Version String: %s\n", pszSystemVersionString); | ||
930 | } | ||
931 | |||
932 | static const IMG_CHAR *deviceTypeToString(PVRSRV_DEVICE_TYPE deviceType) | ||
933 | { | ||
934 | switch (deviceType) | ||
935 | { | ||
936 | default: | ||
937 | { | ||
938 | static IMG_CHAR text[10]; | ||
939 | |||
940 | sprintf(text, "?%x", (IMG_UINT)deviceType); | ||
941 | |||
942 | return text; | ||
943 | } | ||
944 | } | ||
945 | } | ||
946 | |||
947 | |||
948 | static const IMG_CHAR *deviceClassToString(PVRSRV_DEVICE_CLASS deviceClass) | ||
949 | { | ||
950 | switch (deviceClass) | ||
951 | { | ||
952 | case PVRSRV_DEVICE_CLASS_3D: | ||
953 | { | ||
954 | return "3D"; | ||
955 | } | ||
956 | case PVRSRV_DEVICE_CLASS_DISPLAY: | ||
957 | { | ||
958 | return "display"; | ||
959 | } | ||
960 | case PVRSRV_DEVICE_CLASS_BUFFER: | ||
961 | { | ||
962 | return "buffer"; | ||
963 | } | ||
964 | default: | ||
965 | { | ||
966 | static IMG_CHAR text[10]; | ||
967 | |||
968 | sprintf(text, "?%x", (IMG_UINT)deviceClass); | ||
969 | return text; | ||
970 | } | ||
971 | } | ||
972 | } | ||
973 | |||
974 | static IMG_VOID* DecOffPsDev_AnyVaCb(PVRSRV_DEVICE_NODE *psNode, va_list va) | ||
975 | { | ||
976 | off_t *pOff = va_arg(va, off_t*); | ||
977 | if (--(*pOff)) | ||
978 | { | ||
979 | return IMG_NULL; | ||
980 | } | ||
981 | else | ||
982 | { | ||
983 | return psNode; | ||
984 | } | ||
985 | } | ||
986 | |||
987 | /***************************************************************************** | ||
988 | FUNCTION : ProcSeqShowSysNodes | ||
989 | |||
990 | PURPOSE : Print the content of version to /proc file | ||
991 | |||
992 | PARAMETERS : sfile - /proc seq_file | ||
993 | el - Element to print | ||
994 | *****************************************************************************/ | ||
995 | static void ProcSeqShowSysNodes(struct seq_file *sfile,void* el) | ||
996 | { | ||
997 | PVRSRV_DEVICE_NODE *psDevNode; | ||
998 | |||
999 | if(el == PVR_PROC_SEQ_START_TOKEN) | ||
1000 | { | ||
1001 | seq_printf( sfile, | ||
1002 | "Registered nodes\n" | ||
1003 | "Addr Type Class Index Ref pvDev Size Res\n"); | ||
1004 | return; | ||
1005 | } | ||
1006 | |||
1007 | psDevNode = (PVRSRV_DEVICE_NODE*)el; | ||
1008 | |||
1009 | seq_printf( sfile, | ||
1010 | "%p %-8s %-8s %4d %2u %p %3u %p\n", | ||
1011 | psDevNode, | ||
1012 | deviceTypeToString(psDevNode->sDevId.eDeviceType), | ||
1013 | deviceClassToString(psDevNode->sDevId.eDeviceClass), | ||
1014 | psDevNode->sDevId.eDeviceClass, | ||
1015 | psDevNode->ui32RefCount, | ||
1016 | psDevNode->pvDevice, | ||
1017 | psDevNode->ui32pvDeviceSize, | ||
1018 | psDevNode->hResManContext); | ||
1019 | } | ||
1020 | |||
1021 | /***************************************************************************** | ||
1022 | FUNCTION : ProcSeqOff2ElementSysNodes | ||
1023 | |||
1024 | PURPOSE : Transale offset to element (/proc stuff) | ||
1025 | |||
1026 | PARAMETERS : sfile - /proc seq_file | ||
1027 | off - the offset into the buffer | ||
1028 | |||
1029 | RETURNS : element to print | ||
1030 | *****************************************************************************/ | ||
1031 | static void* ProcSeqOff2ElementSysNodes(struct seq_file * sfile, loff_t off) | ||
1032 | { | ||
1033 | SYS_DATA *psSysData; | ||
1034 | PVRSRV_DEVICE_NODE*psDevNode = IMG_NULL; | ||
1035 | |||
1036 | PVR_UNREFERENCED_PARAMETER(sfile); | ||
1037 | |||
1038 | if(!off) | ||
1039 | { | ||
1040 | return PVR_PROC_SEQ_START_TOKEN; | ||
1041 | } | ||
1042 | |||
1043 | psSysData = SysAcquireDataNoCheck(); | ||
1044 | if (psSysData != IMG_NULL) | ||
1045 | { | ||
1046 | /* Find Dev Node */ | ||
1047 | psDevNode = (PVRSRV_DEVICE_NODE*) | ||
1048 | List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, | ||
1049 | DecOffPsDev_AnyVaCb, | ||
1050 | &off); | ||
1051 | } | ||
1052 | |||
1053 | /* Return anything that is not PVR_RPOC_SEQ_START_TOKEN and NULL */ | ||
1054 | return (void*)psDevNode; | ||
1055 | } | ||
1056 | |||
1057 | /***************************************************************************** | ||
1058 | End of file (proc.c) | ||
1059 | *****************************************************************************/ | ||