From 24a1c2a769cf482bef4151859786a30a037e3f64 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:09:55 -0500 Subject: [PATCH] Import 1.1.92 --- Makefile | 4 +- arch/alpha/config.in | 5 - arch/i386/config.in | 3 +- arch/mips/config.in | 1 - arch/sparc/config.in | 5 - drivers/block/README.sonycd535 | 11 +- drivers/block/ll_rw_blk.c | 15 - drivers/block/sonycd535.c | 67 +-- drivers/char/Makefile | 8 +- drivers/char/console.c | 738 +++++++-------------------------- drivers/char/consolemap.c | 286 +++++++++++++ drivers/char/consolemap.h | 13 + drivers/char/kbd_kern.h | 2 + drivers/char/keyboard.c | 27 +- drivers/char/selection.c | 291 +++++++++++++ drivers/char/selection.h | 64 +++ drivers/char/tty_io.c | 29 +- drivers/char/uni_to_437.c | 169 -------- drivers/char/vc_screen.c | 212 ++++++++++ drivers/char/vt.c | 63 ++- drivers/net/3c501.c | 2 +- drivers/net/3c509.c | 2 +- drivers/net/ppp.c | 2 +- drivers/scsi/eata.c | 25 +- drivers/scsi/eata.h | 2 +- drivers/scsi/eata_dma.c | 40 +- drivers/scsi/eata_dma.h | 29 +- drivers/scsi/hosts.c | 11 +- drivers/scsi/scsi.c | 59 ++- drivers/scsi/sr_ioctl.c | 3 +- drivers/scsi/st.c | 4 +- drivers/scsi/u14-34f.c | 21 +- drivers/scsi/u14-34f.h | 4 +- fs/binfmt_elf.c | 2 +- fs/locks.c | 71 ++-- fs/nfs/inode.c | 5 +- fs/open.c | 8 +- fs/proc/array.c | 164 +++++--- include/asm-alpha/system.h | 1 - include/asm-i386/pgtable.h | 11 + include/asm-i386/system.h | 15 - include/linux/fs.h | 1 - include/linux/major.h | 4 +- include/linux/mm.h | 2 +- include/linux/tty.h | 4 + init/main.c | 1 - kernel/ksyms.c | 2 +- mm/filemap.c | 158 ++++--- mm/memory.c | 4 +- mm/mprotect.c | 92 ++-- mm/swap.c | 345 +++++++++------ net/inet/arp.c | 2 +- net/inet/dev.c | 6 + net/inet/ip.c | 16 - 54 files changed, 1876 insertions(+), 1255 deletions(-) create mode 100644 drivers/char/consolemap.c create mode 100644 drivers/char/consolemap.h create mode 100644 drivers/char/selection.c create mode 100644 drivers/char/selection.h delete mode 100644 drivers/char/uni_to_437.c create mode 100644 drivers/char/vc_screen.c diff --git a/Makefile b/Makefile index cf4f2d762745..f91831ae3b3c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 91 +SUBLEVEL = 92 ARCH = i386 @@ -198,7 +198,7 @@ ifdef CONFIG_MODVERSIONS MODV = -DCONFIG_MODVERSIONS endif -modules: dummy +modules: include/linux/version.h @set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i CFLAGS="$(CFLAGS) -DMODULE $(MODV)" modules; done modules_install: diff --git a/arch/alpha/config.in b/arch/alpha/config.in index c34e6e9242de..794f280127f8 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -199,11 +199,6 @@ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y fi bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n -bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n -bool 'VESA Power Saving Protocol Support' CONFIG_VESA_PSPM n -if [ "$CONFIG_VESA_PSPM" = "y" ]; then -bool 'VESA PSPM Force Off' CONFIG_PSPM_FORCE_OFF n -fi bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n diff --git a/arch/i386/config.in b/arch/i386/config.in index f714ae9f1b16..5b902b832a52 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -10,7 +10,7 @@ bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD y bool 'Normal (MFM/RLL) disk and IDE disk/cdrom support' CONFIG_ST506 y if [ "$CONFIG_ST506" = "y" ]; then comment 'Please see drivers/block/README.ide for help/info on IDE drives' - bool ' Use old (reliable) disk-only driver for primary i/f' CONFIG_BLK_DEV_HD y + bool ' Use old disk-only driver for primary i/f' CONFIG_BLK_DEV_HD n if [ "$CONFIG_BLK_DEV_HD" = "y" ]; then bool ' Include new IDE driver for secondary i/f support' CONFIG_BLK_DEV_IDE n else @@ -229,7 +229,6 @@ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y fi bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n -bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n diff --git a/arch/mips/config.in b/arch/mips/config.in index c64fd4503668..14c7554f58c8 100644 --- a/arch/mips/config.in +++ b/arch/mips/config.in @@ -219,7 +219,6 @@ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE n fi bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n -bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n if [ "$CONFIG_QIC02_TAPE" = "y" ]; then diff --git a/arch/sparc/config.in b/arch/sparc/config.in index 5fac1cfe5e72..96504d397213 100644 --- a/arch/sparc/config.in +++ b/arch/sparc/config.in @@ -206,11 +206,6 @@ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y fi bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n -bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n -bool 'VESA Power Saving Protocol Support' CONFIG_VESA_PSPM n -if [ "$CONFIG_VESA_PSPM" = "y" ]; then -bool 'VESA PSPM Force Off' CONFIG_PSPM_FORCE_OFF n -fi bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n diff --git a/drivers/block/README.sonycd535 b/drivers/block/README.sonycd535 index 9e6d3cde67f6..4c6f4da1f152 100644 --- a/drivers/block/README.sonycd535 +++ b/drivers/block/README.sonycd535 @@ -45,7 +45,7 @@ NOTES: ====== 1) The drive MUST be turned on when booting or it will not be recognized! - (but see comments on modulized version below) + (but see comments on modularized version below) 2) when the cdrom device is opened the eject button is disabled to keep the user from ejecting a mounted disk and replacing it with another. @@ -60,8 +60,13 @@ THANKS Many thanks to Ron Jeppesen (ronj.an@site007.saic.com) for getting this project off the ground. He wrote the initial release and the first two patches to this driver (0.1, 0.2, and 0.3). +Thanks also to Eberhard Moenkeberg (emoenke@gwdg.de) for prodding +me to place this code into the mainstream Linux source tree (as +of Linux version 1.1.91), as well as some patches to make it a +better device citizen. Further thanks to "S. Joel Katz" + for his MODULE patches (see details below). -(aknowlegements from Ron Jeppesen in the 0.3 release:) +(Acknowledgments from Ron Jeppesen in the 0.3 release:) Thanks to Corey Minyard who wrote the original CDU-31A driver on which this driver is based. Thanks to Ken Pizzini and Bob Blair who provided patches and feedback on the first release of this driver. @@ -89,7 +94,7 @@ rmmod sony535 to if MODULE is not defined. That means your patched file should behave exactly as it used to if compiled into the kernel. - I have an externel drive, and I usually leave it powered off. I used + I have an external drive, and I usually leave it powered off. I used to have to reboot if I needed to use the CDROM drive. Now I don't. Even if you have an internal drive, why waste the 268K of memory diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 650d5b3f5864..94a97b1d79c0 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -399,9 +399,6 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) int correct_size; struct blk_dev_struct * dev; int i; -#if defined(CONFIG_CDU535) && defined(CONFIG_CDU31A) - int sonycd_save_mem_start; -#endif /* Make sure that the first block contains something reasonable */ while (!*bh) { @@ -545,24 +542,12 @@ long blk_dev_init(long mem_start, long mem_end) #ifdef CONFIG_BLK_DEV_XD mem_start = xd_init(mem_start,mem_end); #endif -#if defined(CONFIG_CDU535) && defined(CONFIG_CDU31A) - { /* since controllers for 535 and 31A can be at same location - * we have to be careful. - */ - sonycd_save_mem_start = mem_start; - mem_start = cdu31a_init(mem_start,mem_end); - if ( mem_start == sonycd_save_mem_start ) { /* CDU31A not found */ - mem_start = sony535_init(mem_start,mem_end); - } - } -#else #ifdef CONFIG_CDU31A mem_start = cdu31a_init(mem_start,mem_end); #endif #ifdef CONFIG_CDU535 mem_start = sony535_init(mem_start,mem_end); #endif -#endif /* CONFIG_CDU31A && CONFIG_CDU535 */ #ifdef CONFIG_MCD mem_start = mcd_init(mem_start,mem_end); #endif diff --git a/drivers/block/sonycd535.c b/drivers/block/sonycd535.c index 6940b60a0a36..64b7754e70ac 100644 --- a/drivers/block/sonycd535.c +++ b/drivers/block/sonycd535.c @@ -44,7 +44,7 @@ * include/linux/cdrom.h). With this interface, CDROMs can be * accessed and standard audio CDs can be played back normally. * - * This interface is (unfortunatly) a polled interface. This is + * This interface is (unfortunately) a polled interface. This is * because most Sony interfaces are set up with DMA and interrupts * disables. Some (like mine) do not even have the capability to * handle interrupts or DMA. For this reason you will see a lot of @@ -65,7 +65,7 @@ * * This ugly hack waits for something to happen, sleeping a little * between every try. it also handles attentions, which are - * asyncronous events from the drive informing the driver that a disk + * asynchronous events from the drive informing the driver that a disk * has been inserted, removed, etc. * * One thing about these drives: They talk in MSF (Minute Second Frame) format. @@ -93,10 +93,11 @@ #include -#ifdef CONFIG_CDU535 +#if defined(CONFIG_CDU535) || defined(MODULE) #ifdef MODULE # include +# include # include #endif @@ -130,16 +131,25 @@ #endif /* - * this is the base address of the interface card for the Sony CDU535 + * this is the base address of the interface card for the Sony CDU-535 * CDROM drive. If your jumpers are set for an address other than * this one (the default), change the following line to the * proper address. */ #ifndef CDU535_ADDRESS -#define CDU535_ADDRESS (0x340) +# define CDU535_ADDRESS (0x340) #endif -#define DEBUG 1 +#ifndef CDU535_HANDLE +# define CDU535_HANDLE "cdu535" +#endif +#ifndef CDU535_MESSAGE_NAME +# define CDU535_MESSAGE_NAME "Sony CDU-535" +#endif + +#ifndef DEBUG +# define DEBUG 1 +#endif /* * SONY535_BUFFER_SIZE determines the size of internal buffer used @@ -440,10 +450,10 @@ check_drive_status(void) * should be placed in the cmd[] array, number of bytes in the command is * stored in nCmd. The response from the command will be stored in the * response array. The number of bytes you expect back (excluding status) - * should be passed in nReponse. Finally, some + * should be passed in nResponse. Finally, some * commands set bit 7 of the return status even when there is no second * status byte, on these commands set ignoreStatusBit7 TRUE. - * If the command was sent and data recieved back, then we return 0, + * If the command was sent and data received back, then we return 0, * else we return TIME_OUT. You still have to check the status yourself. * You should call check_drive_status() before calling this routine * so that you do not lose notifications of disk changes, etc. @@ -843,7 +853,7 @@ do_cdu535_request(void) break; default: - panic("Unkown SONY CD cmd"); + panic("Unknown SONY CD cmd"); } } } @@ -1432,7 +1442,8 @@ init_module(void) if (do_sony_cmd(cmd_buff, 1, status, (Byte *) & drive_config, 28, 1) == 0) { /* was able to get the configuration, set drive mode as rest of init */ #if DEBUG > 0 - if ( (status[0] & 0x7f) != 0 ) + /* 0x50 == CADDY_NOT_INSERTED | NOT_SPINNING */ + if ( (status[0] & 0x7f) != 0 && (status[0] & 0x7f) != 0x50 ) printk("Inquiry command returned status = 0x%x\n", status[0]); #endif cmd_buff[0] = SONY535_SET_DRIVE_MODE; @@ -1448,8 +1459,9 @@ init_module(void) drive_config.product_rev_level); printk(" using %d byte buffer\n", sony_buffer_size); - if (register_blkdev(MAJOR_NR, "cdu-535", &cdu_fops)) { - printk("Unable to get major %d for sony CDU-535 cd\n", MAJOR_NR); + if (register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) { + printk("Unable to get major %d for %s\n", + MAJOR_NR, CDU535_MESSAGE_NAME); #ifndef MODULE return mem_start; #else @@ -1482,19 +1494,17 @@ init_module(void) } } -#ifndef MODULE - if (!initialized) - printk("Did not find a Sony CDU-535 drive\n"); - else - snarf_region(sony_cd_base_io, 4); - return mem_start; -#else if (!initialized) { - printk("Did not find a Sony CDU-535 drive\n"); + printk("Did not find a " CDU535_MESSAGE_NAME " drive\n"); +#ifdef MODULE return -EIO; +#endif } else { - snarf_region(sony_cd_base_io, 4); + request_region(sony_cd_base_io, 4, CDU535_HANDLE); } +#ifndef MODULE + return mem_start; +#else return 0; #endif } @@ -1519,7 +1529,8 @@ sonycd535_setup(char *strings, int *ints) irq_used = ints[2]; #endif if ((strings != NULL) && (*strings != '\0')) - printk("Sony CDU-535: Warning: Unknown interface type: %s\n", strings); + printk("%s: Warning: Unknown interface type: %s\n", + strings, CDU535_MESSAGE_NAME); } #else /* MODULE */ @@ -1527,21 +1538,21 @@ sonycd535_setup(char *strings, int *ints) void cleanup_module(void) { - int i; + int i; if (MOD_IN_USE) { printk("Sony 535 module in use, cannot remove\n"); return; } - if (unregister_blkdev(MAJOR_NR, "cdu-535") == (-EINVAL)) { - printk("Uh oh, couldn't unregister cdu-535\n"); - return; - } + release_region(sony_cd_base_io, 4); kfree_s(sony_toc, sizeof (*sony_toc)); kfree_s(last_sony_subcode, sizeof (*last_sony_subcode)); for (i = 0; i < sony_buffer_sectors; i++) kfree_s(sony_buffer[i], 2048); kfree_s(sony_buffer, 4 * sony_buffer_sectors); - printk("cdu-535 module released\n"); + if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL) + printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n"); + else + printk(CDU535_HANDLE " module released\n"); } #endif /* MODULE */ diff --git a/drivers/char/Makefile b/drivers/char/Makefile index c6b82dcdc93e..45fd9de6d1d8 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -17,12 +17,12 @@ $(CC) $(CFLAGS) -c $< OBJS = tty_io.o n_tty.o console.o keyboard.o serial.o \ - tty_ioctl.o pty.o vt.o mem.o \ - defkeymap.o uni_to_437.o vesa_blank.o + tty_ioctl.o pty.o vt.o mem.o vc_screen.o \ + defkeymap.o consolemap.o vesa_blank.o selection.o SRCS = tty_io.c n_tty.c console.c keyboard.c serial.c \ - tty_ioctl.c pty.c vt.c mem.c \ - defkeymap.c uni_to_437.c vesa_blank.c + tty_ioctl.c pty.c vt.c mem.c vc_screen.c \ + defkeymap.c consolemap.c vesa_blank.c selection.c ifdef CONFIG_CYCLADES diff --git a/drivers/char/console.c b/drivers/char/console.c index a3d31b8ef467..90120c6fb75a 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -25,20 +25,20 @@ * 'void do_blank_screen(int)' * 'void do_unblank_screen(void)' * 'void poke_blanked_console(void)' + * + * 'unsigned short *screen_pos(int currcons, int w_offset, int viewed)' + * 'void complement_pos(int currcons, int offset)' + * 'void invert_screen(int currcons, int offset, int count, int shift)' + * * 'void scrollback(int lines)' * 'void scrollfront(int lines)' - * 'int do_screendump(int arg, int mode)' * * 'int con_get_font(char *)' - * 'int con_set_font(char *)' - * 'int con_get_trans(char *)' - * 'int con_set_trans(char *)' + * 'int con_set_font(char *)' * - * 'int set_selection(const int arg)' - * 'int paste_selection(struct tty_struct *tty)' - * 'int sel_loadlut(const int arg)' + * 'void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)' * 'int mouse_reporting(void)' - * + * * Hopefully this will be a rather complete VT102 implementation. * * Beeping thanks to John T Kohl. @@ -104,40 +104,9 @@ #include "kbd_kern.h" #include "vt_kern.h" +#include "consolemap.h" +#include "selection.h" -#ifdef __alpha__ - -static inline void scrwritew(unsigned short val, unsigned short * addr) -{ - if ((long) addr < 0) - *addr = val; - else - writew(val, (unsigned long) addr); -} - -static inline unsigned short scrreadw(unsigned short * addr) -{ - if ((long) addr < 0) - return *addr; - return readw((unsigned long) addr); -} - -#else - -static inline void scrwritew(unsigned short val, unsigned short * addr) -{ - *addr = val; -} - -static inline unsigned short scrreadw(unsigned short * addr) -{ - return *addr; -} - -#endif - -#define writew(x,y) scrwritew((x),(y)) -#define readw(x) scrreadw(x) #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -149,23 +118,6 @@ static struct tty_struct *console_table[MAX_NR_CONSOLES]; static struct termios *console_termios[MAX_NR_CONSOLES]; static struct termios *console_termios_locked[MAX_NR_CONSOLES]; -#ifdef CONFIG_SELECTION -#include - -/* Routines for selection control. */ -int set_selection(const int arg, struct tty_struct *tty); -int paste_selection(struct tty_struct *tty); -static void clear_selection(void); -static void highlight_pointer(const int currcons, const int where); - -/* Variables for selection control. */ -/* Use a dynamic buffer, instead of static (Dec 1994) */ -static int sel_cons = 0; -static int sel_start = -1; -static int sel_end; -static char *sel_buffer = NULL; -#endif /* CONFIG_SELECTION */ - #define NPAR 16 static void con_setsize(unsigned long rows, unsigned long cols); @@ -194,11 +146,13 @@ static unsigned char video_type; /* Type of display being used */ static unsigned long video_mem_base; /* Base of video memory */ static unsigned long video_mem_term; /* End of video memory */ static unsigned char video_page; /* Initial video page (unused) */ + /* these two also used in vesa_blank.c */ unsigned short video_port_reg; /* Video register select port */ unsigned short video_port_val; /* Video register value port */ -static unsigned long video_num_columns; /* Number of text columns */ -static unsigned long video_num_lines; /* Number of text lines */ -static unsigned long video_size_row; + /* these three also used in selection.c */ + unsigned long video_num_columns; /* Number of text columns */ + unsigned long video_num_lines; /* Number of text lines */ + unsigned long video_size_row; static unsigned long video_screen_size; static int can_do_color = 0; static int printable = 0; /* Is console ready for printing? */ @@ -260,10 +214,10 @@ struct vc_data { unsigned long vc_utf_char; unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */ unsigned char * vc_translate; - unsigned char * vc_G0_charset; - unsigned char * vc_G1_charset; - unsigned char * vc_saved_G0; - unsigned char * vc_saved_G1; + unsigned char vc_G0_charset; + unsigned char vc_G1_charset; + unsigned char vc_saved_G0; + unsigned char vc_saved_G1; /* additional information is in vt_kern.h */ }; @@ -342,7 +296,7 @@ static void memsetw(void * s, unsigned short c, unsigned int count) count /= 2; while (count) { count--; - writew(c, addr++); + scr_writew(c, addr++); } } @@ -352,7 +306,7 @@ static inline void memcpyw(unsigned short *to, unsigned short *from, count /= 2; while (count) { count--; - writew(readw(from++), to++); + scr_writew(scr_readw(from++), to++); } } @@ -522,81 +476,6 @@ void vc_disallocate(unsigned int currcons) #define VT100ID "\033[?1;2c" #define VT102ID "\033[?6c" -static unsigned char * translations[] = { -/* 8-bit Latin-1 mapped to the PC character set: '\0' means non-printable */ -(unsigned char *) - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0" - " !\"#$%&'()*+,-./0123456789:;<=>?" - "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" - "`abcdefghijklmnopqrstuvwxyz{|}~\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376" - "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250" - "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376" - "\376\245\376\376\376\376\231\376\350\376\376\376\232\376\376\341" - "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213" - "\376\244\225\242\223\376\224\366\355\227\243\226\201\376\376\230", -/* vt100 graphics */ -(unsigned char *) - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0" - " !\"#$%&'()*+,-./0123456789:;<=>?" - "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ " - "\004\261\007\007\007\007\370\361\007\007\331\277\332\300\305\304" - "\304\304\137\137\303\264\301\302\263\363\362\343\330\234\007\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376" - "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250" - "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376" - "\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341" - "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213" - "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230", -/* IBM graphics: minimal translations (BS, CR, LF, LL, SO, SI and ESC) */ -(unsigned char *) - "\000\001\002\003\004\005\006\007\000\011\000\013\000\000\000\000" - "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037" - "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" - "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" - "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" - "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" - "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" - "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" - "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" - "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" - "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" - "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" - "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" - "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" - "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" - "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377", - /* USER: customizable mappings, initialized as the previous one (IBM) */ -(unsigned char *) - "\000\001\002\003\004\005\006\007\010\011\000\013\000\000\016\017" - "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037" - "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" - "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" - "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" - "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" - "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" - "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" - "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" - "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" - "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" - "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" - "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" - "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" - "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" - "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" -}; - -#define NORM_TRANS (translations[0]) -#define GRAF_TRANS (translations[1]) -#define NULL_TRANS (translations[2]) -#define USER_TRANS (translations[3]) - static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, 8,12,10,14, 9,13,11,15 }; @@ -641,9 +520,9 @@ static unsigned short __origin; /* offset of currently displayed screen */ static inline void __set_origin(unsigned short offset) { unsigned long flags; -#ifdef CONFIG_SELECTION + clear_selection(); -#endif /* CONFIG_SELECTION */ + save_flags(flags); cli(); __origin = offset; outb_p(12, video_port_reg); @@ -740,12 +619,12 @@ static void scrup(int currcons, unsigned int t, unsigned int b) count = (video_num_lines-1)*video_num_columns; while (count) { count--; - writew(readw(s++),d++); + scr_writew(scr_readw(s++),d++); } count = video_num_columns; while (count) { count--; - writew(video_erase_char, d++); + scr_writew(video_erase_char, d++); } scr_end -= origin-video_mem_start; pos -= origin-video_mem_start; @@ -759,7 +638,7 @@ static void scrup(int currcons, unsigned int t, unsigned int b) count = video_num_columns; while (count) { count--; - writew(video_erase_char, d++); + scr_writew(video_erase_char, d++); } } set_origin(currcons); @@ -770,12 +649,12 @@ static void scrup(int currcons, unsigned int t, unsigned int b) while (count) { count--; - writew(readw(s++), d++); + scr_writew(scr_readw(s++), d++); } count = video_num_columns; while (count) { count--; - writew(video_erase_char, d++); + scr_writew(video_erase_char, d++); } } } @@ -792,12 +671,12 @@ static void scrdown(int currcons, unsigned int t, unsigned int b) count = (b-t-1)*video_num_columns; while (count) { count--; - writew(readw(--s), --d); + scr_writew(scr_readw(--s), --d); } count = video_num_columns; while (count) { count--; - writew(video_erase_char, --d); + scr_writew(video_erase_char, --d); } has_scrolled = 1; } @@ -873,7 +752,7 @@ static void csi_J(int currcons, int vpar) } while (count) { count--; - writew(video_erase_char, start++); + scr_writew(video_erase_char, start++); } need_wrap = 0; } @@ -901,7 +780,7 @@ static void csi_K(int currcons, int vpar) } while (count) { count--; - writew(video_erase_char, start++); + scr_writew(video_erase_char, start++); } need_wrap = 0; } @@ -919,7 +798,7 @@ static void csi_X(int currcons, int vpar) /* erase the following vpar positions while (count) { count--; - writew(video_erase_char, start++); + scr_writew(video_erase_char, start++); } need_wrap = 0; } @@ -934,7 +813,7 @@ static void update_attr(int currcons) attr = (attr & 0xf0) | halfcolor; } if (reverse ^ decscnm) - attr = (attr & 0x88) | (((attr >> 4) | (attr << 4)) & 0x77); + attr = reverse_video_char(attr); if (blink) attr ^= 0x80; if (intensity == 2) @@ -946,7 +825,7 @@ static void update_attr(int currcons) attr = (attr & 0xf0) | 0x08; } if (decscnm) - video_erase_char = (((color & 0x88) | (((color >> 4) | (color << 4)) & 0x77)) << 8) | ' '; + video_erase_char = (reverse_video_char(color) << 8) | ' '; else video_erase_char = (color << 8) | ' '; } @@ -989,7 +868,7 @@ static void csi_m(int currcons) * control chars if defined, don't set * bit 8 on output. */ - translate = (charset == 0 + translate = set_translate(charset == 0 ? G0_charset : G1_charset); disp_ctrl = 0; @@ -999,7 +878,7 @@ static void csi_m(int currcons) * Select first alternate font, let's * chars < 32 be displayed as ROM chars. */ - translate = NULL_TRANS; + translate = set_translate(NULL_MAP); disp_ctrl = 1; toggle_meta = 0; break; @@ -1007,7 +886,7 @@ static void csi_m(int currcons) * Select second alternate font, toggle * high bit before displaying as ROM char. */ - translate = NULL_TRANS; + translate = set_translate(NULL_MAP); disp_ctrl = 1; toggle_meta = 1; break; @@ -1072,9 +951,17 @@ static void cursor_report(int currcons, struct tty_struct * tty) respond_string(buf, tty); } -#ifdef CONFIG_SELECTION -static void mouse_report(int currcons, struct tty_struct * tty, - int butt, int mrx, int mry) +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]; @@ -1082,33 +969,85 @@ static void mouse_report(int currcons, struct tty_struct * tty, (char)('!' + mry)); respond_string(buf, tty); } -#endif -static inline void status_report(int currcons, struct tty_struct * tty) +/* invoked via ioctl(TIOCLINUX) */ +int mouse_reporting(void) { - respond_string("\033[0n", tty); /* Terminal ok */ + int currcons = fg_console; + + return report_mouse; } -static inline void respond_ID(int currcons, struct tty_struct * tty) +static inline unsigned short *screenpos(int currcons, int offset, int viewed) { - respond_string(VT102ID, tty); + unsigned short *p = (unsigned short *)(origin + offset); + if (viewed && currcons == fg_console) + p -= (__real_origin - __origin); + return p; } -static void invert_screen(int currcons) { +/* Note: inverting the screen twice should revert to the original state */ +void invert_screen(int currcons, int offset, int count, int viewed) +{ unsigned short *p; + count /= 2; + p = screenpos(currcons, offset, viewed); if (can_do_color) - for (p = (unsigned short *)origin; p < (unsigned short *)scr_end; p++) { - unsigned short old = readw(p); - writew((old & 0x88ff) | (((old >> 4) | ((old & 0xff00) << 4)) & 0x7700), p); + while (count--) { + unsigned short old = scr_readw(p); + scr_writew(reverse_video_short(old), p); + p++; } else - for (p = (unsigned short *)origin; p < (unsigned short *)scr_end; p++) { - unsigned short old = readw(p); - writew(old ^ ((old & 0x0700 == 0x0100) ? 0x7000 : 0x7700), p); + while (count--) { + unsigned short old = scr_readw(p); + scr_writew(old ^ ((old & 0x0700 == 0x0100) + ? 0x7000 : 0x7700), p); } } +/* used by selection: complement pointer position */ +void complement_pos(int currcons, int offset) +{ + static unsigned short *p = NULL; + static unsigned short old = 0; + + if (p) + scr_writew(old, p); + if (offset == -1) + p = NULL; + else { + p = screenpos(currcons, offset, 1); + old = scr_readw(p); + scr_writew(old ^ 0x7700, p); + } +} + +/* used by selection */ +unsigned short screen_word(int currcons, int offset, int viewed) +{ + return scr_readw(screenpos(currcons, offset, viewed)); +} + +/* used by vcs - note the word offset */ +unsigned short *screen_pos(int currcons, int w_offset, int viewed) +{ + return screenpos(currcons, 2 * w_offset, viewed); +} + +void getconsxy(int currcons, char *p) +{ + p[0] = x; + p[1] = y; +} + +void putconsxy(int currcons, char *p) +{ + gotoxy(currcons, p[0], p[1]); + set_cursor(currcons); +} + static void set_mode(int currcons, int on_off) { int i; @@ -1132,7 +1071,7 @@ static void set_mode(int currcons, int on_off) case 5: /* Inverted screen on/off */ if (decscnm != on_off) { decscnm = on_off; - invert_screen(currcons); + invert_screen(currcons, 0, video_screen_size, 0); update_attr(currcons); } break; @@ -1211,8 +1150,8 @@ static void insert_char(int currcons) unsigned short * p = (unsigned short *) pos; while (i++ < video_num_columns) { - tmp = readw(p); - writew(old, p); + tmp = scr_readw(p); + scr_writew(old, p); old = tmp; p++; } @@ -1231,10 +1170,10 @@ static void delete_char(int currcons) unsigned short * p = (unsigned short *) pos; while (++i < video_num_columns) { - writew(readw(p+1), p); + scr_writew(scr_readw(p+1), p); p++; } - writew(video_erase_char, p); + scr_writew(video_erase_char, p); need_wrap = 0; } @@ -1309,7 +1248,7 @@ static void restore_cur(int currcons) color = s_color; G0_charset = saved_G0; G1_charset = saved_G1; - translate = charset ? G1_charset : G0_charset; + translate = set_translate(charset ? G1_charset : G0_charset); update_attr(currcons); need_wrap = 0; } @@ -1323,9 +1262,9 @@ static void reset_terminal(int currcons, int do_clear) bottom = video_num_lines; vc_state = ESnormal; ques = 0; - translate = NORM_TRANS; - G0_charset = NORM_TRANS; - G1_charset = GRAF_TRANS; + translate = set_translate(NORM_MAP); + G0_charset = NORM_MAP; + G1_charset = GRAF_MAP; charset = 0; need_wrap = 0; report_mouse = 0; @@ -1412,11 +1351,10 @@ static int con_write(struct tty_struct * tty, int from_user, } return 0; } -#ifdef CONFIG_SELECTION - /* clear the selection */ + if (currcons == sel_cons) clear_selection(); -#endif /* CONFIG_SELECTION */ + disable_bh(KEYBOARD_BH); while (!tty->stopped && count) { c = from_user ? get_fs_byte(buf) : *buf; @@ -1426,7 +1364,6 @@ static int con_write(struct tty_struct * tty, int from_user, /* Combine UTF-8 into Unicode */ /* Incomplete characters silently ignored */ if(c > 0x7f) { - /* UTF-8 to Latin-1 decoding */ if (utf_count > 0 && (c & 0xc0) == 0x80) { utf_char = (utf_char << 6) | (c & 0x3f); utf_count--; @@ -1448,18 +1385,15 @@ static int con_write(struct tty_struct * tty, int from_user, utf_count = 0; /* Now try to find out how to display it */ - if (c > 0xff) { - tc = conv_uni_to_pc(c); - if (tc == -2) - continue; - vc_state = ESnormal; - if (tc == -1) - tc = 0376; /* small square: symbol not found */ - ok = 1; - } else { - tc = NORM_TRANS[c]; + tc = conv_uni_to_pc(c); + if (tc == -1 || tc == -2) + continue; + if (tc == -3 || tc == -4) { /* hashtable not valid */ + /* or symbol not found */ + tc = (c <= 0xff) ? translate[c] : 040; ok = 0; - } + } else + ok = 1; } else { /* no utf */ tc = translate[toggle_meta ? (c|0x80) : c]; ok = 0; @@ -1483,7 +1417,7 @@ static int con_write(struct tty_struct * tty, int from_user, } if (decim) insert_char(currcons); - writew((attr << 8) + tc, (unsigned short *) pos); + scr_writew((attr << 8) + tc, (unsigned short *) pos); if (x == video_num_columns - 1) need_wrap = decawm; else { @@ -1522,12 +1456,12 @@ static int con_write(struct tty_struct * tty, int from_user, continue; case 14: charset = 1; - translate = G1_charset; + translate = set_translate(G1_charset); disp_ctrl = 1; continue; case 15: charset = 0; - translate = G0_charset; + translate = set_translate(G0_charset); disp_ctrl = 0; continue; case 24: case 26: @@ -1567,7 +1501,7 @@ static int con_write(struct tty_struct * tty, int from_user, tab_stop[x >> 5] |= (1 << (x & 31)); continue; case 'Z': - respond_ID(currcons,tty); + respond_ID(tty); continue; case '7': save_cur(currcons); @@ -1628,7 +1562,7 @@ static int con_write(struct tty_struct * tty, int from_user, case 'n': if (!ques) if (par[0] == 5) - status_report(currcons,tty); + status_report(tty); else if (par[0] == 6) cursor_report(currcons,tty); continue; @@ -1692,7 +1626,7 @@ static int con_write(struct tty_struct * tty, int from_user, continue; case 'c': if (!par[0]) - respond_ID(currcons,tty); + respond_ID(tty); continue; case 'g': if (!par[0]) @@ -1775,28 +1709,28 @@ static int con_write(struct tty_struct * tty, int from_user, continue; case ESsetG0: if (c == '0') - G0_charset = GRAF_TRANS; + G0_charset = GRAF_MAP; else if (c == 'B') - G0_charset = NORM_TRANS; + G0_charset = NORM_MAP; else if (c == 'U') - G0_charset = NULL_TRANS; + G0_charset = NULL_MAP; else if (c == 'K') - G0_charset = USER_TRANS; + G0_charset = USER_MAP; if (charset == 0) - translate = G0_charset; + translate = set_translate(G0_charset); vc_state = ESnormal; continue; case ESsetG1: if (c == '0') - G1_charset = GRAF_TRANS; + G1_charset = GRAF_MAP; else if (c == 'B') - G1_charset = NORM_TRANS; + G1_charset = NORM_MAP; else if (c == 'U') - G1_charset = NULL_TRANS; + G1_charset = NULL_MAP; else if (c == 'K') - G1_charset = USER_TRANS; + G1_charset = USER_MAP; if (charset == 1) - translate = G1_charset; + translate = set_translate(G1_charset); vc_state = ESnormal; continue; default: @@ -1859,7 +1793,7 @@ void console_print(const char * b) if (c == 10 || c == 13) continue; } - writew((attr << 8) + c, (unsigned short *) pos); + scr_writew((attr << 8) + c, (unsigned short *) pos); if (x == video_num_columns - 1) { need_wrap = 1; continue; @@ -2189,9 +2123,9 @@ void update_screen(int new_console) return; } lock = 1; -#ifdef CONFIG_SELECTION + clear_selection(); -#endif /* CONFIG_SELECTION */ + if (!console_blanked) get_scrmem(fg_console); else @@ -2206,59 +2140,6 @@ void update_screen(int new_console) lock = 0; } -/* - * do_screendump is used for three tasks: - * if (mode==0) is the old ioctl(TIOCLINUX,0) - * if (mode==1) dumps wd,hg, cursor position, and all the char-attr pairs - * if (mode==2) restores what mode1 got. - * the new modes are needed for a fast and complete dump-restore cycle, - * needed to implement root-window menus in text mode (A Rubini Nov 1994) - */ -int do_screendump(unsigned long arg, int mode) -{ - char *sptr, *buf = (char *)arg; - int currcons, l, chcount; - - l = verify_area(VERIFY_READ, buf, 2); - if (l) - return l; - currcons = get_fs_byte(buf+1); - currcons = (currcons ? currcons-1 : fg_console); - if (!vc_cons_allocated(currcons)) - return -EIO; - - /* mode 0 needs 2+wd*ht, modes 1 and 2 need 4+2*wd*ht */ - chcount=video_num_columns*video_num_lines; - l = verify_area(mode==2 ? VERIFY_READ :VERIFY_WRITE, - buf, (2+chcount)*(mode ? 2 : 1)); - if (l) - return l; - if (mode<2) { - put_fs_byte((char)(video_num_lines),buf++); - put_fs_byte((char)(video_num_columns),buf++); - } -#ifdef CONFIG_SELECTION - clear_selection(); -#endif - switch(mode) { - case 0: - sptr = (char *) origin; - for (l=chcount; l>0 ; l--, sptr++) - put_fs_byte(*sptr++,buf++); - break; - case 1: - put_fs_byte((char)x,buf++); put_fs_byte((char)y,buf++); -/*XXX*/ memcpy_tofs(buf,(char *)origin,2*chcount); - break; - case 2: - gotoxy(currcons, get_fs_byte(buf+2), get_fs_byte(buf+3)); - buf+=4; /* ioctl#, console#, x,y */ -/*XXX*/ memcpy_fromfs((char *)origin,buf,2*chcount); - break; - } - return(0); -} - /* * Allocate the console screen memory. */ @@ -2283,289 +2164,6 @@ int con_open(struct tty_struct *tty, struct file * filp) return 0; } -#ifdef CONFIG_SELECTION -/* correction factor for when screen is hardware-scrolled */ -#define hwscroll_offset (currcons == fg_console ? ((__real_origin - __origin) << 1) : 0) - -/* set reverse video on characters s-e of console with selection. */ -static void highlight(const int currcons, const int s, const int e) -{ - unsigned char *p, *p1, *p2; - - p1 = (unsigned char *)origin - hwscroll_offset + s + 1; - p2 = (unsigned char *)origin - hwscroll_offset + e + 1; - - for (p = p1; p <= p2; p += 2) - *p = (*p & 0x88) | ((*p << 4) & 0x70) | ((*p >> 4) & 0x07); -} - -/* use complementary color to show the pointer */ -static void highlight_pointer(const int currcons, const int where) -{ - unsigned char *p; - static unsigned char *prev=NULL; - - if (where==-1) /* remove the pointer */ - { - if (prev) - { - *prev ^= 0x77; - prev=NULL; - } - } - else - { - p = (unsigned char *)origin - hwscroll_offset + where + 1; - *p ^= 0x77; - if (prev) *prev ^= 0x77; /* remove the previous one */ - prev=p; - } -} - - -/* - * This function uses a 128-bit look up table - * WARNING: This depends on both endianness and the ascii code - */ -static unsigned long inwordLut[4]={ - 0x00000000, /* control chars */ - 0x03FF0000, /* digits */ - 0x87FFFFFE, /* uppercase and '_' */ - 0x07FFFFFE /* lowercase */ -}; -static inline int inword(const char c) { - return ( inwordLut[(c>>5)&3] >> (c&0x1F) ) & 1; -} - -/* set inwordLut contents. Invoked by ioctl(). */ -int sel_loadlut(const int arg) -{ - memcpy_fromfs(inwordLut,(unsigned long *)(arg+4),16); - return 0; -} - -/* does screen address p correspond to character at LH/RH edge of screen? */ -static inline int atedge(const int p) -{ - return (!(p % video_size_row) || !((p + 2) % video_size_row)); -} - -/* constrain v such that v <= u */ -static inline unsigned short limit(const unsigned short v, const unsigned short u) -{ -/* gcc miscompiles the ?: operator, so don't use it.. */ - if (v > u) - return u; - return v; -} - -/* invoked via ioctl(TIOCLINUX) */ -int mouse_reporting(void) -{ - int currcons = fg_console; - - return report_mouse; -} - -/* set the current selection. Invoked by ioctl(). */ -int set_selection(const int arg, struct tty_struct *tty) -{ - unsigned short *args, xs, ys, xe, ye; - int currcons = fg_console; - int sel_mode, new_sel_start, new_sel_end, spc; - char *bp, *obp, *spos; - int i, ps, pe; - char *off = (char *)origin - hwscroll_offset; - - unblank_screen(); - args = (unsigned short *)(arg + 1); - xs = get_fs_word(args++) - 1; - ys = get_fs_word(args++) - 1; - xe = get_fs_word(args++) - 1; - ye = get_fs_word(args++) - 1; - sel_mode = get_fs_word(args); - - xs = limit(xs, video_num_columns - 1); - ys = limit(ys, video_num_lines - 1); - xe = limit(xe, video_num_columns - 1); - ye = limit(ye, video_num_lines - 1); - ps = ys * video_size_row + (xs << 1); - pe = ye * video_size_row + (xe << 1); - - if (report_mouse && (sel_mode & 16)) { - mouse_report(currcons, tty, sel_mode & 15, xs, ys); - return 0; - } - - if (ps > pe) /* make sel_start <= sel_end */ - { - int tmp = ps; - ps = pe; - pe = tmp; - } - - switch (sel_mode) - { - case 0: /* character-by-character selection */ - new_sel_start = ps; - new_sel_end = pe; - break; - case 1: /* word-by-word selection */ - spc = isspace(*(off + ps)); - for (new_sel_start = ps; ; ps -= 2) - { - if ((spc && !isspace(*(off + ps))) || - (!spc && !inword(*(off + ps)))) - break; - new_sel_start = ps; - if (!(ps % video_size_row)) - break; - } - spc = isspace(*(off + pe)); - for (new_sel_end = pe; ; pe += 2) - { - if ((spc && !isspace(*(off + pe))) || - (!spc && !inword(*(off + pe)))) - break; - new_sel_end = pe; - if (!((pe + 2) % video_size_row)) - break; - } - break; - case 2: /* line-by-line selection */ - new_sel_start = ps - ps % video_size_row; - new_sel_end = pe + video_size_row - - pe % video_size_row - 2; - break; - case 3: /* pointer highlight */ - if (sel_cons != currcons) - { - clear_selection(); - sel_cons = currcons; - } - highlight_pointer(sel_cons,pe); - return 0; /* nothing more */ - default: - return -EINVAL; - } - /* remove the pointer */ - highlight_pointer(sel_cons,-1); - /* select to end of line if on trailing space */ - if (new_sel_end > new_sel_start && - !atedge(new_sel_end) && isspace(*(off + new_sel_end))) - { - for (pe = new_sel_end + 2; ; pe += 2) - { - if (!isspace(*(off + pe)) || atedge(pe)) - break; - } - if (isspace(*(off + pe))) - new_sel_end = pe; - } - if (sel_cons != currcons) - { - clear_selection(); - sel_cons = currcons; - } - if (sel_start == -1) /* no current selection */ - highlight(sel_cons, 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_cons, sel_end + 2, new_sel_end); - else /* contract from right */ - highlight(sel_cons, new_sel_end + 2, sel_end); - } - else if (new_sel_end == sel_end) - { - if (new_sel_start < sel_start) /* extend to left */ - highlight(sel_cons, new_sel_start, sel_start - 2); - else /* contract from left */ - highlight(sel_cons, sel_start, new_sel_start - 2); - } - else /* some other case; start selection from scratch */ - { - clear_selection(); - highlight(sel_cons, new_sel_start, new_sel_end); - } - sel_start = new_sel_start; - sel_end = new_sel_end; - - /* realloc the buffer (it seems to be efficient, anyway) */ - if (sel_buffer) kfree(sel_buffer); - sel_buffer = kmalloc((sel_end-sel_start)/2+2, GFP_KERNEL); - if (!sel_buffer) - { - printk("selection: kmalloc() failed\n"); - clear_selection(); - return (0); /* is it right? */ - } - obp = bp = sel_buffer; - for (i = sel_start; i <= sel_end; i += 2) - { - spos = (char *)off + i; - *bp++ = *spos; - if (!isspace(*spos)) - obp = bp; - if (! ((i + 2) % video_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; - } - } - *bp = '\0'; - 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 wait_queue wait = { current, NULL }; - char *bp = sel_buffer; - int c, l; - struct vt_struct *vt = (struct vt_struct *) tty->driver_data; - - if (!bp || !bp[0]) - return 0; - unblank_screen(); - c = strlen(sel_buffer); - current->state = TASK_INTERRUPTIBLE; - add_wait_queue(&vt->paste_wait, &wait); - while (c) { - if (test_bit(TTY_THROTTLED, &tty->flags)) { - schedule(); - continue; - } - l = MIN(c, tty->ldisc.receive_room(tty)); - tty->ldisc.receive_buf(tty, bp, 0, l); - c -= l; - bp += l; - } - current->state = TASK_RUNNING; - return 0; -} - -/* remove the current selection highlight, if any, from the console holding - the selection. */ -static void clear_selection() -{ - highlight_pointer(sel_cons, -1); /* hide the pointer */ - if (sel_start != -1) - { - highlight(sel_cons, sel_start, sel_end); - sel_start = -1; - } -} -#endif /* CONFIG_SELECTION */ /* * PIO_FONT support. @@ -2668,6 +2266,7 @@ static int set_get_font(char * arg, int set) int con_set_font (char *arg) { + hashtable_contents_valid = 0; return set_get_font (arg,1); } @@ -2675,36 +2274,3 @@ int con_get_font (char *arg) { return set_get_font (arg,0); } - -/* - * Load customizable translation table (USER_TRANS[]). All checks are here, - * so we need only include 'return con_set_trans(arg)' in the ioctl handler - * arg points to a 256 byte translation table. - */ -int con_set_trans(char * arg) -{ - int i; - - i = verify_area(VERIFY_READ, (void *)arg, E_TABSZ); - if (i) - return i; - - for (i=0; i +#include +#include +#include +#include +#include "consolemap.h" + +static unsigned char * translations[] = { +/* 8-bit Latin-1 mapped to the PC character set: '\0' means non-printable */ +(unsigned char *) + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0" + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376" + "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250" + "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376" + "\376\245\376\376\376\376\231\376\350\376\376\376\232\376\376\341" + "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213" + "\376\244\225\242\223\376\224\366\355\227\243\226\201\376\376\230", +/* vt100 graphics */ +(unsigned char *) + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0" + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ " + "\004\261\007\007\007\007\370\361\007\007\331\277\332\300\305\304" + "\304\304\137\137\303\264\301\302\263\363\362\343\330\234\007\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376" + "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250" + "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376" + "\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341" + "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213" + "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230", +/* IBM graphics: minimal translations (BS, CR, LF, LL, SO, SI and ESC) */ +(unsigned char *) + "\000\001\002\003\004\005\006\007\000\011\000\013\000\000\000\000" + "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037" + "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" + "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" + "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" + "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" + "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" + "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" + "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" + "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377", + /* USER: customizable mappings, initialized as the previous one (IBM) */ +(unsigned char *) + "\000\001\002\003\004\005\006\007\010\011\000\013\000\000\016\017" + "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037" + "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" + "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" + "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" + "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" + "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" + "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" + "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" + "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" +}; + +/* the above mappings are not invertible - this is just a best effort */ +static unsigned char * inv_translate = NULL; +static unsigned char inv_norm_transl[E_TABSZ]; +static unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL }; + +static void set_inverse_transl(int i) +{ + int j; + unsigned char *p = translations[i]; + unsigned char *q = inverse_translations[i]; + + if (!q) { + /* slightly messy to avoid calling kmalloc too early */ + q = inverse_translations[i] = ((i == NORM_MAP) + ? inv_norm_transl + : (unsigned char *) kmalloc(E_TABSZ, GFP_KERNEL)); + if (!q) + return; + } + for (j=0; j current font conversion + * + * A font has at most 512 chars, usually 256. + * But one font position may represent several Unicode chars + * (and moreover, hashtables work best when they are not too full), + * so pick HASHSIZE somewhat larger than 512. + * Since there are likely to be long consecutive stretches + * (like U+0000 to U+00FF), HASHSTEP should not be too small. + * Searches longer than MAXHASHLEVEL steps are refused, unless + * requested explicitly. + * + * Note: no conversion tables are compiled in, so the user + * must supply an explicit mapping herself. See kbd-0.90 (or an + * earlier kernel version) for the default Unicode-to-PC mapping. + * Usually, the mapping will be loaded simultaneously with the font. + */ + +#define HASHSIZE 641 +#define HASHSTEP 189 /* yields hashlevel = 3 initially */ +#define MAXHASHLEVEL 6 +static struct unipair hashtable[HASHSIZE]; + +int hashtable_contents_valid = 0; /* cleared by setfont */ + +static unsigned int hashsize; +static unsigned int hashstep; +static unsigned int hashlevel; +static unsigned int maxhashlevel; + +void +con_clear_unimap(struct unimapinit *ui) { + int i; + + /* read advisory values for hash algorithm */ + hashsize = ui->advised_hashsize; + if (hashsize < 256 || hashsize > HASHSIZE) + hashsize = HASHSIZE; + hashstep = (ui->advised_hashstep % hashsize); + if (hashstep < 64) + hashstep = HASHSTEP; + maxhashlevel = ui->advised_hashlevel; + if (!maxhashlevel) + maxhashlevel = MAXHASHLEVEL; + if (maxhashlevel > hashsize) + maxhashlevel = hashsize; + + /* initialize */ + hashlevel = 0; + for (i=0; iunicode); + i = u % hashsize; + lct = 1; + while ((hu = hashtable[i].unicode) != 0xffff && hu != u) { + if (lct++ >= maxhashlevel) + return -ENOMEM; + i += hashstep; + if (i >= hashsize) + i -= hashsize; + } + if (lct > hashlevel) + hashlevel = lct; + hashtable[i].unicode = u; + hashtable[i].fontpos = get_fs_word(&list->fontpos); + list++; + ct--; + } + return 0; +} + +int +con_get_unimap(ushort ct, ushort *uct, struct unipair *list){ + int i, ect; + + ect = 0; + if (hashtable_contents_valid) + for (i = 0; iunicode); + put_fs_word(hashtable[i].fontpos, &list->fontpos); + list++; + } + } + put_fs_word(ect, uct); + return ((ect <= ct) ? 0 : -ENOMEM); +} + +int +conv_uni_to_pc(unsigned long ucs) { + int i, h; + + if (!hashtable_contents_valid || ucs < 0x20) + return -3; + if (ucs == 0xffff || ucs == 0xfffe) + return -1; + if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f)) + return -2; + + h = ucs % hashsize; + for (i = 0; i < hashlevel; i++) { + if (hashtable[h].unicode == ucs) + return hashtable[h].fontpos; + if ((h += hashstep) >= hashsize) + h -= hashsize; + } + + return -4; /* not found */ +} diff --git a/drivers/char/consolemap.h b/drivers/char/consolemap.h new file mode 100644 index 000000000000..f0a2a91002e0 --- /dev/null +++ b/drivers/char/consolemap.h @@ -0,0 +1,13 @@ +/* + * consolemap.h + * + * Interface between console.c, selection.c and consolemap.c + */ +#define NORM_MAP 0 +#define GRAF_MAP 1 +#define NULL_MAP 2 +#define USER_MAP 3 + +extern int hashtable_contents_valid; +extern unsigned char inverse_translate(unsigned char c); +extern unsigned char *set_translate(int m); diff --git a/drivers/char/kbd_kern.h b/drivers/char/kbd_kern.h index 09d0b6c17efb..b23fa1ed847a 100644 --- a/drivers/char/kbd_kern.h +++ b/drivers/char/kbd_kern.h @@ -4,6 +4,8 @@ #include #include +extern int shift_state; + extern char *func_table[MAX_NR_FUNC]; extern char func_buf[]; extern char *funcbufptr; diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index a340ee9927d1..28002703b84d 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -370,25 +370,29 @@ static void keyboard_interrupt(int irq, struct pt_regs *regs) prev_scancode = 0; goto end_kbd_intr; } + + tty = ttytab[fg_console]; + kbd = kbd_table + fg_console; + if ((raw_mode = (kbd->kbdmode == VC_RAW))) { + put_queue(scancode); + /* we do not return yet, because we want to maintain + the key_down array, so that we have the correct + values when finishing RAW mode or when changing VT's */ + } + if (scancode == 0xff) { + /* in scancode mode 1, my ESC key generates 0xff */ /* the calculator keys on a FOCUS 9000 generate 0xff */ #ifndef KBD_IS_FOCUS_9000 #ifdef KBD_REPORT_ERR - printk("keyboard error\n"); + if (!raw_mode) + printk("keyboard error\n"); #endif #endif prev_scancode = 0; goto end_kbd_intr; } - tty = ttytab[fg_console]; - kbd = kbd_table + fg_console; - if ((raw_mode = (kbd->kbdmode == VC_RAW))) { - put_queue(scancode); - /* we do not return yet, because we want to maintain - the key_down array, so that we have the correct - values when finishing RAW mode or when changing VT's */ - } if (scancode == 0xe0 || scancode == 0xe1) { prev_scancode = scancode; goto end_kbd_intr; @@ -414,7 +418,8 @@ static void keyboard_interrupt(int irq, struct pt_regs *regs) prev_scancode = 0; } else { #ifdef KBD_REPORT_UNKN - printk("keyboard: unknown e1 escape sequence\n"); + if (!raw_mode) + printk("keyboard: unknown e1 escape sequence\n"); #endif prev_scancode = 0; goto end_kbd_intr; @@ -729,7 +734,7 @@ static void SAK(void) * work. */ reset_vc(fg_console); - unblank_screen(); /* not in interrupt routine? */ + do_unblank_screen(); /* not in interrupt routine? */ #endif } diff --git a/drivers/char/selection.c b/drivers/char/selection.c new file mode 100644 index 000000000000..a44b44e57847 --- /dev/null +++ b/drivers/char/selection.c @@ -0,0 +1,291 @@ +/* + * linux/drivers/char/selection.c + * + * This module exports the functions: + * + * 'int set_selection(const int arg)' + * 'void clear_selection(void)' + * 'int paste_selection(struct tty_struct *tty)' + * 'int sel_loadlut(const int arg)' + * + * Now that /dev/vcs exists, most of this can disappear again. + */ + +#include +#include +#include +#include +#include "vt_kern.h" +#include "consolemap.h" +#include "selection.h" + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* Don't take this from : 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 = 0; /* must not be disallocated */ +static volatile int sel_start = -1; /* cleared by clear_selection */ +static int sel_end; +static int sel_buffer_lth = 0; +static char *sel_buffer = NULL; + +#define sel_pos(n) inverse_translate(screen_word(sel_cons, n, 1) & 0xff) + +/* 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(sel_cons, s, e-s+2, 1); +} + +/* use complementary color to show the pointer */ +inline static void +highlight_pointer(const int where) { + complement_pos(sel_cons, where); +} + +/* 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 unsigned long 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 int arg) +{ + int i = verify_area(VERIFY_READ, (char *) arg, 36); + if (i) + return i; + memcpy_fromfs(inwordLut, (unsigned long *)(arg+4), 32); + return 0; +} + +/* does screen address p correspond to character at LH/RH edge of screen? */ +static inline int atedge(const int p) +{ + return (!(p % video_size_row) || !((p + 2) % video_size_row)); +} + +/* constrain v such that v <= u */ +static inline unsigned short limit(const unsigned short v, const unsigned short u) +{ +/* gcc miscompiles the ?: operator, so don't use it.. */ + if (v > u) + return u; + return v; +} + +/* set the current selection. Invoked by ioctl(). */ +int set_selection(const int arg, struct tty_struct *tty) +{ + int sel_mode, new_sel_start, new_sel_end, spc; + char *bp, *obp; + int i, ps, pe; + + do_unblank_screen(); + + { unsigned short *args, xs, ys, xe, ye; + + args = (unsigned short *)(arg + 1); + xs = get_fs_word(args++) - 1; + ys = get_fs_word(args++) - 1; + xe = get_fs_word(args++) - 1; + ye = get_fs_word(args++) - 1; + sel_mode = get_fs_word(args); + + xs = limit(xs, video_num_columns - 1); + ys = limit(ys, video_num_lines - 1); + xe = limit(xe, video_num_columns - 1); + ye = limit(ye, video_num_lines - 1); + ps = ys * video_size_row + (xs << 1); + pe = ye * video_size_row + (xe << 1); + + if (sel_mode == 4) { + /* useful for screendump without selection highlights */ + clear_selection(); + return 0; + } + + if (mouse_reporting() && (sel_mode & 16)) { + mouse_report(tty, sel_mode & 15, xs, ys); + return 0; + } + } + + if (ps > pe) /* make sel_start <= sel_end */ + { + int tmp = ps; + ps = pe; + pe = tmp; + } + + if (sel_cons != fg_console) { + clear_selection(); + sel_cons = fg_console; + } + + switch (sel_mode) + { + case 0: /* character-by-character selection */ + new_sel_start = ps; + new_sel_end = pe; + break; + case 1: /* 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 % video_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) % video_size_row)) + break; + } + break; + case 2: /* line-by-line selection */ + new_sel_start = ps - ps % video_size_row; + new_sel_end = pe + video_size_row + - pe % video_size_row - 2; + break; + case 3: + 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) && isspace(sel_pos(new_sel_end))) { + for (pe = new_sel_end + 2; ; pe += 2) + if (!isspace(sel_pos(pe)) || atedge(pe)) + 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; + + if (sel_buffer) + kfree(sel_buffer); + sel_buffer = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL); + if (!sel_buffer) { + printk("selection: kmalloc() failed\n"); + clear_selection(); + return -ENOMEM; + } + + obp = bp = sel_buffer; + for (i = sel_start; i <= sel_end; i += 2) { + *bp = sel_pos(i); + if (!isspace(*bp++)) + obp = bp; + if (! ((i + 2) % video_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 wait_queue wait = { current, NULL }; + char *bp = sel_buffer; + int c = sel_buffer_lth; + int l; + struct vt_struct *vt = (struct vt_struct *) tty->driver_data; + + if (!bp || !c) + return 0; + do_unblank_screen(); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&vt->paste_wait, &wait); + while (c) { + if (test_bit(TTY_THROTTLED, &tty->flags)) { + schedule(); + continue; + } + l = MIN(c, tty->ldisc.receive_room(tty)); + tty->ldisc.receive_buf(tty, bp, 0, l); + c -= l; + bp += l; + } + current->state = TASK_RUNNING; + return 0; +} diff --git a/drivers/char/selection.h b/drivers/char/selection.h new file mode 100644 index 000000000000..338887e62de6 --- /dev/null +++ b/drivers/char/selection.h @@ -0,0 +1,64 @@ +/* + * selection.h + * + * Interface between console.c, tty_io.c, vt.c, vc_screen.c and selection.c + */ +extern int sel_cons; + +extern void clear_selection(void); +extern int set_selection(const int arg, struct tty_struct *tty); +extern int paste_selection(struct tty_struct *tty); +extern int sel_loadlut(const int arg); +extern int mouse_reporting(void); +extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry); + +extern unsigned long video_num_columns; +extern unsigned long video_num_lines; +extern unsigned long video_size_row; + +extern void do_unblank_screen(void); +extern unsigned short *screen_pos(int currcons, int w_offset, int viewed); +extern unsigned short screen_word(int currcons, int offset, int viewed); +extern void complement_pos(int currcons, int offset); +extern void invert_screen(int currcons, int offset, int count, int shift); + +#define reverse_video_char(a) (((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77)) +#define reverse_video_short(a) (((a) & 0x88ff) | \ + (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4)) +/* this latter line used to have masks 0xf000 and 0x0f00, but selection + requires a self-inverse operation; moreover, the old version looks wrong */ + +extern void getconsxy(int currcons, char *p); +extern void putconsxy(int currcons, char *p); + +/* how to access screen memory */ +#ifdef __alpha__ + +static inline void scr_writew(unsigned short val, unsigned short * addr) +{ + if ((long) addr < 0) + *addr = val; + else + writew(val, (unsigned long) addr); +} + +static inline unsigned short scr_readw(unsigned short * addr) +{ + if ((long) addr < 0) + return *addr; + return readw((unsigned long) addr); +} + +#else + +static inline void scr_writew(unsigned short val, unsigned short * addr) +{ + *addr = val; +} + +static inline unsigned short scr_readw(unsigned short * addr) +{ + return *addr; +} + +#endif diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 126081b38601..3c78d892d88c 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -60,6 +60,7 @@ #include "kbd_kern.h" #include "vt_kern.h" +#include "selection.h" #define CONSOLE_DEV MKDEV(TTY_MAJOR,0) #define TTY_DEV MKDEV(TTYAUX_MAJOR,0) @@ -69,14 +70,6 @@ #define TTY_PARANOIA_CHECK #define CHECK_TTY_COUNT -#ifdef CONFIG_SELECTION -extern int set_selection(const int arg, struct tty_struct *tty); -extern int paste_selection(struct tty_struct *tty); -extern int sel_loadlut(const int arg); -extern int mouse_reporting(void); -extern int shift_state; -#endif /* CONFIG_SELECTION */ -extern int do_screendump(unsigned long arg, int mode); extern void do_blank_screen(int nopowersave); extern void do_unblank_screen(void); extern void set_vesa_blanking(const unsigned long arg); @@ -1247,6 +1240,7 @@ static int tty_fasync(struct inode * inode, struct file * filp, int on) return 0; } +#if 0 /* * XXX does anyone use this anymore?!? */ @@ -1278,6 +1272,7 @@ static int do_get_ps_info(unsigned long arg) put_fs_long(0, (unsigned long *)(ts->present+n)); return(0); } +#endif static int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) @@ -1452,21 +1447,23 @@ static int tty_ioctl(struct inode * inode, struct file * file, return retval; switch (retval = get_fs_byte((char *)arg)) { - case 0: - return do_screendump(arg,0); + case 0: + case 8: + case 9: + printk("TIOCLINUX (0/8/9) ioctl is gone - use /dev/vcs\n"); + return -EINVAL; +#if 0 case 1: printk("Deprecated TIOCLINUX (1) ioctl\n"); return do_get_ps_info(arg); -#ifdef CONFIG_SELECTION +#endif case 2: return set_selection(arg, tty); case 3: return paste_selection(tty); -#endif /* CONFIG_SELECTION */ case 4: do_unblank_screen(); return 0; -#ifdef CONFIG_SELECTION case 5: return sel_loadlut(arg); case 6: @@ -1481,16 +1478,13 @@ static int tty_ioctl(struct inode * inode, struct file * file, case 7: put_fs_byte(mouse_reporting(),arg); return 0; -#endif /* CONFIG_SELECTION */ - case 8: /* second arg is 1 or 2 */ - case 9: /* both are explained in console.c */ - return do_screendump(arg,retval-7); case 10: set_vesa_blanking(arg); return 0; default: return -EINVAL; } + case TIOCTTYGSTRUCT: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct tty_struct)); @@ -1742,5 +1736,6 @@ long tty_init(long kmem_start) kmem_start = cy_init(kmem_start); #endif kmem_start = pty_init(kmem_start); + kmem_start = vcs_init(kmem_start); return kmem_start; } diff --git a/drivers/char/uni_to_437.c b/drivers/char/uni_to_437.c deleted file mode 100644 index 46d0f08805c7..000000000000 --- a/drivers/char/uni_to_437.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * non-Latin-1 (>0x00ff) Unicode -> IBM CP437 conversion hash table - * Markus Kuhn - */ -#define IBM_HASHSIZE 146 -#define IBM_HASHSTEP 19 -#define IBM_HASHLEVEL 4 -static struct { - unsigned short ucs; /* a Unicode code */ - unsigned char ibm437; /* the corresponding IBM code */ -} ibm_hash[IBM_HASHSIZE] = { - {0x221a,0xfb}, {0x2580,0xdf}, {0x2524,0xb4}, {0xffff,0x00}, {0x221e,0xec}, - {0x20a7,0x9e}, {0x2126,0xea}, {0x253c,0xc5}, {0xffff,0x00}, {0x2588,0xdb}, - {0x2666,0x04}, {0x2190,0x1b}, {0x2193,0x19}, {0x2665,0x03}, {0x2195,0x12}, - {0x2663,0x05}, {0x2660,0x06}, {0x2590,0xde}, {0x2022,0x07}, {0x2592,0xb1}, - {0x266c,0x0e}, {0x2502,0xb3}, {0x266a,0x0d}, {0x250c,0xda}, {0x258c,0xdd}, - {0xffff,0x00}, {0xffff,0x00}, {0xffff,0x00}, {0xffff,0x00}, {0x2191,0x18}, - {0x2261,0xf0}, {0x2514,0xc0}, {0x2192,0x1a}, {0x2264,0xf3}, {0x2194,0x1d}, - {0x2591,0xb0}, {0x0393,0xe2}, {0x2593,0xb2}, {0x2500,0xc4}, {0x251c,0xc3}, - {0x2205,0xed}, {0xffff,0x00}, {0x266b,0x0e}, {0x2518,0xd9}, {0x203c,0x13}, - {0xffff,0x00}, {0x2642,0x0b}, {0x2564,0xd1}, {0x2640,0x0c}, {0x2566,0xcb}, - {0x2561,0xb5}, {0x2560,0xcc}, {0x2563,0xb9}, {0x2562,0xb6}, {0x2510,0xbf}, - {0x256c,0xce}, {0x2008,0x00}, {0x03a6,0xe8}, {0x2569,0xca}, {0x2568,0xd0}, - {0x256b,0xd7}, {0x256a,0xd8}, {0x03a9,0xea}, {0xffff,0x00}, {0xffff,0x00}, - {0x25c0,0x11}, {0x0398,0xe9}, {0x2567,0xcf}, {0xffff,0x00}, {0x2248,0xf7}, - {0x03b1,0xe0}, {0x03a3,0xe4}, {0x2265,0xf2}, {0xffff,0x00}, {0x25cb,0x09}, - {0x03b4,0xeb}, {0x2320,0xf4}, {0xffff,0x00}, {0xffff,0x00}, {0xffff,0x00}, - {0x25c4,0x11}, {0xffff,0x00}, {0xffff,0x00}, {0x03bc,0xe6}, {0x2565,0xd2}, - {0xffff,0x00}, {0x22c5,0xf9}, {0x2302,0x7f}, {0x25d9,0x0a}, {0x25d8,0x08}, - {0xffff,0x00}, {0x03c4,0xe7}, {0xffff,0x00}, {0xffff,0x00}, {0x2555,0xb8}, - {0x2554,0xc9}, {0x2557,0xbb}, {0x2556,0xb7}, {0x2551,0xba}, {0x2550,0xcd}, - {0x2553,0xd6}, {0x2552,0xd5}, {0x255d,0xbc}, {0x255c,0xbd}, {0x255f,0xc7}, - {0x2310,0xa9}, {0x2559,0xd3}, {0x2558,0xd4}, {0x255b,0xbe}, {0x255a,0xc8}, - {0xffff,0x00}, {0x0192,0x9f}, {0x2319,0x1c}, {0x2321,0xf5}, {0xffff,0x00}, - {0x25a0,0xfe}, {0xffff,0x00}, {0x21a8,0x17}, {0x263c,0x0f}, {0x25ac,0x16}, - {0x263a,0x01}, {0x263b,0x02}, {0x03c3,0xe5}, {0xffff,0x00}, {0x255e,0xc6}, - {0x03c0,0xe3}, {0x03b2,0xe1}, {0x2300,0xed}, {0xffff,0x00}, {0x25b6,0x10}, - {0x207f,0xfc}, {0xffff,0x00}, {0x2208,0xee}, {0x25b2,0x1e}, {0x220e,0xfe}, - {0x25bc,0x1f}, {0x212b,0x8f}, {0x252c,0xc2}, {0xffff,0x00}, {0x2229,0xef}, - {0xffff,0x00}, {0x25ba,0x10}, {0xffff,0x00}, {0x2584,0xdc}, {0xffff,0x00}, - {0x2534,0xc1} -}; - -/* - * Find the correct PC character set (CP437) code for a - * UCS character outside Latin-1 by hash lookup in ibm_hash[]. - * Return -1 if character not available, return -2 for zero-width - * space characters. - */ -int -conv_uni_to_pc(unsigned long ucs) -{ - int c = -1; - int i, h; - - if (ucs == 0xffff || ucs == 0xfffe) - return -1; - if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f)) - return -2; - - h = (ucs ^ (ucs >> 8)) % IBM_HASHSIZE; - for (i = 0; i < IBM_HASHLEVEL && c == -1; i++) - if (ibm_hash[h].ucs == ucs) - c = ibm_hash[h].ibm437; - else - if ((h += IBM_HASHSTEP) >= IBM_HASHSIZE) - h -= IBM_HASHSIZE; - - return c; -} - -#if 0 -/* - * Conversion from unicode to ibm pc character set (code page 437) - * - * aeb@cwi.nl, Dec 1993 - */ -#define NOTFOUND 254 /* small square */ - -static struct unipc { - long unicode; - unsigned char pc; -} uni_to_pc[255] = { - {0x0020, 0x20}, {0x0021, 0x21}, {0x0022, 0x22}, {0x0023, 0x23}, - {0x0024, 0x24}, {0x0025, 0x25}, {0x0026, 0x26}, {0x0027, 0x27}, - {0x0028, 0x28}, {0x0029, 0x29}, {0x002A, 0x2A}, {0x002B, 0x2B}, - {0x002C, 0x2C}, {0x002D, 0x2D}, {0x002E, 0x2E}, {0x002F, 0x2F}, - {0x0030, 0x30}, {0x0031, 0x31}, {0x0032, 0x32}, {0x0033, 0x33}, - {0x0034, 0x34}, {0x0035, 0x35}, {0x0036, 0x36}, {0x0037, 0x37}, - {0x0038, 0x38}, {0x0039, 0x39}, {0x003A, 0x3A}, {0x003B, 0x3B}, - {0x003C, 0x3C}, {0x003D, 0x3D}, {0x003E, 0x3E}, {0x003F, 0x3F}, - {0x0040, 0x40}, {0x0041, 0x41}, {0x0042, 0x42}, {0x0043, 0x43}, - {0x0044, 0x44}, {0x0045, 0x45}, {0x0046, 0x46}, {0x0047, 0x47}, - {0x0048, 0x48}, {0x0049, 0x49}, {0x004A, 0x4A}, {0x004B, 0x4B}, - {0x004C, 0x4C}, {0x004D, 0x4D}, {0x004E, 0x4E}, {0x004F, 0x4F}, - {0x0050, 0x50}, {0x0051, 0x51}, {0x0052, 0x52}, {0x0053, 0x53}, - {0x0054, 0x54}, {0x0055, 0x55}, {0x0056, 0x56}, {0x0057, 0x57}, - {0x0058, 0x58}, {0x0059, 0x59}, {0x005A, 0x5A}, {0x005B, 0x5B}, - {0x005C, 0x5C}, {0x005D, 0x5D}, {0x005E, 0x5E}, {0x005F, 0x5F}, - {0x0060, 0x60}, {0x0061, 0x61}, {0x0062, 0x62}, {0x0063, 0x63}, - {0x0064, 0x64}, {0x0065, 0x65}, {0x0066, 0x66}, {0x0067, 0x67}, - {0x0068, 0x68}, {0x0069, 0x69}, {0x006A, 0x6A}, {0x006B, 0x6B}, - {0x006C, 0x6C}, {0x006D, 0x6D}, {0x006E, 0x6E}, {0x006F, 0x6F}, - {0x0070, 0x70}, {0x0071, 0x71}, {0x0072, 0x72}, {0x0073, 0x73}, - {0x0074, 0x74}, {0x0075, 0x75}, {0x0076, 0x76}, {0x0077, 0x77}, - {0x0078, 0x78}, {0x0079, 0x79}, {0x007A, 0x7A}, {0x007B, 0x7B}, - {0x007C, 0x7C}, {0x007D, 0x7D}, {0x007E, 0x7E}, {0x00A0, 0xFF}, - {0x00A1, 0xAD}, {0x00A2, 0x9B}, {0x00A3, 0x9C}, {0x00A5, 0x9D}, - {0x00A7, 0x15}, {0x00AA, 0xA6}, {0x00AB, 0xAE}, {0x00AC, 0xAA}, - {0x00B0, 0xF8}, {0x00B1, 0xF1}, {0x00B2, 0xFD}, {0x00B5, 0xE6}, - {0x00B6, 0x14}, {0x00B7, 0xFA}, {0x00BA, 0xA7}, {0x00BB, 0xAF}, - {0x00BC, 0xAC}, {0x00BD, 0xAB}, {0x00BF, 0xA8}, {0x00C4, 0x8E}, - {0x00C5, 0x8F}, {0x00C6, 0x92}, {0x00C7, 0x80}, {0x00C9, 0x90}, - {0x00D1, 0xA5}, {0x00D6, 0x99}, {0x00DC, 0x9A}, {0x00DF, 0xE1}, - {0x00E0, 0x85}, {0x00E1, 0xA0}, {0x00E2, 0x83}, {0x00E4, 0x84}, - {0x00E5, 0x86}, {0x00E6, 0x91}, {0x00E7, 0x87}, {0x00E8, 0x8A}, - {0x00E9, 0x82}, {0x00EA, 0x88}, {0x00EB, 0x89}, {0x00EC, 0x8D}, - {0x00ED, 0xA1}, {0x00EE, 0x8C}, {0x00EF, 0x8B}, {0x00F1, 0xA4}, - {0x00F2, 0x95}, {0x00F3, 0xA2}, {0x00F4, 0x93}, {0x00F6, 0x94}, - {0x00F7, 0xF6}, {0x00F9, 0x97}, {0x00FA, 0xA3}, {0x00FB, 0x96}, - {0x00FC, 0x81}, {0x00FF, 0x98}, {0x0192, 0x9F}, {0x0393, 0xE2}, - {0x0398, 0xE9}, {0x03A3, 0xE4}, {0x03A6, 0xE8}, {0x03A9, 0xEA}, - {0x03B1, 0xE0}, {0x03B4, 0xEB}, {0x03B5, 0xEE}, {0x03C0, 0xE3}, - {0x03C3, 0xE5}, {0x03C4, 0xE7}, {0x03C6, 0xED}, {0x2022, 0x07}, - {0x203C, 0x13}, {0x207F, 0xFC}, {0x20A7, 0x9E}, {0x2190, 0x1B}, - {0x2191, 0x18}, {0x2192, 0x1A}, {0x2193, 0x19}, {0x2194, 0x1D}, - {0x2195, 0x12}, {0x21A8, 0x17}, {0x2219, 0xF9}, {0x221A, 0xFB}, - {0x221E, 0xEC}, {0x221F, 0x1C}, {0x2229, 0xEF}, {0x2248, 0xF7}, - {0x2261, 0xF0}, {0x2264, 0xF3}, {0x2265, 0xF2}, {0x2302, 0x7F}, - {0x2310, 0xA9}, {0x2320, 0xF4}, {0x2321, 0xF5}, {0x2500, 0xC4}, - {0x2502, 0xB3}, {0x250C, 0xDA}, {0x2510, 0xBF}, {0x2514, 0xC0}, - {0x2518, 0xD9}, {0x251C, 0xC3}, {0x2524, 0xB4}, {0x252C, 0xC2}, - {0x2534, 0xC1}, {0x253C, 0xC5}, {0x2550, 0xCD}, {0x2551, 0xBA}, - {0x2552, 0xD5}, {0x2553, 0xD6}, {0x2554, 0xC9}, {0x2555, 0xB8}, - {0x2556, 0xB7}, {0x2557, 0xBB}, {0x2558, 0xD4}, {0x2559, 0xD3}, - {0x255A, 0xC8}, {0x255B, 0xBE}, {0x255C, 0xBD}, {0x255D, 0xBC}, - {0x255E, 0xC6}, {0x255F, 0xC7}, {0x2560, 0xCC}, {0x2561, 0xB5}, - {0x2562, 0xB6}, {0x2563, 0xB9}, {0x2564, 0xD1}, {0x2565, 0xD2}, - {0x2566, 0xCB}, {0x2567, 0xCF}, {0x2568, 0xD0}, {0x2569, 0xCA}, - {0x256A, 0xD8}, {0x256B, 0xD7}, {0x256C, 0xCE}, {0x2580, 0xDF}, - {0x2584, 0xDC}, {0x2588, 0xDB}, {0x258C, 0xDD}, {0x2590, 0xDE}, - {0x2591, 0xB0}, {0x2592, 0xB1}, {0x2593, 0xB2}, {0x25A0, 0xFE}, - {0x25AC, 0x16}, {0x25B2, 0x1E}, {0x25BA, 0x10}, {0x25BC, 0x1F}, - {0x25C4, 0x11}, {0x25CB, 0x09}, {0x25D8, 0x08}, {0x25D9, 0x0A}, - {0x263A, 0x01}, {0x263B, 0x02}, {0x263C, 0x0F}, {0x2640, 0x0C}, - {0x2642, 0x0B}, {0x2660, 0x06}, {0x2663, 0x05}, {0x2665, 0x03}, - {0x2666, 0x04}, {0x266A, 0x0D}, {0x266B, 0x0E} -}; - -unsigned char -conv_uni_to_pc(unsigned long u) { - /* Binary search - no doubt this can be sped up using hash codes */ - /* (or by table lookup if we are in the first half) */ - int step = 128; - struct unipc *up = uni_to_pc + step - 1; - - while(1) { - if(up->unicode == u) - return up->pc; - step >>= 1; - if(!step) - return NOTFOUND; - if(up->unicode < u) - up += step; - else - up -= step; - } -} -#endif diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c new file mode 100644 index 000000000000..f5f389cf8558 --- /dev/null +++ b/drivers/char/vc_screen.c @@ -0,0 +1,212 @@ +/* + * 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) + * [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 + */ + +#include +#include +#include +#include +#include +#include +#include "vt_kern.h" +#include "selection.h" + +#define HEADER_SIZE 4 + +static inline int +vcs_size(struct inode *inode) +{ + int size = video_num_lines * video_num_columns; + if (MINOR(inode->i_rdev) & 128) + size = 2*size + HEADER_SIZE; + return size; +} + +static int +vcs_lseek(struct inode *inode, struct file *file, off_t offset, int orig) +{ + int size = vcs_size(inode); + + switch (orig) { + case 0: + file->f_pos = offset; + break; + case 1: + file->f_pos += offset; + break; + case 2: + file->f_pos = size + offset; + break; + default: + return -EINVAL; + } + if (file->f_pos < 0 || file->f_pos > size) + return -EINVAL; + return file->f_pos; +} + +static int +vcs_read(struct inode *inode, struct file *file, char *buf, int count) +{ + unsigned long p = file->f_pos; + unsigned int cons = MINOR(inode->i_rdev); + int viewed, attr, size, read; + char *buf0; + unsigned short *org; + + attr = (cons & 128); + cons = (cons & 127); + if (cons == 0) { + cons = fg_console; + viewed = 1; + } else { + cons--; + viewed = 0; + } + if (!vc_cons_allocated(cons)) + return -ENXIO; + + size = vcs_size(inode); + if (count < 0 || p > size) + return -EINVAL; + if (count > size - p) + count = size - p; + + buf0 = buf; + if (!attr) { + org = screen_pos(cons, p, viewed); + while (count-- > 0) + put_fs_byte(scr_readw(org++) & 0xff, buf++); + } else { + if (p < HEADER_SIZE) { + char header[HEADER_SIZE]; + header[0] = (char) video_num_lines; + header[1] = (char) video_num_columns; + getconsxy(cons, header+2); + while (p < HEADER_SIZE && count-- > 0) + put_fs_byte(header[p++], buf++); + } + p -= HEADER_SIZE; + org = screen_pos(cons, p/2, viewed); + if ((p & 1) && count-- > 0) + put_fs_byte(scr_readw(org++) >> 8, buf++); + while (count > 1) { + put_fs_word(scr_readw(org++), buf); + buf += 2; + count -= 2; + } + if (count > 0) + put_fs_byte(scr_readw(org) & 0xff, buf++); + } + read = buf - buf0; + file->f_pos += read; + return read; +} + +static int +vcs_write(struct inode *inode, struct file *file, char *buf, int count) +{ + unsigned long p = file->f_pos; + unsigned int cons = MINOR(inode->i_rdev); + int viewed, attr, size, written; + char *buf0; + unsigned short *org; + + attr = (cons & 128); + cons = (cons & 127); + if (cons == 0) { + cons = fg_console; + viewed = 1; + } else { + cons--; + viewed = 0; + } + if (!vc_cons_allocated(cons)) + return -ENXIO; + + size = vcs_size(inode); + if (count < 0 || p > size) + return -EINVAL; + if (count > size - p) + count = size - p; + + buf0 = buf; + if (!attr) { + org = screen_pos(cons, p, viewed); + while (count-- > 0) { + scr_writew((scr_readw(org) & 0xff00) | + get_fs_byte(buf++), org); + org++; + } + } else { + if (p < HEADER_SIZE) { + char header[HEADER_SIZE]; + getconsxy(cons, header+2); + while (p < HEADER_SIZE && count-- > 0) + header[p++] = get_fs_byte(buf++); + if (!viewed) + putconsxy(cons, header+2); + } + p -= HEADER_SIZE; + org = screen_pos(cons, p/2, viewed); + if ((p & 1) && count-- > 0) { + scr_writew((get_fs_byte(buf++) << 8) | + (scr_readw(org) & 0xff), org); + org++; + } + while (count > 1) { + scr_writew(get_fs_word(buf), org++); + buf += 2; + count -= 2; + } + if (count > 0) + scr_writew((scr_readw(org) & 0xff00) | + get_fs_byte(buf++), org); + } + written = buf - buf0; + file->f_pos += written; + return written; +} + +static int +vcs_open(struct inode *inode, struct file *filp) +{ + unsigned int cons = (MINOR(inode->i_rdev) & 127); + if(cons && !vc_cons_allocated(cons-1)) + return -ENXIO; + return 0; +} + +static struct file_operations vcs_fops = { + vcs_lseek, /* lseek */ + vcs_read, /* read */ + vcs_write, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + vcs_open, /* open */ + NULL, /* release */ + NULL /* fsync */ +}; + +long vcs_init(long kmem_start) +{ + if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops)) + printk("unable to get major %d for vcs device", VCS_MAJOR); + return kmem_start; +} diff --git a/drivers/char/vt.c b/drivers/char/vt.c index baf20f501da6..d2b79124df8d 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -24,10 +24,13 @@ #include "kbd_kern.h" #include "vt_kern.h" #include "diacr.h" +#include "selection.h" extern struct tty_driver console_driver; +extern int sel_cons; #define VT_IS_IN_USE(i) (console_driver.table[i] && console_driver.table[i]->count) +#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons) /* * Console (vt and kd) routines, as defined by USL SVR4 manual, and by @@ -62,6 +65,9 @@ extern unsigned int keymap_count; */ extern int con_set_trans(char * table); extern int con_get_trans(char * table); +extern void con_clear_unimap(struct unimapinit *ui); +extern int con_set_unimap(ushort ct, struct unipair *list); +extern int con_get_unimap(ushort ct, ushort *uct, struct unipair *list); extern int con_set_font(char * fontmap); extern int con_get_font(char * fontmap); @@ -792,12 +798,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (arg == 0) { /* disallocate all unused consoles, but leave 0 */ for (i=1; ientry_ct); + list = (struct unipair *) get_fs_long(&ud->entries); + i = verify_area(VERIFY_READ, (void *) list, + ct*sizeof(struct unipair)); + } + if (i) + return i; + return con_set_unimap(ct, list); + } + + case GIO_UNIMAP: + { struct unimapdesc *ud; + u_short ct; + struct unipair *list; + + i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct unimapdesc)); + if (i == 0) { + ud = (struct unimapdesc *) arg; + ct = get_fs_word(&ud->entry_ct); + list = (struct unipair *) get_fs_long(&ud->entries); + if (ct) + i = verify_area(VERIFY_WRITE, (void *) list, + ct*sizeof(struct unipair)); + } + if (i) + return i; + return con_get_unimap(ct, &(ud->entry_ct), list); + } + default: return -ENOIOCTLCMD; } diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index cfde63f106cd..52f7669d2e1e 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -270,7 +270,7 @@ el1_probe1(struct device *dev, int ioaddr) if (autoirq) dev->irq = autoirq; - printk("%s: %s EtherLink at %#x, using %sIRQ %d.\n", + printk("%s: %s EtherLink at %#lx, using %sIRQ %d.\n", dev->name, mname, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq); diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index b45082228c90..cdb34893bb50 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -228,7 +228,7 @@ int el3_probe(struct device *dev) { char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; - printk("%s: 3c509 at %#3.3x tag %d, %s port, address ", + printk("%s: 3c509 at %#3.3lx tag %d, %s port, address ", dev->name, dev->base_addr, current_tag, if_names[dev->if_port]); } diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index 1100ad5c78b3..8d0bfa994b79 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -1485,7 +1485,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i, error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i)); if (error == 0) { put_fs_long (ppp->dev->base_addr, l); - PRINTKN (3,(KERN_INFO "ppp_ioctl: get unit: %d", ppp->dev->base_addr)); + PRINTKN (3,(KERN_INFO "ppp_ioctl: get unit: %ld", ppp->dev->base_addr)); } break; diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index 67dd077a7f2a..664198411aa2 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1,6 +1,11 @@ /* * eata.c - Low-level driver for EATA/DMA SCSI host adapters. * + * 11 Feb 1995 rev. 1.17 for linux 1.1.91 + * Now DEBUG_RESET is disabled by default. + * Register a board even if it does not assert DMA protocol support + * (DPT SK2011B does not report correctly the dmasup bit). + * * 9 Feb 1995 rev. 1.16 for linux 1.1.90 * Use host->wish_block instead of host->block. * New list of Data Out SCSI commands. @@ -124,6 +129,7 @@ #undef DEBUG_DETECT #undef DEBUG_INTERRUPT #undef DEBUG_STATISTICS +#undef DEBUG_RESET #define MAX_TARGET 8 #define MAX_IRQ 16 @@ -390,9 +396,9 @@ static inline int port_detect(ushort *port_base, unsigned int j, if (*port_base & EISA_RANGE) { - if (!info.haaval || info.ata || info.drqvld || !info.dmasup) { - printk("%s: unusable EISA board found (%d%d%d%d), detaching.\n", - name, info.haaval, info.ata, info.drqvld, info.dmasup); + if (!info.haaval || info.ata || info.drqvld) { + printk("%s: unusable EISA board found (%d%d%d), detaching.\n", + name, info.haaval, info.ata, info.drqvld); return FALSE; } @@ -401,9 +407,9 @@ static inline int port_detect(ushort *port_base, unsigned int j, } else { - if (!info.haaval || info.ata || !info.drqvld || !info.dmasup) { - printk("%s: unusable ISA board found (%d%d%d%d), detaching.\n", - name, info.haaval, info.ata, info.drqvld, info.dmasup); + if (!info.haaval || info.ata || !info.drqvld) { + printk("%s: unusable ISA board found (%d%d%d), detaching.\n", + name, info.haaval, info.ata, info.drqvld); return FALSE; } @@ -411,6 +417,9 @@ static inline int port_detect(ushort *port_base, unsigned int j, dma_channel = dma_channel_table[3 - info.drqx]; } + if (!info.dmasup) + printk("%s: warning, DMA protocol support not asserted.\n", name); + if (subversion == ESA && !info.irq_tr) printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n", name, irq); @@ -799,7 +808,11 @@ int eata2x_reset (Scsi_Cmnd *SCarg) { } printk("%s: reset, board reset done, enabling interrupts.\n", BN(j)); + +#if defined (DEBUG_RESET) do_trace = TRUE; +#endif + HD(j)->in_reset = TRUE; sti(); time = jiffies; diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h index bca8489ac117..9652b7f34879 100644 --- a/drivers/scsi/eata.h +++ b/drivers/scsi/eata.h @@ -7,7 +7,7 @@ #include -#define EATA_VERSION "1.16.00" +#define EATA_VERSION "1.17.00" int eata2x_detect(Scsi_Host_Template *); int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); diff --git a/drivers/scsi/eata_dma.c b/drivers/scsi/eata_dma.c index af754f4f03b1..ee97845ac3cc 100644 --- a/drivers/scsi/eata_dma.c +++ b/drivers/scsi/eata_dma.c @@ -44,10 +44,10 @@ * Thanks also to Greg Hosler who did a lot of testing and * * found quite a number of bugs during the development. * ************************************************************ - * last change: 95/01/30 * + * last change: 95/02/13 OS: Linux 1.1.91 or higher * ************************************************************/ -/* Look in eata_dma.h for configuration information */ +/* Look in eata_dma.h for configuration and revision information */ #ifdef MODULE #include @@ -63,12 +63,17 @@ #include #include #include -#include "eata_dma.h" +#include "../block/blk.h" #include "scsi.h" #include "sd.h" +#include "hosts.h" +#include +#include "eata_dma.h" -#if 0 -#include "eata_dma_proc.c" +#if EATA_DMA_PROC +#include "eata_dma_proc.h" /* If you're interested send me a mail */ +ulong reads[13]; /* /proc/scsi probably won't get */ +ulong writes[13]; /* into the kernel before pl. 1.3 */ #endif static uint ISAbases[] = @@ -85,7 +90,7 @@ static unchar reg_IRQL[] = static struct eata_sp status[MAXIRQ]; /* Statuspacket array */ static uint internal_command_finished = TRUE; - +static unchar HBA_interpret = FALSE; static struct geom_emul geometry; /* Drive 1 & 2 geometry */ static ulong int_counter = 0; @@ -96,6 +101,10 @@ void eata_scsi_done (Scsi_Cmnd * SCpnt) return; } +#if EATA_DMA_PROC +#include "eata_dma_proc.c" +#endif + int eata_release(struct Scsi_Host *sh) { if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq); @@ -235,7 +244,10 @@ void eata_int_handler(int irq, struct pt_regs * regs) restore_flags(flags); if(cmd->scsi_done != eata_scsi_done) cmd->scsi_done(cmd); - else internal_command_finished = TRUE; + else { + internal_command_finished = TRUE; + HBA_interpret = FALSE; + } save_flags(flags); cli(); } @@ -337,7 +349,7 @@ int eata_queue(Scsi_Cmnd * cmd, void *(done) (Scsi_Cmnd *)) cp->DataIn = TRUE; /* Input mode */ } - if (done == (void *) eata_scsi_done) + if (done == (void *) eata_scsi_done && HBA_interpret == TRUE) cp->Interpret = TRUE; /* Interpret command */ if (cmd->use_sg) { @@ -699,7 +711,7 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt) return (FALSE); } - if(gc->HAA_valid == FALSE || ntohl(gc->len) == 0x1c || ntohl(gc->len) == 0x1e) + if(gc->HAA_valid == FALSE || ntohl(gc->len) <= 0x1e) gc->MAX_CHAN = 0; if(strncmp("PM2322", &buff[16], 6) && strncmp("PM3021", &buff[16], 6) @@ -746,7 +758,6 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt) "This might be a PM2012 with a defective Firmware\n"); } - size = sizeof(hostdata) + ((sizeof(struct eata_ccb) * ntohs(gc->queuesiz))/ (gc->MAX_CHAN + 1)); @@ -824,11 +835,14 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt) else hd->primary = TRUE; - if (hd->bustype != 'I') + if (hd->bustype != 'I') { sh->unchecked_isa_dma = FALSE; - else + sh->wish_block = FALSE; + } + else { sh->unchecked_isa_dma = TRUE; /* We're doing ISA DMA */ - + sh->wish_block = TRUE; /* This will reduce performance */ + } if((hd->primary == TRUE) && (i == 0) && HARDCODED){ geometry.drv[0].heads = HEADS0; geometry.drv[0].sectors = SECTORS0; diff --git a/drivers/scsi/eata_dma.h b/drivers/scsi/eata_dma.h index dd746620523e..723e2a6d3f07 100644 --- a/drivers/scsi/eata_dma.h +++ b/drivers/scsi/eata_dma.h @@ -2,21 +2,16 @@ * Header file for eata_dma.c Linux EATA-DMA SCSI driver * * (c) 1993,94,95 Michael Neuffer * ********************************************************* -* last change: 95/01/30 * +* last change: 95/02/13 * ********************************************************/ #ifndef _EATA_DMA_H #define _EATA_DMA_H -#include "../block/blk.h" -#include "scsi.h" -#include "hosts.h" -#include - #define VER_MAJOR 2 #define VER_MINOR 3 -#define VER_SUB "0a" +#define VER_SUB "1a" /************************************************************************ * Here you can configure your drives that are using a non-standard * @@ -44,6 +39,7 @@ ************************************************************************/ #define CHECKPAL 0 /* EISA pal checking on/off */ +#define EATA_DMA_PROC 0 /* proc-fs support */ /************************************************************************ * Debug options. * @@ -132,19 +128,22 @@ int eata_release(struct Scsi_Host *); #define C_P_L_CURRENT_MAX 10 /* Until this limit in the mm is removed * Kernels < 1.1.86 died horrible deaths * if you used values >2. The memory management - * of pl.86 seems to cope with 10. + * since pl1.1.86 seems to cope with up to 10 + * queued commands per device. */ #define C_P_L_DIV 4 /* 1 <= C_P_L_DIV <= 8 * You can use this parameter to fine-tune * the driver. Depending on the number of - * devices and their ability to queue commands - * you will get the best results with a value + * devices and their speed and ability to queue + * commands, you will get the best results with a + * value * ~= numdevices-(devices_unable_to_queue_commands/2) - * The reason for this is that the disk driver tents - * to flood the queue, so that other drivers have - * problems to queue commands themselves. This can - * for example result in the effect that the tape - * stops during disk accesses. + * The reason for this is that the disk driver + * tends to flood the queue, so that other + * drivers have problems to queue commands + * themselves. This can for example result in + * the effect that the tape stops during disk + * accesses. */ #define FREE 0 diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 930b11a13116..d6b5337eb71a 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -216,9 +216,6 @@ int next_scsi_host = 0; void scsi_unregister(struct Scsi_Host * sh){ struct Scsi_Host * shpnt; - int j; - - j = sh->extra_bytes; if(scsi_hostlist == sh) scsi_hostlist = sh->next; @@ -227,8 +224,14 @@ scsi_unregister(struct Scsi_Host * sh){ while(shpnt->next != sh) shpnt = shpnt->next; shpnt->next = shpnt->next->next; }; + + /* If we are removing the last host registered, it is safe to reuse + its host number (this avoids "holes" at boot time) (DB) */ + if (max_scsi_hosts == next_scsi_host && !scsi_loadable_module_flag) + max_scsi_hosts--; + next_scsi_host--; - scsi_init_free((char *) sh, sizeof(struct Scsi_Host) + j); + scsi_init_free((char *) sh, sizeof(struct Scsi_Host) + sh->extra_bytes); } /* We call this when we come across a new host adapter. We only do this diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 6f27ade60fb8..3b944ff49d70 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -307,12 +307,15 @@ void scan_scsis (struct Scsi_Host * shpnt) struct Scsi_Device_Template * sdtpnt; Scsi_Cmnd SCmd; + memset(&SCmd, 0, sizeof(SCmd)); ++in_scan_scsis; lun = 0; type = -1; SCmd.next = NULL; SCmd.prev = NULL; SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC); + SCmd.device = SDpnt; /* This was really needed! (DB) */ + memset(SDpnt, 0, sizeof(Scsi_Device)); SDtail = scsi_devices; if(scsi_devices) { while(SDtail->next) SDtail = SDtail->next; @@ -1913,36 +1916,51 @@ int scsi_free(void *obj, unsigned int len) pool */ static unsigned long scsi_init_memory_start = 0; +static unsigned long scsi_memory_lower_value = 0; +static unsigned long scsi_memory_upper_value = 0; int scsi_loadable_module_flag; /* Set after we scan builtin drivers */ void * scsi_init_malloc(unsigned int size, int priority) { unsigned long retval; - if(scsi_loadable_module_flag) { +#if 0 /* Use the statically allocated memory instead of kmalloc (DB) */ + if(scsi_loadable_module_flag && !(priority & GFP_DMA)) +#else + if(scsi_loadable_module_flag) +#endif retval = (unsigned long) kmalloc(size, priority); - } else { + else { /* * Keep all memory aligned on 16-byte boundaries. Some host adaptors * (e.g. BusLogic BT-445S) require DMA buffers to be aligned that way. */ size = (size + 15) & ~15; - retval = scsi_init_memory_start; - scsi_init_memory_start += size; - } + + if(scsi_loadable_module_flag && + (scsi_init_memory_start + size) > scsi_memory_upper_value) { + retval = 0; + printk("scsi_init_malloc: no more statically allocated memory.\n"); + } + else { + retval = scsi_init_memory_start; + scsi_init_memory_start += size; + } + } return (void *) retval; } void scsi_init_free(char * ptr, unsigned int size) -{ /* FIXME - not right. We need to compare addresses to see whether this was - kmalloc'd or not */ - if((unsigned long) ptr > scsi_init_memory_start) { - kfree(ptr); - } else { - size = (size + 15) & ~15; /* Use the same alignment as scsi_init_malloc(). */ +{ /* We need to compare addresses to see whether this was kmalloc'd or not */ + + if((unsigned long) ptr >= scsi_init_memory_start || + (unsigned long) ptr < scsi_memory_lower_value) kfree(ptr); + else { + size = (size + 15) & ~15; /* Use the same alignment as scsi_init_malloc() */ + if(((unsigned long) ptr) + size == scsi_init_memory_start) scsi_init_memory_start = (unsigned long) ptr; - } + } } /* @@ -1967,6 +1985,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end scsi_loadable_module_flag = 0; /* Align everything on 16-byte boundaries. */ scsi_init_memory_start = (memory_start + 15) & ~ 15; + scsi_memory_lower_value = scsi_init_memory_start; timer_table[SCSI_TIMER].fn = scsi_main_timeout; timer_table[SCSI_TIMER].expires = 0; @@ -2068,7 +2087,20 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end (*sdtpnt->finish)(); scsi_loadable_module_flag = 1; + +#if 0 /* This allocates statically some extra memory to be used for modules, + until the kmalloc problem is fixed (DB) */ + + scsi_memory_upper_value = scsi_init_memory_start + + 2 * (scsi_init_memory_start - scsi_memory_lower_value); + + printk ("scsi memory: lower %p, upper %p.\n", + (void *)scsi_memory_lower_value, (void *)scsi_memory_upper_value); + + return scsi_memory_upper_value; +#else return scsi_init_memory_start; +#endif } static void print_inquiry(unsigned char *data) @@ -2292,7 +2324,8 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) commands */ for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next) - if(sdpnt->host->hostt == tpnt && *sdpnt->host->hostt->usage_count) return; + if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->usage_count + && *sdpnt->host->hostt->usage_count) return; for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index f1ec868eca36..463d2d87d4c5 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -15,7 +15,8 @@ #define IOCTL_RETRIES 3 /* The CDROM is fairly slow, so we need a little extra time */ -#define IOCTL_TIMEOUT 2000 +/* In fact, it is very slow if it has to spin up first */ +#define IOCTL_TIMEOUT 3000 extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 3f5d07a6df5b..a0848e094b89 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -54,7 +54,7 @@ #define ST_BLOCK_SIZE 1024 -#define ST_MAX_BUFFERS 2 +#define ST_MAX_BUFFERS (2 + ST_EXTRA_DEVS) #define ST_BUFFER_BLOCKS 32 @@ -1948,7 +1948,7 @@ static void st_init() } /* Allocate the buffers */ - st_nbr_buffers = st_template.dev_noticed; + st_nbr_buffers = st_template.dev_noticed + ST_EXTRA_DEVS; if (st_nbr_buffers > st_max_buffers) st_nbr_buffers = st_max_buffers; st_buffers = (ST_buffer **) scsi_init_malloc(st_nbr_buffers * diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 6364116e4d4a..35ad39196856 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -1,6 +1,10 @@ /* * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. * + * 11 Feb 1995 rev. 1.17 for linux 1.1.91 + * U14F qualified to run with 32 sglists. + * Now DEBUG_RESET is disabled by default. + * * 9 Feb 1995 rev. 1.16 for linux 1.1.90 * Use host->wish_block instead of host->block. * @@ -69,8 +73,8 @@ * * Here a sample configuration using two U14F boards: * - U14F0: PORT 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 16, Mbox 16, CmdLun 2, C1. - U14F1: PORT 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 16, Mbox 16, CmdLun 2, C1. + U14F0: PORT 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 32, Mbox 16, CmdLun 2, C1. + U14F1: PORT 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 32, Mbox 16, CmdLun 2, C1. * * The boot controller must have its BIOS enabled, while other boards can * have their BIOS disabled, or enabled to an higher address. @@ -159,12 +163,14 @@ #undef DEBUG_DETECT #undef DEBUG_INTERRUPT #undef DEBUG_STATISTICS +#undef DEBUG_RESET #define MAX_TARGET 8 #define MAX_IRQ 16 #define MAX_BOARDS 4 #define MAX_MAILBOXES 16 -#define MAX_SGLIST 16 +#define MAX_SGLIST 32 +#define MAX_SAFE_SGLIST 16 #define MAX_CMD_PER_LUN 2 #define FALSE 0 @@ -427,7 +433,6 @@ static inline int port_detect(ushort *port_base, unsigned int j, if (HD(j)->subversion == ESA) { sh[j]->dma_channel = NO_DMA; sh[j]->unchecked_isa_dma = FALSE; - sh[j]->hostt->use_clustering = ENABLE_CLUSTERING; sprintf(BN(j), "U34F%d", j); } else { @@ -435,8 +440,7 @@ static inline int port_detect(ushort *port_base, unsigned int j, #if defined (HAVE_OLD_U14F_FIRMWARE) sh[j]->hostt->use_clustering = DISABLE_CLUSTERING; -#else - sh[j]->hostt->use_clustering = ENABLE_CLUSTERING; + sh[j]->sg_tablesize = MAX_SAFE_SGLIST; #endif sh[j]->dma_channel = dma_channel; @@ -456,6 +460,7 @@ static inline int port_detect(ushort *port_base, unsigned int j, printk("%s: firmware %s is outdated, BIOS rev. should be 2.01.\n", BN(j), &HD(j)->board_id[32]); sh[j]->hostt->use_clustering = DISABLE_CLUSTERING; + sh[j]->sg_tablesize = MAX_SAFE_SGLIST; } } @@ -737,7 +742,11 @@ int u14_34f_reset(Scsi_Cmnd * SCarg) { outb(CMD_RESET, sh[j]->io_port + REG_LCL_INTR); printk("%s: reset, board reset done, enabling interrupts.\n", BN(j)); + +#if defined (DEBUG_RESET) do_trace = TRUE; +#endif + HD(j)->in_reset = TRUE; sti(); time = jiffies; diff --git a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h index d97d491a0f25..169da55de4f3 100644 --- a/drivers/scsi/u14-34f.h +++ b/drivers/scsi/u14-34f.h @@ -10,7 +10,7 @@ int u14_34f_abort(Scsi_Cmnd *); int u14_34f_reset(Scsi_Cmnd *); int u14_34f_biosparam(Disk *, int, int *); -#define U14_34F_VERSION "1.16.00" +#define U14_34F_VERSION "1.17.00" #define ULTRASTOR_14_34F { \ NULL, /* Ptr for modules */ \ @@ -31,6 +31,6 @@ int u14_34f_biosparam(Disk *, int, int *); 0, /* cmd_per_lun, reset by detect */ \ 0, /* number of boards present */ \ 1, /* unchecked isa dma, reset by detect */ \ - 0, /* use_clustering, reset by detect */ \ + ENABLE_CLUSTERING \ } #endif diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 1d93f89ffc87..3cc827f666e0 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -38,7 +38,7 @@ #include #include -typedef int (*sysfun_p)(); +typedef int (*sysfun_p)(int); extern sysfun_p sys_call_table[]; #define SYS(name) (sys_call_table[__NR_##name]) diff --git a/fs/locks.c b/fs/locks.c index 7b7a246dce57..a06f3267dda4 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -15,6 +15,15 @@ * Converted file_lock_table to a linked list from an array, which eliminates * the limits on how many active file locks are open - Chad Page * (pageone@netcom.com), November 27, 1994 + * + * Removed dependency on file descriptors. dup()'ed file descriptors now + * get the same locks as the original file descriptors, and a close() on + * any file descriptor removes ALL the locks on the file for the current + * process. Since locks still depend on the process id, locks are inherited + * after an exec() but not after a fork(). This agrees with POSIX, and both + * BSD and SVR4 practice. + * Andy Walker (andy@keo.kvaerner.no), February 14, 1994 + * */ #define DEADLOCK_DETECTION @@ -30,20 +39,22 @@ #define OFFSET_MAX ((off_t)0x7fffffff) /* FIXME: move elsewhere? */ -static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l, - unsigned int fd); +static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l); static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl); static int overlap(struct file_lock *fl1, struct file_lock *fl2); -static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd); -static struct file_lock *alloc_lock(struct file_lock **pos, struct file_lock *fl, - unsigned int fd); +static int lock_it(struct file *filp, struct file_lock *caller); +static struct file_lock *alloc_lock(struct file_lock **pos, struct file_lock *fl); static void free_lock(struct file_lock **fl); +static void free_list_garbage_collect(void); #ifdef DEADLOCK_DETECTION int locks_deadlocked(int my_pid,int blocked_pid); #endif +#define FREE_LIST_GARBAGE_COLLECT 20 + static struct file_lock *file_lock_table = NULL; static struct file_lock *file_lock_free_list = NULL; +static int free_list_cnt = 0; int fcntl_getlk(unsigned int fd, struct flock *l) { @@ -60,7 +71,7 @@ int fcntl_getlk(unsigned int fd, struct flock *l) memcpy_fromfs(&flock, l, sizeof(flock)); if (flock.l_type == F_UNLCK) return -EINVAL; - if (!copy_flock(filp, &file_lock, &flock, fd)) + if (!copy_flock(filp, &file_lock, &flock)) return -EINVAL; for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) { @@ -102,7 +113,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) if (error) return error; memcpy_fromfs(&flock, l, sizeof(flock)); - if (!copy_flock(filp, &file_lock, &flock, fd)) + if (!copy_flock(filp, &file_lock, &flock)) return -EINVAL; switch (file_lock.fl_type) { case F_RDLCK : @@ -159,7 +170,7 @@ repeat: * Lock doesn't conflict with any other lock ... */ - return lock_it(filp, &file_lock, fd); + return lock_it(filp, &file_lock); } #ifdef DEADLOCK_DETECTION @@ -196,8 +207,7 @@ int locks_deadlocked(int my_pid,int blocked_pid) * This function is called when the file is closed. */ -void fcntl_remove_locks(struct task_struct *task, struct file *filp, - unsigned int fd) +void fcntl_remove_locks(struct task_struct *task, struct file *filp) { struct file_lock *fl; struct file_lock **before; @@ -205,12 +215,12 @@ void fcntl_remove_locks(struct task_struct *task, struct file *filp, /* Find first lock owned by caller ... */ before = &filp->f_inode->i_flock; - while ((fl = *before) && (task != fl->fl_owner || fd != fl->fl_fd)) + while ((fl = *before) && task != fl->fl_owner) before = &fl->fl_next; /* The list is sorted by owner and fd ... */ - while ((fl = *before) && task == fl->fl_owner && fd == fl->fl_fd) + while ((fl = *before) && task == fl->fl_owner) free_lock(before); } @@ -219,8 +229,7 @@ void fcntl_remove_locks(struct task_struct *task, struct file *filp, * Result is a boolean indicating success. */ -static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l, - unsigned int fd) +static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l) { off_t start; @@ -243,7 +252,6 @@ static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l, if (l->l_len == 0 || (fl->fl_end = start + l->l_len - 1) < 0) fl->fl_end = OFFSET_MAX; fl->fl_owner = current; - fl->fl_fd = fd; fl->fl_wait = NULL; /* just for cleanliness */ return 1; } @@ -254,8 +262,7 @@ static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l, static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) { - if ( caller_fl->fl_owner == sys_fl->fl_owner - && caller_fl->fl_fd == sys_fl->fl_fd) + if (caller_fl->fl_owner == sys_fl->fl_owner) return 0; if (!overlap(caller_fl, sys_fl)) return 0; @@ -293,7 +300,7 @@ static int overlap(struct file_lock *fl1, struct file_lock *fl2) * To all purists: Yes, I use a few goto's. Just pass on to the next function. */ -static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd) +static int lock_it(struct file *filp, struct file_lock *caller) { struct file_lock *fl; struct file_lock *left = 0; @@ -306,18 +313,14 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd) */ before = &filp->f_inode->i_flock; - while ((fl = *before) && - (caller->fl_owner != fl->fl_owner || - caller->fl_fd != fl->fl_fd)) + while ((fl = *before) && caller->fl_owner != fl->fl_owner) before = &fl->fl_next; /* * Look up all locks of this owner. */ - while ( (fl = *before) - && caller->fl_owner == fl->fl_owner - && caller->fl_fd == fl->fl_fd) { + while ((fl = *before) && caller->fl_owner == fl->fl_owner) { /* * Detect adjacent or overlapping regions (if same lock type) */ @@ -417,7 +420,7 @@ next_lock: return 0; #endif } - if (! (caller = alloc_lock(before, caller, fd))) + if (! (caller = alloc_lock(before, caller))) return -ENOLCK; } if (right) { @@ -427,7 +430,7 @@ next_lock: * have to allocate one more lock (in this case, even * F_UNLCK may fail!). */ - if (! (left = alloc_lock(before, right, fd))) { + if (! (left = alloc_lock(before, right))) { if (! added) free_lock(before); return -ENOLCK; @@ -446,10 +449,8 @@ next_lock: * Modified to create a new node if no free entries available - Chad Page * */ - static struct file_lock *alloc_lock(struct file_lock **pos, - struct file_lock *fl, - unsigned int fd) + struct file_lock *fl) { struct file_lock *tmp; @@ -468,6 +469,7 @@ static struct file_lock *alloc_lock(struct file_lock **pos, { /* remove from free list */ file_lock_free_list = tmp->fl_next; + free_list_cnt--; } if (tmp->fl_owner != NULL) @@ -477,7 +479,6 @@ static struct file_lock *alloc_lock(struct file_lock **pos, *pos = tmp; tmp->fl_owner = current; /* FIXME: needed? */ - tmp->fl_fd = fd; /* FIXME: needed? */ tmp->fl_wait = NULL; tmp->fl_type = fl->fl_type; @@ -506,5 +507,15 @@ static void free_lock(struct file_lock **fl_p) file_lock_free_list = fl; fl->fl_owner = NULL; /* for sanity checks */ + free_list_cnt++; + if (free_list_cnt == FREE_LIST_GARBAGE_COLLECT) + free_list_garbage_collect(); + wake_up(&fl->fl_wait); } + +static void free_list_garbage_collect(void) +{ + /* Do nothing for now */ + return; +} diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 35dd432ed694..89d44484117f 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -29,7 +29,7 @@ #include #include -extern int close_fp(struct file *filp, unsigned int fd); +extern int close_fp(struct file *filp); static int nfs_notify_change(struct inode *, struct iattr *); static void nfs_put_inode(struct inode *); @@ -54,8 +54,7 @@ static void nfs_put_inode(struct inode * inode) void nfs_put_super(struct super_block *sb) { - /* No locks should be open on this, so 0 should be safe as a fd. */ - close_fp(sb->u.nfs_sb.s_server.file, 0); + close_fp(sb->u.nfs_sb.s_server.file); lock_super(sb); sb->s_dev = 0; unlock_super(sb); diff --git a/fs/open.c b/fs/open.c index 33b67ead34da..5962a6b5090e 100644 --- a/fs/open.c +++ b/fs/open.c @@ -20,7 +20,7 @@ #include -extern void fcntl_remove_locks(struct task_struct *, struct file *, unsigned int fd); +extern void fcntl_remove_locks(struct task_struct *, struct file *); asmlinkage int sys_ustat(int dev, struct ustat * ubuf) { @@ -477,7 +477,7 @@ asmlinkage int sys_creat(const char * pathname, int mode) return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); } -int close_fp(struct file *filp, unsigned int fd) +int close_fp(struct file *filp) { struct inode *inode; @@ -487,7 +487,7 @@ int close_fp(struct file *filp, unsigned int fd) } inode = filp->f_inode; if (inode) - fcntl_remove_locks(current, filp, fd); + fcntl_remove_locks(current, filp); if (filp->f_count > 1) { filp->f_count--; return 0; @@ -511,7 +511,7 @@ asmlinkage int sys_close(unsigned int fd) if (!(filp = current->files->fd[fd])) return -EBADF; current->files->fd[fd] = NULL; - return (close_fp (filp, fd)); + return (close_fp (filp)); } /* diff --git a/fs/proc/array.c b/fs/proc/array.c index 0ed217574289..124641b96643 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -1,3 +1,4 @@ +#define THREE_LEVEL /* * linux/fs/proc/array.c * @@ -334,22 +335,31 @@ static struct task_struct ** get_task(pid_t pid) return NULL; } -static unsigned long get_phys_addr(struct task_struct ** p, unsigned long ptr) +static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr) { - pgd_t *dir; - pte_t *table, pte; + pgd_t *page_dir; + pmd_t *page_middle; + pte_t pte; - if (!p || !*p || ptr >= TASK_SIZE) + if (!p || ptr >= TASK_SIZE) return 0; - dir = PAGE_DIR_OFFSET(*p,ptr); - if (pgd_none(*dir)) + page_dir = pgd_offset(p,ptr); + if (pgd_none(*page_dir)) return 0; - if (pgd_bad(*dir)) { - printk("bad page directory entry %08lx\n", pgd_val(*dir)); + if (pgd_bad(*page_dir)) { + printk("bad page directory entry %08lx\n", pgd_val(*page_dir)); + pgd_clear(page_dir); return 0; } - table = (pte_t *) (pgd_page(*dir) + PAGE_PTR(ptr)); - pte = *table; + page_middle = pmd_offset(page_dir,ptr); + if (pmd_none(*page_middle)) + return 0; + if (pmd_bad(*page_middle)) { + printk("bad page middle entry %08lx\n", pmd_val(*page_middle)); + pmd_clear(page_middle); + return 0; + } + pte = *pte_offset(page_middle,ptr); if (!pte_present(pte)) return 0; return pte_page(pte) + (ptr & ~PAGE_MASK); @@ -364,7 +374,7 @@ static int get_array(struct task_struct ** p, unsigned long start, unsigned long if (start >= end) return result; for (;;) { - addr = get_phys_addr(p, start); + addr = get_phys_addr(*p, start); if (!addr) goto ready; do { @@ -511,55 +521,109 @@ static int get_stat(int pid, char * buffer) sigcatch, wchan); } + +static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size, + int * pages, int * shared, int * dirty, int * total) +{ + pte_t * pte; + unsigned long end; + + if (pmd_none(*pmd)) + return; + if (pmd_bad(*pmd)) { + printk("statm_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd)); + pmd_clear(pmd); + return; + } + pte = pte_offset(pmd, address); + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_t page = *pte; + + address += PAGE_SIZE; + pte++; + if (pte_none(page)) + continue; + ++*total; + if (!pte_present(page)) + continue; + ++*pages; + if (pte_dirty(page)) + ++*dirty; + if (pte_page(page) >= high_memory) + continue; + if (mem_map[MAP_NR(pte_page(page))] > 1) + ++*shared; + } while (address < end); +} + +static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size, + int * pages, int * shared, int * dirty, int * total) +{ + pmd_t * pmd; + unsigned long end; + + if (pgd_none(*pgd)) + return; + if (pgd_bad(*pgd)) { + printk("statm_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd)); + pgd_clear(pgd); + return; + } + pmd = pmd_offset(pgd, address); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + statm_pte_range(pmd, address, end - address, pages, shared, dirty, total); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); +} + +static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end, + int * pages, int * shared, int * dirty, int * total) +{ + while (address < end) { + statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + pgd++; + } +} static int get_statm(int pid, char * buffer) { struct task_struct ** p = get_task(pid); - pgd_t *pagedir; - pte_t *pte; - int i, j, tpag; int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; if (!p || !*p) return 0; - tpag = (*p)->mm->end_code / PAGE_SIZE; if ((*p)->state != TASK_ZOMBIE) { - pagedir = PAGE_DIR_OFFSET(*p, 0); - for (i = 0; i < 0x300; ++i) { - if (pgd_none(pagedir[i])) { - tpag -= PTRS_PER_PAGE; - continue; - } - if (pgd_bad(pagedir[i])) { - printk("bad page table dir %08lx\n", pgd_val(pagedir[i])); - pgd_clear(pagedir+i); - tpag -= PTRS_PER_PAGE; - continue; - } - pte = (pte_t *) pgd_page(pagedir[i]); - for (j = 0; j < PTRS_PER_PAGE; j++, pte++) { - if (!pte_none(*pte)) { - ++size; - if (pte_present(*pte)) { - ++resident; - if (tpag > 0) - ++trs; - else - ++drs; - if (i >= 15 && i < 0x2f0) { - ++lrs; - if (pte_dirty(*pte)) - ++dt; - else - --drs; - } - if (pte_page(*pte) < high_memory && mem_map[MAP_NR(pte_page(*pte))] > 1) - ++share; + struct vm_area_struct * vma = (*p)->mm->mmap; + + while (vma) { + pgd_t *pgd = pgd_offset(*p, vma->vm_start); + int pages = 0, shared = 0, dirty = 0, total = 0; + + statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total); + resident += pages; + share += shared; + dt += dirty; + size += total; + if (vma->vm_flags & VM_EXECUTABLE) + trs += pages; /* text */ + else if (vma->vm_flags & VM_GROWSDOWN) + drs += pages; /* stack */ + else if (vma->vm_end > 0x60000000) + lrs += pages; /* library */ + else + drs += pages; + vma = vma->vm_next; } - } - --tpag; - } - } } return sprintf(buffer,"%d %d %d %d %d %d %d\n", size, resident, share, trs, lrs, drs, dt); diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h index 902e0679661d..7fe10ab55c5e 100644 --- a/include/asm-alpha/system.h +++ b/include/asm-alpha/system.h @@ -81,7 +81,6 @@ extern unsigned long rdusp(void); #define halt() __asm__ __volatile__(".long 0"); -#define move_to_user_mode() printk("Null move_to_user_mode\n") #define switch_to(x) panic("switch_to() not yet done") #ifndef mb diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index 6c758e44c178..2843e36866ef 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h @@ -132,12 +132,18 @@ extern inline int pte_none(pte_t pte) { return !pte_val(pte); } extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; } extern inline int pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)] > 1; } extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; } +extern inline void pte_reuse(pte_t * ptep) +{ + if (!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED)) + mem_map[MAP_NR(ptep)]++; +} extern inline int pmd_none(pmd_t pmd) { return !pmd_val(pmd); } extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE || pmd_val(pmd) > high_memory; } extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _PAGE_PRESENT; } extern inline int pmd_inuse(pmd_t *pmdp) { return 0; } extern inline void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = 0; } +extern inline void pmd_reuse(pmd_t * pmdp) { } #ifdef THREE_LEVEL /* @@ -150,6 +156,11 @@ extern inline int pgd_bad(pgd_t pgd) { return 0; } extern inline int pgd_present(pgd_t pgd) { return 1; } extern inline int pgd_inuse(pgd_t * pgdp) { return mem_map[MAP_NR(pgdp)] > 1; } extern inline void pgd_clear(pgd_t * pgdp) { } +extern inline void pgd_reuse(pgd_t * pgdp) +{ + if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED)) + mem_map[MAP_NR(pgdp)]++; +} #else /* * These are the old (and incorrect) ones needed for code that doesn't diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h index df01e6cc81d3..1b766070ecdc 100644 --- a/include/asm-i386/system.h +++ b/include/asm-i386/system.h @@ -3,21 +3,6 @@ #include -#define move_to_user_mode() \ -__asm__ __volatile__ ("movl %%esp,%%eax\n\t" \ - "pushl %0\n\t" \ - "pushl %%eax\n\t" \ - "pushfl\n\t" \ - "pushl %1\n\t" \ - "pushl $1f\n\t" \ - "iret\n" \ - "1:\tmovl %0,%%eax\n\t" \ - "mov %%ax,%%ds\n\t" \ - "mov %%ax,%%es\n\t" \ - "mov %%ax,%%fs\n\t" \ - "mov %%ax,%%gs" \ - : /* no outputs */ :"i" (USER_DS), "i" (USER_CS):"ax") - /* * Entry into gdt where to find first TSS. GDT layout: * 0 - nul diff --git a/include/linux/fs.h b/include/linux/fs.h index da4830d90c82..24beefff38be 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -269,7 +269,6 @@ struct file_lock { struct file_lock *fl_next; /* singly linked list */ struct file_lock *fl_nextlink; struct task_struct *fl_owner; /* NULL if on free list, for sanity checks */ - unsigned int fl_fd; /* File descriptor for this lock */ struct wait_queue *fl_wait; char fl_type; char fl_whence; diff --git a/include/linux/major.h b/include/linux/major.h index 56d6539c4d16..cb8c4ed03d04 100644 --- a/include/linux/major.h +++ b/include/linux/major.h @@ -24,7 +24,7 @@ * 4 - /dev/tty* * 5 - /dev/tty; /dev/cua* * 6 - lp - * 7 - UNUSED + * 7 - /dev/vcs* * 8 - scsi disk * 9 - scsi tape * 10 - mice @@ -57,7 +57,7 @@ #define TTY_MAJOR 4 #define TTYAUX_MAJOR 5 #define LP_MAJOR 6 -/* unused: 7 */ +#define VCS_MAJOR 7 #define SCSI_DISK_MAJOR 8 #define SCSI_TAPE_MAJOR 9 #define MOUSE_MAJOR 10 diff --git a/include/linux/mm.h b/include/linux/mm.h index 43ac7c16d2fe..11da5fba71b9 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -185,7 +185,7 @@ extern void do_no_page(struct vm_area_struct * vma, unsigned long address, int w extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem); extern void mem_init(unsigned long start_mem, unsigned long end_mem); extern void show_mem(void); -extern void oom(struct task_struct * task); +extern void oom(struct task_struct * tsk); extern void si_meminfo(struct sysinfo * val); /* vmalloc.c */ diff --git a/include/linux/tty.h b/include/linux/tty.h index 5dec59683832..49f2b20ecc53 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -278,6 +278,10 @@ extern long lp_init(long); extern long con_init(long); extern long pty_init(long); extern long tty_init(long); +extern long vcs_init(long); +#ifdef CONFIG_CYCLADES +extern long cy_init(long); +#endif extern int tty_paranoia_check(struct tty_struct *tty, dev_t device, const char *routine); diff --git a/init/main.c b/init/main.c index 8cf70504bdae..abbb512656b7 100644 --- a/init/main.c +++ b/init/main.c @@ -420,7 +420,6 @@ asmlinkage void start_kernel(void) printk(linux_banner); - move_to_user_mode(); if (!fork()) /* we count on this going ok */ init(); /* diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 46ebd2b09afb..345c037536c7 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -67,7 +67,7 @@ extern int sys_tz; extern int request_dma(unsigned int dmanr, char * deviceID); extern void free_dma(unsigned int dmanr); -extern int close_fp(struct file *filp, unsigned int fd); +extern int close_fp(struct file *filp); extern void (* iABI_hook)(struct pt_regs * regs); struct symbol_table symbol_table = { diff --git a/mm/filemap.c b/mm/filemap.c index c86b7db404b4..24a3372109ac 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1,3 +1,4 @@ +#define THREE_LEVEL /* * linux/mm/filemmap.c * @@ -28,7 +29,7 @@ * though. */ -static unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned long address, +static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long address, unsigned long page, int no_share) { struct inode * inode = area->vm_inode; @@ -61,12 +62,13 @@ static unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned lon * - the "swapout()" function needs to swap out the page to * the shared file instead of using the swap device. */ -static inline void file_mmap_sync_page(struct vm_area_struct * vma, +static void filemap_sync_page(struct vm_area_struct * vma, unsigned long offset, unsigned long page) { struct buffer_head * bh; + printk("msync: %ld: [%08lx]\n", offset, page); bh = buffer_pages[MAP_NR(page)]; if (bh) { /* whee.. just mark the buffer heads dirty */ @@ -78,60 +80,94 @@ static inline void file_mmap_sync_page(struct vm_area_struct * vma, return; } /* we'll need to go fetch the buffer heads etc.. RSN */ - printk("msync: %ld: [%08lx]\n", offset, page); printk("Can't handle non-shared page yet\n"); return; } -static void file_mmap_sync(struct vm_area_struct * vma, unsigned long start, +static inline void filemap_sync_pte(pte_t * pte, struct vm_area_struct *vma, + unsigned long address, unsigned int flags) +{ + pte_t page = *pte; + + if (!pte_present(page)) + return; + if (!pte_dirty(page)) + return; + if (flags & MS_INVALIDATE) { + pte_clear(pte); + } else { + mem_map[MAP_NR(pte_page(page))]++; + *pte = pte_mkclean(page); + } + filemap_sync_page(vma, address - vma->vm_start, pte_page(page)); + free_page(pte_page(page)); +} + +static inline void filemap_sync_pte_range(pmd_t * pmd, + unsigned long address, unsigned long size, + struct vm_area_struct *vma, unsigned long offset, unsigned int flags) +{ + pte_t * pte; + unsigned long end; + + if (pmd_none(*pmd)) + return; + if (pmd_bad(*pmd)) { + printk("filemap_sync_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd)); + pmd_clear(pmd); + return; + } + pte = pte_offset(pmd, address); + offset += address & PMD_MASK; + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + filemap_sync_pte(pte, vma, address + offset, flags); + address += PAGE_SIZE; + pte++; + } while (address < end); +} + +static inline void filemap_sync_pmd_range(pgd_t * pgd, + unsigned long address, unsigned long size, + struct vm_area_struct *vma, unsigned int flags) +{ + pmd_t * pmd; + unsigned long offset, end; + + if (pgd_none(*pgd)) + return; + if (pgd_bad(*pgd)) { + printk("filemap_sync_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd)); + pgd_clear(pgd); + return; + } + pmd = pmd_offset(pgd, address); + offset = address & PMD_MASK; + address &= ~PMD_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + filemap_sync_pte_range(pmd, address, end - address, vma, offset, flags); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); +} + +static void filemap_sync(struct vm_area_struct * vma, unsigned long address, size_t size, unsigned int flags) { pgd_t * dir; - unsigned long poff, pcnt; - - size = size >> PAGE_SHIFT; - dir = PAGE_DIR_OFFSET(current,start); - poff = (start >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); - start -= vma->vm_start; - pcnt = PTRS_PER_PAGE - poff; - if (pcnt > size) - pcnt = size; - - for ( ; size > 0; ++dir, size -= pcnt, pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size)) { - pte_t *page_table; - unsigned long pc; - - if (pgd_none(*dir)) { - poff = 0; - start += pcnt*PAGE_SIZE; - continue; - } - if (pgd_bad(*dir)) { - printk("file_mmap_sync: bad page directory entry %08lx.\n", pgd_val(*dir)); - pgd_clear(dir); - poff = 0; - start += pcnt*PAGE_SIZE; - continue; - } - page_table = poff + (pte_t *) pgd_page(*dir); - poff = 0; - for (pc = pcnt; pc--; page_table++, start += PAGE_SIZE) { - pte_t pte; - - pte = *page_table; - if (!pte_present(pte)) - continue; - if (!pte_dirty(pte)) - continue; - if (flags & MS_INVALIDATE) { - pte_clear(page_table); - } else { - mem_map[MAP_NR(pte_page(pte))]++; - *page_table = pte_mkclean(pte); - } - file_mmap_sync_page(vma, start, pte_page(pte)); - free_page(pte_page(pte)); - } + unsigned long end = address + size; + + dir = pgd_offset(current, address); + while (address < end) { + filemap_sync_pmd_range(dir, address, end - address, vma, flags); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; } invalidate(); return; @@ -140,17 +176,17 @@ static void file_mmap_sync(struct vm_area_struct * vma, unsigned long start, /* * This handles area unmaps.. */ -static void file_mmap_unmap(struct vm_area_struct *vma, unsigned long start, size_t len) +static void filemap_unmap(struct vm_area_struct *vma, unsigned long start, size_t len) { - file_mmap_sync(vma, start, len, MS_ASYNC); + filemap_sync(vma, start, len, MS_ASYNC); } /* * This handles complete area closes.. */ -static void file_mmap_close(struct vm_area_struct * vma) +static void filemap_close(struct vm_area_struct * vma) { - file_mmap_sync(vma, vma->vm_start, vma->vm_end - vma->vm_start, MS_ASYNC); + filemap_sync(vma, vma->vm_start, vma->vm_end - vma->vm_start, MS_ASYNC); } /* @@ -160,7 +196,7 @@ static void file_mmap_close(struct vm_area_struct * vma) * so we have to either write it out or just forget it. We currently * forget it.. */ -void file_mmap_swapout(struct vm_area_struct * vma, +void filemap_swapout(struct vm_area_struct * vma, unsigned long offset, pte_t *page_table) { @@ -175,14 +211,14 @@ void file_mmap_swapout(struct vm_area_struct * vma, */ static struct vm_operations_struct file_shared_mmap = { NULL, /* open */ - file_mmap_close, /* close */ - file_mmap_unmap, /* unmap */ + filemap_close, /* close */ + filemap_unmap, /* unmap */ NULL, /* protect */ - file_mmap_sync, /* sync */ + filemap_sync, /* sync */ NULL, /* advise */ - file_mmap_nopage, /* nopage */ + filemap_nopage, /* nopage */ NULL, /* wppage */ - file_mmap_swapout, /* swapout */ + filemap_swapout, /* swapout */ NULL, /* swapin */ }; @@ -199,7 +235,7 @@ static struct vm_operations_struct file_private_mmap = { NULL, /* protect */ NULL, /* sync */ NULL, /* advise */ - file_mmap_nopage, /* nopage */ + filemap_nopage, /* nopage */ NULL, /* wppage */ NULL, /* swapout */ NULL, /* swapin */ @@ -221,9 +257,11 @@ int generic_mmap(struct inode * inode, struct file * file, struct vm_area_struct if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) { static int nr = 0; ops = &file_shared_mmap; +#ifndef SHARED_MMAP_REALLY_WORKS /* it doesn't, yet */ if (nr++ < 5) printk("%s tried to do a shared writeable mapping\n", current->comm); return -EINVAL; +#endif } } if (!IS_RDONLY(inode)) { diff --git a/mm/memory.c b/mm/memory.c index d229b5bcb1cb..dfbc863c2dcb 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -222,7 +222,7 @@ int clone_page_tables(struct task_struct * tsk) pgd_t * pg_dir; pg_dir = pgd_offset(current, 0); - mem_map[MAP_NR(pg_dir)]++; + pgd_reuse(pg_dir); SET_PAGE_DIR(tsk, pg_dir); return 0; } @@ -265,6 +265,7 @@ static inline int copy_one_pmd(pmd_t * old_pmd, pmd_t * new_pmd) } old_pte = pte_offset(old_pmd, 0); if (pte_inuse(old_pte)) { + pte_reuse(old_pte); *new_pmd = *old_pmd; return 0; } @@ -293,6 +294,7 @@ static inline int copy_one_pgd(pgd_t * old_pgd, pgd_t * new_pgd) } old_pmd = pmd_offset(old_pgd, 0); if (pmd_inuse(old_pmd)) { + pmd_reuse(old_pmd); *new_pgd = *old_pgd; return 0; } diff --git a/mm/mprotect.c b/mm/mprotect.c index 8d53c0f32f56..c16f86880e93 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -1,3 +1,4 @@ +#define THREE_LEVEL /* * linux/mm/mprotect.c * @@ -17,44 +18,69 @@ #include #include +static inline void change_pte_range(pmd_t * pmd, unsigned long address, + unsigned long size, pgprot_t newprot) +{ + pte_t * pte; + unsigned long end; + + if (pmd_none(*pmd)) + return; + if (pmd_bad(*pmd)) { + printk("change_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd)); + pmd_clear(pmd); + return; + } + pte = pte_offset(pmd, address); + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_t entry = *pte; + if (pte_present(entry)) + *pte = pte_modify(entry, newprot); + address += PAGE_SIZE; + pte++; + } while (address < end); +} + +static inline void change_pmd_range(pgd_t * pgd, unsigned long address, + unsigned long size, pgprot_t newprot) +{ + pmd_t * pmd; + unsigned long end; + + if (pgd_none(*pgd)) + return; + if (pgd_bad(*pgd)) { + printk("change_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd)); + pgd_clear(pgd); + return; + } + pmd = pmd_offset(pgd, address); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + change_pte_range(pmd, address, end - address, newprot); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); +} + static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot) { pgd_t *dir; - pte_t *page_table, entry; - unsigned long offset; - int nr; - - dir = PAGE_DIR_OFFSET(current, start); - offset = (start >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); - nr = (end - start) >> PAGE_SHIFT; - while (nr > 0) { - if (pgd_none(*dir)) { - dir++; - nr = nr - PTRS_PER_PAGE + offset; - offset = 0; - continue; - } - if (pgd_bad(*dir)) { - printk("Bad page dir entry %08lx\n", pgd_val(*dir)); - pgd_clear(dir); - dir++; - nr = nr - PTRS_PER_PAGE + offset; - offset = 0; - continue; - } - page_table = offset + (pte_t *) pgd_page(*dir); - offset = PTRS_PER_PAGE - offset; - if (offset > nr) - offset = nr; - nr = nr - offset; - do { - entry = *page_table; - if (pte_present(entry)) - *page_table = pte_modify(entry, newprot); - ++page_table; - } while (--offset); + + dir = pgd_offset(current, start); + while (start < end) { + change_pmd_range(dir, start, end - start, newprot); + start = (start + PGDIR_SIZE) & PGDIR_MASK; dir++; } + invalidate(); return; } diff --git a/mm/swap.c b/mm/swap.c index f557aa914b6a..1464d26e4d47 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -1,3 +1,4 @@ +#define THREE_LEVEL /* * linux/mm/swap.c * @@ -387,11 +388,89 @@ static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned offset, p */ #define SWAP_RATIO 128 +static inline int swap_out_pmd(struct vm_area_struct * vma, pmd_t *dir, + unsigned long address, unsigned long size, unsigned long offset) +{ + pte_t * pte; + unsigned long end; + + if (pmd_none(*dir)) + return 0; + if (pmd_bad(*dir)) { + printk("swap_out_pmd: bad pmd (%08lx)\n", pmd_val(*dir)); + pmd_clear(dir); + return 0; + } + pte = pte_offset(dir, address); + offset += address & PMD_MASK; + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + switch (try_to_swap_out(vma, offset+address-vma->vm_start, pte)) { + case 0: + break; + + case 1: + vma->vm_task->mm->rss--; + /* continue with the following page the next time */ + vma->vm_task->mm->swap_address = address + offset + PAGE_SIZE; + return 1; + + default: + vma->vm_task->mm->rss--; + break; + } + address += PAGE_SIZE; + pte++; + } while (address < end); + return 0; +} + +static inline int swap_out_pgd(struct vm_area_struct * vma, pgd_t *dir, + unsigned long address, unsigned long size) +{ + pmd_t * pmd; + unsigned long offset, end; + + if (pgd_none(*dir)) + return 0; + if (pgd_bad(*dir)) { + printk("swap_out_pgd: bad pgd (%08lx)\n", pgd_val(*dir)); + pgd_clear(dir); + return 0; + } + pmd = pmd_offset(dir, address); + offset = address & PGDIR_MASK; + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + if (swap_out_pmd(vma, pmd, address, end - address, offset)) + return 1; + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + return 0; +} + +static int swap_out_vma(struct vm_area_struct * vma, pgd_t *pgdir, + unsigned long start, unsigned long end) +{ + while (start < end) { + if (swap_out_pgd(vma, pgdir, start, end - start)) + return 1; + start = (start + PGDIR_SIZE) & PGDIR_MASK; + pgdir++; + } + return 0; +} + static int swap_out_process(struct task_struct * p) { - pgd_t *pgdir; unsigned long address; - unsigned long offset; struct vm_area_struct* vma; /* @@ -409,60 +488,14 @@ static int swap_out_process(struct task_struct * p) if (address < vma->vm_start) address = vma->vm_start; - pgdir = PAGE_DIR_OFFSET(p, address); - offset = address & ~PGDIR_MASK; - address &= PGDIR_MASK; - for ( ; address < TASK_SIZE ; pgdir++, address = address + PGDIR_SIZE, offset = 0) { - pte_t *pg_table; - - if (pgd_none(*pgdir)) - continue; - if (pgd_bad(*pgdir)) { - printk("Bad page directory at address %08lx: %08lx\n", address, pgd_val(*pgdir)); - pgd_clear(pgdir); - continue; - } - pg_table = (pte_t *) pgd_page(*pgdir); - if (mem_map[MAP_NR((unsigned long) pg_table)] & MAP_PAGE_RESERVED) - continue; - pg_table += offset >> PAGE_SHIFT; - - /* - * Go through this page table. - */ - for( ; offset < ~PGDIR_MASK ; pg_table++, offset += PAGE_SIZE) { - /* - * Update vma again.. - */ - for (;;) { - if (address+offset < vma->vm_end) - break; - vma = vma->vm_next; - if (!vma) - return 0; - } - - switch(try_to_swap_out(vma, offset+address-vma->vm_start, pg_table)) { - case 0: - break; - - case 1: - p->mm->rss--; - /* continue with the following page the next time */ - p->mm->swap_address = address + offset + PAGE_SIZE; - return 1; - - default: - p->mm->rss--; - break; - } - } + for (;;) { + if (swap_out_vma(vma, pgd_offset(p, address), address, vma->vm_end)) + return 1; + vma = vma->vm_next; + if (!vma) + return 0; + address = vma->vm_start; } - /* - * Finish work with this process, if we reached the end of the page - * directory. - */ - return 0; } static int swap_out(unsigned int priority) @@ -748,77 +781,157 @@ void show_free_areas(void) /* * Trying to stop swapping from a file is fraught with races, so * we repeat quite a bit here when we have to pause. swapoff() - * isn't exactly timing-critical, so who cares? + * isn't exactly timing-critical, so who cares (but this is /really/ + * inefficient, ugh). + * + * We return 1 after having slept, which makes the process start over + * from the beginning for this process.. */ -static int try_to_unuse(unsigned int type) +static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address, + pte_t *dir, unsigned int type, unsigned long page) { - int nr; - unsigned long tmp = 0; - struct task_struct *p; + pte_t pte = *dir; + + if (pte_none(pte)) + return 0; + if (pte_present(pte)) { + unsigned long page = pte_page(pte); + if (page >= high_memory) + return 0; + if (!in_swap_cache(page)) + return 0; + if (SWP_TYPE(in_swap_cache(page)) != type) + return 0; + delete_from_swap_cache(page); + *dir = pte_mkdirty(pte); + return 0; + } + if (SWP_TYPE(pte_val(pte)) != type) + return 0; + read_swap_page(pte_val(pte), (char *) page); + if (pte_val(*dir) != pte_val(pte)) { + free_page(page); + return 1; + } + *dir = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + ++vma->vm_task->mm->rss; + swap_free(pte_val(pte)); + return 1; +} + +static inline int unuse_pmd(struct vm_area_struct * vma, pmd_t *dir, + unsigned long address, unsigned long size, unsigned long offset, + unsigned int type, unsigned long page) +{ + pte_t * pte; + unsigned long end; + + if (pmd_none(*dir)) + return 0; + if (pmd_bad(*dir)) { + printk("unuse_pmd: bad pmd (%08lx)\n", pmd_val(*dir)); + pmd_clear(dir); + return 0; + } + pte = pte_offset(dir, address); + offset += address & PMD_MASK; + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + if (unuse_pte(vma, offset+address-vma->vm_start, pte, type, page)) + return 1; + address += PAGE_SIZE; + pte++; + } while (address < end); + return 0; +} + +static inline int unuse_pgd(struct vm_area_struct * vma, pgd_t *dir, + unsigned long address, unsigned long size, + unsigned int type, unsigned long page) +{ + pmd_t * pmd; + unsigned long offset, end; + + if (pgd_none(*dir)) + return 0; + if (pgd_bad(*dir)) { + printk("unuse_pgd: bad pgd (%08lx)\n", pgd_val(*dir)); + pgd_clear(dir); + return 0; + } + pmd = pmd_offset(dir, address); + offset = address & PGDIR_MASK; + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + if (unuse_pmd(vma, pmd, address, end - address, offset, type, page)) + return 1; + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + return 0; +} + +static int unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir, + unsigned long start, unsigned long end, + unsigned int type, unsigned long page) +{ + while (start < end) { + if (unuse_pgd(vma, pgdir, start, end - start, type, page)) + return 1; + start = (start + PGDIR_SIZE) & PGDIR_MASK; + pgdir++; + } + return 0; +} + +static int unuse_process(struct task_struct * p, unsigned int type, unsigned long page) +{ + struct vm_area_struct* vma; + + /* + * Go through process' page directory. + */ + vma = p->mm->mmap; + while (vma) { + pgd_t * pgd = pgd_offset(p, vma->vm_start); + if (unuse_vma(vma, pgd, vma->vm_start, vma->vm_end, type, page)) + return 1; + vma = vma->vm_next; + } + return 0; +} - nr = 0; /* - * When we have to sleep, we restart the whole algorithm from the same - * task we stopped in. That at least rids us of all races. + * To avoid races, we repeat for each process after having + * swapped something in. That gets rid of a few pesky races, + * and "swapoff" isn't exactly timing critical. */ -repeat: - for (; nr < NR_TASKS ; nr++) { - pgd_t * page_dir; - int i; - - p = task[nr]; - if (!p) - continue; - page_dir = PAGE_DIR_OFFSET(p, 0); - for (i = 0 ; i < PTRS_PER_PAGE ; page_dir++, i++) { - int j; - pte_t *page_table; +static int try_to_unuse(unsigned int type) +{ + int nr; + unsigned long page = get_free_page(GFP_KERNEL); - if (pgd_none(*page_dir)) - continue; - if (pgd_bad(*page_dir)) { - printk("bad page directory entry [%d] %08lx\n", i, pgd_val(*page_dir)); - pgd_clear(page_dir); + if (!page) + return -ENOMEM; + nr = 0; + while (nr < NR_TASKS) { + if (task[nr]) { + if (unuse_process(task[nr], type, page)) { + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; continue; } - page_table = (pte_t *) pgd_page(*page_dir); - if (mem_map[MAP_NR((unsigned long) page_table)] & MAP_PAGE_RESERVED) - continue; - for (j = 0 ; j < PTRS_PER_PAGE ; page_table++, j++) { - pte_t pte; - pte = *page_table; - if (pte_none(pte)) - continue; - if (pte_present(pte)) { - unsigned long page = pte_page(pte); - if (page >= high_memory) - continue; - if (!in_swap_cache(page)) - continue; - if (SWP_TYPE(in_swap_cache(page)) != type) - continue; - delete_from_swap_cache(page); - *page_table = pte_mkdirty(pte); - continue; - } - if (SWP_TYPE(pte_val(pte)) != type) - continue; - if (!tmp) { - if (!(tmp = __get_free_page(GFP_KERNEL))) - return -ENOMEM; - goto repeat; - } - read_swap_page(pte_val(pte), (char *) tmp); - if (pte_val(*page_table) != pte_val(pte)) - goto repeat; - *page_table = pte_mkwrite(pte_mkdirty(mk_pte(tmp, PAGE_COPY))); - ++p->mm->rss; - swap_free(pte_val(pte)); - tmp = 0; - } } + nr++; } - free_page(tmp); + free_page(page); return 0; } diff --git a/net/inet/arp.c b/net/inet/arp.c index ecd9fe970dd2..45d8d42e77cd 100644 --- a/net/inet/arp.c +++ b/net/inet/arp.c @@ -841,7 +841,7 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, /* * Find an entry */ - entry = arp_lookup(paddr, 0); + entry = arp_lookup(paddr, 1); if (entry != NULL) /* It exists */ { diff --git a/net/inet/dev.c b/net/inet/dev.c index b95112f7870e..c4ed6e198e33 100644 --- a/net/inet/dev.c +++ b/net/inet/dev.c @@ -28,6 +28,7 @@ * Alan Cox : 100 backlog just doesn't cut it when * you start doing multicast video 8) * Alan Cox : Rewrote net_bh and list manager. + * Alan Cox : Fix ETH_P_ALL echoback lengths. * * Cleaned up and recommented by Alan Cox 2nd April 1994. I hope to have * the rest as well commented in the end. @@ -398,6 +399,11 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) struct sk_buff *skb2; if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) break; + /* + * The protocol knows this has (for other paths) been taken off + * and adds it back. + */ + skb2->len-=skb->dev->hard_header_len; ptype->func(skb2, skb->dev, ptype); nitcount--; } diff --git a/net/inet/ip.c b/net/inet/ip.c index 20496b28e6f1..5d2345691b0f 100644 --- a/net/inet/ip.c +++ b/net/inet/ip.c @@ -2052,19 +2052,6 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt if(level!=SOL_IP) return -EOPNOTSUPP; -#ifdef CONFIG_IP_MULTICAST - if(optname==IP_MULTICAST_TTL) - { - unsigned char ucval; - ucval=get_fs_byte((unsigned char *)optval); - printk("MC TTL %d\n", ucval); - if(ucval<1||ucval>255) - return -EINVAL; - sk->ip_mc_ttl=(int)ucval; - return 0; - } -#endif - switch(optname) { case IP_TOS: @@ -2082,19 +2069,16 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt sk->ip_ttl=val; return 0; #ifdef CONFIG_IP_MULTICAST -#ifdef GCC_WORKS case IP_MULTICAST_TTL: { unsigned char ucval; ucval=get_fs_byte((unsigned char *)optval); - printk("MC TTL %d\n", ucval); if(ucval<1||ucval>255) return -EINVAL; sk->ip_mc_ttl=(int)ucval; return 0; } -#endif case IP_MULTICAST_LOOP: { unsigned char ucval; -- 2.39.5