Make serial devices more useful
They now use interrupts and thus can be blocked on without sitting in a busy loop. Not sure if they still work perfectly, need to debug. Works fine with the console "serial" stuff in qemu. Todo: Investigate further.
This commit is contained in:
parent
1e2ed1e89a
commit
8dfd4ff20a
@ -1,73 +0,0 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
*
|
||||
* Serial Port Driver
|
||||
*/
|
||||
#include <system.h>
|
||||
#include <logging.h>
|
||||
|
||||
#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]);
|
||||
}
|
||||
}
|
@ -6,30 +6,99 @@
|
||||
|
||||
#include <system.h>
|
||||
#include <fs.h>
|
||||
#include <pipe.h>
|
||||
#include <logging.h>
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user