1 /**********************************************************************
3 * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
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.
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.
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.
18 * The full GNU General Public License is included in this distribution in
19 * the file called "COPYING".
21 * Contact Information:
22 * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23 * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
25 ******************************************************************************/
27 #include <linux/init.h>
28 #include <linux/module.h>
29 #include <linux/version.h>
31 #include <linux/proc_fs.h>
33 #include "services_headers.h"
38 #include "pvr_debug.h"
39 #include "pvrversion.h"
42 #include "env_perproc.h"
44 /* The proc entry for our /proc/pvr directory */
46 static struct proc_dir_entry *dir;
48 static off_t procDumpSysNodes(char *buf, size_t size, off_t off);
49 static off_t procDumpVersion(char *buf, size_t size, off_t off);
51 static const char PVRProcDirRoot[] = "pvr";
53 off_t printAppend(char *buffer, size_t size, off_t off, const char *format, ...)
56 int space = size - off;
59 PVR_ASSERT(space >= 0);
62 n = vsnprintf(buffer + off, space, format, ap);
65 if (n >= space || n < 0) {
74 static int pvr_read_proc(char *page, char **start, off_t off,
75 int count, int *eof, void *data)
77 off_t (*pprn)(char *, size_t, off_t) = data;
79 off_t len = pprn(page, count, off);
81 if (len == END_OF_FILE) {
93 static int CreateProcEntryInDir(struct proc_dir_entry *pdir, const char *name,
94 read_proc_t rhandler, write_proc_t whandler,
97 struct proc_dir_entry *file;
101 PVR_DPF(PVR_DBG_ERROR,
102 "CreateProcEntryInDir: parent directory doesn't exist");
115 file = create_proc_entry(name, mode, pdir);
118 file->read_proc = rhandler;
119 file->write_proc = whandler;
122 PVR_DPF(PVR_DBG_MESSAGE, "Created proc entry %s in %s", name,
128 PVR_DPF(PVR_DBG_ERROR,
129 "CreateProcEntry: cannot create proc entry %s in %s", name,
135 int CreateProcEntry(const char *name, read_proc_t rhandler,
136 write_proc_t whandler, void *data)
138 return CreateProcEntryInDir(dir, name, rhandler, whandler, data);
141 static struct proc_dir_entry *
142 ProcessProcDirCreate(u32 pid)
144 struct PVRSRV_ENV_PER_PROCESS_DATA *psPerProc;
148 psPerProc = PVRSRVPerProcessPrivateData(pid);
150 pr_err("%s: no per process data for %d\n", __func__, pid);
154 if (psPerProc->psProcDir)
155 return psPerProc->psProcDir;
157 ret = snprintf(dirname, sizeof(dirname), "%u", pid);
158 if (ret <= 0 || ret >= sizeof(dirname)) {
159 pr_err("%s: couldn't generate per process proc dir for %d\n",
164 psPerProc->psProcDir = proc_mkdir(dirname, dir);
165 if (!psPerProc->psProcDir)
166 pr_err("%s: couldn't create /proc/%s/%u\n",
167 __func__, PVRProcDirRoot, pid);
169 return psPerProc->psProcDir;
172 static struct proc_dir_entry *
173 ProcessProcDirGet(u32 pid)
175 struct PVRSRV_ENV_PER_PROCESS_DATA *psPerProc;
177 psPerProc = PVRSRVPerProcessPrivateData(pid);
179 pr_err("%s: no per process data for %d\n", __func__, pid);
183 if (!psPerProc->psProcDir) {
184 pr_err("%s: couldn't retrieve /proc/%s/%u\n", __func__,
185 PVRProcDirRoot, pid);
189 return psPerProc->psProcDir;
192 int CreatePerProcessProcEntry(u32 pid, const char *name, read_proc_t rhandler,
196 PVR_DPF(PVR_DBG_ERROR,
197 "CreatePerProcessProcEntries: /proc/%s doesn't exist",
204 struct proc_dir_entry *pid_dir = ProcessProcDirCreate(pid);
209 return CreateProcEntryInDir(pid_dir, name, rhandler, NULL,
212 return CreateProcEntryInDir(dir, name, rhandler, NULL, data);
215 int CreateProcReadEntry(const char *name,
216 off_t (handler)(char *, size_t, off_t))
218 struct proc_dir_entry *file;
221 PVR_DPF(PVR_DBG_ERROR, "CreateProcReadEntry: "
222 "cannot make proc entry /proc/%s/%s: no parent",
223 PVRProcDirRoot, name);
229 create_proc_read_entry(name, S_IFREG | S_IRUGO, dir, pvr_read_proc,
235 PVR_DPF(PVR_DBG_ERROR, "CreateProcReadEntry: "
236 "cannot make proc entry /proc/%s/%s: no memory",
237 PVRProcDirRoot, name);
242 int CreateProcEntries(void)
244 dir = proc_mkdir(PVRProcDirRoot, NULL);
247 PVR_DPF(PVR_DBG_ERROR,
248 "CreateProcEntries: cannot make /proc/%s directory",
254 if (CreateProcReadEntry("queue", QueuePrintQueues) ||
255 CreateProcReadEntry("version", procDumpVersion) ||
256 CreateProcReadEntry("nodes", procDumpSysNodes)) {
257 PVR_DPF(PVR_DBG_ERROR,
258 "CreateProcEntries: couldn't make /proc/%s files",
263 #ifdef CONFIG_PVR_DEBUG_EXTRA
265 ("debug_level", PVRDebugProcGetLevel, PVRDebugProcSetLevel, NULL)) {
266 PVR_DPF(PVR_DBG_ERROR,
267 "CreateProcEntries: couldn't make /proc/%s/debug_level",
277 void RemoveProcEntry(const char *name)
280 remove_proc_entry(name, dir);
281 PVR_DPF(PVR_DBG_MESSAGE, "Removing /proc/%s/%s",
282 PVRProcDirRoot, name);
286 void RemovePerProcessProcEntry(u32 pid, const char *name)
289 struct proc_dir_entry *pid_dir = ProcessProcDirGet(pid);
294 remove_proc_entry(name, pid_dir);
296 PVR_DPF(PVR_DBG_MESSAGE, "Removing proc entry %s from %s",
297 name, pid_dir->name);
299 RemoveProcEntry(name);
302 void RemovePerProcessProcDir(struct PVRSRV_ENV_PER_PROCESS_DATA *psPerProc)
304 if (psPerProc->psProcDir) {
305 while (psPerProc->psProcDir->subdir) {
306 PVR_DPF(PVR_DBG_WARNING,
307 "Belatedly removing /proc/%s/%s/%s",
308 PVRProcDirRoot, psPerProc->psProcDir->name,
309 psPerProc->psProcDir->subdir->name);
311 RemoveProcEntry(psPerProc->psProcDir->subdir->name);
313 RemoveProcEntry(psPerProc->psProcDir->name);
317 void RemoveProcEntries(void)
319 #ifdef CONFIG_PVR_DEBUG_EXTRA
320 RemoveProcEntry("debug_level");
322 RemoveProcEntry("queue");
323 RemoveProcEntry("nodes");
324 RemoveProcEntry("version");
326 while (dir->subdir) {
327 PVR_DPF(PVR_DBG_WARNING, "Belatedly removing /proc/%s/%s",
328 PVRProcDirRoot, dir->subdir->name);
330 RemoveProcEntry(dir->subdir->name);
333 remove_proc_entry(PVRProcDirRoot, NULL);
336 static off_t procDumpVersion(char *buf, size_t size, off_t off)
338 struct SYS_DATA *psSysData;
341 return printAppend(buf, size, 0, "Version %s (%s) %s\n",
342 PVRVERSION_STRING, PVR_BUILD_TYPE,
345 if (SysAcquireData(&psSysData) != PVRSRV_OK)
346 return PVRSRV_ERROR_GENERIC;
349 char *pszSystemVersionString = "None";
351 if (psSysData->pszVersionString)
352 pszSystemVersionString = psSysData->pszVersionString;
354 if (strlen(pszSystemVersionString) +
355 strlen("System Version String: \n") + 1 > size)
357 return printAppend(buf, size, 0, "System Version String: %s\n",
358 pszSystemVersionString);
364 static const char *deviceTypeToString(enum PVRSRV_DEVICE_TYPE deviceType)
366 switch (deviceType) {
369 static char text[10];
370 sprintf(text, "?%x", deviceType);
376 static const char *deviceClassToString(enum PVRSRV_DEVICE_CLASS deviceClass)
378 switch (deviceClass) {
379 case PVRSRV_DEVICE_CLASS_3D:
383 case PVRSRV_DEVICE_CLASS_DISPLAY:
387 case PVRSRV_DEVICE_CLASS_BUFFER:
393 static char text[10];
395 sprintf(text, "?%x", deviceClass);
401 static off_t procDumpSysNodes(char *buf, size_t size, off_t off)
403 struct SYS_DATA *psSysData;
404 struct PVRSRV_DEVICE_NODE *psDevNode;
411 return printAppend(buf, size, 0,
413 "Addr Type Class Index Ref pvDev Size Res\n");
415 if (SysAcquireData(&psSysData) != PVRSRV_OK)
416 return PVRSRV_ERROR_GENERIC;
418 for (psDevNode = psSysData->psDeviceNodeList;
419 --off && psDevNode; psDevNode = psDevNode->psNext)
425 len = printAppend(buf, size, 0,
426 "%p %-8s %-8s %4d %2u %p %3u %p\n",
428 deviceTypeToString(psDevNode->sDevId.eDeviceType),
429 deviceClassToString(psDevNode->sDevId.eDeviceClass),
430 psDevNode->sDevId.eDeviceClass,
431 psDevNode->ui32RefCount,
433 psDevNode->ui32pvDeviceSize,
434 psDevNode->hResManContext);