1/*
2    File:       IrDALog.c
3
4    Contains:   Logging support for IrDA.
5
6    Written by: Clark Donahue, Jim Guyton
7
8    Todo: add copyright
9
10
11*/
12//#include <Kernel/kern/clock.h>
13#include <IOKit/IOLib.h>
14#include "IrDALog.h"
15#include "IrDADebugging.h"
16#include "IrDALogPriv.h"
17
18#ifndef nil
19#define nil 0
20#endif
21
22#define DEBUGGER(x) panic(x)    // revisit this!
23
24///////////////////////////////////////////////////////////////////////////////////////////////////////
25// Following moved to IrDALogPriv.h (or IrDADebugging.h)
26//
27//#define hasTracing  1             // set to one to have tracing, to zero to compile out
28//#define USE_IOLOG 1               // true if want to go to IOLog
29//#define IOSLEEPTIME   700         // ms delay after each IOLog
30//#define kEntryCount   (10*1024)   // Number of log entries.   *** Change to runtime alloc?
31//#define kMaxModuleNames   50              // max number of clients (unique module names)
32//#define kMaxModuleNameLen 32              // max length of module name
33//#define kMaxIndex         200             // max event index (# of msgs) per module
34//#define   kMsgBufSize     (20*1024)       // way overkill -- 20k for copies of msgs
35///////////////////////////////////////////////////////////////////////////////////////////////////////
36
37
38#if (hasTracing > 0)
39
40char *GetCachedMsg(EventTraceCauseDesc *desc, UInt16 eventIndex);
41
42// Globals
43IrDAEventDesc fBuffer[kEntryCount+10];  // Buffer (+10 is hack so wrap race condition doesn't smash memory)
44
45#pragma export on               // Start of public code
46#pragma mark Start Exported -------------
47
48IrDALogHdr gIrDALog = {                 // the log header
49	&fBuffer[0],                    // fEventBuffer
50	0,                              // fEventIndex
51	0,                              // fPrintIndex
52	kEntryCount,                    // fNumEntries
53	true,                           // fTracingOn
54	false                           // fWrapped
55	//true                          // fWrappingEnabled
56};
57
58#endif // hasTracing > 0
59
60
61#if (hasTracing > 0)
62#ifdef __cplusplus
63extern "C"
64#endif // __cplusplus
65void IrDALogAdd( UInt16 eventIndex, UInt16 data1, UInt16 data2, EventTraceCauseDesc * desc, Boolean timeStamp)
66{
67
68    IrDAEventDesc *logEntry;
69    UInt32 cTime;
70
71    // sanity checks
72    require(eventIndex > 0, Fail);
73    require(desc, Fail);
74
75    if(!gIrDALog.fTracingOn)        // nop if tracing not enabled
76	return;
77
78    eventIndex--;                   // FOO.  EventIndex is 1 based instead of zero based.
79
80#if (USE_IOLOG > 0)
81    {
82	IOLog("%04x %04x %s\n", data1, data2, desc[eventIndex].description);
83	IOSleep(IOSLEEPTIME);   // in ms
84    }
85#endif
86
87    if( gIrDALog.fEventIndex >= gIrDALog.fNumEntries ) {    // Wrap if hit end of buffer (this one shouldn't be hit, sanity only)
88	gIrDALog.fEventIndex = 0;
89	if (gIrDALog.fEventIndex == gIrDALog.fPrintIndex)   // if newly wrapped index now matches print index
90	    gIrDALog.fWrapped = true;                       // then we've wrapped past it
91    }
92
93    logEntry = &gIrDALog.fEventBuffer[gIrDALog.fEventIndex++];  // Get the log entry pointer & incr ptr
94
95    if( gIrDALog.fEventIndex >= gIrDALog.fNumEntries) {     // Wrap if hit end of buffer (this one should be hit)
96	gIrDALog.fEventIndex = 0;
97    }
98
99    if (gIrDALog.fEventIndex == gIrDALog.fPrintIndex)           // if the (incr'd) index matches printing index
100	gIrDALog.fWrapped = true;                               // then we've wrapped past it
101
102    //if (gIrDALog.fWrappingEnabled == false && gIrDALog.fWrapped == true)  // if not allowed to wrap
103    //  return;
104
105    //
106    // Now that we have a record, get the current time (if requested)
107    //
108    if (timeStamp) {
109	    AbsoluteTime now;
110	    UInt64  nanoseconds;
111	    clock_get_uptime(&now);
112	    absolutetime_to_nanoseconds(now, &nanoseconds);
113	    cTime = nanoseconds / 1000;     // microseconds is plenty for me
114    }
115    else cTime = 0;
116
117    // Ok, stuff a log entry
118    logEntry->data1         = data1;                                // Stuff in the data
119    logEntry->data2         = data2;
120    logEntry->timeStamp     = cTime;                                // log the time
121    logEntry->msg           = GetCachedMsg(desc, eventIndex);       // get pointer to copy of msg (or nil)
122
123Fail:
124    return;
125
126} // IrDALogAdd
127
128
129void
130IrDALogTracingOn(void)
131{
132    gIrDALog.fTracingOn = true;
133}
134
135void
136IrDALogTracingOff(void)
137{
138    gIrDALog.fTracingOn = false;
139}
140
141/*
142void
143IrDALogWrappingOn()
144{
145    gIrDALog.fWrappingEnabled = true;
146}
147
148void
149IrDALogWrappingOff()
150{
151    gIrDALog.fWrappingEnabled = false;
152}
153*/
154
155#endif // hasTracing > 0
156
157#pragma mark Message Cache -------------
158
159#if (hasTracing > 0)
160
161
162char    gMsgBuf[kMsgBufSize];                               // the big buffer for copies of msgs
163char    gModuleNames[kMaxModuleNames][kMaxModuleNameLen];   // table client module names
164char    *gMsgPtrs[kMaxModuleNames][kMaxIndex];              // pointers to copies of msgs
165char    *gNextMsg = &gMsgBuf[0];                            // pointer to next avail byte in gMsgBuf
166int     gNextModuleIndex = 0;                               // index of next avail entry in gModuleNames
167
168UInt32 GetModuleIndex(EventTraceCauseDesc *desc);
169char *CopyMsg(const char *msg);
170
171//EventTraceCauseDesc* gDebugTable;     // temp
172//UInt32                gDebugIndex;
173//char              *gDebugMsg;
174//char              **gDebugMsgAddr;
175//int                   gDebugSize;
176
177char *
178GetCachedMsg(EventTraceCauseDesc *desc, UInt16 eventIndex)
179{
180    UInt32  moduleIndex;        // index to module name in gModuleNames
181    char *msg;
182
183    // TEMP
184    //gDebugTable = desc;
185    //gDebugIndex = eventIndex;
186
187    // Sanity checks
188    if (desc[eventIndex].cause != (eventIndex + 1)) return nil;
189    if (eventIndex >= kMaxIndex) {
190	DEBUGGER("IrDALog: need to incr kMaxIndex");
191	return nil;
192    }
193
194    // if msgcopy in the client array is already set, use that
195    // note: hopefully this will be true a lot more often than not
196    if (desc[eventIndex].msgcopy != nil)
197	return desc[eventIndex].msgcopy;
198
199    // Ok, haven't seen this event msg before. Find this module
200    // in our cache.
201
202    moduleIndex = GetModuleIndex(desc);         // find existing module name or make new entry and return that
203    if (moduleIndex == -1) return nil;          // error return if too many modules
204
205    // If msg is in the module table (but not in the client table) then
206    // the client has died and come back.  Set all msgcopy ptrs for it.
207    if (gMsgPtrs[moduleIndex][eventIndex]) {
208	int i;
209	//DebugStr("\pAbout to set ptrs for an entire module");
210	for (i = 0 ; i < kMaxIndex; i++) {
211	    if (gMsgPtrs[moduleIndex][i])                   // if a copy exists
212		desc[i].msgcopy = gMsgPtrs[moduleIndex][i]; // set the msgcopy ptr
213	}
214	return desc[eventIndex].msgcopy;
215    }
216
217    // Ok, time to make a copy of the msg
218    //gDebugMsg = desc[eventIndex].description;     // TEMP
219    //gDebugMsgAddr = &desc[eventIndex].description;
220    //gDebugSize = sizeof(desc[0]);
221
222    msg = CopyMsg(desc[eventIndex].description);            // get a copy of the msg
223    desc[eventIndex].msgcopy = msg;                         // save msg pointer in client!
224    gMsgPtrs[moduleIndex][eventIndex] = msg;                // and in per-module table
225    return msg;
226}
227
228// This should be rewritten to use a hash table
229int gModuleIndex;
230
231UInt32 GetModuleIndex(EventTraceCauseDesc *desc)
232{
233    int i;
234    const char *modstart;
235    int namelen;
236    char modulename[kMaxModuleNameLen];         // copy of module name (need the trailing null)
237
238    modstart = desc[0].description;             // extract module name from 1st msg in client table
239    {   const char *t;
240	t = strchr(modstart, ':');
241	if (t == nil) return -1;
242	namelen = t - modstart;
243	if (namelen < 1 ||  namelen-1 > kMaxModuleNameLen) {        // check length
244	    DEBUGGER("IrDALog: rejecting module name(len)");
245	    return -1;
246	}
247    }
248    strncpy(modulename, modstart, namelen);     // copy the name
249    modulename[namelen] = 0;                    // make it a C string
250
251    for (i = 0 ; i < gNextModuleIndex; i++) {   // Sigh.  Search the module table.
252	if (strcmp(modulename, gModuleNames[i]) == 0) {
253	    gModuleIndex = i;
254	    return i;                           // found it!
255	}
256    }
257
258    // Not in the current list of module names
259    // make a new entry
260
261    if (gNextModuleIndex < kMaxModuleNames) {                   // if room in the table
262	strlcpy(gModuleNames[gNextModuleIndex++], modulename, sizeof(gModuleNames[0]));   // copy it in
263	gModuleIndex = gNextModuleIndex-1;
264	return gNextModuleIndex-1;
265    }
266    DEBUGGER("IrDALog: need to increase kMaxModuleNames");
267    return -1;
268}
269
270
271// return ptr to a copy of the msg or nil if out of memory
272char *CopyMsg(const char *msg)
273{
274    char *result;
275    int len;
276
277    result = gNextMsg;          // start of next avail msg
278    len = strlen(msg) + 1;      // how much to copy
279
280    if (gNextMsg + len >= &gMsgBuf[kMsgBufSize]) {  // to many msgs?
281	DEBUGGER("IrDALog: need to incr kMsgBufSize");
282	return nil;
283    }
284
285    memcpy(result, msg, len);   // copy msg including null
286    gNextMsg += len;            // incr avail ptr for next msg
287
288    return result;
289}
290
291IrDALogInfo gIrDALogInfo = {
292	&gIrDALog, sizeof(gIrDALog),
293	fBuffer, sizeof(fBuffer),
294	gMsgBuf, sizeof(gMsgBuf) };
295
296
297IrDALogInfo *
298IrDALogGetInfo(void)
299{
300    return &gIrDALogInfo;
301/*
302    if (info == nil) return;
303    info->hdr = &gIrDALog;
304    info->hdrSize = sizeof(gIrDALog);
305    info->eventLog = fBuffer;
306    info->eventLogSize = sizeof(fBuffer);
307    info->msgBuffer = gMsgBuf;
308    info->msgBufferSize = sizeof(gMsgBuf);
309*/
310}
311
312void
313IrDALogReset(void)
314{
315    gIrDALog.fEventIndex = 0;
316    gIrDALog.fPrintIndex = 0;
317    gIrDALog.fNumEntries = kEntryCount;
318    // don't reset fTracingOn
319    //gIrDALog.fTracingOn = true;
320    gIrDALog.fWrapped = false;
321    // don't reset fWrappingEnabled
322}
323
324#endif // hasTracing > 0
325
326
327
328