summaryrefslogtreecommitdiff
path: root/src/kernel/klog.c
blob: 431c09bb5fcd669387f64c6613c4976acd824e73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#include <stdint.h>
#include <io.h>
#include <printf.h>
#include <addr.h>
#include <stdbool.h>
#include <libc.h>
#include <klog.h>

//right now, this program is simply for debuging.
//Later in development, we will hook it up to a TTY, impliment FCS, etc

#define VIDEO_BUFFER PHYS_TO_VIRT(0xb8000)
#define MAX_LOOPBACK_ATTEMPTS 20

#define KLOG_COM1     0
#define KLOG_COM2     1
#define KLOG_COM3     2
#define KLOG_COM4     3
#define KLOG_SCREEN   4

static int debug_output = KLOG_SCREEN;

#define SERIAL_THR                0   //transmitter holding buffer
#define SERIAL_RBR                1   //receiving holding buffer
#define SERIAL_DLL                0   //divisor latch low byte
#define SERIAL_DLH                1   //divisor latch high byte
#define SERIAL_FCR                2
#define SERIAL_IIR                2
#define SERIAL_LCR                3
#define SERIAL_MCR                4
#define SERIAL_LSR                5
#define SERIAL_MSR                6
#define SERIAL_SR                 7

#define COM1 0x3f8
#define COM2 0x2f8
#define COM3 0x3e8
#define COM4 0x2e8

uint16_t serial_ports[4] = {COM1, COM2, COM3, COM4};

/**
enum com_ports {
  COM1 = 0x3f8,
  COM2 = 0x2f8,
  COM3 = 0x3e8,
  COM4 = 0x2e8
};
**/


static bool detect_serial(uint16_t port) {
  outb(port + SERIAL_FCR, 0xe7);
  outb(port + SERIAL_SR, 0xba);
  if((inb(port + SERIAL_IIR) & (1 << 6)) && (inb(port + SERIAL_SR) == 0xba)) {
    outb_wait(port + 1, 0x00); 
    outb_wait(port + 2, 0x00); 
    outb_wait(port + 3, 0x80); 
    outb_wait(port + 0, 0x01);
    outb_wait(port + 1, 0x00);
    outb_wait(port + 3, 0x03); 
    outb_wait(port + 2, 0xc7); 
    outb_wait(port + 4, 0x0b); 
    outb_wait(port + 4, 0x1e); 


    uint8_t loopback_byte;
    for(int attempts = 0; attempts < MAX_LOOPBACK_ATTEMPTS; attempts++) {
      outb_wait(port + 0, 0xae);
      loopback_byte = inb(port);
      if(loopback_byte == 0xae) break;
    }

    if(loopback_byte != 0xae) {
      //you better delete this once you get tty drivers working...
      int a = 0 / 0;
    }
    
    outb_wait(port + 4, 0x0f); 
    return true;
  }
  return false;
}


//this function is going to be teleted after ttys work.
//but, for now, if a serial port is detected, it'll set debug_output to 0-3 (com port #).
//debug_output == 4 is for screen output.
void init_klog() {
  for(unsigned int p = 0; p < (sizeof(serial_ports) / sizeof(uint16_t)); p++) {
    if(detect_serial(serial_ports[p])) {
      debug_output = p;
      return;
    }
  }
  debug_output = KLOG_SCREEN;
  _putchar('\n');
}



void _putchar_serial(uint16_t port, char msg) {
  while(!(inb(port + 5) & 0x20)); //wait for transmit to be done
  outb_wait(port, msg);
}

static unsigned int on_char = 0;
static unsigned int on_line = 0;


void clear_screen() {
  on_char = 0;
  on_line = 0;
  char *screen_buffer = (void *)VIDEO_BUFFER;
  for(unsigned int i = 0; i <= (80 * 25); i++) screen_buffer[i * 2] = ' ';
} 

void next_line() {
  if(on_line >= 25) {
    on_line = 0;
    clear_screen();
  }
  else {
    on_line++;
  }
  on_char = 0;
}

void move_cursor(unsigned int x, unsigned int y) {
  on_char = x;
  on_line = y;
}

void _putchar_screen(char msg) {
  if(on_char >= 80) {
    next_line();
  } else if(msg == '\n') {
    next_line();
    return;
  }
  *(char *)((uint64_t)VIDEO_BUFFER + ((on_line * 160) + (on_char * 2))) = msg;
  on_char++;
}



void _putchar(char character) {
  if(debug_output < (sizeof(serial_ports) / sizeof(uint16_t))) {
    _putchar_serial(serial_ports[debug_output], character); 
  }
  else {
    _putchar_screen(character);
  }
}




/**
 * Set the value "0xE7" to the FCR to test the status of the FIFO flags.
Read the value of the IIR to test for what flags actually got set.
If Bit 6 is set Then
  If Bit 7 is set Then
    If Bit 5 is set Then
      UART is 16750 (64 bit fifo)
    Else
      UART is 16550A (idk why this matters, 16 bit fifo)
    End If
  Else
    UART is 16550 (16 bit fifo)
  End If
Else you know the chip doesn't use FIFO, so we need to check the scratch register
  Set some arbitrary value like 0x2A to the Scratch Register.
  If the arbitrary value comes back identical
    UART is 16450 (idk why this matters, 1 byte at a time)
  Else
    UART is 8250 (one byte at a time)
  End If
End If

#define UART_16750    0
#define UART_16550A   1
#define UART_16550    2
#define UART_16450    3
#define UART_8250     4

#define KLOG_COM1     0
#define KLOG_COM2     1
#define KLOG_COM3     2
#define KLOG_COM4     3
#define KLOG_SCREEN   4 * 5 // 5 leaves enough space for com ports
**/