From: James S. <jsi...@us...> - 2003-08-11 16:38:09
|
Update of /cvsroot/linuxconsole/ruby/ruby-2.6/drivers/char In directory sc8-pr-cvs1:/tmp/cvs-serv30919/ruby-2.6/drivers/char Added Files: Kconfig Makefile console_macros.h consolemap.c decvte.c keyboard.c n_tty.c selection.c sysrq.c tty_io.c vc_screen.c vt.c vt_ioctl.c Log Message: Synced to 2.6.0-test3 --- NEW FILE: Kconfig --- # # Character device configuration # menu "Character devices" config VT bool "Virtual terminal" if EMBEDDED requires INPUT=y default y ---help--- If you say Y here, you will get support for terminal devices with display and keyboard devices. These are called "virtual" because you can run several virtual terminals (also called virtual consoles) on one physical terminal. This is rather useful, for example one virtual terminal can collect system messages and warnings, another one can be used for a text-mode user session, and a third could run an X session, all in parallel. Switching between virtual terminals is done with certain key combinations, usually Alt-<function key>. [...977 lines suppressed...] Semiconductor SCx200 processors. If compiled as a module, it will be called scx200_gpio. config RAW_DRIVER tristate "RAW driver (/dev/raw/rawN)" help The raw driver permits block devices to be bound to /dev/raw/rawN. Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. See the raw(8) manpage for more details. config HANGCHECK_TIMER tristate "Hangcheck timer" help The hangcheck-timer module detects when the system has gone out to lunch past a certain margin. It can reboot the system or merely print a warning. endmenu --- NEW FILE: Makefile --- # # 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 tty_io.o n_tty.o tty_ioctl.o pty.o misc.o random.o obj-$(CONFIG_VT) += vt_ioctl.o decvte.o vc_screen.o consolemap.o consolemap_deftbl.o selection.o keyboard.o obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o obj-$(CONFIG_ROCKETPORT) += rocket.o obj-$(CONFIG_MOXA_SMARTIO) += mxser.o obj-$(CONFIG_MOXA_INTELLIO) += moxa.o obj-$(CONFIG_DIGI) += pcxx.o obj-$(CONFIG_DIGIEPCA) += epca.o obj-$(CONFIG_CYCLADES) += cyclades.o obj-$(CONFIG_STALLION) += stallion.o obj-$(CONFIG_ISTALLION) += istallion.o obj-$(CONFIG_COMPUTONE) += ip2.o ip2main.o obj-$(CONFIG_RISCOM8) += riscom8.o obj-$(CONFIG_ISI) += isicom.o obj-$(CONFIG_ESPSERIAL) += esp.o obj-$(CONFIG_SYNCLINK) += synclink.o obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_SPECIALIX) += specialix.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o obj-$(CONFIG_SX) += sx.o generic_serial.o obj-$(CONFIG_RIO) += rio/ generic_serial.o obj-$(CONFIG_SH_SCI) += sh-sci.o generic_serial.o obj-$(CONFIG_SERIAL167) += serial167.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 obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_PRINTER) += lp.o obj-$(CONFIG_TIPAR) += tipar.o obj-$(CONFIG_PC9800_OLDLP) += lp_old98.o obj-$(CONFIG_BUSMOUSE) += busmouse.o obj-$(CONFIG_DTLK) += dtlk.o obj-$(CONFIG_R3964) += n_r3964.o obj-$(CONFIG_APPLICOM) += applicom.o obj-$(CONFIG_SONYPI) += sonypi.o obj-$(CONFIG_RTC) += rtc.o obj-$(CONFIG_GEN_RTC) += genrtc.o obj-$(CONFIG_EFI_RTC) += efirtc.o ifeq ($(CONFIG_PPC),) obj-$(CONFIG_NVRAM) += nvram.o endif obj-$(CONFIG_TOSHIBA) += toshiba.o obj-$(CONFIG_I8K) += i8k.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_HW_RANDOM) += hw_random.o obj-$(CONFIG_QIC02_TAPE) += tpqic02.o obj-$(CONFIG_FTAPE) += ftape/ obj-$(CONFIG_H8) += h8.o obj-$(CONFIG_PPDEV) += ppdev.o obj-$(CONFIG_DZ) += dz.o obj-$(CONFIG_NWBUTTON) += nwbutton.o obj-$(CONFIG_NWFLASH) += nwflash.o obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_MWAVE) += mwave/ obj-$(CONFIG_AGP) += agp/ obj-$(CONFIG_DRM) += drm/ obj-$(CONFIG_PCMCIA) += pcmcia/ obj-$(CONFIG_IPMI_HANDLER) += ipmi/ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o # Files generated that shall be removed upon make clean clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c quiet_cmd_conmk = CONMK $@ cmd_conmk = scripts/conmakehash $< > $@ $(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE) $(call cmd,conmk) $(obj)/defkeymap.o: $(obj)/defkeymap.c $(obj)/qtronixmap.o: $(obj)/qtronixmap.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)/qtronixmap.c: $(obj)/%.c: $(src)/%.map loadkeys --mktable $< > $@.tmp sed -e 's/^static *//' $@.tmp > $@ rm $@.tmp endif --- NEW FILE: console_macros.h --- #define cons_num (vc->vc_num) #define video_num_columns (vc->vc_cols) #define video_num_lines (vc->vc_rows) #define video_scan_lines (vc->vc_scan_lines) #define video_size_row (vc->vc_size_row) #define vcmode (vc->vc_mode) #define can_do_color (vc->vc_can_do_color) #define screenbuf (vc->vc_screenbuf) #define screenbuf_size (vc->vc_screenbuf_size) #define screensize (vc->vc_screensize) #define scrollback (vc->vc_scrollback) #define origin (vc->vc_origin) #define scr_top (vc->vc_scr_top) #define visible_origin (vc->vc_visible_origin) #define scr_end (vc->vc_scr_end) #define pos (vc->vc_pos) #define top (vc->vc_top) #define bottom (vc->vc_bottom) #define x (vc->vc_x) #define y (vc->vc_y) #define vc_state (vc->vc_state) #define npar (vc->vc_npar) #define par (vc->vc_par) #define ques (vc->vc_ques) #define attr (vc->vc_attr) #define saved_x (vc->vc_saved_x) #define saved_y (vc->vc_saved_y) #define translate (vc->vc_translate) #define G0_charset (vc->vc_G0_charset) #define G1_charset (vc->vc_G1_charset) #define saved_G0 (vc->vc_saved_G0) #define saved_G1 (vc->vc_saved_G1) #define utf (vc->vc_utf) #define utf_count (vc->vc_utf_count) #define utf_char (vc->vc_utf_char) #define video_erase_char (vc->vc_video_erase_char) #define disp_ctrl (vc->vc_disp_ctrl) #define toggle_meta (vc->vc_toggle_meta) #define decscnm (vc->vc_decscnm) #define decom (vc->vc_decom) #define decawm (vc->vc_decawm) #define deccm (vc->vc_deccm) #define decim (vc->vc_decim) #define deccolm (vc->vc_deccolm) #define need_wrap (vc->vc_need_wrap) #define report_mouse (vc->vc_report_mouse) #define color (vc->vc_color) #define s_color (vc->vc_s_color) #define def_color (vc->vc_def_color) #define foreground (color & 0x0f) #define background (color & 0xf0) #define charset (vc->vc_charset) #define s_charset (vc->vc_s_charset) #define intensity (vc->vc_intensity) #define underline (vc->vc_underline) #define blink (vc->vc_blink) #define reverse (vc->vc_reverse) #define s_intensity (vc->vc_s_intensity) #define s_underline (vc->vc_s_underline) #define s_blink (vc->vc_s_blink) #define s_reverse (vc->vc_s_reverse) #define ulcolor (vc->vc_ulcolor) #define halfcolor (vc->vc_halfcolor) #define tab_stop (vc->vc_tab_stop) #define palette (vc->vc_palette) #define bell_pitch (vc->vc_bell_pitch) #define bell_duration (vc->vc_bell_duration) #define cursor_type (vc->vc_cursor_type) #define complement_mask (vc->vc_complement_mask) #define s_complement_mask (vc->vc_s_complement_mask) #define hi_font_mask (vc->vc_hi_font_mask) #define softcursor_original (vc->display_fg->cursor_original) #define sw (vc->display_fg->vt_sw) #define dectcem (vc->vc_dectcem) #define decscl (vc->vc_decscl) #define c8bit (vc->vc_c8bit) #define d8bit (vc->vc_d8bit) #define shift (vc->vc_shift) #define priv1 (vc->vc_priv1) #define priv2 (vc->vc_priv2) #define priv3 (vc->vc_priv3) #define priv4 (vc->vc_priv4) #define decckm (vc->vc_decckm) #define decsclm (vc->vc_decsclm) #define decarm (vc->vc_decarm) #define decnrcm (vc->vc_decnrcm) #define decnkm (vc->vc_decnkm) #define kam (vc->vc_kam) #define crm (vc->vc_crm) #define lnm (vc->vc_lnm) #define irm (vc->vc_irm) #define GL_charset (vc->vc_GL_charset) #define GR_charset (vc->vc_GR_charset) #define G2_charset (vc->vc_G2_charset) #define G3_charset (vc->vc_G3_charset) #define GS_charset (vc->vc_GS_charset) #define saved_G2 (vc->vc_saved_G2) #define saved_G3 (vc->vc_saved_G3) #define saved_GS (vc->vc_saved_GS) --- NEW FILE: consolemap.c --- /* * 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...@ul...>, July 1998 * * Fix bug in inverse translation. Stanislav Voronyi <st...@cn...>, Dec 1998 */ #include <linux/errno.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/init.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, 0xf800, 0xf801, 0x2500, 0xf803, 0xf804, 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]; int readonly; }; static struct uni_pagedir *dflt; static void set_inverse_transl(struct vc_data *vc, 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(vc, t[j]); if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) { /* prefer '-' above SHY etc. */ q[glyph] = j; } } } void set_translate(struct vc_data *vc, int m) { inv_translate[vc->vc_num] = m; vc->vc_translate = 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, or using Unicode. * Still, it is now possible to a certain extent to cut and paste non-ASCII. */ unsigned char inverse_translate(struct vc_data *vc, int glyph) { struct uni_pagedir *p; if (glyph < 0 || glyph >= MAX_GLYPH) return 0; else if (!(p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc) || !p->inverse_translations[inv_translate[vc->vc_num]]) return glyph; else return p->inverse_translations[inv_translate[vc->vc_num]][glyph]; } static void update_user_maps(struct vc_data *vc) { struct uni_pagedir *p, *q = NULL; int i; for (i = 0; i < MAX_NR_USER_CONSOLES; i++) { struct vc_data *tmp = vc->display_fg->vc_cons[i]; if (!tmp) continue; p = (struct uni_pagedir *)*tmp->vc_uni_pagedir_loc; if (p && p != q) { set_inverse_transl(tmp, p, USER_MAP); 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(struct vc_data *vc, unsigned char * arg) { int i; unsigned short *p = translations[USER_MAP]; i = verify_area(VERIFY_READ, (void *)arg, E_TABSZ); if (i) return i; for (i=0; i<E_TABSZ ; i++) { unsigned char uc; __get_user(uc, arg+i); p[i] = UNI_DIRECT_BASE | uc; } update_user_maps(vc); return 0; } int con_get_trans_old(struct vc_data *vc, unsigned char * arg) { int i, ch; unsigned short *p = translations[USER_MAP]; i = verify_area(VERIFY_WRITE, (void *)arg, E_TABSZ); if (i) return i; for (i=0; i<E_TABSZ ; i++) { ch = conv_uni_to_pc(vc, p[i]); __put_user((ch & ~0xff) ? 0 : ch, arg+i); } return 0; } int con_set_trans_new(struct vc_data *vc, ushort * arg) { int i; unsigned short *p = translations[USER_MAP]; i = verify_area(VERIFY_READ, (void *)arg, E_TABSZ*sizeof(unsigned short)); if (i) return i; for (i=0; i<E_TABSZ ; i++) { unsigned short us; __get_user(us, arg+i); p[i] = us; } update_user_maps(vc); return 0; } int con_get_trans_new(struct vc_data *vc, ushort * arg) { int i; unsigned short *p = translations[USER_MAP]; i = verify_area(VERIFY_WRITE, (void *)arg, E_TABSZ*sizeof(unsigned short)); if (i) return i; 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++) if (p1[j]) kfree(p1[j]); kfree(p1); } p->uni_pgdir[i] = NULL; } for (i = 0; i < 4; i++) if (p->inverse_translations[i]) { kfree(p->inverse_translations[i]); p->inverse_translations[i] = 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 *vc, struct uni_pagedir *p) { struct uni_pagedir *q; int i, j, k; for (i = 0; i < MAX_NR_USER_CONSOLES; i++) { struct vc_data *tmp = vc->display_fg->vc_cons[i]; if (!tmp) continue; q = (struct uni_pagedir *)*tmp->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++; *vc->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 = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL); if (!q) { if (p) p->refcount++; return -ENOMEM; } memset(q, 0, sizeof(*q)); 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 *list) { struct uni_pagedir *p, *q; int err = 0, err1, i; 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 */ 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 */ dflt = p; return err; } int con_copy_unimap(struct vc_data *dst, struct vc_data *src) { struct uni_pagedir *q; if (!src || !*src->vc_uni_pagedir_loc) return -EINVAL; if (*dst->vc_uni_pagedir_loc == *src->vc_uni_pagedir_loc) return 0; con_free_unimap(dst); q = (struct uni_pagedir *)*src->vc_uni_pagedir_loc; q->refcount++; *dst->vc_uni_pagedir_loc = (long)q; return 0; } int con_get_unimap(struct vc_data *vc, ushort ct, ushort *uct, struct unipair *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; } int conv_uni_to_pc(struct vc_data *vc, long ucs) { int h; u16 **p1, *p2; struct uni_pagedir *p; /* Only 16-bit codes supported at this time */ if (ucs > 0xffff) ucs = 0xfffd; /* U+FFFD: REPLACEMENT CHARACTER */ else if (ucs < 0x20 || ucs >= 0xfffe) return -1; /* Not a printable character */ else if (ucs == 0xfeff || (ucs >= 0x200a && 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 (!*vc->vc_uni_pagedir_loc) return -3; p = (struct uni_pagedir *)*vc->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) { struct vt_struct *vt = vt_cons; int i; for (i = 0; i < MAX_NR_USER_CONSOLES; i++) { struct vc_data *vc = vt->vc_cons[i]; if (vc && !*vc->vc_uni_pagedir_loc) con_set_default_unimap(vc); } } --- NEW FILE: decvte.c --- /* * decvte.c - DEC VT terminal emulation code. * Copyright (C) 2002 James Simmons (jsi...@in...) * * I moved all the VT emulation code out of console.c to here. It makes life * much easier and the code smaller. It also allows other devices to emulate * a TTY besides the video system. People can also change the makefile to * support a different emulation if they wanted. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * [...2026 lines suppressed...] G3_charset = LAT1_MAP; break; case 'B': /* ASCII */ G3_charset = LAT1_MAP; break; case 'U': G3_charset = IBMPC_MAP; break; case 'K': G3_charset = USER_MAP; break; } if (charset == 1) set_translate(vc, G3_charset); vc_state = ESinit; return; default: vc_state = ESinit; } } --- NEW FILE: keyboard.c --- /* * 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, ae...@cw..., 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 [...1165 lines suppressed...] { }, /* Terminating entry */ }; MODULE_DEVICE_TABLE(input, kbd_ids); static struct input_handler kbd_handler = { .event = kbd_event, .connect = kbd_connect, .disconnect = kbd_disconnect, .name = "kbd", .id_table = kbd_ids, }; int __init kbd_init(void) { input_register_handler(&kbd_handler); tasklet_enable(&keyboard_tasklet); tasklet_schedule(&keyboard_tasklet); return 0; } --- NEW FILE: n_tty.c --- /* * n_tty.c --- implements the N_TTY line discipline. * * This code used to be in tty_io.c, but things are getting hairy * enough that it made sense to split things off. (The N_TTY * processing has changed so much that it's hardly recognizable, * anyway...) * * Note that the open routine for N_TTY is guaranteed never to return * an error. This is because Linux will fall back to setting a line * to N_TTY if it can not switch to any other line discipline. * * Written by Theodore Ts'o, Copyright 1994. * * This file also contains code originally written by Linus Torvalds, * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994. * * This file may be redistributed under the terms of the GNU General Public * License. [...1235 lines suppressed...] struct tty_ldisc tty_ldisc_N_TTY = { TTY_LDISC_MAGIC, /* magic */ "n_tty", /* name */ 0, /* num */ 0, /* flags */ n_tty_open, /* open */ n_tty_close, /* close */ n_tty_flush_buffer, /* flush_buffer */ n_tty_chars_in_buffer, /* chars_in_buffer */ read_chan, /* read */ write_chan, /* write */ n_tty_ioctl, /* ioctl */ n_tty_set_termios, /* set_termios */ normal_poll, /* poll */ n_tty_receive_buf, /* receive_buf */ n_tty_receive_room, /* receive_room */ n_tty_write_wakeup /* write_wakeup */ }; --- NEW FILE: selection.c --- /* * linux/drivers/char/selection.c * * This module exports the functions: * * 'int set_selection(const unsigned long arg)' * 'void clear_selection(void)' * 'int paste_selection(struct tty_struct *tty)' * 'int sel_loadlut(const unsigned long arg)' * * 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/vt_kern.h> #include <linux/consolemap.h> #include <linux/selection.h> #include <linux/tiocl.h> #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ #define isspace(c) ((c) == ' ') /* Variables for selection control. */ /* Use a dynamic buffer, instead of static (Dec 1994) */ int sel_cons; /* must not be disallocated */ 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. */ inline static void highlight(const int s, const int e) { invert_screen(vt_cons->vc_cons[sel_cons], s, e-s+2, 1); } 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; } /* use complementary color to show the pointer */ inline static void highlight_pointer(const int where) { complement_pos(vt_cons->vc_cons[sel_cons], where); } static unsigned char sel_pos(int n) { return inverse_translate(vt_cons->vc_cons[sel_cons], screen_glyph(vt_cons->vc_cons[sel_cons], n)); } /* * 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 unsigned char c) { return ( inwordLut[c>>5] >> (c & 0x1F) ) & 1; } /* set inwordLut contents. Invoked by ioctl(). */ int sel_loadlut(const unsigned long arg) { return copy_from_user(inwordLut, (u32 *)(arg+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; } /* set the current selection. Invoked by ioctl() or by kernel code. */ int set_selection(const struct tiocl_selection *sel, struct tty_struct *tty, int user) { struct vc_data *vc = (struct vc_data *) tty->driver_data; int sel_mode, new_sel_start, new_sel_end, spc; char *bp, *obp; int i, ps, pe; poke_blanked_console(vc->display_fg); { unsigned short xs, ys, xe, ye; if (user) { if (verify_area(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); } else { xs = sel->xs; /* set selection from kernel */ ys = sel->ys; xe = sel->xe; ye = sel->ye; 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(vc) && (sel_mode & TIOCL_SELMOUSEREPORT)) { mouse_report(vc, 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->display_fg->fg_console->vc_num) { clear_selection(); sel_cons = vc->display_fg->fg_console->vc_num; } 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 ... */ bp = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL); if (!bp) { printk(KERN_WARNING "selection: kmalloc() failed\n"); clear_selection(); return -ENOMEM; } if (sel_buffer) kfree(sel_buffer); sel_buffer = bp; obp = bp; for (i = sel_start; i <= sel_end; i += 2) { *bp = sel_pos(i); if (!isspace(*bp++)) 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 = (struct vc_data *) tty->driver_data; int pasted = 0, count; DECLARE_WAITQUEUE(wait, current); poke_blanked_console(vc->display_fg); 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->ldisc.receive_room(tty)); tty->ldisc.receive_buf(tty, sel_buffer + pasted, 0, count); pasted += count; } remove_wait_queue(&vc->paste_wait, &wait); set_current_state(TASK_RUNNING); return 0; } EXPORT_SYMBOL(set_selection); EXPORT_SYMBOL(paste_selection); --- NEW FILE: sysrq.c --- /* -*- linux-c -*- * * $Id: sysrq.c,v 1.1 2003/08/11 16:26:46 jsimmons Exp $ * * Linux Magic System Request Key Hacks * * (c) 1997 Martin Mares <mj...@at...> * based on ideas by Pavel Machek <pa...@at...> * * (c) 2000 Crutcher Dunnavant <cru...@da...> * overhauled to use key registration * based upon discusions in irc://irc.openprojects.net/#kernelnewbies */ #include <linux/config.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/fs.h> #include <linux/tty.h> #include <linux/mount.h> #include <linux/kdev_t.h> #include <linux/major.h> #include <linux/reboot.h> #include <linux/sysrq.h> #include <linux/vt_kern.h> #include <linux/quotaops.h> #include <linux/smp_lock.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/suspend.h> #include <linux/writeback.h> #include <linux/buffer_head.h> /* for fsync_bdev() */ #include <linux/spinlock.h> #include <asm/ptrace.h> extern struct list_head super_blocks; /* Whether we react on sysrq keys or just ignore them */ int sysrq_enabled = 1; /* Machine specific power off function */ void (*sysrq_power_off)(void); /* Loglevel sysrq handler */ static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { int i; i = key - '0'; console_loglevel = 7; printk("Loglevel set to %d\n", i); console_loglevel = i; } static struct sysrq_key_op sysrq_loglevel_op = { .handler = sysrq_handle_loglevel, .help_msg = "loglevel0-8", .action_msg = "Changing Loglevel", }; /* SAK sysrq handler */ #ifdef CONFIG_VT static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { struct vc_data *vc = (struct vc_data *) tty->driver_data; if (tty) do_SAK(tty); if ((tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) && vc) reset_vc(vc); } static struct sysrq_key_op sysrq_SAK_op = { .handler = sysrq_handle_SAK, .help_msg = "saK", .action_msg = "SAK", }; /* unraw sysrq handler */ static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { struct vc_data *vc = (struct vc_data *) tty->driver_data; if ((tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) && vc) vc->kbd_table.kbdmode = VC_XLATE; } static struct sysrq_key_op sysrq_unraw_op = { .handler = sysrq_handle_unraw, .help_msg = "unRaw", .action_msg = "Keyboard mode set to XLATE", }; #endif /* CONFIG_VT */ /* reboot sysrq handler */ static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { machine_restart(NULL); } static struct sysrq_key_op sysrq_reboot_op = { .handler = sysrq_handle_reboot, .help_msg = "reBoot", .action_msg = "Resetting", }; static void sysrq_handle_sync(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { emergency_sync(); } static struct sysrq_key_op sysrq_sync_op = { .handler = sysrq_handle_sync, .help_msg = "Sync", .action_msg = "Emergency Sync", }; static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { emergency_remount(); } static struct sysrq_key_op sysrq_mountro_op = { .handler = sysrq_handle_mountro, .help_msg = "Unmount", .action_msg = "Emergency Remount R/O", }; /* END SYNC SYSRQ HANDLERS BLOCK */ /* SHOW SYSRQ HANDLERS BLOCK */ static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { if (pt_regs) show_regs(pt_regs); } static struct sysrq_key_op sysrq_showregs_op = { .handler = sysrq_handle_showregs, .help_msg = "showPc", .action_msg = "Show Regs", }; static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { show_state(); } static struct sysrq_key_op sysrq_showstate_op = { .handler = sysrq_handle_showstate, .help_msg = "showTasks", .action_msg = "Show State", }; static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { show_mem(); } static struct sysrq_key_op sysrq_showmem_op = { .handler = sysrq_handle_showmem, .help_msg = "showMem", .action_msg = "Show Memory", }; /* SHOW SYSRQ HANDLERS BLOCK */ /* SIGNAL SYSRQ HANDLERS BLOCK */ /* signal sysrq helper function * Sends a signal to all user processes */ static void send_sig_all(int sig) { struct task_struct *p; for_each_process(p) { if (p->mm && p->pid != 1) /* Not swapper, init nor kernel thread */ force_sig(sig, p); } } static void sysrq_handle_term(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { send_sig_all(SIGTERM); console_loglevel = 8; } static struct sysrq_key_op sysrq_term_op = { .handler = sysrq_handle_term, .help_msg = "tErm", .action_msg = "Terminate All Tasks", }; static void sysrq_handle_kill(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { send_sig_all(SIGKILL); console_loglevel = 8; } static struct sysrq_key_op sysrq_kill_op = { .handler = sysrq_handle_kill, .help_msg = "kIll", .action_msg = "Kill All Tasks", }; /* END SIGNAL SYSRQ HANDLERS BLOCK */ /* Key Operations table and lock */ static spinlock_t sysrq_key_table_lock = SPIN_LOCK_UNLOCKED; #define SYSRQ_KEY_TABLE_LENGTH 36 static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = { /* 0 */ &sysrq_loglevel_op, /* 1 */ &sysrq_loglevel_op, /* 2 */ &sysrq_loglevel_op, /* 3 */ &sysrq_loglevel_op, /* 4 */ &sysrq_loglevel_op, /* 5 */ &sysrq_loglevel_op, /* 6 */ &sysrq_loglevel_op, /* 7 */ &sysrq_loglevel_op, /* 8 */ &sysrq_loglevel_op, /* 9 */ &sysrq_loglevel_op, /* a */ NULL, /* Don't use for system provided sysrqs, it is handled specially on the sparc and will never arrive */ /* b */ &sysrq_reboot_op, /* c */ NULL, /* d */ NULL, /* e */ &sysrq_term_op, /* f */ NULL, /* g */ NULL, /* h */ NULL, /* i */ &sysrq_kill_op, /* j */ NULL, #ifdef CONFIG_VT /* k */ &sysrq_SAK_op, #else /* k */ NULL, #endif /* l */ NULL, /* m */ &sysrq_showmem_op, /* n */ NULL, /* o */ NULL, /* This will often be registered as 'Off' at init time */ /* p */ &sysrq_showregs_op, /* q */ NULL, #ifdef CONFIG_VT /* r */ &sysrq_unraw_op, #else /* r */ NULL, #endif /* s */ &sysrq_sync_op, /* t */ &sysrq_showstate_op, /* u */ &sysrq_mountro_op, /* v */ NULL, /* May be assigned at init time by SMP VOYAGER */ /* w */ NULL, /* x */ NULL, /* y */ NULL, /* z */ NULL }; /* key2index calculation, -1 on invalid index */ static __inline__ int sysrq_key_table_key2index(int key) { int retval; if ((key >= '0') & (key <= '9')) { retval = key - '0'; } else if ((key >= 'a') & (key <= 'z')) { retval = key + 10 - 'a'; } else { retval = -1; } return retval; } /* * table lock and unlocking functions, exposed to modules */ void __sysrq_lock_table (void) { spin_lock(&sysrq_key_table_lock); } void __sysrq_unlock_table (void) { spin_unlock(&sysrq_key_table_lock); } /* * get and put functions for the table, exposed to modules. */ struct sysrq_key_op *__sysrq_get_key_op (int key) { struct sysrq_key_op *op_p; int i; i = sysrq_key_table_key2index(key); op_p = (i == -1) ? NULL : sysrq_key_table[i]; return op_p; } void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) { int i; i = sysrq_key_table_key2index(key); if (i != -1) sysrq_key_table[i] = op_p; } /* * This function is called by the keyboard handler when SysRq is pressed * and any other keycode arrives. */ void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { if (!sysrq_enabled) return; __sysrq_lock_table(); __handle_sysrq_nolock(key, pt_regs, tty); __sysrq_unlock_table(); } /* * This is the non-locking version of handle_sysrq * It must/can only be called by sysrq key handlers, * as they are inside of the lock */ void __handle_sysrq_nolock(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { struct sysrq_key_op *op_p; int orig_log_level; int i, j; if (!sysrq_enabled) return; orig_log_level = console_loglevel; console_loglevel = 7; printk(KERN_INFO "SysRq : "); op_p = __sysrq_get_key_op(key); if (op_p) { printk ("%s\n", op_p->action_msg); console_loglevel = orig_log_level; op_p->handler(key, pt_regs, tty); } else { printk("HELP : "); /* Only print the help msg once per handler */ for (i=0; i<SYSRQ_KEY_TABLE_LENGTH; i++) if (sysrq_key_table[i]) { for (j=0; sysrq_key_table[i] != sysrq_key_table[j]; j++); if (j == i) printk ("%s ", sysrq_key_table[i]->help_msg); } printk ("\n"); console_loglevel = orig_log_level; } } EXPORT_SYMBOL(handle_sysrq); EXPORT_SYMBOL(__handle_sysrq_nolock); EXPORT_SYMBOL(__sysrq_lock_table); EXPORT_SYMBOL(__sysrq_unlock_table); EXPORT_SYMBOL(__sysrq_get_key_op); EXPORT_SYMBOL(__sysrq_put_key_op); --- NEW FILE: tty_io.c --- /* * linux/drivers/char/tty_io.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles * or rs-channels. It also implements echoing, cooked mode etc. * * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. * * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the * tty_struct and tty_queue structures. Previously there was an array * of 256 tty_struct's which was statically allocated, and the * tty_queue structures were allocated at boot time. Both are now * dynamically allocated only when the tty is open. * * Also restructured routines so that there is more of a separation [...2461 lines suppressed...] #ifdef CONFIG_DIGIEPCA pc_init(); #endif #ifdef CONFIG_SPECIALIX specialix_init(); #endif #if (defined(CONFIG_8xx) || defined(CONFIG_8260)) rs_8xx_init(); #endif /* CONFIG_8xx */ pty_init(); #ifdef CONFIG_MOXA_INTELLIO moxa_init(); #endif #ifdef CONFIG_TN3270 tub3270_init(); #endif #ifdef CONFIG_A2232 a2232board_init(); #endif } --- NEW FILE: vc_screen.c --- /* * 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. * * ae...@cw... - efter Friedas begravelse - 950211 * * ma...@k3... - 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/config.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/errno.h> #include <linux/tty.h> #include <linux/devfs_fs_kernel.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/init.h> #include <linux/vt_kern.h> #include <linux/selection.h> #include <linux/console.h> #include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/byteorder.h> #include <asm/unaligned.h> #undef attr #undef org #undef addr #define HEADER_SIZE 4 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, char *p) { p[0] = vc->vc_x; p[1] = vc->vc_y; } void putconsxy(struct vc_data *vc, char *p) { 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 && vc->display_fg->cursor_original != -1) return vc->display_fg->cursor_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) { vc->display_fg->cursor_original = -1; add_softcursor(vc); } } static int vcs_size(struct inode *inode) { int minor = minor(inode->i_rdev); int currcons = minor & 127; struct vc_data *vc; int size; vc = find_vc(currcons); if (!vc) return -ENXIO; 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; lock_kernel(); size = vcs_size(file->f_dentry->d_inode); switch (orig) { default: unlock_kernel(); return -EINVAL; case 2: offset += size; break; case 1: offset += file->f_pos; case 0: break; } if (offset < 0 || offset > size) { unlock_kernel(); return -EINVAL; } file->f_pos = offset; unlock_kernel(); return file->f_pos; } /* We share this temporary buffer with the console write code * so that we can easily avoid touching user space while holding the * console spinlock. */ extern char con_buf[PAGE_SIZE]; #define CON_BUF_SIZE PAGE_SIZE extern struct semaphore con_buf_sem; static ssize_t vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; unsigned int currcons = minor(inode->i_rdev); struct vc_data *vc; long pos = *ppos; long viewed, attr, read; int col, maxcol; unsigned short *org = NULL; ssize_t ret; down(&con_buf_sem); /* 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) { viewed = 1; } else { viewed = 0; } ret = -ENXIO; vc = find_vc(currcons); if (!vc) goto unlock_out; ret = -EINVAL; if (pos < 0) goto unlock_out; 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(); up(&con_buf_sem); return ret; } static ssize_t vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; unsigned int currcons = minor(inode->i_rdev); struct vc_data *vc; long pos = *ppos; long viewed, attr, size, written; char *con_buf0; int col, maxcol; u16 *org0 = NULL, *org = NULL; size_t ret; down(&con_buf_sem); /* 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) { viewed = 1; } else { viewed = 0; } ret = -ENXIO; vc = find_vc(currcons); if (!vc) goto unlock_out; 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 - ... [truncated message content] |