source: cmedia/trunk/Drv16/log.cpp

Last change on this file was 553, checked in by rudi, 14 years ago

Adapt sourcecode to OpenWatcom

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
454void LOG::vTrace( USHORT eventNum )
455/* Log the specified event. */
456{
457 //--- Output the string.
458 _ddputstring( eventNum, _apszMsgText[ eventNum ] );
459}
460
461
462void 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
492void 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
588void 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.