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