source: cmedia/trunk/Drv16/log.cpp@ 354

Last change on this file since 354 was 354, checked in by stevenhl, 17 years ago

Import untested baseline cmedia sources, work products and binaries
Binaries and work products should be deleted from repository.
once new builds are verified to work.

File size: 18.9 KB
Line 
1/* SCCSID = %W% %E% */
2/****************************************************************************
3 * *
4 * Copyright (c) IBM Corporation 1994 - 1997. *
5 * *
6 * The following IBM OS/2 source code is provided to you solely for the *
7 * the purpose of assisting you in your development of OS/2 device drivers. *
8 * You may use this code in accordance with the IBM License Agreement *
9 * provided in the IBM Device Driver Source Kit for OS/2. *
10 * *
11 ****************************************************************************/
12/**@internal %W%
13 * Facilities for logging errors, status, and realtime traces. Logged
14 * information can be routed to any combination of display, COM: lines,
15 * system trace buffer (retrieved by TRACEFMT utility), and/or system
16 * error log.
17 * @version %I%
18 * @context 16-bit, Ring 3 or Ring 0, DD Ioctl time context. The BINARYLOG
19 * and PERFLOG methods may be used in Interrupt context.
20 * @notes
21 *
22 * Supported syntax for data formatting (case insensitive)
23 *
24 * >--- % --+-----+--------------- B -+---|
25 * | | | |
26 * +- 0 -+ +----------- Q -+
27 * | |
28 * +-----+---+- D -+
29 * | | | |
30 * +- L -+ +- X -+
31 *
32 * Where
33 * 0 - format with leading 0's
34 * L - long integer
35 * D - format decimal
36 * X - format hexidecimal
37 * B - byte hex (BINARY logs only)
38 * Q - quadword hex (BINARY logs only)
39 * Not supported at this time
40 * S - ASCIIZ data
41 *
42 * @notes bugs
43 * The %b, %q, and %b datatypes are not implemented across all log types.
44 *
45 * @history
46 */
47
48extern "C" {
49#define INCL_NOPMAPI
50#define INCL_DOSMISC
51#include <os2.h>
52}
53
54#include <devhelp.h>
55#include <string.h> // strlen() intrinsic
56#include "iodelay.h"
57#include "log.hpp"
58#include <include.h>
59
60#define CR 0x0d
61#define LF 0x0a
62
63#define LEADING_ZEROES 0x8000
64#define SIGNIFICANT_FIELD 0x0007
65
66#define UART_DATA 0x00 // UART Data port
67#define UART_INT_ENAB 0x01 // UART Interrupt enable
68#define UART_INT_ID 0x02 // interrupt ID
69#define UART_LINE_CTRL 0x03 // line control registers
70#define UART_MODEM_CTRL 0x04 // modem control register
71#define UART_LINE_STAT 0x05 // line status register
72#define UART_MODEM_STAT 0x06 // modem status regiser
73#define UART_DIVISOR_LO 0x00 // divisor latch least sig
74#define UART_DIVISOR_HI 0x01h // divisor latch most sig
75
76// Global logging variables. Values are setup in init.cpp.
77LOG* pStatus; // Points to the status log.
78LOG* pError; // Points to the error log.
79LOG* pSoftError; // Points to the error log.
80BINARYLOG* pTrace; // Points to the trace log.
81PERFLOG* pPerfLog; // Points to Performance trace log.
82
83// Used to convert binary to ascii
84static const char ddhextab[]="0123456789ABCDEF";
85
86
87 //----------- ddprintf_DecWordToASCII -
88PSZ LOG::_DecWordToASCII(PSZ StrPtr, WORD wDecVal, WORD Option)
89/*
90; StrPtr - Output, pointer to location to save resulting ASCII string.
91; wDecVal - Input, 16 bit value to convert.
92; Option - Input, selects leading zeros.
93*/
94{
95 BOOL fNonZero=FALSE;
96 WORD Digit;
97 WORD Power=10000;
98
99 while (Power)
100 {
101 Digit=0;
102 while (wDecVal >=Power) //Digit=wDecVal/Power;
103 {
104 Digit++;
105 wDecVal-=Power;
106 }
107
108 if (Digit)
109 fNonZero=TRUE;
110
111 if (Digit ||
112 fNonZero ||
113 (Option & LEADING_ZEROES) ||
114 ((Power==1) && (fNonZero==FALSE)))
115 {
116 *StrPtr=(char)('0'+Digit);
117 StrPtr++;
118 }
119
120 if (Power==10000)
121 Power=1000;
122 else if (Power==1000)
123 Power=100;
124 else if (Power==100)
125 Power=10;
126 else if (Power==10)
127 Power=1;
128 else
129 Power=0;
130 } // end while
131
132 return (StrPtr);
133}
134
135 //----------- ddprintf_DecLongToASCII -
136PSZ LOG::_DecLongToASCII(PSZ StrPtr, DWORD lDecVal,WORD Option)
137{
138 BOOL fNonZero=FALSE;
139 DWORD Digit;
140 DWORD Power=1000000000; // 1 billion
141
142 while (Power)
143 {
144 Digit=0; // Digit=lDecVal/Power
145 while (lDecVal >=Power) // replaced with while loop
146 {
147 Digit++;
148 lDecVal-=Power;
149 }
150
151 if (Digit)
152 fNonZero=TRUE;
153
154 if (Digit ||
155 fNonZero ||
156 (Option & LEADING_ZEROES) ||
157 ((Power==1) && (fNonZero==FALSE)))
158 {
159 *StrPtr=(char)('0'+Digit);
160 StrPtr++;
161 }
162
163 if (Power==1000000000) // 1 billion
164 Power=100000000;
165 else if (Power==100000000)
166 Power=10000000;
167 else if (Power==10000000)
168 Power=1000000;
169 else if (Power==1000000)
170 Power=100000;
171 else if (Power==100000)
172 Power=10000;
173 else if (Power==10000)
174 Power=1000;
175 else if (Power==1000)
176 Power=100;
177 else if (Power==100)
178 Power=10;
179 else if (Power==10)
180 Power=1;
181 else
182 Power=0;
183 }
184 return (StrPtr);
185}
186 //----------- ddprintf_HexWordToASCII -
187PSZ LOG::_HexWordToASCII(PSZ StrPtr, WORD wHexVal, WORD Option)
188{
189 BOOL fNonZero=FALSE;
190 WORD Digit;
191 WORD Power=0xF000;
192 WORD ShiftVal=12;
193
194 while (Power)
195 {
196 Digit=(wHexVal & Power)>>ShiftVal;
197 if (Digit)
198 fNonZero=TRUE;
199
200 if (Digit ||
201 fNonZero ||
202 (Option & LEADING_ZEROES) ||
203 ((Power==0x0F) && (fNonZero==FALSE)))
204 //*StrPtr++=(char)('0'+Digit);
205 *StrPtr++=ddhextab[Digit];
206
207 Power>>=4;
208 ShiftVal-=4;
209 } // end while
210
211 return (StrPtr);
212}
213
214 //----------- ddprintf_HexLongToASCII -
215PSZ LOG::_HexLongToASCII( PSZ StrPtr, DWORD wHexVal, WORD Option )
216{
217 BOOL fNonZero=FALSE;
218 DWORD Digit;
219 DWORD Power=0xF0000000;
220 DWORD ShiftVal=28;
221
222 while (Power)
223 {
224 Digit=(wHexVal & Power)>>ShiftVal;
225 if (Digit)
226 fNonZero=TRUE;
227
228 if (Digit ||
229 fNonZero ||
230 (Option & LEADING_ZEROES) ||
231 ((Power==0x0F) && (fNonZero==FALSE)))
232 *StrPtr++=ddhextab[Digit];
233
234 if (Power==0xF0000000) // 1 billion
235 Power=0xF000000;
236 else if (Power==0xF000000)
237 Power=0xF00000;
238 else if (Power==0xF00000)
239 Power=0xF0000;
240 else if (Power==0xF0000)
241 Power=0xF000;
242 else if (Power==0xF000)
243 Power=0xF00;
244 else if (Power==0xF00)
245 Power=0xF0;
246 else if (Power==0xF0)
247 Power=0xF;
248 else Power=0;
249
250 ShiftVal-=4;
251 } // end while
252
253 return (StrPtr);
254}
255
256
257USHORT LOG::_ddsprintf ( PSZ pszOutString, PSZ pszFmtString, STACK_ADR Parm )
258/*
259; ddsprintf - "sprintf" function on a vbl number of arguments.
260;
261; pszOutString - Output string saved here.
262; pszFmtString - Input, Ascii string containing text and formating information.
263; Parm - Input, Address of the 1st of the variable number of arguments.
264;
265;Returns:
266; Length of string created.
267*/
268{
269 PSZ BuildPtr = pszOutString;
270 PSZ pStr = (PSZ) pszFmtString;
271 PSZ SubStr;
272 WORD wBuildOption;
273
274 while (*pStr) {
275 // don't overflow target
276 if (BuildPtr >= &pszOutString[ MAX_MsgLen-2 ] )
277 break;
278
279 switch (*pStr) { // the top switch
280 case '%':
281 wBuildOption=0;
282 pStr++;
283 if (*pStr=='0') {
284 wBuildOption|=LEADING_ZEROES;
285 pStr++;
286 }
287
288 switch(*pStr) { // switch on "%" options
289 case 'x':
290 case 'X':
291 BuildPtr=_HexWordToASCII(BuildPtr, *Parm.WordPtr++,wBuildOption);
292 pStr++;
293 continue;
294
295 case 'd':
296 case 'D':
297 BuildPtr=_DecWordToASCII(BuildPtr, *Parm.WordPtr++,wBuildOption);
298 pStr++;
299 continue;
300
301 case 's':
302 case 'S':
303 SubStr = (PSZ) *Parm.StringPtr;
304 while (*SubStr)
305 *BuildPtr++ = *SubStr++;
306 Parm.StringPtr++;
307 BuildPtr--; // remove the \0
308 pStr++;
309 continue;
310
311 case 'l':
312 case 'L':
313 pStr++;
314 switch (*pStr) { // "%l" options
315 case 'x':
316 BuildPtr=_HexLongToASCII(BuildPtr, *Parm.LongPtr++,wBuildOption);
317 pStr++;
318 continue;
319
320 case 'd':
321 BuildPtr=_DecLongToASCII(BuildPtr, *Parm.LongPtr++,wBuildOption);
322 pStr++;
323 continue;
324 } // end switch on "%l" options
325 continue; // dunno what he wants
326
327 case 0:
328 continue;
329 } // end switch on "%" options
330 break;
331
332 case '\\':
333 pStr++;
334 switch (*pStr) {
335 case 'n':
336 *BuildPtr++=CR;
337 *BuildPtr++=LF;
338 pStr++;
339 continue;
340
341 case 'r':
342 *BuildPtr++=CR;
343 pStr++;
344 continue;
345
346 case 0:
347 continue;
348
349 } // end switch
350
351 break; // case '\\'
352
353 case '\n':
354 pStr++;
355 *BuildPtr++=CR;
356 *BuildPtr++=LF;
357 continue;
358 break;
359 } // end top switch
360
361 *BuildPtr++=*pStr++;
362 } // end while
363
364 *BuildPtr=0; // cauterize the string
365 return strlen( (char *) pszOutString );
366}
367
368USHORT _CheckRing(void);
369#pragma aux _CheckRing = \
370 "push cs" \
371 "pop ax " \
372 "and ax,0003H" \
373 parm nomemory \
374 modify [ax];
375
376 //----------------------- ddputstring -
377void LOG::_ddputstring ( USHORT iMsgNum, PSZ pszMsg )
378{
379 int iMsgLength = strlen( (char *) pszMsg );
380 // Sring length of the message.
381
382 // Need to know whether we're still executing at Ring 3.
383 if ( _bInRing3 )
384 if (_CheckRing() != 3) // In Ring 3 last time, still there now?
385 _bInRing3 = FALSE; // Nope, and no need to check again.
386
387 // --- Index through possible places to save this message.
388 for (int destination=0; destination != _nMsgSinks; ++destination) {
389 if ( bMsgSink[destination] ) {
390 switch (destination) {
391 case _Display:
392 // Put message on the display only if we're in Ring 3.
393 if ( _bInRing3 ) {
394 static CHAR szCRLF[] = "\r\n";
395 static int iCRLF_Len = strlen( (char *) szCRLF );
396 DosPutMessage( 1, iMsgLength, (PCHAR) pszMsg );
397 DosPutMessage( 1, iCRLF_Len, (PCHAR) szCRLF );
398 }
399 break;
400 case _SerialLine:
401 { PCHAR pChar = (PCHAR) pszMsg;
402 while (*pChar)
403 _CharOut(*pChar++);
404 }
405 _CharOut( '\n' );
406 break;
407 case _ErrorLog:
408 if ( _bInRing3 )
409 DosSysTrace( _DosTraceMajorCode, iMsgLength, iMsgNum, (PCHAR) pszMsg);
410 else
411 DevHelp_RAS( _DosTraceMajorCode, iMsgNum, iMsgLength, pszMsg);
412 break;
413 case _TraceLog:
414 if ( _bInRing3 )
415 DosSysTrace( _DosTraceMajorCode, iMsgLength, iMsgNum, (PCHAR) pszMsg);
416 else
417 DevHelp_RAS( _DosTraceMajorCode, iMsgNum, iMsgLength, pszMsg);
418 break;
419 }
420 }
421 }
422}
423
424
425void LOG::_CharOut(char c)
426/* Sends a single character to the COM: port. */
427{
428 UCHAR inbyte;
429
430 inbyte = inp((_ComPort + UART_LINE_STAT));
431 while ((inbyte & 0x20) != 0x20) {
432 iodelay(1);
433 inbyte = inp((_ComPort + UART_LINE_STAT));
434 }
435 // Send the character
436 outp((_ComPort + UART_DATA), c);
437}
438
439
440// Create a log. The parms indicate where to stream the messages to.
441LOG::LOG( USHORT DosTraceMajorCode, PSZ* apszMsgText ) :
442 _DosTraceMajorCode ( DosTraceMajorCode ),
443 _bInRing3 ( _CheckRing() != 0 ),
444 _apszMsgText ( apszMsgText ),
445 _ComPort ( 0x2F8 )
446{
447 bMsgSink[ _Display ] = FALSE;
448 bMsgSink[ _SerialLine ] = FALSE;
449 bMsgSink[ _ErrorLog ] = FALSE;
450 bMsgSink[ _TraceLog ] = TRUE;
451}
452
453
454virtual void LOG::vTrace( USHORT eventNum )
455/* Log the specified event. */
456{
457 //--- Output the string.
458 _ddputstring( eventNum, _apszMsgText[ eventNum ] );
459}
460
461
462virtual void LOG::vLog( USHORT eventNum, ... )
463/* Log the specified event, with data. */
464{
465 STACK_ADR Arg1Adr; // Points to the 1st of a variable number
466 // of arguments in the stack.
467 PUSHORT pEventNum;
468
469 //--- Get the stack address of the 1st argument following the error number.
470 pEventNum = (PUSHORT) &eventNum; // Adr of event num
471 ++pEventNum; // Advance ptr past 1st arg.
472 Arg1Adr.VoidPtr = (PVOID) pEventNum; // Adr of 1st after err num.
473
474 //--- Format the message and any of the data.
475 //### Should have check here for error number out of range.
476 _ddsprintf( _dd_BuildString, _apszMsgText[ eventNum ], Arg1Adr );
477
478 //--- Output the string.
479 _ddputstring( eventNum, _dd_BuildString );
480}
481
482
483PERFLOG::PERFLOG( USHORT DosTraceMajorCode, PSZ* apszMsgText ) :
484 LOG( DosTraceMajorCode, apszMsgText )
485{
486 bMsgSink[ _Display ] = FALSE;
487 bMsgSink[ _SerialLine ] = FALSE;
488 bMsgSink[ _ErrorLog ] = FALSE;
489 bMsgSink[ _TraceLog ] = TRUE;
490}
491
492virtual void PERFLOG::vTrace( USHORT eventNum )
493{
494 RDTSC_COUNT rdtsc_result; // Output from Pentium timing instruction.
495 rdtsc( &rdtsc_result );
496 if ( _CheckRing() )
497 DosSysTrace( _DosTraceMajorCode, sizeof(RDTSC_COUNT), eventNum, (PCHAR) &rdtsc_result);
498 else
499 DevHelp_RAS( _DosTraceMajorCode, eventNum, sizeof(RDTSC_COUNT), (PSZ) &rdtsc_result);
500}
501
502
503USHORT BINARYLOG::_ddsprintf ( PSZ pszOutString, PSZ pszFmtString, STACK_ADR Parm )
504/*
505; ddsprintf - "sprintf" function on a vbl number of arguments.
506;
507; pszOutString - Output string saved here.
508; pszFmtString - Input, Ascii string containing text and formating information.
509; Parm - Input, Address of the 1st of the variable number of arguments.
510;
511;Returns
512; USHORT nDataLen - lentgh of the data string that is saved in pszOutString
513;
514;Notes
515; This function needed to reverse the order of the args pushed on the stack.
516*/
517{
518 PSZ pStr = (PSZ) pszFmtString;
519 USHORT uStrLen = 0; // Total string length accumulated here.
520 USHORT nBytes; // Length of one data item saved here.
521 BOOL lFlag;
522
523 /*--- Find out how many bytes of log data have been pushed on
524 * the stack. Do this by walking formatting string and counting
525 * the number of bytes expected by the format control characters.
526 */
527 while ( *pStr ) {
528
529 /* ### FUTURE: Want to seek forward to '%' or '0'. Any quick way to do it? */
530
531 if (*pStr != '%') { // If not the start of a format directive,
532 ++pStr; // then continue to next byte.
533 continue;
534 }
535
536 nBytes = 0; // Not 0 indicates a recognized sequence.
537 lFlag = FALSE; // Set TRUE when "L" is present.
538 ++ pStr; // Advance past '%'
539 if (*pStr == '0') // Advance past '0'
540 ++pStr;
541 if (*pStr == 'l' || *pStr == 'L') {
542 ++pStr; // Advance past "L" if present.
543 lFlag = TRUE;
544 }
545
546 if (*pStr == 'b' || *pStr == 'B')
547 nBytes = 1;
548 else if (*pStr == 'd' || *pStr == 'D' || *pStr == 'x' || *pStr == 'X') {
549 if (lFlag)
550 nBytes = 4;
551 else
552 nBytes = 2;
553 }
554 else if (*pStr == 'q' || *pStr == 'Q')
555 nBytes = 8;
556
557 /* If we recognize the formatting command, then count the bytes,
558 * otherwise ignore this '%' directive and continue.
559 */
560 if (nBytes) {
561 _fmemcpy( (PVOID) pszOutString, Parm.VoidPtr, nBytes );
562//Rudi: stack is word-wise !
563 if( nBytes == 1 )
564 Parm.BytePtr += 2;
565 else
566 Parm.BytePtr += nBytes;
567
568 pszOutString += nBytes;
569 uStrLen += nBytes;
570 }
571
572 ++pStr;
573 }
574 return( uStrLen );
575}
576
577
578BINARYLOG::BINARYLOG( USHORT DosTraceMajorCode, PSZ* apszMsgText ) :
579 LOG( DosTraceMajorCode, apszMsgText )
580{
581 bMsgSink[ _Display ] = FALSE;
582 bMsgSink[ _SerialLine ] = FALSE;
583 bMsgSink[ _ErrorLog ] = FALSE;
584 bMsgSink[ _TraceLog ] = TRUE;
585}
586
587
588virtual void BINARYLOG::vTrace( USHORT eventNum )
589/* Log the specified trace point. */
590{
591 //--- Save the event in the system trace log.
592 if ( _CheckRing() )
593 DosSysTrace( _DosTraceMajorCode, 0, eventNum, (PCHAR) NULL );
594 else
595 DevHelp_RAS( _DosTraceMajorCode, eventNum, 0, (PSZ) NULL );
596}
597
598
599void BINARYLOG::vLog( USHORT eventNum, ... )
600/* Log the specified trace point, with data. */
601{
602 STACK_ADR pStack; // Points to the 1st of a variable number
603 // of arguments in the stack.
604 USHORT usLength; // Number of bytes to log.
605
606 //--- Get the stack address of the 1st argument following the event number.
607 pStack.WordPtr = (WORD*) &eventNum; // Adr of event num
608 ++pStack.WordPtr; // Advance ptr to 1st arg after event number.
609
610 //--- Invoke binary version of _ddsprintf() to get args into the right order.
611 usLength = _ddsprintf( _dd_BuildString, _apszMsgText[ eventNum ], pStack );
612
613 //--- Save data bytes in the System trace log and return.
614 if ( _CheckRing() )
615 DosSysTrace( _DosTraceMajorCode, usLength, eventNum, (PCHAR) _dd_BuildString );
616 else
617 DevHelp_RAS( _DosTraceMajorCode, eventNum, usLength, (PSZ) _dd_BuildString );
618}
Note: See TracBrowser for help on using the repository browser.