diff --git a/kernel/devices/serial.c b/kernel/devices/serial.c deleted file mode 100644 index dff6bbb8..00000000 --- a/kernel/devices/serial.c +++ /dev/null @@ -1,73 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * - * Serial Port Driver - */ -#include -#include - -#if 0 -void serial_handler_a(struct regs *r) { - char serial = serial_recv(SERIAL_PORT_A); - irq_ack(SERIAL_IRQ); - if (serial == 13) serial = '\n'; - kprintf("%c", serial); - serial_send(SERIAL_PORT_B, serial); -} -void serial_handler_b(struct regs *r) { - char serial = serial_recv(SERIAL_PORT_B); - irq_ack(SERIAL_IRQ - 1); - serial_send(SERIAL_PORT_A, serial); -} -#endif - -void serial_enable(int device) { - outportb(device + 1, 0x00); - outportb(device + 3, 0x80); /* Enable divisor mode */ - outportb(device + 0, 0x01); /* Div Low: 01 Set the port to 115200 bps */ - outportb(device + 1, 0x00); /* Div High: 00 */ - outportb(device + 3, 0x03); - outportb(device + 2, 0xC7); - outportb(device + 4, 0x0B); -} - -void serial_install(void) { - debug_print(NOTICE, "Installing serial communication driver"); - - serial_enable(SERIAL_PORT_A); - serial_enable(SERIAL_PORT_B); - -#if 0 - irq_install_handler(SERIAL_IRQ, serial_handler_a); /* Install the serial input handler */ - irq_install_handler(SERIAL_IRQ - 1, serial_handler_b); /* Install the serial input handler */ - outportb(SERIAL_PORT_A + 1, 0x01); /* Enable interrupts on receive */ - outportb(SERIAL_PORT_B + 1, 0x01); /* Enable interrupts on receive */ -#endif -} - -int serial_rcvd(int device) { - return inportb(device + 5) & 1; -} - -char serial_recv(int device) { - while (serial_rcvd(device) == 0) ; - return inportb(device); -} - -char serial_recv_async(int device) { - return inportb(device); -} - -int serial_transmit_empty(int device) { - return inportb(device + 5) & 0x20; -} - -void serial_send(int device, char out) { - while (serial_transmit_empty(device) == 0); - outportb(device, out); -} - -void serial_string(int device, char * out) { - for (uint32_t i = 0; i < strlen(out); ++i) { - serial_send(device, out[i]); - } -} diff --git a/kernel/fs/serialdev.c b/kernel/fs/serialdev.c index c47b61b7..c62264aa 100644 --- a/kernel/fs/serialdev.c +++ b/kernel/fs/serialdev.c @@ -6,30 +6,99 @@ #include #include +#include #include +fs_node_t * _serial_port_a = NULL; +fs_node_t * _serial_port_b = NULL; +fs_node_t * _serial_port_c = NULL; +fs_node_t * _serial_port_d = NULL; + +fs_node_t ** pipe_for_port(int port) { + switch (port) { + case SERIAL_PORT_A: return &_serial_port_a; + case SERIAL_PORT_B: return &_serial_port_b; + case SERIAL_PORT_C: return &_serial_port_c; + case SERIAL_PORT_D: return &_serial_port_d; + } + return NULL; +} + +void serial_handler_ac(struct regs *r) { + char serial; + int port = 0; + if (inportb(SERIAL_PORT_A+1) & 0x01) { + port = SERIAL_PORT_A; + } else { + port = SERIAL_PORT_C; + } + serial = serial_recv(port); + irq_ack(SERIAL_IRQ_AC); + uint8_t buf[] = {serial, 0}; + write_fs(*pipe_for_port(port), 0, 1, buf); +} + +void serial_handler_bd(struct regs *r) { + char serial; + int port = 0; + debug_print(NOTICE, "Received something on secondary port"); + if (inportb(SERIAL_PORT_B+1) & 0x01) { + port = SERIAL_PORT_B; + } else { + port = SERIAL_PORT_D; + } + serial = serial_recv(port); + irq_ack(SERIAL_IRQ_BD); + uint8_t buf[] = {serial, 0}; + write_fs(*pipe_for_port(port), 0, 1, buf); +} + +void serial_enable(int port) { + outportb(port + 1, 0x00); /* Disable interrupts */ + outportb(port + 3, 0x80); /* Enable divisor mode */ + outportb(port + 0, 0x01); /* Div Low: 01 Set the port to 115200 bps */ + outportb(port + 1, 0x00); /* Div High: 00 */ + outportb(port + 3, 0x03); /* Disable divisor mode, set parity */ + outportb(port + 2, 0xC7); /* Enable FIFO and clear */ + outportb(port + 4, 0x0B); /* Enable interrupts */ + outportb(port + 1, 0x01); /* Enable interrupts */ +} + +int serial_rcvd(int device) { + return inportb(device + 5) & 1; +} + +char serial_recv(int device) { + while (serial_rcvd(device) == 0) ; + return inportb(device); +} + +char serial_recv_async(int device) { + return inportb(device); +} + +int serial_transmit_empty(int device) { + return inportb(device + 5) & 0x20; +} + +void serial_send(int device, char out) { + while (serial_transmit_empty(device) == 0); + outportb(device, out); +} + +void serial_string(int device, char * out) { + for (uint32_t i = 0; i < strlen(out); ++i) { + serial_send(device, out[i]); + } +} + uint32_t read_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); uint32_t write_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); void open_serial(fs_node_t *node, unsigned int flags); void close_serial(fs_node_t *node); uint32_t read_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { - if (size < 1) { - return 0; - } - memset(buffer, 0x00, 1); - uint32_t collected = 0; - while (collected < size) { - while (!serial_rcvd((int)node->device)) { - switch_task(1); - } -#if 0 - debug_print(NOTICE, "Data received from TTY, have %d, need %d", collected+1, size); -#endif - buffer[collected] = serial_recv((int)node->device); - collected++; - } - return collected; + return read_fs(*pipe_for_port((int)node->device), offset, size, buffer); } uint32_t write_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { @@ -69,6 +138,16 @@ fs_node_t * serial_device_create(int device) { fnode->mtime = fnode->atime; fnode->ctime = fnode->atime; + serial_enable(device); + + if (device == SERIAL_PORT_A || device == SERIAL_PORT_C) { + irq_install_handler(SERIAL_IRQ_AC, serial_handler_ac); + } else { + irq_install_handler(SERIAL_IRQ_BD, serial_handler_bd); + } + + *pipe_for_port(device) = make_pipe(128); + return fnode; } @@ -85,5 +164,4 @@ void serial_mount_devices(void) { fs_node_t * ttyS3 = serial_device_create(SERIAL_PORT_D); vfs_mount("/dev/ttyS3", ttyS3); - } diff --git a/kernel/include/system.h b/kernel/include/system.h index 9517e3bd..9386b86b 100644 --- a/kernel/include/system.h +++ b/kernel/include/system.h @@ -224,7 +224,8 @@ extern void start_shell(void); #define SERIAL_PORT_C 0x3E8 #define SERIAL_PORT_D 0x2E8 -#define SERIAL_IRQ 4 +#define SERIAL_IRQ_AC 4 +#define SERIAL_IRQ_BD 3 extern void serial_install(void); extern int serial_rcvd(int device); diff --git a/kernel/main.c b/kernel/main.c index b96a648c..50b04fbc 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -119,7 +119,6 @@ int main(struct multiboot *mboot, uint32_t mboot_mag, uintptr_t esp) { /* Hardware drivers */ timer_install(); /* PIC driver */ - serial_install(); /* Serial console */ tasking_install(); /* Multi-tasking */ auto_fpu();