Files

942 lines
28 KiB
C

/*
* <:copyright-BRCM:2010:DUAL/GPL:standard
*
* Copyright (c) 2010 Broadcom Corporation
* All Rights Reserved
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed
* to you under the terms of the GNU General Public License version 2
* (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
* with the following added to such license:
*
* As a special exception, the copyright holders of this software give
* you permission to link this software with independent modules, and
* to copy and distribute the resulting executable under terms of your
* choice, provided that you also meet, for each linked independent
* module, the terms and conditions of the license of that module.
* An independent module is a module which is not derived from this
* software. The special exception does not apply to any modifications
* of the software.
*
* Not withstanding the above, under no circumstances may you combine
* this software in any way with any other Broadcom software provided
* under a license other than the GPL, without Broadcom's express prior
* written consent.
*
:>
*/
#include <asm/uaccess.h> /*copy_from_user*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/bcm_log.h>
#define VERSION "0.1"
#define VER_STR "v" VERSION " " __DATE__ " " __TIME__
#define PROC_ENTRY_NAME "bcmlog"
#if defined(BCM_DATADUMP_SUPPORTED)
#define MAX_NUM_DATADUMP_IDS 20
#define MAX_NUM_QIDS 10
#define PRINTBUF_SIZE 0x10000
#endif
#define BCM_LOG_CHECK_LOG_ID(_logId) \
BCM_ASSERT((_logId) >= 0 && (_logId) < BCM_LOG_ID_MAX);
#define BCM_LOG_CHECK_LOG_LEVEL(_logLevel) \
BCM_ASSERT((_logLevel) >= 0 && (_logLevel) < BCM_LOG_LEVEL_MAX);
#define BCM_LOG_CHECK_DD_LEVEL(_ddLevel) \
BCM_ASSERT((_ddLevel) >= 0 && (_ddLevel) < BCM_LOG_DD_MAX);
static bcmLogLevel_t globalLogLevel = BCM_LOG_LEVEL_DEBUG;
static bcmLogModuleInfo_t modInfo[] = BCM_LOG_MODULE_INFO;
#if defined(BCM_DATADUMP_SUPPORTED)
static bcmLogDataDumpLevel_t globalDataDumpLevel = BCM_LOG_DD_IMPORTANT;
static Bcm_DataDumpPrintFunc *printFuns[MAX_NUM_DATADUMP_IDS*MAX_NUM_QIDS];
static char buf[PRINTBUF_SIZE];
static const char* qids[MAX_NUM_QIDS];
#endif
static bcmFun_t* funTable[BCM_FUN_ID_MAX];
static bcmLogSpiCallbacks_t spiFns = { .reserveSlave = NULL,
.syncTrans = NULL,
.kerSysSlaveWrite = NULL,
.kerSysSlaveRead = NULL,
.bpGet6829PortInfo = NULL};
/**
** Local Functions
**/
static char char2num(char in) {
char out;
if ((in >= '0') && (in <= '9'))
out = (in - '0');
else if ((in >= 'a') && (in <= 'f'))
out = (in - 'a') + 10;
else if ((in >= 'A') && (in <= 'F'))
out = (in - 'A') + 10;
else
out = 0;
return out;
}
static int ishex(char *str) {
return str && (str[0]=='0') && (str[1]=='x');
}
static uint32_t str2val(char *str) {
int i;
int value;
int base = ishex(str) ? 16 : 10;
if (str == NULL) return(0);
for (i=0,value=0; str[i]; i++) {
value = (value*base) + char2num(str[i]);
}
return(value);
}
#define UNIT_SIZE_BYTES 1
#define UNIT_SIZE_HALFWORDS 2
#define UNIT_SIZE_WORDS 4
static void setMem(void *start, uint32_t val, uint32_t len, uint32_t unitSize) {
int i;
uint8_t* curPtr = start;
BCM_ASSERT((unitSize == UNIT_SIZE_BYTES) ||
(unitSize == UNIT_SIZE_HALFWORDS) ||
(unitSize == UNIT_SIZE_WORDS));
BCM_ASSERT(((uint32_t)start&~(unitSize-1)) == (uint32_t)start);
for (i = 0; i < len; ++i) {
switch (unitSize) {
case UNIT_SIZE_BYTES:
{
*curPtr = (uint8_t)val;
break;
}
case UNIT_SIZE_HALFWORDS:
{
uint16_t *cur16Ptr = (uint16_t*)curPtr;
*cur16Ptr = (uint16_t)val;
break;
}
case UNIT_SIZE_WORDS:
{
uint32_t *cur32Ptr = (uint32_t*)curPtr;
*cur32Ptr = (uint32_t)val;
break;
}
default:
break;
}
curPtr += unitSize;
}
}
static void dumpHexData(void *start, uint32_t len, uint32_t unitSize, int bSpiRead)
{
int i;
unsigned long temp;
/*Force natural alignment*/
uint8_t* curPtr;
BCM_ASSERT((unitSize == UNIT_SIZE_BYTES) ||
(unitSize == UNIT_SIZE_HALFWORDS) ||
(unitSize == UNIT_SIZE_WORDS));
curPtr = (uint8_t*)((uint32_t)start&(~(unitSize-1)));
for (i = 0; i < len; ++i) {
if (i % (4/unitSize) == 0)
bcmPrint(" ");
if (i % (16/unitSize) == 0)
bcmPrint("\n0x%08X : ", (unsigned int)curPtr);
switch (unitSize) {
case UNIT_SIZE_BYTES:
{
if ( bSpiRead )
{
spiFns.kerSysSlaveRead((unsigned long)curPtr, &temp, unitSize);
bcmPrint("%02X ", (unsigned char)temp);
}
else
{
bcmPrint("%02X ", *curPtr);
}
break;
}
case UNIT_SIZE_HALFWORDS:
{
uint16_t *cur16Ptr = (uint16_t*)curPtr;
if ( bSpiRead )
{
spiFns.kerSysSlaveRead((unsigned long)curPtr, &temp, unitSize);
bcmPrint("%04X ", (unsigned short)temp);
}
else
{
bcmPrint("%04X ", *cur16Ptr);
}
break;
}
case UNIT_SIZE_WORDS:
{
uint32_t *cur32Ptr = (uint32_t*)curPtr;
if ( bSpiRead )
{
spiFns.kerSysSlaveRead((unsigned long)curPtr, &temp, unitSize);
bcmPrint("%08lX ", (unsigned long)temp);
}
else
{
bcmPrint("%08X ", *cur32Ptr);
}
break;
}
default:
break;
}
curPtr += unitSize;
}
bcmPrint("\n");
}
static bcmLogModuleInfo_t *getModInfoByName(char *name) {
int logId;
for(logId=0; logId<BCM_LOG_ID_MAX; logId++) {
if(!strcmp(modInfo[logId].name, name))
return &modInfo[logId];
}
return NULL;
}
static ssize_t log_proc_read(struct file *f,
char *buf,
size_t cnt,
loff_t *pos) {
return 0;
}
static ssize_t log_proc_write(struct file *f, const char *buf, size_t cnt, loff_t *pos) {
int i;
#define MAX_ARGS 5
#define MAX_ARG_SIZE 32
typedef char arg_t[MAX_ARG_SIZE];
arg_t arg[MAX_ARGS];
int argc;
char cmd;
bcmLogModuleInfo_t *pModInfo;
#define LOG_WR_KBUF_SIZE 128
char kbuf[LOG_WR_KBUF_SIZE];
if ((cnt > LOG_WR_KBUF_SIZE-1) || (copy_from_user(kbuf, buf, cnt) != 0))
return -EFAULT;
kbuf[cnt]=0;
argc = sscanf(kbuf, "%c %s %s %s %s %s", &cmd, arg[0], arg[1], arg[2], arg[3], arg[4]);
for (i=0; i<MAX_ARGS; ++i) {
arg[i][MAX_ARG_SIZE-1] = '\0';
}
BCM_LOG_INFO(BCM_LOG_ID_LOG, "WRITE: cmd: %c, argc: %d", cmd, argc);
for (i=0; i<argc-1; ++i) {
BCM_LOG_INFO(BCM_LOG_ID_LOG, "arg[%d]: %s ", i, arg[i]);
}
switch ( cmd ) {
BCM_LOGCODE(
case 'g':
{
bcmLogLevel_t logLevel = str2val(arg[0]);
if(argc == 2 && logLevel >= 0 && logLevel < BCM_LOG_LEVEL_MAX)
bcmLog_setGlobalLogLevel(logLevel);
else
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Invalid Parameter '%s'\n", arg[0]);
break;
} )
BCM_LOGCODE(
case 'r':
{
bcmPrint ("Global Log Level : %d\n", bcmLog_getGlobalLogLevel());
break;
} )
BCM_LOGCODE(
case 'i':
{
if (argc == 1) {
int logId;
for(logId=0; logId<BCM_LOG_ID_MAX; logId++) {
pModInfo = &modInfo[logId];
bcmPrint("Name : %s\n", pModInfo->name);
bcmPrint("Id : %d, Log Level : %d\n", pModInfo->logId, bcmLog_getLogLevel(pModInfo->logId));
}
}
else if((argc==2) && ((pModInfo=getModInfoByName(arg[0])) != NULL)) {
bcmPrint("Name : %s\n", pModInfo->name);
bcmPrint("Id : %d, Log Level : %d\n", pModInfo->logId, bcmLog_getLogLevel(pModInfo->logId));
} else {
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Invalid Parameter '%s'\n", arg[0]);
}
break;
} )
BCM_LOGCODE(
case 'l':
{
bcmLogLevel_t logLevel = str2val(arg[1]);
if(argc == 3 && ((pModInfo=getModInfoByName(arg[0])) != NULL)) {
if(logLevel >= 0 && logLevel < BCM_LOG_LEVEL_MAX) {
bcmLog_setLogLevel( pModInfo->logId, logLevel);
break;
}
}
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Invalid Parameters '%s' '%s'\n", arg[0], arg[1]);
break;
} )
BCM_DATADUMPCODE(
case 'd':
{
bcmLogDataDumpLevel_t ddLevel = str2val(arg[1]);
if(argc == 3 && ((pModInfo=getModInfoByName(arg[0])) != NULL)) {
if(ddLevel >= 0 && ddLevel < BCM_LOG_DD_MAX) {
pModInfo->ddLevel = ddLevel;
break;
}
}
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Invalid Parameters '%s' '%s'\n", arg[0], arg[1]);
break;
} )
BCM_DATADUMPCODE(
case 'e':
{
if (argc == 1) {
int logId;
for(logId=0; logId<BCM_LOG_ID_MAX; logId++) {
pModInfo = &modInfo[logId];
bcmPrint("Name : %s\n", pModInfo->name);
bcmPrint("Id : %d, DataDump Level : %d\n", pModInfo->logId, pModInfo->ddLevel);
}
}
else if((argc==2) && ((pModInfo=getModInfoByName(arg[0])) != NULL)) {
bcmPrint("Name : %s\n", pModInfo->name);
bcmPrint("Id : %d, DataDump Level : %d\n", pModInfo->logId, pModInfo->ddLevel);
} else {
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Invalid Parameter '%s'\n", arg[0]);
}
break;
} )
BCM_DATADUMPCODE(
case 'h':
{
bcmLogDataDumpLevel_t ddLevel = str2val(arg[0]);
if(argc == 2 && ddLevel >= 0 && ddLevel < BCM_LOG_DD_MAX)
globalDataDumpLevel = ddLevel;
else
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Invalid Parameter '%s'\n", arg[0]);
break;
} )
BCM_LOGCODE(
case 's':
{
bcmPrint ("Global Datadump Level : %d\n", globalDataDumpLevel);
break;
} )
case 'm':
{
uint32_t addr = 0;
uint32_t len = 1;
uint32_t unitSize = UNIT_SIZE_BYTES;
int cmdValid = 1;
if ((argc < 3) || (argc > 4)) {
cmdValid = 0;
}
else {
if (!ishex(arg[0])) {
cmdValid = 0;
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Incorrect address: %s Must be in hex., starting with 0x\n", arg[0]);
}
else {
addr = str2val(arg[0]);
}
if (argc >= 3)
len = str2val(arg[1]);
if (argc == 4) {
switch (arg[2][0]) {
case 'b':
unitSize = UNIT_SIZE_BYTES;
break;
case 'h':
unitSize = UNIT_SIZE_HALFWORDS;
break;
case 'w':
unitSize = UNIT_SIZE_WORDS;
break;
default:
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Incorrect unit size '%s', must be 'b', 'h' or 'w'\n", arg[2]);
cmdValid = 0;
}
}
}
if (cmdValid) {
dumpHexData((void *)addr, len, unitSize, 0);
} else {
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Invalid Command: %s", kbuf);
}
break;
}
case 'w':
{
uint32_t addr = 0;
uint32_t val = 0;
uint32_t len = 1;
uint32_t unitSize = UNIT_SIZE_BYTES;
int cmdValid = 1;
if ((argc < 3) || (argc > 5)) {
cmdValid = 0;
}
else {
if (!ishex(arg[0])) {
cmdValid = 0;
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Incorrect address: %s Must be in hex., starting with 0x\n", arg[0]);
}
else {
addr = str2val(arg[0]);
}
val = str2val(arg[1]);
if (argc >= 4) {
len = str2val(arg[2]);
}
if (argc == 5) {
switch (arg[3][0]) {
case 'b':
unitSize = UNIT_SIZE_BYTES;
break;
case 'h':
unitSize = UNIT_SIZE_HALFWORDS;
break;
case 'w':
unitSize = UNIT_SIZE_WORDS;
break;
default:
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Incorrect unit size '%s', must be 'b', 'h' or 'w'\n", arg[3]);
cmdValid = 0;
}
}
}
if ((addr&~(unitSize-1)) != addr) {
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Incorrect address alignment: 0x%08X\n", addr);
cmdValid = 0;
}
if (cmdValid) {
setMem((void *)addr, val, len, unitSize);
bcmPrint("Done.\n");
} else {
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Invalid Command: %s", kbuf);
}
break;
}
case 'p':
{
// Generic SPI commands
// Should be usable with any SPI device
// Leg(0)/HS(1), CS (0-3), CLK Speed, Write Data (hex), length
uint32_t busnum = 0;
uint32_t chipsel = 0;
uint32_t clkspeed = 0;
uint32_t writeint = 0;
uint32_t length = 0;
unsigned char txbuf[32];
unsigned char rxbuf[32];
int cmdValid = 1;
if (argc != 6) {
cmdValid = 0;
}
else if (spiFns.syncTrans == NULL) {
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Attempt to use spi before registered\n");
cmdValid = 0;
}
else {
if (!ishex(arg[3])) {
cmdValid = 0;
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Incorrect write data: %s Must be in hex., starting with 0x\n", arg[3]);
}
else {
// Pad the write buffer with 0s to ensure it is a complete 4 bytes word
for (i=0;i<10;++i) {
if(arg[3][i] == 0) {
arg[3][i] = 0x30;
}
}
arg[3][10] = 0;
if ((length = str2val(arg[4])) > 32) {
cmdValid = 0;
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Incorrect length: Must be <= 32\n");
}
else {
busnum = str2val(arg[0]);
chipsel = str2val(arg[1]);
clkspeed = str2val(arg[2]);
writeint = str2val(arg[3]);
memset(txbuf,0,sizeof(txbuf));
memset(rxbuf,0,sizeof(txbuf));
txbuf[0] = (writeint >> 24) & 0x000000FF;
txbuf[1] = (writeint >> 16) & 0x000000FF;
txbuf[2] = (writeint >> 8) & 0x000000FF;
txbuf[3] = (writeint >> 0) & 0x000000FF;
if (0 != spiFns.reserveSlave(busnum, chipsel, clkspeed))
{
bcmPrint ("Spi device already reserved, clkspeed parameter ignored\n");
}
spiFns.syncTrans(txbuf, rxbuf, 0, length, busnum, chipsel);
bcmPrint ("Transmitted:\n");
dumpHexData((void *)txbuf, length, UNIT_SIZE_BYTES, 0);
bcmPrint ("Received:\n");
dumpHexData((void *)rxbuf, length, UNIT_SIZE_BYTES, 0);
}
}
}
if (0 == cmdValid) {
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Invalid Command: %s", kbuf);
}
break;
}
#if defined(CONFIG_BCM96816)
// SPI command to read/write to an external BRCM chip configured as spi slave device (eg. 6829 for BHR)
case 'u':
{
unsigned long addr = 0;
unsigned long val = 0;
unsigned long rwCount = 0;
int unitSize = 0;
int loopCount;
int cmdValid = 1;
unsigned char portInfo6829;
if (spiFns.kerSysSlaveRead == NULL)
{
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "SPI slave not registered");
cmdValid = 0;
}
else if ( (0 != spiFns.bpGet6829PortInfo(&portInfo6829)) )
{
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Board parameter error");
cmdValid = 0;
}
else
{
if ( 0 == portInfo6829)
{
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "External SPI slave device not present");
cmdValid = 0;
}
}
if ((0 == cmdValid) || ((argc != 5) && (argc != 4)))
{
cmdValid = 0;
}
else
{
if (!ishex(arg[0]))
{
cmdValid = 0;
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Incorrect address: %s Must be in hex., starting with 0x\n", arg[0]);
}
else
{
char trSize;
addr = str2val(arg[0]);
trSize = arg[1][0];
rwCount = str2val(arg[2]);
if ( 5 == argc )
{
val = str2val(arg[3]);
}
switch (trSize)
{
case 'b':
unitSize = 1;
break;
case 'h':
unitSize = 2;
break;
case 'w':
unitSize = 4;
break;
default:
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Incorrect unit size '%s', must be 'b', 'h' or 'w'\n", arg[2]);
cmdValid = 0;
unitSize = 0;
break;
}
if ( 1 == cmdValid )
{
if ( 4 == argc )
{
/* read operation */
dumpHexData((void *)addr, rwCount, unitSize, 1);
}
else
{
/* write operation */
for ( loopCount = 0; loopCount < rwCount; loopCount++ )
{
spiFns.kerSysSlaveWrite(addr, val, unitSize);
addr += unitSize;
}
}
}
}
}
if (0 == cmdValid)
{
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Invalid Command: %s", kbuf);
}
break;
}
#endif
default:
{
bcmPrint("Usage:\n");
BCM_LOGCODE(
bcmPrint("g <level> : Set global log level\n");
bcmPrint("r : Get global log level\n");
bcmPrint("l <module_name> <level> : Set the log level of a module\n");
bcmPrint("i [<module_name>] : Get module information\n");
)
BCM_DATADUMPCODE(
bcmPrint("h <level> : Set global datadump level\n");
bcmPrint("s : Get global datadump level\n");
bcmPrint("d <module_name> <level> : Set data dump detail level\n");
bcmPrint("e [<module_name>] : Get data dump detail level\n");
)
bcmPrint("m <hexaddr> [<length> [<unitsize>]]: Dump a memory region\n");
bcmPrint("w <hexaddr> <val> [<length> [<unitsize>]]: Write to a memory region\n");
break;
}
}
return cnt;
}
static struct file_operations log_proc_fops = {
read: log_proc_read,
write: log_proc_write
};
/**
** Helper Functions
**/
bcmLogModuleInfo_t *bcmLog_logIsEnabled(bcmLogId_t logId, bcmLogLevel_t logLevel) {
BCM_LOG_CHECK_LOG_ID(logId);
BCM_LOG_CHECK_LOG_LEVEL(logLevel);
if(globalLogLevel >= logLevel &&
modInfo[logId].logLevel >= logLevel)
return &modInfo[logId];
return NULL;
}
#if defined(BCM_DATADUMP_SUPPORTED)
bcmLogModuleInfo_t *bcmLog_ddIsEnabled(bcmLogId_t logId, bcmLogDataDumpLevel_t ddLevel) {
BCM_LOG_CHECK_LOG_ID(logId);
BCM_LOG_CHECK_DD_LEVEL(ddLevel);
if(globalDataDumpLevel >= ddLevel &&
modInfo[logId].ddLevel >= ddLevel)
return &modInfo[logId];
return NULL;
}
#endif
EXPORT_SYMBOL(bcmLog_logIsEnabled);
/**
** Public API
**/
void bcmLog_setGlobalLogLevel(bcmLogLevel_t logLevel) {
bcmLogId_t logId;
bcmLogLevel_t oldGlobalLevel;
BCM_LOG_CHECK_LOG_LEVEL(logLevel);
oldGlobalLevel = globalLogLevel;
globalLogLevel = logLevel;
for (logId = 0; logId < BCM_LOG_ID_MAX; logId++)
{
if (modInfo[logId].lcCallback)
{
bcmLogLevel_t oldLevel;
bcmLogLevel_t newLevel;
oldLevel = min(modInfo[logId].logLevel, oldGlobalLevel);
newLevel = min(modInfo[logId].logLevel, globalLogLevel);
if (oldLevel != newLevel)
{
modInfo[logId].lcCallback(logId, newLevel, modInfo[logId].lcCallbackCtx);
}
}
}
BCM_LOG_INFO(BCM_LOG_ID_LOG, "Global log level was set to %d", globalLogLevel);
}
bcmLogLevel_t bcmLog_getGlobalLogLevel(void) {
return globalLogLevel;
}
void bcmLog_setLogLevel(bcmLogId_t logId, bcmLogLevel_t logLevel) {
bcmLogLevel_t oldLocalLevel;
BCM_LOG_CHECK_LOG_ID(logId);
BCM_LOG_CHECK_LOG_LEVEL(logLevel);
oldLocalLevel = modInfo[logId].logLevel;
modInfo[logId].logLevel = logLevel;
if (modInfo[logId].lcCallback)
{
bcmLogLevel_t newLevel;
bcmLogLevel_t oldLevel;
oldLevel = min(oldLocalLevel, globalLogLevel);
newLevel = min(modInfo[logId].logLevel, globalLogLevel);
if (oldLevel != newLevel)
{
modInfo[logId].lcCallback(logId, newLevel, modInfo[logId].lcCallbackCtx);
}
}
BCM_LOG_INFO(BCM_LOG_ID_LOG, "Log level of %s was set to %d",
modInfo[logId].name, modInfo[logId].logLevel);
}
void bcmLog_registerLevelChangeCallback(bcmLogId_t logId, bcmLogLevelChangeCallback_t callback, void *ctx) {
BCM_LOG_CHECK_LOG_ID(logId);
modInfo[logId].lcCallback = callback;
modInfo[logId].lcCallbackCtx = ctx;
}
bcmLogLevel_t bcmLog_getLogLevel(bcmLogId_t logId) {
BCM_LOG_CHECK_LOG_ID(logId);
return modInfo[logId].logLevel;
}
char *bcmLog_getModName(bcmLogId_t logId) {
BCM_LOG_CHECK_LOG_ID(logId);
return modInfo[logId].name;
}
#if defined(BCM_DATADUMP_SUPPORTED)
/*Dummy implementation*/
void bcm_dataDumpRegPrinter(uint32_t qId, uint32_t dataDumpId, Bcm_DataDumpPrintFunc *printFun) {
BCM_ASSERT(qId < MAX_NUM_QIDS);
BCM_ASSERT(dataDumpId < MAX_NUM_DATADUMP_IDS);
printFuns[qId*MAX_NUM_DATADUMP_IDS + dataDumpId] = printFun;
}
/*Dummy implementation*/
void bcm_dataDump(uint32_t qID, uint32_t dataDumpID, const char* dataDumpName, void *ptr, uint32_t numBytes) {
Bcm_DataDumpPrintFunc* printFun;
BCM_ASSERT( qID < MAX_NUM_QIDS);
BCM_ASSERT( dataDumpID < MAX_NUM_DATADUMP_IDS);
bcmPrint("---DataDump Start---\n");
if (qids[qID] == 0) {
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "DataDump qID %d not registered.\n", qID);
}
else {
printFun = printFuns[qID*MAX_NUM_DATADUMP_IDS + dataDumpID];
bcmPrint("qID: %s, DataDump ID: %s, numBytes: %d\n", qids[qID], dataDumpName, numBytes);
if (printFun) {
buf[0]=0;
(*printFun)(dataDumpID, ptr, numBytes, buf, PRINTBUF_SIZE);
bcmPrint(buf);
}
else {
uint32_t *data = ptr;
uint8_t *dataBytes;
int i=0;
while (i+16<=numBytes) {
bcmPrint("%4.4x: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n", i, data[i/4], data[i/4+1], data[i/4+2], data[i/4+3]);
i+=16;
}
if (i+4<=numBytes) {
bcmPrint("%4.4x: ", i);
while (i+4<=numBytes) {
bcmPrint("0x%8.8x ", data[i/4]);
i+=4;
}
}
if (i< numBytes) {
dataBytes = (uint8_t*)data;
bcmPrint("0x");
while (i<numBytes) {
bcmPrint("%2.2x", *dataBytes++);
++i;
}
bcmPrint("\n");
}
}
}
bcmPrint("---DataDump End---\n");
}
uint32_t bcm_dataDumpCreateQ(const char* qName) {
int i;
for (i=0; i<MAX_NUM_QIDS; ++i) {
if (qids[i] == 0) {
qids[i] = qName;
return i;
}
}
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Can not create dataDump queue. Max. #qids reached.\n");
return ~0U;
}
void bcm_dataDumpDeleteQ(uint32_t qid) {
BCM_ASSERT( qid < MAX_NUM_QIDS);
if (qids[qid] != 0) {
qids[qid] = 0;
}
else {
BCM_LOG_ERROR(BCM_LOG_ID_LOG, "Can not delete dataDump queue. qid unknown.\n");
}
}
void bcmFun_reg(bcmFunId_t funId, bcmFun_t *f) {
BCM_ASSERT(f);
BCM_ASSERT(funId < BCM_FUN_ID_MAX);
funTable[funId] = f;
}
void bcmFun_dereg(bcmFunId_t funId) {
BCM_ASSERT(funId < BCM_FUN_ID_MAX);
funTable[funId] = 0;
}
bcmFun_t* bcmFun_get(bcmFunId_t funId) {
BCM_ASSERT(funId < BCM_FUN_ID_MAX);
return funTable[funId];
}
void __init bcmLog_init( void ) {
struct proc_dir_entry *p;
p = create_proc_entry(PROC_ENTRY_NAME, 0, 0);
if (!p) {
bcmPrint("bcmlog: unable to create /proc/%s!\n", PROC_ENTRY_NAME);
return;
}
p->proc_fops = &log_proc_fops;
bcmPrint("Broadcom Logger %s\n", VER_STR);
}
void bcmLog_registerSpiCallbacks(bcmLogSpiCallbacks_t callbacks)
{
spiFns = callbacks;
BCM_ASSERT(spiFns.reserveSlave != NULL);
BCM_ASSERT(spiFns.syncTrans != NULL);
}
EXPORT_SYMBOL(bcmLog_ddIsEnabled);
EXPORT_SYMBOL(bcm_dataDumpRegPrinter);
EXPORT_SYMBOL(bcm_dataDump);
EXPORT_SYMBOL(bcm_dataDumpCreateQ);
EXPORT_SYMBOL(bcm_dataDumpDeleteQ);
EXPORT_SYMBOL(bcmFun_reg);
EXPORT_SYMBOL(bcmFun_dereg);
EXPORT_SYMBOL(bcmFun_get);
#endif /*defined(BCM_DATADUMP_SUPPORTED)*/
EXPORT_SYMBOL(bcmLog_setGlobalLogLevel);
EXPORT_SYMBOL(bcmLog_getGlobalLogLevel);
EXPORT_SYMBOL(bcmLog_setLogLevel);
EXPORT_SYMBOL(bcmLog_getLogLevel);
EXPORT_SYMBOL(bcmLog_getModName);
EXPORT_SYMBOL(bcmLog_registerSpiCallbacks);
EXPORT_SYMBOL(bcmLog_registerLevelChangeCallback);