Commit 24a1c2a7 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.92

parent 55415e93
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:
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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"
<stimpson@panix.com> 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
......
......@@ -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
......
......@@ -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 <linux/config.h>
#ifdef CONFIG_CDU535
#if defined(CONFIG_CDU535) || defined(MODULE)
#ifdef MODULE
# include <linux/module.h>
# include <linux/malloc.h>
# include <linux/version.h>
#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 */
......@@ -1532,16 +1543,16 @@ cleanup_module(void)
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 */
......
......@@ -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
......
......@@ -25,18 +25,18 @@
* '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 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.
......@@ -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 <linux/ctype.h>
/* 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)
if (tc == -1 || tc == -2)
continue;
vc_state = ESnormal;
if (tc == -1)
tc = 0376; /* small square: symbol not found */
ok = 1;
} else {
tc = NORM_TRANS[c];
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<E_TABSZ ; i++) USER_TRANS[i] = get_fs_byte(arg+i);
USER_TRANS[012]=0;
USER_TRANS[014]=0;
USER_TRANS[015]=0;
USER_TRANS[033]=0;
return 0;
}
int con_get_trans(char * arg)
{
int i;
i = verify_area(VERIFY_WRITE, (void *)arg, E_TABSZ);
if (i)
return i;
for (i=0; i<E_TABSZ ; i++) put_fs_byte(USER_TRANS[i],arg+i);
return 0;
}
/*
* consolemap.c
*
* Mapping from internal code (such as Latin-1 or Unicode or IBM PC code)
* to font positions.
*
* aeb, 950210
*/
#include <linux/kd.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <asm/segment.h>
#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<E_TABSZ; j++)
q[j] = 0;
for (j=0; j<E_TABSZ; j++)
if (q[p[j]] < 32) /* prefer '-' above SHY etc. */
q[p[j]] = j;
}
unsigned char *set_translate(int m)
{
if (!inverse_translations[m])
set_inverse_transl(m);
inv_translate = inverse_translations[m];
return translations[m];
}
/*
* Inverse translation is impossible for several reasons:
* 1. The translation maps are not 1-1
* 2. The text may have been written while a different translation map
* was active
* Still, it is now possible to a certain extent to cut and paste non-ASCII.
*/
unsigned char inverse_translate(unsigned char c) {
return ((inv_translate && inv_translate[c]) ? inv_translate[c] : c);
}
/*
* Load customizable translation table
* arg points to a 256 byte translation table.
*/
int con_set_trans(char * arg)
{
int i;
unsigned char *p = translations[USER_MAP];
i = verify_area(VERIFY_READ, (void *)arg, E_TABSZ);
if (i)
return i;
for (i=0; i<E_TABSZ ; i++)
p[i] = get_fs_byte(arg+i);
p[012] = p[014] = p[015] = p[033] = 0;
set_inverse_transl(USER_MAP);
return 0;
}
int con_get_trans(char * arg)
{
int i;
unsigned char *p = translations[USER_MAP];
i = verify_area(VERIFY_WRITE, (void *)arg, E_TABSZ);
if (i)
return i;
for (i=0; i<E_TABSZ ; i++) put_fs_byte(p[i],arg+i);
return 0;
}
/*
* Unicode -> current font conversion
*
* A font has at most 512 chars, usually 256.
* But one font position may represent several Unicode chars
* (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; i<hashsize; i++)
hashtable[i].unicode = 0xffff;
hashtable_contents_valid = 1;
}
int
con_set_unimap(ushort ct, struct unipair *list){
int i, lct;
ushort u, hu;
struct unimapinit hashdefaults = { 0, 0, 0 };
if (!hashtable_contents_valid)
con_clear_unimap(&hashdefaults);
while(ct) {
u = get_fs_word(&list->unicode);
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; i<hashsize; i++)
if (hashtable[i].unicode != 0xffff) {
if (ect++ < ct) {
put_fs_word(hashtable[i].unicode, &list->unicode);
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 */
}
/*
* 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);
......@@ -4,6 +4,8 @@
#include <linux/interrupt.h>
#include <linux/keyboard.h>
extern int shift_state;
extern char *func_table[MAX_NR_FUNC];
extern char func_buf[];
extern char *funcbufptr;
......
......@@ -370,10 +370,22 @@ 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
if (!raw_mode)
printk("keyboard error\n");
#endif
#endif
......@@ -381,14 +393,6 @@ static void keyboard_interrupt(int irq, struct pt_regs *regs)
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,6 +418,7 @@ static void keyboard_interrupt(int irq, struct pt_regs *regs)
prev_scancode = 0;
} else {
#ifdef KBD_REPORT_UNKN
if (!raw_mode)
printk("keyboard: unknown e1 escape sequence\n");
#endif
prev_scancode = 0;
......@@ -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
}
......
/*
* 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 <linux/tty.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#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 <ctype.h>: 011-015 on the screen aren't spaces */
#define isspace(c) ((c) == ' ')
/* Variables for selection control. */
/* Use a dynamic buffer, instead of static (Dec 1994) */
int sel_cons = 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;
}
/*
* 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
......@@ -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)
......@@ -1453,20 +1448,22 @@ static int tty_ioctl(struct inode * inode, struct file * file,
switch (retval = get_fs_byte((char *)arg))
{
case 0:
return do_screendump(arg,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;
}
/*
* 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
/*
* 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 <linux/kernel.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/fs.h>
#include <asm/segment.h>
#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;
}
......@@ -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; i<MAX_NR_CONSOLES; i++)
if (! VT_IS_IN_USE(i) && i != fg_console)
if (! VT_BUSY(i))
vc_disallocate(i);
} else {
/* disallocate a single console, if possible */
arg--;
if (VT_IS_IN_USE(arg) || arg == fg_console)
if (VT_BUSY(arg))
return -EBUSY;
if (arg) /* leave 0 */
vc_disallocate(arg);
......@@ -836,11 +842,60 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (!perm)
return -EPERM;
return con_set_trans((char *)arg);
/* con_set_trans() defined in console.c */
case GIO_SCRNMAP:
return con_get_trans((char *)arg);
/* con_get_trans() defined in console.c */
case PIO_UNIMAPCLR:
{ struct unimapinit ui;
if (!perm)
return -EPERM;
i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct unimapinit));
if (i)
return i;
memcpy_fromfs(&ui, (void *)arg, sizeof(struct unimapinit));
con_clear_unimap(&ui);
return 0;
}
case PIO_UNIMAP:
{ struct unimapdesc *ud;
u_short ct;
struct unipair *list;
if (!perm)
return -EPERM;
i = verify_area(VERIFY_READ, (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);
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;
......
......@@ -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);
......
......@@ -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]);
}
......
......@@ -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;
......
/*
* 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;
......
......@@ -7,7 +7,7 @@
#include <linux/scsicam.h>
#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 *));
......
......@@ -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 <linux/module.h>
......@@ -63,12 +63,17 @@
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/dma.h>
#include "eata_dma.h"
#include "../block/blk.h"
#include "scsi.h"
#include "sd.h"
#include "hosts.h"
#include <linux/scsicam.h>
#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;
......
......@@ -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 <linux/scsicam.h>
#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
......
......@@ -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
......
......@@ -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,33 +1916,48 @@ 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;
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)
{
......
......@@ -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);
......
......@@ -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 *
......
/*
* 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;
......
......@@ -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
......@@ -38,7 +38,7 @@
#include <linux/config.h>
#include <linux/unistd.h>
typedef int (*sysfun_p)();
typedef int (*sysfun_p)(int);
extern sysfun_p sys_call_table[];
#define SYS(name) (sys_call_table[__NR_##name])
......
......@@ -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 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
* 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 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd)
return 0;
#endif
}
if (! (caller = alloc_lock(before, caller, fd)))
if (! (caller = alloc_lock(before, caller)))
return -ENOLCK;
}
if (right) {
......@@ -427,7 +430,7 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd)
* 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 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd)
* 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;
}
......@@ -29,7 +29,7 @@
#include <linux/errno.h>
#include <linux/locks.h>
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);
......
......@@ -20,7 +20,7 @@
#include <asm/segment.h>
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));
}
/*
......
#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 {
......@@ -512,53 +522,107 @@ static int get_stat(int pid, char * buffer)
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;
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;
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;
}
}
--tpag;
}
drs += pages;
vma = vma->vm_next;
}
}
return sprintf(buffer,"%d %d %d %d %d %d %d\n",
......
......@@ -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
......
......@@ -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
......
......@@ -3,21 +3,6 @@
#include <asm/segment.h>
#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
......
......@@ -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;
......
......@@ -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
......
......@@ -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 */
......
......@@ -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);
......
......@@ -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();
/*
......
......@@ -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 = {
......
#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,
size_t size, unsigned int flags)
static inline void filemap_sync_pte(pte_t * pte, struct vm_area_struct *vma,
unsigned long address, 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;
pte_t page = *pte;
if (!pte_present(page))
return;
if (!pte_dirty(page))
return;
if (flags & MS_INVALIDATE) {
pte_clear(page_table);
pte_clear(pte);
} else {
mem_map[MAP_NR(pte_page(pte))]++;
*page_table = pte_mkclean(pte);
mem_map[MAP_NR(pte_page(page))]++;
*pte = pte_mkclean(page);
}
file_mmap_sync_page(vma, start, pte_page(pte));
free_page(pte_page(pte));
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 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)) {
......
......@@ -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;
}
......
#define THREE_LEVEL
/*
* linux/mm/mprotect.c
*
......@@ -17,44 +18,69 @@
#include <asm/system.h>
#include <asm/pgtable.h>
static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot)
static inline void change_pte_range(pmd_t * pmd, unsigned long address,
unsigned long size, 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;
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;
}
page_table = offset + (pte_t *) pgd_page(*dir);
offset = PTRS_PER_PAGE - offset;
if (offset > nr)
offset = nr;
nr = nr - offset;
pte = pte_offset(pmd, address);
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
do {
entry = *page_table;
pte_t entry = *pte;
if (pte_present(entry))
*page_table = pte_modify(entry, newprot);
++page_table;
} while (--offset);
*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;
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;
}
......
#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;
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;
}
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;
}
}
}
/*
* 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;
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.
*/
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;
pte_t pte = *dir;
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);
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;
return 0;
if (pte_present(pte)) {
unsigned long page = pte_page(pte);
if (page >= high_memory)
continue;
return 0;
if (!in_swap_cache(page))
continue;
return 0;
if (SWP_TYPE(in_swap_cache(page)) != type)
continue;
return 0;
delete_from_swap_cache(page);
*page_table = pte_mkdirty(pte);
continue;
*dir = pte_mkdirty(pte);
return 0;
}
if (SWP_TYPE(pte_val(pte)) != type)
continue;
if (!tmp) {
if (!(tmp = __get_free_page(GFP_KERNEL)))
return -ENOMEM;
goto repeat;
return 0;
read_swap_page(pte_val(pte), (char *) page);
if (pte_val(*dir) != pte_val(pte)) {
free_page(page);
return 1;
}
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;
*dir = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
++vma->vm_task->mm->rss;
swap_free(pte_val(pte));
tmp = 0;
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;
}
/*
* 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.
*/
static int try_to_unuse(unsigned int type)
{
int nr;
unsigned long page = get_free_page(GFP_KERNEL);
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;
}
}
free_page(tmp);
nr++;
}
free_page(page);
return 0;
}
......
......@@ -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 */
{
......
......@@ -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--;
}
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment