summaryrefslogtreecommitdiff
path: root/console
diff options
context:
space:
mode:
Diffstat (limited to 'console')
-rw-r--r--console/Makefile34
-rw-r--r--console/bdf.c986
-rw-r--r--console/bdf.h272
-rw-r--r--console/console.c511
-rw-r--r--console/console.h98
-rw-r--r--console/display.h79
-rw-r--r--console/dynafont.c371
-rw-r--r--console/dynafont.h74
-rw-r--r--console/focus.c110
-rw-r--r--console/focus.h31
-rw-r--r--console/input.h62
-rw-r--r--console/main.c461
-rw-r--r--console/mutations.h26
-rw-r--r--console/priv.h1
-rw-r--r--console/vga-display.c832
-rw-r--r--console/vga-hw.h111
-rw-r--r--console/vga.c189
-rw-r--r--console/vga.h62
18 files changed, 4310 insertions, 0 deletions
diff --git a/console/Makefile b/console/Makefile
new file mode 100644
index 00000000..b44c583d
--- /dev/null
+++ b/console/Makefile
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2002 Free Software Foundation, Inc.
+# Written by Marcus Brinkmann.
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# The GNU Hurd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+
+dir := console
+makemode := server
+
+target = console
+SRCS = main.c console.c focus.c vga-display.c vga.c dynafont.c bdf.c
+LCLHDRS = focus.h input.h console.h display.h vga.h vga-hw.h dynafont.h bdf.h \
+ mutations.h priv.h
+
+HURDLIBS = trivfs fshelp iohelp threads ports ihash shouldbeinlibc
+OBJS = $(subst .c,.o,$(SRCS)) tioctlServer.o
+
+MIGSFLAGS += -imacros $(srcdir)/mutations.h
+
+include ../Makeconf
diff --git a/console/bdf.c b/console/bdf.c
new file mode 100644
index 00000000..2e9e02bd
--- /dev/null
+++ b/console/bdf.c
@@ -0,0 +1,986 @@
+/* Adobe Glyph Bitmap Distribution Format (BDF) parser.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann <marcus@gnu.org>.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <search.h>
+
+#include "bdf.h"
+
+
+/* Return a statically allocated string describing the BDF error value
+ ERR. */
+const char *
+bdf_strerror (bdf_error_t err)
+{
+ switch (err)
+ {
+ case BDF_NO_ERROR:
+ return "Success";
+ case BDF_SYSTEM_ERROR:
+ return "System error";
+ case BDF_SYNTAX_ERROR:
+ return "Syntax error";
+ case BDF_INVALID_ARGUMENT:
+ return "Invalid Argument";
+ case BDF_COUNT_MISMATCH:
+ return "Count mismatch";
+ default:
+ return "Unknown error";
+ }
+}
+
+
+/* Copy the string starting from ARG and return the pointer to it in
+ STRING. If QUOTED is true, outer double quotes are stripped, and
+ two consecutive double quotes within the string are replaced by one
+ douple quotes. */
+static bdf_error_t
+parse_string (char *arg, char **string, int quoted)
+{
+ if (quoted)
+ {
+ char *value = ++arg;
+ do
+ {
+ value = strchr (value, '"');
+ if (!value)
+ return BDF_INVALID_ARGUMENT;
+ else if (*(value + 1) == '"')
+ {
+ char *copyp = value++;
+ while (*(++copyp))
+ *(copyp - 1) = *copyp;
+ *(copyp - 1) = 0;
+ }
+ }
+ while (*value != '"' || *(value + 1) == '"');
+ *value = 0;
+ }
+
+ *string = strdup (arg);
+ if (!*string)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ return 0;
+}
+
+
+/* Parse the string STR for format TEMPLATE, and require an exact
+ match. Set err if a parsing error occurs. TEMPLATE must be a
+ string constant. */
+#define parse_template(str, template, rest...) \
+ do \
+ { \
+ int parse_template_count = -1; \
+ sscanf (str, template " %n", rest, &parse_template_count); \
+ if (parse_template_count == -1 || *(str + parse_template_count)) \
+ err = BDF_SYNTAX_ERROR; \
+ } \
+ while (0)
+
+#define hex2nr(c) (((c) >= '0' && (c) <= '9') ? (c) - '0' \
+ : (((c) >= 'a' && (c) <= 'f') ? (c) - 'a' \
+ : (((c) >= 'A' && (c) <= 'F') ? (c) - 'A' : 0)))
+
+/* Convert a two-digit hex number starting from LINE to a char and
+ return the result in BYTE. */
+static bdf_error_t
+parse_hexbyte (char *line, unsigned char *byte)
+{
+ if (!isxdigit (*line) || !isxdigit(*(line + 1)))
+ return BDF_SYNTAX_ERROR;
+ else
+ *byte = (hex2nr (*line) << 4) + hex2nr (*(line + 1));
+ return 0;
+}
+
+
+/* Like getline(), but keeps track of line count in COUNT, skips
+ COMMENT lines, and removes whitespace at the beginning and end of a
+ line. */
+static int
+next_line (char **line, int *size, FILE *file, int *count)
+{
+ int len;
+
+ do
+ {
+ len = getline (line, size, file);
+ if (len >= 0)
+ {
+ char *cline = *line;
+ if (count)
+ (*count)++;
+ if (!strncmp (cline, "COMMENT", 7))
+ len = 0;
+ else
+ while (len > 0 && (cline[len - 1] == '\n' || cline[len - 1] == '\r'
+ || cline[len - 1] == ' '
+ || cline[len - 1] == '\t'))
+ cline[--len] = 0;
+ }
+ }
+ while (len <= 0 && !feof (file) && !ferror (file));
+ return len;
+}
+
+
+/* Isolate the next white-space seperated argument from the current
+ line, and set ARGP to the beginning of the next argument. It is an
+ error if there is no further argument. */
+static bdf_error_t
+find_arg (char **argp)
+{
+ char *arg = *argp;
+
+ arg = strchr (arg, ' ');
+ if (arg)
+ {
+ *(arg++) = 0;
+ while (*arg == ' ' || *arg == '\t')
+ arg++;
+ }
+ if (!arg || !*arg)
+ return BDF_SYNTAX_ERROR;
+ *argp = arg;
+ return 0;
+}
+
+
+/* Read the font from stream FILE, and return it in FONT. If
+ LINECOUNT is not zero, it will contain the number of lines in the
+ file at success, and the line an error occured at failure. */
+bdf_error_t
+bdf_read (FILE *filep, bdf_font_t *font, int *linecount)
+{
+ bdf_error_t err = 0;
+ char *line = 0;
+ int line_size = 0;
+ int len;
+ int done = 0;
+ bdf_font_t bdf;
+ struct
+ {
+ /* Current line. */
+ enum { START, FONT, PROPERTIES, GLYPHS, GLYPH, BITMAP } location;
+ /* The number of properties parsed so far. */
+ int properties;
+ /* The number of glyphs parsed so far. */
+ int glyphs;
+
+ /* True if we have seen a SIZE keyword so far. */
+ int has_size : 1;
+ /* True if we have seen a FONTBOUNDINGBOX keyword so far. */
+ int has_fbbx : 1;
+ /* True if we have seen a METRICSSET keyword so far. */
+ int has_metricsset : 1;
+
+ /* Current glyph. */
+ struct bdf_glyph *glyph;
+ /* True if we have seen an ENCODING keyword for the glyph. */
+ int glyph_has_encoding : 1;
+ /* True if we have seen an BBX keyword for the glyph. */
+ int glyph_has_bbx : 1;
+ /* Width of the glyph in bytes. */
+ int glyph_bwidth;
+ /* Height of the glyph in pixel. */
+ int glyph_bheight;
+ /* How many bitmap lines have been parsed already. */
+ int glyph_blines;
+ } parser = { location: START, properties: 0, glyphs: 0,
+ has_size: 0, has_fbbx: 0 };
+
+ bdf = calloc (1, sizeof *bdf);
+ if (!bdf)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+
+ if (linecount)
+ *linecount = 0;
+
+ while (!err && (len = next_line (&line, &line_size, filep, linecount)) >= 0)
+ {
+ switch (parser.location)
+ {
+ case START:
+ {
+ /* This is the start of the file, only comments are allowed
+ until STARTFONT is encountered. */
+ char *arg = line;
+ err = find_arg (&arg);
+
+ if (err)
+ continue;
+ if (!strcmp (line, "STARTFONT"))
+ {
+ char *minor = strchr (arg, '.');
+ if (minor)
+ *(minor++) = '\0';
+ parser.location = FONT;
+ parse_template (arg, "%i", &bdf->version_maj);
+ if (minor)
+ parse_template (minor, "%i", &bdf->version_min);
+ else
+ bdf->version_min = 0;
+ }
+ else
+ err = BDF_SYNTAX_ERROR;
+ }
+ break;
+
+ case FONT:
+ {
+ /* This is the global header before the CHARS. */
+ char *arg = line;
+ err = find_arg (&arg);
+
+ if (err)
+ continue;
+ else if (!bdf->has_content_version
+ && !strcmp (line, "CONTENTVERSION"))
+ {
+ bdf->has_content_version = 1;
+ parse_template (arg, "%i", &bdf->content_version);
+ }
+ else if (!bdf->name && !strcmp (line, "FONT"))
+ err = parse_string (arg, &bdf->name, 0);
+ else if (!parser.has_size
+ && !strcmp (line, "SIZE"))
+ {
+ parser.has_size = 1;
+ parse_template (arg, "%i%i%i", &bdf->point_size,
+ &bdf->res_x, &bdf->res_y);
+ }
+ else if (!parser.has_fbbx && !strcmp (line, "FONTBOUNDINGBOX"))
+ {
+ parser.has_fbbx = 1;
+ parse_template (arg, "%i%i%i%i", &bdf->bbox.width,
+ &bdf->bbox.height, &bdf->bbox.offx,
+ &bdf->bbox.offy);
+ }
+ else if (!parser.has_metricsset && !strcmp (line, "METRICSSET"))
+ {
+ parser.has_metricsset = 1;
+ parse_template (arg, "%i", &bdf->metricsset);
+ if (!err && (bdf->metricsset < 0
+ || bdf->metricsset > 2))
+ err = BDF_INVALID_ARGUMENT;
+ }
+ else if (!bdf->properties && !strcmp (line, "STARTPROPERTIES"))
+ {
+ parser.location = PROPERTIES;
+ parse_template (arg, "%i", &bdf->properties_count);
+ if (!err && (bdf->properties_count <= 0))
+ err = BDF_INVALID_ARGUMENT;
+ if (err)
+ goto leave;
+ bdf->__properties_allocated = bdf->properties_count;
+ bdf->properties = calloc (bdf->properties_count,
+ sizeof (struct bdf_property));
+ if (!bdf->properties)
+ {
+ errno = ENOMEM;
+ err = BDF_SYSTEM_ERROR;
+ }
+ }
+ else if (!strcmp (line, "CHARS"))
+ {
+ /* This marks the end of the first section, so check
+ for mandatory global options. */
+ if (!bdf->name || !parser.has_size || !parser.has_fbbx)
+ err = BDF_SYNTAX_ERROR;
+ else
+ {
+ parser.location = GLYPHS;
+ parse_template (arg, "%i", &bdf->glyphs_count);
+ if (!err && (bdf->glyphs_count < 0))
+ err = BDF_INVALID_ARGUMENT;
+ if (!err)
+ {
+ bdf->__glyphs_allocated = bdf->glyphs_count;
+ bdf->glyphs = calloc (bdf->glyphs_count,
+ sizeof (struct bdf_glyph));
+ if (!bdf->glyphs)
+ {
+ errno = ENOMEM;
+ err = BDF_SYSTEM_ERROR;
+ }
+ }
+ }
+ }
+ else if (!bdf->has_swidth && !strcmp (line, "SWIDTH"))
+ {
+ bdf->has_swidth = 1;
+ parse_template (arg, "%i%i", &bdf->swidth.x, &bdf->swidth.y);
+ }
+ else if (!bdf->has_dwidth && !strcmp (line, "DWIDTH"))
+ {
+ bdf->has_dwidth = 1;
+ parse_template (arg, "%i%i", &bdf->dwidth.x, &bdf->dwidth.y);
+ }
+ else if (!bdf->has_swidth1 && !strcmp (line, "SWIDTH1"))
+ {
+ bdf->has_swidth1 = 1;
+ parse_template (arg, "%i%i", &bdf->swidth1.x, &bdf->swidth1.y);
+ }
+ else if (!bdf->has_dwidth1 && !strcmp (line, "DWIDTH1"))
+ {
+ bdf->has_dwidth1 = 1;
+ parse_template (arg, "%i%i", &bdf->dwidth1.x, &bdf->dwidth1.y);
+ }
+ else if (!bdf->has_vvector && !strcmp (line, "VVECTOR"))
+ {
+ bdf->has_vvector = 1;
+ parse_template (arg, "%i%i", &bdf->vvector.x, &bdf->vvector.y);
+ }
+ else
+ err = BDF_SYNTAX_ERROR;
+ }
+ break;
+
+ case PROPERTIES:
+ /* This is the property list in the global header, between
+ STARTPROPERTIES and ENDPROPERTIES. */
+ if (!strcmp (line, "ENDPROPERTIES"))
+ {
+ parser.location = FONT;
+ if (parser.properties != bdf->properties_count)
+ err = BDF_COUNT_MISMATCH;
+ }
+ else
+ {
+ if (parser.properties == bdf->properties_count)
+ err = BDF_COUNT_MISMATCH;
+ else
+ {
+ struct bdf_property *prop
+ = &bdf->properties[parser.properties++];
+ char *arg = line;
+
+ err = find_arg (&arg);
+ if (err)
+ continue;
+
+ err = parse_string (line, &prop->name, 0);
+ if (!err)
+ {
+ if (*arg == '"')
+ {
+ prop->type = BDF_PROPERTY_STRING;
+ err = parse_string (arg, &prop->value.string, 1);
+ }
+ else
+ {
+ prop->type = BDF_PROPERTY_NUMBER;
+ parse_template (arg, "%i", &prop->value.number);
+ }
+ }
+ }
+ }
+ break;
+
+ case GLYPHS:
+ /* This is the second section of the file, containing the
+ glyphs. */
+ if (!strcmp (line, "ENDFONT"))
+ {
+ if (parser.glyphs != bdf->glyphs_count)
+ err = BDF_COUNT_MISMATCH;
+ done = 1;
+ }
+ else
+ {
+ char *arg = line;
+
+ err = find_arg (&arg);
+ if (err)
+ continue;
+ else if (!strcmp (line, "STARTCHAR"))
+ {
+ if (parser.glyphs == bdf->glyphs_count)
+ err = BDF_COUNT_MISMATCH;
+
+ parser.location = GLYPH;
+ parser.glyph = &bdf->glyphs[parser.glyphs++];
+ parser.glyph_has_encoding = 0;
+ parser.glyph_has_bbx = 0;
+ parser.glyph_blines = 0;
+ err = parse_string (arg, &(parser.glyph->name), 0);
+ }
+ else
+ err = BDF_SYNTAX_ERROR;
+ }
+ break;
+
+ case GLYPH:
+ /* This is a glyph, but not its bitmap yet. */
+ if (!strcmp (line, "BITMAP"))
+ {
+ if (!parser.glyph_has_encoding
+ || !parser.glyph_has_bbx
+
+ /* In writing mode 0, SWIDTH and DWIDTH are mandatory. */
+ || (bdf->metricsset != 1
+ && (!(parser.glyph->has_swidth || bdf->has_swidth)
+ || !(parser.glyph->has_dwidth || bdf->has_dwidth)))
+
+ /* In writing mode 1, SWIDTH1, DWIDTH1 and VVECTOR
+ are mandatory. */
+ || (bdf->metricsset != 0
+ && (!(parser.glyph->has_swidth1 || bdf->has_swidth1)
+ || !(parser.glyph->has_dwidth1 || bdf->has_dwidth1)
+ || !(parser.glyph->has_vvector
+ || bdf->has_vvector))))
+ err = BDF_SYNTAX_ERROR;
+
+ parser.location = BITMAP;
+ parser.glyph->bitmap = malloc (parser.glyph_bwidth
+ * parser.glyph_bheight);
+ if (!parser.glyph->bitmap)
+ {
+ errno = ENOMEM;
+ err = BDF_SYSTEM_ERROR;
+ }
+ }
+ else
+ {
+ char *arg = line;
+
+ err = find_arg (&arg);
+ if (err)
+ continue;
+ else if (!parser.glyph_has_encoding
+ && !strcmp (line, "ENCODING"))
+ {
+ parser.glyph_has_encoding = 1;
+ parse_template (arg, "%i", &parser.glyph->encoding);
+ if (err == BDF_SYNTAX_ERROR)
+ {
+ err = 0;
+ parse_template (arg, "%i%i", &parser.glyph->encoding,
+ &parser.glyph->internal_encoding);
+ if (!err && parser.glyph->encoding != -1)
+ err = BDF_SYNTAX_ERROR;
+ }
+ }
+ else if (!parser.glyph_has_bbx && !strcmp (line, "BBX"))
+ {
+ parser.glyph_has_bbx = 1;
+ parse_template (arg, "%i%i%i%i", &parser.glyph->bbox.width,
+ &parser.glyph->bbox.height,
+ &parser.glyph->bbox.offx,
+ &parser.glyph->bbox.offy);
+ if (!err)
+ {
+ parser.glyph_bwidth = (parser.glyph->bbox.width + 7) / 8;
+ parser.glyph_bheight = parser.glyph->bbox.height;
+ }
+ }
+ else if (!parser.glyph->has_swidth && !strcmp (line, "SWIDTH"))
+ {
+ parser.glyph->has_swidth = 1;
+ parse_template (arg, "%i%i", &parser.glyph->swidth.x,
+ &parser.glyph->swidth.y);
+ }
+ else if (!parser.glyph->has_dwidth && !strcmp (line, "DWIDTH"))
+ {
+ parser.glyph->has_dwidth = 1;
+ parse_template (arg, "%i%i", &parser.glyph->dwidth.x,
+ &parser.glyph->dwidth.y);
+ }
+ else if (!parser.glyph->has_swidth1 && !strcmp (line, "SWIDTH1"))
+ {
+ parser.glyph->has_swidth1 = 1;
+ parse_template (arg, "%i%i", &parser.glyph->swidth1.x,
+ &parser.glyph->swidth1.y);
+ }
+ else if (!parser.glyph->has_dwidth1 && !strcmp (line, "DWIDTH1"))
+ {
+ parser.glyph->has_dwidth1 = 1;
+ parse_template (arg, "%i%i", &parser.glyph->dwidth1.x,
+ &parser.glyph->dwidth1.y);
+ }
+ else if (!parser.glyph->has_vvector && !strcmp (line, "VVECTOR"))
+ {
+ parser.glyph->has_vvector = 1;
+ parse_template (arg, "%i%i", &parser.glyph->vvector.x,
+ &parser.glyph->vvector.y);
+ }
+ else
+ err = BDF_SYNTAX_ERROR;
+ }
+ break;
+
+ case BITMAP:
+ /* This is the bitmap of a glyph. */
+ if (!strcmp (line, "ENDCHAR"))
+ {
+ if (parser.glyph_blines != parser.glyph_bheight)
+ err = BDF_COUNT_MISMATCH;
+ parser.location = GLYPHS;
+ parser.glyph = 0;
+ }
+ else
+ {
+ if (strlen (line) != 2 * parser.glyph_bwidth)
+ err = BDF_SYNTAX_ERROR;
+ else if (parser.glyph_blines == parser.glyph_bheight)
+ err = BDF_COUNT_MISMATCH;
+ else
+ {
+ char *number = line;
+ unsigned char *bline = parser.glyph->bitmap
+ + parser.glyph_bwidth * parser.glyph_blines++;
+
+ do
+ {
+ err = parse_hexbyte (number, bline);
+ number += 2;
+ bline++;
+ }
+ while (!err && *number);
+ }
+ }
+ break;
+ }
+ }
+ while (!err && !done && !feof (filep) && !ferror (filep));
+
+ leave:
+ if (ferror (filep))
+ err = ferror (filep);
+ if (err)
+ free (bdf);
+ else
+ *font = bdf;
+ return err;
+}
+
+
+/* Destroy the BDF font object and release all associated
+ resources. */
+void
+bdf_destroy (bdf_font_t font)
+{
+ int i;
+ for (i = 0; i < font->glyphs_count; i++)
+ free (font->glyphs[i].name);
+ free (font->glyphs);
+ for (i = 0; i < font->properties_count; i++)
+ {
+ free (font->properties[i].name);
+ if (font->properties[i].type == BDF_PROPERTY_STRING)
+ free (font->properties[i].value.string);
+ }
+ free (font->properties);
+ free (font->name);
+}
+
+
+bdf_error_t
+bdf_new (bdf_font_t *font, int version_maj, int version_min,
+ const char *name, int point_size, int res_x, int res_y,
+ int bbox_width, int bbox_height, int bbox_offx, int bbox_offy,
+ int metricsset)
+{
+ bdf_font_t bdf;
+
+ if (!font
+ || (version_maj != 2)
+ || (version_min != 1 && version_min != 2)
+ || !name)
+ return BDF_INVALID_ARGUMENT;
+
+ bdf = calloc (1, sizeof *bdf);
+ if (!bdf)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+
+ bdf->version_maj = version_maj;
+ bdf->version_min = version_min;
+ bdf->name = strdup (name);
+ if (!name)
+ {
+ free (bdf);
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+
+ bdf->point_size = point_size;
+ bdf->res_x = res_x;
+ bdf->res_y = res_y;
+ bdf->bbox.width = bbox_width;
+ bdf->bbox.height = bbox_height;
+ bdf->bbox.offx = bbox_offx;
+ bdf->bbox.offy = bbox_offy;
+ bdf->metricsset = metricsset;
+ *font = bdf;
+ return 0;
+}
+
+#define bdf_set_something(what) \
+bdf_error_t \
+bdf_set_##what (bdf_font_t font, int glyph, int x, int y) \
+{ \
+ if (x < 0 || y < 0 || glyph > font->glyphs_count - 1) \
+ return BDF_INVALID_ARGUMENT; \
+ if (glyph < 0) \
+ { \
+ font->has_##what = 1; \
+ font->what.x = x; \
+ font->what.y = y; \
+ } \
+ else \
+ { \
+ font->glyphs[glyph].has_##what = 1; \
+ font->glyphs[glyph].what.x = x; \
+ font->glyphs[glyph].what.y = y; \
+ } \
+ return 0; \
+}
+
+bdf_set_something (swidth)
+bdf_set_something (dwidth)
+bdf_set_something (swidth1)
+bdf_set_something (dwidth1)
+bdf_set_something (vvector)
+
+
+static bdf_error_t
+expand_properties (bdf_font_t font, int count)
+{
+ if (font->__properties_allocated == font->properties_count)
+ {
+ struct bdf_property *new;
+ new = realloc (font->properties,
+ (font->__properties_allocated + count)
+ * sizeof (struct bdf_property));
+ if (!new)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ font->__properties_allocated += count;
+ font->properties = new;
+ }
+ return 0;
+}
+
+
+/* Add a new string property to the font FONT. */
+bdf_error_t
+bdf_add_string_property (bdf_font_t font, const char *name, const char *value)
+{
+ bdf_error_t err;
+ struct bdf_property *prop;
+
+ err = expand_properties (font, 16);
+ if (err)
+ {
+ err = expand_properties (font, 1);
+ if (err)
+ return err;
+ }
+
+ prop = &font->properties[font->properties_count];
+ prop->type = BDF_PROPERTY_STRING;
+ prop->name = strdup (name);
+ if (prop->name)
+ prop->value.string = strdup (value);
+ if (!prop->name || !prop->value.string)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ font->properties_count++;
+ return 0;
+}
+
+
+/* Add a new number property to the font FONT. */
+bdf_error_t
+bdf_add_number_property (bdf_font_t font, const char *name, int value)
+{
+ bdf_error_t err;
+ struct bdf_property *prop;
+
+ err = expand_properties (font, 16);
+ if (err)
+ {
+ err = expand_properties (font, 1);
+ if (err)
+ return err;
+ }
+
+ prop = &font->properties[font->properties_count];
+ prop->type = BDF_PROPERTY_NUMBER;
+ prop->name = strdup (name);
+ if (!prop->name)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ prop->value.number = value;
+ font->properties_count++;
+ return 0;
+}
+
+
+static bdf_error_t
+expand_glyphs (bdf_font_t font, int count)
+{
+ if (font->__glyphs_allocated == font->glyphs_count)
+ {
+ struct bdf_glyph *new;
+ new = realloc (font->glyphs,
+ (font->__glyphs_allocated + count)
+ * sizeof (struct bdf_glyph));
+ if (!new)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ font->__glyphs_allocated += count;
+ font->glyphs = new;
+ }
+ return 0;
+}
+
+
+/* Add a new glyph with the specified paramters to the font FONT. If
+ encoding is -1, internal_encoding specifies the internal
+ encoding. All other parameters are mandatory. */
+bdf_error_t
+bdf_add_glyph (bdf_font_t font, const char *name, int encoding,
+ int internal_encoding, int bbox_width, int bbox_height,
+ int bbox_offx, int bbox_offy, const unsigned char *bitmap)
+{
+ bdf_error_t err;
+ struct bdf_glyph *glyph;
+ int bsize;
+
+ err = expand_glyphs (font, 64);
+ if (err)
+ {
+ err = expand_glyphs (font, 1);
+ if (err)
+ return err;
+ }
+
+ glyph = &font->glyphs[font->glyphs_count];
+ memset (glyph, 0, sizeof (*glyph));
+
+ glyph->name = strdup (name);
+ if (!glyph->name)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ glyph->encoding = encoding;
+ if (encoding == -1)
+ glyph->internal_encoding = internal_encoding;
+ glyph->bbox.width = bbox_width;
+ glyph->bbox.height = bbox_height;
+ glyph->bbox.offx = bbox_offx;
+ glyph->bbox.offy = bbox_offy;
+ bsize = ((bbox_width + 7) / 8) * bbox_height;
+ glyph->bitmap = malloc (bsize);
+ if (!glyph->bitmap)
+ {
+ free (glyph->name);
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ memcpy (glyph->bitmap, bitmap, bsize);
+ font->glyphs_count++;
+ return 0;
+}
+
+
+/* Write the font FONT in BDF format to stream FILEP. */
+bdf_error_t
+bdf_write (FILE *filep, bdf_font_t font)
+{
+ int index;
+
+ if (font->version_maj != 2
+ || (font->version_min != 1 && font->version_min != 2))
+ return BDF_INVALID_ARGUMENT;
+ fprintf (filep, "STARTFONT %i.%i\n", font->version_maj, font->version_min);
+
+ if (!font->name)
+ return BDF_INVALID_ARGUMENT;
+ fprintf (filep, "FONT %s\n", font->name);
+ fprintf (filep, "SIZE %i %i %i\n", font->point_size,
+ font->res_x, font->res_y);
+ fprintf (filep, "FONTBOUNDINGBOX %i %i %i %i\n",
+ font->bbox.width, font->bbox.height,
+ font->bbox.offx, font->bbox.offy);
+ if (font->has_swidth)
+ fprintf (filep, "SWIDTH %i %i\n", font->swidth.x, font->swidth.y);
+ if (font->has_dwidth)
+ fprintf (filep, "DWIDTH %i %i\n", font->dwidth.x, font->dwidth.y);
+ if (font->has_swidth1)
+ fprintf (filep, "SWIDTH1 %i %i\n", font->swidth1.x, font->swidth1.y);
+ if (font->has_dwidth1)
+ fprintf (filep, "DWIDTH1 %i %i\n", font->dwidth1.x, font->dwidth1.y);
+ if (font->has_vvector)
+ fprintf (filep, "VVECTOR %i %i\n", font->vvector.x, font->vvector.y);
+ if (font->properties_count < 0)
+ return BDF_INVALID_ARGUMENT;
+ if (font->properties_count > 0)
+ {
+ fprintf (filep, "STARTPROPERTIES %i\n", font->properties_count);
+ for (index = 0; index < font->properties_count; index++)
+ {
+ struct bdf_property *prop = &font->properties[index];
+
+ if (prop->type == BDF_PROPERTY_NUMBER)
+ fprintf (filep, "%s %i\n", prop->name, prop->value.number);
+ else
+ {
+ char *val = prop->value.string;
+
+ fprintf (filep, "%s \"", prop->name);
+ while (*val)
+ {
+ fputc (*val, filep);
+ if (*(val++) == '"')
+ fputc ('"', filep);
+ }
+ fprintf (filep, "\"\n");
+ }
+ }
+ fprintf (filep, "ENDPROPERTIES\n");
+ }
+ if (font->glyphs_count <= 0)
+ return BDF_INVALID_ARGUMENT;
+ fprintf (filep, "CHARS %i\n", font->glyphs_count);
+
+ for (index = 0; index < font->glyphs_count; index++)
+ {
+ struct bdf_glyph *glyph = &font->glyphs[index];
+ unsigned char *bitmap;
+ int row, col;
+
+ fprintf (filep, "STARTCHAR %s\n", glyph->name);
+ if (glyph->encoding != -1)
+ fprintf (filep, "ENCODING %i\n", glyph->encoding);
+ else
+ fprintf (filep, "ENCODING %i %i\n", glyph->encoding,
+ glyph->internal_encoding);
+ if (glyph->has_swidth)
+ fprintf (filep, "SWIDTH %i %i\n", glyph->swidth.x, glyph->swidth.y);
+ if (glyph->has_dwidth)
+ fprintf (filep, "DWIDTH %i %i\n", glyph->dwidth.x, glyph->dwidth.y);
+ if (glyph->has_swidth1)
+ fprintf (filep, "SWIDTH1 %i %i\n", glyph->swidth1.x, glyph->swidth1.y);
+ if (glyph->has_dwidth1)
+ fprintf (filep, "DWIDTH1 %i %i\n", glyph->dwidth1.x, glyph->dwidth1.y);
+ if (glyph->has_vvector)
+ fprintf (filep, "VVECTOR %i %i\n", glyph->vvector.x, glyph->vvector.y);
+ fprintf (filep, "BBX %i %i %i %i\n", glyph->bbox.width,
+ glyph->bbox.height, glyph->bbox.offx, glyph->bbox.offy);
+ fprintf (filep, "BITMAP\n");
+ bitmap = glyph->bitmap;
+ for (row = 0; row < glyph->bbox.height; row++)
+ {
+ for (col = 0; col < (glyph->bbox.width + 7) / 8; col++)
+ fprintf (filep, "%02X", *(bitmap++));
+ fputc ('\n', filep);
+ }
+ fprintf (filep, "ENDCHAR\n");
+ }
+ fprintf (filep, "ENDFONT\n");
+ if (ferror (filep))
+ {
+ errno = ferror (filep);
+ return BDF_SYSTEM_ERROR;
+ }
+ return 0;
+}
+
+
+/* The function returns -1 if the encoding of glyph A is lower than
+ the encoding of glyph B, 1 if it is the other way round, and 0 if
+ the encoding of both glyphs is the same. */
+int
+bdf_compare_glyphs (const void *a, const void *b)
+{
+ struct bdf_glyph *first = (struct bdf_glyph *) a;
+ struct bdf_glyph *second = (struct bdf_glyph *) b;
+
+ if (first->encoding < second->encoding)
+ return -1;
+ else if (first->encoding > second->encoding)
+ return 1;
+ else
+ {
+ if (first->encoding == -1)
+ {
+ if (first->internal_encoding < second->internal_encoding)
+ return -1;
+ else if (first->internal_encoding > second->internal_encoding)
+ return 1;
+ else
+ return 0;
+ }
+ else
+ return 0;
+ }
+}
+
+
+/* Sort the glyphs in the font FONT. This must be called before using
+ bdf_find_glyphs, after the font has been created or after new
+ glyphs have been added to the font. */
+void
+bdf_sort_glyphs (bdf_font_t font)
+{
+ qsort (font->glyphs, font->glyphs_count, sizeof (struct bdf_glyph),
+ bdf_compare_glyphs);
+}
+
+
+/* Find the glyph with the encoding ENC (and INTERNAL_ENC, if ENC is
+ -1) in the font FONT. Requires that the glyphs in the font are
+ sorted. */
+struct bdf_glyph *
+bdf_find_glyph (bdf_font_t font, int enc, int internal_enc)
+{
+ struct bdf_glyph key = { encoding: enc, internal_encoding: internal_enc };
+ return bsearch (&key, font->glyphs, font->glyphs_count,
+ sizeof (struct bdf_glyph), bdf_compare_glyphs);
+}
diff --git a/console/bdf.h b/console/bdf.h
new file mode 100644
index 00000000..968c9f59
--- /dev/null
+++ b/console/bdf.h
@@ -0,0 +1,272 @@
+/* bdf.h - Interface to Adobe Glyph Bitmap Distribution Format (BDF) parser.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann <marcus@gnu.org>.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _BDF_H_
+#define _BDF_H_
+
+#include <stdio.h>
+
+/* Version 2.2 of the Glyph Bitmap Distribution Format Specification
+ was released by Adobe 22 March 1993 and is a superset of version 2.1.
+
+ The format of a BDF file is a human-readable ASCII text file.
+ Every line consists of a keyword, which may be followed by one or
+ more arguments. The specification is vague about the exact data
+ types of the arguments, so we treat a string as an 8-bit string
+ which must not contain a binary null, and a number like an integer
+ as an int. Leading and trailing white space are removed, multiple
+ spaces that seperate arguments are replaced by a single white
+ space, and empty lines are ignored. */
+
+
+/* Possible error values returned by the BDF functions. */
+typedef enum
+{
+ /* No error occured. This is guaranteed to be zero. */
+ BDF_NO_ERROR = 0,
+
+ /* A system error occured. The caller should consult errno. */
+ BDF_SYSTEM_ERROR,
+
+ /* All following errors indicate that the file is not a valid BDF
+ file. */
+ BDF_SYNTAX_ERROR,
+
+ /* An argument is out of range or of an invalid type. */
+ BDF_INVALID_ARGUMENT,
+
+ /* The number of properties, glyphs or bitmap lines is
+ incorrect. */
+ BDF_COUNT_MISMATCH
+} bdf_error_t;
+
+/* Return a statically allocated string describing the error value ERR. */
+const char *bdf_strerror (bdf_error_t err);
+
+
+/* A property in the BDF font file is an unspecified KEYWORD VALUE
+ pair in a line after STARTPROPERTIES and before ENDPROPERTIES.
+ VALUE can be an integer or a string in double quotes (two
+ consecutives double quotes can be used to include a double quote in
+ the string. */
+struct bdf_property
+{
+ /* The property name. */
+ char *name;
+
+ /* The type indicates which member of the union is valid. */
+ enum { BDF_PROPERTY_NUMBER, BDF_PROPERTY_STRING } type;
+ union
+ {
+ int number;
+ char *string;
+ } value;
+};
+typedef struct property *bdf_property_t;
+
+/* The bounding box of a font or a glyph within. */
+struct bdf_bbox
+{
+ int width;
+ int height;
+ int offx;
+ int offy;
+};
+
+/* A vector, used for displacement and resolution. */
+struct bdf_vector
+{
+ int x;
+ int y;
+};
+
+/* A single glyph in the font. */
+struct bdf_glyph
+{
+ /* The name of the glyph. */
+ char *name;
+
+ /* The Adode Standard Encoding of the glyph, or -1 if not
+ available. */
+ int encoding;
+
+ /* If encoding is -1, internal_encoding contains the internal
+ encoding of the glyph. The internal encoding is private to the
+ font and the application. */
+ int internal_encoding;
+
+ /* The bounding box of the glyph. The width of the bounding box,
+ divided by 8 (rounding up), specifies how many bytes are used in
+ the bitmap for each row of the glyph. The height specifies the
+ number of rows. */
+ struct bdf_bbox bbox;
+
+ /* The bitmap of the glyph, row-by-row from top to bottom, and
+ byte-by-byte within a row from left to right. Within a byte, the
+ most significant bit is left in the glyph. */
+ unsigned char *bitmap;
+
+ /* If the writing direction is horizontal, SWIDTH and DWIDTH are
+ relevant. If the writing direction is vertical, SWIDTH1, DWIDTH1
+ and VVECTOR are relevant. Relevant values have to be specified
+ here, or font-wide in the global section. A global value can be
+ overridden for individual glyphs. */
+ int has_swidth : 1;
+ int has_dwidth : 1;
+ int has_swidth1 : 1;
+ int has_dwidth1 : 1;
+ int has_vvector : 1;
+ struct bdf_vector swidth;
+ struct bdf_vector dwidth;
+ struct bdf_vector swidth1;
+ struct bdf_vector dwidth1;
+ struct bdf_vector vvector;
+};
+
+/* A font is a set of glyphs with some font-wide attributes. */
+struct bdf_font
+{
+ /* The version of the font format. Should be 2.1 or 2.2. It is
+ split up into major and minor component to make precise
+ comparison possible. */
+ int version_maj;
+ int version_min;
+
+ /* The font name. */
+ char *name;
+
+ /* The content version, if available. The content version indicates
+ the revision of the appearance of the glyphs within the font. */
+ int has_content_version : 1;
+ int content_version;
+
+ /* The point size of the font in device pixels. */
+ int point_size;
+
+ /* The resolution of the display the font is intended for (dpi).
+ This is needed if you want to scale the glyphs for a different
+ device than they were intended for. */
+ int res_x;
+ int res_y;
+
+ /* The global bounding box parameters. */
+ struct bdf_bbox bbox;
+
+ int __properties_allocated;
+ int properties_count;
+ struct bdf_property *properties;
+ int __glyphs_allocated;
+ int glyphs_count;
+ struct bdf_glyph *glyphs;
+
+ /* The metricsset. If 0, the font has a horizontal writing
+ direction. If 1, the font has a vertical writing direction. If
+ 2, the font has a mixed writing direction. */
+ int metricsset;
+
+ /* The following have the same meaning as the corresponding members
+ in the glyph structure and specify a font wide default which must
+ be used if the glyph does not provide its own values. */
+ int has_swidth : 1;
+ int has_dwidth : 1;
+ int has_swidth1 : 1;
+ int has_dwidth1 : 1;
+ int has_vvector : 1;
+ struct bdf_vector swidth;
+ struct bdf_vector dwidth;
+ struct bdf_vector swidth1;
+ struct bdf_vector dwidth1;
+ struct bdf_vector vvector;
+};
+typedef struct bdf_font *bdf_font_t;
+
+
+/* Read the font from stream FILE, and return it in FONT. If
+ LINECOUNT is not zero, it will contain the number of lines in the
+ file at success, and the current line an error occured at
+ failure. */
+bdf_error_t bdf_read (FILE *file, bdf_font_t *font, int *linecount);
+
+/* Destroy the BDF font object and release all associated
+ resources. */
+void bdf_destroy (bdf_font_t font);
+
+/* Create a new font object with the specified mandatory
+ parameters. */
+bdf_error_t bdf_new (bdf_font_t *font, int version_maj, int version_min,
+ const char *name, int point_size, int res_x, int res_y,
+ int bbox_width, int bbox_height, int bbox_offx,
+ int bbox_offy, int metricsset);
+
+/* Set the SWIDTH of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_swidth (bdf_font_t font, int glyph, int x, int y);
+
+/* Set the DWIDTH of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_dwidth (bdf_font_t font, int glyph, int x, int y);
+
+/* Set the SWIDTH1 of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_swidth1 (bdf_font_t font, int glyph, int x, int y);
+
+/* Set the DWIDTH1 of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_dwidth1 (bdf_font_t font, int glyph, int x, int y);
+
+/* Set the VVECTOR of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_vvector (bdf_font_t font, int glyph, int x, int y);
+
+/* Add a new string property to the font FONT. */
+bdf_error_t bdf_add_string_property (bdf_font_t font, const char *name,
+ const char *value);
+
+/* Add a new number property to the font FONT. */
+bdf_error_t bdf_add_number_property (bdf_font_t font, const char *name,
+ int value);
+
+/* Add a new glyph with the specified paramters to the font FONT. If
+ encoding is -1, internal_encoding specifies the internal
+ encoding. All other parameters are mandatory. */
+bdf_error_t bdf_add_glyph (bdf_font_t font, const char *name, int encoding,
+ int internal_encoding, int bbox_width,
+ int bbox_height, int bbox_offx, int bbox_offy,
+ const unsigned char *bitmap);
+
+/* Write the font FONT in BDF format to stream FILEP. */
+bdf_error_t bdf_write (FILE *filep, bdf_font_t font);
+
+/* The function returns -1 if the encoding of glyph A is lower than
+ the encoding of glyph B, 1 if it is the other way round, and 0 if
+ the encoding of both glyphs is the same. */
+int bdf_compare_glyphs (const void *a, const void *b);
+
+/* Sort the glyphs in the font FONT. This must be called before using
+ bdf_find_glyphs, after the font has been created or after new
+ glyphs have been added to the font. */
+void bdf_sort_glyphs (bdf_font_t font);
+
+/* Find the glyph with the encoding ENC (and INTERNAL_ENC, if ENC is
+ -1) in the font FONT. Requires that the glyphs in the font are
+ sorted. */
+struct bdf_glyph *bdf_find_glyph (bdf_font_t font, int enc, int internal_enc);
+
+#endif /* _BDF_H_ */
diff --git a/console/console.c b/console/console.c
new file mode 100644
index 00000000..ac7c807d
--- /dev/null
+++ b/console/console.c
@@ -0,0 +1,511 @@
+/* console.c - The device independant part of a console.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <cthreads.h>
+
+#include "console.h"
+#include "display.h"
+#include "input.h"
+
+
+struct vcons
+{
+ /* Protected by cons_list_lock. */
+ vcons_t next;
+ vcons_t prev;
+ int refcnt;
+
+ /* The following members remain constant over the lifetime of the
+ object and don't need to be locked. */
+ cons_t cons;
+ int id;
+ void *display_console;
+
+ struct mutex lock;
+ /* Indicates if OWNER_ID is initialized. */
+ int has_owner;
+ /* Specifies the ID of the process that should receive the WINCH
+ signal for this virtual console. */
+ int owner_id;
+
+ /* The output queue holds the characters that are to be outputted.
+ The display driver might refuse to handle some incomplete
+ multi-byte or composed character at the end of the buffer, so we
+ have to keep them around. */
+ struct mutex output_lock;
+ int output_stopped;
+ struct condition output_resumed;
+ char *output;
+ size_t output_allocated;
+ size_t output_size;
+
+ struct mutex input_lock;
+ /* XXX input queue. */
+ char *input;
+ size_t input_allocated;
+ size_t input_size;
+};
+
+
+struct cons
+{
+ /* Protected by cons_list_lock. */
+ cons_t prev;
+ cons_t next;
+ int refcnt;
+ vcons_t vcons_list;
+ size_t vcons_length;
+ vcons_t vcons_active;
+
+ /* The following members are static and don't need to be locked. */
+ char *name;
+ display_ops_t display_ops;
+};
+
+
+/* The lock protects the console list, all virtual console lists of
+ all consoles, and their reference counters. */
+struct mutex cons_list_lock;
+cons_t cons_list;
+size_t cons_length;
+
+
+struct mutex config_lock;
+/* The default encoding. */
+const char *config_encoding;
+display_ops_t config_display;
+
+
+/* Lookup the console with name NAME, acquire a reference for it, and
+ return it in R_CONS. If NAME doesn't exist, return ESRCH. */
+error_t
+cons_lookup (const char *name, cons_t *r_cons)
+{
+ cons_t cons;
+
+ mutex_lock (&cons_list_lock);
+ cons = cons_list;
+ while (cons)
+ {
+ if (!strcmp (name, cons->name))
+ {
+ cons->refcnt++;
+ mutex_unlock (&cons_list_lock);
+ *r_cons = cons;
+ return 0;
+ }
+ cons = cons->next;
+ }
+ mutex_unlock (&cons_list_lock);
+ return ESRCH;
+}
+
+
+/* Release a reference to CONS. */
+void
+cons_release (cons_t cons)
+{
+ mutex_lock (&cons_list_lock);
+ cons->refcnt--;
+ mutex_unlock (&cons_list_lock);
+}
+
+
+/* Lookup the virtual console with number ID in the console CONS,
+ acquire a reference for it, and return it in R_VCONS. If CREATE is
+ true, the virtual console will be created if it doesn't exist yet.
+ If CREATE is true, and ID 0, the first free virtual console id is
+ used. */
+error_t
+vcons_lookup (cons_t cons, int id, int create, vcons_t *r_vcons)
+{
+ error_t err;
+ vcons_t previous_cons = 0;
+ vcons_t vcons;
+
+ if (!id && !create)
+ return EINVAL;
+
+ mutex_lock (&cons_list_lock);
+ if (id)
+ {
+ if (cons->vcons_list && cons->vcons_list->id <= id)
+ {
+ previous_cons = cons->vcons_list;
+ while (previous_cons->next && previous_cons->next->id <= id)
+ previous_cons = previous_cons->next;
+ if (previous_cons->id == id)
+ {
+ previous_cons->refcnt++;
+ mutex_unlock (&cons_list_lock);
+ *r_vcons = previous_cons;
+ return 0;
+ }
+ else if (!create)
+ {
+ mutex_unlock (&cons_list_lock);
+ return ESRCH;
+ }
+ }
+ }
+ else
+ {
+ id = 1;
+ if (cons->vcons_list && cons->vcons_list->id == 1)
+ {
+ previous_cons = cons->vcons_list;
+ while (previous_cons && previous_cons->id == id)
+ {
+ id++;
+ previous_cons = previous_cons->next;
+ }
+ }
+ }
+
+ vcons = calloc (1, sizeof (struct vcons));
+ if (!vcons)
+ {
+ mutex_unlock (&cons_list_lock);
+ return ENOMEM;
+ }
+ mutex_init (&vcons->lock);
+ mutex_init (&vcons->output_lock);
+ condition_init (&vcons->output_resumed);
+ vcons->refcnt = 1;
+ err = (*(cons->display_ops->create)) (&vcons->display_console,
+ config_encoding);
+ if (err)
+ {
+ mutex_unlock (&cons_list_lock);
+ free (vcons);
+ return err;
+ }
+ /* XXX Set up keyboard input etc. */
+ vcons->cons = cons;
+ cons->refcnt++;
+ cons->vcons_length++;
+ /* Insert the virtual console into the doubly linked list. */
+ if (previous_cons)
+ {
+ vcons->prev = previous_cons;
+ if (previous_cons->next)
+ {
+ previous_cons->next->prev = vcons;
+ vcons->next = previous_cons->next;
+ }
+ previous_cons->next = vcons;
+ }
+ else
+ {
+ if (cons->vcons_list)
+ {
+ cons->vcons_list->prev = vcons;
+ vcons->next = cons->vcons_list;
+ }
+ cons->vcons_list = vcons;
+ }
+ mutex_unlock (&cons_list_lock);
+ *r_vcons = vcons;
+ return 0;
+}
+
+
+/* Release a reference to the virtual console VCONS. If this was the
+ last reference the virtual console is destroyed. */
+void
+vcons_release (vcons_t vcons)
+{
+ mutex_lock (&cons_list_lock);
+ if (--vcons->refcnt)
+ {
+ /* As we keep a reference for all input focus groups pointing to
+ the virtual console, and a reference for the active console,
+ we know that without references, this virtual console is
+ neither active nor used by any input group. */
+
+ (*vcons->cons->display_ops->destroy) (vcons->display_console);
+ /* XXX Destroy the rest of the state. */
+
+ if (vcons->prev)
+ vcons->prev->next = vcons->next;
+ if (vcons->next)
+ vcons->next->prev = vcons->prev;
+ vcons->cons->vcons_length--;
+ vcons->cons->refcnt--;
+ free (vcons);
+ }
+ mutex_unlock (&cons_list_lock);
+}
+
+
+/* Activate virtual console VCONS for WHO. WHO is a unique identifier
+ for the entity requesting the activation (which can be used by the
+ display driver to group several activation requests together). */
+void
+vcons_activate (vcons_t vcons, int who)
+{
+ mutex_lock (&cons_list_lock);
+ if (vcons->cons->vcons_active != vcons)
+ {
+ (*vcons->cons->display_ops->activate) (vcons->display_console, who);
+ vcons->cons->vcons_active->refcnt--;
+ vcons->refcnt++;
+ vcons->cons->vcons_active = vcons;
+ }
+ mutex_unlock (&cons_list_lock);
+}
+
+
+/* Resume the output on the virtual console VCONS. */
+void
+vcons_start_output (vcons_t vcons)
+{
+ mutex_lock (&vcons->output_lock);
+ if (vcons->output_stopped)
+ {
+ vcons->output_stopped = 0;
+ condition_broadcast (&vcons->output_resumed);
+ }
+ mutex_unlock (&vcons->output_lock);
+}
+
+
+/* Stop all output on the virtual console VCONS. */
+void
+vcons_stop_output (vcons_t vcons)
+{
+ mutex_lock (&vcons->output_lock);
+ vcons->output_stopped = 1;
+ mutex_unlock (&vcons->output_lock);
+}
+
+
+/* Return the number of pending output bytes for VCONS. */
+size_t
+vcons_pending_output (vcons_t vcons)
+{
+ int output_size;
+ mutex_lock (&vcons->output_lock);
+ output_size = vcons->output_size;
+ mutex_unlock (&vcons->output_lock);
+ return output_size;
+}
+
+
+/* Fush the input buffer, discarding all pending data. */
+void
+vcons_flush_input (vcons_t vcons)
+{
+ mutex_lock (&vcons->input_lock);
+ vcons->input_size = 0;
+ mutex_unlock (&vcons->input_lock);
+}
+
+
+/* Flush the output buffer, discarding all pending data. */
+void
+vcons_discard_output (vcons_t vcons)
+{
+ mutex_lock (&vcons->output_lock);
+ vcons->output_size = 0;
+ mutex_unlock (&vcons->output_lock);
+}
+
+
+/* Output DATALEN characters from the buffer DATA on the virtual
+ console VCONS. The DATA must be supplied in the system encoding
+ configured for VCONS. The function returns the amount of bytes
+ written (might be smaller than DATALEN) or -1 and the error number
+ in errno. If NONBLOCK is not zero, return with -1 and set errno
+ to EWOULDBLOCK if operation would block for a long time. */
+ssize_t
+vcons_output (vcons_t vcons, int nonblock, char *data, size_t datalen)
+{
+ error_t err;
+ char *output;
+ size_t output_size;
+ ssize_t amount;
+
+ error_t ensure_output_buffer_size (size_t new_size)
+ {
+ /* Must be a power of two. */
+#define OUTPUT_ALLOCSIZE 32
+
+ if (vcons->output_allocated < new_size)
+ {
+ char *new_output;
+ new_size = (new_size + OUTPUT_ALLOCSIZE - 1) & ~(OUTPUT_ALLOCSIZE - 1);
+ new_output = realloc (vcons->output, new_size);
+ if (!new_output)
+ return ENOMEM;
+ vcons->output = new_output;
+ vcons->output_allocated = new_size;
+ }
+ return 0;
+ }
+
+ mutex_lock (&vcons->output_lock);
+ while (vcons->output_stopped)
+ {
+ if (nonblock)
+ {
+ mutex_unlock (&vcons->output_lock);
+ errno = EWOULDBLOCK;
+ return -1;
+ }
+ if (hurd_condition_wait (&vcons->output_resumed, &vcons->output_lock))
+ {
+ mutex_unlock (&vcons->output_lock);
+ errno = EINTR;
+ return -1;
+ }
+ }
+
+ if (vcons->output_size)
+ {
+ err = ensure_output_buffer_size (vcons->output_size + datalen);
+ if (err)
+ {
+ mutex_unlock (&vcons->output_lock);
+ errno = ENOMEM;
+ return -1;
+ }
+ output = vcons->output;
+ output_size = vcons->output_size;
+ memcpy (output + output_size, data, datalen);
+ output_size += datalen;
+ }
+ else
+ {
+ output = data;
+ output_size = datalen;
+ }
+ amount = output_size;
+ err = (*vcons->cons->display_ops->output) (vcons->display_console,
+ &output, &output_size);
+ amount -= output_size;
+
+ if (err && !amount)
+ {
+ mutex_unlock (&vcons->output_lock);
+ errno = err;
+ return err;
+ }
+
+ /* XXX What should be done with invalid characters etc? */
+ if (output_size)
+ {
+ /* If we used the caller's buffer DATA, the remaining bytes
+ might not fit in our internal output buffer. In this case we
+ can reallocate the buffer in VCONS without needing to update
+ OUTPUT (as it points into DATA). */
+ err = ensure_output_buffer_size (output_size);
+ if (err)
+ {
+ mutex_unlock (&vcons->output_lock);
+ return err;
+ }
+ memmove (vcons->output, output, output_size);
+ }
+ vcons->output_size = output_size;
+ amount += output_size;
+
+ mutex_unlock (&vcons->output_lock);
+ return amount;
+}
+
+
+/* Add DATALEN bytes starting from DATA to the input queue in
+ VCONS. */
+error_t
+vcons_input (vcons_t vcons, char *data, size_t datalen)
+{
+ error_t err = 0;
+
+ error_t ensure_input_buffer_size (size_t new_size)
+ {
+ /* Must be a power of two. */
+#define INPUT_ALLOCSIZE 32
+
+ if (vcons->input_allocated < new_size)
+ {
+ char *new_input;
+ new_size = (new_size + INPUT_ALLOCSIZE - 1) & ~(INPUT_ALLOCSIZE - 1);
+ new_input = realloc (vcons->input, new_size);
+ if (!new_input)
+ return ENOMEM;
+ vcons->input = new_input;
+ vcons->input_allocated = new_size;
+ }
+ return 0;
+ }
+
+ mutex_lock (&vcons->input_lock);
+ err = ensure_input_buffer_size (vcons->input_size + datalen);
+ if (err)
+ {
+ mutex_unlock (&vcons->input_lock);
+ return err;
+ }
+ memcpy (vcons->input + vcons->input_size, data, datalen);
+ vcons->input_size += datalen;
+ mutex_unlock (&vcons->input_lock);
+ return 0;
+}
+
+
+/* Return the dimension of the virtual console VCONS in WINSIZE. */
+void
+vcons_getsize (vcons_t vcons, struct winsize *size)
+{
+ (*vcons->cons->display_ops->getsize) (vcons->display_console, size);
+}
+
+
+/* Set the owner of the virtual console VCONS to PID. The owner
+ receives the SIGWINCH signal when the terminal size changes. */
+error_t
+vcons_set_owner (vcons_t vcons, pid_t pid)
+{
+ mutex_lock (&vcons->lock);
+ vcons->has_owner = 1;
+ vcons->owner_id = pid;
+ mutex_unlock (&vcons->lock);
+ return 0;
+}
+
+
+/* Return the owner of the virtual console VCONS in PID. If there is
+ no owner, return ENOTTY. */
+error_t
+vcons_get_owner (vcons_t vcons, pid_t *pid)
+{
+ error_t err = 0;
+ mutex_lock (&vcons->lock);
+ if (!vcons->has_owner)
+ err = ENOTTY;
+ else
+ *pid = vcons->owner_id;
+ mutex_unlock (&vcons->lock);
+ return err;
+}
diff --git a/console/console.h b/console/console.h
new file mode 100644
index 00000000..b768afa4
--- /dev/null
+++ b/console/console.h
@@ -0,0 +1,98 @@
+/* console.h - Interface for the device independant part of a virtual console.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <argp.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+
+/* A handle for a console device. */
+typedef struct cons *cons_t;
+
+/* A handle for a virtual console device. */
+typedef struct vcons *vcons_t;
+
+
+/* Lookup the console with name NAME, acquire a reference for it, and
+ return it in R_CONS. If NAME doesn't exist, return ESRCH. */
+error_t cons_lookup (const char *name, cons_t *r_cons);
+
+/* Release a reference to CONS. */
+void cons_release (cons_t cons);
+
+/* Lookup the virtual console with number ID in the console CONS,
+ acquire a reference for it, and return it in R_VCONS. If CREATE is
+ true, the virtual console will be created if it doesn't exist yet.
+ If CREATE is true, and ID 0, the first free virtual console id is
+ used. */
+error_t vcons_lookup (cons_t cons, int id, int create, vcons_t *r_vcons);
+
+/* Release a reference to the virtual console VCONS. If this was the
+ last reference the virtual console is destroyed. */
+void vcons_release (vcons_t vcons);
+
+
+/* Activate virtual console VCONS for WHO. WHO is a unique identifier
+ for the entity requesting the activation (which can be used by the
+ display driver to group several activation requests together). */
+void vcons_activate (vcons_t vcons, int who);
+
+/* Resume the output on the virtual console VCONS. */
+void vcons_start_output (vcons_t vcons);
+
+/* Stop all output on the virtual console VCONS. */
+void vcons_stop_output (vcons_t vcons);
+
+/* Return the number of pending output bytes for VCONS. */
+size_t vcons_pending_output (vcons_t vcons);
+
+/* Fush the input buffer, discarding all pending data. */
+void vcons_flush_input (vcons_t vcons);
+
+/* Fush the output buffer, discarding all pending data. */
+void vcons_discard_output (vcons_t vcons);
+
+/* Add DATALEN bytes starting from DATA to the input queue in
+ VCONS. */
+error_t vcons_input (vcons_t vcons, char *data, size_t datalen);
+
+/* Output DATALEN characters from the buffer DATA on the virtual
+ console VCONS. The DATA must be supplied in the system encoding
+ configured for VCONS. The function returns the amount of bytes
+ written (might be smaller than DATALEN) or -1 and the error number
+ in errno. If NONBLOCK is not zero, return with -1 and set errno
+ to EWOULDBLOCK if operation would block for a long time. */
+ssize_t vcons_output (vcons_t vcons, int nonblock, char *data, size_t datalen);
+
+/* Hang interruptible until one of the conditions in TYPE is
+ fulfilled. Return the conditions fulfilled in TYPE. */
+error_t vcons_select (vcons_t vcons, int *type);
+
+/* Return the dimension of the virtual console VCONS in WINSIZE. */
+void vcons_getsize (vcons_t vcons, struct winsize *winsize);
+
+/* Set the owner of the virtual console VCONS to PID. The owner
+ receives the SIGWINCH signal when the terminal size changes. */
+error_t vcons_set_owner (vcons_t vcons, pid_t pid);
+
+/* Return the owner of the virtual console VCONS in PID. If there is
+ no owner, return ENOTTY. */
+error_t vcons_get_owner (vcons_t vcons, pid_t *pid);
diff --git a/console/display.h b/console/display.h
new file mode 100644
index 00000000..803d3180
--- /dev/null
+++ b/console/display.h
@@ -0,0 +1,79 @@
+/* display.h - The interface to a display driver.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _DISPLAY_H_
+#define _DISPLAY_H_ 1
+
+#include <errno.h>
+#include <argp.h>
+#include <sys/ioctl.h>
+
+
+struct display_ops
+{
+ /* Initialize the subsystem. */
+ error_t (*init) (void);
+
+ /* Create a new (virtual) console display, with the system encoding
+ being ENCODING. A failure at the first time this is called is
+ critical. Subsequent calls might return an error if multiple
+ virtual consoles are not supported. Further operations on this
+ console will be called with the first parameter being *HOOK,
+ which should be set to some unique identifier for this
+ console. */
+ error_t (*create) (void **console, const char *encoding);
+
+ /* Destroy the console CONSOLE. The caller will first activate a
+ different console as the active one. */
+ void (*destroy) (void *console);
+
+ /* Change the active console of WHO to CONSOLE. WHO is a unique identifier
+ for the entity requesting the activation (which can be used by the
+ display driver to group several activation requests together). */
+ void (*activate) (void *console, int who);
+
+ /* Scroll the console CONSOLE by the desired amount. This is only a
+ hint, the actual amount scrolled might depend on the capability
+ of the subsystem. Negative AMOUNT scrolls back in history. */
+ error_t (*scroll) (void *console, int amount);
+
+ /* Output LENGTH bytes starting from BUFFER in the system encoding.
+ Set BUFFER and LENGTH to the new values. The exact semantics are
+ just as in the iconv interface. */
+ error_t (*output) (void *console, char **buffer, size_t *length);
+
+ /* Return the current size of CONSOLE in WINSIZE. */
+ void (*getsize) (void *console, struct winsize *size);
+};
+typedef struct display_ops *display_ops_t;
+
+extern struct display_ops vga_display_ops;
+extern struct display_ops mach_display_ops;
+
+display_ops_t display_driver[] =
+ {
+#if defined(__i386__)
+ &vga_display_ops,
+#endif
+ &mach_display_ops,
+ 0
+ };
+
+#endif /* _DISPLAY_H_ */
diff --git a/console/dynafont.c b/console/dynafont.c
new file mode 100644
index 00000000..588457e9
--- /dev/null
+++ b/console/dynafont.c
@@ -0,0 +1,371 @@
+/* dynafont.c - Dynamic font handling.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <assert.h>
+#include <malloc.h>
+#include <wchar.h>
+#include <hurd/ihash.h>
+
+#include "vga-hw.h"
+#include "vga.h"
+#include "bdf.h"
+#include "dynafont.h"
+
+
+/* The currently active (visible) dynafont. */
+static dynafont_t active_dynafont;
+
+/* One glyph in a VGA font is 8 pixels wide and 32 pixels high. Only
+ the first N lines are visible, and N depends on the VGA register
+ settings. */
+typedef char vga_font_glyph[VGA_FONT_HEIGHT];
+
+/* For each glyph in the VGA font, one instance of this structure is
+ held in the dynafont. */
+struct mapped_character
+{
+ /* Reference count of the mapped character. If this drops zero, we
+ can remove the mapping at any time. */
+ int refs;
+
+ /* Remember the character this glyph belongs to, so the glyph can be
+ reloaded when the font is changed. */
+ wchar_t character;
+
+ /* Used by libihash for fast removal of elements. */
+ void **locp;
+};
+
+
+struct dynafont
+{
+ /* The sorted font to take the glyphs from. */
+ bdf_font_t font;
+
+ /* The size of the VGA font (256 or 512). Must be a power of 2! */
+ int size;
+
+ /* A hash containing a pointer to a struct mapped_character for each
+ UCS-4 character we map to a VGA font index. */
+ ihash_t charmap;
+
+ /* The struct mapped_characters are preallocated for all vga font
+ index values. This points to an array of SIZE such elements. */
+ struct mapped_character *charmap_data;
+
+ /* The last vga font index that had been free (or could be reused). */
+ int vga_font_last_free_index;
+
+ /* The number of free slots in the VGA font. */
+ int vga_font_free_indices;
+
+ /* The font memory as stored on the card. */
+ vga_font_glyph *vga_font;
+};
+
+
+/* Create a new dynafont object, which uses glyphs from the font FONT
+ (which must be 8 pixels wide and up to 32 pixels heigh). SIZE is
+ either 256 or 512, and specifies the number of available glyphs in
+ the font cache. The object is returned in DYNAFONT. The caller
+ must ensure the integrity of FONT until the object is destroyed or
+ the font is changed with dynafont_change_font. */
+error_t
+dynafont_new (bdf_font_t font, int size, dynafont_t *dynafont)
+{
+ error_t err = 0;
+ dynafont_t df;
+ struct bdf_glyph *glyph = NULL;
+
+ df = malloc (sizeof *df);
+ if (!df)
+ return ENOMEM;
+
+ df->font = font;
+ df->size = size;
+ err = ihash_create (&df->charmap);
+ if (err)
+ {
+ free (df);
+ return err;
+ }
+
+ df->charmap_data = calloc (size, sizeof (struct mapped_character));
+ if (!df->charmap_data)
+ {
+ ihash_free (df->charmap);
+ free (df);
+ return ENOMEM;
+ }
+
+ df->vga_font = malloc (sizeof (vga_font_glyph) * size);
+ if (!df->vga_font)
+ {
+ ihash_free (df->charmap);
+ free (df->charmap_data);
+ free (df);
+ return ENOMEM;
+ }
+ df->vga_font_free_indices = df->size;
+ df->vga_font_last_free_index = 0;
+
+ /* The encoding of the unknown glyph. Some fonts provide an empty
+ box for this encoding. Undefine this if you always want to use
+ the built-in font. XXX Make this a command line option. */
+#define ENCODING_UNKNOWN 0
+ /* The encoding of the space. All fonts should provide it. */
+#define ENCODING_SPACE 32
+
+ {
+ struct mapped_character *chr = &df->charmap_data[FONT_INDEX_UNKNOWN];
+ df->vga_font_free_indices--;
+ chr->refs = 1;
+
+#if defined(ENCODING_UNKNOWN)
+ glyph = bdf_find_glyph (df->font, ENCODING_UNKNOWN, 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (df->font, -1, ENCODING_UNKNOWN);
+#endif
+ if (glyph)
+ {
+ /* XXX Take glyph size into account. */
+ memcpy (df->vga_font[FONT_INDEX_UNKNOWN], glyph->bitmap, 32);
+ /* Update the hash table. */
+ ihash_add (df->charmap, ENCODING_UNKNOWN, chr, &chr->locp);
+ }
+ else
+ {
+ int i;
+ char *gl = df->vga_font[FONT_INDEX_UNKNOWN];
+ /* XXX Take font height into account. */
+ gl[0] = 0xFF; /* ******** */
+ gl[1] = 0xC3; /* ** ** */
+ gl[2] = 0x99; /* * ** * */
+ gl[3] = 0x99; /* * ** * */
+ gl[4] = 0xF9; /* ***** * */
+ gl[5] = 0xF3; /* **** ** */
+ gl[6] = 0xF3; /* **** ** */
+ gl[7] = 0xE7; /* *** *** */
+ gl[8] = 0xE7; /* *** *** */
+ gl[9] = 0xFF; /* ******** */
+ gl[10] = 0xE7; /* *** *** */
+ gl[11] = 0xFF; /* ******** */
+ for (i = 12; i < 32; i++)
+ gl[i] = 0;
+ }
+
+#if defined(ENCODING_SPACE)
+ glyph = bdf_find_glyph (df->font, ENCODING_SPACE, 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (df->font, -1, ENCODING_SPACE);
+#endif
+ if (glyph)
+ {
+ /* XXX Take glyph size into account. */
+ memcpy (df->vga_font[FONT_INDEX_SPACE], glyph->bitmap, 32);
+ /* Update the hash table. */
+ ihash_add (df->charmap, ENCODING_SPACE, chr, &chr->locp);
+ }
+ else
+ {
+ int i;
+ char *gl = df->vga_font[FONT_INDEX_SPACE];
+ for (i = 0; i < 32; i++)
+ gl[i] = 0;
+ }
+ }
+ *dynafont = df;
+ return err;
+}
+
+
+/* Release a dynafont object and its associated resources. */
+void
+dynafont_free (dynafont_t df)
+{
+ ihash_free (df->charmap);
+ free (df->charmap_data);
+ free (df->vga_font);
+ free (df);
+}
+
+
+/* Look up the vga font index for an UCS-4 character. If not already
+ mapped, try to find space for a new entry and add the mapping.
+ Acquires an additional reference to the character. Might return
+ the glyph for the unrepresentable character if the glyph is ot
+ available for this character or no free slot is available right
+ now. In the former case, some information gets lost (to do
+ otherwise, one would have to either assign one of the scarce font
+ indices to each undisplayable character value on screen, or to
+ store the whole scrollback buffer as wide chars as well to recover
+ the lost info from that copy of the original text. */
+int
+dynafont_lookup (dynafont_t df, wchar_t wide_chr)
+{
+ struct mapped_character *chr = ihash_find (df->charmap, (int) wide_chr);
+
+ if (chr)
+ {
+ if (!chr->refs++)
+ df->vga_font_free_indices--;
+ return (chr - df->charmap_data) / sizeof (struct mapped_character);
+ }
+
+ /* The character is not currently mapped. Look for an empty
+ slot and add it. */
+ if (df->vga_font_free_indices)
+ {
+ int pos = (df->vga_font_last_free_index + 1) % df->size;
+ struct bdf_glyph *glyph;
+
+ glyph = bdf_find_glyph (df->font, (int) wide_chr, 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (df->font, -1, (int) wide_chr);
+ if (glyph)
+ {
+ while (pos != df->vga_font_last_free_index)
+ {
+ if (df->charmap_data[pos].refs == 0)
+ {
+ /* Ok, we found a new entry, use it. */
+ df->vga_font_last_free_index = pos;
+ chr = &df->charmap_data[pos];
+ chr->refs = 1;
+ memcpy (df->vga_font[pos], glyph->bitmap, VGA_FONT_HEIGHT);
+ /* XXX This will have to be updated when fonts are
+ cached. */
+ if (active_dynafont == df)
+ vga_write_font_buffer (0, pos, (char *) glyph->bitmap,
+ VGA_FONT_HEIGHT);
+ /* Update the hash table. */
+ if (chr->locp)
+ ihash_locp_remove (df->charmap, chr->locp);
+ ihash_add (df->charmap, (int) wide_chr, chr, &chr->locp);
+ return pos;
+ }
+ pos = (pos + 1) % df->size;
+ }
+ /* Should never be reached. */
+ assert (!"No free vga font index.");
+ }
+ }
+
+ df->charmap_data[FONT_INDEX_UNKNOWN].refs++;
+ return FONT_INDEX_UNKNOWN;
+}
+
+
+/* Release a reference to the glyph VGA_FONT_INDEX in dynafont DF. */
+void
+dynafont_release (dynafont_t df, int vga_font_index)
+{
+ if (! --df->charmap_data[vga_font_index].refs)
+ df->vga_font_free_indices++;
+}
+
+
+/* Load the VGA font to the card and make it active. */
+void
+dynafont_activate (dynafont_t df)
+{
+ /* XXX Replace this with some caching method. We have eight font
+ slots available. */
+ vga_write_font_buffer (0, 0, (char *) df->vga_font,
+ df->size * VGA_FONT_HEIGHT);
+ vga_select_font_buffer (0, (df->size == 512) ? 1 : 0);
+ active_dynafont = df;
+}
+
+
+/* Change the font used by dynafont DF to FONT. This transformation
+ is initially loss-less, if the new font can't display some
+ characters on the screen, you can always go back to a font that
+ does and get the glyphs for those characters back. (However, the
+ comments in dynafont_lookup hold for glyphs looked up after the font
+ change.) */
+void
+dynafont_change_font (dynafont_t df, bdf_font_t font)
+{
+ int i;
+
+ df->font = font;
+ for (i = 0; i < df->size; i++)
+ {
+ /* If we don't derive the unknown or space glyph from the font,
+ we don't update it. */
+#ifndef ENCODING_UNKNOWN
+ if (i == FONT_INDEX_UNKNOWN)
+ continue;
+#endif
+#ifndef ENCODING_SPACE
+ if (i == FONT_INDEX_SPACE)
+ continue;
+#endif
+ if (! df->charmap_data[i].refs)
+ {
+ /* The glyph is not used. If it is mapped, we need to
+ remove the mapping to invalidate the glyph. */
+ if (df->charmap_data[i].locp)
+ ihash_locp_remove (df->charmap, df->charmap_data[i].locp);
+ }
+
+ else
+ {
+ /* The glyph is mapped and in use. We will not destroy the
+ mapping, but just override the glyph in the VGA font.
+ This way the user can recover from loading a bad font by
+ going back to a better one. */
+ struct bdf_glyph *glyph;
+ glyph = bdf_find_glyph (df->font,
+ (int) df->charmap_data[i].character, 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (df->font, -1,
+ (int) df->charmap_data[i].character);
+ if (!glyph)
+ {
+#ifdef ENCODING_UNKNOWN
+ /* The new font doesn't have a representation for the
+ unknown glyph at the desired place, so keep the old
+ one. XXX Should load the built-in one here. */
+ if (i == FONT_INDEX_UNKNOWN)
+ continue;
+#endif
+#ifdef ENCODING_SPACE
+ /* The new font doesn't have a representation for the
+ blank glyph at the desired place, so keep the old
+ one. XXX Should load the built-in one here. */
+ if (i == FONT_INDEX_SPACE)
+ continue;
+#endif
+ memcpy (df->vga_font[i], df->vga_font[FONT_INDEX_UNKNOWN],
+ 32);
+ }
+ else
+ /* XXX Take font size and glyph size into account. */
+ memcpy (df->vga_font[i], glyph->bitmap, 32);
+ }
+ }
+
+ /* XXX This will have to be changed when we use font caching. */
+ if (active_dynafont == df)
+ vga_write_font_buffer (0, 0, (char *) df->vga_font,
+ df->size * VGA_FONT_HEIGHT);
+}
diff --git a/console/dynafont.h b/console/dynafont.h
new file mode 100644
index 00000000..8eb8d3dc
--- /dev/null
+++ b/console/dynafont.h
@@ -0,0 +1,74 @@
+/* dynafont.h - Interfaces for the dynamic font handling.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <wchar.h>
+
+#include "bdf.h"
+
+
+/* The dynafont interface does not do locking on its own, for maximum
+ efficiency it relies on locking by the caller (because usually the
+ caller has some other data structures to lock along with the
+ dynafont. However, it is safe to call two functions on different
+ dynafonts asynchronously. */
+typedef struct dynafont *dynafont_t;
+
+/* Some glyphs are always available at a fixed location. This
+ includes the representation for the unknown glyph and the blank.
+ Conveniently, the blank is located at its position in ASCII. */
+#define FONT_INDEX_UNKNOWN 0
+#define FONT_INDEX_SPACE 32
+
+/* Create a new dynafont object, which uses glyphs from the font FONT
+ (which must be 8 pixels wide and up to 32 pixels heigh). SIZE is
+ either 256 or 512, and specifies the number of available glyphs in
+ the font cache. The object is returned in DYNAFONT. The caller
+ must ensure the integrity of FONT until the object is destroyed or
+ the font is changed with dynafont_change_font. */
+error_t dynafont_new (bdf_font_t font, int size, dynafont_t *dynafont);
+
+/* Release a dynafont object and its associated resources. */
+void dynafont_free (dynafont_t df);
+
+/* Look up the vga font index for an UCS-4 character. If not already
+ mapped, try to find space for a new entry and add the mapping.
+ Acquires an additional reference to the character. Might return
+ the glyph for the unrepresentable character if the glyph is ot
+ available for this character or no free slot is available right
+ now. In the former case, some information gets lost (to do
+ otherwise, one would have to either assign one of the scarce font
+ indices to each undisplayable character value on screen, or to
+ store the whole scrollback buffer as wide chars as well to recover
+ the lost info from that copy of the original text. */
+int dynafont_lookup (dynafont_t df, wchar_t wide_chr);
+
+/* Release a reference to the glyph VGA_FONT_INDEX in dynafont DF. */
+void dynafont_release (dynafont_t df, int vga_font_index);
+
+/* Load the VGA font to the card and make it active. */
+void dynafont_activate (dynafont_t df);
+
+/* Change the font used by dynafont DF to FONT. This transformation
+ is initially loss-less, if the new font can't display some
+ characters on the screen, you can always go back to a font that
+ does and get the glyphs for those characters back. (However, the
+ comments in dynafont_lookup hold for glyphs looked up after the font
+ change.) */
+void dynafont_change_font (dynafont_t df, bdf_font_t font);
diff --git a/console/focus.c b/console/focus.c
new file mode 100644
index 00000000..7eedbd6a
--- /dev/null
+++ b/console/focus.c
@@ -0,0 +1,110 @@
+#include <argp.h>
+#include <cthreads.h>
+
+#include "console.h"
+#include "input.h"
+#include "focus.h"
+
+struct argp_option focus_argp_options[] =
+ {
+ { "focus-group", 'f', "NAME", OPTION_ARG_OPTIONAL, "Start a new focus group" },
+ { "input-device", 'i', "NAME", 0, "Add input device NAME to focus group" },
+ { "focus", 'F', "CONS[/VCONS]", 0, "Put focus on console CONS, and virtual console VCONS within if specified" },
+ { 0 }
+ };
+
+struct
+{
+ focus_t focus;
+} focus_config;
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ switch (opt)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+ case ARGP_KEY_INIT:
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR:
+ break;
+ case 'f':
+ /* Start a new focus group. */
+ focus_config.focus = 0;
+ break;
+ case 'i':
+ {
+ /* Start a new input device. */
+ int found = 0;
+ int i = 0;
+ while (input_driver[i])
+ {
+ // if (state->child_inputs[i])
+ // {
+ // input_driver->end_config
+ if (! strcmp (input_driver[i]->name, arg))
+ {
+ found = 1;
+ state->child_inputs[i] = (void *) 1;
+ }
+ else
+ state->child_inputs[i] = NULL;
+ }
+ if (!found)
+ argp_error (state, "unknown input device %s", arg);
+ }
+ }
+ return 0;
+}
+
+struct argp focus_argp =
+ { focus_argp_options, parse_opt, 0, 0, 0 /* XXX input_argp_childs */};
+
+typedef struct input *input_t;
+struct input
+{
+ input_t next;
+};
+
+struct focus
+{
+ struct mutex lock;
+
+ /* The virtual console receiving our input characters. */
+ vcons_t vcons;
+
+ /* The list of input devices. */
+ input_t input_list;
+};
+
+
+error_t
+focus_create (focus_t *r_focus)
+{
+ focus_t focus = calloc (1, sizeof (*focus));
+ if (!focus)
+ return ENOMEM;
+ mutex_init (&focus->lock);
+
+ return 0;
+}
+
+
+void
+focus_add (focus_t focus, input_t input)
+{
+ mutex_lock (&focus->lock);
+ input->next = focus->input_list;
+ focus->input_list = input;
+ mutex_unlock (&focus->lock);
+}
+
+void
+focus_switch_to (focus_t focus, vcons_t vcons)
+{
+ mutex_lock (&focus->lock);
+ vcons_activate (vcons, (int) focus);
+ focus->vcons = vcons;
+ mutex_unlock (&focus->lock);
+}
diff --git a/console/focus.h b/console/focus.h
new file mode 100644
index 00000000..bd9d8e1c
--- /dev/null
+++ b/console/focus.h
@@ -0,0 +1,31 @@
+/* focus.h - The interface to an input group.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _FOCUS_H_
+#define _FOCUS_H_ 1
+
+typedef struct focus *focus_t;
+
+extern struct argp focus_argp;
+
+#define FOCUS_ARGP_CHILD \
+ { &focus_argp, 0, "Multiple input devices in the same group share focus" }
+
+#endif /* _FOCUS_H_ */
diff --git a/console/input.h b/console/input.h
new file mode 100644
index 00000000..e660fa22
--- /dev/null
+++ b/console/input.h
@@ -0,0 +1,62 @@
+/* input.h - The interface to an input driver.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _INPUT_H_
+#define _INPUT_H_ 1
+
+#include <errno.h>
+#include <argp.h>
+
+#include "focus.h"
+
+
+struct input_ops
+{
+ const char *name;
+
+ /* Fill in ARGP with the argp_child structure for this display. */
+ error_t (*argp) (struct argp_child *argp);
+
+ /* Initialize the subsystem. */
+ error_t (*init) (void);
+
+ /* Assign the input device to the focus group FOCUS. */
+ error_t (*set_focus) (focus_t *focus);
+
+ /* Output LENGTH bytes starting from BUFFER in the system encoding.
+ Set BUFFER and LENGTH to the new values. The exact semantics are
+ just as in the iconv interface. */
+ error_t (*input) (char **buffer, size_t *length);
+};
+typedef struct input_ops *input_ops_t;
+
+extern struct input_ops pckbd_input_ops;
+extern struct input_ops mach_input_ops;
+
+input_ops_t input_driver[] =
+ {
+#if defined (__i386__)
+ &pckbd_input_ops,
+#endif
+ &mach_input_ops,
+ 0
+ };
+
+#endif
diff --git a/console/main.c b/console/main.c
new file mode 100644
index 00000000..b571b580
--- /dev/null
+++ b/console/main.c
@@ -0,0 +1,461 @@
+/* main.c - The main routine of the console server.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <hurd.h>
+#include <fcntl.h>
+#include <hurd/trivfs.h>
+#include <stdio.h>
+#include <argp.h>
+#include <hurd/fsys.h>
+#include <string.h>
+
+#include <version.h>
+
+#include "priv.h"
+#include "tioctl_S.h"
+#include "console.h"
+#include "focus.h"
+
+
+const char *argp_program_version = STANDARD_HURD_VERSION (console);
+
+int trivfs_fstype = FSTYPE_DEV;
+int trivfs_fsid = 0;
+int trivfs_support_read = 1;
+int trivfs_support_write = 1;
+int trivfs_support_exec = 0;
+
+int trivfs_allow_open = O_READ|O_WRITE;
+
+/* Properties of the underlying node. */
+int console_mode;
+int console_owner;
+int console_group;
+
+/* The argument line options. */
+struct
+{
+ char *encoding;
+ int rdev;
+} main_config;
+
+static struct argp_option options[] =
+ {
+ {"rdev", 'n', "ID", 0,
+ "The stat rdev number for this node; may be either a"
+ " single integer, or of the form MAJOR,MINOR"},
+ {"encoding", 'e', "NAME", 0,
+ "The encoding to use for input and output"},
+ {0}
+ };
+
+static struct argp_child argp_childs[] =
+ {
+ FOCUS_ARGP_CHILD,
+ /* XXX CONSOLE_ARGP_CHILD, */
+ { 0 }
+ };
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ switch (opt)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+ case ARGP_KEY_INIT:
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR:
+ break;
+ case 'n':
+ {
+ char *start = arg;
+ char *end;
+ int rdev;
+
+ rdev = strtoul (start, &end, 0);
+ if (*end == ',')
+ /* MAJOR,MINOR form */
+ {
+ start = end;
+ rdev = (rdev << 8) + strtoul (start, &end, 0);
+ }
+
+ if (end == start || *end != '\0')
+ {
+ argp_error (state, "%s: Invalid argument to --rdev", arg);
+ return EINVAL;
+ }
+ main_config.rdev = rdev;
+ }
+ break;
+ }
+ return 0;
+}
+
+static struct argp main_argp =
+ { options, parse_opt, 0, "A translator providing a console device.\v"\
+ "The translator provides access to a hardeware console usable\n"\
+ "by the HURDIO backend of the term translator.\n", argp_childs };
+
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+ struct stat st;
+
+ argp_parse (&main_argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ {
+ fprintf (stderr, "Must be started as a translator\n");
+ exit (1);
+ }
+
+ /* Set our node */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ {
+ perror ("Starting translator");
+ exit (1);
+ }
+
+ /* Initialize status from underlying node. */
+ err = io_stat (fsys->underlying, &st);
+ if (err)
+ {
+ /* We cannot stat the underlying node. Fallback to the defaults. */
+ console_owner = console_group = 0;
+ console_mode = S_IRUSR | S_IWUSR;
+ err = 0;
+ }
+ else
+ {
+ console_owner = st.st_uid;
+ console_group = st.st_gid;
+ console_mode = (st.st_mode & ACCESSPERMS);
+ }
+ console_mode |= S_IFCHR | S_IROOT;
+
+ /* Launch. */
+ ports_manage_port_operations_multithread (fsys->pi.bucket, trivfs_demuxer,
+ 0, 0, 0);
+
+ return 0;
+}
+
+
+kern_return_t
+S_tioctl_tiocflush (struct trivfs_protid *cred, int queue_selector)
+{
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openmodes & (O_READ | O_WRITE)))
+ return EBADF;
+
+ vcons = (vcons_t) cred->po->hook;
+ if (!queue_selector)
+ queue_selector = O_READ | O_WRITE;
+
+ if (queue_selector & O_READ)
+ vcons_flush_input (vcons);
+ if (queue_selector & O_WRITE)
+ vcons_discard_output (vcons);
+
+ return 0;
+}
+
+
+kern_return_t
+S_tioctl_tiogwinsz (struct trivfs_protid *cred, struct winsize *size)
+{
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ vcons = (vcons_t) cred->po->hook;
+ vcons_getsize (vcons, size);
+ return 0;
+}
+
+
+kern_return_t
+S_tioctl_tiocstart (struct trivfs_protid *cred)
+{
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openmodes & (O_READ | O_WRITE)))
+ return EBADF;
+
+ vcons = (vcons_t) cred->po->hook;
+ vcons_start_output (vcons);
+ return 0;
+}
+
+
+kern_return_t
+S_tioctl_tiocstop (struct trivfs_protid *cred)
+{
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openmodes & (O_READ | O_WRITE)))
+ return EBADF;
+
+ vcons = (vcons_t) cred->po->hook;
+ vcons_stop_output (vcons);
+ return 0;
+}
+
+
+kern_return_t
+S_tioctl_tiocoutq (struct trivfs_protid *cred, int *queue_size)
+{
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openmodes & (O_READ | O_WRITE)))
+ return EBADF;
+
+ vcons = (vcons_t) cred->po->hook;
+ *queue_size = vcons_pending_output (vcons);
+ return 0;
+}
+
+
+kern_return_t
+S_tioctl_tiocspgrp (struct trivfs_protid *cred, int pgrp)
+{
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openmodes & (O_READ | O_WRITE)))
+ return EBADF;
+
+ vcons = (vcons_t) cred->po->hook;
+ vcons_set_owner (vcons, -pgrp);
+ return 0;
+}
+
+
+kern_return_t
+S_tioctl_tiocgpgrp (struct trivfs_protid *cred, int *pgrp)
+{
+ error_t err;
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openmodes & (O_READ | O_WRITE)))
+ return EBADF;
+
+ vcons = (vcons_t) cred->po->hook;
+ err = vcons_get_owner (vcons, pgrp);
+ if (!err)
+ *pgrp = -*pgrp;
+
+ return err;
+}
+
+
+error_t
+trivfs_S_file_set_size (struct trivfs_protid *cred, off_t size)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openmodes & (O_READ | O_WRITE)))
+ return EBADF;
+ return 0;
+}
+
+
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred, off_t off, int whence,
+ off_t *newp)
+{
+ return ESPIPE;
+}
+
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ st->st_blksize = 512;
+ st->st_ino = 0;
+ st->st_rdev = main_config.rdev;
+ st->st_mode = console_mode;
+ st->st_uid = console_owner;
+ st->st_gid = console_group;
+}
+
+
+/* Called for user writes to the console as described in
+ <hurd/io.defs>. */
+error_t
+trivfs_S_io_write (struct trivfs_protid *cred, char *data, u_int datalen,
+ off_t offset, int *amount)
+{
+ error_t err = 0;
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (! (cred->po->openmodes & O_WRITE))
+ return EBADF;
+
+ vcons = (vcons_t) cred->po->hook;
+ *amount = vcons_output (vcons, cred->po->openmodes & O_NONBLOCK,
+ data, datalen);
+ if (*amount == -1)
+ err = errno;
+
+ return err;
+}
+
+
+/* Called for user reads from the console. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred, char **data, u_int *datalen,
+ off_t offset, int amount)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+
+ /* XXX */
+ return EOPNOTSUPP;
+}
+
+
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred, int *type)
+{
+ error_t err = 0;
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (! (cred->po->openmodes & O_READ))
+ *type &= ~SELECT_READ;
+ if (! (cred->po->openmodes & O_WRITE))
+ *type &= ~SELECT_WRITE;
+
+ vcons = (vcons_t) cred->po->hook;
+ if (type)
+ err = vcons_select (vcons, type);
+ return err;
+}
+
+
+error_t
+trivfs_S_io_readable (struct trivfs_protid *cred, int *amt)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ if ((cred->po->openmodes & O_READ) == 0)
+ return EBADF;
+
+ /* XXX */
+ // *amt = qsize (inputq);
+ return 0;
+}
+
+
+kern_return_t
+trivfs_S_io_get_openmodes (struct trivfs_protid *cred, int *bits)
+{
+ return EOPNOTSUPP;
+}
+
+
+error_t
+trivfs_S_io_set_all_openmodes (struct trivfs_protid *cred, int bits)
+{
+ return EOPNOTSUPP;
+}
+
+
+error_t
+trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred, int bits)
+{
+ return EOPNOTSUPP;
+}
+
+
+error_t
+trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred, int bits)
+{
+ return EOPNOTSUPP;
+}
+
+
+error_t
+trivfs_S_io_mod_owner (struct trivfs_protid *cred, pid_t owner)
+{
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openmodes & (O_READ | O_WRITE)))
+ return EBADF;
+
+ vcons = (vcons_t) cred->po->hook;
+ vcons_set_owner (vcons, owner);
+ return 0;
+}
+
+
+error_t
+trivfs_S_io_get_owner (struct trivfs_protid *cred, pid_t *owner)
+{
+ error_t err;
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openmodes & (O_READ | O_WRITE)))
+ return EBADF;
+
+ vcons = (vcons_t) cred->po->hook;
+ err = vcons_get_owner (vcons, owner);
+ return err;
+}
+
+
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ return EBUSY;
+}
diff --git a/console/mutations.h b/console/mutations.h
new file mode 100644
index 00000000..396bf1e5
--- /dev/null
+++ b/console/mutations.h
@@ -0,0 +1,26 @@
+/* mutations.h - Automagic type transformation for MiG interfaces.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* Only CPP macro definitions should go in this file. */
+
+#define IO_INTRAN trivfs_protid_t trivfs_begin_using_protid (io_t)
+#define IO_DESTRUCTOR trivfs_end_using_protid (trivfs_protid_t)
+
+#define IO_IMPORTS import "priv.h";
diff --git a/console/priv.h b/console/priv.h
new file mode 100644
index 00000000..98e61bdf
--- /dev/null
+++ b/console/priv.h
@@ -0,0 +1 @@
+typedef struct trivfs_protid *trivfs_protid_t;
diff --git a/console/vga-display.c b/console/vga-display.c
new file mode 100644
index 00000000..6b7dc146
--- /dev/null
+++ b/console/vga-display.c
@@ -0,0 +1,832 @@
+/* vga-display.c - The VGA device dependant part of a (virtual) console.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <iconv.h>
+#include <argp.h>
+
+#include <sys/io.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <cthreads.h>
+
+#include "vga.h"
+#include "dynafont.h"
+#include "display.h"
+
+
+struct vga_display_console
+{
+ /* The lock for the vga display console structure. */
+ struct mutex lock;
+
+ /* The state of the conversion of output characters. */
+ iconv_t cd;
+
+ /* The parsing state of output characters, needed to handle escape
+ character sequences. */
+ enum
+ {
+ STATE_NORMAL = 0,
+ /* An escape character has just been parsed. */
+ STATE_ESC,
+ STATE_ESC_BRACKET_INIT,
+ STATE_ESC_BRACKET,
+ STATE_ESC_BRACKET_QUESTION
+ } parse_state;
+
+ /* How many parameters an escape sequence may have. */
+#define PARSE_MAX_PARAMS 10
+ int parse_params[PARSE_MAX_PARAMS];
+ int parse_nparams;
+
+ /* The VGA font for this virtual console. */
+ dynafont_t df;
+
+ /* The complete video buffer, including the scroll back buffer. */
+ char *video_buffer;
+
+ /* The size of the video buffer, in lines. */
+ int video_buffer_lines;
+
+ /* The top most line of the screen in the video buffer. */
+ int current_line;
+
+ /* The number of lines scrolled back. */
+ int scrolling;
+
+ /* Maximum number of lines scrolled back. */
+ int scrolling_max;
+
+ /* True if the cursor is not displayed. */
+ int cursor_off;
+
+ int width;
+ int height;
+ int cursor_x;
+ int cursor_y;
+ /* Current attribute. */
+ char attr;
+};
+
+
+/* Protects the VGA hardware and all global variables, like the active
+ console. */
+static struct mutex vga_lock;
+
+/* The currently active console. */
+static struct vga_display_console *active_console;
+
+
+/* Initialize the subsystem. */
+error_t
+vga_display_init ()
+{
+ mutex_init (&vga_lock);
+ return vga_init ();
+}
+
+
+/* Create a new (virtual) console display, with the system encoding
+ being ENCODING. A failure at the first time this is called is
+ critical. Subsequent calls might return an error if multiple
+ virtual consoles are not supported. Further operations on this
+ console will be called with the first parameter being *HOOK, which
+ should be set to some unique identifier for this console. */
+error_t
+vga_display_create (void **console, const char *encoding)
+{
+ error_t err = 0;
+ struct vga_display_console *cons;
+
+ cons = calloc (1, sizeof *cons);
+ if (cons)
+ return ENOMEM;
+ mutex_init (&cons->lock);
+ err = dynafont_new (0 /*XXX*/, 256, &cons->df);
+ if (err)
+ {
+ free (cons);
+ return err;
+ }
+
+ cons->width = 80;
+ cons->height = 25;
+ cons->video_buffer_lines = 200; /* XXX For now. */
+ cons->video_buffer = malloc (cons->video_buffer_lines * cons->width * 2);
+ if (!cons->video_buffer)
+ {
+ dynafont_free (cons->df);
+ free (cons);
+ return ENOMEM;
+ }
+ cons->current_line = 0;
+ /* XXX Fill out the first cons->height lines of the buffer here (or
+ later). */
+
+ /* WCHAR_T happens to be UCS-4 on the GNU system. */
+ cons->cd = iconv_open ("WCHAR_T", encoding);
+ if (cons->cd == (iconv_t) -1)
+ {
+ err = errno;
+ dynafont_free (cons->df);
+ free (cons->video_buffer);
+ free (cons);
+ }
+ return err;
+}
+
+
+/* Destroy the console CONSOLE. The caller will first activate a
+ different console. */
+void
+vga_display_destroy (void *console)
+{
+ struct vga_display_console *cons = console;
+ iconv_close (cons->cd);
+ dynafont_free (cons->df);
+ free (cons);
+}
+
+
+/* Update the cursor position on the screen. Expects CONS and the VGA
+ hardware to be locked and CONS to be the active console. */
+static void
+vga_display_update_cursor (struct vga_display_console *cons)
+{
+ int pos;
+
+ if (cons->cursor_off)
+ return;
+
+ pos = cons->cursor_x + (cons->cursor_y + cons->scrolling) * cons->width;
+
+ vga_set_cursor (pos);
+}
+
+
+/* Update the screen content. Expects CONS and the VGA hardware to be
+ locked and CONS to be the active console. XXX Maybe inline/macro. */
+static void
+vga_display_update_screen (struct vga_display_console *cons)
+{
+ int start_line = cons->current_line - cons->scrolling;
+ int lines;
+
+ if (start_line < 0)
+ start_line += cons->video_buffer_lines;
+ lines = cons->video_buffer_lines - start_line;
+ if (lines > cons->height)
+ lines = cons->height;
+
+ memcpy (vga_videomem, cons->video_buffer + start_line * cons->width * 2,
+ lines * cons->width * 2);
+ if (lines < cons->height)
+ memcpy (vga_videomem, cons->video_buffer,
+ (cons->height - lines) * cons->width * 2);
+}
+
+
+/* Change the active console to CONSOLE. */
+void
+vga_display_activate (void *console, int key)
+{
+ struct vga_display_console *cons = console;
+
+ mutex_lock (&cons->lock);
+ mutex_lock (&vga_lock);
+ active_console = cons;
+ dynafont_activate (cons->df);
+ vga_display_update_screen (cons);
+ vga_display_update_cursor (cons);
+ vga_display_cursor (!cons->cursor_off);
+ mutex_unlock (&vga_lock);
+ mutex_unlock (&cons->lock);
+}
+
+
+/* Scroll the console CONSOLE by the desired amount. This is only a
+ hint, the actual amount scrolled might depend on the capability of
+ the subsystem. Negative AMOUNT scrolls back in history. */
+error_t
+vga_display_scroll (void *console, int amount)
+{
+ struct vga_display_console *cons = console;
+ int old_scrolling;
+ int cursor_state_change = 0;
+
+ mutex_lock (&cons->lock);
+ old_scrolling = cons->scrolling;
+ cons->scrolling -= amount;
+ if (cons->scrolling < 0)
+ cons->scrolling = 0;
+ else if (cons->scrolling > cons->scrolling_max)
+ cons->scrolling = cons->scrolling_max;
+
+ if (old_scrolling != cons->scrolling)
+ {
+ if ((!cons->cursor_off
+ && cons->cursor_y + cons->scrolling >= cons->height)
+ || (cons->cursor_off
+ && cons->cursor_y + cons->scrolling < cons->height))
+ {
+ cons->cursor_off = !cons->cursor_off;
+ cursor_state_change = 1;
+ }
+
+ mutex_lock (&vga_lock);
+ if (active_console == cons)
+ {
+ /* XXX Replace this with a fast memmove in the video
+ memory. */
+ vga_display_update_screen (cons);
+ if (cursor_state_change)
+ vga_display_cursor (!cons->cursor_off);
+ }
+ mutex_unlock (&vga_lock);
+ }
+ mutex_unlock (&cons->lock);
+ return 0;
+}
+
+
+/* Change the font on the console CONSOLE to font. The old font will
+ not be accessed by the vga console subsystem anymore after this
+ call completed. */
+void
+vga_display_change_font (void *console, bdf_font_t font)
+{
+ struct vga_display_console *cons = console;
+ mutex_lock (&cons->lock);
+ dynafont_change_font (cons->df, font);
+ mutex_unlock (&cons->lock);
+}
+
+
+#if 0
+static void
+limit_cursor (struct emu *emu)
+{
+ if (emu->x >= emu->width)
+ emu->x = emu->width - 1;
+ else if (emu->x < 0)
+ emu->x = 0;
+
+ if (emu->y >= emu->height)
+ emu->y = emu->height - 1;
+ else if (emu->y < 0)
+ emu->y = 0;
+}
+
+static void
+handle_esc_bracket_hl (struct emu *emu, int code, int flag)
+{
+ switch (code)
+ {
+ case 34: /* cursor standout: <cnorm>, <cvvis> */
+ emu->cursor_standout = flag;
+ recalc_cursor (emu);
+ break;
+ }
+}
+
+static void
+handle_esc_bracket_m (struct emu *emu, int code)
+{
+ switch (code)
+ {
+ case 0: /* all attributes off: <sgr0> */
+ emu->fg = emu->def_fg;
+ emu->bg = emu->def_bg;
+ emu->reverse = emu->bold = emu->blink =
+ emu->invisible = emu->dim = emu->underline = 0;
+ /* Cursor attributes aren't text attributes. */
+ break;
+ case 1: /* bold on: <bold> */
+ emu->bold = 1;
+ break;
+ case 2: /* dim on: <dim> */
+ emu->dim = 1;
+ break;
+ case 4: /* underline on: <smul> */
+ emu->underline = 1;
+ break;
+ case 5: /* blink on: <blink> */
+ emu->blink = 1;
+ break;
+ case 7: /* reverse video on: <rev>, <smso> */
+ emu->reverse = 1;
+ break;
+ case 8: /* concealed on: <invis> */
+ emu->invisible = 1;
+ break;
+ case 21: /* bold off */
+ emu->bold = 0;
+ break;
+ case 22: /* dim off */
+ emu->dim = 0;
+ break;
+ case 24: /* underline off: <rmul> */
+ emu->underline = 0;
+ break;
+ case 25: /* blink off */
+ emu->blink = 0;
+ break;
+ case 27: /* reverse video off: <rmso> */
+ emu->reverse = 0;
+ break;
+ case 28: /* concealed off */
+ emu->invisible = 0;
+ break;
+ /* Case ranges are a GCC extension. */
+ case 30 ... 37: /* set foreground color: <setaf> */
+ emu->fg = code - 30;
+ break;
+ case 39: /* default foreground color; ANSI? */
+ emu->fg = emu->def_fg;
+ break;
+ case 40 ... 47: /* set background color: <setab> */
+ emu->bg = code - 40;
+ break;
+ case 49: /* default background color; ANSI? */
+ emu->bg = emu->def_bg;
+ break;
+ }
+}
+
+static void
+handle_esc_bracket (struct emu *emu, char op)
+{
+ int i;
+ switch (op)
+ {
+ case 'H': case 'f': /* cursor position: <cup> */
+ emu->x = emu->params[1] - 1;
+ emu->y = emu->params[0] - 1;
+ limit_cursor (emu);
+ break;
+ case 'G': /* horizontal position: <hpa> */
+ emu->x = emu->params[0] - 1;
+ limit_cursor (emu);
+ break;
+ case 'F': /* beginning of previous line */
+ emu->x = 0;
+ /* fall through */
+ case 'A': /* cursor up: <cuu>, <cuu1> */
+ /* (a ?: b) is a GCC extension meaning (a ? a : b). */
+ emu->y -= (emu->params[0] ?: 1);
+ limit_cursor (emu);
+ break;
+ case 'E': /* beginning of next line */
+ emu->x = 0;
+ /* fall through */
+ case 'B': /* cursor down: <cud1>, <cud> */
+ emu->y += (emu->params[0] ?: 1);
+ limit_cursor (emu);
+ break;
+ case 'C': /* cursor right: <cuf1>, <cuf> */
+ emu->x += (emu->params[0] ?: 1);
+ limit_cursor (emu);
+ break;
+ case 'D': /* cursor left: <cub>, <cub1> */
+ emu->x -= (emu->params[0] ?: 1);
+ limit_cursor (emu);
+ break;
+ case 's': /* save cursor position: <sc> */
+ emu->saved_x = emu->x;
+ emu->saved_y = emu->y;
+ break;
+ case 'u': /* restore cursor position: <rc> */
+ emu->x = emu->saved_x;
+ emu->y = emu->saved_y;
+ limit_cursor (emu); /* in case the screen was larger before */
+ break;
+ case 'h': /* reset mode */
+ for (i = 0; i < emu->nparams; ++i)
+ handle_esc_bracket_hl (emu, emu->params[i], 0);
+ break;
+ case 'l': /* set mode */
+ for (i = 0; i < emu->nparams; ++i)
+ handle_esc_bracket_hl (emu, emu->params[i], 1);
+ break;
+ case 'm':
+ for (i = 0; i < emu->nparams; ++i)
+ handle_esc_bracket_m (emu, emu->params[i]);
+ recalc_attr (emu);
+ break;
+ case 'J':
+ switch (emu->params[0])
+ {
+ case 0: /* clear to end of screen: <ed> */
+ screen_fill (emu->screen, emu->x, emu->y, emu->width - emu->x, 1,
+ emu->attr | ' ');
+ screen_fill (emu->screen, 0, emu->y+1,
+ emu->width, emu->height - emu->y,
+ emu->attr | ' ');
+ break;
+ case 1: /* clear to beginning of screen */
+ screen_fill (emu->screen, 0, 0, emu->width, emu->y,
+ emu->attr | ' ');
+ screen_fill (emu->screen, 0, emu->y, emu->x + 1, 1,
+ emu->attr | ' ');
+ break;
+ case 2: /* clear entire screen */
+ screen_fill (emu->screen, 0, 0, emu->width, emu->height,
+ emu->attr | ' ');
+ break;
+ }
+ break;
+ case 'K':
+ switch (emu->params[0])
+ {
+ case 0: /* clear to end of line: <el> */
+ screen_fill (emu->screen, emu->x, emu->y, emu->width - emu->x, 1,
+ emu->attr | ' ');
+ break;
+ case 1: /* clear to beginning of line: <el1> */
+ screen_fill (emu->screen, 0, emu->y, emu->x + 1, 1,
+ emu->attr | ' ');
+ break;
+ case 2: /* clear entire line */
+ screen_fill (emu->screen, 0, emu->y, emu->width, 1,
+ emu->attr | ' ');
+ break;
+ }
+ break;
+ case 'L': /* insert line(s): <il1>, <il> */
+ screen_scroll_down (emu->screen, 0, emu->y,
+ emu->width, emu->height - emu->y,
+ emu->params[0] ?: 1, emu->attr | ' ');
+ break;
+ case 'M': /* delete line(s): <dl1>, <dl> */
+ screen_scroll_up (emu->screen, 0, emu->y,
+ emu->width, emu->height - emu->y,
+ emu->params[0] ?: 1, emu->attr | ' ');
+ break;
+ case '@': /* insert character(s): <ich1>, <ich> */
+ screen_scroll_right (emu->screen, emu->x, emu->y,
+ emu->width - emu->x, 1,
+ emu->params[0] ?: 1, emu->attr | ' ');
+ break;
+ case 'P': /* delete character(s): <dch1>, <dch> */
+ screen_scroll_left (emu->screen, emu->x, emu->y,
+ emu->width - emu->x, 1,
+ emu->params[0] ?: 1, emu->attr | ' ');
+ break;
+ case 'S': /* scroll up: <ind>, <indn> */
+ screen_scroll_up (emu->screen, 0, 0, emu->width, emu->height,
+ emu->params[0] ?: 1, emu->attr | ' ');
+ break;
+ case 'T': /* scroll down: <ri>, <rin> */
+ screen_scroll_down (emu->screen, 0, 0, emu->width, emu->height,
+ emu->params[0] ?: 1, emu->attr | ' ');
+ break;
+ case 'X': /* erase character(s): <ech> */
+ screen_fill (emu->screen, emu->x, emu->y, emu->params[0] ?: 1, 1,
+ emu->attr | ' ');
+ break;
+ }
+}
+
+static void
+handle_esc_bracket_question_hl (struct emu *emu, int code, int flag)
+{
+ switch (code)
+ {
+ case 25: /* cursor invisibility: <civis>, <cnorm> */
+ emu->cursor_invisible = flag;
+ recalc_cursor (emu);
+ break;
+ }
+}
+
+static void
+handle_esc_bracket_question (struct emu *emu, char op)
+{
+ int i;
+ switch (op)
+ {
+ case 'h': /* reset mode */
+ for (i = 0; i < emu->nparams; ++i)
+ handle_esc_bracket_question_hl (emu, emu->params[i], 0);
+ break;
+ case 'l': /* set mode */
+ for (i = 0; i < emu->nparams; ++i)
+ handle_esc_bracket_question_hl (emu, emu->params[i], 1);
+ break;
+ }
+}
+#endif
+
+/* Console must be locked. */
+static void
+vga_display_output_one (struct vga_display_console *cons, wchar_t chr)
+{
+#if 0
+ switch (cons->parse_state)
+ {
+ case STATE_NORMAL:
+ switch (chr)
+ {
+ case '\r':
+ /* Carriage return: <cr>. */
+ if (cons->cursor_x)
+ {
+ cons->cursor_x = 0;
+ mutex_lock (&vga_lock);
+ if (active_console == cons)
+ vga_display_update_cursor (cons);
+ mutex_unlock (&vga_lock);
+ }
+ break;
+ case '\n':
+ /* Cursor down: <cud1>, scroll up: <ind>. */
+ if (cons->cursor_y < cons->height - 1)
+ {
+ cons->cursor_y++;
+ mutex_lock (&vga_lock);
+ if (active_console == cons)
+ vga_display_update_cursor (cons);
+ mutex_unlock (&vga_lock);
+ }
+ else
+ {
+ if (cons->current_line == cons->video_buffer_lines - 1)
+ cons->current_line = 0;
+ else
+ cons->current_line++;
+ /* XXX Empty out current line with spaces. */
+ if (cons->scrolling_max
+ < cons->video_buffer_lines - cons->height)
+ cons->scrolling_max++;
+ mutex_lock (&vga_lock);
+ if (active_console == cons)
+ vga_display_update_screen (cons);
+ mutex_unlock (&vga_lock);
+ }
+ break;
+ case '\b':
+ /* Cursor backward: <cub1>. */
+ if (cons->cursor_x > 0 || cons->cursor_y > 0)
+ {
+ if (cons->cursor_x > 0)
+ cons->cursor_x--;
+ else
+ {
+ /* XXX This implements the <bw> functionality.
+ The alternative is to cut off and set x to 0. */
+ cons->cursor_x = cons->width - 1;
+ cons->cursor_y--;
+ }
+ mutex_lock (&vga_lock);
+ if (active_console == cons)
+ vga_display_update_cursor (cons);
+ mutex_unlock (&vga_lock);
+ }
+ break;
+ case '\t': /* horizontal tab: <ht> */
+ cons->cursor_x = (cons->cursor_x | 7) + 1;
+ if (cons->cursor_x >= cons->width)
+ {
+ cons->cursor_x = 0;
+ if (cons->cursor_y < cons->height - 1)
+ cons->cursor_y++;
+ else
+ {
+ if (cons->current_line == cons->video_buffer_lines - 1)
+ cons->current_line = 0;
+ else
+ cons->current_line++;
+ /* XXX Empty out current line with spaces. */
+ if (cons->scrolling_max
+ < cons->video_buffer_lines - cons->height)
+ cons->scrolling_max++;
+ mutex_lock (&vga_lock);
+ if (active_console == cons)
+ {
+ vga_display_update_screen (cons);
+ vga_display_update_cursor (cons);
+ }
+ mutex_unlock (&vga_lock);
+ /* Out. */
+ break;
+ }
+ }
+ mutex_lock (&vga_lock);
+ if (active_console == cons)
+ vga_display_update_cursor (cons);
+ mutex_unlock (&vga_lock);
+ break;
+ case '\033':
+ cons->parse_state = STATE_ESC;
+ break;
+ case '\0':
+ /* Padding character: <pad>. */
+ break;
+ default:
+ {
+ int charval = dynafont_lookup (cons->df, chr);
+ int line = (cons->current_line + cons->cursor_y)
+ % cons->video_buffer_lines;
+
+ cons->video_buffer[(line * cons->width + cons->cursor_x) * 2]
+ = charval & 0xff;
+ cons->video_buffer[(line * cons->width + cons->cursor_x) * 2 + 1]
+ = cons->attr | (cons->size == 512 ? (charval >> 5) & 0x8 : 0);
+
+ /* XXX Taking the lock twice, once here, and once below. */
+ if (cons->cursor_y + cons->scrolling < cons->height)
+ {
+ mutex_lock (&vga_lock);
+ if (active_console == cons)
+ {
+ vga_videomem[((cons->cursor_y + cons->scrolling)
+ * cons->width
+ + cons->cursor_x) * 2] = charval;
+ vga_videomem[((cons->cursor_y + cons->scrolling)
+ * cons->width
+ + cons->cursor_x) * 2 + 1] = cons->attr;
+ }
+ mutex_unlock (&vga_lock);
+ }
+
+ cons->cursor_x++;
+ if (cons->cursor_x == cons->height)
+ {
+ cons->cursor_x = 0;
+ if (cons->cursor_y < cons->height - 1)
+ cons->cursor_y++;
+ else
+ {
+ if (cons->current_line == cons->video_buffer_lines - 1)
+ cons->current_line = 0;
+ else
+ cons->current_line++;
+ /* XXX Empty out current line with spaces. */
+ if (cons->scrolling_max
+ < cons->video_buffer_lines - cons->height)
+ cons->scrolling_max++;
+ mutex_lock (&vga_lock);
+ if (active_console == cons)
+ {
+ vga_display_update_screen (cons);
+ vga_display_update_cursor (cons);
+ }
+ mutex_unlock (&vga_lock);
+ /* Out. */
+ break;
+ }
+ }
+ mutex_lock (&vga_lock);
+ if (active_console == cons)
+ vga_display_update_cursor (cons);
+ mutex_unlock (&vga_lock);
+ break;
+ }
+ }
+ break;
+
+ case STATE_ESC:
+ switch (chr)
+ {
+ case '[':
+ cons->parse_state = STATE_ESC_BRACKET_INIT;
+ break;
+ case 'c':
+ /* Clear screen and home cursor: <clear>. */
+ /* XXX */
+ // screen_fill (cons->screen, 0, 0, cons->width, cons->height,
+ // emu->attr | ' ');
+ cons->cursor_x = cons->cursor_y = 0;
+ cons->parse_state = STATE_NORMAL;
+ break;
+ default:
+ /* Unsupported escape sequence. */
+ cons->parse_state = STATE_NORMAL;
+ break;
+ }
+ break;
+
+ case STATE_ESC_BRACKET_INIT:
+ memset (&cons->parse_params, 0, sizeof cons->parse_params);
+ cons->parse_nparams = 0;
+ if (chr == '?')
+ {
+ cons->parse_state = STATE_ESC_BRACKET_QUESTION;
+ break; /* Consume the question mark. */
+ }
+ else
+ cons->parse_state = STATE_ESC_BRACKET;
+ /* Fall through. */
+ case STATE_ESC_BRACKET:
+ case STATE_ESC_BRACKET_QUESTION:
+ if (chr >= '0' && chr <= '9')
+ cons->parse_params[cons->parse_nparams]
+ = cons->parse_params[cons->parse_nparams]*10 + chr - '0';
+ else if (chr == ';')
+ {
+ if (++(cons->parse_nparams) >= PARSE_MAX_PARAMS)
+ cons->parse_state = STATE_NORMAL; /* too many */
+ }
+ else
+ {
+ cons->parse_nparams++;
+ if (cons->parse_state == STATE_ESC_BRACKET)
+ handle_esc_bracket (emu, chr);
+ else
+ handle_esc_bracket_question (emu, chr);
+ cons->parse_state = STATE_NORMAL;
+ }
+ break;
+ default:
+ abort ();
+ }
+#endif
+}
+
+
+/* Output LENGTH bytes starting from BUFFER in the system encoding.
+ Set BUFFER and LENGTH to the new values. The exact semantics are
+ just as in the iconv interface. */
+error_t
+vga_display_output (void *console, char **buffer, size_t *length)
+{
+#define CONV_OUTBUF_SIZE 256
+ struct vga_display_console *cons = console;
+ error_t err = 0;
+
+ mutex_lock (&cons->lock);
+ while (!err && *length > 0)
+ {
+ size_t nconv;
+ wchar_t outbuf[CONV_OUTBUF_SIZE];
+ char *outptr = (char *) outbuf;
+ size_t outsize = CONV_OUTBUF_SIZE;
+ error_t saved_err;
+ int i;
+
+ nconv = iconv (cons->cd, buffer, length, &outptr, &outsize);
+ saved_err = errno;
+
+ /* First process all successfully converted characters. */
+ for (i = 0; i < CONV_OUTBUF_SIZE - outsize; i++)
+ vga_display_output_one (cons, outbuf[i]);
+
+ if (nconv == (size_t) -1)
+ {
+ /* Conversion didn't work out. */
+ if (saved_err == EINVAL)
+ /* This is only an unfinished byte sequence at the end of
+ the input buffer. */
+ break;
+ else if (saved_err != E2BIG)
+ err = saved_err;
+ }
+ }
+ mutex_unlock (&cons->lock);
+ return err;
+}
+
+
+void
+vga_display_getsize (void *console, struct winsize *winsize)
+{
+ struct vga_display_console *cons = console;
+ mutex_lock (&cons->lock);
+ winsize->ws_row = cons->height;
+ winsize->ws_col = cons->width;
+ winsize->ws_xpixel = 0;
+ winsize->ws_ypixel = 0;
+ mutex_unlock (&cons->lock);
+}
+
+
+struct display_ops vga_display_ops =
+{
+ vga_display_init,
+ vga_display_create,
+ vga_display_destroy,
+ vga_display_activate,
+ vga_display_scroll,
+ vga_display_output,
+ vga_display_getsize
+};
diff --git a/console/vga-hw.h b/console/vga-hw.h
new file mode 100644
index 00000000..dc147e00
--- /dev/null
+++ b/console/vga-hw.h
@@ -0,0 +1,111 @@
+/* vga-hw.h - Definitions for the VGA hardware.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _VGA_HW_H_
+#define _VGA_HW_H_ 1
+
+#define VGA_VIDEO_MEM_BASE_ADDR 0x0a0000
+#define VGA_VIDEO_MEM_LENGTH 0x004000
+
+#define VGA_FONT_BUFFER 8
+#define VGA_FONT_SIZE 256
+#define VGA_FONT_HEIGHT 32
+
+#define VGA_MIN_REG 0x3c0
+#define VGA_MAX_REG 0x3df
+
+/* The sequencer address register selects the sub-register of the
+ sequencer that is accessed through the sequencer data register. */
+#define VGA_SEQ_ADDR_REG 0x3c4
+#define VGA_SEQ_DATA_REG 0x3c5
+
+/* The reset subregister can be used to asynchronously or
+ synchronously halt or clear the sequencer. */
+#define VGA_SEQ_RESET_ADDR 0x00
+#define VGA_SEQ_RESET_ASYNC 0x10 /* Can cause loss of video data. */
+#define VGA_SEQ_RESET_SYNC 0x01
+#define VGA_SEQ_RESET_CLEAR 0x11 /* Sequencer can operate. */
+
+/* The map subregister specifies which planes are written to. */
+#define VGA_SEQ_MAP_ADDR 0x02
+#define VGA_SEQ_MAP_PLANE0 0x01
+#define VGA_SEQ_MAP_PLANE1 0x02
+#define VGA_SEQ_MAP_PLANE2 0x04
+#define VGA_SEQ_MAP_PLANE3 0x08
+
+/* The font subregister. */
+#define VGA_SEQ_FONT_ADDR 0x03
+
+/* The memory mode subregister specifies the way that memory is
+ accessed. */
+#define VGA_SEQ_MODE_ADDR 0x04
+#define VGA_SEQ_MODE_EXT 0x02 /* Access 265kB rather than 64kB. */
+#define VGA_SEQ_MODE_SEQUENTIAL 0x04 /* Sequential, not odd/even addr. */
+#define VGA_SEQ_MODE_CHAIN4 0x08 /* Chain 4 addressing. */
+
+
+/* The graphics address register selects the sub-register that is
+ accessed through the graphics data register. */
+#define VGA_GFX_ADDR_REG 0x3ce
+#define VGA_GFX_DATA_REG 0x3cf
+
+/* The map subregister selects the plane to read from. */
+#define VGA_GFX_MAP_ADDR 0x04
+#define VGA_GFX_MAP_PLANE0 0x00
+#define VGA_GFX_MAP_PLANE1 0x01
+#define VGA_GFX_MAP_PLANE2 0x02
+#define VGA_GFX_MAP_PLANE3 0x03
+
+/* The mode subregister selects the memory access mode. */
+#define VGA_GFX_MODE_ADDR 0x05
+#define VGA_GFX_MODE_SHIFT256 0x40
+#define VGA_GFX_MODE_SHIFT 0x20
+#define VGA_GFX_MODE_HOSTOE 0x10
+#define VGA_GFX_MODE_READ0 0x00
+#define VGA_GFX_MODE_READ1 0x08
+#define VGA_GFX_MODE_WRITE0 0x00
+#define VGA_GFX_MODE_WRITE1 0x01
+#define VGA_GFX_MODE_WRITE2 0x02
+#define VGA_GFX_MODE_WRITE3 0x03
+
+/* The miscellaneous subregister. */
+#define VGA_GFX_MISC_ADDR 0x06
+#define VGA_GFX_MISC_GFX 0x01 /* Switch on graphics mode. */
+#define VGA_GFX_MISC_CHAINOE 0x02
+#define VGA_GFX_MISC_A0TOBF 0x00
+#define VGA_GFX_MISC_A0TOAF 0x04
+#define VGA_GFX_MISC_B0TOB7 0x08
+#define VGA_GFX_MISC_B8TOBF 0x0c
+
+
+/* The CRTC Registers. XXX Depends on the I/O Address Select field.
+ However, the only need to use the other values is for compatibility
+ with monochrome adapters. */
+#define VGA_CRT_ADDR_REG 0x3d4
+#define VGA_CRT_DATA_REG 0x3d5
+
+/* The cursor start subregister. */
+#define VGA_CRT_CURSOR_START 0x0a
+#define VGA_CRT_CURSOR_DISABLE 0x10
+
+#define VGA_CRT_CURSOR_HIGH 0x0e
+#define VGA_CRT_CURSOR_LOW 0x0f
+
+#endif
diff --git a/console/vga.c b/console/vga.c
new file mode 100644
index 00000000..9ad9c08c
--- /dev/null
+++ b/console/vga.c
@@ -0,0 +1,189 @@
+/* vga.c - VGA hardware access.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/io.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include "vga-hw.h"
+#include "vga.h"
+
+
+/* The base of the video memory mapping. */
+char *vga_videomem;
+
+/* Initialize the VGA hardware and set up the permissions and memory
+ mappings. */
+error_t
+vga_init (void)
+{
+ error_t err;
+ int fd;
+
+ if (io_perm (VGA_MIN_REG, VGA_MAX_REG - VGA_MIN_REG + 1, 1) < 0)
+ return errno;
+
+ fd = open ("/dev/mem", O_RDWR);
+ if (fd < 0)
+ return errno;
+ vga_videomem = mmap (0, VGA_VIDEO_MEM_LENGTH, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, VGA_VIDEO_MEM_BASE_ADDR);
+ err = errno;
+ close (fd);
+ if (vga_videomem == (void *) -1)
+ return err;
+ return 0;
+}
+
+
+/* Release the resources and privileges associated with the VGA
+ hardware access. */
+void
+vga_deinit (void)
+{
+ io_perm (VGA_MIN_REG, VGA_MAX_REG, 0);
+ munmap (vga_videomem, VGA_VIDEO_MEM_LENGTH);
+}
+
+
+/* Write DATALEN bytes from DATA to the font buffer BUFFER, starting
+ from glyph INDEX. */
+void
+vga_write_font_buffer (int buffer, int index, char *data, size_t datalen)
+{
+ char saved_seq_map;
+ char saved_seq_mode;
+ char saved_gfx_mode;
+ char saved_gfx_misc;
+
+ int offset = buffer * VGA_FONT_SIZE + index * VGA_FONT_HEIGHT;
+ assert (offset >= 0 && offset + datalen <= VGA_VIDEO_MEM_LENGTH);
+
+ /* Select plane 2 for sequential writing. */
+ outb_p (VGA_SEQ_MAP_ADDR, VGA_SEQ_ADDR_REG);
+ saved_seq_map = inb_p (VGA_SEQ_DATA_REG);
+ outb_p (VGA_SEQ_MAP_PLANE2, VGA_SEQ_DATA_REG);
+ outb_p (VGA_SEQ_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ saved_seq_mode = inb_p (VGA_SEQ_DATA_REG);
+ outb_p (VGA_SEQ_MODE_SEQUENTIAL | VGA_SEQ_MODE_EXT | 0x1 /* XXX Why? */,
+ VGA_SEQ_DATA_REG);
+
+ /* Set write mode 0, but assume that rotate count, enable set/reset,
+ logical operation and bit mask fields are set to their
+ `do-not-modify-host-value' default. The misc register is set to
+ select sequential addressing in text mode. */
+ outb_p (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ saved_gfx_mode = inb_p (VGA_GFX_DATA_REG);
+ outb_p (VGA_GFX_MODE_WRITE0, VGA_GFX_DATA_REG);
+ outb_p (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ saved_gfx_misc = inb_p (VGA_GFX_DATA_REG);
+ outb_p (VGA_GFX_MISC_A0TOAF, VGA_GFX_DATA_REG);
+
+ memcpy (vga_videomem + offset, data, datalen);
+
+ /* Restore sequencer and graphic register values. */
+ outb_p (VGA_SEQ_MAP_ADDR, VGA_SEQ_ADDR_REG);
+ outb_p (saved_seq_map, VGA_SEQ_DATA_REG);
+ outb_p (VGA_SEQ_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ outb_p (saved_seq_mode, VGA_SEQ_DATA_REG);
+
+ outb_p (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ outb_p (saved_gfx_mode, VGA_GFX_DATA_REG);
+ outb_p (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ outb_p (saved_gfx_misc, VGA_GFX_DATA_REG);
+}
+
+
+/* Read DATALEN bytes into DATA from the font buffer BUFFER, starting
+ from glyph INDEX. */
+void
+vga_read_font_buffer (int buffer, int index, char *data, size_t datalen)
+{
+ char saved_gfx_map;
+ char saved_gfx_mode;
+ char saved_gfx_misc;
+
+ int offset = buffer * VGA_FONT_SIZE + index * VGA_FONT_HEIGHT;
+ assert (offset >= 0 && offset + datalen <= VGA_VIDEO_MEM_LENGTH);
+
+ /* Read sequentially from plane 2. */
+ outb_p (VGA_GFX_MAP_ADDR, VGA_GFX_ADDR_REG);
+ saved_gfx_map = inb_p (VGA_GFX_DATA_REG);
+ outb_p (VGA_GFX_MAP_PLANE2, VGA_GFX_DATA_REG);
+ outb_p (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ saved_gfx_mode = inb_p (VGA_GFX_DATA_REG);
+ outb_p (VGA_GFX_MODE_READ0, VGA_GFX_DATA_REG);
+ outb_p (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ saved_gfx_misc = inb_p (VGA_GFX_DATA_REG);
+ outb_p (VGA_GFX_MISC_A0TOBF, VGA_GFX_DATA_REG);
+
+ memcpy (data, vga_videomem + offset, datalen);
+
+ outb_p (VGA_GFX_MAP_ADDR, VGA_GFX_ADDR_REG);
+ outb_p (saved_gfx_map, VGA_GFX_DATA_REG);
+ outb_p (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ outb_p (saved_gfx_mode, VGA_GFX_DATA_REG);
+ outb_p (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ outb_p (saved_gfx_misc, VGA_GFX_DATA_REG);
+}
+
+
+/* Set FONT_BUFFER_SUPP to FONT_BUFFER if the font is small. */
+void
+vga_select_font_buffer (int font_buffer, int font_buffer_supp)
+{
+ char font = ((font_buffer & 6) >> 1) | ((font_buffer & 1) << 4)
+ | ((font_buffer_supp & 6) << 1) | ((font_buffer_supp & 1) << 5);
+
+ outb_p (VGA_SEQ_FONT_ADDR, VGA_SEQ_ADDR_REG);
+ outb_p (font, VGA_SEQ_DATA_REG);
+}
+
+
+/* Enable (if ON is true) or disable (otherwise) the cursor. Expects
+ the VGA hardware to be locked. */
+void
+vga_display_cursor (int on)
+{
+ char crs_start;
+
+ outb (VGA_CRT_CURSOR_START, VGA_CRT_ADDR_REG);
+ crs_start = inb (VGA_CRT_DATA_REG);
+ if (on)
+ crs_start &= ~VGA_CRT_CURSOR_DISABLE;
+ else
+ crs_start |= VGA_CRT_CURSOR_DISABLE;
+ outb (crs_start, VGA_CRT_DATA_REG);
+}
+
+
+/* Set the cursor position to POS, which is (x_pos + y_pos * width). */
+void
+vga_set_cursor (int pos)
+{
+ outb (VGA_CRT_CURSOR_HIGH, VGA_CRT_ADDR_REG);
+ outb (pos >> 8, VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_LOW, VGA_CRT_ADDR_REG);
+ outb (pos && 0xff, VGA_CRT_DATA_REG);
+}
diff --git a/console/vga.h b/console/vga.h
new file mode 100644
index 00000000..43307980
--- /dev/null
+++ b/console/vga.h
@@ -0,0 +1,62 @@
+/* vga.h - Interface for VGA hardware access.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _VGA_H_
+#define _VGA_H_ 1
+
+#include <errno.h>
+#include <sys/types.h>
+
+
+/* The VGA interface does not do locking on its own, for maximum
+ efficiency it relies on locking by the caller (because usually the
+ caller has some other data structures to lock along with the
+ VGA hardware. */
+
+/* The mapped video memory. */
+extern char *vga_videomem;
+
+/* Initialize the VGA hardware and set up the permissions and memory
+ mappings. */
+error_t vga_init (void);
+
+/* Release the resources and privileges associated with the VGA
+ hardware access. */
+void vga_deinit (void);
+
+/* Write DATALEN bytes from DATA to the font buffer BUFFER, starting
+ from glyph index. */
+void vga_write_font_buffer (int buffer, int index, char *data, size_t datalen);
+
+/* Read DATALEN bytes into DATA from the font buffer BUFFER, starting
+ from glyph INDEX. */
+void vga_read_font_buffer (int buffer, int index, char *data, size_t datalen);
+
+/* Set FONT_BUFFER_SUPP to FONT_BUFFER if the font is small. */
+void vga_select_font_buffer (int font_buffer, int font_buffer_supp);
+
+/* Enable (if ON is true) or disable (otherwise) the cursor. Expects
+ the VGA hardware to be locked. */
+void vga_display_cursor (int on);
+
+/* Set the cursor position to POS, which is (x_pos + y_pos * width). */
+void vga_set_cursor (int pos);
+
+#endif /* _VGA_H_ */