mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
tty: tty abstraction initial implementation
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
#define DEV_MAJOR_NULL 1
|
||||
#define DEV_MAJOR_FULL 2
|
||||
#define DEV_MAJOR_ZERO 3
|
||||
#define DEV_MAJOR_CONSOLE 4
|
||||
#define DEV_MAJOR_TTY 4
|
||||
#define DEV_MAJOR_FB 5
|
||||
#define DEV_MAJOR_KEYBOARD 6
|
||||
#define DEV_MAJOR_BLOCK 7
|
||||
@@ -17,6 +17,7 @@
|
||||
#define DEV_MAJOR_URANDOM 9
|
||||
#define DEV_MAJOR_NET 10
|
||||
#define DEV_MAJOR_MOUSE 11
|
||||
#define DEV_MAJOR_CONSOLE 12
|
||||
|
||||
typedef struct {
|
||||
int (*open)(int minor, int flags);
|
||||
@@ -29,6 +30,7 @@ typedef struct {
|
||||
int (*isatty)(int minor);
|
||||
int (*ioctl)(int minor, unsigned long request, void *arg, int *result);
|
||||
int (*maxseek)(int minor, size_t *max);
|
||||
void (*inactive)(int minor);
|
||||
} devops_t;
|
||||
|
||||
typedef struct devnode_t {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef _TTY_H
|
||||
#define _TTY_H
|
||||
|
||||
#include <mutex.h>
|
||||
#include <termios.h>
|
||||
#include <kernel/poll.h>
|
||||
#include <ringbuffer.h>
|
||||
|
||||
#define DEVICE_BUFFER_SIZE 512
|
||||
#define READ_BUFFER_SIZE 4096
|
||||
|
||||
typedef void (*ttydevicewritefn_t)(char *str, size_t size);
|
||||
|
||||
typedef struct {
|
||||
pollheader_t pollheader;
|
||||
char *name;
|
||||
ringbuffer_t readbuffer;
|
||||
mutex_t readmutex;
|
||||
mutex_t writemutex;
|
||||
termios_t termios;
|
||||
char *devicebuffer;
|
||||
int devicepos;
|
||||
ttydevicewritefn_t writetodevice;
|
||||
int minor;
|
||||
winsize_t winsize;
|
||||
} tty_t;
|
||||
|
||||
void tty_init();
|
||||
tty_t *tty_create(char *name, ttydevicewritefn_t fn);
|
||||
void tty_destroy(char *name, tty_t *tty);
|
||||
void tty_process(tty_t *tty, char c);
|
||||
|
||||
#endif
|
||||
@@ -10,6 +10,7 @@ typedef unsigned int tcflag_t;
|
||||
#define NCCS 32
|
||||
#define ECHO 0000010
|
||||
#define ICANON 0000002
|
||||
#define VTIME 5
|
||||
#define VMIN 6
|
||||
#define INLCR 0000100
|
||||
#define IGNCR 0000200
|
||||
|
||||
+19
-191
@@ -8,15 +8,11 @@
|
||||
#include <kernel/keyboard.h>
|
||||
#include <termios.h>
|
||||
#include <kernel/poll.h>
|
||||
#include <kernel/tty.h>
|
||||
|
||||
#define BUFFER_SIZE 4096
|
||||
static mutex_t writemutex;
|
||||
static mutex_t readmutex;
|
||||
static semaphore_t readsemaphore;
|
||||
static ringbuffer_t readbuffer;
|
||||
static thread_t *thread;
|
||||
static volatile termios_t termios;
|
||||
static pollheader_t pollheader;
|
||||
static tty_t *tty;
|
||||
|
||||
void console_write(char *str, size_t count) {
|
||||
MUTEX_ACQUIRE(&writemutex, false);
|
||||
@@ -30,8 +26,6 @@ void console_putc(char c) {
|
||||
console_write(&c, 1);
|
||||
}
|
||||
|
||||
#define THREAD_BUFFER_SIZE 128
|
||||
|
||||
// taken from https://en.wikipedia.org/wiki/ANSI_escape_code#Terminal_input_sequences
|
||||
|
||||
#define HOME_STR "\e[1~"
|
||||
@@ -47,34 +41,25 @@ void console_putc(char c) {
|
||||
#define LEFT_STR "\e[D"
|
||||
|
||||
static void consolethread() {
|
||||
char buffer[THREAD_BUFFER_SIZE + 1];
|
||||
uintmax_t buffpos = 0;
|
||||
|
||||
for (;;) {
|
||||
kbpacket_t packet;
|
||||
keyboard_wait(keyboard_console, &packet);
|
||||
if (packet.flags & KBPACKET_FLAGS_RELEASED)
|
||||
continue;
|
||||
|
||||
char asciibuffer[2] = {0, 0};
|
||||
char *target = asciibuffer;
|
||||
|
||||
if (packet.ascii) {
|
||||
if (packet.ascii == '\r' && (termios.c_iflag & IGNCR))
|
||||
continue;
|
||||
|
||||
if (packet.ascii == '\r' && (termios.c_iflag & ICRNL))
|
||||
packet.ascii = '\n';
|
||||
else if (packet.ascii == '\n' && (termios.c_iflag & INLCR))
|
||||
packet.ascii = '\r';
|
||||
|
||||
// control characters
|
||||
if (packet.flags & (KBPACKET_FLAGS_LEFTCTRL | KBPACKET_FLAGS_RIGHTCTRL)) {
|
||||
if (!((packet.ascii > 'a' && packet.ascii < 'z') || (packet.ascii > 'A' && packet.ascii < 'Z')))
|
||||
continue;
|
||||
|
||||
packet.ascii = packet.ascii > 'a' ? packet.ascii - 0x60 : packet.ascii - 0x40;
|
||||
}
|
||||
|
||||
tty_process(tty, packet.ascii);
|
||||
} else {
|
||||
// no ascii for key but we can send in a escape sequence for it
|
||||
char *target = NULL;
|
||||
switch (packet.keycode) {
|
||||
case KEYCODE_HOME:
|
||||
target = HOME_STR;
|
||||
@@ -109,185 +94,28 @@ static void consolethread() {
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
// TODO SWITCH OF SPECIAL KEYS
|
||||
}
|
||||
|
||||
asciibuffer[0] = packet.ascii;
|
||||
size_t targetlen = strlen(target);
|
||||
if (targetlen == 0)
|
||||
continue;
|
||||
|
||||
if (termios.c_lflag & ICANON) {
|
||||
bool flush = false;
|
||||
if (packet.ascii == '\b') {
|
||||
if (buffpos == 0)
|
||||
continue;
|
||||
--buffpos;
|
||||
buffer[buffpos] = '\0';
|
||||
if (termios.c_lflag & ECHO)
|
||||
console_write("\b \b", 3);
|
||||
continue;
|
||||
} else if (packet.ascii == '\n') {
|
||||
flush = true;
|
||||
}
|
||||
|
||||
if (termios.c_lflag & ECHO)
|
||||
console_write(target, targetlen);
|
||||
|
||||
for (size_t i = 0; i < targetlen; ++i) {
|
||||
buffer[buffpos++] = target[i];
|
||||
if (buffpos == THREAD_BUFFER_SIZE) {
|
||||
flush = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flush) {
|
||||
MUTEX_ACQUIRE(&readmutex, false);
|
||||
ringbuffer_write(&readbuffer, buffer, buffpos);
|
||||
buffpos = 0;
|
||||
size_t datacount = RINGBUFFER_DATACOUNT(&readbuffer);
|
||||
if (datacount) {
|
||||
if (datacount >= termios.c_cc[VMIN])
|
||||
poll_event(&pollheader, POLLIN);
|
||||
|
||||
semaphore_signal(&readsemaphore);
|
||||
}
|
||||
MUTEX_RELEASE(&readmutex);
|
||||
}
|
||||
} else {
|
||||
if (termios.c_lflag & ECHO)
|
||||
console_write(target, targetlen);
|
||||
|
||||
MUTEX_ACQUIRE(&readmutex, false);
|
||||
ringbuffer_write(&readbuffer, target, targetlen);
|
||||
size_t datacount = RINGBUFFER_DATACOUNT(&readbuffer);
|
||||
if (datacount) {
|
||||
if (datacount >= termios.c_cc[VMIN])
|
||||
poll_event(&pollheader, POLLIN);
|
||||
|
||||
semaphore_signal(&readsemaphore);
|
||||
}
|
||||
MUTEX_RELEASE(&readmutex);
|
||||
size_t len = strlen(target);
|
||||
for (int i = 0; i < len; ++i)
|
||||
tty_process(tty, target[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc) {
|
||||
size_t total = 0;
|
||||
for (;;) {
|
||||
if (semaphore_test(&readsemaphore) == false) {
|
||||
*readc = 0;
|
||||
if (termios.c_cc[VMIN] == 0)
|
||||
return 0;
|
||||
|
||||
if (flags & V_FFLAGS_NONBLOCKING)
|
||||
return EAGAIN;
|
||||
|
||||
int i = semaphore_wait(&readsemaphore, true);
|
||||
if (i)
|
||||
return i;
|
||||
}
|
||||
|
||||
MUTEX_ACQUIRE(&readmutex, false);
|
||||
|
||||
size_t read = ringbuffer_read(&readbuffer, buffer, size);
|
||||
size_t left = readbuffer.write - readbuffer.read;
|
||||
|
||||
MUTEX_RELEASE(&readmutex);
|
||||
|
||||
size -= read;
|
||||
buffer = (void *)((uintptr_t)buffer + read);
|
||||
total += read;
|
||||
|
||||
if (size == 0 || total >= termios.c_cc[VMIN]) {
|
||||
if (left > 0)
|
||||
semaphore_signal(&readsemaphore);
|
||||
*readc = total;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int write(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *writec) {
|
||||
*writec = size;
|
||||
console_write(buffer, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int poll(int minor, polldata_t *data, int events) {
|
||||
int revents = 0;
|
||||
|
||||
if (events & POLLOUT)
|
||||
events |= POLLOUT;
|
||||
|
||||
MUTEX_ACQUIRE(&readmutex, false);
|
||||
|
||||
size_t datacount = RINGBUFFER_DATACOUNT(&readbuffer);
|
||||
|
||||
if ((events & POLLIN) && datacount >= termios.c_cc[VMIN])
|
||||
revents |= POLLIN;
|
||||
|
||||
MUTEX_RELEASE(&readmutex);
|
||||
|
||||
if (revents == 0 && data)
|
||||
poll_add(&pollheader, data, events);
|
||||
|
||||
return revents;
|
||||
}
|
||||
|
||||
static int ioctl(int minor, unsigned long req, void *arg, int *result) {
|
||||
switch (req) {
|
||||
case TIOCGWINSZ:
|
||||
size_t x, y, fbx, fby;
|
||||
term_getsize(&x, &y, &fbx, &fby);
|
||||
winsize_t *w = arg;
|
||||
w->ws_col = x;
|
||||
w->ws_row = y;
|
||||
w->ws_xpixel = fbx;
|
||||
w->ws_ypixel = fby;
|
||||
break;
|
||||
case TCGETS:
|
||||
*(termios_t *)arg = termios;
|
||||
break;
|
||||
case TCSETS:
|
||||
termios = *(termios_t *)arg;
|
||||
break;
|
||||
default:
|
||||
return ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isatty(int minor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static devops_t devops = {
|
||||
.write = write,
|
||||
.read = read,
|
||||
.isatty = isatty,
|
||||
.poll = poll,
|
||||
.ioctl = ioctl
|
||||
};
|
||||
|
||||
void console_init() {
|
||||
SEMAPHORE_INIT(&readsemaphore, 0);
|
||||
MUTEX_INIT(&writemutex);
|
||||
MUTEX_INIT(&readmutex);
|
||||
__assert(ringbuffer_init(&readbuffer, BUFFER_SIZE) == 0);
|
||||
__assert(devfs_register(&devops, "console", V_TYPE_CHDEV, DEV_MAJOR_CONSOLE, 0, 0644) == 0);
|
||||
|
||||
thread = sched_newthread(consolethread, PAGE_SIZE * 16, 0, NULL, NULL);
|
||||
__assert(thread);
|
||||
sched_queue(thread);
|
||||
|
||||
termios.c_iflag = ICRNL;
|
||||
termios.c_lflag = ECHO | ICANON | ISIG;
|
||||
termios.c_cc[VINTR] = 0x03;
|
||||
termios.ibaud = 38400;
|
||||
termios.obaud = 38400;
|
||||
termios.c_cc[VMIN] = 1;
|
||||
tty = tty_create("console", console_write);
|
||||
__assert(tty);
|
||||
|
||||
POLL_INITHEADER(&pollheader);
|
||||
size_t x, y, fbx, fby;
|
||||
term_getsize(&x, &y, &fbx, &fby);
|
||||
tty->winsize.ws_col = x;
|
||||
tty->winsize.ws_row = y;
|
||||
tty->winsize.ws_xpixel = fbx;
|
||||
tty->winsize.ws_ypixel = fby;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
#include <kernel/tty.h>
|
||||
#include <kernel/devfs.h>
|
||||
#include <logging.h>
|
||||
#include <kernel/alloc.h>
|
||||
|
||||
#define TTY_MAX_COUNT 4096
|
||||
#define CONTROLLING_TTY_MINOR TTY_MAX_COUNT
|
||||
static mutex_t listmutex;
|
||||
static tty_t *ttylist[TTY_MAX_COUNT];
|
||||
|
||||
void tty_process(tty_t *tty, char c) {
|
||||
if (c == '\r' && (tty->termios.c_iflag & IGNCR))
|
||||
return;
|
||||
|
||||
if (c == '\r' && (tty->termios.c_iflag & ICRNL))
|
||||
c = '\n';
|
||||
else if (c == '\n' && (tty->termios.c_iflag & INLCR))
|
||||
c = '\r';
|
||||
|
||||
// TODO signal stuff
|
||||
|
||||
if (tty->termios.c_lflag & ICANON) {
|
||||
bool flush = false;
|
||||
if (c == '\b') {
|
||||
// backspace
|
||||
if (tty->devicepos == 0)
|
||||
return;
|
||||
|
||||
--tty->devicepos;
|
||||
tty->devicebuffer[tty->devicepos] = '\0';
|
||||
|
||||
if (tty->termios.c_lflag & ECHO)
|
||||
tty->writetodevice("\b \b", 3);
|
||||
return;
|
||||
} else if (c == '\n') {
|
||||
// newline
|
||||
flush = true;
|
||||
}
|
||||
|
||||
if (tty->termios.c_lflag & ECHO)
|
||||
tty->writetodevice(&c, 1);
|
||||
|
||||
// check if buffer is full
|
||||
tty->devicebuffer[tty->devicepos++] = c;
|
||||
if (tty->devicepos == DEVICE_BUFFER_SIZE)
|
||||
flush = true;
|
||||
|
||||
if (flush) {
|
||||
MUTEX_ACQUIRE(&tty->readmutex, false);
|
||||
ringbuffer_write(&tty->readbuffer, tty->devicebuffer, tty->devicepos);
|
||||
tty->devicepos = 0;
|
||||
// XXX is this needed?
|
||||
size_t datacount = RINGBUFFER_DATACOUNT(&tty->readbuffer);
|
||||
if (datacount)
|
||||
poll_event(&tty->pollheader, POLLIN);
|
||||
|
||||
MUTEX_RELEASE(&tty->readmutex);
|
||||
}
|
||||
} else {
|
||||
if (tty->termios.c_lflag & ECHO)
|
||||
tty->writetodevice(&c, 1);
|
||||
|
||||
MUTEX_ACQUIRE(&tty->readmutex, false);
|
||||
|
||||
ringbuffer_write(&tty->readbuffer, &c, 1);
|
||||
poll_event(&tty->pollheader, POLLIN);
|
||||
|
||||
MUTEX_RELEASE(&tty->readmutex);
|
||||
}
|
||||
}
|
||||
|
||||
static inline tty_t *ttyget(int minor) {
|
||||
if (minor >= TTY_MAX_COUNT)
|
||||
return NULL;
|
||||
|
||||
return ttylist[minor];
|
||||
}
|
||||
|
||||
static int internalpoll(tty_t *tty, polldata_t *data, int events) {
|
||||
int revents = 0;
|
||||
|
||||
// XXX would the device not be in the foregroup group affect this?
|
||||
if (events & POLLOUT)
|
||||
revents |= POLLOUT;
|
||||
|
||||
MUTEX_ACQUIRE(&tty->readmutex, false);
|
||||
|
||||
if ((events & POLLIN) && RINGBUFFER_DATACOUNT(&tty->readbuffer))
|
||||
revents |= POLLIN;
|
||||
|
||||
MUTEX_RELEASE(&tty->readmutex);
|
||||
|
||||
if (revents == 0 && data)
|
||||
poll_add(&tty->pollheader, data, events);
|
||||
|
||||
return revents;
|
||||
}
|
||||
|
||||
static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc) {
|
||||
tty_t *tty = ttyget(minor);
|
||||
if (tty == NULL)
|
||||
return ENODEV;
|
||||
|
||||
// for non canonical read
|
||||
// VMIN = 0 VTIME = 0: return immediatelly if no data in buffer
|
||||
// VMIN > 0 VTIME = 0: block until enough data has been read
|
||||
// VMIN = 0 VTIME > 0: block until either a timeout or until there is data to read
|
||||
// VMIN > 0 VTIME > 0: wait for a character indefinetly, and then keep reading more
|
||||
// with an inter byte timeout until either the timeout expires os we have read the minimum amount of data
|
||||
// for canonical read, min and time will be VMIN 1 VTIME 0
|
||||
|
||||
// XXX
|
||||
// does changing the VMIN and VTIME value from another thread change this?
|
||||
int min = (tty->termios.c_lflag & ICANON) ? 1 : tty->termios.c_cc[VMIN];
|
||||
int time = (tty->termios.c_lflag & ICANON) ? 0 : tty->termios.c_cc[VTIME];
|
||||
|
||||
// TODO
|
||||
// bg and fg process group stuff
|
||||
|
||||
// read data and if theres nothing just return
|
||||
if (min == 0 && time == 0) {
|
||||
MUTEX_ACQUIRE(&tty->readmutex, false);
|
||||
*readc = ringbuffer_read(&tty->readbuffer, buffer, size);
|
||||
MUTEX_RELEASE(&tty->readmutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// time is in 1/10 of a second
|
||||
size_t timeoutus = time * 100000;
|
||||
uintmax_t spins = 0;
|
||||
|
||||
int error = 0;
|
||||
size_t readcount = 0;
|
||||
size_t spaceleft = size;
|
||||
|
||||
// TODO hangup stuff
|
||||
|
||||
for (;;) {
|
||||
// for VMIN > 0 and VTIME > 0, the timeout is inter byte only.
|
||||
size_t effectivetimeout = (min > 0 && time > 0 && spins == 0) ? 0 : timeoutus;
|
||||
|
||||
polldesc_t desc = {0};
|
||||
error = poll_initdesc(&desc, 1);
|
||||
if (error)
|
||||
goto leave;
|
||||
|
||||
int revents = internalpoll(tty, &desc.data[0], POLLIN);
|
||||
|
||||
if (revents) {
|
||||
// theres data to read
|
||||
MUTEX_ACQUIRE(&tty->readmutex, false);
|
||||
|
||||
size_t actuallyread = ringbuffer_read(&tty->readbuffer, (void *)((uintptr_t)buffer + readcount), spaceleft);
|
||||
readcount += actuallyread;
|
||||
spaceleft -= actuallyread;
|
||||
MUTEX_RELEASE(&tty->readmutex);
|
||||
|
||||
// XXX is this valid?
|
||||
if (spaceleft > 0 && readcount < min)
|
||||
continue;
|
||||
|
||||
poll_leave(&desc);
|
||||
poll_destroydesc(&desc);
|
||||
break;
|
||||
}
|
||||
|
||||
if (revents == 0 && flags & V_FFLAGS_NONBLOCKING) {
|
||||
// nothing to read and nonblocking
|
||||
poll_leave(&desc);
|
||||
poll_destroydesc(&desc);
|
||||
error = EAGAIN;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
error = poll_dowait(&desc, effectivetimeout);
|
||||
if (desc.event->revents == 0) {
|
||||
// timed out!
|
||||
break;
|
||||
}
|
||||
|
||||
poll_leave(&desc);
|
||||
poll_destroydesc(&desc);
|
||||
|
||||
if (error)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
*readc = readcount;
|
||||
|
||||
leave:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int write(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *writec) {
|
||||
tty_t *tty = ttyget(minor);
|
||||
if (tty == NULL)
|
||||
return ENODEV;
|
||||
|
||||
// TODO background process stuff etc
|
||||
*writec = size;
|
||||
tty->writetodevice(buffer, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int poll(int minor, polldata_t *data, int events) {
|
||||
tty_t *tty = ttyget(minor);
|
||||
if (tty == NULL)
|
||||
return POLLERR;
|
||||
|
||||
return internalpoll(tty, data, events);
|
||||
}
|
||||
|
||||
static int ioctl(int minor, unsigned long req, void *arg, int *result) {
|
||||
tty_t *tty = ttyget(minor);
|
||||
if (tty == NULL)
|
||||
return ENODEV;
|
||||
|
||||
switch (req) {
|
||||
case TIOCGWINSZ:
|
||||
winsize_t *w = arg;
|
||||
*w = tty->winsize;
|
||||
break;
|
||||
case TCGETS:
|
||||
*(termios_t *)arg = tty->termios;
|
||||
break;
|
||||
case TCSETS:
|
||||
tty->termios = *(termios_t *)arg;
|
||||
break;
|
||||
default:
|
||||
return ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isatty(int minor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int allocminor(tty_t *tty) {
|
||||
MUTEX_ACQUIRE(&listmutex, false);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < TTY_MAX_COUNT; ++i) {
|
||||
if (ttylist[i] == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
ttylist[i] = tty;
|
||||
|
||||
MUTEX_RELEASE(&listmutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static void freeminor(int minor) {
|
||||
MUTEX_ACQUIRE(&listmutex, false);
|
||||
__assert(ttylist[minor]);
|
||||
ttylist[minor] = NULL;
|
||||
MUTEX_RELEASE(&listmutex);
|
||||
}
|
||||
|
||||
static devops_t devops = {
|
||||
.write = write,
|
||||
.poll = poll,
|
||||
.read = read,
|
||||
.ioctl = ioctl,
|
||||
.isatty = isatty
|
||||
};
|
||||
|
||||
tty_t *tty_create(char *name, ttydevicewritefn_t fn) {
|
||||
tty_t *tty = alloc(sizeof(tty_t));
|
||||
if (tty == NULL)
|
||||
return NULL;
|
||||
|
||||
tty->name = alloc(strlen(name) + 1);
|
||||
if (tty->name == NULL)
|
||||
goto error;
|
||||
|
||||
tty->devicebuffer = alloc(DEVICE_BUFFER_SIZE);
|
||||
if (tty->devicebuffer == NULL)
|
||||
goto error;
|
||||
|
||||
if (ringbuffer_init(&tty->readbuffer, READ_BUFFER_SIZE))
|
||||
goto error;
|
||||
|
||||
int minor = allocminor(tty);
|
||||
if (minor == TTY_MAX_COUNT) {
|
||||
ringbuffer_destroy(&tty->readbuffer);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (devfs_register(&devops, name, V_TYPE_CHDEV, DEV_MAJOR_TTY, minor, 0644)) {
|
||||
freeminor(minor);
|
||||
ringbuffer_destroy(&tty->readbuffer);
|
||||
goto error;
|
||||
}
|
||||
|
||||
POLL_INITHEADER(&tty->pollheader);
|
||||
strcpy(tty->name, name);
|
||||
MUTEX_INIT(&tty->readmutex);
|
||||
MUTEX_INIT(&tty->writemutex);
|
||||
|
||||
tty->termios.c_iflag = ICRNL;
|
||||
tty->termios.c_lflag = ECHO | ICANON | ISIG;
|
||||
tty->termios.c_cc[VINTR] = 0x03;
|
||||
tty->termios.ibaud = 38400;
|
||||
tty->termios.obaud = 38400;
|
||||
tty->termios.c_cc[VMIN] = 1;
|
||||
|
||||
tty->writetodevice = fn;
|
||||
tty->minor = minor;
|
||||
|
||||
return tty;
|
||||
error:
|
||||
if (tty->name)
|
||||
free(tty->name);
|
||||
|
||||
if (tty->devicebuffer)
|
||||
free(tty->devicebuffer);
|
||||
|
||||
free(tty);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void tty_destroy(char *name, tty_t *tty) {
|
||||
|
||||
}
|
||||
|
||||
void tty_init() {
|
||||
__assert(devfs_register(&devops, "tty", V_TYPE_CHDEV, DEV_MAJOR_TTY, CONTROLLING_TTY_MINOR, 0644) == 0);
|
||||
MUTEX_INIT(&listmutex);
|
||||
}
|
||||
Reference in New Issue
Block a user