diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-08 11:31:40 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-08 11:31:40 -0700 |
commit | 607ca0f742b7d990b6efb3c3e7a52830f7e96419 (patch) | |
tree | f2e18a88abae18a83488486210b609104c6863ed /drivers/tty/vt | |
parent | 1daf117f1d6b5056e27353fa289ef1bbcb619e8d (diff) | |
parent | 0fec518018cc5ceffa706370b6e3acbbb1e3c798 (diff) | |
download | linux-607ca0f742b7d990b6efb3c3e7a52830f7e96419.tar.bz2 |
Merge tag 'tty-6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty / serial driver updates from Greg KH:
"Here is the big set of tty and serial driver changes for 6.0-rc1.
It was delayed from last week as I wanted to make sure the last commit
here got some good testing in linux-next and elsewhere as it seemed to
show up only late in testing for some reason.
Nothing major here, just lots of cleanups from Jiri and Ilpo to make
the tty core cleaner (Jiri) and the rs485 code simpler to use (Ilpo).
Also included in here is the obligatory n_gsm updates from Daniel
Starke and lots of tiny driver updates and minor fixes and tweaks for
other smaller serial drivers.
All of these have been in linux-next for a while with no reported
problems"
* tag 'tty-6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (186 commits)
tty: serial: qcom-geni-serial: Fix %lu -> %u in print statements
tty: amiserial: Fix comment typo
tty: serial: document uart_get_console()
tty: serial: serial_core, reformat kernel-doc for functions
Documentation: serial: link uart_ops properly
Documentation: serial: move GPIO kernel-doc to the functions
Documentation: serial: dedup kernel-doc for uart functions
Documentation: serial: move uart_ops documentation to the struct
dt-bindings: serial: snps-dw-apb-uart: Document Rockchip RV1126
serial: mvebu-uart: uart2 error bits clearing
tty: serial: fsl_lpuart: correct the count of break characters
serial: stm32: make info structs static to avoid sparse warnings
serial: fsl_lpuart: zero out parity bit in CS7 mode
tty: serial: qcom-geni-serial: Fix get_clk_div_rate() which otherwise could return a sub-optimal clock rate.
serial: 8250_bcm2835aux: Add missing clk_disable_unprepare()
tty: vt: initialize unicode screen buffer
serial: remove VR41XX serial driver
serial: 8250: lpc18xx: Remove redundant sanity check for RS485 flags
serial: 8250_dwlib: remove redundant sanity check for RS485 flags
dt_bindings: rs485: Correct delay values
...
Diffstat (limited to 'drivers/tty/vt')
-rw-r--r-- | drivers/tty/vt/Makefile | 2 | ||||
-rw-r--r-- | drivers/tty/vt/consolemap.c | 684 | ||||
-rw-r--r-- | drivers/tty/vt/defkeymap.c_shipped | 6 | ||||
-rw-r--r-- | drivers/tty/vt/selection.c | 3 | ||||
-rw-r--r-- | drivers/tty/vt/vt.c | 16 |
5 files changed, 386 insertions, 325 deletions
diff --git a/drivers/tty/vt/Makefile b/drivers/tty/vt/Makefile index fe30ce512819..b3dfe9d5717e 100644 --- a/drivers/tty/vt/Makefile +++ b/drivers/tty/vt/Makefile @@ -30,6 +30,6 @@ $(obj)/defkeymap.o: $(obj)/defkeymap.c ifdef GENERATE_KEYMAP $(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map - loadkeys --mktable $< > $@ + loadkeys --mktable --unicode $< > $@ endif diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index d815ac98b39e..f02d21e2a96e 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -23,6 +23,8 @@ * stack overflow. */ +#include <linux/bitfield.h> +#include <linux/bits.h> #include <linux/module.h> #include <linux/kd.h> #include <linux/errno.h> @@ -36,9 +38,9 @@ #include <linux/vt_kern.h> #include <linux/string.h> -static unsigned short translations[][256] = { +static unsigned short translations[][E_TABSZ] = { /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */ - { + [LAT1_MAP] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, @@ -71,9 +73,9 @@ static unsigned short translations[][256] = { 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff - }, + }, /* VT100 graphics mapped to Unicode */ - { + [GRAF_MAP] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, @@ -108,8 +110,8 @@ static unsigned short translations[][256] = { 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff }, /* IBM Codepage 437 mapped to Unicode */ - { - 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, + [IBMPC_MAP] = { + 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c, 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc, @@ -141,9 +143,9 @@ static unsigned short translations[][256] = { 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 - }, + }, /* User mapping -- default to codes for direct font mapping */ - { + [USER_MAP] = { 0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007, 0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f, 0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017, @@ -184,78 +186,105 @@ static unsigned short translations[][256] = { #define MAX_GLYPH 512 /* Max possible glyph value */ -static int inv_translate[MAX_NR_CONSOLES]; +static enum translation_map inv_translate[MAX_NR_CONSOLES]; + +#define UNI_DIRS 32U +#define UNI_DIR_ROWS 32U +#define UNI_ROW_GLYPHS 64U + +#define UNI_DIR_BITS GENMASK(15, 11) +#define UNI_ROW_BITS GENMASK(10, 6) +#define UNI_GLYPH_BITS GENMASK( 5, 0) -struct uni_pagedir { - u16 **uni_pgdir[32]; +#define UNI_DIR(uni) FIELD_GET(UNI_DIR_BITS, (uni)) +#define UNI_ROW(uni) FIELD_GET(UNI_ROW_BITS, (uni)) +#define UNI_GLYPH(uni) FIELD_GET(UNI_GLYPH_BITS, (uni)) + +#define UNI(dir, row, glyph) (FIELD_PREP(UNI_DIR_BITS, (dir)) | \ + FIELD_PREP(UNI_ROW_BITS, (row)) | \ + FIELD_PREP(UNI_GLYPH_BITS, (glyph))) + +/** + * struct uni_pagedict -- unicode directory + * + * @uni_pgdir: 32*32*64 table with glyphs + * @refcount: reference count of this structure + * @sum: checksum + * @inverse_translations: best-effort inverse mapping + * @inverse_trans_unicode: best-effort inverse mapping to unicode + */ +struct uni_pagedict { + u16 **uni_pgdir[UNI_DIRS]; unsigned long refcount; unsigned long sum; - unsigned char *inverse_translations[4]; + unsigned char *inverse_translations[LAST_MAP + 1]; u16 *inverse_trans_unicode; }; -static struct uni_pagedir *dflt; +static struct uni_pagedict *dflt; -static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i) +static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *dict, + enum translation_map m) { - int j, glyph; - unsigned short *t = translations[i]; - unsigned char *q; - - if (!p) return; - q = p->inverse_translations[i]; - - if (!q) { - q = p->inverse_translations[i] = kmalloc(MAX_GLYPH, GFP_KERNEL); - if (!q) return; + unsigned short *t = translations[m]; + unsigned char *inv; + + if (!dict) + return; + inv = dict->inverse_translations[m]; + + if (!inv) { + inv = dict->inverse_translations[m] = kmalloc(MAX_GLYPH, + GFP_KERNEL); + if (!inv) + return; } - memset(q, 0, MAX_GLYPH); + memset(inv, 0, MAX_GLYPH); - for (j = 0; j < E_TABSZ; j++) { - glyph = conv_uni_to_pc(conp, t[j]); - if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) { + for (unsigned int ch = 0; ch < ARRAY_SIZE(translations[m]); ch++) { + int glyph = conv_uni_to_pc(conp, t[ch]); + if (glyph >= 0 && glyph < MAX_GLYPH && inv[glyph] < 32) { /* prefer '-' above SHY etc. */ - q[glyph] = j; + inv[glyph] = ch; } } } -static void set_inverse_trans_unicode(struct vc_data *conp, - struct uni_pagedir *p) +static void set_inverse_trans_unicode(struct uni_pagedict *dict) { - int i, j, k, glyph; - u16 **p1, *p2; - u16 *q; - - if (!p) return; - q = p->inverse_trans_unicode; - if (!q) { - q = p->inverse_trans_unicode = - kmalloc_array(MAX_GLYPH, sizeof(u16), GFP_KERNEL); - if (!q) + unsigned int d, r, g; + u16 *inv; + + if (!dict) + return; + + inv = dict->inverse_trans_unicode; + if (!inv) { + inv = dict->inverse_trans_unicode = kmalloc_array(MAX_GLYPH, + sizeof(*inv), GFP_KERNEL); + if (!inv) return; } - memset(q, 0, MAX_GLYPH * sizeof(u16)); + memset(inv, 0, MAX_GLYPH * sizeof(*inv)); - for (i = 0; i < 32; i++) { - p1 = p->uni_pgdir[i]; - if (!p1) + for (d = 0; d < UNI_DIRS; d++) { + u16 **dir = dict->uni_pgdir[d]; + if (!dir) continue; - for (j = 0; j < 32; j++) { - p2 = p1[j]; - if (!p2) + for (r = 0; r < UNI_DIR_ROWS; r++) { + u16 *row = dir[r]; + if (!row) continue; - for (k = 0; k < 64; k++) { - glyph = p2[k]; - if (glyph >= 0 && glyph < MAX_GLYPH - && q[glyph] < 32) - q[glyph] = (i << 11) + (j << 6) + k; + for (g = 0; g < UNI_ROW_GLYPHS; g++) { + u16 glyph = row[g]; + if (glyph < MAX_GLYPH && inv[glyph] < 32) + inv[glyph] = UNI(d, r, g); } } } } -unsigned short *set_translate(int m, struct vc_data *vc) +unsigned short *set_translate(enum translation_map m, struct vc_data *vc) { inv_translate[vc->vc_num] = m; return translations[m]; @@ -268,44 +297,45 @@ unsigned short *set_translate(int m, struct vc_data *vc) * was active. * Still, it is now possible to a certain extent to cut and paste non-ASCII. */ -u16 inverse_translate(const struct vc_data *conp, int glyph, int use_unicode) +u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode) { - struct uni_pagedir *p; - int m; - if (glyph < 0 || glyph >= MAX_GLYPH) + struct uni_pagedict *p; + enum translation_map m; + + if (glyph >= MAX_GLYPH) return 0; - else { - p = *conp->vc_uni_pagedir_loc; - if (!p) + + p = *conp->uni_pagedict_loc; + if (!p) + return glyph; + + if (use_unicode) { + if (!p->inverse_trans_unicode) return glyph; - else if (use_unicode) { - if (!p->inverse_trans_unicode) - return glyph; - else - return p->inverse_trans_unicode[glyph]; - } else { - m = inv_translate[conp->vc_num]; - if (!p->inverse_translations[m]) - return glyph; - else - return p->inverse_translations[m][glyph]; - } + + return p->inverse_trans_unicode[glyph]; } + + m = inv_translate[conp->vc_num]; + if (!p->inverse_translations[m]) + return glyph; + + return p->inverse_translations[m][glyph]; } EXPORT_SYMBOL_GPL(inverse_translate); static void update_user_maps(void) { int i; - struct uni_pagedir *p, *q = NULL; - + struct uni_pagedict *p, *q = NULL; + for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons_allocated(i)) continue; - p = *vc_cons[i].d->vc_uni_pagedir_loc; + p = *vc_cons[i].d->uni_pagedict_loc; if (p && p != q) { set_inverse_transl(vc_cons[i].d, p, USER_MAP); - set_inverse_trans_unicode(vc_cons[i].d, p); + set_inverse_trans_unicode(p); q = p; } } @@ -321,15 +351,15 @@ static void update_user_maps(void) */ int con_set_trans_old(unsigned char __user * arg) { - int i; unsigned short inbuf[E_TABSZ]; - unsigned char ubuf[E_TABSZ]; - - if (copy_from_user(ubuf, arg, E_TABSZ)) - return -EFAULT; + unsigned int i; + unsigned char ch; - for (i = 0; i < E_TABSZ ; i++) - inbuf[i] = UNI_DIRECT_BASE | ubuf[i]; + for (i = 0; i < ARRAY_SIZE(inbuf); i++) { + if (get_user(ch, &arg[i])) + return -EFAULT; + inbuf[i] = UNI_DIRECT_BASE | ch; + } console_lock(); memcpy(translations[USER_MAP], inbuf, sizeof(inbuf)); @@ -345,7 +375,7 @@ int con_get_trans_old(unsigned char __user * arg) unsigned char outbuf[E_TABSZ]; console_lock(); - for (i = 0; i < E_TABSZ ; i++) + for (i = 0; i < ARRAY_SIZE(outbuf); i++) { ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]); outbuf[i] = (ch & ~0xff) ? 0 : ch; @@ -381,7 +411,7 @@ int con_get_trans_new(ushort __user * arg) } /* - * Unicode -> current font conversion + * Unicode -> current font conversion * * A font has at most 512 chars, usually 256. * But one font position may represent several Unicode chars. @@ -393,78 +423,82 @@ int con_get_trans_new(ushort __user * arg) extern u8 dfont_unicount[]; /* Defined in console_defmap.c */ extern u16 dfont_unitable[]; -static void con_release_unimap(struct uni_pagedir *p) +static void con_release_unimap(struct uni_pagedict *dict) { - u16 **p1; - int i, j; - - if (p == dflt) dflt = NULL; - for (i = 0; i < 32; i++) { - p1 = p->uni_pgdir[i]; - if (p1 != NULL) { - for (j = 0; j < 32; j++) - kfree(p1[j]); - kfree(p1); + unsigned int d, r; + + if (dict == dflt) + dflt = NULL; + + for (d = 0; d < UNI_DIRS; d++) { + u16 **dir = dict->uni_pgdir[d]; + if (dir != NULL) { + for (r = 0; r < UNI_DIR_ROWS; r++) + kfree(dir[r]); + kfree(dir); } - p->uni_pgdir[i] = NULL; + dict->uni_pgdir[d] = NULL; } - for (i = 0; i < 4; i++) { - kfree(p->inverse_translations[i]); - p->inverse_translations[i] = NULL; + + for (r = 0; r < ARRAY_SIZE(dict->inverse_translations); r++) { + kfree(dict->inverse_translations[r]); + dict->inverse_translations[r] = NULL; } - kfree(p->inverse_trans_unicode); - p->inverse_trans_unicode = NULL; + + kfree(dict->inverse_trans_unicode); + dict->inverse_trans_unicode = NULL; } /* Caller must hold the console lock */ void con_free_unimap(struct vc_data *vc) { - struct uni_pagedir *p; + struct uni_pagedict *p; - p = *vc->vc_uni_pagedir_loc; + p = *vc->uni_pagedict_loc; if (!p) return; - *vc->vc_uni_pagedir_loc = NULL; + *vc->uni_pagedict_loc = NULL; if (--p->refcount) return; con_release_unimap(p); kfree(p); } - -static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p) + +static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *dict1) { - int i, j, k; - struct uni_pagedir *q; - - for (i = 0; i < MAX_NR_CONSOLES; i++) { - if (!vc_cons_allocated(i)) + struct uni_pagedict *dict2; + unsigned int cons, d, r; + + for (cons = 0; cons < MAX_NR_CONSOLES; cons++) { + if (!vc_cons_allocated(cons)) continue; - q = *vc_cons[i].d->vc_uni_pagedir_loc; - if (!q || q == p || q->sum != p->sum) + dict2 = *vc_cons[cons].d->uni_pagedict_loc; + if (!dict2 || dict2 == dict1 || dict2->sum != dict1->sum) continue; - for (j = 0; j < 32; j++) { - u16 **p1, **q1; - p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j]; - if (!p1 && !q1) + for (d = 0; d < UNI_DIRS; d++) { + u16 **dir1 = dict1->uni_pgdir[d]; + u16 **dir2 = dict2->uni_pgdir[d]; + if (!dir1 && !dir2) continue; - if (!p1 || !q1) + if (!dir1 || !dir2) break; - for (k = 0; k < 32; k++) { - if (!p1[k] && !q1[k]) + for (r = 0; r < UNI_DIR_ROWS; r++) { + if (!dir1[r] && !dir2[r]) continue; - if (!p1[k] || !q1[k]) + if (!dir1[r] || !dir2[r]) break; - if (memcmp(p1[k], q1[k], 64*sizeof(u16))) + if (memcmp(dir1[r], dir2[r], UNI_ROW_GLYPHS * + sizeof(*dir1[r]))) break; } - if (k < 32) + if (r < UNI_DIR_ROWS) break; } - if (j == 32) { - q->refcount++; - *conp->vc_uni_pagedir_loc = q; - con_release_unimap(p); - kfree(p); + if (d == UNI_DIRS) { + dict2->refcount++; + *conp->uni_pagedict_loc = dict2; + con_release_unimap(dict1); + kfree(dict1); return 1; } } @@ -472,55 +506,66 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p) } static int -con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) +con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) { - int i, n; - u16 **p1, *p2; - - p1 = p->uni_pgdir[n = unicode >> 11]; - if (!p1) { - p1 = p->uni_pgdir[n] = kmalloc_array(32, sizeof(u16 *), - GFP_KERNEL); - if (!p1) return -ENOMEM; - for (i = 0; i < 32; i++) - p1[i] = NULL; + u16 **dir, *row; + unsigned int n; + + n = UNI_DIR(unicode); + dir = p->uni_pgdir[n]; + if (!dir) { + dir = p->uni_pgdir[n] = kcalloc(UNI_DIR_ROWS, sizeof(*dir), + GFP_KERNEL); + if (!dir) + return -ENOMEM; } - p2 = p1[n = (unicode >> 6) & 0x1f]; - if (!p2) { - p2 = p1[n] = kmalloc_array(64, sizeof(u16), GFP_KERNEL); - if (!p2) return -ENOMEM; - memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */ + n = UNI_ROW(unicode); + row = dir[n]; + if (!row) { + row = dir[n] = kmalloc_array(UNI_ROW_GLYPHS, sizeof(*row), + GFP_KERNEL); + if (!row) + return -ENOMEM; + /* No glyphs for the characters (yet) */ + memset(row, 0xff, UNI_ROW_GLYPHS * sizeof(*row)); } - p2[unicode & 0x3f] = fontpos; - + row[UNI_GLYPH(unicode)] = fontpos; + p->sum += (fontpos << 20U) + unicode; return 0; } +static int con_allocate_new(struct vc_data *vc) +{ + struct uni_pagedict *new, *old = *vc->uni_pagedict_loc; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) + return -ENOMEM; + + new->refcount = 1; + *vc->uni_pagedict_loc = new; + + if (old) + old->refcount--; + + return 0; +} + /* Caller must hold the lock */ static int con_do_clear_unimap(struct vc_data *vc) { - struct uni_pagedir *p, *q; - - p = *vc->vc_uni_pagedir_loc; - if (!p || --p->refcount) { - q = kzalloc(sizeof(*p), GFP_KERNEL); - if (!q) { - if (p) - p->refcount++; - return -ENOMEM; - } - q->refcount=1; - *vc->vc_uni_pagedir_loc = q; - } else { - if (p == dflt) dflt = NULL; - p->refcount++; - p->sum = 0; - con_release_unimap(p); - } + struct uni_pagedict *old = *vc->uni_pagedict_loc; + + if (!old || old->refcount > 1) + return con_allocate_new(vc); + + old->sum = 0; + con_release_unimap(old); + return 0; } @@ -532,91 +577,93 @@ int con_clear_unimap(struct vc_data *vc) console_unlock(); return ret; } - + +static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc, + struct uni_pagedict *old) +{ + struct uni_pagedict *new; + unsigned int d, r, g; + int ret; + u16 uni = 0; + + ret = con_allocate_new(vc); + if (ret) + return ERR_PTR(ret); + + new = *vc->uni_pagedict_loc; + + /* + * uni_pgdir is a 32*32*64 table with rows allocated when its first + * entry is added. The unicode value must still be incremented for + * empty rows. We are copying entries from "old" to "new". + */ + for (d = 0; d < UNI_DIRS; d++) { + u16 **dir = old->uni_pgdir[d]; + if (!dir) { + /* Account for empty table */ + uni += UNI_DIR_ROWS * UNI_ROW_GLYPHS; + continue; + } + + for (r = 0; r < UNI_DIR_ROWS; r++) { + u16 *row = dir[r]; + if (!row) { + /* Account for row of 64 empty entries */ + uni += UNI_ROW_GLYPHS; + continue; + } + + for (g = 0; g < UNI_ROW_GLYPHS; g++, uni++) { + if (row[g] == 0xffff) + continue; + /* + * Found one, copy entry for unicode uni with + * fontpos value row[g]. + */ + ret = con_insert_unipair(new, uni, row[g]); + if (ret) { + old->refcount++; + *vc->uni_pagedict_loc = old; + con_release_unimap(new); + kfree(new); + return ERR_PTR(ret); + } + } + } + } + + return new; +} + int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) { - int err = 0, err1, i; - struct uni_pagedir *p, *q; + int err = 0, err1; + struct uni_pagedict *dict; struct unipair *unilist, *plist; if (!ct) return 0; - unilist = vmemdup_user(list, array_size(sizeof(struct unipair), ct)); + unilist = vmemdup_user(list, array_size(sizeof(*unilist), ct)); if (IS_ERR(unilist)) return PTR_ERR(unilist); console_lock(); /* Save original vc_unipagdir_loc in case we allocate a new one */ - p = *vc->vc_uni_pagedir_loc; - - if (!p) { + dict = *vc->uni_pagedict_loc; + if (!dict) { err = -EINVAL; - goto out_unlock; } - - if (p->refcount > 1) { - int j, k; - u16 **p1, *p2, l; - - err1 = con_do_clear_unimap(vc); - if (err1) { - err = err1; + + if (dict->refcount > 1) { + dict = con_unshare_unimap(vc, dict); + if (IS_ERR(dict)) { + err = PTR_ERR(dict); goto out_unlock; } - - /* - * Since refcount was > 1, con_clear_unimap() allocated a - * a new uni_pagedir for this vc. Re: p != q - */ - q = *vc->vc_uni_pagedir_loc; - - /* - * uni_pgdir is a 32*32*64 table with rows allocated - * when its first entry is added. The unicode value must - * still be incremented for empty rows. We are copying - * entries from "p" (old) to "q" (new). - */ - l = 0; /* unicode value */ - for (i = 0; i < 32; i++) { - p1 = p->uni_pgdir[i]; - if (p1) - for (j = 0; j < 32; j++) { - p2 = p1[j]; - if (p2) { - for (k = 0; k < 64; k++, l++) - if (p2[k] != 0xffff) { - /* - * Found one, copy entry for unicode - * l with fontpos value p2[k]. - */ - err1 = con_insert_unipair(q, l, p2[k]); - if (err1) { - p->refcount++; - *vc->vc_uni_pagedir_loc = p; - con_release_unimap(q); - kfree(q); - err = err1; - goto out_unlock; - } - } - } else { - /* Account for row of 64 empty entries */ - l += 64; - } - } - else - /* Account for empty table */ - l += 32 * 64; - } - - /* - * Finished copying font table, set vc_uni_pagedir to new table - */ - p = q; - } else if (p == dflt) { + } else if (dict == dflt) { dflt = NULL; } @@ -624,20 +671,20 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) * Insert user specified unicode pairs into new table. */ for (plist = unilist; ct; ct--, plist++) { - err1 = con_insert_unipair(p, plist->unicode, plist->fontpos); + err1 = con_insert_unipair(dict, plist->unicode, plist->fontpos); if (err1) err = err1; } - + /* * Merge with fontmaps of any other virtual consoles. */ - if (con_unify_unimap(vc, p)) + if (con_unify_unimap(vc, dict)) goto out_unlock; - for (i = 0; i <= 3; i++) - set_inverse_transl(vc, p, i); /* Update inverse translations */ - set_inverse_trans_unicode(vc, p); + for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++) + set_inverse_transl(vc, dict, m); + set_inverse_trans_unicode(dict); out_unlock: console_unlock(); @@ -652,55 +699,56 @@ out_unlock: * Loads the unimap for the hardware font, as defined in uni_hash.tbl. * The representation used was the most compact I could come up * with. This routine is executed at video setup, and when the - * PIO_FONTRESET ioctl is called. + * PIO_FONTRESET ioctl is called. * * The caller must hold the console lock */ int con_set_default_unimap(struct vc_data *vc) { - int i, j, err = 0, err1; - u16 *q; - struct uni_pagedir *p; + struct uni_pagedict *dict; + unsigned int fontpos, count; + int err = 0, err1; + u16 *dfont; if (dflt) { - p = *vc->vc_uni_pagedir_loc; - if (p == dflt) + dict = *vc->uni_pagedict_loc; + if (dict == dflt) return 0; dflt->refcount++; - *vc->vc_uni_pagedir_loc = dflt; - if (p && !--p->refcount) { - con_release_unimap(p); - kfree(p); + *vc->uni_pagedict_loc = dflt; + if (dict && !--dict->refcount) { + con_release_unimap(dict); + kfree(dict); } return 0; } - + /* The default font is always 256 characters */ err = con_do_clear_unimap(vc); if (err) return err; - - p = *vc->vc_uni_pagedir_loc; - q = dfont_unitable; - - for (i = 0; i < 256; i++) - for (j = dfont_unicount[i]; j; j--) { - err1 = con_insert_unipair(p, *(q++), i); + + dict = *vc->uni_pagedict_loc; + dfont = dfont_unitable; + + for (fontpos = 0; fontpos < 256U; fontpos++) + for (count = dfont_unicount[fontpos]; count; count--) { + err1 = con_insert_unipair(dict, *(dfont++), fontpos); if (err1) err = err1; } - - if (con_unify_unimap(vc, p)) { - dflt = *vc->vc_uni_pagedir_loc; + + if (con_unify_unimap(vc, dict)) { + dflt = *vc->uni_pagedict_loc; return err; } - for (i = 0; i <= 3; i++) - set_inverse_transl(vc, p, i); /* Update all inverse translations */ - set_inverse_trans_unicode(vc, p); - dflt = p; + for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++) + set_inverse_transl(vc, dict, m); + set_inverse_trans_unicode(dict); + dflt = dict; return err; } EXPORT_SYMBOL(con_set_default_unimap); @@ -714,16 +762,16 @@ EXPORT_SYMBOL(con_set_default_unimap); */ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) { - struct uni_pagedir *q; + struct uni_pagedict *src; - if (!*src_vc->vc_uni_pagedir_loc) + if (!*src_vc->uni_pagedict_loc) return -EINVAL; - if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc) + if (*dst_vc->uni_pagedict_loc == *src_vc->uni_pagedict_loc) return 0; con_free_unimap(dst_vc); - q = *src_vc->vc_uni_pagedir_loc; - q->refcount++; - *dst_vc->vc_uni_pagedir_loc = q; + src = *src_vc->uni_pagedict_loc; + src->refcount++; + *dst_vc->uni_pagedict_loc = src; return 0; } EXPORT_SYMBOL(con_copy_unimap); @@ -734,46 +782,53 @@ EXPORT_SYMBOL(con_copy_unimap); * Read the console unicode data for this console. Called from the ioctl * handlers. */ -int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list) +int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, + struct unipair __user *list) { - int i, j, k, ret = 0; ushort ect; - u16 **p1, *p2; - struct uni_pagedir *p; + struct uni_pagedict *dict; struct unipair *unilist; + unsigned int d, r, g; + int ret = 0; - unilist = kvmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL); + unilist = kvmalloc_array(ct, sizeof(*unilist), GFP_KERNEL); if (!unilist) return -ENOMEM; console_lock(); ect = 0; - if (*vc->vc_uni_pagedir_loc) { - p = *vc->vc_uni_pagedir_loc; - for (i = 0; i < 32; i++) { - p1 = p->uni_pgdir[i]; - if (p1) - for (j = 0; j < 32; j++) { - p2 = *(p1++); - if (p2) - for (k = 0; k < 64; k++, p2++) { - if (*p2 >= MAX_GLYPH) - continue; - if (ect < ct) { - unilist[ect].unicode = - (i<<11)+(j<<6)+k; - unilist[ect].fontpos = *p2; - } - ect++; + dict = *vc->uni_pagedict_loc; + if (!dict) + goto unlock; + + for (d = 0; d < UNI_DIRS; d++) { + u16 **dir = dict->uni_pgdir[d]; + if (!dir) + continue; + + for (r = 0; r < UNI_DIR_ROWS; r++) { + u16 *row = dir[r]; + if (!row) + continue; + + for (g = 0; g < UNI_ROW_GLYPHS; g++, row++) { + if (*row >= MAX_GLYPH) + continue; + if (ect < ct) { + unilist[ect].unicode = UNI(d, r, g); + unilist[ect].fontpos = *row; } + ect++; } } } +unlock: console_unlock(); - if (copy_to_user(list, unilist, min(ect, ct) * sizeof(struct unipair))) + if (copy_to_user(list, unilist, min(ect, ct) * sizeof(*unilist))) + ret = -EFAULT; + if (put_user(ect, uct)) ret = -EFAULT; - put_user(ect, uct); kvfree(unilist); return ret ? ret : (ect <= ct) ? 0 : -ENOMEM; } @@ -798,20 +853,18 @@ u32 conv_8bit_to_uni(unsigned char c) int conv_uni_to_8bit(u32 uni) { int c; - for (c = 0; c < 0x100; c++) + for (c = 0; c < ARRAY_SIZE(translations[USER_MAP]); c++) if (translations[USER_MAP][c] == uni || (translations[USER_MAP][c] == (c | 0xf000) && uni == c)) return c; return -1; } -int -conv_uni_to_pc(struct vc_data *conp, long ucs) +int conv_uni_to_pc(struct vc_data *conp, long ucs) { - int h; - u16 **p1, *p2; - struct uni_pagedir *p; - + struct uni_pagedict *dict; + u16 **dir, *row, glyph; + /* Only 16-bit codes supported at this time */ if (ucs > 0xffff) return -4; /* Not found */ @@ -826,17 +879,24 @@ conv_uni_to_pc(struct vc_data *conp, long ucs) */ else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE) return ucs & UNI_DIRECT_MASK; - - if (!*conp->vc_uni_pagedir_loc) + + dict = *conp->uni_pagedict_loc; + if (!dict) return -3; - p = *conp->vc_uni_pagedir_loc; - if ((p1 = p->uni_pgdir[ucs >> 11]) && - (p2 = p1[(ucs >> 6) & 0x1f]) && - (h = p2[ucs & 0x3f]) < MAX_GLYPH) - return h; + dir = dict->uni_pgdir[UNI_DIR(ucs)]; + if (!dir) + return -4; - return -4; /* not found */ + row = dir[UNI_ROW(ucs)]; + if (!row) + return -4; + + glyph = row[UNI_GLYPH(ucs)]; + if (glyph >= MAX_GLYPH) + return -4; + + return glyph; } /* @@ -844,13 +904,13 @@ conv_uni_to_pc(struct vc_data *conp, long ucs) * initialized. It must be possible to call kmalloc(..., GFP_KERNEL) * from this function, hence the call from sys_setup. */ -void __init +void __init console_map_init(void) { int i; - + for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc) + if (vc_cons_allocated(i) && !*vc_cons[i].d->uni_pagedict_loc) con_set_default_unimap(vc_cons[i].d); } diff --git a/drivers/tty/vt/defkeymap.c_shipped b/drivers/tty/vt/defkeymap.c_shipped index 094d95bf0005..0c043e4f292e 100644 --- a/drivers/tty/vt/defkeymap.c_shipped +++ b/drivers/tty/vt/defkeymap.c_shipped @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -/* Do not edit this file! It was automatically generated by */ -/* loadkeys --mktable defkeymap.map > defkeymap.c */ +/* Do not edit this file! It was automatically generated by */ +/* loadkeys --mktable --unicode defkeymap.map > defkeymap.c */ #include <linux/types.h> #include <linux/keyboard.h> @@ -139,7 +139,7 @@ static unsigned short ctrl_alt_map[NR_KEYS] = { 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, }; -ushort *key_maps[MAX_NR_KEYMAPS] = { +unsigned short *key_maps[MAX_NR_KEYMAPS] = { plain_map, shift_map, altgr_map, NULL, ctrl_map, shift_ctrl_map, NULL, NULL, alt_map, NULL, NULL, NULL, diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index f7755e73696e..6ef22f01cc51 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -68,7 +68,8 @@ sel_pos(int n, bool unicode) { if (unicode) return screen_glyph_unicode(vc_sel.cons, n / 2); - return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n), 0); + return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n), + false); } /** diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index dfc1f4b445f3..ae9c926acd6f 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -344,7 +344,7 @@ static struct uni_screen *vc_uniscr_alloc(unsigned int cols, unsigned int rows) /* allocate everything in one go */ memsize = cols * rows * sizeof(char32_t); memsize += rows * sizeof(char32_t *); - p = vmalloc(memsize); + p = vzalloc(memsize); if (!p) return NULL; @@ -1063,10 +1063,10 @@ static void visual_init(struct vc_data *vc, int num, int init) __module_get(vc->vc_sw->owner); vc->vc_num = num; vc->vc_display_fg = &master_display_fg; - if (vc->vc_uni_pagedir_loc) + if (vc->uni_pagedict_loc) con_free_unimap(vc); - vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir; - vc->vc_uni_pagedir = NULL; + vc->uni_pagedict_loc = &vc->uni_pagedict; + vc->uni_pagedict = NULL; vc->vc_hi_font_mask = 0; vc->vc_complement_mask = 0; vc->vc_can_do_color = 0; @@ -1136,7 +1136,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ visual_init(vc, currcons, 1); - if (!*vc->vc_uni_pagedir_loc) + if (!*vc->uni_pagedict_loc) con_set_default_unimap(vc); err = -EINVAL; @@ -3939,7 +3939,7 @@ static ssize_t show_bind(struct device *dev, struct device_attribute *attr, bind = con_is_bound(con->con); console_unlock(); - return snprintf(buf, PAGE_SIZE, "%i\n", bind); + return sysfs_emit(buf, "%i\n", bind); } static ssize_t show_name(struct device *dev, struct device_attribute *attr, @@ -3947,7 +3947,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, { struct con_driver *con = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%s %s\n", + return sysfs_emit(buf, "%s %s\n", (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)", con->desc); @@ -4741,7 +4741,7 @@ u32 screen_glyph_unicode(const struct vc_data *vc, int n) if (uniscr) return uniscr->lines[n / vc->vc_cols][n % vc->vc_cols]; - return inverse_translate(vc, screen_glyph(vc, n * 2), 1); + return inverse_translate(vc, screen_glyph(vc, n * 2), true); } EXPORT_SYMBOL_GPL(screen_glyph_unicode); |