Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | /*
* Copyright 2003 Digi International (www.digi.com)
* Scott H Kilau <Scott_Kilau at digi dot com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
* NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
*
* This is shared code between Digi's CVS archive and the
* Linux Kernel sources.
* Changing the source just for reformatting needlessly breaks
* our CVS diff history.
*
* Send any bug fixes/changes to: Eng.Linux at digi dot com.
* Thank you.
*
*/
#include <linux/kernel.h>
#include <linux/sched.h> /* For jiffies, task states */
#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
#include <linux/vmalloc.h>
#include "dgnc_driver.h"
#include "dgnc_trace.h"
#define TRC_TO_CONSOLE 1
/* file level globals */
static char *dgnc_trcbuf; /* the ringbuffer */
#if defined(TRC_TO_KMEM)
static int dgnc_trcbufi = 0; /* index of the tilde at the end of */
#endif
#if defined(TRC_TO_KMEM)
static DEFINE_SPINLOCK(dgnc_tracef_lock);
#endif
#if 0
#if !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE)
void dgnc_tracef(const char *fmt, ...)
{
return;
}
#else /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
void dgnc_tracef(const char *fmt, ...)
{
va_list ap;
char buf[TRC_MAXMSG+1];
size_t lenbuf;
int i;
static int failed = FALSE;
# if defined(TRC_TO_KMEM)
unsigned long flags;
#endif
if (failed)
return;
# if defined(TRC_TO_KMEM)
DGNC_LOCK(dgnc_tracef_lock, flags);
#endif
/* Format buf using fmt and arguments contained in ap. */
va_start(ap, fmt);
i = vsprintf(buf, fmt, ap);
va_end(ap);
lenbuf = strlen(buf);
# if defined(TRC_TO_KMEM)
{
static int initd = 0;
/*
* Now, in addition to (or instead of) printing this stuff out
* (which is a buffered operation), also tuck it away into a
* corner of memory which can be examined post-crash in kdb.
*/
if (!initd) {
dgnc_trcbuf = (char *) vmalloc(dgnc_trcbuf_size);
if (!dgnc_trcbuf) {
failed = TRUE;
printk("dgnc: tracing init failed!\n");
return;
}
memset(dgnc_trcbuf, '\0', dgnc_trcbuf_size);
dgnc_trcbufi = 0;
initd++;
printk("dgnc: tracing enabled - " TRC_DTRC
" 0x%lx 0x%x\n",
(unsigned long)dgnc_trcbuf,
dgnc_trcbuf_size);
}
# if defined(TRC_ON_OVERFLOW_WRAP_AROUND)
/*
* This is the less CPU-intensive way to do things. We simply
* wrap around before we fall off the end of the buffer. A
* tilde (~) demarcates the current end of the trace.
*
* This method should be used if you are concerned about race
* conditions as it is less likely to affect the timing of
* things.
*/
if (dgnc_trcbufi + lenbuf >= dgnc_trcbuf_size) {
/* We are wrapping, so wipe out the last tilde. */
dgnc_trcbuf[dgnc_trcbufi] = '\0';
/* put the new string at the beginning of the buffer */
dgnc_trcbufi = 0;
}
strcpy(&dgnc_trcbuf[dgnc_trcbufi], buf);
dgnc_trcbufi += lenbuf;
dgnc_trcbuf[dgnc_trcbufi] = '~';
# elif defined(TRC_ON_OVERFLOW_SHIFT_BUFFER)
/*
* This is the more CPU-intensive way to do things. If we
* venture into the last 1/8 of the buffer, we shift the
* last 7/8 of the buffer forward, wiping out the first 1/8.
* Advantage: No wrap-around, only truncation from the
* beginning.
*
* This method should not be used if you are concerned about
* timing changes affecting the behaviour of the driver (ie,
* race conditions).
*/
strcpy(&dgnc_trcbuf[dgnc_trcbufi], buf);
dgnc_trcbufi += lenbuf;
dgnc_trcbuf[dgnc_trcbufi] = '~';
dgnc_trcbuf[dgnc_trcbufi+1] = '\0';
/* If we're near the end of the trace buffer... */
if (dgnc_trcbufi > (dgnc_trcbuf_size/8)*7) {
/* Wipe out the first eighth to make some more room. */
strcpy(dgnc_trcbuf, &dgnc_trcbuf[dgnc_trcbuf_size/8]);
dgnc_trcbufi = strlen(dgnc_trcbuf)-1;
/* Plop overflow message at the top of the buffer. */
bcopy(TRC_OVERFLOW, dgnc_trcbuf, strlen(TRC_OVERFLOW));
}
# else
# error "TRC_ON_OVERFLOW_WRAP_AROUND or TRC_ON_OVERFLOW_SHIFT_BUFFER?"
# endif
}
DGNC_UNLOCK(dgnc_tracef_lock, flags);
# endif /* defined(TRC_TO_KMEM) */
}
#endif /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
#endif
/*
* dgnc_tracer_free()
*
*
*/
void dgnc_tracer_free(void)
{
if (dgnc_trcbuf)
vfree(dgnc_trcbuf);
}
|