blob: 9f0016f9a151b5cf7fd25006c470e08abb77391a [file] [log] [blame]
/**********************************************************************
*
* Copyright (C) Imagination Technologies Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful but, except
* as otherwise stated in writing, without any warranty; without even the
* implied warranty of merchantability or fitness for a particular purpose.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* Imagination Technologies Ltd. <gpl-support@imgtec.com>
* Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
*
******************************************************************************/
#include <linux/version.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))
#ifndef AUTOCONF_INCLUDED
#include <linux/config.h>
#endif
#endif
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/hardirq.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <stdarg.h>
#include "img_types.h"
#include "servicesext.h"
#include "pvr_debug.h"
#include "srvkm.h"
#include "proc.h"
#include "mutex.h"
#include "linkage.h"
#include "pvr_uaccess.h"
#if !defined(CONFIG_PREEMPT)
#define PVR_DEBUG_ALWAYS_USE_SPINLOCK
#endif
static IMG_BOOL VBAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz,
const IMG_CHAR* pszFormat, va_list VArgs)
IMG_FORMAT_PRINTF(3, 0);
#if defined(PVRSRV_NEED_PVR_DPF)
#define PVR_MAX_FILEPATH_LEN 256
static IMG_BOOL BAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz,
const IMG_CHAR *pszFormat, ...)
IMG_FORMAT_PRINTF(3, 4);
IMG_UINT32 gPVRDebugLevel =
(DBGPRIV_FATAL | DBGPRIV_ERROR | DBGPRIV_WARNING);
#endif
#define PVR_MAX_MSG_LEN PVR_MAX_DEBUG_MESSAGE_LEN
#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
static IMG_CHAR gszBufferNonIRQ[PVR_MAX_MSG_LEN + 1];
#endif
static IMG_CHAR gszBufferIRQ[PVR_MAX_MSG_LEN + 1];
#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
static PVRSRV_LINUX_MUTEX gsDebugMutexNonIRQ;
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39))
static spinlock_t gsDebugLockIRQ = SPIN_LOCK_UNLOCKED;
#else
static DEFINE_SPINLOCK(gsDebugLockIRQ);
#endif
#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
#if !defined (USE_SPIN_LOCK)
#define USE_SPIN_LOCK (in_interrupt() || !preemptible())
#endif
#endif
static inline void GetBufferLock(unsigned long *pulLockFlags)
{
#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
if (USE_SPIN_LOCK)
#endif
{
spin_lock_irqsave(&gsDebugLockIRQ, *pulLockFlags);
}
#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
else
{
LinuxLockMutex(&gsDebugMutexNonIRQ);
}
#endif
}
static inline void ReleaseBufferLock(unsigned long ulLockFlags)
{
#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
if (USE_SPIN_LOCK)
#endif
{
spin_unlock_irqrestore(&gsDebugLockIRQ, ulLockFlags);
}
#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
else
{
LinuxUnLockMutex(&gsDebugMutexNonIRQ);
}
#endif
}
static inline void SelectBuffer(IMG_CHAR **ppszBuf, IMG_UINT32 *pui32BufSiz)
{
#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
if (USE_SPIN_LOCK)
#endif
{
*ppszBuf = gszBufferIRQ;
*pui32BufSiz = sizeof(gszBufferIRQ);
}
#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
else
{
*ppszBuf = gszBufferNonIRQ;
*pui32BufSiz = sizeof(gszBufferNonIRQ);
}
#endif
}
static IMG_BOOL VBAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR* pszFormat, va_list VArgs)
{
IMG_UINT32 ui32Used;
IMG_UINT32 ui32Space;
IMG_INT32 i32Len;
ui32Used = strlen(pszBuf);
BUG_ON(ui32Used >= ui32BufSiz);
ui32Space = ui32BufSiz - ui32Used;
i32Len = vsnprintf(&pszBuf[ui32Used], ui32Space, pszFormat, VArgs);
pszBuf[ui32BufSiz - 1] = 0;
return (i32Len < 0 || i32Len >= (IMG_INT32)ui32Space) ? IMG_TRUE : IMG_FALSE;
}
IMG_VOID PVRDPFInit(IMG_VOID)
{
#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
LinuxInitMutex(&gsDebugMutexNonIRQ);
#endif
}
IMG_VOID PVRSRVReleasePrintf(const IMG_CHAR *pszFormat, ...)
{
va_list vaArgs;
unsigned long ulLockFlags = 0;
IMG_CHAR *pszBuf;
IMG_UINT32 ui32BufSiz;
SelectBuffer(&pszBuf, &ui32BufSiz);
va_start(vaArgs, pszFormat);
GetBufferLock(&ulLockFlags);
strncpy (pszBuf, "PVR_K: ", (ui32BufSiz -1));
if (VBAppend(pszBuf, ui32BufSiz, pszFormat, vaArgs))
{
printk(KERN_INFO "PVR_K:(Message Truncated): %s\n", pszBuf);
}
else
{
printk(KERN_INFO "%s\n", pszBuf);
}
ReleaseBufferLock(ulLockFlags);
va_end(vaArgs);
}
#if defined(PVRSRV_NEED_PVR_ASSERT)
IMG_VOID PVRSRVDebugAssertFail(const IMG_CHAR* pszFile, IMG_UINT32 uLine)
{
PVRSRVDebugPrintf(DBGPRIV_FATAL, pszFile, uLine, "Debug assertion failed!");
BUG();
}
#endif
#if defined(PVRSRV_NEED_PVR_TRACE)
IMG_VOID PVRSRVTrace(const IMG_CHAR* pszFormat, ...)
{
va_list VArgs;
unsigned long ulLockFlags = 0;
IMG_CHAR *pszBuf;
IMG_UINT32 ui32BufSiz;
SelectBuffer(&pszBuf, &ui32BufSiz);
va_start(VArgs, pszFormat);
GetBufferLock(&ulLockFlags);
strncpy(pszBuf, "PVR: ", (ui32BufSiz -1));
if (VBAppend(pszBuf, ui32BufSiz, pszFormat, VArgs))
{
printk(KERN_INFO "PVR_K:(Message Truncated): %s\n", pszBuf);
}
else
{
printk(KERN_INFO "%s\n", pszBuf);
}
ReleaseBufferLock(ulLockFlags);
va_end(VArgs);
}
#endif
#if defined(PVRSRV_NEED_PVR_DPF)
static IMG_BOOL BAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR *pszFormat, ...)
{
va_list VArgs;
IMG_BOOL bTrunc;
va_start (VArgs, pszFormat);
bTrunc = VBAppend(pszBuf, ui32BufSiz, pszFormat, VArgs);
va_end (VArgs);
return bTrunc;
}
IMG_VOID PVRSRVDebugPrintf (
IMG_UINT32 ui32DebugLevel,
const IMG_CHAR* pszFullFileName,
IMG_UINT32 ui32Line,
const IMG_CHAR* pszFormat,
...
)
{
IMG_BOOL bTrace;
const IMG_CHAR *pszFileName = pszFullFileName;
IMG_CHAR *pszLeafName;
bTrace = (IMG_BOOL)(ui32DebugLevel & DBGPRIV_CALLTRACE) ? IMG_TRUE : IMG_FALSE;
if (gPVRDebugLevel & ui32DebugLevel)
{
va_list vaArgs;
unsigned long ulLockFlags = 0;
IMG_CHAR *pszBuf;
IMG_UINT32 ui32BufSiz;
SelectBuffer(&pszBuf, &ui32BufSiz);
va_start(vaArgs, pszFormat);
GetBufferLock(&ulLockFlags);
if (bTrace == IMG_FALSE)
{
switch(ui32DebugLevel)
{
case DBGPRIV_FATAL:
{
strncpy (pszBuf, "PVR_K:(Fatal): ", (ui32BufSiz -1));
break;
}
case DBGPRIV_ERROR:
{
strncpy (pszBuf, "PVR_K:(Error): ", (ui32BufSiz -1));
break;
}
case DBGPRIV_WARNING:
{
strncpy (pszBuf, "PVR_K:(Warning): ", (ui32BufSiz -1));
break;
}
case DBGPRIV_MESSAGE:
{
strncpy (pszBuf, "PVR_K:(Message): ", (ui32BufSiz -1));
break;
}
case DBGPRIV_VERBOSE:
{
strncpy (pszBuf, "PVR_K:(Verbose): ", (ui32BufSiz -1));
break;
}
default:
{
strncpy (pszBuf, "PVR_K:(Unknown message level)", (ui32BufSiz -1));
break;
}
}
}
else
{
strncpy (pszBuf, "PVR_K: ", (ui32BufSiz -1));
}
if (VBAppend(pszBuf, ui32BufSiz, pszFormat, vaArgs))
{
printk(KERN_INFO "PVR_K:(Message Truncated): %s\n", pszBuf);
}
else
{
if (bTrace == IMG_FALSE)
{
#ifdef DEBUG_LOG_PATH_TRUNCATE
static IMG_CHAR szFileNameRewrite[PVR_MAX_FILEPATH_LEN];
IMG_CHAR* pszTruncIter;
IMG_CHAR* pszTruncBackInter;
if (strlen(pszFullFileName) > strlen(DEBUG_LOG_PATH_TRUNCATE)+1)
pszFileName = pszFullFileName + strlen(DEBUG_LOG_PATH_TRUNCATE)+1;
strncpy(szFileNameRewrite, pszFileName,PVR_MAX_FILEPATH_LEN);
if(strlen(szFileNameRewrite) == PVR_MAX_FILEPATH_LEN-1) {
IMG_CHAR szTruncateMassage[] = "FILENAME TRUNCATED";
strcpy(szFileNameRewrite + (PVR_MAX_FILEPATH_LEN - 1 - strlen(szTruncateMassage)), szTruncateMassage);
}
pszTruncIter = szFileNameRewrite;
while(*pszTruncIter++ != 0)
{
IMG_CHAR* pszNextStartPoint;
if(
!( ( *pszTruncIter == '/' && (pszTruncIter-4 >= szFileNameRewrite) ) &&
( *(pszTruncIter-1) == '.') &&
( *(pszTruncIter-2) == '.') &&
( *(pszTruncIter-3) == '/') )
) continue;
pszTruncBackInter = pszTruncIter - 3;
while(*(--pszTruncBackInter) != '/')
{
if(pszTruncBackInter <= szFileNameRewrite) break;
}
pszNextStartPoint = pszTruncBackInter;
while(*pszTruncIter != 0)
{
*pszTruncBackInter++ = *pszTruncIter++;
}
*pszTruncBackInter = 0;
pszTruncIter = pszNextStartPoint;
}
pszFileName = szFileNameRewrite;
if(*pszFileName == '/') pszFileName++;
#endif
#if !defined(__sh__)
pszLeafName = (IMG_CHAR *)strrchr (pszFileName, '\\');
if (pszLeafName)
{
pszFileName = pszLeafName;
}
#endif
if (BAppend(pszBuf, ui32BufSiz, " [%u, %s]", ui32Line, pszFileName))
{
printk(KERN_INFO "PVR_K:(Message Truncated): %s\n", pszBuf);
}
else
{
printk(KERN_INFO "%s\n", pszBuf);
}
}
else
{
printk(KERN_INFO "%s\n", pszBuf);
}
}
ReleaseBufferLock(ulLockFlags);
va_end (vaArgs);
}
}
#endif
#if defined(DEBUG)
IMG_INT PVRDebugProcSetLevel(struct file *file, const IMG_CHAR *buffer, IMG_UINT32 count, IMG_VOID *data)
{
#define _PROC_SET_BUFFER_SZ 2
IMG_CHAR data_buffer[_PROC_SET_BUFFER_SZ];
if (count != _PROC_SET_BUFFER_SZ)
{
return -EINVAL;
}
else
{
if (pvr_copy_from_user(data_buffer, buffer, count))
return -EINVAL;
if (data_buffer[count - 1] != '\n')
return -EINVAL;
gPVRDebugLevel = data_buffer[0] - '0';
}
return (count);
}
void ProcSeqShowDebugLevel(struct seq_file *sfile,void* el)
{
seq_printf(sfile, "%u\n", gPVRDebugLevel);
}
#endif