#define _CONSOLE_H
#include <klibc/extern.h>
+#include <dev.h>
-struct dev_info;
-__extern int openconsole(const struct dev_info *);
+__extern int openconsole(const struct input_dev *, const struct output_dev *);
/* Standard line-oriented console */
-extern const struct dev_info dev_stdcon;
+extern const struct input_dev dev_stdcon_r;
+extern const struct output_dev dev_stdcon_w;
/* Raw character-oriented console */
-extern const struct dev_info dev_rawcon;
+extern const struct input_dev dev_rawcon_r;
+extern const struct output_dev dev_rawcon_w;
#endif /* _CONSOLE_H */
--- /dev/null
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * console.h
+ *
+ * Alternative consoles
+ */
+
+#ifndef _DEV_H
+#define _DEV_H
+
+#include <klibc/extern.h>
+#include <stdint.h>
+
+struct input_dev;
+struct output_dev;
+
+__extern int opendev(const struct input_dev *, const struct output_dev *, int);
+
+/* Common generic devices */
+extern const struct input_dev dev_null_r;
+extern const struct output_dev dev_null_w;
+
+extern const struct input_dev dev_error_r;
+extern const struct output_dev dev_error_w;
+
+#endif /* _DEV_H */
+
__extern __noreturn _exit(int);
__extern int open(const char *, int, ...);
-struct dev_info;
-__extern int opendev(const struct dev_info *, int);
__extern int close(int);
__extern ssize_t read(int, void *, size_t);
libgcc/__moddi3.o sys/entry.o sys/exit.o sys/fileinfo.o \
sys/opendev.o sys/read.o sys/write.o sys/close.o sys/open.o \
sys/fileread.o sys/fileclose.o sys/isatty.o sys/openconsole.o \
- sys/line_input.o sys/stdcon.o sys/stdcon_write.o \
- sys/stdcon_read.o sys/rawcon.o sys/rawcon_write.o \
- sys/rawcon_read.o
+ sys/line_input.o \
+ sys/stdcon_read.o sys/stdcon_write.o \
+ sys/rawcon_read.o sys/rawcon_write.o \
+ sys/err_read.o sys/err_write.o \
+ sys/null_read.o sys/null_write.o \
all: libcom32.a
struct file_info *fp = &__file_info[fd];
int rv = 0;
- if ( fd >= NFILES || !fp->ops ) {
+ if ( fd >= NFILES || !fp->iop || !fp->oop ) {
errno = EBADF;
return -1;
}
- if ( fp->ops->close ) {
- rv = fp->ops->close(fp);
+ if ( fp->iop->close ) {
+ rv = fp->iop->close(fp);
+ if ( rv )
+ return rv;
+ }
+
+ if ( fp->oop->close ) {
+ rv = fp->oop->close(fp);
if ( rv )
return rv;
}
* ----------------------------------------------------------------------- */
/*
- * rawcon.c
+ * err_read.c
*
- * Raw console
+ * Reading from a device which doesn't support reading
*/
#include <errno.h>
#include <string.h>
#include <com32.h>
#include <minmax.h>
-#include <fcntl.h>
-#include <console.h>
#include "file.h"
-extern ssize_t __rawcon_read(struct file_info *, void *, size_t);
-extern ssize_t __rawcon_write(struct file_info *, const void *, size_t);
+static ssize_t __err_read(struct file_info *fp, void *buf, size_t count)
+{
+ (void)fp; (void)buf; (void)count;
+ errno = -EINVAL;
+ return -1;
+}
-const struct dev_info dev_rawcon = {
- .dev_magic = __DEV_MAGIC,
- .flags = __DEV_TTY,
- .fileflags = O_RDWR|O_CREAT|O_TRUNC|O_APPEND,
- .read = __rawcon_read,
- .write = __rawcon_write,
- .close = NULL,
+const struct input_dev dev_error_r = {
+ .dev_magic = __DEV_MAGIC,
+ .flags = __DEV_INPUT | __DEV_ERROR,
+ .fileflags = O_RDONLY,
+ .read = __err_read,
+ .close = NULL,
};
* ----------------------------------------------------------------------- */
/*
- * stdcon.c
+ * err_write.c
*
- * Default console
+ * Writing to a device which doesn't support writing
*/
#include <errno.h>
#include <string.h>
#include <com32.h>
#include <minmax.h>
-#include <fcntl.h>
-#include <console.h>
#include "file.h"
-extern ssize_t __stdcon_read(struct file_info *, void *, size_t);
-extern ssize_t __stdcon_write(struct file_info *, const void *, size_t);
+static ssize_t __err_write(struct file_info *fp, const void *buf, size_t count)
+{
+ (void)fp; (void)buf; (void)count;
+ errno = -EINVAL;
+ return -1;
+}
-const struct dev_info dev_stdcon = {
- .dev_magic = __DEV_MAGIC,
- .flags = __DEV_TTY,
- .fileflags = O_RDWR|O_CREAT|O_TRUNC|O_APPEND,
- .read = __stdcon_read,
- .write = __stdcon_write,
- .close = NULL,
+const struct output_dev dev_error_w = {
+ .dev_magic = __DEV_MAGIC,
+ .flags = __DEV_OUTPUT | __DEV_ERROR,
+ .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND,
+ .write = __err_write,
+ .close = NULL,
};
#ident "$Id$"
/* ----------------------------------------------------------------------- *
*
- * Copyright 2003 H. Peter Anvin - All Rights Reserved
+ * Copyright 2003-2004 H. Peter Anvin - All Rights Reserved
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
#include <inttypes.h>
#include <stdlib.h>
#include <sys/types.h>
+#include <dev.h>
+#include <fcntl.h>
/* Device structure; contains the relevant operations */
#define __DEV_MAGIC 0xf4e7
#define __DEV_TTY 0x0001 /* TTY - must be bit 0 */
#define __DEV_FILE 0x0002 /* Ordinary file */
-struct dev_info {
+#define __DEV_OUTPUT 0x0004 /* This is an output device */
+#define __DEV_INPUT 0 /* Dummy */
+#define __DEV_ERROR 0x0008 /* This is the error device */
+#define __DEV_NULL 0x0010 /* This is the null device */
+
+struct input_dev {
uint16_t dev_magic; /* Magic number */
uint16_t flags; /* Flags */
int fileflags; /* Permitted file flags */
ssize_t (*read)(struct file_info *, void *, size_t);
+ int (*close)(struct file_info *);
+};
+struct output_dev {
+ uint16_t dev_magic; /* Magic number */
+ uint16_t flags; /* Flags */
+ int fileflags;
ssize_t (*write)(struct file_info *, const void *, size_t);
int (*close)(struct file_info *);
};
#define MAXBLOCK 16384 /* Defined by ABI */
struct file_info {
- const struct dev_info *ops; /* Operations structure */
+ const struct input_dev *iop; /* Input operations */
+ const struct output_dev *oop; /* Output operations */
- union {
- /* Structure used for ordinary files */
- struct {
- int blocklg2; /* Blocksize log 2 */
- size_t offset; /* Current file offset */
- size_t length; /* Total file length */
- uint16_t filedes; /* File descriptor */
- uint16_t _filler; /* Unused */
- size_t nbytes; /* Number of bytes available in buffer */
- char *datap; /* Current data pointer */
- char buf[MAXBLOCK];
- } f;
- } p;
+ /* Structure used for input blocking */
+ struct {
+ int blocklg2; /* Blocksize log 2 */
+ size_t offset; /* Current file offset */
+ size_t length; /* Total file length */
+ uint16_t filedes; /* File descriptor */
+ uint16_t _filler; /* Unused */
+ size_t nbytes; /* Number of bytes available in buffer */
+ char *datap; /* Current data pointer */
+ char buf[MAXBLOCK];
+ } i;
};
extern struct file_info __file_info[NFILES];
{
com32sys_t regs;
- if ( fp->p.f.filedes ) {
+ if ( fp->i.filedes ) {
memset(®s, 0, sizeof regs);
regs.eax.w[0] = 0x0008; /* Close file */
- regs.esi.w[0] = fp->p.f.filedes;
+ regs.esi.w[0] = fp->i.filedes;
__com32.cs_intcall(0x22, ®s, NULL);
}
ireg.es = SEG(__com32.cs_bounce);
while ( count ) {
- if ( fp->p.f.nbytes == 0 ) {
- if ( fp->p.f.offset >= fp->p.f.length || !fp->p.f.filedes )
+ if ( fp->i.nbytes == 0 ) {
+ if ( fp->i.offset >= fp->i.length || !fp->i.filedes )
return n; /* As good as it gets... */
- ireg.esi.w[0] = fp->p.f.filedes;
- ireg.ecx.w[0] = MAXBLOCK >> fp->p.f.blocklg2;
+ ireg.esi.w[0] = fp->i.filedes;
+ ireg.ecx.w[0] = MAXBLOCK >> fp->i.blocklg2;
__intcall(0x22, &ireg, &oreg);
return -1;
}
- fp->p.f.filedes = ireg.esi.w[0];
- fp->p.f.nbytes = min(fp->p.f.length-fp->p.f.offset, (unsigned)MAXBLOCK);
- fp->p.f.datap = fp->p.f.buf;
- memcpy(fp->p.f.buf, __com32.cs_bounce, fp->p.f.nbytes);
+ fp->i.filedes = ireg.esi.w[0];
+ fp->i.nbytes = min(fp->i.length-fp->i.offset, (unsigned)MAXBLOCK);
+ fp->i.datap = fp->i.buf;
+ memcpy(fp->i.buf, __com32.cs_bounce, fp->i.nbytes);
}
- ncopy = min(count, fp->p.f.nbytes);
- memcpy(bufp, fp->p.f.datap, ncopy);
+ ncopy = min(count, fp->i.nbytes);
+ memcpy(bufp, fp->i.datap, ncopy);
n += ncopy;
bufp += ncopy;
count -= ncopy;
- fp->p.f.datap += ncopy;
- fp->p.f.offset += ncopy;
- fp->p.f.nbytes -= ncopy;
+ fp->i.datap += ncopy;
+ fp->i.offset += ncopy;
+ fp->i.nbytes -= ncopy;
}
return n;
{
struct file_info *fp = &__file_info[fd];
- if ( fd >= NFILES || !fp->ops ) {
+ if ( fd >= NFILES || !fp->iop ) {
errno = EBADF;
return -1;
}
- return (fp->ops->flags & __DEV_TTY);
+ return (fp->iop->flags & __DEV_TTY);
}
{
size_t n = 0;
char ch;
+ ssize_t (* const Write)(struct file_info *, const void *, size_t) =
+ fp->oop->write;
for(;;) {
if ( get_char(fp, &ch, 1) != 1 )
switch ( ch ) {
case '\r':
*buf = '\n';
- fp->ops->write(fp, "\n", 1);
+ Write(fp, "\n", 1);
return n+1;
case '\b':
if ( n > 0 ) {
n--; buf--;
- fp->ops->write(fp, "\b \b", 3);
+ Write(fp, "\b \b", 3);
}
break;
case '\x15': /* Ctrl-U */
while ( n ) {
n--; buf--;
- fp->ops->write(fp, "\b \b", 3);
+ Write(fp, "\b \b", 3);
}
break;
default:
if ( n < bufsize-1 ) {
*buf = ch;
- fp->ops->write(fp, buf, 1);
+ Write(fp, buf, 1);
n++;
buf++;
}
--- /dev/null
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * null_read.c
+ *
+ * Reading null device
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <com32.h>
+#include <minmax.h>
+#include "file.h"
+
+static ssize_t __null_read(struct file_info *fp, void *buf, size_t count)
+{
+ (void)fp; (void)buf; (void)count;
+ return 0;
+}
+
+const struct input_dev dev_null_r = {
+ .dev_magic = __DEV_MAGIC,
+ .flags = __DEV_INPUT | __DEV_NULL,
+ .fileflags = O_RDONLY,
+ .read = __null_read,
+ .close = NULL,
+};
--- /dev/null
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * null_write.c
+ *
+ * Null writing device
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <com32.h>
+#include <minmax.h>
+#include "file.h"
+
+static ssize_t __null_write(struct file_info *fp, const void *buf, size_t count)
+{
+ (void)fp; (void)buf; (void)count;
+ return count;
+}
+
+const struct output_dev dev_null_w = {
+ .dev_magic = __DEV_MAGIC,
+ .flags = __DEV_OUTPUT | __DEV_NULL,
+ .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND,
+ .write = __null_write,
+ .close = NULL,
+};
extern ssize_t __file_read(struct file_info *, void *, size_t);
extern int __file_close(struct file_info *);
-static const struct dev_info file_dev = {
+static const struct input_dev file_dev = {
.dev_magic = __DEV_MAGIC,
- .flags = __DEV_FILE,
+ .flags = __DEV_FILE | __DEV_INPUT,
.fileflags = O_RDONLY,
.read = __file_read,
- .write = NULL, /* File writes are not supported */
.close = __file_close,
};
int fd;
struct file_info *fp;
- fd = opendev(&file_dev, flags);
+ fd = opendev(&file_dev, NULL, flags);
if ( fd < 0 )
return -1;
{
uint16_t blklg2;
asm("bsrw %1,%0" : "=r" (blklg2) : "rm" (regs.ecx.w[0]));
- fp->p.f.blocklg2 = blklg2;
+ fp->i.blocklg2 = blklg2;
}
- fp->p.f.length = regs.eax.l;
- fp->p.f.filedes = regs.esi.w[0];
- fp->p.f.offset = 0;
- fp->p.f.nbytes = 0;
+ fp->i.length = regs.eax.l;
+ fp->i.filedes = regs.esi.w[0];
+ fp->i.offset = 0;
+ fp->i.nbytes = 0;
return fd;
}
#include <console.h>
#include <fcntl.h>
-int openconsole(const struct dev_info *dev)
+int openconsole(const struct input_dev *idev, const struct output_dev *odev)
{
close(0);
- if ( opendev(dev, O_RDONLY) != 0 )
+ if ( opendev(idev, odev, O_RDONLY) != 0 )
return -1;
close(1);
- if ( opendev(dev, O_WRONLY) != 1 )
+ if ( opendev(idev, odev, O_WRONLY) != 1 )
return -1;
close(2);
- if ( opendev(dev, O_WRONLY) != 2 )
+ if ( opendev(idev, odev, O_WRONLY) != 2 )
return -1;
return 0;
* Open a special device
*/
-int opendev(const struct dev_info *dev, int flags)
+int opendev(const struct input_dev *idev, const struct output_dev *odev, int flags)
{
int fd;
struct file_info *fp;
-
- if ( !(flags & 3) || (flags & ~dev->fileflags) ) {
+ int okflags;
+
+ okflags = (idev ? idev->fileflags : 0) | (odev ? odev->fileflags : 0);
+
+ if ( !(flags & 3) || (flags & ~okflags) ) {
errno = EINVAL;
return -1;
}
for ( fd = 0, fp = __file_info ; fd < NFILES ; fd++, fp++ )
- if ( !fp->ops )
+ if ( !fp->iop && !fp->oop )
break;
if ( fd >= NFILES ) {
return -1;
}
- fp->ops = dev;
- fp->p.f.offset = 0;
- fp->p.f.nbytes = 0;
- fp->p.f.datap = fp->p.f.buf;
+ fp->iop = idev ? idev : &dev_error_r;
+ fp->oop = odev ? odev : &dev_error_w;
+ fp->i.offset = 0;
+ fp->i.nbytes = 0;
+ fp->i.datap = fp->i.buf;
return fd;
}
#include <minmax.h>
#include "file.h"
+/* Global, since it's used by stdcon_read */
ssize_t __rawcon_read(struct file_info *fp, void *buf, size_t count)
{
com32sys_t ireg, oreg;
return n;
}
+
+const struct input_dev dev_rawcon_r = {
+ .dev_magic = __DEV_MAGIC,
+ .flags = __DEV_TTY | __DEV_INPUT,
+ .fileflags = O_RDONLY,
+ .read = __rawcon_read,
+ .close = NULL,
+};
#include <minmax.h>
#include "file.h"
-ssize_t __rawcon_write(struct file_info *fp, const void *buf, size_t count)
+static ssize_t __rawcon_write(struct file_info *fp, const void *buf, size_t count)
{
com32sys_t ireg;
const char *bufp = buf;
return n;
}
+
+const struct output_dev dev_rawcon_w = {
+ .dev_magic = __DEV_MAGIC,
+ .flags = __DEV_TTY | __DEV_OUTPUT,
+ .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND,
+ .write = __rawcon_write,
+ .close = NULL,
+};
{
struct file_info *fp = &__file_info[fd];
- if ( fd >= NFILES || !fp->ops ) {
+ if ( fd >= NFILES || !fp->iop ) {
errno = EBADF;
return -1;
}
- if ( __unlikely(!fp->ops->read) ) {
- errno = EINVAL;
- return -1;
- }
-
- return fp->ops->read(fp, buf, count);
+ return fp->iop->read(fp, buf, count);
}
extern ssize_t __rawcon_read(struct file_info *fp, void *buf, size_t count);
-ssize_t __stdcon_read(struct file_info *fp, void *buf, size_t count)
+static ssize_t __stdcon_read(struct file_info *fp, void *buf, size_t count)
{
char *bufp = buf;
size_t n = 0;
(void)fp;
while ( n < count ) {
- if ( fp->p.f.nbytes ) {
- ch = *bufp++ = *fp->p.f.datap++;
- fp->p.f.nbytes--;
+ if ( fp->i.nbytes ) {
+ ch = *bufp++ = *fp->i.datap++;
+ fp->i.nbytes--;
n++;
if ( ch == '\n' )
return n;
} else {
- fp->p.f.nbytes = __line_input(fp, fp->p.f.buf, MAXBLOCK,
+ fp->i.nbytes = __line_input(fp, fp->i.buf, MAXBLOCK,
__rawcon_read);
- fp->p.f.datap = fp->p.f.buf;
+ fp->i.datap = fp->i.buf;
- if ( fp->p.f.nbytes == 0 )
+ if ( fp->i.nbytes == 0 )
return n;
}
}
return n;
}
+
+const struct input_dev dev_stdcon_r = {
+ .dev_magic = __DEV_MAGIC,
+ .flags = __DEV_TTY | __DEV_INPUT,
+ .fileflags = O_RDONLY,
+ .read = __stdcon_read,
+ .close = NULL,
+};
#include <minmax.h>
#include "file.h"
-ssize_t __stdcon_write(struct file_info *fp, const void *buf, size_t count)
+static ssize_t __stdcon_write(struct file_info *fp, const void *buf, size_t count)
{
com32sys_t ireg;
const char *bufp = buf;
return n;
}
+
+const struct output_dev dev_stdcon_w = {
+ .dev_magic = __DEV_MAGIC,
+ .flags = __DEV_TTY | __DEV_OUTPUT,
+ .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND,
+ .write = __stdcon_write,
+ .close = NULL,
+};
{
struct file_info *fp = &__file_info[fd];
- if ( fd >= NFILES || !fp->ops ) {
+ if ( fd >= NFILES || !fp->oop ) {
errno = EBADF;
return -1;
}
- if ( __unlikely(!fp->ops->write) ) {
- errno = EINVAL;
- return -1;
- }
-
- return fp->ops->write(fp, buf, count);
+ return fp->oop->write(fp, buf, count);
}
{
char buffer[1024];
- openconsole(&dev_stdcon);
+ openconsole(&dev_stdcon_r, &dev_stdcon_w);
printf("Hello, World!\n");