diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2010-11-04 19:50:47 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-11-05 15:16:52 (GMT) |
commit | 60d4ae8d436b8be6a8aedb63440203d5395e9f53 (patch) | |
tree | 2e0798d278100518634b999dc6705e9f02027d9f /drivers/char | |
parent | 96fd7ce58ffb5c7bf376796b5525ba3ea1c9d69f (diff) | |
download | linux-fsl-qoriq-60d4ae8d436b8be6a8aedb63440203d5395e9f53.tar.xz |
TTY: create drivers/tty/vt and move the vt code there
The vt and other related code is moved into the drivers/tty/vt directory.
Acked-by: Arnd Bergmann <arnd@arndb.de>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/Makefile | 33 | ||||
-rw-r--r-- | drivers/char/consolemap.c | 745 | ||||
-rw-r--r-- | drivers/char/cp437.uni | 291 | ||||
-rw-r--r-- | drivers/char/defkeymap.c_shipped | 262 | ||||
-rw-r--r-- | drivers/char/defkeymap.map | 357 | ||||
-rw-r--r-- | drivers/char/keyboard.c | 1454 | ||||
-rw-r--r-- | drivers/char/selection.c | 348 | ||||
-rw-r--r-- | drivers/char/vc_screen.c | 644 | ||||
-rw-r--r-- | drivers/char/vt.c | 4209 | ||||
-rw-r--r-- | drivers/char/vt_ioctl.c | 1788 |
10 files changed, 0 insertions, 10131 deletions
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index f308494..ba53ec9 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -2,18 +2,10 @@ # Makefile for the kernel character device drivers. # -# -# This file contains the font map for the default (hardware) font -# -FONTMAPFILE = cp437.uni - obj-y += mem.o random.o obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o obj-y += misc.o -obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o -obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o -obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o @@ -106,28 +98,3 @@ obj-$(CONFIG_RAMOOPS) += ramoops.o obj-$(CONFIG_JS_RTC) += js-rtc.o js-rtc-y = rtc.o - -# Files generated that shall be removed upon make clean -clean-files := consolemap_deftbl.c defkeymap.c - -quiet_cmd_conmk = CONMK $@ - cmd_conmk = scripts/conmakehash $< > $@ - -$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE) - $(call cmd,conmk) - -$(obj)/defkeymap.o: $(obj)/defkeymap.c - -# Uncomment if you're changing the keymap and have an appropriate -# loadkeys version for the map. By default, we'll use the shipped -# versions. -# GENERATE_KEYMAP := 1 - -ifdef GENERATE_KEYMAP - -$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map - loadkeys --mktable $< > $@.tmp - sed -e 's/^static *//' $@.tmp > $@ - rm $@.tmp - -endif diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c deleted file mode 100644 index 45d3e80..0000000 --- a/drivers/char/consolemap.c +++ /dev/null @@ -1,745 +0,0 @@ -/* - * consolemap.c - * - * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code) - * to font positions. - * - * aeb, 950210 - * - * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998 - * - * Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998 - */ - -#include <linux/module.h> -#include <linux/kd.h> -#include <linux/errno.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <asm/uaccess.h> -#include <linux/consolemap.h> -#include <linux/vt_kern.h> - -static unsigned short translations[][256] = { - /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */ - { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, - 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, - 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, - 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, - 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, - 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, - 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, - 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, - 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, - 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, - 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 */ - { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f, - 0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0, - 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, - 0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, - 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, - 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f, - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, - 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, - 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, - 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, - 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, - 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, - 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, - 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, - 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, - 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, - 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, - 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, - 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff - }, - /* IBM Codepage 437 mapped to Unicode */ - { - 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, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, - 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, - 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, - 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, - 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, - 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, - 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, - 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, - 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, - 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, - 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, - 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 */ - { - 0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007, - 0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f, - 0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017, - 0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, - 0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027, - 0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f, - 0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, - 0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f, - 0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047, - 0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f, - 0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057, - 0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f, - 0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067, - 0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f, - 0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077, - 0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f, - 0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087, - 0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f, - 0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097, - 0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f, - 0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7, - 0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af, - 0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7, - 0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf, - 0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7, - 0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf, - 0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7, - 0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df, - 0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7, - 0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef, - 0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7, - 0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff - } -}; - -/* The standard kernel character-to-font mappings are not invertible - -- this is just a best effort. */ - -#define MAX_GLYPH 512 /* Max possible glyph value */ - -static int inv_translate[MAX_NR_CONSOLES]; - -struct uni_pagedir { - u16 **uni_pgdir[32]; - unsigned long refcount; - unsigned long sum; - unsigned char *inverse_translations[4]; - u16 *inverse_trans_unicode; - int readonly; -}; - -static struct uni_pagedir *dflt; - -static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i) -{ - 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] = (unsigned char *) - kmalloc(MAX_GLYPH, GFP_KERNEL); - if (!q) return; - } - memset(q, 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) { - /* prefer '-' above SHY etc. */ - q[glyph] = j; - } - } -} - -static void set_inverse_trans_unicode(struct vc_data *conp, - struct uni_pagedir *p) -{ - 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(MAX_GLYPH * sizeof(u16), GFP_KERNEL); - if (!q) - return; - } - memset(q, 0, MAX_GLYPH * sizeof(u16)); - - for (i = 0; i < 32; i++) { - p1 = p->uni_pgdir[i]; - if (!p1) - continue; - for (j = 0; j < 32; j++) { - p2 = p1[j]; - if (!p2) - 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; - } - } - } -} - -unsigned short *set_translate(int m, struct vc_data *vc) -{ - inv_translate[vc->vc_num] = m; - return translations[m]; -} - -/* - * Inverse translation is impossible for several reasons: - * 1. The font<->character maps are not 1-1. - * 2. The text may have been written while a different translation map - * was active. - * Still, it is now possible to a certain extent to cut and paste non-ASCII. - */ -u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode) -{ - struct uni_pagedir *p; - int m; - if (glyph < 0 || glyph >= MAX_GLYPH) - return 0; - else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc)) - 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]; - } -} -EXPORT_SYMBOL_GPL(inverse_translate); - -static void update_user_maps(void) -{ - int i; - struct uni_pagedir *p, *q = NULL; - - for (i = 0; i < MAX_NR_CONSOLES; i++) { - if (!vc_cons_allocated(i)) - continue; - p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; - if (p && p != q) { - set_inverse_transl(vc_cons[i].d, p, USER_MAP); - set_inverse_trans_unicode(vc_cons[i].d, p); - q = p; - } - } -} - -/* - * Load customizable translation table - * arg points to a 256 byte translation table. - * - * The "old" variants are for translation directly to font (using the - * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set - * Unicodes explicitly. - */ -int con_set_trans_old(unsigned char __user * arg) -{ - int i; - unsigned short *p = translations[USER_MAP]; - - if (!access_ok(VERIFY_READ, arg, E_TABSZ)) - return -EFAULT; - - for (i=0; i<E_TABSZ ; i++) { - unsigned char uc; - __get_user(uc, arg+i); - p[i] = UNI_DIRECT_BASE | uc; - } - - update_user_maps(); - return 0; -} - -int con_get_trans_old(unsigned char __user * arg) -{ - int i, ch; - unsigned short *p = translations[USER_MAP]; - - if (!access_ok(VERIFY_WRITE, arg, E_TABSZ)) - return -EFAULT; - - for (i=0; i<E_TABSZ ; i++) - { - ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]); - __put_user((ch & ~0xff) ? 0 : ch, arg+i); - } - return 0; -} - -int con_set_trans_new(ushort __user * arg) -{ - int i; - unsigned short *p = translations[USER_MAP]; - - if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short))) - return -EFAULT; - - for (i=0; i<E_TABSZ ; i++) { - unsigned short us; - __get_user(us, arg+i); - p[i] = us; - } - - update_user_maps(); - return 0; -} - -int con_get_trans_new(ushort __user * arg) -{ - int i; - unsigned short *p = translations[USER_MAP]; - - if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short))) - return -EFAULT; - - for (i=0; i<E_TABSZ ; i++) - __put_user(p[i], arg+i); - - return 0; -} - -/* - * Unicode -> current font conversion - * - * A font has at most 512 chars, usually 256. - * But one font position may represent several Unicode chars. - * A hashtable is somewhat of a pain to deal with, so use a - * "paged table" instead. Simulation has shown the memory cost of - * this 3-level paged table scheme to be comparable to a hash table. - */ - -extern u8 dfont_unicount[]; /* Defined in console_defmap.c */ -extern u16 dfont_unitable[]; - -static void con_release_unimap(struct uni_pagedir *p) -{ - u16 **p1; - int i, j; - - if (p == dflt) dflt = NULL; - for (i = 0; i < 32; i++) { - if ((p1 = p->uni_pgdir[i]) != NULL) { - for (j = 0; j < 32; j++) - kfree(p1[j]); - kfree(p1); - } - p->uni_pgdir[i] = NULL; - } - for (i = 0; i < 4; i++) { - kfree(p->inverse_translations[i]); - p->inverse_translations[i] = NULL; - } - if (p->inverse_trans_unicode) { - kfree(p->inverse_trans_unicode); - p->inverse_trans_unicode = NULL; - } -} - -void con_free_unimap(struct vc_data *vc) -{ - struct uni_pagedir *p; - - p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; - if (!p) - return; - *vc->vc_uni_pagedir_loc = 0; - if (--p->refcount) - return; - con_release_unimap(p); - kfree(p); -} - -static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p) -{ - int i, j, k; - struct uni_pagedir *q; - - for (i = 0; i < MAX_NR_CONSOLES; i++) { - if (!vc_cons_allocated(i)) - continue; - q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; - if (!q || q == p || q->sum != p->sum) - continue; - for (j = 0; j < 32; j++) { - u16 **p1, **q1; - p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j]; - if (!p1 && !q1) - continue; - if (!p1 || !q1) - break; - for (k = 0; k < 32; k++) { - if (!p1[k] && !q1[k]) - continue; - if (!p1[k] || !q1[k]) - break; - if (memcmp(p1[k], q1[k], 64*sizeof(u16))) - break; - } - if (k < 32) - break; - } - if (j == 32) { - q->refcount++; - *conp->vc_uni_pagedir_loc = (unsigned long)q; - con_release_unimap(p); - kfree(p); - return 1; - } - } - return 0; -} - -static int -con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) -{ - int i, n; - u16 **p1, *p2; - - if (!(p1 = p->uni_pgdir[n = unicode >> 11])) { - p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL); - if (!p1) return -ENOMEM; - for (i = 0; i < 32; i++) - p1[i] = NULL; - } - - if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) { - p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL); - if (!p2) return -ENOMEM; - memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */ - } - - p2[unicode & 0x3f] = fontpos; - - p->sum += (fontpos << 20) + unicode; - - return 0; -} - -/* ui is a leftover from using a hashtable, but might be used again */ -int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) -{ - struct uni_pagedir *p, *q; - - p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; - if (p && p->readonly) return -EIO; - 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 = (unsigned long)q; - } else { - if (p == dflt) dflt = NULL; - p->refcount++; - p->sum = 0; - con_release_unimap(p); - } - return 0; -} - -int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) -{ - int err = 0, err1, i; - struct uni_pagedir *p, *q; - - p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; - if (p->readonly) return -EIO; - - if (!ct) return 0; - - if (p->refcount > 1) { - int j, k; - u16 **p1, *p2, l; - - err1 = con_clear_unimap(vc, NULL); - if (err1) return err1; - - q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; - for (i = 0, l = 0; i < 32; i++) - if ((p1 = p->uni_pgdir[i])) - for (j = 0; j < 32; j++) - if ((p2 = p1[j])) - for (k = 0; k < 64; k++, l++) - if (p2[k] != 0xffff) { - err1 = con_insert_unipair(q, l, p2[k]); - if (err1) { - p->refcount++; - *vc->vc_uni_pagedir_loc = (unsigned long)p; - con_release_unimap(q); - kfree(q); - return err1; - } - } - p = q; - } else if (p == dflt) - dflt = NULL; - - while (ct--) { - unsigned short unicode, fontpos; - __get_user(unicode, &list->unicode); - __get_user(fontpos, &list->fontpos); - if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0) - err = err1; - list++; - } - - if (con_unify_unimap(vc, p)) - return err; - - for (i = 0; i <= 3; i++) - set_inverse_transl(vc, p, i); /* Update all inverse translations */ - set_inverse_trans_unicode(vc, p); - - return err; -} - -/* 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 sys_setup time, and when the - PIO_FONTRESET ioctl is called. */ - -int con_set_default_unimap(struct vc_data *vc) -{ - int i, j, err = 0, err1; - u16 *q; - struct uni_pagedir *p; - - if (dflt) { - p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; - if (p == dflt) - return 0; - dflt->refcount++; - *vc->vc_uni_pagedir_loc = (unsigned long)dflt; - if (p && --p->refcount) { - con_release_unimap(p); - kfree(p); - } - return 0; - } - - /* The default font is always 256 characters */ - - err = con_clear_unimap(vc, NULL); - if (err) return err; - - p = (struct uni_pagedir *)*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); - if (err1) - err = err1; - } - - if (con_unify_unimap(vc, p)) { - dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_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; - return err; -} -EXPORT_SYMBOL(con_set_default_unimap); - -int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) -{ - struct uni_pagedir *q; - - if (!*src_vc->vc_uni_pagedir_loc) - return -EINVAL; - if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc) - return 0; - con_free_unimap(dst_vc); - q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc; - q->refcount++; - *dst_vc->vc_uni_pagedir_loc = (long)q; - return 0; -} - -int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list) -{ - int i, j, k, ect; - u16 **p1, *p2; - struct uni_pagedir *p; - - ect = 0; - if (*vc->vc_uni_pagedir_loc) { - p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; - for (i = 0; i < 32; i++) - if ((p1 = p->uni_pgdir[i])) - for (j = 0; j < 32; j++) - if ((p2 = *(p1++))) - for (k = 0; k < 64; k++) { - if (*p2 < MAX_GLYPH && ect++ < ct) { - __put_user((u_short)((i<<11)+(j<<6)+k), - &list->unicode); - __put_user((u_short) *p2, - &list->fontpos); - list++; - } - p2++; - } - } - __put_user(ect, uct); - return ((ect <= ct) ? 0 : -ENOMEM); -} - -void con_protect_unimap(struct vc_data *vc, int rdonly) -{ - struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; - - if (p) - p->readonly = rdonly; -} - -/* - * Always use USER_MAP. These functions are used by the keyboard, - * which shouldn't be affected by G0/G1 switching, etc. - * If the user map still contains default values, i.e. the - * direct-to-font mapping, then assume user is using Latin1. - */ -/* may be called during an interrupt */ -u32 conv_8bit_to_uni(unsigned char c) -{ - unsigned short uni = translations[USER_MAP][c]; - return uni == (0xf000 | c) ? c : uni; -} - -int conv_uni_to_8bit(u32 uni) -{ - int c; - for (c = 0; c < 0x100; 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 h; - u16 **p1, *p2; - struct uni_pagedir *p; - - /* Only 16-bit codes supported at this time */ - if (ucs > 0xffff) - return -4; /* Not found */ - else if (ucs < 0x20) - return -1; /* Not a printable character */ - else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f)) - return -2; /* Zero-width space */ - /* - * UNI_DIRECT_BASE indicates the start of the region in the User Zone - * which always has a 1:1 mapping to the currently loaded font. The - * UNI_DIRECT_MASK indicates the bit span of the region. - */ - else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE) - return ucs & UNI_DIRECT_MASK; - - if (!*conp->vc_uni_pagedir_loc) - return -3; - - p = (struct uni_pagedir *)*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; - - return -4; /* not found */ -} - -/* - * This is called at sys_setup time, after memory and the console are - * initialized. It must be possible to call kmalloc(..., GFP_KERNEL) - * from this function, hence the call from sys_setup. - */ -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) - con_set_default_unimap(vc_cons[i].d); -} - -EXPORT_SYMBOL(con_copy_unimap); diff --git a/drivers/char/cp437.uni b/drivers/char/cp437.uni deleted file mode 100644 index bc61634..0000000 --- a/drivers/char/cp437.uni +++ /dev/null @@ -1,291 +0,0 @@ -# -# Unicode table for IBM Codepage 437. Note that there are many more -# substitutions that could be conceived (for example, thick-line -# graphs probably should be replaced with double-line ones, accented -# Latin characters should replaced with their nonaccented versions, -# and some upper case Greek characters could be replaced by Latin), however, -# I have limited myself to the Unicodes used by the kernel ISO 8859-1, -# DEC VT, and IBM CP 437 tables. -# -# -------------------------------- -# -# Basic IBM dingbats, some of which will never have a purpose clear -# to mankind -# -0x00 U+0000 -0x01 U+263a -0x02 U+263b -0x03 U+2665 -0x04 U+2666 U+25c6 -0x05 U+2663 -0x06 U+2660 -0x07 U+2022 -0x08 U+25d8 -0x09 U+25cb -0x0a U+25d9 -0x0b U+2642 -0x0c U+2640 -0x0d U+266a -0x0e U+266b -0x0f U+263c U+00a4 -0x10 U+25b6 U+25ba -0x11 U+25c0 U+25c4 -0x12 U+2195 -0x13 U+203c -0x14 U+00b6 -0x15 U+00a7 -0x16 U+25ac -0x17 U+21a8 -0x18 U+2191 -0x19 U+2193 -0x1a U+2192 -0x1b U+2190 -0x1c U+221f -0x1d U+2194 -0x1e U+25b2 -0x1f U+25bc -# -# The ASCII range is identity-mapped, but some of the characters also -# have to act as substitutes, especially the upper-case characters. -# -0x20 U+0020 -0x21 U+0021 -0x22 U+0022 U+00a8 -0x23 U+0023 -0x24 U+0024 -0x25 U+0025 -0x26 U+0026 -0x27 U+0027 U+00b4 -0x28 U+0028 -0x29 U+0029 -0x2a U+002a -0x2b U+002b -0x2c U+002c U+00b8 -0x2d U+002d U+00ad -0x2e U+002e -0x2f U+002f -0x30 U+0030 -0x31 U+0031 -0x32 U+0032 -0x33 U+0033 -0x34 U+0034 -0x35 U+0035 -0x36 U+0036 -0x37 U+0037 -0x38 U+0038 -0x39 U+0039 -0x3a U+003a -0x3b U+003b -0x3c U+003c -0x3d U+003d -0x3e U+003e -0x3f U+003f -0x40 U+0040 -0x41 U+0041 U+00c0 U+00c1 U+00c2 U+00c3 -0x42 U+0042 -0x43 U+0043 U+00a9 -0x44 U+0044 U+00d0 -0x45 U+0045 U+00c8 U+00ca U+00cb -0x46 U+0046 -0x47 U+0047 -0x48 U+0048 -0x49 U+0049 U+00cc U+00cd U+00ce U+00cf -0x4a U+004a -0x4b U+004b U+212a -0x4c U+004c -0x4d U+004d -0x4e U+004e -0x4f U+004f U+00d2 U+00d3 U+00d4 U+00d5 -0x50 U+0050 -0x51 U+0051 -0x52 U+0052 U+00ae -0x53 U+0053 -0x54 U+0054 -0x55 U+0055 U+00d9 U+00da U+00db -0x56 U+0056 -0x57 U+0057 -0x58 U+0058 -0x59 U+0059 U+00dd -0x5a U+005a -0x5b U+005b -0x5c U+005c -0x5d U+005d -0x5e U+005e -0x5f U+005f U+23bd U+f804 -0x60 U+0060 -0x61 U+0061 U+00e3 -0x62 U+0062 -0x63 U+0063 -0x64 U+0064 -0x65 U+0065 -0x66 U+0066 -0x67 U+0067 -0x68 U+0068 -0x69 U+0069 -0x6a U+006a -0x6b U+006b -0x6c U+006c -0x6d U+006d -0x6e U+006e -0x6f U+006f U+00f5 -0x70 U+0070 -0x71 U+0071 -0x72 U+0072 -0x73 U+0073 -0x74 U+0074 -0x75 U+0075 -0x76 U+0076 -0x77 U+0077 -0x78 U+0078 U+00d7 -0x79 U+0079 U+00fd -0x7a U+007a -0x7b U+007b -0x7c U+007c U+00a6 -0x7d U+007d -0x7e U+007e -# -# Okay, what on Earth is this one supposed to be used for? -# -0x7f U+2302 -# -# Non-English characters, mostly lower case letters... -# -0x80 U+00c7 -0x81 U+00fc -0x82 U+00e9 -0x83 U+00e2 -0x84 U+00e4 -0x85 U+00e0 -0x86 U+00e5 -0x87 U+00e7 -0x88 U+00ea -0x89 U+00eb -0x8a U+00e8 -0x8b U+00ef -0x8c U+00ee -0x8d U+00ec -0x8e U+00c4 -0x8f U+00c5 U+212b -0x90 U+00c9 -0x91 U+00e6 -0x92 U+00c6 -0x93 U+00f4 -0x94 U+00f6 -0x95 U+00f2 -0x96 U+00fb -0x97 U+00f9 -0x98 U+00ff -0x99 U+00d6 -0x9a U+00dc -0x9b U+00a2 -0x9c U+00a3 -0x9d U+00a5 -0x9e U+20a7 -0x9f U+0192 -0xa0 U+00e1 -0xa1 U+00ed -0xa2 U+00f3 -0xa3 U+00fa -0xa4 U+00f1 -0xa5 U+00d1 -0xa6 U+00aa -0xa7 U+00ba -0xa8 U+00bf -0xa9 U+2310 -0xaa U+00ac -0xab U+00bd -0xac U+00bc -0xad U+00a1 -0xae U+00ab -0xaf U+00bb -# -# Block graphics -# -0xb0 U+2591 -0xb1 U+2592 -0xb2 U+2593 -0xb3 U+2502 -0xb4 U+2524 -0xb5 U+2561 -0xb6 U+2562 -0xb7 U+2556 -0xb8 U+2555 -0xb9 U+2563 -0xba U+2551 -0xbb U+2557 -0xbc U+255d -0xbd U+255c -0xbe U+255b -0xbf U+2510 -0xc0 U+2514 -0xc1 U+2534 -0xc2 U+252c -0xc3 U+251c -0xc4 U+2500 -0xc5 U+253c -0xc6 U+255e -0xc7 U+255f -0xc8 U+255a -0xc9 U+2554 -0xca U+2569 -0xcb U+2566 -0xcc U+2560 -0xcd U+2550 -0xce U+256c -0xcf U+2567 -0xd0 U+2568 -0xd1 U+2564 -0xd2 U+2565 -0xd3 U+2559 -0xd4 U+2558 -0xd5 U+2552 -0xd6 U+2553 -0xd7 U+256b -0xd8 U+256a -0xd9 U+2518 -0xda U+250c -0xdb U+2588 -0xdc U+2584 -0xdd U+258c -0xde U+2590 -0xdf U+2580 -# -# Greek letters and mathematical symbols -# -0xe0 U+03b1 -0xe1 U+03b2 U+00df -0xe2 U+0393 -0xe3 U+03c0 -0xe4 U+03a3 -0xe5 U+03c3 -0xe6 U+00b5 U+03bc -0xe7 U+03c4 -0xe8 U+03a6 U+00d8 -0xe9 U+0398 -0xea U+03a9 U+2126 -0xeb U+03b4 U+00f0 -0xec U+221e -0xed U+03c6 U+00f8 -0xee U+03b5 U+2208 -0xef U+2229 -0xf0 U+2261 -0xf1 U+00b1 -0xf2 U+2265 -0xf3 U+2264 -0xf4 U+2320 -0xf5 U+2321 -0xf6 U+00f7 -0xf7 U+2248 -0xf8 U+00b0 -0xf9 U+2219 -0xfa U+00b7 -0xfb U+221a -0xfc U+207f -0xfd U+00b2 -# -# Square bullet, non-spacing blank -# Mapping U+fffd to the square bullet means it is the substitution -# character -# -0xfe U+25a0 U+fffd -0xff U+00a0 diff --git a/drivers/char/defkeymap.c_shipped b/drivers/char/defkeymap.c_shipped deleted file mode 100644 index d2208dfe..0000000 --- a/drivers/char/defkeymap.c_shipped +++ /dev/null @@ -1,262 +0,0 @@ -/* Do not edit this file! It was automatically generated by */ -/* loadkeys --mktable defkeymap.map > defkeymap.c */ - -#include <linux/types.h> -#include <linux/keyboard.h> -#include <linux/kd.h> - -u_short plain_map[NR_KEYS] = { - 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, - 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009, - 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, - 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73, - 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, - 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, - 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf30c, - 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, - 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf209, 0xf307, - 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, - 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03c, 0xf10a, - 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, - 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, - 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short shift_map[NR_KEYS] = { - 0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, - 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009, - 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, - 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53, - 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a, - 0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, - 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf30c, - 0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, - 0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf213, 0xf203, 0xf307, - 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, - 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a, - 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, - 0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116, - 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short altgr_map[NR_KEYS] = { - 0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, - 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, - 0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, - 0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201, 0xf702, 0xf914, 0xfb73, - 0xf917, 0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200, - 0xf200, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xf916, 0xfb76, - 0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c, - 0xf703, 0xf200, 0xf207, 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, - 0xf511, 0xf512, 0xf513, 0xf514, 0xf515, 0xf208, 0xf202, 0xf911, - 0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b, - 0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516, - 0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, - 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, - 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short ctrl_map[NR_KEYS] = { - 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, - 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200, - 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, - 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013, - 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, - 0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016, - 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf30c, - 0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, - 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf204, 0xf307, - 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, - 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf10a, - 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, - 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, - 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short shift_ctrl_map[NR_KEYS] = { - 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, - 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, - 0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013, - 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, - 0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, - 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c, - 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xf307, - 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, - 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, - 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, - 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short alt_map[NR_KEYS] = { - 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, - 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809, - 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869, - 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873, - 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b, - 0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876, - 0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf30c, - 0xf703, 0xf820, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, - 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf209, 0xf907, - 0xf908, 0xf909, 0xf30b, 0xf904, 0xf905, 0xf906, 0xf30a, 0xf901, - 0xf902, 0xf903, 0xf900, 0xf310, 0xf206, 0xf200, 0xf83c, 0xf50a, - 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, - 0xf118, 0xf210, 0xf211, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, - 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short ctrl_alt_map[NR_KEYS] = { - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, - 0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813, - 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, - 0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816, - 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c, - 0xf703, 0xf200, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, - 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf200, 0xf307, - 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, - 0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a, - 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, - 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c, - 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -ushort *key_maps[MAX_NR_KEYMAPS] = { - plain_map, shift_map, altgr_map, NULL, - ctrl_map, shift_ctrl_map, NULL, NULL, - alt_map, NULL, NULL, NULL, - ctrl_alt_map, NULL -}; - -unsigned int keymap_count = 7; - -/* - * Philosophy: most people do not define more strings, but they who do - * often want quite a lot of string space. So, we statically allocate - * the default and allocate dynamically in chunks of 512 bytes. - */ - -char func_buf[] = { - '\033', '[', '[', 'A', 0, - '\033', '[', '[', 'B', 0, - '\033', '[', '[', 'C', 0, - '\033', '[', '[', 'D', 0, - '\033', '[', '[', 'E', 0, - '\033', '[', '1', '7', '~', 0, - '\033', '[', '1', '8', '~', 0, - '\033', '[', '1', '9', '~', 0, - '\033', '[', '2', '0', '~', 0, - '\033', '[', '2', '1', '~', 0, - '\033', '[', '2', '3', '~', 0, - '\033', '[', '2', '4', '~', 0, - '\033', '[', '2', '5', '~', 0, - '\033', '[', '2', '6', '~', 0, - '\033', '[', '2', '8', '~', 0, - '\033', '[', '2', '9', '~', 0, - '\033', '[', '3', '1', '~', 0, - '\033', '[', '3', '2', '~', 0, - '\033', '[', '3', '3', '~', 0, - '\033', '[', '3', '4', '~', 0, - '\033', '[', '1', '~', 0, - '\033', '[', '2', '~', 0, - '\033', '[', '3', '~', 0, - '\033', '[', '4', '~', 0, - '\033', '[', '5', '~', 0, - '\033', '[', '6', '~', 0, - '\033', '[', 'M', 0, - '\033', '[', 'P', 0, -}; - -char *funcbufptr = func_buf; -int funcbufsize = sizeof(func_buf); -int funcbufleft = 0; /* space left */ - -char *func_table[MAX_NR_FUNC] = { - func_buf + 0, - func_buf + 5, - func_buf + 10, - func_buf + 15, - func_buf + 20, - func_buf + 25, - func_buf + 31, - func_buf + 37, - func_buf + 43, - func_buf + 49, - func_buf + 55, - func_buf + 61, - func_buf + 67, - func_buf + 73, - func_buf + 79, - func_buf + 85, - func_buf + 91, - func_buf + 97, - func_buf + 103, - func_buf + 109, - func_buf + 115, - func_buf + 120, - func_buf + 125, - func_buf + 130, - func_buf + 135, - func_buf + 140, - func_buf + 145, - NULL, - NULL, - func_buf + 149, - NULL, -}; - -struct kbdiacruc accent_table[MAX_DIACR] = { - {'`', 'A', 0300}, {'`', 'a', 0340}, - {'\'', 'A', 0301}, {'\'', 'a', 0341}, - {'^', 'A', 0302}, {'^', 'a', 0342}, - {'~', 'A', 0303}, {'~', 'a', 0343}, - {'"', 'A', 0304}, {'"', 'a', 0344}, - {'O', 'A', 0305}, {'o', 'a', 0345}, - {'0', 'A', 0305}, {'0', 'a', 0345}, - {'A', 'A', 0305}, {'a', 'a', 0345}, - {'A', 'E', 0306}, {'a', 'e', 0346}, - {',', 'C', 0307}, {',', 'c', 0347}, - {'`', 'E', 0310}, {'`', 'e', 0350}, - {'\'', 'E', 0311}, {'\'', 'e', 0351}, - {'^', 'E', 0312}, {'^', 'e', 0352}, - {'"', 'E', 0313}, {'"', 'e', 0353}, - {'`', 'I', 0314}, {'`', 'i', 0354}, - {'\'', 'I', 0315}, {'\'', 'i', 0355}, - {'^', 'I', 0316}, {'^', 'i', 0356}, - {'"', 'I', 0317}, {'"', 'i', 0357}, - {'-', 'D', 0320}, {'-', 'd', 0360}, - {'~', 'N', 0321}, {'~', 'n', 0361}, - {'`', 'O', 0322}, {'`', 'o', 0362}, - {'\'', 'O', 0323}, {'\'', 'o', 0363}, - {'^', 'O', 0324}, {'^', 'o', 0364}, - {'~', 'O', 0325}, {'~', 'o', 0365}, - {'"', 'O', 0326}, {'"', 'o', 0366}, - {'/', 'O', 0330}, {'/', 'o', 0370}, - {'`', 'U', 0331}, {'`', 'u', 0371}, - {'\'', 'U', 0332}, {'\'', 'u', 0372}, - {'^', 'U', 0333}, {'^', 'u', 0373}, - {'"', 'U', 0334}, {'"', 'u', 0374}, - {'\'', 'Y', 0335}, {'\'', 'y', 0375}, - {'T', 'H', 0336}, {'t', 'h', 0376}, - {'s', 's', 0337}, {'"', 'y', 0377}, - {'s', 'z', 0337}, {'i', 'j', 0377}, -}; - -unsigned int accent_table_size = 68; diff --git a/drivers/char/defkeymap.map b/drivers/char/defkeymap.map deleted file mode 100644 index 50b30ca..0000000 --- a/drivers/char/defkeymap.map +++ /dev/null @@ -1,357 +0,0 @@ -# Default kernel keymap. This uses 7 modifier combinations. -keymaps 0-2,4-5,8,12 -# Change the above line into -# keymaps 0-2,4-6,8,12 -# in case you want the entries -# altgr control keycode 83 = Boot -# altgr control keycode 111 = Boot -# below. -# -# In fact AltGr is used very little, and one more keymap can -# be saved by mapping AltGr to Alt (and adapting a few entries): -# keycode 100 = Alt -# -keycode 1 = Escape Escape - alt keycode 1 = Meta_Escape -keycode 2 = one exclam - alt keycode 2 = Meta_one -keycode 3 = two at at - control keycode 3 = nul - shift control keycode 3 = nul - alt keycode 3 = Meta_two -keycode 4 = three numbersign - control keycode 4 = Escape - alt keycode 4 = Meta_three -keycode 5 = four dollar dollar - control keycode 5 = Control_backslash - alt keycode 5 = Meta_four -keycode 6 = five percent - control keycode 6 = Control_bracketright - alt keycode 6 = Meta_five -keycode 7 = six asciicircum - control keycode 7 = Control_asciicircum - alt keycode 7 = Meta_six -keycode 8 = seven ampersand braceleft - control keycode 8 = Control_underscore - alt keycode 8 = Meta_seven -keycode 9 = eight asterisk bracketleft - control keycode 9 = Delete - alt keycode 9 = Meta_eight -keycode 10 = nine parenleft bracketright - alt keycode 10 = Meta_nine -keycode 11 = zero parenright braceright - alt keycode 11 = Meta_zero -keycode 12 = minus underscore backslash - control keycode 12 = Control_underscore - shift control keycode 12 = Control_underscore - alt keycode 12 = Meta_minus -keycode 13 = equal plus - alt keycode 13 = Meta_equal -keycode 14 = Delete Delete - control keycode 14 = BackSpace - alt keycode 14 = Meta_Delete -keycode 15 = Tab Tab - alt keycode 15 = Meta_Tab -keycode 16 = q -keycode 17 = w -keycode 18 = e - altgr keycode 18 = Hex_E -keycode 19 = r -keycode 20 = t -keycode 21 = y -keycode 22 = u -keycode 23 = i -keycode 24 = o -keycode 25 = p -keycode 26 = bracketleft braceleft - control keycode 26 = Escape - alt keycode 26 = Meta_bracketleft -keycode 27 = bracketright braceright asciitilde - control keycode 27 = Control_bracketright - alt keycode 27 = Meta_bracketright -keycode 28 = Return - alt keycode 28 = Meta_Control_m -keycode 29 = Control -keycode 30 = a - altgr keycode 30 = Hex_A -keycode 31 = s -keycode 32 = d - altgr keycode 32 = Hex_D -keycode 33 = f - altgr keycode 33 = Hex_F -keycode 34 = g -keycode 35 = h -keycode 36 = j -keycode 37 = k -keycode 38 = l -keycode 39 = semicolon colon - alt keycode 39 = Meta_semicolon -keycode 40 = apostrophe quotedbl - control keycode 40 = Control_g - alt keycode 40 = Meta_apostrophe -keycode 41 = grave asciitilde - control keycode 41 = nul - alt keycode 41 = Meta_grave -keycode 42 = Shift -keycode 43 = backslash bar - control keycode 43 = Control_backslash - alt keycode 43 = Meta_backslash -keycode 44 = z -keycode 45 = x -keycode 46 = c - altgr keycode 46 = Hex_C -keycode 47 = v -keycode 48 = b - altgr keycode 48 = Hex_B -keycode 49 = n -keycode 50 = m -keycode 51 = comma less - alt keycode 51 = Meta_comma -keycode 52 = period greater - control keycode 52 = Compose - alt keycode 52 = Meta_period -keycode 53 = slash question - control keycode 53 = Delete - alt keycode 53 = Meta_slash -keycode 54 = Shift -keycode 55 = KP_Multiply -keycode 56 = Alt -keycode 57 = space space - control keycode 57 = nul - alt keycode 57 = Meta_space -keycode 58 = Caps_Lock -keycode 59 = F1 F11 Console_13 - control keycode 59 = F1 - alt keycode 59 = Console_1 - control alt keycode 59 = Console_1 -keycode 60 = F2 F12 Console_14 - control keycode 60 = F2 - alt keycode 60 = Console_2 - control alt keycode 60 = Console_2 -keycode 61 = F3 F13 Console_15 - control keycode 61 = F3 - alt keycode 61 = Console_3 - control alt keycode 61 = Console_3 -keycode 62 = F4 F14 Console_16 - control keycode 62 = F4 - alt keycode 62 = Console_4 - control alt keycode 62 = Console_4 -keycode 63 = F5 F15 Console_17 - control keycode 63 = F5 - alt keycode 63 = Console_5 - control alt keycode 63 = Console_5 -keycode 64 = F6 F16 Console_18 - control keycode 64 = F6 - alt keycode 64 = Console_6 - control alt keycode 64 = Console_6 -keycode 65 = F7 F17 Console_19 - control keycode 65 = F7 - alt keycode 65 = Console_7 - control alt keycode 65 = Console_7 -keycode 66 = F8 F18 Console_20 - control keycode 66 = F8 - alt keycode 66 = Console_8 - control alt keycode 66 = Console_8 -keycode 67 = F9 F19 Console_21 - control keycode 67 = F9 - alt keycode 67 = Console_9 - control alt keycode 67 = Console_9 -keycode 68 = F10 F20 Console_22 - control keycode 68 = F10 - alt keycode 68 = Console_10 - control alt keycode 68 = Console_10 -keycode 69 = Num_Lock - shift keycode 69 = Bare_Num_Lock -keycode 70 = Scroll_Lock Show_Memory Show_Registers - control keycode 70 = Show_State - alt keycode 70 = Scroll_Lock -keycode 71 = KP_7 - alt keycode 71 = Ascii_7 - altgr keycode 71 = Hex_7 -keycode 72 = KP_8 - alt keycode 72 = Ascii_8 - altgr keycode 72 = Hex_8 -keycode 73 = KP_9 - alt keycode 73 = Ascii_9 - altgr keycode 73 = Hex_9 -keycode 74 = KP_Subtract -keycode 75 = KP_4 - alt keycode 75 = Ascii_4 - altgr keycode 75 = Hex_4 -keycode 76 = KP_5 - alt keycode 76 = Ascii_5 - altgr keycode 76 = Hex_5 -keycode 77 = KP_6 - alt keycode 77 = Ascii_6 - altgr keycode 77 = Hex_6 -keycode 78 = KP_Add -keycode 79 = KP_1 - alt keycode 79 = Ascii_1 - altgr keycode 79 = Hex_1 -keycode 80 = KP_2 - alt keycode 80 = Ascii_2 - altgr keycode 80 = Hex_2 -keycode 81 = KP_3 - alt keycode 81 = Ascii_3 - altgr keycode 81 = Hex_3 -keycode 82 = KP_0 - alt keycode 82 = Ascii_0 - altgr keycode 82 = Hex_0 -keycode 83 = KP_Period -# altgr control keycode 83 = Boot - control alt keycode 83 = Boot -keycode 84 = Last_Console -keycode 85 = -keycode 86 = less greater bar - alt keycode 86 = Meta_less -keycode 87 = F11 F11 Console_23 - control keycode 87 = F11 - alt keycode 87 = Console_11 - control alt keycode 87 = Console_11 -keycode 88 = F12 F12 Console_24 - control keycode 88 = F12 - alt keycode 88 = Console_12 - control alt keycode 88 = Console_12 -keycode 89 = -keycode 90 = -keycode 91 = -keycode 92 = -keycode 93 = -keycode 94 = -keycode 95 = -keycode 96 = KP_Enter -keycode 97 = Control -keycode 98 = KP_Divide -keycode 99 = Control_backslash - control keycode 99 = Control_backslash - alt keycode 99 = Control_backslash -keycode 100 = AltGr -keycode 101 = Break -keycode 102 = Find -keycode 103 = Up -keycode 104 = Prior - shift keycode 104 = Scroll_Backward -keycode 105 = Left - alt keycode 105 = Decr_Console -keycode 106 = Right - alt keycode 106 = Incr_Console -keycode 107 = Select -keycode 108 = Down -keycode 109 = Next - shift keycode 109 = Scroll_Forward -keycode 110 = Insert -keycode 111 = Remove -# altgr control keycode 111 = Boot - control alt keycode 111 = Boot -keycode 112 = Macro -keycode 113 = F13 -keycode 114 = F14 -keycode 115 = Help -keycode 116 = Do -keycode 117 = F17 -keycode 118 = KP_MinPlus -keycode 119 = Pause -keycode 120 = -keycode 121 = -keycode 122 = -keycode 123 = -keycode 124 = -keycode 125 = -keycode 126 = -keycode 127 = -string F1 = "\033[[A" -string F2 = "\033[[B" -string F3 = "\033[[C" -string F4 = "\033[[D" -string F5 = "\033[[E" -string F6 = "\033[17~" -string F7 = "\033[18~" -string F8 = "\033[19~" -string F9 = "\033[20~" -string F10 = "\033[21~" -string F11 = "\033[23~" -string F12 = "\033[24~" -string F13 = "\033[25~" -string F14 = "\033[26~" -string F15 = "\033[28~" -string F16 = "\033[29~" -string F17 = "\033[31~" -string F18 = "\033[32~" -string F19 = "\033[33~" -string F20 = "\033[34~" -string Find = "\033[1~" -string Insert = "\033[2~" -string Remove = "\033[3~" -string Select = "\033[4~" -string Prior = "\033[5~" -string Next = "\033[6~" -string Macro = "\033[M" -string Pause = "\033[P" -compose '`' 'A' to 'À' -compose '`' 'a' to 'à' -compose '\'' 'A' to 'Á' -compose '\'' 'a' to 'á' -compose '^' 'A' to 'Â' -compose '^' 'a' to 'â' -compose '~' 'A' to 'Ã' -compose '~' 'a' to 'ã' -compose '"' 'A' to 'Ä' -compose '"' 'a' to 'ä' -compose 'O' 'A' to 'Å' -compose 'o' 'a' to 'å' -compose '0' 'A' to 'Å' -compose '0' 'a' to 'å' -compose 'A' 'A' to 'Å' -compose 'a' 'a' to 'å' -compose 'A' 'E' to 'Æ' -compose 'a' 'e' to 'æ' -compose ',' 'C' to 'Ç' -compose ',' 'c' to 'ç' -compose '`' 'E' to 'È' -compose '`' 'e' to 'è' -compose '\'' 'E' to 'É' -compose '\'' 'e' to 'é' -compose '^' 'E' to 'Ê' -compose '^' 'e' to 'ê' -compose '"' 'E' to 'Ë' -compose '"' 'e' to 'ë' -compose '`' 'I' to 'Ì' -compose '`' 'i' to 'ì' -compose '\'' 'I' to 'Í' -compose '\'' 'i' to 'í' -compose '^' 'I' to 'Î' -compose '^' 'i' to 'î' -compose '"' 'I' to 'Ï' -compose '"' 'i' to 'ï' -compose '-' 'D' to 'Ð' -compose '-' 'd' to 'ð' -compose '~' 'N' to 'Ñ' -compose '~' 'n' to 'ñ' -compose '`' 'O' to 'Ò' -compose '`' 'o' to 'ò' -compose '\'' 'O' to 'Ó' -compose '\'' 'o' to 'ó' -compose '^' 'O' to 'Ô' -compose '^' 'o' to 'ô' -compose '~' 'O' to 'Õ' -compose '~' 'o' to 'õ' -compose '"' 'O' to 'Ö' -compose '"' 'o' to 'ö' -compose '/' 'O' to 'Ø' -compose '/' 'o' to 'ø' -compose '`' 'U' to 'Ù' -compose '`' 'u' to 'ù' -compose '\'' 'U' to 'Ú' -compose '\'' 'u' to 'ú' -compose '^' 'U' to 'Û' -compose '^' 'u' to 'û' -compose '"' 'U' to 'Ü' -compose '"' 'u' to 'ü' -compose '\'' 'Y' to 'Ý' -compose '\'' 'y' to 'ý' -compose 'T' 'H' to 'Þ' -compose 't' 'h' to 'þ' -compose 's' 's' to 'ß' -compose '"' 'y' to 'ÿ' -compose 's' 'z' to 'ß' -compose 'i' 'j' to 'ÿ' diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c deleted file mode 100644 index e95d787..0000000 --- a/drivers/char/keyboard.c +++ /dev/null @@ -1,1454 +0,0 @@ -/* - * linux/drivers/char/keyboard.c - * - * Written for linux by Johan Myreen as a translation from - * the assembly version by Linus (with diacriticals added) - * - * Some additional features added by Christoph Niemann (ChN), March 1993 - * - * Loadable keymaps by Risto Kankkunen, May 1993 - * - * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993 - * Added decr/incr_console, dynamic keymaps, Unicode support, - * dynamic function/string keys, led setting, Sept 1994 - * `Sticky' modifier keys, 951006. - * - * 11-11-96: SAK should now work in the raw mode (Martin Mares) - * - * Modified to provide 'generic' keyboard support by Hamish Macdonald - * Merge with the m68k keyboard driver and split-off of the PC low-level - * parts by Geert Uytterhoeven, May 1997 - * - * 27-05-97: Added support for the Magic SysRq Key (Martin Mares) - * 30-07-98: Dead keys redone, aeb@cwi.nl. - * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik) - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/consolemap.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/mm.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/irq.h> - -#include <linux/kbd_kern.h> -#include <linux/kbd_diacr.h> -#include <linux/vt_kern.h> -#include <linux/input.h> -#include <linux/reboot.h> -#include <linux/notifier.h> -#include <linux/jiffies.h> - -extern void ctrl_alt_del(void); - -/* - * Exported functions/variables - */ - -#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) - -/* - * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on. - * This seems a good reason to start with NumLock off. On HIL keyboards - * of PARISC machines however there is no NumLock key and everyone expects the keypad - * to be used for numbers. - */ - -#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD)) -#define KBD_DEFLEDS (1 << VC_NUMLOCK) -#else -#define KBD_DEFLEDS 0 -#endif - -#define KBD_DEFLOCK 0 - -void compute_shiftstate(void); - -/* - * Handler Tables. - */ - -#define K_HANDLERS\ - k_self, k_fn, k_spec, k_pad,\ - k_dead, k_cons, k_cur, k_shift,\ - k_meta, k_ascii, k_lock, k_lowercase,\ - k_slock, k_dead2, k_brl, k_ignore - -typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, - char up_flag); -static k_handler_fn K_HANDLERS; -static k_handler_fn *k_handler[16] = { K_HANDLERS }; - -#define FN_HANDLERS\ - fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ - fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ - fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ - fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ - fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num - -typedef void (fn_handler_fn)(struct vc_data *vc); -static fn_handler_fn FN_HANDLERS; -static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; - -/* - * Variables exported for vt_ioctl.c - */ - -/* maximum values each key_handler can handle */ -const int max_vals[] = { - 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, - NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, - 255, NR_LOCK - 1, 255, NR_BRL - 1 -}; - -const int NR_TYPES = ARRAY_SIZE(max_vals); - -struct kbd_struct kbd_table[MAX_NR_CONSOLES]; -EXPORT_SYMBOL_GPL(kbd_table); -static struct kbd_struct *kbd = kbd_table; - -struct vt_spawn_console vt_spawn_con = { - .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock), - .pid = NULL, - .sig = 0, -}; - -/* - * Variables exported for vt.c - */ - -int shift_state = 0; - -/* - * Internal Data. - */ - -static struct input_handler kbd_handler; -static DEFINE_SPINLOCK(kbd_event_lock); -static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ -static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ -static bool dead_key_next; -static int npadch = -1; /* -1 or number assembled on pad */ -static unsigned int diacr; -static char rep; /* flag telling character repeat */ - -static unsigned char ledstate = 0xff; /* undefined */ -static unsigned char ledioctl; - -static struct ledptr { - unsigned int *addr; - unsigned int mask; - unsigned char valid:1; -} ledptrs[3]; - -/* - * Notifier list for console keyboard events - */ -static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list); - -int register_keyboard_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&keyboard_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(register_keyboard_notifier); - -int unregister_keyboard_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(unregister_keyboard_notifier); - -/* - * Translation of scancodes to keycodes. We set them on only the first - * keyboard in the list that accepts the scancode and keycode. - * Explanation for not choosing the first attached keyboard anymore: - * USB keyboards for example have two event devices: one for all "normal" - * keys and one for extra function keys (like "volume up", "make coffee", - * etc.). So this means that scancodes for the extra function keys won't - * be valid for the first event device, but will be for the second. - */ - -struct getset_keycode_data { - struct input_keymap_entry ke; - int error; -}; - -static int getkeycode_helper(struct input_handle *handle, void *data) -{ - struct getset_keycode_data *d = data; - - d->error = input_get_keycode(handle->dev, &d->ke); - - return d->error == 0; /* stop as soon as we successfully get one */ -} - -int getkeycode(unsigned int scancode) -{ - struct getset_keycode_data d = { - .ke = { - .flags = 0, - .len = sizeof(scancode), - .keycode = 0, - }, - .error = -ENODEV, - }; - - memcpy(d.ke.scancode, &scancode, sizeof(scancode)); - - input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper); - - return d.error ?: d.ke.keycode; -} - -static int setkeycode_helper(struct input_handle *handle, void *data) -{ - struct getset_keycode_data *d = data; - - d->error = input_set_keycode(handle->dev, &d->ke); - - return d->error == 0; /* stop as soon as we successfully set one */ -} - -int setkeycode(unsigned int scancode, unsigned int keycode) -{ - struct getset_keycode_data d = { - .ke = { - .flags = 0, - .len = sizeof(scancode), - .keycode = keycode, - }, - .error = -ENODEV, - }; - - memcpy(d.ke.scancode, &scancode, sizeof(scancode)); - - input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper); - - return d.error; -} - -/* - * Making beeps and bells. Note that we prefer beeps to bells, but when - * shutting the sound off we do both. - */ - -static int kd_sound_helper(struct input_handle *handle, void *data) -{ - unsigned int *hz = data; - struct input_dev *dev = handle->dev; - - if (test_bit(EV_SND, dev->evbit)) { - if (test_bit(SND_TONE, dev->sndbit)) { - input_inject_event(handle, EV_SND, SND_TONE, *hz); - if (*hz) - return 0; - } - if (test_bit(SND_BELL, dev->sndbit)) - input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0); - } - - return 0; -} - -static void kd_nosound(unsigned long ignored) -{ - static unsigned int zero; - - input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper); -} - -static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); - -void kd_mksound(unsigned int hz, unsigned int ticks) -{ - del_timer_sync(&kd_mksound_timer); - - input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper); - - if (hz && ticks) - mod_timer(&kd_mksound_timer, jiffies + ticks); -} -EXPORT_SYMBOL(kd_mksound); - -/* - * Setting the keyboard rate. - */ - -static int kbd_rate_helper(struct input_handle *handle, void *data) -{ - struct input_dev *dev = handle->dev; - struct kbd_repeat *rep = data; - - if (test_bit(EV_REP, dev->evbit)) { - - if (rep[0].delay > 0) - input_inject_event(handle, - EV_REP, REP_DELAY, rep[0].delay); - if (rep[0].period > 0) - input_inject_event(handle, - EV_REP, REP_PERIOD, rep[0].period); - - rep[1].delay = dev->rep[REP_DELAY]; - rep[1].period = dev->rep[REP_PERIOD]; - } - - return 0; -} - -int kbd_rate(struct kbd_repeat *rep) -{ - struct kbd_repeat data[2] = { *rep }; - - input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper); - *rep = data[1]; /* Copy currently used settings */ - - return 0; -} - -/* - * Helper Functions. - */ -static void put_queue(struct vc_data *vc, int ch) -{ - struct tty_struct *tty = vc->port.tty; - - if (tty) { - tty_insert_flip_char(tty, ch, 0); - con_schedule_flip(tty); - } -} - -static void puts_queue(struct vc_data *vc, char *cp) -{ - struct tty_struct *tty = vc->port.tty; - - if (!tty) - return; - - while (*cp) { - tty_insert_flip_char(tty, *cp, 0); - cp++; - } - con_schedule_flip(tty); -} - -static void applkey(struct vc_data *vc, int key, char mode) -{ - static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; - - buf[1] = (mode ? 'O' : '['); - buf[2] = key; - puts_queue(vc, buf); -} - -/* - * Many other routines do put_queue, but I think either - * they produce ASCII, or they produce some user-assigned - * string, and in both cases we might assume that it is - * in utf-8 already. - */ -static void to_utf8(struct vc_data *vc, uint c) -{ - if (c < 0x80) - /* 0******* */ - put_queue(vc, c); - else if (c < 0x800) { - /* 110***** 10****** */ - put_queue(vc, 0xc0 | (c >> 6)); - put_queue(vc, 0x80 | (c & 0x3f)); - } else if (c < 0x10000) { - if (c >= 0xD800 && c < 0xE000) - return; - if (c == 0xFFFF) - return; - /* 1110**** 10****** 10****** */ - put_queue(vc, 0xe0 | (c >> 12)); - put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); - put_queue(vc, 0x80 | (c & 0x3f)); - } else if (c < 0x110000) { - /* 11110*** 10****** 10****** 10****** */ - put_queue(vc, 0xf0 | (c >> 18)); - put_queue(vc, 0x80 | ((c >> 12) & 0x3f)); - put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); - put_queue(vc, 0x80 | (c & 0x3f)); - } -} - -/* - * Called after returning from RAW mode or when changing consoles - recompute - * shift_down[] and shift_state from key_down[] maybe called when keymap is - * undefined, so that shiftkey release is seen - */ -void compute_shiftstate(void) -{ - unsigned int i, j, k, sym, val; - - shift_state = 0; - memset(shift_down, 0, sizeof(shift_down)); - - for (i = 0; i < ARRAY_SIZE(key_down); i++) { - - if (!key_down[i]) - continue; - - k = i * BITS_PER_LONG; - - for (j = 0; j < BITS_PER_LONG; j++, k++) { - - if (!test_bit(k, key_down)) - continue; - - sym = U(key_maps[0][k]); - if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) - continue; - - val = KVAL(sym); - if (val == KVAL(K_CAPSSHIFT)) - val = KVAL(K_SHIFT); - - shift_down[val]++; - shift_state |= (1 << val); - } - } -} - -/* - * We have a combining character DIACR here, followed by the character CH. - * If the combination occurs in the table, return the corresponding value. - * Otherwise, if CH is a space or equals DIACR, return DIACR. - * Otherwise, conclude that DIACR was not combining after all, - * queue it and return CH. - */ -static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) -{ - unsigned int d = diacr; - unsigned int i; - - diacr = 0; - - if ((d & ~0xff) == BRL_UC_ROW) { - if ((ch & ~0xff) == BRL_UC_ROW) - return d | ch; - } else { - for (i = 0; i < accent_table_size; i++) - if (accent_table[i].diacr == d && accent_table[i].base == ch) - return accent_table[i].result; - } - - if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d) - return d; - - if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, d); - else { - int c = conv_uni_to_8bit(d); - if (c != -1) - put_queue(vc, c); - } - - return ch; -} - -/* - * Special function handlers - */ -static void fn_enter(struct vc_data *vc) -{ - if (diacr) { - if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, diacr); - else { - int c = conv_uni_to_8bit(diacr); - if (c != -1) - put_queue(vc, c); - } - diacr = 0; - } - - put_queue(vc, 13); - if (vc_kbd_mode(kbd, VC_CRLF)) - put_queue(vc, 10); -} - -static void fn_caps_toggle(struct vc_data *vc) -{ - if (rep) - return; - - chg_vc_kbd_led(kbd, VC_CAPSLOCK); -} - -static void fn_caps_on(struct vc_data *vc) -{ - if (rep) - return; - - set_vc_kbd_led(kbd, VC_CAPSLOCK); -} - -static void fn_show_ptregs(struct vc_data *vc) -{ - struct pt_regs *regs = get_irq_regs(); - - if (regs) - show_regs(regs); -} - -static void fn_hold(struct vc_data *vc) -{ - struct tty_struct *tty = vc->port.tty; - - if (rep || !tty) - return; - - /* - * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty); - * these routines are also activated by ^S/^Q. - * (And SCROLLOCK can also be set by the ioctl KDSKBLED.) - */ - if (tty->stopped) - start_tty(tty); - else - stop_tty(tty); -} - -static void fn_num(struct vc_data *vc) -{ - if (vc_kbd_mode(kbd, VC_APPLIC)) - applkey(vc, 'P', 1); - else - fn_bare_num(vc); -} - -/* - * Bind this to Shift-NumLock if you work in application keypad mode - * but want to be able to change the NumLock flag. - * Bind this to NumLock if you prefer that the NumLock key always - * changes the NumLock flag. - */ -static void fn_bare_num(struct vc_data *vc) -{ - if (!rep) - chg_vc_kbd_led(kbd, VC_NUMLOCK); -} - -static void fn_lastcons(struct vc_data *vc) -{ - /* switch to the last used console, ChN */ - set_console(last_console); -} - -static void fn_dec_console(struct vc_data *vc) -{ - int i, cur = fg_console; - - /* Currently switching? Queue this next switch relative to that. */ - if (want_console != -1) - cur = want_console; - - for (i = cur - 1; i != cur; i--) { - if (i == -1) - i = MAX_NR_CONSOLES - 1; - if (vc_cons_allocated(i)) - break; - } - set_console(i); -} - -static void fn_inc_console(struct vc_data *vc) -{ - int i, cur = fg_console; - - /* Currently switching? Queue this next switch relative to that. */ - if (want_console != -1) - cur = want_console; - - for (i = cur+1; i != cur; i++) { - if (i == MAX_NR_CONSOLES) - i = 0; - if (vc_cons_allocated(i)) - break; - } - set_console(i); -} - -static void fn_send_intr(struct vc_data *vc) -{ - struct tty_struct *tty = vc->port.tty; - - if (!tty) - return; - tty_insert_flip_char(tty, 0, TTY_BREAK); - con_schedule_flip(tty); -} - -static void fn_scroll_forw(struct vc_data *vc) -{ - scrollfront(vc, 0); -} - -static void fn_scroll_back(struct vc_data *vc) -{ - scrollback(vc, 0); -} - -static void fn_show_mem(struct vc_data *vc) -{ - show_mem(); -} - -static void fn_show_state(struct vc_data *vc) -{ - show_state(); -} - -static void fn_boot_it(struct vc_data *vc) -{ - ctrl_alt_del(); -} - -static void fn_compose(struct vc_data *vc) -{ - dead_key_next = true; -} - -static void fn_spawn_con(struct vc_data *vc) -{ - spin_lock(&vt_spawn_con.lock); - if (vt_spawn_con.pid) - if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) { - put_pid(vt_spawn_con.pid); - vt_spawn_con.pid = NULL; - } - spin_unlock(&vt_spawn_con.lock); -} - -static void fn_SAK(struct vc_data *vc) -{ - struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; - schedule_work(SAK_work); -} - -static void fn_null(struct vc_data *vc) -{ - compute_shiftstate(); -} - -/* - * Special key handlers - */ -static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag) -{ -} - -static void k_spec(struct vc_data *vc, unsigned char value, char up_flag) -{ - if (up_flag) - return; - if (value >= ARRAY_SIZE(fn_handler)) - return; - if ((kbd->kbdmode == VC_RAW || - kbd->kbdmode == VC_MEDIUMRAW) && - value != KVAL(K_SAK)) - return; /* SAK is allowed even in raw mode */ - fn_handler[value](vc); -} - -static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag) -{ - pr_err("k_lowercase was called - impossible\n"); -} - -static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag) -{ - if (up_flag) - return; /* no action, if this is a key release */ - - if (diacr) - value = handle_diacr(vc, value); - - if (dead_key_next) { - dead_key_next = false; - diacr = value; - return; - } - if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, value); - else { - int c = conv_uni_to_8bit(value); - if (c != -1) - put_queue(vc, c); - } -} - -/* - * Handle dead key. Note that we now may have several - * dead keys modifying the same character. Very useful - * for Vietnamese. - */ -static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag) -{ - if (up_flag) - return; - - diacr = (diacr ? handle_diacr(vc, value) : value); -} - -static void k_self(struct vc_data *vc, unsigned char value, char up_flag) -{ - k_unicode(vc, conv_8bit_to_uni(value), up_flag); -} - -static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag) -{ - k_deadunicode(vc, value, up_flag); -} - -/* - * Obsolete - for backwards compatibility only - */ -static void k_dead(struct vc_data *vc, unsigned char value, char up_flag) -{ - static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; - - k_deadunicode(vc, ret_diacr[value], up_flag); -} - -static void k_cons(struct vc_data *vc, unsigned char value, char up_flag) -{ - if (up_flag) - return; - - set_console(value); -} - -static void k_fn(struct vc_data *vc, unsigned char value, char up_flag) -{ - if (up_flag) - return; - - if ((unsigned)value < ARRAY_SIZE(func_table)) { - if (func_table[value]) - puts_queue(vc, func_table[value]); - } else - pr_err("k_fn called with value=%d\n", value); -} - -static void k_cur(struct vc_data *vc, unsigned char value, char up_flag) -{ - static const char cur_chars[] = "BDCA"; - - if (up_flag) - return; - - applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE)); -} - -static void k_pad(struct vc_data *vc, unsigned char value, char up_flag) -{ - static const char pad_chars[] = "0123456789+-*/\015,.?()#"; - static const char app_map[] = "pqrstuvwxylSRQMnnmPQS"; - - if (up_flag) - return; /* no action, if this is a key release */ - - /* kludge... shift forces cursor/number keys */ - if (vc_kbd_mode(kbd, VC_APPLIC) && !shift_down[KG_SHIFT]) { - applkey(vc, app_map[value], 1); - return; - } - - if (!vc_kbd_led(kbd, VC_NUMLOCK)) { - - switch (value) { - case KVAL(K_PCOMMA): - case KVAL(K_PDOT): - k_fn(vc, KVAL(K_REMOVE), 0); - return; - case KVAL(K_P0): - k_fn(vc, KVAL(K_INSERT), 0); - return; - case KVAL(K_P1): - k_fn(vc, KVAL(K_SELECT), 0); - return; - case KVAL(K_P2): - k_cur(vc, KVAL(K_DOWN), 0); - return; - case KVAL(K_P3): - k_fn(vc, KVAL(K_PGDN), 0); - return; - case KVAL(K_P4): - k_cur(vc, KVAL(K_LEFT), 0); - return; - case KVAL(K_P6): - k_cur(vc, KVAL(K_RIGHT), 0); - return; - case KVAL(K_P7): - k_fn(vc, KVAL(K_FIND), 0); - return; - case KVAL(K_P8): - k_cur(vc, KVAL(K_UP), 0); - return; - case KVAL(K_P9): - k_fn(vc, KVAL(K_PGUP), 0); - return; - case KVAL(K_P5): - applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC)); - return; - } - } - - put_queue(vc, pad_chars[value]); - if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) - put_queue(vc, 10); -} - -static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) -{ - int old_state = shift_state; - - if (rep) - return; - /* - * Mimic typewriter: - * a CapsShift key acts like Shift but undoes CapsLock - */ - if (value == KVAL(K_CAPSSHIFT)) { - value = KVAL(K_SHIFT); - if (!up_flag) - clr_vc_kbd_led(kbd, VC_CAPSLOCK); - } - - if (up_flag) { - /* - * handle the case that two shift or control - * keys are depressed simultaneously - */ - if (shift_down[value]) - shift_down[value]--; - } else - shift_down[value]++; - - if (shift_down[value]) - shift_state |= (1 << value); - else - shift_state &= ~(1 << value); - - /* kludge */ - if (up_flag && shift_state != old_state && npadch != -1) { - if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, npadch); - else - put_queue(vc, npadch & 0xff); - npadch = -1; - } -} - -static void k_meta(struct vc_data *vc, unsigned char value, char up_flag) -{ - if (up_flag) - return; - - if (vc_kbd_mode(kbd, VC_META)) { - put_queue(vc, '\033'); - put_queue(vc, value); - } else - put_queue(vc, value | 0x80); -} - -static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) -{ - int base; - - if (up_flag) - return; - - if (value < 10) { - /* decimal input of code, while Alt depressed */ - base = 10; - } else { - /* hexadecimal input of code, while AltGr depressed */ - value -= 10; - base = 16; - } - - if (npadch == -1) - npadch = value; - else - npadch = npadch * base + value; -} - -static void k_lock(struct vc_data *vc, unsigned char value, char up_flag) -{ - if (up_flag || rep) - return; - - chg_vc_kbd_lock(kbd, value); -} - -static void k_slock(struct vc_data *vc, unsigned char value, char up_flag) -{ - k_shift(vc, value, up_flag); - if (up_flag || rep) - return; - - chg_vc_kbd_slock(kbd, value); - /* try to make Alt, oops, AltGr and such work */ - if (!key_maps[kbd->lockstate ^ kbd->slockstate]) { - kbd->slockstate = 0; - chg_vc_kbd_slock(kbd, value); - } -} - -/* by default, 300ms interval for combination release */ -static unsigned brl_timeout = 300; -MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)"); -module_param(brl_timeout, uint, 0644); - -static unsigned brl_nbchords = 1; -MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)"); -module_param(brl_nbchords, uint, 0644); - -static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag) -{ - static unsigned long chords; - static unsigned committed; - - if (!brl_nbchords) - k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag); - else { - committed |= pattern; - chords++; - if (chords == brl_nbchords) { - k_unicode(vc, BRL_UC_ROW | committed, up_flag); - chords = 0; - committed = 0; - } - } -} - -static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) -{ - static unsigned pressed, committing; - static unsigned long releasestart; - - if (kbd->kbdmode != VC_UNICODE) { - if (!up_flag) - pr_warning("keyboard mode must be unicode for braille patterns\n"); - return; - } - - if (!value) { - k_unicode(vc, BRL_UC_ROW, up_flag); - return; - } - - if (value > 8) - return; - - if (!up_flag) { - pressed |= 1 << (value - 1); - if (!brl_timeout) - committing = pressed; - } else if (brl_timeout) { - if (!committing || - time_after(jiffies, - releasestart + msecs_to_jiffies(brl_timeout))) { - committing = pressed; - releasestart = jiffies; - } - pressed &= ~(1 << (value - 1)); - if (!pressed && committing) { - k_brlcommit(vc, committing, 0); - committing = 0; - } - } else { - if (committing) { - k_brlcommit(vc, committing, 0); - committing = 0; - } - pressed &= ~(1 << (value - 1)); - } -} - -/* - * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, - * or (ii) whatever pattern of lights people want to show using KDSETLED, - * or (iii) specified bits of specified words in kernel memory. - */ -unsigned char getledstate(void) -{ - return ledstate; -} - -void setledstate(struct kbd_struct *kbd, unsigned int led) -{ - if (!(led & ~7)) { - ledioctl = led; - kbd->ledmode = LED_SHOW_IOCTL; - } else - kbd->ledmode = LED_SHOW_FLAGS; - - set_leds(); -} - -static inline unsigned char getleds(void) -{ - struct kbd_struct *kbd = kbd_table + fg_console; - unsigned char leds; - int i; - - if (kbd->ledmode == LED_SHOW_IOCTL) - return ledioctl; - - leds = kbd->ledflagstate; - - if (kbd->ledmode == LED_SHOW_MEM) { - for (i = 0; i < 3; i++) - if (ledptrs[i].valid) { - if (*ledptrs[i].addr & ledptrs[i].mask) - leds |= (1 << i); - else - leds &= ~(1 << i); - } - } - return leds; -} - -static int kbd_update_leds_helper(struct input_handle *handle, void *data) -{ - unsigned char leds = *(unsigned char *)data; - - if (test_bit(EV_LED, handle->dev->evbit)) { - input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); - input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); - input_inject_event(handle, EV_SYN, SYN_REPORT, 0); - } - - return 0; -} - -/* - * This is the tasklet that updates LED state on all keyboards - * attached to the box. The reason we use tasklet is that we - * need to handle the scenario when keyboard handler is not - * registered yet but we already getting updates form VT to - * update led state. - */ -static void kbd_bh(unsigned long dummy) -{ - unsigned char leds = getleds(); - - if (leds != ledstate) { - input_handler_for_each_handle(&kbd_handler, &leds, - kbd_update_leds_helper); - ledstate = leds; - } -} - -DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); - -#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\ - defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\ - defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\ - (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\ - defined(CONFIG_AVR32) - -#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ - ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) - -static const unsigned short x86_keycodes[256] = - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92, - 284,285,309, 0,312, 91,327,328,329,331,333,335,336,337,338,339, - 367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349, - 360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355, - 103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361, - 291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114, - 264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116, - 377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307, - 308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330, - 332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 }; - -#ifdef CONFIG_SPARC -static int sparc_l1_a_state; -extern void sun_do_break(void); -#endif - -static int emulate_raw(struct vc_data *vc, unsigned int keycode, - unsigned char up_flag) -{ - int code; - - switch (keycode) { - - case KEY_PAUSE: - put_queue(vc, 0xe1); - put_queue(vc, 0x1d | up_flag); - put_queue(vc, 0x45 | up_flag); - break; - - case KEY_HANGEUL: - if (!up_flag) - put_queue(vc, 0xf2); - break; - - case KEY_HANJA: - if (!up_flag) - put_queue(vc, 0xf1); - break; - - case KEY_SYSRQ: - /* - * Real AT keyboards (that's what we're trying - * to emulate here emit 0xe0 0x2a 0xe0 0x37 when - * pressing PrtSc/SysRq alone, but simply 0x54 - * when pressing Alt+PrtSc/SysRq. - */ - if (test_bit(KEY_LEFTALT, key_down) || - test_bit(KEY_RIGHTALT, key_down)) { - put_queue(vc, 0x54 | up_flag); - } else { - put_queue(vc, 0xe0); - put_queue(vc, 0x2a | up_flag); - put_queue(vc, 0xe0); - put_queue(vc, 0x37 | up_flag); - } - break; - - default: - if (keycode > 255) - return -1; - - code = x86_keycodes[keycode]; - if (!code) - return -1; - - if (code & 0x100) - put_queue(vc, 0xe0); - put_queue(vc, (code & 0x7f) | up_flag); - - break; - } - - return 0; -} - -#else - -#define HW_RAW(dev) 0 - -static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) -{ - if (keycode > 127) - return -1; - - put_queue(vc, keycode | up_flag); - return 0; -} -#endif - -static void kbd_rawcode(unsigned char data) -{ - struct vc_data *vc = vc_cons[fg_console].d; - - kbd = kbd_table + vc->vc_num; - if (kbd->kbdmode == VC_RAW) - put_queue(vc, data); -} - -static void kbd_keycode(unsigned int keycode, int down, int hw_raw) -{ - struct vc_data *vc = vc_cons[fg_console].d; - unsigned short keysym, *key_map; - unsigned char type; - bool raw_mode; - struct tty_struct *tty; - int shift_final; - struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down }; - int rc; - - tty = vc->port.tty; - - if (tty && (!tty->driver_data)) { - /* No driver data? Strange. Okay we fix it then. */ - tty->driver_data = vc; - } - - kbd = kbd_table + vc->vc_num; - -#ifdef CONFIG_SPARC - if (keycode == KEY_STOP) - sparc_l1_a_state = down; -#endif - - rep = (down == 2); - - raw_mode = (kbd->kbdmode == VC_RAW); - if (raw_mode && !hw_raw) - if (emulate_raw(vc, keycode, !down << 7)) - if (keycode < BTN_MISC && printk_ratelimit()) - pr_warning("can't emulate rawmode for keycode %d\n", - keycode); - -#ifdef CONFIG_SPARC - if (keycode == KEY_A && sparc_l1_a_state) { - sparc_l1_a_state = false; - sun_do_break(); - } -#endif - - if (kbd->kbdmode == VC_MEDIUMRAW) { - /* - * This is extended medium raw mode, with keys above 127 - * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing - * the 'up' flag if needed. 0 is reserved, so this shouldn't - * interfere with anything else. The two bytes after 0 will - * always have the up flag set not to interfere with older - * applications. This allows for 16384 different keycodes, - * which should be enough. - */ - if (keycode < 128) { - put_queue(vc, keycode | (!down << 7)); - } else { - put_queue(vc, !down << 7); - put_queue(vc, (keycode >> 7) | 0x80); - put_queue(vc, keycode | 0x80); - } - raw_mode = true; - } - - if (down) - set_bit(keycode, key_down); - else - clear_bit(keycode, key_down); - - if (rep && - (!vc_kbd_mode(kbd, VC_REPEAT) || - (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) { - /* - * Don't repeat a key if the input buffers are not empty and the - * characters get aren't echoed locally. This makes key repeat - * usable with slow applications and under heavy loads. - */ - return; - } - - param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate; - param.ledstate = kbd->ledflagstate; - key_map = key_maps[shift_final]; - - rc = atomic_notifier_call_chain(&keyboard_notifier_list, - KBD_KEYCODE, ¶m); - if (rc == NOTIFY_STOP || !key_map) { - atomic_notifier_call_chain(&keyboard_notifier_list, - KBD_UNBOUND_KEYCODE, ¶m); - compute_shiftstate(); - kbd->slockstate = 0; - return; - } - - if (keycode < NR_KEYS) - keysym = key_map[keycode]; - else if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8) - keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1)); - else - return; - - type = KTYP(keysym); - - if (type < 0xf0) { - param.value = keysym; - rc = atomic_notifier_call_chain(&keyboard_notifier_list, - KBD_UNICODE, ¶m); - if (rc != NOTIFY_STOP) - if (down && !raw_mode) - to_utf8(vc, keysym); - return; - } - - type -= 0xf0; - - if (type == KT_LETTER) { - type = KT_LATIN; - if (vc_kbd_led(kbd, VC_CAPSLOCK)) { - key_map = key_maps[shift_final ^ (1 << KG_SHIFT)]; - if (key_map) - keysym = key_map[keycode]; - } - } - - param.value = keysym; - rc = atomic_notifier_call_chain(&keyboard_notifier_list, - KBD_KEYSYM, ¶m); - if (rc == NOTIFY_STOP) - return; - - if (raw_mode && type != KT_SPEC && type != KT_SHIFT) - return; - - (*k_handler[type])(vc, keysym & 0xff, !down); - - param.ledstate = kbd->ledflagstate; - atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, ¶m); - - if (type != KT_SLOCK) - kbd->slockstate = 0; -} - -static void kbd_event(struct input_handle *handle, unsigned int event_type, - unsigned int event_code, int value) -{ - /* We are called with interrupts disabled, just take the lock */ - spin_lock(&kbd_event_lock); - - if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) - kbd_rawcode(value); - if (event_type == EV_KEY) - kbd_keycode(event_code, value, HW_RAW(handle->dev)); - - spin_unlock(&kbd_event_lock); - - tasklet_schedule(&keyboard_tasklet); - do_poke_blanked_console = 1; - schedule_console_callback(); -} - -static bool kbd_match(struct input_handler *handler, struct input_dev *dev) -{ - int i; - - if (test_bit(EV_SND, dev->evbit)) - return true; - - if (test_bit(EV_KEY, dev->evbit)) { - for (i = KEY_RESERVED; i < BTN_MISC; i++) - if (test_bit(i, dev->keybit)) - return true; - for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++) - if (test_bit(i, dev->keybit)) - return true; - } - - return false; -} - -/* - * When a keyboard (or other input device) is found, the kbd_connect - * function is called. The function then looks at the device, and if it - * likes it, it can open it and get events from it. In this (kbd_connect) - * function, we should decide which VT to bind that keyboard to initially. - */ -static int kbd_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) -{ - struct input_handle *handle; - int error; - - handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); - if (!handle) - return -ENOMEM; - - handle->dev = dev; - handle->handler = handler; - handle->name = "kbd"; - - error = input_register_handle(handle); - if (error) - goto err_free_handle; - - error = input_open_device(handle); - if (error) - goto err_unregister_handle; - - return 0; - - err_unregister_handle: - input_unregister_handle(handle); - err_free_handle: - kfree(handle); - return error; -} - -static void kbd_disconnect(struct input_handle *handle) -{ - input_close_device(handle); - input_unregister_handle(handle); - kfree(handle); -} - -/* - * Start keyboard handler on the new keyboard by refreshing LED state to - * match the rest of the system. - */ -static void kbd_start(struct input_handle *handle) -{ - tasklet_disable(&keyboard_tasklet); - - if (ledstate != 0xff) - kbd_update_leds_helper(handle, &ledstate); - - tasklet_enable(&keyboard_tasklet); -} - -static const struct input_device_id kbd_ids[] = { - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT, - .evbit = { BIT_MASK(EV_KEY) }, - }, - - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT, - .evbit = { BIT_MASK(EV_SND) }, - }, - - { }, /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(input, kbd_ids); - -static struct input_handler kbd_handler = { - .event = kbd_event, - .match = kbd_match, - .connect = kbd_connect, - .disconnect = kbd_disconnect, - .start = kbd_start, - .name = "kbd", - .id_table = kbd_ids, -}; - -int __init kbd_init(void) -{ - int i; - int error; - - for (i = 0; i < MAX_NR_CONSOLES; i++) { - kbd_table[i].ledflagstate = KBD_DEFLEDS; - kbd_table[i].default_ledflagstate = KBD_DEFLEDS; - kbd_table[i].ledmode = LED_SHOW_FLAGS; - kbd_table[i].lockstate = KBD_DEFLOCK; - kbd_table[i].slockstate = 0; - kbd_table[i].modeflags = KBD_DEFMODE; - kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; - } - - error = input_register_handler(&kbd_handler); - if (error) - return error; - - tasklet_enable(&keyboard_tasklet); - tasklet_schedule(&keyboard_tasklet); - - return 0; -} diff --git a/drivers/char/selection.c b/drivers/char/selection.c deleted file mode 100644 index ebae344..0000000 --- a/drivers/char/selection.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * linux/drivers/char/selection.c - * - * This module exports the functions: - * - * 'int set_selection(struct tiocl_selection __user *, struct tty_struct *)' - * 'void clear_selection(void)' - * 'int paste_selection(struct tty_struct *)' - * 'int sel_loadlut(char __user *)' - * - * Now that /dev/vcs exists, most of this can disappear again. - */ - -#include <linux/module.h> -#include <linux/tty.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/types.h> - -#include <asm/uaccess.h> - -#include <linux/kbd_kern.h> -#include <linux/vt_kern.h> -#include <linux/consolemap.h> -#include <linux/selection.h> -#include <linux/tiocl.h> -#include <linux/console.h> -#include <linux/smp_lock.h> - -/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ -#define isspace(c) ((c) == ' ') - -extern void poke_blanked_console(void); - -/* Variables for selection control. */ -/* Use a dynamic buffer, instead of static (Dec 1994) */ -struct vc_data *sel_cons; /* must not be deallocated */ -static int use_unicode; -static volatile int sel_start = -1; /* cleared by clear_selection */ -static int sel_end; -static int sel_buffer_lth; -static char *sel_buffer; - -/* clear_selection, highlight and highlight_pointer can be called - from interrupt (via scrollback/front) */ - -/* set reverse video on characters s-e of console with selection. */ -static inline void highlight(const int s, const int e) -{ - invert_screen(sel_cons, s, e-s+2, 1); -} - -/* use complementary color to show the pointer */ -static inline void highlight_pointer(const int where) -{ - complement_pos(sel_cons, where); -} - -static u16 -sel_pos(int n) -{ - return inverse_translate(sel_cons, screen_glyph(sel_cons, n), - use_unicode); -} - -/* remove the current selection highlight, if any, - from the console holding the selection. */ -void -clear_selection(void) { - highlight_pointer(-1); /* hide the pointer */ - if (sel_start != -1) { - highlight(sel_start, sel_end); - sel_start = -1; - } -} - -/* - * User settable table: what characters are to be considered alphabetic? - * 256 bits - */ -static u32 inwordLut[8]={ - 0x00000000, /* control chars */ - 0x03FF0000, /* digits */ - 0x87FFFFFE, /* uppercase and '_' */ - 0x07FFFFFE, /* lowercase */ - 0x00000000, - 0x00000000, - 0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */ - 0xFF7FFFFF /* latin-1 accented letters, not division sign */ -}; - -static inline int inword(const u16 c) { - return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1); -} - -/* set inwordLut contents. Invoked by ioctl(). */ -int sel_loadlut(char __user *p) -{ - return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0; -} - -/* does screen address p correspond to character at LH/RH edge of screen? */ -static inline int atedge(const int p, int size_row) -{ - return (!(p % size_row) || !((p + 2) % size_row)); -} - -/* constrain v such that v <= u */ -static inline unsigned short limit(const unsigned short v, const unsigned short u) -{ - return (v > u) ? u : v; -} - -/* stores the char in UTF8 and returns the number of bytes used (1-3) */ -static int store_utf8(u16 c, char *p) -{ - if (c < 0x80) { - /* 0******* */ - p[0] = c; - return 1; - } else if (c < 0x800) { - /* 110***** 10****** */ - p[0] = 0xc0 | (c >> 6); - p[1] = 0x80 | (c & 0x3f); - return 2; - } else { - /* 1110**** 10****** 10****** */ - p[0] = 0xe0 | (c >> 12); - p[1] = 0x80 | ((c >> 6) & 0x3f); - p[2] = 0x80 | (c & 0x3f); - return 3; - } -} - -/* set the current selection. Invoked by ioctl() or by kernel code. */ -int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) -{ - struct vc_data *vc = vc_cons[fg_console].d; - int sel_mode, new_sel_start, new_sel_end, spc; - char *bp, *obp; - int i, ps, pe, multiplier; - u16 c; - struct kbd_struct *kbd = kbd_table + fg_console; - - poke_blanked_console(); - - { unsigned short xs, ys, xe, ye; - - if (!access_ok(VERIFY_READ, sel, sizeof(*sel))) - return -EFAULT; - __get_user(xs, &sel->xs); - __get_user(ys, &sel->ys); - __get_user(xe, &sel->xe); - __get_user(ye, &sel->ye); - __get_user(sel_mode, &sel->sel_mode); - xs--; ys--; xe--; ye--; - xs = limit(xs, vc->vc_cols - 1); - ys = limit(ys, vc->vc_rows - 1); - xe = limit(xe, vc->vc_cols - 1); - ye = limit(ye, vc->vc_rows - 1); - ps = ys * vc->vc_size_row + (xs << 1); - pe = ye * vc->vc_size_row + (xe << 1); - - if (sel_mode == TIOCL_SELCLEAR) { - /* useful for screendump without selection highlights */ - clear_selection(); - return 0; - } - - if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT)) { - mouse_report(tty, sel_mode & TIOCL_SELBUTTONMASK, xs, ys); - return 0; - } - } - - if (ps > pe) /* make sel_start <= sel_end */ - { - int tmp = ps; - ps = pe; - pe = tmp; - } - - if (sel_cons != vc_cons[fg_console].d) { - clear_selection(); - sel_cons = vc_cons[fg_console].d; - } - use_unicode = kbd && kbd->kbdmode == VC_UNICODE; - - switch (sel_mode) - { - case TIOCL_SELCHAR: /* character-by-character selection */ - new_sel_start = ps; - new_sel_end = pe; - break; - case TIOCL_SELWORD: /* word-by-word selection */ - spc = isspace(sel_pos(ps)); - for (new_sel_start = ps; ; ps -= 2) - { - if ((spc && !isspace(sel_pos(ps))) || - (!spc && !inword(sel_pos(ps)))) - break; - new_sel_start = ps; - if (!(ps % vc->vc_size_row)) - break; - } - spc = isspace(sel_pos(pe)); - for (new_sel_end = pe; ; pe += 2) - { - if ((spc && !isspace(sel_pos(pe))) || - (!spc && !inword(sel_pos(pe)))) - break; - new_sel_end = pe; - if (!((pe + 2) % vc->vc_size_row)) - break; - } - break; - case TIOCL_SELLINE: /* line-by-line selection */ - new_sel_start = ps - ps % vc->vc_size_row; - new_sel_end = pe + vc->vc_size_row - - pe % vc->vc_size_row - 2; - break; - case TIOCL_SELPOINTER: - highlight_pointer(pe); - return 0; - default: - return -EINVAL; - } - - /* remove the pointer */ - highlight_pointer(-1); - - /* select to end of line if on trailing space */ - if (new_sel_end > new_sel_start && - !atedge(new_sel_end, vc->vc_size_row) && - isspace(sel_pos(new_sel_end))) { - for (pe = new_sel_end + 2; ; pe += 2) - if (!isspace(sel_pos(pe)) || - atedge(pe, vc->vc_size_row)) - break; - if (isspace(sel_pos(pe))) - new_sel_end = pe; - } - if (sel_start == -1) /* no current selection */ - highlight(new_sel_start, new_sel_end); - else if (new_sel_start == sel_start) - { - if (new_sel_end == sel_end) /* no action required */ - return 0; - else if (new_sel_end > sel_end) /* extend to right */ - highlight(sel_end + 2, new_sel_end); - else /* contract from right */ - highlight(new_sel_end + 2, sel_end); - } - else if (new_sel_end == sel_end) - { - if (new_sel_start < sel_start) /* extend to left */ - highlight(new_sel_start, sel_start - 2); - else /* contract from left */ - highlight(sel_start, new_sel_start - 2); - } - else /* some other case; start selection from scratch */ - { - clear_selection(); - highlight(new_sel_start, new_sel_end); - } - sel_start = new_sel_start; - sel_end = new_sel_end; - - /* Allocate a new buffer before freeing the old one ... */ - multiplier = use_unicode ? 3 : 1; /* chars can take up to 3 bytes */ - bp = kmalloc(((sel_end-sel_start)/2+1)*multiplier, GFP_KERNEL); - if (!bp) { - printk(KERN_WARNING "selection: kmalloc() failed\n"); - clear_selection(); - return -ENOMEM; - } - kfree(sel_buffer); - sel_buffer = bp; - - obp = bp; - for (i = sel_start; i <= sel_end; i += 2) { - c = sel_pos(i); - if (use_unicode) - bp += store_utf8(c, bp); - else - *bp++ = c; - if (!isspace(c)) - obp = bp; - if (! ((i + 2) % vc->vc_size_row)) { - /* strip trailing blanks from line and add newline, - unless non-space at end of line. */ - if (obp != bp) { - bp = obp; - *bp++ = '\r'; - } - obp = bp; - } - } - sel_buffer_lth = bp - sel_buffer; - return 0; -} - -/* Insert the contents of the selection buffer into the - * queue of the tty associated with the current console. - * Invoked by ioctl(). - */ -int paste_selection(struct tty_struct *tty) -{ - struct vc_data *vc = tty->driver_data; - int pasted = 0; - unsigned int count; - struct tty_ldisc *ld; - DECLARE_WAITQUEUE(wait, current); - - /* always called with BTM from vt_ioctl */ - WARN_ON(!tty_locked()); - - acquire_console_sem(); - poke_blanked_console(); - release_console_sem(); - - ld = tty_ldisc_ref(tty); - if (!ld) { - tty_unlock(); - ld = tty_ldisc_ref_wait(tty); - tty_lock(); - } - - add_wait_queue(&vc->paste_wait, &wait); - while (sel_buffer && sel_buffer_lth > pasted) { - set_current_state(TASK_INTERRUPTIBLE); - if (test_bit(TTY_THROTTLED, &tty->flags)) { - schedule(); - continue; - } - count = sel_buffer_lth - pasted; - count = min(count, tty->receive_room); - tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted, - NULL, count); - pasted += count; - } - remove_wait_queue(&vc->paste_wait, &wait); - __set_current_state(TASK_RUNNING); - - tty_ldisc_deref(ld); - return 0; -} diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c deleted file mode 100644 index 273ab44..0000000 --- a/drivers/char/vc_screen.c +++ /dev/null @@ -1,644 +0,0 @@ -/* - * linux/drivers/char/vc_screen.c - * - * Provide access to virtual console memory. - * /dev/vcs0: the screen as it is being viewed right now (possibly scrolled) - * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63) - * [minor: N] - * - * /dev/vcsaN: idem, but including attributes, and prefixed with - * the 4 bytes lines,columns,x,y (as screendump used to give). - * Attribute/character pair is in native endianity. - * [minor: N+128] - * - * This replaces screendump and part of selection, so that the system - * administrator can control access using file system permissions. - * - * aeb@cwi.nl - efter Friedas begravelse - 950211 - * - * machek@k332.feld.cvut.cz - modified not to send characters to wrong console - * - fixed some fatal off-by-one bugs (0-- no longer == -1 -> looping and looping and looping...) - * - making it shorter - scr_readw are macros which expand in PRETTY long code - */ - -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/errno.h> -#include <linux/tty.h> -#include <linux/interrupt.h> -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/mutex.h> -#include <linux/vt_kern.h> -#include <linux/selection.h> -#include <linux/kbd_kern.h> -#include <linux/console.h> -#include <linux/device.h> -#include <linux/smp_lock.h> -#include <linux/sched.h> -#include <linux/fs.h> -#include <linux/poll.h> -#include <linux/signal.h> -#include <linux/slab.h> -#include <linux/notifier.h> - -#include <asm/uaccess.h> -#include <asm/byteorder.h> -#include <asm/unaligned.h> - -#undef attr -#undef org -#undef addr -#define HEADER_SIZE 4 - -struct vcs_poll_data { - struct notifier_block notifier; - unsigned int cons_num; - bool seen_last_update; - wait_queue_head_t waitq; - struct fasync_struct *fasync; -}; - -static int -vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param) -{ - struct vt_notifier_param *param = _param; - struct vc_data *vc = param->vc; - struct vcs_poll_data *poll = - container_of(nb, struct vcs_poll_data, notifier); - int currcons = poll->cons_num; - - if (code != VT_UPDATE) - return NOTIFY_DONE; - - if (currcons == 0) - currcons = fg_console; - else - currcons--; - if (currcons != vc->vc_num) - return NOTIFY_DONE; - - poll->seen_last_update = false; - wake_up_interruptible(&poll->waitq); - kill_fasync(&poll->fasync, SIGIO, POLL_IN); - return NOTIFY_OK; -} - -static void -vcs_poll_data_free(struct vcs_poll_data *poll) -{ - unregister_vt_notifier(&poll->notifier); - kfree(poll); -} - -static struct vcs_poll_data * -vcs_poll_data_get(struct file *file) -{ - struct vcs_poll_data *poll = file->private_data; - - if (poll) - return poll; - - poll = kzalloc(sizeof(*poll), GFP_KERNEL); - if (!poll) - return NULL; - poll->cons_num = iminor(file->f_path.dentry->d_inode) & 127; - init_waitqueue_head(&poll->waitq); - poll->notifier.notifier_call = vcs_notifier; - if (register_vt_notifier(&poll->notifier) != 0) { - kfree(poll); - return NULL; - } - - /* - * This code may be called either through ->poll() or ->fasync(). - * If we have two threads using the same file descriptor, they could - * both enter this function, both notice that the structure hasn't - * been allocated yet and go ahead allocating it in parallel, but - * only one of them must survive and be shared otherwise we'd leak - * memory with a dangling notifier callback. - */ - spin_lock(&file->f_lock); - if (!file->private_data) { - file->private_data = poll; - } else { - /* someone else raced ahead of us */ - vcs_poll_data_free(poll); - poll = file->private_data; - } - spin_unlock(&file->f_lock); - - return poll; -} - -static int -vcs_size(struct inode *inode) -{ - int size; - int minor = iminor(inode); - int currcons = minor & 127; - struct vc_data *vc; - - if (currcons == 0) - currcons = fg_console; - else - currcons--; - if (!vc_cons_allocated(currcons)) - return -ENXIO; - vc = vc_cons[currcons].d; - - size = vc->vc_rows * vc->vc_cols; - - if (minor & 128) - size = 2*size + HEADER_SIZE; - return size; -} - -static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) -{ - int size; - - mutex_lock(&con_buf_mtx); - size = vcs_size(file->f_path.dentry->d_inode); - switch (orig) { - default: - mutex_unlock(&con_buf_mtx); - return -EINVAL; - case 2: - offset += size; - break; - case 1: - offset += file->f_pos; - case 0: - break; - } - if (offset < 0 || offset > size) { - mutex_unlock(&con_buf_mtx); - return -EINVAL; - } - file->f_pos = offset; - mutex_unlock(&con_buf_mtx); - return file->f_pos; -} - - -static ssize_t -vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) -{ - struct inode *inode = file->f_path.dentry->d_inode; - unsigned int currcons = iminor(inode); - struct vc_data *vc; - struct vcs_poll_data *poll; - long pos; - long viewed, attr, read; - int col, maxcol; - unsigned short *org = NULL; - ssize_t ret; - - mutex_lock(&con_buf_mtx); - - pos = *ppos; - - /* Select the proper current console and verify - * sanity of the situation under the console lock. - */ - acquire_console_sem(); - - attr = (currcons & 128); - currcons = (currcons & 127); - if (currcons == 0) { - currcons = fg_console; - viewed = 1; - } else { - currcons--; - viewed = 0; - } - ret = -ENXIO; - if (!vc_cons_allocated(currcons)) - goto unlock_out; - vc = vc_cons[currcons].d; - - ret = -EINVAL; - if (pos < 0) - goto unlock_out; - poll = file->private_data; - if (count && poll) - poll->seen_last_update = true; - read = 0; - ret = 0; - while (count) { - char *con_buf0, *con_buf_start; - long this_round, size; - ssize_t orig_count; - long p = pos; - - /* Check whether we are above size each round, - * as copy_to_user at the end of this loop - * could sleep. - */ - size = vcs_size(inode); - if (pos >= size) - break; - if (count > size - pos) - count = size - pos; - - this_round = count; - if (this_round > CON_BUF_SIZE) - this_round = CON_BUF_SIZE; - - /* Perform the whole read into the local con_buf. - * Then we can drop the console spinlock and safely - * attempt to move it to userspace. - */ - - con_buf_start = con_buf0 = con_buf; - orig_count = this_round; - maxcol = vc->vc_cols; - if (!attr) { - org = screen_pos(vc, p, viewed); - col = p % maxcol; - p += maxcol - col; - while (this_round-- > 0) { - *con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff); - if (++col == maxcol) { - org = screen_pos(vc, p, viewed); - col = 0; - p += maxcol; - } - } - } else { - if (p < HEADER_SIZE) { - size_t tmp_count; - - con_buf0[0] = (char)vc->vc_rows; - con_buf0[1] = (char)vc->vc_cols; - getconsxy(vc, con_buf0 + 2); - - con_buf_start += p; - this_round += p; - if (this_round > CON_BUF_SIZE) { - this_round = CON_BUF_SIZE; - orig_count = this_round - p; - } - - tmp_count = HEADER_SIZE; - if (tmp_count > this_round) - tmp_count = this_round; - - /* Advance state pointers and move on. */ - this_round -= tmp_count; - p = HEADER_SIZE; - con_buf0 = con_buf + HEADER_SIZE; - /* If this_round >= 0, then p is even... */ - } else if (p & 1) { - /* Skip first byte for output if start address is odd - * Update region sizes up/down depending on free - * space in buffer. - */ - con_buf_start++; - if (this_round < CON_BUF_SIZE) - this_round++; - else - orig_count--; - } - if (this_round > 0) { - unsigned short *tmp_buf = (unsigned short *)con_buf0; - - p -= HEADER_SIZE; - p /= 2; - col = p % maxcol; - - org = screen_pos(vc, p, viewed); - p += maxcol - col; - - /* Buffer has even length, so we can always copy - * character + attribute. We do not copy last byte - * to userspace if this_round is odd. - */ - this_round = (this_round + 1) >> 1; - - while (this_round) { - *tmp_buf++ = vcs_scr_readw(vc, org++); - this_round --; - if (++col == maxcol) { - org = screen_pos(vc, p, viewed); - col = 0; - p += maxcol; - } - } - } - } - - /* Finally, release the console semaphore while we push - * all the data to userspace from our temporary buffer. - * - * AKPM: Even though it's a semaphore, we should drop it because - * the pagefault handling code may want to call printk(). - */ - - release_console_sem(); - ret = copy_to_user(buf, con_buf_start, orig_count); - acquire_console_sem(); - - if (ret) { - read += (orig_count - ret); - ret = -EFAULT; - break; - } - buf += orig_count; - pos += orig_count; - read += orig_count; - count -= orig_count; - } - *ppos += read; - if (read) - ret = read; -unlock_out: - release_console_sem(); - mutex_unlock(&con_buf_mtx); - return ret; -} - -static ssize_t -vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) -{ - struct inode *inode = file->f_path.dentry->d_inode; - unsigned int currcons = iminor(inode); - struct vc_data *vc; - long pos; - long viewed, attr, size, written; - char *con_buf0; - int col, maxcol; - u16 *org0 = NULL, *org = NULL; - size_t ret; - - mutex_lock(&con_buf_mtx); - - pos = *ppos; - - /* Select the proper current console and verify - * sanity of the situation under the console lock. - */ - acquire_console_sem(); - - attr = (currcons & 128); - currcons = (currcons & 127); - - if (currcons == 0) { - currcons = fg_console; - viewed = 1; - } else { - currcons--; - viewed = 0; - } - ret = -ENXIO; - if (!vc_cons_allocated(currcons)) - goto unlock_out; - vc = vc_cons[currcons].d; - - size = vcs_size(inode); - ret = -EINVAL; - if (pos < 0 || pos > size) - goto unlock_out; - if (count > size - pos) - count = size - pos; - written = 0; - while (count) { - long this_round = count; - size_t orig_count; - long p; - - if (this_round > CON_BUF_SIZE) - this_round = CON_BUF_SIZE; - - /* Temporarily drop the console lock so that we can read - * in the write data from userspace safely. - */ - release_console_sem(); - ret = copy_from_user(con_buf, buf, this_round); - acquire_console_sem(); - - if (ret) { - this_round -= ret; - if (!this_round) { - /* Abort loop if no data were copied. Otherwise - * fail with -EFAULT. - */ - if (written) - break; - ret = -EFAULT; - goto unlock_out; - } - } - - /* The vcs_size might have changed while we slept to grab - * the user buffer, so recheck. - * Return data written up to now on failure. - */ - size = vcs_size(inode); - if (pos >= size) - break; - if (this_round > size - pos) - this_round = size - pos; - - /* OK, now actually push the write to the console - * under the lock using the local kernel buffer. - */ - - con_buf0 = con_buf; - orig_count = this_round; - maxcol = vc->vc_cols; - p = pos; - if (!attr) { - org0 = org = screen_pos(vc, p, viewed); - col = p % maxcol; - p += maxcol - col; - - while (this_round > 0) { - unsigned char c = *con_buf0++; - - this_round--; - vcs_scr_writew(vc, - (vcs_scr_readw(vc, org) & 0xff00) | c, org); - org++; - if (++col == maxcol) { - org = screen_pos(vc, p, viewed); - col = 0; - p += maxcol; - } - } - } else { - if (p < HEADER_SIZE) { - char header[HEADER_SIZE]; - - getconsxy(vc, header + 2); - while (p < HEADER_SIZE && this_round > 0) { - this_round--; - header[p++] = *con_buf0++; - } - if (!viewed) - putconsxy(vc, header + 2); - } - p -= HEADER_SIZE; - col = (p/2) % maxcol; - if (this_round > 0) { - org0 = org = screen_pos(vc, p/2, viewed); - if ((p & 1) && this_round > 0) { - char c; - - this_round--; - c = *con_buf0++; -#ifdef __BIG_ENDIAN - vcs_scr_writew(vc, c | - (vcs_scr_readw(vc, org) & 0xff00), org); -#else - vcs_scr_writew(vc, (c << 8) | - (vcs_scr_readw(vc, org) & 0xff), org); -#endif - org++; - p++; - if (++col == maxcol) { - org = screen_pos(vc, p/2, viewed); - col = 0; - } - } - p /= 2; - p += maxcol - col; - } - while (this_round > 1) { - unsigned short w; - - w = get_unaligned(((unsigned short *)con_buf0)); - vcs_scr_writew(vc, w, org++); - con_buf0 += 2; - this_round -= 2; - if (++col == maxcol) { - org = screen_pos(vc, p, viewed); - col = 0; - p += maxcol; - } - } - if (this_round > 0) { - unsigned char c; - - c = *con_buf0++; -#ifdef __BIG_ENDIAN - vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org); -#else - vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org); -#endif - } - } - count -= orig_count; - written += orig_count; - buf += orig_count; - pos += orig_count; - if (org0) - update_region(vc, (unsigned long)(org0), org - org0); - } - *ppos += written; - ret = written; - if (written) - vcs_scr_updated(vc); - -unlock_out: - release_console_sem(); - - mutex_unlock(&con_buf_mtx); - - return ret; -} - -static unsigned int -vcs_poll(struct file *file, poll_table *wait) -{ - struct vcs_poll_data *poll = vcs_poll_data_get(file); - int ret = 0; - - if (poll) { - poll_wait(file, &poll->waitq, wait); - if (!poll->seen_last_update) - ret = POLLIN | POLLRDNORM; - } - return ret; -} - -static int -vcs_fasync(int fd, struct file *file, int on) -{ - struct vcs_poll_data *poll = file->private_data; - - if (!poll) { - /* don't allocate anything if all we want is disable fasync */ - if (!on) - return 0; - poll = vcs_poll_data_get(file); - if (!poll) - return -ENOMEM; - } - - return fasync_helper(fd, file, on, &poll->fasync); -} - -static int -vcs_open(struct inode *inode, struct file *filp) -{ - unsigned int currcons = iminor(inode) & 127; - int ret = 0; - - tty_lock(); - if(currcons && !vc_cons_allocated(currcons-1)) - ret = -ENXIO; - tty_unlock(); - return ret; -} - -static int vcs_release(struct inode *inode, struct file *file) -{ - struct vcs_poll_data *poll = file->private_data; - - if (poll) - vcs_poll_data_free(poll); - return 0; -} - -static const struct file_operations vcs_fops = { - .llseek = vcs_lseek, - .read = vcs_read, - .write = vcs_write, - .poll = vcs_poll, - .fasync = vcs_fasync, - .open = vcs_open, - .release = vcs_release, -}; - -static struct class *vc_class; - -void vcs_make_sysfs(int index) -{ - device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL, - "vcs%u", index + 1); - device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL, - "vcsa%u", index + 1); -} - -void vcs_remove_sysfs(int index) -{ - device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1)); - device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129)); -} - -int __init vcs_init(void) -{ - unsigned int i; - - if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops)) - panic("unable to get major %d for vcs device", VCS_MAJOR); - vc_class = class_create(THIS_MODULE, "vc"); - - device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); - device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); - for (i = 0; i < MIN_NR_CONSOLES; i++) - vcs_make_sysfs(i); - return 0; -} diff --git a/drivers/char/vt.c b/drivers/char/vt.c deleted file mode 100644 index a8ec48e..0000000 --- a/drivers/char/vt.c +++ /dev/null @@ -1,4209 +0,0 @@ -/* - * linux/drivers/char/vt.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* - * Hopefully this will be a rather complete VT102 implementation. - * - * Beeping thanks to John T Kohl. - * - * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics - * Chars, and VT100 enhancements by Peter MacDonald. - * - * Copy and paste function by Andrew Haylett, - * some enhancements by Alessandro Rubini. - * - * Code to check for different video-cards mostly by Galen Hunt, - * <g-hunt@ee.utah.edu> - * - * Rudimentary ISO 10646/Unicode/UTF-8 character set support by - * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>. - * - * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 - * Resizing of consoles, aeb, 940926 - * - * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 - * <poe@daimi.aau.dk> - * - * User-defined bell sound, new setterm control sequences and printk - * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95 - * - * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp> - * - * Merge with the abstract console driver by Geert Uytterhoeven - * <geert@linux-m68k.org>, Jan 1997. - * - * Original m68k console driver modifications by - * - * - Arno Griffioen <arno@usn.nl> - * - David Carter <carter@cs.bris.ac.uk> - * - * The abstract console driver provides a generic interface for a text - * console. It supports VGA text mode, frame buffer based graphical consoles - * and special graphics processors that are only accessible through some - * registers (e.g. a TMS340x0 GSP). - * - * The interface to the hardware is specified using a special structure - * (struct consw) which contains function pointers to console operations - * (see <linux/console.h> for more information). - * - * Support for changeable cursor shape - * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997 - * - * Ported to i386 and con_scrolldelta fixed - * by Emmanuel Marty <core@ggi-project.org>, April 1998 - * - * Resurrected character buffers in videoram plus lots of other trickery - * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998 - * - * Removed old-style timers, introduced console_timer, made timer - * deletion SMP-safe. 17Jun00, Andrew Morton - * - * Removed console_lock, enabled interrupts across all console operations - * 13 March 2001, Andrew Morton - * - * Fixed UTF-8 mode so alternate charset modes always work according - * to control sequences interpreted in do_con_trol function - * preserving backward VT100 semigraphics compatibility, - * malformed UTF sequences represented as sequences of replacement glyphs, - * original codes or '?' as a last resort if replacement glyph is undefined - * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006 - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/sched.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/kd.h> -#include <linux/slab.h> -#include <linux/major.h> -#include <linux/mm.h> -#include <linux/console.h> -#include <linux/init.h> -#include <linux/mutex.h> -#include <linux/vt_kern.h> -#include <linux/selection.h> -#include <linux/smp_lock.h> -#include <linux/tiocl.h> -#include <linux/kbd_kern.h> -#include <linux/consolemap.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/workqueue.h> -#include <linux/pm.h> -#include <linux/font.h> -#include <linux/bitops.h> -#include <linux/notifier.h> -#include <linux/device.h> -#include <linux/io.h> -#include <asm/system.h> -#include <linux/uaccess.h> -#include <linux/kdb.h> -#include <linux/ctype.h> - -#define MAX_NR_CON_DRIVER 16 - -#define CON_DRIVER_FLAG_MODULE 1 -#define CON_DRIVER_FLAG_INIT 2 -#define CON_DRIVER_FLAG_ATTR 4 - -struct con_driver { - const struct consw *con; - const char *desc; - struct device *dev; - int node; - int first; - int last; - int flag; -}; - -static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER]; -const struct consw *conswitchp; - -/* A bitmap for codes <32. A bit of 1 indicates that the code - * corresponding to that bit number invokes some special action - * (such as cursor movement) and should not be displayed as a - * glyph unless the disp_ctrl mode is explicitly enabled. - */ -#define CTRL_ACTION 0x0d00ff81 -#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ - -/* - * Here is the default bell parameters: 750HZ, 1/8th of a second - */ -#define DEFAULT_BELL_PITCH 750 -#define DEFAULT_BELL_DURATION (HZ/8) - -struct vc vc_cons [MAX_NR_CONSOLES]; - -#ifndef VT_SINGLE_DRIVER -static const struct consw *con_driver_map[MAX_NR_CONSOLES]; -#endif - -static int con_open(struct tty_struct *, struct file *); -static void vc_init(struct vc_data *vc, unsigned int rows, - unsigned int cols, int do_clear); -static void gotoxy(struct vc_data *vc, int new_x, int new_y); -static void save_cur(struct vc_data *vc); -static void reset_terminal(struct vc_data *vc, int do_clear); -static void con_flush_chars(struct tty_struct *tty); -static int set_vesa_blanking(char __user *p); -static void set_cursor(struct vc_data *vc); -static void hide_cursor(struct vc_data *vc); -static void console_callback(struct work_struct *ignored); -static void blank_screen_t(unsigned long dummy); -static void set_palette(struct vc_data *vc); - -static int printable; /* Is console ready for printing? */ -int default_utf8 = true; -module_param(default_utf8, int, S_IRUGO | S_IWUSR); -int global_cursor_default = -1; -module_param(global_cursor_default, int, S_IRUGO | S_IWUSR); - -static int cur_default = CUR_DEFAULT; -module_param(cur_default, int, S_IRUGO | S_IWUSR); - -/* - * ignore_poke: don't unblank the screen when things are typed. This is - * mainly for the privacy of braille terminal users. - */ -static int ignore_poke; - -int do_poke_blanked_console; -int console_blanked; - -static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ -static int vesa_off_interval; -static int blankinterval = 10*60; -core_param(consoleblank, blankinterval, int, 0444); - -static DECLARE_WORK(console_work, console_callback); - -/* - * fg_console is the current virtual console, - * last_console is the last used one, - * want_console is the console we want to switch to, - * saved_* variants are for save/restore around kernel debugger enter/leave - */ -int fg_console; -int last_console; -int want_console = -1; -static int saved_fg_console; -static int saved_last_console; -static int saved_want_console; -static int saved_vc_mode; -static int saved_console_blanked; - -/* - * For each existing display, we have a pointer to console currently visible - * on that display, allowing consoles other than fg_console to be refreshed - * appropriately. Unless the low-level driver supplies its own display_fg - * variable, we use this one for the "master display". - */ -static struct vc_data *master_display_fg; - -/* - * Unfortunately, we need to delay tty echo when we're currently writing to the - * console since the code is (and always was) not re-entrant, so we schedule - * all flip requests to process context with schedule-task() and run it from - * console_callback(). - */ - -/* - * For the same reason, we defer scrollback to the console callback. - */ -static int scrollback_delta; - -/* - * Hook so that the power management routines can (un)blank - * the console on our behalf. - */ -int (*console_blank_hook)(int); - -static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0); -static int blank_state; -static int blank_timer_expired; -enum { - blank_off = 0, - blank_normal_wait, - blank_vesa_wait, -}; - -/* - * Notifier list for console events. - */ -static ATOMIC_NOTIFIER_HEAD(vt_notifier_list); - -int register_vt_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&vt_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(register_vt_notifier); - -int unregister_vt_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&vt_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(unregister_vt_notifier); - -static void notify_write(struct vc_data *vc, unsigned int unicode) -{ - struct vt_notifier_param param = { .vc = vc, unicode = unicode }; - atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, ¶m); -} - -static void notify_update(struct vc_data *vc) -{ - struct vt_notifier_param param = { .vc = vc }; - atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, ¶m); -} -/* - * Low-Level Functions - */ - -#define IS_FG(vc) ((vc)->vc_num == fg_console) - -#ifdef VT_BUF_VRAM_ONLY -#define DO_UPDATE(vc) 0 -#else -#define DO_UPDATE(vc) (CON_IS_VISIBLE(vc) && !console_blanked) -#endif - -static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) -{ - unsigned short *p; - - if (!viewed) - p = (unsigned short *)(vc->vc_origin + offset); - else if (!vc->vc_sw->con_screen_pos) - p = (unsigned short *)(vc->vc_visible_origin + offset); - else - p = vc->vc_sw->con_screen_pos(vc, offset); - return p; -} - -/* Called from the keyboard irq path.. */ -static inline void scrolldelta(int lines) -{ - /* FIXME */ - /* scrolldelta needs some kind of consistency lock, but the BKL was - and still is not protecting versus the scheduled back end */ - scrollback_delta += lines; - schedule_console_callback(); -} - -void schedule_console_callback(void) -{ - schedule_work(&console_work); -} - -static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) -{ - unsigned short *d, *s; - - if (t+nr >= b) - nr = b - t - 1; - if (b > vc->vc_rows || t >= b || nr < 1) - return; - if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr)) - return; - d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); - s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); - scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); - scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, - vc->vc_size_row * nr); -} - -static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) -{ - unsigned short *s; - unsigned int step; - - if (t+nr >= b) - nr = b - t - 1; - if (b > vc->vc_rows || t >= b || nr < 1) - return; - if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr)) - return; - s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); - step = vc->vc_cols * nr; - scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row); - scr_memsetw(s, vc->vc_video_erase_char, 2 * step); -} - -static void do_update_region(struct vc_data *vc, unsigned long start, int count) -{ -#ifndef VT_BUF_VRAM_ONLY - unsigned int xx, yy, offset; - u16 *p; - - p = (u16 *) start; - if (!vc->vc_sw->con_getxy) { - offset = (start - vc->vc_origin) / 2; - xx = offset % vc->vc_cols; - yy = offset / vc->vc_cols; - } else { - int nxx, nyy; - start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy); - xx = nxx; yy = nyy; - } - for(;;) { - u16 attrib = scr_readw(p) & 0xff00; - int startx = xx; - u16 *q = p; - while (xx < vc->vc_cols && count) { - if (attrib != (scr_readw(p) & 0xff00)) { - if (p > q) - vc->vc_sw->con_putcs(vc, q, p-q, yy, startx); - startx = xx; - q = p; - attrib = scr_readw(p) & 0xff00; - } - p++; - xx++; - count--; - } - if (p > q) - vc->vc_sw->con_putcs(vc, q, p-q, yy, startx); - if (!count) - break; - xx = 0; - yy++; - if (vc->vc_sw->con_getxy) { - p = (u16 *)start; - start = vc->vc_sw->con_getxy(vc, start, NULL, NULL); - } - } -#endif -} - -void update_region(struct vc_data *vc, unsigned long start, int count) -{ - WARN_CONSOLE_UNLOCKED(); - - if (DO_UPDATE(vc)) { - hide_cursor(vc); - do_update_region(vc, start, count); - set_cursor(vc); - } -} - -/* Structure of attributes is hardware-dependent */ - -static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, - u8 _underline, u8 _reverse, u8 _italic) -{ - if (vc->vc_sw->con_build_attr) - return vc->vc_sw->con_build_attr(vc, _color, _intensity, - _blink, _underline, _reverse, _italic); - -#ifndef VT_BUF_VRAM_ONLY -/* - * ++roman: I completely changed the attribute format for monochrome - * mode (!can_do_color). The formerly used MDA (monochrome display - * adapter) format didn't allow the combination of certain effects. - * Now the attribute is just a bit vector: - * Bit 0..1: intensity (0..2) - * Bit 2 : underline - * Bit 3 : reverse - * Bit 7 : blink - */ - { - u8 a = _color; - if (!vc->vc_can_do_color) - return _intensity | - (_italic ? 2 : 0) | - (_underline ? 4 : 0) | - (_reverse ? 8 : 0) | - (_blink ? 0x80 : 0); - if (_italic) - a = (a & 0xF0) | vc->vc_itcolor; - else if (_underline) - a = (a & 0xf0) | vc->vc_ulcolor; - else if (_intensity == 0) - a = (a & 0xf0) | vc->vc_ulcolor; - if (_reverse) - a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77); - if (_blink) - a ^= 0x80; - if (_intensity == 2) - a ^= 0x08; - if (vc->vc_hi_font_mask == 0x100) - a <<= 1; - return a; - } -#else - return 0; -#endif -} - -static void update_attr(struct vc_data *vc) -{ - vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, - vc->vc_blink, vc->vc_underline, - vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic); - vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' '; -} - -/* Note: inverting the screen twice should revert to the original state */ -void invert_screen(struct vc_data *vc, int offset, int count, int viewed) -{ - unsigned short *p; - - WARN_CONSOLE_UNLOCKED(); - - count /= 2; - p = screenpos(vc, offset, viewed); - if (vc->vc_sw->con_invert_region) - vc->vc_sw->con_invert_region(vc, p, count); -#ifndef VT_BUF_VRAM_ONLY - else { - u16 *q = p; - int cnt = count; - u16 a; - - if (!vc->vc_can_do_color) { - while (cnt--) { - a = scr_readw(q); - a ^= 0x0800; - scr_writew(a, q); - q++; - } - } else if (vc->vc_hi_font_mask == 0x100) { - while (cnt--) { - a = scr_readw(q); - a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); - scr_writew(a, q); - q++; - } - } else { - while (cnt--) { - a = scr_readw(q); - a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); - scr_writew(a, q); - q++; - } - } - } -#endif - if (DO_UPDATE(vc)) - do_update_region(vc, (unsigned long) p, count); -} - -/* used by selection: complement pointer position */ -void complement_pos(struct vc_data *vc, int offset) -{ - static int old_offset = -1; - static unsigned short old; - static unsigned short oldx, oldy; - - WARN_CONSOLE_UNLOCKED(); - - if (old_offset != -1 && old_offset >= 0 && - old_offset < vc->vc_screenbuf_size) { - scr_writew(old, screenpos(vc, old_offset, 1)); - if (DO_UPDATE(vc)) - vc->vc_sw->con_putc(vc, old, oldy, oldx); - } - - old_offset = offset; - - if (offset != -1 && offset >= 0 && - offset < vc->vc_screenbuf_size) { - unsigned short new; - unsigned short *p; - p = screenpos(vc, offset, 1); - old = scr_readw(p); - new = old ^ vc->vc_complement_mask; - scr_writew(new, p); - if (DO_UPDATE(vc)) { - oldx = (offset >> 1) % vc->vc_cols; - oldy = (offset >> 1) / vc->vc_cols; - vc->vc_sw->con_putc(vc, new, oldy, oldx); - } - } - -} - -static void insert_char(struct vc_data *vc, unsigned int nr) -{ - unsigned short *p, *q = (unsigned short *)vc->vc_pos; - - p = q + vc->vc_cols - nr - vc->vc_x; - while (--p >= q) - scr_writew(scr_readw(p), p + nr); - scr_memsetw(q, vc->vc_video_erase_char, nr * 2); - vc->vc_need_wrap = 0; - if (DO_UPDATE(vc)) { - unsigned short oldattr = vc->vc_attr; - vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1, - vc->vc_cols - vc->vc_x - nr); - vc->vc_attr = vc->vc_video_erase_char >> 8; - while (nr--) - vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr); - vc->vc_attr = oldattr; - } -} - -static void delete_char(struct vc_data *vc, unsigned int nr) -{ - unsigned int i = vc->vc_x; - unsigned short *p = (unsigned short *)vc->vc_pos; - - while (++i <= vc->vc_cols - nr) { - scr_writew(scr_readw(p+nr), p); - p++; - } - scr_memsetw(p, vc->vc_video_erase_char, nr * 2); - vc->vc_need_wrap = 0; - if (DO_UPDATE(vc)) { - unsigned short oldattr = vc->vc_attr; - vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1, - vc->vc_cols - vc->vc_x - nr); - vc->vc_attr = vc->vc_video_erase_char >> 8; - while (nr--) - vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, - vc->vc_cols - 1 - nr); - vc->vc_attr = oldattr; - } -} - -static int softcursor_original; - -static void add_softcursor(struct vc_data *vc) -{ - int i = scr_readw((u16 *) vc->vc_pos); - u32 type = vc->vc_cursor_type; - - if (! (type & 0x10)) return; - if (softcursor_original != -1) return; - softcursor_original = i; - i |= ((type >> 8) & 0xff00 ); - i ^= ((type) & 0xff00 ); - if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000; - if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; - scr_writew(i, (u16 *) vc->vc_pos); - if (DO_UPDATE(vc)) - vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x); -} - -static void hide_softcursor(struct vc_data *vc) -{ - if (softcursor_original != -1) { - scr_writew(softcursor_original, (u16 *)vc->vc_pos); - if (DO_UPDATE(vc)) - vc->vc_sw->con_putc(vc, softcursor_original, - vc->vc_y, vc->vc_x); - softcursor_original = -1; - } -} - -static void hide_cursor(struct vc_data *vc) -{ - if (vc == sel_cons) - clear_selection(); - vc->vc_sw->con_cursor(vc, CM_ERASE); - hide_softcursor(vc); -} - -static void set_cursor(struct vc_data *vc) -{ - if (!IS_FG(vc) || console_blanked || - vc->vc_mode == KD_GRAPHICS) - return; - if (vc->vc_deccm) { - if (vc == sel_cons) - clear_selection(); - add_softcursor(vc); - if ((vc->vc_cursor_type & 0x0f) != 1) - vc->vc_sw->con_cursor(vc, CM_DRAW); - } else - hide_cursor(vc); -} - -static void set_origin(struct vc_data *vc) -{ - WARN_CONSOLE_UNLOCKED(); - - if (!CON_IS_VISIBLE(vc) || - !vc->vc_sw->con_set_origin || - !vc->vc_sw->con_set_origin(vc)) - vc->vc_origin = (unsigned long)vc->vc_screenbuf; - vc->vc_visible_origin = vc->vc_origin; - vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size; - vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x; -} - -static inline void save_screen(struct vc_data *vc) -{ - WARN_CONSOLE_UNLOCKED(); - - if (vc->vc_sw->con_save_screen) - vc->vc_sw->con_save_screen(vc); -} - -/* - * Redrawing of screen - */ - -static void clear_buffer_attributes(struct vc_data *vc) -{ - unsigned short *p = (unsigned short *)vc->vc_origin; - int count = vc->vc_screenbuf_size / 2; - int mask = vc->vc_hi_font_mask | 0xff; - - for (; count > 0; count--, p++) { - scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p); - } -} - -void redraw_screen(struct vc_data *vc, int is_switch) -{ - int redraw = 0; - - WARN_CONSOLE_UNLOCKED(); - - if (!vc) { - /* strange ... */ - /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */ - return; - } - - if (is_switch) { - struct vc_data *old_vc = vc_cons[fg_console].d; - if (old_vc == vc) - return; - if (!CON_IS_VISIBLE(vc)) - redraw = 1; - *vc->vc_display_fg = vc; - fg_console = vc->vc_num; - hide_cursor(old_vc); - if (!CON_IS_VISIBLE(old_vc)) { - save_screen(old_vc); - set_origin(old_vc); - } - } else { - hide_cursor(vc); - redraw = 1; - } - - if (redraw) { - int update; - int old_was_color = vc->vc_can_do_color; - - set_origin(vc); - update = vc->vc_sw->con_switch(vc); - set_palette(vc); - /* - * If console changed from mono<->color, the best we can do - * is to clear the buffer attributes. As it currently stands, - * rebuilding new attributes from the old buffer is not doable - * without overly complex code. - */ - if (old_was_color != vc->vc_can_do_color) { - update_attr(vc); - clear_buffer_attributes(vc); - } - - /* Forcibly update if we're panicing */ - if ((update && vc->vc_mode != KD_GRAPHICS) || - vt_force_oops_output(vc)) - do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2); - } - set_cursor(vc); - if (is_switch) { - set_leds(); - compute_shiftstate(); - notify_update(vc); - } -} - -/* - * Allocation, freeing and resizing of VTs. - */ - -int vc_cons_allocated(unsigned int i) -{ - return (i < MAX_NR_CONSOLES && vc_cons[i].d); -} - -static void visual_init(struct vc_data *vc, int num, int init) -{ - /* ++Geert: vc->vc_sw->con_init determines console size */ - if (vc->vc_sw) - module_put(vc->vc_sw->owner); - vc->vc_sw = conswitchp; -#ifndef VT_SINGLE_DRIVER - if (con_driver_map[num]) - vc->vc_sw = con_driver_map[num]; -#endif - __module_get(vc->vc_sw->owner); - vc->vc_num = num; - vc->vc_display_fg = &master_display_fg; - vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir; - vc->vc_uni_pagedir = 0; - vc->vc_hi_font_mask = 0; - vc->vc_complement_mask = 0; - vc->vc_can_do_color = 0; - vc->vc_panic_force_write = false; - vc->vc_sw->con_init(vc, init); - if (!vc->vc_complement_mask) - vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; - vc->vc_s_complement_mask = vc->vc_complement_mask; - vc->vc_size_row = vc->vc_cols << 1; - vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row; -} - -int vc_allocate(unsigned int currcons) /* return 0 on success */ -{ - WARN_CONSOLE_UNLOCKED(); - - if (currcons >= MAX_NR_CONSOLES) - return -ENXIO; - if (!vc_cons[currcons].d) { - struct vc_data *vc; - struct vt_notifier_param param; - - /* prevent users from taking too much memory */ - if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) - return -EPERM; - - /* due to the granularity of kmalloc, we waste some memory here */ - /* the alloc is done in two steps, to optimize the common situation - of a 25x80 console (structsize=216, screenbuf_size=4000) */ - /* although the numbers above are not valid since long ago, the - point is still up-to-date and the comment still has its value - even if only as a historical artifact. --mj, July 1998 */ - param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL); - if (!vc) - return -ENOMEM; - vc_cons[currcons].d = vc; - tty_port_init(&vc->port); - INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); - visual_init(vc, currcons, 1); - if (!*vc->vc_uni_pagedir_loc) - con_set_default_unimap(vc); - vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); - if (!vc->vc_screenbuf) { - kfree(vc); - vc_cons[currcons].d = NULL; - return -ENOMEM; - } - - /* If no drivers have overridden us and the user didn't pass a - boot option, default to displaying the cursor */ - if (global_cursor_default == -1) - global_cursor_default = 1; - - vc_init(vc, vc->vc_rows, vc->vc_cols, 1); - vcs_make_sysfs(currcons); - atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, ¶m); - } - return 0; -} - -static inline int resize_screen(struct vc_data *vc, int width, int height, - int user) -{ - /* Resizes the resolution of the display adapater */ - int err = 0; - - if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize) - err = vc->vc_sw->con_resize(vc, width, height, user); - - return err; -} - -/* - * Change # of rows and columns (0 means unchanged/the size of fg_console) - * [this is to be used together with some user program - * like resize that changes the hardware videomode] - */ -#define VC_RESIZE_MAXCOL (32767) -#define VC_RESIZE_MAXROW (32767) - -/** - * vc_do_resize - resizing method for the tty - * @tty: tty being resized - * @real_tty: real tty (different to tty if a pty/tty pair) - * @vc: virtual console private data - * @cols: columns - * @lines: lines - * - * Resize a virtual console, clipping according to the actual constraints. - * If the caller passes a tty structure then update the termios winsize - * information and perform any necessary signal handling. - * - * Caller must hold the console semaphore. Takes the termios mutex and - * ctrl_lock of the tty IFF a tty is passed. - */ - -static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, - unsigned int cols, unsigned int lines) -{ - unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; - unsigned long end; - unsigned int old_cols, old_rows, old_row_size, old_screen_size; - unsigned int new_cols, new_rows, new_row_size, new_screen_size; - unsigned int user; - unsigned short *newscreen; - - WARN_CONSOLE_UNLOCKED(); - - if (!vc) - return -ENXIO; - - user = vc->vc_resize_user; - vc->vc_resize_user = 0; - - if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) - return -EINVAL; - - new_cols = (cols ? cols : vc->vc_cols); - new_rows = (lines ? lines : vc->vc_rows); - new_row_size = new_cols << 1; - new_screen_size = new_row_size * new_rows; - - if (new_cols == vc->vc_cols && new_rows == vc->vc_rows) - return 0; - - newscreen = kmalloc(new_screen_size, GFP_USER); - if (!newscreen) - return -ENOMEM; - - old_rows = vc->vc_rows; - old_cols = vc->vc_cols; - old_row_size = vc->vc_size_row; - old_screen_size = vc->vc_screenbuf_size; - - err = resize_screen(vc, new_cols, new_rows, user); - if (err) { - kfree(newscreen); - return err; - } - - vc->vc_rows = new_rows; - vc->vc_cols = new_cols; - vc->vc_size_row = new_row_size; - vc->vc_screenbuf_size = new_screen_size; - - rlth = min(old_row_size, new_row_size); - rrem = new_row_size - rlth; - old_origin = vc->vc_origin; - new_origin = (long) newscreen; - new_scr_end = new_origin + new_screen_size; - - if (vc->vc_y > new_rows) { - if (old_rows - vc->vc_y < new_rows) { - /* - * Cursor near the bottom, copy contents from the - * bottom of buffer - */ - old_origin += (old_rows - new_rows) * old_row_size; - } else { - /* - * Cursor is in no man's land, copy 1/2 screenful - * from the top and bottom of cursor position - */ - old_origin += (vc->vc_y - new_rows/2) * old_row_size; - } - } - - end = old_origin + old_row_size * min(old_rows, new_rows); - - update_attr(vc); - - while (old_origin < end) { - scr_memcpyw((unsigned short *) new_origin, - (unsigned short *) old_origin, rlth); - if (rrem) - scr_memsetw((void *)(new_origin + rlth), - vc->vc_video_erase_char, rrem); - old_origin += old_row_size; - new_origin += new_row_size; - } - if (new_scr_end > new_origin) - scr_memsetw((void *)new_origin, vc->vc_video_erase_char, - new_scr_end - new_origin); - kfree(vc->vc_screenbuf); - vc->vc_screenbuf = newscreen; - vc->vc_screenbuf_size = new_screen_size; - set_origin(vc); - - /* do part of a reset_terminal() */ - vc->vc_top = 0; - vc->vc_bottom = vc->vc_rows; - gotoxy(vc, vc->vc_x, vc->vc_y); - save_cur(vc); - - if (tty) { - /* Rewrite the requested winsize data with the actual - resulting sizes */ - struct winsize ws; - memset(&ws, 0, sizeof(ws)); - ws.ws_row = vc->vc_rows; - ws.ws_col = vc->vc_cols; - ws.ws_ypixel = vc->vc_scan_lines; - tty_do_resize(tty, &ws); - } - - if (CON_IS_VISIBLE(vc)) - update_screen(vc); - vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num); - return err; -} - -/** - * vc_resize - resize a VT - * @vc: virtual console - * @cols: columns - * @rows: rows - * - * Resize a virtual console as seen from the console end of things. We - * use the common vc_do_resize methods to update the structures. The - * caller must hold the console sem to protect console internals and - * vc->port.tty - */ - -int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows) -{ - return vc_do_resize(vc->port.tty, vc, cols, rows); -} - -/** - * vt_resize - resize a VT - * @tty: tty to resize - * @ws: winsize attributes - * - * Resize a virtual terminal. This is called by the tty layer as we - * register our own handler for resizing. The mutual helper does all - * the actual work. - * - * Takes the console sem and the called methods then take the tty - * termios_mutex and the tty ctrl_lock in that order. - */ -static int vt_resize(struct tty_struct *tty, struct winsize *ws) -{ - struct vc_data *vc = tty->driver_data; - int ret; - - acquire_console_sem(); - ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row); - release_console_sem(); - return ret; -} - -void vc_deallocate(unsigned int currcons) -{ - WARN_CONSOLE_UNLOCKED(); - - if (vc_cons_allocated(currcons)) { - struct vc_data *vc = vc_cons[currcons].d; - struct vt_notifier_param param = { .vc = vc }; - - atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, ¶m); - vcs_remove_sysfs(currcons); - vc->vc_sw->con_deinit(vc); - put_pid(vc->vt_pid); - module_put(vc->vc_sw->owner); - kfree(vc->vc_screenbuf); - if (currcons >= MIN_NR_CONSOLES) - kfree(vc); - vc_cons[currcons].d = NULL; - } -} - -/* - * VT102 emulator - */ - -#define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) -#define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) -#define is_kbd(vc, x) vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) - -#define decarm VC_REPEAT -#define decckm VC_CKMODE -#define kbdapplic VC_APPLIC -#define lnm VC_CRLF - -/* - * this is what the terminal answers to a ESC-Z or csi0c query. - */ -#define VT100ID "\033[?1;2c" -#define VT102ID "\033[?6c" - -unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, - 8,12,10,14, 9,13,11,15 }; - -/* the default colour table, for VGA+ colour systems */ -int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, - 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; -int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, - 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; -int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, - 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; - -module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR); -module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR); -module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR); - -/* - * gotoxy() must verify all boundaries, because the arguments - * might also be negative. If the given position is out of - * bounds, the cursor is placed at the nearest margin. - */ -static void gotoxy(struct vc_data *vc, int new_x, int new_y) -{ - int min_y, max_y; - - if (new_x < 0) - vc->vc_x = 0; - else { - if (new_x >= vc->vc_cols) - vc->vc_x = vc->vc_cols - 1; - else - vc->vc_x = new_x; - } - - if (vc->vc_decom) { - min_y = vc->vc_top; - max_y = vc->vc_bottom; - } else { - min_y = 0; - max_y = vc->vc_rows; - } - if (new_y < min_y) - vc->vc_y = min_y; - else if (new_y >= max_y) - vc->vc_y = max_y - 1; - else - vc->vc_y = new_y; - vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1); - vc->vc_need_wrap = 0; -} - -/* for absolute user moves, when decom is set */ -static void gotoxay(struct vc_data *vc, int new_x, int new_y) -{ - gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y); -} - -void scrollback(struct vc_data *vc, int lines) -{ - if (!lines) - lines = vc->vc_rows / 2; - scrolldelta(-lines); -} - -void scrollfront(struct vc_data *vc, int lines) -{ - if (!lines) - lines = vc->vc_rows / 2; - scrolldelta(lines); -} - -static void lf(struct vc_data *vc) -{ - /* don't scroll if above bottom of scrolling region, or - * if below scrolling region - */ - if (vc->vc_y + 1 == vc->vc_bottom) - scrup(vc, vc->vc_top, vc->vc_bottom, 1); - else if (vc->vc_y < vc->vc_rows - 1) { - vc->vc_y++; - vc->vc_pos += vc->vc_size_row; - } - vc->vc_need_wrap = 0; - notify_write(vc, '\n'); -} - -static void ri(struct vc_data *vc) -{ - /* don't scroll if below top of scrolling region, or - * if above scrolling region - */ - if (vc->vc_y == vc->vc_top) - scrdown(vc, vc->vc_top, vc->vc_bottom, 1); - else if (vc->vc_y > 0) { - vc->vc_y--; - vc->vc_pos -= vc->vc_size_row; - } - vc->vc_need_wrap = 0; -} - -static inline void cr(struct vc_data *vc) -{ - vc->vc_pos -= vc->vc_x << 1; - vc->vc_need_wrap = vc->vc_x = 0; - notify_write(vc, '\r'); -} - -static inline void bs(struct vc_data *vc) -{ - if (vc->vc_x) { - vc->vc_pos -= 2; - vc->vc_x--; - vc->vc_need_wrap = 0; - notify_write(vc, '\b'); - } -} - -static inline void del(struct vc_data *vc) -{ - /* ignored */ -} - -static void csi_J(struct vc_data *vc, int vpar) -{ - unsigned int count; - unsigned short * start; - - switch (vpar) { - case 0: /* erase from cursor to end of display */ - count = (vc->vc_scr_end - vc->vc_pos) >> 1; - start = (unsigned short *)vc->vc_pos; - if (DO_UPDATE(vc)) { - /* do in two stages */ - vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, - vc->vc_cols - vc->vc_x); - vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0, - vc->vc_rows - vc->vc_y - 1, - vc->vc_cols); - } - break; - case 1: /* erase from start to cursor */ - count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1; - start = (unsigned short *)vc->vc_origin; - if (DO_UPDATE(vc)) { - /* do in two stages */ - vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y, - vc->vc_cols); - vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, - vc->vc_x + 1); - } - break; - case 2: /* erase whole display */ - count = vc->vc_cols * vc->vc_rows; - start = (unsigned short *)vc->vc_origin; - if (DO_UPDATE(vc)) - vc->vc_sw->con_clear(vc, 0, 0, - vc->vc_rows, - vc->vc_cols); - break; - default: - return; - } - scr_memsetw(start, vc->vc_video_erase_char, 2 * count); - vc->vc_need_wrap = 0; -} - -static void csi_K(struct vc_data *vc, int vpar) -{ - unsigned int count; - unsigned short * start; - - switch (vpar) { - case 0: /* erase from cursor to end of line */ - count = vc->vc_cols - vc->vc_x; - start = (unsigned short *)vc->vc_pos; - if (DO_UPDATE(vc)) - vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, - vc->vc_cols - vc->vc_x); - break; - case 1: /* erase from start of line to cursor */ - start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); - count = vc->vc_x + 1; - if (DO_UPDATE(vc)) - vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, - vc->vc_x + 1); - break; - case 2: /* erase whole line */ - start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); - count = vc->vc_cols; - if (DO_UPDATE(vc)) - vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, - vc->vc_cols); - break; - default: - return; - } - scr_memsetw(start, vc->vc_video_erase_char, 2 * count); - vc->vc_need_wrap = 0; -} - -static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */ -{ /* not vt100? */ - int count; - - if (!vpar) - vpar++; - count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar; - - scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count); - if (DO_UPDATE(vc)) - vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count); - vc->vc_need_wrap = 0; -} - -static void default_attr(struct vc_data *vc) -{ - vc->vc_intensity = 1; - vc->vc_italic = 0; - vc->vc_underline = 0; - vc->vc_reverse = 0; - vc->vc_blink = 0; - vc->vc_color = vc->vc_def_color; -} - -/* console_sem is held */ -static void csi_m(struct vc_data *vc) -{ - int i; - - for (i = 0; i <= vc->vc_npar; i++) - switch (vc->vc_par[i]) { - case 0: /* all attributes off */ - default_attr(vc); - break; - case 1: - vc->vc_intensity = 2; - break; - case 2: - vc->vc_intensity = 0; - break; - case 3: - vc->vc_italic = 1; - break; - case 4: - vc->vc_underline = 1; - break; - case 5: - vc->vc_blink = 1; - break; - case 7: - vc->vc_reverse = 1; - break; - case 10: /* ANSI X3.64-1979 (SCO-ish?) - * Select primary font, don't display - * control chars if defined, don't set - * bit 8 on output. - */ - vc->vc_translate = set_translate(vc->vc_charset == 0 - ? vc->vc_G0_charset - : vc->vc_G1_charset, vc); - vc->vc_disp_ctrl = 0; - vc->vc_toggle_meta = 0; - break; - case 11: /* ANSI X3.64-1979 (SCO-ish?) - * Select first alternate font, lets - * chars < 32 be displayed as ROM chars. - */ - vc->vc_translate = set_translate(IBMPC_MAP, vc); - vc->vc_disp_ctrl = 1; - vc->vc_toggle_meta = 0; - break; - case 12: /* ANSI X3.64-1979 (SCO-ish?) - * Select second alternate font, toggle - * high bit before displaying as ROM char. - */ - vc->vc_translate = set_translate(IBMPC_MAP, vc); - vc->vc_disp_ctrl = 1; - vc->vc_toggle_meta = 1; - break; - case 21: - case 22: - vc->vc_intensity = 1; - break; - case 23: - vc->vc_italic = 0; - break; - case 24: - vc->vc_underline = 0; - break; - case 25: - vc->vc_blink = 0; - break; - case 27: - vc->vc_reverse = 0; - break; - case 38: /* ANSI X3.64-1979 (SCO-ish?) - * Enables underscore, white foreground - * with white underscore (Linux - use - * default foreground). - */ - vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); - vc->vc_underline = 1; - break; - case 39: /* ANSI X3.64-1979 (SCO-ish?) - * Disable underline option. - * Reset colour to default? It did this - * before... - */ - vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); - vc->vc_underline = 0; - break; - case 49: - vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f); - break; - default: - if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37) - vc->vc_color = color_table[vc->vc_par[i] - 30] - | (vc->vc_color & 0xf0); - else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47) - vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4) - | (vc->vc_color & 0x0f); - break; - } - update_attr(vc); -} - -static void respond_string(const char *p, struct tty_struct *tty) -{ - while (*p) { - tty_insert_flip_char(tty, *p, 0); - p++; - } - con_schedule_flip(tty); -} - -static void cursor_report(struct vc_data *vc, struct tty_struct *tty) -{ - char buf[40]; - - sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1); - respond_string(buf, tty); -} - -static inline void status_report(struct tty_struct *tty) -{ - respond_string("\033[0n", tty); /* Terminal ok */ -} - -static inline void respond_ID(struct tty_struct * tty) -{ - respond_string(VT102ID, tty); -} - -void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry) -{ - char buf[8]; - - sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), - (char)('!' + mry)); - respond_string(buf, tty); -} - -/* invoked via ioctl(TIOCLINUX) and through set_selection */ -int mouse_reporting(void) -{ - return vc_cons[fg_console].d->vc_report_mouse; -} - -/* console_sem is held */ -static void set_mode(struct vc_data *vc, int on_off) -{ - int i; - - for (i = 0; i <= vc->vc_npar; i++) - if (vc->vc_ques) { - switch(vc->vc_par[i]) { /* DEC private modes set/reset */ - case 1: /* Cursor keys send ^[Ox/^[[x */ - if (on_off) - set_kbd(vc, decckm); - else - clr_kbd(vc, decckm); - break; - case 3: /* 80/132 mode switch unimplemented */ - vc->vc_deccolm = on_off; -#if 0 - vc_resize(deccolm ? 132 : 80, vc->vc_rows); - /* this alone does not suffice; some user mode - utility has to change the hardware regs */ -#endif - break; - case 5: /* Inverted screen on/off */ - if (vc->vc_decscnm != on_off) { - vc->vc_decscnm = on_off; - invert_screen(vc, 0, vc->vc_screenbuf_size, 0); - update_attr(vc); - } - break; - case 6: /* Origin relative/absolute */ - vc->vc_decom = on_off; - gotoxay(vc, 0, 0); - break; - case 7: /* Autowrap on/off */ - vc->vc_decawm = on_off; - break; - case 8: /* Autorepeat on/off */ - if (on_off) - set_kbd(vc, decarm); - else - clr_kbd(vc, decarm); - break; - case 9: - vc->vc_report_mouse = on_off ? 1 : 0; - break; - case 25: /* Cursor on/off */ - vc->vc_deccm = on_off; - break; - case 1000: - vc->vc_report_mouse = on_off ? 2 : 0; - break; - } - } else { - switch(vc->vc_par[i]) { /* ANSI modes set/reset */ - case 3: /* Monitor (display ctrls) */ - vc->vc_disp_ctrl = on_off; - break; - case 4: /* Insert Mode on/off */ - vc->vc_decim = on_off; - break; - case 20: /* Lf, Enter == CrLf/Lf */ - if (on_off) - set_kbd(vc, lnm); - else - clr_kbd(vc, lnm); - break; - } - } -} - -/* console_sem is held */ -static void setterm_command(struct vc_data *vc) -{ - switch(vc->vc_par[0]) { - case 1: /* set color for underline mode */ - if (vc->vc_can_do_color && - vc->vc_par[1] < 16) { - vc->vc_ulcolor = color_table[vc->vc_par[1]]; - if (vc->vc_underline) - update_attr(vc); - } - break; - case 2: /* set color for half intensity mode */ - if (vc->vc_can_do_color && - vc->vc_par[1] < 16) { - vc->vc_halfcolor = color_table[vc->vc_par[1]]; - if (vc->vc_intensity == 0) - update_attr(vc); - } - break; - case 8: /* store colors as defaults */ - vc->vc_def_color = vc->vc_attr; - if (vc->vc_hi_font_mask == 0x100) - vc->vc_def_color >>= 1; - default_attr(vc); - update_attr(vc); - break; - case 9: /* set blanking interval */ - blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60; - poke_blanked_console(); - break; - case 10: /* set bell frequency in Hz */ - if (vc->vc_npar >= 1) - vc->vc_bell_pitch = vc->vc_par[1]; - else - vc->vc_bell_pitch = DEFAULT_BELL_PITCH; - break; - case 11: /* set bell duration in msec */ - if (vc->vc_npar >= 1) - vc->vc_bell_duration = (vc->vc_par[1] < 2000) ? - vc->vc_par[1] * HZ / 1000 : 0; - else - vc->vc_bell_duration = DEFAULT_BELL_DURATION; - break; - case 12: /* bring specified console to the front */ - if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1)) - set_console(vc->vc_par[1] - 1); - break; - case 13: /* unblank the screen */ - poke_blanked_console(); - break; - case 14: /* set vesa powerdown interval */ - vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ; - break; - case 15: /* activate the previous console */ - set_console(last_console); - break; - } -} - -/* console_sem is held */ -static void csi_at(struct vc_data *vc, unsigned int nr) -{ - if (nr > vc->vc_cols - vc->vc_x) - nr = vc->vc_cols - vc->vc_x; - else if (!nr) - nr = 1; - insert_char(vc, nr); -} - -/* console_sem is held */ -static void csi_L(struct vc_data *vc, unsigned int nr) -{ - if (nr > vc->vc_rows - vc->vc_y) - nr = vc->vc_rows - vc->vc_y; - else if (!nr) - nr = 1; - scrdown(vc, vc->vc_y, vc->vc_bottom, nr); - vc->vc_need_wrap = 0; -} - -/* console_sem is held */ -static void csi_P(struct vc_data *vc, unsigned int nr) -{ - if (nr > vc->vc_cols - vc->vc_x) - nr = vc->vc_cols - vc->vc_x; - else if (!nr) - nr = 1; - delete_char(vc, nr); -} - -/* console_sem is held */ -static void csi_M(struct vc_data *vc, unsigned int nr) -{ - if (nr > vc->vc_rows - vc->vc_y) - nr = vc->vc_rows - vc->vc_y; - else if (!nr) - nr=1; - scrup(vc, vc->vc_y, vc->vc_bottom, nr); - vc->vc_need_wrap = 0; -} - -/* console_sem is held (except via vc_init->reset_terminal */ -static void save_cur(struct vc_data *vc) -{ - vc->vc_saved_x = vc->vc_x; - vc->vc_saved_y = vc->vc_y; - vc->vc_s_intensity = vc->vc_intensity; - vc->vc_s_italic = vc->vc_italic; - vc->vc_s_underline = vc->vc_underline; - vc->vc_s_blink = vc->vc_blink; - vc->vc_s_reverse = vc->vc_reverse; - vc->vc_s_charset = vc->vc_charset; - vc->vc_s_color = vc->vc_color; - vc->vc_saved_G0 = vc->vc_G0_charset; - vc->vc_saved_G1 = vc->vc_G1_charset; -} - -/* console_sem is held */ -static void restore_cur(struct vc_data *vc) -{ - gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y); - vc->vc_intensity = vc->vc_s_intensity; - vc->vc_italic = vc->vc_s_italic; - vc->vc_underline = vc->vc_s_underline; - vc->vc_blink = vc->vc_s_blink; - vc->vc_reverse = vc->vc_s_reverse; - vc->vc_charset = vc->vc_s_charset; - vc->vc_color = vc->vc_s_color; - vc->vc_G0_charset = vc->vc_saved_G0; - vc->vc_G1_charset = vc->vc_saved_G1; - vc->vc_translate = set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc); - update_attr(vc); - vc->vc_need_wrap = 0; -} - -enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, - EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, - ESpalette }; - -/* console_sem is held (except via vc_init()) */ -static void reset_terminal(struct vc_data *vc, int do_clear) -{ - vc->vc_top = 0; - vc->vc_bottom = vc->vc_rows; - vc->vc_state = ESnormal; - vc->vc_ques = 0; - vc->vc_translate = set_translate(LAT1_MAP, vc); - vc->vc_G0_charset = LAT1_MAP; - vc->vc_G1_charset = GRAF_MAP; - vc->vc_charset = 0; - vc->vc_need_wrap = 0; - vc->vc_report_mouse = 0; - vc->vc_utf = default_utf8; - vc->vc_utf_count = 0; - - vc->vc_disp_ctrl = 0; - vc->vc_toggle_meta = 0; - - vc->vc_decscnm = 0; - vc->vc_decom = 0; - vc->vc_decawm = 1; - vc->vc_deccm = global_cursor_default; - vc->vc_decim = 0; - - set_kbd(vc, decarm); - clr_kbd(vc, decckm); - clr_kbd(vc, kbdapplic); - clr_kbd(vc, lnm); - kbd_table[vc->vc_num].lockstate = 0; - kbd_table[vc->vc_num].slockstate = 0; - kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS; - kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate; - /* do not do set_leds here because this causes an endless tasklet loop - when the keyboard hasn't been initialized yet */ - - vc->vc_cursor_type = cur_default; - vc->vc_complement_mask = vc->vc_s_complement_mask; - - default_attr(vc); - update_attr(vc); - - vc->vc_tab_stop[0] = 0x01010100; - vc->vc_tab_stop[1] = - vc->vc_tab_stop[2] = - vc->vc_tab_stop[3] = - vc->vc_tab_stop[4] = - vc->vc_tab_stop[5] = - vc->vc_tab_stop[6] = - vc->vc_tab_stop[7] = 0x01010101; - - vc->vc_bell_pitch = DEFAULT_BELL_PITCH; - vc->vc_bell_duration = DEFAULT_BELL_DURATION; - - gotoxy(vc, 0, 0); - save_cur(vc); - if (do_clear) - csi_J(vc, 2); -} - -/* console_sem is held */ -static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) -{ - /* - * Control characters can be used in the _middle_ - * of an escape sequence. - */ - switch (c) { - case 0: - return; - case 7: - if (vc->vc_bell_duration) - kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration); - return; - case 8: - bs(vc); - return; - case 9: - vc->vc_pos -= (vc->vc_x << 1); - while (vc->vc_x < vc->vc_cols - 1) { - vc->vc_x++; - if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31))) - break; - } - vc->vc_pos += (vc->vc_x << 1); - notify_write(vc, '\t'); - return; - case 10: case 11: case 12: - lf(vc); - if (!is_kbd(vc, lnm)) - return; - case 13: - cr(vc); - return; - case 14: - vc->vc_charset = 1; - vc->vc_translate = set_translate(vc->vc_G1_charset, vc); - vc->vc_disp_ctrl = 1; - return; - case 15: - vc->vc_charset = 0; - vc->vc_translate = set_translate(vc->vc_G0_charset, vc); - vc->vc_disp_ctrl = 0; - return; - case 24: case 26: - vc->vc_state = ESnormal; - return; - case 27: - vc->vc_state = ESesc; - return; - case 127: - del(vc); - return; - case 128+27: - vc->vc_state = ESsquare; - return; - } - switch(vc->vc_state) { - case ESesc: - vc->vc_state = ESnormal; - switch (c) { - case '[': - vc->vc_state = ESsquare; - return; - case ']': - vc->vc_state = ESnonstd; - return; - case '%': - vc->vc_state = ESpercent; - return; - case 'E': - cr(vc); - lf(vc); - return; - case 'M': - ri(vc); - return; - case 'D': - lf(vc); - return; - case 'H': - vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31)); - return; - case 'Z': - respond_ID(tty); - return; - case '7': - save_cur(vc); - return; - case '8': - restore_cur(vc); - return; - case '(': - vc->vc_state = ESsetG0; - return; - case ')': - vc->vc_state = ESsetG1; - return; - case '#': - vc->vc_state = EShash; - return; - case 'c': - reset_terminal(vc, 1); - return; - case '>': /* Numeric keypad */ - clr_kbd(vc, kbdapplic); - return; - case '=': /* Appl. keypad */ - set_kbd(vc, kbdapplic); - return; - } - return; - case ESnonstd: - if (c=='P') { /* palette escape sequence */ - for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++) - vc->vc_par[vc->vc_npar] = 0; - vc->vc_npar = 0; - vc->vc_state = ESpalette; - return; - } else if (c=='R') { /* reset palette */ - reset_palette(vc); - vc->vc_state = ESnormal; - } else - vc->vc_state = ESnormal; - return; - case ESpalette: - if (isxdigit(c)) { - vc->vc_par[vc->vc_npar++] = hex_to_bin(c); - if (vc->vc_npar == 7) { - int i = vc->vc_par[0] * 3, j = 1; - vc->vc_palette[i] = 16 * vc->vc_par[j++]; - vc->vc_palette[i++] += vc->vc_par[j++]; - vc->vc_palette[i] = 16 * vc->vc_par[j++]; - vc->vc_palette[i++] += vc->vc_par[j++]; - vc->vc_palette[i] = 16 * vc->vc_par[j++]; - vc->vc_palette[i] += vc->vc_par[j]; - set_palette(vc); - vc->vc_state = ESnormal; - } - } else - vc->vc_state = ESnormal; - return; - case ESsquare: - for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++) - vc->vc_par[vc->vc_npar] = 0; - vc->vc_npar = 0; - vc->vc_state = ESgetpars; - if (c == '[') { /* Function key */ - vc->vc_state=ESfunckey; - return; - } - vc->vc_ques = (c == '?'); - if (vc->vc_ques) - return; - case ESgetpars: - if (c == ';' && vc->vc_npar < NPAR - 1) { - vc->vc_npar++; - return; - } else if (c>='0' && c<='9') { - vc->vc_par[vc->vc_npar] *= 10; - vc->vc_par[vc->vc_npar] += c - '0'; - return; - } else - vc->vc_state = ESgotpars; - case ESgotpars: - vc->vc_state = ESnormal; - switch(c) { - case 'h': - set_mode(vc, 1); - return; - case 'l': - set_mode(vc, 0); - return; - case 'c': - if (vc->vc_ques) { - if (vc->vc_par[0]) - vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16); - else - vc->vc_cursor_type = cur_default; - return; - } - break; - case 'm': - if (vc->vc_ques) { - clear_selection(); - if (vc->vc_par[0]) - vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1]; - else - vc->vc_complement_mask = vc->vc_s_complement_mask; - return; - } - break; - case 'n': - if (!vc->vc_ques) { - if (vc->vc_par[0] == 5) - status_report(tty); - else if (vc->vc_par[0] == 6) - cursor_report(vc, tty); - } - return; - } - if (vc->vc_ques) { - vc->vc_ques = 0; - return; - } - switch(c) { - case 'G': case '`': - if (vc->vc_par[0]) - vc->vc_par[0]--; - gotoxy(vc, vc->vc_par[0], vc->vc_y); - return; - case 'A': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]); - return; - case 'B': case 'e': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]); - return; - case 'C': case 'a': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y); - return; - case 'D': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y); - return; - case 'E': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]); - return; - case 'F': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]); - return; - case 'd': - if (vc->vc_par[0]) - vc->vc_par[0]--; - gotoxay(vc, vc->vc_x ,vc->vc_par[0]); - return; - case 'H': case 'f': - if (vc->vc_par[0]) - vc->vc_par[0]--; - if (vc->vc_par[1]) - vc->vc_par[1]--; - gotoxay(vc, vc->vc_par[1], vc->vc_par[0]); - return; - case 'J': - csi_J(vc, vc->vc_par[0]); - return; - case 'K': - csi_K(vc, vc->vc_par[0]); - return; - case 'L': - csi_L(vc, vc->vc_par[0]); - return; - case 'M': - csi_M(vc, vc->vc_par[0]); - return; - case 'P': - csi_P(vc, vc->vc_par[0]); - return; - case 'c': - if (!vc->vc_par[0]) - respond_ID(tty); - return; - case 'g': - if (!vc->vc_par[0]) - vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31)); - else if (vc->vc_par[0] == 3) { - vc->vc_tab_stop[0] = - vc->vc_tab_stop[1] = - vc->vc_tab_stop[2] = - vc->vc_tab_stop[3] = - vc->vc_tab_stop[4] = - vc->vc_tab_stop[5] = - vc->vc_tab_stop[6] = - vc->vc_tab_stop[7] = 0; - } - return; - case 'm': - csi_m(vc); - return; - case 'q': /* DECLL - but only 3 leds */ - /* map 0,1,2,3 to 0,1,2,4 */ - if (vc->vc_par[0] < 4) - setledstate(kbd_table + vc->vc_num, - (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4); - return; - case 'r': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - if (!vc->vc_par[1]) - vc->vc_par[1] = vc->vc_rows; - /* Minimum allowed region is 2 lines */ - if (vc->vc_par[0] < vc->vc_par[1] && - vc->vc_par[1] <= vc->vc_rows) { - vc->vc_top = vc->vc_par[0] - 1; - vc->vc_bottom = vc->vc_par[1]; - gotoxay(vc, 0, 0); - } - return; - case 's': - save_cur(vc); - return; - case 'u': - restore_cur(vc); - return; - case 'X': - csi_X(vc, vc->vc_par[0]); - return; - case '@': - csi_at(vc, vc->vc_par[0]); - return; - case ']': /* setterm functions */ - setterm_command(vc); - return; - } - return; - case ESpercent: - vc->vc_state = ESnormal; - switch (c) { - case '@': /* defined in ISO 2022 */ - vc->vc_utf = 0; - return; - case 'G': /* prelim official escape code */ - case '8': /* retained for compatibility */ - vc->vc_utf = 1; - return; - } - return; - case ESfunckey: - vc->vc_state = ESnormal; - return; - case EShash: - vc->vc_state = ESnormal; - if (c == '8') { - /* DEC screen alignment test. kludge :-) */ - vc->vc_video_erase_char = - (vc->vc_video_erase_char & 0xff00) | 'E'; - csi_J(vc, 2); - vc->vc_video_erase_char = - (vc->vc_video_erase_char & 0xff00) | ' '; - do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2); - } - return; - case ESsetG0: - if (c == '0') - vc->vc_G0_charset = GRAF_MAP; - else if (c == 'B') - vc->vc_G0_charset = LAT1_MAP; - else if (c == 'U') - vc->vc_G0_charset = IBMPC_MAP; - else if (c == 'K') - vc->vc_G0_charset = USER_MAP; - if (vc->vc_charset == 0) - vc->vc_translate = set_translate(vc->vc_G0_charset, vc); - vc->vc_state = ESnormal; - return; - case ESsetG1: - if (c == '0') - vc->vc_G1_charset = GRAF_MAP; - else if (c == 'B') - vc->vc_G1_charset = LAT1_MAP; - else if (c == 'U') - vc->vc_G1_charset = IBMPC_MAP; - else if (c == 'K') - vc->vc_G1_charset = USER_MAP; - if (vc->vc_charset == 1) - vc->vc_translate = set_translate(vc->vc_G1_charset, vc); - vc->vc_state = ESnormal; - return; - default: - vc->vc_state = ESnormal; - } -} - -/* This is a temporary buffer used to prepare a tty console write - * so that we can easily avoid touching user space while holding the - * console spinlock. It is allocated in con_init and is shared by - * this code and the vc_screen read/write tty calls. - * - * We have to allocate this statically in the kernel data section - * since console_init (and thus con_init) are called before any - * kernel memory allocation is available. - */ -char con_buf[CON_BUF_SIZE]; -DEFINE_MUTEX(con_buf_mtx); - -/* is_double_width() is based on the wcwidth() implementation by - * Markus Kuhn -- 2007-05-26 (Unicode 5.0) - * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c - */ -struct interval { - uint32_t first; - uint32_t last; -}; - -static int bisearch(uint32_t ucs, const struct interval *table, int max) -{ - int min = 0; - int mid; - - if (ucs < table[0].first || ucs > table[max].last) - return 0; - while (max >= min) { - mid = (min + max) / 2; - if (ucs > table[mid].last) - min = mid + 1; - else if (ucs < table[mid].first) - max = mid - 1; - else - return 1; - } - return 0; -} - -static int is_double_width(uint32_t ucs) -{ - static const struct interval double_width[] = { - { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E }, - { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF }, - { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 }, - { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD } - }; - return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1); -} - -/* acquires console_sem */ -static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count) -{ -#ifdef VT_BUF_VRAM_ONLY -#define FLUSH do { } while(0); -#else -#define FLUSH if (draw_x >= 0) { \ - vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \ - draw_x = -1; \ - } -#endif - - int c, tc, ok, n = 0, draw_x = -1; - unsigned int currcons; - unsigned long draw_from = 0, draw_to = 0; - struct vc_data *vc; - unsigned char vc_attr; - struct vt_notifier_param param; - uint8_t rescan; - uint8_t inverse; - uint8_t width; - u16 himask, charmask; - - if (in_interrupt()) - return count; - - might_sleep(); - - acquire_console_sem(); - vc = tty->driver_data; - if (vc == NULL) { - printk(KERN_ERR "vt: argh, driver_data is NULL !\n"); - release_console_sem(); - return 0; - } - - currcons = vc->vc_num; - if (!vc_cons_allocated(currcons)) { - /* could this happen? */ - printk_once("con_write: tty %d not allocated\n", currcons+1); - release_console_sem(); - return 0; - } - - himask = vc->vc_hi_font_mask; - charmask = himask ? 0x1ff : 0xff; - - /* undraw cursor first */ - if (IS_FG(vc)) - hide_cursor(vc); - - param.vc = vc; - - while (!tty->stopped && count) { - int orig = *buf; - c = orig; - buf++; - n++; - count--; - rescan = 0; - inverse = 0; - width = 1; - - /* Do no translation at all in control states */ - if (vc->vc_state != ESnormal) { - tc = c; - } else if (vc->vc_utf && !vc->vc_disp_ctrl) { - /* Combine UTF-8 into Unicode in vc_utf_char. - * vc_utf_count is the number of continuation bytes still - * expected to arrive. - * vc_npar is the number of continuation bytes arrived so - * far - */ -rescan_last_byte: - if ((c & 0xc0) == 0x80) { - /* Continuation byte received */ - static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff }; - if (vc->vc_utf_count) { - vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f); - vc->vc_npar++; - if (--vc->vc_utf_count) { - /* Still need some bytes */ - continue; - } - /* Got a whole character */ - c = vc->vc_utf_char; - /* Reject overlong sequences */ - if (c <= utf8_length_changes[vc->vc_npar - 1] || - c > utf8_length_changes[vc->vc_npar]) - c = 0xfffd; - } else { - /* Unexpected continuation byte */ - vc->vc_utf_count = 0; - c = 0xfffd; - } - } else { - /* Single ASCII byte or first byte of a sequence received */ - if (vc->vc_utf_count) { - /* Continuation byte expected */ - rescan = 1; - vc->vc_utf_count = 0; - c = 0xfffd; - } else if (c > 0x7f) { - /* First byte of a multibyte sequence received */ - vc->vc_npar = 0; - if ((c & 0xe0) == 0xc0) { - vc->vc_utf_count = 1; - vc->vc_utf_char = (c & 0x1f); - } else if ((c & 0xf0) == 0xe0) { - vc->vc_utf_count = 2; - vc->vc_utf_char = (c & 0x0f); - } else if ((c & 0xf8) == 0xf0) { - vc->vc_utf_count = 3; - vc->vc_utf_char = (c & 0x07); - } else if ((c & 0xfc) == 0xf8) { - vc->vc_utf_count = 4; - vc->vc_utf_char = (c & 0x03); - } else if ((c & 0xfe) == 0xfc) { - vc->vc_utf_count = 5; - vc->vc_utf_char = (c & 0x01); - } else { - /* 254 and 255 are invalid */ - c = 0xfffd; - } - if (vc->vc_utf_count) { - /* Still need some bytes */ - continue; - } - } - /* Nothing to do if an ASCII byte was received */ - } - /* End of UTF-8 decoding. */ - /* c is the received character, or U+FFFD for invalid sequences. */ - /* Replace invalid Unicode code points with U+FFFD too */ - if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff) - c = 0xfffd; - tc = c; - } else { /* no utf or alternate charset mode */ - tc = vc_translate(vc, c); - } - - param.c = tc; - if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE, - ¶m) == NOTIFY_STOP) - continue; - - /* If the original code was a control character we - * only allow a glyph to be displayed if the code is - * not normally used (such as for cursor movement) or - * if the disp_ctrl mode has been explicitly enabled. - * Certain characters (as given by the CTRL_ALWAYS - * bitmap) are always displayed as control characters, - * as the console would be pretty useless without - * them; to display an arbitrary font position use the - * direct-to-font zone in UTF-8 mode. - */ - ok = tc && (c >= 32 || - !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 : - vc->vc_utf || ((CTRL_ACTION >> c) & 1))) - && (c != 127 || vc->vc_disp_ctrl) - && (c != 128+27); - - if (vc->vc_state == ESnormal && ok) { - if (vc->vc_utf && !vc->vc_disp_ctrl) { - if (is_double_width(c)) - width = 2; - } - /* Now try to find out how to display it */ - tc = conv_uni_to_pc(vc, tc); - if (tc & ~charmask) { - if (tc == -1 || tc == -2) { - continue; /* nothing to display */ - } - /* Glyph not found */ - if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) { - /* In legacy mode use the glyph we get by a 1:1 mapping. - This would make absolutely no sense with Unicode in mind, - but do this for ASCII characters since a font may lack - Unicode mapping info and we don't want to end up with - having question marks only. */ - tc = c; - } else { - /* Display U+FFFD. If it's not found, display an inverse question mark. */ - tc = conv_uni_to_pc(vc, 0xfffd); - if (tc < 0) { - inverse = 1; - tc = conv_uni_to_pc(vc, '?'); - if (tc < 0) tc = '?'; - } - } - } - - if (!inverse) { - vc_attr = vc->vc_attr; - } else { - /* invert vc_attr */ - if (!vc->vc_can_do_color) { - vc_attr = (vc->vc_attr) ^ 0x08; - } else if (vc->vc_hi_font_mask == 0x100) { - vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4); - } else { - vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4); - } - FLUSH - } - - while (1) { - if (vc->vc_need_wrap || vc->vc_decim) - FLUSH - if (vc->vc_need_wrap) { - cr(vc); - lf(vc); - } - if (vc->vc_decim) - insert_char(vc, 1); - scr_writew(himask ? - ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : - (vc_attr << 8) + tc, - (u16 *) vc->vc_pos); - if (DO_UPDATE(vc) && draw_x < 0) { - draw_x = vc->vc_x; - draw_from = vc->vc_pos; - } - if (vc->vc_x == vc->vc_cols - 1) { - vc->vc_need_wrap = vc->vc_decawm; - draw_to = vc->vc_pos + 2; - } else { - vc->vc_x++; - draw_to = (vc->vc_pos += 2); - } - - if (!--width) break; - - tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */ - if (tc < 0) tc = ' '; - } - notify_write(vc, c); - - if (inverse) { - FLUSH - } - - if (rescan) { - rescan = 0; - inverse = 0; - width = 1; - c = orig; - goto rescan_last_byte; - } - continue; - } - FLUSH - do_con_trol(tty, vc, orig); - } - FLUSH - console_conditional_schedule(); - release_console_sem(); - notify_update(vc); - return n; -#undef FLUSH -} - -/* - * This is the console switching callback. - * - * Doing console switching in a process context allows - * us to do the switches asynchronously (needed when we want - * to switch due to a keyboard interrupt). Synchronization - * with other console code and prevention of re-entrancy is - * ensured with console_sem. - */ -static void console_callback(struct work_struct *ignored) -{ - acquire_console_sem(); - - if (want_console >= 0) { - if (want_console != fg_console && - vc_cons_allocated(want_console)) { - hide_cursor(vc_cons[fg_console].d); - change_console(vc_cons[want_console].d); - /* we only changed when the console had already - been allocated - a new console is not created - in an interrupt routine */ - } - want_console = -1; - } - if (do_poke_blanked_console) { /* do not unblank for a LED change */ - do_poke_blanked_console = 0; - poke_blanked_console(); - } - if (scrollback_delta) { - struct vc_data *vc = vc_cons[fg_console].d; - clear_selection(); - if (vc->vc_mode == KD_TEXT) - vc->vc_sw->con_scrolldelta(vc, scrollback_delta); - scrollback_delta = 0; - } - if (blank_timer_expired) { - do_blank_screen(0); - blank_timer_expired = 0; - } - notify_update(vc_cons[fg_console].d); - - release_console_sem(); -} - -int set_console(int nr) -{ - struct vc_data *vc = vc_cons[fg_console].d; - - if (!vc_cons_allocated(nr) || vt_dont_switch || - (vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) { - - /* - * Console switch will fail in console_callback() or - * change_console() so there is no point scheduling - * the callback - * - * Existing set_console() users don't check the return - * value so this shouldn't break anything - */ - return -EINVAL; - } - - want_console = nr; - schedule_console_callback(); - - return 0; -} - -struct tty_driver *console_driver; - -#ifdef CONFIG_VT_CONSOLE - -/** - * vt_kmsg_redirect() - Sets/gets the kernel message console - * @new: The new virtual terminal number or -1 if the console should stay - * unchanged - * - * By default, the kernel messages are always printed on the current virtual - * console. However, the user may modify that default with the - * TIOCL_SETKMSGREDIRECT ioctl call. - * - * This function sets the kernel message console to be @new. It returns the old - * virtual console number. The virtual terminal number 0 (both as parameter and - * return value) means no redirection (i.e. always printed on the currently - * active console). - * - * The parameter -1 means that only the current console is returned, but the - * value is not modified. You may use the macro vt_get_kmsg_redirect() in that - * case to make the code more understandable. - * - * When the kernel is compiled without CONFIG_VT_CONSOLE, this function ignores - * the parameter and always returns 0. - */ -int vt_kmsg_redirect(int new) -{ - static int kmsg_con; - - if (new != -1) - return xchg(&kmsg_con, new); - else - return kmsg_con; -} - -/* - * Console on virtual terminal - * - * The console must be locked when we get here. - */ - -static void vt_console_print(struct console *co, const char *b, unsigned count) -{ - struct vc_data *vc = vc_cons[fg_console].d; - unsigned char c; - static DEFINE_SPINLOCK(printing_lock); - const ushort *start; - ushort cnt = 0; - ushort myx; - int kmsg_console; - - /* console busy or not yet initialized */ - if (!printable) - return; - if (!spin_trylock(&printing_lock)) - return; - - kmsg_console = vt_get_kmsg_redirect(); - if (kmsg_console && vc_cons_allocated(kmsg_console - 1)) - vc = vc_cons[kmsg_console - 1].d; - - /* read `x' only after setting currcons properly (otherwise - the `x' macro will read the x of the foreground console). */ - myx = vc->vc_x; - - if (!vc_cons_allocated(fg_console)) { - /* impossible */ - /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */ - goto quit; - } - - if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc)) - goto quit; - - /* undraw cursor first */ - if (IS_FG(vc)) - hide_cursor(vc); - - start = (ushort *)vc->vc_pos; - - /* Contrived structure to try to emulate original need_wrap behaviour - * Problems caused when we have need_wrap set on '\n' character */ - while (count--) { - c = *b++; - if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) { - if (cnt > 0) { - if (CON_IS_VISIBLE(vc)) - vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); - vc->vc_x += cnt; - if (vc->vc_need_wrap) - vc->vc_x--; - cnt = 0; - } - if (c == 8) { /* backspace */ - bs(vc); - start = (ushort *)vc->vc_pos; - myx = vc->vc_x; - continue; - } - if (c != 13) - lf(vc); - cr(vc); - start = (ushort *)vc->vc_pos; - myx = vc->vc_x; - if (c == 10 || c == 13) - continue; - } - scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos); - notify_write(vc, c); - cnt++; - if (myx == vc->vc_cols - 1) { - vc->vc_need_wrap = 1; - continue; - } - vc->vc_pos += 2; - myx++; - } - if (cnt > 0) { - if (CON_IS_VISIBLE(vc)) - vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); - vc->vc_x += cnt; - if (vc->vc_x == vc->vc_cols) { - vc->vc_x--; - vc->vc_need_wrap = 1; - } - } - set_cursor(vc); - notify_update(vc); - -quit: - spin_unlock(&printing_lock); -} - -static struct tty_driver *vt_console_device(struct console *c, int *index) -{ - *index = c->index ? c->index-1 : fg_console; - return console_driver; -} - -static struct console vt_console_driver = { - .name = "tty", - .write = vt_console_print, - .device = vt_console_device, - .unblank = unblank_screen, - .flags = CON_PRINTBUFFER, - .index = -1, -}; -#endif - -/* - * Handling of Linux-specific VC ioctls - */ - -/* - * Generally a bit racy with respect to console_sem(). - * - * There are some functions which don't need it. - * - * There are some functions which can sleep for arbitrary periods - * (paste_selection) but we don't need the lock there anyway. - * - * set_selection has locking, and definitely needs it - */ - -int tioclinux(struct tty_struct *tty, unsigned long arg) -{ - char type, data; - char __user *p = (char __user *)arg; - int lines; - int ret; - - if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(type, p)) - return -EFAULT; - ret = 0; - - switch (type) - { - case TIOCL_SETSEL: - acquire_console_sem(); - ret = set_selection((struct tiocl_selection __user *)(p+1), tty); - release_console_sem(); - break; - case TIOCL_PASTESEL: - ret = paste_selection(tty); - break; - case TIOCL_UNBLANKSCREEN: - acquire_console_sem(); - unblank_screen(); - release_console_sem(); - break; - case TIOCL_SELLOADLUT: - ret = sel_loadlut(p); - break; - case TIOCL_GETSHIFTSTATE: - - /* - * Make it possible to react to Shift+Mousebutton. - * Note that 'shift_state' is an undocumented - * kernel-internal variable; programs not closely - * related to the kernel should not use this. - */ - data = shift_state; - ret = __put_user(data, p); - break; - case TIOCL_GETMOUSEREPORTING: - data = mouse_reporting(); - ret = __put_user(data, p); - break; - case TIOCL_SETVESABLANK: - ret = set_vesa_blanking(p); - break; - case TIOCL_GETKMSGREDIRECT: - data = vt_get_kmsg_redirect(); - ret = __put_user(data, p); - break; - case TIOCL_SETKMSGREDIRECT: - if (!capable(CAP_SYS_ADMIN)) { - ret = -EPERM; - } else { - if (get_user(data, p+1)) - ret = -EFAULT; - else - vt_kmsg_redirect(data); - } - break; - case TIOCL_GETFGCONSOLE: - ret = fg_console; - break; - case TIOCL_SCROLLCONSOLE: - if (get_user(lines, (s32 __user *)(p+4))) { - ret = -EFAULT; - } else { - scrollfront(vc_cons[fg_console].d, lines); - ret = 0; - } - break; - case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */ - acquire_console_sem(); - ignore_poke = 1; - do_blank_screen(0); - release_console_sem(); - break; - case TIOCL_BLANKEDSCREEN: - ret = console_blanked; - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -/* - * /dev/ttyN handling - */ - -static int con_write(struct tty_struct *tty, const unsigned char *buf, int count) -{ - int retval; - - retval = do_con_write(tty, buf, count); - con_flush_chars(tty); - - return retval; -} - -static int con_put_char(struct tty_struct *tty, unsigned char ch) -{ - if (in_interrupt()) - return 0; /* n_r3964 calls put_char() from interrupt context */ - return do_con_write(tty, &ch, 1); -} - -static int con_write_room(struct tty_struct *tty) -{ - if (tty->stopped) - return 0; - return 32768; /* No limit, really; we're not buffering */ -} - -static int con_chars_in_buffer(struct tty_struct *tty) -{ - return 0; /* we're not buffering */ -} - -/* - * con_throttle and con_unthrottle are only used for - * paste_selection(), which has to stuff in a large number of - * characters... - */ -static void con_throttle(struct tty_struct *tty) -{ -} - -static void con_unthrottle(struct tty_struct *tty) -{ - struct vc_data *vc = tty->driver_data; - - wake_up_interruptible(&vc->paste_wait); -} - -/* - * Turn the Scroll-Lock LED on when the tty is stopped - */ -static void con_stop(struct tty_struct *tty) -{ - int console_num; - if (!tty) - return; - console_num = tty->index; - if (!vc_cons_allocated(console_num)) - return; - set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); - set_leds(); -} - -/* - * Turn the Scroll-Lock LED off when the console is started - */ -static void con_start(struct tty_struct *tty) -{ - int console_num; - if (!tty) - return; - console_num = tty->index; - if (!vc_cons_allocated(console_num)) - return; - clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); - set_leds(); -} - -static void con_flush_chars(struct tty_struct *tty) -{ - struct vc_data *vc; - - if (in_interrupt()) /* from flush_to_ldisc */ - return; - - /* if we race with con_close(), vt may be null */ - acquire_console_sem(); - vc = tty->driver_data; - if (vc) - set_cursor(vc); - release_console_sem(); -} - -/* - * Allocate the console screen memory. - */ -static int con_open(struct tty_struct *tty, struct file *filp) -{ - unsigned int currcons = tty->index; - int ret = 0; - - acquire_console_sem(); - if (tty->driver_data == NULL) { - ret = vc_allocate(currcons); - if (ret == 0) { - struct vc_data *vc = vc_cons[currcons].d; - - /* Still being freed */ - if (vc->port.tty) { - release_console_sem(); - return -ERESTARTSYS; - } - tty->driver_data = vc; - vc->port.tty = tty; - - if (!tty->winsize.ws_row && !tty->winsize.ws_col) { - tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; - tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; - } - if (vc->vc_utf) - tty->termios->c_iflag |= IUTF8; - else - tty->termios->c_iflag &= ~IUTF8; - release_console_sem(); - return ret; - } - } - release_console_sem(); - return ret; -} - -static void con_close(struct tty_struct *tty, struct file *filp) -{ - /* Nothing to do - we defer to shutdown */ -} - -static void con_shutdown(struct tty_struct *tty) -{ - struct vc_data *vc = tty->driver_data; - BUG_ON(vc == NULL); - acquire_console_sem(); - vc->port.tty = NULL; - release_console_sem(); - tty_shutdown(tty); -} - -static int default_italic_color = 2; // green (ASCII) -static int default_underline_color = 3; // cyan (ASCII) -module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR); -module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR); - -static void vc_init(struct vc_data *vc, unsigned int rows, - unsigned int cols, int do_clear) -{ - int j, k ; - - vc->vc_cols = cols; - vc->vc_rows = rows; - vc->vc_size_row = cols << 1; - vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row; - - set_origin(vc); - vc->vc_pos = vc->vc_origin; - reset_vc(vc); - for (j=k=0; j<16; j++) { - vc->vc_palette[k++] = default_red[j] ; - vc->vc_palette[k++] = default_grn[j] ; - vc->vc_palette[k++] = default_blu[j] ; - } - vc->vc_def_color = 0x07; /* white */ - vc->vc_ulcolor = default_underline_color; - vc->vc_itcolor = default_italic_color; - vc->vc_halfcolor = 0x08; /* grey */ - init_waitqueue_head(&vc->paste_wait); - reset_terminal(vc, do_clear); -} - -/* - * This routine initializes console interrupts, and does nothing - * else. If you want the screen to clear, call tty_write with - * the appropriate escape-sequence. - */ - -static int __init con_init(void) -{ - const char *display_desc = NULL; - struct vc_data *vc; - unsigned int currcons = 0, i; - - acquire_console_sem(); - - if (conswitchp) - display_desc = conswitchp->con_startup(); - if (!display_desc) { - fg_console = 0; - release_console_sem(); - return 0; - } - - for (i = 0; i < MAX_NR_CON_DRIVER; i++) { - struct con_driver *con_driver = ®istered_con_driver[i]; - - if (con_driver->con == NULL) { - con_driver->con = conswitchp; - con_driver->desc = display_desc; - con_driver->flag = CON_DRIVER_FLAG_INIT; - con_driver->first = 0; - con_driver->last = MAX_NR_CONSOLES - 1; - break; - } - } - - for (i = 0; i < MAX_NR_CONSOLES; i++) - con_driver_map[i] = conswitchp; - - if (blankinterval) { - blank_state = blank_normal_wait; - mod_timer(&console_timer, jiffies + (blankinterval * HZ)); - } - - for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { - vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT); - INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); - tty_port_init(&vc->port); - visual_init(vc, currcons, 1); - vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT); - vc_init(vc, vc->vc_rows, vc->vc_cols, - currcons || !vc->vc_sw->con_save_screen); - } - currcons = fg_console = 0; - master_display_fg = vc = vc_cons[currcons].d; - set_origin(vc); - save_screen(vc); - gotoxy(vc, vc->vc_x, vc->vc_y); - csi_J(vc, 0); - update_screen(vc); - printk("Console: %s %s %dx%d", - vc->vc_can_do_color ? "colour" : "mono", - display_desc, vc->vc_cols, vc->vc_rows); - printable = 1; - printk("\n"); - - release_console_sem(); - -#ifdef CONFIG_VT_CONSOLE - register_console(&vt_console_driver); -#endif - return 0; -} -console_initcall(con_init); - -static const struct tty_operations con_ops = { - .open = con_open, - .close = con_close, - .write = con_write, - .write_room = con_write_room, - .put_char = con_put_char, - .flush_chars = con_flush_chars, - .chars_in_buffer = con_chars_in_buffer, - .ioctl = vt_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = vt_compat_ioctl, -#endif - .stop = con_stop, - .start = con_start, - .throttle = con_throttle, - .unthrottle = con_unthrottle, - .resize = vt_resize, - .shutdown = con_shutdown -}; - -static struct cdev vc0_cdev; - -int __init vty_init(const struct file_operations *console_fops) -{ - cdev_init(&vc0_cdev, console_fops); - if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || - register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) - panic("Couldn't register /dev/tty0 driver\n"); - device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); - - vcs_init(); - - console_driver = alloc_tty_driver(MAX_NR_CONSOLES); - if (!console_driver) - panic("Couldn't allocate console driver\n"); - console_driver->owner = THIS_MODULE; - console_driver->name = "tty"; - console_driver->name_base = 1; - console_driver->major = TTY_MAJOR; - console_driver->minor_start = 1; - console_driver->type = TTY_DRIVER_TYPE_CONSOLE; - console_driver->init_termios = tty_std_termios; - if (default_utf8) - console_driver->init_termios.c_iflag |= IUTF8; - console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; - tty_set_operations(console_driver, &con_ops); - if (tty_register_driver(console_driver)) - panic("Couldn't register console driver\n"); - kbd_init(); - console_map_init(); -#ifdef CONFIG_MDA_CONSOLE - mda_console_init(); -#endif - return 0; -} - -#ifndef VT_SINGLE_DRIVER - -static struct class *vtconsole_class; - -static int bind_con_driver(const struct consw *csw, int first, int last, - int deflt) -{ - struct module *owner = csw->owner; - const char *desc = NULL; - struct con_driver *con_driver; - int i, j = -1, k = -1, retval = -ENODEV; - - if (!try_module_get(owner)) - return -ENODEV; - - acquire_console_sem(); - - /* check if driver is registered */ - for (i = 0; i < MAX_NR_CON_DRIVER; i++) { - con_driver = ®istered_con_driver[i]; - - if (con_driver->con == csw) { - desc = con_driver->desc; - retval = 0; - break; - } - } - - if (retval) - goto err; - - if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) { - csw->con_startup(); - con_driver->flag |= CON_DRIVER_FLAG_INIT; - } - - if (deflt) { - if (conswitchp) - module_put(conswitchp->owner); - - __module_get(owner); - conswitchp = csw; - } - - first = max(first, con_driver->first); - last = min(last, con_driver->last); - - for (i = first; i <= last; i++) { - int old_was_color; - struct vc_data *vc = vc_cons[i].d; - - if (con_driver_map[i]) - module_put(con_driver_map[i]->owner); - __module_get(owner); - con_driver_map[i] = csw; - - if (!vc || !vc->vc_sw) - continue; - - j = i; - - if (CON_IS_VISIBLE(vc)) { - k = i; - save_screen(vc); - } - - old_was_color = vc->vc_can_do_color; - vc->vc_sw->con_deinit(vc); - vc->vc_origin = (unsigned long)vc->vc_screenbuf; - visual_init(vc, i, 0); - set_origin(vc); - update_attr(vc); - - /* If the console changed between mono <-> color, then - * the attributes in the screenbuf will be wrong. The - * following resets all attributes to something sane. - */ - if (old_was_color != vc->vc_can_do_color) - clear_buffer_attributes(vc); - } - - printk("Console: switching "); - if (!deflt) - printk("consoles %d-%d ", first+1, last+1); - if (j >= 0) { - struct vc_data *vc = vc_cons[j].d; - - printk("to %s %s %dx%d\n", - vc->vc_can_do_color ? "colour" : "mono", - desc, vc->vc_cols, vc->vc_rows); - - if (k >= 0) { - vc = vc_cons[k].d; - update_screen(vc); - } - } else - printk("to %s\n", desc); - - retval = 0; -err: - release_console_sem(); - module_put(owner); - return retval; -}; - -#ifdef CONFIG_VT_HW_CONSOLE_BINDING -static int con_is_graphics(const struct consw *csw, int first, int last) -{ - int i, retval = 0; - - for (i = first; i <= last; i++) { - struct vc_data *vc = vc_cons[i].d; - - if (vc && vc->vc_mode == KD_GRAPHICS) { - retval = 1; - break; - } - } - - return retval; -} - -/** - * unbind_con_driver - unbind a console driver - * @csw: pointer to console driver to unregister - * @first: first in range of consoles that @csw should be unbound from - * @last: last in range of consoles that @csw should be unbound from - * @deflt: should next bound console driver be default after @csw is unbound? - * - * To unbind a driver from all possible consoles, pass 0 as @first and - * %MAX_NR_CONSOLES as @last. - * - * @deflt controls whether the console that ends up replacing @csw should be - * the default console. - * - * RETURNS: - * -ENODEV if @csw isn't a registered console driver or can't be unregistered - * or 0 on success. - */ -int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) -{ - struct module *owner = csw->owner; - const struct consw *defcsw = NULL; - struct con_driver *con_driver = NULL, *con_back = NULL; - int i, retval = -ENODEV; - - if (!try_module_get(owner)) - return -ENODEV; - - acquire_console_sem(); - - /* check if driver is registered and if it is unbindable */ - for (i = 0; i < MAX_NR_CON_DRIVER; i++) { - con_driver = ®istered_con_driver[i]; - - if (con_driver->con == csw && - con_driver->flag & CON_DRIVER_FLAG_MODULE) { - retval = 0; - break; - } - } - - if (retval) { - release_console_sem(); - goto err; - } - - retval = -ENODEV; - - /* check if backup driver exists */ - for (i = 0; i < MAX_NR_CON_DRIVER; i++) { - con_back = ®istered_con_driver[i]; - - if (con_back->con && - !(con_back->flag & CON_DRIVER_FLAG_MODULE)) { - defcsw = con_back->con; - retval = 0; - break; - } - } - - if (retval) { - release_console_sem(); - goto err; - } - - if (!con_is_bound(csw)) { - release_console_sem(); - goto err; - } - - first = max(first, con_driver->first); - last = min(last, con_driver->last); - - for (i = first; i <= last; i++) { - if (con_driver_map[i] == csw) { - module_put(csw->owner); - con_driver_map[i] = NULL; - } - } - - if (!con_is_bound(defcsw)) { - const struct consw *defconsw = conswitchp; - - defcsw->con_startup(); - con_back->flag |= CON_DRIVER_FLAG_INIT; - /* - * vgacon may change the default driver to point - * to dummycon, we restore it here... - */ - conswitchp = defconsw; - } - - if (!con_is_bound(csw)) - con_driver->flag &= ~CON_DRIVER_FLAG_INIT; - - release_console_sem(); - /* ignore return value, binding should not fail */ - bind_con_driver(defcsw, first, last, deflt); -err: - module_put(owner); - return retval; - -} -EXPORT_SYMBOL(unbind_con_driver); - -static int vt_bind(struct con_driver *con) -{ - const struct consw *defcsw = NULL, *csw = NULL; - int i, more = 1, first = -1, last = -1, deflt = 0; - - if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || - con_is_graphics(con->con, con->first, con->last)) - goto err; - - csw = con->con; - - for (i = 0; i < MAX_NR_CON_DRIVER; i++) { - struct con_driver *con = ®istered_con_driver[i]; - - if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) { - defcsw = con->con; - break; - } - } - - if (!defcsw) - goto err; - - while (more) { - more = 0; - - for (i = con->first; i <= con->last; i++) { - if (con_driver_map[i] == defcsw) { - if (first == -1) - first = i; - last = i; - more = 1; - } else if (first != -1) - break; - } - - if (first == 0 && last == MAX_NR_CONSOLES -1) - deflt = 1; - - if (first != -1) - bind_con_driver(csw, first, last, deflt); - - first = -1; - last = -1; - deflt = 0; - } - -err: - return 0; -} - -static int vt_unbind(struct con_driver *con) -{ - const struct consw *csw = NULL; - int i, more = 1, first = -1, last = -1, deflt = 0; - - if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || - con_is_graphics(con->con, con->first, con->last)) - goto err; - - csw = con->con; - - while (more) { - more = 0; - - for (i = con->first; i <= con->last; i++) { - if (con_driver_map[i] == csw) { - if (first == -1) - first = i; - last = i; - more = 1; - } else if (first != -1) - break; - } - - if (first == 0 && last == MAX_NR_CONSOLES -1) - deflt = 1; - - if (first != -1) - unbind_con_driver(csw, first, last, deflt); - - first = -1; - last = -1; - deflt = 0; - } - -err: - return 0; -} -#else -static inline int vt_bind(struct con_driver *con) -{ - return 0; -} -static inline int vt_unbind(struct con_driver *con) -{ - return 0; -} -#endif /* CONFIG_VT_HW_CONSOLE_BINDING */ - -static ssize_t store_bind(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct con_driver *con = dev_get_drvdata(dev); - int bind = simple_strtoul(buf, NULL, 0); - - if (bind) - vt_bind(con); - else - vt_unbind(con); - - return count; -} - -static ssize_t show_bind(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct con_driver *con = dev_get_drvdata(dev); - int bind = con_is_bound(con->con); - - return snprintf(buf, PAGE_SIZE, "%i\n", bind); -} - -static ssize_t show_name(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct con_driver *con = dev_get_drvdata(dev); - - return snprintf(buf, PAGE_SIZE, "%s %s\n", - (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)", - con->desc); - -} - -static struct device_attribute device_attrs[] = { - __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind), - __ATTR(name, S_IRUGO, show_name, NULL), -}; - -static int vtconsole_init_device(struct con_driver *con) -{ - int i; - int error = 0; - - con->flag |= CON_DRIVER_FLAG_ATTR; - dev_set_drvdata(con->dev, con); - for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { - error = device_create_file(con->dev, &device_attrs[i]); - if (error) - break; - } - - if (error) { - while (--i >= 0) - device_remove_file(con->dev, &device_attrs[i]); - con->flag &= ~CON_DRIVER_FLAG_ATTR; - } - - return error; -} - -static void vtconsole_deinit_device(struct con_driver *con) -{ - int i; - - if (con->flag & CON_DRIVER_FLAG_ATTR) { - for (i = 0; i < ARRAY_SIZE(device_attrs); i++) - device_remove_file(con->dev, &device_attrs[i]); - con->flag &= ~CON_DRIVER_FLAG_ATTR; - } -} - -/** - * con_is_bound - checks if driver is bound to the console - * @csw: console driver - * - * RETURNS: zero if unbound, nonzero if bound - * - * Drivers can call this and if zero, they should release - * all resources allocated on con_startup() - */ -int con_is_bound(const struct consw *csw) -{ - int i, bound = 0; - - for (i = 0; i < MAX_NR_CONSOLES; i++) { - if (con_driver_map[i] == csw) { - bound = 1; - break; - } - } - - return bound; -} -EXPORT_SYMBOL(con_is_bound); - -/** - * con_debug_enter - prepare the console for the kernel debugger - * @sw: console driver - * - * Called when the console is taken over by the kernel debugger, this - * function needs to save the current console state, then put the console - * into a state suitable for the kernel debugger. - * - * RETURNS: - * Zero on success, nonzero if a failure occurred when trying to prepare - * the console for the debugger. - */ -int con_debug_enter(struct vc_data *vc) -{ - int ret = 0; - - saved_fg_console = fg_console; - saved_last_console = last_console; - saved_want_console = want_console; - saved_vc_mode = vc->vc_mode; - saved_console_blanked = console_blanked; - vc->vc_mode = KD_TEXT; - console_blanked = 0; - if (vc->vc_sw->con_debug_enter) - ret = vc->vc_sw->con_debug_enter(vc); -#ifdef CONFIG_KGDB_KDB - /* Set the initial LINES variable if it is not already set */ - if (vc->vc_rows < 999) { - int linecount; - char lns[4]; - const char *setargs[3] = { - "set", - "LINES", - lns, - }; - if (kdbgetintenv(setargs[0], &linecount)) { - snprintf(lns, 4, "%i", vc->vc_rows); - kdb_set(2, setargs); - } - } -#endif /* CONFIG_KGDB_KDB */ - return ret; -} -EXPORT_SYMBOL_GPL(con_debug_enter); - -/** - * con_debug_leave - restore console state - * @sw: console driver - * - * Restore the console state to what it was before the kernel debugger - * was invoked. - * - * RETURNS: - * Zero on success, nonzero if a failure occurred when trying to restore - * the console. - */ -int con_debug_leave(void) -{ - struct vc_data *vc; - int ret = 0; - - fg_console = saved_fg_console; - last_console = saved_last_console; - want_console = saved_want_console; - console_blanked = saved_console_blanked; - vc_cons[fg_console].d->vc_mode = saved_vc_mode; - - vc = vc_cons[fg_console].d; - if (vc->vc_sw->con_debug_leave) - ret = vc->vc_sw->con_debug_leave(vc); - return ret; -} -EXPORT_SYMBOL_GPL(con_debug_leave); - -/** - * register_con_driver - register console driver to console layer - * @csw: console driver - * @first: the first console to take over, minimum value is 0 - * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1 - * - * DESCRIPTION: This function registers a console driver which can later - * bind to a range of consoles specified by @first and @last. It will - * also initialize the console driver by calling con_startup(). - */ -int register_con_driver(const struct consw *csw, int first, int last) -{ - struct module *owner = csw->owner; - struct con_driver *con_driver; - const char *desc; - int i, retval = 0; - - if (!try_module_get(owner)) - return -ENODEV; - - acquire_console_sem(); - - for (i = 0; i < MAX_NR_CON_DRIVER; i++) { - con_driver = ®istered_con_driver[i]; - - /* already registered */ - if (con_driver->con == csw) - retval = -EINVAL; - } - - if (retval) - goto err; - - desc = csw->con_startup(); - - if (!desc) - goto err; - - retval = -EINVAL; - - for (i = 0; i < MAX_NR_CON_DRIVER; i++) { - con_driver = ®istered_con_driver[i]; - - if (con_driver->con == NULL) { - con_driver->con = csw; - con_driver->desc = desc; - con_driver->node = i; - con_driver->flag = CON_DRIVER_FLAG_MODULE | - CON_DRIVER_FLAG_INIT; - con_driver->first = first; - con_driver->last = last; - retval = 0; - break; - } - } - - if (retval) - goto err; - - con_driver->dev = device_create(vtconsole_class, NULL, - MKDEV(0, con_driver->node), - NULL, "vtcon%i", - con_driver->node); - - if (IS_ERR(con_driver->dev)) { - printk(KERN_WARNING "Unable to create device for %s; " - "errno = %ld\n", con_driver->desc, - PTR_ERR(con_driver->dev)); - con_driver->dev = NULL; - } else { - vtconsole_init_device(con_driver); - } - -err: - release_console_sem(); - module_put(owner); - return retval; -} -EXPORT_SYMBOL(register_con_driver); - -/** - * unregister_con_driver - unregister console driver from console layer - * @csw: console driver - * - * DESCRIPTION: All drivers that registers to the console layer must - * call this function upon exit, or if the console driver is in a state - * where it won't be able to handle console services, such as the - * framebuffer console without loaded framebuffer drivers. - * - * The driver must unbind first prior to unregistration. - */ -int unregister_con_driver(const struct consw *csw) -{ - int i, retval = -ENODEV; - - acquire_console_sem(); - - /* cannot unregister a bound driver */ - if (con_is_bound(csw)) - goto err; - - for (i = 0; i < MAX_NR_CON_DRIVER; i++) { - struct con_driver *con_driver = ®istered_con_driver[i]; - - if (con_driver->con == csw && - con_driver->flag & CON_DRIVER_FLAG_MODULE) { - vtconsole_deinit_device(con_driver); - device_destroy(vtconsole_class, - MKDEV(0, con_driver->node)); - con_driver->con = NULL; - con_driver->desc = NULL; - con_driver->dev = NULL; - con_driver->node = 0; - con_driver->flag = 0; - con_driver->first = 0; - con_driver->last = 0; - retval = 0; - break; - } - } -err: - release_console_sem(); - return retval; -} -EXPORT_SYMBOL(unregister_con_driver); - -/* - * If we support more console drivers, this function is used - * when a driver wants to take over some existing consoles - * and become default driver for newly opened ones. - * - * take_over_console is basically a register followed by unbind - */ -int take_over_console(const struct consw *csw, int first, int last, int deflt) -{ - int err; - - err = register_con_driver(csw, first, last); - - if (!err) - bind_con_driver(csw, first, last, deflt); - - return err; -} - -/* - * give_up_console is a wrapper to unregister_con_driver. It will only - * work if driver is fully unbound. - */ -void give_up_console(const struct consw *csw) -{ - unregister_con_driver(csw); -} - -static int __init vtconsole_class_init(void) -{ - int i; - - vtconsole_class = class_create(THIS_MODULE, "vtconsole"); - if (IS_ERR(vtconsole_class)) { - printk(KERN_WARNING "Unable to create vt console class; " - "errno = %ld\n", PTR_ERR(vtconsole_class)); - vtconsole_class = NULL; - } - - /* Add system drivers to sysfs */ - for (i = 0; i < MAX_NR_CON_DRIVER; i++) { - struct con_driver *con = ®istered_con_driver[i]; - - if (con->con && !con->dev) { - con->dev = device_create(vtconsole_class, NULL, - MKDEV(0, con->node), - NULL, "vtcon%i", - con->node); - - if (IS_ERR(con->dev)) { - printk(KERN_WARNING "Unable to create " - "device for %s; errno = %ld\n", - con->desc, PTR_ERR(con->dev)); - con->dev = NULL; - } else { - vtconsole_init_device(con); - } - } - } - - return 0; -} -postcore_initcall(vtconsole_class_init); - -#endif - -/* - * Screen blanking - */ - -static int set_vesa_blanking(char __user *p) -{ - unsigned int mode; - - if (get_user(mode, p + 1)) - return -EFAULT; - - vesa_blank_mode = (mode < 4) ? mode : 0; - return 0; -} - -void do_blank_screen(int entering_gfx) -{ - struct vc_data *vc = vc_cons[fg_console].d; - int i; - - WARN_CONSOLE_UNLOCKED(); - - if (console_blanked) { - if (blank_state == blank_vesa_wait) { - blank_state = blank_off; - vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0); - } - return; - } - - /* entering graphics mode? */ - if (entering_gfx) { - hide_cursor(vc); - save_screen(vc); - vc->vc_sw->con_blank(vc, -1, 1); - console_blanked = fg_console + 1; - blank_state = blank_off; - set_origin(vc); - return; - } - - if (blank_state != blank_normal_wait) - return; - blank_state = blank_off; - - /* don't blank graphics */ - if (vc->vc_mode != KD_TEXT) { - console_blanked = fg_console + 1; - return; - } - - hide_cursor(vc); - del_timer_sync(&console_timer); - blank_timer_expired = 0; - - save_screen(vc); - /* In case we need to reset origin, blanking hook returns 1 */ - i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0); - console_blanked = fg_console + 1; - if (i) - set_origin(vc); - - if (console_blank_hook && console_blank_hook(1)) - return; - - if (vesa_off_interval && vesa_blank_mode) { - blank_state = blank_vesa_wait; - mod_timer(&console_timer, jiffies + vesa_off_interval); - } - vt_event_post(VT_EVENT_BLANK, vc->vc_num, vc->vc_num); -} -EXPORT_SYMBOL(do_blank_screen); - -/* - * Called by timer as well as from vt_console_driver - */ -void do_unblank_screen(int leaving_gfx) -{ - struct vc_data *vc; - - /* This should now always be called from a "sane" (read: can schedule) - * context for the sake of the low level drivers, except in the special - * case of oops_in_progress - */ - if (!oops_in_progress) - might_sleep(); - - WARN_CONSOLE_UNLOCKED(); - - ignore_poke = 0; - if (!console_blanked) - return; - if (!vc_cons_allocated(fg_console)) { - /* impossible */ - printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); - return; - } - vc = vc_cons[fg_console].d; - /* Try to unblank in oops case too */ - if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc)) - return; /* but leave console_blanked != 0 */ - - if (blankinterval) { - mod_timer(&console_timer, jiffies + (blankinterval * HZ)); - blank_state = blank_normal_wait; - } - - console_blanked = 0; - if (vc->vc_sw->con_blank(vc, 0, leaving_gfx) || vt_force_oops_output(vc)) - /* Low-level driver cannot restore -> do it ourselves */ - update_screen(vc); - if (console_blank_hook) - console_blank_hook(0); - set_palette(vc); - set_cursor(vc); - vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num); -} -EXPORT_SYMBOL(do_unblank_screen); - -/* - * This is called by the outside world to cause a forced unblank, mostly for - * oopses. Currently, I just call do_unblank_screen(0), but we could eventually - * call it with 1 as an argument and so force a mode restore... that may kill - * X or at least garbage the screen but would also make the Oops visible... - */ -void unblank_screen(void) -{ - do_unblank_screen(0); -} - -/* - * We defer the timer blanking to work queue so it can take the console mutex - * (console operations can still happen at irq time, but only from printk which - * has the console mutex. Not perfect yet, but better than no locking - */ -static void blank_screen_t(unsigned long dummy) -{ - if (unlikely(!keventd_up())) { - mod_timer(&console_timer, jiffies + (blankinterval * HZ)); - return; - } - blank_timer_expired = 1; - schedule_work(&console_work); -} - -void poke_blanked_console(void) -{ - WARN_CONSOLE_UNLOCKED(); - - /* Add this so we quickly catch whoever might call us in a non - * safe context. Nowadays, unblank_screen() isn't to be called in - * atomic contexts and is allowed to schedule (with the special case - * of oops_in_progress, but that isn't of any concern for this - * function. --BenH. - */ - might_sleep(); - - /* This isn't perfectly race free, but a race here would be mostly harmless, - * at worse, we'll do a spurrious blank and it's unlikely - */ - del_timer(&console_timer); - blank_timer_expired = 0; - - if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS) - return; - if (console_blanked) - unblank_screen(); - else if (blankinterval) { - mod_timer(&console_timer, jiffies + (blankinterval * HZ)); - blank_state = blank_normal_wait; - } -} - -/* - * Palettes - */ - -static void set_palette(struct vc_data *vc) -{ - WARN_CONSOLE_UNLOCKED(); - - if (vc->vc_mode != KD_GRAPHICS) - vc->vc_sw->con_set_palette(vc, color_table); -} - -static int set_get_cmap(unsigned char __user *arg, int set) -{ - int i, j, k; - - WARN_CONSOLE_UNLOCKED(); - - for (i = 0; i < 16; i++) - if (set) { - get_user(default_red[i], arg++); - get_user(default_grn[i], arg++); - get_user(default_blu[i], arg++); - } else { - put_user(default_red[i], arg++); - put_user(default_grn[i], arg++); - put_user(default_blu[i], arg++); - } - if (set) { - for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i)) { - for (j = k = 0; j < 16; j++) { - vc_cons[i].d->vc_palette[k++] = default_red[j]; - vc_cons[i].d->vc_palette[k++] = default_grn[j]; - vc_cons[i].d->vc_palette[k++] = default_blu[j]; - } - set_palette(vc_cons[i].d); - } - } - return 0; -} - -/* - * Load palette into the DAC registers. arg points to a colour - * map, 3 bytes per colour, 16 colours, range from 0 to 255. - */ - -int con_set_cmap(unsigned char __user *arg) -{ - int rc; - - acquire_console_sem(); - rc = set_get_cmap (arg,1); - release_console_sem(); - - return rc; -} - -int con_get_cmap(unsigned char __user *arg) -{ - int rc; - - acquire_console_sem(); - rc = set_get_cmap (arg,0); - release_console_sem(); - - return rc; -} - -void reset_palette(struct vc_data *vc) -{ - int j, k; - for (j=k=0; j<16; j++) { - vc->vc_palette[k++] = default_red[j]; - vc->vc_palette[k++] = default_grn[j]; - vc->vc_palette[k++] = default_blu[j]; - } - set_palette(vc); -} - -/* - * Font switching - * - * Currently we only support fonts up to 32 pixels wide, at a maximum height - * of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, - * depending on width) reserved for each character which is kinda wasty, but - * this is done in order to maintain compatibility with the EGA/VGA fonts. It - * is upto the actual low-level console-driver convert data into its favorite - * format (maybe we should add a `fontoffset' field to the `display' - * structure so we won't have to convert the fontdata all the time. - * /Jes - */ - -#define max_font_size 65536 - -static int con_font_get(struct vc_data *vc, struct console_font_op *op) -{ - struct console_font font; - int rc = -EINVAL; - int c; - - if (vc->vc_mode != KD_TEXT) - return -EINVAL; - - if (op->data) { - font.data = kmalloc(max_font_size, GFP_KERNEL); - if (!font.data) - return -ENOMEM; - } else - font.data = NULL; - - acquire_console_sem(); - if (vc->vc_sw->con_font_get) - rc = vc->vc_sw->con_font_get(vc, &font); - else - rc = -ENOSYS; - release_console_sem(); - - if (rc) - goto out; - - c = (font.width+7)/8 * 32 * font.charcount; - - if (op->data && font.charcount > op->charcount) - rc = -ENOSPC; - if (!(op->flags & KD_FONT_FLAG_OLD)) { - if (font.width > op->width || font.height > op->height) - rc = -ENOSPC; - } else { - if (font.width != 8) - rc = -EIO; - else if ((op->height && font.height > op->height) || - font.height > 32) - rc = -ENOSPC; - } - if (rc) - goto out; - - op->height = font.height; - op->width = font.width; - op->charcount = font.charcount; - - if (op->data && copy_to_user(op->data, font.data, c)) - rc = -EFAULT; - -out: - kfree(font.data); - return rc; -} - -static int con_font_set(struct vc_data *vc, struct console_font_op *op) -{ - struct console_font font; - int rc = -EINVAL; - int size; - - if (vc->vc_mode != KD_TEXT) - return -EINVAL; - if (!op->data) - return -EINVAL; - if (op->charcount > 512) - return -EINVAL; - if (!op->height) { /* Need to guess font height [compat] */ - int h, i; - u8 __user *charmap = op->data; - u8 tmp; - - /* If from KDFONTOP ioctl, don't allow things which can be done in userland, - so that we can get rid of this soon */ - if (!(op->flags & KD_FONT_FLAG_OLD)) - return -EINVAL; - for (h = 32; h > 0; h--) - for (i = 0; i < op->charcount; i++) { - if (get_user(tmp, &charmap[32*i+h-1])) - return -EFAULT; - if (tmp) - goto nonzero; - } - return -EINVAL; - nonzero: - op->height = h; - } - if (op->width <= 0 || op->width > 32 || op->height > 32) - return -EINVAL; - size = (op->width+7)/8 * 32 * op->charcount; - if (size > max_font_size) - return -ENOSPC; - font.charcount = op->charcount; - font.height = op->height; - font.width = op->width; - font.data = memdup_user(op->data, size); - if (IS_ERR(font.data)) - return PTR_ERR(font.data); - acquire_console_sem(); - if (vc->vc_sw->con_font_set) - rc = vc->vc_sw->con_font_set(vc, &font, op->flags); - else - rc = -ENOSYS; - release_console_sem(); - kfree(font.data); - return rc; -} - -static int con_font_default(struct vc_data *vc, struct console_font_op *op) -{ - struct console_font font = {.width = op->width, .height = op->height}; - char name[MAX_FONT_NAME]; - char *s = name; - int rc; - - if (vc->vc_mode != KD_TEXT) - return -EINVAL; - - if (!op->data) - s = NULL; - else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0) - return -EFAULT; - else - name[MAX_FONT_NAME - 1] = 0; - - acquire_console_sem(); - if (vc->vc_sw->con_font_default) - rc = vc->vc_sw->con_font_default(vc, &font, s); - else - rc = -ENOSYS; - release_console_sem(); - if (!rc) { - op->width = font.width; - op->height = font.height; - } - return rc; -} - -static int con_font_copy(struct vc_data *vc, struct console_font_op *op) -{ - int con = op->height; - int rc; - - if (vc->vc_mode != KD_TEXT) - return -EINVAL; - - acquire_console_sem(); - if (!vc->vc_sw->con_font_copy) - rc = -ENOSYS; - else if (con < 0 || !vc_cons_allocated(con)) - rc = -ENOTTY; - else if (con == vc->vc_num) /* nothing to do */ - rc = 0; - else - rc = vc->vc_sw->con_font_copy(vc, con); - release_console_sem(); - return rc; -} - -int con_font_op(struct vc_data *vc, struct console_font_op *op) -{ - switch (op->op) { - case KD_FONT_OP_SET: - return con_font_set(vc, op); - case KD_FONT_OP_GET: - return con_font_get(vc, op); - case KD_FONT_OP_SET_DEFAULT: - return con_font_default(vc, op); - case KD_FONT_OP_COPY: - return con_font_copy(vc, op); - } - return -ENOSYS; -} - -/* - * Interface exported to selection and vcs. - */ - -/* used by selection */ -u16 screen_glyph(struct vc_data *vc, int offset) -{ - u16 w = scr_readw(screenpos(vc, offset, 1)); - u16 c = w & 0xff; - - if (w & vc->vc_hi_font_mask) - c |= 0x100; - return c; -} -EXPORT_SYMBOL_GPL(screen_glyph); - -/* used by vcs - note the word offset */ -unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed) -{ - return screenpos(vc, 2 * w_offset, viewed); -} - -void getconsxy(struct vc_data *vc, unsigned char *p) -{ - p[0] = vc->vc_x; - p[1] = vc->vc_y; -} - -void putconsxy(struct vc_data *vc, unsigned char *p) -{ - hide_cursor(vc); - gotoxy(vc, p[0], p[1]); - set_cursor(vc); -} - -u16 vcs_scr_readw(struct vc_data *vc, const u16 *org) -{ - if ((unsigned long)org == vc->vc_pos && softcursor_original != -1) - return softcursor_original; - return scr_readw(org); -} - -void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org) -{ - scr_writew(val, org); - if ((unsigned long)org == vc->vc_pos) { - softcursor_original = -1; - add_softcursor(vc); - } -} - -void vcs_scr_updated(struct vc_data *vc) -{ - notify_update(vc); -} - -/* - * Visible symbols for modules - */ - -EXPORT_SYMBOL(color_table); -EXPORT_SYMBOL(default_red); -EXPORT_SYMBOL(default_grn); -EXPORT_SYMBOL(default_blu); -EXPORT_SYMBOL(update_region); -EXPORT_SYMBOL(redraw_screen); -EXPORT_SYMBOL(vc_resize); -EXPORT_SYMBOL(fg_console); -EXPORT_SYMBOL(console_blank_hook); -EXPORT_SYMBOL(console_blanked); -EXPORT_SYMBOL(vc_cons); -EXPORT_SYMBOL(global_cursor_default); -#ifndef VT_SINGLE_DRIVER -EXPORT_SYMBOL(take_over_console); -EXPORT_SYMBOL(give_up_console); -#endif diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c deleted file mode 100644 index 6b68a0f..0000000 --- a/drivers/char/vt_ioctl.c +++ /dev/null @@ -1,1788 +0,0 @@ -/* - * linux/drivers/char/vt_ioctl.c - * - * Copyright (C) 1992 obz under the linux copyright - * - * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 - * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 - * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 - * Some code moved for less code duplication - Andi Kleen - Mar 1997 - * Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001 - */ - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/tty.h> -#include <linux/timer.h> -#include <linux/kernel.h> -#include <linux/compat.h> -#include <linux/module.h> -#include <linux/kd.h> -#include <linux/vt.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/major.h> -#include <linux/fs.h> -#include <linux/console.h> -#include <linux/consolemap.h> -#include <linux/signal.h> -#include <linux/smp_lock.h> -#include <linux/timex.h> - -#include <asm/io.h> -#include <asm/uaccess.h> - -#include <linux/kbd_kern.h> -#include <linux/vt_kern.h> -#include <linux/kbd_diacr.h> -#include <linux/selection.h> - -char vt_dont_switch; -extern struct tty_driver *console_driver; - -#define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count) -#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons) - -/* - * Console (vt and kd) routines, as defined by USL SVR4 manual, and by - * experimentation and study of X386 SYSV handling. - * - * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and - * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, - * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will - * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to - * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using - * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing - * to the current console is done by the main ioctl code. - */ - -#ifdef CONFIG_X86 -#include <linux/syscalls.h> -#endif - -static void complete_change_console(struct vc_data *vc); - -/* - * User space VT_EVENT handlers - */ - -struct vt_event_wait { - struct list_head list; - struct vt_event event; - int done; -}; - -static LIST_HEAD(vt_events); -static DEFINE_SPINLOCK(vt_event_lock); -static DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue); - -/** - * vt_event_post - * @event: the event that occurred - * @old: old console - * @new: new console - * - * Post an VT event to interested VT handlers - */ - -void vt_event_post(unsigned int event, unsigned int old, unsigned int new) -{ - struct list_head *pos, *head; - unsigned long flags; - int wake = 0; - - spin_lock_irqsave(&vt_event_lock, flags); - head = &vt_events; - - list_for_each(pos, head) { - struct vt_event_wait *ve = list_entry(pos, - struct vt_event_wait, list); - if (!(ve->event.event & event)) - continue; - ve->event.event = event; - /* kernel view is consoles 0..n-1, user space view is - console 1..n with 0 meaning current, so we must bias */ - ve->event.oldev = old + 1; - ve->event.newev = new + 1; - wake = 1; - ve->done = 1; - } - spin_unlock_irqrestore(&vt_event_lock, flags); - if (wake) - wake_up_interruptible(&vt_event_waitqueue); -} - -/** - * vt_event_wait - wait for an event - * @vw: our event - * - * Waits for an event to occur which completes our vt_event_wait - * structure. On return the structure has wv->done set to 1 for success - * or 0 if some event such as a signal ended the wait. - */ - -static void vt_event_wait(struct vt_event_wait *vw) -{ - unsigned long flags; - /* Prepare the event */ - INIT_LIST_HEAD(&vw->list); - vw->done = 0; - /* Queue our event */ - spin_lock_irqsave(&vt_event_lock, flags); - list_add(&vw->list, &vt_events); - spin_unlock_irqrestore(&vt_event_lock, flags); - /* Wait for it to pass */ - wait_event_interruptible_tty(vt_event_waitqueue, vw->done); - /* Dequeue it */ - spin_lock_irqsave(&vt_event_lock, flags); - list_del(&vw->list); - spin_unlock_irqrestore(&vt_event_lock, flags); -} - -/** - * vt_event_wait_ioctl - event ioctl handler - * @arg: argument to ioctl - * - * Implement the VT_WAITEVENT ioctl using the VT event interface - */ - -static int vt_event_wait_ioctl(struct vt_event __user *event) -{ - struct vt_event_wait vw; - - if (copy_from_user(&vw.event, event, sizeof(struct vt_event))) - return -EFAULT; - /* Highest supported event for now */ - if (vw.event.event & ~VT_MAX_EVENT) - return -EINVAL; - - vt_event_wait(&vw); - /* If it occurred report it */ - if (vw.done) { - if (copy_to_user(event, &vw.event, sizeof(struct vt_event))) - return -EFAULT; - return 0; - } - return -EINTR; -} - -/** - * vt_waitactive - active console wait - * @event: event code - * @n: new console - * - * Helper for event waits. Used to implement the legacy - * event waiting ioctls in terms of events - */ - -int vt_waitactive(int n) -{ - struct vt_event_wait vw; - do { - if (n == fg_console + 1) - break; - vw.event.event = VT_EVENT_SWITCH; - vt_event_wait(&vw); - if (vw.done == 0) - return -EINTR; - } while (vw.event.newev != n); - return 0; -} - -/* - * these are the valid i/o ports we're allowed to change. they map all the - * video ports - */ -#define GPFIRST 0x3b4 -#define GPLAST 0x3df -#define GPNUM (GPLAST - GPFIRST + 1) - -#define i (tmp.kb_index) -#define s (tmp.kb_table) -#define v (tmp.kb_value) -static inline int -do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd) -{ - struct kbentry tmp; - ushort *key_map, val, ov; - - if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) - return -EFAULT; - - if (!capable(CAP_SYS_TTY_CONFIG)) - perm = 0; - - switch (cmd) { - case KDGKBENT: - key_map = key_maps[s]; - if (key_map) { - val = U(key_map[i]); - if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) - val = K_HOLE; - } else - val = (i ? K_HOLE : K_NOSUCHMAP); - return put_user(val, &user_kbe->kb_value); - case KDSKBENT: - if (!perm) - return -EPERM; - if (!i && v == K_NOSUCHMAP) { - /* deallocate map */ - key_map = key_maps[s]; - if (s && key_map) { - key_maps[s] = NULL; - if (key_map[0] == U(K_ALLOCATED)) { - kfree(key_map); - keymap_count--; - } - } - break; - } - - if (KTYP(v) < NR_TYPES) { - if (KVAL(v) > max_vals[KTYP(v)]) - return -EINVAL; - } else - if (kbd->kbdmode != VC_UNICODE) - return -EINVAL; - - /* ++Geert: non-PC keyboards may generate keycode zero */ -#if !defined(__mc68000__) && !defined(__powerpc__) - /* assignment to entry 0 only tests validity of args */ - if (!i) - break; -#endif - - if (!(key_map = key_maps[s])) { - int j; - - if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && - !capable(CAP_SYS_RESOURCE)) - return -EPERM; - - key_map = kmalloc(sizeof(plain_map), - GFP_KERNEL); - if (!key_map) - return -ENOMEM; - key_maps[s] = key_map; - key_map[0] = U(K_ALLOCATED); - for (j = 1; j < NR_KEYS; j++) - key_map[j] = U(K_HOLE); - keymap_count++; - } - ov = U(key_map[i]); - if (v == ov) - break; /* nothing to do */ - /* - * Attention Key. - */ - if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) - return -EPERM; - key_map[i] = U(v); - if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) - compute_shiftstate(); - break; - } - return 0; -} -#undef i -#undef s -#undef v - -static inline int -do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm) -{ - struct kbkeycode tmp; - int kc = 0; - - if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) - return -EFAULT; - switch (cmd) { - case KDGETKEYCODE: - kc = getkeycode(tmp.scancode); - if (kc >= 0) - kc = put_user(kc, &user_kbkc->keycode); - break; - case KDSETKEYCODE: - if (!perm) - return -EPERM; - kc = setkeycode(tmp.scancode, tmp.keycode); - break; - } - return kc; -} - -static inline int -do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) -{ - struct kbsentry *kbs; - char *p; - u_char *q; - u_char __user *up; - int sz; - int delta; - char *first_free, *fj, *fnw; - int i, j, k; - int ret; - - if (!capable(CAP_SYS_TTY_CONFIG)) - perm = 0; - - kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); - if (!kbs) { - ret = -ENOMEM; - goto reterr; - } - - /* we mostly copy too much here (512bytes), but who cares ;) */ - if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { - ret = -EFAULT; - goto reterr; - } - kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; - i = kbs->kb_func; - - switch (cmd) { - case KDGKBSENT: - sz = sizeof(kbs->kb_string) - 1; /* sz should have been - a struct member */ - up = user_kdgkb->kb_string; - p = func_table[i]; - if(p) - for ( ; *p && sz; p++, sz--) - if (put_user(*p, up++)) { - ret = -EFAULT; - goto reterr; - } - if (put_user('\0', up)) { - ret = -EFAULT; - goto reterr; - } - kfree(kbs); - return ((p && *p) ? -EOVERFLOW : 0); - case KDSKBSENT: - if (!perm) { - ret = -EPERM; - goto reterr; - } - - q = func_table[i]; - first_free = funcbufptr + (funcbufsize - funcbufleft); - for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) - ; - if (j < MAX_NR_FUNC) - fj = func_table[j]; - else - fj = first_free; - - delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); - if (delta <= funcbufleft) { /* it fits in current buf */ - if (j < MAX_NR_FUNC) { - memmove(fj + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] += delta; - } - if (!q) - func_table[i] = fj; - funcbufleft -= delta; - } else { /* allocate a larger buffer */ - sz = 256; - while (sz < funcbufsize - funcbufleft + delta) - sz <<= 1; - fnw = kmalloc(sz, GFP_KERNEL); - if(!fnw) { - ret = -ENOMEM; - goto reterr; - } - - if (!q) - func_table[i] = fj; - if (fj > funcbufptr) - memmove(fnw, funcbufptr, fj - funcbufptr); - for (k = 0; k < j; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr); - - if (first_free > fj) { - memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; - } - if (funcbufptr != func_buf) - kfree(funcbufptr); - funcbufptr = fnw; - funcbufleft = funcbufleft - delta + sz - funcbufsize; - funcbufsize = sz; - } - strcpy(func_table[i], kbs->kb_string); - break; - } - ret = 0; -reterr: - kfree(kbs); - return ret; -} - -static inline int -do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op) -{ - struct consolefontdesc cfdarg; - int i; - - if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) - return -EFAULT; - - switch (cmd) { - case PIO_FONTX: - if (!perm) - return -EPERM; - op->op = KD_FONT_OP_SET; - op->flags = KD_FONT_FLAG_OLD; - op->width = 8; - op->height = cfdarg.charheight; - op->charcount = cfdarg.charcount; - op->data = cfdarg.chardata; - return con_font_op(vc_cons[fg_console].d, op); - case GIO_FONTX: { - op->op = KD_FONT_OP_GET; - op->flags = KD_FONT_FLAG_OLD; - op->width = 8; - op->height = cfdarg.charheight; - op->charcount = cfdarg.charcount; - op->data = cfdarg.chardata; - i = con_font_op(vc_cons[fg_console].d, op); - if (i) - return i; - cfdarg.charheight = op->height; - cfdarg.charcount = op->charcount; - if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc))) - return -EFAULT; - return 0; - } - } - return -EINVAL; -} - -static inline int -do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc) -{ - struct unimapdesc tmp; - - if (copy_from_user(&tmp, user_ud, sizeof tmp)) - return -EFAULT; - if (tmp.entries) - if (!access_ok(VERIFY_WRITE, tmp.entries, - tmp.entry_ct*sizeof(struct unipair))) - return -EFAULT; - switch (cmd) { - case PIO_UNIMAP: - if (!perm) - return -EPERM; - return con_set_unimap(vc, tmp.entry_ct, tmp.entries); - case GIO_UNIMAP: - if (!perm && fg_console != vc->vc_num) - return -EPERM; - return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); - } - return 0; -} - - - -/* - * We handle the console-specific ioctl's here. We allow the - * capability to modify any console, not just the fg_console. - */ -int vt_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct vc_data *vc = tty->driver_data; - struct console_font_op op; /* used in multiple places here */ - struct kbd_struct * kbd; - unsigned int console; - unsigned char ucval; - unsigned int uival; - void __user *up = (void __user *)arg; - int i, perm; - int ret = 0; - - console = vc->vc_num; - - tty_lock(); - - if (!vc_cons_allocated(console)) { /* impossible? */ - ret = -ENOIOCTLCMD; - goto out; - } - - - /* - * To have permissions to do most of the vt ioctls, we either have - * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. - */ - perm = 0; - if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) - perm = 1; - - kbd = kbd_table + console; - switch (cmd) { - case TIOCLINUX: - ret = tioclinux(tty, arg); - break; - case KIOCSOUND: - if (!perm) - goto eperm; - /* - * The use of PIT_TICK_RATE is historic, it used to be - * the platform-dependent CLOCK_TICK_RATE between 2.6.12 - * and 2.6.36, which was a minor but unfortunate ABI - * change. - */ - if (arg) - arg = PIT_TICK_RATE / arg; - kd_mksound(arg, 0); - break; - - case KDMKTONE: - if (!perm) - goto eperm; - { - unsigned int ticks, count; - - /* - * Generate the tone for the appropriate number of ticks. - * If the time is zero, turn off sound ourselves. - */ - ticks = HZ * ((arg >> 16) & 0xffff) / 1000; - count = ticks ? (arg & 0xffff) : 0; - if (count) - count = PIT_TICK_RATE / count; - kd_mksound(count, ticks); - break; - } - - case KDGKBTYPE: - /* - * this is naive. - */ - ucval = KB_101; - goto setchar; - - /* - * These cannot be implemented on any machine that implements - * ioperm() in user level (such as Alpha PCs) or not at all. - * - * XXX: you should never use these, just call ioperm directly.. - */ -#ifdef CONFIG_X86 - case KDADDIO: - case KDDELIO: - /* - * KDADDIO and KDDELIO may be able to add ports beyond what - * we reject here, but to be safe... - */ - if (arg < GPFIRST || arg > GPLAST) { - ret = -EINVAL; - break; - } - ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; - break; - - case KDENABIO: - case KDDISABIO: - ret = sys_ioperm(GPFIRST, GPNUM, - (cmd == KDENABIO)) ? -ENXIO : 0; - break; -#endif - - /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */ - - case KDKBDREP: - { - struct kbd_repeat kbrep; - - if (!capable(CAP_SYS_TTY_CONFIG)) - goto eperm; - - if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) { - ret = -EFAULT; - break; - } - ret = kbd_rate(&kbrep); - if (ret) - break; - if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat))) - ret = -EFAULT; - break; - } - - case KDSETMODE: - /* - * currently, setting the mode from KD_TEXT to KD_GRAPHICS - * doesn't do a whole lot. i'm not sure if it should do any - * restoration of modes or what... - * - * XXX It should at least call into the driver, fbdev's definitely - * need to restore their engine state. --BenH - */ - if (!perm) - goto eperm; - switch (arg) { - case KD_GRAPHICS: - break; - case KD_TEXT0: - case KD_TEXT1: - arg = KD_TEXT; - case KD_TEXT: - break; - default: - ret = -EINVAL; - goto out; - } - if (vc->vc_mode == (unsigned char) arg) - break; - vc->vc_mode = (unsigned char) arg; - if (console != fg_console) - break; - /* - * explicitly blank/unblank the screen if switching modes - */ - acquire_console_sem(); - if (arg == KD_TEXT) - do_unblank_screen(1); - else - do_blank_screen(1); - release_console_sem(); - break; - - case KDGETMODE: - uival = vc->vc_mode; - goto setint; - - case KDMAPDISP: - case KDUNMAPDISP: - /* - * these work like a combination of mmap and KDENABIO. - * this could be easily finished. - */ - ret = -EINVAL; - break; - - case KDSKBMODE: - if (!perm) - goto eperm; - switch(arg) { - case K_RAW: - kbd->kbdmode = VC_RAW; - break; - case K_MEDIUMRAW: - kbd->kbdmode = VC_MEDIUMRAW; - break; - case K_XLATE: - kbd->kbdmode = VC_XLATE; - compute_shiftstate(); - break; - case K_UNICODE: - kbd->kbdmode = VC_UNICODE; - compute_shiftstate(); - break; - default: - ret = -EINVAL; - goto out; - } - tty_ldisc_flush(tty); - break; - - case KDGKBMODE: - uival = ((kbd->kbdmode == VC_RAW) ? K_RAW : - (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : - (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : - K_XLATE); - goto setint; - - /* this could be folded into KDSKBMODE, but for compatibility - reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ - case KDSKBMETA: - switch(arg) { - case K_METABIT: - clr_vc_kbd_mode(kbd, VC_META); - break; - case K_ESCPREFIX: - set_vc_kbd_mode(kbd, VC_META); - break; - default: - ret = -EINVAL; - } - break; - - case KDGKBMETA: - uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); - setint: - ret = put_user(uival, (int __user *)arg); - break; - - case KDGETKEYCODE: - case KDSETKEYCODE: - if(!capable(CAP_SYS_TTY_CONFIG)) - perm = 0; - ret = do_kbkeycode_ioctl(cmd, up, perm); - break; - - case KDGKBENT: - case KDSKBENT: - ret = do_kdsk_ioctl(cmd, up, perm, kbd); - break; - - case KDGKBSENT: - case KDSKBSENT: - ret = do_kdgkb_ioctl(cmd, up, perm); - break; - - case KDGKBDIACR: - { - struct kbdiacrs __user *a = up; - struct kbdiacr diacr; - int i; - - if (put_user(accent_table_size, &a->kb_cnt)) { - ret = -EFAULT; - break; - } - for (i = 0; i < accent_table_size; i++) { - diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr); - diacr.base = conv_uni_to_8bit(accent_table[i].base); - diacr.result = conv_uni_to_8bit(accent_table[i].result); - if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) { - ret = -EFAULT; - break; - } - } - break; - } - case KDGKBDIACRUC: - { - struct kbdiacrsuc __user *a = up; - - if (put_user(accent_table_size, &a->kb_cnt)) - ret = -EFAULT; - else if (copy_to_user(a->kbdiacruc, accent_table, - accent_table_size*sizeof(struct kbdiacruc))) - ret = -EFAULT; - break; - } - - case KDSKBDIACR: - { - struct kbdiacrs __user *a = up; - struct kbdiacr diacr; - unsigned int ct; - int i; - - if (!perm) - goto eperm; - if (get_user(ct,&a->kb_cnt)) { - ret = -EFAULT; - break; - } - if (ct >= MAX_DIACR) { - ret = -EINVAL; - break; - } - accent_table_size = ct; - for (i = 0; i < ct; i++) { - if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) { - ret = -EFAULT; - break; - } - accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr); - accent_table[i].base = conv_8bit_to_uni(diacr.base); - accent_table[i].result = conv_8bit_to_uni(diacr.result); - } - break; - } - - case KDSKBDIACRUC: - { - struct kbdiacrsuc __user *a = up; - unsigned int ct; - - if (!perm) - goto eperm; - if (get_user(ct,&a->kb_cnt)) { - ret = -EFAULT; - break; - } - if (ct >= MAX_DIACR) { - ret = -EINVAL; - break; - } - accent_table_size = ct; - if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc))) - ret = -EFAULT; - break; - } - - /* the ioctls below read/set the flags usually shown in the leds */ - /* don't use them - they will go away without warning */ - case KDGKBLED: - ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); - goto setchar; - - case KDSKBLED: - if (!perm) - goto eperm; - if (arg & ~0x77) { - ret = -EINVAL; - break; - } - kbd->ledflagstate = (arg & 7); - kbd->default_ledflagstate = ((arg >> 4) & 7); - set_leds(); - break; - - /* the ioctls below only set the lights, not the functions */ - /* for those, see KDGKBLED and KDSKBLED above */ - case KDGETLED: - ucval = getledstate(); - setchar: - ret = put_user(ucval, (char __user *)arg); - break; - - case KDSETLED: - if (!perm) - goto eperm; - setledstate(kbd, arg); - break; - - /* - * A process can indicate its willingness to accept signals - * generated by pressing an appropriate key combination. - * Thus, one can have a daemon that e.g. spawns a new console - * upon a keypress and then changes to it. - * See also the kbrequest field of inittab(5). - */ - case KDSIGACCEPT: - { - if (!perm || !capable(CAP_KILL)) - goto eperm; - if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) - ret = -EINVAL; - else { - spin_lock_irq(&vt_spawn_con.lock); - put_pid(vt_spawn_con.pid); - vt_spawn_con.pid = get_pid(task_pid(current)); - vt_spawn_con.sig = arg; - spin_unlock_irq(&vt_spawn_con.lock); - } - break; - } - - case VT_SETMODE: - { - struct vt_mode tmp; - - if (!perm) - goto eperm; - if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) { - ret = -EFAULT; - goto out; - } - if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) { - ret = -EINVAL; - goto out; - } - acquire_console_sem(); - vc->vt_mode = tmp; - /* the frsig is ignored, so we set it to 0 */ - vc->vt_mode.frsig = 0; - put_pid(vc->vt_pid); - vc->vt_pid = get_pid(task_pid(current)); - /* no switch is required -- saw@shade.msu.ru */ - vc->vt_newvt = -1; - release_console_sem(); - break; - } - - case VT_GETMODE: - { - struct vt_mode tmp; - int rc; - - acquire_console_sem(); - memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode)); - release_console_sem(); - - rc = copy_to_user(up, &tmp, sizeof(struct vt_mode)); - if (rc) - ret = -EFAULT; - break; - } - - /* - * Returns global vt state. Note that VT 0 is always open, since - * it's an alias for the current VT, and people can't use it here. - * We cannot return state for more than 16 VTs, since v_state is short. - */ - case VT_GETSTATE: - { - struct vt_stat __user *vtstat = up; - unsigned short state, mask; - - if (put_user(fg_console + 1, &vtstat->v_active)) - ret = -EFAULT; - else { - state = 1; /* /dev/tty0 is always open */ - for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; - ++i, mask <<= 1) - if (VT_IS_IN_USE(i)) - state |= mask; - ret = put_user(state, &vtstat->v_state); - } - break; - } - - /* - * Returns the first available (non-opened) console. - */ - case VT_OPENQRY: - for (i = 0; i < MAX_NR_CONSOLES; ++i) - if (! VT_IS_IN_USE(i)) - break; - uival = i < MAX_NR_CONSOLES ? (i+1) : -1; - goto setint; - - /* - * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, - * with num >= 1 (switches to vt 0, our console, are not allowed, just - * to preserve sanity). - */ - case VT_ACTIVATE: - if (!perm) - goto eperm; - if (arg == 0 || arg > MAX_NR_CONSOLES) - ret = -ENXIO; - else { - arg--; - acquire_console_sem(); - ret = vc_allocate(arg); - release_console_sem(); - if (ret) - break; - set_console(arg); - } - break; - - case VT_SETACTIVATE: - { - struct vt_setactivate vsa; - - if (!perm) - goto eperm; - - if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg, - sizeof(struct vt_setactivate))) { - ret = -EFAULT; - goto out; - } - if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES) - ret = -ENXIO; - else { - vsa.console--; - acquire_console_sem(); - ret = vc_allocate(vsa.console); - if (ret == 0) { - struct vc_data *nvc; - /* This is safe providing we don't drop the - console sem between vc_allocate and - finishing referencing nvc */ - nvc = vc_cons[vsa.console].d; - nvc->vt_mode = vsa.mode; - nvc->vt_mode.frsig = 0; - put_pid(nvc->vt_pid); - nvc->vt_pid = get_pid(task_pid(current)); - } - release_console_sem(); - if (ret) - break; - /* Commence switch and lock */ - set_console(arg); - } - } - - /* - * wait until the specified VT has been activated - */ - case VT_WAITACTIVE: - if (!perm) - goto eperm; - if (arg == 0 || arg > MAX_NR_CONSOLES) - ret = -ENXIO; - else - ret = vt_waitactive(arg); - break; - - /* - * If a vt is under process control, the kernel will not switch to it - * immediately, but postpone the operation until the process calls this - * ioctl, allowing the switch to complete. - * - * According to the X sources this is the behavior: - * 0: pending switch-from not OK - * 1: pending switch-from OK - * 2: completed switch-to OK - */ - case VT_RELDISP: - if (!perm) - goto eperm; - - if (vc->vt_mode.mode != VT_PROCESS) { - ret = -EINVAL; - break; - } - /* - * Switching-from response - */ - acquire_console_sem(); - if (vc->vt_newvt >= 0) { - if (arg == 0) - /* - * Switch disallowed, so forget we were trying - * to do it. - */ - vc->vt_newvt = -1; - - else { - /* - * The current vt has been released, so - * complete the switch. - */ - int newvt; - newvt = vc->vt_newvt; - vc->vt_newvt = -1; - ret = vc_allocate(newvt); - if (ret) { - release_console_sem(); - break; - } - /* - * When we actually do the console switch, - * make sure we are atomic with respect to - * other console switches.. - */ - complete_change_console(vc_cons[newvt].d); - } - } else { - /* - * Switched-to response - */ - /* - * If it's just an ACK, ignore it - */ - if (arg != VT_ACKACQ) - ret = -EINVAL; - } - release_console_sem(); - break; - - /* - * Disallocate memory associated to VT (but leave VT1) - */ - case VT_DISALLOCATE: - if (arg > MAX_NR_CONSOLES) { - ret = -ENXIO; - break; - } - if (arg == 0) { - /* deallocate all unused consoles, but leave 0 */ - acquire_console_sem(); - for (i=1; i<MAX_NR_CONSOLES; i++) - if (! VT_BUSY(i)) - vc_deallocate(i); - release_console_sem(); - } else { - /* deallocate a single console, if possible */ - arg--; - if (VT_BUSY(arg)) - ret = -EBUSY; - else if (arg) { /* leave 0 */ - acquire_console_sem(); - vc_deallocate(arg); - release_console_sem(); - } - } - break; - - case VT_RESIZE: - { - struct vt_sizes __user *vtsizes = up; - struct vc_data *vc; - - ushort ll,cc; - if (!perm) - goto eperm; - if (get_user(ll, &vtsizes->v_rows) || - get_user(cc, &vtsizes->v_cols)) - ret = -EFAULT; - else { - acquire_console_sem(); - for (i = 0; i < MAX_NR_CONSOLES; i++) { - vc = vc_cons[i].d; - - if (vc) { - vc->vc_resize_user = 1; - vc_resize(vc_cons[i].d, cc, ll); - } - } - release_console_sem(); - } - break; - } - - case VT_RESIZEX: - { - struct vt_consize __user *vtconsize = up; - ushort ll,cc,vlin,clin,vcol,ccol; - if (!perm) - goto eperm; - if (!access_ok(VERIFY_READ, vtconsize, - sizeof(struct vt_consize))) { - ret = -EFAULT; - break; - } - /* FIXME: Should check the copies properly */ - __get_user(ll, &vtconsize->v_rows); - __get_user(cc, &vtconsize->v_cols); - __get_user(vlin, &vtconsize->v_vlin); - __get_user(clin, &vtconsize->v_clin); - __get_user(vcol, &vtconsize->v_vcol); - __get_user(ccol, &vtconsize->v_ccol); - vlin = vlin ? vlin : vc->vc_scan_lines; - if (clin) { - if (ll) { - if (ll != vlin/clin) { - /* Parameters don't add up */ - ret = -EINVAL; - break; - } - } else - ll = vlin/clin; - } - if (vcol && ccol) { - if (cc) { - if (cc != vcol/ccol) { - ret = -EINVAL; - break; - } - } else - cc = vcol/ccol; - } - - if (clin > 32) { - ret = -EINVAL; - break; - } - - for (i = 0; i < MAX_NR_CONSOLES; i++) { - if (!vc_cons[i].d) - continue; - acquire_console_sem(); - if (vlin) - vc_cons[i].d->vc_scan_lines = vlin; - if (clin) - vc_cons[i].d->vc_font.height = clin; - vc_cons[i].d->vc_resize_user = 1; - vc_resize(vc_cons[i].d, cc, ll); - release_console_sem(); - } - break; - } - - case PIO_FONT: { - if (!perm) - goto eperm; - op.op = KD_FONT_OP_SET; - op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ - op.width = 8; - op.height = 0; - op.charcount = 256; - op.data = up; - ret = con_font_op(vc_cons[fg_console].d, &op); - break; - } - - case GIO_FONT: { - op.op = KD_FONT_OP_GET; - op.flags = KD_FONT_FLAG_OLD; - op.width = 8; - op.height = 32; - op.charcount = 256; - op.data = up; - ret = con_font_op(vc_cons[fg_console].d, &op); - break; - } - - case PIO_CMAP: - if (!perm) - ret = -EPERM; - else - ret = con_set_cmap(up); - break; - - case GIO_CMAP: - ret = con_get_cmap(up); - break; - - case PIO_FONTX: - case GIO_FONTX: - ret = do_fontx_ioctl(cmd, up, perm, &op); - break; - - case PIO_FONTRESET: - { - if (!perm) - goto eperm; - -#ifdef BROKEN_GRAPHICS_PROGRAMS - /* With BROKEN_GRAPHICS_PROGRAMS defined, the default - font is not saved. */ - ret = -ENOSYS; - break; -#else - { - op.op = KD_FONT_OP_SET_DEFAULT; - op.data = NULL; - ret = con_font_op(vc_cons[fg_console].d, &op); - if (ret) - break; - con_set_default_unimap(vc_cons[fg_console].d); - break; - } -#endif - } - - case KDFONTOP: { - if (copy_from_user(&op, up, sizeof(op))) { - ret = -EFAULT; - break; - } - if (!perm && op.op != KD_FONT_OP_GET) - goto eperm; - ret = con_font_op(vc, &op); - if (ret) - break; - if (copy_to_user(up, &op, sizeof(op))) - ret = -EFAULT; - break; - } - - case PIO_SCRNMAP: - if (!perm) - ret = -EPERM; - else - ret = con_set_trans_old(up); - break; - - case GIO_SCRNMAP: - ret = con_get_trans_old(up); - break; - - case PIO_UNISCRNMAP: - if (!perm) - ret = -EPERM; - else - ret = con_set_trans_new(up); - break; - - case GIO_UNISCRNMAP: - ret = con_get_trans_new(up); - break; - - case PIO_UNIMAPCLR: - { struct unimapinit ui; - if (!perm) - goto eperm; - ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); - if (ret) - ret = -EFAULT; - else - con_clear_unimap(vc, &ui); - break; - } - - case PIO_UNIMAP: - case GIO_UNIMAP: - ret = do_unimap_ioctl(cmd, up, perm, vc); - break; - - case VT_LOCKSWITCH: - if (!capable(CAP_SYS_TTY_CONFIG)) - goto eperm; - vt_dont_switch = 1; - break; - case VT_UNLOCKSWITCH: - if (!capable(CAP_SYS_TTY_CONFIG)) - goto eperm; - vt_dont_switch = 0; - break; - case VT_GETHIFONTMASK: - ret = put_user(vc->vc_hi_font_mask, - (unsigned short __user *)arg); - break; - case VT_WAITEVENT: - ret = vt_event_wait_ioctl((struct vt_event __user *)arg); - break; - default: - ret = -ENOIOCTLCMD; - } -out: - tty_unlock(); - return ret; -eperm: - ret = -EPERM; - goto out; -} - -void reset_vc(struct vc_data *vc) -{ - vc->vc_mode = KD_TEXT; - kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; - vc->vt_mode.mode = VT_AUTO; - vc->vt_mode.waitv = 0; - vc->vt_mode.relsig = 0; - vc->vt_mode.acqsig = 0; - vc->vt_mode.frsig = 0; - put_pid(vc->vt_pid); - vc->vt_pid = NULL; - vc->vt_newvt = -1; - if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ - reset_palette(vc); -} - -void vc_SAK(struct work_struct *work) -{ - struct vc *vc_con = - container_of(work, struct vc, SAK_work); - struct vc_data *vc; - struct tty_struct *tty; - - acquire_console_sem(); - vc = vc_con->d; - if (vc) { - tty = vc->port.tty; - /* - * SAK should also work in all raw modes and reset - * them properly. - */ - if (tty) - __do_SAK(tty); - reset_vc(vc); - } - release_console_sem(); -} - -#ifdef CONFIG_COMPAT - -struct compat_consolefontdesc { - unsigned short charcount; /* characters in font (256 or 512) */ - unsigned short charheight; /* scan lines per character (1-32) */ - compat_caddr_t chardata; /* font data in expanded form */ -}; - -static inline int -compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd, - int perm, struct console_font_op *op) -{ - struct compat_consolefontdesc cfdarg; - int i; - - if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc))) - return -EFAULT; - - switch (cmd) { - case PIO_FONTX: - if (!perm) - return -EPERM; - op->op = KD_FONT_OP_SET; - op->flags = KD_FONT_FLAG_OLD; - op->width = 8; - op->height = cfdarg.charheight; - op->charcount = cfdarg.charcount; - op->data = compat_ptr(cfdarg.chardata); - return con_font_op(vc_cons[fg_console].d, op); - case GIO_FONTX: - op->op = KD_FONT_OP_GET; - op->flags = KD_FONT_FLAG_OLD; - op->width = 8; - op->height = cfdarg.charheight; - op->charcount = cfdarg.charcount; - op->data = compat_ptr(cfdarg.chardata); - i = con_font_op(vc_cons[fg_console].d, op); - if (i) - return i; - cfdarg.charheight = op->height; - cfdarg.charcount = op->charcount; - if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc))) - return -EFAULT; - return 0; - } - return -EINVAL; -} - -struct compat_console_font_op { - compat_uint_t op; /* operation code KD_FONT_OP_* */ - compat_uint_t flags; /* KD_FONT_FLAG_* */ - compat_uint_t width, height; /* font size */ - compat_uint_t charcount; - compat_caddr_t data; /* font data with height fixed to 32 */ -}; - -static inline int -compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop, - int perm, struct console_font_op *op, struct vc_data *vc) -{ - int i; - - if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op))) - return -EFAULT; - if (!perm && op->op != KD_FONT_OP_GET) - return -EPERM; - op->data = compat_ptr(((struct compat_console_font_op *)op)->data); - op->flags |= KD_FONT_FLAG_OLD; - i = con_font_op(vc, op); - if (i) - return i; - ((struct compat_console_font_op *)op)->data = (unsigned long)op->data; - if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op))) - return -EFAULT; - return 0; -} - -struct compat_unimapdesc { - unsigned short entry_ct; - compat_caddr_t entries; -}; - -static inline int -compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud, - int perm, struct vc_data *vc) -{ - struct compat_unimapdesc tmp; - struct unipair __user *tmp_entries; - - if (copy_from_user(&tmp, user_ud, sizeof tmp)) - return -EFAULT; - tmp_entries = compat_ptr(tmp.entries); - if (tmp_entries) - if (!access_ok(VERIFY_WRITE, tmp_entries, - tmp.entry_ct*sizeof(struct unipair))) - return -EFAULT; - switch (cmd) { - case PIO_UNIMAP: - if (!perm) - return -EPERM; - return con_set_unimap(vc, tmp.entry_ct, tmp_entries); - case GIO_UNIMAP: - if (!perm && fg_console != vc->vc_num) - return -EPERM; - return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries); - } - return 0; -} - -long vt_compat_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct vc_data *vc = tty->driver_data; - struct console_font_op op; /* used in multiple places here */ - struct kbd_struct *kbd; - unsigned int console; - void __user *up = (void __user *)arg; - int perm; - int ret = 0; - - console = vc->vc_num; - - tty_lock(); - - if (!vc_cons_allocated(console)) { /* impossible? */ - ret = -ENOIOCTLCMD; - goto out; - } - - /* - * To have permissions to do most of the vt ioctls, we either have - * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. - */ - perm = 0; - if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) - perm = 1; - - kbd = kbd_table + console; - switch (cmd) { - /* - * these need special handlers for incompatible data structures - */ - case PIO_FONTX: - case GIO_FONTX: - ret = compat_fontx_ioctl(cmd, up, perm, &op); - break; - - case KDFONTOP: - ret = compat_kdfontop_ioctl(up, perm, &op, vc); - break; - - case PIO_UNIMAP: - case GIO_UNIMAP: - ret = compat_unimap_ioctl(cmd, up, perm, vc); - break; - - /* - * all these treat 'arg' as an integer - */ - case KIOCSOUND: - case KDMKTONE: -#ifdef CONFIG_X86 - case KDADDIO: - case KDDELIO: -#endif - case KDSETMODE: - case KDMAPDISP: - case KDUNMAPDISP: - case KDSKBMODE: - case KDSKBMETA: - case KDSKBLED: - case KDSETLED: - case KDSIGACCEPT: - case VT_ACTIVATE: - case VT_WAITACTIVE: - case VT_RELDISP: - case VT_DISALLOCATE: - case VT_RESIZE: - case VT_RESIZEX: - goto fallback; - - /* - * the rest has a compatible data structure behind arg, - * but we have to convert it to a proper 64 bit pointer. - */ - default: - arg = (unsigned long)compat_ptr(arg); - goto fallback; - } -out: - tty_unlock(); - return ret; - -fallback: - tty_unlock(); - return vt_ioctl(tty, file, cmd, arg); -} - - -#endif /* CONFIG_COMPAT */ - - -/* - * Performs the back end of a vt switch. Called under the console - * semaphore. - */ -static void complete_change_console(struct vc_data *vc) -{ - unsigned char old_vc_mode; - int old = fg_console; - - last_console = fg_console; - - /* - * If we're switching, we could be going from KD_GRAPHICS to - * KD_TEXT mode or vice versa, which means we need to blank or - * unblank the screen later. - */ - old_vc_mode = vc_cons[fg_console].d->vc_mode; - switch_screen(vc); - - /* - * This can't appear below a successful kill_pid(). If it did, - * then the *blank_screen operation could occur while X, having - * received acqsig, is waking up on another processor. This - * condition can lead to overlapping accesses to the VGA range - * and the framebuffer (causing system lockups). - * - * To account for this we duplicate this code below only if the - * controlling process is gone and we've called reset_vc. - */ - if (old_vc_mode != vc->vc_mode) { - if (vc->vc_mode == KD_TEXT) - do_unblank_screen(1); - else - do_blank_screen(1); - } - - /* - * If this new console is under process control, send it a signal - * telling it that it has acquired. Also check if it has died and - * clean up (similar to logic employed in change_console()) - */ - if (vc->vt_mode.mode == VT_PROCESS) { - /* - * Send the signal as privileged - kill_pid() will - * tell us if the process has gone or something else - * is awry - */ - if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) { - /* - * The controlling process has died, so we revert back to - * normal operation. In this case, we'll also change back - * to KD_TEXT mode. I'm not sure if this is strictly correct - * but it saves the agony when the X server dies and the screen - * remains blanked due to KD_GRAPHICS! It would be nice to do - * this outside of VT_PROCESS but there is no single process - * to account for and tracking tty count may be undesirable. - */ - reset_vc(vc); - - if (old_vc_mode != vc->vc_mode) { - if (vc->vc_mode == KD_TEXT) - do_unblank_screen(1); - else - do_blank_screen(1); - } - } - } - - /* - * Wake anyone waiting for their VT to activate - */ - vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num); - return; -} - -/* - * Performs the front-end of a vt switch - */ -void change_console(struct vc_data *new_vc) -{ - struct vc_data *vc; - - if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch) - return; - - /* - * If this vt is in process mode, then we need to handshake with - * that process before switching. Essentially, we store where that - * vt wants to switch to and wait for it to tell us when it's done - * (via VT_RELDISP ioctl). - * - * We also check to see if the controlling process still exists. - * If it doesn't, we reset this vt to auto mode and continue. - * This is a cheap way to track process control. The worst thing - * that can happen is: we send a signal to a process, it dies, and - * the switch gets "lost" waiting for a response; hopefully, the - * user will try again, we'll detect the process is gone (unless - * the user waits just the right amount of time :-) and revert the - * vt to auto control. - */ - vc = vc_cons[fg_console].d; - if (vc->vt_mode.mode == VT_PROCESS) { - /* - * Send the signal as privileged - kill_pid() will - * tell us if the process has gone or something else - * is awry. - * - * We need to set vt_newvt *before* sending the signal or we - * have a race. - */ - vc->vt_newvt = new_vc->vc_num; - if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { - /* - * It worked. Mark the vt to switch to and - * return. The process needs to send us a - * VT_RELDISP ioctl to complete the switch. - */ - return; - } - - /* - * The controlling process has died, so we revert back to - * normal operation. In this case, we'll also change back - * to KD_TEXT mode. I'm not sure if this is strictly correct - * but it saves the agony when the X server dies and the screen - * remains blanked due to KD_GRAPHICS! It would be nice to do - * this outside of VT_PROCESS but there is no single process - * to account for and tracking tty count may be undesirable. - */ - reset_vc(vc); - - /* - * Fall through to normal (VT_AUTO) handling of the switch... - */ - } - - /* - * Ignore all switches in KD_GRAPHICS+VT_AUTO mode - */ - if (vc->vc_mode == KD_GRAPHICS) - return; - - complete_change_console(new_vc); -} - -/* Perform a kernel triggered VT switch for suspend/resume */ - -static int disable_vt_switch; - -int vt_move_to_console(unsigned int vt, int alloc) -{ - int prev; - - acquire_console_sem(); - /* Graphics mode - up to X */ - if (disable_vt_switch) { - release_console_sem(); - return 0; - } - prev = fg_console; - - if (alloc && vc_allocate(vt)) { - /* we can't have a free VC for now. Too bad, - * we don't want to mess the screen for now. */ - release_console_sem(); - return -ENOSPC; - } - - if (set_console(vt)) { - /* - * We're unable to switch to the SUSPEND_CONSOLE. - * Let the calling function know so it can decide - * what to do. - */ - release_console_sem(); - return -EIO; - } - release_console_sem(); - tty_lock(); - if (vt_waitactive(vt + 1)) { - pr_debug("Suspend: Can't switch VCs."); - tty_unlock(); - return -EINTR; - } - tty_unlock(); - return prev; -} - -/* - * Normally during a suspend, we allocate a new console and switch to it. - * When we resume, we switch back to the original console. This switch - * can be slow, so on systems where the framebuffer can handle restoration - * of video registers anyways, there's little point in doing the console - * switch. This function allows you to disable it by passing it '0'. - */ -void pm_set_vt_switch(int do_switch) -{ - acquire_console_sem(); - disable_vt_switch = !do_switch; - release_console_sem(); -} -EXPORT_SYMBOL(pm_set_vt_switch); |