mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 06:58:22 +00:00
pty: initial implementation
This commit is contained in:
@@ -36,6 +36,7 @@
|
|||||||
#include <kernel/sock.h>
|
#include <kernel/sock.h>
|
||||||
#include <kernel/mouse.h>
|
#include <kernel/mouse.h>
|
||||||
#include <kernel/tty.h>
|
#include <kernel/tty.h>
|
||||||
|
#include <kernel/pty.h>
|
||||||
|
|
||||||
static cpu_t bsp_cpu;
|
static cpu_t bsp_cpu;
|
||||||
|
|
||||||
@@ -71,6 +72,7 @@ void kernel_entry() {
|
|||||||
ext2_init();
|
ext2_init();
|
||||||
|
|
||||||
tty_init();
|
tty_init();
|
||||||
|
pty_init();
|
||||||
|
|
||||||
netdev_init();
|
netdev_init();
|
||||||
loopback_init();
|
loopback_init();
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef _PTY_H
|
||||||
|
#define _PTY_H
|
||||||
|
|
||||||
|
#include <kernel/tty.h>
|
||||||
|
#include <spinlock.h>
|
||||||
|
#include <ringbuffer.h>
|
||||||
|
#include <kernel/poll.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool hangup;
|
||||||
|
tty_t *tty;
|
||||||
|
int minor;
|
||||||
|
vnode_t *mastervnode;
|
||||||
|
ringbuffer_t ringbuffer;
|
||||||
|
pollheader_t pollheader;
|
||||||
|
spinlock_t lock;
|
||||||
|
} pty_t;
|
||||||
|
|
||||||
|
void pty_init();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -10,7 +10,8 @@
|
|||||||
#define DEVICE_BUFFER_SIZE 512
|
#define DEVICE_BUFFER_SIZE 512
|
||||||
#define READ_BUFFER_SIZE 4096
|
#define READ_BUFFER_SIZE 4096
|
||||||
|
|
||||||
typedef void (*ttydevicewritefn_t)(char *str, size_t size);
|
typedef size_t (*ttydevicewritefn_t)(void *internal, char *str, size_t size);
|
||||||
|
typedef void (*ttyinactivefn_t)(void *internal);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
pollheader_t pollheader;
|
pollheader_t pollheader;
|
||||||
@@ -19,17 +20,19 @@ typedef struct {
|
|||||||
mutex_t readmutex;
|
mutex_t readmutex;
|
||||||
mutex_t writemutex;
|
mutex_t writemutex;
|
||||||
termios_t termios;
|
termios_t termios;
|
||||||
|
void *deviceinternal;
|
||||||
char *devicebuffer;
|
char *devicebuffer;
|
||||||
int devicepos;
|
int devicepos;
|
||||||
ttydevicewritefn_t writetodevice;
|
ttydevicewritefn_t writetodevice;
|
||||||
|
ttyinactivefn_t inactivedevice;
|
||||||
int minor;
|
int minor;
|
||||||
winsize_t winsize;
|
winsize_t winsize;
|
||||||
vnode_t *mastervnode;
|
vnode_t *mastervnode;
|
||||||
} tty_t;
|
} tty_t;
|
||||||
|
|
||||||
void tty_init();
|
void tty_init();
|
||||||
tty_t *tty_create(char *name, ttydevicewritefn_t fn);
|
tty_t *tty_create(char *name, ttydevicewritefn_t writefn, ttyinactivefn_t inactivefn, void *internal);
|
||||||
void tty_destroy(char *name, tty_t *tty);
|
|
||||||
void tty_process(tty_t *tty, char c);
|
void tty_process(tty_t *tty, char c);
|
||||||
|
void tty_unregister(tty_t *tty);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -14,12 +14,17 @@ static mutex_t writemutex;
|
|||||||
static thread_t *thread;
|
static thread_t *thread;
|
||||||
static tty_t *tty;
|
static tty_t *tty;
|
||||||
|
|
||||||
void console_write(char *str, size_t count) {
|
size_t console_write(char *str, size_t count) {
|
||||||
MUTEX_ACQUIRE(&writemutex, false);
|
MUTEX_ACQUIRE(&writemutex, false);
|
||||||
|
|
||||||
term_write(str, count);
|
term_write(str, count);
|
||||||
|
|
||||||
MUTEX_RELEASE(&writemutex);
|
MUTEX_RELEASE(&writemutex);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t console_ttywrite(void *internal, char *str, size_t count) {
|
||||||
|
return console_write(str, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void console_putc(char c) {
|
void console_putc(char c) {
|
||||||
@@ -109,7 +114,7 @@ void console_init() {
|
|||||||
__assert(thread);
|
__assert(thread);
|
||||||
sched_queue(thread);
|
sched_queue(thread);
|
||||||
|
|
||||||
tty = tty_create("console", console_write);
|
tty = tty_create("console", console_ttywrite, NULL, NULL);
|
||||||
__assert(tty);
|
__assert(tty);
|
||||||
|
|
||||||
size_t x, y, fbx, fby;
|
size_t x, y, fbx, fby;
|
||||||
|
|||||||
@@ -0,0 +1,293 @@
|
|||||||
|
#include <kernel/pty.h>
|
||||||
|
#include <kernel/devfs.h>
|
||||||
|
#include <spinlock.h>
|
||||||
|
#include <logging.h>
|
||||||
|
#include <kernel/alloc.h>
|
||||||
|
|
||||||
|
#define PTY_BUFFER 4096
|
||||||
|
#define PTY_MAX 1024
|
||||||
|
#define PTMX_MINOR PTY_MAX
|
||||||
|
static spinlock_t listlock;
|
||||||
|
static pty_t *ptylist[PTY_MAX];
|
||||||
|
|
||||||
|
static inline pty_t *ptyget(int minor) {
|
||||||
|
if (minor >= PTY_MAX)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return ptylist[minor];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int allocateptyminor(pty_t *pty) {
|
||||||
|
bool intstatus = interrupt_set(false);
|
||||||
|
spinlock_acquire(&listlock);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < PTY_MAX; ++i) {
|
||||||
|
if (ptylist[i] == NULL) {
|
||||||
|
ptylist[i] = pty;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spinlock_release(&listlock);
|
||||||
|
interrupt_set(intstatus);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void freeptyminor(int pty) {
|
||||||
|
bool intstatus = interrupt_set(false);
|
||||||
|
spinlock_acquire(&listlock);
|
||||||
|
|
||||||
|
ptylist[pty] = NULL;
|
||||||
|
|
||||||
|
spinlock_release(&listlock);
|
||||||
|
interrupt_set(intstatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
static pty_t *allocpty() {
|
||||||
|
pty_t *pty = alloc(sizeof(pty_t));
|
||||||
|
if (pty == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (ringbuffer_init(&pty->ringbuffer, PTY_BUFFER)) {
|
||||||
|
free(pty);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
POLL_INITHEADER(&pty->pollheader);
|
||||||
|
SPINLOCK_INIT(pty->lock);
|
||||||
|
|
||||||
|
return pty;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void freepty(pty_t *pty) {
|
||||||
|
ringbuffer_destroy(&pty->ringbuffer);
|
||||||
|
free(pty);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t writetopty(void *_pty, char *data, size_t size) {
|
||||||
|
pty_t *pty = _pty;
|
||||||
|
bool intstatus = interrupt_set(false);
|
||||||
|
spinlock_acquire(&pty->lock);
|
||||||
|
|
||||||
|
size_t written = ringbuffer_write(&pty->ringbuffer, data, size);
|
||||||
|
poll_event(&pty->pollheader, POLLIN);
|
||||||
|
|
||||||
|
spinlock_release(&pty->lock);
|
||||||
|
interrupt_set(intstatus);
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void inactivepty(void *_pty) {
|
||||||
|
pty_t *pty = _pty;
|
||||||
|
freeptyminor(pty->minor);
|
||||||
|
freepty(pty);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int isatty(int minor) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open(int minor, vnode_t **vnode, int flags);
|
||||||
|
|
||||||
|
static int close(int minor, int flags) {
|
||||||
|
pty_t *pty = ptyget(minor);
|
||||||
|
if (pty == NULL)
|
||||||
|
return ENODEV;
|
||||||
|
|
||||||
|
// TODO do tty cleanup stuff like sending sighup
|
||||||
|
bool intstatus = interrupt_set(false);
|
||||||
|
spinlock_acquire(&pty->lock);
|
||||||
|
pty->hangup = true;
|
||||||
|
spinlock_release(&pty->lock);
|
||||||
|
interrupt_set(intstatus);
|
||||||
|
|
||||||
|
// this should remove the implicit pty -> tty master vnode reference
|
||||||
|
// the master vnode of the pty will be unheld once the close exits
|
||||||
|
// the pty_t structure and minor number will be free once the tty calls the device inactive function,
|
||||||
|
// in case there are still processes with the pts open
|
||||||
|
tty_unregister(pty->tty);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int internalpoll(pty_t *pty, polldata_t *data, int events) {
|
||||||
|
int revents = 0;
|
||||||
|
|
||||||
|
if (events & POLLOUT)
|
||||||
|
revents |= POLLOUT;
|
||||||
|
|
||||||
|
if ((events & POLLIN) && RINGBUFFER_DATACOUNT(&pty->ringbuffer))
|
||||||
|
revents |= POLLIN;
|
||||||
|
|
||||||
|
if (revents == 0 && data)
|
||||||
|
poll_add(&pty->pollheader, data, events);
|
||||||
|
|
||||||
|
return revents;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc) {
|
||||||
|
pty_t *pty = ptyget(minor);
|
||||||
|
if (pty == NULL)
|
||||||
|
return ENODEV;
|
||||||
|
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
polldesc_t desc = {0};
|
||||||
|
int e = poll_initdesc(&desc, 1);
|
||||||
|
if (e)
|
||||||
|
return e;
|
||||||
|
|
||||||
|
bool intstatus = interrupt_set(false);
|
||||||
|
spinlock_acquire(&pty->lock);
|
||||||
|
|
||||||
|
int revents = internalpoll(pty, &desc.data[0], POLLIN);
|
||||||
|
|
||||||
|
if (revents) {
|
||||||
|
*readc = ringbuffer_read(&pty->ringbuffer, buffer, size);
|
||||||
|
|
||||||
|
spinlock_release(&pty->lock);
|
||||||
|
interrupt_set(intstatus);
|
||||||
|
|
||||||
|
poll_leave(&desc);
|
||||||
|
poll_destroydesc(&desc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
spinlock_release(&pty->lock);
|
||||||
|
interrupt_set(intstatus);
|
||||||
|
|
||||||
|
if (flags & V_FFLAGS_NONBLOCKING) {
|
||||||
|
poll_leave(&desc);
|
||||||
|
poll_destroydesc(&desc);
|
||||||
|
return EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
e = poll_dowait(&desc, 0);
|
||||||
|
|
||||||
|
poll_leave(&desc);
|
||||||
|
poll_destroydesc(&desc);
|
||||||
|
|
||||||
|
if (e)
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int poll(int minor, polldata_t *data, int events) {
|
||||||
|
pty_t *pty = ptyget(minor);
|
||||||
|
if (pty == NULL)
|
||||||
|
return POLLERR;
|
||||||
|
|
||||||
|
bool intstatus = interrupt_set(false);
|
||||||
|
spinlock_acquire(&pty->lock);
|
||||||
|
|
||||||
|
int revents = internalpoll(pty, data, events);
|
||||||
|
|
||||||
|
spinlock_release(&pty->lock);
|
||||||
|
interrupt_set(intstatus);
|
||||||
|
|
||||||
|
return revents;
|
||||||
|
}
|
||||||
|
#define TIOCGPTN 0x80045430
|
||||||
|
static int ioctl(int minor, unsigned long request, void *_arg, int *result) {
|
||||||
|
pty_t *pty = ptyget(minor);
|
||||||
|
if (pty == NULL)
|
||||||
|
return ENODEV;
|
||||||
|
|
||||||
|
switch (request) {
|
||||||
|
case TIOCGPTN:
|
||||||
|
{
|
||||||
|
int *arg = _arg;
|
||||||
|
*arg = pty->minor;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ENOTTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *writec) {
|
||||||
|
pty_t *pty = ptyget(minor);
|
||||||
|
if (pty == NULL)
|
||||||
|
return ENODEV;
|
||||||
|
|
||||||
|
char *str = buffer;
|
||||||
|
|
||||||
|
for (int i = 0; i < size; ++i)
|
||||||
|
tty_process(pty->tty, str[i]);
|
||||||
|
|
||||||
|
*writec = size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static devops_t devops = {
|
||||||
|
.open = open,
|
||||||
|
.isatty = isatty,
|
||||||
|
.write = write,
|
||||||
|
.close = close,
|
||||||
|
.poll = poll,
|
||||||
|
.read = read,
|
||||||
|
.ioctl = ioctl
|
||||||
|
};
|
||||||
|
|
||||||
|
static int open(int oldminor, vnode_t **vnode, int flags) {
|
||||||
|
if (oldminor != PTMX_MINOR)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
pty_t *pty = allocpty();
|
||||||
|
if (pty == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
|
||||||
|
int newminor = allocateptyminor(pty);
|
||||||
|
if (newminor == PTMX_MINOR) {
|
||||||
|
freepty(pty);
|
||||||
|
return ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
pty->minor = newminor;
|
||||||
|
|
||||||
|
char tmpname[20];
|
||||||
|
snprintf(tmpname, 20, ".ptmx%d", newminor);
|
||||||
|
|
||||||
|
// register a master device and immediatelly remove it from the filesystem and tables
|
||||||
|
// while holding the refcount
|
||||||
|
int error = devfs_register(&devops, tmpname, V_TYPE_CHDEV, DEV_MAJOR_PTY, newminor, 0644);
|
||||||
|
if (error) {
|
||||||
|
freeptyminor(newminor);
|
||||||
|
freepty(pty);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
__assert(devfs_getbyname(tmpname, &pty->mastervnode) == 0);
|
||||||
|
|
||||||
|
devfs_remove(tmpname, DEV_MAJOR_PTY, newminor);
|
||||||
|
|
||||||
|
// we are now the only ones to hold the master vnode and its inaccessible from devfs
|
||||||
|
// create a pairing slave device
|
||||||
|
|
||||||
|
snprintf(tmpname, 20, "pts/%d", newminor);
|
||||||
|
pty->tty = tty_create(tmpname, writetopty, inactivepty, pty);
|
||||||
|
if (pty->tty == NULL) {
|
||||||
|
VOP_RELEASE(pty->mastervnode);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// theres an implicit pty -> tty reference to the master vnode,
|
||||||
|
// as the pts/* link will ALWAYS exist as long as the pty has not closed
|
||||||
|
|
||||||
|
VOP_RELEASE(*vnode);
|
||||||
|
*vnode = pty->mastervnode;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pty_init() {
|
||||||
|
__assert(devfs_register(&devops, "ptmx", V_TYPE_CHDEV, DEV_MAJOR_PTY, PTMX_MINOR, 0644) == 0);
|
||||||
|
__assert(devfs_createdir("pts") == 0);
|
||||||
|
SPINLOCK_INIT(listlock);
|
||||||
|
}
|
||||||
+32
-15
@@ -31,7 +31,7 @@ void tty_process(tty_t *tty, char c) {
|
|||||||
tty->devicebuffer[tty->devicepos] = '\0';
|
tty->devicebuffer[tty->devicepos] = '\0';
|
||||||
|
|
||||||
if (tty->termios.c_lflag & ECHO)
|
if (tty->termios.c_lflag & ECHO)
|
||||||
tty->writetodevice("\b \b", 3);
|
tty->writetodevice(tty->deviceinternal, "\b \b", 3);
|
||||||
return;
|
return;
|
||||||
} else if (c == '\n') {
|
} else if (c == '\n') {
|
||||||
// newline
|
// newline
|
||||||
@@ -39,7 +39,7 @@ void tty_process(tty_t *tty, char c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tty->termios.c_lflag & ECHO)
|
if (tty->termios.c_lflag & ECHO)
|
||||||
tty->writetodevice(&c, 1);
|
tty->writetodevice(tty->deviceinternal, &c, 1);
|
||||||
|
|
||||||
// check if buffer is full
|
// check if buffer is full
|
||||||
tty->devicebuffer[tty->devicepos++] = c;
|
tty->devicebuffer[tty->devicepos++] = c;
|
||||||
@@ -59,7 +59,7 @@ void tty_process(tty_t *tty, char c) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (tty->termios.c_lflag & ECHO)
|
if (tty->termios.c_lflag & ECHO)
|
||||||
tty->writetodevice(&c, 1);
|
tty->writetodevice(tty->deviceinternal, &c, 1);
|
||||||
|
|
||||||
MUTEX_ACQUIRE(&tty->readmutex, false);
|
MUTEX_ACQUIRE(&tty->readmutex, false);
|
||||||
|
|
||||||
@@ -89,11 +89,11 @@ static int internalpoll(tty_t *tty, polldata_t *data, int events) {
|
|||||||
if ((events & POLLIN) && RINGBUFFER_DATACOUNT(&tty->readbuffer))
|
if ((events & POLLIN) && RINGBUFFER_DATACOUNT(&tty->readbuffer))
|
||||||
revents |= POLLIN;
|
revents |= POLLIN;
|
||||||
|
|
||||||
MUTEX_RELEASE(&tty->readmutex);
|
|
||||||
|
|
||||||
if (revents == 0 && data)
|
if (revents == 0 && data)
|
||||||
poll_add(&tty->pollheader, data, events);
|
poll_add(&tty->pollheader, data, events);
|
||||||
|
|
||||||
|
MUTEX_RELEASE(&tty->readmutex);
|
||||||
|
|
||||||
return revents;
|
return revents;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +199,7 @@ static int write(int minor, void *buffer, size_t size, uintmax_t offset, int fla
|
|||||||
|
|
||||||
// TODO background process stuff etc
|
// TODO background process stuff etc
|
||||||
*writec = size;
|
*writec = size;
|
||||||
tty->writetodevice(buffer, size);
|
tty->writetodevice(tty->deviceinternal, buffer, size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,16 +283,35 @@ static void freeminor(int minor) {
|
|||||||
MUTEX_RELEASE(&listmutex);
|
MUTEX_RELEASE(&listmutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tty_destroy(tty_t *tty) {
|
||||||
|
freeminor(tty->minor);
|
||||||
|
ringbuffer_destroy(&tty->readbuffer);
|
||||||
|
free(tty->devicebuffer);
|
||||||
|
free(tty->name);
|
||||||
|
free(tty);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void inactive(int minor) {
|
||||||
|
tty_t *tty = ttyget(minor);
|
||||||
|
__assert(tty);
|
||||||
|
|
||||||
|
if (tty->inactivedevice)
|
||||||
|
tty->inactivedevice(tty->deviceinternal);
|
||||||
|
|
||||||
|
tty_destroy(tty);
|
||||||
|
}
|
||||||
|
|
||||||
static devops_t devops = {
|
static devops_t devops = {
|
||||||
.write = write,
|
.write = write,
|
||||||
.poll = poll,
|
.poll = poll,
|
||||||
.read = read,
|
.read = read,
|
||||||
.ioctl = ioctl,
|
.ioctl = ioctl,
|
||||||
.isatty = isatty,
|
.isatty = isatty,
|
||||||
.open = open
|
.open = open,
|
||||||
|
.inactive = inactive
|
||||||
};
|
};
|
||||||
|
|
||||||
tty_t *tty_create(char *name, ttydevicewritefn_t fn) {
|
tty_t *tty_create(char *name, ttydevicewritefn_t writefn, ttyinactivefn_t inactivefn, void *internal) {
|
||||||
tty_t *tty = alloc(sizeof(tty_t));
|
tty_t *tty = alloc(sizeof(tty_t));
|
||||||
if (tty == NULL)
|
if (tty == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -332,14 +351,15 @@ tty_t *tty_create(char *name, ttydevicewritefn_t fn) {
|
|||||||
tty->termios.obaud = 38400;
|
tty->termios.obaud = 38400;
|
||||||
tty->termios.c_cc[VMIN] = 1;
|
tty->termios.c_cc[VMIN] = 1;
|
||||||
|
|
||||||
tty->writetodevice = fn;
|
tty->writetodevice = writefn;
|
||||||
|
tty->inactivedevice = inactivefn;
|
||||||
tty->minor = minor;
|
tty->minor = minor;
|
||||||
|
tty->deviceinternal = internal;
|
||||||
|
|
||||||
vnode_t *newnode;
|
vnode_t *newnode;
|
||||||
__assert(devfs_getnode(NULL, DEV_MAJOR_TTY, minor, &newnode) == 0);
|
__assert(devfs_getnode(NULL, DEV_MAJOR_TTY, minor, &newnode) == 0);
|
||||||
|
|
||||||
tty->mastervnode = (vnode_t *)((devnode_t *)newnode)->master;
|
tty->mastervnode = (vnode_t *)((devnode_t *)newnode)->master;
|
||||||
VOP_HOLD(tty->mastervnode);
|
|
||||||
|
|
||||||
VOP_RELEASE(newnode);
|
VOP_RELEASE(newnode);
|
||||||
|
|
||||||
@@ -355,13 +375,10 @@ tty_t *tty_create(char *name, ttydevicewritefn_t fn) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tty_unregister(char *name, tty_t *tty) {
|
void tty_unregister(tty_t *tty) {
|
||||||
|
devfs_remove(tty->name, DEV_MAJOR_TTY, tty->minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tty_destroy(char *name, tty_t *tty) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void tty_init() {
|
void tty_init() {
|
||||||
__assert(devfs_register(&devops, "tty", V_TYPE_CHDEV, DEV_MAJOR_TTY, CONTROLLING_TTY_MINOR, 0644) == 0);
|
__assert(devfs_register(&devops, "tty", V_TYPE_CHDEV, DEV_MAJOR_TTY, CONTROLLING_TTY_MINOR, 0644) == 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user