Browse Source

serial: new direct tty serial driver

K. Lange 3 years ago
parent
commit
81ba10fe3f
4 changed files with 87 additions and 158 deletions
  1. 16 48
      apps/getty.c
  2. 3 0
      base/usr/include/kernel/pty.h
  3. 8 4
      kernel/fs/tty.c
  4. 60 106
      modules/serial.c

+ 16 - 48
apps/getty.c

@@ -17,7 +17,7 @@
 #include <sys/fswait.h>
 
 int main(int argc, char * argv[]) {
-	int fd_master, fd_slave, fd_serial;
+	int fd_serial;
 	char * file = "/dev/ttyS0";
 	char * user = NULL;
 
@@ -39,59 +39,27 @@ int main(int argc, char * argv[]) {
 		file = argv[optind];
 	}
 
-	openpty(&fd_master, &fd_slave, NULL, NULL, NULL);
 	fd_serial = open(file, O_RDWR);
 
-	pid_t child = fork();
-
-	if (!child) {
-		setsid();
-		dup2(fd_slave, 0);
-		dup2(fd_slave, 1);
-		dup2(fd_slave, 2);
-
-		system("ttysize -q");
-
-		char * tokens[] = {"/bin/login",NULL,NULL,NULL};
-
-		if (user) {
-			tokens[1] = "-f";
-			tokens[2] = user;
-		}
-
-		execvp(tokens[0], tokens);
-		exit(1);
-	} else {
+	if (fd_serial < 0) {
+		perror("open");
+		return 1;
+	}
 
-		int fds[2] = {fd_serial, fd_master};
+	setsid();
+	dup2(fd_serial, 0);
+	dup2(fd_serial, 1);
+	dup2(fd_serial, 2);
 
-		while (1) {
-			int index = fswait2(2,fds,200);
-			char buf[1024];
-			int r;
-			switch (index) {
-				case 0: /* fd_serial */
-					r = read(fd_serial, buf, 1);
-					write(fd_master, buf, 1);
-					break;
-				case 1: /* fd_master */
-					r = read(fd_master, buf, 1024);
-					write(fd_serial, buf, r);
-					break;
-				default: /* timeout */
-					{
-						int result = waitpid(child, NULL, WNOHANG);
-						if (result > 0) {
-							/* Child login shell has returned (session ended) */
-							return 0;
-						}
-					}
-					break;
-			}
+	system("ttysize -q");
 
-		}
+	char * tokens[] = {"/bin/login",NULL,NULL,NULL};
 
+	if (user) {
+		tokens[1] = "-f";
+		tokens[2] = user;
 	}
 
-	return 0;
+	execvp(tokens[0], tokens);
+	exit(1);
 }

+ 3 - 0
base/usr/include/kernel/pty.h

@@ -35,8 +35,11 @@ typedef struct pty {
 
 	int next_is_verbatim;
 
+	void (*fill_name)(struct pty *, char *);
+
 } pty_t;
 
 void tty_output_process_slave(pty_t * pty, uint8_t c);
 void tty_output_process(pty_t * pty, uint8_t c);
 void tty_input_process(pty_t * pty, uint8_t c);
+pty_t * pty_new(struct winsize * size);

+ 8 - 4
kernel/fs/tty.c

@@ -74,7 +74,6 @@ void tty_output_process_slave(pty_t * pty, uint8_t c) {
 }
 
 void tty_output_process(pty_t * pty, uint8_t c) {
-	if (ring_buffer_available(pty->out) < 2) return; /* uh oh */
 	output_process_slave(pty, c);
 }
 
@@ -245,6 +244,11 @@ void tty_input_process(pty_t * pty, uint8_t c) {
 	IN(c);
 }
 
+static void tty_fill_name(pty_t * pty, char * out) {
+	((char*)out)[0] = '\0';
+	sprintf((char*)out, "/dev/pts/%d", pty->name);
+}
+
 int pty_ioctl(pty_t * pty, int request, void * argp) {
 	switch (request) {
 		case IOCTLDTYPE:
@@ -258,8 +262,7 @@ int pty_ioctl(pty_t * pty, int request, void * argp) {
 		case IOCTLTTYNAME:
 			if (!argp) return -EINVAL;
 			validate(argp);
-			((char*)argp)[0] = '\0';
-			sprintf((char*)argp, "/dev/pts/%d", pty->name);
+			pty->fill_name(pty, argp);
 			return 0;
 		case IOCTLTTYLOGIN:
 			/* Set the user id of the login user */
@@ -501,7 +504,7 @@ static int readlink_dev_tty(fs_node_t * node, char * buf, size_t size) {
 	if (!pty) {
 		sprintf(tmp, "/dev/null");
 	} else {
-		sprintf(tmp, "/dev/pts/%d", pty->name);
+		pty->fill_name(pty, tmp);
 	}
 
 	req = strlen(tmp) + 1;
@@ -655,6 +658,7 @@ pty_t * pty_new(struct winsize * size) {
 
 	/* tty name */
 	pty->name   = _pty_counter++;
+	pty->fill_name = tty_fill_name;
 
 	pty->write_in = pty_write_in;
 	pty->write_out = pty_write_out;

+ 60 - 106
modules/serial.c

@@ -13,6 +13,8 @@
 #include <kernel/logging.h>
 #include <kernel/args.h>
 #include <kernel/module.h>
+#include <kernel/pty.h>
+#include <kernel/printf.h>
 
 #define SERIAL_PORT_A 0x3F8
 #define SERIAL_PORT_B 0x2F8
@@ -22,23 +24,39 @@
 #define SERIAL_IRQ_AC 4
 #define SERIAL_IRQ_BD 3
 
-static char serial_recv(int device);
+static pty_t * _serial_port_pty_a = NULL;
+static pty_t * _serial_port_pty_b = NULL;
+static pty_t * _serial_port_pty_c = NULL;
+static pty_t * _serial_port_pty_d = NULL;
 
-static fs_node_t * _serial_port_a = NULL;
-static fs_node_t * _serial_port_b = NULL;
-static fs_node_t * _serial_port_c = NULL;
-static fs_node_t * _serial_port_d = NULL;
-
-static fs_node_t ** pipe_for_port(int port) {
+static pty_t ** pty_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;
+		case SERIAL_PORT_A: return &_serial_port_pty_a;
+		case SERIAL_PORT_B: return &_serial_port_pty_b;
+		case SERIAL_PORT_C: return &_serial_port_pty_c;
+		case SERIAL_PORT_D: return &_serial_port_pty_d;
 	}
 	__builtin_unreachable();
 }
 
+static int serial_rcvd(int device) {
+	return inportb(device + 5) & 1;
+}
+
+static char serial_recv(int device) {
+	while (serial_rcvd(device) == 0) ;
+	return inportb(device);
+}
+
+static int serial_transmit_empty(int device) {
+	return inportb(device + 5) & 0x20;
+}
+
+static void serial_send(int device, char out) {
+	while (serial_transmit_empty(device) == 0);
+	outportb(device, out);
+}
+
 static int serial_handler_ac(struct regs *r) {
 	char serial;
 	int  port = 0;
@@ -49,7 +67,7 @@ static int serial_handler_ac(struct regs *r) {
 	}
 	serial = serial_recv(port);
 	irq_ack(SERIAL_IRQ_AC);
-	write_fs(*pipe_for_port(port), 0, 1, (uint8_t*)&serial);
+	tty_input_process(*pty_for_port(port), serial);
 	return 1;
 }
 
@@ -64,7 +82,7 @@ static int serial_handler_bd(struct regs *r) {
 	}
 	serial = serial_recv(port);
 	irq_ack(SERIAL_IRQ_BD);
-	write_fs(*pipe_for_port(port), 0, 1, (uint8_t*)&serial);
+	tty_input_process(*pty_for_port(port), serial);
 	return 1;
 }
 
@@ -79,93 +97,38 @@ static void serial_enable(int port) {
 	outportb(port + 1, 0x01); /* Enable interrupts */
 }
 
-static int serial_rcvd(int device) {
-	return inportb(device + 5) & 1;
-}
-
-static char serial_recv(int device) {
-	while (serial_rcvd(device) == 0) ;
-	return inportb(device);
-}
-
-static int serial_transmit_empty(int device) {
-	return inportb(device + 5) & 0x20;
-}
-
-static void serial_send(int device, char out) {
-	while (serial_transmit_empty(device) == 0);
-	outportb(device, out);
-}
-
-static void serial_string(char * out) {
-	for (uint32_t i = 0; i < strlen(out); ++i) {
-		serial_send(SERIAL_PORT_A, out[i]);
-	}
-}
-
-static uint32_t read_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer);
-static uint32_t write_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer);
-static void open_serial(fs_node_t *node, unsigned int flags);
-static void close_serial(fs_node_t *node);
-
-static uint32_t read_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
-	return read_fs(*pipe_for_port((int)node->device), offset, size, buffer);
-}
+static int have_installed_ac = 0;
+static int have_installed_bd = 0;
 
-static uint32_t write_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
-	uint32_t sent = 0;
-	while (sent < size) {
-		serial_send((int)node->device, buffer[sent]);
-		sent++;
-	}
-	return size;
+static void serial_write_out(pty_t * pty, uint8_t c) {
+	if (pty == _serial_port_pty_a) serial_send(SERIAL_PORT_A, c);
+	if (pty == _serial_port_pty_b) serial_send(SERIAL_PORT_B, c);
+	if (pty == _serial_port_pty_c) serial_send(SERIAL_PORT_C, c);
+	if (pty == _serial_port_pty_d) serial_send(SERIAL_PORT_D, c);
 }
 
-static void open_serial(fs_node_t * node, unsigned int flags) {
-	return;
-}
+#define DEV_PATH "/dev/"
+#define TTY_A "ttyS0"
+#define TTY_B "ttyS1"
+#define TTY_C "ttyS2"
+#define TTY_D "ttyS3"
 
-static void close_serial(fs_node_t * node) {
-	return;
+static void serial_fill_name(pty_t * pty, char * name) {
+	if (pty == _serial_port_pty_a) sprintf(name, DEV_PATH TTY_A);
+	if (pty == _serial_port_pty_b) sprintf(name, DEV_PATH TTY_B);
+	if (pty == _serial_port_pty_c) sprintf(name, DEV_PATH TTY_C);
+	if (pty == _serial_port_pty_d) sprintf(name, DEV_PATH TTY_D);
 }
 
-static int wait_serial(fs_node_t * node, void * process) {
-	return selectwait_fs(*pipe_for_port((int)node->device), process);
-}
-static int check_serial(fs_node_t * node) {
-	return selectcheck_fs(*pipe_for_port((int)node->device));
-}
+static fs_node_t * serial_device_create(int port) {
+	pty_t * pty = pty_new(NULL);
+	*pty_for_port(port) = pty;
+	pty->write_out = serial_write_out;
+	pty->fill_name = serial_fill_name;
 
-static int have_installed_ac = 0;
-static int have_installed_bd = 0;
+	serial_enable(port);
 
-static fs_node_t * serial_device_create(int device) {
-	fs_node_t * fnode = malloc(sizeof(fs_node_t));
-	memset(fnode, 0x00, sizeof(fs_node_t));
-	fnode->device= (void *)device;
-	strcpy(fnode->name, "serial");
-	fnode->uid = 0;
-	fnode->gid = 0;
-	fnode->mask    = 0660;
-	fnode->flags   = FS_CHARDEVICE;
-	fnode->read    = read_serial;
-	fnode->write   = write_serial;
-	fnode->open    = open_serial;
-	fnode->close   = close_serial;
-	fnode->readdir = NULL;
-	fnode->finddir = NULL;
-	fnode->ioctl   = NULL; /* TODO ioctls for raw serial devices */
-
-	fnode->selectcheck = check_serial;
-	fnode->selectwait  = wait_serial;
-
-	fnode->atime = now();
-	fnode->mtime = fnode->atime;
-	fnode->ctime = fnode->atime;
-
-	serial_enable(device);
-
-	if (device == SERIAL_PORT_A || device == SERIAL_PORT_C) {
+	if (port == SERIAL_PORT_A || port == SERIAL_PORT_C) {
 		if (!have_installed_ac) {
 			irq_install_handler(SERIAL_IRQ_AC, serial_handler_ac, "serial ac");
 			have_installed_ac = 1;
@@ -177,24 +140,15 @@ static fs_node_t * serial_device_create(int device) {
 		}
 	}
 
-	*pipe_for_port(device) = make_pipe(128);
-
-	return fnode;
+	return pty->slave;
 }
 
 static int serial_mount_devices(void) {
 
-	fs_node_t * ttyS0 = serial_device_create(SERIAL_PORT_A);
-	vfs_mount("/dev/ttyS0", ttyS0);
-
-	fs_node_t * ttyS1 = serial_device_create(SERIAL_PORT_B);
-	vfs_mount("/dev/ttyS1", ttyS1);
-
-	fs_node_t * ttyS2 = serial_device_create(SERIAL_PORT_C);
-	vfs_mount("/dev/ttyS2", ttyS2);
-
-	fs_node_t * ttyS3 = serial_device_create(SERIAL_PORT_D);
-	vfs_mount("/dev/ttyS3", ttyS3);
+	fs_node_t * ttyS0 = serial_device_create(SERIAL_PORT_A); vfs_mount(DEV_PATH TTY_A, ttyS0);
+	fs_node_t * ttyS1 = serial_device_create(SERIAL_PORT_B); vfs_mount(DEV_PATH TTY_B, ttyS1);
+	fs_node_t * ttyS2 = serial_device_create(SERIAL_PORT_C); vfs_mount(DEV_PATH TTY_C, ttyS2);
+	fs_node_t * ttyS3 = serial_device_create(SERIAL_PORT_D); vfs_mount(DEV_PATH TTY_D, ttyS3);
 
 	char * c;
 	if ((c = args_value("logtoserial"))) {