Rough PTY support (needs work)
This commit is contained in:
parent
cef1d359a1
commit
e02cf79e2a
266
kernel/fs/tty.c
Normal file
266
kernel/fs/tty.c
Normal file
@ -0,0 +1,266 @@
|
||||
#include <system.h>
|
||||
#include <fs.h>
|
||||
#include <pipe.h>
|
||||
#include <logging.h>
|
||||
|
||||
#define TTY_BUFFER_SIZE 512
|
||||
|
||||
struct winsize {
|
||||
unsigned short row, col, pix_w, pix_h;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t * buffer;
|
||||
size_t write_ptr;
|
||||
size_t read_ptr;
|
||||
size_t size;
|
||||
uint8_t volatile lock;
|
||||
list_t * wait_queue;
|
||||
} ring_buffer_t;
|
||||
|
||||
typedef struct pty {
|
||||
int name;
|
||||
fs_node_t * master;
|
||||
fs_node_t * slave;
|
||||
struct winsize size;
|
||||
|
||||
ring_buffer_t in;
|
||||
ring_buffer_t out;
|
||||
} pty_t;
|
||||
|
||||
list_t * pty_list = NULL;
|
||||
|
||||
static inline size_t ring_buffer_unread(ring_buffer_t * ring_buffer) {
|
||||
if (ring_buffer->read_ptr == ring_buffer->write_ptr) {
|
||||
return 0;
|
||||
}
|
||||
if (ring_buffer->read_ptr > ring_buffer->write_ptr) {
|
||||
return (ring_buffer->size - ring_buffer->read_ptr) + ring_buffer->write_ptr;
|
||||
} else {
|
||||
return (ring_buffer->write_ptr - ring_buffer->read_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
size_t ring_buffer_size(fs_node_t * node) {
|
||||
ring_buffer_t * ring_buffer = (ring_buffer_t *)node->inode;
|
||||
return ring_buffer_unread(ring_buffer);
|
||||
}
|
||||
|
||||
static inline size_t ring_buffer_available(ring_buffer_t * ring_buffer) {
|
||||
if (ring_buffer->read_ptr == ring_buffer->write_ptr) {
|
||||
return ring_buffer->size - 1;
|
||||
}
|
||||
|
||||
if (ring_buffer->read_ptr > ring_buffer->write_ptr) {
|
||||
return ring_buffer->read_ptr - ring_buffer->write_ptr - 1;
|
||||
} else {
|
||||
return (ring_buffer->size - ring_buffer->write_ptr) + ring_buffer->read_ptr - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ring_buffer_increment_read(ring_buffer_t * ring_buffer) {
|
||||
ring_buffer->read_ptr++;
|
||||
if (ring_buffer->read_ptr == ring_buffer->size) {
|
||||
ring_buffer->read_ptr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ring_buffer_increment_write(ring_buffer_t * ring_buffer) {
|
||||
ring_buffer->write_ptr++;
|
||||
if (ring_buffer->write_ptr == ring_buffer->size) {
|
||||
ring_buffer->write_ptr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t read_pty_master(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) {
|
||||
pty_t * pty = (pty_t *)node->inode;
|
||||
|
||||
/* Standard pipe read */
|
||||
size_t collected = 0;
|
||||
while (collected == 0) {
|
||||
spin_lock(&pty->out.lock);
|
||||
while (ring_buffer_unread(&pty->out) > 0 && collected < size) {
|
||||
buffer[collected] = pty->out.buffer[pty->out.read_ptr];
|
||||
ring_buffer_increment_read(&pty->out);
|
||||
collected++;
|
||||
}
|
||||
spin_unlock(&pty->out.lock);
|
||||
wakeup_queue(pty->out.wait_queue);
|
||||
if (collected == 0) {
|
||||
sleep_on(pty->out.wait_queue);
|
||||
}
|
||||
}
|
||||
|
||||
return collected;
|
||||
}
|
||||
uint32_t write_pty_master(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) {
|
||||
pty_t * pty = (pty_t *)node->inode;
|
||||
|
||||
size_t written = 0;
|
||||
while (written < size) {
|
||||
spin_lock(&pty->in.lock);
|
||||
|
||||
while (ring_buffer_available(&pty->in) > 0 && written < size) {
|
||||
pty->in.buffer[pty->in.write_ptr] = buffer[written];
|
||||
ring_buffer_increment_write(&pty->in);
|
||||
written++;
|
||||
}
|
||||
|
||||
spin_unlock(&pty->in.lock);
|
||||
wakeup_queue(pty->in.wait_queue);
|
||||
if (written < size) {
|
||||
sleep_on(pty->in.wait_queue);
|
||||
}
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
void open_pty_master(fs_node_t * node, uint8_t read, uint8_t write) {
|
||||
return;
|
||||
}
|
||||
void close_pty_master(fs_node_t * node) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t read_pty_slave(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) {
|
||||
pty_t * pty = (pty_t *)node->inode;
|
||||
|
||||
/* Standard pipe read */
|
||||
size_t collected = 0;
|
||||
while (collected == 0) {
|
||||
spin_lock(&pty->in.lock);
|
||||
while (ring_buffer_unread(&pty->in) > 0 && collected < size) {
|
||||
buffer[collected] = pty->in.buffer[pty->in.read_ptr];
|
||||
ring_buffer_increment_read(&pty->in);
|
||||
collected++;
|
||||
}
|
||||
spin_unlock(&pty->in.lock);
|
||||
wakeup_queue(pty->in.wait_queue);
|
||||
if (collected == 0) {
|
||||
sleep_on(pty->in.wait_queue);
|
||||
}
|
||||
}
|
||||
|
||||
return collected;
|
||||
}
|
||||
uint32_t write_pty_slave(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) {
|
||||
pty_t * pty = (pty_t *)node->inode;
|
||||
|
||||
size_t written = 0;
|
||||
while (written < size) {
|
||||
spin_lock(&pty->out.lock);
|
||||
|
||||
while (ring_buffer_available(&pty->out) > 0 && written < size) {
|
||||
pty->out.buffer[pty->out.write_ptr] = buffer[written];
|
||||
ring_buffer_increment_write(&pty->out);
|
||||
written++;
|
||||
}
|
||||
|
||||
spin_unlock(&pty->out.lock);
|
||||
wakeup_queue(pty->out.wait_queue);
|
||||
if (written < size) {
|
||||
sleep_on(pty->out.wait_queue);
|
||||
}
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
void open_pty_slave(fs_node_t * node, uint8_t read, uint8_t write) {
|
||||
return;
|
||||
}
|
||||
void close_pty_slave(fs_node_t * node) {
|
||||
return;
|
||||
}
|
||||
|
||||
fs_node_t * pty_master_create(pty_t * pty) {
|
||||
fs_node_t * fnode = malloc(sizeof(fs_node_t));
|
||||
memset(fnode, 0x00, sizeof(fs_node_t));
|
||||
|
||||
fnode->name[0] = '\0';
|
||||
sprintf(fnode->name, "pty master");
|
||||
fnode->uid = 0;
|
||||
fnode->gid = 0;
|
||||
fnode->flags = FS_PIPE;
|
||||
fnode->read = read_pty_master;
|
||||
fnode->write = write_pty_master;
|
||||
fnode->open = open_pty_master;
|
||||
fnode->close = close_pty_master;
|
||||
fnode->readdir = NULL;
|
||||
fnode->finddir = NULL;
|
||||
|
||||
fnode->inode = (uintptr_t)pty;
|
||||
|
||||
return fnode;
|
||||
}
|
||||
|
||||
fs_node_t * pty_slave_create(pty_t * pty) {
|
||||
fs_node_t * fnode = malloc(sizeof(fs_node_t));
|
||||
memset(fnode, 0x00, sizeof(fs_node_t));
|
||||
|
||||
fnode->name[0] = '\0';
|
||||
sprintf(fnode->name, "pty slave");
|
||||
fnode->uid = 0;
|
||||
fnode->gid = 0;
|
||||
fnode->flags = FS_PIPE;
|
||||
fnode->read = read_pty_slave;
|
||||
fnode->write = write_pty_slave;
|
||||
fnode->open = open_pty_slave;
|
||||
fnode->close = close_pty_slave;
|
||||
fnode->readdir = NULL;
|
||||
fnode->finddir = NULL;
|
||||
|
||||
fnode->inode = (uintptr_t)pty;
|
||||
|
||||
return fnode;
|
||||
}
|
||||
|
||||
void pty_install(void) {
|
||||
pty_list = list_create();
|
||||
}
|
||||
|
||||
pty_t * pty_new(struct winsize * size) {
|
||||
pty_t * pty = malloc(sizeof(pty_t));
|
||||
|
||||
pty->in.buffer = malloc(TTY_BUFFER_SIZE);
|
||||
pty->in.write_ptr = 0;
|
||||
pty->in.read_ptr = 0;
|
||||
pty->in.lock = 0;
|
||||
pty->in.size = TTY_BUFFER_SIZE;
|
||||
pty->in.wait_queue = list_create();
|
||||
|
||||
pty->out.buffer = malloc(TTY_BUFFER_SIZE);
|
||||
pty->out.write_ptr = 0;
|
||||
pty->out.read_ptr = 0;
|
||||
pty->out.lock = 0;
|
||||
pty->out.wait_queue = list_create();
|
||||
pty->out.size = TTY_BUFFER_SIZE;
|
||||
|
||||
pty->master = pty_master_create(pty);
|
||||
pty->slave = pty_slave_create(pty);
|
||||
|
||||
list_insert(pty_list, pty);
|
||||
pty->name = list_index_of(pty_list, pty);
|
||||
|
||||
if (size) {
|
||||
memcpy(&pty->size, size, sizeof(struct winsize));
|
||||
} else {
|
||||
/* Sane defaults */
|
||||
pty->size.row = 25;
|
||||
pty->size.col = 80;
|
||||
}
|
||||
return pty;
|
||||
}
|
||||
|
||||
int openpty(int * master, int * slave, char * name, void * _ign0, void * size) {
|
||||
if (!master || !slave) return -1;
|
||||
|
||||
pty_t * pty = pty_new(size);
|
||||
|
||||
*master = process_append_fd((process_t *)current_process, pty->master);
|
||||
*slave = process_append_fd((process_t *)current_process, pty->slave);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,7 @@ extern fs_node_t *fs_root;
|
||||
extern fs_node_t * null_device_create();
|
||||
extern fs_node_t * serial_device_create(int device);
|
||||
extern void serial_mount_devices();
|
||||
extern int openpty(int * master, int * slave, char * name, void * _ign0, void * size);
|
||||
|
||||
extern fs_node_t * hello_device_create();
|
||||
|
||||
|
@ -605,7 +605,7 @@ static uintptr_t syscalls[] = {
|
||||
(uintptr_t)&sys_sbrk,
|
||||
(uintptr_t)&getgraphicsaddress,
|
||||
(uintptr_t)&uname, /* 12 */
|
||||
(uintptr_t)RESERVED,
|
||||
(uintptr_t)&openpty,
|
||||
(uintptr_t)&seek,
|
||||
(uintptr_t)&stat,
|
||||
(uintptr_t)&setgraphicsoffset, /* 16 */
|
||||
|
@ -61,6 +61,7 @@ DECL_SYSCALL0(getpid);
|
||||
DECL_SYSCALL1(sbrk, int);
|
||||
DECL_SYSCALL0(getgraphicsaddress);
|
||||
DECL_SYSCALL1(uname, void *);
|
||||
DECL_SYSCALL5(openpty, int *, int *, char *, void *, void *);
|
||||
DECL_SYSCALL3(lseek, int, int, int);
|
||||
DECL_SYSCALL2(fstat, int, void *);
|
||||
DECL_SYSCALL1(setgraphicsoffset, int);
|
||||
|
@ -36,7 +36,7 @@ DEFN_SYSCALL0(getpid, 9);
|
||||
DEFN_SYSCALL1(sbrk, 10, int);
|
||||
DEFN_SYSCALL0(getgraphicsaddress, 11);
|
||||
DEFN_SYSCALL1(uname, 12, void *);
|
||||
/* RESERVED syscall 13 */
|
||||
DEFN_SYSCALL5(openpty, 13, int *, int *, char *, void *, void *);
|
||||
DEFN_SYSCALL3(lseek, 14, int, int, int);
|
||||
DEFN_SYSCALL2(fstat, 15, int, void *);
|
||||
DEFN_SYSCALL1(setgraphicsoffset, 16, int);
|
||||
|
@ -72,6 +72,7 @@ typedef struct _terminal_cell {
|
||||
* we read from ofd and write to ifd, so make sure you don't
|
||||
* get them backwards. */
|
||||
static int ofd, ifd;
|
||||
static int fd_master, fd_slave;
|
||||
|
||||
int scale_fonts = 0; /* Whether fonts should be scaled */
|
||||
float font_scaling = 1.0; /* How much they should be scaled by */
|
||||
@ -217,7 +218,7 @@ void (*redraw_cursor)(void) = NULL;
|
||||
* Useful for things like the ANSI DSR command. */
|
||||
void input_buffer_stuff(char * str) {
|
||||
size_t s = strlen(str);
|
||||
write(ifd, str, s);
|
||||
write(fd_master, str, s);
|
||||
}
|
||||
|
||||
/* Write the contents of the buffer, as they were all non-escaped data. */
|
||||
@ -1343,10 +1344,10 @@ int buffer_put(char c) {
|
||||
|
||||
void handle_input(char c) {
|
||||
if (_unbuffered) {
|
||||
write(ifd, &c, 1);
|
||||
write(fd_master, &c, 1);
|
||||
} else {
|
||||
if (buffer_put(c)) {
|
||||
write(ifd, input_buffer, input_collected);
|
||||
write(fd_master, input_buffer, input_collected);
|
||||
clear_input();
|
||||
}
|
||||
}
|
||||
@ -1717,16 +1718,21 @@ int main(int argc, char ** argv) {
|
||||
|
||||
reinit();
|
||||
|
||||
/*
|
||||
ofd = syscall_mkpipe();
|
||||
ifd = syscall_mkpipe();
|
||||
*/
|
||||
|
||||
syscall_openpty(&fd_master, &fd_slave, NULL, NULL, NULL);
|
||||
|
||||
|
||||
int pid = getpid();
|
||||
uint32_t f = fork();
|
||||
|
||||
if (getpid() != pid) {
|
||||
syscall_dup2(ifd, 0);
|
||||
syscall_dup2(ofd, 1);
|
||||
syscall_dup2(ofd, 2);
|
||||
syscall_dup2(fd_slave, 0);
|
||||
syscall_dup2(fd_slave, 1);
|
||||
syscall_dup2(fd_slave, 2);
|
||||
|
||||
if (argv[optind] != NULL) {
|
||||
char * tokens[] = {argv[optind], NULL};
|
||||
@ -1754,7 +1760,7 @@ int main(int argc, char ** argv) {
|
||||
|
||||
if (!_windowed || _force_kernel) {
|
||||
/* Request kernel output to this terminal */
|
||||
syscall_system_function(4, (char **)ofd);
|
||||
syscall_system_function(4, (char **)fd_slave);
|
||||
}
|
||||
|
||||
child_pid = f;
|
||||
@ -1774,9 +1780,9 @@ int main(int argc, char ** argv) {
|
||||
flip_cursor();
|
||||
}
|
||||
|
||||
fstat(ofd, &_stat);
|
||||
fstat(fd_master, &_stat);
|
||||
if (_stat.st_size) {
|
||||
int r = read(ofd, buf, min(_stat.st_size, 1024));
|
||||
int r = read(fd_master, buf, min(_stat.st_size, 1024));
|
||||
for (uint32_t i = 0; i < r; ++i) {
|
||||
ansi_put(buf[i]);
|
||||
#if DEBUG_TERMINAL_WITH_SERIAL
|
||||
|
Loading…
Reference in New Issue
Block a user