dos port underway
[retroray] / src / dos / logger.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdarg.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include "logger.h"
8 #include "util.h"
9
10 #ifdef __WATCOMC__
11 #include <i86.h>
12 #endif
13 #ifdef __DJGPP__
14 #include <pc.h>
15 #endif
16
17 void ser_putchar(int c);
18 void ser_puts(const char *s);
19 void ser_printf(const char *fmt, ...);
20
21 static int setup_serial(int sdev);
22
23 static int logfd = -1, orig_fd1 = -1;
24 static int log_isfile;
25
26 int init_logger(const char *fname)
27 {
28         int sdev;
29
30         if(logfd != -1) return -1;
31
32         log_isfile = 0;
33         if(strcasecmp(fname, "CON") == 0) {
34                 return 0;
35         }
36
37         if((logfd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1) {
38                 fprintf(stderr, "init_logger: failed to open %s: %s\n", fname, strerror(errno));
39                 return -1;
40         }
41
42         if(sscanf(fname, "COM%d", &sdev) == 1) {
43                 setup_serial(sdev - 1);
44         } else {
45                 log_isfile = 1;
46         }
47
48         orig_fd1 = dup(1);
49         close(1);
50         close(2);
51         dup(logfd);
52         dup(logfd);
53         return 0;
54 }
55
56 void stop_logger(void)
57 {
58         if(logfd >= 0) {
59                 close(logfd);
60                 logfd = -1;
61         }
62         if(orig_fd1 >= 0) {
63                 close(1);
64                 close(2);
65                 dup(orig_fd1);
66                 dup(orig_fd1);
67                 orig_fd1 = -1;
68
69                 freopen("CON", "w", stdout);
70                 freopen("CON", "w", stderr);
71         }
72 }
73
74 int print_tail(const char *fname)
75 {
76         FILE *fp;
77         char buf[512];
78         long lineoffs[16];
79         int c, nlines;
80
81         if(!log_isfile) return 0;
82
83         printf("demo_abort called. see demo.log for details. Last lines:\n\n");
84
85         if(!(fp = fopen(fname, "rb"))) {
86                 return -1;
87         }
88         nlines = 0;
89         lineoffs[nlines++] = 0;
90         while(fgets(buf, sizeof buf, fp)) {
91                 lineoffs[nlines & 0xf] = ftell(fp);
92                 nlines++;
93         }
94
95         if(nlines > 16) {
96                 long offs = lineoffs[nlines & 0xf];
97                 fseek(fp, offs, SEEK_SET);
98         }
99         while((c = fgetc(fp)) != -1) {
100                 fputc(c, stdout);
101         }
102         fclose(fp);
103         return 0;
104 }
105
106 #define UART1_BASE      0x3f8
107 #define UART2_BASE      0x2f8
108
109 #define UART_DATA       0
110 #define UART_DIVLO      0
111 #define UART_DIVHI      1
112 #define UART_FIFO       2
113 #define UART_LCTL       3
114 #define UART_MCTL       4
115 #define UART_LSTAT      5
116
117 #define DIV_9600                        (115200 / 9600)
118 #define DIV_38400                       (115200 / 38400)
119 #define LCTL_8N1                        0x03
120 #define LCTL_DLAB                       0x80
121 #define FIFO_ENABLE_CLEAR       0x07
122 #define MCTL_DTR_RTS_OUT2       0x0b
123 #define LST_TRIG_EMPTY          0x20
124
125 static unsigned int iobase;
126
127 static int setup_serial(int sdev)
128 {
129         if(sdev < 0 || sdev > 1) {
130                 return -1;
131         }
132         iobase = sdev == 0 ? UART1_BASE : UART2_BASE;
133
134         /* set clock divisor */
135         outp(iobase | UART_LCTL, LCTL_DLAB);
136         outp(iobase | UART_DIVLO, DIV_9600 & 0xff);
137         outp(iobase | UART_DIVHI, DIV_9600 >> 8);
138         /* set format 8n1 */
139         outp(iobase | UART_LCTL, LCTL_8N1);
140         /* assert RTS and DTR */
141         outp(iobase | UART_MCTL, MCTL_DTR_RTS_OUT2);
142         return 0;
143 }
144
145 void ser_putchar(int c)
146 {
147         if(c == '\n') {
148                 ser_putchar('\r');
149         }
150
151         while((inp(iobase | UART_LSTAT) & LST_TRIG_EMPTY) == 0);
152         outp(iobase | UART_DATA, c);
153 }
154
155 void ser_puts(const char *s)
156 {
157         while(*s) {
158                 ser_putchar(*s++);
159         }
160 }
161
162 void ser_printf(const char *fmt, ...)
163 {
164         va_list ap;
165         char buf[512];
166
167         va_start(ap, fmt);
168         vsprintf(buf, fmt, ap);
169         va_end(ap);
170
171         ser_puts(buf);
172 }