+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
+
+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 3 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, see <https://www.gnu.org/licenses/>.
+*/
#include <stdio.h>
#include <string.h>
+#include "config.h"
#include "serial.h"
#include "asmops.h"
+#include "intr.h"
+#include "panic.h"
#define UART1_BASE 0x3f8
#define UART2_BASE 0x2f8
#define BNEXT(x) (((x) + 1) & 0xff)
#define BEMPTY(b) (b##_ridx == b##_widx)
-/*
static int have_recv(int base);
-static void recv_intr(void);*/
+static void recv_intr();
static struct serial_port ports[2];
static int num_open;
static int uart_base[] = {UART1_BASE, UART2_BASE};
-/*static int uart_irq[] = {UART1_IRQ, UART2_IRQ};*/
+static int uart_irq[] = {UART1_IRQ, UART2_IRQ};
int ser_open(int pidx, int baud, unsigned int mode)
{
unsigned short div = 115200 / baud;
- int base; /*intr*/
+ int base, intr;
unsigned int fmt;
- /*int prev_if;*/
if(pidx < 0 || pidx > 1) {
printf("ser_open: invalid serial port: %d\n", pidx);
memset(ports + pidx, 0, sizeof ports[pidx]);
base = uart_base[pidx];
- /*intr = uart_irq[pidx] | 8;*/
+ intr = uart_irq[pidx];
if(mode & SER_8N2) {
fmt = COM_FMT_8N2;
fmt = COM_FMT_8N1;
}
- /*prev_if = disable_intr();*/
- /* TODO set interrupt handler */
- /* unmask the appropriate interrupt */
- /*outb(inb(PIC1_DATA_PORT) & ~(1 << uart_irq[pidx]), PIC1_DATA_PORT);*/
+ interrupt(IRQ_TO_INTR(uart_irq[pidx]), recv_intr);
outb(LCTL_DLAB, base + UART_LCTL);
outb(div & 0xff, base + UART_DIVLO);
outb(fmt, base + UART_LCTL); /* fmt should be LCTL_8N1, LCTL_8N2 etc */
outb(FIFO_ENABLE | FIFO_SEND_CLEAR | FIFO_RECV_CLEAR, base + UART_FIFO);
outb(MCTL_DTR | MCTL_RTS | MCTL_OUT2, base + UART_MCTL);
- /*outb(INTR_RECV, base + UART_INTR);
-
- restore_intr(prev_if);*/
+ outb(INTR_RECV, base + UART_INTR);
ports[pidx].base = base;
- /*ports[pidx].intr = intr;*/
+ ports[pidx].intr = intr;
ports[pidx].blocking = 1;
++num_open;
return pidx;
void ser_close(int fd)
{
if(--num_open == 0) {
- /*int prev_if = disable_intr();*/
- /*outb(0, ports[fd].base + UART_INTR);*/
+ outb(0, ports[fd].base + UART_INTR);
outb(0, ports[fd].base + UART_MCTL);
- /*restore_intr(prev_if);*/
}
ports[fd].base = 0;
void ser_putc(int fd, char c)
{
int base = ports[fd].base;
+
+ if(c == '\n') {
+ ser_putc(fd, '\r');
+ }
+
while(!can_send(fd));
- while((inb(base + UART_MSTAT) & MST_CTS) == 0);
+ /*while((inb(base + UART_MSTAT) & MST_CTS) == 0);*/
outb(c, base + UART_DATA);
}
return 0;
}
-#if 0
static int have_recv(int base)
{
unsigned short stat = inb(base + UART_LSTAT);
if(stat & LST_ERROR) {
- printf("serial receive error\n");
- panic();
+ panic("serial receive error\n");
}
return stat & LST_DRDY;
}
-static void __interrupt __far recv_intr()
+static void recv_intr()
{
int i, idreg, c;
while(have_recv(base)) {
c = inb(base + UART_DATA);
- p->inbuf[p->inbuf_widx] = inb(base + UART_DATA);
+#ifdef ENABLE_GDB_STUB
+ if(c == 3 && i == GDB_SERIAL_PORT) {
+ asm("int $3");
+ continue;
+ }
+#endif
+
+ p->inbuf[p->inbuf_widx] = c;
p->inbuf_widx = BNEXT(p->inbuf_widx);
if(p->inbuf_widx == p->inbuf_ridx) {
}
}
}
+}
- outb(OCW2_EOI, PIC1_CMD_PORT);
+#ifdef ENABLE_GDB_STUB
+void putDebugChar(int c)
+{
+ ser_putc(GDB_SERIAL_PORT, c);
+}
+
+int getDebugChar(void)
+{
+ return ser_getc(GDB_SERIAL_PORT);
}
#endif