aboutsummaryrefslogtreecommitdiff
path: root/inc/dlog.h
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2026-10-26 00:50:06 +0100
committerJavier <dev.git@javispedro.com>2026-10-26 00:50:06 +0100
commit6b8a368c51082fdd010ef5e1b0be4eb9b5059d1a (patch)
treee274d41a8dd5e912e20617a937a1fda5af91f8de /inc/dlog.h
parent9b1cf601360fb194047e6dcc2af75c2f38c611ec (diff)
downloadchu-6b8a368c51082fdd010ef5e1b0be4eb9b5059d1a.tar.gz
chu-6b8a368c51082fdd010ef5e1b0be4eb9b5059d1a.zip
refactor common parts into inc/ch375.h and add win9x, linux drivers
Diffstat (limited to 'inc/dlog.h')
-rw-r--r--inc/dlog.h439
1 files changed, 439 insertions, 0 deletions
diff --git a/inc/dlog.h b/inc/dlog.h
new file mode 100644
index 0000000..ab6f4e9
--- /dev/null
+++ b/inc/dlog.h
@@ -0,0 +1,439 @@
+/*
+ * VBMouse - printf & logging routines
+ * Copyright (C) 2022 Javier S. Pedro
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef DLOG_H
+#define DLOG_H
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <i86.h>
+#include <conio.h>
+
+// Customizable defines
+/** If 0, these routines become nops */
+#ifndef ENABLE_DLOG
+#define ENABLE_DLOG 0
+#endif
+/** Target of logging messages. See DLOG_TARGET_* below. */
+#ifndef DLOG_TARGET
+#define DLOG_TARGET DLOG_TARGET_UNDEF
+#endif
+/** When using DLOG_TARGET_IOPORT, which IO port to target.
+ * VirtualBox uses 0x504, Bochs, DOSBox and descendants use 0xE9.
+ * When using DLOG_TARGET_SERIAL, the desired UART IO base port. (e.g. COM1 = 0x3F8). */
+#ifndef DLOG_TARGET_PORT
+#define DLOG_TARGET_PORT 0x504
+#endif
+
+// End of customizable defines
+
+/** You provide your own dlog_init and dputc routines. */
+#define DLOG_TARGET_UNDEF 0
+/** Output to the screen using BIOS TTY interface. */
+#define DLOG_TARGET_BIOSTTY 1
+/** Output to a serial port. UART io base defined in DLOG_TARGET_PORT. */
+#define DLOG_TARGET_SERIAL 2
+/** Output to a raw IO port defined in DLOG_TARGET_PORT.*/
+#define DLOG_TARGET_IOPORT 3
+
+#if ENABLE_DLOG
+
+/** Initializes the debug log port. */
+static void dlog_init();
+
+/** Logs a single character to the debug message IO port. */
+static inline void dputc(char c);
+
+#if DLOG_TARGET == DLOG_TARGET_BIOSTTY
+
+static inline void dlog_init()
+{
+ // No initialization required
+}
+
+static inline void dconputc(char c);
+#pragma aux dconputc = \
+ "mov ah, 0x0E" \
+ "xor bx, bx" \
+ "int 0x10" \
+ __parm [AL] \
+ __modify __exact [AH AL BH BL];
+
+static inline void dputc(char c)
+{
+ // Need to convert CR into CRLF...
+ if (c == '\n') {
+ dconputc('\n');
+ dconputc('\r');
+ } else {
+ dconputc(c);
+ }
+}
+
+
+#elif DLOG_TARGET == DLOG_TARGET_SERIAL
+
+static void dlog_init()
+{
+ // Comes from https://wiki.osdev.org/Serial_Ports#Initialization
+ outp(DLOG_TARGET_PORT + 1, 0x00); // Disable all interrupts
+ outp(DLOG_TARGET_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
+ outp(DLOG_TARGET_PORT + 0, 0x01); // Set divisor to 1 (lo byte) 115200 baud
+ outp(DLOG_TARGET_PORT + 1, 0x00); // (hi byte)
+ outp(DLOG_TARGET_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
+ outp(DLOG_TARGET_PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
+ outp(DLOG_TARGET_PORT + 4, 0x03); // RTS/DSR set, IRQs disabled
+}
+
+static inline void dputc(char c)
+{
+ while (!(inp(DLOG_TARGET_PORT + 5) & 0x20));
+ outp(DLOG_TARGET_PORT, c);
+}
+
+#elif DLOG_TARGET == DLOG_TARGET_IOPORT
+
+static inline void dlog_init()
+{
+ // No initialization required
+}
+
+static inline void dputc(char c)
+{
+ outp(DLOG_TARGET_PORT, c);
+}
+
+#endif /* DLOG_TARGET */
+
+static void d_utoa(unsigned num, unsigned base)
+{
+#if UINT_MAX > 99999
+ char buf[12];
+#else
+ char buf[6];
+#endif
+ int i = 0;
+
+ do {
+ unsigned digit = num % base;
+
+ if (digit < 10) {
+ buf[i] = '0' + digit;
+ } else {
+ buf[i] = 'a' + (digit - 10);
+ }
+
+ i++;
+ num /= base;
+ } while (num > 0 && i < sizeof(buf));
+
+ while (i--) {
+ dputc(buf[i]);
+ }
+}
+
+static void d_ultoa(unsigned long num, unsigned base)
+{
+ char buf[12];
+ int i = 0;
+
+ do {
+ unsigned digit = 0;
+
+ // Do unsigned long division with remained on whichever platform we are
+ static inline void uldiv(void);
+#if M_I86
+ // 16-bit code
+ #if _M_IX86 >= 300
+ // 16-bit compiler, but for running on 386+: preserve 32-bit regs and use them.
+ #pragma aux uldiv = \
+ "push eax" /* save 32-bit regs, compiler does not know about them*/ \
+ "push ecx" \
+ "push edx" \
+ "mov eax, [num]" \
+ "movzx ecx, [base]" \
+ "xor edx, edx" \
+ \
+ "div ecx" \
+ \
+ "mov [num], eax" \
+ "mov [digit], dx" \
+ \
+ "pop edx" \
+ "pop ecx" \
+ "pop eax" \
+ __modify __exact [];
+ #else
+ // 16-bit compiler, 16-bit code: 16-bit division
+ #pragma aux uldiv = \
+ "mov cx, word ptr [num]" \
+ "mov ax, word ptr [num+2]" \
+ "mov bx, [base]" \
+ "xor dx, dx" \
+ \
+ "div bx" /* ax = HI(num)/base -> HI quotient, dx = HI(num)%base -> HI remainder */ \
+ "xchg ax,cx" /* cx = HI(num)/base, ax = LO(num) */ \
+ "div bx" /* ax = (HI(num)%base)/base -> true quotient , dx = (HI(num)%base)%base -> true remainder */ \
+ \
+ "mov word ptr [num], ax" \
+ "mov word ptr [num+2], cx" \
+ "mov [digit], dx" \
+ __modify __exact [];
+ #endif
+#elif M_I386
+ // 32-bit compiler, 32-bit code
+ #pragma aux uldiv = \
+ "mov eax, [num]" \
+ "mov ecx, [base]" \
+ "xor edx, edx" \
+ \
+ "div ecx" \
+ \
+ "mov [num], eax" \
+ "mov [digit], edx" \
+ __modify __exact [eax ecx edx];
+#else
+ #error unknown platform
+#endif
+ uldiv();
+
+ if (digit < 10) {
+ buf[i] = '0' + digit;
+ } else {
+ buf[i] = 'a' + (digit - 10);
+ }
+
+ i++;
+ } while (num > 0 && i < sizeof(buf));
+
+ while (i--) {
+ dputc(buf[i]);
+ }
+}
+
+static void d_itoa(int num, unsigned base)
+{
+ unsigned unum;
+
+ if (num < 0) {
+ dputc('-');
+ unum = -num;
+ } else {
+ unum = num;
+ }
+
+ d_utoa(unum, base);
+}
+
+static void d_ltoa(long num, unsigned base)
+{
+ unsigned long unum;
+
+ if (num < 0) {
+ dputc('-');
+ unum = -num;
+ } else {
+ unum = num;
+ }
+
+ d_ultoa(unum, base);
+}
+
+static unsigned d_strtou(const char * __far *str)
+{
+ unsigned i = 0;
+ const char *s = *str;
+ char c = *s;
+ while (c >= '0' && c <= '9') {
+ i = (i * 10) + (c - '0');
+ c = *(++s);
+ }
+ *str = s;
+ return i;
+}
+
+static void d_printstr(const char __far *s, unsigned l)
+{
+ while (l > 0 && *s) {
+ dputc(*s++);
+ l--;
+ }
+}
+
+static void dprintf(const char *fmt, ...)
+{
+ va_list va;
+ char c;
+
+ va_start(va, fmt);
+
+ while ((c = *(fmt++))) {
+ if (c == '%') {
+ unsigned width, precision, size;
+ bool is_far = false;
+
+ width = d_strtou(&fmt);
+
+ if ((c = *fmt) == '.') {
+ fmt++;
+ precision = d_strtou(&fmt);
+ } else {
+ precision = UINT_MAX;
+ }
+
+ switch ((c = *fmt)) {
+ case 'l':
+ size = sizeof(long);
+ fmt++;
+ break;
+ case 'h':
+ size = sizeof(short);
+ fmt++;
+ break;
+ case 'F':
+ is_far = true;
+ fmt++;
+ break;
+ default:
+ size = sizeof(int);
+ break;
+ }
+
+ switch ((c = *fmt)) {
+ case 'd':
+ switch (size) {
+#if INT_MAX != SHRT_MAX
+ case sizeof(short):
+ d_itoa(va_arg(va, short), 10);
+ break;
+#endif
+ case sizeof(int):
+ d_itoa(va_arg(va, int), 10);
+ break;
+#if INT_MAX != LONG_MAX
+ case sizeof(long):
+ d_ltoa(va_arg(va, long), 10);
+ break;
+#endif
+ }
+ break;
+ case 'u':
+ switch (size) {
+#if INT_MAX != SHRT_MAX
+ case sizeof(short):
+ d_utoa(va_arg(va, unsigned short), 10);
+ break;
+#endif
+ case sizeof(int):
+ d_utoa(va_arg(va, unsigned int), 10);
+ break;
+#if INT_MAX != LONG_MAX
+ case sizeof(long):
+ d_ultoa(va_arg(va, unsigned long), 10);
+ break;
+#endif
+ }
+ break;
+ case 'x':
+ switch (size) {
+#if INT_MAX != SHRT_MAX
+ case sizeof(short):
+ d_utoa(va_arg(va, unsigned short), 16);
+ break;
+#endif
+ case sizeof(int):
+ d_utoa(va_arg(va, unsigned int), 16);
+ break;
+#if INT_MAX != LONG_MAX
+ case sizeof(long):
+ d_ultoa(va_arg(va, unsigned long), 16);
+ break;
+#endif
+ }
+ break;
+ case 'b':
+ switch (size) {
+#if INT_MAX != SHRT_MAX
+ case sizeof(short):
+ d_utoa(va_arg(va, unsigned short), 2);
+ break;
+#endif
+ case sizeof(int):
+ d_utoa(va_arg(va, unsigned int), 2);
+ break;
+#if INT_MAX != LONG_MAX
+ case sizeof(long):
+ d_ultoa(va_arg(va, long), 2);
+ break;
+#endif
+ }
+ break;
+ case 'p':
+ if (is_far) {
+ void __far *p = va_arg(va, void __far *);
+ d_utoa(FP_SEG(p), 16);
+ dputc(':');
+ d_utoa(FP_OFF(p), 16);
+ } else {
+ d_utoa((unsigned) va_arg(va, void*), 16);
+ }
+ break;
+ case 's':
+ d_printstr(is_far ? va_arg(va, const char __far *)
+ : va_arg(va, const char *),
+ precision);
+ break;
+ case 'c':
+ dputc(va_arg(va, char));
+ break;
+ case '%':
+ dputc('%');
+ break;
+ }
+ fmt++;
+ } else {
+ dputc(c);
+ }
+ }
+
+ va_end(va);
+}
+
+static void dputs(const char *s)
+{
+ char c;
+ while ((c = *(s++))) {
+ dputc(c);
+ }
+ dputc('\n');
+}
+
+#else /* ENABLE_DLOG */
+
+#define dlog_nop() do { } while(0)
+#define dlog_init() dlog_nop()
+#define dputc(c) dlog_nop()
+#define dputs(s) dlog_nop()
+#define dprintf(...) dlog_nop()
+
+
+#endif /* ENABLE_DLOG */
+
+#endif /* DLOG_H */