149 lines
3.5 KiB
C
149 lines
3.5 KiB
C
#include "serialport.h"
|
|
#include "x86.h"
|
|
#include "tty.h"
|
|
#include "const.h"
|
|
#include "type.h"
|
|
#include "assert.h"
|
|
#include "stdio.h"
|
|
#include "memman.h"
|
|
|
|
|
|
void put_irq_handler(int irq, irq_handler handler);
|
|
void enable_irq(int irq);
|
|
static void serial_buf_push(NTTY* tty, u32 key);
|
|
|
|
void serial_handler(int irq) {
|
|
volatile char ch = read_serial();
|
|
// kprintf("[%d]", ch);
|
|
serial_buf_push(get_tty(2), ch);
|
|
}
|
|
|
|
void serial_tty_init_i(NTTY* tty) {
|
|
serial_buf* sp = (serial_buf*)tty->input_buf;
|
|
sp->buf = (void*)K_PHY2LIN(do_kmalloc(SERIAL_BUF_SIZE));
|
|
sp->head = sp->tail = sp->readable = sp->len = 0;
|
|
outb(PORT + 1, 0x01);
|
|
put_irq_handler(RS232_IRQ, serial_handler);
|
|
enable_irq(RS232_IRQ);
|
|
}
|
|
|
|
void serial_tty_init_o(NTTY* tty) {
|
|
// do nothing
|
|
}
|
|
|
|
#define NEXTKEY(x) NEXT(x, SERIAL_BUF_SIZE)
|
|
#define LASTKEY(x) LAST(x, SERIAL_BUF_SIZE)
|
|
|
|
static void serial_buf_push(NTTY* tty, u32 key) {
|
|
serial_buf* sp = (serial_buf*)tty->input_buf;
|
|
u8* buf = sp->buf;
|
|
switch (key)
|
|
{
|
|
case '\r':
|
|
case '\n': // escape ENTER
|
|
key = '\n';
|
|
buf[sp->tail] = '\n';
|
|
sp->len++;
|
|
sp->tail = NEXTKEY(sp->tail);
|
|
sp->readable = CYCLE_SUB(sp->head, sp->tail, SERIAL_BUF_SIZE);
|
|
serial_tty_rcevbuf(tty, '\n');
|
|
break;
|
|
case '\b': case 127:
|
|
key = '\b';
|
|
if (sp->len > sp->readable)
|
|
{
|
|
sp->len--;
|
|
sp->tail = LASTKEY(sp->tail);
|
|
serial_tty_rcevbuf(tty, '\b');
|
|
serial_tty_rcevbuf(tty, ' ');
|
|
serial_tty_rcevbuf(tty, '\b');
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if ((key & 0xff) == 0)
|
|
return;
|
|
if (sp->len == SERIAL_BUF_SIZE - 1)
|
|
return;
|
|
buf[sp->tail] = (u8)(key & 0xff);
|
|
sp->len++;
|
|
sp->tail = NEXTKEY(sp->tail);
|
|
serial_tty_rcevbuf(tty, key & 0xff);
|
|
break;
|
|
}
|
|
}
|
|
|
|
int serial_tty_read(NTTY* tty, char* buf, int nr) {
|
|
assert(tty->input_buf);
|
|
serial_buf *sp = (serial_buf *)tty->input_buf;
|
|
int i = 0;
|
|
while (1)
|
|
{
|
|
if (sp->readable)
|
|
{
|
|
disable_int();
|
|
break;
|
|
}
|
|
}
|
|
assert(sp->buf);
|
|
u8 *ibuf = sp->buf;
|
|
for (; i < nr && i < sp->readable; ++i)
|
|
{
|
|
*buf ++ = ibuf[sp->head];
|
|
sp->head = NEXTKEY(sp->head);
|
|
}
|
|
sp->readable -= i;
|
|
sp->len -= i;
|
|
enable_int();
|
|
return i;
|
|
}
|
|
|
|
void serial_tty_write(NTTY* tty, char ch) {
|
|
write_serial(ch);
|
|
}
|
|
|
|
void serial_tty_rcevbuf(NTTY* tty, char ch) {
|
|
serial_tty_write(tty, ch);
|
|
}
|
|
|
|
int init_serial() {
|
|
outb(PORT + 1, 0x00); // Disable all interrupts
|
|
outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
|
|
outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
|
|
outb(PORT + 1, 0x00); // (hi byte)
|
|
outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit
|
|
outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
|
outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
|
outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip
|
|
outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte)
|
|
|
|
// Check if serial is faulty (i.e: not same byte as sent)
|
|
if(inb(PORT + 0) != 0xAE) {
|
|
assert(0);
|
|
return 1;
|
|
}
|
|
|
|
// If serial is not faulty set it in normal operation mode
|
|
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
|
|
outb(PORT + 4, 0x0f);
|
|
return 0;
|
|
}
|
|
static inline int is_transmit_empty() {
|
|
return inb(PORT + 5) & 0x20;
|
|
}
|
|
|
|
static inline int serial_received() {
|
|
return inb(PORT + 5) & 1;
|
|
}
|
|
|
|
char read_serial() {
|
|
while (serial_received() == 0);
|
|
|
|
return inb(PORT);
|
|
}
|
|
|
|
void write_serial(char a) {
|
|
while (is_transmit_empty() == 0);
|
|
|
|
outb(PORT,a);
|
|
} |