| /********************************************************************** |
| * |
| * 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 |