1/************************************************************************
2 * flight_recorder.c
3 ************************************************************************
4 * This code supports the a generic flight recorder.                    *
5 * Copyright (C) 20yy  <Allan H Trautman> <IBM Corp>                    *
6 *                                                                      *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or    *
10 * (at your option) any later version.                                  *
11 *                                                                      *
12 * This program is distributed in the hope that it will be useful,      *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
15 * GNU General Public License for more details.                         *
16 *                                                                      *
17 * You should have received a copy of the GNU General Public License    *
18 * along with this program; if not, write to the:                       *
19 * Free Software Foundation, Inc.,                                      *
20 * 59 Temple Place, Suite 330,                                          *
21 * Boston, MA  02111-1307  USA                                          *
22 ************************************************************************
23 * This is a simple text based flight recorder.  Useful for logging
24 * information the you may want to retreive at a latter time.  Errors or
25 * debug inforamtion are good examples.   A good method to dump the
26 * information is via the proc file system.
27 *
28 * To use.
29 * 1. Create the flight recorder object.  Passing a NULL pointer will
30 *    kmalloc the space for you.  If it is too early for kmalloc, create
31 *    space for the object.   Beware, don't lie about the size, you will
32 *    pay for that later.
33 * 		FlightRecorder* TestFr = alloc_Flight_Recorder(NULL,"TestFr",4096);
34 *
35 * 2. Log any notable events, initialzation, error conditions, etc.
36 *		LOGFR(TestFr,"5. Stack Variable(10) %d",StackVariable);
37 *
38 * 3. Dump the information to a buffer.
39 *		fr_Dump(TestFr, proc_file_buffer, proc_file_buffer_size);
40 *
41 ************************************************************************/
42#include <stdarg.h>
43#include <linux/kernel.h>
44#include <linux/rtc.h>
45#include <linux/slab.h>
46#include <asm/string.h>
47#include <asm/time.h>
48#include <asm/flight_recorder.h>
49
50static  char       LogText[512];
51static  int        LogTextIndex;
52static  int        LogCount = 0;
53static  spinlock_t Fr_Lock;
54
55/************************************************************************
56 * Build the log time prefix based on Flags.
57 *  00 = No time prefix
58 *  01 = Date(mmddyy) Time(hhmmss) prefix
59 *  02 = Day(dd) Time(hhmmss) prefix
60 *  03 = Time(hhmmss) prefix
61 ************************************************************************/
62static void fr_Log_Time(FlightRecorder* Fr)
63{
64	struct  timeval  TimeClock;
65	struct  rtc_time LogTime;
66
67	do_gettimeofday(&TimeClock);
68	to_tm(TimeClock.tv_sec, &LogTime);
69
70	if (Fr->Flags == 1) {
71		LogTextIndex = sprintf(LogText,"%02d%02d%02d %02d%02d%02d ",
72		                       LogTime.tm_mon, LogTime.tm_mday, LogTime.tm_year-2000,
73	     	                  LogTime.tm_hour,LogTime.tm_min, LogTime.tm_sec);
74	}
75	else if (Fr->Flags == 2) {
76		LogTextIndex = sprintf(LogText,"%02d %02d%02d%02d ",
77		                       LogTime.tm_mday,
78	     	                  LogTime.tm_hour,LogTime.tm_min, LogTime.tm_sec);
79	}
80
81	else if (Fr->Flags == 3) {
82		LogTextIndex = sprintf(LogText,"%02d%02d%02d ",
83	     	                  LogTime.tm_hour,LogTime.tm_min, LogTime.tm_sec);
84	}
85	else {
86		++LogCount;
87		LogTextIndex = sprintf(LogText,"%04d. ",LogCount);
88	}
89}
90
91/************************************************************************/
92/* Log entry into buffer,                                               */
93/* ->If entry is going to wrap, log "WRAP" and start at the top.        */
94/************************************************************************/
95static void fr_Log_Data(FlightRecorder* Fr)
96{
97	int 	TextLen  = strlen(LogText);
98	int 	Residual = ( Fr->EndPointer - Fr->NextPointer)-15;
99	if (TextLen > Residual) {
100		strcpy(Fr->NextPointer,"WRAP");
101		Fr->WrapPointer = Fr->NextPointer + 5;
102		Fr->NextPointer = Fr->StartPointer;
103	}
104	strcpy(Fr->NextPointer,LogText);
105	Fr->NextPointer += TextLen+1;
106	strcpy(Fr->NextPointer,"<=");
107}
108/************************************************************************
109 * Build the log text, support variable args.
110 ************************************************************************/
111void fr_Log_Entry(struct flightRecorder* LogFr, const char *fmt, ...)
112{
113	va_list arg_ptr;
114	spin_lock(&Fr_Lock);
115
116	fr_Log_Time(LogFr);
117	va_start(arg_ptr, fmt);
118	vsprintf(LogText+LogTextIndex, fmt, arg_ptr);
119	va_end(arg_ptr);
120	fr_Log_Data(LogFr);
121
122	spin_unlock(&Fr_Lock);
123
124}
125/************************************************************************
126 * Dump Flight Recorder into buffer.
127 * -> Handles the buffer wrapping.
128 ************************************************************************/
129int fr_Dump(FlightRecorder* Fr, char *Buffer, int BufferLen)
130{
131	int   LineLen = 0;
132	char* StartEntry;
133	char* EndEntry;
134	spin_lock(&Fr_Lock);
135	/****************************************************************
136	 * If Buffer has wrapped, find last usable entry to start with.
137	 ****************************************************************/
138	if (Fr->WrapPointer != NULL) {
139		StartEntry  = Fr->NextPointer+3;
140		StartEntry += strlen(StartEntry)+1;
141		EndEntry    = Fr->WrapPointer;
142
143		while (EndEntry > StartEntry && LineLen < BufferLen) {
144			LineLen    += sprintf(Buffer+LineLen,"%s\n",StartEntry);
145			StartEntry += strlen(StartEntry) + 1;
146		}
147	}
148
149	/****************************************************************
150	 * Dump from the beginning to the last logged entry
151	 ****************************************************************/
152	StartEntry = Fr->StartPointer;
153	EndEntry   = Fr->NextPointer;
154	while (EndEntry > StartEntry && LineLen < BufferLen) {
155		LineLen    += sprintf(Buffer+LineLen,"%s\n",StartEntry);
156		StartEntry += strlen(StartEntry) + 1;
157	}
158	spin_unlock(&Fr_Lock);
159	return LineLen;
160}
161
162/************************************************************************
163 * Allocate and Initialized the Flight Recorder
164 * -> If no FlightRecorder pointer is passed, the space is kmalloc.
165 ************************************************************************/
166FlightRecorder* alloc_Flight_Recorder(FlightRecorder* FrPtr, char* Signature, int SizeOfFr)
167{
168	FlightRecorder* Fr     = FrPtr;				/* Pointer to Object */
169	int             FrSize = (SizeOfFr/16)*16;	/* Could be static   */
170	if (Fr == NULL)
171		Fr = (FlightRecorder*)kmalloc(SizeOfFr, GFP_KERNEL);
172	memset(Fr,0,SizeOfFr);
173	strcpy(Fr->Signature,Signature);
174	Fr->Size         = FrSize;
175	Fr->Flags        = 0;
176	Fr->StartPointer = (char*)&Fr->Buffer;
177	Fr->EndPointer   = (char*)Fr + Fr->Size;
178	Fr->NextPointer  = Fr->StartPointer;
179
180	fr_Log_Entry(Fr,"Initialized.");
181	return Fr;
182}
183