diff options
Diffstat (limited to 'drivers/tty/vt')
-rw-r--r-- | drivers/tty/vt/.gitignore | 1 | ||||
-rw-r--r-- | drivers/tty/vt/Makefile | 6 | ||||
-rw-r--r-- | drivers/tty/vt/conmakehash.c | 290 | ||||
-rw-r--r-- | drivers/tty/vt/selection.c | 35 | ||||
-rw-r--r-- | drivers/tty/vt/vt.c | 25 | ||||
-rw-r--r-- | drivers/tty/vt/vt_ioctl.c | 17 |
6 files changed, 354 insertions, 20 deletions
diff --git a/drivers/tty/vt/.gitignore b/drivers/tty/vt/.gitignore index 9b38b85f9d9a..3ecf42234d89 100644 --- a/drivers/tty/vt/.gitignore +++ b/drivers/tty/vt/.gitignore @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 +conmakehash consolemap_deftbl.c defkeymap.c diff --git a/drivers/tty/vt/Makefile b/drivers/tty/vt/Makefile index edbbe0ccdb83..fe30ce512819 100644 --- a/drivers/tty/vt/Makefile +++ b/drivers/tty/vt/Makefile @@ -12,10 +12,12 @@ obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o # Files generated that shall be removed upon make clean clean-files := consolemap_deftbl.c defkeymap.c +hostprogs += conmakehash + quiet_cmd_conmk = CONMK $@ - cmd_conmk = scripts/conmakehash $< > $@ + cmd_conmk = $(obj)/conmakehash $< > $@ -$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE) +$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE) $(obj)/conmakehash $(call cmd,conmk) $(obj)/defkeymap.o: $(obj)/defkeymap.c diff --git a/drivers/tty/vt/conmakehash.c b/drivers/tty/vt/conmakehash.c new file mode 100644 index 000000000000..cddd789fe46e --- /dev/null +++ b/drivers/tty/vt/conmakehash.c @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * conmakehash.c + * + * Create arrays for initializing the kernel folded tables (using a hash + * table turned out to be to limiting...) Unfortunately we can't simply + * preinitialize the tables at compile time since kfree() cannot accept + * memory not allocated by kmalloc(), and doing our own memory management + * just for this seems like massive overkill. + * + * Copyright (C) 1995-1997 H. Peter Anvin + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sysexits.h> +#include <string.h> +#include <ctype.h> + +#define MAX_FONTLEN 256 + +typedef unsigned short unicode; + +static void usage(char *argv0) +{ + fprintf(stderr, "Usage: \n" + " %s chartable [hashsize] [hashstep] [maxhashlevel]\n", argv0); + exit(EX_USAGE); +} + +static int getunicode(char **p0) +{ + char *p = *p0; + + while (*p == ' ' || *p == '\t') + p++; + if (*p != 'U' || p[1] != '+' || + !isxdigit(p[2]) || !isxdigit(p[3]) || !isxdigit(p[4]) || + !isxdigit(p[5]) || isxdigit(p[6])) + return -1; + *p0 = p+6; + return strtol(p+2,0,16); +} + +unicode unitable[MAX_FONTLEN][255]; + /* Massive overkill, but who cares? */ +int unicount[MAX_FONTLEN]; + +static void addpair(int fp, int un) +{ + int i; + + if ( un <= 0xfffe ) + { + /* Check it isn't a duplicate */ + + for ( i = 0 ; i < unicount[fp] ; i++ ) + if ( unitable[fp][i] == un ) + return; + + /* Add to list */ + + if ( unicount[fp] > 254 ) + { + fprintf(stderr, "ERROR: Only 255 unicodes/glyph permitted!\n"); + exit(EX_DATAERR); + } + + unitable[fp][unicount[fp]] = un; + unicount[fp]++; + } + + /* otherwise: ignore */ +} + +int main(int argc, char *argv[]) +{ + FILE *ctbl; + char *tblname; + char buffer[65536]; + int fontlen; + int i, nuni, nent; + int fp0, fp1, un0, un1; + char *p, *p1; + + if ( argc < 2 || argc > 5 ) + usage(argv[0]); + + if ( !strcmp(argv[1],"-") ) + { + ctbl = stdin; + tblname = "stdin"; + } + else + { + ctbl = fopen(tblname = argv[1], "r"); + if ( !ctbl ) + { + perror(tblname); + exit(EX_NOINPUT); + } + } + + /* For now we assume the default font is always 256 characters. */ + fontlen = 256; + + /* Initialize table */ + + for ( i = 0 ; i < fontlen ; i++ ) + unicount[i] = 0; + + /* Now we come to the tricky part. Parse the input table. */ + + while ( fgets(buffer, sizeof(buffer), ctbl) != NULL ) + { + if ( (p = strchr(buffer, '\n')) != NULL ) + *p = '\0'; + else + fprintf(stderr, "%s: Warning: line too long\n", tblname); + + p = buffer; + +/* + * Syntax accepted: + * <fontpos> <unicode> <unicode> ... + * <range> idem + * <range> <unicode range> + * + * where <range> ::= <fontpos>-<fontpos> + * and <unicode> ::= U+<h><h><h><h> + * and <h> ::= <hexadecimal digit> + */ + + while (*p == ' ' || *p == '\t') + p++; + if (!*p || *p == '#') + continue; /* skip comment or blank line */ + + fp0 = strtol(p, &p1, 0); + if (p1 == p) + { + fprintf(stderr, "Bad input line: %s\n", buffer); + exit(EX_DATAERR); + } + p = p1; + + while (*p == ' ' || *p == '\t') + p++; + if (*p == '-') + { + p++; + fp1 = strtol(p, &p1, 0); + if (p1 == p) + { + fprintf(stderr, "Bad input line: %s\n", buffer); + exit(EX_DATAERR); + } + p = p1; + } + else + fp1 = 0; + + if ( fp0 < 0 || fp0 >= fontlen ) + { + fprintf(stderr, + "%s: Glyph number (0x%x) larger than font length\n", + tblname, fp0); + exit(EX_DATAERR); + } + if ( fp1 && (fp1 < fp0 || fp1 >= fontlen) ) + { + fprintf(stderr, + "%s: Bad end of range (0x%x)\n", + tblname, fp1); + exit(EX_DATAERR); + } + + if (fp1) + { + /* we have a range; expect the word "idem" or a Unicode range of the + same length */ + while (*p == ' ' || *p == '\t') + p++; + if (!strncmp(p, "idem", 4)) + { + for (i=fp0; i<=fp1; i++) + addpair(i,i); + p += 4; + } + else + { + un0 = getunicode(&p); + while (*p == ' ' || *p == '\t') + p++; + if (*p != '-') + { + fprintf(stderr, +"%s: Corresponding to a range of font positions, there should be a Unicode range\n", + tblname); + exit(EX_DATAERR); + } + p++; + un1 = getunicode(&p); + if (un0 < 0 || un1 < 0) + { + fprintf(stderr, +"%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n", + tblname, fp0, fp1); + exit(EX_DATAERR); + } + if (un1 - un0 != fp1 - fp0) + { + fprintf(stderr, +"%s: Unicode range U+%x-U+%x not of the same length as font position range 0x%x-0x%x\n", + tblname, un0, un1, fp0, fp1); + exit(EX_DATAERR); + } + for(i=fp0; i<=fp1; i++) + addpair(i,un0-fp0+i); + } + } + else + { + /* no range; expect a list of unicode values for a single font position */ + + while ( (un0 = getunicode(&p)) >= 0 ) + addpair(fp0, un0); + } + while (*p == ' ' || *p == '\t') + p++; + if (*p && *p != '#') + fprintf(stderr, "%s: trailing junk (%s) ignored\n", tblname, p); + } + + /* Okay, we hit EOF, now output hash table */ + + fclose(ctbl); + + + /* Compute total size of Unicode list */ + nuni = 0; + for ( i = 0 ; i < fontlen ; i++ ) + nuni += unicount[i]; + + printf("\ +/*\n\ + * Do not edit this file; it was automatically generated by\n\ + *\n\ + * conmakehash %s > [this file]\n\ + *\n\ + */\n\ +\n\ +#include <linux/types.h>\n\ +\n\ +u8 dfont_unicount[%d] = \n\ +{\n\t", argv[1], fontlen); + + for ( i = 0 ; i < fontlen ; i++ ) + { + printf("%3d", unicount[i]); + if ( i == fontlen-1 ) + printf("\n};\n"); + else if ( i % 8 == 7 ) + printf(",\n\t"); + else + printf(", "); + } + + printf("\nu16 dfont_unitable[%d] = \n{\n\t", nuni); + + fp0 = 0; + nent = 0; + for ( i = 0 ; i < nuni ; i++ ) + { + while ( nent >= unicount[fp0] ) + { + fp0++; + nent = 0; + } + printf("0x%04x", unitable[fp0][nent++]); + if ( i == nuni-1 ) + printf("\n};\n"); + else if ( i % 8 == 7 ) + printf(",\n\t"); + else + printf(", "); + } + + exit(EX_OK); +} diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 78732feaf65b..d7d2e4b844bc 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -16,6 +16,7 @@ #include <linux/tty.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/mutex.h> #include <linux/slab.h> #include <linux/types.h> @@ -29,6 +30,8 @@ #include <linux/console.h> #include <linux/tty_flip.h> +#include <linux/sched/signal.h> + /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ #define isspace(c) ((c) == ' ') @@ -43,6 +46,7 @@ static volatile int sel_start = -1; /* cleared by clear_selection */ static int sel_end; static int sel_buffer_lth; static char *sel_buffer; +static DEFINE_MUTEX(sel_lock); /* clear_selection, highlight and highlight_pointer can be called from interrupt (via scrollback/front) */ @@ -177,14 +181,14 @@ int set_selection_user(const struct tiocl_selection __user *sel, return set_selection_kernel(&v, tty); } -int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) +static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) { struct vc_data *vc = vc_cons[fg_console].d; int new_sel_start, new_sel_end, spc; char *bp, *obp; int i, ps, pe, multiplier; u32 c; - int mode; + int mode, ret = 0; poke_blanked_console(); @@ -332,7 +336,21 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) } } sel_buffer_lth = bp - sel_buffer; - return 0; + + return ret; +} + +int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) +{ + int ret; + + mutex_lock(&sel_lock); + console_lock(); + ret = __set_selection_kernel(v, tty); + console_unlock(); + mutex_unlock(&sel_lock); + + return ret; } EXPORT_SYMBOL_GPL(set_selection_kernel); @@ -350,6 +368,7 @@ int paste_selection(struct tty_struct *tty) unsigned int count; struct tty_ldisc *ld; DECLARE_WAITQUEUE(wait, current); + int ret = 0; console_lock(); poke_blanked_console(); @@ -361,10 +380,17 @@ int paste_selection(struct tty_struct *tty) tty_buffer_lock_exclusive(&vc->port); add_wait_queue(&vc->paste_wait, &wait); + mutex_lock(&sel_lock); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { + ret = -EINTR; + break; + } if (tty_throttled(tty)) { + mutex_unlock(&sel_lock); schedule(); + mutex_lock(&sel_lock); continue; } __set_current_state(TASK_RUNNING); @@ -373,11 +399,12 @@ int paste_selection(struct tty_struct *tty) count); pasted += count; } + mutex_unlock(&sel_lock); remove_wait_queue(&vc->paste_wait, &wait); __set_current_state(TASK_RUNNING); tty_buffer_unlock_exclusive(&vc->port); tty_ldisc_deref(ld); - return 0; + return ret; } EXPORT_SYMBOL_GPL(paste_selection); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 34aa39d1aed9..15d27698054a 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -936,10 +936,21 @@ static void flush_scrollback(struct vc_data *vc) WARN_CONSOLE_UNLOCKED(); set_origin(vc); - if (vc->vc_sw->con_flush_scrollback) + if (vc->vc_sw->con_flush_scrollback) { vc->vc_sw->con_flush_scrollback(vc); - else + } else if (con_is_visible(vc)) { + /* + * When no con_flush_scrollback method is provided then the + * legacy way for flushing the scrollback buffer is to use + * a side effect of the con_switch method. We do it only on + * the foreground console as background consoles have no + * scrollback buffers in that case and we obviously don't + * want to switch to them. + */ + hide_cursor(vc); vc->vc_sw->con_switch(vc); + set_cursor(vc); + } } /* @@ -3035,10 +3046,8 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) switch (type) { case TIOCL_SETSEL: - console_lock(); ret = set_selection_user((struct tiocl_selection __user *)(p+1), tty); - console_unlock(); break; case TIOCL_PASTESEL: ret = paste_selection(tty); @@ -3326,8 +3335,9 @@ static int __init con_init(void) console_lock(); - if (conswitchp) - display_desc = conswitchp->con_startup(); + if (!conswitchp) + conswitchp = &dummy_con; + display_desc = conswitchp->con_startup(); if (!display_desc) { fg_console = 0; console_unlock(); @@ -3567,7 +3577,6 @@ err: #ifdef CONFIG_VT_HW_CONSOLE_BINDING -/* unlocked version of unbind_con_driver() */ int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt) { struct module *owner = csw->owner; @@ -4095,7 +4104,7 @@ static void con_driver_unregister_callback(struct work_struct *ignored) * when a driver wants to take over some existing consoles * and become default driver for newly opened ones. * - * do_take_over_console is basically a register followed by unbind + * do_take_over_console is basically a register followed by bind */ int do_take_over_console(const struct consw *csw, int first, int last, int deflt) { diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 8b0ed139592f..ee6c91ef1f6c 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -876,15 +876,20 @@ int vt_ioctl(struct tty_struct *tty, return -EINVAL; for (i = 0; i < MAX_NR_CONSOLES; i++) { + struct vc_data *vcp; + if (!vc_cons[i].d) continue; console_lock(); - if (v.v_vlin) - vc_cons[i].d->vc_scan_lines = v.v_vlin; - if (v.v_clin) - vc_cons[i].d->vc_font.height = v.v_clin; - vc_cons[i].d->vc_resize_user = 1; - vc_resize(vc_cons[i].d, v.v_cols, v.v_rows); + vcp = vc_cons[i].d; + if (vcp) { + if (v.v_vlin) + vcp->vc_scan_lines = v.v_vlin; + if (v.v_clin) + vcp->vc_font.height = v.v_clin; + vcp->vc_resize_user = 1; + vc_resize(vcp, v.v_cols, v.v_rows); + } console_unlock(); } break; |