#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); tty->recvbuf(tty, '\n'); break; case '\b': case 127: key = '\b'; if (sp->len > sp->readable) { sp->len--; sp->tail = LASTKEY(sp->tail); tty->recvbuf(tty, '\b'); tty->recvbuf(tty, ' '); tty->recvbuf(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); tty->recvbuf(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_recvbuf(NTTY* tty, u32 ch) { tty->write(tty, ch & 0xff); } 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); }